ble_mesh: Enable Segmented Control Messages [Zephyr]

The function bt_mesh_ctl_send() used to support maximum length of
11 bytes. The segmentation complies with the BLE Mesh Standard.
The ack is disabled in case of non unicast address.
This commit is contained in:
lly 2020-03-24 18:37:50 +08:00
parent f14cdd5d3a
commit 1717c2face

View file

@ -1039,16 +1039,12 @@ static inline s32_t ack_timeout(struct seg_rx *rx)
return MAX(to, K_MSEC(400));
}
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,
const struct bt_mesh_send_cb *cb, void *cb_data)
static int ctl_send_unseg(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
size_t data_len, u64_t *seq_auth,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct net_buf *buf = NULL;
BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src,
tx->ctx->addr, tx->ctx->send_ttl, ctl_op);
BT_DBG("len %u: %s", data_len, bt_hex(data, data_len));
buf = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit, BUF_TIMEOUT);
if (!buf) {
BT_ERR("%s, Out of transport buffers", __func__);
@ -1076,6 +1072,107 @@ int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
return bt_mesh_net_send(tx, buf, cb, cb_data);
}
static int ctl_send_seg(struct bt_mesh_net_tx *tx, u8_t ctl_op,
void *data, size_t data_len, u64_t *seq_auth,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct seg_tx *tx_seg = NULL;
u16_t unsent = data_len;
u16_t seq_zero = 0;
u8_t seg_o = 0;
int i;
for (tx_seg = NULL, i = 0; i < ARRAY_SIZE(seg_tx); i++) {
if (!seg_tx[i].nack_count) {
tx_seg = &seg_tx[i];
break;
}
}
if (!tx_seg) {
BT_ERR("%s, No multi-segment message contexts available", __func__);
return -EBUSY;
}
tx_seg->dst = tx->ctx->addr;
tx_seg->seg_n = (data_len - 1) / 8;
tx_seg->nack_count = tx_seg->seg_n + 1;
tx_seg->seq_auth = SEQ_AUTH(BLE_MESH_NET_IVI_TX, bt_mesh.seq);
tx_seg->sub = tx->sub;
tx_seg->new_key = tx->sub->kr_flag;
tx_seg->cb = cb;
tx_seg->cb_data = cb_data;
if (tx->ctx->send_ttl == BLE_MESH_TTL_DEFAULT) {
tx_seg->ttl = bt_mesh_default_ttl_get();
} else {
tx_seg->ttl = tx->ctx->send_ttl;
}
seq_zero = tx_seg->seq_auth & TRANS_SEQ_ZERO_MASK;
BT_DBG("SeqZero 0x%04x", seq_zero);
for (seg_o = 0; seg_o <= tx_seg->seg_n; seg_o++) {
struct net_buf *seg = NULL;
u16_t len = 0;
int err = 0;
seg = bt_mesh_adv_create(BLE_MESH_ADV_DATA, tx->xmit,
BUF_TIMEOUT);
if (!seg) {
BT_ERR("%s, Out of segment buffers", __func__);
seg_tx_reset(tx_seg);
return -ENOBUFS;
}
BLE_MESH_ADV(seg)->seg.attempts = SEG_RETRANSMIT_ATTEMPTS;
net_buf_reserve(seg, BLE_MESH_NET_HDR_LEN);
net_buf_add_u8(seg, TRANS_CTL_HDR(ctl_op, 1));
net_buf_add_u8(seg, (tx->aszmic << 7) | seq_zero >> 6);
net_buf_add_u8(seg, (((seq_zero & 0x3f) << 2) | (seg_o >> 3)));
net_buf_add_u8(seg, ((seg_o & 0x07) << 5) | tx_seg->seg_n);
len = MIN(unsent, 8);
net_buf_add_mem(seg, (u8_t *)data + (data_len - unsent), len);
unsent -= len;
tx_seg->seg[seg_o] = net_buf_ref(seg);
BT_DBG("Sending %u/%u", seg_o, tx_seg->seg_n);
err = bt_mesh_net_send(tx, seg,
seg_o ? &seg_sent_cb : &first_sent_cb,
tx_seg);
if (err) {
BT_ERR("%s, Sending segment failed", __func__);
seg_tx_reset(tx_seg);
return err;
}
}
return 0;
}
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,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
BT_DBG("src 0x%04x dst 0x%04x ttl 0x%02x ctl 0x%02x", tx->src,
tx->ctx->addr, tx->ctx->send_ttl, ctl_op);
BT_DBG("len %zu: %s", data_len, bt_hex(data, data_len));
if (data_len <= 11) {
return ctl_send_unseg(tx, ctl_op, data, data_len, seq_auth,
cb, cb_data);
} else {
return ctl_send_seg(tx, ctl_op, data, data_len, seq_auth,
cb, cb_data);
}
}
static int send_ack(struct bt_mesh_subnet *sub, u16_t src, u16_t dst,
u8_t ttl, u64_t *seq_auth, u32_t block, u8_t obo)
{