net: coap: Rework pending retransmission logic

Introduce retransmission counter to the coap_pending structure. This
allows to simplify the retransmission logic and allows to keep track of
the number of remaining retranmissions.

Additionally, extend the `coap_pending_init()` function with `retries`
parameter, which allows to set the retransmission count individually for
each confirmable transaction.

Fixes #28117

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2021-01-18 13:13:26 +01:00 committed by Anas Nashif
commit 538e19ee2e
6 changed files with 35 additions and 25 deletions

View file

@ -58,6 +58,10 @@ API Changes
timeout usage must use the new-style k_timeout_t type and not the timeout usage must use the new-style k_timeout_t type and not the
legacy/deprecated millisecond counts. legacy/deprecated millisecond counts.
* The :c:func:`coap_pending_init` function now accepts an additional ``retries``
parameter, allowing to specify the maximum retransmission count of the
confirmable message.
Deprecated in this release Deprecated in this release
========================== ==========================

View file

@ -233,6 +233,8 @@ typedef int (*coap_reply_t)(const struct coap_packet *response,
struct coap_reply *reply, struct coap_reply *reply,
const struct sockaddr *from); const struct sockaddr *from);
#define COAP_DEFAULT_MAX_RETRANSMIT 4
/** /**
* @brief Represents a request awaiting for an acknowledgment (ACK). * @brief Represents a request awaiting for an acknowledgment (ACK).
*/ */
@ -243,6 +245,7 @@ struct coap_pending {
uint16_t id; uint16_t id;
uint8_t *data; uint8_t *data;
uint16_t len; uint16_t len;
uint8_t retries;
}; };
/** /**
@ -687,12 +690,14 @@ void coap_reply_init(struct coap_reply *reply,
* confirmation message, initialized with data from @a request * confirmation message, initialized with data from @a request
* @param request Message waiting for confirmation * @param request Message waiting for confirmation
* @param addr Address to send the retransmission * @param addr Address to send the retransmission
* @param retries Maximum number of retransmissions of the message.
* *
* @return 0 in case of success or negative in case of error. * @return 0 in case of success or negative in case of error.
*/ */
int coap_pending_init(struct coap_pending *pending, int coap_pending_init(struct coap_pending *pending,
const struct coap_packet *request, const struct coap_packet *request,
const struct sockaddr *addr); const struct sockaddr *addr,
uint8_t retries);
/** /**
* @brief Returns the next available pending struct, that can be used * @brief Returns the next available pending struct, that can be used

View file

@ -995,7 +995,8 @@ static int create_pending_request(struct coap_packet *response,
return -ENOMEM; return -ENOMEM;
} }
r = coap_pending_init(pending, response, addr); r = coap_pending_init(pending, response, addr,
COAP_DEFAULT_MAX_RETRANSMIT);
if (r < 0) { if (r < 0) {
return -EINVAL; return -EINVAL;
} }

View file

@ -1072,7 +1072,8 @@ size_t coap_next_block(const struct coap_packet *cpkt,
int coap_pending_init(struct coap_pending *pending, int coap_pending_init(struct coap_pending *pending,
const struct coap_packet *request, const struct coap_packet *request,
const struct sockaddr *addr) const struct sockaddr *addr,
uint8_t retries)
{ {
memset(pending, 0, sizeof(*pending)); memset(pending, 0, sizeof(*pending));
@ -1083,6 +1084,7 @@ int coap_pending_init(struct coap_pending *pending,
pending->data = request->data; pending->data = request->data;
pending->len = request->offset; pending->len = request->offset;
pending->t0 = k_uptime_get_32(); pending->t0 = k_uptime_get_32();
pending->retries = retries;
return 0; return 0;
} }
@ -1201,30 +1203,24 @@ struct coap_pending *coap_pending_next_to_expire(
*/ */
#define INIT_ACK_TIMEOUT CONFIG_COAP_INIT_ACK_TIMEOUT_MS #define INIT_ACK_TIMEOUT CONFIG_COAP_INIT_ACK_TIMEOUT_MS
static int32_t next_timeout(int32_t previous)
{
switch (previous) {
case INIT_ACK_TIMEOUT:
case (INIT_ACK_TIMEOUT * 2):
case (INIT_ACK_TIMEOUT * 4):
return previous << 1;
case (INIT_ACK_TIMEOUT * 8):
/* equal value is returned to end retransmit */
return previous;
}
/* initial or unrecognized */
return INIT_ACK_TIMEOUT;
}
bool coap_pending_cycle(struct coap_pending *pending) bool coap_pending_cycle(struct coap_pending *pending)
{ {
int32_t old = pending->timeout; if (pending->timeout == 0) {
/* Initial transmission. */
pending->timeout = INIT_ACK_TIMEOUT;
return true;
}
if (pending->retries == 0) {
return false;
}
pending->t0 += pending->timeout; pending->t0 += pending->timeout;
pending->timeout = next_timeout(pending->timeout); pending->timeout = pending->timeout << 1;
pending->retries--;
return (old != pending->timeout); return true;
} }
void coap_pending_clear(struct coap_pending *pending) void coap_pending_clear(struct coap_pending *pending)

View file

@ -961,7 +961,8 @@ int lwm2m_init_message(struct lwm2m_message *msg)
goto cleanup; goto cleanup;
} }
r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr); r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr,
COAP_DEFAULT_MAX_RETRANSMIT);
if (r < 0) { if (r < 0) {
LOG_ERR("Unable to initialize a pending " LOG_ERR("Unable to initialize a pending "
"retransmission (err:%d).", r); "retransmission (err:%d).", r);
@ -3996,7 +3997,9 @@ static int lwm2m_response_promote_to_con(struct lwm2m_message *msg)
return -ENOMEM; return -ENOMEM;
} }
ret = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr); ret = coap_pending_init(msg->pending, &msg->cpkt,
&msg->ctx->remote_addr,
COAP_DEFAULT_MAX_RETRANSMIT);
if (ret < 0) { if (ret < 0) {
LOG_ERR("Unable to initialize a pending " LOG_ERR("Unable to initialize a pending "
"retransmission (err:%d).", ret); "retransmission (err:%d).", ret);

View file

@ -1099,7 +1099,8 @@ static int test_retransmit_second_round(void)
goto done; goto done;
} }
r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr); r = coap_pending_init(pending, &cpkt, (struct sockaddr *) &dummy_addr,
COAP_DEFAULT_MAX_RETRANSMIT);
if (r < 0) { if (r < 0) {
TC_PRINT("Could not initialize packet\n"); TC_PRINT("Could not initialize packet\n");
goto done; goto done;