net: lwm2m: Notify the application on network error

Add a simple backoff mechanism between consecutive registration attempts
in case of registration failures. Finally, notify the application in
case the registration failed several times.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
This commit is contained in:
Robert Lubos 2020-09-08 11:54:31 +02:00 committed by Carles Cufí
commit 7127f0a742
4 changed files with 52 additions and 4 deletions

View file

@ -848,6 +848,7 @@ enum lwm2m_rd_client_event {
LWM2M_RD_CLIENT_EVENT_DEREGISTER_FAILURE,
LWM2M_RD_CLIENT_EVENT_DISCONNECT,
LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF,
LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR,
};
/*

View file

@ -418,6 +418,11 @@ static void rd_client_event(struct lwm2m_ctx *client,
case LWM2M_RD_CLIENT_EVENT_QUEUE_MODE_RX_OFF:
LOG_DBG("Queue mode RX window closed");
break;
case LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR:
LOG_ERR("LwM2M engine reported a network erorr.");
lwm2m_rd_client_stop(client, rd_client_event);
break;
}
}

View file

@ -127,6 +127,16 @@ config LWM2M_RD_CLIENT_ENDPOINT_NAME_MAX_LENGTH
help
Default: room for 32 hexadeciaml digits (UUID) + NULL
config LWM2M_RD_CLIENT_MAX_RETRIES
int "Specify maximum number of registration retries"
default 5
help
Specify maximum number of registration retries, before the application
is notified about the network failure. Once application is notified,
it's up to the application to handle this situation in a way
appropriate for the specific use-case (for instance by waiting for
LTE link to be re-established).
config LWM2M_PEER_PORT
int "LWM2M server port"
depends on LWM2M_RD_CLIENT_SUPPORT

View file

@ -92,13 +92,16 @@ enum sm_engine_state {
ENGINE_DEREGISTER,
ENGINE_DEREGISTER_SENT,
ENGINE_DEREGISTER_FAILED,
ENGINE_DEREGISTERED
ENGINE_DEREGISTERED,
ENGINE_NETWORK_ERROR,
};
struct lwm2m_rd_client_info {
uint32_t lifetime;
struct lwm2m_ctx *ctx;
uint8_t engine_state;
uint8_t retries;
uint8_t retry_delay;
int64_t last_update;
int64_t last_tx;
@ -147,6 +150,13 @@ static void set_sm_state(uint8_t sm_state)
(client.engine_state >= ENGINE_DO_REGISTRATION &&
client.engine_state <= ENGINE_DEREGISTER_SENT)) {
event = LWM2M_RD_CLIENT_EVENT_DISCONNECT;
} else if (sm_state == ENGINE_NETWORK_ERROR) {
client.retry_delay = 1 << client.retries;
client.retries++;
if (client.retries > CONFIG_LWM2M_RD_CLIENT_MAX_RETRIES) {
client.retries = 0;
event = LWM2M_RD_CLIENT_EVENT_NETWORK_ERROR;
}
}
/* TODO: add locking? */
@ -516,6 +526,7 @@ static int sm_do_init(void)
client.ctx->srv_obj_inst = -1;
client.trigger_update = false;
client.lifetime = 0U;
client.retries = 0U;
/* Do bootstrap or registration */
#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
@ -584,7 +595,6 @@ cleanup:
static int sm_do_bootstrap_reg(void)
{
struct lwm2m_message *msg;
int ret;
/* clear out existing connection data */
@ -608,6 +618,7 @@ static int sm_do_bootstrap_reg(void)
ret = lwm2m_engine_start(client.ctx);
if (ret < 0) {
LOG_ERR("Cannot init LWM2M engine (%d)", ret);
set_sm_state(ENGINE_NETWORK_ERROR);
return ret;
}
@ -617,7 +628,7 @@ static int sm_do_bootstrap_reg(void)
} else {
LOG_ERR("Bootstrap registration err: %d", ret);
lwm2m_engine_context_close(client.ctx);
/* exit and try again */
set_sm_state(ENGINE_NETWORK_ERROR);
}
return ret;
@ -811,6 +822,7 @@ static int sm_do_registration(void)
ret = lwm2m_engine_start(client.ctx);
if (ret < 0) {
LOG_ERR("Cannot init LWM2M engine (%d)", ret);
set_sm_state(ENGINE_NETWORK_ERROR);
return ret;
}
@ -822,7 +834,7 @@ static int sm_do_registration(void)
} else {
LOG_ERR("Registration err: %d", ret);
lwm2m_engine_context_close(client.ctx);
/* exit and try again */
set_sm_state(ENGINE_NETWORK_ERROR);
}
return ret;
@ -917,6 +929,22 @@ cleanup:
return ret;
}
static void sm_do_network_error(void)
{
if (--client.retry_delay > 0) {
return;
}
#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)
if (client.ctx->bootstrap_mode) {
set_sm_state(ENGINE_DO_BOOTSTRAP_REG);
return;
}
#endif
set_sm_state(ENGINE_DO_REGISTRATION);
}
static void lwm2m_rd_client_service(struct k_work *work)
{
if (client.ctx) {
@ -979,6 +1007,10 @@ static void lwm2m_rd_client_service(struct k_work *work)
set_sm_state(ENGINE_IDLE);
break;
case ENGINE_NETWORK_ERROR:
sm_do_network_error();
break;
default:
LOG_ERR("Unhandled state: %d", get_sm_state());