Bluetooth: Mesh: Private Beacons
Adds support for private beacon sending and receiving. Co-authored-by: Krzysztof Kopyściński <krzysztof.kopyscinski@codecoup.pl> Co-authored-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no> Signed-off-by: Trond Einar Snekvik <Trond.Einar.Snekvik@nordicsemi.no> Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
parent
e2086c22bc
commit
f9b19010ed
26 changed files with 1711 additions and 125 deletions
|
@ -6,7 +6,7 @@ Mesh models
|
|||
Foundation models
|
||||
*****************
|
||||
|
||||
The Bluetooth mesh specification defines four foundation models that can be
|
||||
The Bluetooth mesh specification defines six foundation models that can be
|
||||
used by network administrators to configure and diagnose mesh nodes.
|
||||
|
||||
.. toctree::
|
||||
|
@ -16,11 +16,13 @@ used by network administrators to configure and diagnose mesh nodes.
|
|||
cfg_cli
|
||||
health_srv
|
||||
health_cli
|
||||
priv_beacon_srv
|
||||
priv_beacon_cli
|
||||
|
||||
Model specification models
|
||||
**************************
|
||||
|
||||
In addition to the Foundation models defined in the Bluetooth Mesh specification, the Bluetooth Mesh Model specification defines several models, some of which are implemented in Zephyr:
|
||||
In addition to the foundation models defined in the Bluetooth mesh specification, the Bluetooth Mesh Model Specification defines several models, some of which are implemented in Zephyr:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
|
36
doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst
Normal file
36
doc/connectivity/bluetooth/api/mesh/priv_beacon_cli.rst
Normal file
|
@ -0,0 +1,36 @@
|
|||
.. _bluetooth_mesh_models_priv_beacon_cli:
|
||||
|
||||
Private Beacon Client
|
||||
#####################
|
||||
|
||||
The Private Beacon Client model is a foundation model defined by the Bluetooth
|
||||
mesh specification. It is enabled with the
|
||||
:kconfig:option:`CONFIG_BT_MESH_PRIV_BEACON_CLI` option.
|
||||
|
||||
The Private Beacon Client model is introduced in the Bluetooth Mesh Profile
|
||||
Specification version 1.1, and provides functionality for configuring the
|
||||
:ref:`bluetooth_mesh_models_priv_beacon_srv` models.
|
||||
|
||||
The Private Beacons feature adds privacy to the different Bluetooth mesh
|
||||
beacons by periodically randomizing the beacon input data. This protects the
|
||||
mesh node from being tracked by devices outside the mesh network, and hides the
|
||||
network's IV index, IV update and the Key Refresh state.
|
||||
|
||||
The Private Beacon Client model communicates with a
|
||||
:ref:`bluetooth_mesh_models_priv_beacon_srv` model using the device key of the
|
||||
target node. The Private Beacon Client model may communicate with servers on
|
||||
other nodes or self-configure through the local Private Beacon Server model.
|
||||
|
||||
All configuration functions in the Private Beacon Client API have ``net_idx``
|
||||
and ``addr`` as their first parameters. These should be set to the network
|
||||
index and the primary unicast address the target node was provisioned with.
|
||||
|
||||
The Private Beacon Client model is optional, and can be instantiated on any
|
||||
element.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_priv_beacon_cli
|
||||
:project: Zephyr
|
||||
:members:
|
39
doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst
Normal file
39
doc/connectivity/bluetooth/api/mesh/priv_beacon_srv.rst
Normal file
|
@ -0,0 +1,39 @@
|
|||
.. _bluetooth_mesh_models_priv_beacon_srv:
|
||||
|
||||
Private Beacon Server
|
||||
#####################
|
||||
|
||||
The Private Beacon Server model is a foundation model defined by the Bluetooth
|
||||
mesh specification. It is enabled with
|
||||
:kconfig:option:`CONFIG_BT_MESH_PRIV_BEACON_SRV` option.
|
||||
|
||||
The Private Beacon Server model is introduced in the Bluetooth Mesh Profile
|
||||
Specification version 1.1, and controls the mesh node's Private Beacon state,
|
||||
Private GATT Proxy state and Private Node Identity state.
|
||||
|
||||
The Private Beacons feature adds privacy to the different Bluetooth mesh
|
||||
beacons by periodically randomizing the beacon input data. This protects the
|
||||
mesh node from being tracked by devices outside the mesh network, and hides the
|
||||
network's IV index, IV update and the Key Refresh state. The Private Beacon Server
|
||||
must be instantiated for the device to support sending of the private beacons,
|
||||
but the node will process received private beacons without it.
|
||||
|
||||
The Private Beacon Server does not have an API of its own, but relies on a
|
||||
:ref:`bluetooth_mesh_models_priv_beacon_cli` to control it. The Private Beacon
|
||||
Server model only accepts messages encrypted with the node's device key.
|
||||
|
||||
The application can configure the initial parameters of the Private Beacon
|
||||
Server model through the :c:struct:`bt_mesh_priv_beacon_srv` instance passed to
|
||||
:c:macro:`BT_MESH_MODEL_PRIV_BEACON_SRV`. Note that if the mesh node stored
|
||||
changes to this configuration in the settings subsystem, the initial values may
|
||||
be overwritten upon loading.
|
||||
|
||||
The Private Beacon Server model is optional, and can only be instantiated in the
|
||||
node's primary element.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_priv_beacon_srv
|
||||
:project: Zephyr
|
||||
:members:
|
|
@ -25,6 +25,8 @@
|
|||
#include <zephyr/bluetooth/mesh/health_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/blob_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/blob_io_flash.h>
|
||||
#include <zephyr/bluetooth/mesh/priv_beacon_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/priv_beacon_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/dfu_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/dfd_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/dfu_cli.h>
|
||||
|
|
|
@ -128,6 +128,8 @@ struct bt_mesh_elem {
|
|||
#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003
|
||||
#define BT_MESH_MODEL_ID_REMOTE_PROV_SRV 0x0004
|
||||
#define BT_MESH_MODEL_ID_REMOTE_PROV_CLI 0x0005
|
||||
#define BT_MESH_MODEL_ID_PRIV_BEACON_SRV 0x000a
|
||||
#define BT_MESH_MODEL_ID_PRIV_BEACON_CLI 0x000b
|
||||
#define BT_MESH_MODEL_ID_SAR_CFG_SRV 0x000e
|
||||
#define BT_MESH_MODEL_ID_SAR_CFG_CLI 0x000f
|
||||
#define BT_MESH_MODEL_ID_LARGE_COMP_DATA_SRV 0x0012
|
||||
|
|
|
@ -49,10 +49,17 @@ enum bt_mesh_feat_state {
|
|||
#define BT_MESH_BEACON_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_BEACON_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
|
||||
#define BT_MESH_PRIV_BEACON_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_PRIV_BEACON_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
|
||||
#define BT_MESH_GATT_PROXY_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_GATT_PROXY_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_GATT_PROXY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
#define BT_MESH_PRIV_GATT_PROXY_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_PRIV_GATT_PROXY_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_PRIV_GATT_PROXY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
||||
#define BT_MESH_FRIEND_DISABLED BT_MESH_FEATURE_DISABLED
|
||||
#define BT_MESH_FRIEND_ENABLED BT_MESH_FEATURE_ENABLED
|
||||
#define BT_MESH_FRIEND_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
|
||||
|
@ -73,6 +80,50 @@ void bt_mesh_beacon_set(bool beacon);
|
|||
*/
|
||||
bool bt_mesh_beacon_enabled(void);
|
||||
|
||||
/** @brief Enable or disable sending of the Mesh Private beacon.
|
||||
*
|
||||
* Support for the Private beacon state must be enabled with @c
|
||||
* CONFIG_BT_MESH_PRIV_BEACONS.
|
||||
*
|
||||
* @param priv_beacon New Mesh Private beacon state. Must be one of
|
||||
* @ref BT_MESH_FEATURE_ENABLED and
|
||||
* @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval 0 Successfully changed the Mesh Private beacon feature state.
|
||||
* @retval -ENOTSUP The Mesh Private beacon feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already in the given state.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_set(enum bt_mesh_feat_state priv_beacon);
|
||||
|
||||
/** @brief Get the current Mesh Private beacon state.
|
||||
*
|
||||
* @returns The Mesh Private beacon feature state.
|
||||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_priv_beacon_get(void);
|
||||
|
||||
/** @brief Set the current Mesh Private beacon update interval.
|
||||
*
|
||||
* The Mesh Private beacon's randomization value is updated regularly to
|
||||
* maintain the node's privacy. The update interval controls how often
|
||||
* the beacon is updated, in 10 second increments.
|
||||
*
|
||||
* @param interval Private beacon update interval in 10 second steps, or 0 to
|
||||
* update on every beacon transmission.
|
||||
*/
|
||||
void bt_mesh_priv_beacon_update_interval_set(uint8_t interval);
|
||||
|
||||
/** @brief Get the current Mesh Private beacon update interval.
|
||||
*
|
||||
* The Mesh Private beacon's randomization value is updated regularly to
|
||||
* maintain the node's privacy. The update interval controls how often
|
||||
* the beacon is updated, in 10 second increments.
|
||||
*
|
||||
* @returns The Private beacon update interval in 10 second steps, or 0 if
|
||||
* the beacon is updated every time it's transmitted.
|
||||
*/
|
||||
uint8_t bt_mesh_priv_beacon_update_interval_get(void);
|
||||
|
||||
/** @brief Set the default TTL value.
|
||||
*
|
||||
* The default TTL value is used when no explicit TTL value is set. Models will
|
||||
|
@ -181,6 +232,29 @@ int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy);
|
|||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void);
|
||||
|
||||
/** @brief Enable or disable the Private GATT Proxy feature.
|
||||
*
|
||||
* Support for the Private GATT Proxy feature must be enabled through the
|
||||
* @kconfig{CONFIG_BT_MESH_PRIV_BEACONS} and @kconfig{CONFIG_BT_MESH_GATT_PROXY}
|
||||
* configuration options.
|
||||
*
|
||||
* @param priv_gatt_proxy New Private GATT Proxy state. Must be one of
|
||||
* @ref BT_MESH_FEATURE_ENABLED and
|
||||
* @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval 0 Successfully changed the Private GATT Proxy feature state.
|
||||
* @retval -ENOTSUP The Private GATT Proxy feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already in the given state.
|
||||
*/
|
||||
int bt_mesh_priv_gatt_proxy_set(enum bt_mesh_feat_state priv_gatt_proxy);
|
||||
|
||||
/** @brief Get the current Private GATT Proxy state.
|
||||
*
|
||||
* @returns The Private GATT Proxy feature state.
|
||||
*/
|
||||
enum bt_mesh_feat_state bt_mesh_priv_gatt_proxy_get(void);
|
||||
|
||||
/** @brief Enable or disable the Friend feature.
|
||||
*
|
||||
* Any active friendships will be terminated immediately if the Friend feature
|
||||
|
@ -341,6 +415,45 @@ uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx,
|
|||
uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state *node_id);
|
||||
|
||||
/** @brief Set the Private Node Identity state of the Subnet.
|
||||
*
|
||||
* The Private Node Identity state of a Subnet determines whether the Subnet
|
||||
* advertises connectable Private Node Identity beacons for Proxy Clients to
|
||||
* connect to. Once started, the Node Identity beacon runs for 60 seconds,
|
||||
* or until it is stopped.
|
||||
*
|
||||
* Private Node Identity can only be enabled if regular Node Identity is not
|
||||
* enabled for any subnet.
|
||||
*
|
||||
* GATT Proxy and Private Beacon support must be enabled through
|
||||
* @kconfig{CONFIG_BT_MESH_GATT_PROXY} and
|
||||
* @kconfig{CONFIG_BT_MESH_PRIV_BEACONS}.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param priv_node_id New Private Node Identity state, must be either @ref
|
||||
* BT_MESH_FEATURE_ENABLED or @ref BT_MESH_FEATURE_DISABLED.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Successfully set the Private Node Identity state of the Subnet.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
* @retval STATUS_FEAT_NOT_SUPP The Private Node Identity feature is not supported.
|
||||
* @retval STATUS_TEMP_STATE_CHG_FAIL The Private Node Identity state cannot be enabled, because
|
||||
* Node Identity state is already enabled.
|
||||
* @retval STATUS_CANNOT_SET Couldn't set the Private Node Identity state.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_priv_node_id_set(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state priv_node_id);
|
||||
|
||||
/** @brief Get the Private Node Identity state of the Subnet.
|
||||
*
|
||||
* @param net_idx Network index.
|
||||
* @param priv_node_id Private Node Identity variable to fill.
|
||||
*
|
||||
* @retval STATUS_SUCCESS Successfully populated the @c priv_node_id variable.
|
||||
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
|
||||
*/
|
||||
uint8_t bt_mesh_subnet_priv_node_id_get(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state *priv_node_id);
|
||||
|
||||
/** @brief Get a list of all known Subnet indexes.
|
||||
*
|
||||
* Builds a list of all known Subnet indexes in the @c net_idxs array.
|
||||
|
|
145
include/zephyr/bluetooth/mesh/priv_beacon_cli.h
Normal file
145
include/zephyr/bluetooth/mesh/priv_beacon_cli.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_priv_beacon_cli Bluetooth Mesh Private Beacon Client
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_CLI_H__
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_CLI_H__
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Private Beacon Client model composition data entry.
|
||||
*
|
||||
* @param cli_data Pointer to a @ref bt_mesh_priv_beacon_cli instance.
|
||||
*/
|
||||
#define BT_MESH_MODEL_PRIV_BEACON_CLI(cli_data) \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_PRIV_BEACON_CLI, \
|
||||
bt_mesh_priv_beacon_cli_op, NULL, cli_data, \
|
||||
&bt_mesh_priv_beacon_cli_cb)
|
||||
|
||||
/** Mesh Private Beacon Client model */
|
||||
struct bt_mesh_priv_beacon_cli {
|
||||
/** Timeout value in milliseconds. */
|
||||
int32_t timeout;
|
||||
struct bt_mesh_model *mod;
|
||||
|
||||
/* Internal parameters for tracking message responses. */
|
||||
struct bt_mesh_msg_ack_ctx ack_ctx;
|
||||
};
|
||||
|
||||
/** Private Beacon */
|
||||
struct bt_mesh_priv_beacon {
|
||||
/** Private beacon is enabled */
|
||||
uint8_t enabled;
|
||||
/** Random refresh interval (in 10 second steps), or 0 to keep current
|
||||
* value.
|
||||
*/
|
||||
uint8_t rand_interval;
|
||||
};
|
||||
|
||||
/** Private Node Identity */
|
||||
struct bt_mesh_priv_node_id {
|
||||
/** Index of the NetKey. */
|
||||
uint16_t net_idx;
|
||||
/** Private Node Identity state */
|
||||
uint8_t state;
|
||||
/** Response status code. */
|
||||
uint8_t status;
|
||||
};
|
||||
|
||||
/** @brief Set the target's Private Beacon state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param val New Private Beacon value. Returns response status on success.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr,
|
||||
struct bt_mesh_priv_beacon *val);
|
||||
|
||||
/** @brief Get the target's Private Beacon state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param val Response buffer for Private Beacon value.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr,
|
||||
struct bt_mesh_priv_beacon *val);
|
||||
|
||||
/** @brief Set the target's Private GATT Proxy state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param val New Private GATT Proxy value. Returns response status on
|
||||
* success.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr,
|
||||
uint8_t *val);
|
||||
|
||||
/** @brief Get the target's Private GATT Proxy state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param val Response buffer for Private GATT Proxy value.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr,
|
||||
uint8_t *val);
|
||||
|
||||
/** @brief Set the target's Private Node Identity state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param val New Private Node Identity value. Returns response status on
|
||||
* success.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr,
|
||||
struct bt_mesh_priv_node_id *val);
|
||||
|
||||
/** @brief Get the target's Private Node Identity state.
|
||||
*
|
||||
* @param net_idx Network index to encrypt with.
|
||||
* @param addr Target node address.
|
||||
* @param key_net_idx Network index to get the Private Node Identity state of.
|
||||
* @param val Response buffer for Private Node Identity value.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx, uint16_t addr,
|
||||
uint16_t key_net_idx,
|
||||
struct bt_mesh_priv_node_id *val);
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op bt_mesh_priv_beacon_cli_op[];
|
||||
extern const struct bt_mesh_model_cb bt_mesh_priv_beacon_cli_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_CLI_H__ */
|
||||
|
||||
/** @} */
|
43
include/zephyr/bluetooth/mesh/priv_beacon_srv.h
Normal file
43
include/zephyr/bluetooth/mesh/priv_beacon_srv.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_priv_beacon_srv Bluetooth Mesh Private Beacon Server
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_SRV_H__
|
||||
#define ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_SRV_H__
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Private Beacon Server model composition data entry.
|
||||
*/
|
||||
#define BT_MESH_MODEL_PRIV_BEACON_SRV \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_PRIV_BEACON_SRV, \
|
||||
bt_mesh_priv_beacon_srv_op, NULL, NULL, \
|
||||
&bt_mesh_priv_beacon_srv_cb)
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op bt_mesh_priv_beacon_srv_op[];
|
||||
extern const struct bt_mesh_model_cb bt_mesh_priv_beacon_srv_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_PRIV_BEACON_SRV_H__ */
|
||||
|
||||
/** @} */
|
|
@ -62,6 +62,16 @@ struct bt_mesh_proxy_cb {
|
|||
*/
|
||||
int bt_mesh_proxy_identity_enable(void);
|
||||
|
||||
/** @brief Enable advertising with Private Node Identity.
|
||||
*
|
||||
* This API requires that GATT Proxy support has been enabled. Once called
|
||||
* each subnet will start advertising using Private Node Identity for the next
|
||||
* 60 seconds.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code on failure.
|
||||
*/
|
||||
int bt_mesh_proxy_private_identity_enable(void);
|
||||
|
||||
/** @brief Allow Proxy Client to auto connect to a network.
|
||||
*
|
||||
* This API allows a proxy client to auto-connect a given network.
|
||||
|
|
|
@ -73,6 +73,10 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_LARGE_COMP_DATA_SRV large_comp_data
|
|||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_LARGE_COMP_DATA_CLI large_comp_data_cli.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PRIV_BEACON_SRV priv_beacon_srv.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PRIV_BEACON_CLI priv_beacon_cli.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SELF_TEST test.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_CDB cdb.c)
|
||||
|
|
|
@ -446,6 +446,7 @@ config BT_MESH_ADV_STACK_SIZE
|
|||
int "Mesh advertiser thread stack size"
|
||||
depends on BT_MESH_ADV_LEGACY
|
||||
default 1024 if BT_HOST_CRYPTO
|
||||
default 776 if BT_MESH_PRIV_BEACONS
|
||||
default 768
|
||||
help
|
||||
Size of bt mesh adv thread stack.
|
||||
|
@ -1212,6 +1213,26 @@ config BT_MESH_LARGE_COMP_DATA_CLI
|
|||
help
|
||||
Enable support for the Large Composition Data Client model.
|
||||
|
||||
config BT_MESH_PRIV_BEACONS
|
||||
bool "Support for private beacons"
|
||||
default y
|
||||
help
|
||||
Enable support for private beacons.
|
||||
|
||||
if BT_MESH_PRIV_BEACONS
|
||||
|
||||
config BT_MESH_PRIV_BEACON_SRV
|
||||
bool "Support for Private Beacon Server Model"
|
||||
help
|
||||
Enable support for the Private Beacon Server model.
|
||||
|
||||
config BT_MESH_PRIV_BEACON_CLI
|
||||
bool "Support for Private Beacon Client Model"
|
||||
help
|
||||
Enable support for the Private Beacon Client model.
|
||||
|
||||
endif # BT_MESH_PRIV_BEACONS
|
||||
|
||||
menu "Transport SAR configuration"
|
||||
|
||||
config BT_MESH_SAR_TX_SEG_INT_STEP
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <errno.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
|
||||
#include <zephyr/net/buf.h>
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
|
@ -22,7 +23,7 @@
|
|||
#include "prov.h"
|
||||
#include "crypto.h"
|
||||
#include "beacon.h"
|
||||
#include "foundation.h"
|
||||
#include "cfg.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_BEACON_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -32,6 +33,7 @@ LOG_MODULE_REGISTER(bt_mesh_beacon);
|
|||
|
||||
#define BEACON_TYPE_UNPROVISIONED 0x00
|
||||
#define BEACON_TYPE_SECURE 0x01
|
||||
#define BEACON_TYPE_PRIVATE 0x02
|
||||
|
||||
/* 3 transmissions, 20ms interval */
|
||||
#define UNPROV_XMIT BT_MESH_TRANSMIT(2, 20)
|
||||
|
@ -40,20 +42,39 @@ LOG_MODULE_REGISTER(bt_mesh_beacon);
|
|||
#define PROV_XMIT BT_MESH_TRANSMIT(0, 20)
|
||||
|
||||
static struct k_work_delayable beacon_timer;
|
||||
static struct {
|
||||
/**
|
||||
* Identifier for the current Private beacon random-value.
|
||||
* Each time we regenerate the random-value, we'll update this idx.
|
||||
* Whenever it's time for a subnet to create a beacon, it'll compare
|
||||
* the subnet's beacon idx to determine whether the random value has
|
||||
* changed since the last beacon was sent. If this is the case, we'll
|
||||
* regenerate the beacon based on the new random value.
|
||||
*/
|
||||
uint16_t idx;
|
||||
uint8_t val[13];
|
||||
uint64_t timestamp;
|
||||
} priv_random;
|
||||
|
||||
static bool beacon_cache_match(struct bt_mesh_subnet *sub, void *beacon_data)
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
static int private_beacon_create(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf);
|
||||
static int private_beacon_update(struct bt_mesh_subnet *sub);
|
||||
#endif
|
||||
|
||||
static bool beacon_cache_match(struct bt_mesh_subnet *sub, void *auth)
|
||||
{
|
||||
return !memcmp(sub->beacon_cache, beacon_data, 21);
|
||||
return !memcmp(sub->beacon_cache, auth, sizeof(sub->beacon_cache));
|
||||
}
|
||||
|
||||
static void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub)
|
||||
static void cache_add(const uint8_t auth[8], struct bt_mesh_subnet *sub)
|
||||
{
|
||||
memcpy(sub->beacon_cache, data, 21);
|
||||
memcpy(sub->beacon_cache, auth, sizeof(sub->beacon_cache));
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_cache_clear(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
(void)memset(sub->beacon_cache, 0, 21);
|
||||
(void)memset(sub->beacon_cache, 0, sizeof(sub->beacon_cache));
|
||||
}
|
||||
|
||||
static void beacon_complete(int err, void *user_data)
|
||||
|
@ -65,7 +86,7 @@ static void beacon_complete(int err, void *user_data)
|
|||
sub->beacon_sent = k_uptime_get_32();
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
||||
static void secure_beacon_create(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t flags = bt_mesh_net_flags(sub);
|
||||
|
@ -90,11 +111,99 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
|||
LOG_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, bt_hex(sub->auth, 8));
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
static int private_random_update(void)
|
||||
{
|
||||
uint8_t interval = bt_mesh_priv_beacon_update_interval_get();
|
||||
uint64_t uptime = k_uptime_get();
|
||||
int err;
|
||||
|
||||
/* The Private beacon random value should change every N seconds to maintain privacy.
|
||||
* N = (10 * interval) seconds, or on every beacon creation, if the interval is 0.
|
||||
*/
|
||||
if (interval &&
|
||||
uptime - priv_random.timestamp < (10 * interval * MSEC_PER_SEC)) {
|
||||
/* Not time yet */
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = bt_rand(priv_random.val, sizeof(priv_random.val));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Update the index to indicate to all subnets that the private beacon must be regenerated.
|
||||
* Each subnet maintains the random index their private beacon data was generated with.
|
||||
*/
|
||||
priv_random.idx++;
|
||||
priv_random.timestamp = uptime;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int private_beacon_update(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
struct bt_mesh_subnet_keys *keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
|
||||
uint8_t flags = bt_mesh_net_flags(sub);
|
||||
int err;
|
||||
|
||||
err = bt_mesh_beacon_encrypt(keys->priv_beacon, flags, bt_mesh.iv_index,
|
||||
priv_random.val, sub->priv_beacon.data,
|
||||
sub->auth);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
sub->priv_beacon.idx = priv_random.idx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int private_beacon_create(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* Refresh beacon data */
|
||||
err = private_random_update();
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (sub->priv_beacon.idx != priv_random.idx) {
|
||||
err = private_beacon_update(sub);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
net_buf_simple_add_u8(buf, BEACON_TYPE_PRIVATE);
|
||||
net_buf_simple_add_mem(buf, priv_random.val, 13);
|
||||
net_buf_simple_add_mem(buf, sub->priv_beacon.data, 5);
|
||||
net_buf_simple_add_mem(buf, sub->auth, 8);
|
||||
|
||||
LOG_DBG("0x%03x", sub->net_idx);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
if (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED) {
|
||||
return private_beacon_create(sub, buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
secure_beacon_create(sub, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the interval has passed or is within 5 seconds from now send a beacon */
|
||||
#define BEACON_THRESHOLD(sub) \
|
||||
((10 * ((sub)->beacons_last + 1)) * MSEC_PER_SEC - (5 * MSEC_PER_SEC))
|
||||
|
||||
static bool secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
static bool net_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
static const struct bt_mesh_send_cb send_cb = {
|
||||
.end = beacon_complete,
|
||||
|
@ -103,6 +212,7 @@ static bool secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
|
|||
struct net_buf *buf;
|
||||
uint32_t time_diff;
|
||||
uint32_t time_since_last_recv;
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
|
@ -121,7 +231,10 @@ static bool secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
|
|||
return true; /* Bail out */
|
||||
}
|
||||
|
||||
bt_mesh_beacon_create(sub, &buf->b);
|
||||
err = bt_mesh_beacon_create(sub, &buf->b);
|
||||
if (err) {
|
||||
return true; /* Bail out */
|
||||
}
|
||||
|
||||
bt_mesh_adv_send(buf, &send_cb, sub);
|
||||
net_buf_unref(buf);
|
||||
|
@ -242,18 +355,24 @@ static void update_beacon_observation(void)
|
|||
bt_mesh_subnet_foreach(sub_update_beacon_observation);
|
||||
}
|
||||
|
||||
static bool net_beacon_is_running(void)
|
||||
{
|
||||
return bt_mesh_beacon_enabled() ||
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) ||
|
||||
(bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED);
|
||||
}
|
||||
|
||||
static void beacon_send(struct k_work *work)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
if (!bt_mesh_beacon_enabled() &&
|
||||
!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) {
|
||||
if (!net_beacon_is_running()) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_beacon_observation();
|
||||
(void)bt_mesh_subnet_find(secure_beacon_send, NULL);
|
||||
(void)bt_mesh_subnet_find(net_beacon_send, NULL);
|
||||
|
||||
k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL);
|
||||
return;
|
||||
|
@ -271,7 +390,13 @@ static void beacon_send(struct k_work *work)
|
|||
}
|
||||
|
||||
struct beacon_params {
|
||||
union {
|
||||
const uint8_t *net_id;
|
||||
struct {
|
||||
const uint8_t *data;
|
||||
const uint8_t *random;
|
||||
} private;
|
||||
};
|
||||
const uint8_t *auth;
|
||||
uint32_t iv_index;
|
||||
uint8_t flags;
|
||||
|
@ -300,7 +425,7 @@ static bool auth_match(struct bt_mesh_subnet_keys *keys,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool subnet_by_id(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
static bool secure_beacon_authenticate(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
struct beacon_params *params = cb_data;
|
||||
|
||||
|
@ -314,74 +439,128 @@ static bool subnet_by_id(struct bt_mesh_subnet *sub, void *cb_data)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
struct beacon_params *params = cb_data;
|
||||
uint8_t out[5];
|
||||
int err;
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) {
|
||||
if (!sub->keys[i].valid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = bt_mesh_beacon_decrypt(sub->keys[i].priv_beacon,
|
||||
params->private.random,
|
||||
params->private.data, params->auth,
|
||||
out);
|
||||
if (!err) {
|
||||
params->new_key = (i > 0);
|
||||
params->flags = out[0];
|
||||
params->iv_index = sys_get_be32(&out[1]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void net_beacon_register(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
if (bt_mesh_beacon_enabled() && sub->beacons_cur < 0xff) {
|
||||
sub->beacons_cur++;
|
||||
sub->beacon_recv = k_uptime_get_32();
|
||||
}
|
||||
}
|
||||
|
||||
static void net_beacon_recv(struct bt_mesh_subnet *sub,
|
||||
const struct beacon_params *params)
|
||||
{
|
||||
bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params->flags),
|
||||
params->new_key);
|
||||
|
||||
/* If we have NetKey0 accept IV index initiation only from it */
|
||||
if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
|
||||
sub->net_idx != BT_MESH_KEY_PRIMARY) {
|
||||
LOG_WRN("Ignoring secure beacon on non-primary subnet");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("net_idx 0x%04x flags %u iv_index 0x%08x, "
|
||||
"current iv_index 0x%08x",
|
||||
sub->net_idx, params->flags, params->iv_index, bt_mesh.iv_index);
|
||||
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
|
||||
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
|
||||
BT_MESH_IV_UPDATE(params->flags))) {
|
||||
bt_mesh_beacon_ivu_initiator(false);
|
||||
}
|
||||
|
||||
bt_mesh_net_iv_update(params->iv_index,
|
||||
BT_MESH_IV_UPDATE(params->flags));
|
||||
}
|
||||
|
||||
static void net_beacon_resolve(struct beacon_params *params,
|
||||
bool (*matcher)(struct bt_mesh_subnet *sub,
|
||||
void *cb_data))
|
||||
{
|
||||
struct bt_mesh_subnet *sub;
|
||||
|
||||
sub = bt_mesh_subnet_find(beacon_cache_match, (void *)params->auth);
|
||||
if (sub) {
|
||||
/* We've seen this beacon before - just update the stats */
|
||||
net_beacon_register(sub);
|
||||
return;
|
||||
}
|
||||
|
||||
sub = bt_mesh_subnet_find(matcher, params);
|
||||
if (!sub) {
|
||||
LOG_DBG("No subnet that matched beacon");
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params->new_key) {
|
||||
LOG_WRN("Ignoring Phase 2 KR Update secured using old key");
|
||||
return;
|
||||
}
|
||||
|
||||
cache_add(params->auth, sub);
|
||||
|
||||
net_beacon_recv(sub, params);
|
||||
net_beacon_register(sub);
|
||||
}
|
||||
|
||||
static void secure_beacon_recv(struct net_buf_simple *buf)
|
||||
{
|
||||
struct beacon_params params;
|
||||
struct bt_mesh_subnet *sub;
|
||||
uint8_t *data;
|
||||
|
||||
if (buf->len < 21) {
|
||||
LOG_ERR("Too short secure beacon (len %u)", buf->len);
|
||||
return;
|
||||
}
|
||||
|
||||
sub = bt_mesh_subnet_find(beacon_cache_match, buf->data);
|
||||
if (sub) {
|
||||
/* We've seen this beacon before - just update the stats */
|
||||
goto update_stats;
|
||||
}
|
||||
|
||||
/* So we can add to the cache if auth matches */
|
||||
data = buf->data;
|
||||
|
||||
params.flags = net_buf_simple_pull_u8(buf);
|
||||
params.net_id = net_buf_simple_pull_mem(buf, 8);
|
||||
params.iv_index = net_buf_simple_pull_be32(buf);
|
||||
params.auth = buf->data;
|
||||
|
||||
LOG_DBG("flags 0x%02x id %s iv_index 0x%08x", params.flags, bt_hex(params.net_id, 8),
|
||||
params.iv_index);
|
||||
net_beacon_resolve(¶ms, secure_beacon_authenticate);
|
||||
}
|
||||
|
||||
sub = bt_mesh_subnet_find(subnet_by_id, ¶ms);
|
||||
if (!sub) {
|
||||
LOG_DBG("No subnet that matched beacon");
|
||||
static void private_beacon_recv(struct net_buf_simple *buf)
|
||||
{
|
||||
struct beacon_params params;
|
||||
|
||||
if (buf->len < 26) {
|
||||
LOG_ERR("Too short private beacon (len %u)", buf->len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params.new_key) {
|
||||
LOG_WRN("Ignoring Phase 2 KR Update secured using old key");
|
||||
return;
|
||||
}
|
||||
params.private.random = net_buf_simple_pull_mem(buf, 13);
|
||||
params.private.data = net_buf_simple_pull_mem(buf, 5);
|
||||
params.auth = buf->data;
|
||||
|
||||
cache_add(data, sub);
|
||||
|
||||
bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params.flags),
|
||||
params.new_key);
|
||||
|
||||
/* If we have NetKey0 accept initiation only from it */
|
||||
if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
|
||||
sub->net_idx != BT_MESH_KEY_PRIMARY) {
|
||||
LOG_WRN("Ignoring secure beacon on non-primary subnet");
|
||||
goto update_stats;
|
||||
}
|
||||
|
||||
LOG_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x", sub->net_idx,
|
||||
params.iv_index, bt_mesh.iv_index);
|
||||
|
||||
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
|
||||
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
|
||||
BT_MESH_IV_UPDATE(params.flags))) {
|
||||
bt_mesh_beacon_ivu_initiator(false);
|
||||
}
|
||||
|
||||
bt_mesh_net_iv_update(params.iv_index, BT_MESH_IV_UPDATE(params.flags));
|
||||
|
||||
update_stats:
|
||||
if (bt_mesh_beacon_enabled() &&
|
||||
sub->beacons_cur < 0xff) {
|
||||
sub->beacons_cur++;
|
||||
sub->beacon_recv = k_uptime_get_32();
|
||||
}
|
||||
net_beacon_resolve(¶ms, priv_beacon_decrypt);
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_recv(struct net_buf_simple *buf)
|
||||
|
@ -405,6 +584,9 @@ void bt_mesh_beacon_recv(struct net_buf_simple *buf)
|
|||
case BEACON_TYPE_SECURE:
|
||||
secure_beacon_recv(buf);
|
||||
break;
|
||||
case BEACON_TYPE_PRIVATE:
|
||||
private_beacon_recv(buf);
|
||||
break;
|
||||
default:
|
||||
LOG_WRN("Unknown beacon type 0x%02x", type);
|
||||
break;
|
||||
|
@ -415,7 +597,6 @@ void bt_mesh_beacon_update(struct bt_mesh_subnet *sub)
|
|||
{
|
||||
uint8_t flags = bt_mesh_net_flags(sub);
|
||||
struct bt_mesh_subnet_keys *keys;
|
||||
int err;
|
||||
|
||||
keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
|
||||
|
||||
|
@ -423,11 +604,13 @@ void bt_mesh_beacon_update(struct bt_mesh_subnet *sub)
|
|||
SUBNET_KEY_TX_IDX(sub) ? "new" : "current");
|
||||
LOG_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index);
|
||||
|
||||
err = bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id,
|
||||
bt_mesh.iv_index, sub->auth);
|
||||
if (err) {
|
||||
LOG_ERR("Failed updating net beacon for 0x%03x", sub->net_idx);
|
||||
}
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
/* Invalidate private beacon to force regeneration: */
|
||||
sub->priv_beacon.idx = priv_random.idx - 1;
|
||||
#endif
|
||||
|
||||
bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index,
|
||||
sub->auth);
|
||||
}
|
||||
|
||||
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
|
||||
|
@ -444,6 +627,10 @@ BT_MESH_SUBNET_CB_DEFINE(beacon) = {
|
|||
void bt_mesh_beacon_init(void)
|
||||
{
|
||||
k_work_init_delayable(&beacon_timer, beacon_send);
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
private_random_update();
|
||||
#endif
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_ivu_initiator(bool enable)
|
||||
|
@ -481,8 +668,12 @@ void bt_mesh_beacon_enable(void)
|
|||
|
||||
void bt_mesh_beacon_disable(void)
|
||||
{
|
||||
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) {
|
||||
/* If this fails, we'll do an early exit in the work handler. */
|
||||
(void)k_work_cancel_delayable(&beacon_timer);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_beacon_priv_random_get(uint8_t *random, size_t size)
|
||||
{
|
||||
__ASSERT(size <= sizeof(priv_random.val), "Invalid random value size %u", size);
|
||||
memcpy(random, priv_random.val, size);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,9 @@ void bt_mesh_beacon_ivu_initiator(bool enable);
|
|||
|
||||
void bt_mesh_beacon_recv(struct net_buf_simple *buf);
|
||||
|
||||
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
||||
int bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
|
||||
struct net_buf_simple *buf);
|
||||
|
||||
void bt_mesh_beacon_init(void);
|
||||
void bt_mesh_beacon_update(struct bt_mesh_subnet *sub);
|
||||
void bt_mesh_beacon_priv_random_get(uint8_t *random, size_t size);
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
#include "settings.h"
|
||||
#include "heartbeat.h"
|
||||
#include "friend.h"
|
||||
#include "cfg.h"
|
||||
#include "adv.h"
|
||||
#include "cfg.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_CFG_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -30,6 +30,10 @@ struct cfg_val {
|
|||
uint8_t gatt_proxy;
|
||||
uint8_t frnd;
|
||||
uint8_t default_ttl;
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
uint8_t priv_beacon;
|
||||
uint8_t priv_beacon_int;
|
||||
#endif
|
||||
};
|
||||
|
||||
void bt_mesh_beacon_set(bool beacon)
|
||||
|
@ -82,6 +86,58 @@ static enum bt_mesh_feat_state feature_get(int feature_flag)
|
|||
BT_MESH_FEATURE_DISABLED;
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_set(enum bt_mesh_feat_state priv_beacon)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
err = feature_set(BT_MESH_PRIV_BEACON, priv_beacon);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (priv_beacon == BT_MESH_FEATURE_ENABLED) {
|
||||
bt_mesh_beacon_enable();
|
||||
} else if (bt_mesh_beacon_enabled()) {
|
||||
bt_mesh_beacon_disable();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum bt_mesh_feat_state bt_mesh_priv_beacon_get(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return BT_MESH_FEATURE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return feature_get(BT_MESH_PRIV_BEACON);
|
||||
}
|
||||
|
||||
void bt_mesh_priv_beacon_update_interval_set(uint8_t interval)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
bt_mesh.priv_beacon_int = interval;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_priv_beacon_update_interval_get(void)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
return bt_mesh.priv_beacon_int;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool node_id_is_running(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
return sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING;
|
||||
|
@ -125,6 +181,42 @@ enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void)
|
|||
return feature_get(BT_MESH_GATT_PROXY);
|
||||
}
|
||||
|
||||
int bt_mesh_priv_gatt_proxy_set(enum bt_mesh_feat_state priv_gatt_proxy)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) || !IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return BT_MESH_FEATURE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
err = feature_set(BT_MESH_PRIV_GATT_PROXY, priv_gatt_proxy);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (priv_gatt_proxy == BT_MESH_FEATURE_ENABLED) {
|
||||
/* Re-generate proxy beacon */
|
||||
bt_mesh_adv_gatt_update();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
|
||||
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_CFG_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum bt_mesh_feat_state bt_mesh_priv_gatt_proxy_get(void)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) || !IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return BT_MESH_FEATURE_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return feature_get(BT_MESH_PRIV_GATT_PROXY);
|
||||
}
|
||||
|
||||
|
||||
int bt_mesh_default_ttl_set(uint8_t default_ttl)
|
||||
{
|
||||
if (default_ttl == 1 || default_ttl > BT_MESH_TTL_MAX) {
|
||||
|
@ -349,6 +441,11 @@ static void store_pending_cfg(void)
|
|||
val.gatt_proxy = bt_mesh_gatt_proxy_get();
|
||||
val.frnd = bt_mesh_friend_get();
|
||||
val.default_ttl = bt_mesh_default_ttl_get();
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
val.priv_beacon = bt_mesh_priv_beacon_get();
|
||||
val.priv_beacon_int = bt_mesh_priv_beacon_update_interval_get();
|
||||
#endif
|
||||
|
||||
|
||||
err = settings_save_one("bt/mesh/Cfg", &val, sizeof(val));
|
||||
if (err) {
|
||||
|
|
|
@ -546,6 +546,13 @@ static int gatt_proxy_set(struct bt_mesh_model *model,
|
|||
|
||||
(void)bt_mesh_gatt_proxy_set(buf->data[0]);
|
||||
|
||||
/** 4.2.46.1: If the value of the Node Identity state of the node for any subnet is 0x01,
|
||||
* then the value of the Private Node Identity state shall be Disable (0x00).
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS) && buf->data[0]) {
|
||||
(void)bt_mesh_priv_gatt_proxy_set(BT_MESH_FEATURE_DISABLED);
|
||||
}
|
||||
|
||||
return send_gatt_proxy_status(model, ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -702,3 +702,126 @@ int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t *
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int private_beacon_obf(const uint8_t pbk[16], const uint8_t data[5],
|
||||
const uint8_t random[13], uint8_t out[5])
|
||||
{
|
||||
uint8_t salt[16];
|
||||
int i, err;
|
||||
|
||||
/* C1 = 0x01 | random | 0x0001 */
|
||||
salt[0] = 0x01;
|
||||
memcpy(&salt[1], random, 13);
|
||||
sys_put_be16(0x0001, &salt[14]);
|
||||
|
||||
/* ObfData = e(pbk, C1) ^ (flags | iv_index) */
|
||||
err = bt_encrypt_be(pbk, salt, salt);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
out[i] = data[i] ^ salt[i];
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int private_beacon_auth(const uint8_t pbk[16],
|
||||
const uint8_t beacon_data[5],
|
||||
const uint8_t random[13], uint8_t auth[8])
|
||||
{
|
||||
uint8_t salt[16], tmp[16];
|
||||
int i, err;
|
||||
|
||||
/* B0 = 0x19 | random | 0x0005 */
|
||||
salt[0] = 0x19;
|
||||
memcpy(&salt[1], random, 13);
|
||||
sys_put_be16(0x0005, &salt[14]);
|
||||
|
||||
/* T0 = e(PBK, b0) */
|
||||
err = bt_encrypt_be(pbk, salt, tmp);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* P = flags | iv_index | 000 */
|
||||
/* T1 = e(PBK, P ^ T0) */
|
||||
for (i = 0; i < 5; i++) {
|
||||
tmp[i] ^= beacon_data[i];
|
||||
}
|
||||
|
||||
err = bt_encrypt_be(pbk, tmp, tmp);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* C0 = 0x01 | random | 0x0000 */
|
||||
salt[0] = 0x01;
|
||||
sys_put_be16(0x0000, &salt[14]);
|
||||
|
||||
/* T2 = T1 ^ e(PBK, C0) */
|
||||
memcpy(auth, tmp, 8);
|
||||
|
||||
err = bt_encrypt_be(pbk, salt, tmp);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Auth = T2[0..7] */
|
||||
for (i = 0; i < 8; i++) {
|
||||
auth[i] ^= tmp[i];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_mesh_beacon_decrypt(const uint8_t pbk[16], const uint8_t random[13],
|
||||
const uint8_t data[5],
|
||||
const uint8_t expected_auth[8], uint8_t out[5])
|
||||
{
|
||||
uint8_t auth[8];
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
err = private_beacon_obf(pbk, data, random, out);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = private_beacon_auth(pbk, out, random, auth);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("0x%02x, 0x%08x", out[0], sys_get_be32(&out[1]));
|
||||
|
||||
if (memcmp(auth, expected_auth, 8)) {
|
||||
LOG_DBG("Invalid auth: %s expected %s", bt_hex(auth, 8),
|
||||
bt_hex(expected_auth, 8));
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_mesh_beacon_encrypt(const uint8_t pbk[16], uint8_t flags,
|
||||
uint32_t iv_index, const uint8_t random[13],
|
||||
uint8_t data[5], uint8_t auth[8])
|
||||
{
|
||||
int err;
|
||||
|
||||
LOG_WRN("Enc beacon: 0x%02x, 0x%08x", flags, iv_index);
|
||||
|
||||
data[0] = flags;
|
||||
sys_put_be32(iv_index, &data[1]);
|
||||
|
||||
err = private_beacon_auth(pbk, data, random, auth);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return private_beacon_obf(pbk, data, random, data);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,12 @@ static inline int bt_mesh_beacon_key(const uint8_t net_key[16],
|
|||
return bt_mesh_id128(net_key, "nkbk", beacon_key);
|
||||
}
|
||||
|
||||
static inline int bt_mesh_private_beacon_key(const uint8_t net_key[16],
|
||||
uint8_t private_beacon_key[16])
|
||||
{
|
||||
return bt_mesh_id128(net_key, "nkpk", private_beacon_key);
|
||||
}
|
||||
|
||||
int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags,
|
||||
const uint8_t net_id[8], uint32_t iv_index,
|
||||
uint8_t auth[8]);
|
||||
|
@ -150,3 +156,10 @@ int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13],
|
|||
const uint8_t data[25], uint8_t out[25 + 8]);
|
||||
|
||||
int bt_mesh_dhkey_gen(const uint8_t *pub_key, const uint8_t *priv_key, uint8_t *dhkey);
|
||||
|
||||
int bt_mesh_beacon_decrypt(const uint8_t pbk[16], const uint8_t random[13],
|
||||
const uint8_t data[5], const uint8_t expected_auth[8],
|
||||
uint8_t out[5]);
|
||||
|
||||
int bt_mesh_beacon_encrypt(const uint8_t pbk[16], uint8_t flags, uint32_t iv_index,
|
||||
const uint8_t random[13], uint8_t data[5], uint8_t auth[8]);
|
||||
|
|
|
@ -102,6 +102,16 @@
|
|||
#define OP_MODELS_METADATA_GET BT_MESH_MODEL_OP_2(0x80, 0x76)
|
||||
#define OP_MODELS_METADATA_STATUS BT_MESH_MODEL_OP_2(0x80, 0x77)
|
||||
|
||||
#define OP_PRIV_BEACON_GET BT_MESH_MODEL_OP_2(0x80, 0x60)
|
||||
#define OP_PRIV_BEACON_SET BT_MESH_MODEL_OP_2(0x80, 0x61)
|
||||
#define OP_PRIV_BEACON_STATUS BT_MESH_MODEL_OP_2(0x80, 0x62)
|
||||
#define OP_PRIV_GATT_PROXY_GET BT_MESH_MODEL_OP_2(0x80, 0x63)
|
||||
#define OP_PRIV_GATT_PROXY_SET BT_MESH_MODEL_OP_2(0x80, 0x64)
|
||||
#define OP_PRIV_GATT_PROXY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x65)
|
||||
#define OP_PRIV_NODE_ID_GET BT_MESH_MODEL_OP_2(0x80, 0x66)
|
||||
#define OP_PRIV_NODE_ID_SET BT_MESH_MODEL_OP_2(0x80, 0x67)
|
||||
#define OP_PRIV_NODE_ID_STATUS BT_MESH_MODEL_OP_2(0x80, 0x68)
|
||||
|
||||
#define STATUS_SUCCESS 0x00
|
||||
#define STATUS_INVALID_ADDRESS 0x01
|
||||
#define STATUS_INVALID_MODEL 0x02
|
||||
|
|
|
@ -96,6 +96,10 @@ struct bt_mesh_net bt_mesh = {
|
|||
.sar_tx = BT_MESH_SAR_TX_INIT,
|
||||
.sar_rx = BT_MESH_SAR_RX_INIT,
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
.priv_beacon_int = 0x3c,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Mesh Profile Specification 3.10.6
|
||||
|
@ -355,7 +359,8 @@ do_update:
|
|||
bt_mesh_subnet_foreach(bt_mesh_beacon_update);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
|
||||
(bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED)) {
|
||||
bt_mesh_proxy_beacon_send(NULL);
|
||||
}
|
||||
|
||||
|
@ -673,7 +678,8 @@ static bool relay_to_adv(enum bt_mesh_net_if net_if)
|
|||
case BT_MESH_NET_IF_ADV:
|
||||
return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
|
||||
case BT_MESH_NET_IF_PROXY:
|
||||
return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
|
||||
return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) ||
|
||||
(bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -693,7 +699,8 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf,
|
|||
if (rx->net_if == BT_MESH_NET_IF_ADV &&
|
||||
!rx->friend_cred &&
|
||||
bt_mesh_relay_get() != BT_MESH_RELAY_ENABLED &&
|
||||
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED) {
|
||||
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_ENABLED &&
|
||||
bt_mesh_priv_gatt_proxy_get() != BT_MESH_PRIV_GATT_PROXY_ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -747,7 +754,8 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf,
|
|||
*/
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
|
||||
(rx->friend_cred ||
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED)) {
|
||||
bt_mesh_proxy_relay(buf, rx->ctx.recv_dst);
|
||||
}
|
||||
|
||||
|
@ -858,6 +866,7 @@ void bt_mesh_net_recv(struct net_buf_simple *data, int8_t rssi,
|
|||
bt_mesh_proxy_addr_add(data, rx.ctx.addr);
|
||||
|
||||
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_PRIV_GATT_PROXY_DISABLED &&
|
||||
!rx.local_match) {
|
||||
LOG_INF("Proxy is disabled; ignoring message");
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "subnet.h"
|
||||
#include <zephyr/bluetooth/mesh/sar_cfg.h>
|
||||
|
||||
#define BT_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01)
|
||||
#define BT_MESH_KEY_REFRESH(flags) (flags & 0x01)
|
||||
|
@ -185,6 +186,8 @@ enum {
|
|||
BT_MESH_BEACON,
|
||||
BT_MESH_GATT_PROXY,
|
||||
BT_MESH_FRIEND,
|
||||
BT_MESH_PRIV_BEACON,
|
||||
BT_MESH_PRIV_GATT_PROXY,
|
||||
|
||||
/* Don't touch - intentionally last */
|
||||
BT_MESH_FLAG_COUNT,
|
||||
|
@ -216,6 +219,10 @@ struct bt_mesh_net {
|
|||
uint8_t relay_xmit;
|
||||
uint8_t default_ttl;
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
uint8_t priv_beacon_int;
|
||||
#endif
|
||||
|
||||
/* Timer to track duration in current IV Update state */
|
||||
struct k_work_delayable ivu_timer;
|
||||
|
||||
|
|
303
subsys/bluetooth/mesh/priv_beacon_cli.c
Normal file
303
subsys/bluetooth/mesh/priv_beacon_cli.c
Normal file
|
@ -0,0 +1,303 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include "net.h"
|
||||
#include "foundation.h"
|
||||
#include "access.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_priv_beacon_cli);
|
||||
|
||||
static struct bt_mesh_priv_beacon_cli *cli;
|
||||
|
||||
static int handle_beacon_status(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_priv_beacon *rsp;
|
||||
uint8_t beacon, rand_int;
|
||||
|
||||
beacon = net_buf_simple_pull_u8(buf);
|
||||
rand_int = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (beacon != BT_MESH_BEACON_DISABLED &&
|
||||
beacon != BT_MESH_BEACON_ENABLED) {
|
||||
LOG_WRN("Invalid beacon value 0x%02x", beacon);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_DBG("0x%02x (%u s)", beacon, 10U * rand_int);
|
||||
|
||||
if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, ctx->addr,
|
||||
(void **)&rsp)) {
|
||||
LOG_WRN("Unexpected beacon status from 0x%04x", ctx->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rsp->enabled = beacon;
|
||||
rsp->rand_interval = rand_int;
|
||||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_gatt_proxy_status(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t *rsp;
|
||||
uint8_t proxy;
|
||||
|
||||
proxy = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (proxy != BT_MESH_GATT_PROXY_DISABLED &&
|
||||
proxy != BT_MESH_GATT_PROXY_ENABLED &&
|
||||
proxy != BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
|
||||
LOG_WRN("Invalid GATT proxy value 0x%02x", proxy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, ctx->addr,
|
||||
(void **)&rsp)) {
|
||||
LOG_WRN("Unexpected proxy status from 0x%04x", ctx->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*rsp = proxy;
|
||||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_node_id_status(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_priv_node_id *rsp;
|
||||
uint8_t status, node_id;
|
||||
uint16_t net_idx;
|
||||
|
||||
status = net_buf_simple_pull_u8(buf);
|
||||
net_idx = net_buf_simple_pull_le16(buf);
|
||||
node_id = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (node_id != BT_MESH_NODE_IDENTITY_STOPPED &&
|
||||
node_id != BT_MESH_NODE_IDENTITY_RUNNING &&
|
||||
node_id != BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) {
|
||||
LOG_WRN("Invalid node ID value 0x%02x", node_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
if (!bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, ctx->addr,
|
||||
(void **)&rsp)) {
|
||||
LOG_WRN("Unexpected node ID status from 0x%04x", ctx->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rsp->status = status;
|
||||
rsp->state = node_id;
|
||||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op bt_mesh_priv_beacon_cli_op[] = {
|
||||
{ OP_PRIV_BEACON_STATUS, BT_MESH_LEN_EXACT(2), handle_beacon_status },
|
||||
{ OP_PRIV_GATT_PROXY_STATUS, BT_MESH_LEN_EXACT(1), handle_gatt_proxy_status },
|
||||
{ OP_PRIV_NODE_ID_STATUS, BT_MESH_LEN_EXACT(4), handle_node_id_status },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static int priv_beacon_cli_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("Private Beacon Client only allowed in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cli = mod->user_data;
|
||||
cli->mod = mod;
|
||||
cli->timeout = 2 * MSEC_PER_SEC;
|
||||
mod->keys[0] = BT_MESH_KEY_DEV_ANY;
|
||||
mod->flags |= BT_MESH_MOD_DEVKEY_ONLY;
|
||||
|
||||
bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb bt_mesh_priv_beacon_cli_cb = {
|
||||
.init = priv_beacon_cli_init,
|
||||
};
|
||||
|
||||
static int send(struct bt_mesh_priv_beacon_cli *cli, uint16_t net_idx,
|
||||
uint16_t addr, struct net_buf_simple *buf)
|
||||
{
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.net_idx = net_idx,
|
||||
.app_idx = BT_MESH_KEY_DEV_REMOTE,
|
||||
.addr = addr,
|
||||
.send_ttl = BT_MESH_TTL_DEFAULT,
|
||||
};
|
||||
|
||||
return bt_mesh_model_send(cli->mod, &ctx, buf, NULL, NULL);
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_set(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_SET, 2);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_SET);
|
||||
|
||||
net_buf_simple_add_u8(&buf, val->enabled);
|
||||
if (val->rand_interval) {
|
||||
net_buf_simple_add_u8(&buf, val->rand_interval);
|
||||
}
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_get(uint16_t net_idx, uint16_t addr, struct bt_mesh_priv_beacon *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_BEACON_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_GET, 0);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_GET);
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!val || (*val != BT_MESH_GATT_PROXY_DISABLED &&
|
||||
*val != BT_MESH_GATT_PROXY_ENABLED)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_SET, 1);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_SET);
|
||||
|
||||
net_buf_simple_add_u8(&buf, *val);
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_GATT_PROXY_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_GET, 0);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_GET);
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_node_id_set(uint16_t net_idx, uint16_t addr,
|
||||
struct bt_mesh_priv_node_id *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!val || val->net_idx > 0xfff ||
|
||||
(val->state != BT_MESH_NODE_IDENTITY_STOPPED &&
|
||||
val->state != BT_MESH_NODE_IDENTITY_RUNNING)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_SET, 3);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_SET);
|
||||
|
||||
net_buf_simple_add_le16(&buf, val->net_idx);
|
||||
net_buf_simple_add_u8(&buf, val->state);
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
||||
|
||||
int bt_mesh_priv_beacon_cli_node_id_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx,
|
||||
struct bt_mesh_priv_node_id *val)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_msg_ack_ctx_prepare(&cli->ack_ctx, OP_PRIV_NODE_ID_STATUS, addr, val);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
val->net_idx = key_net_idx;
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_GET, 2);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_GET);
|
||||
|
||||
net_buf_simple_add_le16(&buf, key_net_idx);
|
||||
|
||||
err = send(cli, net_idx, addr, &buf);
|
||||
if (err) {
|
||||
bt_mesh_msg_ack_ctx_clear(&cli->ack_ctx);
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_msg_ack_ctx_wait(&cli->ack_ctx, K_MSEC(cli->timeout));
|
||||
}
|
189
subsys/bluetooth/mesh/priv_beacon_srv.c
Normal file
189
subsys/bluetooth/mesh/priv_beacon_srv.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include "net.h"
|
||||
#include "adv.h"
|
||||
#include <zephyr/bluetooth/conn.h>
|
||||
#include "proxy.h"
|
||||
#include "foundation.h"
|
||||
#include "beacon.h"
|
||||
#include "cfg.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_priv_beacon_srv);
|
||||
|
||||
static int beacon_status_rsp(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_BEACON_STATUS, 2);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_BEACON_STATUS);
|
||||
|
||||
net_buf_simple_add_u8(&buf, bt_mesh_priv_beacon_get());
|
||||
net_buf_simple_add_u8(&buf, bt_mesh_priv_beacon_update_interval_get());
|
||||
|
||||
bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_beacon_get(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
beacon_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_beacon_set(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t beacon;
|
||||
|
||||
if (buf->len > 2U) {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
beacon = net_buf_simple_pull_u8(buf);
|
||||
if (beacon != BT_MESH_BEACON_DISABLED &&
|
||||
beacon != BT_MESH_BEACON_ENABLED) {
|
||||
LOG_WRN("Invalid beacon value %u", beacon);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (buf->len == 1U) {
|
||||
bt_mesh_priv_beacon_update_interval_set(net_buf_simple_pull_u8(buf));
|
||||
}
|
||||
|
||||
(void)bt_mesh_priv_beacon_set(beacon);
|
||||
beacon_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gatt_proxy_status_rsp(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_GATT_PROXY_STATUS, 1);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_GATT_PROXY_STATUS);
|
||||
|
||||
net_buf_simple_add_u8(&buf, bt_mesh_priv_gatt_proxy_get());
|
||||
|
||||
bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
|
||||
}
|
||||
|
||||
static int handle_gatt_proxy_get(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
gatt_proxy_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_gatt_proxy_set(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t gatt_proxy;
|
||||
|
||||
gatt_proxy = net_buf_simple_pull_u8(buf);
|
||||
if (gatt_proxy != BT_MESH_GATT_PROXY_DISABLED &&
|
||||
gatt_proxy != BT_MESH_GATT_PROXY_ENABLED) {
|
||||
LOG_WRN("Invalid GATT proxy value %u", gatt_proxy);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_DBG("%u", gatt_proxy);
|
||||
|
||||
bt_mesh_priv_gatt_proxy_set(gatt_proxy);
|
||||
|
||||
gatt_proxy_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void node_id_status_rsp(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx, uint8_t status,
|
||||
uint16_t net_idx, uint8_t node_id)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_PRIV_NODE_ID_STATUS, 4);
|
||||
bt_mesh_model_msg_init(&buf, OP_PRIV_NODE_ID_STATUS);
|
||||
|
||||
net_buf_simple_add_u8(&buf, status);
|
||||
net_buf_simple_add_le16(&buf, net_idx);
|
||||
net_buf_simple_add_u8(&buf, node_id);
|
||||
|
||||
bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
|
||||
}
|
||||
|
||||
static int handle_node_id_get(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t node_id, status;
|
||||
uint16_t net_idx;
|
||||
|
||||
net_idx = net_buf_simple_pull_le16(buf) & 0xfff;
|
||||
|
||||
status = bt_mesh_subnet_priv_node_id_get(net_idx, (enum bt_mesh_feat_state *)&node_id);
|
||||
node_id_status_rsp(mod, ctx, status, net_idx, node_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_node_id_set(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t node_id, status;
|
||||
uint16_t net_idx;
|
||||
|
||||
net_idx = net_buf_simple_pull_le16(buf) & 0xfff;
|
||||
node_id = net_buf_simple_pull_u8(buf);
|
||||
if (node_id != BT_MESH_NODE_IDENTITY_RUNNING &&
|
||||
node_id != BT_MESH_NODE_IDENTITY_STOPPED) {
|
||||
LOG_ERR("Invalid node ID value 0x%02x", node_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
status = bt_mesh_subnet_priv_node_id_set(net_idx, node_id);
|
||||
node_id_status_rsp(mod, ctx, status, net_idx, node_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op bt_mesh_priv_beacon_srv_op[] = {
|
||||
{ OP_PRIV_BEACON_GET, BT_MESH_LEN_EXACT(0), handle_beacon_get },
|
||||
{ OP_PRIV_BEACON_SET, BT_MESH_LEN_MIN(1), handle_beacon_set },
|
||||
{ OP_PRIV_GATT_PROXY_GET, BT_MESH_LEN_EXACT(0), handle_gatt_proxy_get },
|
||||
{ OP_PRIV_GATT_PROXY_SET, BT_MESH_LEN_EXACT(1), handle_gatt_proxy_set },
|
||||
{ OP_PRIV_NODE_ID_GET, BT_MESH_LEN_EXACT(2), handle_node_id_get },
|
||||
{ OP_PRIV_NODE_ID_SET, BT_MESH_LEN_EXACT(3), handle_node_id_set },
|
||||
BT_MESH_MODEL_OP_END
|
||||
};
|
||||
|
||||
static int priv_beacon_srv_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("Priv beacon server not in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mod->keys[0] = BT_MESH_KEY_DEV_LOCAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb bt_mesh_priv_beacon_srv_cb = {
|
||||
.init = priv_beacon_srv_init,
|
||||
};
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
#define BT_MESH_ID_TYPE_NET 0x00
|
||||
#define BT_MESH_ID_TYPE_NODE 0x01
|
||||
#define BT_MESH_ID_TYPE_PRIV_NET 0x02
|
||||
#define BT_MESH_ID_TYPE_PRIV_NODE 0x03
|
||||
|
||||
int bt_mesh_proxy_gatt_enable(void);
|
||||
int bt_mesh_proxy_gatt_disable(void);
|
||||
|
@ -29,7 +31,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub);
|
|||
|
||||
int bt_mesh_proxy_adv_start(void);
|
||||
|
||||
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub);
|
||||
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub, bool private);
|
||||
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub);
|
||||
|
||||
bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <zephyr/bluetooth/conn.h>
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
|
||||
|
@ -35,6 +36,12 @@
|
|||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_gatt);
|
||||
|
||||
/* Interval to update random value in (10 minutes).
|
||||
*
|
||||
* Defined in the Bluetooth Mesh Specification v1.1, Section 7.2.2.2.4.
|
||||
*/
|
||||
#define PROXY_RANDOM_UPDATE_INTERVAL (10 * 60 * MSEC_PER_SEC)
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME)
|
||||
#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME
|
||||
#else
|
||||
|
@ -312,10 +319,15 @@ static void proxy_msg_recv(struct bt_mesh_proxy_role *role)
|
|||
static int beacon_send(struct bt_mesh_proxy_client *client,
|
||||
struct bt_mesh_subnet *sub)
|
||||
{
|
||||
NET_BUF_SIMPLE_DEFINE(buf, 23);
|
||||
int err;
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE(buf, 28);
|
||||
|
||||
net_buf_simple_reserve(&buf, 1);
|
||||
bt_mesh_beacon_create(sub, &buf);
|
||||
err = bt_mesh_beacon_create(sub, &buf);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return bt_mesh_proxy_msg_send(client->cli->conn, BT_MESH_PROXY_BEACON,
|
||||
&buf, NULL, NULL);
|
||||
|
@ -354,7 +366,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
|
|||
}
|
||||
}
|
||||
|
||||
static void node_id_start(struct bt_mesh_subnet *sub)
|
||||
static void identity_enabled(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
|
||||
sub->node_id_start = k_uptime_get_32();
|
||||
|
@ -366,9 +378,31 @@ static void node_id_start(struct bt_mesh_subnet *sub)
|
|||
}
|
||||
}
|
||||
|
||||
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
|
||||
static void node_id_start(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
sub->priv_beacon.node_id = false;
|
||||
#endif
|
||||
|
||||
identity_enabled(sub);
|
||||
}
|
||||
|
||||
static void private_node_id_start(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
sub->priv_beacon.node_id = true;
|
||||
#endif
|
||||
|
||||
identity_enabled(sub);
|
||||
}
|
||||
|
||||
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub, bool private)
|
||||
{
|
||||
if (private) {
|
||||
private_node_id_start(sub);
|
||||
} else {
|
||||
node_id_start(sub);
|
||||
}
|
||||
|
||||
/* Prioritize the recently enabled subnet */
|
||||
beacon_sub = sub;
|
||||
|
@ -401,20 +435,39 @@ int bt_mesh_proxy_identity_enable(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define NODE_ID_LEN 19
|
||||
int bt_mesh_proxy_private_identity_enable(void)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (!bt_mesh_is_provisioned()) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
if (bt_mesh_subnet_foreach(private_node_id_start)) {
|
||||
bt_mesh_adv_gatt_update();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ENC_ID_LEN 19
|
||||
#define NET_ID_LEN 11
|
||||
|
||||
#define NODE_ID_TIMEOUT (CONFIG_BT_MESH_NODE_ID_TIMEOUT * MSEC_PER_SEC)
|
||||
|
||||
static uint8_t proxy_svc_data[NODE_ID_LEN] = {
|
||||
static uint8_t proxy_svc_data[ENC_ID_LEN] = {
|
||||
BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
|
||||
};
|
||||
|
||||
static const struct bt_data node_id_ad[] = {
|
||||
static const struct bt_data enc_id_ad[] = {
|
||||
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
|
||||
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
|
||||
BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
|
||||
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
|
||||
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, ENC_ID_LEN),
|
||||
};
|
||||
|
||||
static const struct bt_data net_id_ad[] = {
|
||||
|
@ -424,46 +477,113 @@ static const struct bt_data net_id_ad[] = {
|
|||
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
|
||||
};
|
||||
|
||||
static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
static int randomize_bt_addr(void)
|
||||
{
|
||||
/* TODO: There appears to be no way to force an RPA/NRPA refresh. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enc_id_adv(struct bt_mesh_subnet *sub, uint8_t type,
|
||||
uint8_t hash[16], int32_t duration)
|
||||
{
|
||||
struct bt_le_adv_param slow_adv_param = {
|
||||
.options = ADV_OPT_PROXY,
|
||||
ADV_SLOW_INT,
|
||||
};
|
||||
struct bt_le_adv_param fast_adv_param = {
|
||||
.options = ADV_OPT_PROXY,
|
||||
ADV_FAST_INT,
|
||||
};
|
||||
uint8_t tmp[16];
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
proxy_svc_data[2] = BT_MESH_ID_TYPE_NODE;
|
||||
|
||||
err = bt_rand(proxy_svc_data + 11, 8);
|
||||
err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, hash, hash);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
(void)memset(tmp, 0, 6);
|
||||
memcpy(tmp + 6, proxy_svc_data + 11, 8);
|
||||
sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
|
||||
|
||||
err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
|
||||
tmp);
|
||||
/* Section 7.2.2.2.4: The AdvA field shall be regenerated whenever the Random field is
|
||||
* regenerated.
|
||||
*/
|
||||
err = randomize_bt_addr();
|
||||
if (err) {
|
||||
LOG_ERR("AdvA refresh failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(proxy_svc_data + 3, tmp + 8, 8);
|
||||
proxy_svc_data[2] = type;
|
||||
memcpy(&proxy_svc_data[3], &hash[8], 8);
|
||||
|
||||
err = bt_mesh_adv_gatt_start(&fast_adv_param, duration, node_id_ad,
|
||||
ARRAY_SIZE(node_id_ad), NULL, 0);
|
||||
err = bt_mesh_adv_gatt_start(
|
||||
type == BT_MESH_ID_TYPE_PRIV_NET ? &slow_adv_param : &fast_adv_param,
|
||||
duration, enc_id_ad, ARRAY_SIZE(enc_id_ad), NULL, 0);
|
||||
if (err) {
|
||||
LOG_WRN("Failed to advertise using Node ID (err %d)", err);
|
||||
LOG_WRN("Failed to advertise using type 0x%02x (err %d)", type, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
uint8_t *random = &proxy_svc_data[11];
|
||||
uint8_t tmp[16];
|
||||
int err;
|
||||
|
||||
LOG_DBG("0x%03x", sub->net_idx);
|
||||
|
||||
err = bt_rand(random, 8);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&tmp[0], 0x00, 6);
|
||||
memcpy(&tmp[6], random, 8);
|
||||
sys_put_be16(bt_mesh_primary_addr(), &tmp[14]);
|
||||
|
||||
return enc_id_adv(sub, BT_MESH_ID_TYPE_NODE, tmp, duration);
|
||||
}
|
||||
|
||||
static int priv_node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
uint8_t *random = &proxy_svc_data[11];
|
||||
uint8_t tmp[16];
|
||||
int err;
|
||||
|
||||
LOG_DBG("0x%03x", sub->net_idx);
|
||||
|
||||
err = bt_rand(random, 8);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memset(&tmp[0], 0x00, 5);
|
||||
tmp[5] = 0x03;
|
||||
memcpy(&tmp[6], random, 8);
|
||||
sys_put_be16(bt_mesh_primary_addr(), &tmp[14]);
|
||||
|
||||
return enc_id_adv(sub, BT_MESH_ID_TYPE_PRIV_NODE, tmp, duration);
|
||||
}
|
||||
|
||||
static int priv_net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
uint8_t *random = &proxy_svc_data[11];
|
||||
uint8_t tmp[16];
|
||||
int err;
|
||||
|
||||
LOG_DBG("0x%03x", sub->net_idx);
|
||||
|
||||
err = bt_rand(random, 8);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
memcpy(&tmp[0], sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
|
||||
memcpy(&tmp[8], random, 8);
|
||||
|
||||
return enc_id_adv(sub, BT_MESH_ID_TYPE_PRIV_NET, tmp, duration);
|
||||
}
|
||||
|
||||
static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||
{
|
||||
struct bt_le_adv_param slow_adv_param = {
|
||||
|
@ -472,8 +592,6 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
|||
};
|
||||
int err;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
proxy_svc_data[2] = BT_MESH_ID_TYPE_NET;
|
||||
|
||||
LOG_DBG("Advertising with NetId %s", bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
|
||||
|
@ -497,7 +615,8 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub)
|
|||
}
|
||||
|
||||
return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
|
||||
}
|
||||
|
||||
static struct bt_mesh_subnet *next_sub(void)
|
||||
|
@ -591,12 +710,20 @@ static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
|||
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
|
||||
uint32_t active = k_uptime_get_32() - sub->node_id_start;
|
||||
bool priv_node_id = false;
|
||||
|
||||
if (active < NODE_ID_TIMEOUT) {
|
||||
remaining = MIN(remaining, NODE_ID_TIMEOUT - active);
|
||||
LOG_DBG("Node ID active for %u ms, %d ms remaining", active,
|
||||
remaining);
|
||||
LOG_DBG("Node ID active for %u ms, %d ms remaining",
|
||||
active, remaining);
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
priv_node_id = sub->priv_beacon.node_id;
|
||||
#endif
|
||||
if (priv_node_id) {
|
||||
err = priv_node_id_adv(sub, remaining);
|
||||
} else {
|
||||
err = node_id_adv(sub, remaining);
|
||||
}
|
||||
planned = true;
|
||||
} else {
|
||||
bt_mesh_proxy_identity_stop(sub);
|
||||
|
@ -608,11 +735,26 @@ static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
|||
* A node that does not support the Proxy feature or
|
||||
* has the GATT Proxy state disabled shall not advertise with Network ID.
|
||||
*/
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED &&
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) {
|
||||
if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS) &&
|
||||
(bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED)) {
|
||||
/* Bluetooth mesh specification v1.1, section 7.2.2.2.4: The Random
|
||||
* field should be updated every 10 minutes. Limit advertising to
|
||||
* 10 minutes to ensure regeneration of a new random value at least
|
||||
* that often.
|
||||
*/
|
||||
if (remaining == SYS_FOREVER_MS ||
|
||||
remaining > PROXY_RANDOM_UPDATE_INTERVAL) {
|
||||
remaining = PROXY_RANDOM_UPDATE_INTERVAL;
|
||||
}
|
||||
|
||||
err = priv_net_id_adv(sub, remaining);
|
||||
planned = true;
|
||||
} else if (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED) {
|
||||
err = net_id_adv(sub, remaining);
|
||||
planned = true;
|
||||
}
|
||||
}
|
||||
|
||||
beacon_sub = bt_mesh_subnet_next(sub);
|
||||
|
||||
|
|
|
@ -328,6 +328,16 @@ static int net_keys_create(struct bt_mesh_subnet_keys *keys,
|
|||
|
||||
LOG_DBG("BeaconKey %s", bt_hex(keys->beacon, 16));
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
err = bt_mesh_private_beacon_key(key, keys->priv_beacon);
|
||||
if (err) {
|
||||
LOG_ERR("Unable to generate private beacon key");
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("PrivateBeaconKey %s", bt_hex(keys->priv_beacon, 16));
|
||||
#endif
|
||||
|
||||
keys->valid = 1U;
|
||||
|
||||
return 0;
|
||||
|
@ -533,7 +543,7 @@ uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx,
|
|||
}
|
||||
|
||||
if (node_id) {
|
||||
bt_mesh_proxy_identity_start(sub);
|
||||
bt_mesh_proxy_identity_start(sub, false);
|
||||
} else {
|
||||
bt_mesh_proxy_identity_stop(sub);
|
||||
}
|
||||
|
@ -559,6 +569,61 @@ uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint8_t bt_mesh_subnet_priv_node_id_set(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state priv_node_id)
|
||||
{
|
||||
struct bt_mesh_subnet *sub;
|
||||
|
||||
if (priv_node_id == BT_MESH_FEATURE_NOT_SUPPORTED) {
|
||||
return STATUS_CANNOT_SET;
|
||||
}
|
||||
|
||||
sub = bt_mesh_subnet_get(net_idx);
|
||||
if (!sub) {
|
||||
return STATUS_INVALID_NETKEY;
|
||||
}
|
||||
|
||||
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) ||
|
||||
!IS_ENABLED(CONFIG_BT_MESH_PRIV_BEACONS)) {
|
||||
return STATUS_FEAT_NOT_SUPP;
|
||||
}
|
||||
|
||||
if (priv_node_id) {
|
||||
bt_mesh_proxy_identity_start(sub, true);
|
||||
} else {
|
||||
bt_mesh_proxy_identity_stop(sub);
|
||||
}
|
||||
|
||||
bt_mesh_adv_gatt_update();
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t bt_mesh_subnet_priv_node_id_get(uint16_t net_idx,
|
||||
enum bt_mesh_feat_state *priv_node_id)
|
||||
{
|
||||
struct bt_mesh_subnet *sub;
|
||||
|
||||
sub = bt_mesh_subnet_get(net_idx);
|
||||
if (!sub) {
|
||||
*priv_node_id = 0x00;
|
||||
return STATUS_INVALID_NETKEY;
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_GATT_PROXY && CONFIG_BT_MESH_PRIV_BEACONS
|
||||
if (sub->node_id == BT_MESH_FEATURE_ENABLED && sub->priv_beacon.node_id) {
|
||||
*priv_node_id = sub->node_id;
|
||||
} else {
|
||||
*priv_node_id = BT_MESH_FEATURE_DISABLED;
|
||||
}
|
||||
#else
|
||||
*priv_node_id = BT_MESH_FEATURE_NOT_SUPPORTED;
|
||||
#endif
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
|
|
@ -44,7 +44,7 @@ struct bt_mesh_subnet {
|
|||
* currently ongoing window.
|
||||
*/
|
||||
|
||||
uint8_t beacon_cache[21]; /* Cached last authenticated beacon */
|
||||
uint8_t beacon_cache[8]; /* Cached last beacon auth value */
|
||||
|
||||
uint16_t net_idx; /* NetKeyIndex */
|
||||
|
||||
|
@ -53,6 +53,13 @@ struct bt_mesh_subnet {
|
|||
uint8_t node_id; /* Node Identity State */
|
||||
uint32_t node_id_start; /* Node Identity started timestamp */
|
||||
|
||||
#if defined(CONFIG_BT_MESH_PRIV_BEACONS)
|
||||
struct {
|
||||
uint16_t idx; /* Private beacon random index */
|
||||
bool node_id; /* Private Node Identity enabled */
|
||||
uint8_t data[5]; /* Private Beacon data */
|
||||
} priv_beacon;
|
||||
#endif
|
||||
uint8_t auth[8]; /* Beacon Authentication Value */
|
||||
|
||||
struct bt_mesh_subnet_keys {
|
||||
|
@ -64,6 +71,7 @@ struct bt_mesh_subnet {
|
|||
uint8_t identity[16]; /* IdentityKey */
|
||||
#endif
|
||||
uint8_t beacon[16]; /* BeaconKey */
|
||||
uint8_t priv_beacon[16]; /* PrivateBeaconKey */
|
||||
} keys[2];
|
||||
};
|
||||
|
||||
|
@ -183,6 +191,8 @@ uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub);
|
|||
* @param kr_flag Key Refresh flag.
|
||||
* @param new_key Whether the Key Refresh event was received on the new key
|
||||
* set.
|
||||
*
|
||||
* @returns Whether the Key Refresh event caused a change.
|
||||
*/
|
||||
void bt_mesh_kr_update(struct bt_mesh_subnet *sub, bool kr_flag, bool new_key);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue