Skip to content

Commit d0cba34

Browse files
SeppoTakalocfriedt
authored andcommitted
net: lwm2m: Prevent QUEUE_RX_OFF while waiting for CoAP Ack
The LwM2M RD client state machine have no knowledge of ongoing observations or any other CoAP traffic and might trigger QUEUE_RX_OFF state while engine is still waiting for Ack. This can happen if CoAP Ack timeout is longer than CONFIG_LWM2M_QUEUE_MODE_UPTIME and response is lost or taking longer than QUEUE_MODE_UPTIME. When observation is lost, CoAP Ack may be send, but socket is not listening anymore if its closed or not polled while in RX_OFF and this stops observation. Signed-off-by: Seppo Takalo <[email protected]>
1 parent 5ac8c48 commit d0cba34

File tree

7 files changed

+85
-7
lines changed

7 files changed

+85
-7
lines changed

subsys/net/lib/lwm2m/lwm2m_engine.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -653,8 +653,9 @@ static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoi
653653
{
654654
bool empty;
655655
size_t pendings;
656+
int next_state = -1;
656657

657-
if (!ctx || !ctx->set_socket_state) {
658+
if (!ctx) {
658659
return;
659660
}
660661

@@ -677,14 +678,23 @@ static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoi
677678
bool ongoing_block_tx = coap_block_has_more(&ongoing_tx->cpkt);
678679

679680
if (!empty || ongoing_block_tx) {
680-
ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONGOING);
681+
next_state = LWM2M_SOCKET_STATE_ONGOING;
681682
} else if (ongoing_tx->type == COAP_TYPE_CON) {
682-
ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_ONE_RESPONSE);
683+
next_state = LWM2M_SOCKET_STATE_ONE_RESPONSE;
683684
} else {
684-
ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_LAST);
685+
next_state = LWM2M_SOCKET_STATE_LAST;
685686
}
686687
} else if (empty && pendings == 0) {
687-
ctx->set_socket_state(ctx->sock_fd, LWM2M_SOCKET_STATE_NO_DATA);
688+
next_state = LWM2M_SOCKET_STATE_NO_DATA;
689+
}
690+
691+
if (next_state < 0) {
692+
return;
693+
}
694+
695+
lwm2m_rd_client_hint_socket_state(ctx, next_state);
696+
if (ctx->set_socket_state) {
697+
ctx->set_socket_state(ctx->sock_fd, next_state);
688698
}
689699
}
690700

subsys/net/lib/lwm2m/lwm2m_engine.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,4 +399,15 @@ void lwm2m_client_lock(struct lwm2m_ctx *ctx);
399399
*/
400400
void lwm2m_client_unlock(struct lwm2m_ctx *ctx);
401401

402+
/**
403+
* @brief Hints the RD client about the current socket state.
404+
*
405+
* Prevents the RD client from going to QUEUE_RX_OFF state when the socket is
406+
* in use.
407+
*
408+
* @param ctx LwM2M context
409+
* @param state Current socket state
410+
*/
411+
void lwm2m_rd_client_hint_socket_state(struct lwm2m_ctx *ctx, enum lwm2m_socket_states state);
412+
402413
#endif /* LWM2M_ENGINE_H */

subsys/net/lib/lwm2m/lwm2m_rd_client.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ struct lwm2m_rd_client_info {
120120
uint8_t engine_state;
121121
uint8_t retries;
122122
uint8_t retry_delay;
123+
enum lwm2m_socket_states socket_state;
123124

124125
int64_t last_update;
125126
int64_t last_tx;
@@ -170,6 +171,24 @@ struct lwm2m_message *lwm2m_get_ongoing_rd_msg(void)
170171
return &client.rd_message;
171172
}
172173

174+
static bool ongoing_traffic(void)
175+
{
176+
switch (client.socket_state) {
177+
case LWM2M_SOCKET_STATE_NO_DATA:
178+
case LWM2M_SOCKET_STATE_LAST:
179+
return false;
180+
default:
181+
return true;
182+
}
183+
}
184+
185+
void lwm2m_rd_client_hint_socket_state(struct lwm2m_ctx *ctx, enum lwm2m_socket_states state)
186+
{
187+
if (ctx && client.ctx == ctx) {
188+
client.socket_state = state;
189+
}
190+
}
191+
173192
void engine_update_tx_time(void)
174193
{
175194
client.last_tx = k_uptime_get();
@@ -1144,7 +1163,11 @@ static int64_t next_update(void)
11441163
static int64_t next_rx_off(void)
11451164
{
11461165
if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
1147-
return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC;
1166+
if (!ongoing_traffic()) {
1167+
return client.last_tx + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC;
1168+
} else {
1169+
return k_uptime_get() + CONFIG_LWM2M_QUEUE_MODE_UPTIME * MSEC_PER_SEC;
1170+
}
11481171
} else {
11491172
return next_update();
11501173
}

tests/net/lib/lwm2m/lwm2m_engine/src/stubs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ DEFINE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *);
4444
DEFINE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t);
4545
DEFINE_FAKE_VOID_FUNC(engine_update_tx_time);
4646
DEFINE_FAKE_VALUE_FUNC(bool, coap_block_has_more, struct coap_packet *);
47+
DEFINE_FAKE_VOID_FUNC(lwm2m_rd_client_hint_socket_state, struct lwm2m_ctx *,
48+
enum lwm2m_socket_states);
4749

