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:
Jiang Jiang Jian 2020-03-16 13:26:44 +08:00
commit 36cddd0bae
7 changed files with 285 additions and 47 deletions

View file

@ -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;

View file

@ -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);

View file

@ -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)) {

View file

@ -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;

View file

@ -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,

View file

@ -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;

View file

@ -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;