bluetooth: mesh: Remove illegal use of NET_BUF_FRAG in friend.c

This commit removes illegal use of NET_BUF_FRAG in friend.c, which is an
internal flag.

Now `struct bt_mesh_friend_seg` keeps pointer to a first received
segment of a segmented message. The rest segments are added as fragments
using net_buf API. Friend Queue keeps only head of the fragments.
When one segment (currently head of fragments) is removed from Friend
Queue, the next segment is added to the queue. Head has always 2
references: one when allocated, another one when added as fragments
head.

Signed-off-by: Pavel Vasilyev <pavel.vasilyev@nordicsemi.no>
This commit is contained in:
Pavel Vasilyev 2022-12-05 17:12:17 +01:00 committed by Johan Hedberg
commit 5d059117fd
2 changed files with 43 additions and 27 deletions

View file

@ -124,13 +124,22 @@ static void purge_buffers(sys_slist_t *list)
buf = (void *)sys_slist_get_not_empty(list);
buf->frags = NULL;
buf->flags &= ~NET_BUF_FRAGS;
net_buf_unref(buf);
}
}
static void purge_seg_buffers(struct net_buf *buf)
{
/* Fragments head has always 2 references: one when allocated, one when becomes
* fragments head.
*/
net_buf_unref(buf);
do {
buf = net_buf_frag_del(NULL, buf);
} while (buf != NULL);
}
/* Intentionally start a little bit late into the ReceiveWindow when
* it's large enough. This may improve reliability with some platforms,
* like the PTS, where the receiver might not have sufficiently compensated
@ -166,8 +175,10 @@ static void friend_clear(struct bt_mesh_friend *frnd)
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
purge_buffers(&seg->queue);
seg->seg_count = 0U;
if (seg->buf) {
purge_seg_buffers(seg->buf);
seg->seg_count = 0U;
}
}
STRUCT_SECTION_FOREACH(bt_mesh_friend_cb, cb) {
@ -1054,7 +1065,7 @@ init_friend:
static bool is_seg(struct bt_mesh_friend_seg *seg, uint16_t src, uint16_t seq_zero)
{
struct net_buf *buf = (void *)sys_slist_peek_head(&seg->queue);
struct net_buf *buf = seg->buf;
struct net_buf_simple_state state;
uint16_t buf_seq_zero;
uint16_t buf_src;
@ -1087,7 +1098,7 @@ static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
return seg;
}
if (!unassigned && !sys_slist_peek_head(&seg->queue)) {
if (!unassigned && !seg->buf) {
unassigned = seg;
}
}
@ -1122,16 +1133,13 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
return;
}
net_buf_slist_put(&seg->queue, buf);
seg->buf = net_buf_frag_add(seg->buf, buf);
if (type == BT_MESH_FRIEND_PDU_COMPLETE) {
sys_slist_merge_slist(&frnd->queue, &seg->queue);
net_buf_slist_put(&frnd->queue, seg->buf);
frnd->queue_size += seg->seg_count;
seg->seg_count = 0U;
} else {
/* Mark the buffer as having more to come after it */
buf->flags |= NET_BUF_FRAGS;
}
}
@ -1248,6 +1256,15 @@ static void friend_timeout(struct k_work *work)
return;
}
/* Put next segment to the friend queue. */
if (frnd->last != net_buf_frag_last(frnd->last)) {
struct net_buf *next;
next = net_buf_frag_del(NULL, frnd->last);
net_buf_frag_add(NULL, next);
sys_slist_prepend(&frnd->queue, &next->node);
}
md = (uint8_t)(sys_slist_peek_head(&frnd->queue) != NULL);
update_overwrite(frnd->last, md);
@ -1256,10 +1273,6 @@ static void friend_timeout(struct k_work *work)
return;
}
/* Clear the flag we use for segment tracking */
frnd->last->flags &= ~NET_BUF_FRAGS;
frnd->last->frags = NULL;
LOG_DBG("Sending buf %p from Friend Queue of LPN 0x%04x", frnd->last, frnd->lpn);
frnd->queue_size--;
@ -1333,16 +1346,11 @@ int bt_mesh_friend_init(void)
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
int j;
sys_slist_init(&frnd->queue);
k_work_init_delayable(&frnd->timer, friend_timeout);
k_work_init_delayable(&frnd->clear.timer, clear_timeout);
for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
sys_slist_init(&frnd->seg[j].queue);
}
}
return 0;
@ -1636,11 +1644,16 @@ static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, uint16_t add
frnd->queue_size--;
avail_space++;
pending_segments = (buf->flags & NET_BUF_FRAGS);
if (buf != net_buf_frag_last(buf)) {
struct net_buf *next;
/* Make sure old slist entry state doesn't remain */
buf->frags = NULL;
buf->flags &= ~NET_BUF_FRAGS;
next = net_buf_frag_del(NULL, buf);
net_buf_frag_add(NULL, next);
sys_slist_prepend(&frnd->queue, &next->node);
pending_segments = true;
}
net_buf_unref(buf);
}
@ -1761,7 +1774,7 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src,
LOG_WRN("Clearing incomplete segments for 0x%04x", src);
purge_buffers(&seg->queue);
purge_seg_buffers(seg->buf);
seg->seg_count = 0U;
break;
}

View file

@ -67,7 +67,10 @@ struct bt_mesh_friend {
struct k_work_delayable timer;
struct bt_mesh_friend_seg {
sys_slist_t queue;
/* First received segment of a segmented message. Rest
* segments are added as net_buf fragments.
*/
struct net_buf *buf;
/* The target number of segments, i.e. not necessarily
* the current number of segments, in the queue. This is