Merge branch 'bugfix/ble_mesh_update_3.3' into 'release/v3.3'
Bugfix/ble mesh update 3.3 See merge request espressif/esp-idf!7801
This commit is contained in:
commit
36cddd0bae
7 changed files with 285 additions and 47 deletions
|
@ -1944,8 +1944,8 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg)
|
|||
break;
|
||||
}
|
||||
case BTC_BLE_MESH_ACT_SERVER_MODEL_SEND: {
|
||||
/* arg->model_send.length contains opcode & message, 8 is used for TransMIC */
|
||||
struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 8);
|
||||
/* arg->model_send.length contains opcode & message, 4 is used for TransMIC */
|
||||
struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 4);
|
||||
if (!buf) {
|
||||
BT_ERR("%s, Failed to allocate memory", __func__);
|
||||
break;
|
||||
|
@ -1962,8 +1962,8 @@ void btc_ble_mesh_model_call_handler(btc_msg_t *msg)
|
|||
}
|
||||
case BTC_BLE_MESH_ACT_CLIENT_MODEL_SEND: {
|
||||
bt_mesh_role_param_t common = {0};
|
||||
/* arg->model_send.length contains opcode & message, 8 is used for TransMIC */
|
||||
struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 8);
|
||||
/* arg->model_send.length contains opcode & message, 4 is used for TransMIC */
|
||||
struct net_buf_simple *buf = bt_mesh_alloc_buf(arg->model_send.length + 4);
|
||||
if (!buf) {
|
||||
BT_ERR("%s, Failed to allocate memory", __func__);
|
||||
break;
|
||||
|
|
|
@ -1394,6 +1394,24 @@ static bool ready_to_recv(void)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool ignore_net_msg(u16_t src, u16_t dst)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_BLE_MESH_PROVISIONER) &&
|
||||
bt_mesh_is_provisioner_en() &&
|
||||
BLE_MESH_ADDR_IS_UNICAST(dst) &&
|
||||
bt_mesh_elem_find(dst)) {
|
||||
/* If the destination address of the message is the element
|
||||
* address of Provisioner, but Provisioner fails to find the
|
||||
* node in its provisioning database, then this message will
|
||||
* be ignored.
|
||||
*/
|
||||
if (!bt_mesh_provisioner_get_node_with_addr(src)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi,
|
||||
enum bt_mesh_net_if net_if)
|
||||
{
|
||||
|
@ -1411,6 +1429,10 @@ void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi,
|
|||
return;
|
||||
}
|
||||
|
||||
if (ignore_net_msg(rx.ctx.addr, rx.ctx.recv_dst)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Save the state so the buffer can later be relayed */
|
||||
net_buf_simple_save(&buf, &state);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "access.h"
|
||||
#include "settings.h"
|
||||
#include "friend.h"
|
||||
#include "transport.h"
|
||||
#include "mesh_common.h"
|
||||
#include "proxy_client.h"
|
||||
#include "provisioner_prov.h"
|
||||
|
@ -380,7 +381,6 @@ int bt_mesh_provisioner_provision(const bt_mesh_addr_t *addr, const u8_t uuid[16
|
|||
static int provisioner_remove_node(u16_t index, bool erase)
|
||||
{
|
||||
struct bt_mesh_node *node = NULL;
|
||||
struct bt_mesh_rpl *rpl = NULL;
|
||||
bool is_prov = false;
|
||||
int i;
|
||||
|
||||
|
@ -398,17 +398,12 @@ static int provisioner_remove_node(u16_t index, bool erase)
|
|||
/* Reset corresponding network cache when reset the node */
|
||||
bt_mesh_msg_cache_clear(node->unicast_addr, node->element_num);
|
||||
|
||||
/* Reset corresponding rpl when removing the node */
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) {
|
||||
rpl = &bt_mesh.rpl[i];
|
||||
if (rpl->src >= node->unicast_addr &&
|
||||
rpl->src < node->unicast_addr + node->element_num) {
|
||||
memset(rpl, 0, sizeof(struct bt_mesh_rpl));
|
||||
|
||||
if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
|
||||
bt_mesh_clear_rpl_single(node->unicast_addr);
|
||||
}
|
||||
}
|
||||
/* Reset corresponding transport info when removing the node */
|
||||
for (i = 0; i < node->element_num; i++) {
|
||||
bt_mesh_rx_reset_single(node->unicast_addr + i);
|
||||
}
|
||||
for (i = 0; i < node->element_num; i++) {
|
||||
bt_mesh_tx_reset_single(node->unicast_addr + i);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND)) {
|
||||
|
|
|
@ -125,6 +125,19 @@ static void bt_mesh_tx_seg_unlock(void)
|
|||
bt_mesh_mutex_unlock(&tx_seg_lock);
|
||||
}
|
||||
|
||||
u8_t bt_mesh_get_seg_retrans_num(void)
|
||||
{
|
||||
return SEG_RETRANSMIT_ATTEMPTS;
|
||||
}
|
||||
|
||||
s32_t bt_mesh_get_seg_retrans_timeout(u8_t ttl)
|
||||
{
|
||||
struct seg_tx tx = {
|
||||
.ttl = ttl,
|
||||
};
|
||||
return SEG_RETRANSMIT_TIMEOUT(&tx);
|
||||
}
|
||||
|
||||
void bt_mesh_set_hb_sub_dst(u16_t addr)
|
||||
{
|
||||
hb_sub_dst = addr;
|
||||
|
@ -1130,13 +1143,33 @@ static void seg_rx_reset(struct seg_rx *rx, bool full_reset)
|
|||
}
|
||||
}
|
||||
|
||||
static u32_t incomplete_timeout(struct seg_rx *rx)
|
||||
{
|
||||
u32_t timeout = 0U;
|
||||
u8_t ttl = 0U;
|
||||
|
||||
if (rx->ttl == BLE_MESH_TTL_DEFAULT) {
|
||||
ttl = bt_mesh_default_ttl_get();
|
||||
} else {
|
||||
ttl = rx->ttl;
|
||||
}
|
||||
|
||||
/* "The incomplete timer shall be set to a minimum of 10 seconds." */
|
||||
timeout = K_SECONDS(10);
|
||||
|
||||
/* The less segments being received, the shorter timeout will be used. */
|
||||
timeout += K_MSEC(ttl * popcount(rx->block) * 100U);
|
||||
|
||||
return MIN(timeout, K_SECONDS(60));
|
||||
}
|
||||
|
||||
static void seg_ack(struct k_work *work)
|
||||
{
|
||||
struct seg_rx *rx = CONTAINER_OF(work, struct seg_rx, ack);
|
||||
|
||||
BT_DBG("rx %p", rx);
|
||||
|
||||
if (k_uptime_get_32() - rx->last > K_SECONDS(60)) {
|
||||
if (k_uptime_get_32() - rx->last > incomplete_timeout(rx)) {
|
||||
BT_WARN("Incomplete timer expired");
|
||||
seg_rx_reset(rx, false);
|
||||
return;
|
||||
|
@ -1584,6 +1617,50 @@ void bt_mesh_tx_reset(void)
|
|||
}
|
||||
}
|
||||
|
||||
#if CONFIG_BLE_MESH_PROVISIONER
|
||||
void bt_mesh_rx_reset_single(u16_t src)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!BLE_MESH_ADDR_IS_UNICAST(src)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
|
||||
struct seg_rx *rx = &seg_rx[i];
|
||||
if (src == rx->src) {
|
||||
seg_rx_reset(rx, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bt_mesh.rpl); i++) {
|
||||
struct bt_mesh_rpl *rpl = &bt_mesh.rpl[i];
|
||||
if (src == rpl->src) {
|
||||
memset(rpl, 0, sizeof(struct bt_mesh_rpl));
|
||||
if (IS_ENABLED(CONFIG_BLE_MESH_SETTINGS)) {
|
||||
bt_mesh_clear_rpl_single(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bt_mesh_tx_reset_single(u16_t dst)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!BLE_MESH_ADDR_IS_UNICAST(dst)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_tx); i++) {
|
||||
struct seg_tx *tx = &seg_tx[i];
|
||||
if (dst == tx->dst) {
|
||||
seg_tx_reset(tx);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_BLE_MESH_PROVISIONER */
|
||||
|
||||
void bt_mesh_trans_init(void)
|
||||
{
|
||||
int i;
|
||||
|
|
|
@ -80,6 +80,10 @@ struct bt_mesh_ctl_friend_sub_confirm {
|
|||
u8_t xact;
|
||||
} __packed;
|
||||
|
||||
u8_t bt_mesh_get_seg_retrans_num(void);
|
||||
|
||||
s32_t bt_mesh_get_seg_retrans_timeout(u8_t ttl);
|
||||
|
||||
void bt_mesh_set_hb_sub_dst(u16_t addr);
|
||||
|
||||
struct bt_mesh_app_key *bt_mesh_app_key_find(u16_t app_idx);
|
||||
|
@ -88,6 +92,8 @@ bool bt_mesh_tx_in_progress(void);
|
|||
|
||||
void bt_mesh_rx_reset(void);
|
||||
void bt_mesh_tx_reset(void);
|
||||
void bt_mesh_rx_reset_single(u16_t src);
|
||||
void bt_mesh_tx_reset_single(u16_t dst);
|
||||
|
||||
int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
|
||||
size_t data_len, u64_t *seq_auth,
|
||||
|
|
|
@ -17,9 +17,15 @@
|
|||
|
||||
#include "mesh.h"
|
||||
#include "mesh_main.h"
|
||||
#include "transport.h"
|
||||
#include "foundation.h"
|
||||
#include "client_common.h"
|
||||
#include "mesh_common.h"
|
||||
|
||||
#define UNSEG_ACCESS_MSG_MAX_LEN 11 /* 11 octets (Opcode + Payload), 4 octets TransMIC */
|
||||
#define SEG_ACCESS_MSG_SEG_LEN 12 /* 12 * 32 = 384 octets (Opcode + Payload + TransMIC) */
|
||||
#define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */
|
||||
|
||||
static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, u16_t tx_dst)
|
||||
{
|
||||
bt_mesh_client_node_t *node = NULL;
|
||||
|
@ -156,6 +162,100 @@ static u32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pai
|
|||
return 0;
|
||||
}
|
||||
|
||||
static s32_t bt_mesh_get_adv_duration(void)
|
||||
{
|
||||
u16_t duration, adv_int;
|
||||
u8_t xmit;
|
||||
|
||||
xmit = bt_mesh_net_transmit_get(); /* Network transmit */
|
||||
adv_int = BLE_MESH_TRANSMIT_INT(xmit);
|
||||
duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10);
|
||||
|
||||
return (s32_t)duration;
|
||||
}
|
||||
|
||||
static s32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx,
|
||||
struct net_buf_simple *msg,
|
||||
u32_t opcode, s32_t timeout)
|
||||
{
|
||||
s32_t seg_retrans_to, duration, time;
|
||||
u8_t seg_count, seg_retrans_num;
|
||||
u8_t mic_size;
|
||||
bool need_seg;
|
||||
|
||||
if (msg->len > UNSEG_ACCESS_MSG_MAX_LEN || ctx->send_rel) {
|
||||
need_seg = true; /* Needs segmentation */
|
||||
}
|
||||
|
||||
mic_size = (need_seg && net_buf_simple_tailroom(msg) >= 8U) ? 8U : 4U;
|
||||
|
||||
if (need_seg) {
|
||||
/* Based on the message length, calculate how many segments are needed.
|
||||
* All the messages sent from here are access messages.
|
||||
*/
|
||||
seg_retrans_num = bt_mesh_get_seg_retrans_num();
|
||||
seg_retrans_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl);
|
||||
seg_count = (msg->len + mic_size - 1) / 12U + 1U;
|
||||
|
||||
duration = bt_mesh_get_adv_duration();
|
||||
|
||||
/* Currenlty only consider the time consumption of the same segmented
|
||||
* messages, but if there are other messages between any two retrans-
|
||||
* missions of the same segmented messages, then the whole time will
|
||||
* be longer.
|
||||
*/
|
||||
if (duration + HCI_TIME_FOR_START_ADV < seg_retrans_to) {
|
||||
s32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV);
|
||||
time = (seg_duration + seg_retrans_to) * (seg_retrans_num - 1) + seg_duration;
|
||||
} else {
|
||||
/* If the duration is bigger than the segment retransmit timeout
|
||||
* value. In this situation, the segment retransmit timeout value
|
||||
* may need to be optimized based on the "Network Transmit" value.
|
||||
*/
|
||||
time = seg_count * (duration + HCI_TIME_FOR_START_ADV) * seg_retrans_num;
|
||||
}
|
||||
|
||||
BT_INFO("Original timeout %dms, calculated timeout %dms", timeout, time);
|
||||
|
||||
if (time < timeout) {
|
||||
/* If the calculated time is smaller than the input timeout value,
|
||||
* then use the original timeout value.
|
||||
*/
|
||||
time = timeout;
|
||||
}
|
||||
} else {
|
||||
/* For unsegmented access messages, directly use the timeout
|
||||
* value from the application layer.
|
||||
*/
|
||||
time = timeout;
|
||||
}
|
||||
|
||||
BT_INFO("Client message 0x%08x with timeout %dms", opcode, time);
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
static void msg_send_start(u16_t duration, int err, void *cb_data)
|
||||
{
|
||||
bt_mesh_client_node_t *node = cb_data;
|
||||
|
||||
BT_DBG("%s, duration %ums", __func__, duration);
|
||||
|
||||
if (err) {
|
||||
if (!k_delayed_work_free(&node->timer)) {
|
||||
bt_mesh_client_free_node(node);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
k_delayed_work_submit(&node->timer, node->timeout);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_send_cb send_cb = {
|
||||
.start = msg_send_start,
|
||||
.end = NULL,
|
||||
};
|
||||
|
||||
int bt_mesh_client_send_msg(struct bt_mesh_model *model,
|
||||
u32_t opcode,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
|
@ -166,7 +266,7 @@ int bt_mesh_client_send_msg(struct bt_mesh_model *model,
|
|||
void *cb_data)
|
||||
{
|
||||
bt_mesh_client_internal_data_t *internal = NULL;
|
||||
bt_mesh_client_user_data_t *cli = NULL;
|
||||
bt_mesh_client_user_data_t *client = NULL;
|
||||
bt_mesh_client_node_t *node = NULL;
|
||||
int err = 0;
|
||||
|
||||
|
@ -175,43 +275,80 @@ int bt_mesh_client_send_msg(struct bt_mesh_model *model,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
cli = (bt_mesh_client_user_data_t *)model->user_data;
|
||||
__ASSERT(cli, "Invalid client value when sent client msg.");
|
||||
internal = (bt_mesh_client_internal_data_t *)cli->internal_data;
|
||||
__ASSERT(internal, "Invalid internal value when sent client msg.");
|
||||
client = (bt_mesh_client_user_data_t *)model->user_data;
|
||||
if (!client) {
|
||||
BT_ERR("%s, Invalid client user data", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
internal = (bt_mesh_client_internal_data_t *)client->internal_data;
|
||||
if (!internal) {
|
||||
BT_ERR("%s, Invalid client internal data", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ctx->addr == BLE_MESH_ADDR_UNASSIGNED) {
|
||||
BT_ERR("%s, Invalid DST 0x%04x", __func__, ctx->addr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!need_ack) {
|
||||
/* If this is an unack message, send it directly. */
|
||||
return bt_mesh_model_send(model, ctx, msg, cb, cb_data);
|
||||
}
|
||||
|
||||
if (!BLE_MESH_ADDR_IS_UNICAST(ctx->addr)) {
|
||||
/* If an acknowledged message is not sent to a unicast address,
|
||||
* for example to a group/virtual address, then all the
|
||||
* corresponding responses will be treated as publish messages.
|
||||
* And no timeout will be used for the message.
|
||||
*/
|
||||
return bt_mesh_model_send(model, ctx, msg, cb, cb_data);
|
||||
}
|
||||
|
||||
if (!timer_handler) {
|
||||
BT_ERR("%s, Invalid timeout handler", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bt_mesh_client_check_node_in_list(&internal->queue, ctx->addr)) {
|
||||
BT_ERR("%s, Busy sending message to DST 0x%04x", __func__, ctx->addr);
|
||||
err = -EBUSY;
|
||||
} else {
|
||||
/* Don't forget to free the node in the timeout (timer_handler) function. */
|
||||
node = (bt_mesh_client_node_t *)bt_mesh_calloc(sizeof(bt_mesh_client_node_t));
|
||||
if (!node) {
|
||||
BT_ERR("%s, Failed to allocate memory", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(&node->ctx, ctx, sizeof(struct bt_mesh_msg_ctx));
|
||||
node->ctx.model = model;
|
||||
node->opcode = opcode;
|
||||
if ((node->op_pending = bt_mesh_client_get_status_op(cli->op_pair, cli->op_pair_size, opcode)) == 0) {
|
||||
BT_ERR("%s, Not found the status opcode in the op_pair list", __func__);
|
||||
bt_mesh_free(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((err = bt_mesh_model_send(model, ctx, msg, cb, cb_data)) != 0) {
|
||||
bt_mesh_free(node);
|
||||
} else {
|
||||
bt_mesh_list_lock();
|
||||
sys_slist_append(&internal->queue, &node->client_node);
|
||||
bt_mesh_list_unlock();
|
||||
k_delayed_work_init(&node->timer, timer_handler);
|
||||
k_delayed_work_submit(&node->timer, timeout ? timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT);
|
||||
}
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Don't forget to free the node in the timeout (timer_handler) function. */
|
||||
node = (bt_mesh_client_node_t *)bt_mesh_calloc(sizeof(bt_mesh_client_node_t));
|
||||
if (!node) {
|
||||
BT_ERR("%s, Failed to allocate memory", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memcpy(&node->ctx, ctx, sizeof(struct bt_mesh_msg_ctx));
|
||||
node->ctx.model = model;
|
||||
node->opcode = opcode;
|
||||
node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, opcode);
|
||||
if (node->op_pending == 0U) {
|
||||
BT_ERR("%s, Not found the status opcode in the op_pair list", __func__);
|
||||
bt_mesh_free(node);
|
||||
return -EINVAL;
|
||||
}
|
||||
node->timeout = bt_mesh_client_calc_timeout(ctx, msg, opcode, timeout ? timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT);
|
||||
|
||||
k_delayed_work_init(&node->timer, timer_handler);
|
||||
|
||||
bt_mesh_list_lock();
|
||||
sys_slist_append(&internal->queue, &node->client_node);
|
||||
bt_mesh_list_unlock();
|
||||
|
||||
/* "bt_mesh_model_send" will post the mesh packet to the mesh adv queue.
|
||||
* Due to the higher priority of adv_thread (than btc task), we need to
|
||||
* send the packet after the list item "node" is initialized properly.
|
||||
*/
|
||||
err = bt_mesh_model_send(model, ctx, msg, &send_cb, node);
|
||||
if (err) {
|
||||
BT_ERR("Failed to send client message 0x%08x", node->opcode);
|
||||
k_delayed_work_free(&node->timer);
|
||||
bt_mesh_client_free_node(node);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
|
|
@ -65,6 +65,7 @@ typedef struct {
|
|||
struct bt_mesh_msg_ctx ctx; /* Message context */
|
||||
u32_t opcode; /* Message opcode */
|
||||
u32_t op_pending; /* Expected status message opcode */
|
||||
s32_t timeout; /* Calculated message timeout value */
|
||||
struct k_delayed_work timer; /* Time used to get response. Only for internal use. */
|
||||
} bt_mesh_client_node_t;
|
||||
|
||||
|
|
Loading…
Reference in a new issue