Skip to content

Commit e74d5da

Browse files
mlaschLukasWoodtli
authored andcommitted
coap: Check for duplicate messages
According to rfc7252#section-4.5 duplicate packets must be dropped.
1 parent 7761974 commit e74d5da

File tree

6 files changed

+150
-2
lines changed

6 files changed

+150
-2
lines changed

coap/message_dedup.c

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* CoAP message deduplication tracking.
3+
* RFC7252 section 4.2
4+
*/
5+
6+
#include <stdbool.h>
7+
8+
#include "message_dedup.h"
9+
#include <internals.h>
10+
#include <liblwm2m.h>
11+
12+
void coap_cleanup_message_deduplication_step(coap_msg_dedup_t **message_dedup, const time_t current_time,
13+
time_t *timeout) {
14+
LOG_DBG("Entering");
15+
coap_msg_dedup_t *message_dedup_check = *message_dedup;
16+
coap_msg_dedup_t *message_dedup_check_prev = *message_dedup;
17+
while (message_dedup_check != NULL) {
18+
time_t diff = current_time - message_dedup_check->timestamp;
19+
if (diff >= EXCHANGE_LIFETIME) {
20+
LOG_DBG("Message %d deduplication period ended", message_dedup_check->mid);
21+
if (message_dedup_check_prev != *message_dedup) {
22+
message_dedup_check_prev->next = message_dedup_check->next;
23+
} else {
24+
*message_dedup = message_dedup_check->next;
25+
message_dedup_check_prev = message_dedup_check->next;
26+
}
27+
coap_msg_dedup_t *message_dedup_check_next = message_dedup_check->next;
28+
lwm2m_free(message_dedup_check);
29+
message_dedup_check = message_dedup_check_next;
30+
} else {
31+
LOG_DBG("Message %d check deduplication", message_dedup_check->mid);
32+
time_t message_dedup_timeout;
33+
if ((message_dedup_timeout = (message_dedup_check->timestamp + EXCHANGE_LIFETIME) - current_time) < 0) {
34+
message_dedup_timeout = 0;
35+
}
36+
if (message_dedup_timeout < *timeout) {
37+
LOG_DBG("Message %d check again in %ds deduplication", message_dedup_check->mid, message_dedup_timeout);
38+
*timeout = message_dedup_timeout;
39+
}
40+
message_dedup_check_prev = message_dedup_check;
41+
message_dedup_check = message_dedup_check->next;
42+
}
43+
}
44+
}
45+
46+
bool coap_check_message_duplication(coap_msg_dedup_t **message_dedup, const uint16_t mid, const void *session) {
47+
LOG_DBG("Entering");
48+
coap_msg_dedup_t *message_dedup_check = *message_dedup;
49+
while (message_dedup_check != NULL) {
50+
bool is_equal = lwm2m_session_is_equal(message_dedup_check->session, (void *)session, NULL);
51+
if (message_dedup_check->mid == mid && is_equal) {
52+
LOG_DBG("Duplicate, ignore mid %d (session: %p)", mid, session);
53+
return true;
54+
}
55+
message_dedup_check = message_dedup_check->next;
56+
}
57+
LOG_DBG("Register mid %d (session: %p) for deduplication check", mid, session);
58+
/* The message was not received in the past. Remember for future checks. */
59+
coap_msg_dedup_t *new_message;
60+
new_message = lwm2m_malloc(sizeof(coap_msg_dedup_t));
61+
if (new_message == NULL) {
62+
/* Memory allocation failed, mark packet as duplicate. Further allocations during packet processing would fail
63+
* anyway. */
64+
return true;
65+
}
66+
memset(new_message, 0, sizeof(coap_msg_dedup_t));
67+
new_message->mid = mid;
68+
new_message->session = (void *)session;
69+
new_message->timestamp = lwm2m_gettime();
70+
71+
/* Add message id to deduplication list */
72+
coap_msg_dedup_t *message_dedup_temp = *message_dedup;
73+
*message_dedup = new_message;
74+
(*message_dedup)->next = message_dedup_temp;
75+
76+
return false;
77+
}
78+
79+
void coap_deduplication_free(lwm2m_context_t *ctx) {
80+
LOG_DBG("Remove and free the whole message deduplication list");
81+
while (ctx->message_dedup != NULL) {
82+
coap_msg_dedup_t *msg_dedup;
83+
msg_dedup = ctx->message_dedup;
84+
ctx->message_dedup = ctx->message_dedup->next;
85+
lwm2m_free(msg_dedup);
86+
}
87+
}

