Bluetooth: Mesh: Add full virtual addresses support
This commit adds the following features related to virtual addresses support: - Allows to store Label UUIDs which virtual addresses collide; - Allows to decrypt messages encrypted with a virtual address with collision; - Allows to publish a message to a specific Label UUID to avoid virtual addresses collision by adding a pointer to Label UUID to struct bt_mesh_msg_ctx and struct bt_mesh_model_pub; - Allows to differentiate Label UUIDs in the model's Subscription List by storing all subscribed UUIDs in struct bt_mesh_model.uuids field. Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
1956b06ecc
commit
648378b292
22 changed files with 1047 additions and 722 deletions
|
@ -17,10 +17,18 @@
|
||||||
/* Internal macros used to initialize array members */
|
/* Internal macros used to initialize array members */
|
||||||
#define BT_MESH_KEY_UNUSED_ELT_(IDX, _) BT_MESH_KEY_UNUSED
|
#define BT_MESH_KEY_UNUSED_ELT_(IDX, _) BT_MESH_KEY_UNUSED
|
||||||
#define BT_MESH_ADDR_UNASSIGNED_ELT_(IDX, _) BT_MESH_ADDR_UNASSIGNED
|
#define BT_MESH_ADDR_UNASSIGNED_ELT_(IDX, _) BT_MESH_ADDR_UNASSIGNED
|
||||||
|
#define BT_MESH_UUID_UNASSIGNED_ELT_(IDX, _) NULL
|
||||||
#define BT_MESH_MODEL_KEYS_UNUSED(_keys) \
|
#define BT_MESH_MODEL_KEYS_UNUSED(_keys) \
|
||||||
{ LISTIFY(_keys, BT_MESH_KEY_UNUSED_ELT_, (,)) }
|
{ LISTIFY(_keys, BT_MESH_KEY_UNUSED_ELT_, (,)) }
|
||||||
#define BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps) \
|
#define BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps) \
|
||||||
{ LISTIFY(_grps, BT_MESH_ADDR_UNASSIGNED_ELT_, (,)) }
|
{ LISTIFY(_grps, BT_MESH_ADDR_UNASSIGNED_ELT_, (,)) }
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
#define BT_MESH_MODEL_UUIDS_UNASSIGNED() \
|
||||||
|
.uuids = (const uint8_t *[]){ LISTIFY(CONFIG_BT_MESH_LABEL_COUNT, \
|
||||||
|
BT_MESH_UUID_UNASSIGNED_ELT_, (,)) },
|
||||||
|
#else
|
||||||
|
#define BT_MESH_MODEL_UUIDS_UNASSIGNED()
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Access layer
|
* @brief Access layer
|
||||||
|
@ -286,6 +294,7 @@ struct bt_mesh_model_op {
|
||||||
.keys_cnt = _keys, \
|
.keys_cnt = _keys, \
|
||||||
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \
|
||||||
.groups_cnt = _grps, \
|
.groups_cnt = _grps, \
|
||||||
|
BT_MESH_MODEL_UUIDS_UNASSIGNED() \
|
||||||
.op = _op, \
|
.op = _op, \
|
||||||
.cb = _cb, \
|
.cb = _cb, \
|
||||||
.user_data = _user_data, \
|
.user_data = _user_data, \
|
||||||
|
@ -319,6 +328,7 @@ struct bt_mesh_model_op {
|
||||||
.keys_cnt = _keys, \
|
.keys_cnt = _keys, \
|
||||||
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(_grps), \
|
||||||
.groups_cnt = _grps, \
|
.groups_cnt = _grps, \
|
||||||
|
BT_MESH_MODEL_UUIDS_UNASSIGNED() \
|
||||||
.user_data = _user_data, \
|
.user_data = _user_data, \
|
||||||
.cb = _cb, \
|
.cb = _cb, \
|
||||||
}
|
}
|
||||||
|
@ -364,6 +374,7 @@ struct bt_mesh_model_op {
|
||||||
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
||||||
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
||||||
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
||||||
|
BT_MESH_MODEL_UUIDS_UNASSIGNED() \
|
||||||
.op = _op, \
|
.op = _op, \
|
||||||
.cb = _cb, \
|
.cb = _cb, \
|
||||||
.user_data = _user_data, \
|
.user_data = _user_data, \
|
||||||
|
@ -418,6 +429,7 @@ struct bt_mesh_model_op {
|
||||||
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
.keys_cnt = CONFIG_BT_MESH_MODEL_KEY_COUNT, \
|
||||||
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
.groups = (uint16_t []) BT_MESH_MODEL_GROUPS_UNASSIGNED(CONFIG_BT_MESH_MODEL_GROUP_COUNT), \
|
||||||
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
.groups_cnt = CONFIG_BT_MESH_MODEL_GROUP_COUNT, \
|
||||||
|
BT_MESH_MODEL_UUIDS_UNASSIGNED() \
|
||||||
.user_data = _user_data, \
|
.user_data = _user_data, \
|
||||||
.cb = _cb, \
|
.cb = _cb, \
|
||||||
.metadata = _metadata, \
|
.metadata = _metadata, \
|
||||||
|
@ -545,6 +557,7 @@ struct bt_mesh_model_pub {
|
||||||
struct bt_mesh_model *mod;
|
struct bt_mesh_model *mod;
|
||||||
|
|
||||||
uint16_t addr; /**< Publish Address. */
|
uint16_t addr; /**< Publish Address. */
|
||||||
|
const uint8_t *uuid; /**< Label UUID if Publish Address is Virtual Address. */
|
||||||
uint16_t key:12, /**< Publish AppKey Index. */
|
uint16_t key:12, /**< Publish AppKey Index. */
|
||||||
cred:1, /**< Friendship Credentials Flag. */
|
cred:1, /**< Friendship Credentials Flag. */
|
||||||
send_rel:1, /**< Force reliable sending (segment acks) */
|
send_rel:1, /**< Force reliable sending (segment acks) */
|
||||||
|
@ -744,6 +757,11 @@ struct bt_mesh_model {
|
||||||
uint16_t * const groups;
|
uint16_t * const groups;
|
||||||
const uint16_t groups_cnt;
|
const uint16_t groups_cnt;
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
/** List of Label UUIDs the model is subscribed to. */
|
||||||
|
const uint8_t ** const uuids;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Opcode handler list */
|
/** Opcode handler list */
|
||||||
const struct bt_mesh_model_op * const op;
|
const struct bt_mesh_model_op * const op;
|
||||||
|
|
||||||
|
|
|
@ -854,6 +854,23 @@ int bt_mesh_friend_terminate(uint16_t lpn_addr);
|
||||||
*/
|
*/
|
||||||
void bt_mesh_rpl_pending_store(uint16_t addr);
|
void bt_mesh_rpl_pending_store(uint16_t addr);
|
||||||
|
|
||||||
|
/** @brief Iterate stored Label UUIDs.
|
||||||
|
*
|
||||||
|
* When @c addr is @ref BT_MESH_ADDR_UNASSIGNED, this function iterates over all available addresses
|
||||||
|
* starting with @c uuid. In this case, use @c retaddr to get virtual address representation of
|
||||||
|
* the returned Label UUID. When @c addr is a virtual address, this function returns next Label
|
||||||
|
* UUID corresponding to the @c addr. When @c uuid is NULL, this function returns the first
|
||||||
|
* available UUID. If @c uuid is previously returned uuid, this function returns following uuid.
|
||||||
|
*
|
||||||
|
* @param addr Virtual address to search for, or @ref BT_MESH_ADDR_UNASSIGNED.
|
||||||
|
* @param uuid Pointer to the previously returned Label UUID or NULL.
|
||||||
|
* @param retaddr Pointer to a memory where virtual address representation of the returning UUID is
|
||||||
|
* to be stored to.
|
||||||
|
*
|
||||||
|
* @return Pointer to Label UUID, or NULL if no more entries found.
|
||||||
|
*/
|
||||||
|
const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -86,6 +86,9 @@ struct bt_mesh_msg_ctx {
|
||||||
/** Destination address of a received message. Not used for sending. */
|
/** Destination address of a received message. Not used for sending. */
|
||||||
uint16_t recv_dst;
|
uint16_t recv_dst;
|
||||||
|
|
||||||
|
/** Label UUID if Remote address is Virtual address, or NULL otherwise. */
|
||||||
|
const uint8_t *uuid;
|
||||||
|
|
||||||
/** RSSI of received packet. Not used for sending. */
|
/** RSSI of received packet. Not used for sending. */
|
||||||
int8_t recv_rssi;
|
int8_t recv_rssi;
|
||||||
|
|
||||||
|
@ -102,6 +105,8 @@ struct bt_mesh_msg_ctx {
|
||||||
/**
|
/**
|
||||||
* @brief Helper for bt_mesh_msg_ctx structure initialization.
|
* @brief Helper for bt_mesh_msg_ctx structure initialization.
|
||||||
*
|
*
|
||||||
|
* @note If @c dst is a Virtual Address, Label UUID shall be initialized separately.
|
||||||
|
*
|
||||||
* @param net_key_idx NetKey Index of the subnet to send the message on. Only used if
|
* @param net_key_idx NetKey Index of the subnet to send the message on. Only used if
|
||||||
* @c app_key_idx points to devkey.
|
* @c app_key_idx points to devkey.
|
||||||
* @param app_key_idx AppKey Index to encrypt the message with.
|
* @param app_key_idx AppKey Index to encrypt the message with.
|
||||||
|
@ -141,7 +146,12 @@ struct bt_mesh_msg_ctx {
|
||||||
* @param pub Pointer to a model publication context.
|
* @param pub Pointer to a model publication context.
|
||||||
*/
|
*/
|
||||||
#define BT_MESH_MSG_CTX_INIT_PUB(pub) \
|
#define BT_MESH_MSG_CTX_INIT_PUB(pub) \
|
||||||
BT_MESH_MSG_CTX_INIT(0, (pub)->key, (pub)->addr, (pub)->ttl)
|
{ \
|
||||||
|
.app_idx = (pub)->key, \
|
||||||
|
.addr = (pub)->addr, \
|
||||||
|
.send_ttl = (pub)->ttl, \
|
||||||
|
.uuid = (pub)->uuid, \
|
||||||
|
}
|
||||||
|
|
||||||
/** @brief Initialize a model message.
|
/** @brief Initialize a model message.
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH
|
||||||
msg.c
|
msg.c
|
||||||
cfg_srv.c
|
cfg_srv.c
|
||||||
health_srv.c
|
health_srv.c
|
||||||
|
va.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if (CONFIG_BT_MESH_V1d1)
|
if (CONFIG_BT_MESH_V1d1)
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "foundation.h"
|
#include "foundation.h"
|
||||||
#include "op_agg.h"
|
#include "op_agg.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_ACCESS_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -34,13 +35,16 @@ LOG_MODULE_REGISTER(bt_mesh_access);
|
||||||
|
|
||||||
/* Model publication information for persistent storage. */
|
/* Model publication information for persistent storage. */
|
||||||
struct mod_pub_val {
|
struct mod_pub_val {
|
||||||
uint16_t addr;
|
struct {
|
||||||
uint16_t key;
|
uint16_t addr;
|
||||||
uint8_t ttl;
|
uint16_t key;
|
||||||
uint8_t retransmit;
|
uint8_t ttl;
|
||||||
uint8_t period;
|
uint8_t retransmit;
|
||||||
uint8_t period_div:4,
|
uint8_t period;
|
||||||
cred:1;
|
uint8_t period_div:4,
|
||||||
|
cred:1;
|
||||||
|
} base;
|
||||||
|
uint16_t uuidx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct comp_foreach_model_arg {
|
struct comp_foreach_model_arg {
|
||||||
|
@ -1002,6 +1006,69 @@ uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr)
|
||||||
return ctx.entry;
|
return ctx.entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
static const uint8_t **model_uuid_get(struct bt_mesh_model *mod, const uint8_t *uuid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) {
|
||||||
|
if (mod->uuids[i] == uuid) {
|
||||||
|
/* If we are looking for a new entry, ensure that we find a model where
|
||||||
|
* there is empty entry in both, uuids and groups list.
|
||||||
|
*/
|
||||||
|
if (uuid == NULL && !model_group_get(mod, BT_MESH_ADDR_UNASSIGNED)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &mod->uuids[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct find_uuid_visitor_ctx {
|
||||||
|
const uint8_t **entry;
|
||||||
|
struct bt_mesh_model *mod;
|
||||||
|
const uint8_t *uuid;
|
||||||
|
};
|
||||||
|
|
||||||
|
static enum bt_mesh_walk find_uuid_mod_visitor(struct bt_mesh_model *mod, void *user_data)
|
||||||
|
{
|
||||||
|
struct find_uuid_visitor_ctx *ctx = user_data;
|
||||||
|
|
||||||
|
if (mod->elem_idx != ctx->mod->elem_idx) {
|
||||||
|
return BT_MESH_WALK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->entry = model_uuid_get(mod, ctx->uuid);
|
||||||
|
if (ctx->entry) {
|
||||||
|
ctx->mod = mod;
|
||||||
|
return BT_MESH_WALK_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_MESH_WALK_CONTINUE;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
||||||
|
|
||||||
|
const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid)
|
||||||
|
{
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
struct find_uuid_visitor_ctx ctx = {
|
||||||
|
.mod = *mod,
|
||||||
|
.entry = NULL,
|
||||||
|
.uuid = uuid,
|
||||||
|
};
|
||||||
|
|
||||||
|
bt_mesh_model_extensions_walk(*mod, find_uuid_mod_visitor, &ctx);
|
||||||
|
|
||||||
|
*mod = ctx.mod;
|
||||||
|
return ctx.entry;
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
|
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
|
||||||
uint16_t group_addr)
|
uint16_t group_addr)
|
||||||
{
|
{
|
||||||
|
@ -1117,11 +1184,13 @@ bool bt_mesh_model_has_key(struct bt_mesh_model *mod, uint16_t key)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst)
|
static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst, const uint8_t *uuid)
|
||||||
{
|
{
|
||||||
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
|
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
|
||||||
return (dev_comp->elem[mod->elem_idx].addr == dst);
|
return (dev_comp->elem[mod->elem_idx].addr == dst);
|
||||||
} else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst) ||
|
} else if (BT_MESH_ADDR_IS_VIRTUAL(dst)) {
|
||||||
|
return !!bt_mesh_model_find_uuid(&mod, uuid);
|
||||||
|
} else if (BT_MESH_ADDR_IS_GROUP(dst) ||
|
||||||
(BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) {
|
(BT_MESH_ADDR_IS_FIXED_GROUP(dst) && mod->elem_idx != 0)) {
|
||||||
return !!bt_mesh_model_find_group(&mod, dst);
|
return !!bt_mesh_model_find_group(&mod, dst);
|
||||||
}
|
}
|
||||||
|
@ -1217,8 +1286,7 @@ static int get_opcode(struct net_buf_simple *buf, uint32_t *opcode)
|
||||||
CODE_UNREACHABLE;
|
CODE_UNREACHABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int element_model_recv(struct bt_mesh_msg_ctx *ctx,
|
static int element_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf,
|
||||||
struct net_buf_simple *buf, uint16_t addr,
|
|
||||||
struct bt_mesh_elem *elem, uint32_t opcode)
|
struct bt_mesh_elem *elem, uint32_t opcode)
|
||||||
{
|
{
|
||||||
const struct bt_mesh_model_op *op;
|
const struct bt_mesh_model_op *op;
|
||||||
|
@ -1237,8 +1305,8 @@ static int element_model_recv(struct bt_mesh_msg_ctx *ctx,
|
||||||
return ACCESS_STATUS_WRONG_KEY;
|
return ACCESS_STATUS_WRONG_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!model_has_dst(model, addr)) {
|
if (!model_has_dst(model, ctx->recv_dst, ctx->uuid)) {
|
||||||
LOG_ERR("Invalid address 0x%02x", addr);
|
LOG_ERR("Invalid address 0x%02x", ctx->recv_dst);
|
||||||
return ACCESS_STATUS_INVALID_ADDRESS;
|
return ACCESS_STATUS_INVALID_ADDRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1291,13 +1359,13 @@ int bt_mesh_model_recv(struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf)
|
||||||
} else {
|
} else {
|
||||||
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
||||||
|
|
||||||
err = element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode);
|
err = element_model_recv(ctx, buf, elem, opcode);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (index = 0; index < dev_comp->elem_count; index++) {
|
for (index = 0; index < dev_comp->elem_count; index++) {
|
||||||
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
struct bt_mesh_elem *elem = &dev_comp->elem[index];
|
||||||
|
|
||||||
(void)element_model_recv(ctx, buf, ctx->recv_dst, elem, opcode);
|
(void)element_model_recv(ctx, buf, elem, opcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1581,6 +1649,64 @@ static int mod_set_sub(struct bt_mesh_model *mod, size_t len_rd,
|
||||||
LOG_HEXDUMP_DBG(mod->groups, len, "val");
|
LOG_HEXDUMP_DBG(mod->groups, len, "val");
|
||||||
|
|
||||||
LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0]));
|
LOG_DBG("Decoded %zu subscribed group addresses for model", len / sizeof(mod->groups[0]));
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
/* If uuids[0] is NULL, then either the model is not subscribed to virtual addresses or
|
||||||
|
* uuids are not yet recovered.
|
||||||
|
*/
|
||||||
|
if (mod->uuids[0] == NULL) {
|
||||||
|
int i, j = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < mod->groups_cnt && j < CONFIG_BT_MESH_LABEL_COUNT; i++) {
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) {
|
||||||
|
/* Recover from implementation where uuid was not stored for
|
||||||
|
* virtual address. It is safe to pick first matched label because
|
||||||
|
* previously the stack wasn't able to store virtual addresses with
|
||||||
|
* collisions.
|
||||||
|
*/
|
||||||
|
mod->uuids[j] = bt_mesh_va_uuid_get(mod->groups[i], NULL, NULL);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mod_set_sub_va(struct bt_mesh_model *mod, size_t len_rd,
|
||||||
|
settings_read_cb read_cb, void *cb_arg)
|
||||||
|
{
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT];
|
||||||
|
ssize_t len;
|
||||||
|
int i;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
/* Start with empty array regardless of cleared or set value */
|
||||||
|
(void)memset(mod->uuids, 0, CONFIG_BT_MESH_LABEL_COUNT * sizeof(mod->uuids[0]));
|
||||||
|
|
||||||
|
if (len_rd == 0) {
|
||||||
|
LOG_DBG("Cleared subscriptions for model");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = read_cb(cb_arg, uuidxs, sizeof(uuidxs));
|
||||||
|
if (len < 0) {
|
||||||
|
LOG_ERR("Failed to read value (err %zd)", len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_HEXDUMP_DBG(uuidxs, len, "val");
|
||||||
|
|
||||||
|
for (i = 0, count = 0; i < len / sizeof(uint16_t); i++) {
|
||||||
|
mod->uuids[count] = bt_mesh_va_get_uuid_by_idx(uuidxs[i]);
|
||||||
|
if (mod->uuids[count] != NULL) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DBG("Decoded %zu subscribed virtual addresses for model", count);
|
||||||
|
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1603,6 +1729,7 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd,
|
||||||
mod->pub->period = 0U;
|
mod->pub->period = 0U;
|
||||||
mod->pub->retransmit = 0U;
|
mod->pub->retransmit = 0U;
|
||||||
mod->pub->count = 0U;
|
mod->pub->count = 0U;
|
||||||
|
mod->pub->uuid = NULL;
|
||||||
|
|
||||||
LOG_DBG("Cleared publication for model");
|
LOG_DBG("Cleared publication for model");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1612,22 +1739,41 @@ static int mod_set_pub(struct bt_mesh_model *mod, size_t len_rd,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub));
|
err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub.base));
|
||||||
if (err) {
|
if (!err) {
|
||||||
LOG_ERR("Failed to set \'model-pub\'");
|
/* Recover from implementation where uuid was not stored for virtual address. It
|
||||||
return err;
|
* is safe to pick first matched label because previously the stack wasn't able
|
||||||
|
* to store virtual addresses with collisions.
|
||||||
|
*/
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) {
|
||||||
|
mod->pub->uuid = bt_mesh_va_uuid_get(pub.base.addr, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto pub_base_set;
|
||||||
|
} else {
|
||||||
|
err = bt_mesh_settings_set(read_cb, cb_arg, &pub, sizeof(pub));
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to set \'model-pub\'");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod->pub->addr = pub.addr;
|
if (BT_MESH_ADDR_IS_VIRTUAL(pub.base.addr)) {
|
||||||
mod->pub->key = pub.key;
|
mod->pub->uuid = bt_mesh_va_get_uuid_by_idx(pub.uuidx);
|
||||||
mod->pub->cred = pub.cred;
|
}
|
||||||
mod->pub->ttl = pub.ttl;
|
|
||||||
mod->pub->period = pub.period;
|
pub_base_set:
|
||||||
mod->pub->retransmit = pub.retransmit;
|
mod->pub->addr = pub.base.addr;
|
||||||
mod->pub->period_div = pub.period_div;
|
mod->pub->key = pub.base.key;
|
||||||
|
mod->pub->cred = pub.base.cred;
|
||||||
|
mod->pub->ttl = pub.base.ttl;
|
||||||
|
mod->pub->period = pub.base.period;
|
||||||
|
mod->pub->retransmit = pub.base.retransmit;
|
||||||
|
mod->pub->period_div = pub.base.period_div;
|
||||||
mod->pub->count = 0U;
|
mod->pub->count = 0U;
|
||||||
|
|
||||||
LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.addr, pub.key);
|
LOG_DBG("Restored model publication, dst 0x%04x app_idx 0x%03x", pub.base.addr,
|
||||||
|
pub.base.key);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1675,26 +1821,35 @@ static int mod_set(bool vnd, const char *name, size_t len_rd,
|
||||||
}
|
}
|
||||||
|
|
||||||
len = settings_name_next(name, &next);
|
len = settings_name_next(name, &next);
|
||||||
|
|
||||||
if (!next) {
|
if (!next) {
|
||||||
LOG_ERR("Insufficient number of arguments");
|
LOG_ERR("Insufficient number of arguments");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strncmp(next, "bind", len)) {
|
/* `len` contains length of model id string representation. Call settings_name_next() again
|
||||||
return mod_set_bind(mod, len_rd, read_cb, cb_arg);
|
* to get length of `next`.
|
||||||
}
|
*/
|
||||||
|
switch (settings_name_next(next, NULL)) {
|
||||||
|
case 4:
|
||||||
|
if (!strncmp(next, "bind", 4)) {
|
||||||
|
return mod_set_bind(mod, len_rd, read_cb, cb_arg);
|
||||||
|
} else if (!strncmp(next, "subv", 4)) {
|
||||||
|
return mod_set_sub_va(mod, len_rd, read_cb, cb_arg);
|
||||||
|
} else if (!strncmp(next, "data", 4)) {
|
||||||
|
return mod_data_set(mod, next, len_rd, read_cb, cb_arg);
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncmp(next, "sub", len)) {
|
break;
|
||||||
return mod_set_sub(mod, len_rd, read_cb, cb_arg);
|
case 3:
|
||||||
}
|
if (!strncmp(next, "sub", 3)) {
|
||||||
|
return mod_set_sub(mod, len_rd, read_cb, cb_arg);
|
||||||
|
} else if (!strncmp(next, "pub", 3)) {
|
||||||
|
return mod_set_pub(mod, len_rd, read_cb, cb_arg);
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncmp(next, "pub", len)) {
|
break;
|
||||||
return mod_set_pub(mod, len_rd, read_cb, cb_arg);
|
default:
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (!strncmp(next, "data", len)) {
|
|
||||||
return mod_data_set(mod, next, len_rd, read_cb, cb_arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_WRN("Unknown module key %s", next);
|
LOG_WRN("Unknown module key %s", next);
|
||||||
|
@ -1786,8 +1941,7 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
|
||||||
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
|
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
err = settings_save_one(path, groups,
|
err = settings_save_one(path, groups, count * sizeof(groups[0]));
|
||||||
count * sizeof(groups[0]));
|
|
||||||
} else {
|
} else {
|
||||||
err = settings_delete(path);
|
err = settings_delete(path);
|
||||||
}
|
}
|
||||||
|
@ -1799,6 +1953,38 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void store_pending_mod_sub_va(struct bt_mesh_model *mod, bool vnd)
|
||||||
|
{
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
uint16_t uuidxs[CONFIG_BT_MESH_LABEL_COUNT];
|
||||||
|
char path[20];
|
||||||
|
int i, count, err;
|
||||||
|
|
||||||
|
for (i = 0, count = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) {
|
||||||
|
if (mod->uuids[i] != NULL) {
|
||||||
|
err = bt_mesh_va_get_idx_by_uuid(mod->uuids[i], &uuidxs[count]);
|
||||||
|
if (!err) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encode_mod_path(mod, vnd, "subv", path, sizeof(path));
|
||||||
|
|
||||||
|
if (count) {
|
||||||
|
err = settings_save_one(path, uuidxs, count * sizeof(uuidxs[0]));
|
||||||
|
} else {
|
||||||
|
err = settings_delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to store %s value", path);
|
||||||
|
} else {
|
||||||
|
LOG_DBG("Stored %s value", path);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
||||||
|
}
|
||||||
|
|
||||||
static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
|
static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
|
||||||
{
|
{
|
||||||
struct mod_pub_val pub = {0};
|
struct mod_pub_val pub = {0};
|
||||||
|
@ -1810,15 +1996,21 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
|
||||||
if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
|
if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||||
err = settings_delete(path);
|
err = settings_delete(path);
|
||||||
} else {
|
} else {
|
||||||
pub.addr = mod->pub->addr;
|
pub.base.addr = mod->pub->addr;
|
||||||
pub.key = mod->pub->key;
|
pub.base.key = mod->pub->key;
|
||||||
pub.ttl = mod->pub->ttl;
|
pub.base.ttl = mod->pub->ttl;
|
||||||
pub.retransmit = mod->pub->retransmit;
|
pub.base.retransmit = mod->pub->retransmit;
|
||||||
pub.period = mod->pub->period;
|
pub.base.period = mod->pub->period;
|
||||||
pub.period_div = mod->pub->period_div;
|
pub.base.period_div = mod->pub->period_div;
|
||||||
pub.cred = mod->pub->cred;
|
pub.base.cred = mod->pub->cred;
|
||||||
|
|
||||||
err = settings_save_one(path, &pub, sizeof(pub));
|
if (BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr)) {
|
||||||
|
(void)bt_mesh_va_get_idx_by_uuid(mod->pub->uuid, &pub.uuidx);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = settings_save_one(path, &pub,
|
||||||
|
BT_MESH_ADDR_IS_VIRTUAL(mod->pub->addr) ? sizeof(pub) :
|
||||||
|
sizeof(pub.base));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -1844,6 +2036,7 @@ static void store_pending_mod(struct bt_mesh_model *mod,
|
||||||
if (mod->flags & BT_MESH_MOD_SUB_PENDING) {
|
if (mod->flags & BT_MESH_MOD_SUB_PENDING) {
|
||||||
mod->flags &= ~BT_MESH_MOD_SUB_PENDING;
|
mod->flags &= ~BT_MESH_MOD_SUB_PENDING;
|
||||||
store_pending_mod_sub(mod, vnd);
|
store_pending_mod_sub(mod, vnd);
|
||||||
|
store_pending_mod_sub_va(mod, vnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mod->flags & BT_MESH_MOD_PUB_PENDING) {
|
if (mod->flags & BT_MESH_MOD_PUB_PENDING) {
|
||||||
|
|
|
@ -41,6 +41,7 @@ void bt_mesh_model_extensions_walk(struct bt_mesh_model *root,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr);
|
uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr);
|
||||||
|
const uint8_t **bt_mesh_model_find_uuid(struct bt_mesh_model **mod, const uint8_t *uuid);
|
||||||
|
|
||||||
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
|
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
|
||||||
struct bt_mesh_elem *elem,
|
struct bt_mesh_elem *elem,
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "friend.h"
|
#include "friend.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -130,7 +131,7 @@ static struct bt_mesh_model *get_model(struct bt_mesh_elem *elem,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr, const uint8_t *uuid,
|
||||||
uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period,
|
uint16_t app_idx, uint8_t cred_flag, uint8_t ttl, uint8_t period,
|
||||||
uint8_t retransmit, bool store)
|
uint8_t retransmit, bool store)
|
||||||
{
|
{
|
||||||
|
@ -158,6 +159,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
||||||
model->pub->period = 0U;
|
model->pub->period = 0U;
|
||||||
model->pub->retransmit = 0U;
|
model->pub->retransmit = 0U;
|
||||||
model->pub->count = 0U;
|
model->pub->count = 0U;
|
||||||
|
model->pub->uuid = NULL;
|
||||||
|
|
||||||
if (model->pub->update) {
|
if (model->pub->update) {
|
||||||
/* If this fails, the timer will check pub->addr and
|
/* If this fails, the timer will check pub->addr and
|
||||||
|
@ -179,11 +181,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
||||||
|
|
||||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(model->pub->addr)) {
|
if (BT_MESH_ADDR_IS_VIRTUAL(model->pub->addr)) {
|
||||||
uint8_t *uuid = bt_mesh_va_label_get(model->pub->addr);
|
(void)bt_mesh_va_del(model->pub->uuid);
|
||||||
|
|
||||||
if (uuid) {
|
|
||||||
bt_mesh_va_del(uuid, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -193,6 +191,7 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
|
||||||
model->pub->ttl = ttl;
|
model->pub->ttl = ttl;
|
||||||
model->pub->period = period;
|
model->pub->period = period;
|
||||||
model->pub->retransmit = retransmit;
|
model->pub->retransmit = retransmit;
|
||||||
|
model->pub->uuid = uuid;
|
||||||
|
|
||||||
if (model->pub->update) {
|
if (model->pub->update) {
|
||||||
int32_t period_ms;
|
int32_t period_ms;
|
||||||
|
@ -273,7 +272,7 @@ static uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool st
|
||||||
}
|
}
|
||||||
|
|
||||||
if (model->pub && model->pub->key == key_idx) {
|
if (model->pub && model->pub->key == key_idx) {
|
||||||
_mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED,
|
_mod_pub_set(model, BT_MESH_ADDR_UNASSIGNED, NULL,
|
||||||
0, 0, 0, 0, 0, store);
|
0, 0, 0, 0, 0, store);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -803,7 +802,7 @@ static int mod_pub_set(struct bt_mesh_model *model,
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl,
|
status = _mod_pub_set(mod, pub_addr, NULL, pub_app_idx, cred_flag, pub_ttl,
|
||||||
pub_period, retransmit, true);
|
pub_period, retransmit, true);
|
||||||
|
|
||||||
send_status:
|
send_status:
|
||||||
|
@ -813,32 +812,31 @@ send_status:
|
||||||
|
|
||||||
static size_t mod_sub_list_clear(struct bt_mesh_model *mod)
|
static size_t mod_sub_list_clear(struct bt_mesh_model *mod)
|
||||||
{
|
{
|
||||||
uint8_t *label_uuid;
|
|
||||||
size_t clear_count;
|
size_t clear_count;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Unref stored labels related to this model */
|
|
||||||
for (i = 0, clear_count = 0; i < mod->groups_cnt; i++) {
|
for (i = 0, clear_count = 0; i < mod->groups_cnt; i++) {
|
||||||
if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) {
|
/* mod->groups contains both, group and virtual addrs. Virtual addrs deletion will
|
||||||
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
* be handled separately.
|
||||||
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
|
*/
|
||||||
clear_count++;
|
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
|
||||||
}
|
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
|
||||||
|
clear_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
/* Unref stored labels related to this model */
|
||||||
|
for (i = 0; i < CONFIG_BT_MESH_LABEL_COUNT; i++) {
|
||||||
|
if (mod->uuids[i] == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_uuid = bt_mesh_va_label_get(mod->groups[i]);
|
(void)bt_mesh_va_del(mod->uuids[i]);
|
||||||
|
mod->uuids[i] = NULL;
|
||||||
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
|
/* No need to increment `clear_count` as `groups` contains virtual addresses. */
|
||||||
clear_count++;
|
|
||||||
|
|
||||||
if (label_uuid) {
|
|
||||||
bt_mesh_va_del(label_uuid, NULL);
|
|
||||||
} else {
|
|
||||||
LOG_ERR("Label UUID not found");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return clear_count;
|
return clear_count;
|
||||||
}
|
}
|
||||||
|
@ -847,11 +845,13 @@ static int mod_pub_va_set(struct bt_mesh_model *model,
|
||||||
struct bt_mesh_msg_ctx *ctx,
|
struct bt_mesh_msg_ctx *ctx,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
|
const struct bt_mesh_va *va;
|
||||||
uint8_t retransmit, status, pub_ttl, pub_period, cred_flag;
|
uint8_t retransmit, status, pub_ttl, pub_period, cred_flag;
|
||||||
uint16_t elem_addr, pub_addr, pub_app_idx;
|
uint16_t elem_addr, pub_app_idx;
|
||||||
|
uint16_t pub_addr = 0U;
|
||||||
struct bt_mesh_model *mod;
|
struct bt_mesh_model *mod;
|
||||||
struct bt_mesh_elem *elem;
|
struct bt_mesh_elem *elem;
|
||||||
uint8_t *label_uuid;
|
const uint8_t *uuid;
|
||||||
uint8_t *mod_id;
|
uint8_t *mod_id;
|
||||||
bool vnd;
|
bool vnd;
|
||||||
|
|
||||||
|
@ -866,7 +866,7 @@ static int mod_pub_va_set(struct bt_mesh_model *model,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_uuid = net_buf_simple_pull_mem(buf, 16);
|
uuid = net_buf_simple_pull_mem(buf, 16);
|
||||||
pub_app_idx = net_buf_simple_pull_le16(buf);
|
pub_app_idx = net_buf_simple_pull_le16(buf);
|
||||||
cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1));
|
cred_flag = ((pub_app_idx >> 12) & BIT_MASK(1));
|
||||||
pub_app_idx &= BIT_MASK(12);
|
pub_app_idx &= BIT_MASK(12);
|
||||||
|
@ -890,27 +890,27 @@ static int mod_pub_va_set(struct bt_mesh_model *model,
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
mod = NULL;
|
mod = NULL;
|
||||||
vnd = (buf->len == 4U);
|
vnd = (buf->len == 4U);
|
||||||
pub_addr = 0U;
|
|
||||||
status = STATUS_INVALID_ADDRESS;
|
status = STATUS_INVALID_ADDRESS;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = get_model(elem, buf, &vnd);
|
mod = get_model(elem, buf, &vnd);
|
||||||
if (!mod) {
|
if (!mod) {
|
||||||
pub_addr = 0U;
|
|
||||||
status = STATUS_INVALID_MODEL;
|
status = STATUS_INVALID_MODEL;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = bt_mesh_va_add(label_uuid, &pub_addr);
|
status = bt_mesh_va_add(uuid, &va);
|
||||||
if (status != STATUS_SUCCESS) {
|
if (status != STATUS_SUCCESS) {
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = _mod_pub_set(mod, pub_addr, pub_app_idx, cred_flag, pub_ttl,
|
pub_addr = va->addr;
|
||||||
|
|
||||||
|
status = _mod_pub_set(mod, pub_addr, va->uuid, pub_app_idx, cred_flag, pub_ttl,
|
||||||
pub_period, retransmit, true);
|
pub_period, retransmit, true);
|
||||||
if (status != STATUS_SUCCESS) {
|
if (status != STATUS_SUCCESS) {
|
||||||
bt_mesh_va_del(label_uuid, NULL);
|
(void)bt_mesh_va_del(va->uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
send_status:
|
send_status:
|
||||||
|
@ -1383,12 +1383,14 @@ static int mod_sub_va_add(struct bt_mesh_model *model,
|
||||||
struct bt_mesh_msg_ctx *ctx,
|
struct bt_mesh_msg_ctx *ctx,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
uint16_t elem_addr, sub_addr;
|
const struct bt_mesh_va *va;
|
||||||
|
uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
||||||
struct bt_mesh_model *mod;
|
struct bt_mesh_model *mod;
|
||||||
struct bt_mesh_elem *elem;
|
struct bt_mesh_elem *elem;
|
||||||
uint8_t *label_uuid;
|
const uint8_t *uuid;
|
||||||
uint8_t *mod_id;
|
uint8_t *mod_id;
|
||||||
uint16_t *entry;
|
uint16_t *group_entry;
|
||||||
|
const uint8_t **label_entry;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
bool vnd;
|
bool vnd;
|
||||||
|
|
||||||
|
@ -1403,7 +1405,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_uuid = net_buf_simple_pull_mem(buf, 16);
|
uuid = net_buf_simple_pull_mem(buf, 16);
|
||||||
|
|
||||||
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
||||||
|
|
||||||
|
@ -1412,42 +1414,59 @@ static int mod_sub_va_add(struct bt_mesh_model *model,
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
mod = NULL;
|
mod = NULL;
|
||||||
vnd = (buf->len == 4U);
|
vnd = (buf->len == 4U);
|
||||||
sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
status = STATUS_INVALID_ADDRESS;
|
status = STATUS_INVALID_ADDRESS;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = get_model(elem, buf, &vnd);
|
mod = get_model(elem, buf, &vnd);
|
||||||
if (!mod) {
|
if (!mod) {
|
||||||
sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
status = STATUS_INVALID_MODEL;
|
status = STATUS_INVALID_MODEL;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = bt_mesh_va_add(label_uuid, &sub_addr);
|
status = bt_mesh_va_add(uuid, &va);
|
||||||
if (status != STATUS_SUCCESS) {
|
if (status != STATUS_SUCCESS) {
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bt_mesh_model_find_group(&mod, sub_addr)) {
|
if (bt_mesh_model_find_uuid(&mod, va->uuid)) {
|
||||||
/* Tried to add existing subscription */
|
/* Tried to add existing subscription */
|
||||||
status = STATUS_SUCCESS;
|
status = STATUS_SUCCESS;
|
||||||
bt_mesh_va_del(label_uuid, NULL);
|
(void)bt_mesh_va_del(va->uuid);
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label_entry = bt_mesh_model_find_uuid(&mod, NULL);
|
||||||
entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED);
|
if (!label_entry) {
|
||||||
if (!entry) {
|
|
||||||
status = STATUS_INSUFF_RESOURCES;
|
status = STATUS_INSUFF_RESOURCES;
|
||||||
bt_mesh_va_del(label_uuid, NULL);
|
(void)bt_mesh_va_del(va->uuid);
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
*entry = sub_addr;
|
group_entry = NULL;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
for (int i = 0; i < mod->groups_cnt; i++) {
|
||||||
bt_mesh_lpn_group_add(sub_addr);
|
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
|
||||||
|
group_entry = &mod->groups[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* bt_mesh_model_find_uuid() should find a model where both, uuids and groups lists have
|
||||||
|
* empty entry.
|
||||||
|
*/
|
||||||
|
if (!group_entry) {
|
||||||
|
status = STATUS_INSUFF_RESOURCES;
|
||||||
|
(void)bt_mesh_va_del(va->uuid);
|
||||||
|
goto send_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
*group_entry = va->addr;
|
||||||
|
*label_entry = va->uuid;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 &&
|
||||||
|
!bt_mesh_va_collision_check(va->addr)) {
|
||||||
|
bt_mesh_lpn_group_add(va->addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
|
@ -1455,6 +1474,7 @@ static int mod_sub_va_add(struct bt_mesh_model *model,
|
||||||
}
|
}
|
||||||
|
|
||||||
status = STATUS_SUCCESS;
|
status = STATUS_SUCCESS;
|
||||||
|
sub_addr = va->addr;
|
||||||
|
|
||||||
send_status:
|
send_status:
|
||||||
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
||||||
|
@ -1465,12 +1485,13 @@ static int mod_sub_va_del(struct bt_mesh_model *model,
|
||||||
struct bt_mesh_msg_ctx *ctx,
|
struct bt_mesh_msg_ctx *ctx,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
uint16_t elem_addr, sub_addr;
|
const struct bt_mesh_va *va;
|
||||||
|
uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
||||||
struct bt_mesh_model *mod;
|
struct bt_mesh_model *mod;
|
||||||
struct bt_mesh_elem *elem;
|
struct bt_mesh_elem *elem;
|
||||||
uint8_t *label_uuid;
|
const uint8_t *uuid;
|
||||||
uint8_t *mod_id;
|
uint8_t *mod_id;
|
||||||
uint16_t *match;
|
const uint8_t **label_match;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
bool vnd;
|
bool vnd;
|
||||||
|
|
||||||
|
@ -1485,7 +1506,7 @@ static int mod_sub_va_del(struct bt_mesh_model *model,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_uuid = net_buf_simple_pull_mem(buf, 16);
|
uuid = net_buf_simple_pull_mem(buf, 16);
|
||||||
|
|
||||||
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
||||||
|
|
||||||
|
@ -1495,40 +1516,50 @@ static int mod_sub_va_del(struct bt_mesh_model *model,
|
||||||
if (!elem) {
|
if (!elem) {
|
||||||
mod = NULL;
|
mod = NULL;
|
||||||
vnd = (buf->len == 4U);
|
vnd = (buf->len == 4U);
|
||||||
sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
status = STATUS_INVALID_ADDRESS;
|
status = STATUS_INVALID_ADDRESS;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
mod = get_model(elem, buf, &vnd);
|
mod = get_model(elem, buf, &vnd);
|
||||||
if (!mod) {
|
if (!mod) {
|
||||||
sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
status = STATUS_INVALID_MODEL;
|
status = STATUS_INVALID_MODEL;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = bt_mesh_va_del(label_uuid, &sub_addr);
|
va = bt_mesh_va_find(uuid);
|
||||||
if (sub_addr == BT_MESH_ADDR_UNASSIGNED) {
|
if (!va) {
|
||||||
|
status = STATUS_CANNOT_REMOVE;
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 &&
|
||||||
bt_mesh_lpn_group_del(&sub_addr, 1);
|
!bt_mesh_va_collision_check(va->addr)) {
|
||||||
|
bt_mesh_lpn_group_del(&va->addr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
match = bt_mesh_model_find_group(&mod, sub_addr);
|
label_match = bt_mesh_model_find_uuid(&mod, va->uuid);
|
||||||
if (match) {
|
if (!label_match) {
|
||||||
*match = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
bt_mesh_model_sub_store(mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
status = STATUS_SUCCESS;
|
|
||||||
} else {
|
|
||||||
status = STATUS_CANNOT_REMOVE;
|
status = STATUS_CANNOT_REMOVE;
|
||||||
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < mod->groups_cnt; i++) {
|
||||||
|
if (mod->groups[i] == va->addr) {
|
||||||
|
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*label_match = NULL;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
|
bt_mesh_model_sub_store(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_addr = va->addr;
|
||||||
|
(void)bt_mesh_va_del(va->uuid);
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
|
||||||
send_status:
|
send_status:
|
||||||
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
||||||
mod_id, vnd);
|
mod_id, vnd);
|
||||||
|
@ -1538,10 +1569,11 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model,
|
||||||
struct bt_mesh_msg_ctx *ctx,
|
struct bt_mesh_msg_ctx *ctx,
|
||||||
struct net_buf_simple *buf)
|
struct net_buf_simple *buf)
|
||||||
{
|
{
|
||||||
|
const struct bt_mesh_va *va;
|
||||||
uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
uint16_t elem_addr, sub_addr = BT_MESH_ADDR_UNASSIGNED;
|
||||||
struct bt_mesh_model *mod;
|
struct bt_mesh_model *mod;
|
||||||
struct bt_mesh_elem *elem;
|
struct bt_mesh_elem *elem;
|
||||||
uint8_t *label_uuid;
|
const uint8_t *uuid;
|
||||||
uint8_t *mod_id;
|
uint8_t *mod_id;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
bool vnd;
|
bool vnd;
|
||||||
|
@ -1557,7 +1589,7 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
label_uuid = net_buf_simple_pull_mem(buf, 16);
|
uuid = net_buf_simple_pull_mem(buf, 16);
|
||||||
|
|
||||||
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
LOG_DBG("elem_addr 0x%04x", elem_addr);
|
||||||
|
|
||||||
|
@ -1577,26 +1609,33 @@ static int mod_sub_va_overwrite(struct bt_mesh_model *model,
|
||||||
goto send_status;
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CONFIG_BT_MESH_LABEL_COUNT == 0 || mod->groups_cnt == 0) {
|
||||||
if (mod->groups_cnt > 0) {
|
(void)va;
|
||||||
|
|
||||||
status = bt_mesh_va_add(label_uuid, &sub_addr);
|
|
||||||
if (status == STATUS_SUCCESS) {
|
|
||||||
bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL);
|
|
||||||
mod->groups[0] = sub_addr;
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
bt_mesh_model_sub_store(mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
|
||||||
bt_mesh_lpn_group_add(sub_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
status = STATUS_INSUFF_RESOURCES;
|
status = STATUS_INSUFF_RESOURCES;
|
||||||
|
goto send_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
status = bt_mesh_va_add(uuid, &va);
|
||||||
|
if (status != STATUS_SUCCESS) {
|
||||||
|
goto send_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
bt_mesh_model_extensions_walk(mod, mod_sub_clear_visitor, NULL);
|
||||||
|
mod->groups[0] = va->addr;
|
||||||
|
mod->uuids[0] = va->uuid;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
|
bt_mesh_model_sub_store(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) && va->ref == 1 &&
|
||||||
|
!bt_mesh_va_collision_check(va->addr)) {
|
||||||
|
bt_mesh_lpn_group_add(va->addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub_addr = va->addr;
|
||||||
|
#endif
|
||||||
send_status:
|
send_status:
|
||||||
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
return send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
|
||||||
mod_id, vnd);
|
mod_id, vnd);
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "access.h"
|
#include "access.h"
|
||||||
#include "foundation.h"
|
#include "foundation.h"
|
||||||
#include "friend.h"
|
#include "friend.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_FRIEND_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_FRIEND_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -60,9 +61,15 @@ struct friend_pdu_info {
|
||||||
uint32_t iv_index;
|
uint32_t iv_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BUILD_ASSERT(CONFIG_BT_MESH_LABEL_COUNT <= 0xFFFU, "Friend doesn't support more than 4096 labels.");
|
||||||
|
|
||||||
struct friend_adv {
|
struct friend_adv {
|
||||||
uint16_t app_idx;
|
uint16_t app_idx;
|
||||||
bool seg;
|
struct {
|
||||||
|
/* CONFIG_BT_MESH_LABEL_COUNT max value is 4096. */
|
||||||
|
uint16_t uuidx:15,
|
||||||
|
seg:1;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BT_MESH_ADV_DATA_SIZE,
|
NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT, BT_MESH_ADV_DATA_SIZE,
|
||||||
|
@ -309,6 +316,7 @@ static void friend_sub_add(struct bt_mesh_friend *frnd, uint16_t addr)
|
||||||
|
|
||||||
if (empty_idx != INT_MAX) {
|
if (empty_idx != INT_MAX) {
|
||||||
frnd->sub_list[empty_idx] = addr;
|
frnd->sub_list[empty_idx] = addr;
|
||||||
|
LOG_DBG("%04x added %04x to subscription list", frnd->lpn, addr);
|
||||||
} else {
|
} else {
|
||||||
LOG_WRN("No space in friend subscription list");
|
LOG_WRN("No space in friend subscription list");
|
||||||
}
|
}
|
||||||
|
@ -320,6 +328,7 @@ static void friend_sub_rem(struct bt_mesh_friend *frnd, uint16_t addr)
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
|
for (i = 0; i < ARRAY_SIZE(frnd->sub_list); i++) {
|
||||||
if (frnd->sub_list[i] == addr) {
|
if (frnd->sub_list[i] == addr) {
|
||||||
|
LOG_DBG("%04x removed %04x from subscription list", frnd->lpn, addr);
|
||||||
frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED;
|
frnd->sub_list[i] = BT_MESH_ADDR_UNASSIGNED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -370,6 +379,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
|
||||||
struct unseg_app_sdu_meta *meta)
|
struct unseg_app_sdu_meta *meta)
|
||||||
{
|
{
|
||||||
uint16_t app_idx = FRIEND_ADV(buf)->app_idx;
|
uint16_t app_idx = FRIEND_ADV(buf)->app_idx;
|
||||||
|
uint16_t uuidx = FRIEND_ADV(buf)->uuidx;
|
||||||
struct bt_mesh_net_rx net = {
|
struct bt_mesh_net_rx net = {
|
||||||
.ctx = {
|
.ctx = {
|
||||||
.app_idx = app_idx,
|
.app_idx = app_idx,
|
||||||
|
@ -393,10 +403,7 @@ static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
|
||||||
meta->crypto.aszmic = 0;
|
meta->crypto.aszmic = 0;
|
||||||
|
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) {
|
if (BT_MESH_ADDR_IS_VIRTUAL(meta->crypto.dst)) {
|
||||||
meta->crypto.ad = bt_mesh_va_label_get(meta->crypto.dst);
|
meta->crypto.ad = bt_mesh_va_get_uuid_by_idx(uuidx);
|
||||||
if (!meta->crypto.ad) {
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
meta->crypto.ad = NULL;
|
meta->crypto.ad = NULL;
|
||||||
}
|
}
|
||||||
|
@ -1504,11 +1511,26 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
|
||||||
* when encrypting in transport and network.
|
* when encrypting in transport and network.
|
||||||
*/
|
*/
|
||||||
FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx;
|
FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx;
|
||||||
|
|
||||||
|
/* When reencrypting a virtual address message, we need to know uuid as well. */
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) {
|
||||||
|
uint16_t uuidx;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = bt_mesh_va_get_idx_by_uuid(tx->ctx->uuid, &uuidx);
|
||||||
|
if (err) {
|
||||||
|
net_buf_unref(buf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FRIEND_ADV(buf)->uuidx = uuidx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
|
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
|
||||||
|
|
||||||
LOG_DBG("Queued message for LPN 0x%04x", frnd->lpn);
|
LOG_DBG("Queued message for LPN 0x%04x, dst: %04x, uuid: %p", frnd->lpn, tx->ctx->addr,
|
||||||
|
tx->ctx->uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx,
|
static bool friend_lpn_matches(struct bt_mesh_friend *frnd, uint16_t net_idx,
|
||||||
|
|
|
@ -966,7 +966,7 @@ void bt_mesh_lpn_group_add(uint16_t group)
|
||||||
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
|
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count)
|
void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ static inline bool bt_mesh_lpn_waiting_update(void)
|
||||||
void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx);
|
void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx);
|
||||||
|
|
||||||
void bt_mesh_lpn_group_add(uint16_t group);
|
void bt_mesh_lpn_group_add(uint16_t group);
|
||||||
void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count);
|
void bt_mesh_lpn_group_del(const uint16_t *groups, size_t group_count);
|
||||||
|
|
||||||
void bt_mesh_lpn_disable(bool force);
|
void bt_mesh_lpn_disable(bool force);
|
||||||
void bt_mesh_lpn_friendship_end(void);
|
void bt_mesh_lpn_friendship_end(void);
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "cfg.h"
|
#include "cfg.h"
|
||||||
#include "solicitation.h"
|
#include "solicitation.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "heartbeat.h"
|
#include "heartbeat.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -59,20 +60,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport);
|
||||||
/* How long to wait for available buffers before giving up */
|
/* How long to wait for available buffers before giving up */
|
||||||
#define BUF_TIMEOUT K_NO_WAIT
|
#define BUF_TIMEOUT K_NO_WAIT
|
||||||
|
|
||||||
struct virtual_addr {
|
|
||||||
uint16_t ref:15,
|
|
||||||
changed:1;
|
|
||||||
uint16_t addr;
|
|
||||||
uint8_t uuid[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Virtual Address information for persistent storage. */
|
|
||||||
struct va_val {
|
|
||||||
uint16_t ref;
|
|
||||||
uint16_t addr;
|
|
||||||
uint8_t uuid[16];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
#define ACK_DELAY(seg_n) \
|
#define ACK_DELAY(seg_n) \
|
||||||
(MIN(2 * seg_n + 1, BT_MESH_SAR_RX_ACK_DELAY_INC_X2) * \
|
(MIN(2 * seg_n + 1, BT_MESH_SAR_RX_ACK_DELAY_INC_X2) * \
|
||||||
BT_MESH_SAR_RX_SEG_INT_MS / 2)
|
BT_MESH_SAR_RX_SEG_INT_MS / 2)
|
||||||
|
@ -131,8 +118,6 @@ static struct seg_rx {
|
||||||
|
|
||||||
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
|
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
|
||||||
|
|
||||||
static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
|
|
||||||
|
|
||||||
static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
||||||
const struct bt_mesh_send_cb *cb, void *cb_data,
|
const struct bt_mesh_send_cb *cb, void *cb_data,
|
||||||
const uint8_t *ctl_op)
|
const uint8_t *ctl_op)
|
||||||
|
@ -652,7 +637,7 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k
|
||||||
};
|
};
|
||||||
|
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) {
|
if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) {
|
||||||
crypto.ad = bt_mesh_va_label_get(tx->ctx->addr);
|
crypto.ad = tx->ctx->uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bt_mesh_app_encrypt(key, &crypto, msg);
|
return bt_mesh_app_encrypt(key, &crypto, msg);
|
||||||
|
@ -759,15 +744,35 @@ struct decrypt_ctx {
|
||||||
static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key,
|
static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key,
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
{
|
{
|
||||||
const struct decrypt_ctx *ctx = cb_data;
|
struct decrypt_ctx *ctx = cb_data;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (ctx->seg) {
|
ctx->crypto.ad = NULL;
|
||||||
seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic);
|
|
||||||
|
do {
|
||||||
|
if (ctx->seg) {
|
||||||
|
seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
||||||
|
ctx->crypto.ad = bt_mesh_va_uuid_get(rx->ctx.recv_dst, ctx->crypto.ad,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!ctx->crypto.ad) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_reset(ctx->sdu);
|
||||||
|
|
||||||
|
err = bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu);
|
||||||
|
} while (err && ctx->crypto.ad != NULL);
|
||||||
|
|
||||||
|
if (!err && BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
||||||
|
rx->ctx.uuid = ctx->crypto.ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_buf_simple_reset(ctx->sdu);
|
return err;
|
||||||
|
|
||||||
return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
|
@ -794,10 +799,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
|
||||||
ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
||||||
rx, sdu_try_decrypt, &ctx);
|
rx, sdu_try_decrypt, &ctx);
|
||||||
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
||||||
|
@ -805,6 +806,8 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rx->ctx.uuid = ctx.crypto.ad;
|
||||||
|
|
||||||
LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx);
|
LOG_DBG("Decrypted (AppIdx: 0x%03x)", rx->ctx.app_idx);
|
||||||
|
|
||||||
(void)bt_mesh_model_recv(&rx->ctx, sdu);
|
(void)bt_mesh_model_recv(&rx->ctx, sdu);
|
||||||
|
@ -1683,11 +1686,6 @@ void bt_mesh_rx_reset(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void store_va_label(void)
|
|
||||||
{
|
|
||||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bt_mesh_trans_reset(void)
|
void bt_mesh_trans_reset(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1700,18 +1698,8 @@ void bt_mesh_trans_reset(void)
|
||||||
seg_tx_reset(&seg_tx[i]);
|
seg_tx_reset(&seg_tx[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref) {
|
|
||||||
virtual_addrs[i].ref = 0U;
|
|
||||||
virtual_addrs[i].changed = 1U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_mesh_rpl_clear();
|
bt_mesh_rpl_clear();
|
||||||
|
bt_mesh_va_clear();
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
store_va_label();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_mesh_trans_init(void)
|
void bt_mesh_trans_init(void)
|
||||||
|
@ -1727,199 +1715,3 @@ void bt_mesh_trans_init(void)
|
||||||
k_work_init_delayable(&seg_rx[i].discard, seg_discard);
|
k_work_init_delayable(&seg_rx[i].discard, seg_discard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void va_store(struct virtual_addr *store)
|
|
||||||
{
|
|
||||||
store->changed = 1U;
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
store_va_label();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr)
|
|
||||||
{
|
|
||||||
struct virtual_addr *va = NULL;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (!virtual_addrs[i].ref) {
|
|
||||||
if (!va) {
|
|
||||||
va = &virtual_addrs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(uuid, virtual_addrs[i].uuid,
|
|
||||||
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
|
||||||
*addr = virtual_addrs[i].addr;
|
|
||||||
virtual_addrs[i].ref++;
|
|
||||||
va_store(&virtual_addrs[i]);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!va) {
|
|
||||||
return STATUS_INSUFF_RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid));
|
|
||||||
err = bt_mesh_virtual_addr(uuid, &va->addr);
|
|
||||||
if (err) {
|
|
||||||
va->addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
return STATUS_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
va->ref = 1;
|
|
||||||
va_store(va);
|
|
||||||
|
|
||||||
*addr = va->addr;
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr)
|
|
||||||
{
|
|
||||||
struct virtual_addr *va = NULL;
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref &&
|
|
||||||
!memcmp(uuid, virtual_addrs[i].uuid,
|
|
||||||
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
|
||||||
va = &virtual_addrs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!va) {
|
|
||||||
return STATUS_CANNOT_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
va->ref--;
|
|
||||||
if (addr) {
|
|
||||||
*addr = va->addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_store(va);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *bt_mesh_va_label_get(uint16_t addr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DBG("addr 0x%04x", addr);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) {
|
|
||||||
LOG_DBG("Found Label UUID for 0x%04x: %s", addr,
|
|
||||||
bt_hex(virtual_addrs[i].uuid, 16));
|
|
||||||
return virtual_addrs[i].uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WRN("No matching Label UUID for 0x%04x", addr);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
|
||||||
static struct virtual_addr *bt_mesh_va_get(uint16_t index)
|
|
||||||
{
|
|
||||||
if (index >= ARRAY_SIZE(virtual_addrs)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &virtual_addrs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int va_set(const char *name, size_t len_rd,
|
|
||||||
settings_read_cb read_cb, void *cb_arg)
|
|
||||||
{
|
|
||||||
struct va_val va;
|
|
||||||
struct virtual_addr *lab;
|
|
||||||
uint16_t index;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
LOG_ERR("Insufficient number of arguments");
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = strtol(name, NULL, 16);
|
|
||||||
|
|
||||||
if (len_rd == 0) {
|
|
||||||
LOG_WRN("Mesh Virtual Address length = 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va));
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("Failed to set \'virtual address\'");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va.ref == 0) {
|
|
||||||
LOG_WRN("Ignore Mesh Virtual Address ref = 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lab = bt_mesh_va_get(index);
|
|
||||||
if (lab == NULL) {
|
|
||||||
LOG_WRN("Out of labels buffers");
|
|
||||||
return -ENOBUFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(lab->uuid, va.uuid, 16);
|
|
||||||
lab->addr = va.addr;
|
|
||||||
lab->ref = va.ref;
|
|
||||||
|
|
||||||
LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_MESH_SETTINGS_DEFINE(va, "Va", va_set);
|
|
||||||
|
|
||||||
#define IS_VA_DEL(_label) ((_label)->ref == 0)
|
|
||||||
void bt_mesh_va_pending_store(void)
|
|
||||||
{
|
|
||||||
struct virtual_addr *lab;
|
|
||||||
struct va_val va;
|
|
||||||
char path[18];
|
|
||||||
uint16_t i;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) {
|
|
||||||
if (!lab->changed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lab->changed = 0U;
|
|
||||||
|
|
||||||
snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
|
|
||||||
|
|
||||||
if (IS_VA_DEL(lab)) {
|
|
||||||
err = settings_delete(path);
|
|
||||||
} else {
|
|
||||||
va.ref = lab->ref;
|
|
||||||
va.addr = lab->addr;
|
|
||||||
memcpy(va.uuid, lab->uuid, 16);
|
|
||||||
|
|
||||||
err = settings_save_one(path, &va, sizeof(va));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("Failed to %s %s value (err %d)",
|
|
||||||
IS_VA_DEL(lab) ? "delete" : "store", path, err);
|
|
||||||
} else {
|
|
||||||
LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void bt_mesh_va_pending_store(void)
|
|
||||||
{
|
|
||||||
/* Do nothing. */
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
|
||||||
|
|
|
@ -101,13 +101,4 @@ int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg,
|
||||||
int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx);
|
int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx);
|
||||||
|
|
||||||
void bt_mesh_trans_init(void);
|
void bt_mesh_trans_init(void);
|
||||||
|
|
||||||
void bt_mesh_trans_reset(void);
|
void bt_mesh_trans_reset(void);
|
||||||
|
|
||||||
uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr);
|
|
||||||
|
|
||||||
uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr);
|
|
||||||
|
|
||||||
uint8_t *bt_mesh_va_label_get(uint16_t addr);
|
|
||||||
|
|
||||||
void bt_mesh_va_pending_store(void);
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "heartbeat.h"
|
#include "heartbeat.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
|
#include "va.h"
|
||||||
|
|
||||||
#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
|
#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
|
@ -78,20 +79,6 @@ LOG_MODULE_REGISTER(bt_mesh_transport);
|
||||||
/* How long to wait for available buffers before giving up */
|
/* How long to wait for available buffers before giving up */
|
||||||
#define BUF_TIMEOUT K_NO_WAIT
|
#define BUF_TIMEOUT K_NO_WAIT
|
||||||
|
|
||||||
struct virtual_addr {
|
|
||||||
uint16_t ref:15,
|
|
||||||
changed:1;
|
|
||||||
uint16_t addr;
|
|
||||||
uint8_t uuid[16];
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Virtual Address information for persistent storage. */
|
|
||||||
struct va_val {
|
|
||||||
uint16_t ref;
|
|
||||||
uint16_t addr;
|
|
||||||
uint8_t uuid[16];
|
|
||||||
} __packed;
|
|
||||||
|
|
||||||
static struct seg_tx {
|
static struct seg_tx {
|
||||||
struct bt_mesh_subnet *sub;
|
struct bt_mesh_subnet *sub;
|
||||||
void *seg[BT_MESH_TX_SEG_MAX];
|
void *seg[BT_MESH_TX_SEG_MAX];
|
||||||
|
@ -138,8 +125,6 @@ static struct seg_rx {
|
||||||
|
|
||||||
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
|
K_MEM_SLAB_DEFINE(segs, BT_MESH_APP_SEG_SDU_MAX, CONFIG_BT_MESH_SEG_BUFS, 4);
|
||||||
|
|
||||||
static struct virtual_addr virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
|
|
||||||
|
|
||||||
static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
static int send_unseg(struct bt_mesh_net_tx *tx, struct net_buf_simple *sdu,
|
||||||
const struct bt_mesh_send_cb *cb, void *cb_data,
|
const struct bt_mesh_send_cb *cb, void *cb_data,
|
||||||
const uint8_t *ctl_op)
|
const uint8_t *ctl_op)
|
||||||
|
@ -613,7 +598,10 @@ static int trans_encrypt(const struct bt_mesh_net_tx *tx, const struct bt_mesh_k
|
||||||
};
|
};
|
||||||
|
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) {
|
if (BT_MESH_ADDR_IS_VIRTUAL(tx->ctx->addr)) {
|
||||||
crypto.ad = bt_mesh_va_label_get(tx->ctx->addr);
|
crypto.ad = tx->ctx->uuid;
|
||||||
|
if (crypto.ad == NULL) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return bt_mesh_app_encrypt(key, &crypto, msg);
|
return bt_mesh_app_encrypt(key, &crypto, msg);
|
||||||
|
@ -720,15 +708,35 @@ struct decrypt_ctx {
|
||||||
static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key,
|
static int sdu_try_decrypt(struct bt_mesh_net_rx *rx, const struct bt_mesh_key *key,
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
{
|
{
|
||||||
const struct decrypt_ctx *ctx = cb_data;
|
struct decrypt_ctx *ctx = cb_data;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (ctx->seg) {
|
ctx->crypto.ad = NULL;
|
||||||
seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic);
|
|
||||||
|
do {
|
||||||
|
if (ctx->seg) {
|
||||||
|
seg_rx_assemble(ctx->seg, ctx->buf, ctx->crypto.aszmic);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
||||||
|
ctx->crypto.ad = bt_mesh_va_uuid_get(rx->ctx.recv_dst, ctx->crypto.ad,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!ctx->crypto.ad) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_reset(ctx->sdu);
|
||||||
|
|
||||||
|
err = bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu);
|
||||||
|
} while (err && ctx->crypto.ad != NULL);
|
||||||
|
|
||||||
|
if (!err && BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
||||||
|
rx->ctx.uuid = ctx->crypto.ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
net_buf_simple_reset(ctx->sdu);
|
return err;
|
||||||
|
|
||||||
return bt_mesh_app_decrypt(key, &ctx->crypto, ctx->buf, ctx->sdu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
|
@ -755,10 +763,6 @@ static int sdu_recv(struct bt_mesh_net_rx *rx, uint8_t hdr, uint8_t aszmic,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
|
|
||||||
ctx.crypto.ad = bt_mesh_va_label_get(rx->ctx.recv_dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
rx->ctx.app_idx = bt_mesh_app_key_find(ctx.crypto.dev_key, AID(&hdr),
|
||||||
rx, sdu_try_decrypt, &ctx);
|
rx, sdu_try_decrypt, &ctx);
|
||||||
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
if (rx->ctx.app_idx == BT_MESH_KEY_UNUSED) {
|
||||||
|
@ -1625,11 +1629,6 @@ void bt_mesh_rx_reset(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void store_va_label(void)
|
|
||||||
{
|
|
||||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bt_mesh_trans_reset(void)
|
void bt_mesh_trans_reset(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -1642,18 +1641,8 @@ void bt_mesh_trans_reset(void)
|
||||||
seg_tx_reset(&seg_tx[i]);
|
seg_tx_reset(&seg_tx[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref) {
|
|
||||||
virtual_addrs[i].ref = 0U;
|
|
||||||
virtual_addrs[i].changed = 1U;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_mesh_rpl_clear();
|
bt_mesh_rpl_clear();
|
||||||
|
bt_mesh_va_clear();
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
store_va_label();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void bt_mesh_trans_init(void)
|
void bt_mesh_trans_init(void)
|
||||||
|
@ -1668,199 +1657,3 @@ void bt_mesh_trans_init(void)
|
||||||
k_work_init_delayable(&seg_rx[i].ack, seg_ack);
|
k_work_init_delayable(&seg_rx[i].ack, seg_ack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void va_store(struct virtual_addr *store)
|
|
||||||
{
|
|
||||||
store->changed = 1U;
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
|
||||||
store_va_label();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bt_mesh_va_add(const uint8_t uuid[16], uint16_t *addr)
|
|
||||||
{
|
|
||||||
struct virtual_addr *va = NULL;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (!virtual_addrs[i].ref) {
|
|
||||||
if (!va) {
|
|
||||||
va = &virtual_addrs[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!memcmp(uuid, virtual_addrs[i].uuid,
|
|
||||||
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
|
||||||
*addr = virtual_addrs[i].addr;
|
|
||||||
virtual_addrs[i].ref++;
|
|
||||||
va_store(&virtual_addrs[i]);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!va) {
|
|
||||||
return STATUS_INSUFF_RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid));
|
|
||||||
err = bt_mesh_virtual_addr(uuid, &va->addr);
|
|
||||||
if (err) {
|
|
||||||
va->addr = BT_MESH_ADDR_UNASSIGNED;
|
|
||||||
return STATUS_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
|
|
||||||
va->ref = 1;
|
|
||||||
va_store(va);
|
|
||||||
|
|
||||||
*addr = va->addr;
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bt_mesh_va_del(const uint8_t uuid[16], uint16_t *addr)
|
|
||||||
{
|
|
||||||
struct virtual_addr *va = NULL;
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref &&
|
|
||||||
!memcmp(uuid, virtual_addrs[i].uuid,
|
|
||||||
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
|
||||||
va = &virtual_addrs[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!va) {
|
|
||||||
return STATUS_CANNOT_REMOVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
va->ref--;
|
|
||||||
if (addr) {
|
|
||||||
*addr = va->addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
va_store(va);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *bt_mesh_va_label_get(uint16_t addr)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
LOG_DBG("addr 0x%04x", addr);
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
|
||||||
if (virtual_addrs[i].ref && virtual_addrs[i].addr == addr) {
|
|
||||||
LOG_DBG("Found Label UUID for 0x%04x: %s", addr,
|
|
||||||
bt_hex(virtual_addrs[i].uuid, 16));
|
|
||||||
return virtual_addrs[i].uuid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_WRN("No matching Label UUID for 0x%04x", addr);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
|
||||||
static struct virtual_addr *bt_mesh_va_get(uint16_t index)
|
|
||||||
{
|
|
||||||
if (index >= ARRAY_SIZE(virtual_addrs)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &virtual_addrs[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
static int va_set(const char *name, size_t len_rd,
|
|
||||||
settings_read_cb read_cb, void *cb_arg)
|
|
||||||
{
|
|
||||||
struct va_val va;
|
|
||||||
struct virtual_addr *lab;
|
|
||||||
uint16_t index;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!name) {
|
|
||||||
LOG_ERR("Insufficient number of arguments");
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
index = strtol(name, NULL, 16);
|
|
||||||
|
|
||||||
if (len_rd == 0) {
|
|
||||||
LOG_WRN("Mesh Virtual Address length = 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va));
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("Failed to set \'virtual address\'");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (va.ref == 0) {
|
|
||||||
LOG_WRN("Ignore Mesh Virtual Address ref = 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lab = bt_mesh_va_get(index);
|
|
||||||
if (lab == NULL) {
|
|
||||||
LOG_WRN("Out of labels buffers");
|
|
||||||
return -ENOBUFS;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(lab->uuid, va.uuid, 16);
|
|
||||||
lab->addr = va.addr;
|
|
||||||
lab->ref = va.ref;
|
|
||||||
|
|
||||||
LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BT_MESH_SETTINGS_DEFINE(va, "Va", va_set);
|
|
||||||
|
|
||||||
#define IS_VA_DEL(_label) ((_label)->ref == 0)
|
|
||||||
void bt_mesh_va_pending_store(void)
|
|
||||||
{
|
|
||||||
struct virtual_addr *lab;
|
|
||||||
struct va_val va;
|
|
||||||
char path[18];
|
|
||||||
uint16_t i;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
for (i = 0; (lab = bt_mesh_va_get(i)) != NULL; i++) {
|
|
||||||
if (!lab->changed) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lab->changed = 0U;
|
|
||||||
|
|
||||||
snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
|
|
||||||
|
|
||||||
if (IS_VA_DEL(lab)) {
|
|
||||||
err = settings_delete(path);
|
|
||||||
} else {
|
|
||||||
va.ref = lab->ref;
|
|
||||||
va.addr = lab->addr;
|
|
||||||
memcpy(va.uuid, lab->uuid, 16);
|
|
||||||
|
|
||||||
err = settings_save_one(path, &va, sizeof(va));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
LOG_ERR("Failed to %s %s value (err %d)",
|
|
||||||
IS_VA_DEL(lab) ? "delete" : "store", path, err);
|
|
||||||
} else {
|
|
||||||
LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void bt_mesh_va_pending_store(void)
|
|
||||||
{
|
|
||||||
/* Do nothing. */
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
|
||||||
|
|
319
subsys/bluetooth/mesh/va.c
Normal file
319
subsys/bluetooth/mesh/va.c
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017 Intel Corporation
|
||||||
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <zephyr/settings/settings.h>
|
||||||
|
#include <zephyr/net/buf.h>
|
||||||
|
|
||||||
|
#include <zephyr/bluetooth/mesh.h>
|
||||||
|
|
||||||
|
#include "common/bt_str.h"
|
||||||
|
|
||||||
|
#include "va.h"
|
||||||
|
#include "foundation.h"
|
||||||
|
#include "msg.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#define LOG_LEVEL CONFIG_BT_MESH_TRANS_LOG_LEVEL
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(bt_mesh_va);
|
||||||
|
|
||||||
|
static struct bt_mesh_va virtual_addrs[CONFIG_BT_MESH_LABEL_COUNT];
|
||||||
|
|
||||||
|
/* Virtual Address information for persistent storage. */
|
||||||
|
struct va_val {
|
||||||
|
uint16_t ref;
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t uuid[16];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static void va_store(struct bt_mesh_va *store)
|
||||||
|
{
|
||||||
|
store->changed = 1U;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry)
|
||||||
|
{
|
||||||
|
struct bt_mesh_va *va = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||||
|
if (!virtual_addrs[i].ref) {
|
||||||
|
if (!va) {
|
||||||
|
va = &virtual_addrs[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(uuid, virtual_addrs[i].uuid,
|
||||||
|
ARRAY_SIZE(virtual_addrs[i].uuid))) {
|
||||||
|
if (entry) {
|
||||||
|
*entry = &virtual_addrs[i];
|
||||||
|
}
|
||||||
|
virtual_addrs[i].ref++;
|
||||||
|
va_store(&virtual_addrs[i]);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!va) {
|
||||||
|
return STATUS_INSUFF_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(va->uuid, uuid, ARRAY_SIZE(va->uuid));
|
||||||
|
err = bt_mesh_virtual_addr(uuid, &va->addr);
|
||||||
|
if (err) {
|
||||||
|
va->addr = BT_MESH_ADDR_UNASSIGNED;
|
||||||
|
return STATUS_UNSPECIFIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
va->ref = 1;
|
||||||
|
va_store(va);
|
||||||
|
|
||||||
|
if (entry) {
|
||||||
|
*entry = va;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t bt_mesh_va_del(const uint8_t *uuid)
|
||||||
|
{
|
||||||
|
struct bt_mesh_va *va;
|
||||||
|
|
||||||
|
if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
|
||||||
|
return STATUS_CANNOT_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid);
|
||||||
|
|
||||||
|
if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) {
|
||||||
|
return STATUS_CANNOT_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
va->ref--;
|
||||||
|
va_store(va);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *bt_mesh_va_uuid_get(uint16_t addr, const uint8_t *uuid, uint16_t *retaddr)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid != NULL) {
|
||||||
|
struct bt_mesh_va *va;
|
||||||
|
|
||||||
|
va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid);
|
||||||
|
i = ARRAY_INDEX(virtual_addrs, va);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||||
|
if (virtual_addrs[i].ref &&
|
||||||
|
(virtual_addrs[i].addr == addr || addr == BT_MESH_ADDR_UNASSIGNED)) {
|
||||||
|
if (!uuid) {
|
||||||
|
LOG_DBG("Found Label UUID for 0x%04x: %s", addr,
|
||||||
|
bt_hex(virtual_addrs[i].uuid, 16));
|
||||||
|
|
||||||
|
if (retaddr) {
|
||||||
|
*retaddr = virtual_addrs[i].addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return virtual_addrs[i].uuid;
|
||||||
|
} else if (uuid == virtual_addrs[i].uuid) {
|
||||||
|
uuid = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_WRN("No matching Label UUID for 0x%04x", addr);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bt_mesh_va_collision_check(uint16_t addr)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
const uint8_t *uuid = NULL;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uuid = bt_mesh_va_uuid_get(addr, uuid, NULL);
|
||||||
|
} while (uuid && ++count);
|
||||||
|
|
||||||
|
return count > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||||
|
if (virtual_addrs[i].ref && !memcmp(virtual_addrs[i].uuid, uuid, 16)) {
|
||||||
|
return &virtual_addrs[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bt_mesh_va *va_get_by_idx(uint16_t index)
|
||||||
|
{
|
||||||
|
if (index >= ARRAY_SIZE(virtual_addrs)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &virtual_addrs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx)
|
||||||
|
{
|
||||||
|
struct bt_mesh_va *va;
|
||||||
|
|
||||||
|
va = va_get_by_idx(idx);
|
||||||
|
return (va && va->ref > 0) ? va->uuid : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx)
|
||||||
|
{
|
||||||
|
struct bt_mesh_va *va;
|
||||||
|
|
||||||
|
if (CONFIG_BT_MESH_LABEL_COUNT == 0) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
va = CONTAINER_OF(uuid, struct bt_mesh_va, uuid);
|
||||||
|
|
||||||
|
if (!PART_OF_ARRAY(virtual_addrs, va) || va->ref == 0) {
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
*uuidx = ARRAY_INDEX(virtual_addrs, va);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CONFIG_BT_MESH_LABEL_COUNT > 0
|
||||||
|
static int va_set(const char *name, size_t len_rd,
|
||||||
|
settings_read_cb read_cb, void *cb_arg)
|
||||||
|
{
|
||||||
|
struct va_val va;
|
||||||
|
struct bt_mesh_va *lab;
|
||||||
|
uint16_t index;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
LOG_ERR("Insufficient number of arguments");
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
index = strtol(name, NULL, 16);
|
||||||
|
|
||||||
|
if (len_rd == 0) {
|
||||||
|
LOG_WRN("Mesh Virtual Address length = 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_mesh_settings_set(read_cb, cb_arg, &va, sizeof(va));
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to set \'virtual address\'");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (va.ref == 0) {
|
||||||
|
LOG_WRN("Ignore Mesh Virtual Address ref = 0");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lab = va_get_by_idx(index);
|
||||||
|
if (lab == NULL) {
|
||||||
|
LOG_WRN("Out of labels buffers");
|
||||||
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(lab->uuid, va.uuid, 16);
|
||||||
|
lab->addr = va.addr;
|
||||||
|
lab->ref = va.ref;
|
||||||
|
|
||||||
|
LOG_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x", lab->addr, lab->ref);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_MESH_SETTINGS_DEFINE(va, "Va", va_set);
|
||||||
|
|
||||||
|
#define IS_VA_DEL(_label) ((_label)->ref == 0)
|
||||||
|
void bt_mesh_va_pending_store(void)
|
||||||
|
{
|
||||||
|
struct bt_mesh_va *lab;
|
||||||
|
struct va_val va;
|
||||||
|
char path[18];
|
||||||
|
uint16_t i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
for (i = 0; (lab = va_get_by_idx(i)) != NULL; i++) {
|
||||||
|
if (!lab->changed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
lab->changed = 0U;
|
||||||
|
|
||||||
|
snprintk(path, sizeof(path), "bt/mesh/Va/%x", i);
|
||||||
|
|
||||||
|
if (IS_VA_DEL(lab)) {
|
||||||
|
err = settings_delete(path);
|
||||||
|
} else {
|
||||||
|
va.ref = lab->ref;
|
||||||
|
va.addr = lab->addr;
|
||||||
|
memcpy(va.uuid, lab->uuid, 16);
|
||||||
|
|
||||||
|
err = settings_save_one(path, &va, sizeof(va));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
LOG_ERR("Failed to %s %s value (err %d)",
|
||||||
|
IS_VA_DEL(lab) ? "delete" : "store", path, err);
|
||||||
|
} else {
|
||||||
|
LOG_DBG("%s %s value", IS_VA_DEL(lab) ? "Deleted" : "Stored", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void bt_mesh_va_pending_store(void)
|
||||||
|
{
|
||||||
|
/* Do nothing. */
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_BT_MESH_LABEL_COUNT > 0 */
|
||||||
|
|
||||||
|
void bt_mesh_va_clear(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(virtual_addrs); i++) {
|
||||||
|
if (virtual_addrs[i].ref) {
|
||||||
|
virtual_addrs[i].ref = 0U;
|
||||||
|
virtual_addrs[i].changed = 1U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
|
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_VA_PENDING);
|
||||||
|
}
|
||||||
|
}
|
79
subsys/bluetooth/mesh/va.h
Normal file
79
subsys/bluetooth/mesh/va.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Virtual address entry. */
|
||||||
|
struct bt_mesh_va {
|
||||||
|
uint16_t ref:15,
|
||||||
|
changed:1;
|
||||||
|
uint16_t addr;
|
||||||
|
uint8_t uuid[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @brief Store Label UUID.
|
||||||
|
*
|
||||||
|
* @param uuid Label UUID to be stored.
|
||||||
|
* @param entry Pointer to a memory where a new or updated entry will be stored, or NULL.
|
||||||
|
*
|
||||||
|
* @return STATUS_SUCCESS if entry is stored or updated, error code otherwise.
|
||||||
|
*/
|
||||||
|
uint8_t bt_mesh_va_add(const uint8_t uuid[16], const struct bt_mesh_va **entry);
|
||||||
|
|
||||||
|
/** @brief Delete Label UUID.
|
||||||
|
*
|
||||||
|
* @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid
|
||||||
|
* pointer.
|
||||||
|
*
|
||||||
|
* @param uuid Label UUID to delete.
|
||||||
|
*
|
||||||
|
* @return STATUS_SUCCESS if entry is deleted, error code otherwise.
|
||||||
|
*/
|
||||||
|
uint8_t bt_mesh_va_del(const uint8_t *uuid);
|
||||||
|
|
||||||
|
/** @brief Find virtual address entry by Label UUID.
|
||||||
|
*
|
||||||
|
* @c uuid can be a user data.
|
||||||
|
*
|
||||||
|
* @param uuid pointer to memory with Label UUID to be found.
|
||||||
|
*
|
||||||
|
* @return Pointer to a valid entry, NULL otherwise.
|
||||||
|
*/
|
||||||
|
const struct bt_mesh_va *bt_mesh_va_find(const uint8_t *uuid);
|
||||||
|
|
||||||
|
/** @brief Check if there are more than one Label UUID which hash has the specificed virtual
|
||||||
|
* address.
|
||||||
|
*
|
||||||
|
* @param addr Virtual address to check
|
||||||
|
*
|
||||||
|
* @return True if there is collision, false otherwise.
|
||||||
|
*/
|
||||||
|
bool bt_mesh_va_collision_check(uint16_t addr);
|
||||||
|
|
||||||
|
/* Needed for storing va as indexes in persistent storage. */
|
||||||
|
/** @brief Get Label UUID by index.
|
||||||
|
*
|
||||||
|
* @param idx Index of virtual address entry.
|
||||||
|
*
|
||||||
|
* @return Pointer to a valid Label UUID, or NULL if entry is not found.
|
||||||
|
*/
|
||||||
|
const uint8_t *bt_mesh_va_get_uuid_by_idx(uint16_t idx);
|
||||||
|
|
||||||
|
/** @brief Get virtual address entry index by Label UUID.
|
||||||
|
*
|
||||||
|
* @c uuid must be a pointer to @ref bt_mesh_va.uuid. Use @ref bt_mesh_va_uuid_get to get valid
|
||||||
|
* pointer.
|
||||||
|
*
|
||||||
|
* @param uuid Label UUID which index to find
|
||||||
|
* @param uuidx Pointer to a memory where to store index.
|
||||||
|
*
|
||||||
|
* @return 0 if entry is found, error code otherwise.
|
||||||
|
*/
|
||||||
|
int bt_mesh_va_get_idx_by_uuid(const uint8_t *uuid, uint16_t *uuidx);
|
||||||
|
|
||||||
|
/** @brief Store pending virtual address entries in the persistent storage.*/
|
||||||
|
void bt_mesh_va_pending_store(void);
|
||||||
|
|
||||||
|
/** @brief Remove all stored virtual addresses and remove them from the persistent storage. */
|
||||||
|
void bt_mesh_va_clear(void);
|
|
@ -15,6 +15,8 @@
|
||||||
#include <zephyr/logging/log.h>
|
#include <zephyr/logging/log.h>
|
||||||
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
|
|
||||||
|
#include "common/bt_str.h"
|
||||||
|
|
||||||
/* Max number of messages that can be pending on RX at the same time */
|
/* Max number of messages that can be pending on RX at the same time */
|
||||||
#define RECV_QUEUE_SIZE 32
|
#define RECV_QUEUE_SIZE 32
|
||||||
|
|
||||||
|
@ -303,7 +305,7 @@ static struct bt_mesh_test_msg *blocking_recv(k_timeout_t timeout)
|
||||||
return k_queue_get(&recv, timeout);
|
return k_queue_get(&recv, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout)
|
int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout)
|
||||||
{
|
{
|
||||||
struct bt_mesh_test_msg *msg = blocking_recv(timeout);
|
struct bt_mesh_test_msg *msg = blocking_recv(timeout);
|
||||||
|
|
||||||
|
@ -321,6 +323,19 @@ int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BT_MESH_ADDR_IS_VIRTUAL(msg->ctx.recv_dst) &&
|
||||||
|
((uuid != NULL && msg->ctx.uuid == NULL) ||
|
||||||
|
(uuid == NULL && msg->ctx.uuid != NULL) ||
|
||||||
|
memcmp(uuid, msg->ctx.uuid, 16))) {
|
||||||
|
LOG_ERR("Recv: Label UUID mismatch for virtual address 0x%04x");
|
||||||
|
if (uuid && msg->ctx.uuid) {
|
||||||
|
LOG_ERR("Got: %s", bt_hex(msg->ctx.uuid, 16));
|
||||||
|
LOG_ERR("Expected: %s", bt_hex(uuid, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
k_mem_slab_free(&msg_pool, (void **)&msg);
|
k_mem_slab_free(&msg_pool, (void **)&msg);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -390,7 +405,7 @@ static void tx_ended(int err, void *data)
|
||||||
k_sem_give(&send_ctx->sem);
|
k_sem_give(&send_ctx->sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_mesh_test_send_async(uint16_t addr, size_t len,
|
int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len,
|
||||||
enum bt_mesh_test_send_flags flags,
|
enum bt_mesh_test_send_flags flags,
|
||||||
const struct bt_mesh_send_cb *send_cb,
|
const struct bt_mesh_send_cb *send_cb,
|
||||||
void *cb_data)
|
void *cb_data)
|
||||||
|
@ -403,6 +418,7 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len,
|
||||||
test_send_ctx.addr = addr;
|
test_send_ctx.addr = addr;
|
||||||
test_send_ctx.send_rel = (flags & FORCE_SEGMENTATION);
|
test_send_ctx.send_rel = (flags & FORCE_SEGMENTATION);
|
||||||
test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT;
|
test_send_ctx.send_ttl = BT_MESH_TTL_DEFAULT;
|
||||||
|
test_send_ctx.uuid = uuid;
|
||||||
|
|
||||||
BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_1, BT_MESH_TX_SDU_MAX);
|
BT_MESH_MODEL_BUF_DEFINE(buf, TEST_MSG_OP_1, BT_MESH_TX_SDU_MAX);
|
||||||
bt_mesh_model_msg_init(&buf, TEST_MSG_OP_1);
|
bt_mesh_model_msg_init(&buf, TEST_MSG_OP_1);
|
||||||
|
@ -441,11 +457,11 @@ int bt_mesh_test_send_async(uint16_t addr, size_t len,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_mesh_test_send(uint16_t addr, size_t len,
|
int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len,
|
||||||
enum bt_mesh_test_send_flags flags, k_timeout_t timeout)
|
enum bt_mesh_test_send_flags flags, k_timeout_t timeout)
|
||||||
{
|
{
|
||||||
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
|
||||||
return bt_mesh_test_send_async(addr, len, flags, NULL, NULL);
|
return bt_mesh_test_send_async(addr, uuid, len, flags, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct bt_mesh_send_cb send_cb = {
|
static const struct bt_mesh_send_cb send_cb = {
|
||||||
|
@ -457,7 +473,7 @@ int bt_mesh_test_send(uint16_t addr, size_t len,
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
k_sem_init(&send_ctx.sem, 0, 1);
|
k_sem_init(&send_ctx.sem, 0, 1);
|
||||||
err = bt_mesh_test_send_async(addr, len, flags, &send_cb, &send_ctx);
|
err = bt_mesh_test_send_async(addr, uuid, len, flags, &send_cb, &send_ctx);
|
||||||
if (err) {
|
if (err) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,13 +141,13 @@ void bt_mesh_test_timeout(bs_time_t HW_device_time);
|
||||||
|
|
||||||
void bt_mesh_device_setup(const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp);
|
void bt_mesh_device_setup(const struct bt_mesh_prov *prov, const struct bt_mesh_comp *comp);
|
||||||
|
|
||||||
int bt_mesh_test_recv(uint16_t len, uint16_t dst, k_timeout_t timeout);
|
int bt_mesh_test_recv(uint16_t len, uint16_t dst, const uint8_t *uuid, k_timeout_t timeout);
|
||||||
int bt_mesh_test_recv_msg(struct bt_mesh_test_msg *msg, k_timeout_t timeout);
|
int bt_mesh_test_recv_msg(struct bt_mesh_test_msg *msg, k_timeout_t timeout);
|
||||||
int bt_mesh_test_recv_clear(void);
|
int bt_mesh_test_recv_clear(void);
|
||||||
|
|
||||||
int bt_mesh_test_send(uint16_t addr, size_t len,
|
int bt_mesh_test_send(uint16_t addr, const uint8_t *uuid, size_t len,
|
||||||
enum bt_mesh_test_send_flags flags, k_timeout_t timeout);
|
enum bt_mesh_test_send_flags flags, k_timeout_t timeout);
|
||||||
int bt_mesh_test_send_async(uint16_t addr, size_t len,
|
int bt_mesh_test_send_async(uint16_t addr, const uint8_t *uuid, size_t len,
|
||||||
enum bt_mesh_test_send_flags flags,
|
enum bt_mesh_test_send_flags flags,
|
||||||
const struct bt_mesh_send_cb *send_cb,
|
const struct bt_mesh_send_cb *send_cb,
|
||||||
void *cb_data);
|
void *cb_data);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "mesh_test.h"
|
#include "mesh_test.h"
|
||||||
#include "mesh/net.h"
|
#include "mesh/net.h"
|
||||||
#include "mesh/transport.h"
|
#include "mesh/transport.h"
|
||||||
|
#include "mesh/va.h"
|
||||||
#include <zephyr/sys/byteorder.h>
|
#include <zephyr/sys/byteorder.h>
|
||||||
#include "argparse.h"
|
#include "argparse.h"
|
||||||
|
|
||||||
|
@ -156,7 +157,7 @@ static void test_friend_msg(void)
|
||||||
|
|
||||||
/* Send unsegmented message from friend to LPN: */
|
/* Send unsegmented message from friend to LPN: */
|
||||||
LOG_INF("Sending unsegmented message");
|
LOG_INF("Sending unsegmented message");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0,
|
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0,
|
||||||
K_SECONDS(1)),
|
K_SECONDS(1)),
|
||||||
"Unseg send failed");
|
"Unseg send failed");
|
||||||
|
|
||||||
|
@ -164,7 +165,7 @@ static void test_friend_msg(void)
|
||||||
friend_wait_for_polls(2);
|
friend_wait_for_polls(2);
|
||||||
|
|
||||||
/* Send segmented message */
|
/* Send segmented message */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 13, 0,
|
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 13, 0,
|
||||||
K_SECONDS(1)),
|
K_SECONDS(1)),
|
||||||
"Unseg send failed");
|
"Unseg send failed");
|
||||||
|
|
||||||
|
@ -178,23 +179,23 @@ static void test_friend_msg(void)
|
||||||
* transport and network parts of the second packet.
|
* transport and network parts of the second packet.
|
||||||
* Ensures coverage for the regression reported in #32033.
|
* Ensures coverage for the regression reported in #32033.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL,
|
||||||
BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)),
|
BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)),
|
||||||
"Unseg send failed");
|
"Unseg send failed");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
ASSERT_OK_MSG(bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL,
|
||||||
BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)),
|
BT_MESH_SDU_UNSEG_MAX, 0, K_SECONDS(1)),
|
||||||
"Unseg send failed");
|
"Unseg send failed");
|
||||||
|
|
||||||
/* Two messages require 2 polls plus the "no more messages" msg */
|
/* Two messages require 2 polls plus the "no more messages" msg */
|
||||||
friend_wait_for_polls(3);
|
friend_wait_for_polls(3);
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(10)),
|
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(10)),
|
||||||
"Receive from LPN failed");
|
"Receive from LPN failed");
|
||||||
|
|
||||||
/* Receive a segmented message from the LPN. LPN should poll for the ack
|
/* Receive a segmented message from the LPN. LPN should poll for the ack
|
||||||
* after sending the segments.
|
* after sending the segments.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_SECONDS(10)));
|
ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_SECONDS(10)));
|
||||||
/* 4 polls (2 if legacy transport layer is used):
|
/* 4 polls (2 if legacy transport layer is used):
|
||||||
* - The first one triggered manually by transport when sending segmented message;
|
* - The first one triggered manually by transport when sending segmented message;
|
||||||
* - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages);
|
* - 2 for each SegAck (SegAcks are sent faster than Friend Poll messages);
|
||||||
|
@ -227,13 +228,13 @@ static void test_friend_overflow(void)
|
||||||
|
|
||||||
/* Fill the queue */
|
/* Fill the queue */
|
||||||
for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) {
|
for (int i = 0; i < CONFIG_BT_MESH_FRIEND_QUEUE_SIZE; i++) {
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add one more message, which should overflow the queue and cause the
|
/* Add one more message, which should overflow the queue and cause the
|
||||||
* first message to be discarded.
|
* first message to be discarded.
|
||||||
*/
|
*/
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
||||||
K_SECONDS(35)),
|
K_SECONDS(35)),
|
||||||
|
@ -246,12 +247,12 @@ static void test_friend_overflow(void)
|
||||||
|
|
||||||
/* Make room in the Friend Queue for only one unsegmented message. */
|
/* Make room in the Friend Queue for only one unsegmented message. */
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
||||||
BT_MESH_SDU_UNSEG_MAX *
|
NULL, BT_MESH_SDU_UNSEG_MAX *
|
||||||
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 1),
|
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 1),
|
||||||
0, K_SECONDS(1)),
|
0, K_SECONDS(1)),
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
/* This message should preempt the segmented one. */
|
/* This message should preempt the segmented one. */
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
||||||
K_SECONDS(35)),
|
K_SECONDS(35)),
|
||||||
|
@ -266,17 +267,17 @@ static void test_friend_overflow(void)
|
||||||
* message won't preempt this segmented message.
|
* message won't preempt this segmented message.
|
||||||
*/
|
*/
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
||||||
BT_MESH_SDU_UNSEG_MAX *
|
NULL, BT_MESH_SDU_UNSEG_MAX *
|
||||||
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2),
|
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2),
|
||||||
0, K_SECONDS(1));
|
0, K_SECONDS(1));
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
/* This segmented message should preempt the previous segmented message. */
|
/* This segmented message should preempt the previous segmented message. */
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(),
|
||||||
BT_MESH_SDU_UNSEG_MAX *
|
NULL, BT_MESH_SDU_UNSEG_MAX *
|
||||||
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2),
|
(CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - 2),
|
||||||
0, K_SECONDS(1));
|
0, K_SECONDS(1));
|
||||||
/* This message should fit in Friend Queue as well. */
|
/* This message should fit in Friend Queue as well. */
|
||||||
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), 5, 0, K_NO_WAIT);
|
bt_mesh_test_send(bt_mesh_test_friendship_addr_get(), NULL, 5, 0, K_NO_WAIT);
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
||||||
K_SECONDS(35)),
|
K_SECONDS(35)),
|
||||||
|
@ -295,7 +296,7 @@ static void test_friend_overflow(void)
|
||||||
*/
|
*/
|
||||||
static void test_friend_group(void)
|
static void test_friend_group(void)
|
||||||
{
|
{
|
||||||
uint16_t virtual_addr;
|
const struct bt_mesh_va *va;
|
||||||
|
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
|
@ -306,7 +307,7 @@ static void test_friend_group(void)
|
||||||
"Friendship not established");
|
"Friendship not established");
|
||||||
bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED);
|
bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED);
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr));
|
ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va));
|
||||||
|
|
||||||
/* The other mesh device will send its messages in the first poll */
|
/* The other mesh device will send its messages in the first poll */
|
||||||
ASSERT_OK(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
ASSERT_OK(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED,
|
||||||
|
@ -317,10 +318,10 @@ static void test_friend_group(void)
|
||||||
bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED);
|
bt_mesh_test_friendship_evt_clear(BT_MESH_TEST_FRIEND_POLLED);
|
||||||
|
|
||||||
/* Send a group message to the LPN */
|
/* Send a group message to the LPN */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)),
|
||||||
"Failed to send to LPN");
|
"Failed to send to LPN");
|
||||||
/* Send a virtual message to the LPN */
|
/* Send a virtual message to the LPN */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)),
|
||||||
"Failed to send to LPN");
|
"Failed to send to LPN");
|
||||||
|
|
||||||
/* Wait for the LPN to poll for each message, then for adding the
|
/* Wait for the LPN to poll for each message, then for adding the
|
||||||
|
@ -331,7 +332,7 @@ static void test_friend_group(void)
|
||||||
/* Send a group message to an address the LPN added after the friendship
|
/* Send a group message to an address the LPN added after the friendship
|
||||||
* was established.
|
* was established.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR + 1, NULL, 5, 0, K_SECONDS(1)),
|
||||||
"Failed to send to LPN");
|
"Failed to send to LPN");
|
||||||
|
|
||||||
bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(10));
|
bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_FRIEND_POLLED, K_SECONDS(10));
|
||||||
|
@ -410,7 +411,7 @@ static void test_lpn_msg_frnd(void)
|
||||||
|
|
||||||
/* Receive unsegmented message */
|
/* Receive unsegmented message */
|
||||||
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1)),
|
||||||
"Failed to receive message");
|
"Failed to receive message");
|
||||||
|
|
||||||
/* Give friend time to prepare the message */
|
/* Give friend time to prepare the message */
|
||||||
|
@ -418,7 +419,7 @@ static void test_lpn_msg_frnd(void)
|
||||||
|
|
||||||
/* Receive segmented message */
|
/* Receive segmented message */
|
||||||
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, K_SECONDS(2)),
|
ASSERT_OK_MSG(bt_mesh_test_recv(13, cfg->addr, NULL, K_SECONDS(2)),
|
||||||
"Failed to receive message");
|
"Failed to receive message");
|
||||||
|
|
||||||
/* Give friend time to prepare the messages */
|
/* Give friend time to prepare the messages */
|
||||||
|
@ -427,10 +428,10 @@ static void test_lpn_msg_frnd(void)
|
||||||
/* Receive two unsegmented messages */
|
/* Receive two unsegmented messages */
|
||||||
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr,
|
ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr,
|
||||||
K_SECONDS(2)),
|
NULL, K_SECONDS(2)),
|
||||||
"Failed to receive message");
|
"Failed to receive message");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr,
|
ASSERT_OK_MSG(bt_mesh_test_recv(BT_MESH_SDU_UNSEG_MAX, cfg->addr,
|
||||||
K_SECONDS(2)),
|
NULL, K_SECONDS(2)),
|
||||||
"Failed to receive message");
|
"Failed to receive message");
|
||||||
|
|
||||||
k_sleep(K_SECONDS(3));
|
k_sleep(K_SECONDS(3));
|
||||||
|
@ -438,7 +439,7 @@ static void test_lpn_msg_frnd(void)
|
||||||
/* Send an unsegmented message to the friend.
|
/* Send an unsegmented message to the friend.
|
||||||
* Should not be affected by the LPN mode at all.
|
* Should not be affected by the LPN mode at all.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 5, 0, K_MSEC(500)),
|
ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 5, 0, K_MSEC(500)),
|
||||||
"Send to friend failed");
|
"Send to friend failed");
|
||||||
|
|
||||||
k_sleep(K_SECONDS(5));
|
k_sleep(K_SECONDS(5));
|
||||||
|
@ -446,7 +447,7 @@ static void test_lpn_msg_frnd(void)
|
||||||
/* Send a segmented message to the friend. Should trigger a poll for the
|
/* Send a segmented message to the friend. Should trigger a poll for the
|
||||||
* ack.
|
* ack.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, 15, 0, K_SECONDS(5)),
|
ASSERT_OK_MSG(bt_mesh_test_send(friend_cfg.addr, NULL, 15, 0, K_SECONDS(5)),
|
||||||
"Send to friend failed");
|
"Send to friend failed");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
@ -472,17 +473,18 @@ static void test_lpn_msg_mesh(void)
|
||||||
/* Send an unsegmented message to a third mesh node.
|
/* Send an unsegmented message to a third mesh node.
|
||||||
* Should not be affected by the LPN mode at all.
|
* Should not be affected by the LPN mode at all.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 5, 0, K_NO_WAIT), "Send to mesh failed");
|
ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_NO_WAIT),
|
||||||
|
"Send to mesh failed");
|
||||||
|
|
||||||
/* Receive an unsegmented message back */
|
/* Receive an unsegmented message back */
|
||||||
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_FOREVER));
|
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER));
|
||||||
|
|
||||||
/* Send a segmented message to the mesh node. */
|
/* Send a segmented message to the mesh node. */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, 15, 0, K_FOREVER),
|
ASSERT_OK_MSG(bt_mesh_test_send(other_cfg.addr, NULL, 15, 0, K_FOREVER),
|
||||||
"Send to other failed");
|
"Send to other failed");
|
||||||
|
|
||||||
/* Receive a segmented message back */
|
/* Receive a segmented message back */
|
||||||
ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, K_FOREVER));
|
ASSERT_OK(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER));
|
||||||
|
|
||||||
/* Send an unsegmented message with friend credentials to a third mesh
|
/* Send an unsegmented message with friend credentials to a third mesh
|
||||||
* node. The friend shall relay it.
|
* node. The friend shall relay it.
|
||||||
|
@ -664,6 +666,7 @@ static void test_lpn_overflow(void)
|
||||||
static void test_lpn_group(void)
|
static void test_lpn_group(void)
|
||||||
{
|
{
|
||||||
struct bt_mesh_test_msg msg;
|
struct bt_mesh_test_msg msg;
|
||||||
|
const struct bt_mesh_va *va;
|
||||||
uint16_t vaddr;
|
uint16_t vaddr;
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
int err;
|
int err;
|
||||||
|
@ -683,6 +686,10 @@ static void test_lpn_group(void)
|
||||||
FAIL("VA addr add failed with err %d status 0x%x", err, status);
|
FAIL("VA addr add failed with err %d status 0x%x", err, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
va = bt_mesh_va_find(test_va_uuid);
|
||||||
|
ASSERT_TRUE(va != NULL);
|
||||||
|
ASSERT_EQUAL(vaddr, va->addr);
|
||||||
|
|
||||||
bt_mesh_lpn_set(true);
|
bt_mesh_lpn_set(true);
|
||||||
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED,
|
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED,
|
||||||
K_SECONDS(5)), "LPN not established");
|
K_SECONDS(5)), "LPN not established");
|
||||||
|
@ -693,7 +700,7 @@ static void test_lpn_group(void)
|
||||||
* start up first.
|
* start up first.
|
||||||
*/
|
*/
|
||||||
k_sleep(K_MSEC(10));
|
k_sleep(K_MSEC(10));
|
||||||
ASSERT_OK(bt_mesh_test_send(other_cfg.addr, 5, 0, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_send(other_cfg.addr, NULL, 5, 0, K_SECONDS(1)));
|
||||||
|
|
||||||
k_sleep(K_SECONDS(5));
|
k_sleep(K_SECONDS(5));
|
||||||
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
||||||
|
@ -706,7 +713,8 @@ static void test_lpn_group(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
|
||||||
if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != other_cfg.addr) {
|
if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != other_cfg.addr ||
|
||||||
|
msg.ctx.uuid != va->uuid) {
|
||||||
FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
|
FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
|
||||||
msg.ctx.recv_dst);
|
msg.ctx.recv_dst);
|
||||||
}
|
}
|
||||||
|
@ -722,7 +730,7 @@ static void test_lpn_group(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv_msg(&msg, K_SECONDS(1)));
|
||||||
if (msg.ctx.recv_dst != vaddr || msg.ctx.addr != friend_cfg.addr) {
|
if (msg.ctx.recv_dst != va->addr || msg.ctx.addr != friend_cfg.addr) {
|
||||||
FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
|
FAIL("Unexpected message: 0x%04x -> 0x%04x", msg.ctx.addr,
|
||||||
msg.ctx.recv_dst);
|
msg.ctx.recv_dst);
|
||||||
}
|
}
|
||||||
|
@ -763,6 +771,7 @@ static void test_lpn_group(void)
|
||||||
static void test_lpn_loopback(void)
|
static void test_lpn_loopback(void)
|
||||||
{
|
{
|
||||||
struct bt_mesh_test_msg msg;
|
struct bt_mesh_test_msg msg;
|
||||||
|
const struct bt_mesh_va *va;
|
||||||
uint16_t vaddr;
|
uint16_t vaddr;
|
||||||
uint8_t status = 0;
|
uint8_t status = 0;
|
||||||
int err;
|
int err;
|
||||||
|
@ -782,6 +791,10 @@ static void test_lpn_loopback(void)
|
||||||
FAIL("VA addr add failed with err %d status 0x%x", err, status);
|
FAIL("VA addr add failed with err %d status 0x%x", err, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
va = bt_mesh_va_find(test_va_uuid);
|
||||||
|
ASSERT_TRUE(va != NULL);
|
||||||
|
ASSERT_EQUAL(vaddr, va->addr);
|
||||||
|
|
||||||
bt_mesh_lpn_set(true);
|
bt_mesh_lpn_set(true);
|
||||||
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED,
|
ASSERT_OK_MSG(bt_mesh_test_friendship_evt_wait(BT_MESH_TEST_LPN_ESTABLISHED,
|
||||||
K_SECONDS(5)),
|
K_SECONDS(5)),
|
||||||
|
@ -791,12 +804,16 @@ static void test_lpn_loopback(void)
|
||||||
k_sleep(K_SECONDS(1));
|
k_sleep(K_SECONDS(1));
|
||||||
|
|
||||||
/* Loopback on unicast, shouldn't even leave the device */
|
/* Loopback on unicast, shouldn't even leave the device */
|
||||||
ASSERT_OK(bt_mesh_test_send_async(cfg->addr, 5, 0, NULL, NULL));
|
ASSERT_OK(bt_mesh_test_send_async(cfg->addr, NULL, 5, 0, NULL, NULL));
|
||||||
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1)));
|
||||||
|
|
||||||
/* Loopback on group address, should not come back from the friend */
|
/* Loopback on group address, should not come back from the friend */
|
||||||
ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, 5, 0, NULL, NULL));
|
ASSERT_OK(bt_mesh_test_send_async(GROUP_ADDR, NULL, 5, 0, NULL, NULL));
|
||||||
ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv(5, GROUP_ADDR, NULL, K_SECONDS(1)));
|
||||||
|
|
||||||
|
/* Loopback on virtual address, should not come back from the friend */
|
||||||
|
ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL));
|
||||||
|
ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1)));
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
ASSERT_OK_MSG(bt_mesh_lpn_poll(), "Poll failed");
|
||||||
err = bt_mesh_test_recv_msg(&msg, K_SECONDS(2));
|
err = bt_mesh_test_recv_msg(&msg, K_SECONDS(2));
|
||||||
|
@ -805,8 +822,8 @@ static void test_lpn_loopback(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loopback on virtual address, should not come back from the friend */
|
/* Loopback on virtual address, should not come back from the friend */
|
||||||
ASSERT_OK(bt_mesh_test_send_async(vaddr, 5, 0, NULL, NULL));
|
ASSERT_OK(bt_mesh_test_send_async(va->addr, va->uuid, 5, 0, NULL, NULL));
|
||||||
ASSERT_OK(bt_mesh_test_recv(5, vaddr, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv(5, va->addr, va->uuid, K_SECONDS(1)));
|
||||||
|
|
||||||
k_sleep(K_SECONDS(2));
|
k_sleep(K_SECONDS(2));
|
||||||
|
|
||||||
|
@ -844,27 +861,32 @@ static void test_other_msg(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Receive an unsegmented message from the LPN. */
|
/* Receive an unsegmented message from the LPN. */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, K_FOREVER), "Failed to receive from LPN");
|
ASSERT_OK_MSG(bt_mesh_test_recv(5, cfg->addr, NULL, K_FOREVER),
|
||||||
|
"Failed to receive from LPN");
|
||||||
|
|
||||||
/* Minor delay that allows LPN's adv to complete sending. */
|
/* Minor delay that allows LPN's adv to complete sending. */
|
||||||
k_sleep(K_SECONDS(2));
|
k_sleep(K_SECONDS(2));
|
||||||
|
|
||||||
/* Send an unsegmented message to the LPN */
|
/* Send an unsegmented message to the LPN */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 5, 0, K_NO_WAIT), "Failed to send to LPN");
|
ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 5, 0, K_NO_WAIT),
|
||||||
|
"Failed to send to LPN");
|
||||||
|
|
||||||
/* Receive a segmented message from the LPN. */
|
/* Receive a segmented message from the LPN. */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, K_FOREVER), "Failed to receive from LPN");
|
ASSERT_OK_MSG(bt_mesh_test_recv(15, cfg->addr, NULL, K_FOREVER),
|
||||||
|
"Failed to receive from LPN");
|
||||||
|
|
||||||
/* Minor delay that allows LPN's adv to complete sending. */
|
/* Minor delay that allows LPN's adv to complete sending. */
|
||||||
k_sleep(K_SECONDS(2));
|
k_sleep(K_SECONDS(2));
|
||||||
|
|
||||||
/* Send a segmented message to the friend. */
|
/* Send a segmented message to the friend. */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, 15, 0, K_FOREVER), "Send to LPN failed");
|
ASSERT_OK_MSG(bt_mesh_test_send(LPN_ADDR_START, NULL, 15, 0, K_FOREVER),
|
||||||
|
"Send to LPN failed");
|
||||||
|
|
||||||
/* Receive an unsegmented message from the LPN, originally sent with
|
/* Receive an unsegmented message from the LPN, originally sent with
|
||||||
* friend credentials.
|
* friend credentials.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, K_FOREVER), "Failed to receive from LPN");
|
ASSERT_OK_MSG(bt_mesh_test_recv(1, cfg->addr, NULL, K_FOREVER),
|
||||||
|
"Failed to receive from LPN");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
@ -874,20 +896,20 @@ static void test_other_msg(void)
|
||||||
*/
|
*/
|
||||||
static void test_other_group(void)
|
static void test_other_group(void)
|
||||||
{
|
{
|
||||||
uint16_t virtual_addr;
|
const struct bt_mesh_va *va;
|
||||||
|
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_va_add(test_va_uuid, &virtual_addr));
|
ASSERT_OK(bt_mesh_va_add(test_va_uuid, &va));
|
||||||
|
|
||||||
/* Wait for LPN to send us a message after establishing the friendship */
|
/* Wait for LPN to send us a message after establishing the friendship */
|
||||||
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, K_SECONDS(1)));
|
ASSERT_OK(bt_mesh_test_recv(5, cfg->addr, NULL, K_SECONDS(1)));
|
||||||
|
|
||||||
/* Send a group message to the LPN */
|
/* Send a group message to the LPN */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(GROUP_ADDR, NULL, 5, 0, K_SECONDS(1)),
|
||||||
"Failed to send to LPN");
|
"Failed to send to LPN");
|
||||||
/* Send a virtual message to the LPN */
|
/* Send a virtual message to the LPN */
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(virtual_addr, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(va->addr, va->uuid, 5, 0, K_SECONDS(1)),
|
||||||
"Failed to send to LPN");
|
"Failed to send to LPN");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
|
|
@ -134,7 +134,8 @@ static void test_ivu_deferring(void)
|
||||||
atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
|
atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
|
||||||
bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS;
|
bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS;
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_send_async(0x0002, 20, FORCE_SEGMENTATION, &async_send_cb, &sem));
|
ASSERT_OK(bt_mesh_test_send_async(0x0002, NULL, 20, FORCE_SEGMENTATION, &async_send_cb,
|
||||||
|
&sem));
|
||||||
ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
|
ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
|
||||||
ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
|
ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
|
||||||
|
|
||||||
|
|
|
@ -185,7 +185,7 @@ static void test_rx_invalid_packet(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify that test data is received correct. */
|
/* Verify that test data is received correct. */
|
||||||
err = bt_mesh_test_recv(10, cfg->addr, K_SECONDS(10));
|
err = bt_mesh_test_recv(10, cfg->addr, NULL, K_SECONDS(10));
|
||||||
ASSERT_OK_MSG(err, "Failed receiving with valid ad_type");
|
ASSERT_OK_MSG(err, "Failed receiving with valid ad_type");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
|
|
@ -6,8 +6,18 @@
|
||||||
#include "mesh_test.h"
|
#include "mesh_test.h"
|
||||||
#include "mesh/net.h"
|
#include "mesh/net.h"
|
||||||
#include "mesh/transport.h"
|
#include "mesh/transport.h"
|
||||||
|
#include "mesh/va.h"
|
||||||
#include <zephyr/sys/byteorder.h>
|
#include <zephyr/sys/byteorder.h>
|
||||||
|
|
||||||
|
#include "mesh/crypto.h"
|
||||||
|
|
||||||
|
#define LOG_MODULE_NAME test_transport
|
||||||
|
|
||||||
|
#include <zephyr/logging/log.h>
|
||||||
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
|
|
||||||
|
#include "common/bt_str.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Transport layer tests:
|
* Transport layer tests:
|
||||||
* This file contains tests for sending and receiving messages end-to-end in
|
* This file contains tests for sending and receiving messages end-to-end in
|
||||||
|
@ -121,7 +131,7 @@ static void test_tx_unicast(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_send(rx_cfg.addr, test_vector[i].len,
|
err = bt_mesh_test_send(rx_cfg.addr, NULL, test_vector[i].len,
|
||||||
test_vector[i].flags, K_SECONDS(10));
|
test_vector[i].flags, K_SECONDS(10));
|
||||||
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
||||||
}
|
}
|
||||||
|
@ -138,7 +148,7 @@ static void test_tx_group(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len,
|
err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len,
|
||||||
test_vector[i].flags, K_SECONDS(20));
|
test_vector[i].flags, K_SECONDS(20));
|
||||||
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
||||||
}
|
}
|
||||||
|
@ -150,19 +160,19 @@ static void test_tx_group(void)
|
||||||
*/
|
*/
|
||||||
static void test_tx_va(void)
|
static void test_tx_va(void)
|
||||||
{
|
{
|
||||||
uint16_t virtual_addr;
|
const struct bt_mesh_va *va;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
err = bt_mesh_va_add(test_va_uuid, &virtual_addr);
|
err = bt_mesh_va_add(test_va_uuid, &va);
|
||||||
ASSERT_OK_MSG(err, "Virtual addr add failed (err %d)", err);
|
ASSERT_OK_MSG(err, "Virtual addr add failed (err %d)", err);
|
||||||
|
|
||||||
/* Wait for the receiver to subscribe on address. */
|
/* Wait for the receiver to subscribe on address. */
|
||||||
k_sleep(K_SECONDS(1));
|
k_sleep(K_SECONDS(1));
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_send(virtual_addr, test_vector[i].len,
|
err = bt_mesh_test_send(va->addr, va->uuid, test_vector[i].len,
|
||||||
test_vector[i].flags, K_SECONDS(20));
|
test_vector[i].flags, K_SECONDS(20));
|
||||||
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
||||||
}
|
}
|
||||||
|
@ -179,10 +189,10 @@ static void test_tx_loopback(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_send(cfg->addr, test_vector[i].len, test_vector[i].flags,
|
err = bt_mesh_test_send(cfg->addr, NULL, test_vector[i].len, test_vector[i].flags,
|
||||||
K_NO_WAIT);
|
K_NO_WAIT);
|
||||||
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
ASSERT_OK_MSG(err, "Failed sending vector %d", i);
|
||||||
bt_mesh_test_recv(test_vector[i].len, cfg->addr, K_SECONDS(1));
|
bt_mesh_test_recv(test_vector[i].len, cfg->addr, NULL, K_SECONDS(1));
|
||||||
|
|
||||||
if (test_stats.received != i + 1) {
|
if (test_stats.received != i + 1) {
|
||||||
FAIL("Didn't receive message %d", i);
|
FAIL("Didn't receive message %d", i);
|
||||||
|
@ -219,10 +229,10 @@ static void test_tx_unknown_app(void)
|
||||||
|
|
||||||
test_send_ctx.app_idx = 1;
|
test_send_ctx.app_idx = 1;
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 5, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 5, 0, K_SECONDS(1)),
|
||||||
"Failed sending unsegmented");
|
"Failed sending unsegmented");
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, 25, 0, K_SECONDS(1)),
|
ASSERT_OK_MSG(bt_mesh_test_send(rx_cfg.addr, NULL, 25, 0, K_SECONDS(1)),
|
||||||
"Failed sending segmented");
|
"Failed sending segmented");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
@ -247,7 +257,7 @@ static void test_tx_loopback_group(void)
|
||||||
err, status);
|
err, status);
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_send(GROUP_ADDR, test_vector[i].len,
|
err = bt_mesh_test_send(GROUP_ADDR, NULL, test_vector[i].len,
|
||||||
test_vector[i].flags,
|
test_vector[i].flags,
|
||||||
K_SECONDS(20));
|
K_SECONDS(20));
|
||||||
|
|
||||||
|
@ -255,7 +265,7 @@ static void test_tx_loopback_group(void)
|
||||||
|
|
||||||
k_sleep(K_SECONDS(1));
|
k_sleep(K_SECONDS(1));
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR,
|
ASSERT_OK_MSG(bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR,
|
||||||
K_SECONDS(1)),
|
NULL, K_SECONDS(1)),
|
||||||
"Failed receiving loopback %d", i);
|
"Failed receiving loopback %d", i);
|
||||||
|
|
||||||
if (test_stats.received != i + 1) {
|
if (test_stats.received != i + 1) {
|
||||||
|
@ -277,11 +287,11 @@ static void test_tx_seg_block(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT));
|
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT));
|
||||||
|
|
||||||
/* Send some more to the same address before the first is finished. */
|
/* Send some more to the same address before the first is finished. */
|
||||||
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_NO_WAIT));
|
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_NO_WAIT));
|
||||||
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, 20, 0, K_SECONDS(10)));
|
ASSERT_OK(bt_mesh_test_send(rx_cfg.addr, NULL, 20, 0, K_SECONDS(10)));
|
||||||
|
|
||||||
if (test_stats.sent != 3) {
|
if (test_stats.sent != 3) {
|
||||||
FAIL("Not all messages completed (%u/3)", test_stats.sent);
|
FAIL("Not all messages completed (%u/3)", test_stats.sent);
|
||||||
|
@ -303,10 +313,10 @@ static void test_tx_seg_concurrent(void)
|
||||||
k_sem_init(&sem, 0, 1);
|
k_sem_init(&sem, 0, 1);
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 20, 0, &async_send_cb, &sem));
|
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 20, 0, &async_send_cb, &sem));
|
||||||
|
|
||||||
/* Send some more to the same address before the first is finished. */
|
/* Send some more to the same address before the first is finished. */
|
||||||
ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, 20, 0, K_SECONDS(10)));
|
ASSERT_OK(bt_mesh_test_send(GROUP_ADDR, NULL, 20, 0, K_SECONDS(10)));
|
||||||
|
|
||||||
/* Ensure that the first message finishes as well */
|
/* Ensure that the first message finishes as well */
|
||||||
ASSERT_OK(k_sem_take(&sem, K_SECONDS(1)));
|
ASSERT_OK(k_sem_take(&sem, K_SECONDS(1)));
|
||||||
|
@ -336,7 +346,7 @@ static void test_tx_seg_ivu(void)
|
||||||
|
|
||||||
iv_index = BT_MESH_NET_IVI_TX;
|
iv_index = BT_MESH_NET_IVI_TX;
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb,
|
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb,
|
||||||
&sem));
|
&sem));
|
||||||
/* Start IV update */
|
/* Start IV update */
|
||||||
bt_mesh_iv_update();
|
bt_mesh_iv_update();
|
||||||
|
@ -347,7 +357,7 @@ static void test_tx_seg_ivu(void)
|
||||||
|
|
||||||
k_sem_take(&sem, K_SECONDS(20));
|
k_sem_take(&sem, K_SECONDS(20));
|
||||||
|
|
||||||
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, 255, 0, &async_send_cb,
|
ASSERT_OK(bt_mesh_test_send_async(rx_cfg.addr, NULL, 255, 0, &async_send_cb,
|
||||||
&sem));
|
&sem));
|
||||||
|
|
||||||
/* End IV update */
|
/* End IV update */
|
||||||
|
@ -377,7 +387,7 @@ static void test_tx_seg_fail(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
expected_send_err = -ETIMEDOUT;
|
expected_send_err = -ETIMEDOUT;
|
||||||
ASSERT_OK(bt_mesh_test_send_async(0x0fff, 20, 0, &async_send_cb, &sem));
|
ASSERT_OK(bt_mesh_test_send_async(0x0fff, NULL, 20, 0, &async_send_cb, &sem));
|
||||||
ASSERT_OK(k_sem_take(&sem, K_SECONDS(10)));
|
ASSERT_OK(k_sem_take(&sem, K_SECONDS(10)));
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
|
@ -396,7 +406,7 @@ static void test_rx_unicast(void)
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_recv(test_vector[i].len, cfg->addr,
|
err = bt_mesh_test_recv(test_vector[i].len, cfg->addr,
|
||||||
K_SECONDS(10));
|
NULL, K_SECONDS(10));
|
||||||
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +428,7 @@ static void test_rx_group(void)
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR,
|
err = bt_mesh_test_recv(test_vector[i].len, GROUP_ADDR,
|
||||||
K_SECONDS(20));
|
NULL, K_SECONDS(20));
|
||||||
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,7 +451,7 @@ static void test_rx_va(void)
|
||||||
|
|
||||||
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
|
||||||
err = bt_mesh_test_recv(test_vector[i].len, virtual_addr,
|
err = bt_mesh_test_recv(test_vector[i].len, virtual_addr,
|
||||||
K_SECONDS(20));
|
test_va_uuid, K_SECONDS(20));
|
||||||
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
ASSERT_OK_MSG(err, "Failed receiving vector %d", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,9 +481,9 @@ static void test_rx_seg_block(void)
|
||||||
{
|
{
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
@ -496,8 +506,8 @@ static void test_rx_seg_concurrent(void)
|
||||||
* Note: The receive order is technically irrelevant, but the test_recv
|
* Note: The receive order is technically irrelevant, but the test_recv
|
||||||
* function fails if the order is wrong.
|
* function fails if the order is wrong.
|
||||||
*/
|
*/
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, K_SECONDS(2)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(20, cfg->addr, NULL, K_SECONDS(2)), "RX fail");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, K_SECONDS(2)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(20, GROUP_ADDR, NULL, K_SECONDS(2)), "RX fail");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
@ -509,8 +519,8 @@ static void test_rx_seg_ivu(void)
|
||||||
bt_mesh_test_setup();
|
bt_mesh_test_setup();
|
||||||
rx_sar_conf();
|
rx_sar_conf();
|
||||||
|
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail");
|
||||||
ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, K_SECONDS(5)), "RX fail");
|
ASSERT_OK_MSG(bt_mesh_test_recv(255, cfg->addr, NULL, K_SECONDS(5)), "RX fail");
|
||||||
|
|
||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue