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

@ -192,6 +192,11 @@ config LWM2M_QUEUE_MODE_UPTIME
defaults to 93 seconds, see RFC 7252), it does not forbid other
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
bool "support for LWM2M client bootstrap/registration state machine"
default y

View file

@ -1338,6 +1338,9 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release)
if (msg->ctx) {
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) {
@ -1421,15 +1424,85 @@ cleanup:
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)
{
#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);
if (IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT) &&
IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) {
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;
}
@ -5250,7 +5323,7 @@ static int generate_notify_message(struct lwm2m_ctx *ctx,
goto cleanup;
}
lwm2m_send_message_async(msg);
lwm2m_information_interface_send(msg);
LOG_DBG("NOTIFY MSG: SENT");
return 0;
@ -5344,6 +5417,44 @@ static int32_t lwm2m_engine_service(const int64_t 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 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);
coap_replies_clear(client_ctx->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);
client_ctx->sock_fd = -1;
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->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 */
@ -5633,6 +5752,7 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
socklen_t addr_len;
int flags;
int ret;
bool allocate_socket = false;
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
uint8_t tmp;
@ -5653,15 +5773,20 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
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 */
{
client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family,
SOCK_DGRAM, IPPROTO_UDP);
if (client_ctx->sock_fd < 0) {
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) {
@ -5683,6 +5808,18 @@ int lwm2m_socket_start(struct lwm2m_ctx *client_ctx)
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)) {
/** store character at len position */
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);
return lwm2m_socket_add(client_ctx);
if (allocate_socket) {
return lwm2m_socket_add(client_ctx);
}
return 0;
error:
lwm2m_engine_context_close(client_ctx);
return ret;
@ -6334,7 +6472,7 @@ int lwm2m_engine_send(struct lwm2m_ctx *ctx, char const *path_list[], uint8_t pa
goto cleanup;
}
LOG_INF("Send op to server (/dp)");
lwm2m_send_message_async(msg);
lwm2m_information_interface_send(msg);
return 0;
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);
int lwm2m_init_message(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_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);
void lwm2m_socket_del(struct lwm2m_ctx *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);
#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 &&
(sm_state == ENGINE_REGISTRATION_DONE ||
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;
} 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;
} else if (sm_state == ENGINE_REGISTRATION_DONE_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 ||
sm_state == ENGINE_DEREGISTERED) &&
(client.engine_state >= ENGINE_DO_REGISTRATION &&
@ -919,6 +928,15 @@ static int sm_registration_done(void)
update_objects = client.update_objects;
client.trigger_update = 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,
do_update_reply_cb,
@ -1154,6 +1172,35 @@ struct lwm2m_ctx *lwm2m_rd_client_ctx(void)
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)
{
k_mutex_init(&client.mutex);

View file

@ -43,7 +43,9 @@ int engine_trigger_bootstrap(void);
#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
void engine_bootstrap_finish(void);
#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);
#endif /* LWM2M_RD_CLIENT_H */