net: lwm2m: DTLS session cache enable and queue mode update

Enabled DTLS session cache for support session resume.
Fixed LwM2M queue mode for close connection and reconnect automatically.
Re-connect will do Registration update before it send queued data.
Session resume is helping a case when NAT change address and cause less
network traffic.

Signed-off-by: Juha Heiskanen <juha.heiskanen@nordicsemi.no>
This commit is contained in:
Juha Heiskanen 2022-04-08 05:20:55 -07:00 committed by Carles Cufí
commit f20eeebbd1
6 changed files with 230 additions and 15 deletions

View file

@ -117,6 +117,9 @@ struct lwm2m_ctx {
struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING]; struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING];
struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES];
sys_slist_t pending_sends; sys_slist_t pending_sends;
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
sys_slist_t queued_messages;
#endif
sys_slist_t observer; sys_slist_t observer;
/** A pointer to currently processed request, for internal LwM2M engine /** A pointer to currently processed request, for internal LwM2M engine
@ -151,6 +154,19 @@ struct lwm2m_ctx {
*/ */
bool use_dtls; bool use_dtls;
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
/**
* Flag to indicate that the socket connection is suspended.
* With queue mode, this will tell if there is a need to reconnect.
*/
bool connection_suspended;
/**
* Flag to indicate that the client is buffering Notifications and Send messages.
* True value buffer Notifications and Send messages.
*/
bool buffer_client_messages;
#endif
/** Current index of Security Object used for server credentials */ /** Current index of Security Object used for server credentials */
int sec_obj_inst; int sec_obj_inst;

View file

@ -192,6 +192,11 @@ config LWM2M_QUEUE_MODE_UPTIME
defaults to 93 seconds, see RFC 7252), it does not forbid other defaults to 93 seconds, see RFC 7252), it does not forbid other
values though. values though.
config LWM2M_TLS_SESSION_CACHING
bool "TLS session caching"
help
Enabling this only when feature is supported in TLS library.
config LWM2M_RD_CLIENT_SUPPORT config LWM2M_RD_CLIENT_SUPPORT
bool "support for LWM2M client bootstrap/registration state machine" bool "support for LWM2M client bootstrap/registration state machine"
default y default y

View file

@ -1338,6 +1338,9 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release)
if (msg->ctx) { if (msg->ctx) {
sys_slist_find_and_remove(&msg->ctx->pending_sends, &msg->node); sys_slist_find_and_remove(&msg->ctx->pending_sends, &msg->node);
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
sys_slist_find_and_remove(&msg->ctx->queued_messages, &msg->node);
#endif
} }
if (release) { if (release) {
@ -1421,15 +1424,85 @@ cleanup:
return r; return r;
} }
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx)
{
#ifdef CONFIG_LWM2M_DTLS_SUPPORT
if (!client_ctx->use_dtls) {
return 0;
}
if (client_ctx->connection_suspended) {
client_ctx->connection_suspended = false;
LOG_DBG("Resume suspended connection");
return lwm2m_socket_start(client_ctx);
}
#endif
return 0;
}
#endif
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx)
{
client_ctx->buffer_client_messages = false;
while (!sys_slist_is_empty(&client_ctx->queued_messages)) {
sys_snode_t *msg_node = sys_slist_get(&client_ctx->queued_messages);
struct lwm2m_message *msg;
if (!msg_node) {
break;
}
msg = SYS_SLIST_CONTAINER(msg_node, msg, node);
sys_slist_append(&msg->ctx->pending_sends, &msg->node);
}
return 0;
}
#endif
int lwm2m_send_message_async(struct lwm2m_message *msg) int lwm2m_send_message_async(struct lwm2m_message *msg)
{ {
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT)
int ret;
ret = lwm2m_rd_client_connection_resume(msg->ctx);
if (ret) {
lwm2m_reset_message(msg, true);
return ret;
}
#endif
sys_slist_append(&msg->ctx->pending_sends, &msg->node); sys_slist_append(&msg->ctx->pending_sends, &msg->node);
if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT) && if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT) &&
IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
engine_update_tx_time(); engine_update_tx_time();
} }
return 0;
}
int lwm2m_information_interface_send(struct lwm2m_message *msg)
{
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) && defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT)
int ret;
ret = lwm2m_rd_client_connection_resume(msg->ctx);
if (ret) {
lwm2m_reset_message(msg, true);
return ret;
}
if (msg->ctx->buffer_client_messages) {
sys_slist_append(&msg->ctx->queued_messages, &msg->node);
return 0;
}
#endif
sys_slist_append(&msg->ctx->pending_sends, &msg->node);
if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT) &&
IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
engine_update_tx_time();
}
return 0; return 0;
} }
@ -5250,7 +5323,7 @@ static int generate_notify_message(struct lwm2m_ctx *ctx,
goto cleanup; goto cleanup;
} }
lwm2m_send_message_async(msg); lwm2m_information_interface_send(msg);
LOG_DBG("NOTIFY MSG: SENT"); LOG_DBG("NOTIFY MSG: SENT");
return 0; return 0;
@ -5344,6 +5417,44 @@ static int32_t lwm2m_engine_service(const int64_t timestamp)
timestamp); timestamp);
} }
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_engine_close_socket_connection(struct lwm2m_ctx *client_ctx)
{
int ret = 0;
/* Enable Queue mode buffer store */
client_ctx->buffer_client_messages = true;
#ifdef CONFIG_LWM2M_DTLS_SUPPORT
if (!client_ctx->use_dtls) {
return 0;
}
if (client_ctx->sock_fd >= 0) {
ret = close(client_ctx->sock_fd);
if (ret) {
LOG_ERR("Failed to close socket: %d", errno);
ret = -errno;
return ret;
}
client_ctx->sock_fd = -1;
client_ctx->connection_suspended = true;
}
/* Open socket again that Observation and re-send functionality works */
client_ctx->sock_fd =
socket(client_ctx->remote_addr.sa_family, SOCK_DGRAM, IPPROTO_DTLS_1_2);
if (client_ctx->sock_fd < 0) {
LOG_ERR("Failed to create socket: %d", errno);
return -errno;
}
#endif
return ret;
}
#endif
int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx) int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
{ {
int sock_fd = client_ctx->sock_fd; int sock_fd = client_ctx->sock_fd;
@ -5369,7 +5480,10 @@ int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
CONFIG_LWM2M_ENGINE_MAX_PENDING); CONFIG_LWM2M_ENGINE_MAX_PENDING);
coap_replies_clear(client_ctx->replies, coap_replies_clear(client_ctx->replies,
CONFIG_LWM2M_ENGINE_MAX_REPLIES); CONFIG_LWM2M_ENGINE_MAX_REPLIES);
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
client_ctx->connection_suspended = false;
client_ctx->buffer_client_messages = true;
#endif
lwm2m_socket_del(client_ctx); lwm2m_socket_del(client_ctx);
client_ctx->sock_fd = -1; client_ctx->sock_fd = -1;
if (sock_fd >= 0) { if (sock_fd >= 0) {
@ -5383,6 +5497,11 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
{ {
sys_slist_init(&client_ctx->pending_sends); sys_slist_init(&client_ctx->pending_sends);
sys_slist_init(&client_ctx->observer); sys_slist_init(&client_ctx->observer);
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
client_ctx->buffer_client_messages = true;
client_ctx->connection_suspended = false;
sys_slist_init(&client_ctx->queued_messages);
#endif
} }
/* LwM2M Socket Integration */ /* LwM2M Socket Integration */
@ -5633,6 +5752,7 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
socklen_t addr_len; socklen_t addr_len;
int flags; int flags;
int ret; int ret;
bool allocate_socket = false;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT) #if defined(CONFIG_LWM2M_DTLS_SUPPORT)
uint8_t tmp; uint8_t tmp;
@ -5653,15 +5773,20 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
return ret; return ret;
} }
} }
if (client_ctx->use_dtls) {
client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family,
SOCK_DGRAM, IPPROTO_DTLS_1_2);
} else
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ #endif /* CONFIG_LWM2M_DTLS_SUPPORT */
{
client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family, if (client_ctx->sock_fd < 0) {
SOCK_DGRAM, IPPROTO_UDP); allocate_socket = true;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
if (client_ctx->use_dtls) {
client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family, SOCK_DGRAM,
IPPROTO_DTLS_1_2);
} else
#endif /* CONFIG_LWM2M_DTLS_SUPPORT */
{
client_ctx->sock_fd =
socket(client_ctx->remote_addr.sa_family, SOCK_DGRAM, IPPROTO_UDP);
}
} }
if (client_ctx->sock_fd < 0) { if (client_ctx->sock_fd < 0) {
@ -5683,6 +5808,18 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
goto error; goto error;
} }
if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) {
int session_cache = TLS_SESSION_CACHE_ENABLED;
ret = setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SESSION_CACHE,
&session_cache, sizeof(session_cache));
if (ret < 0) {
ret = -errno;
LOG_ERR("Failed to set TLS_SESSION_CACHE option: %d", errno);
goto error;
}
}
if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) { if (client_ctx->hostname_verify && (client_ctx->desthostname != NULL)) {
/** store character at len position */ /** store character at len position */
tmp = client_ctx->desthostname[client_ctx->desthostnamelen]; tmp = client_ctx->desthostname[client_ctx->desthostnamelen];
@ -5734,9 +5871,10 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
} }
LOG_INF("Connected, sock id %d", client_ctx->sock_fd); LOG_INF("Connected, sock id %d", client_ctx->sock_fd);
if (allocate_socket) {
return lwm2m_socket_add(client_ctx); return lwm2m_socket_add(client_ctx);
}
return 0;
error: error:
lwm2m_engine_context_close(client_ctx); lwm2m_engine_context_close(client_ctx);
return ret; return ret;
@ -6334,7 +6472,7 @@ int lwm2m_engine_send(struct lwm2m_ctx *ctx, char const *path_list[], uint8_t pa
goto cleanup; goto cleanup;
} }
LOG_INF("Send op to server (/dp)"); LOG_INF("Send op to server (/dp)");
lwm2m_send_message_async(msg); lwm2m_information_interface_send(msg);
return 0; return 0;
cleanup: cleanup:

