ble_mesh: Provisioner supports receiving heartbeat

This commit is contained in:
lly 2020-02-27 13:42:56 +08:00 committed by baohongde
parent b6cb812499
commit b6bcdad3db
9 changed files with 620 additions and 4 deletions

View File

@ -1755,6 +1755,17 @@ if BLE_MESH
This option specifies how many application keys the Provisioner can have.
Indeed, this value decides the number of the application keys which can be added by a Provisioner.
config BLE_MESH_PROVISIONER_HB_FILTER_SIZE
int "Maximum number of filter entries for receiving heartbeat by Provisioner"
default 3
range 1 1000
help
This option specifies how many heartbeat filter entries Provisioner supports.
The entries of heartbeat filter (whitelist or blacklist) are used to store a
list of addresses which can be used to decide which heartbeat will be processed
and notified to the application layer by Provisioner. And in default, the filter
is blacklist and empty.
endif # BLE_MESH_PROVISIONER
# Virtual option enabled whenever Generic Provisioning layer is needed

View File

@ -719,6 +719,69 @@ uint8_t esp_ble_mesh_provisioner_get_free_settings_user_id_count(void)
}
#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
esp_err_t esp_ble_mesh_provisioner_start_recv_heartbeat(void)
{
btc_msg_t msg = {0};
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_PROV;
msg.act = BTC_BLE_MESH_ACT_PROVISIONER_START_RECV_HEARTBEAT;
return (btc_transfer_context(&msg, NULL, 0, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_type(uint8_t filter_type)
{
btc_ble_mesh_prov_args_t arg = {0};
btc_msg_t msg = {0};
if (filter_type > ESP_BLE_MESH_PROVISIONER_HB_FILTER_BLACKLIST) {
return ESP_ERR_INVALID_ARG;
}
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_PROV;
msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE;
arg.set_heartbeat_filter_type.filter_type = filter_type;
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_info(uint8_t op_flag, esp_ble_mesh_provisioner_hb_filter_info_t *info)
{
btc_ble_mesh_prov_args_t arg = {0};
btc_msg_t msg = {0};
if (op_flag > ESP_BLE_MESH_PROVISIONER_HB_FILTER_CLEAN || info == NULL) {
return ESP_ERR_INVALID_ARG;
}
if (!ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_src) &&
!ESP_BLE_MESH_ADDR_IS_UNICAST(info->hb_dst) &&
!ESP_BLE_MESH_ADDR_IS_GROUP(info->hb_dst)) {
return ESP_ERR_INVALID_ARG;
}
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
msg.sig = BTC_SIG_API_CALL;
msg.pid = BTC_PID_PROV;
msg.act = BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO;
arg.set_heartbeat_filter_info.op_flag = op_flag;
arg.set_heartbeat_filter_info.hb_src = info->hb_src;
arg.set_heartbeat_filter_info.hb_dst = info->hb_dst;
arg.set_heartbeat_filter_info.expiry = info->expiry;
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_mesh_prov_args_t), NULL)
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
}
#endif /* CONFIG_BLE_MESH_PROVISIONER */
#if (CONFIG_BLE_MESH_FAST_PROV)

View File

@ -601,6 +601,81 @@ uint8_t esp_ble_mesh_provisioner_get_settings_index(const char *user_id);
*/
uint8_t esp_ble_mesh_provisioner_get_free_settings_user_id_count(void);
/**
* @brief This function is called by Provisioner to start receiving and processing
* heartbeat messages.
*
* @note If starting receiving heartbeat message successfully, the filter will be
* an empty blacklist, which means all the heartbeat messages received by
* Provisioner will be processed and reported to the application layer.
*
* @return ESP_OK on success or error code otherwise.
*
*/
esp_err_t esp_ble_mesh_provisioner_start_recv_heartbeat(void);
/**
* @brief This function is called by Provisioner to set the heartbeat filter type.
*
* @note 1. If the filter type is not the same with the current value, then all the
* addresses in the filter will be cleared.
* 2. If the previous type is blacklist, and changed to whitelist, then the
* filter will be an empty whitelist, which means no heartbeat messages will
* be reported. And users need to add source addresses into the filter, then
* heartbeat messages from these addresses will be reported.
*
* @param[in] filter_type: Heartbeat filter type (whitelist or blacklist).
*
* @return ESP_OK on success or error code otherwise.
*
*/
esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_type(uint8_t filter_type);
/**
* @brief This function is called by Provisioner to add, remove or clean the corresponding
* information from the heartbeat filter.
*
* @note 1. If the op_flag is "add", the hb_src can be set to the source address (can only
* be a unicast address) of heartbeat messages, and the hb_dst can be set to the
* destination address (unicast address or group address), at least one of them needs
* to be set.
* If only one of them is set, the filter entry will only use the configured source
* address or destination address to filter heartbeat messages. If both of them are
* set, then the source address and destination address will both be used to decide
* if a heartbeat message can be reported.
* And when the filter is whitelist, users can use the expiry (in seconds) to decide
* how long the filter entry can be used to filter heartbeat messages. If the expiry
* is set to 0, then the corresponding filter entry will be valid indefinitely. Only
* when the filter entry is removed, cleaned or the filter_type is changed (whitelist
* to blacklist), then the filter entry will be invalid.
* If part of the filter information already exists, then the corresponding filter
* entry will be updated. For example, if the source address already exists, and users
* try to add a filter entry with the same source address. In this situation, the
* existed filter entry will be updated. The same for the destination address.
* And if the source address and destination address are both set, then all the filter
* entries which contain any of the two addresses will be cleaned. After this, a new
* filter entry will be allocated to store the filter information.
* 2. If the op_flag is "remove", the hb_src can be set to the source address (can only
* be a unicast address) of heartbeat messages, and the hb_dst can be set to the
* destination address (unicast address or group address), at least one of them needs
* to be set. If only one of the two addresses is set, then the filter entry with the
* same source address or destination address will be removed. And if both of them are
* set, then only the filter entry with the same source address and destination address
* will be removed. User don't need to set the expiry parameter.
* 3. If the op_flag is "clean", then Provisioner will remove all the information from
* each heartbeat filter entry, users don't need to set the parameter info.
*
* @param[in] op_flag: Add, remove or clean
* @param[in] info: Pointer to heartbeat filter entry information, the information includes:
hb_src - Heartbeat source address;
hb_dst - Heartbeat destination address;
expiry - Period (in seconds) for receiving heartbeat messages
*
* @return ESP_OK on success or error code otherwise.
*
*/
esp_err_t esp_ble_mesh_provisioner_set_heartbeat_filter_info(uint8_t op_flag, esp_ble_mesh_provisioner_hb_filter_info_t *info);
/**
* @brief This function is called to get fast provisioning application key.
*

View File

@ -702,6 +702,7 @@ typedef struct {
char name[ESP_BLE_MESH_NODE_NAME_MAX_LEN]; /*!< Node name */
uint16_t comp_length; /*!< Length of Composition Data */
uint8_t *comp_data; /*!< Value of Composition Data */
uint32_t last_hb; /*!< Time (in seconds) when the last heartbeat is received */
} __attribute__((packed)) esp_ble_mesh_node_t;
/** Context of fast provisioning which need to be set. */
@ -731,6 +732,22 @@ typedef enum {
PROXY_FILTER_BLACKLIST,
} esp_ble_mesh_proxy_filter_type_t;
/*!< Provisioner heartbeat filter type */
#define ESP_BLE_MESH_PROVISIONER_HB_FILTER_WHITELIST 0x0
#define ESP_BLE_MESH_PROVISIONER_HB_FILTER_BLACKLIST 0x1
/*!< Provisioner heartbeat filter operation */
#define ESP_BLE_MESH_PROVISIONER_HB_FILTER_ADD 0x0
#define ESP_BLE_MESH_PROVISIONER_HB_FILTER_REMOVE 0x1
#define ESP_BLE_MESH_PROVISIONER_HB_FILTER_CLEAN 0x2
/** Context of Provisioner heartbeat filter information to be set */
typedef struct {
uint16_t hb_src; /*!< Heartbeat source address (unicast address) */
uint16_t hb_dst; /*!< Heartbeat destination address (unicast address or group address) */
uint32_t expiry; /*!< Expiry (in seconds) for the whitelist filter entry */
} esp_ble_mesh_provisioner_hb_filter_info_t;
/*!< This enum value is the event of node/provisioner/fast provisioning */
typedef enum {
ESP_BLE_MESH_PROV_REGISTER_COMP_EVT, /*!< Initialize BLE Mesh provisioning capabilities and internal data information completion event */
@ -789,6 +806,10 @@ typedef enum {
ESP_BLE_MESH_PROVISIONER_RELEASE_SETTINGS_WITH_USER_ID_COMP_EVT, /*!< Provisioner release settings with user_id completion event */
ESP_BLE_MESH_PROVISIONER_DELETE_SETTINGS_WITH_INDEX_COMP_EVT, /*!< Provisioner delete settings with index completion event */
ESP_BLE_MESH_PROVISIONER_DELETE_SETTINGS_WITH_USER_ID_COMP_EVT, /*!< Provisioner delete settings with user_id completion event */
ESP_BLE_MESH_PROVISIONER_START_RECV_HEARTBEAT_COMP_EVT, /*!< Provisioner start to receive Heartbeat message completion event */
ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT, /*!< Provisioner set the filter type of receiving heartbeat message completion event */
ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT, /*!< Provisioner set the filter information of receiving heartbeat message completion event */
ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT, /*!< Provisioner receives heartbeat message event */
ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT, /*!< Set fast provisioning information (e.g. unicast address range, net_idx, etc.) completion event */
ESP_BLE_MESH_SET_FAST_PROV_ACTION_COMP_EVT, /*!< Set fast provisioning action completion event */
ESP_BLE_MESH_HEARTBEAT_MESSAGE_RECV_EVT, /*!< Receive Heartbeat message event */
@ -1195,6 +1216,41 @@ typedef union {
int err_code; /*!< Indicate the result of deleting settings with user_id by the Provisioner */
uint8_t index; /*!< Index of Provisioner settings */
} provisioner_delete_settings_with_user_id_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_DELETE_SETTINGS_WITH_USER_ID_COMP_EVT */
/**
* @brief ESP_BLE_MESH_PROVISIONER_START_RECV_HEARTBEAT_COMP_EVT
*/
struct ble_mesh_provisioner_start_recv_heartbeat_comp_param {
int err_code; /*!< Indicate the result of starting to receive heartbeat messages by the Provisioner */
} provisioner_start_recv_heartbeat_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_START_RECV_HEARTBEAT_COMP_EVT */
/**
* @brief ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT
*/
struct ble_mesh_provisioner_set_heartbeat_filter_type_comp_param {
int err_code; /*!< Indicate the result of setting the heartbeat filter type by the Provisioner */
uint8_t filter_type; /*!< Type of the filter used for receiving heartbeat messages */
} provisioner_set_heartbeat_filter_type_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT */
/**
* @brief ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT
*/
struct ble_mesh_provisioner_set_heartbeat_filter_info_comp_param {
int err_code; /*!< Indicate the result of setting the heartbeat filter address by the Provisioner */
uint8_t op_flag; /*!< Operation (add, remove, clean) */
uint16_t hb_src; /*!< Heartbeat source address */
uint16_t hb_dst; /*!< Heartbeat destination address */
uint32_t expiry; /*!< Expiry of the source address */
} provisioner_set_heartbeat_filter_info_comp; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT */
/**
* @brief ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT
*/
struct ble_mesh_provisioner_recv_heartbeat_msg_param {
uint16_t hb_src; /*!< Heartbeat source address */
uint16_t hb_dst; /*!< Heartbeat destination address */
uint8_t init_ttl; /*!< Heartbeat InitTTL */
uint8_t rx_ttl; /*!< Heartbeat RxTTL */
uint8_t hops; /*!< Heartbeat hops (InitTTL - RxTTL + 1) */
uint16_t feature; /*!< Bit field of currently active features of the node */
uint32_t count; /*!< Number of received heartbeat messages */
} provisioner_recv_heartbeat_msg; /*!< Event parameters of ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT */
/**
* @brief ESP_BLE_MESH_SET_FAST_PROV_INFO_COMP_EVT
*/

View File

@ -804,9 +804,28 @@ uint8_t btc_ble_mesh_provisioner_get_free_settings_user_id_count(void)
return bt_mesh_provisioner_get_free_settings_user_id_count();
}
#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
static void btc_ble_mesh_provisioner_recv_heartbeat_cb(u16_t hb_src, u16_t hb_dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat, u32_t count)
{
esp_ble_mesh_prov_cb_param_t mesh_param = {0};
BT_DBG("%s", __func__);
mesh_param.provisioner_recv_heartbeat_msg.hb_src = hb_src;
mesh_param.provisioner_recv_heartbeat_msg.hb_dst = hb_dst;
mesh_param.provisioner_recv_heartbeat_msg.init_ttl = init_ttl;
mesh_param.provisioner_recv_heartbeat_msg.rx_ttl = rx_ttl;
mesh_param.provisioner_recv_heartbeat_msg.hops = hops;
mesh_param.provisioner_recv_heartbeat_msg.feature = feat;
mesh_param.provisioner_recv_heartbeat_msg.count = count;
btc_ble_mesh_prov_callback(&mesh_param, ESP_BLE_MESH_PROVISIONER_RECV_HEARTBEAT_MESSAGE_EVT);
return;
}
#endif /* CONFIG_BLE_MESH_PROVISIONER */
static void btc_ble_mesh_heartbeat_msg_recv_cb(u8_t hops, u16_t feature)
static void btc_ble_mesh_node_recv_heartbeat_cb(u8_t hops, u16_t feature)
{
esp_ble_mesh_prov_cb_param_t mesh_param = {0};
@ -1106,7 +1125,7 @@ static void btc_ble_mesh_model_op_add(esp_ble_mesh_model_t *model)
model->op = (esp_ble_mesh_model_op_t *)bt_mesh_cfg_srv_op;
struct bt_mesh_cfg_srv *srv = (struct bt_mesh_cfg_srv *)model->user_data;
if (srv) {
srv->hb_sub.func = btc_ble_mesh_heartbeat_msg_recv_cb;
srv->hb_sub.func = btc_ble_mesh_node_recv_heartbeat_cb;
}
break;
}
@ -1871,6 +1890,28 @@ void btc_ble_mesh_prov_call_handler(btc_msg_t *msg)
&param.provisioner_delete_settings_with_user_id_comp.index);
break;
#endif /* CONFIG_BLE_MESH_USE_MULTIPLE_NAMESPACE */
case BTC_BLE_MESH_ACT_PROVISIONER_START_RECV_HEARTBEAT:
act = ESP_BLE_MESH_PROVISIONER_START_RECV_HEARTBEAT_COMP_EVT;
param.provisioner_start_recv_heartbeat_comp.err_code =
bt_mesh_provisioner_start_recv_heartbeat(btc_ble_mesh_provisioner_recv_heartbeat_cb);
break;
case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE:
act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE_COMP_EVT;
param.provisioner_set_heartbeat_filter_type_comp.filter_type = arg->set_heartbeat_filter_type.filter_type;
param.provisioner_set_heartbeat_filter_type_comp.err_code =
bt_mesh_provisioner_set_heartbeat_filter_type(arg->set_heartbeat_filter_type.filter_type);
break;
case BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO:
act = ESP_BLE_MESH_PROVISIONER_SET_HEARTBEAT_FILTER_INFO_COMP_EVT;
param.provisioner_set_heartbeat_filter_info_comp.op_flag = arg->set_heartbeat_filter_info.op_flag;
param.provisioner_set_heartbeat_filter_info_comp.hb_src = arg->set_heartbeat_filter_info.hb_src;
param.provisioner_set_heartbeat_filter_info_comp.hb_dst = arg->set_heartbeat_filter_info.hb_dst;
param.provisioner_set_heartbeat_filter_info_comp.expiry = arg->set_heartbeat_filter_info.expiry;
param.provisioner_set_heartbeat_filter_info_comp.err_code =
bt_mesh_provisioner_set_heartbeat_filter_info(arg->set_heartbeat_filter_info.op_flag,
arg->set_heartbeat_filter_info.hb_src, arg->set_heartbeat_filter_info.hb_dst,
arg->set_heartbeat_filter_info.expiry);
break;
#endif /* CONFIG_BLE_MESH_PROVISIONER */
#if CONFIG_BLE_MESH_FAST_PROV
case BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO:

