From 462582035437ce9bd13a60defa38c8d7fbd0d01c Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Wed, 28 Oct 2020 16:15:27 +0100 Subject: [PATCH] net: lwm2m: Send Registration Update on lifetime change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to LwM2M specfication v1.0.2, par. 5.3.2, the LwM2M client MUST send an “Update” operation to the LwM2M Server whenever the lifetime parameter of the Server object changes the server). The same applies for the object instances created/deleted. The changes in objects seem to already be handled, but the lifetime was not. Additionally, the "Update" message shall only contain these parameters which changed since the last update (including objects). As it's straightforward to determine if the liftime changed but it's not easy to tell if there were updates in the object instances, add an additional parameter to the engine_trigger_update() function, indicating that new object information shall be sent in the "Update" message. Eventually add a proper error checking in `sm_send_registration` as the function is reworked anyway. Signed-off-by: Robert Lubos --- subsys/net/lib/lwm2m/lwm2m_engine.c | 4 +- subsys/net/lib/lwm2m/lwm2m_obj_server.c | 29 ++++- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 144 +++++++++++++++--------- subsys/net/lib/lwm2m/lwm2m_rd_client.h | 2 +- subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c | 2 +- 5 files changed, 120 insertions(+), 61 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index d166bce7f61..d9a1b3e17fa 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -2838,7 +2838,7 @@ static int lwm2m_delete_handler(struct lwm2m_message *msg) ret = lwm2m_delete_obj_inst(msg->path.obj_id, msg->path.obj_inst_id); #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT) if (!ret && !msg->ctx->bootstrap_mode) { - engine_trigger_update(); + engine_trigger_update(true); } #endif @@ -3239,7 +3239,7 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg, #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT) if (!msg->ctx->bootstrap_mode) { - engine_trigger_update(); + engine_trigger_update(true); } #endif } diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index 7059412454b..1b56ece7fa7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -100,7 +100,28 @@ static int disable_cb(uint16_t obj_inst_id) static int update_trigger_cb(uint16_t obj_inst_id) { #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT - engine_trigger_update(); + engine_trigger_update(false); + return 0; +#else + return -EPERM; +#endif +} + +static int lifetime_write_cb(uint16_t obj_inst_id, uint16_t res_id, + uint16_t res_inst_id, uint8_t *data, + uint16_t data_len, bool last_block, + size_t total_size) +{ + ARG_UNUSED(obj_inst_id); + ARG_UNUSED(res_id); + ARG_UNUSED(res_inst_id); + ARG_UNUSED(data); + ARG_UNUSED(data_len); + ARG_UNUSED(last_block); + ARG_UNUSED(total_size); + +#ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT + engine_trigger_update(false); return 0; #else return -EPERM; @@ -189,9 +210,9 @@ static struct lwm2m_engine_obj_inst *server_create(uint16_t obj_inst_id) INIT_OBJ_RES_DATA(SERVER_SHORT_SERVER_ID, res[index], i, res_inst[index], j, &server_id[index], sizeof(*server_id)); - INIT_OBJ_RES_DATA(SERVER_LIFETIME_ID, res[index], i, - res_inst[index], j, - &lifetime[index], sizeof(*lifetime)); + INIT_OBJ_RES(SERVER_LIFETIME_ID, res[index], i, res_inst[index], j, + 1U, true, &lifetime[index], sizeof(*lifetime), + NULL, NULL, lifetime_write_cb, NULL); INIT_OBJ_RES_DATA(SERVER_DEFAULT_MIN_PERIOD_ID, res[index], i, res_inst[index], j, &default_min_period[index], diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index e59de93909c..69a62255b22 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -99,8 +99,6 @@ struct lwm2m_rd_client_info { uint32_t lifetime; struct lwm2m_ctx *ctx; uint8_t engine_state; - uint8_t use_bootstrap; - uint8_t trigger_update; int64_t last_update; int64_t last_tx; @@ -109,6 +107,10 @@ struct lwm2m_rd_client_info { char server_ep[CLIENT_EP_LEN]; lwm2m_ctx_event_cb_t event_cb; + + bool use_bootstrap : 1; + bool trigger_update : 1; + bool update_objects : 1; } client; /* buffers */ @@ -209,10 +211,14 @@ void engine_trigger_restart(void) } /* force re-update with remote peer */ -void engine_trigger_update(void) +void engine_trigger_update(bool update_objects) { /* TODO: add locking? */ - client.trigger_update = 1U; + client.trigger_update = true; + + if (update_objects) { + client.update_objects = true; + } } /* state machine reply callbacks */ @@ -424,15 +430,23 @@ static bool sm_bootstrap_verify(bool bootstrap_server, int sec_obj_inst) } } -static void sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) +static bool sm_update_lifetime(int srv_obj_inst, uint32_t *lifetime) { char pathstr[MAX_RESOURCE_LEN]; + uint32_t new_lifetime; snprintk(pathstr, sizeof(pathstr), "1/%d/1", srv_obj_inst); - if (lwm2m_engine_get_u32(pathstr, lifetime) < 0) { - *lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; - LOG_INF("Using default lifetime: %u", *lifetime); + if (lwm2m_engine_get_u32(pathstr, &new_lifetime) < 0) { + new_lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + LOG_INF("Using default lifetime: %u", new_lifetime); } + + if (new_lifetime != *lifetime) { + *lifetime = new_lifetime; + return true; + } + + return false; } static int sm_select_server_inst(int sec_obj_inst, int *srv_obj_inst, @@ -457,7 +471,6 @@ static int sm_select_server_inst(int sec_obj_inst, int *srv_obj_inst, } *srv_obj_inst = obj_inst_id; - sm_update_lifetime(*srv_obj_inst, lifetime); return 0; } @@ -499,7 +512,7 @@ static int sm_do_init(void) { client.ctx->sec_obj_inst = -1; client.ctx->srv_obj_inst = -1; - client.trigger_update = 0U; + client.trigger_update = false; client.lifetime = 0U; /* Do bootstrap or registration */ @@ -645,47 +658,76 @@ static int sm_send_registration(bool send_obj_support_data, goto cleanup; } - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - LWM2M_RD_CLIENT_URI, - strlen(LWM2M_RD_CLIENT_URI)); - - if (!sm_is_registered()) { - /* include client endpoint in URI QUERY on 1st registration */ - coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT, - LWM2M_FORMAT_APP_LINK_FORMAT); - snprintk(query_buffer, sizeof(query_buffer) - 1, - "lwm2m=%s", LWM2M_PROTOCOL_VERSION); - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); - snprintk(query_buffer, sizeof(query_buffer) - 1, - "ep=%s", client.ep_name); - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); - } else { - /* include server endpoint in URI PATH otherwise */ - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - client.server_ep, - strlen(client.server_ep)); + ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + LWM2M_RD_CLIENT_URI, + strlen(LWM2M_RD_CLIENT_URI)); + if (ret < 0) { + goto cleanup; } - snprintk(query_buffer, sizeof(query_buffer) - 1, - "lt=%d", client.lifetime); - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + if (sm_is_registered()) { + ret = coap_packet_append_option( + &msg->cpkt, COAP_OPTION_URI_PATH, + client.server_ep, strlen(client.server_ep)); + if (ret < 0) { + goto cleanup; + } + } + + if (send_obj_support_data) { + ret = coap_append_option_int( + &msg->cpkt, COAP_OPTION_CONTENT_FORMAT, + LWM2M_FORMAT_APP_LINK_FORMAT); + if (ret < 0) { + goto cleanup; + } + } + + if (!sm_is_registered()) { + snprintk(query_buffer, sizeof(query_buffer) - 1, + "lwm2m=%s", LWM2M_PROTOCOL_VERSION); + ret = coap_packet_append_option( + &msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + if (ret < 0) { + goto cleanup; + } + + snprintk(query_buffer, sizeof(query_buffer) - 1, + "ep=%s", client.ep_name); + ret = coap_packet_append_option( + &msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + if (ret < 0) { + goto cleanup; + } + } + + /* Send lifetime only if changed or on initial registration.*/ + if (sm_update_lifetime(client.ctx->srv_obj_inst, &client.lifetime) || + !sm_is_registered()) { + snprintk(query_buffer, sizeof(query_buffer) - 1, + "lt=%d", client.lifetime); + ret = coap_packet_append_option( + &msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + if (ret < 0) { + goto cleanup; + } + } lwm2m_engine_get_binding(binding); /* UDP is a default binding, no need to add option if UDP is used. */ - if (strcmp(binding, "U") != 0) { + if ((!sm_is_registered() && strcmp(binding, "U") != 0)) { snprintk(query_buffer, sizeof(query_buffer) - 1, "b=%s", binding); - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, - query_buffer, strlen(query_buffer)); + + ret = coap_packet_append_option( + &msg->cpkt, COAP_OPTION_URI_QUERY, + query_buffer, strlen(query_buffer)); + if (ret < 0) { + goto cleanup; + } } if (send_obj_support_data) { @@ -774,7 +816,7 @@ static int sm_do_registration(void) static int sm_registration_done(void) { int ret = 0; - bool forced_update; + bool update_objects; /* * check for lifetime seconds - SECONDS_TO_UPDATE_EARLY @@ -784,15 +826,11 @@ static int sm_registration_done(void) (client.trigger_update || ((client.lifetime - SECONDS_TO_UPDATE_EARLY) <= (k_uptime_get() - client.last_update) / 1000))) { - forced_update = client.trigger_update; - client.trigger_update = 0U; + update_objects = client.update_objects; + client.trigger_update = false; + client.update_objects = false; - /** The LwM2M server might've changed the lifetime, - * update it just in case. - */ - sm_update_lifetime(client.ctx->srv_obj_inst, &client.lifetime); - - ret = sm_send_registration(forced_update, + ret = sm_send_registration(update_objects, do_update_reply_cb, do_update_timeout_cb); if (!ret) { diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.h b/subsys/net/lib/lwm2m/lwm2m_rd_client.h index 78cbb7287ab..d5403b52d11 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.h +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.h @@ -39,7 +39,7 @@ #define LWM2M_RD_CLIENT_H void engine_trigger_restart(void); -void engine_trigger_update(void); +void engine_trigger_update(bool update_objects); #if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) void engine_bootstrap_finish(void); #endif diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index 3eef9e0a806..69a8b1b9c0f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -982,7 +982,7 @@ int do_write_op_tlv(struct lwm2m_message *msg) #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT if (!msg->ctx->bootstrap_mode) { - engine_trigger_update(); + engine_trigger_update(true); } #endif }