Skip to content

Commit

Permalink
Bluetooth: Mesh: Adds subnet bridge states
Browse files Browse the repository at this point in the history
`brg_cfg` module implements the states needed for subnet bridge
feature. It provides two states - enable state, and bridging table
state. APIs are provided to access the states.

Signed-off-by: Omkar Kulkarni <[email protected]>
  • Loading branch information
omkar3141 committed Jul 5, 2024
1 parent 470c0d1 commit 90e8505
Show file tree
Hide file tree
Showing 11 changed files with 877 additions and 2 deletions.
2 changes: 1 addition & 1 deletion subsys/bluetooth/mesh/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV sol_pdu_rpl_srv.c)

zephyr_library_sources_ifdef(CONFIG_BT_MESH_BRG_CFG_CLI brg_cfg_cli.c)

zephyr_library_sources_ifdef(CONFIG_BT_MESH_BRG_CFG_SRV brg_cfg_srv.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_BRG_CFG_SRV brg_cfg_srv.c brg_cfg.c)

zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c)

Expand Down
12 changes: 12 additions & 0 deletions subsys/bluetooth/mesh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,18 @@ config BT_MESH_BRG_CFG_SRV
The Bridge Configuration Server model is used to support the configuration
of the subnet bridge functionality of a node.

menu "Subnet Bridge configuration"
visible if BT_MESH_BRG_CFG_SRV

config BT_MESH_BRG_TABLE_ITEMS_MAX
int "Maximum number of entries in the bridging table"
default 16
range 16 255
help
The maximum number of entries in the bridging table.

endmenu

config BT_MESH_BRG_CFG_CLI
bool "Support for Bridge Configuration Client model"
help
Expand Down
317 changes: 317 additions & 0 deletions subsys/bluetooth/mesh/brg_cfg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

/* Implimentation for Bridging Table state of Subnet Bridge feature
* in Bluetooth Mesh Protocol v1.1 specification
*/

#include <zephyr/kernel.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <zephyr/sys/atomic.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/net/buf.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/mesh.h>

#include "mesh.h"
#include "net.h"
#include "subnet.h"
#include "settings.h"
#include "brg_cfg.h"

#define LOG_LEVEL CONFIG_BT_MESH_NET_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_mesh_brg_cfg);

/* Bridging table state. Each item is a slist node. */
static struct brg_tbl_row brg_tbl[CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX];
static uint32_t brg_tbl_row_cnt;
static bool brg_enabled;

static void brg_tbl_compact(void)
{
int j = 0;

for (int k = 0; k < brg_tbl_row_cnt; k++) {
if (brg_tbl[k].direction != 0) {
brg_tbl[j] = brg_tbl[k];
j++;
}
}
memset(&brg_tbl[j], 0, sizeof(brg_tbl[j]));
brg_tbl_row_cnt--;
}

#if IS_ENABLED(CONFIG_BT_SETTINGS)
static int brgen_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
{
int err;

if (len_rd == 0) {
brg_enabled = 0;
LOG_DBG("Cleared bridge enable state");
return 0;
}

err = bt_mesh_settings_set(read_cb, cb_arg, &brg_enabled, sizeof(brg_enabled));
if (err) {
LOG_ERR("Failed to set bridge enable state");
return err;
}

LOG_DBG("Restored sbren");

return 0;
}

/* Define a setting for storing enable state */
BT_MESH_SETTINGS_DEFINE(brgen, "brgen", brgen_set);

/* Set function for initializing bridging table rows from brg_tbl slist */
static int brg_tbl_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *cb_arg)
{
if (len_rd == 0) {
memset(brg_tbl, 0, sizeof(brg_tbl));
brg_tbl_row_cnt = 0;
LOG_DBG("Cleared bridging table entries");
return 0;
}

int err = bt_mesh_settings_set(read_cb, cb_arg, &brg_tbl, sizeof(brg_tbl));

if (err) {
LOG_ERR("Failed to set bridging table entries");
return err;
}

LOG_DBG("Restored brg_tbl");

return 0;
}

/* Define a setting for storing briging table rows */
BT_MESH_SETTINGS_DEFINE(brgbt, "brgbt", brg_tbl_set);
#endif

bool brg_cfg_enable_get(void)
{
return brg_enabled;
}

int brg_cfg_enable_set(bool enable)
{
if (brg_enabled == enable) {
return 0;
}

brg_enabled = enable;
#if IS_ENABLED(CONFIG_BT_SETTINGS)
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_BRG_PENDING);
#endif
return 0;
}

void bt_mesh_brg_en_pending_store(void)
{
#if CONFIG_BT_SETTINGS
char *path = "bt/mesh/brgen";
int err;

if (brg_enabled) {
err = settings_save_one(path, &brg_enabled, sizeof(brg_enabled));
} else {
err = settings_delete(path);
}

if (err) {
LOG_ERR("Failed to store %s value", path);
}
#endif
}

void bt_mesh_brg_tbl_pending_store(void)
{
#if CONFIG_BT_SETTINGS
char *path = "bt/mesh/brgbt";
char path_bt[20];
int err;

if (!brg_tbl_row_cnt) {
err = settings_save_one(path, &brg_tbl, brg_tbl_row_cnt * sizeof(brg_tbl[0]));
} else {
err = settings_delete(path);
}

if (err) {
LOG_ERR("Failed to store %s value", path_bt);
}
#endif
}

