Skip to content

Commit 820cfc5

Browse files
trond-snekvikcarlescufi
authored andcommitted
Bluetooth: Mesh: Rework publication timer
Periodic publication would previously build and send the first publication inside the bt_mesh_model_pub() function, before cancelling and rescheduling the next publication. The timer handler would only handle retransmissions, and would abandon the rest of the publication event if one of the packets failed to send. This design has three issues: - If the initial timer cancel fails, the publication would interfer with the periodic publication management, which might skip an event or send too many packets. - If any of the messages fail to publish, the full publication event would be abandoned. This is not predictable or expected from the API. - bt_mesh_model_pub() required 384 bytes of stack to build the message, which has to be factored into all calling threads. This patch moves all transmission into the publication timer by replacing k_work_cancel with a single k_work_reschedule(K_NO_WAIT). It also changes the error recovery behavior to attempt to finish the full publication event even if some of the transmissions fail. Split out from #33782. Signed-off-by: Trond Einar Snekvik <[email protected]>
1 parent fe3fced commit 820cfc5

File tree

4 files changed

+95
-116
lines changed

4 files changed

+95
-116
lines changed

include/bluetooth/mesh/access.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -340,17 +340,17 @@ struct bt_mesh_model_pub {
340340
/** The model the context belongs to. Initialized by the stack. */
341341
struct bt_mesh_model *mod;
342342

343-
uint16_t addr; /**< Publish Address. */
344-
uint16_t key:12, /**< Publish AppKey Index. */
345-
cred:1, /**< Friendship Credentials Flag. */
346-
send_rel:1; /**< Force reliable sending (segment acks) */
343+
uint16_t addr; /**< Publish Address. */
344+
uint16_t key:12, /**< Publish AppKey Index. */
345+
cred:1, /**< Friendship Credentials Flag. */
346+
send_rel:1, /**< Force reliable sending (segment acks) */
347+
fast_period:1; /**< Use FastPeriodDivisor */
347348

348349
uint8_t ttl; /**< Publish Time to Live. */
349350
uint8_t retransmit; /**< Retransmit Count & Interval Steps. */
350351
uint8_t period; /**< Publish Period. */
351352
uint8_t period_div:4, /**< Divisor for the Period. */
352-
fast_period:1,/**< Use FastPeriodDivisor */
353-
count:3; /**< Retransmissions left. */
353+
count:4; /**< Transmissions left. */
354354

355355
uint32_t period_start; /**< Start of the current period. */
356356

@@ -381,7 +381,7 @@ struct bt_mesh_model_pub {
381381
int (*update)(struct bt_mesh_model *mod);
382382

383383
/** Publish Period Timer. Only for stack-internal use. */
384-
struct k_delayed_work timer;
384+
struct k_work_delayable timer;
385385
};
386386

387387
/** @def BT_MESH_MODEL_PUB_DEFINE

subsys/bluetooth/mesh/access.c

Lines changed: 72 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,10 @@ static void publish_sent(int err, void *user_data)
150150

151151
if (delay) {
152152
BT_DBG("Publishing next time in %dms", delay);
153-
k_delayed_work_submit(&mod->pub->timer, K_MSEC(delay));
153+
/* Using schedule() in case the application has already called
154+
* bt_mesh_publish, and a publication is pending.
155+
*/
156+
k_work_schedule(&mod->pub->timer, K_MSEC(delay));
154157
}
155158
}
156159

@@ -161,6 +164,7 @@ static void publish_start(uint16_t duration, int err, void *user_data)
161164

162165
if (err) {
163166
BT_ERR("Failed to publish: err %d", err);
167+
publish_sent(err, user_data);
164168
return;
165169
}
166170

@@ -175,7 +179,7 @@ static const struct bt_mesh_send_cb pub_sent_cb = {
175179
.end = publish_sent,
176180
};
177181

178-
static int publish_retransmit(struct bt_mesh_model *mod)
182+
static int publish_transmit(struct bt_mesh_model *mod)
179183
{
180184
NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
181185
struct bt_mesh_model_pub *pub = mod->pub;
@@ -192,67 +196,68 @@ static int publish_retransmit(struct bt_mesh_model *mod)
192196

193197
net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len);
194198

195-
pub->count--;
196-
197199
return bt_mesh_trans_send(&tx, &sdu, &pub_sent_cb, mod);
198200
}
199201

200-
static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub)
202+
static int pub_period_start(struct bt_mesh_model_pub *pub)
201203
{
202-
/* Cancel all retransmits for this publish attempt */
203-
pub->count = 0U;
204-
/* Make sure the publish timer gets reset */
205-
publish_sent(err, pub->mod);
204+
int err;
205+
206+
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
207+
208+
if (!pub->update) {
209+
return 0;
210+
}
211+
212+
err = pub->update(pub->mod);
213+
if (err) {
214+
/* Skip this publish attempt. */
215+
BT_DBG("Update failed, skipping publish (err: %d)", err);
216+
pub->count = 0;
217+
pub->period_start = k_uptime_get_32();
218+
publish_sent(err, pub);
219+
return err;
220+
}
221+
222+
return 0;
206223
}
207224

208225
static void mod_publish(struct k_work *work)
209226
{
210-
struct bt_mesh_model_pub *pub = CONTAINER_OF(work,
227+
struct k_work_delayable *dwork = k_work_delayable_from_work(work);
228+
struct bt_mesh_model_pub *pub = CONTAINER_OF(dwork,
211229
struct bt_mesh_model_pub,
212-
timer.work);
213-
int32_t period_ms;
230+
timer);
214231
int err;
215232

216-
BT_DBG("");
233+
if (pub->addr == BT_MESH_ADDR_UNASSIGNED ||
234+
atomic_test_bit(bt_mesh.flags, BT_MESH_SUSPENDED)) {
235+
/* Publication is no longer active, but the cancellation of the
236+
* delayed work failed. Abandon recurring timer.
237+
*/
238+
return;
239+
}
217240

218-
period_ms = bt_mesh_model_pub_period_get(pub->mod);
219-
BT_DBG("period %u ms", period_ms);
241+
BT_DBG("");
220242

221243
if (pub->count) {
222-
err = publish_retransmit(pub->mod);
244+
pub->count--;
245+
} else {
246+
/* First publication in this period */
247+
err = pub_period_start(pub);
223248
if (err) {
224-
BT_ERR("Failed to retransmit (err %d)", err);
225-
226-
pub->count = 0U;
227-
228-
/* Continue with normal publication */
229-
if (period_ms) {
230-
k_delayed_work_submit(&pub->timer,
231-
K_MSEC(period_ms));
232-
}
249+
return;
233250
}
234-
235-
return;
236251
}
237252

238-
if (!period_ms) {
239-
return;
240-
}
241-
242-
__ASSERT_NO_MSG(pub->update != NULL);
243-
244-
err = pub->update(pub->mod);
253+
err = publish_transmit(pub->mod);
245254
if (err) {
246-
/* Cancel this publish attempt. */
247-
BT_DBG("Update failed, skipping publish (err: %d)", err);
248-
pub->period_start = k_uptime_get_32();
249-
publish_retransmit_end(err, pub);
250-
return;
251-
}
255+
BT_ERR("Failed to publish (err %d)", err);
256+
if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) {
257+
pub->period_start = k_uptime_get_32();
258+
}
252259

253-
err = bt_mesh_model_publish(pub->mod);
254-
if (err) {
255-
BT_ERR("Publishing failed (err %d)", err);
260+
publish_sent(err, pub->mod);
256261
}
257262
}
258263

@@ -301,7 +306,7 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
301306

302307
if (mod->pub) {
303308
mod->pub->mod = mod;
304-
k_delayed_work_init(&mod->pub->timer, mod_publish);
309+
k_work_init_delayable(&mod->pub->timer, mod_publish);
305310
}
306311

307312
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
@@ -630,102 +635,67 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf)
630635
}
631636
}
632637

633-
static int model_send(struct bt_mesh_model *model,
634-
struct bt_mesh_net_tx *tx, bool implicit_bind,
635-
struct net_buf_simple *msg,
636-
const struct bt_mesh_send_cb *cb, void *cb_data)
638+
int bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
639+
struct net_buf_simple *msg,
640+
const struct bt_mesh_send_cb *cb, void *cb_data)
637641
{
638-
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx,
639-
tx->ctx->app_idx, tx->ctx->addr);
642+
struct bt_mesh_net_tx tx = {
643+
.ctx = ctx,
644+
.src = bt_mesh_model_elem(model)->addr,
645+
};
646+
647+
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx.ctx->net_idx,
648+
tx.ctx->app_idx, tx.ctx->addr);
640649
BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len));
641650

642651
if (!bt_mesh_is_provisioned()) {
643652
BT_ERR("Local node is not yet provisioned");
644653
return -EAGAIN;
645654
}
646655

647-
if (net_buf_simple_tailroom(msg) < 4) {
648-
BT_ERR("Not enough tailroom for TransMIC");
656+
if (!model_has_key(model, tx.ctx->app_idx)) {
657+
BT_ERR("Model not bound to AppKey 0x%04x", tx.ctx->app_idx);
649658
return -EINVAL;
650659
}
651660

652-
if (msg->len > BT_MESH_TX_SDU_MAX - 4) {
653-
BT_ERR("Too big message");
654-
return -EMSGSIZE;
655-
}
656-
657-
if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) {
658-
BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx);
659-
return -EINVAL;
660-
}
661-
662-
return bt_mesh_trans_send(tx, msg, cb, cb_data);
663-
}
664-
665-
int bt_mesh_model_send(struct bt_mesh_model *model,
666-
struct bt_mesh_msg_ctx *ctx,
667-
struct net_buf_simple *msg,
668-
const struct bt_mesh_send_cb *cb, void *cb_data)
669-
{
670-
struct bt_mesh_net_tx tx = {
671-
.ctx = ctx,
672-
.src = bt_mesh_model_elem(model)->addr,
673-
};
674-
675-
return model_send(model, &tx, false, msg, cb, cb_data);
661+
return bt_mesh_trans_send(&tx, msg, cb, cb_data);
676662
}
677663