View file

@ -123,6 +123,8 @@ struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx);
void lwm2m_reset_message(struct lwm2m_message *msg, bool release); void lwm2m_reset_message(struct lwm2m_message *msg, bool release);
int lwm2m_init_message(struct lwm2m_message *msg); int lwm2m_init_message(struct lwm2m_message *msg);
int lwm2m_send_message_async(struct lwm2m_message *msg); int lwm2m_send_message_async(struct lwm2m_message *msg);
/* Notification and Send operation */
int lwm2m_information_interface_send(struct lwm2m_message *msg);
int lwm2m_send_empty_ack(struct lwm2m_ctx *client_ctx, uint16_t mid); int lwm2m_send_empty_ack(struct lwm2m_ctx *client_ctx, uint16_t mid);
int lwm2m_register_payload_handler(struct lwm2m_message *msg); int lwm2m_register_payload_handler(struct lwm2m_message *msg);
@ -192,6 +194,11 @@ const char *lwm2m_engine_get_attr_name(const struct lwm2m_attr *attr);
int lwm2m_socket_add(struct lwm2m_ctx *ctx); int lwm2m_socket_add(struct lwm2m_ctx *ctx);
void lwm2m_socket_del(struct lwm2m_ctx *ctx); void lwm2m_socket_del(struct lwm2m_ctx *ctx);
int lwm2m_socket_start(struct lwm2m_ctx *client_ctx); int lwm2m_socket_start(struct lwm2m_ctx *client_ctx);
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_engine_close_socket_connection(struct lwm2m_ctx *client_ctx);
int lwm2m_engine_connection_resume(struct lwm2m_ctx *client_ctx);
int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx);
#endif
int lwm2m_parse_peerinfo(char *url, struct lwm2m_ctx *client_ctx, bool is_firmware_uri); int lwm2m_parse_peerinfo(char *url, struct lwm2m_ctx *client_ctx, bool is_firmware_uri);
#endif /* LWM2M_ENGINE_H */ #endif /* LWM2M_ENGINE_H */

