ble_mesh: Encrypt friend packets on send

Stores friend queue packets unencrypted, removing any out-of-order
issues caused by seqnum allocation. Also moves as much of the metadata
storage as possible into the packet, allowing us to free up some bytes
of net_buf user data for friend packets.
pull/4625/head
lly 2019-10-23 10:51:33 +08:00
rodzic 99a63ce81d
commit 89a681fd4a
4 zmienionych plików z 471 dodań i 118 usunięć

Wyświetl plik

@ -963,6 +963,20 @@ static inline void *net_buf_user_data(struct net_buf *buf)
*/
#define net_buf_pull(buf, len) net_buf_simple_pull(&(buf)->b, len)
/**
* @def net_buf_pull_mem
* @brief Remove data from the beginning of the buffer.
*
* Removes data from the beginning of the buffer by modifying the data
* pointer and buffer length.
*
* @param buf Buffer to update.
* @param len Number of bytes to remove.
*
* @return Pointer to the old beginning of the buffer data.
*/
#define net_buf_pull_mem(buf, len) net_buf_simple_pull_mem(&(buf)->b, len)
/**
* @def net_buf_pull_u8
* @brief Remove a 8-bit value from the beginning of the buffer
@ -1052,6 +1066,180 @@ static inline void *net_buf_user_data(struct net_buf *buf)
*/
#define net_buf_headroom(buf) net_buf_simple_headroom(&(buf)->b)
/**
* @def net_buf_tail
* @brief Get the tail pointer for a buffer.
*
* Get a pointer to the end of the data in a buffer.
*
* @param buf Buffer.
*
* @return Tail pointer for the buffer.
*/
#define net_buf_tail(buf) net_buf_simple_tail(&(buf)->b)
/**
* @brief Find the last fragment in the fragment list.
*
* @return Pointer to last fragment in the list.
*/
struct net_buf *net_buf_frag_last(struct net_buf *frags);
/**
* @brief Insert a new fragment to a chain of bufs.
*
* Insert a new fragment into the buffer fragments list after the parent.
*
* Note: This function takes ownership of the fragment reference so the
* caller is not required to unref.
*
* @param parent Parent buffer/fragment.
* @param frag Fragment to insert.
*/
void net_buf_frag_insert(struct net_buf *parent, struct net_buf *frag);
/**
* @brief Add a new fragment to the end of a chain of bufs.
*
* Append a new fragment into the buffer fragments list.
*
* Note: This function takes ownership of the fragment reference so the
* caller is not required to unref.
*
* @param head Head of the fragment chain.
* @param frag Fragment to add.
*
* @return New head of the fragment chain. Either head (if head
* was non-NULL) or frag (if head was NULL).
*/
struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag);
/**
* @brief Delete existing fragment from a chain of bufs.
*
* @param parent Parent buffer/fragment, or NULL if there is no parent.
* @param frag Fragment to delete.
*
* @return Pointer to the buffer following the fragment, or NULL if it
* had no further fragments.
*/
#if defined(CONFIG_BLE_MESH_NET_BUF_LOG)
struct net_buf *net_buf_frag_del_debug(struct net_buf *parent,
struct net_buf *frag,
const char *func, int line);
#define net_buf_frag_del(_parent, _frag) \
net_buf_frag_del_debug(_parent, _frag, __func__, __LINE__)
#else
struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag);
#endif
/**
* @brief Copy bytes from net_buf chain starting at offset to linear buffer
*
* Copy (extract) @a len bytes from @a src net_buf chain, starting from @a
* offset in it, to a linear buffer @a dst. Return number of bytes actually
* copied, which may be less than requested, if net_buf chain doesn't have
* enough data, or destination buffer is too small.
*
* @param dst Destination buffer
* @param dst_len Destination buffer length
* @param src Source net_buf chain
* @param offset Starting offset to copy from
* @param len Number of bytes to copy
* @return number of bytes actually copied
*/
size_t net_buf_linearize(void *dst, size_t dst_len,
struct net_buf *src, size_t offset, size_t len);
/**
* @typedef net_buf_allocator_cb
* @brief Network buffer allocator callback.
*
* @details The allocator callback is called when net_buf_append_bytes
* needs to allocate a new net_buf.
*
* @param timeout Affects the action taken should the net buf pool be empty.
* If K_NO_WAIT, then return immediately. If K_FOREVER, then
* wait as long as necessary. Otherwise, wait up to the specified
* number of milliseconds before timing out.
* @param user_data The user data given in net_buf_append_bytes call.
* @return pointer to allocated net_buf or NULL on error.
*/
typedef struct net_buf *(*net_buf_allocator_cb)(s32_t timeout, void *user_data);
/**
* @brief Append data to a list of net_buf
*
* @details Append data to a net_buf. If there is not enough space in the
* net_buf then more net_buf will be added, unless there are no free net_buf
* and timeout occurs.
*
* @param buf Network buffer.
* @param len Total length of input data
* @param value Data to be added
* @param timeout Timeout is passed to the net_buf allocator callback.
* @param allocate_cb When a new net_buf is required, use this callback.
* @param user_data A user data pointer to be supplied to the allocate_cb.
* This pointer is can be anything from a mem_pool or a net_pkt, the
* logic is left up to the allocate_cb function.
*
* @return Length of data actually added. This may be less than input
* length if other timeout than K_FOREVER was used, and there
* were no free fragments in a pool to accommodate all data.
*/
size_t net_buf_append_bytes(struct net_buf *buf, size_t len,
const void *value, s32_t timeout,
net_buf_allocator_cb allocate_cb, void *user_data);
/**
* @brief Skip N number of bytes in a net_buf
*
* @details Skip N number of bytes starting from fragment's offset. If the total
* length of data is placed in multiple fragments, this function will skip from
* all fragments until it reaches N number of bytes. Any fully skipped buffers
* are removed from the net_buf list.
*
* @param buf Network buffer.
* @param len Total length of data to be skipped.
*
* @return Pointer to the fragment or
* NULL and pos is 0 after successful skip,
* NULL and pos is 0xffff otherwise.
*/
static inline struct net_buf *net_buf_skip(struct net_buf *buf, size_t len)
{
while (buf && len--) {
net_buf_pull_u8(buf);
if (!buf->len) {
buf = net_buf_frag_del(NULL, buf);
}
}
return buf;
}
/**
* @brief Calculate amount of bytes stored in fragments.
*
* Calculates the total amount of data stored in the given buffer and the
* fragments linked to it.
*
* @param buf Buffer to start off with.
*
* @return Number of bytes in the buffer and its fragments.
*/
static inline size_t net_buf_frags_len(struct net_buf *buf)
{
size_t bytes = 0;
while (buf) {
bytes += buf->len;
buf = buf->frags;
}
return bytes;
}
/**
* @}
*/

