mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-03 12:44:33 +02:00
feat(ble_mesh): Add lock to avoid tx being modified at the same time
This commit is contained in:
@@ -94,6 +94,7 @@ static struct seg_tx {
|
||||
const struct bt_mesh_send_cb *cb;
|
||||
void *cb_data;
|
||||
struct k_delayed_work rtx_timer; /* Segment Retransmission timer */
|
||||
bt_mesh_mutex_t lock;
|
||||
} seg_tx[CONFIG_BLE_MESH_TX_SEG_MSG_COUNT];
|
||||
|
||||
static struct seg_rx {
|
||||
@@ -120,17 +121,16 @@ static struct seg_rx {
|
||||
static uint8_t seg_rx_buf_data[(CONFIG_BLE_MESH_RX_SEG_MSG_COUNT *
|
||||
CONFIG_BLE_MESH_RX_SDU_MAX)];
|
||||
|
||||
static bt_mesh_mutex_t seg_tx_lock;
|
||||
static bt_mesh_mutex_t seg_rx_lock;
|
||||
|
||||
static inline void bt_mesh_seg_tx_lock(void)
|
||||
static inline void bt_mesh_seg_tx_lock(struct seg_tx *tx)
|
||||
{
|
||||
bt_mesh_mutex_lock(&seg_tx_lock);
|
||||
bt_mesh_r_mutex_lock(&tx->lock);
|
||||
}
|
||||
|
||||
static inline void bt_mesh_seg_tx_unlock(void)
|
||||
static inline void bt_mesh_seg_tx_unlock(struct seg_tx *tx)
|
||||
{
|
||||
bt_mesh_mutex_unlock(&seg_tx_lock);
|
||||
bt_mesh_r_mutex_unlock(&tx->lock);
|
||||
}
|
||||
|
||||
static inline void bt_mesh_seg_rx_lock(void)
|
||||
@@ -331,7 +331,7 @@ static void seg_tx_reset(struct seg_tx *tx)
|
||||
{
|
||||
int i;
|
||||
|
||||
bt_mesh_seg_tx_lock();
|
||||
bt_mesh_seg_tx_lock(tx);
|
||||
|
||||
k_delayed_work_cancel(&tx->rtx_timer);
|
||||
|
||||
@@ -351,7 +351,7 @@ static void seg_tx_reset(struct seg_tx *tx)
|
||||
|
||||
tx->nack_count = 0U;
|
||||
|
||||
bt_mesh_seg_tx_unlock();
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
|
||||
if (bt_mesh_atomic_test_and_clear_bit(bt_mesh.flags, BLE_MESH_IVU_PENDING)) {
|
||||
BT_DBG("Proceeding with pending IV Update");
|
||||
@@ -380,6 +380,7 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err)
|
||||
|
||||
static void schedule_retransmit(struct seg_tx *tx)
|
||||
{
|
||||
bt_mesh_seg_tx_lock(tx);
|
||||
/* It's possible that a segment broadcast hasn't finished,
|
||||
* but the tx are already released. Only the seg_pending
|
||||
* of this segment remains unprocessed. So, here, we
|
||||
@@ -391,20 +392,24 @@ static void schedule_retransmit(struct seg_tx *tx)
|
||||
if (tx->seg_pending) {
|
||||
tx->seg_pending--;
|
||||
}
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (--tx->seg_pending) {
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BLE_MESH_ADDR_IS_UNICAST(tx->dst) && !tx->attempts) {
|
||||
BT_INFO("Complete tx sdu to group");
|
||||
seg_tx_complete(tx, 0);
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
return;
|
||||
}
|
||||
|
||||
k_delayed_work_submit(&tx->rtx_timer, SEG_RETRANSMIT_TIMEOUT(tx));
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
}
|
||||
|
||||
static void seg_first_send_start(uint16_t duration, int err, void *user_data)
|
||||
@@ -450,11 +455,11 @@ static void seg_tx_send_unacked(struct seg_tx *tx)
|
||||
{
|
||||
int i, err = 0;
|
||||
|
||||
bt_mesh_seg_tx_lock();
|
||||
bt_mesh_seg_tx_lock(tx);
|
||||
|
||||
if (!(tx->attempts--)) {
|
||||
BT_WARN("Ran out of retransmit attempts");
|
||||
bt_mesh_seg_tx_unlock();
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
seg_tx_complete(tx, -ETIMEDOUT);
|
||||
return;
|
||||
}
|
||||
@@ -487,13 +492,13 @@ static void seg_tx_send_unacked(struct seg_tx *tx)
|
||||
&seg_sent_cb, tx);
|
||||
if (err) {
|
||||
BT_ERR("Sending segment failed");
|
||||
bt_mesh_seg_tx_unlock();
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
seg_tx_complete(tx, -EIO);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bt_mesh_seg_tx_unlock();
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
}
|
||||
|
||||
static void seg_retransmit(struct k_work *work)
|
||||
@@ -511,6 +516,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu,
|
||||
uint16_t seq_zero = 0U;
|
||||
uint8_t seg_hdr = 0U;
|
||||
uint8_t seg_o = 0U;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
BT_DBG("src 0x%04x dst 0x%04x app_idx 0x%04x aszmic %u sdu_len %u",
|
||||
@@ -583,16 +589,17 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu,
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
bt_mesh_seg_tx_lock(tx);
|
||||
|
||||
for (seg_o = 0U; sdu->len; seg_o++) {
|
||||
struct net_buf *seg = NULL;
|
||||
uint16_t len = 0U;
|
||||
int err = 0;
|
||||
|
||||
seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, BUF_TIMEOUT);
|
||||
if (!seg) {
|
||||
BT_ERR("Out of segment buffers");
|
||||
seg_tx_reset(tx);
|
||||
return -ENOBUFS;
|
||||
err = -ENOBUFS;
|
||||
break;
|
||||
}
|
||||
|
||||
net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN);
|
||||
@@ -637,8 +644,7 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu,
|
||||
tx);
|
||||
if (err) {
|
||||
BT_ERR("Sending segment failed (err %d)", err);
|
||||
seg_tx_reset(tx);
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If security credentials is updated in the network layer,
|
||||
@@ -650,6 +656,13 @@ static int send_seg(struct bt_mesh_net_tx *net_tx, struct net_buf_simple *sdu,
|
||||
}
|
||||
}
|
||||
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
|
||||
if (err) {
|
||||
seg_tx_reset(tx);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* This can happen if segments only went into the Friend Queue */
|
||||
if (IS_ENABLED(CONFIG_BLE_MESH_FRIEND) && !tx->seg[0]) {
|
||||
seg_tx_reset(tx);
|
||||
@@ -984,9 +997,9 @@ static int trans_ack(struct bt_mesh_net_rx *rx, uint8_t hdr,
|
||||
while ((bit = find_lsb_set(ack))) {
|
||||
if (tx->seg[bit - 1]) {
|
||||
BT_INFO("Seg %u/%u acked", bit - 1, tx->seg_n);
|
||||
bt_mesh_seg_tx_lock();
|
||||
bt_mesh_seg_tx_lock(tx);
|
||||
seg_tx_done(tx, bit - 1);
|
||||
bt_mesh_seg_tx_unlock();
|
||||
bt_mesh_seg_tx_unlock(tx);
|
||||
}
|
||||
|
||||
ack &= ~BIT(bit - 1);
|
||||
@@ -1786,6 +1799,7 @@ void bt_mesh_trans_init(void)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_tx); i++) {
|
||||
k_delayed_work_init(&seg_tx[i].rtx_timer, seg_retransmit);
|
||||
bt_mesh_r_mutex_create(&seg_tx[i].lock);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
|
||||
@@ -1795,7 +1809,6 @@ void bt_mesh_trans_init(void)
|
||||
seg_rx[i].buf.data = seg_rx[i].buf.__buf;
|
||||
}
|
||||
|
||||
bt_mesh_mutex_create(&seg_tx_lock);
|
||||
bt_mesh_mutex_create(&seg_rx_lock);
|
||||
}
|
||||
|
||||
@@ -1810,13 +1823,13 @@ void bt_mesh_trans_deinit(bool erase)
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_tx); i++) {
|
||||
k_delayed_work_free(&seg_tx[i].rtx_timer);
|
||||
bt_mesh_r_mutex_free(&seg_tx[i].lock);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(seg_rx); i++) {
|
||||
k_delayed_work_free(&seg_rx[i].ack_timer);
|
||||
}
|
||||
|
||||
bt_mesh_mutex_free(&seg_tx_lock);
|
||||
bt_mesh_mutex_free(&seg_rx_lock);
|
||||
}
|
||||
#endif /* CONFIG_BLE_MESH_DEINIT */
|
||||
|
Reference in New Issue
Block a user