4850
static sys_slist_t obs_obj_path_list = SYS_SLIST_STATIC_INIT(&obs_obj_path_list);
4951
sys_slist_t *lwm2m_obs_obj_path_list(void)

tests/net/lib/lwm2m/lwm2m_engine/src/stubs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ DECLARE_FAKE_VALUE_FUNC(int, lwm2m_security_mode, struct lwm2m_ctx *);
5959
DECLARE_FAKE_VALUE_FUNC(int, z_impl_zsock_setsockopt, int, int, int, const void *, socklen_t);
6060
DECLARE_FAKE_VOID_FUNC(engine_update_tx_time);
6161
DECLARE_FAKE_VALUE_FUNC(bool, coap_block_has_more, struct coap_packet *);
62+
DECLARE_FAKE_VOID_FUNC(lwm2m_rd_client_hint_socket_state, struct lwm2m_ctx *,
63+
enum lwm2m_socket_states);
6264

6365
#define DO_FOREACH_FAKE(FUNC) \
6466
do { \
@@ -91,6 +93,7 @@ DECLARE_FAKE_VALUE_FUNC(bool, coap_block_has_more, struct coap_packet *);
9193
FUNC(z_impl_zsock_setsockopt) \
9294
FUNC(engine_update_tx_time) \
9395
FUNC(coap_block_has_more) \
96+
FUNC(lwm2m_rd_client_hint_socket_state) \
9497
} while (0)
9598

9699
#endif /* STUBS_H */

tests/net/lib/lwm2m/lwm2m_rd_client/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ add_compile_definitions(CONFIG_LWM2M_COAP_BLOCK_SIZE=256)
2424
add_compile_definitions(CONFIG_LWM2M_COAP_MAX_MSG_SIZE=512)
2525
add_compile_definitions(CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME=20)
2626
add_compile_definitions(CONFIG_LWM2M_SECURITY_INSTANCE_COUNT=1)
27-
add_compile_definitions(CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY=10)
27+
add_compile_definitions(CONFIG_LWM2M_SECONDS_TO_UPDATE_EARLY=5)
2828
add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_UPTIME=10)
2929
add_compile_definitions(CONFIG_LWM2M_LOG_LEVEL=4)
3030
add_compile_definitions(CONFIG_LWM2M_QUEUE_MODE_ENABLED=1)

tests/net/lib/lwm2m/lwm2m_rd_client/src/main.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,8 +339,37 @@ ZTEST(lwm2m_rd_client, test_rx_off)
339339
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE),
340340
NULL);
341341

342+
/* Should not go to RX_OFF while ongoing traffic */
343+
lwm2m_rd_client_hint_socket_state(&ctx, LWM2M_SOCKET_STATE_ONGOING);
342344
engine_update_tx_time();
343345
k_sleep(K_SECONDS(15));
346+
zassert_false(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF),
347+
NULL);
348+
349+
/* Should not go to RX_OFF while waiting for response */
350+
lwm2m_rd_client_hint_socket_state(&ctx, LWM2M_SOCKET_STATE_ONE_RESPONSE);
351+
engine_update_tx_time();
352+
k_sleep(K_SECONDS(15));
353+
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE),
354+
NULL);
355+
zassert_false(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF),
356+
NULL);
357+
358+
/* Should go to RX_OFF after response to a registration request */
359+
lwm2m_rd_client_hint_socket_state(&ctx, LWM2M_SOCKET_STATE_LAST);
360+
engine_update_tx_time();
361+
k_sleep(K_SECONDS(15));
362+
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE),
363+
NULL);
364+
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF),
365+
NULL);
366+
367+
/* Should go to RX_OFF normally */
368+
lwm2m_rd_client_hint_socket_state(&ctx, LWM2M_SOCKET_STATE_NO_DATA);
369+
engine_update_tx_time();
370+
k_sleep(K_SECONDS(15));
371+
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE),
372+
NULL);
344373
zassert_true(expect_lwm2m_rd_client_event(LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF),
345374
NULL);
346375
}

0 commit comments

Comments
 (0)