/* Remove the entry from the bridging table that corresponds with the netkey index
* of the removed subnet.
*/
static void brg_tbl_netkey_removed_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
for (int i = 0; i < CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX; i++) {
if (brg_tbl[i].direction && (
brg_tbl[i].net_idx1 == sub->net_idx ||
brg_tbl[i].net_idx2 == sub->net_idx)) {
memset(&brg_tbl[i], 0, sizeof(brg_tbl[i]));
brg_tbl_compact();
}
}

#if IS_ENABLED(CONFIG_BT_SETTINGS)
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_BRG_PENDING);
#endif
}

/* Add event hook for key deletion event */
BT_MESH_SUBNET_CB_DEFINE(sbr) = {
.evt_handler = brg_tbl_netkey_removed_evt,
};

int brg_cfg_init(void)
{
memset(brg_tbl, 0, sizeof(brg_tbl));
brg_tbl_row_cnt = 0;
return 0;
}

int brg_cfg_tbl_reset(void)
{
brg_cfg_init();

int err = settings_delete("bt/mesh/brgen");

if (err) {
return err;
}
err = settings_delete("bt/mesh/brgbt");

return err;
}

int brg_cfg_tbl_get(const struct brg_tbl_row **rows)
{
*rows = brg_tbl;
return brg_tbl_row_cnt;
}

int brg_cfg_tbl_add(enum brg_tbl_direction direction, uint16_t net_idx1, uint16_t net_idx2,
uint16_t addr1, uint16_t addr2)
{
/* Sanity check */
if (!BT_MESH_ADDR_IS_UNICAST(addr1) || net_idx1 == net_idx2 || addr1 == addr2 ||
net_idx1 > 0x03FF || net_idx2 > 0x03FF ||
(direction != BRG_ADDR1_TO_ADDR2 && direction != BRG_ADDR1_TF_ADDR2) ||
(direction == BRG_ADDR1_TO_ADDR2 &&
(addr2 == BT_MESH_ADDR_UNASSIGNED || addr2 == BT_MESH_ADDR_ALL_NODES)) ||
(direction == BRG_ADDR1_TF_ADDR2 && !BT_MESH_ADDR_IS_UNICAST(addr2))) {
return -EINVAL;
}

/* Check if entry already exists, if yes, then it is success. */
for (int i = 0; i < brg_tbl_row_cnt; i++) {
if (brg_tbl[i].direction == direction && brg_tbl[i].net_idx1 == net_idx1 &&
brg_tbl[i].net_idx2 == net_idx2 && brg_tbl[i].addr1 == addr1 &&
brg_tbl[i].addr2 == addr2) {
return 0;
}
}

/* Empty element, is the current table row counter */
if (brg_tbl_row_cnt == CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX) {
return -ENOMEM;
}

/* Update the row */
brg_tbl[brg_tbl_row_cnt].direction = direction;
brg_tbl[brg_tbl_row_cnt].net_idx1 = net_idx1;
brg_tbl[brg_tbl_row_cnt].net_idx2 = net_idx2;
brg_tbl[brg_tbl_row_cnt].addr1 = addr1;
brg_tbl[brg_tbl_row_cnt].addr2 = addr2;
brg_tbl_row_cnt++;

#if IS_ENABLED(CONFIG_BT_SETTINGS)
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_BRG_PENDING);
#endif

return 0;
}

static int itr;

int brg_cfg_tbl_check_start(void)
{
itr = 0;

if (!brg_tbl_row_cnt) {
return -ENOENT;
}

return 0;
}

int brg_cfg_tbl_check_itr(uint16_t src, uint16_t dst, uint16_t netidx, uint16_t *new_netidx)
{
/* Iterate over items */
*new_netidx = BRG_NETIDX_NOMATCH;
if (itr >= brg_tbl_row_cnt) {
return -ENOENT;
}

if ((brg_tbl[itr].direction == 1 || brg_tbl[itr].direction == 2) &&
brg_tbl[itr].net_idx1 == netidx && brg_tbl[itr].addr1 == src &&
brg_tbl[itr].addr2 == dst) {
*new_netidx = brg_tbl[itr].net_idx2;
goto exititr;
}

if (brg_tbl[itr].direction == 2 &&
brg_tbl[itr].net_idx2 == netidx && brg_tbl[itr].addr2 == src &&
brg_tbl[itr].addr1 == dst) {
*new_netidx = brg_tbl[itr].net_idx1;
goto exititr;
}

exititr:
itr++;
return 0;
}

int brg_cfg_tbl_remove(uint16_t net_idx1, uint16_t net_idx2, uint16_t addr1, uint16_t addr2)
{
/* Iterate over items and set matching row to 0, if nothing exist, or
* nopthing matches, then it is success.
*/
if (brg_tbl_row_cnt == 0) {
return 0;
}

for (int i = 0; i < brg_tbl_row_cnt; i++) {
if (brg_tbl[i].direction && brg_tbl[i].net_idx1 == net_idx1 &&
brg_tbl[i].net_idx2 == net_idx2 && brg_tbl[i].addr1 == addr1 &&
brg_tbl[i].addr2 == addr2) {
memset(&brg_tbl[i], 0, sizeof(brg_tbl[i]));
brg_tbl_compact();
#if IS_ENABLED(CONFIG_BT_SETTINGS)
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_BRG_PENDING);
#endif

return 0;
}
}

return 0;
}
Loading

0 comments on commit 90e8505

Please sign in to comment.