From ccc745a57cf0253d9a10ea6c9f07815838f10a78 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 15 May 2018 10:58:46 -0700 Subject: [PATCH 01/18] net: lwm2m: make lwm2m_engine_exec_cb_t more generic Let's rename lwm2m_engine_exec_cb_t to lwm2m_engine_user_cb_t so that future user-code callbacks can make use of the same definition. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 8 ++++---- subsys/net/lib/lwm2m/lwm2m_engine.c | 2 +- subsys/net/lib/lwm2m/lwm2m_obj_firmware.c | 8 ++++---- subsys/net/lib/lwm2m/lwm2m_object.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 047cca1a8525b..19cb5ff479778 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -81,7 +81,7 @@ typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id, typedef int (*lwm2m_engine_set_data_cb_t)(u16_t obj_inst_id, u8_t *data, u16_t data_len, bool last_block, size_t total_size); -typedef int (*lwm2m_engine_exec_cb_t)(u16_t obj_inst_id); +typedef int (*lwm2m_engine_user_cb_t)(u16_t obj_inst_id); /* LWM2M Device Object */ @@ -144,8 +144,8 @@ void lwm2m_firmware_set_write_cb(lwm2m_engine_set_data_cb_t cb); lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void); #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT) -void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb); -lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void); +void lwm2m_firmware_set_update_cb(lwm2m_engine_user_cb_t cb); +lwm2m_engine_user_cb_t lwm2m_firmware_get_update_cb(void); #endif #endif @@ -205,7 +205,7 @@ int lwm2m_engine_register_pre_write_callback(char *path, int lwm2m_engine_register_post_write_callback(char *path, lwm2m_engine_set_data_cb_t cb); int lwm2m_engine_register_exec_callback(char *path, - lwm2m_engine_exec_cb_t cb); + lwm2m_engine_user_cb_t cb); /* resource data bit values */ #define LWM2M_RES_DATA_READ_ONLY 0 diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index bfdf9544f9c62..3aea90031e701 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -1883,7 +1883,7 @@ int lwm2m_engine_register_post_write_callback(char *pathstr, } int lwm2m_engine_register_exec_callback(char *pathstr, - lwm2m_engine_exec_cb_t cb) + lwm2m_engine_user_cb_t cb) { int ret; struct lwm2m_engine_res_inst *res = NULL; diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index 6e288725bfa0a..0f5338a5b53d7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -57,7 +57,7 @@ static struct lwm2m_engine_obj_inst inst; static struct lwm2m_engine_res_inst res[FIRMWARE_MAX_ID]; static lwm2m_engine_set_data_cb_t write_cb; -static lwm2m_engine_exec_cb_t update_cb; +static lwm2m_engine_user_cb_t update_cb; #ifdef CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_SUPPORT extern int lwm2m_firmware_start_transfer(char *package_uri); @@ -256,19 +256,19 @@ lwm2m_engine_set_data_cb_t lwm2m_firmware_get_write_cb(void) return write_cb; } -void lwm2m_firmware_set_update_cb(lwm2m_engine_exec_cb_t cb) +void lwm2m_firmware_set_update_cb(lwm2m_engine_user_cb_t cb) { update_cb = cb; } -lwm2m_engine_exec_cb_t lwm2m_firmware_get_update_cb(void) +lwm2m_engine_user_cb_t lwm2m_firmware_get_update_cb(void) { return update_cb; } static int firmware_update_cb(u16_t obj_inst_id) { - lwm2m_engine_exec_cb_t callback; + lwm2m_engine_user_cb_t callback; u8_t state; int ret; diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 22798d76c79e5..af2976cbb8fcc 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -230,7 +230,7 @@ struct lwm2m_engine_res_inst { lwm2m_engine_get_data_cb_t read_cb; lwm2m_engine_get_data_cb_t pre_write_cb; lwm2m_engine_set_data_cb_t post_write_cb; - lwm2m_engine_exec_cb_t execute_cb; + lwm2m_engine_user_cb_t execute_cb; u8_t *multi_count_var; void *data_ptr; From ccb7909f48e875fbace61acbaaa1eccdb58da081 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 15 May 2018 11:04:11 -0700 Subject: [PATCH 02/18] net: lwm2m: introduce user-code callbacks for obj create/delete LwM2M engine now supports optional resources that may need to be setup or torn down in user-based code during object instance creation / deletion. Let's provide callbacks that can be used for this purpose. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 4 +++ subsys/net/lib/lwm2m/lwm2m_engine.c | 51 +++++++++++++++++++++++++++++ subsys/net/lib/lwm2m/lwm2m_object.h | 2 ++ 3 files changed, 57 insertions(+) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 19cb5ff479778..a9f42b97ae3ca 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -206,6 +206,10 @@ int lwm2m_engine_register_post_write_callback(char *path, lwm2m_engine_set_data_cb_t cb); int lwm2m_engine_register_exec_callback(char *path, lwm2m_engine_user_cb_t cb); +int lwm2m_engine_register_create_callback(u16_t obj_id, + lwm2m_engine_user_cb_t cb); +int lwm2m_engine_register_delete_callback(u16_t obj_id, + lwm2m_engine_user_cb_t cb); /* resource data bit values */ #define LWM2M_RES_DATA_READ_ONLY 0 diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 3aea90031e701..a1f34696f346b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -685,6 +685,7 @@ int lwm2m_create_obj_inst(u16_t obj_id, u16_t obj_inst_id, struct lwm2m_engine_obj_inst **obj_inst) { struct lwm2m_engine_obj *obj; + int ret; *obj_inst = NULL; obj = get_engine_obj(obj_id); @@ -718,6 +719,17 @@ int lwm2m_create_obj_inst(u16_t obj_id, u16_t obj_inst_id, (*obj_inst)->obj = obj; (*obj_inst)->obj_inst_id = obj_inst_id; engine_register_obj_inst(*obj_inst); + + if (obj->user_create_cb) { + ret = obj->user_create_cb(obj_inst_id); + if (ret < 0) { + SYS_LOG_ERR("Error in user obj create %u/%u: %d", + obj_id, obj_inst_id, ret); + lwm2m_delete_obj_inst(obj_id, obj_inst_id); + return ret; + } + } + #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT engine_trigger_update(); #endif @@ -740,6 +752,15 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id) return -ENOENT; } + if (obj->user_delete_cb) { + ret = obj->user_delete_cb(obj_inst_id); + if (ret < 0) { + SYS_LOG_ERR("Error in user obj delete %u/%u: %d", + obj_id, obj_inst_id, ret); + /* don't return error */ + } + } + engine_unregister_obj_inst(obj_inst); obj->instance_count--; @@ -1897,6 +1918,36 @@ int lwm2m_engine_register_exec_callback(char *pathstr, return 0; } +int lwm2m_engine_register_create_callback(u16_t obj_id, + lwm2m_engine_user_cb_t cb) +{ + struct lwm2m_engine_obj *obj = NULL; + + obj = get_engine_obj(obj_id); + if (!obj) { + SYS_LOG_ERR("unable to find obj: %u", obj_id); + return -ENOENT; + } + + obj->user_create_cb = cb; + return 0; +} + +int lwm2m_engine_register_delete_callback(u16_t obj_id, + lwm2m_engine_user_cb_t cb) +{ + struct lwm2m_engine_obj *obj = NULL; + + obj = get_engine_obj(obj_id); + if (!obj) { + SYS_LOG_ERR("unable to find obj: %u", obj_id); + return -ENOENT; + } + + obj->user_delete_cb = cb; + return 0; +} + /* generic data handlers */ static int lwm2m_read_handler(struct lwm2m_engine_obj_inst *obj_inst, diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index af2976cbb8fcc..27c9782295f14 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -169,6 +169,8 @@ struct lwm2m_engine_obj { /* object event callbacks */ lwm2m_engine_obj_create_cb_t create_cb; lwm2m_engine_obj_delete_cb_t delete_cb; + lwm2m_engine_user_cb_t user_create_cb; + lwm2m_engine_user_cb_t user_delete_cb; /* object member data */ u16_t obj_id; From 9458fba18ae772c2095651c66669fa205447294b Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Tue, 15 May 2018 11:48:03 -0700 Subject: [PATCH 03/18] net: lwm2m: use ARRAY_SIZE to calculate # of options Don't use hard-coded value of 4 for passing the # of options to coap_find_options() in handle_request(). This can easily get out of sync. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index a1f34696f346b..13b7f26f1fafe 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -3124,7 +3124,8 @@ static int handle_request(struct coap_packet *request, } /* parse the URL path into components */ - r = coap_find_options(in.in_cpkt, COAP_OPTION_URI_PATH, options, 4); + r = coap_find_options(in.in_cpkt, COAP_OPTION_URI_PATH, options, + ARRAY_SIZE(options)); if (r <= 0) { /* '/' is used by bootstrap-delete only */ From 0a835027995c8e66827bde07369accd18319644e Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 14:51:46 -0700 Subject: [PATCH 04/18] net: lwm2m: read past not supported TLV resources During transfer of object data via OMA TLV format, we can encounter resources which are optional or not handled in base LwM2M engine. When these resources cannot be handled let's read past them and continue on. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c | 54 ++++++++++++++++++++----- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index 2d2953b31b26d..e70256295c5a1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -717,6 +717,21 @@ const struct lwm2m_reader oma_tlv_reader = { get_opaque }; +static int do_write_op_tlv_dummy_read(struct lwm2m_engine_context *context) +{ + struct lwm2m_input_context *in = context->in; + struct oma_tlv tlv; + u8_t read_char; + + oma_tlv_get(&tlv, in, false); + while (in->frag && tlv.length--) { + in->frag = net_frag_read_u8(in->frag, in->offset, &in->offset, + &read_char); + } + + return 0; +} + static int do_write_op_tlv_item(struct lwm2m_engine_context *context) { struct lwm2m_engine_obj_inst *obj_inst = NULL; @@ -727,26 +742,24 @@ static int do_write_op_tlv_item(struct lwm2m_engine_context *context) ret = lwm2m_get_or_create_engine_obj(context, &obj_inst, &created); if (ret < 0) { - return ret; + goto error; } obj_field = lwm2m_get_engine_obj_field(obj_inst->obj, context->path->res_id); - /* if obj_field is not found, treat as an optional resource */ if (!obj_field) { - if (context->operation == LWM2M_OP_CREATE) { - return -ENOTSUP; - } - - return -ENOENT; + ret = -ENOENT; + goto error; } if (!LWM2M_HAS_PERM(obj_field, LWM2M_PERM_W)) { - return -EPERM; + ret = -EPERM; + goto error; } if (!obj_inst->resources || obj_inst->resource_count == 0) { - return -EINVAL; + ret = -EINVAL; + goto error; } for (i = 0; i < obj_inst->resource_count; i++) { @@ -757,10 +770,29 @@ static int do_write_op_tlv_item(struct lwm2m_engine_context *context) } if (!res) { - return -ENOENT; + /* if OPTIONAL and OP_CREATE use ENOTSUP */ + if (context->operation == LWM2M_OP_CREATE && + LWM2M_HAS_PERM(obj_field, BIT(LWM2M_FLAG_OPTIONAL))) { + ret = -ENOTSUP; + goto error; + } + + ret = -ENOENT; + goto error; + } + + ret = lwm2m_write_handler(obj_inst, res, obj_field, context); + if (ret == -EACCES || ret == -ENOENT) { + /* if read-only or non-existent data buffer move on */ + do_write_op_tlv_dummy_read(context); + ret = 0; } - return lwm2m_write_handler(obj_inst, res, obj_field, context); + return ret; + +error: + do_write_op_tlv_dummy_read(context); + return ret; } int do_write_op_tlv(struct lwm2m_engine_obj *obj, From 82c5d82a09bcee33351a8f1ecc5aed7f490d4c63 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:03:38 -0700 Subject: [PATCH 05/18] net: lwm2m: add lwm2m_engine_context_close() to engine This function will cleanup the engine context, even if it's in various different states. In general, the LwM2M subsys should always call this function to perform the context close. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 32 +++++++++++++++++++++++++++-- subsys/net/lib/lwm2m/lwm2m_engine.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 13b7f26f1fafe..fdb27fac43cdd 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -3880,6 +3880,35 @@ int lwm2m_engine_set_net_pkt_pool(struct lwm2m_ctx *ctx, } #endif /* CONFIG_NET_CONTEXT_NET_PKT_POOL */ +/* HACK: Fix this */ +void _net_app_tls_handler_stop(struct net_app_ctx *ctx); + +int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx) +{ + int ret = 0; + + k_delayed_work_cancel(&client_ctx->retransmit_work); + + ret = net_app_close(&client_ctx->net_app_ctx); + if (ret < 0) { + return ret; + } + +#if defined(CONFIG_NET_APP_DTLS) + if (client_ctx->net_app_ctx.dtls.ctx) { + SYS_LOG_DBG("Releasing DTLS context %p", + client_ctx->net_app_ctx.dtls.ctx); + + _net_app_tls_handler_stop(&client_ctx->net_app_ctx); + } + + client_ctx->net_app_ctx.tls.handshake_done = false; +#endif /* CONFIG_NET_APP_DTLS */ + + ret = net_app_release(&client_ctx->net_app_ctx); + return ret; +} + void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) { k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request); @@ -3976,8 +4005,7 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, return 0; error_start: - net_app_close(&client_ctx->net_app_ctx); - net_app_release(&client_ctx->net_app_ctx); + lwm2m_engine_context_close(client_ctx); return ret; } diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 135b9eabb3dd0..a37c7fb0e56ab 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -95,6 +95,7 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_engine_context *context, u8_t *created); /* LwM2M context functions */ +int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx); void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx); /* LwM2M message functions */ From 5be0b47690d1a5da59855df31b3a51712e6f4623 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:17:09 -0700 Subject: [PATCH 06/18] net: lwm2m: security obj: add client_identity buffer Add client_identity buffer to security object for use with bootstrap operation. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_obj_security.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index c98569e1d64c6..2fb94d1189f0c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -33,9 +33,11 @@ #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SECURITY_INSTANCE_COUNT #define SECURITY_URI_LEN 255 +#define IDENTITY_LEN 128 /* resource state variables */ static char security_uri[MAX_INSTANCE_COUNT][SECURITY_URI_LEN]; +static u8_t client_identity[MAX_INSTANCE_COUNT][IDENTITY_LEN]; static bool bootstrap_flag[MAX_INSTANCE_COUNT]; static u8_t security_mode[MAX_INSTANCE_COUNT]; static u16_t short_server_id[MAX_INSTANCE_COUNT]; @@ -45,7 +47,7 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(SECURITY_SERVER_URI_ID, RW, STRING), OBJ_FIELD_DATA(SECURITY_BOOTSTRAP_FLAG_ID, W, BOOL), OBJ_FIELD_DATA(SECURITY_MODE_ID, W, U8), - OBJ_FIELD_DATA(SECURITY_CLIENT_PK_ID, W, OPAQUE), /* TODO */ + OBJ_FIELD_DATA(SECURITY_CLIENT_PK_ID, W, OPAQUE), OBJ_FIELD_DATA(SECURITY_SERVER_PK_ID, W, OPAQUE), /* TODO */ OBJ_FIELD_DATA(SECURITY_SECRET_KEY_ID, W, OPAQUE), /* TODO */ OBJ_FIELD_DATA(SECURITY_SMS_MODE_ID, W_OPT, U8), @@ -87,6 +89,7 @@ static struct lwm2m_engine_obj_inst *security_create(u16_t obj_inst_id) /* default values */ security_uri[index][0] = '\0'; + client_identity[index][0] = '\0'; bootstrap_flag[index] = 0; security_mode[index] = 0; short_server_id[index] = 0; @@ -99,7 +102,8 @@ static struct lwm2m_engine_obj_inst *security_create(u16_t obj_inst_id) INIT_OBJ_RES_DATA(res[index], i, SECURITY_MODE_ID, &security_mode[index], sizeof(*security_mode)); /* TODO: */ - INIT_OBJ_RES_DUMMY(res[index], i, SECURITY_CLIENT_PK_ID); + INIT_OBJ_RES_DATA(res[index], i, SECURITY_CLIENT_PK_ID, + &client_identity[index], IDENTITY_LEN), INIT_OBJ_RES_DUMMY(res[index], i, SECURITY_SERVER_PK_ID), INIT_OBJ_RES_DUMMY(res[index], i, SECURITY_SECRET_KEY_ID), INIT_OBJ_RES_DATA(res[index], i, SECURITY_SHORT_SERVER_ID, From 1a96fd7d0c828f72b181b838af87faaeacafe0a1 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:25:07 -0700 Subject: [PATCH 07/18] net: lwm2m: security obj: add server key storage Add server public and private key storage buffers to LwM2M security object. These will be used for bootstrap and future changes moving the security information out of RD client. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/Kconfig | 8 ++++++++ subsys/net/lib/lwm2m/lwm2m_obj_security.c | 16 +++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1e1d1722d41b4..484c5533b4c87 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -80,6 +80,14 @@ config LWM2M_SECURITY_INSTANCE_COUNT This setting establishes the total count of LWM2M Security instances available to the client. +config LWM2M_SECURITY_KEY_SIZE + int "Buffer size of the security key resources" + default 16 + range 16 256 + help + This setting establishes the size of the key (pre-shared / public) + resources in the security object instances. + config LWM2M_SERVER_INSTANCE_COUNT int "Maximum # of LWM2M Server object instances" default 1 diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 2fb94d1189f0c..491af066a0f25 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -34,10 +34,13 @@ #define SECURITY_URI_LEN 255 #define IDENTITY_LEN 128 +#define KEY_LEN CONFIG_LWM2M_SECURITY_KEY_SIZE /* resource state variables */ static char security_uri[MAX_INSTANCE_COUNT][SECURITY_URI_LEN]; static u8_t client_identity[MAX_INSTANCE_COUNT][IDENTITY_LEN]; +static u8_t server_pk[MAX_INSTANCE_COUNT][KEY_LEN]; +static u8_t secret_key[MAX_INSTANCE_COUNT][KEY_LEN]; static bool bootstrap_flag[MAX_INSTANCE_COUNT]; static u8_t security_mode[MAX_INSTANCE_COUNT]; static u16_t short_server_id[MAX_INSTANCE_COUNT]; @@ -48,8 +51,8 @@ static struct lwm2m_engine_obj_field fields[] = { OBJ_FIELD_DATA(SECURITY_BOOTSTRAP_FLAG_ID, W, BOOL), OBJ_FIELD_DATA(SECURITY_MODE_ID, W, U8), OBJ_FIELD_DATA(SECURITY_CLIENT_PK_ID, W, OPAQUE), - OBJ_FIELD_DATA(SECURITY_SERVER_PK_ID, W, OPAQUE), /* TODO */ - OBJ_FIELD_DATA(SECURITY_SECRET_KEY_ID, W, OPAQUE), /* TODO */ + OBJ_FIELD_DATA(SECURITY_SERVER_PK_ID, W, OPAQUE), + OBJ_FIELD_DATA(SECURITY_SECRET_KEY_ID, W, OPAQUE), OBJ_FIELD_DATA(SECURITY_SMS_MODE_ID, W_OPT, U8), OBJ_FIELD_DATA(SECURITY_SMS_BINDING_KEY_PARAM_ID, W_OPT, OPAQUE), OBJ_FIELD_DATA(SECURITY_SMS_BINDING_SECRET_KEY_ID, W_OPT, OPAQUE), @@ -90,6 +93,8 @@ static struct lwm2m_engine_obj_inst *security_create(u16_t obj_inst_id) /* default values */ security_uri[index][0] = '\0'; client_identity[index][0] = '\0'; + server_pk[index][0] = '\0'; + secret_key[index][0] = '\0'; bootstrap_flag[index] = 0; security_mode[index] = 0; short_server_id[index] = 0; @@ -101,11 +106,12 @@ static struct lwm2m_engine_obj_inst *security_create(u16_t obj_inst_id) &bootstrap_flag[index], sizeof(*bootstrap_flag)); INIT_OBJ_RES_DATA(res[index], i, SECURITY_MODE_ID, &security_mode[index], sizeof(*security_mode)); - /* TODO: */ INIT_OBJ_RES_DATA(res[index], i, SECURITY_CLIENT_PK_ID, &client_identity[index], IDENTITY_LEN), - INIT_OBJ_RES_DUMMY(res[index], i, SECURITY_SERVER_PK_ID), - INIT_OBJ_RES_DUMMY(res[index], i, SECURITY_SECRET_KEY_ID), + INIT_OBJ_RES_DATA(res[index], i, SECURITY_SERVER_PK_ID, + &server_pk[index], KEY_LEN), + INIT_OBJ_RES_DATA(res[index], i, SECURITY_SECRET_KEY_ID, + &secret_key[index], KEY_LEN), INIT_OBJ_RES_DATA(res[index], i, SECURITY_SHORT_SERVER_ID, &short_server_id[index], sizeof(*short_server_id)); From d63f319287aae591b40f3c80d467739793db5468 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:44:42 -0700 Subject: [PATCH 08/18] net: lwm2m: add security index/instance lookup functions Add functions to the security obj for: - finding a specific object instance by index - finding a security index by object instance id These will be needed to use the security data for connecting to servers instead of passing in the data from the client. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.h | 4 ++++ subsys/net/lib/lwm2m/lwm2m_obj_security.c | 25 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index a37c7fb0e56ab..3ad8bcbd7c765 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -125,6 +125,10 @@ int lwm2m_engine_get_resource(char *pathstr, size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, u8_t *buf, size_t buflen, bool *last_block); +/* security index/instance lookup functions */ +int lwm2m_security_inst_id_to_index(u16_t obj_inst_id); +int lwm2m_security_index_to_inst_id(int index); + #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT) u8_t lwm2m_firmware_get_update_state(void); void lwm2m_firmware_set_update_state(u8_t state); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 491af066a0f25..5bc8c3d824c43 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -121,6 +121,31 @@ static struct lwm2m_engine_obj_inst *security_create(u16_t obj_inst_id) return &inst[index]; } +int lwm2m_security_inst_id_to_index(u16_t obj_inst_id) { + int i; + + for (i = 0; i < MAX_INSTANCE_COUNT; i++) { + if (inst[i].obj && inst[i].obj_inst_id == obj_inst_id) { + return i; + } + } + + return -ENOENT; +} + +int lwm2m_security_index_to_inst_id(int index) { + if (index >= MAX_INSTANCE_COUNT) { + return -EINVAL; + } + + /* not instanstiated */ + if (!inst[index].obj) { + return -ENOENT; + } + + return inst[index].obj_inst_id; +} + static int lwm2m_security_init(struct device *dev) { struct lwm2m_engine_obj_inst *obj_inst = NULL; From dc33becf2ba419970e4a6506f943a6e780b1f84a Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:52:08 -0700 Subject: [PATCH 09/18] net: lwm2m: add config LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP This config enables the bootstrap support logic in the RD client. It also adjusts the default # of server and security instances to reflect that the client will be connecting to a minimum of 2 servers. NOTE: Related code will be added to the RD client over the next few patches. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/Kconfig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 484c5533b4c87..d40e619d6e835 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -75,6 +75,7 @@ config LWM2M_LOCAL_PORT config LWM2M_SECURITY_INSTANCE_COUNT int "Maximum # of LWM2M Security object instances" default 1 + default 2 if LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP range 1 10 help This setting establishes the total count of LWM2M Security instances @@ -91,6 +92,7 @@ config LWM2M_SECURITY_KEY_SIZE config LWM2M_SERVER_INSTANCE_COUNT int "Maximum # of LWM2M Server object instances" default 1 + default 2 if LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP range 1 10 help This setting establishes the total count of LWM2M Server instances @@ -103,6 +105,12 @@ config LWM2M_RD_CLIENT_SUPPORT Client will use registration state machine to locate and connect to LWM2M servers (including bootstrap server support) +config LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP + bool "Enable bootstrap support" + default n + help + Enabling this setting allows the RD client to support bootstrap mode. + config LWM2M_PEER_PORT int "LWM2M server port" depends on LWM2M_RD_CLIENT_SUPPORT From f7611e8350b864c3014e104f00be018c1bdb895b Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 15:58:49 -0700 Subject: [PATCH 10/18] net: lwm2m: set MAX_RESOURCE_LEN to 16 and make it public MAX_RESOURCE_LEN can be used by sample applications when creating storage buffers resource locations, so let's make it public. Also, the previous value of 20 was incorrect, as resource instance id is not included. Instead correct the value to 16. Signed-off-by: Michael Scott --- include/net/lwm2m.h | 3 +++ subsys/net/lib/lwm2m/lwm2m_object.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index a9f42b97ae3ca..dd7627a7306c1 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -27,6 +27,9 @@ #define IPSO_OBJECT_TEMP_SENSOR_ID 3303 #define IPSO_OBJECT_LIGHT_CONTROL_ID 3311 +/* #####/###/##### + NULL */ +#define MAX_RESOURCE_LEN 16 + /** * @brief LwM2M context structure * diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 27c9782295f14..6f17a45a63eee 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -53,9 +53,6 @@ #include #include -/* #####/###/#####/### + NULL */ -#define MAX_RESOURCE_LEN 20 - /* operations / permissions */ /* values from 0 to 7 can be used as permission checks */ #define LWM2M_OP_READ 0 From 18228653ccc4d594e776a40df826b063876588bf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 16:58:18 -0700 Subject: [PATCH 11/18] net: lwm2m: server obj: update RW flags for bootstrap During bootstrap mode both SERVER_SHORT_SERVER_ID and SERVER_TRANSPORT_BINDING_ID can be overwritten with new information. These need to be flagged as RW for now, otherwise bootstrap process will error out. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_obj_server.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_server.c b/subsys/net/lib/lwm2m/lwm2m_obj_server.c index 120cf00c2ffa8..e612d7473c4e4 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -50,15 +50,19 @@ static char transport_binding[MAX_INSTANCE_COUNT][TRANSPORT_BINDING_LEN]; static struct lwm2m_engine_obj server; static struct lwm2m_engine_obj_field fields[] = { - OBJ_FIELD_DATA(SERVER_SHORT_SERVER_ID, R, U16), + /* + * LwM2M TS "E.2 LwM2M Object: LwM2M Server" page 107, describes + * Short Server ID as READ-ONLY, but BOOTSTRAP server will attempt + * to write it, so it needs to be RW + */ + OBJ_FIELD_DATA(SERVER_SHORT_SERVER_ID, RW, U16), OBJ_FIELD_DATA(SERVER_LIFETIME_ID, RW, U32), OBJ_FIELD_DATA(SERVER_DEFAULT_MIN_PERIOD_ID, RW_OPT, U32), OBJ_FIELD_DATA(SERVER_DEFAULT_MAX_PERIOD_ID, RW_OPT, U32), OBJ_FIELD_EXECUTE_OPT(SERVER_DISABLE_ID), OBJ_FIELD_DATA(SERVER_DISABLE_TIMEOUT_ID, RW_OPT, U32), OBJ_FIELD_DATA(SERVER_STORE_NOTIFY_ID, RW, U8), - /* Mark Transport Binding RO as we only support UDP atm */ - OBJ_FIELD_DATA(SERVER_TRANSPORT_BINDING_ID, R, STRING), + OBJ_FIELD_DATA(SERVER_TRANSPORT_BINDING_ID, RW, STRING), OBJ_FIELD_EXECUTE(SERVER_REG_UPDATE_TRIGGER_ID), }; From 07cb4ece1d254126e603c722fb4b39acbc3759fa Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:14:38 -0700 Subject: [PATCH 12/18] net: lwm2m: WIP: RD client BS support, use security instance info Signed-off-by: Michael Scott --- include/net/lwm2m.h | 18 +- samples/net/lwm2m_client/overlay-dtls.conf | 4 + samples/net/lwm2m_client/prj.conf | 4 +- samples/net/lwm2m_client/src/lwm2m-client.c | 60 ++- subsys/net/lib/lwm2m/lwm2m_engine.c | 125 ++++-- subsys/net/lib/lwm2m/lwm2m_rd_client.c | 405 ++++++++++++-------- subsys/net/lib/lwm2m/lwm2m_rd_client.h | 3 + 7 files changed, 413 insertions(+), 206 deletions(-) diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index dd7627a7306c1..abaea7c3403a2 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -61,13 +61,10 @@ struct lwm2m_ctx { struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES]; struct k_delayed_work retransmit_work; -#if defined(CONFIG_NET_APP_DTLS) - /** Pre-Shared Key Information*/ - unsigned char *client_psk; - size_t client_psk_len; - char *client_psk_id; - size_t client_psk_id_len; + /* current security object index */ + int sec_obj_inst; +#if defined(CONFIG_NET_APP_DTLS) /** DTLS support structures */ char *cert_host; u8_t *dtls_result_buf; @@ -233,16 +230,16 @@ int lwm2m_engine_set_net_pkt_pool(struct lwm2m_ctx *ctx, net_pkt_get_slab_func_t tx_slab, net_pkt_get_pool_func_t data_pool); #endif -int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port); +int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, bool is_bootstrap_mode); /* LWM2M RD Client */ /* Client events */ enum lwm2m_rd_client_event { LWM2M_RD_CLIENT_EVENT_NONE, - LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE, - LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE, + LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE, LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE, LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE, LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE, @@ -256,7 +253,6 @@ typedef void (*lwm2m_ctx_event_cb_t)(struct lwm2m_ctx *ctx, enum lwm2m_rd_client_event event); int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port, const char *ep_name, lwm2m_ctx_event_cb_t event_cb); diff --git a/samples/net/lwm2m_client/overlay-dtls.conf b/samples/net/lwm2m_client/overlay-dtls.conf index eb1c154537c8c..6a0de691896eb 100644 --- a/samples/net/lwm2m_client/overlay-dtls.conf +++ b/samples/net/lwm2m_client/overlay-dtls.conf @@ -6,3 +6,7 @@ CONFIG_MBEDTLS_ENABLE_HEAP=y CONFIG_MBEDTLS_HEAP_SIZE=8192 CONFIG_MBEDTLS_CFG_FILE="config-coap.h" CONFIG_LWM2M_PEER_PORT=5684 + +# DTLS urls +CONFIG_NET_APP_PEER_IPV6_ADDR="coaps://[2001:db8::2]:5684" +CONFIG_NET_APP_PEER_IPV4_ADDR="coaps://192.0.2.2:5684" diff --git a/samples/net/lwm2m_client/prj.conf b/samples/net/lwm2m_client/prj.conf index 94fcbad7605cc..43c1480f40f02 100644 --- a/samples/net/lwm2m_client/prj.conf +++ b/samples/net/lwm2m_client/prj.conf @@ -35,6 +35,6 @@ CONFIG_LWM2M_IPSO_TEMP_SENSOR=y CONFIG_LWM2M_IPSO_LIGHT_CONTROL=y CONFIG_NET_APP_MY_IPV6_ADDR="2001:db8::1" -CONFIG_NET_APP_PEER_IPV6_ADDR="2001:db8::2" +CONFIG_NET_APP_PEER_IPV6_ADDR="coap://2001:db8::2" CONFIG_NET_APP_MY_IPV4_ADDR="192.0.2.1" -CONFIG_NET_APP_PEER_IPV4_ADDR="192.0.2.2" +CONFIG_NET_APP_PEER_IPV4_ADDR="coap://192.0.2.2" diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 40378802655de..5eaa34fd9ad60 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -77,7 +77,7 @@ static struct lwm2m_ctx client; NET_APP_TLS_POOL_DEFINE(dtls_pool, 10); /* "000102030405060708090a0b0c0d0e0f" */ -static unsigned char client_psk[] = { +static const unsigned char client_psk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; @@ -222,8 +222,37 @@ static int firmware_block_received_cb(u16_t obj_inst_id, static int lwm2m_setup(void) { struct float32_value float_value; + int ret; + char *server_url; + u16_t server_url_len; + u8_t server_url_flags; /* setup SECURITY object */ + + /* Server URL */ + ret = lwm2m_engine_get_res_data("0/0/0", + (void **)&server_url, &server_url_len, + &server_url_flags); + if (ret < 0) { + return ret; + } + + snprintk(server_url, server_url_len, "%s", + IS_ENABLED(CONFIG_NET_IPV6) ? CONFIG_NET_APP_PEER_IPV6_ADDR : + CONFIG_NET_APP_PEER_IPV4_ADDR); + + /* Bootstrap Mode */ + lwm2m_engine_set_bool("0/0/1", + IS_ENABLED(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP)); + /* Security Mode */ + lwm2m_engine_set_u8("0/0/2", IS_ENABLED(CONFIG_NET_APP_DTLS) ? 0 : 3); +#if defined(CONFIG_NET_APP_DTLS) + lwm2m_engine_set_opaque("0/0/3", + (void *)client_psk_id, sizeof(client_psk_id)); + lwm2m_engine_set_opaque("0/0/5", + (void *)client_psk, sizeof(client_psk)); +#endif /* CONFIG_NET_APP_DTLS */ + /* setup SERVER object */ /* setup DEVICE object */ @@ -309,12 +338,16 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE: - SYS_LOG_DBG("Bootstrap failure!"); + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: + SYS_LOG_DBG("Bootstrap registration failure!"); break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE: - SYS_LOG_DBG("Bootstrap complete"); + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE: + SYS_LOG_DBG("Bootstrap registration complete"); + break; + + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE: + SYS_LOG_DBG("Bootstrap transfer complete"); break; case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE: @@ -367,10 +400,6 @@ void main(void) #endif #if defined(CONFIG_NET_APP_DTLS) - client.client_psk = client_psk; - client.client_psk_len = 16; - client.client_psk_id = (char *)client_psk_id; - client.client_psk_id_len = strlen(client_psk_id); client.cert_host = HOSTNAME; client.dtls_pool = &dtls_pool; client.dtls_result_buf = dtls_result; @@ -379,18 +408,7 @@ void main(void) client.dtls_stack_len = K_THREAD_STACK_SIZEOF(net_app_dtls_stack); #endif /* CONFIG_NET_APP_DTLS */ -#if defined(CONFIG_NET_IPV6) - ret = lwm2m_rd_client_start(&client, CONFIG_NET_APP_PEER_IPV6_ADDR, - CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, - rd_client_event); -#elif defined(CONFIG_NET_IPV4) - ret = lwm2m_rd_client_start(&client, CONFIG_NET_APP_PEER_IPV4_ADDR, - CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, - rd_client_event); -#else - SYS_LOG_ERR("LwM2M client requires IPv4 or IPv6."); - ret = -EPROTONOSUPPORT; -#endif + ret = lwm2m_rd_client_start(&client, CONFIG_BOARD, rd_client_event); if (ret < 0) { SYS_LOG_ERR("LWM2M init LWM2M RD client error (%d)", ret); diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index fdb27fac43cdd..5ace7ddce7ac7 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -118,6 +118,7 @@ struct notification_attrs { }; static struct observe_node observe_node_data[CONFIG_LWM2M_ENGINE_MAX_OBSERVER]; +static bool bootstrap_mode; #define MAX_PERIODIC_SERVICE 10 @@ -3926,25 +3927,88 @@ static int setup_cert(struct net_app_ctx *app_ctx, void *cert) struct lwm2m_ctx *client_ctx = CONTAINER_OF(app_ctx, struct lwm2m_ctx, net_app_ctx); + char path[MAX_RESOURCE_LEN]; + u8_t *psk, *psk_id; + int ret; + u16_t psk_len, psk_id_len; + u8_t psk_data_flags, psk_id_data_flags; + + snprintk(path, sizeof(path), "0/%d/3", client_ctx->sec_obj_inst); + ret = lwm2m_engine_get_res_data(path, (void **)&psk_id, &psk_id_len, + &psk_id_data_flags); + if (ret < 0) { + return ret; + } + + snprintk(path, sizeof(path), "0/%d/5", client_ctx->sec_obj_inst); + ret = lwm2m_engine_get_res_data(path, (void **)&psk, &psk_len, + &psk_data_flags); + if (ret < 0) { + return ret; + } + return mbedtls_ssl_conf_psk( &app_ctx->tls.mbedtls.conf, - (const unsigned char *)client_ctx->client_psk, - client_ctx->client_psk_len, - (const unsigned char *)client_ctx->client_psk_id, - client_ctx->client_psk_id_len); + (const unsigned char *)psk, (size_t)psk_len, + (const unsigned char *)psk_id, strlen(psk_id)); #else return 0; #endif } #endif /* CONFIG_NET_APP_DTLS */ -int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port) +int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, bool is_bootstrap_mode) { + char pathstr[MAX_RESOURCE_LEN]; + char *data_ptr, *peer_str; struct sockaddr client_addr; int ret = 0; + u16_t peer_strlen; + u8_t peer_data_flags; +#if defined(CONFIG_NET_APP_DTLS) + bool use_dtls = false; +#endif + + /* get the server URL */ + snprintk(pathstr, sizeof(pathstr), "0/%d/0", client_ctx->sec_obj_inst); + ret = lwm2m_engine_get_res_data(pathstr, (void **)&data_ptr, + &peer_strlen, + &peer_data_flags); + if (ret < 0) { + return ret; + } - /* TODO: use security object for initial setup */ + /* walk forward till colon shifting to lower case */ + peer_str = data_ptr; + while (*peer_str != '\0' && *peer_str != ':') { + *peer_str = tolower(*peer_str); + peer_str += 1; + } + + /* check to make sure there was a colon */ + if (*peer_str != ':') { + return -EINVAL; + } + + if (strncmp(data_ptr, "coap:", 5) != 0 && + strncmp(data_ptr, "coaps:", 6) != 0) { + return -EPROTONOSUPPORT; + } + + if (strncmp(data_ptr, "coaps:", 6) == 0) { +#if defined(CONFIG_NET_APP_DTLS) + use_dtls = true; +#else + return -EPROTONOSUPPORT; +#endif + } + + /* skip the colons and slashes */ + while (*peer_str == ':' || *peer_str == '/') { + peer_str += 1; + } + + SYS_LOG_DBG("URL: %s", data_ptr); /* setup the local client port */ memset(&client_addr, 0, sizeof(client_addr)); @@ -3956,10 +4020,13 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, net_sin(&client_addr)->sin_port = htons(CONFIG_LWM2M_LOCAL_PORT); #endif + /* save bootstrap_mode for later */ + bootstrap_mode = is_bootstrap_mode; + ret = net_app_init_udp_client(&client_ctx->net_app_ctx, &client_addr, NULL, peer_str, - peer_port, + CONFIG_LWM2M_PEER_PORT, client_ctx->net_init_timeout, client_ctx); if (ret) { @@ -3978,20 +4045,22 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, } #if defined(CONFIG_NET_APP_DTLS) - ret = net_app_client_tls(&client_ctx->net_app_ctx, - client_ctx->dtls_result_buf, - client_ctx->dtls_result_buf_len, - INSTANCE_INFO, - strlen(INSTANCE_INFO), - setup_cert, - client_ctx->cert_host, - NULL, - client_ctx->dtls_pool, - client_ctx->dtls_stack, - client_ctx->dtls_stack_len); - if (ret < 0) { - SYS_LOG_ERR("Cannot init DTLS (%d)", ret); - goto error_start; + if (use_dtls) { + ret = net_app_client_tls(&client_ctx->net_app_ctx, + client_ctx->dtls_result_buf, + client_ctx->dtls_result_buf_len, + INSTANCE_INFO, + strlen(INSTANCE_INFO), + setup_cert, + client_ctx->cert_host, + NULL, + client_ctx->dtls_pool, + client_ctx->dtls_stack, + client_ctx->dtls_stack_len); + if (ret < 0) { + SYS_LOG_ERR("Cannot init DTLS (%d)", ret); + goto error_start; + } } #endif @@ -4002,6 +4071,18 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, goto error_start; } +#if defined(CONFIG_NET_APP_DTLS) + if (use_dtls) { + SYS_LOG_DBG("Waiting for TLS handshake"); + while (!client_ctx->net_app_ctx.tls.handshake_done) { + k_sleep(K_SECONDS(1)); + SYS_LOG_DBG("Check TLS handshake: %d", client_ctx->net_app_ctx.tls.handshake_done); + } + + SYS_LOG_DBG("TLS handshake complete!"); + } +#endif + return 0; error_start: diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index dcd9629a00369..ab54c21ee990a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -76,9 +76,12 @@ */ enum sm_engine_state { ENGINE_INIT, - ENGINE_DO_BOOTSTRAP, - ENGINE_BOOTSTRAP_SENT, - ENGINE_BOOTSTRAP_DONE, +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + ENGINE_DO_BOOTSTRAP_REG, + ENGINE_BOOTSTRAP_REG_SENT, + ENGINE_BOOTSTRAP_REG_DONE, + ENGINE_BOOTSTRAP_TRANS_DONE, +#endif ENGINE_DO_REGISTRATION, ENGINE_REGISTRATION_SENT, ENGINE_REGISTRATION_DONE, @@ -90,18 +93,12 @@ enum sm_engine_state { }; struct lwm2m_rd_client_info { - u16_t lifetime; struct lwm2m_ctx *ctx; + s64_t last_update; + u32_t lifetime; u8_t engine_state; - u8_t use_bootstrap; - u8_t has_bs_server_info; - u8_t use_registration; - u8_t has_registration_info; - u8_t bootstrapped; /* bootstrap done */ u8_t trigger_update; - s64_t last_update; - char ep_name[CLIENT_EP_LEN]; char server_ep[CLIENT_EP_LEN]; @@ -117,16 +114,20 @@ static void set_sm_state(u8_t sm_state) enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; /* Determine if a callback to the app is needed */ - if (sm_state == ENGINE_BOOTSTRAP_DONE) { - event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE; - } else if (client.engine_state == ENGINE_UPDATE_SENT && +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (sm_state == ENGINE_BOOTSTRAP_REG_DONE) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE; + } else if (sm_state == ENGINE_BOOTSTRAP_TRANS_DONE) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE; +#endif + if (client.engine_state == ENGINE_UPDATE_SENT && sm_state == ENGINE_REGISTRATION_DONE) { event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_COMPLETE; } else if (sm_state == ENGINE_REGISTRATION_DONE) { event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_COMPLETE; } else if ((sm_state == ENGINE_INIT || sm_state == ENGINE_DEREGISTERED) && - (client.engine_state > ENGINE_BOOTSTRAP_DONE && + (client.engine_state > ENGINE_DO_REGISTRATION && client.engine_state < ENGINE_DEREGISTER)) { event = LWM2M_RD_CLIENT_EVENT_DISCONNECT; } @@ -156,9 +157,12 @@ static void sm_handle_timeout_state(struct lwm2m_message *msg, { enum lwm2m_rd_client_event event = LWM2M_RD_CLIENT_EVENT_NONE; - if (client.engine_state == ENGINE_BOOTSTRAP_SENT) { - event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE; - } else if (client.engine_state == ENGINE_REGISTRATION_SENT) { +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (client.engine_state == ENGINE_BOOTSTRAP_REG_SENT) { + event = LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE; + } else +#endif + if (client.engine_state == ENGINE_REGISTRATION_SENT) { event = LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE; } else if (client.engine_state == ENGINE_UPDATE_SENT) { event = LWM2M_RD_CLIENT_EVENT_REG_UPDATE_FAILURE; @@ -184,6 +188,7 @@ void engine_trigger_update(void) /* state machine reply callbacks */ +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) static int do_bootstrap_reply_cb(const struct coap_packet *response, struct coap_reply *reply, const struct sockaddr *from) @@ -196,12 +201,14 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, COAP_RESPONSE_CODE_DETAIL(code)); if (code == COAP_RESPONSE_CODE_CHANGED) { - SYS_LOG_DBG("Considered done!"); - set_sm_state(ENGINE_BOOTSTRAP_DONE); + SYS_LOG_INF("Bootstrap registration done!"); + set_sm_state(ENGINE_BOOTSTRAP_REG_DONE); } else if (code == COAP_RESPONSE_CODE_NOT_FOUND) { + /* TODO: try and find another bootstrap server entry? */ SYS_LOG_ERR("Failed: NOT_FOUND. Not Retrying."); set_sm_state(ENGINE_DO_REGISTRATION); } else if (code == COAP_RESPONSE_CODE_FORBIDDEN) { + /* TODO: try and find another bootstrap server entry? */ SYS_LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying."); set_sm_state(ENGINE_DO_REGISTRATION); } else { @@ -215,13 +222,18 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, return 0; } -static void do_bootstrap_timeout_cb(struct lwm2m_message *msg) +static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg) { SYS_LOG_WRN("Bootstrap Timeout"); + /* TODO: + * Look for the "next" BOOTSTRAP server entry in our security info + */ + /* Restart from scratch */ sm_handle_timeout_state(msg, ENGINE_INIT); } +#endif static int do_registration_reply_cb(const struct coap_packet *response, struct coap_reply *reply, @@ -286,6 +298,10 @@ static void do_registration_timeout_cb(struct lwm2m_message *msg) { SYS_LOG_WRN("Registration Timeout"); + /* TODO: + * Look for the "next" normal server entry in our security info + */ + /* Restart from scratch */ sm_handle_timeout_state(msg, ENGINE_INIT); } @@ -361,148 +377,218 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) sm_handle_timeout_state(msg, ENGINE_INIT); } +/* utility functions */ + +static int sm_select_next_sec_inst(bool bootstrap_server, + int *sec_obj_inst, u32_t *lifetime) +{ + char pathstr[MAX_RESOURCE_LEN]; + int ret, end, i, obj_inst_id, found = -1; + bool is_bootstrap_server; + + /* lookup existing index */ + i = lwm2m_security_inst_id_to_index(*sec_obj_inst); + if (i < 0) { + *sec_obj_inst = -1; + i = -1; + } + + /* store end marker, due to looping */ + end = (i == -1 ? CONFIG_LWM2M_SECURITY_INSTANCE_COUNT : i); + + /* loop through servers starting from the index after the current one */ + for (i++; i != end; i++) { + if (i >= CONFIG_LWM2M_SECURITY_INSTANCE_COUNT) { + i = 0; + } + + obj_inst_id = lwm2m_security_index_to_inst_id(i); + if (obj_inst_id < 0) { + continue; + } + + snprintk(pathstr, sizeof(pathstr), "0/%d/1", + obj_inst_id); + ret = lwm2m_engine_get_bool(pathstr, &is_bootstrap_server); + if (ret < 0) { + continue; + } + +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (is_bootstrap_server == bootstrap_server) { +#else + if (is_bootstrap_server == false) { +#endif + found = obj_inst_id; + break; + } + } + + if (found > -1) { + *sec_obj_inst = found; + + /* query the lifetime */ + /* TODO: use Short Server ID to link to server info */ + snprintk(pathstr, sizeof(pathstr), "1/%d/1", + obj_inst_id); + if (lwm2m_engine_get_u32(pathstr, lifetime) < 0) { + *lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + SYS_LOG_DBG("Using default lifetime: %u", *lifetime); + } + } + + if (*sec_obj_inst < 0) { + /* no servers found */ + SYS_LOG_DBG("sec_obj_inst: NOT_FOUND"); + return -ENOENT; + } + + SYS_LOG_DBG("sec_obj_inst: %d", *sec_obj_inst); + return 0; +} + /* state machine step functions */ static int sm_do_init(void) { - SYS_LOG_INF("RD Client started with endpoint " - "'%s' and client lifetime %d", - client.ep_name, - client.lifetime); - /* Zephyr has joined network already */ - client.has_registration_info = 1; - client.bootstrapped = 0; client.trigger_update = 0; -#if defined(CONFIG_LWM2M_BOOTSTRAP_SERVER) - client.use_bootstrap = 1; + + /* reset security object instance */ + client.ctx->sec_obj_inst = -1; + +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + set_sm_state(ENGINE_DO_BOOTSTRAP_REG); #else - client.use_registration = 1; + set_sm_state(ENGINE_DO_REGISTRATION); #endif - if (client.lifetime == 0) { - client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; - } - /* Do bootstrap or registration */ - if (client.use_bootstrap) { - set_sm_state(ENGINE_DO_BOOTSTRAP); - } else { - set_sm_state(ENGINE_DO_REGISTRATION); - } return 0; } -static int sm_do_bootstrap(void) +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) +static int sm_do_bootstrap_reg(void) { struct lwm2m_message *msg; struct net_app_ctx *app_ctx = NULL; int ret; struct sockaddr *remote = NULL; - if (client.use_bootstrap && - client.bootstrapped == 0 && - client.has_bs_server_info) { - app_ctx = &client.ctx->net_app_ctx; - msg = lwm2m_get_message(client.ctx); - if (!msg) { - SYS_LOG_ERR("Unable to get a lwm2m message!"); - return -ENOMEM; - } + /* TODO: clear out connection data? */ - msg->type = COAP_TYPE_CON; - msg->code = COAP_METHOD_POST; - msg->mid = 0; - msg->reply_cb = do_bootstrap_reply_cb; - msg->message_timeout_cb = do_bootstrap_timeout_cb; + ret = sm_select_next_sec_inst(true, + &client.ctx->sec_obj_inst, + &client.lifetime); + if (ret < 0) { + /* try again */ + return ret; + } - ret = lwm2m_init_message(msg); - if (ret) { - goto cleanup; - } + if (client.lifetime == 0) { + client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + } - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - "bs", strlen("bs")); + SYS_LOG_INF("Bootstrap started with endpoint " + "'%s' with client lifetime %d", + client.ep_name, client.lifetime); - 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)); + ret = lwm2m_engine_start(client.ctx, true); + if (ret < 0) { + SYS_LOG_ERR("Cannot init LWM2M engine (%d)", ret); + goto cleanup_engine; + } + + if (!client.ctx->net_app_ctx.default_ctx) { + SYS_LOG_ERR("Default net_app_ctx not selected!"); + ret = -EINVAL; + goto cleanup_engine; + } + + app_ctx = &client.ctx->net_app_ctx; + msg = lwm2m_get_message(client.ctx); + if (!msg) { + SYS_LOG_ERR("Unable to get a lwm2m message!"); + return -ENOMEM; + } - /* log the bootstrap attempt */ + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_POST; + msg->mid = 0; + msg->reply_cb = do_bootstrap_reply_cb; + msg->message_timeout_cb = do_bootstrap_reg_timeout_cb; + + ret = lwm2m_init_message(msg); + if (ret) { + goto cleanup; + } + + /* TODO: handle return error */ + coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, + "bs", strlen("bs")); + + 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)); + + /* log the bootstrap attempt */ #if defined(CONFIG_NET_APP_DTLS) - if (app_ctx->dtls.ctx) { - remote = &app_ctx->dtls.ctx->remote; - } + if (app_ctx->dtls.ctx) { + remote = &app_ctx->dtls.ctx->remote; + } #endif - if (!remote) { - remote = &app_ctx->default_ctx->remote; - } - - SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'", - lwm2m_sprint_ip_addr(remote), - query_buffer); + if (!remote) { + remote = &app_ctx->default_ctx->remote; + } - ret = lwm2m_send_message(msg); - if (ret < 0) { - SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", - ret); - goto cleanup; - } + SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'", + lwm2m_sprint_ip_addr(remote), + query_buffer); - set_sm_state(ENGINE_BOOTSTRAP_SENT); + ret = lwm2m_send_message(msg); + if (ret < 0) { + SYS_LOG_ERR("Error sending LWM2M packet (err:%d).", + ret); + goto cleanup; } + + set_sm_state(ENGINE_BOOTSTRAP_REG_SENT); return 0; cleanup: lwm2m_reset_message(msg, true); return ret; + +cleanup_engine: + lwm2m_engine_context_close(client.ctx); + return ret; } static int sm_bootstrap_done(void) { - /* TODO: Fix this */ - /* check that we should still use bootstrap */ - if (client.use_bootstrap) { -#ifdef CONFIG_LWM2M_SECURITY_OBJ_SUPPORT - int i; - - SYS_LOG_DBG("*** Bootstrap - checking for server info ..."); - - /* get the server URI */ - if (sec_data->server_uri_len > 0) { - /* TODO: Write endpoint parsing function */ -#if 0 - if (!parse_endpoint(sec_data->server_uri, - sec_data->server_uri_len, - &client.reg_server)) { -#else - if (true) { -#endif - SYS_LOG_ERR("Failed to parse URI!"); - } else { - client.has_registration_info = 1; - client.bootstrapped++; - } - } else { - SYS_LOG_ERR("** failed to parse URI"); - } + return 0; +} - /* if we did not register above - then fail this and restart */ - if (client.bootstrapped == 0) { - /* Not ready - Retry with the bootstrap server again */ - set_sm_state(ENGINE_DO_BOOTSTRAP); - } else { - set_sm_state(ENGINE_DO_REGISTRATION); - } - } else { -#endif - set_sm_state(ENGINE_DO_REGISTRATION); - } +void engine_bootstrap_finish(void) +{ + SYS_LOG_INF("Bootstrap data transfer done!"); + set_sm_state(ENGINE_BOOTSTRAP_TRANS_DONE); +} + +static int sm_bootstrap_trans_done(void) +{ + /* close down net_app contexts */ + lwm2m_engine_context_close(client.ctx); + + /* reset security object instance */ + client.ctx->sec_obj_inst = -1; + + set_sm_state(ENGINE_DO_REGISTRATION); return 0; } +#endif static int sm_send_registration(bool send_obj_support_data, coap_reply_t reply_cb, @@ -619,9 +705,37 @@ static int sm_do_registration(void) { int ret = 0; - if (client.use_registration && - !sm_is_registered() && - client.has_registration_info) { + /* TODO: clear out connection data? */ + + ret = sm_select_next_sec_inst(false, + &client.ctx->sec_obj_inst, + &client.lifetime); + if (ret < 0) { + set_sm_state(ENGINE_INIT); + return -EINVAL; + } + + if (client.lifetime == 0) { + client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + } + + SYS_LOG_INF("RD Client started with endpoint " + "'%s' with client lifetime %d", + client.ep_name, client.lifetime); + + ret = lwm2m_engine_start(client.ctx, false); + if (ret < 0) { + SYS_LOG_ERR("Cannot init LWM2M engine (%d)", ret); + goto cleanup_engine; + } + + if (!client.ctx->net_app_ctx.default_ctx) { + SYS_LOG_ERR("Default net_app_ctx not selected!"); + ret = -EINVAL; + goto cleanup_engine; + } + + if (!sm_is_registered()) { ret = sm_send_registration(true, do_registration_reply_cb, do_registration_timeout_cb); @@ -633,6 +747,10 @@ static int sm_do_registration(void) } return ret; + +cleanup_engine: + lwm2m_engine_context_close(client.ctx); + return ret; } static int sm_registration_done(void) @@ -718,18 +836,25 @@ static void lwm2m_rd_client_service(void) sm_do_init(); break; - case ENGINE_DO_BOOTSTRAP: - sm_do_bootstrap(); +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + case ENGINE_DO_BOOTSTRAP_REG: + sm_do_bootstrap_reg(); break; - case ENGINE_BOOTSTRAP_SENT: - /* wait for bootstrap to be done or timeout */ + case ENGINE_BOOTSTRAP_REG_SENT: + /* wait for bootstrap registration done */ break; - case ENGINE_BOOTSTRAP_DONE: + case ENGINE_BOOTSTRAP_REG_DONE: sm_bootstrap_done(); + /* wait for transfer done */ break; + case ENGINE_BOOTSTRAP_TRANS_DONE: + sm_bootstrap_trans_done(); + break; +#endif + case ENGINE_DO_REGISTRATION: sm_do_registration(); break; @@ -768,24 +893,9 @@ static void lwm2m_rd_client_service(void) } int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port, const char *ep_name, lwm2m_ctx_event_cb_t event_cb) { - int ret = 0; - - ret = lwm2m_engine_start(client_ctx, peer_str, peer_port); - if (ret < 0) { - SYS_LOG_ERR("Cannot init LWM2M engine (%d)", ret); - goto cleanup; - } - - if (!client_ctx->net_app_ctx.default_ctx) { - SYS_LOG_ERR("Default net_app_ctx not selected!"); - return -EINVAL; - } - - /* TODO: use server URI data from security */ client.ctx = client_ctx; client.event_cb = event_cb; set_sm_state(ENGINE_INIT); @@ -793,11 +903,6 @@ int lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, SYS_LOG_INF("LWM2M Client: %s", client.ep_name); return 0; - -cleanup: - net_app_close(&client_ctx->net_app_ctx); - net_app_release(&client_ctx->net_app_ctx); - return ret; } static int lwm2m_rd_client_init(struct device *dev) diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.h b/subsys/net/lib/lwm2m/lwm2m_rd_client.h index 39453ab2aa7c7..61fa8480bf9d2 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.h +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.h @@ -38,5 +38,8 @@ #define LWM2M_RD_CLIENT_H void engine_trigger_update(void); +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) +void engine_bootstrap_finish(void); +#endif #endif /* LWM2M_RD_CLIENT_H */ From b10603112c1e9fb04d3ae48c07c59421b4e67214 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:20:28 -0700 Subject: [PATCH 13/18] net: lwm2m: add BOOTSTRAP_WRITE handling to TLV formatter During BOOTSTRAP_WRITE we can safely ignore optional resources (similar to OP_CREATE). Let's add this handling to the OMA TLV formatter. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 1 + subsys/net/lib/lwm2m/lwm2m_object.h | 1 + subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c | 16 +++++++++------- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 5ace7ddce7ac7..1f5e98da6d667 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -3106,6 +3106,7 @@ static int handle_request(struct coap_packet *request, context.out = &out; context.path = &path; engine_clear_context(&context); + context.bootstrap_mode = bootstrap_mode; /* set CoAP request / message */ in.in_cpkt = request; diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 6f17a45a63eee..129a719ac7529 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -347,6 +347,7 @@ struct lwm2m_engine_context { struct lwm2m_output_context *out; struct lwm2m_obj_path *path; u8_t operation; + bool bootstrap_mode; }; /* inline multi-format write / read functions */ diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index e70256295c5a1..0b27fa0ab97bb 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -770,8 +770,9 @@ static int do_write_op_tlv_item(struct lwm2m_engine_context *context) } if (!res) { - /* if OPTIONAL and OP_CREATE use ENOTSUP */ - if (context->operation == LWM2M_OP_CREATE && + /* if OPTIONAL and BOOTSTRAP-WRITE or OP_CREATE use ENOTSUP */ + if ((context->bootstrap_mode || + context->operation == LWM2M_OP_CREATE) && LWM2M_HAS_PERM(obj_field, BIT(LWM2M_FLAG_OPTIONAL))) { ret = -ENOTSUP; goto error; @@ -858,12 +859,13 @@ int do_write_op_tlv(struct lwm2m_engine_obj *obj, path->level = 3; ret = do_write_op_tlv_item(context); /* - * ignore errors for CREATE op - * TODO: support BOOTSTRAP WRITE where optional - * resources are ignored + * for OP_CREATE and BOOTSTRAP WRITE: errors on optional + * resources are ignored (ENOTSUP) */ - if (ret < 0 && (context->operation != LWM2M_OP_CREATE || - ret != -ENOTSUP)) { + if (ret < 0 && + !((ret == -ENOTSUP) && + (context->bootstrap_mode || + context->operation == LWM2M_OP_CREATE))) { return ret; } } From e0c4587c1a5a24489eb61542a8f8f87d1abbd690 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:24:24 -0700 Subject: [PATCH 14/18] net: lwm2m: don't trigger engine update during bootstrap For object create and delete we normally will trigger the RD client to send an updated list of object data. However, we don't want to do this during bootstrap mode. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 1f5e98da6d667..38ee7cd0e2f92 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -732,7 +732,9 @@ int lwm2m_create_obj_inst(u16_t obj_id, u16_t obj_inst_id, } #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT - engine_trigger_update(); + if (!bootstrap_mode) { + engine_trigger_update(); + } #endif return 0; } @@ -779,7 +781,9 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id) clear_attrs(obj_inst); memset(obj_inst, 0, sizeof(struct lwm2m_engine_obj_inst)); #ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT - engine_trigger_update(); + if (!bootstrap_mode) { + engine_trigger_update(); + } #endif return ret; } From ee9285f6d16ca9664e303d0745b4477f4b408cdf Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:26:19 -0700 Subject: [PATCH 15/18] net: lwm2m: ignore empty OPAQUE data and continue During BOOTSTRAP_WRITE, empty OPAQUE data can being written to the secuity objects. Instead of looking for more data which will never land, let's check the length and exit early if there's no data. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 38ee7cd0e2f92..251f75903a09a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -2125,6 +2125,11 @@ static int lwm2m_write_handler_opaque(struct lwm2m_engine_obj_inst *obj_inst, if (first_read) { len = engine_get_opaque(in, (u8_t *)data_ptr, data_len, &last_pkt_block); + if (len == 0) { + /* ignore empty content and continue */ + return 0; + } + first_read = false; } else { len = lwm2m_engine_get_opaque_more(in, (u8_t *)data_ptr, From 6b4debfb33a244dc484aa388fe169ceab8f172ce Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:31:44 -0700 Subject: [PATCH 16/18] net: lwm2m: update do_discovery for bootstrap mode During bootstrap a DISCOVERY OP needs to be slightly changed: - No object ID is required - Don't avoid security object - Don't return resource information NOTE: Several comments had their "TODO" items updated. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 251f75903a09a..fa5269bf7a784 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -2882,11 +2882,11 @@ static int do_discover_op(struct lwm2m_engine_context *context, bool well_known) u16_t temp_len; bool reported = false; - /* object ID is required unless it's bootstrap discover (TODO) or it's + /* object ID is required unless it's bootstrap discover or it's * a ".well-known/core" discovery * ref: lwm2m spec 20170208-A table 11 */ - if (!well_known && + if (!bootstrap_mode && !well_known && (path->level == 0 || (path->level > 0 && path->obj_id == LWM2M_OBJECT_SECURITY_ID))) { return -EPERM; @@ -2933,18 +2933,21 @@ static int do_discover_op(struct lwm2m_engine_context *context, bool well_known) return 0; } - /* TODO: lwm2m spec 20170208-A sec 5.2.7.3 bootstrap discover on "/" + /* + * lwm2m spec 20170208-A sec 5.2.7.3 bootstrap discover on "/" * - report object 0 (security) with ssid - * - prefixed w/ lwm2m enabler version. e.g. lwm2m="1.0" + * - (TODO) prefixed w/ lwm2m enabler version. e.g. lwm2m="1.0" * - returns object and object instances only */ SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_inst_list, obj_inst, node) { - /* TODO: support bootstrap discover - * Avoid discovery for security object (5.2.7.3) - * Skip reporting unrelated object + /* + * - Avoid discovery for security object (5.2.7.3) unless + * Bootstrap discover + * - Skip reporting unrelated object */ - if (obj_inst->obj->obj_id == LWM2M_OBJECT_SECURITY_ID || + if ((!bootstrap_mode && + obj_inst->obj->obj_id == LWM2M_OBJECT_SECURITY_ID) || obj_inst->obj->obj_id != path->obj_id) { continue; } @@ -2997,6 +3000,11 @@ static int do_discover_op(struct lwm2m_engine_context *context, bool well_known) reported = true; } + /* don't return resource info for bootstrap discovery */ + if (bootstrap_mode) { + continue; + } + for (int i = 0; i < obj_inst->resource_count; i++) { /* skip unrelated resources */ if (path->level == 3 && From 0a16453ed745fc7199a720c37deadeb8dec1de31 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:36:33 -0700 Subject: [PATCH 17/18] net: lwm2m: add BOOTSTRAP_DELETE handling A bootstrap delete operation removes the existing security information from the client prior to writing new information. Let's handle this in the engine. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 55 +++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index fa5269bf7a784..79a1f9ae663a0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -3097,6 +3097,29 @@ static int do_write_op(struct lwm2m_engine_obj *obj, } } +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) +static int bootstrap_delete(void) +{ + struct lwm2m_engine_obj_inst *obj_inst, *tmp; + int ret = 0; + + /* delete SECURITY instances > 0 */ + SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&engine_obj_inst_list, + obj_inst, tmp, node) { + if (obj_inst->obj->obj_id == LWM2M_OBJECT_SECURITY_ID && + obj_inst->obj_inst_id > 0) { + ret = lwm2m_delete_obj_inst(obj_inst->obj->obj_id, + obj_inst->obj_inst_id); + if (ret < 0) { + return ret; + } + } + } + + return ret; +} +#endif + static int handle_request(struct coap_packet *request, struct lwm2m_message *msg) { @@ -3146,14 +3169,32 @@ static int handle_request(struct coap_packet *request, r = coap_find_options(in.in_cpkt, COAP_OPTION_URI_PATH, options, ARRAY_SIZE(options)); if (r <= 0) { - /* '/' is used by bootstrap-delete only */ + switch (code & COAP_REQUEST_MASK) { +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + case COAP_METHOD_DELETE: + if (bootstrap_mode) { + r = bootstrap_delete(); + if (r < 0) { + goto error; + } - /* - * TODO: Handle bootstrap deleted -- - * re-add when DTLS support ready - */ - r = -EPERM; - goto error; + msg->code = COAP_RESPONSE_CODE_DELETED; + r = lwm2m_init_message(msg); + } else { + r = -EPERM; + } + + if (r < 0) { + goto error; + } + + return 0; +#endif + default: + r = -EPERM; + goto error; + break; + } } /* check for .well-known/core URI query (DISCOVER) */ From cb1fe67b65fcbeeadf4cecdb199f6781d60be790 Mon Sep 17 00:00:00 2001 From: Michael Scott Date: Thu, 24 May 2018 17:38:39 -0700 Subject: [PATCH 18/18] net: lwm2m: add "Bootstrap-Finish" handling Once the LwM2M server has finished transferring the bootstrap information, a "Bootstrap-Finish" operation will be sent to the LwM2M client. Per LwM2M Tech Specification 1.0.2 page 76, a Bootstrap-Finish operation is a POST with the URI=/bs. Add this handling to the LwM2M engine. Signed-off-by: Michael Scott --- subsys/net/lib/lwm2m/lwm2m_engine.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index 79a1f9ae663a0..1c75e9831873c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -3209,6 +3209,20 @@ static int handle_request(struct coap_packet *request, } well_known = true; +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + /* bootstrap transfer finish is marked by resource /bs */ + } else if (bootstrap_mode && r == 1 && + (options[0].len == 2 && + strncmp(options[0].value, "bs", 2) == 0)) { + msg->code = COAP_RESPONSE_CODE_CHANGED; + r = lwm2m_init_message(msg); + if (r < 0) { + goto error; + } + + engine_bootstrap_finish(); + return 0; +#endif } else { r = coap_options_to_path(options, r, &path); if (r < 0) {