View File

@ -63,6 +63,9 @@ typedef enum {
BTC_BLE_MESH_ACT_PROVISIONER_RELEASE_SETTINGS_WITH_USER_ID,
BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_INDEX,
BTC_BLE_MESH_ACT_PROVISIONER_DELETE_SETTINGS_WITH_USER_ID,
BTC_BLE_MESH_ACT_PROVISIONER_START_RECV_HEARTBEAT,
BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_TYPE,
BTC_BLE_MESH_ACT_PROVISIONER_SET_HEARTBEAT_FILTER_INFO,
BTC_BLE_MESH_ACT_SET_FAST_PROV_INFO,
BTC_BLE_MESH_ACT_SET_FAST_PROV_ACTION,
BTC_BLE_MESH_ACT_LPN_ENABLE,
@ -229,6 +232,15 @@ typedef union {
struct ble_mesh_provisioner_delete_settings_with_user_id_args {
char user_id[ESP_BLE_MESH_SETTINGS_USER_ID_SIZE + 1];
} delete_settings_with_user_id;
struct ble_mesh_provisioner_set_heartbeat_filter_type_args {
uint8_t filter_type;
} set_heartbeat_filter_type;
struct ble_mesh_provisioner_set_heartbeat_filter_info_args {
uint8_t op_flag;
uint16_t hb_src;
uint16_t hb_dst;
uint32_t expiry;
} set_heartbeat_filter_info;
struct ble_mesh_set_fast_prov_info_args {
uint16_t unicast_min;
uint16_t unicast_max;

View File

@ -34,6 +34,34 @@ static bt_mesh_mutex_t provisioner_lock;
static u16_t all_node_count;
static u16_t prov_node_count;
#define PROVISIONER_HB_FILTER_WHITELIST 0x0
#define PROVISIONER_HB_FILTER_BLACKLIST 0x1
#define PROVISIONER_HB_FILTER_ADD 0x0
#define PROVISIONER_HB_FILTER_REMOVE 0x1
#define PROVISIONER_HB_FILTER_CLEAN 0x2
#define PROVISIONER_HB_FILTER_WITH_SRC BIT(0)
#define PROVISIONER_HB_FILTER_WITH_DST BIT(1)
#define PROVISIONER_HB_FILTER_WITH_BOTH (BIT(1) | BIT(0))
#define PROVISIONER_HB_RECV_MAX_COUNT 0xFFFFFFFF
static struct bt_mesh_provisioner_hb {
struct provisioner_hb_rx {
struct hb_rx_filter {
u16_t src; /* Heartbeat source address, only unicast address */
u16_t dst; /* Heartbeat destination address, unicast address or group address */
s64_t expiry; /* In milliseconds, 0 means no expiry will be used */
u32_t count; /* Number of received heartbeat messages when using whitelist */
} filter[CONFIG_BLE_MESH_PROVISIONER_HB_FILTER_SIZE];
u8_t filter_type; /* Heartbeat rx filter type */
u32_t count; /* Number of received heartbeat messages when using blacklist */
void (*func)(u16_t hb_src, u16_t hb_dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat, u32_t count);
} rx;
} provisioner_hb;
static int provisioner_remove_node(u16_t index, bool erase);
static void bt_mesh_provisioner_mutex_new(void)
@ -224,6 +252,7 @@ int bt_mesh_provisioner_deinit(bool erase)
bt_mesh_provisioner_release_netkey(erase);
bt_mesh_provisioner_release_appkey(erase);
bt_mesh_provisioner_release_node(erase);
memset(&provisioner_hb.rx, 0, sizeof(provisioner_hb.rx));
bt_mesh_provisioner_mutex_free();
return 0;
}
@ -338,6 +367,7 @@ static int provisioner_store_node(struct bt_mesh_node *node, bool prov, bool sto
}
memcpy(mesh_nodes[i], node, sizeof(struct bt_mesh_node));
node->last_hb = k_uptime_get_32() / 1000;
provisioner_node_count_inc(prov);
if (index) {
*index = i;
@ -1537,6 +1567,314 @@ int bt_mesh_provisioner_bind_local_model_app_idx(u16_t elem_addr, u16_t mod_id,
return -ENOMEM;
}
int bt_mesh_provisioner_start_recv_heartbeat(void (*cb)(u16_t hb_src, u16_t hb_dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat, u32_t count)
)
{
if (cb == NULL) {
BT_ERR("%s, Invalid heartbeat callback", __func__);
return -EINVAL;
}
memset(&provisioner_hb.rx, 0, sizeof(provisioner_hb.rx));
/* Start with an empty blacklist, which means all heartbeat messages will be reported */
provisioner_hb.rx.filter_type = PROVISIONER_HB_FILTER_BLACKLIST;
provisioner_hb.rx.func = cb;
return 0;
}
int bt_mesh_provisioner_set_heartbeat_filter_type(u8_t filter_type)
{
if (filter_type > PROVISIONER_HB_FILTER_BLACKLIST) {
BT_ERR("%s, Invalid filter type 0x%02x", __func__, filter_type);
return -EINVAL;
}
if (provisioner_hb.rx.filter_type != filter_type) {
memset(&provisioner_hb.rx, 0, offsetof(struct provisioner_hb_rx, func));
}
provisioner_hb.rx.filter_type = filter_type;
return 0;
}
static u8_t hb_filter_addr_type(u16_t src, u16_t dst)
{
if (BLE_MESH_ADDR_IS_UNICAST(src)) {
if (BLE_MESH_ADDR_IS_UNICAST(dst) || BLE_MESH_ADDR_IS_GROUP(dst)) {
return PROVISIONER_HB_FILTER_WITH_BOTH;
} else {
return PROVISIONER_HB_FILTER_WITH_SRC;
}
} else {
return PROVISIONER_HB_FILTER_WITH_DST;
}
}
static int hb_filter_alloc(u16_t src, u16_t dst, u32_t expiry)
{
int i;
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
struct hb_rx_filter *filter = &provisioner_hb.rx.filter[i];
if (filter->src == BLE_MESH_ADDR_UNASSIGNED &&
filter->dst == BLE_MESH_ADDR_UNASSIGNED) {
filter->src = src;
filter->dst = dst;
filter->expiry = expiry ? (k_uptime_get() + K_SECONDS(expiry)) : expiry;
filter->count = 0U;
return 0;
}
}
BT_ERR("%s, Heartbeat filter is full, src 0x%04x, dst 0x%04x", __func__, src, dst);
return -ENOMEM;
}
static void hb_filter_free(struct hb_rx_filter *filter)
{
filter->src = BLE_MESH_ADDR_UNASSIGNED;
filter->dst = BLE_MESH_ADDR_UNASSIGNED;
filter->expiry = 0;
filter->count = 0U;
}
static int hb_filter_add(u16_t src, u16_t dst, u32_t expiry)
{
struct hb_rx_filter *filter = NULL;
u8_t type = 0U;
int i;
if (!BLE_MESH_ADDR_IS_UNICAST(src) &&
!BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) {
BT_ERR("%s, Invalid filter address, src 0x%04x, dst 0x%04x", __func__, src, dst);
return -EINVAL;
}
type = hb_filter_addr_type(src, dst);
switch (type) {
case PROVISIONER_HB_FILTER_WITH_SRC: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == filter->src) {
filter->dst = dst;
filter->expiry = expiry ? (k_uptime_get() + K_SECONDS(expiry)) : expiry;
filter->count = 0U;
return 0;
}
}
return hb_filter_alloc(src, dst, expiry);
}
case PROVISIONER_HB_FILTER_WITH_DST: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (dst == filter->dst) {
filter->src = src;
filter->expiry = expiry ? (k_uptime_get() + K_SECONDS(expiry)) : expiry;
filter->count = 0U;
return 0;
}
}
return hb_filter_alloc(src, dst, expiry);
}
case PROVISIONER_HB_FILTER_WITH_BOTH: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
/* Clear already existed src and dst in the filter */
if (src == filter->src || dst == filter->dst) {
filter->src = BLE_MESH_ADDR_UNASSIGNED;
filter->dst = BLE_MESH_ADDR_UNASSIGNED;
filter->expiry = 0;
filter->count = 0U;
}
}
return hb_filter_alloc(src, dst, expiry);
}
default:
BT_ERR("%s, Unknown filter addr type 0x%02x", __func__, type);
return -EINVAL;
}
}
static int hb_filter_remove(u16_t src, u16_t dst)
{
struct hb_rx_filter *filter = NULL;
u8_t type = 0U;
int i;
if (!BLE_MESH_ADDR_IS_UNICAST(src) &&
!BLE_MESH_ADDR_IS_UNICAST(dst) && !BLE_MESH_ADDR_IS_GROUP(dst)) {
BT_ERR("%s, Invalid filter address, src 0x%04x, dst 0x%04x", __func__, src, dst);
return -EINVAL;
}
type = hb_filter_addr_type(src, dst);
switch (type) {
case PROVISIONER_HB_FILTER_WITH_SRC: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == filter->src && dst == BLE_MESH_ADDR_UNASSIGNED) {
hb_filter_free(filter);
}
}
return 0;
}
case PROVISIONER_HB_FILTER_WITH_DST: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == BLE_MESH_ADDR_UNASSIGNED && dst == filter->dst) {
hb_filter_free(filter);
}
}
return 0;
}
case PROVISIONER_HB_FILTER_WITH_BOTH: {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == filter->src && dst == filter->dst) {
hb_filter_free(filter);
}
}
return 0;
}
default:
BT_ERR("%s, Unknown filter addr type 0x%02x", __func__, type);
return -EINVAL;
}
}
int bt_mesh_provisioner_set_heartbeat_filter_info(u8_t op_flag, u16_t src, u16_t dst, u32_t expiry)
{
switch (op_flag) {
case PROVISIONER_HB_FILTER_ADD:
return hb_filter_add(src, dst, expiry);
case PROVISIONER_HB_FILTER_REMOVE:
return hb_filter_remove(src, dst);
case PROVISIONER_HB_FILTER_CLEAN:
memset(&provisioner_hb.rx, 0, offsetof(struct provisioner_hb_rx, filter_type));
return 0;
default:
BT_ERR("%s, Invalid operation flag 0x%02x", __func__, op_flag);
return -EINVAL;
}
}
void bt_mesh_provisioner_heartbeat(u16_t src, u16_t dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat)
{
struct hb_rx_filter *filter = NULL;
struct bt_mesh_node *node = NULL;
bool ignore = true;
u32_t count = 0U;
u8_t type = 0U;
int i;
if (provisioner_hb.rx.func == NULL) {
BT_DBG("Receiving heartbeat is not enabled");
return;
}
if (provisioner_hb.rx.filter_type == PROVISIONER_HB_FILTER_BLACKLIST) {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == filter->src || dst == filter->dst) {
type = hb_filter_addr_type(filter->src, filter->dst);
switch (type) {
case PROVISIONER_HB_FILTER_WITH_SRC:
if (src == filter->src) {
BT_INFO("Heartbeat filtered by backlist with src 0x%04x", src);
return;
}
break;
case PROVISIONER_HB_FILTER_WITH_DST:
if (dst == filter->dst) {
BT_INFO("Heartbeat filtered by backlist with dst 0x%04x", dst);
return;
}
break;
case PROVISIONER_HB_FILTER_WITH_BOTH:
if (src == filter->src && dst == filter->dst) {
BT_INFO("Heartbeat filtered by backlist with src 0x%04x, dst 0x%04x", src, dst);
return;
}
break;
default:
BT_ERR("%s, Unknown filter addr type 0x%02x", __func__, type);
return;
}
}
}
if (provisioner_hb.rx.count < PROVISIONER_HB_RECV_MAX_COUNT) {
provisioner_hb.rx.count++;
}
count = provisioner_hb.rx.count;
} else {
for (i = 0; i < ARRAY_SIZE(provisioner_hb.rx.filter); i++) {
filter = &provisioner_hb.rx.filter[i];
if (src == filter->src || dst == filter->dst) {
type = hb_filter_addr_type(filter->src, filter->dst);
switch (type) {
case PROVISIONER_HB_FILTER_WITH_SRC:
if (src == filter->src) {
ignore = false;
}
break;
case PROVISIONER_HB_FILTER_WITH_DST:
if (dst == filter->dst) {
ignore = false;
}
break;
case PROVISIONER_HB_FILTER_WITH_BOTH:
if (src == filter->src && dst == filter->dst) {
ignore = false;
}
break;
default:
BT_ERR("%s, Unknown filter addr type 0x%02x", __func__, type);
return;
}
if (ignore == false) {
break;
}
}
}
if (ignore == true) {
BT_INFO("Heartbeat filtered by whitelist, src 0x%04x, dst 0x%04x", src, dst);
return;
}
if (filter->expiry && k_uptime_get() > filter->expiry) {
BT_INFO("Period for heartbeat from 0x%04x expired", src);
return;
}
if (filter->count < PROVISIONER_HB_RECV_MAX_COUNT) {
filter->count++;
}
count = filter->count;
}
node = bt_mesh_provisioner_get_node_with_addr(src);
if (node) {
node->last_hb = k_uptime_get_32() / 1000;
}
BT_INFO("src 0x%04x, dst 0x%04x, init_ttl %u, rx_ttl %u, hops %u, feat 0x%04x, count %u",
src, dst, init_ttl, rx_ttl, hops, feat, count);
if (provisioner_hb.rx.func) {
provisioner_hb.rx.func(src, dst, init_ttl, rx_ttl, hops, feat, count);
}
}
int bt_mesh_print_local_composition_data(void)
{
const struct bt_mesh_comp *comp = NULL;

View File

@ -41,6 +41,7 @@ struct bt_mesh_node {
char name[BLE_MESH_NODE_NAME_SIZE]; /* Node name */
u16_t comp_length; /* Length of Composition Data */
u8_t *comp_data; /* Value of Composition Data */
u32_t last_hb; /* Time (in seconds) when the last heartbeat is received */
} __packed;
int bt_mesh_provisioner_init(void);
@ -122,6 +123,18 @@ int bt_mesh_provisioner_local_net_key_delete(u16_t net_idx);
int bt_mesh_provisioner_bind_local_model_app_idx(u16_t elem_addr, u16_t mod_id,
u16_t cid, u16_t app_idx);
int bt_mesh_provisioner_start_recv_heartbeat(void (*cb)(u16_t src, u16_t dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat,
u32_t count)
);
int bt_mesh_provisioner_set_heartbeat_filter_type(u8_t filter_type);
int bt_mesh_provisioner_set_heartbeat_filter_info(u8_t op_flag, u16_t src, u16_t dst, u32_t expiry);
void bt_mesh_provisioner_heartbeat(u16_t src, u16_t dst, u8_t init_ttl,
u8_t rx_ttl, u8_t hops, u16_t feat);
/* Provisioner print own element information */
int bt_mesh_print_local_composition_data(void);

View File

@ -885,7 +885,8 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx,
return -EINVAL;
}
if (rx->ctx.recv_dst != hb_sub_dst) {
if (IS_ENABLED(CONFIG_BLE_MESH_NODE) && bt_mesh_is_provisioned() &&
rx->ctx.recv_dst != hb_sub_dst) {
BT_WARN("Ignoring heartbeat to non-subscribed destination");
return 0;
}
@ -899,7 +900,13 @@ static int trans_heartbeat(struct bt_mesh_net_rx *rx,
rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops,
(hops == 1U) ? "" : "s", feat);
if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) &&
bt_mesh_is_provisioner_en() && !bt_mesh_is_provisioned()) {
bt_mesh_provisioner_heartbeat(
rx->ctx.addr, rx->ctx.recv_dst, init_ttl, rx->ctx.recv_ttl, hops, feat);
} else {
bt_mesh_heartbeat(rx->ctx.addr, rx->ctx.recv_dst, hops, feat);
}
return 0;
}