Wyświetl plik

@ -447,4 +447,143 @@ struct net_buf *net_buf_alloc_fixed(struct net_buf_pool *pool, s32_t timeout)
return net_buf_alloc_len(pool, fixed->data_size, timeout);
}
#endif
#endif
struct net_buf *net_buf_frag_last(struct net_buf *buf)
{
NET_BUF_ASSERT(buf);
while (buf->frags) {
buf = buf->frags;
}
return buf;
}
void net_buf_frag_insert(struct net_buf *parent, struct net_buf *frag)
{
NET_BUF_ASSERT(parent);
NET_BUF_ASSERT(frag);
if (parent->frags) {
net_buf_frag_last(frag)->frags = parent->frags;
}
/* Take ownership of the fragment reference */
parent->frags = frag;
}
struct net_buf *net_buf_frag_add(struct net_buf *head, struct net_buf *frag)
{
NET_BUF_ASSERT(frag);
if (!head) {
return net_buf_ref(frag);
}
net_buf_frag_insert(net_buf_frag_last(head), frag);
return head;
}
#if defined(CONFIG_BLE_MESH_NET_BUF_LOG)
struct net_buf *net_buf_frag_del_debug(struct net_buf *parent,
struct net_buf *frag,
const char *func, int line)
#else
struct net_buf *net_buf_frag_del(struct net_buf *parent, struct net_buf *frag)
#endif
{
struct net_buf *next_frag;
NET_BUF_ASSERT(frag);
if (parent) {
NET_BUF_ASSERT(parent->frags);
NET_BUF_ASSERT(parent->frags == frag);
parent->frags = frag->frags;
}
next_frag = frag->frags;
frag->frags = NULL;
#if defined(CONFIG_BLE_MESH_NET_BUF_LOG)
net_buf_unref_debug(frag, func, line);
#else
net_buf_unref(frag);
#endif
return next_frag;
}
size_t net_buf_linearize(void *dst, size_t dst_len, struct net_buf *src,
size_t offset, size_t len)
{
struct net_buf *frag;
size_t to_copy;
size_t copied;
len = MIN(len, dst_len);
frag = src;
/* find the right fragment to start copying from */
while (frag && offset >= frag->len) {
offset -= frag->len;
frag = frag->frags;
}
/* traverse the fragment chain until len bytes are copied */
copied = 0;
while (frag && len > 0) {
to_copy = MIN(len, frag->len - offset);
memcpy((u8_t *)dst + copied, frag->data + offset, to_copy);
copied += to_copy;
/* to_copy is always <= len */
len -= to_copy;
frag = frag->frags;
/* after the first iteration, this value will be 0 */
offset = 0;
}
return copied;
}
/* This helper routine will append multiple bytes, if there is no place for
* the data in current fragment then create new fragment and add it to
* the buffer. It assumes that the buffer has at least one fragment.
*/
size_t net_buf_append_bytes(struct net_buf *buf, size_t len,
const void *value, s32_t timeout,
net_buf_allocator_cb allocate_cb, void *user_data)
{
struct net_buf *frag = net_buf_frag_last(buf);
size_t added_len = 0;
const u8_t *value8 = value;
do {
u16_t count = MIN(len, net_buf_tailroom(frag));
net_buf_add_mem(frag, value8, count);
len -= count;
added_len += count;
value8 += count;
if (len == 0) {
return added_len;
}
frag = allocate_cb(timeout, user_data);
if (!frag) {
return added_len;
}
net_buf_frag_add(buf, frag);
} while (1);
/* Unreachable */
return 0;
}