coap/message_dedup.h

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef _COAP_MESSAGE_DEDUP_H_
2+
#define _COAP_MESSAGE_DEDUP_H_
3+
4+
#include <stdint.h>
5+
#include <time.h>
6+
7+
#include <liblwm2m.h>
8+
9+
/*
10+
* EXCHANGE_LIFETIME https://datatracker.ietf.org/doc/html/rfc7252#section-4.8.2
11+
* Time to block message ids from a client to prevent receiving duplicate packets.
12+
* Special value for Lemonbeat transmissions: Expected worst case latency per packet: 1s.
13+
* EXCHANGE_LIFETIME = (ACK_TIMEOUT * ((2 ** MAX_RETRANSMIT) - 1) + LEMONBEAT_DELAY) * ACK_RANDOM_FACTOR
14+
* With ACK_RANDOM_FACTOR=1.5, LEMONBEAT_DELAY=1, MAX_RETRANSMIT=4
15+
* (2 * ((2 ** 4) - 1) + 1) * 1.5 = 46.5 -> ~47s
16+
*/
17+
#define EXCHANGE_LIFETIME 47
18+
19+
typedef struct _coap_msg_dedup_ {
20+
struct _coap_msg_dedup_ *next;
21+
uint16_t mid;
22+
void *session;
23+
time_t timestamp;
24+
} coap_msg_dedup_t;
25+
26+
/**
27+
* Cleanup message ids after EXCHANGE_LIFETIME.
28+
* @param message_dedup list of message ids for deduplication
29+
* @param current_time current timestamp
30+
* @param timeout next timeout in main loop
31+
*/
32+
void coap_cleanup_message_deduplication_step(coap_msg_dedup_t **message_dedup, time_t current_time, time_t *timeout);
33+
34+
/**
35+
* Check whether a message was already received.
36+
* @param message_dedup list of message ids for deduplication
37+
* @param mid message id
38+
* @param session pointer to the session the message was received from
39+
* @return true if the message was already seen within in the EXCHANGE_LIFETIME window, false otherwise.
40+
*/
41+
bool coap_check_message_duplication(coap_msg_dedup_t **message_dedup, uint16_t mid, const void *session);
42+
43+
/**
44+
* Remove and free the whole message deduplication list
45+
* @param ctx lwm2m context
46+
*/
47+
void coap_deduplication_free(lwm2m_context_t *ctx);
48+
49+
#endif // _COAP_MESSAGE_DEDUP_H_

core/liblwm2m.c

+3
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
*/
5252

5353
#include "internals.h"
54+
#include "message_dedup.h"
5455

5556
#include <stdlib.h>
5657
#include <string.h>
@@ -223,6 +224,7 @@ void lwm2m_close(lwm2m_context_t * contextP)
223224
#endif
224225

225226
prv_deleteTransactionList(contextP);
227+
coap_deduplication_free(contextP);
226228
lwm2m_free(contextP);
227229
}
228230

@@ -493,6 +495,7 @@ int lwm2m_step(lwm2m_context_t * contextP,
493495

494496
registration_step(contextP, tv_sec, timeoutP);
495497
transaction_step(contextP, tv_sec, timeoutP);
498+
coap_cleanup_message_deduplication_step(&contextP->message_dedup, tv_sec, timeoutP);
496499

497500
LOG_ARG_DBG("Final timeoutP: %d", (int)*timeoutP);
498501
#ifdef LWM2M_CLIENT_MODE

core/packet.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ Contains code snippets which are:
8787

8888

8989
#include "internals.h"
90+
#include "message_dedup.h"
9091

9192
#include <stdlib.h>
9293
#include <string.h>
@@ -498,6 +499,12 @@ void lwm2m_handle_packet(lwm2m_context_t *contextP, uint8_t *buffer, size_t leng
498499
message->type, message->token_len, message->code >> 5, message->code & 0x1F, message->mid,
499500
message->content_type);
500501
LOG_ARG_DBG("Payload: %.*s", (int)message->payload_len, STR_NULL2EMPTY(message->payload));
502+
503+
if (coap_check_message_duplication(&contextP->message_dedup, message->mid, fromSessionH)) {
504+
LOG_DBG("Warning: Message already seen in transmission window");
505+
return;
506+
}
507+
501508
if (message->code >= COAP_GET && message->code <= COAP_DELETE)
502509
{
503510
uint32_t block_num = 0;
@@ -892,4 +899,3 @@ uint8_t message_send(lwm2m_context_t * contextP,
892899

893900
return result;
894901
}
895-

include/liblwm2m.h

+3
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,8 @@ typedef int (*lwm2m_bootstrap_callback_t)(lwm2m_context_t *contextP, void *sessi
823823
void *userData);
824824
#endif
825825

826+
typedef struct _coap_msg_dedup_ coap_msg_dedup_t;
827+
826828
struct _lwm2m_context_
827829
{
828830
#ifdef LWM2M_CLIENT_MODE
@@ -850,6 +852,7 @@ struct _lwm2m_context_
850852
#endif
851853
uint16_t nextMID;
852854
lwm2m_transaction_t * transactionList;
855+
coap_msg_dedup_t *message_dedup;
853856
void * userData;
854857
};
855858

wakaama.cmake

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ function(target_sources_coap target)
201201
target_sources(
202202
${target}
203203
PRIVATE ${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap/block.c ${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap/er-coap-13/er-coap-13.c
204-
${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap/transaction.c
204+
${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap/message_dedup.c ${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap/transaction.c
205205
)
206206
# We should not (have to) do this!
207207
target_include_directories(${target} PRIVATE ${WAKAAMA_TOP_LEVEL_DIRECTORY}/coap)

0 commit comments

Comments
 (0)