Skip to content

Commit 679d616

Browse files
committed
Bluetooth: Mesh: Fix regression in PB-ADV
After #35702, the provisioner is unable to mark a link as closed, as it depends on the send_end callback to be called, so it can start its timer. PB-Adv keeps a reference to the buffers of reliable messages, which prevents this callback to be invoked, as the buffer destructor is never called. Move scheduling of the retransmit timer to the initial transmission, and replace the timer based LINK_CLOSE message tx duration with a message counting solution. Signed-off-by: Trond Einar Snekvik <[email protected]>
1 parent 5513b86 commit 679d616

File tree

1 file changed

+66
-54
lines changed

1 file changed

+66
-54
lines changed

subsys/bluetooth/mesh/pb_adv.c

Lines changed: 66 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,10 @@
5454
/* Acked messages, will do retransmissions manually, taking acks into account:
5555
*/
5656
#define RETRANSMITS_RELIABLE 0
57-
/* Unacked messages: */
58-
#define RETRANSMITS_UNRELIABLE 2
5957
/* PDU acks: */
6058
#define RETRANSMITS_ACK 2
59+
/* Link close retransmits: */
60+
#define RETRANSMITS_LINK_CLOSE 2
6161

6262
enum {
6363
ADV_LINK_ACTIVE, /* Link has been opened */
@@ -126,17 +126,25 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf);
126126
static void link_ack(struct prov_rx *rx, struct net_buf_simple *buf);
127127
static void link_close(struct prov_rx *rx, struct net_buf_simple *buf);
128128
static void prov_link_close(enum prov_bearer_link_status status);
129+
static void close_link(enum prov_bearer_link_status status);
129130

130131
static void buf_sent(int err, void *user_data)
131132
{
132-
if (!link.tx.buf[0]) {
133+
if (atomic_test_and_clear_bit(link.flags, ADV_LINK_CLOSING)) {
134+
close_link(PROV_BEARER_LINK_STATUS_SUCCESS);
133135
return;
134136
}
137+
}
135138

136-
k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT);
139+
static void buf_start(uint16_t duration, int err, void *user_data)
140+
{
141+
if (err) {
142+
buf_sent(err, user_data);
143+
}
137144
}
138145

139146
static struct bt_mesh_send_cb buf_sent_cb = {
147+
.start = buf_start,
140148
.end = buf_sent,
141149
};
142150

@@ -573,64 +581,40 @@ static void send_reliable(void)
573581

574582
BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
575583

576-
if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) {
577-
bt_mesh_adv_send(buf, NULL, NULL);
578-
} else {
579-
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
580-
}
584+
bt_mesh_adv_send(buf, NULL, NULL);
581585
}
586+
587+
k_work_reschedule(&link.tx.retransmit, RETRANSMIT_TIMEOUT);
582588
}
583589

584590
static void prov_retransmit(struct k_work *work)
585591
{
586-
int32_t timeout_ms;
587-
588592
BT_DBG("");
589593

590594
if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
591595
BT_WARN("Link not active");
592596
return;
593597
}
594598

595-
/*
596-
* According to mesh profile spec (5.3.1.4.3), the close message should
597-
* be restransmitted at least three times. Retransmit the link_close
598-
* message until CLOSING_TIMEOUT has elapsed.
599-
*/
600-
if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) {
601-
timeout_ms = CLOSING_TIMEOUT;
602-
} else {
603-
timeout_ms = TRANSACTION_TIMEOUT;
604-
}
605-
606-
if (k_uptime_get() - link.tx.start > timeout_ms) {
607-
if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) {
608-
close_link(PROV_BEARER_LINK_STATUS_SUCCESS);
609-
} else {
610-
BT_WARN("Giving up transaction");
611-
prov_link_close(PROV_BEARER_LINK_STATUS_FAIL);
612-
}
613-
599+
if (k_uptime_get() - link.tx.start > TRANSACTION_TIMEOUT) {
600+
BT_WARN("Giving up transaction");
601+
prov_link_close(PROV_BEARER_LINK_STATUS_FAIL);
614602
return;
615603
}
616604

617605
send_reliable();
618606
}
619607