Wyświetl plik

@ -46,15 +46,10 @@ struct bt_mesh_adv {
busy: 1;
u8_t xmit;
union {
/* Address, used e.g. for Friend Queue messages */
u16_t addr;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
};
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
};
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);

Wyświetl plik

@ -37,9 +37,6 @@
#define FRIEND_BUF_COUNT ((CONFIG_BLE_MESH_FRIEND_QUEUE_SIZE + 1) * \
CONFIG_BLE_MESH_FRIEND_LPN_COUNT)
#define FRIEND_ADV(buf) CONTAINER_OF(BLE_MESH_ADV(buf), \
struct friend_adv, adv)
/* PDUs from Friend to the LPN should only be transmitted once with the
* smallest possible interval (20ms).
*/
@ -60,10 +57,7 @@ struct friend_pdu_info {
NET_BUF_POOL_FIXED_DEFINE(friend_buf_pool, FRIEND_BUF_COUNT,
BLE_MESH_ADV_DATA_SIZE, NULL);
static struct friend_adv {
struct bt_mesh_adv adv;
u64_t seq_auth;
} adv_pool[FRIEND_BUF_COUNT];
static struct bt_mesh_adv adv_pool[FRIEND_BUF_COUNT];
enum {
BLE_MESH_FRIENDSHIP_TERMINATE_ESTABLISH_FAIL,
@ -79,7 +73,7 @@ static void (*friend_cb)(bool establish, u16_t lpn_addr, u8_t reason);
static struct bt_mesh_adv *adv_alloc(int id)
{
return &adv_pool[id].adv;
return &adv_pool[id];
}
static bool is_lpn_unicast(struct bt_mesh_friend *frnd, u16_t addr)
@ -318,13 +312,7 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd,
struct friend_pdu_info *info,
struct net_buf_simple *sdu)
{
struct bt_mesh_subnet *sub;
const u8_t *enc, *priv;
struct net_buf *buf;
u8_t nid;
sub = bt_mesh_subnet_get(frnd->net_idx);
__ASSERT_NO_MSG(sub != NULL);
buf = bt_mesh_adv_create_from_pool(&friend_buf_pool, adv_alloc,
BLE_MESH_ADV_DATA,
@ -333,22 +321,7 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd,
return NULL;
}
BLE_MESH_ADV(buf)->addr = info->src;
FRIEND_ADV(buf)->seq_auth = TRANS_SEQ_AUTH_NVAL;
/* Friend Offer needs master security credentials */
if (info->ctl && TRANS_CTL_OP(sdu->data) == TRANS_CTL_OP_FRIEND_OFFER) {
enc = sub->keys[sub->kr_flag].enc;
priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid;
} else {
if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
BT_ERR("%s, friend_cred_get failed", __func__);
goto failed;
}
}
net_buf_add_u8(buf, (nid | (info->iv_index & 1) << 7));
net_buf_add_u8(buf, (info->iv_index & 1) << 7); /* Will be reset in encryption */
if (info->ctl) {
net_buf_add_u8(buf, info->ttl | 0x80);
@ -363,25 +336,55 @@ static struct net_buf *create_friend_pdu(struct bt_mesh_friend *frnd,
net_buf_add_mem(buf, sdu->data, sdu->len);
/* We re-encrypt and obfuscate using the received IVI rather than
* the normal TX IVI (which may be different) since the transport
* layer nonce includes the IVI.
*/
if (bt_mesh_net_encrypt(enc, &buf->b, info->iv_index, false)) {
BT_ERR("%s, Re-encrypting failed", __func__);
goto failed;
}
if (bt_mesh_net_obfuscate(buf->data, info->iv_index, priv)) {
BT_ERR("%s, Re-obfuscating failed", __func__);
goto failed;
}
return buf;
}
failed:
net_buf_unref(buf);
return NULL;
static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct net_buf *buf, bool master_cred)
{
struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
const u8_t *enc, *priv;
u32_t iv_index;
u16_t src;
u8_t nid;
if (master_cred) {
enc = sub->keys[sub->kr_flag].enc;
priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid;
} else {
if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
BT_ERR("friend_cred_get failed");
return -ENOENT;
}
}
src = sys_get_be16(&buf->data[5]);
if (bt_mesh_elem_find(src)) {
/* Local messages were stored with a blank seqnum */
u32_t seq = bt_mesh_next_seq();
buf->data[2] = seq >> 16;
buf->data[3] = seq >> 8;
buf->data[4] = seq;
iv_index = BLE_MESH_NET_IVI_TX;
} else {
u8_t ivi = (buf->data[0] >> 7);
iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi));
}
buf->data[0] = (nid | (iv_index & 1) << 7);
if (bt_mesh_net_encrypt(enc, &buf->b, iv_index, false)) {
BT_ERR("Encrypting failed");
return -EINVAL;
}
if (bt_mesh_net_obfuscate(buf->data, iv_index, priv)) {
BT_ERR("Obfuscating failed");
return -EINVAL;
}
return 0;
}
static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd,
@ -389,7 +392,6 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd,
struct net_buf_simple *sdu)
{
struct friend_pdu_info info;
u32_t seq;
BT_DBG("LPN 0x%04x", frnd->lpn);
@ -401,10 +403,7 @@ static struct net_buf *encode_friend_ctl(struct bt_mesh_friend *frnd,
info.ctl = 1U;
info.ttl = 0U;
seq = bt_mesh_next_seq();
info.seq[0] = seq >> 16;
info.seq[1] = seq >> 8;
info.seq[2] = seq;
memset(info.seq, 0, sizeof(info.seq));
info.iv_index = BLE_MESH_NET_IVI_TX;
@ -450,6 +449,10 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, u8_t xact)
return;
}
if (encrypt_friend_pdu(frnd, buf, false)) {
return;
}
if (frnd->last) {
BT_DBG("Discarding last PDU");
net_buf_unref(frnd->last);
@ -759,6 +762,10 @@ static void enqueue_offer(struct bt_mesh_friend *frnd, s8_t rssi)
return;
}
if (encrypt_friend_pdu(frnd, buf, true)) {
return;
}
frnd->counter++;
if (frnd->last) {
@ -904,8 +911,29 @@ init_friend:
return 0;
}
static bool is_seg(struct bt_mesh_friend_seg *seg, u16_t src, u16_t seq_zero)
{
struct net_buf *buf = (void *)sys_slist_peek_head(&seg->queue);
struct net_buf_simple_state state;
u16_t buf_seq_zero;
u16_t buf_src;
if (!buf) {
return false;
}
net_buf_simple_save(&buf->b, &state);
net_buf_skip(buf, 5); /* skip IVI, NID, CTL, TTL, SEQ */
buf_src = net_buf_pull_be16(buf);
net_buf_skip(buf, 3); /* skip DST, OP/AID */
buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK);
net_buf_simple_restore(&buf->b, &state);
return ((src == buf_src) && (seq_zero == buf_seq_zero));
}
static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
u16_t src, u64_t *seq_auth,
u16_t src, u16_t seq_zero,
u8_t seg_count)
{
struct bt_mesh_friend_seg *unassigned = NULL;
@ -913,14 +941,12 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
struct net_buf *buf = (void *)sys_slist_peek_head(&seg->queue);
if (buf && BLE_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
if (is_seg(seg, src, seq_zero)) {
return seg;
}
if (!unassigned && !buf) {
if (!unassigned && !sys_slist_peek_head(&seg->queue)) {
unassigned = seg;
}
}
@ -934,10 +960,10 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
enum bt_mesh_friend_pdu_type type,
u8_t seg_count, struct net_buf *buf)
u16_t src, u8_t seg_count,
struct net_buf *buf)
{
struct bt_mesh_friend_seg *seg;
struct friend_adv *adv;
BT_DBG("type %u", type);
@ -950,11 +976,11 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
return;
}
adv = FRIEND_ADV(buf);
seg = get_seg(frnd, BLE_MESH_ADV(buf)->addr, &adv->seq_auth, seg_count);
u16_t seq_zero = (((buf->data[10] << 8 | buf->data[11]) >> 2) & TRANS_SEQ_ZERO_MASK);
seg = get_seg(frnd, src, seq_zero, seg_count);
if (!seg) {
BT_ERR("%s, No free friend segment RX contexts for 0x%04x",
__func__, BLE_MESH_ADV(buf)->addr);
BT_ERR("No free friend segment RX contexts for 0x%04x", src);
net_buf_unref(buf);
return;
}
@ -966,16 +992,9 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
enqueue_update(frnd, 1);
}
/* Only acks should have a valid SeqAuth in the Friend queue
* (otherwise we can't easily detect them there), so clear
* the SeqAuth information from the segments before merging.
*/
SYS_SLIST_FOR_EACH_CONTAINER(&seg->queue, buf, node) {
FRIEND_ADV(buf)->seq_auth = TRANS_SEQ_AUTH_NVAL;
frnd->queue_size++;
}
sys_slist_merge_slist(&frnd->queue, &seg->queue);
frnd->queue_size += seg->seg_count;
seg->seg_count = 0U;
} else {
/* Mark the buffer as having more to come after it */
@ -1052,6 +1071,10 @@ static void friend_timeout(struct k_work *work)
return;
}
if (encrypt_friend_pdu(frnd, frnd->last, false)) {
return;
}
/* Clear the flag we use for segment tracking */
frnd->last->flags &= ~NET_BUF_FRAGS;
frnd->last->frags = NULL;
@ -1094,6 +1117,42 @@ int bt_mesh_friend_init(void)
return 0;
}
static bool is_segack(struct net_buf *buf, u64_t *seqauth, u16_t src)
{
struct net_buf_simple_state state;
bool found = false;
if (buf->len != 16) {
return false;
}
net_buf_simple_save(&buf->b, &state);
net_buf_skip(buf, 1); /* skip IVI, NID */
if (!(net_buf_pull_u8(buf) >> 7)) {
goto end;
}
net_buf_pull(buf, 3); /* skip SEQNUM */
if (src != net_buf_pull_be16(buf)) {
goto end;
}
net_buf_skip(buf, 2); /* skip dst */
if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) {
goto end;
}
found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) ==
(*seqauth & TRANS_SEQ_ZERO_MASK);
end:
net_buf_simple_restore(&buf->b, &state);
return found;
}
static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
u16_t src)
{
@ -1105,8 +1164,7 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
cur != NULL; prev = cur, cur = sys_slist_peek_next(cur)) {
struct net_buf *buf = (void *)cur;
if (BLE_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
if (is_segack(buf, seq_auth, src)) {
BT_DBG("Removing old ack from Friend Queue");
sys_slist_remove(&frnd->queue, prev, cur);
@ -1158,11 +1216,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
return;
}
if (seq_auth) {
FRIEND_ADV(buf)->seq_auth = *seq_auth;
}
enqueue_friend_pdu(frnd, type, seg_count, buf);
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
BT_DBG("Queued message for LPN 0x%04x, queue_size %u",
frnd->lpn, frnd->queue_size);
@ -1176,7 +1230,6 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
{
struct friend_pdu_info info;
struct net_buf *buf;
u32_t seq;
BT_DBG("LPN 0x%04x", frnd->lpn);
@ -1190,10 +1243,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
info.ttl = tx->ctx->send_ttl;
info.ctl = (tx->ctx->app_idx == BLE_MESH_KEY_UNUSED);
seq = bt_mesh_next_seq();
info.seq[0] = seq >> 16;
info.seq[1] = seq >> 8;
info.seq[2] = seq;
memset(info.seq, 0, sizeof(info.seq)); /* Will be allocated before encryption */
info.iv_index = BLE_MESH_NET_IVI_TX;
@ -1203,11 +1253,7 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
return;
}
if (seq_auth) {
FRIEND_ADV(buf)->seq_auth = *seq_auth;
}
enqueue_friend_pdu(frnd, type, seg_count, buf);
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
BT_DBG("Queued message for LPN 0x%04x", frnd->lpn);
}
@ -1270,17 +1316,11 @@ static bool friend_queue_has_space(struct bt_mesh_friend *frnd, u16_t addr,
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
if (seq_auth) {
struct net_buf *buf;
if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
/* If there's a segment queue for this message then the
* space verification has already happened.
*/
buf = (void *)sys_slist_peek_head(&seg->queue);
if (buf && BLE_MESH_ADV(buf)->addr == addr &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
return true;
}
return true;
}
total += seg->seg_count;
@ -1454,18 +1494,8 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[j];
struct net_buf *buf;
buf = (void *)sys_slist_peek_head(&seg->queue);
if (!buf) {
continue;
}
if (BLE_MESH_ADV(buf)->addr != src) {
continue;
}
if (FRIEND_ADV(buf)->seq_auth != *seq_auth) {
if (!is_seg(seg, src, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
continue;
}
@ -1473,6 +1503,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
purge_buffers(&seg->queue);
seg->seg_count = 0U;
break;
}
}
}