zephyr/subsys/bluetooth/mesh/settings.c
Krzysztof Kopyściński d0995541fb Bluetooth: Mesh: add implementation for Proxy Solicitation
This is initial implementation of Proxy solicitation procedure.
This includes:
- support for sending and receiving Solicitation PDUs
- On-Demand Private Proxy functionality (Server and Client) controlling
  behaviour of node after receiving Solicitation PDU
- Solicitation PDU RPL Configuration (Server and Client), which manages
  Replay Protection List for Solicitation PDUs.

Proxy Solicitation allows to enable advertising of Proxy service on node
by sending Solicitation PDUs. These PDUs are not part of Mesh messages;
instead, these are non-connectable, undirected advertising PDUs with
their own format, containing Proxy Solicitation UUID.

Signed-off-by: Krzysztof Kopyściński <krzysztof.kopyscinski@codecoup.pl>
2023-03-06 13:52:15 +01:00

240 lines
6.3 KiB
C

/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <errno.h>
#include <sys/types.h>
#include <zephyr/sys/util.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/settings/settings.h>
#include "host/hci_core.h"
#include "mesh.h"
#include "subnet.h"
#include "app_keys.h"
#include "net.h"
#include "cdb.h"
#include "crypto.h"
#include "rpl.h"
#include "transport.h"
#include "heartbeat.h"
#include "access.h"
#include "proxy.h"
#include "pb_gatt_srv.h"
#include "settings.h"
#include "cfg.h"
#include "solicitation.h"
#define LOG_LEVEL CONFIG_BT_MESH_SETTINGS_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_mesh_settings);
#ifdef CONFIG_BT_MESH_RPL_STORE_TIMEOUT
#define RPL_STORE_TIMEOUT CONFIG_BT_MESH_RPL_STORE_TIMEOUT
#else
#define RPL_STORE_TIMEOUT (-1)
#endif
static struct k_work_delayable pending_store;
static ATOMIC_DEFINE(pending_flags, BT_MESH_SETTINGS_FLAG_COUNT);
int bt_mesh_settings_set(settings_read_cb read_cb, void *cb_arg,
void *out, size_t read_len)
{
ssize_t len;
len = read_cb(cb_arg, out, read_len);
if (len < 0) {
LOG_ERR("Failed to read value (err %zd)", len);
return len;
}
LOG_HEXDUMP_DBG(out, len, "val");
if (len != read_len) {
LOG_ERR("Unexpected value length (%zd != %zu)", len, read_len);
return -EINVAL;
}
return 0;
}
static int mesh_commit(void)
{
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_INIT)) {
return 0;
}
if (!atomic_test_bit(bt_dev.flags, BT_DEV_ENABLE)) {
/* The Bluetooth mesh settings loader calls bt_mesh_start() immediately
* after loading the settings. This is not intended to work before
* bt_enable(). The doc on @ref bt_enable requires the "bt/" settings
* tree to be loaded after @ref bt_enable is completed, so this handler
* will be called again later.
*/
return 0;
}
if (!bt_mesh_subnet_next(NULL)) {
/* Nothing to do since we're not yet provisioned */
return 0;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
(void)bt_mesh_pb_gatt_srv_disable();
}
bt_mesh_net_settings_commit();
bt_mesh_model_settings_commit();
atomic_set_bit(bt_mesh.flags, BT_MESH_VALID);
bt_mesh_start();
return 0;
}
SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, NULL, mesh_commit,
NULL);
/* Pending flags that use K_NO_WAIT as the storage timeout */
#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_PENDING) | \
BIT(BT_MESH_SETTINGS_IV_PENDING) | \
BIT(BT_MESH_SETTINGS_SEQ_PENDING) | \
BIT(BT_MESH_SETTINGS_CDB_PENDING))
/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */
#define GENERIC_PENDING_BITS (BIT(BT_MESH_SETTINGS_NET_KEYS_PENDING) | \
BIT(BT_MESH_SETTINGS_APP_KEYS_PENDING) | \
BIT(BT_MESH_SETTINGS_HB_PUB_PENDING) | \
BIT(BT_MESH_SETTINGS_CFG_PENDING) | \
BIT(BT_MESH_SETTINGS_MOD_PENDING) | \
BIT(BT_MESH_SETTINGS_VA_PENDING) | \
BIT(BT_MESH_SETTINGS_SSEQ_PENDING))
void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
{
uint32_t timeout_ms, remaining_ms;
atomic_set_bit(pending_flags, flag);
if (atomic_get(pending_flags) & NO_WAIT_PENDING_BITS) {
timeout_ms = 0;
} else if (IS_ENABLED(CONFIG_BT_MESH_RPL_STORAGE_MODE_SETTINGS) && RPL_STORE_TIMEOUT >= 0 &&
(atomic_test_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING) ||
atomic_test_bit(pending_flags, BT_MESH_SETTINGS_SRPL_PENDING)) &&
!(atomic_get(pending_flags) & GENERIC_PENDING_BITS)) {
timeout_ms = RPL_STORE_TIMEOUT * MSEC_PER_SEC;
} else {
timeout_ms = CONFIG_BT_MESH_STORE_TIMEOUT * MSEC_PER_SEC;
}
remaining_ms = k_ticks_to_ms_floor32(k_work_delayable_remaining_get(&pending_store));
LOG_DBG("Waiting %u ms vs rem %u ms", timeout_ms, remaining_ms);
/* If the new deadline is sooner, override any existing
* deadline; otherwise schedule without changing any existing
* deadline.
*/
if (timeout_ms < remaining_ms) {
k_work_reschedule(&pending_store, K_MSEC(timeout_ms));
} else {
k_work_schedule(&pending_store, K_MSEC(timeout_ms));
}
}
void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)
{
atomic_clear_bit(pending_flags, flag);
}
static void store_pending(struct k_work *work)
{
LOG_DBG("");
if (IS_ENABLED(CONFIG_BT_MESH_RPL_STORAGE_MODE_SETTINGS) &&
atomic_test_and_clear_bit(pending_flags, BT_MESH_SETTINGS_RPL_PENDING)) {
bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_NET_KEYS_PENDING)) {
bt_mesh_subnet_pending_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_APP_KEYS_PENDING)) {
bt_mesh_app_key_pending_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_NET_PENDING)) {
bt_mesh_net_pending_net_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_IV_PENDING)) {
bt_mesh_net_pending_iv_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_SEQ_PENDING)) {
bt_mesh_net_pending_seq_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_HB_PUB_PENDING)) {
bt_mesh_hb_pub_pending_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_CFG_PENDING)) {
bt_mesh_cfg_pending_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_MOD_PENDING)) {
bt_mesh_model_pending_store();
}
if (atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_VA_PENDING)) {
bt_mesh_va_pending_store();
}
if (IS_ENABLED(CONFIG_BT_MESH_CDB) &&
atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_CDB_PENDING)) {
bt_mesh_cdb_pending_store();
}
if (IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) &&
atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_SRPL_PENDING)) {
bt_mesh_srpl_pending_store();
}
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) &&
atomic_test_and_clear_bit(pending_flags,
BT_MESH_SETTINGS_SSEQ_PENDING)) {
bt_mesh_sseq_pending_store();
}
}
void bt_mesh_settings_init(void)
{
k_work_init_delayable(&pending_store, store_pending);
}
void bt_mesh_settings_store_pending(void)
{
(void)k_work_cancel_delayable(&pending_store);
store_pending(&pending_store.work);
}