From 35bcfc25b76b6be19093a5e85b94485e9160104c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Narajowski?= Date: Tue, 20 Feb 2018 14:23:49 +0100 Subject: [PATCH] mesh: Fix handling of failed transmissions When sending a segmented message, the state could get stuck if the advertising bearer fails in transmitting and we don't detect that it happened. Add a send_start callback for all packets so we can always know if sending fails. X-Original-Commit: c2f6fa5baf8eab609a705347e1c1b881e48bd710 --- nimble/host/mesh/src/transport.c | 36 ++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/nimble/host/mesh/src/transport.c b/nimble/host/mesh/src/transport.c index 9902a6d7c..4ae20f37b 100644 --- a/nimble/host/mesh/src/transport.c +++ b/nimble/host/mesh/src/transport.c @@ -46,6 +46,12 @@ /* Number of retransmit attempts (after the initial transmit) per segment */ #define SEG_RETRANSMIT_ATTEMPTS 4 +/* "This timer shall be set to a minimum of 200 + 50 * TTL milliseconds.". + * We use 400 since 300 is a common send duration for standard HCI, and we + * need to have a timeout that's bigger than that. + */ +#define SEG_RETRANSMIT_TIMEOUT(tx) (K_MSEC(400) + 50 * (tx)->ttl) + /* How long to wait for available buffers before giving up */ #define BUF_TIMEOUT K_NO_WAIT @@ -191,7 +197,7 @@ static inline void seg_tx_complete(struct seg_tx *tx, int err) seg_tx_reset(tx); } -static void seg_send_start(u16_t duration, int err, void *user_data) +static void seg_first_send_start(u16_t duration, int err, void *user_data) { struct seg_tx *tx = user_data; @@ -200,27 +206,35 @@ static void seg_send_start(u16_t duration, int err, void *user_data) } } +static void seg_send_start(u16_t duration, int err, void *user_data) +{ + struct seg_tx *tx = user_data; + + /* If there's an error in transmitting the 'sent' callback will never + * be called. Make sure that we kick the retransmit timer also in this + * case since otherwise we risk the transmission of becoming stale. + */ + if (err) { + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); + } +} + static void seg_sent(int err, void *user_data) { struct seg_tx *tx = user_data; - s32_t timeout; - /* "This timer shall be set to a minimum of 200 + 50 * TTL - * milliseconds.". We use 400 since 300 is a common send - * duration for standard HCI, and we need to have a timeout - * that's bigger than that. - */ - timeout = K_MSEC(400) + 50 * tx->ttl; - - k_delayed_work_submit(&tx->retransmit, timeout); + k_delayed_work_submit(&tx->retransmit, + SEG_RETRANSMIT_TIMEOUT(tx)); } static const struct bt_mesh_send_cb first_sent_cb = { - .start = seg_send_start, + .start = seg_first_send_start, .end = seg_sent, }; static const struct bt_mesh_send_cb seg_sent_cb = { + .start = seg_send_start, .end = seg_sent, };