620-
static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len,
621-
bool reliable)
608+
static struct net_buf *ctl_buf_create(uint8_t op, const void *data, uint8_t data_len,
609+
uint8_t retransmits)
622610
{
623611
struct net_buf *buf;
624612

625613
BT_DBG("op 0x%02x data_len %u", op, data_len);
626614

627-
prov_clear_tx();
628-
k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
629-
630-
buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE :
631-
RETRANSMITS_UNRELIABLE);
615+
buf = adv_buf_create(retransmits);
632616
if (!buf) {
633-
return -ENOBUFS;
617+
return NULL;
634618
}
635619

636620
net_buf_add_be32(buf, link.id);
@@ -639,15 +623,37 @@ static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len,
639623
net_buf_add_u8(buf, GPC_CTL(op));
640624
net_buf_add_mem(buf, data, data_len);
641625

642-
if (reliable) {
643-
link.tx.start = k_uptime_get();
644-
link.tx.buf[0] = buf;
645-
send_reliable();
646-
} else {
647-
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
648-
net_buf_unref(buf);
626+
return buf;
627+
}
628+
629+
static int bearer_ctl_send(struct net_buf *buf)
630+
{
631+
if (!buf) {
632+
return -ENOMEM;
649633
}
650634

635+
prov_clear_tx();
636+
k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
637+
638+
link.tx.start = k_uptime_get();
639+
link.tx.buf[0] = buf;
640+
send_reliable();
641+
642+
return 0;
643+
}
644+
645+
static int bearer_ctl_send_unacked(struct net_buf *buf)
646+
{
647+
if (!buf) {
648+
return -ENOMEM;
649+
}
650+
651+
prov_clear_tx();
652+
k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
653+
654+
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
655+
net_buf_unref(buf);
656+
651657
return 0;
652658
}
653659

@@ -724,6 +730,8 @@ static int prov_send_adv(struct net_buf_simple *msg,
724730

725731
static void link_open(struct prov_rx *rx, struct net_buf_simple *buf)
726732
{
733+
int err;
734+
727735
BT_DBG("len %u", buf->len);
728736

729737
if (buf->len < 16) {
@@ -733,13 +741,14 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf)
733741

734742
if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
735743
/* Send another link ack if the provisioner missed the last */
736-
if (link.id == rx->link_id) {
737-
BT_DBG("Resending link ack");
738-
bearer_ctl_send(LINK_ACK, NULL, 0, false);
739-
} else {
744+
if (link.id != rx->link_id) {
740745
BT_DBG("Ignoring bearer open: link already active");
746+
return;
741747
}
742748

749+
BT_DBG("Resending link ack");
750+
/* Ignore errors, message will be attempted again if we keep receiving link open: */
751+
(void)bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK));
743752
return;
744753
}
745754

@@ -752,7 +761,11 @@ static void link_open(struct prov_rx *rx, struct net_buf_simple *buf)
752761
atomic_set_bit(link.flags, ADV_LINK_ACTIVE);
753762
net_buf_simple_reset(link.rx.buf);
754763

755-
bearer_ctl_send(LINK_ACK, NULL, 0, false);
764+
err = bearer_ctl_send_unacked(ctl_buf_create(LINK_ACK, NULL, 0, RETRANSMITS_ACK));
765+
if (err) {
766+
reset_adv_link();
767+
return;
768+
}
756769

757770
link.cb->link_opened(&pb_adv, link.cb_data);
758771
}
@@ -840,9 +853,7 @@ static int prov_link_open(const uint8_t uuid[16], k_timeout_t timeout,
840853

841854
net_buf_simple_reset(link.rx.buf);
842855

843-
bearer_ctl_send(LINK_OPEN, uuid, 16, true);
844-
845-
return 0;
856+
return bearer_ctl_send(ctl_buf_create(LINK_OPEN, uuid, 16, RETRANSMITS_RELIABLE));
846857
}
847858

848859
static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data)
@@ -878,7 +889,8 @@ static void prov_link_close(enum prov_bearer_link_status status)
878889
return;
879890
}
880891

881-
bearer_ctl_send(LINK_CLOSE, &status, 1, true);
892+
/* Ignore errors, the link will time out eventually if this doesn't get sent */
893+
bearer_ctl_send_unacked(ctl_buf_create(LINK_CLOSE, &status, 1, RETRANSMITS_LINK_CLOSE));
882894
}
883895

884896
void pb_adv_init(void)

0 commit comments

Comments
 (0)