View file

@ -146,11 +146,20 @@ static void set_sm_state(uint8_t sm_state)
if (client.engine_state == ENGINE_UPDATE_SENT && if (client.engine_state == ENGINE_UPDATE_SENT &&
(sm_state == ENGINE_REGISTRATION_DONE || (sm_state == ENGINE_REGISTRATION_DONE ||
sm_state == ENGINE_REGISTRATION_DONE_RX_OFF)) { sm_state == ENGINE_REGISTRATION_DONE_RX_OFF)) {
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
lwm2m_push_queued_buffers(client.ctx);
#endif
event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE; event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE;
} else if (sm_state == ENGINE_REGISTRATION_DONE) { } else if (sm_state == ENGINE_REGISTRATION_DONE) {
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
lwm2m_push_queued_buffers(client.ctx);
#endif
event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE; event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE;
} else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) { } else if (sm_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF; event = LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF;
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
lwm2m_engine_close_socket_connection(client.ctx);
#endif
} else if ((sm_state == ENGINE_INIT || } else if ((sm_state == ENGINE_INIT ||
sm_state == ENGINE_DEREGISTERED) && sm_state == ENGINE_DEREGISTERED) &&
(client.engine_state >= ENGINE_DO_REGISTRATION && (client.engine_state >= ENGINE_DO_REGISTRATION &&
@ -919,6 +928,15 @@ static int sm_registration_done(void)
update_objects = client.update_objects; update_objects = client.update_objects;
client.trigger_update = false; client.trigger_update = false;
client.update_objects = false; client.update_objects = false;
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
ret = lwm2m_engine_connection_resume(client.ctx);
if (ret) {
lwm2m_engine_context_close(client.ctx);
/* perform full registration */
set_sm_state(ENGINE_DO_REGISTRATION);
return ret;
}
#endif
ret = sm_send_registration(update_objects, ret = sm_send_registration(update_objects,
do_update_reply_cb, do_update_reply_cb,
@ -1154,6 +1172,35 @@ struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
return client.ctx; return client.ctx;
} }
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx)
{
if (client.ctx != client_ctx) {
return -EPERM;
}
if (client.engine_state == ENGINE_REGISTRATION_DONE_RX_OFF) {
#ifdef CONFIG_LWM2M_DTLS_SUPPORT
/*
* Switch state for triggering a proper registration message
* if CONFIG_LWM2M_TLS_SESSION_CACHING is false we force full
* registration after Fully DTLS handshake
*/
if (IS_ENABLED(CONFIG_LWM2M_TLS_SESSION_CACHING)) {
client.engine_state = ENGINE_REGISTRATION_DONE;
} else {
client.engine_state = ENGINE_DO_REGISTRATION;
}
#else
client.engine_state = ENGINE_REGISTRATION_DONE;
#endif
client.trigger_update = true;
}
return 0;
}
#endif
static int lwm2m_rd_client_init(const struct device *dev) static int lwm2m_rd_client_init(const struct device *dev)
{ {
k_mutex_init(&client.mutex); k_mutex_init(&client.mutex);

View file

@ -43,7 +43,9 @@ int engine_trigger_bootstrap(void);
#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
void engine_bootstrap_finish(void); void engine_bootstrap_finish(void);
#endif #endif
#if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED)
int lwm2m_rd_client_connection_resume(struct lwm2m_ctx *client_ctx);
#endif
void engine_update_tx_time(void); void engine_update_tx_time(void);
#endif /* LWM2M_RD_CLIENT_H */ #endif /* LWM2M_RD_CLIENT_H */