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>
This commit is contained in:
parent
56298dff73
commit
d0995541fb
40 changed files with 1851 additions and 75 deletions
|
@ -31,3 +31,5 @@ In addition to the foundation models defined in the Bluetooth mesh specification
|
|||
|
||||
blob
|
||||
dfu
|
||||
srpl
|
||||
od
|
||||
|
|
14
doc/connectivity/bluetooth/api/mesh/od.rst
Normal file
14
doc/connectivity/bluetooth/api/mesh/od.rst
Normal file
|
@ -0,0 +1,14 @@
|
|||
.. _bluetooth_mesh_od:
|
||||
|
||||
On-Demand Private GATT Proxy models
|
||||
###################################
|
||||
|
||||
On-Demand Private GATT Proxy state defines how long a node will advertise Mesh Proxy Service with Private Network Identity type after it receives Solicitation PDU.
|
||||
|
||||
On-Demand Private GATT Proxy models are:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
od_srv
|
||||
od_cli
|
13
doc/connectivity/bluetooth/api/mesh/od_cli.rst
Normal file
13
doc/connectivity/bluetooth/api/mesh/od_cli.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
.. _bluetooth_mesh_od_cli:
|
||||
|
||||
On-Demand Private Proxy Client
|
||||
##############################
|
||||
|
||||
On-Demand Private Proxy Client model is used to set and retrieve the On-Demand Private GATT Proxy state, and to adjust message transmission timeout.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_od_priv_proxy_cli
|
||||
:project: Zephyr
|
||||
:members:
|
13
doc/connectivity/bluetooth/api/mesh/od_srv.rst
Normal file
13
doc/connectivity/bluetooth/api/mesh/od_srv.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
.. _bluetooth_mesh_od_srv:
|
||||
|
||||
On-Demand Private Proxy Server
|
||||
##############################
|
||||
|
||||
On-Demand Private Proxy Server manages the On-Demand Private GATT Proxy state of the node that is a recipient of Solicitation PDUs.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_od_priv_proxy_srv
|
||||
:project: Zephyr
|
||||
:members:
|
16
doc/connectivity/bluetooth/api/mesh/srpl.rst
Normal file
16
doc/connectivity/bluetooth/api/mesh/srpl.rst
Normal file
|
@ -0,0 +1,16 @@
|
|||
.. _bluetooth_mesh_srpl:
|
||||
|
||||
Solicitation PDU RPL Configuration models
|
||||
#########################################
|
||||
|
||||
Solicitation PDU RPL Configuration models provide functionality for saving and clearing the solicitation replay protection list (SRPL).
|
||||
|
||||
Solicitation RPL secures the solicitation mechanism from replay attacks by storing solicitation sequence number (SSEQ) and solicitation source (SSRC) pairs of valid Solicitation PDUs processed by a node.
|
||||
|
||||
Solicitation PDU RPL Configuration models are:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
srpl_srv
|
||||
srpl_cli
|
13
doc/connectivity/bluetooth/api/mesh/srpl_cli.rst
Normal file
13
doc/connectivity/bluetooth/api/mesh/srpl_cli.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
.. _bluetooth_mesh_srpl_cli:
|
||||
|
||||
Solicitation PDU RPL Configuration Client
|
||||
#########################################
|
||||
|
||||
Solicitation PDU RPL Configuration Client model is used for clearing the solicitation replay protection list (SRPL) of a node that supports the Solicitation PDU RPL Configuration Server model.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_sol_pdu_rpl_cli
|
||||
:project: Zephyr
|
||||
:members:
|
13
doc/connectivity/bluetooth/api/mesh/srpl_srv.rst
Normal file
13
doc/connectivity/bluetooth/api/mesh/srpl_srv.rst
Normal file
|
@ -0,0 +1,13 @@
|
|||
.. _bluetooth_mesh_srpl_srv:
|
||||
|
||||
Solicitation PDU RPL Configuration Server
|
||||
#########################################
|
||||
|
||||
Solicitation PDU RPL Configuration Server model manages the solicitation RPL saved on the device.
|
||||
|
||||
API reference
|
||||
*************
|
||||
|
||||
.. doxygengroup:: bt_mesh_sol_pdu_rpl_srv
|
||||
:project: Zephyr
|
||||
:members:
|
|
@ -42,5 +42,9 @@
|
|||
#include <zephyr/bluetooth/mesh/op_agg_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/large_comp_data_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/large_comp_data_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/od_priv_proxy_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/od_priv_proxy_cli.h>
|
||||
#include <zephyr/bluetooth/mesh/sol_pdu_rpl_srv.h>
|
||||
#include <zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h>
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_H_ */
|
||||
|
|
|
@ -136,6 +136,10 @@ struct bt_mesh_elem {
|
|||
#define BT_MESH_MODEL_ID_OP_AGG_CLI 0x0011
|
||||
#define BT_MESH_MODEL_ID_LARGE_COMP_DATA_SRV 0x0012
|
||||
#define BT_MESH_MODEL_ID_LARGE_COMP_DATA_CLI 0x0013
|
||||
#define BT_MESH_MODEL_ID_SOL_PDU_RPL_SRV 0x0014
|
||||
#define BT_MESH_MODEL_ID_SOL_PDU_RPL_CLI 0x0015
|
||||
#define BT_MESH_MODEL_ID_ON_DEMAND_PROXY_SRV 0x000c
|
||||
#define BT_MESH_MODEL_ID_ON_DEMAND_PROXY_CLI 0x000d
|
||||
|
||||
/* Models from the Mesh Model Specification */
|
||||
#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000
|
||||
|
|
|
@ -144,6 +144,30 @@ int bt_mesh_default_ttl_set(uint8_t default_ttl);
|
|||
*/
|
||||
uint8_t bt_mesh_default_ttl_get(void);
|
||||
|
||||
/** @brief Get the current Mesh On-Demand Private Proxy state.
|
||||
*
|
||||
* @retval 0 or positive value represents On-Demand Private Proxy feature state
|
||||
* @retval -ENOTSUP The On-Demand Private Proxy feature is not supported.
|
||||
*/
|
||||
int bt_mesh_od_priv_proxy_get(void);
|
||||
|
||||
/** @brief Set state of Mesh On-Demand Private Proxy.
|
||||
*
|
||||
* Support for the On-Demand Private Proxy state must be enabled with @c
|
||||
* BT_MESH_OD_PRIV_PROXY_SRV.
|
||||
*
|
||||
* @param on_demand_proxy New Mesh On-Demand Private Proxy state. Value of 0x00 means that
|
||||
* advertising with Private Network Identity cannot be enabled on demand.
|
||||
* Values in range 0x01 - 0xFF set interval of this advertising after
|
||||
* valid Solicitation PDU is received or client disconnects.
|
||||
*
|
||||
* @retval 0 Successfully changed the Mesh On-Demand Private Proxy feature state.
|
||||
* @retval -ENOTSUP The On-Demand Private Proxy feature is not supported.
|
||||
* @retval -EINVAL Invalid parameter.
|
||||
* @retval -EALREADY Already in the given state.
|
||||
*/
|
||||
int bt_mesh_od_priv_proxy_set(uint8_t on_demand_proxy);
|
||||
|
||||
/** @brief Set the Network Transmit parameters.
|
||||
*
|
||||
* The Network Transmit parameters determine the parameters local messages are
|
||||
|
|
99
include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h
Normal file
99
include/zephyr/bluetooth/mesh/od_priv_proxy_cli.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_od_priv_proxy_cli Bluetooth Mesh On-Demand Private GATT Proxy Client
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef BT_MESH_OD_PRIV_PROXY_CLI_H__
|
||||
#define BT_MESH_OD_PRIV_PROXY_CLI_H__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** On-Demand Private Proxy Client Model Context */
|
||||
struct bt_mesh_od_priv_proxy_cli {
|
||||
/** Solicitation PDU RPL model entry pointer. */
|
||||
struct bt_mesh_model *model;
|
||||
|
||||
/* Internal parameters for tracking message responses. */
|
||||
struct bt_mesh_msg_ack_ctx ack_ctx;
|
||||
|
||||
/** @brief Optional callback for On-Demand Private Proxy Status messages.
|
||||
*
|
||||
* Handles received On-Demand Private Proxy Status messages from a On-Demand Private Proxy
|
||||
* server.The @c state param represents state of On-Demand Private Proxy server.
|
||||
*
|
||||
* @param cli On-Demand Private Proxy client that received the status message.
|
||||
* @param addr Address of the sender.
|
||||
* @param state State value.
|
||||
*/
|
||||
void (*od_status)(struct bt_mesh_od_priv_proxy_cli *cli, uint16_t addr, uint8_t state);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief On-Demand Private Proxy Client model composition data entry.
|
||||
*/
|
||||
#define BT_MESH_MODEL_OD_PRIV_PROXY_CLI(cli_data) \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_ON_DEMAND_PROXY_CLI, \
|
||||
_bt_mesh_od_priv_proxy_cli_op, NULL, cli_data, \
|
||||
&_bt_mesh_od_priv_proxy_cli_cb)
|
||||
|
||||
|
||||
/** @brief Get the target's On-Demand Private GATT Proxy state.
|
||||
*
|
||||
* This method can be used asynchronously by setting @p val_rsp as NULL.
|
||||
* This way the method will not wait for response and will
|
||||
* return immediately after sending the command.
|
||||
*
|
||||
* To process the response arguments of an async method, register
|
||||
* the @c od_status callback in @c bt_mesh_od_priv_proxy_cli struct.
|
||||
*
|
||||
* @param ctx Message context for the message.
|
||||
* @param val_rsp Response buffer for On-Demand Private GATT Proxy value.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_od_priv_proxy_cli_get(struct bt_mesh_msg_ctx *ctx, uint8_t *val_rsp);
|
||||
|
||||
/** @brief Set the target's On-Demand Private GATT Proxy state.
|
||||
*
|
||||
* This method can be used asynchronously by setting @p val_rsp as NULL.
|
||||
* This way the method will not wait for response and will
|
||||
* return immediately after sending the command.
|
||||
*
|
||||
* To process the response arguments of an async method, register
|
||||
* the @c od_status callback in @c bt_mesh_od_priv_proxy_cli struct.
|
||||
*
|
||||
* @param ctx Message context for the message.
|
||||
* @param val On-Demand Private GATT Proxy state to be set
|
||||
* @param val_rsp Response buffer for On-Demand Private GATT Proxy value.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_od_priv_proxy_cli_set(struct bt_mesh_msg_ctx *ctx, uint8_t val, uint8_t *val_rsp);
|
||||
|
||||
/** @brief Set the transmission timeout value.
|
||||
*
|
||||
* @param timeout The new transmission timeout in milliseconds.
|
||||
*/
|
||||
void bt_mesh_od_priv_proxy_cli_timeout_set(int32_t timeout);
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op _bt_mesh_od_priv_proxy_cli_op[];
|
||||
extern const struct bt_mesh_model_cb _bt_mesh_od_priv_proxy_cli_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BT_MESH_OD_PRIV_PROXY_CLI_H__ */
|
||||
|
||||
/** @} */
|
41
include/zephyr/bluetooth/mesh/od_priv_proxy_srv.h
Normal file
41
include/zephyr/bluetooth/mesh/od_priv_proxy_srv.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_od_priv_proxy_srv Bluetooth Mesh On-Demand Private GATT Proxy Server
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef BT_MESH_OD_PRIV_PROXY_SRV_H__
|
||||
#define BT_MESH_OD_PRIV_PROXY_SRV_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief On-Demand Private Proxy Server model composition data entry.
|
||||
*/
|
||||
#define BT_MESH_MODEL_OD_PRIV_PROXY_SRV \
|
||||
BT_MESH_MODEL_SOL_PDU_RPL_SRV, \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_ON_DEMAND_PROXY_SRV, \
|
||||
_bt_mesh_od_priv_proxy_srv_op, NULL, NULL, \
|
||||
&_bt_mesh_od_priv_proxy_srv_cb)
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op _bt_mesh_od_priv_proxy_srv_op[];
|
||||
extern const struct bt_mesh_model_cb _bt_mesh_od_priv_proxy_srv_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BT_MESH_OD_PRIV_PROXY_SRV_H__ */
|
||||
|
||||
/** @} */
|
|
@ -92,6 +92,21 @@ int bt_mesh_proxy_connect(uint16_t net_idx);
|
|||
*/
|
||||
int bt_mesh_proxy_disconnect(uint16_t net_idx);
|
||||
|
||||
/** @brief Schedule advertising of Solicitation PDUs on Proxy Client .
|
||||
*
|
||||
* Once called Proxy Client will schedule advertising Solicitation PDUs for the amount of time
|
||||
* defined by @c adv_int * (@c CONFIG_BT_MESH_SOL_ADV_XMIT + 1), where @c adv_int is 20ms
|
||||
* for Bluetooth v5.0 or higher, or 100ms otherwise.
|
||||
*
|
||||
* If the number of advertised Solicitation PDUs reached 0xFFFFFF, the advertisements will
|
||||
* no longer be started until the node is reprovisioned.
|
||||
*
|
||||
* @param net_idx Network Key Index
|
||||
*
|
||||
* @return 0 on success, or (negative) error code on failure.
|
||||
*/
|
||||
int bt_mesh_proxy_solicit(uint16_t net_idx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
102
include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h
Normal file
102
include/zephyr/bluetooth/mesh/sol_pdu_rpl_cli.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_sol_pdu_rpl_cli Bluetooth Mesh Solicitation PDU RPL Client
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef BT_MESH_SOL_PDU_RPL_CLI_H__
|
||||
#define BT_MESH_SOL_PDU_RPL_CLI_H__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Solicitation PDU RPL Client Model Context */
|
||||
struct bt_mesh_sol_pdu_rpl_cli {
|
||||
/** Solicitation PDU RPL model entry pointer. */
|
||||
struct bt_mesh_model *model;
|
||||
|
||||
/* Internal parameters for tracking message responses. */
|
||||
struct bt_mesh_msg_ack_ctx ack_ctx;
|
||||
|
||||
/** @brief Optional callback for Solicitation PDU RPL Status messages.
|
||||
*
|
||||
* Handles received Solicitation PDU RPL Status messages from a Solicitation
|
||||
* PDU RPL server.The @c start param represents the start of range that server
|
||||
* has cleared. The @c length param represents length of range cleared by server.
|
||||
*
|
||||
* @param cli Solicitation PDU RPL client that received the status message.
|
||||
* @param addr Address of the sender.
|
||||
* @param range_start Range start value.
|
||||
* @param range_length Range length value.
|
||||
*/
|
||||
void (*srpl_status)(struct bt_mesh_sol_pdu_rpl_cli *cli, uint16_t addr,
|
||||
uint16_t range_start, uint8_t range_length);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Solicitation PDU RPL Client model composition data entry.
|
||||
*/
|
||||
#define BT_MESH_MODEL_SOL_PDU_RPL_CLI(cli_data) \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_SOL_PDU_RPL_CLI, \
|
||||
_bt_mesh_sol_pdu_rpl_cli_op, NULL, cli_data, \
|
||||
&_bt_mesh_sol_pdu_rpl_cli_cb)
|
||||
|
||||
/** @brief Remove entries from Solicitation PDU RPL of addresses in given range.
|
||||
*
|
||||
* This method can be used asynchronously by setting @p start_rsp or
|
||||
* @p len_rsp as NULL. This way the method will not wait for response and will
|
||||
* return immediately after sending the command.
|
||||
*
|
||||
* To process the response arguments of an async method, register
|
||||
* the @c srpl_status callback in @c bt_mesh_sol_pdu_rpl_cli struct.
|
||||
*
|
||||
* @param ctx Message context for the message.
|
||||
* @param range_start Start of Unicast address range.
|
||||
* @param range_len Length of Unicast address range. Valid values are 0x00 and 0x02
|
||||
* to 0xff.
|
||||
* @param start_rsp Range start response buffer.
|
||||
* @param len_rsp Range length response buffer.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_sol_pdu_rpl_clear(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
||||
uint8_t range_len, uint16_t *start_rsp, uint8_t *len_rsp);
|
||||
|
||||
|
||||
/** @brief Remove entries from Solicitation PDU RPL of addresses in given range (unacked).
|
||||
*
|
||||
* @param ctx Message context for the message.
|
||||
* @param range_start Start of Unicast address range.
|
||||
* @param range_len Length of Unicast address range. Valid values are 0x00 and 0x02
|
||||
* to 0xff.
|
||||
*
|
||||
* @return 0 on success, or (negative) error code otherwise.
|
||||
*/
|
||||
int bt_mesh_sol_pdu_rpl_clear_unack(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
||||
uint8_t range_len);
|
||||
|
||||
/** @brief Set the transmission timeout value.
|
||||
*
|
||||
* @param timeout The new transmission timeout in milliseconds.
|
||||
*/
|
||||
void bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout);
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_cli_op[];
|
||||
extern const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_cli_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BT_MESH_SOL_PDU_RPL_CLI_H__ */
|
||||
|
||||
/** @} */
|
38
include/zephyr/bluetooth/mesh/sol_pdu_rpl_srv.h
Normal file
38
include/zephyr/bluetooth/mesh/sol_pdu_rpl_srv.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @defgroup bt_mesh_sol_pdu_rpl_srv Bluetooth Mesh Solicitation PDU RPL Server
|
||||
* @{
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef BT_MESH_SOL_PDU_RPL_SRV_H__
|
||||
#define BT_MESH_SOL_PDU_RPL_SRV_H__
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Solicitation PDU RPL Server model composition data entry.
|
||||
*/
|
||||
#define BT_MESH_MODEL_SOL_PDU_RPL_SRV \
|
||||
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_SOL_PDU_RPL_SRV, \
|
||||
_bt_mesh_sol_pdu_rpl_srv_op, NULL, NULL, \
|
||||
&_bt_mesh_sol_pdu_rpl_srv_cb)
|
||||
|
||||
/** @cond INTERNAL_HIDDEN */
|
||||
extern const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_srv_op[];
|
||||
extern const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_srv_cb;
|
||||
/** @endcond */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* BT_MESH_SOL_PDU_RPL_SRV_H__ */
|
||||
|
||||
/** @} */
|
|
@ -598,6 +598,10 @@ struct bt_uuid_128 {
|
|||
*/
|
||||
#define BT_UUID_MESH_PROXY \
|
||||
BT_UUID_DECLARE_16(BT_UUID_MESH_PROXY_VAL)
|
||||
/**
|
||||
* @brief Proxy Solicitation UUID value
|
||||
*/
|
||||
#define BT_UUID_MESH_PROXY_SOLICITATION_VAL 0x7fcb
|
||||
/**
|
||||
* @brief Reconnection Configuration Service UUID value
|
||||
*/
|
||||
|
|
|
@ -108,3 +108,13 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_DFU_METADATA dfu_metadata.c)
|
|||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_RPR_CLI rpr_cli.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_RPR_SRV rpr_srv.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_CLI od_priv_proxy_cli.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV od_priv_proxy_srv.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOL_PDU_RPL_CLI sol_pdu_rpl_cli.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV sol_pdu_rpl_srv.c)
|
||||
|
||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SOLICITATION solicitation.c)
|
||||
|
|
|
@ -319,12 +319,12 @@ endchoice
|
|||
if BT_MESH_RPL_STORAGE_MODE_SETTINGS && BT_SETTINGS
|
||||
|
||||
config BT_MESH_RPL_STORE_TIMEOUT
|
||||
int "Minimum interval after which unsaved RPL entries are updated in the settings subsystem"
|
||||
int "Minimum interval after which unsaved RPL and SRPL entries are updated in the settings subsystem"
|
||||
range -1 1000000
|
||||
default 5
|
||||
help
|
||||
This value defines in seconds how soon unsaved RPL entries
|
||||
gets written to the persistent storage. Setting this value
|
||||
This value defines time in seconds until unsaved RPL and SRPL entries
|
||||
are written to the persistent storage. Setting this value
|
||||
to a large number may lead to security vulnerabilities if a node
|
||||
gets powered off before the timer is fired. When flash is used
|
||||
as the persistent storage setting this value to a low number
|
||||
|
@ -1286,6 +1286,80 @@ config BT_MESH_MODEL_EXTENSION_LIST_SIZE
|
|||
Equals to the number of `bt_mesh_model_extend` and `bt_mesh_model_correspond` calls.
|
||||
This information is used to construct Composition Data Page 1.
|
||||
|
||||
config BT_MESH_SOLICITATION
|
||||
bool
|
||||
|
||||
config BT_MESH_PROXY_SOLICITATION
|
||||
bool "Proxy solicitation feature for Proxy Client support"
|
||||
depends on BT_MESH_PROXY_CLIENT
|
||||
select BT_MESH_SOLICITATION
|
||||
help
|
||||
This option enables support for sending Solicitation PDUs for Proxy Client.
|
||||
|
||||
config BT_MESH_SOL_ADV_XMIT
|
||||
int "Solicitation PDU retransmission count"
|
||||
depends on BT_MESH_PROXY_SOLICITATION
|
||||
range 0 10
|
||||
default 2
|
||||
help
|
||||
How many times Solicitation PDU advertisements will be repeated. 0 means that there will be
|
||||
1 transmission without retransmissions.
|
||||
|
||||
config BT_MESH_OD_PRIV_PROXY_CLI
|
||||
bool "Support for On-Demand Private Proxy Client model"
|
||||
help
|
||||
On-Demand Private Proxy Client allows to configure and check the state
|
||||
of On-Demand Private Proxy Servers. The state determines if the peers will
|
||||
advertise the Private Network Identity type after receiving a Solicitation PDU.
|
||||
|
||||
|
||||
config BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT
|
||||
int "Solicitation PDU RPL Configuration Client model timeout in milliseconds"
|
||||
default 5000
|
||||
depends on BT_MESH_OD_PRIV_PROXY_CLI
|
||||
help
|
||||
This timeout controls how long the Solicitation PDU RPL Configuration Client waits
|
||||
for a response message to arrive. This value can be changed at runtime
|
||||
using @ref bt_mesh_sol_pdu_rpl_cli_timeout_set.
|
||||
|
||||
config BT_MESH_OD_PRIV_PROXY_SRV
|
||||
bool "Support for On-Demand Private Proxy Server model"
|
||||
depends on BT_MESH_PRIV_BEACON_SRV
|
||||
select BT_MESH_SOLICITATION
|
||||
help
|
||||
The On-Demand Private Proxy Server is used to support configuration of
|
||||
advertising with Private Network Identity type of a node.
|
||||
When enabled, the Solicitation PDU RPL Configuration Server model is also enabled.
|
||||
|
||||
config BT_MESH_PROXY_SRPL_SIZE
|
||||
int "Size of solicitation replay protection list (SRPL)"
|
||||
depends on BT_MESH_OD_PRIV_PROXY_SRV
|
||||
default 10
|
||||
range 1 255
|
||||
help
|
||||
Size of SRPL. The list is used to determine if a received Solicitation PDU
|
||||
is valid. It is valid when the SSRC field value of the received Solicitation PDU
|
||||
is stored in the SRPL and the SSEQ field value is bigger than the corresponding
|
||||
stored SSEQ value, or if the SSRC was not stored in the RPL and the SRPL still has
|
||||
space for new entries.
|
||||
|
||||
config BT_MESH_SOL_PDU_RPL_CLI
|
||||
bool "Support for Solicitation PDU RPL Configuration Client model"
|
||||
help
|
||||
The Solicitation PDU RPL Configuration Client is used to support the
|
||||
functionality of removing addresses from the solicitation replay
|
||||
protection list (SRPL) of a node that supports the Solicitation
|
||||
PDU RPL Configuration Server model.
|
||||
|
||||
config BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT
|
||||
int "Solicitation PDU RPL Configuration Client model timeout in milliseconds"
|
||||
default 5000
|
||||
depends on BT_MESH_SOL_PDU_RPL_CLI
|
||||
help
|
||||
This timeout controls how long Solicitation PDU RPL Configuration Client waits
|
||||
for a response message to arrive. This value can be changed at runtime
|
||||
using @ref bt_mesh_sol_pdu_rpl_cli_timeout_set.
|
||||
|
||||
menu "Transport SAR configuration"
|
||||
|
||||
config BT_MESH_SAR_TX_SEG_INT_STEP
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "prov.h"
|
||||
#include "proxy.h"
|
||||
#include "pb_gatt_srv.h"
|
||||
#include "solicitation.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -306,6 +307,15 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
|
|||
case BT_DATA_MESH_BEACON:
|
||||
bt_mesh_beacon_recv(buf);
|
||||
break;
|
||||
case BT_DATA_UUID16_SOME:
|
||||
/* Fall through */
|
||||
case BT_DATA_UUID16_ALL:
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)) {
|
||||
/* Restore buffer with Solicitation PDU */
|
||||
net_buf_simple_restore(buf, &state);
|
||||
bt_mesh_sol_recv(buf, len - 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -108,3 +108,6 @@ static inline void bt_mesh_adv_send_end(
|
|||
}
|
||||
|
||||
int bt_mesh_scan_active_set(bool active);
|
||||
|
||||
int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval,
|
||||
const struct bt_data *ad, size_t ad_len);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "adv.h"
|
||||
#include "net.h"
|
||||
#include "proxy.h"
|
||||
#include "solicitation.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -182,38 +183,46 @@ static int adv_start(struct bt_mesh_ext_adv *adv,
|
|||
return err;
|
||||
}
|
||||
|
||||
static int buf_send(struct bt_mesh_ext_adv *adv, struct net_buf *buf)
|
||||
static int bt_data_send(struct bt_mesh_ext_adv *adv, uint8_t num_events, uint16_t adv_interval,
|
||||
const struct bt_data *ad, size_t ad_len)
|
||||
{
|
||||
struct bt_le_ext_adv_start_param start = {
|
||||
.num_events =
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1,
|
||||
.num_events = num_events,
|
||||
};
|
||||
|
||||
adv_interval = MAX(ADV_INT_FAST_MS, adv_interval);
|
||||
|
||||
/* Only update advertising parameters if they're different */
|
||||
if (adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_interval)) {
|
||||
adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_interval);
|
||||
adv->adv_param.interval_max = adv->adv_param.interval_min;
|
||||
atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS);
|
||||
}
|
||||
|
||||
return adv_start(adv, &adv->adv_param, &start, ad, ad_len, NULL, 0);
|
||||
}
|
||||
|
||||
static int buf_send(struct bt_mesh_ext_adv *adv, struct net_buf *buf)
|
||||
{
|
||||
uint8_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1;
|
||||
uint16_t duration, adv_int;
|
||||
struct bt_data ad;
|
||||
int err;
|
||||
|
||||
adv_int = MAX(ADV_INT_FAST_MS,
|
||||
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
|
||||
adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit);
|
||||
/* Upper boundary estimate: */
|
||||
duration = start.num_events * (adv_int + 10);
|
||||
duration = num_events * (adv_int + 10);
|
||||
|
||||
LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, buf->len,
|
||||
bt_hex(buf->data, buf->len));
|
||||
LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
|
||||
buf->len, bt_hex(buf->data, buf->len));
|
||||
LOG_DBG("count %u interval %ums duration %ums",
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, duration);
|
||||
num_events, adv_int, duration);
|
||||
|
||||
ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
|
||||
/* Only update advertising parameters if they're different */
|
||||
if (adv->adv_param.interval_min != BT_MESH_ADV_SCAN_UNIT(adv_int)) {
|
||||
adv->adv_param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_int);
|
||||
adv->adv_param.interval_max = adv->adv_param.interval_min;
|
||||
atomic_set_bit(adv->flags, ADV_FLAG_UPDATE_PARAMS);
|
||||
}
|
||||
|
||||
err = adv_start(adv, &adv->adv_param, &start, &ad, 1, NULL, 0);
|
||||
err = bt_data_send(adv, num_events, adv_int, &ad, 1);
|
||||
if (!err) {
|
||||
adv->buf = net_buf_ref(buf);
|
||||
}
|
||||
|
@ -293,6 +302,11 @@ static void send_pending_adv(struct k_work *work)
|
|||
return;
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) &&
|
||||
!bt_mesh_sol_send()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!bt_mesh_adv_gatt_send()) {
|
||||
atomic_set_bit(adv->flags, ADV_FLAG_PROXY);
|
||||
}
|
||||
|
@ -300,7 +314,6 @@ static void send_pending_adv(struct k_work *work)
|
|||
if (atomic_test_and_clear_bit(adv->flags, ADV_FLAG_SCHEDULE_PENDING)) {
|
||||
schedule_send(adv);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static bool schedule_send(struct bt_mesh_ext_adv *adv)
|
||||
|
@ -474,3 +487,9 @@ int bt_mesh_adv_gatt_start(const struct bt_le_adv_param *param,
|
|||
|
||||
return adv_start(adv, param, &start, ad, ad_len, sd, sd_len);
|
||||
}
|
||||
|
||||
int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_interval,
|
||||
const struct bt_data *ad, size_t ad_len)
|
||||
{
|
||||
return bt_data_send(&adv_main, num_events, adv_interval, ad, ad_len);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "beacon.h"
|
||||
#include "host/ecc.h"
|
||||
#include "prov.h"
|
||||
#include "solicitation.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_ADV_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -40,19 +41,22 @@ static struct k_thread adv_thread_data;
|
|||
static K_KERNEL_STACK_DEFINE(adv_thread_stack, CONFIG_BT_MESH_ADV_STACK_SIZE);
|
||||
static int32_t adv_timeout;
|
||||
|
||||
static inline void adv_send(struct net_buf *buf)
|
||||
static int bt_data_send(uint8_t num_events, uint16_t adv_int,
|
||||
const struct bt_data *ad, size_t ad_len,
|
||||
struct bt_mesh_adv *adv)
|
||||
{
|
||||
struct bt_le_adv_param param = {};
|
||||
uint64_t uptime = k_uptime_get();
|
||||
uint16_t duration;
|
||||
int err;
|
||||
const int32_t adv_int_min =
|
||||
((bt_dev.hci_version >= BT_HCI_VERSION_5_0) ?
|
||||
ADV_INT_FAST_MS :
|
||||
ADV_INT_DEFAULT_MS);
|
||||
struct bt_le_adv_param param = {};
|
||||
uint16_t duration, adv_int;
|
||||
struct bt_data ad;
|
||||
int err;
|
||||
ADV_INT_FAST_MS :
|
||||
ADV_INT_DEFAULT_MS);
|
||||
|
||||
adv_int = MAX(adv_int_min,
|
||||
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
|
||||
adv_int = MAX(adv_int_min, adv_int);
|
||||
|
||||
ARG_UNUSED(uptime);
|
||||
|
||||
/* Zephyr Bluetooth Low Energy Controller for mesh stack uses
|
||||
* pre-emptible continuous scanning, allowing advertising events to be
|
||||
|
@ -62,9 +66,7 @@ static inline void adv_send(struct net_buf *buf)
|
|||
* advertising is stopped and started in quick succession, hence add
|
||||
* advertising interval to the total advertising duration.
|
||||
*/
|
||||
duration = adv_int +
|
||||
((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
|
||||
(adv_int + 10));
|
||||
duration = adv_int + num_events * (adv_int + 10);
|
||||
|
||||
/* Zephyr Bluetooth Low Energy Controller built for nRF51x SoCs use
|
||||
* CONFIG_BT_CTLR_LOW_LAT=y, and continuous scanning cannot be
|
||||
|
@ -77,14 +79,8 @@ static inline void adv_send(struct net_buf *buf)
|
|||
duration += BT_MESH_SCAN_WINDOW_MS;
|
||||
}
|
||||
|
||||
LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type, buf->len,
|
||||
bt_hex(buf->data, buf->len));
|
||||
LOG_DBG("count %u interval %ums duration %ums",
|
||||
BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1, adv_int, duration);
|
||||
|
||||
ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
num_events, adv_int, duration);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR)) {
|
||||
param.options = BT_LE_ADV_OPT_USE_IDENTITY;
|
||||
|
@ -96,30 +92,54 @@ static inline void adv_send(struct net_buf *buf)
|
|||
param.interval_min = BT_MESH_ADV_SCAN_UNIT(adv_int);
|
||||
param.interval_max = param.interval_min;
|
||||
|
||||
uint64_t time = k_uptime_get();
|
||||
|
||||
ARG_UNUSED(time);
|
||||
|
||||
err = bt_le_adv_start(¶m, &ad, 1, NULL, 0);
|
||||
|
||||
bt_mesh_adv_send_start(duration, err, BT_MESH_ADV(buf));
|
||||
err = bt_le_adv_start(¶m, ad, ad_len, NULL, 0);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Advertising failed: err %d", err);
|
||||
return;
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Advertising started. Sleeping %u ms", duration);
|
||||
|
||||
if (adv) {
|
||||
bt_mesh_adv_send_start(duration, err, adv);
|
||||
}
|
||||
|
||||
k_sleep(K_MSEC(duration));
|
||||
|
||||
err = bt_le_adv_stop();
|
||||
if (err) {
|
||||
LOG_ERR("Stopping advertising failed: err %d", err);
|
||||
return;
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Advertising stopped (%u ms)", (uint32_t) k_uptime_delta(&time));
|
||||
LOG_DBG("Advertising stopped (%u ms)", (uint32_t) k_uptime_delta(&uptime));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bt_mesh_adv_bt_data_send(uint8_t num_events, uint16_t adv_int,
|
||||
const struct bt_data *ad, size_t ad_len)
|
||||
{
|
||||
return bt_data_send(num_events, adv_int, ad, ad_len, NULL);
|
||||
}
|
||||
|
||||
static inline void buf_send(struct net_buf *buf)
|
||||
{
|
||||
uint16_t num_events = BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1;
|
||||
uint16_t adv_int;
|
||||
struct bt_data ad;
|
||||
|
||||
adv_int = BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit);
|
||||
|
||||
LOG_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
|
||||
buf->len, bt_hex(buf->data, buf->len));
|
||||
|
||||
ad.type = bt_mesh_adv_type[BT_MESH_ADV(buf)->type];
|
||||
ad.data_len = buf->len;
|
||||
ad.data = buf->data;
|
||||
|
||||
bt_data_send(num_events, adv_int, &ad, 1, BT_MESH_ADV(buf));
|
||||
}
|
||||
|
||||
static void adv_thread(void *p1, void *p2, void *p3)
|
||||
|
@ -131,6 +151,10 @@ static void adv_thread(void *p1, void *p2, void *p3)
|
|||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) {
|
||||
buf = bt_mesh_adv_buf_get(K_NO_WAIT);
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) {
|
||||
(void)bt_mesh_sol_send();
|
||||
}
|
||||
|
||||
while (!buf) {
|
||||
|
||||
/* Adv timeout may be set by a call from proxy
|
||||
|
@ -141,6 +165,10 @@ static void adv_thread(void *p1, void *p2, void *p3)
|
|||
|
||||
buf = bt_mesh_adv_buf_get(SYS_TIMEOUT_MS(adv_timeout));
|
||||
bt_le_adv_stop();
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) && !buf) {
|
||||
(void)bt_mesh_sol_send();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
buf = bt_mesh_adv_buf_get(K_FOREVER);
|
||||
|
@ -153,7 +181,7 @@ static void adv_thread(void *p1, void *p2, void *p3)
|
|||
/* busy == 0 means this was canceled */
|
||||
if (BT_MESH_ADV(buf)->busy) {
|
||||
BT_MESH_ADV(buf)->busy = 0U;
|
||||
adv_send(buf);
|
||||
buf_send(buf);
|
||||
}
|
||||
|
||||
net_buf_unref(buf);
|
||||
|
|
|
@ -34,6 +34,9 @@ struct cfg_val {
|
|||
uint8_t priv_beacon;
|
||||
uint8_t priv_beacon_int;
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
uint8_t on_demand_state;
|
||||
#endif
|
||||
};
|
||||
|
||||
void bt_mesh_beacon_set(bool beacon)
|
||||
|
@ -138,6 +141,33 @@ uint8_t bt_mesh_priv_beacon_update_interval_get(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
int bt_mesh_od_priv_proxy_get(void)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
return bt_mesh.on_demand_state;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
int bt_mesh_od_priv_proxy_set(uint8_t on_demand_proxy)
|
||||
{
|
||||
#if !IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
return -ENOTSUP;
|
||||
#else
|
||||
|
||||
if (bt_mesh_priv_gatt_proxy_get() != BT_MESH_FEATURE_NOT_SUPPORTED) {
|
||||
bt_mesh.on_demand_state = on_demand_proxy;
|
||||
}
|
||||
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool node_id_is_running(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
return sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING;
|
||||
|
@ -409,6 +439,9 @@ static int cfg_set(const char *name, size_t len_rd,
|
|||
bt_mesh_gatt_proxy_set(cfg.gatt_proxy);
|
||||
bt_mesh_friend_set(cfg.frnd);
|
||||
bt_mesh_default_ttl_set(cfg.default_ttl);
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
bt_mesh_od_priv_proxy_set(cfg.on_demand_state);
|
||||
#endif
|
||||
|
||||
LOG_DBG("Restored configuration state");
|
||||
|
||||
|
@ -445,6 +478,9 @@ static void store_pending_cfg(void)
|
|||
val.priv_beacon = bt_mesh_priv_beacon_get();
|
||||
val.priv_beacon_int = bt_mesh_priv_beacon_update_interval_get();
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
val.on_demand_state = bt_mesh_od_priv_proxy_get();
|
||||
#endif
|
||||
|
||||
|
||||
err = settings_save_one("bt/mesh/Cfg", &val, sizeof(val));
|
||||
|
|
|
@ -291,12 +291,11 @@ int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16])
|
|||
static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu,
|
||||
uint32_t iv_index)
|
||||
{
|
||||
memset(nonce, 0, 13);
|
||||
|
||||
/* Nonce Type */
|
||||
nonce[0] = 0x03;
|
||||
|
||||
/* Pad */
|
||||
nonce[1] = 0x00;
|
||||
|
||||
/* Sequence Number */
|
||||
nonce[2] = pdu[2];
|
||||
nonce[3] = pdu[3];
|
||||
|
@ -306,14 +305,27 @@ static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu,
|
|||
nonce[5] = pdu[5];
|
||||
nonce[6] = pdu[6];
|
||||
|
||||
/* Pad */
|
||||
nonce[7] = 0U;
|
||||
nonce[8] = 0U;
|
||||
|
||||
/* IV Index */
|
||||
sys_put_be32(iv_index, &nonce[9]);
|
||||
}
|
||||
|
||||
static void create_proxy_sol_nonce(uint8_t nonce[13], const uint8_t *pdu)
|
||||
{
|
||||
memset(nonce, 0, 13);
|
||||
|
||||
/* Nonce Type */
|
||||
nonce[0] = 0x04;
|
||||
|
||||
/* Sequence Number */
|
||||
nonce[2] = pdu[2];
|
||||
nonce[3] = pdu[3];
|
||||
nonce[4] = pdu[4];
|
||||
|
||||
/* Source Address */
|
||||
nonce[5] = pdu[5];
|
||||
nonce[6] = pdu[6];
|
||||
}
|
||||
|
||||
static void create_net_nonce(uint8_t nonce[13], const uint8_t *pdu,
|
||||
uint32_t iv_index)
|
||||
{
|
||||
|
@ -367,7 +379,7 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index,
|
|||
}
|
||||
|
||||
int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
||||
uint32_t iv_index, bool proxy)
|
||||
uint32_t iv_index, enum bt_mesh_nonce_type type)
|
||||
{
|
||||
uint8_t mic_len = NET_MIC_LEN(buf->data);
|
||||
uint8_t nonce[13];
|
||||
|
@ -376,8 +388,11 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
|||
LOG_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16), mic_len);
|
||||
LOG_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len));
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && type == BT_MESH_NONCE_PROXY) {
|
||||
create_proxy_nonce(nonce, buf->data, iv_index);
|
||||
} else if (IS_ENABLED(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV) &&
|
||||
type == BT_MESH_NONCE_SOLICITATION) {
|
||||
create_proxy_sol_nonce(nonce, buf->data);
|
||||
} else {
|
||||
create_net_nonce(nonce, buf->data, iv_index);
|
||||
}
|
||||
|
@ -394,7 +409,7 @@ int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
|||
}
|
||||
|
||||
int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
||||
uint32_t iv_index, bool proxy)
|
||||
uint32_t iv_index, enum bt_mesh_nonce_type type)
|
||||
{
|
||||
uint8_t mic_len = NET_MIC_LEN(buf->data);
|
||||
uint8_t nonce[13];
|
||||
|
@ -402,8 +417,11 @@ int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
|||
LOG_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len));
|
||||
LOG_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16), mic_len);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) {
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && type == BT_MESH_NONCE_PROXY) {
|
||||
create_proxy_nonce(nonce, buf->data, iv_index);
|
||||
} else if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION) &&
|
||||
type == BT_MESH_NONCE_SOLICITATION) {
|
||||
create_proxy_sol_nonce(nonce, buf->data);
|
||||
} else {
|
||||
create_net_nonce(nonce, buf->data, iv_index);
|
||||
}
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
enum bt_mesh_nonce_type {
|
||||
BT_MESH_NONCE_NETWORK,
|
||||
BT_MESH_NONCE_PROXY,
|
||||
BT_MESH_NONCE_SOLICITATION,
|
||||
};
|
||||
|
||||
int bt_mesh_s1(const char *m, size_t m_len, uint8_t salt[16]);
|
||||
|
||||
|
@ -110,11 +115,10 @@ int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index,
|
|||
const uint8_t privacy_key[16]);
|
||||
|
||||
int bt_mesh_net_encrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
||||
uint32_t iv_index, bool proxy);
|
||||
uint32_t iv_index, enum bt_mesh_nonce_type type);
|
||||
|
||||
int bt_mesh_net_decrypt(const uint8_t key[16], struct net_buf_simple *buf,
|
||||
uint32_t iv_index, bool proxy);
|
||||
|
||||
uint32_t iv_index, enum bt_mesh_nonce_type type);
|
||||
|
||||
struct bt_mesh_app_crypto_ctx {
|
||||
bool dev_key;
|
||||
|
|
|
@ -114,6 +114,14 @@
|
|||
#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 OP_OD_PRIV_PROXY_GET BT_MESH_MODEL_OP_2(0x80, 0x69)
|
||||
#define OP_OD_PRIV_PROXY_SET BT_MESH_MODEL_OP_2(0x80, 0x6a)
|
||||
#define OP_OD_PRIV_PROXY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x6b)
|
||||
|
||||
#define OP_SOL_PDU_RPL_ITEM_CLEAR BT_MESH_MODEL_OP_2(0x80, 0x78)
|
||||
#define OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED BT_MESH_MODEL_OP_2(0x80, 0x79)
|
||||
#define OP_SOL_PDU_RPL_ITEM_STATUS BT_MESH_MODEL_OP_2(0x80, 0x7a)
|
||||
|
||||
#define STATUS_SUCCESS 0x00
|
||||
#define STATUS_INVALID_ADDRESS 0x01
|
||||
#define STATUS_INVALID_MODEL 0x02
|
||||
|
|
|
@ -514,7 +514,7 @@ static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf,
|
|||
|
||||
buf->data[0] = (cred->nid | (iv_index & 1) << 7);
|
||||
|
||||
if (bt_mesh_net_encrypt(cred->enc, &buf->b, iv_index, false)) {
|
||||
if (bt_mesh_net_encrypt(cred->enc, &buf->b, iv_index, BT_MESH_NONCE_NETWORK)) {
|
||||
LOG_ERR("Encrypting failed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "pb_gatt_srv.h"
|
||||
#include "settings.h"
|
||||
#include "mesh.h"
|
||||
#include "solicitation.h"
|
||||
#include "gatt_cli.h"
|
||||
|
||||
LOG_MODULE_REGISTER(bt_mesh_main, CONFIG_BT_MESH_LOG_LEVEL);
|
||||
|
@ -352,6 +353,10 @@ void bt_mesh_reset(void)
|
|||
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
|
||||
bt_mesh_prov_reset();
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_SOLICITATION)) {
|
||||
bt_mesh_sol_reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool bt_mesh_is_provisioned(void)
|
||||
|
|
|
@ -476,7 +476,7 @@ static int net_header_encode(struct bt_mesh_net_tx *tx, uint8_t nid,
|
|||
|
||||
static int net_encrypt(struct net_buf_simple *buf,
|
||||
const struct bt_mesh_net_cred *cred, uint32_t iv_index,
|
||||
bool proxy)
|
||||
enum bt_mesh_nonce_type proxy)
|
||||
{
|
||||
int err;
|
||||
|
||||
|
@ -489,7 +489,7 @@ static int net_encrypt(struct net_buf_simple *buf,
|
|||
}
|
||||
|
||||
int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
|
||||
bool proxy)
|
||||
enum bt_mesh_nonce_type type)
|
||||
{
|
||||
const struct bt_mesh_net_cred *cred;
|
||||
int err;
|
||||
|
@ -500,7 +500,7 @@ int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
|
|||
return err;
|
||||
}
|
||||
|
||||
return net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, proxy);
|
||||
return net_encrypt(buf, cred, BT_MESH_NET_IVI_TX, type);
|
||||
}
|
||||
|
||||
static int net_loopback(const struct bt_mesh_net_tx *tx, const uint8_t *data,
|
||||
|
@ -570,7 +570,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
|
|||
goto done;
|
||||
}
|
||||
|
||||
err = net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_TX, false);
|
||||
err = net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_TX, BT_MESH_NONCE_NETWORK);
|
||||
if (err) {
|
||||
goto done;
|
||||
}
|
||||
|
@ -743,7 +743,7 @@ static void bt_mesh_net_relay(struct net_buf_simple *sbuf,
|
|||
* the normal TX IVI (which may be different) since the transport
|
||||
* layer nonce includes the IVI.
|
||||
*/
|
||||
if (net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_RX(rx), false)) {
|
||||
if (net_encrypt(&buf->b, cred, BT_MESH_NET_IVI_RX(rx), BT_MESH_NONCE_NETWORK)) {
|
||||
LOG_ERR("Re-encrypting failed");
|
||||
goto done;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#define BT_MESH_NET_MAX_PDU_LEN (BT_MESH_NET_HDR_LEN + 16 + 4)
|
||||
|
||||
struct bt_mesh_net_cred;
|
||||
enum bt_mesh_nonce_type;
|
||||
|
||||
struct bt_mesh_node {
|
||||
uint16_t addr;
|
||||
|
@ -189,6 +190,7 @@ enum {
|
|||
BT_MESH_FRIEND,
|
||||
BT_MESH_PRIV_BEACON,
|
||||
BT_MESH_PRIV_GATT_PROXY,
|
||||
BT_MESH_OD_PRIV_PROXY,
|
||||
|
||||
/* Don't touch - intentionally last */
|
||||
BT_MESH_FLAG_COUNT,
|
||||
|
@ -231,6 +233,9 @@ struct bt_mesh_net {
|
|||
|
||||
#if defined(CONFIG_BT_MESH_RPR_SRV)
|
||||
uint8_t dev_key_cand[16];
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
uint8_t on_demand_state;
|
||||
#endif
|
||||
struct bt_mesh_sar_tx sar_tx; /* Transport SAR Transmitter configuration */
|
||||
struct bt_mesh_sar_rx sar_rx; /* Transport SAR Receiver configuration */
|
||||
|
@ -284,7 +289,7 @@ int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
|
|||
bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update);
|
||||
|
||||
int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
|
||||
bool proxy);
|
||||
enum bt_mesh_nonce_type type);
|
||||
|
||||
int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
|
||||
const struct bt_mesh_send_cb *cb, void *cb_data);
|
||||
|
|
113
subsys/bluetooth/mesh/od_priv_proxy_cli.c
Normal file
113
subsys/bluetooth/mesh/od_priv_proxy_cli.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#include "cfg.h"
|
||||
#include "access.h"
|
||||
#include "foundation.h"
|
||||
#include "msg.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_od_priv_proxy_cli);
|
||||
|
||||
/** On-Demand Private Proxy Client Model Context */
|
||||
static struct bt_mesh_od_priv_proxy_cli *cli;
|
||||
|
||||
static int32_t msg_timeout;
|
||||
|
||||
static int handle_proxy_status(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t *state;
|
||||
uint8_t state_rsp;
|
||||
|
||||
state_rsp = net_buf_simple_pull_u8(buf);
|
||||
|
||||
LOG_DBG("On-Demand Private Proxy status received: state: %u", state_rsp);
|
||||
|
||||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_OD_PRIV_PROXY_STATUS,
|
||||
ctx->addr, (void **)&state)) {
|
||||
|
||||
if (state) {
|
||||
*state = state_rsp;
|
||||
}
|
||||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||||
}
|
||||
|
||||
|
||||
if (cli->od_status) {
|
||||
cli->od_status(cli, ctx->addr, state_rsp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op _bt_mesh_od_priv_proxy_cli_op[] = {
|
||||
{ OP_OD_PRIV_PROXY_STATUS, BT_MESH_LEN_EXACT(1), handle_proxy_status },
|
||||
|
||||
BT_MESH_MODEL_OP_END
|
||||
};
|
||||
|
||||
int bt_mesh_od_priv_proxy_cli_get(struct bt_mesh_msg_ctx *ctx, uint8_t *val)
|
||||
{
|
||||
const struct bt_mesh_msg_rsp_ctx rsp = {
|
||||
.ack = &cli->ack_ctx,
|
||||
.op = OP_OD_PRIV_PROXY_STATUS,
|
||||
.user_data = val,
|
||||
.timeout = msg_timeout,
|
||||
};
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_OD_PRIV_PROXY_GET, 0);
|
||||
bt_mesh_model_msg_init(&msg, OP_OD_PRIV_PROXY_GET);
|
||||
|
||||
return bt_mesh_msg_ackd_send(cli->model, ctx, &msg, val ? &rsp : NULL);
|
||||
}
|
||||
|
||||
int bt_mesh_od_priv_proxy_cli_set(struct bt_mesh_msg_ctx *ctx, uint8_t val, uint8_t *val_rsp)
|
||||
{
|
||||
const struct bt_mesh_msg_rsp_ctx rsp = {
|
||||
.ack = &cli->ack_ctx,
|
||||
.op = OP_OD_PRIV_PROXY_STATUS,
|
||||
.user_data = val_rsp,
|
||||
.timeout = msg_timeout,
|
||||
};
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_OD_PRIV_PROXY_SET, 1);
|
||||
bt_mesh_model_msg_init(&msg, OP_OD_PRIV_PROXY_SET);
|
||||
|
||||
net_buf_simple_add_u8(&msg, val);
|
||||
|
||||
return bt_mesh_msg_ackd_send(cli->model, ctx, &msg, val_rsp ? &rsp : NULL);
|
||||
}
|
||||
|
||||
void bt_mesh_od_priv_proxy_cli_timeout_set(int32_t timeout)
|
||||
{
|
||||
msg_timeout = timeout;
|
||||
}
|
||||
|
||||
static int on_demand_proxy_cli_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("On-Demand Private Proxy client not in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cli = mod->user_data;
|
||||
cli->model = mod;
|
||||
mod->keys[0] = BT_MESH_KEY_DEV_ANY;
|
||||
mod->flags |= BT_MESH_MOD_DEVKEY_ONLY;
|
||||
msg_timeout = CONFIG_BT_MESH_OD_PRIV_PROXY_CLI_TIMEOUT;
|
||||
|
||||
bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb _bt_mesh_od_priv_proxy_cli_cb = {
|
||||
.init = on_demand_proxy_cli_init,
|
||||
};
|
94
subsys/bluetooth/mesh/od_priv_proxy_srv.c
Normal file
94
subsys/bluetooth/mesh/od_priv_proxy_srv.c
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#include "access.h"
|
||||
#include "cfg.h"
|
||||
#include "foundation.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_od_priv_proxy_srv);
|
||||
|
||||
static int proxy_status_rsp(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_OD_PRIV_PROXY_STATUS, 1);
|
||||
bt_mesh_model_msg_init(&buf, OP_OD_PRIV_PROXY_STATUS);
|
||||
|
||||
net_buf_simple_add_u8(&buf, bt_mesh_od_priv_proxy_get());
|
||||
|
||||
bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_proxy_get(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
LOG_DBG("");
|
||||
|
||||
proxy_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_proxy_set(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
uint8_t state;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
state = net_buf_simple_pull_u8(buf);
|
||||
LOG_DBG("state %d", state);
|
||||
|
||||
bt_mesh_od_priv_proxy_set(state);
|
||||
proxy_status_rsp(mod, ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op _bt_mesh_od_priv_proxy_srv_op[] = {
|
||||
{ OP_OD_PRIV_PROXY_GET, BT_MESH_LEN_EXACT(0), handle_proxy_get },
|
||||
{ OP_OD_PRIV_PROXY_SET, BT_MESH_LEN_EXACT(1), handle_proxy_set },
|
||||
|
||||
BT_MESH_MODEL_OP_END
|
||||
};
|
||||
|
||||
static int od_priv_proxy_srv_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
struct bt_mesh_model *priv_beacon_srv = bt_mesh_model_find(
|
||||
bt_mesh_model_elem(mod), BT_MESH_MODEL_ID_PRIV_BEACON_SRV);
|
||||
struct bt_mesh_model *sol_pdu_rpl_srv = bt_mesh_model_find(
|
||||
bt_mesh_model_elem(mod), BT_MESH_MODEL_ID_SOL_PDU_RPL_SRV);
|
||||
|
||||
if (priv_beacon_srv == NULL) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("On-Demand Private Proxy server not in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mod->keys[0] = BT_MESH_KEY_DEV_LOCAL;
|
||||
mod->flags |= BT_MESH_MOD_DEVKEY_ONLY;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_MESH_MODEL_EXTENSIONS)) {
|
||||
bt_mesh_model_extend(mod, priv_beacon_srv);
|
||||
bt_mesh_model_correspond(mod, sol_pdu_rpl_srv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb _bt_mesh_od_priv_proxy_srv_cb = {
|
||||
.init = od_priv_proxy_srv_init,
|
||||
};
|
|
@ -31,6 +31,7 @@
|
|||
#include "access.h"
|
||||
#include "proxy.h"
|
||||
#include "proxy_msg.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_PROXY_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -210,7 +211,7 @@ static void send_filter_status(struct bt_mesh_proxy_client *client,
|
|||
|
||||
LOG_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
|
||||
|
||||
err = bt_mesh_net_encode(&tx, buf, true);
|
||||
err = bt_mesh_net_encode(&tx, buf, BT_MESH_NONCE_PROXY);
|
||||
if (err) {
|
||||
LOG_ERR("Encoding Proxy cfg message failed (err %d)", err);
|
||||
return;
|
||||
|
@ -615,6 +616,9 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub)
|
|||
}
|
||||
|
||||
return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
sub->solicited ||
|
||||
#endif
|
||||
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
|
||||
}
|
||||
|
@ -668,6 +672,37 @@ static int sub_count(void)
|
|||
return count;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
static void gatt_proxy_solicited(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
int64_t now = k_uptime_get();
|
||||
int64_t timeout = 0;
|
||||
int32_t remaining;
|
||||
|
||||
if (sub->priv_net_id_sent > 0) {
|
||||
timeout = sub->priv_net_id_sent + MSEC_PER_SEC * bt_mesh_od_priv_proxy_get();
|
||||
}
|
||||
|
||||
remaining = MIN(timeout - now, INT32_MAX);
|
||||
if ((timeout > 0 && now > timeout) || (remaining / MSEC_PER_SEC < 1)) {
|
||||
LOG_DBG("Advertising Private Network ID timed out "
|
||||
"after solicitation");
|
||||
sub->priv_net_id_sent = 0;
|
||||
sub->solicited = false;
|
||||
} else {
|
||||
LOG_DBG("Advertising Private Network ID for %ds"
|
||||
"(%d remaining)",
|
||||
bt_mesh_od_priv_proxy_get(),
|
||||
remaining / MSEC_PER_SEC);
|
||||
priv_net_id_adv(sub, remaining);
|
||||
|
||||
if (!sub->priv_net_id_sent) {
|
||||
sub->priv_net_id_sent = now;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
int32_t remaining = SYS_FOREVER_MS;
|
||||
|
@ -754,6 +789,13 @@ static int gatt_proxy_advertise(struct bt_mesh_subnet *sub)
|
|||
err = net_id_adv(sub, remaining);
|
||||
planned = true;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
else if (bt_mesh_od_priv_proxy_get() > 0 &&
|
||||
sub->solicited) {
|
||||
gatt_proxy_solicited(sub);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
beacon_sub = bt_mesh_subnet_next(sub);
|
||||
|
@ -970,6 +1012,14 @@ bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst)
|
|||
return relayed;
|
||||
}
|
||||
|
||||
static void solicitation_reset(struct bt_mesh_subnet *sub)
|
||||
{
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
sub->solicited = false;
|
||||
sub->priv_net_id_sent = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gatt_connected(struct bt_conn *conn, uint8_t err)
|
||||
{
|
||||
struct bt_mesh_proxy_client *client;
|
||||
|
@ -990,6 +1040,11 @@ static void gatt_connected(struct bt_conn *conn, uint8_t err)
|
|||
client->cli = bt_mesh_proxy_role_setup(conn, proxy_send,
|
||||
proxy_msg_recv);
|
||||
|
||||
/* If connection was formed after Proxy Solicitation we need to stop future
|
||||
* Private Network ID advertisements
|
||||
*/
|
||||
bt_mesh_subnet_foreach(solicitation_reset);
|
||||
|
||||
/* Try to re-enable advertising in case it's possible */
|
||||
if (bt_mesh_proxy_has_avail_conn()) {
|
||||
bt_mesh_adv_gatt_update();
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#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>
|
||||
|
@ -113,7 +114,8 @@ SETTINGS_STATIC_HANDLER_DEFINE(bt_mesh, "bt/mesh", NULL, NULL, mesh_commit,
|
|||
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_VA_PENDING) | \
|
||||
BIT(BT_MESH_SETTINGS_SSEQ_PENDING))
|
||||
|
||||
void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
|
||||
{
|
||||
|
@ -124,7 +126,8 @@ void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag 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_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 {
|
||||
|
@ -209,6 +212,18 @@ static void store_pending(struct k_work *work)
|
|||
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)
|
||||
|
|
|
@ -17,6 +17,8 @@ enum bt_mesh_settings_flag {
|
|||
BT_MESH_SETTINGS_MOD_PENDING,
|
||||
BT_MESH_SETTINGS_VA_PENDING,
|
||||
BT_MESH_SETTINGS_CDB_PENDING,
|
||||
BT_MESH_SETTINGS_SRPL_PENDING,
|
||||
BT_MESH_SETTINGS_SSEQ_PENDING,
|
||||
|
||||
BT_MESH_SETTINGS_FLAG_COUNT,
|
||||
};
|
||||
|
|
180
subsys/bluetooth/mesh/sol_pdu_rpl_cli.c
Normal file
180
subsys/bluetooth/mesh/sol_pdu_rpl_cli.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#include "foundation.h"
|
||||
#include "msg.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_cli);
|
||||
|
||||
static struct bt_mesh_sol_pdu_rpl_cli *cli;
|
||||
|
||||
static int32_t msg_timeout;
|
||||
|
||||
struct sol_rpl_param {
|
||||
uint16_t *start;
|
||||
uint8_t *len;
|
||||
};
|
||||
|
||||
static int handle_status(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
struct sol_rpl_param *param;
|
||||
uint16_t primary, range;
|
||||
uint8_t len = 0;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
if (buf->len > 3) {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
range = net_buf_simple_pull_le16(buf);
|
||||
primary = range >> 1;
|
||||
if (primary == 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (range & BIT(0)) {
|
||||
if (buf->len == 0) {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
len = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (len < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DBG("SRPL clear status received: range start: %u, range len: %u",
|
||||
primary, len);
|
||||
|
||||
if (bt_mesh_msg_ack_ctx_match(&cli->ack_ctx, OP_SOL_PDU_RPL_ITEM_STATUS,
|
||||
ctx->addr, (void **)¶m)) {
|
||||
if (param->start) {
|
||||
*param->start = primary;
|
||||
}
|
||||
|
||||
if (param->len) {
|
||||
*param->len = len;
|
||||
}
|
||||
|
||||
bt_mesh_msg_ack_ctx_rx(&cli->ack_ctx);
|
||||
}
|
||||
|
||||
if (cli->srpl_status) {
|
||||
cli->srpl_status(cli, ctx->addr, primary, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sol_pdu_rpl_clear_pdu_create(uint16_t range_start, uint8_t range_len,
|
||||
struct net_buf_simple *msg)
|
||||
{
|
||||
uint16_t range;
|
||||
|
||||
range = range_start << 1 | (range_len >= 2 ? 1U : 0);
|
||||
net_buf_simple_add_le16(msg, range);
|
||||
if (range_len >= 2) {
|
||||
net_buf_simple_add_u8(msg, range_len);
|
||||
}
|
||||
}
|
||||
|
||||
int bt_mesh_sol_pdu_rpl_clear(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
||||
uint8_t range_len, uint16_t *start_rsp, uint8_t *len_rsp)
|
||||
{
|
||||
struct sol_rpl_param param = {
|
||||
.start = start_rsp,
|
||||
.len = len_rsp,
|
||||
};
|
||||
|
||||
const struct bt_mesh_msg_rsp_ctx rsp = {
|
||||
.ack = &cli->ack_ctx,
|
||||
.op = OP_SOL_PDU_RPL_ITEM_STATUS,
|
||||
.user_data = ¶m,
|
||||
.timeout = msg_timeout,
|
||||
};
|
||||
|
||||
if (range_len == 1) {
|
||||
LOG_ERR("Invalid range length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
|
||||
LOG_ERR("Range outside unicast address range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
|
||||
range_len >= 2 ? 3 : 2);
|
||||
|
||||
bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR);
|
||||
|
||||
sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
|
||||
|
||||
return bt_mesh_msg_ackd_send(cli->model, ctx, &msg,
|
||||
(start_rsp && len_rsp) ? &rsp : NULL);
|
||||
}
|
||||
|
||||
int bt_mesh_sol_pdu_rpl_clear_unack(struct bt_mesh_msg_ctx *ctx, uint16_t range_start,
|
||||
uint8_t range_len)
|
||||
{
|
||||
if (range_len == 1) {
|
||||
LOG_ERR("Invalid range length");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((range_start + (range_len > 1 ? range_len : 0)) > 0x8000 || range_start == 0) {
|
||||
LOG_ERR("Range outside unicast address range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
BT_MESH_MODEL_BUF_DEFINE(msg, OP_SOL_PDU_RPL_ITEM_CLEAR,
|
||||
range_len >= 2 ? 3 : 2);
|
||||
|
||||
bt_mesh_model_msg_init(&msg, OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED);
|
||||
|
||||
sol_pdu_rpl_clear_pdu_create(range_start, range_len, &msg);
|
||||
|
||||
return bt_mesh_msg_send(cli->model, ctx, &msg);
|
||||
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_cli_op[] = {
|
||||
{ OP_SOL_PDU_RPL_ITEM_STATUS, BT_MESH_LEN_MIN(2), handle_status },
|
||||
|
||||
BT_MESH_MODEL_OP_END
|
||||
};
|
||||
|
||||
void bt_mesh_sol_pdu_rpl_cli_timeout_set(int32_t timeout)
|
||||
{
|
||||
msg_timeout = timeout;
|
||||
}
|
||||
|
||||
static int sol_pdu_rpl_cli_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("Solicitation PDU RPL Configuration client not in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
msg_timeout = CONFIG_BT_MESH_SOL_PDU_RPL_CLI_TIMEOUT;
|
||||
|
||||
cli = mod->user_data;
|
||||
cli->model = mod;
|
||||
bt_mesh_msg_ack_ctx_init(&cli->ack_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_cli_cb = {
|
||||
.init = sol_pdu_rpl_cli_init,
|
||||
};
|
114
subsys/bluetooth/mesh/sol_pdu_rpl_srv.c
Normal file
114
subsys/bluetooth/mesh/sol_pdu_rpl_srv.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
|
||||
#include "foundation.h"
|
||||
#include "subnet.h"
|
||||
#include "solicitation.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_sol_pdu_rpl_srv);
|
||||
|
||||
static void sol_rpl_status_rsp(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
uint16_t range,
|
||||
uint8_t len)
|
||||
{
|
||||
BT_MESH_MODEL_BUF_DEFINE(buf, OP_SOL_PDU_RPL_ITEM_STATUS, 2 + (len < 2 ? 0 : 1));
|
||||
|
||||
bt_mesh_model_msg_init(&buf, OP_SOL_PDU_RPL_ITEM_STATUS);
|
||||
|
||||
net_buf_simple_add_le16(&buf, range);
|
||||
|
||||
if (len >= 2) {
|
||||
net_buf_simple_add_u8(&buf, len);
|
||||
}
|
||||
|
||||
bt_mesh_model_send(mod, ctx, &buf, NULL, NULL);
|
||||
}
|
||||
|
||||
static int item_clear(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf,
|
||||
bool acked)
|
||||
{
|
||||
uint16_t primary, range;
|
||||
uint8_t len = 0;
|
||||
|
||||
LOG_DBG("");
|
||||
|
||||
if (buf->len > 3) {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
range = net_buf_simple_pull_le16(buf);
|
||||
primary = range >> 1;
|
||||
|
||||
LOG_DBG("Start address: 0x%02x, %d", primary, buf->len);
|
||||
if (range & BIT(0)) {
|
||||
if (buf->len == 0) {
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
len = net_buf_simple_pull_u8(buf);
|
||||
|
||||
if (len < 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((primary + len) > 0x8000 || primary == 0) {
|
||||
LOG_WRN("Range outside unicast address range or equal to 0");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
bt_mesh_srpl_entry_clear(primary + i);
|
||||
}
|
||||
|
||||
if (acked) {
|
||||
sol_rpl_status_rsp(mod, ctx, range, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_item_clear(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
return item_clear(mod, ctx, buf, true);
|
||||
}
|
||||
|
||||
static int handle_item_clear_unacked(struct bt_mesh_model *mod,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *buf)
|
||||
{
|
||||
return item_clear(mod, ctx, buf, false);
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_op _bt_mesh_sol_pdu_rpl_srv_op[] = {
|
||||
{ OP_SOL_PDU_RPL_ITEM_CLEAR, BT_MESH_LEN_MIN(2), handle_item_clear },
|
||||
{ OP_SOL_PDU_RPL_ITEM_CLEAR_UNACKED, BT_MESH_LEN_MIN(2), handle_item_clear_unacked },
|
||||
|
||||
BT_MESH_MODEL_OP_END
|
||||
};
|
||||
|
||||
static int sol_pdu_rpl_srv_init(struct bt_mesh_model *mod)
|
||||
{
|
||||
if (!bt_mesh_model_in_primary(mod)) {
|
||||
LOG_ERR("Solicitation PDU RPL Configuration server not in primary element");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct bt_mesh_model_cb _bt_mesh_sol_pdu_rpl_srv_cb = {
|
||||
.init = sol_pdu_rpl_srv_init,
|
||||
};
|
542
subsys/bluetooth/mesh/solicitation.c
Normal file
542
subsys/bluetooth/mesh/solicitation.c
Normal file
|
@ -0,0 +1,542 @@
|
|||
/*
|
||||
* Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/bluetooth/mesh.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zephyr/bluetooth/bluetooth.h>
|
||||
#include <zephyr/bluetooth/hci.h>
|
||||
#include <zephyr/bluetooth/uuid.h>
|
||||
#include "access.h"
|
||||
#include "adv.h"
|
||||
#include "cfg.h"
|
||||
#include "crypto.h"
|
||||
#include "mesh.h"
|
||||
#include "net.h"
|
||||
#include "proxy.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include "common/bt_str.h"
|
||||
|
||||
#include "host/hci_core.h"
|
||||
|
||||
#define LOG_LEVEL CONFIG_BT_MESH_MODEL_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(bt_mesh_solicitation);
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
static struct srpl_entry {
|
||||
uint32_t sseq;
|
||||
uint16_t ssrc;
|
||||
} sol_pdu_rpl[CONFIG_BT_MESH_PROXY_SRPL_SIZE];
|
||||
|
||||
static ATOMIC_DEFINE(store, CONFIG_BT_MESH_PROXY_SRPL_SIZE);
|
||||
static atomic_t clear;
|
||||
#endif
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
static uint32_t sseq_out;
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
static struct srpl_entry *srpl_find_by_addr(uint16_t ssrc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sol_pdu_rpl); i++) {
|
||||
if (sol_pdu_rpl[i].ssrc == ssrc) {
|
||||
return &sol_pdu_rpl[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int srpl_entry_save(struct bt_mesh_subnet *sub, uint32_t sseq, uint16_t ssrc)
|
||||
{
|
||||
struct srpl_entry *entry;
|
||||
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(ssrc)) {
|
||||
LOG_DBG("Addr not in unicast range");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry = srpl_find_by_addr(ssrc);
|
||||
if (entry) {
|
||||
if (entry->sseq >= sseq && sseq != 0) {
|
||||
LOG_WRN("Higher or equal SSEQ already saved for this SSRC");
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
} else {
|
||||
entry = srpl_find_by_addr(BT_MESH_ADDR_UNASSIGNED);
|
||||
if (!entry) {
|
||||
/* No space to save new PDU in RPL for this SSRC
|
||||
* and this PDU is first for this SSRC
|
||||
*/
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
entry->sseq = sseq;
|
||||
entry->ssrc = ssrc;
|
||||
|
||||
LOG_DBG("Added: SSRC %d SSEQ %d to SRPL", entry->ssrc, entry->sseq);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
atomic_set_bit(store, entry - &sol_pdu_rpl[0]);
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SRPL_PENDING);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_mesh_sseq_pending_store(void)
|
||||
{
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
char *path = "bt/mesh/SSeq";
|
||||
int err;
|
||||
|
||||
if (sseq_out) {
|
||||
err = settings_save_one(path, &sseq_out, sizeof(sseq_out));
|
||||
} else {
|
||||
err = settings_delete(path);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Failed to %s SSeq %s value", (sseq_out == 0 ? "delete" : "store"), path);
|
||||
} else {
|
||||
LOG_DBG("%s %s value", (sseq_out == 0 ? "Deleted" : "Stored"), path);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
static int sseq_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &sseq_out, sizeof(sseq_out));
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set \'sseq\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
LOG_DBG("Restored SSeq value 0x%06x", sseq_out);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(sseq, "SSeq", sseq_set);
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
static bool sol_pdu_decrypt(struct bt_mesh_subnet *sub, void *data)
|
||||
{
|
||||
struct net_buf_simple *in = data;
|
||||
struct net_buf_simple *out = NET_BUF_SIMPLE(17);
|
||||
int err, i;
|
||||
uint32_t sseq;
|
||||
uint16_t ssrc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(sub->keys); i++) {
|
||||
if (!sub->keys[i].valid) {
|
||||
LOG_ERR("invalid keys %d", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
net_buf_simple_init(out, 0);
|
||||
net_buf_simple_add_mem(out, in->data, in->len);
|
||||
|
||||
err = bt_mesh_net_obfuscate(out->data, 0, sub->keys[i].msg.privacy);
|
||||
if (err) {
|
||||
LOG_DBG("obfuscation err %d", err);
|
||||
continue;
|
||||
}
|
||||
err = bt_mesh_net_decrypt(sub->keys[i].msg.enc, out,
|
||||
0, BT_MESH_NONCE_SOLICITATION);
|
||||
if (!err) {
|
||||
LOG_DBG("Decrypted PDU %s", bt_hex(out->data, out->len));
|
||||
memcpy(&sseq, &out->data[2], 3);
|
||||
memcpy(&ssrc, &out->data[5], 2);
|
||||
err = srpl_entry_save(sub,
|
||||
sys_be24_to_cpu(sseq),
|
||||
sys_be16_to_cpu(ssrc));
|
||||
return err ? false : true;
|
||||
}
|
||||
LOG_DBG("decrypt err %d", err);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_mesh_sol_recv(struct net_buf_simple *buf, uint8_t uuid_list_len)
|
||||
{
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
uint8_t type;
|
||||
struct bt_mesh_subnet *sub;
|
||||
uint16_t uuid;
|
||||
uint8_t reported_len;
|
||||
uint8_t svc_data_type;
|
||||
bool sol_uuid_found = false;
|
||||
bool svc_data_found = false;
|
||||
|
||||
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_priv_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED ||
|
||||
bt_mesh_od_priv_proxy_get() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get rid of ad_type that was checked in bt_mesh_scan_cb */
|
||||
type = net_buf_simple_pull_u8(buf);
|
||||
if (type != BT_DATA_UUID16_SOME && type != BT_DATA_UUID16_ALL) {
|
||||
LOG_ERR("Invalid type 0x%x, expected 0x%x or 0x%x",
|
||||
type, BT_DATA_UUID16_SOME, BT_DATA_UUID16_ALL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf->len < 24) {
|
||||
LOG_DBG("Invalid length (%u) Solicitation PDU", buf->len);
|
||||
return;
|
||||
}
|
||||
|
||||
while (uuid_list_len >= 2) {
|
||||
uuid = net_buf_simple_pull_le16(buf);
|
||||
if (uuid == BT_UUID_MESH_PROXY_SOLICITATION_VAL) {
|
||||
sol_uuid_found = true;
|
||||
}
|
||||
uuid_list_len -= 2;
|
||||
}
|
||||
|
||||
if (!sol_uuid_found) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (buf->len >= 22) {
|
||||
reported_len = net_buf_simple_pull_u8(buf);
|
||||
svc_data_type = net_buf_simple_pull_u8(buf);
|
||||
uuid = net_buf_simple_pull_le16(buf);
|
||||
|
||||
if (reported_len == 21 && svc_data_type == BT_DATA_SVC_DATA16 &&
|
||||
uuid == BT_UUID_MESH_PROXY_SOLICITATION_VAL) {
|
||||
svc_data_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (buf->len <= reported_len - 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
net_buf_simple_pull_mem(buf, reported_len - 3);
|
||||
}
|
||||
|
||||
if (!svc_data_found) {
|
||||
return;
|
||||
}
|
||||
|
||||
type = net_buf_simple_pull_u8(buf);
|
||||
if (type != 0) {
|
||||
LOG_ERR("Invalid type %d, expected 0x00", type);
|
||||
return;
|
||||
}
|
||||
|
||||
sub = bt_mesh_subnet_find(sol_pdu_decrypt, (void *)buf);
|
||||
if (!sub) {
|
||||
LOG_DBG("Unable to find subnetwork for received solicitation PDU");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DBG("Decrypted solicitation PDU for existing subnet");
|
||||
|
||||
sub->solicited = true;
|
||||
bt_mesh_adv_gatt_update();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int bt_mesh_proxy_solicit(uint16_t net_idx)
|
||||
{
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
struct bt_mesh_subnet *sub;
|
||||
|
||||
sub = bt_mesh_subnet_get(net_idx);
|
||||
if (!sub) {
|
||||
LOG_ERR("No subnet with net_idx %d", net_idx);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (sub->sol_tx == true) {
|
||||
LOG_ERR("Solicitation already scheduled for this subnet");
|
||||
return -EALREADY;
|
||||
}
|
||||
|
||||
/* SSeq reached its maximum value */
|
||||
if (sseq_out > 0xFFFFFF) {
|
||||
LOG_ERR("SSeq out of range");
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
sub->sol_tx = true;
|
||||
|
||||
bt_mesh_adv_gatt_update();
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
static int sol_pdu_create(struct bt_mesh_subnet *sub, struct net_buf_simple *pdu)
|
||||
{
|
||||
int err;
|
||||
|
||||
net_buf_simple_add_u8(pdu, sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.nid);
|
||||
/* CTL = 1, TTL = 0 */
|
||||
net_buf_simple_add_u8(pdu, 0x80);
|
||||
net_buf_simple_add_le24(pdu, sys_cpu_to_be24(sseq_out));
|
||||
net_buf_simple_add_le16(pdu, sys_cpu_to_be16(bt_mesh_primary_addr()));
|
||||
/* DST = 0x0000 */
|
||||
net_buf_simple_add_le16(pdu, 0x0000);
|
||||
|
||||
err = bt_mesh_net_encrypt(sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.enc,
|
||||
pdu, 0, BT_MESH_NONCE_SOLICITATION);
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("Encryption failed, err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = bt_mesh_net_obfuscate(pdu->data, 0,
|
||||
sub->keys[SUBNET_KEY_TX_IDX(sub)].msg.privacy);
|
||||
if (err) {
|
||||
LOG_ERR("Obfuscation failed, err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
net_buf_simple_push_u8(pdu, 0);
|
||||
net_buf_simple_push_le16(pdu, BT_UUID_MESH_PROXY_SOLICITATION_VAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
static int srpl_set(const char *name, size_t len_rd,
|
||||
settings_read_cb read_cb, void *cb_arg)
|
||||
{
|
||||
struct srpl_entry *entry;
|
||||
int err;
|
||||
uint16_t ssrc;
|
||||
uint32_t sseq;
|
||||
|
||||
if (!name) {
|
||||
LOG_ERR("Insufficient number of arguments");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
ssrc = strtol(name, NULL, 16);
|
||||
entry = srpl_find_by_addr(ssrc);
|
||||
|
||||
if (len_rd == 0) {
|
||||
LOG_DBG("val (null)");
|
||||
if (entry) {
|
||||
(void)memset(entry, 0, sizeof(*entry));
|
||||
} else {
|
||||
LOG_WRN("Unable to find RPL entry for 0x%04x", ssrc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
entry = srpl_find_by_addr(BT_MESH_ADDR_UNASSIGNED);
|
||||
if (!entry) {
|
||||
LOG_ERR("Unable to allocate SRPL entry for 0x%04x", ssrc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
err = bt_mesh_settings_set(read_cb, cb_arg, &sseq, sizeof(sseq));
|
||||
if (err) {
|
||||
LOG_ERR("Failed to set \'sseq\'");
|
||||
return err;
|
||||
}
|
||||
|
||||
entry->ssrc = ssrc;
|
||||
entry->sseq = sseq;
|
||||
|
||||
LOG_DBG("SRPL entry for 0x%04x: Seq 0x%06x", entry->ssrc,
|
||||
entry->sseq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BT_MESH_SETTINGS_DEFINE(srpl, "SRPL", srpl_set);
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
static void srpl_entry_clear(int i)
|
||||
{
|
||||
uint16_t addr = sol_pdu_rpl[i].ssrc;
|
||||
|
||||
LOG_DBG("Removing entry SSRC: %d, SSEQ: %d from RPL",
|
||||
sol_pdu_rpl[i].ssrc,
|
||||
sol_pdu_rpl[i].sseq);
|
||||
sol_pdu_rpl[i].ssrc = 0;
|
||||
sol_pdu_rpl[i].sseq = 0;
|
||||
|
||||
atomic_clear_bit(store, i);
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||
char path[18];
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/SRPL/%x", addr);
|
||||
|
||||
settings_delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void srpl_store(struct srpl_entry *entry)
|
||||
{
|
||||
char path[18];
|
||||
int err;
|
||||
|
||||
LOG_DBG("src 0x%04x seq 0x%06x", entry->ssrc, entry->sseq);
|
||||
|
||||
snprintk(path, sizeof(path), "bt/mesh/SRPL/%x", entry->ssrc);
|
||||
|
||||
err = settings_save_one(path, &entry->sseq, sizeof(entry->sseq));
|
||||
if (err) {
|
||||
LOG_ERR("Failed to store RPL %s value", path);
|
||||
} else {
|
||||
LOG_DBG("Stored RPL %s value", path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void bt_mesh_srpl_pending_store(void)
|
||||
{
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
bool clr;
|
||||
|
||||
clr = atomic_cas(&clear, 1, 0);
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(sol_pdu_rpl); i++) {
|
||||
LOG_DBG("src 0x%04x seq 0x%06x", sol_pdu_rpl[i].ssrc, sol_pdu_rpl[i].sseq);
|
||||
|
||||
if (clr) {
|
||||
srpl_entry_clear(i);
|
||||
} else if (atomic_test_and_clear_bit(store, i)) {
|
||||
srpl_store(&sol_pdu_rpl[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void bt_mesh_srpl_entry_clear(uint16_t addr)
|
||||
{
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
struct srpl_entry *entry;
|
||||
|
||||
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
|
||||
LOG_DBG("Addr not in unicast range");
|
||||
return;
|
||||
}
|
||||
|
||||
entry = srpl_find_by_addr(addr);
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
srpl_entry_clear(entry - &sol_pdu_rpl[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
void bt_mesh_sol_reset(void)
|
||||
{
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
sseq_out = 0;
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SSEQ_PENDING);
|
||||
#endif
|
||||
|
||||
#if CONFIG_BT_MESH_OD_PRIV_PROXY_SRV
|
||||
(void)atomic_cas(&clear, 0, 1);
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SRPL_PENDING);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
static bool sol_subnet_find(struct bt_mesh_subnet *sub, void *cb_data)
|
||||
{
|
||||
return sub->sol_tx;
|
||||
}
|
||||
#endif
|
||||
|
||||
int bt_mesh_sol_send(void)
|
||||
{
|
||||
#if CONFIG_BT_MESH_PROXY_SOLICITATION
|
||||
uint16_t adv_int;
|
||||
struct bt_mesh_subnet *sub;
|
||||
int err;
|
||||
|
||||
NET_BUF_SIMPLE_DEFINE(pdu, 20);
|
||||
|
||||
sub = bt_mesh_subnet_find(sol_subnet_find, NULL);
|
||||
if (!sub) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/* SSeq reached its maximum value */
|
||||
if (sseq_out > 0xFFFFFF) {
|
||||
LOG_ERR("SSeq out of range");
|
||||
sub->sol_tx = false;
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
net_buf_simple_init(&pdu, 3);
|
||||
|
||||
adv_int = BT_MESH_TRANSMIT_INT(CONFIG_BT_MESH_SOL_ADV_XMIT);
|
||||
|
||||
err = sol_pdu_create(sub, &pdu);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to create Solicitation PDU, err=%d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
struct bt_data 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_SOLICITATION_VAL)),
|
||||
BT_DATA(BT_DATA_SVC_DATA16, pdu.data, pdu.size),
|
||||
};
|
||||
|
||||
err = bt_mesh_adv_bt_data_send(CONFIG_BT_MESH_SOL_ADV_XMIT,
|
||||
adv_int, ad, 3);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to advertise Solicitation PDU, err=%d", err);
|
||||
|
||||
sub->sol_tx = false;
|
||||
|
||||
return err;
|
||||
}
|
||||
sub->sol_tx = false;
|
||||
|
||||
sseq_out++;
|
||||
|
||||
bt_mesh_settings_store_schedule(BT_MESH_SETTINGS_SSEQ_PENDING);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
17
subsys/bluetooth/mesh/solicitation.h
Normal file
17
subsys/bluetooth/mesh/solicitation.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
void bt_mesh_sol_reset(void);
|
||||
|
||||
void bt_mesh_sol_recv(struct net_buf_simple *buf, uint8_t uuid_list_len);
|
||||
|
||||
void bt_mesh_srpl_entry_clear(uint16_t addr);
|
||||
|
||||
void bt_mesh_srpl_pending_store(void);
|
||||
|
||||
void bt_mesh_sseq_pending_store(void);
|
||||
|
||||
int bt_mesh_sol_send(void);
|
|
@ -73,6 +73,15 @@ struct bt_mesh_subnet {
|
|||
uint8_t beacon[16]; /* BeaconKey */
|
||||
uint8_t priv_beacon[16]; /* PrivateBeaconKey */
|
||||
} keys[2];
|
||||
#if defined(CONFIG_BT_MESH_PROXY_SOLICITATION)
|
||||
bool sol_tx;
|
||||
#endif
|
||||
#if defined(CONFIG_BT_MESH_OD_PRIV_PROXY_SRV)
|
||||
uint32_t priv_net_id_sent; /* Timestamp for Private Network ID advertising
|
||||
* started via Proxy Solicitation
|
||||
*/
|
||||
bool solicited; /* Subnet received valid Solicitation PDU */
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Subnet callback structure. Instantiate with @ref BT_MESH_SUBNET_CB */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue