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>
diff --git a/doc/releases/release-notes-2.5.rst b/doc/releases/release-notes-2.5.rst
index 7d95723..fbb687c 100644
--- a/doc/releases/release-notes-2.5.rst
+++ b/doc/releases/release-notes-2.5.rst
@@ -58,6 +58,10 @@
timeout usage must use the new-style k_timeout_t type and not the
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
==========================
diff --git a/include/net/coap.h b/include/net/coap.h
index 32bc989..91e3b31 100644
--- a/include/net/coap.h
+++ b/include/net/coap.h
@@ -233,6 +233,8 @@
struct coap_reply *reply,
const struct sockaddr *from);
+#define COAP_DEFAULT_MAX_RETRANSMIT 4
+
/**
* @brief Represents a request awaiting for an acknowledgment (ACK).
*/
@@ -243,6 +245,7 @@
uint16_t id;
uint8_t *data;
uint16_t len;
+ uint8_t retries;
};
/**
@@ -687,12 +690,14 @@
* confirmation message, initialized with data from @a request
* @param request Message waiting for confirmation
* @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.
*/
int coap_pending_init(struct coap_pending *pending,
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
diff --git a/samples/net/sockets/coap_server/src/coap-server.c b/samples/net/sockets/coap_server/src/coap-server.c
index 2341618..adc5be9 100644
--- a/samples/net/sockets/coap_server/src/coap-server.c
+++ b/samples/net/sockets/coap_server/src/coap-server.c
@@ -995,7 +995,8 @@
return -ENOMEM;
}
- r = coap_pending_init(pending, response, addr);
+ r = coap_pending_init(pending, response, addr,
+ COAP_DEFAULT_MAX_RETRANSMIT);
if (r < 0) {
return -EINVAL;
}
diff --git a/subsys/net/lib/coap/coap.c b/subsys/net/lib/coap/coap.c
index 17767b2..ff0a1f7 100644
--- a/subsys/net/lib/coap/coap.c
+++ b/subsys/net/lib/coap/coap.c
@@ -1072,7 +1072,8 @@
int coap_pending_init(struct coap_pending *pending,
const struct coap_packet *request,
- const struct sockaddr *addr)
+ const struct sockaddr *addr,
+ uint8_t retries)
{
memset(pending, 0, sizeof(*pending));
@@ -1083,6 +1084,7 @@
pending->data = request->data;
pending->len = request->offset;
pending->t0 = k_uptime_get_32();
+ pending->retries = retries;
return 0;
}
@@ -1201,30 +1203,24 @@
*/
#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)
{
- 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->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)
diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c
index 7a138a6..8c98fea 100644
--- a/subsys/net/lib/lwm2m/lwm2m_engine.c
+++ b/subsys/net/lib/lwm2m/lwm2m_engine.c
@@ -961,7 +961,8 @@
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) {
LOG_ERR("Unable to initialize a pending "
"retransmission (err:%d).", r);
@@ -3996,7 +3997,9 @@
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) {
LOG_ERR("Unable to initialize a pending "
"retransmission (err:%d).", ret);
diff --git a/tests/net/lib/coap/src/main.c b/tests/net/lib/coap/src/main.c
index 0363ffe..902613b 100644
--- a/tests/net/lib/coap/src/main.c
+++ b/tests/net/lib/coap/src/main.c
@@ -1099,7 +1099,8 @@
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) {
TC_PRINT("Could not initialize packet\n");
goto done;