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 4, 2024
1 parent 470c0d1 commit 12dc649
Show file tree
Hide file tree
Showing 9 changed files with 800 additions and 1 deletion.
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
284 changes: 284 additions & 0 deletions subsys/bluetooth/mesh/brg_cfg.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
/*
* 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--;
}

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 brgen");
return 0;
}

err = bt_mesh_settings_set(read_cb, cb_arg, &brg_enabled, sizeof(brg_enabled));
if (err) {
LOG_ERR("Failed to set brgen");
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));
LOG_DBG("Cleared brg_tbl");
return 0;
}

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

if (err) {
LOG_ERR("Failed to set brg_tbl");
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);

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;

bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SBR_PENDING);

return 0;
}

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

err = settings_save_one(path, &brg_enabled, sizeof(brg_enabled));

if (err) {
LOG_ERR("Failed to %s SSeq %s value",
(brg_enabled == 0 ? "delete" : "store"), path);
} else {
LOG_DBG("%s %s value", (brg_enabled == 0 ? "Deleted" : "Stored"), path);
}
#endif
}

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

err = settings_save_one(path, &brg_tbl, brg_tbl_row_cnt * sizeof(brg_tbl[0]));

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 sbr_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].netidx1 == sub->net_idx ||
brg_tbl[i].netidx2 == sub->net_idx)) {
memset(&brg_tbl[i], 0, sizeof(brg_tbl[i]));
brg_tbl_compact();
}
}

bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SBR_PENDING);
}

/* Add event hook for key deletion event */
BT_MESH_SUBNET_CB_DEFINE(sbr) = {
.evt_handler = sbr_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;
}

const struct brg_tbl_row *brg_cfg_tbl_get(void)
{
return brg_tbl;
}

int brg_cfg_tbl_add(enum brg_tbl_direction direction, uint16_t netidx1, uint16_t netidx2,
uint16_t addr1, uint16_t addr2)
{
/* Sanity check */
if (!BT_MESH_ADDR_IS_UNICAST(addr1) || netidx1 == netidx2 || addr1 == addr2 ||
netidx1 > 0x03FF || netidx2 > 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].netidx1 == netidx1 &&
brg_tbl[i].netidx2 == netidx2 && 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].netidx1 = netidx1;
brg_tbl[brg_tbl_row_cnt].netidx2 = netidx2;
brg_tbl[brg_tbl_row_cnt].addr1 = addr1;
brg_tbl[brg_tbl_row_cnt].addr2 = addr2;
brg_tbl_row_cnt++;

bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SBR_PENDING);

return 0;
}

int brg_cfg_tbl_check(uint16_t src, uint16_t dst, uint16_t netidx, uint16_t *new_netidx)
{
/* Iterate over items */
for (int i = 0; i < brg_tbl_row_cnt; i++) {
if ((brg_tbl[i].direction == 1 || brg_tbl[i].direction == 2) &&
brg_tbl[i].netidx1 == netidx && brg_tbl[i].addr1 == src &&
brg_tbl[i].addr2 == dst) {
*new_netidx = brg_tbl[i].netidx2;
return 0;
}

if (brg_tbl[i].direction == 2 &&
brg_tbl[i].netidx2 == netidx && brg_tbl[i].addr2 == src &&
brg_tbl[i].addr1 == dst) {
*new_netidx = brg_tbl[i].netidx1;
return 0;
}
}

return -ENOENT;
}

int brg_cfg_tbl_remove(uint16_t netidx1, uint16_t netidx2, 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].netidx1 == netidx1 &&
brg_tbl[i].netidx2 == netidx2 && brg_tbl[i].addr1 == addr1 &&
brg_tbl[i].addr2 == addr2) {
memset(&brg_tbl[i], 0, sizeof(brg_tbl[i]));
brg_tbl_compact();
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SBR_PENDING);

return 0;
}
}

return 0;
}
49 changes: 49 additions & 0 deletions subsys/bluetooth/mesh/brg_cfg.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_BRG_CFG_H_
#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_BRG_CFG_H_

#include <stdint.h>
#include <sys/types.h>
#include <zephyr/kernel.h>

/** These are internal APIs. They do not sanitize input params. */

enum brg_tbl_direction {
BRG_PROHIBITED = 0,
BRG_ADDR1_TO_ADDR2 = 1,
BRG_ADDR1_TF_ADDR2 = 2,
BRG_RFU_MAX = 3,
};

/* One row of the bridging table */
struct brg_tbl_row {
/* Direction of the entry in the bridging table
* 0 - no entry,
* 1 - bridge messages with src as addr1 and dst as addr2
* 2 - bridge messages with src as addr1 and dst as addr2 and vice-versa
*/
uint32_t direction:8;
uint32_t netidx1:12;
uint32_t netidx2:12;
uint16_t addr1;
uint16_t addr2;
};

bool brg_cfg_enable_get(void);
int brg_cfg_enable_set(bool enable);
void bt_mesh_brg_en_pending_store(void);
void bt_mesh_brg_tbl_pending_store(void);
int brg_cfg_init(void);
int brg_cfg_tbl_reset(void);
int brg_cfg_tbl_add(enum brg_tbl_direction direction, uint16_t netidx1, uint16_t netidx2,
uint16_t addr1, uint16_t addr2);
int brg_cfg_tbl_remove(uint16_t netidx1, uint16_t netidx2, uint16_t addr1, uint16_t addr2);
int brg_cfg_tbl_check(uint16_t src, uint16_t dst, uint16_t netidx, uint16_t *new_netidx);
int brg_cfg_tbl_reset(void);

#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_BRG_CFG_H_ */
10 changes: 9 additions & 1 deletion subsys/bluetooth/mesh/settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, NULL, mesh_commit,
BIT(BT_MESH_SETTINGS_VA_PENDING) | \
BIT(BT_MESH_SETTINGS_SSEQ_PENDING) | \
BIT(BT_MESH_SETTINGS_COMP_PENDING) | \
BIT(BT_MESH_SETTINGS_DEV_KEY_CAND_PENDING))
BIT(BT_MESH_SETTINGS_DEV_KEY_CAND_PENDING) | \
BIT(BT_MESH_SETTINGS_SBR_PENDING))

void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
{
Expand Down Expand Up @@ -262,6 +263,13 @@ static void store_pending(struct k_work *work)
BT_MESH_SETTINGS_SSEQ_PENDING)) {
bt_mesh_sseq_pending_store();
}

if (IS_ENABLED(CONFIG_BT_MESH_BRG_CFG_SRV) &&
atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_SBR_PENDING)) {
bt_mesh_brg_en_pending_store();
bt_mesh_brg_tbl_pending_store();
}
}

void bt_mesh_settings_init(void)
Expand Down
1 change: 1 addition & 0 deletions subsys/bluetooth/mesh/settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ enum bt_mesh_settings_flag {
BT_MESH_SETTINGS_SSEQ_PENDING,
BT_MESH_SETTINGS_COMP_PENDING,
BT_MESH_SETTINGS_DEV_KEY_CAND_PENDING,
BT_MESH_SETTINGS_SBR_PENDING,

BT_MESH_SETTINGS_FLAG_COUNT,
};
Expand Down
Loading

0 comments on commit 12dc649

Please sign in to comment.