678664
int bt_mesh_model_publish(struct bt_mesh_model *model)
679665
{
680-
NET_BUF_SIMPLE_DEFINE(sdu, BT_MESH_TX_SDU_MAX);
681666
struct bt_mesh_model_pub *pub = model->pub;
682667

683668
if (!pub) {
684669
return -ENOTSUP;
685670
}
686671

687-
struct bt_mesh_msg_ctx ctx = {
688-
.addr = pub->addr,
689-
.send_ttl = pub->ttl,
690-
.send_rel = pub->send_rel,
691-
.app_idx = pub->key,
692-
};
693-
struct bt_mesh_net_tx tx = {
694-
.ctx = &ctx,
695-
.src = bt_mesh_model_elem(model)->addr,
696-
};
697-
int err;
698-
699672
BT_DBG("");
700673

701674
if (pub->addr == BT_MESH_ADDR_UNASSIGNED) {
702675
return -EADDRNOTAVAIL;
703676
}
704677

705-
if (pub->msg->len + 4 > BT_MESH_TX_SDU_MAX) {
678+
if (!pub->msg || !pub->msg->len) {
679+
BT_ERR("No publication message");
680+
return -EINVAL;
681+
}
682+
683+
if (pub->msg->len + BT_MESH_MIC_SHORT > BT_MESH_TX_SDU_MAX) {
706684
BT_ERR("Message does not fit maximum SDU size");
707685
return -EMSGSIZE;
708686
}
709687

710688
if (pub->count) {
711689
BT_WARN("Clearing publish retransmit timer");
712-
k_delayed_work_cancel(&pub->timer);
713690
}
714691

715-
net_buf_simple_add_mem(&sdu, pub->msg->data, pub->msg->len);
716-
717-
tx.friend_cred = pub->cred;
718-
719-
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
692+
/* Account for initial transmission */
693+
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit) + 1;
720694

721695
BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
722696
BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
723697

724-
err = model_send(model, &tx, true, &sdu, &pub_sent_cb, model);
725-
if (err) {
726-
publish_retransmit_end(err, pub);
727-
return err;
728-
}
698+
k_work_reschedule(&pub->timer, K_NO_WAIT);
729699

730700
return 0;
731701
}
@@ -1208,7 +1178,7 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
12081178

12091179
if (ms > 0) {
12101180
BT_DBG("Starting publish timer (period %u ms)", ms);
1211-
k_delayed_work_submit(&mod->pub->timer, K_MSEC(ms));
1181+
k_work_schedule(&mod->pub->timer, K_MSEC(ms));
12121182
}
12131183
}
12141184

subsys/bluetooth/mesh/cfg_srv.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,10 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
201201
model->pub->count = 0U;
202202

203203
if (model->pub->update) {
204-
k_delayed_work_cancel(&model->pub->timer);
204+
/* If this fails, the timer will check pub->addr and
205+
* exit without transmitting.
206+
*/
207+
(void)k_work_cancel_delayable(&model->pub->timer);
205208
}
206209

207210
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
@@ -239,10 +242,13 @@ static uint8_t _mod_pub_set(struct bt_mesh_model *model, uint16_t pub_addr,
239242
BT_DBG("period %u ms", period_ms);
240243

241244
if (period_ms > 0) {
242-
k_delayed_work_submit(&model->pub->timer,
243-
K_MSEC(period_ms));
245+
k_work_reschedule(&model->pub->timer,
246+
K_MSEC(period_ms));
244247
} else {
245-
k_delayed_work_cancel(&model->pub->timer);
248+
/* If this fails, publication will stop after the
249+
* ongoing set of retransmits.
250+
*/
251+
(void)k_work_cancel_delayable(&model->pub->timer);
246252
}
247253
}
248254

subsys/bluetooth/mesh/main.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@ static void model_suspend(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
227227
{
228228
if (mod->pub && mod->pub->update) {
229229
mod->pub->count = 0U;
230-
k_delayed_work_cancel(&mod->pub->timer);
230+
/* If this fails, the work handler will check the suspend call
231+
* and exit without transmitting.
232+
*/
233+
(void)k_work_cancel_delayable(&mod->pub->timer);
231234
}
232235
}
233236

@@ -268,8 +271,8 @@ static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
268271
int32_t period_ms = bt_mesh_model_pub_period_get(mod);
269272

270273
if (period_ms) {
271-
k_delayed_work_submit(&mod->pub->timer,
272-
K_MSEC(period_ms));
274+
k_work_reschedule(&mod->pub->timer,
275+
K_MSEC(period_ms));
273276
}
274277
}
275278
}

0 commit comments

Comments
 (0)