Bluetooth: tests: use global testlib in read_fill_buf
This deduplicates a copy of testlib from before testlib was a globally available cmake library. Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
This commit is contained in:
parent
adedf14c42
commit
1e2b889bbb
|
@ -6,11 +6,7 @@ find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
|||
project(app)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
../testlib/bs_main.c
|
||||
../testlib/scan.c
|
||||
../testlib/connect.c
|
||||
../testlib/security.c
|
||||
../testlib/att_read.c
|
||||
../bs_main.c
|
||||
main.c
|
||||
)
|
||||
|
||||
|
@ -18,3 +14,6 @@ zephyr_include_directories(
|
|||
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
)
|
||||
|
||||
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
|
||||
target_link_libraries(app PRIVATE testlib)
|
||||
|
|
|
@ -10,19 +10,19 @@
|
|||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include "../common_defs.h"
|
||||
#include <testlib/att_read.h>
|
||||
#include <testlib/conn.h>
|
||||
#include <testlib/scan.h>
|
||||
#include <testlib/security.h>
|
||||
|
||||
#include "../testlib/att_read.h"
|
||||
#include "../testlib/bs_macro.h"
|
||||
#include "../testlib/connect.h"
|
||||
#include "../testlib/scan.h"
|
||||
#include "../testlib/security.h"
|
||||
#include "../bs_macro.h"
|
||||
#include "../common_defs.h"
|
||||
|
||||
LOG_MODULE_REGISTER(client, LOG_LEVEL_DBG);
|
||||
|
||||
#define BT_LOCAL_ATT_MTU_EATT MIN(BT_L2CAP_SDU_RX_MTU, BT_L2CAP_SDU_TX_MTU)
|
||||
#define BT_LOCAL_ATT_MTU_UATT MIN(BT_L2CAP_RX_MTU, BT_L2CAP_TX_MTU)
|
||||
#define BT_ATT_BUF_SIZE MAX(BT_LOCAL_ATT_MTU_UATT, BT_LOCAL_ATT_MTU_EATT)
|
||||
#define BT_ATT_BUF_SIZE MAX(BT_LOCAL_ATT_MTU_UATT, BT_LOCAL_ATT_MTU_EATT)
|
||||
|
||||
void test_long_read(struct bt_conn *conn, enum bt_att_chan_opt bearer)
|
||||
{
|
||||
|
@ -43,20 +43,20 @@ void test_long_read(struct bt_conn *conn, enum bt_att_chan_opt bearer)
|
|||
LOG_INF("ATT_READ_BY_TYPE");
|
||||
/* Aka. "read by uuid". */
|
||||
err = bt_testlib_att_read_by_type_sync(&attr_value, &actual_read_len,
|
||||
&handle, conn, bearer,
|
||||
&handle, NULL, conn, bearer,
|
||||
MTU_VALIDATION_CHRC, 1, 0xffff);
|
||||
break;
|
||||
case 1:
|
||||
LOG_INF("ATT_READ");
|
||||
/* Arg `offset == 0`: the stack should choose ATT_READ PDU. */
|
||||
err = bt_testlib_att_read_by_handle_sync(&attr_value, &actual_read_len,
|
||||
conn, bearer, handle, 0);
|
||||
NULL, conn, bearer, handle, 0);
|
||||
break;
|
||||
case 2:
|
||||
LOG_INF("ATT_READ_BLOB");
|
||||
/* Arg `offset != 0`: the stack should choose ATT_READ_BLOB PDU. */
|
||||
err = bt_testlib_att_read_by_handle_sync(&attr_value, &actual_read_len,
|
||||
conn, bearer, handle, 1);
|
||||
NULL, conn, bearer, handle, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})
|
|||
project(app)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
../testlib/bs_main.c
|
||||
../testlib/adv.c
|
||||
../bs_main.c
|
||||
main.c
|
||||
)
|
||||
|
||||
|
@ -15,3 +14,6 @@ zephyr_include_directories(
|
|||
${BSIM_COMPONENTS_PATH}/libPhyComv1/src/
|
||||
${BSIM_COMPONENTS_PATH}/libUtilv1/src/
|
||||
)
|
||||
|
||||
add_subdirectory(${ZEPHYR_BASE}/tests/bluetooth/common/testlib testlib)
|
||||
target_link_libraries(app PRIVATE testlib)
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
#include <zephyr/sys/__assert.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include "../testlib/bs_macro.h"
|
||||
#include "../testlib/adv.h"
|
||||
#include <testlib/adv.h>
|
||||
|
||||
#include "../bs_macro.h"
|
||||
#include "../common_defs.h"
|
||||
|
||||
LOG_MODULE_REGISTER(server, LOG_LEVEL_DBG);
|
||||
|
|
|
@ -1,83 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/l2cap.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
struct bt_testlib_adv_ctx {
|
||||
struct bt_conn **result;
|
||||
struct k_condvar done;
|
||||
};
|
||||
|
||||
/* Context pool (with capacity of one). */
|
||||
static K_SEM_DEFINE(g_ctx_free, 1, 1);
|
||||
static K_MUTEX_DEFINE(g_ctx_lock);
|
||||
static struct bt_testlib_adv_ctx *g_ctx;
|
||||
|
||||
static void connected_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_connected_info *info)
|
||||
{
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
|
||||
if (g_ctx->result) {
|
||||
*g_ctx->result = bt_conn_ref(info->conn);
|
||||
}
|
||||
k_condvar_signal(&g_ctx->done);
|
||||
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
}
|
||||
|
||||
int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options)
|
||||
{
|
||||
int api_err;
|
||||
struct bt_le_ext_adv *adv = NULL;
|
||||
struct bt_le_adv_param param = {};
|
||||
struct bt_testlib_adv_ctx ctx = {
|
||||
.result = conn,
|
||||
};
|
||||
static const struct bt_le_ext_adv_cb cb = {
|
||||
.connected = connected_cb,
|
||||
};
|
||||
|
||||
param.id = id;
|
||||
param.interval_min = BT_GAP_ADV_FAST_INT_MIN_1;
|
||||
param.interval_max = BT_GAP_ADV_FAST_INT_MAX_1;
|
||||
param.options |= BT_LE_ADV_OPT_CONNECTABLE;
|
||||
param.options |= adv_options;
|
||||
|
||||
k_condvar_init(&ctx.done);
|
||||
|
||||
k_sem_take(&g_ctx_free, K_FOREVER);
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
g_ctx = &ctx;
|
||||
|
||||
api_err = bt_le_ext_adv_create(¶m, &cb, &adv);
|
||||
if (!api_err) {
|
||||
api_err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
|
||||
}
|
||||
|
||||
if (!api_err) {
|
||||
k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
|
||||
}
|
||||
|
||||
/* Delete adv before giving semaphore so that it's potentially available
|
||||
* for the next taker of the semaphore.
|
||||
*/
|
||||
if (adv) {
|
||||
bt_le_ext_adv_delete(adv);
|
||||
}
|
||||
|
||||
g_ctx = NULL;
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
k_sem_give(&g_ctx_free);
|
||||
|
||||
return api_err;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
int bt_testlib_adv_conn(struct bt_conn **conn, int id, uint32_t adv_options);
|
|
@ -1,126 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/l2cap.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
#include "att_read.h"
|
||||
|
||||
struct bt_testlib_att_read_closure {
|
||||
uint8_t att_err;
|
||||
struct bt_conn *conn;
|
||||
struct bt_gatt_read_params params;
|
||||
uint16_t *result_size;
|
||||
uint16_t *result_handle;
|
||||
struct net_buf_simple *result_data;
|
||||
struct k_mutex lock;
|
||||
struct k_condvar done;
|
||||
};
|
||||
|
||||
static inline uint8_t att_read_cb(struct bt_conn *conn, uint8_t att_err,
|
||||
struct bt_gatt_read_params *params, const void *read_data,
|
||||
uint16_t read_len)
|
||||
{
|
||||
struct bt_testlib_att_read_closure *ctx =
|
||||
CONTAINER_OF(params, struct bt_testlib_att_read_closure, params);
|
||||
|
||||
k_mutex_lock(&ctx->lock, K_FOREVER);
|
||||
|
||||
ctx->att_err = att_err;
|
||||
|
||||
if (!att_err && ctx->result_handle) {
|
||||
*ctx->result_handle = params->by_uuid.start_handle;
|
||||
}
|
||||
|
||||
if (!att_err && ctx->result_size) {
|
||||
*ctx->result_size = read_len;
|
||||
}
|
||||
|
||||
if (!att_err && ctx->result_data) {
|
||||
uint16_t result_data_size =
|
||||
MIN(read_len, net_buf_simple_tailroom(ctx->result_data));
|
||||
net_buf_simple_add_mem(ctx->result_data, read_data, result_data_size);
|
||||
}
|
||||
|
||||
k_condvar_signal(&ctx->done);
|
||||
k_mutex_unlock(&ctx->lock);
|
||||
return BT_GATT_ITER_STOP;
|
||||
}
|
||||
|
||||
static inline int bt_testlib_sync_bt_gatt_read(struct bt_testlib_att_read_closure *ctx)
|
||||
{
|
||||
int api_err;
|
||||
|
||||
ctx->params.func = att_read_cb;
|
||||
|
||||
k_mutex_init(&ctx->lock);
|
||||
k_condvar_init(&ctx->done);
|
||||
|
||||
k_mutex_lock(&ctx->lock, K_FOREVER);
|
||||
|
||||
api_err = bt_gatt_read(ctx->conn, &ctx->params);
|
||||
|
||||
if (!api_err) {
|
||||
k_condvar_wait(&ctx->done, &ctx->lock, K_FOREVER);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&ctx->lock);
|
||||
|
||||
if (api_err) {
|
||||
__ASSERT_NO_MSG(api_err < 0);
|
||||
return api_err;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(ctx->att_err >= 0);
|
||||
return ctx->att_err;
|
||||
}
|
||||
|
||||
int bt_testlib_att_read_by_type_sync(struct net_buf_simple *result_data, uint16_t *result_size,
|
||||
uint16_t *result_handle, struct bt_conn *conn,
|
||||
enum bt_att_chan_opt bearer, const struct bt_uuid *type,
|
||||
uint16_t start_handle, uint16_t end_handle)
|
||||
{
|
||||
struct bt_testlib_att_read_closure ctx = {
|
||||
.result_handle = result_handle,
|
||||
.result_size = result_size,
|
||||
.conn = conn,
|
||||
.result_data = result_data,
|
||||
.params = {.by_uuid = {.uuid = type,
|
||||
.start_handle = start_handle,
|
||||
.end_handle = end_handle},
|
||||
IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer))},
|
||||
};
|
||||
|
||||
if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) {
|
||||
__ASSERT(IS_ENABLED(CONFIG_BT_EATT), "EATT not complied in");
|
||||
}
|
||||
|
||||
return bt_testlib_sync_bt_gatt_read(&ctx);
|
||||
}
|
||||
|
||||
int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint16_t *result_size,
|
||||
struct bt_conn *conn, enum bt_att_chan_opt bearer,
|
||||
uint16_t handle, uint16_t offset)
|
||||
{
|
||||
struct bt_testlib_att_read_closure ctx = {
|
||||
.result_size = result_size,
|
||||
.conn = conn,
|
||||
.result_data = result_data,
|
||||
.params = {.handle_count = 1,
|
||||
.single = {.handle = handle, .offset = offset},
|
||||
IF_ENABLED(CONFIG_BT_EATT, (.chan_opt = bearer))},
|
||||
};
|
||||
|
||||
if (bearer == BT_ATT_CHAN_OPT_ENHANCED_ONLY) {
|
||||
__ASSERT(IS_ENABLED(CONFIG_BT_EATT), "EATT not complied in");
|
||||
}
|
||||
|
||||
return bt_testlib_sync_bt_gatt_read(&ctx);
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
|
||||
int bt_testlib_att_read_by_type_sync(struct net_buf_simple *result_data, uint16_t *result_size,
|
||||
uint16_t *result_handle, struct bt_conn *conn,
|
||||
enum bt_att_chan_opt bearer, const struct bt_uuid *type,
|
||||
uint16_t start_handle, uint16_t end_handle);
|
||||
|
||||
int bt_testlib_att_read_by_handle_sync(struct net_buf_simple *result_data, uint16_t *result_size,
|
||||
struct bt_conn *conn, enum bt_att_chan_opt bearer,
|
||||
uint16_t handle, uint16_t offset);
|
|
@ -1,71 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
||||
#include "connect.h"
|
||||
|
||||
struct bt_testlib_connect_closure {
|
||||
uint8_t conn_err;
|
||||
struct bt_conn **conn;
|
||||
struct k_mutex lock;
|
||||
struct k_condvar done;
|
||||
};
|
||||
|
||||
/* Context pool (with capacity of one). */
|
||||
static K_SEM_DEFINE(g_ctx_free, 1, 1);
|
||||
static K_MUTEX_DEFINE(g_ctx_lock);
|
||||
static struct bt_testlib_connect_closure *g_ctx;
|
||||
|
||||
static void connected_cb(struct bt_conn *conn, uint8_t conn_err)
|
||||
{
|
||||
/* Loop over each (allocated) item in pool. */
|
||||
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
|
||||
if (g_ctx && conn == *g_ctx->conn) {
|
||||
g_ctx->conn_err = conn_err;
|
||||
k_condvar_signal(&g_ctx->done);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.connected = connected_cb,
|
||||
};
|
||||
|
||||
int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **conn)
|
||||
{
|
||||
int api_err;
|
||||
struct bt_testlib_connect_closure ctx = {
|
||||
.conn = conn,
|
||||
};
|
||||
|
||||
k_condvar_init(&ctx.done);
|
||||
|
||||
k_sem_take(&g_ctx_free, K_FOREVER);
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
g_ctx = &ctx;
|
||||
|
||||
api_err = bt_conn_le_create(peer, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, conn);
|
||||
|
||||
if (!api_err) {
|
||||
k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
|
||||
}
|
||||
|
||||
g_ctx = NULL;
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
k_sem_give(&g_ctx_free);
|
||||
|
||||
if (api_err) {
|
||||
__ASSERT_NO_MSG(api_err < 0);
|
||||
return api_err;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(ctx.conn_err >= 0);
|
||||
return ctx.conn_err;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
|
||||
int bt_testlib_connect(const bt_addr_le_t *peer, struct bt_conn **conn);
|
|
@ -1,87 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
#include "scan.h"
|
||||
|
||||
struct bt_scan_find_name_closure {
|
||||
char *wanted_name;
|
||||
bt_addr_le_t *result;
|
||||
struct k_condvar done;
|
||||
};
|
||||
|
||||
/* Context pool (with capacity of one). */
|
||||
static K_SEM_DEFINE(g_ctx_free, 1, 1);
|
||||
static K_MUTEX_DEFINE(g_ctx_lock);
|
||||
static struct bt_scan_find_name_closure *g_ctx;
|
||||
|
||||
static bool bt_scan_find_name_cb_data_cb(struct bt_data *data, void *user_data)
|
||||
{
|
||||
char **wanted = user_data;
|
||||
|
||||
if (data->type == BT_DATA_NAME_COMPLETE) {
|
||||
if (data->data_len == strlen(*wanted) &&
|
||||
!memcmp(*wanted, data->data, data->data_len)) {
|
||||
*wanted = NULL;
|
||||
/* Stop bt_data_parse. */
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Continue with next ad data. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bt_scan_find_name_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
char *wanted;
|
||||
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
|
||||
__ASSERT_NO_MSG(g_ctx);
|
||||
__ASSERT_NO_MSG(g_ctx->wanted_name);
|
||||
|
||||
wanted = g_ctx->wanted_name;
|
||||
|
||||
bt_data_parse(buf, bt_scan_find_name_cb_data_cb, &wanted);
|
||||
|
||||
if (!wanted) {
|
||||
(void)bt_le_scan_stop();
|
||||
*g_ctx->result = *addr;
|
||||
k_condvar_signal(&g_ctx->done);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
}
|
||||
|
||||
int bt_testlib_scan_find_name(bt_addr_le_t *result, char name[])
|
||||
{
|
||||
int api_err;
|
||||
struct bt_scan_find_name_closure ctx = {
|
||||
.wanted_name = name,
|
||||
.result = result,
|
||||
};
|
||||
|
||||
k_condvar_init(&ctx.done);
|
||||
|
||||
k_sem_take(&g_ctx_free, K_FOREVER);
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
g_ctx = &ctx;
|
||||
|
||||
api_err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, bt_scan_find_name_cb);
|
||||
if (!api_err) {
|
||||
k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
|
||||
}
|
||||
|
||||
g_ctx = NULL;
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
k_sem_give(&g_ctx_free);
|
||||
|
||||
return api_err;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
||||
int bt_testlib_scan_find_name(bt_addr_le_t *result, char name[]);
|
|
@ -1,103 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/l2cap.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/__assert.h>
|
||||
|
||||
struct testlib_security_ctx {
|
||||
enum bt_security_err result;
|
||||
struct bt_conn *conn;
|
||||
bt_security_t new_minimum;
|
||||
struct k_condvar done;
|
||||
};
|
||||
|
||||
/* Context pool (with capacity of one). */
|
||||
static K_SEM_DEFINE(g_ctx_free, 1, 1);
|
||||
static K_MUTEX_DEFINE(g_ctx_lock);
|
||||
static struct testlib_security_ctx *g_ctx;
|
||||
|
||||
static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
|
||||
{
|
||||
/* Mutex operations establish a happens-before relationship. This
|
||||
* ensures variables have the expected values despite non-atomic
|
||||
* accesses.
|
||||
*/
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
|
||||
if (g_ctx && (g_ctx->conn == conn)) {
|
||||
g_ctx->result = err;
|
||||
/* Assumption: A security error means there will be further
|
||||
* security changes for this connection.
|
||||
*/
|
||||
if (err || level >= g_ctx->new_minimum) {
|
||||
k_condvar_signal(&g_ctx->done);
|
||||
}
|
||||
}
|
||||
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
}
|
||||
|
||||
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||
.security_changed = security_changed,
|
||||
};
|
||||
|
||||
int bt_testlib_secure(struct bt_conn *conn, bt_security_t new_minimum)
|
||||
{
|
||||
int api_err = 0;
|
||||
struct testlib_security_ctx ctx = {
|
||||
.conn = conn,
|
||||
.new_minimum = new_minimum,
|
||||
};
|
||||
|
||||
k_condvar_init(&ctx.done);
|
||||
|
||||
/* The semaphore allocates `g_ctx` to this invocation of
|
||||
* `bt_testlib_secure`, in case this function is called from multiple
|
||||
* threads in parallel.
|
||||
*/
|
||||
k_sem_take(&g_ctx_free, K_FOREVER);
|
||||
/* The mutex synchronizes this function with `security_changed()`. */
|
||||
k_mutex_lock(&g_ctx_lock, K_FOREVER);
|
||||
|
||||
/* Do the thing. */
|
||||
api_err = bt_conn_set_security(conn, new_minimum);
|
||||
|
||||
/* Holding the mutex will pause any thread entering
|
||||
* `security_changed_cb`, delaying it until `k_condvar_wait`. This
|
||||
* ensures that the condition variable is signaled while this thread is
|
||||
* in `k_condvar_wait`, even if the event happens before, e.g. between
|
||||
* `bt_conn_get_security` and `k_condvar_wait`.
|
||||
*
|
||||
* If the security level is already satisfied, there is no point in
|
||||
* waiting, and it would deadlock if security was already satisfied
|
||||
* before the mutex was taken, `bt_conn_set_security` will result in no
|
||||
* operation.
|
||||
*/
|
||||
if (!api_err && bt_conn_get_security(conn) < new_minimum) {
|
||||
/* Waiting on a condvar releases the mutex and waits for a
|
||||
* signal on the condvar, atomically, without a gap between the
|
||||
* release and wait. The mutex is locked again before returning.
|
||||
*/
|
||||
g_ctx = &ctx;
|
||||
k_condvar_wait(&ctx.done, &g_ctx_lock, K_FOREVER);
|
||||
g_ctx = NULL;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&g_ctx_lock);
|
||||
k_sem_give(&g_ctx_free);
|
||||
|
||||
if (api_err) {
|
||||
__ASSERT_NO_MSG(api_err < 0);
|
||||
return api_err;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(ctx.result >= 0);
|
||||
return ctx.result;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
/* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
|
||||
int bt_testlib_secure(struct bt_conn *conn, bt_security_t new_minimum);
|
Loading…
Reference in a new issue