diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 047cca1a8525b..abaea7c3403a2 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 * @@ -58,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; @@ -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,11 @@ 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); +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 @@ -226,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, @@ -249,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/Kconfig b/subsys/net/lib/lwm2m/Kconfig index 1e1d1722d41b4..d40e619d6e835 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -75,14 +75,24 @@ 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 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 + default 2 if LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP range 1 10 help This setting establishes the total count of LWM2M Server instances @@ -95,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 diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index bfdf9544f9c62..1c75e9831873c 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 @@ -685,6 +686,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,8 +720,21 @@ 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(); + if (!bootstrap_mode) { + engine_trigger_update(); + } #endif return 0; } @@ -740,6 +755,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--; @@ -757,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; } @@ -1883,7 +1909,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; @@ -1897,6 +1923,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, @@ -2069,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, @@ -2821,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; @@ -2872,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; } @@ -2936,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 && @@ -3028,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) { @@ -3054,6 +3146,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; @@ -3073,16 +3166,35 @@ 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 */ + 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) */ @@ -3097,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) { @@ -3828,6 +3954,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); @@ -3845,25 +4000,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; + } + + /* 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; + } - /* TODO: use security object for initial setup */ + /* 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)); @@ -3875,10 +4093,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) { @@ -3897,20 +4118,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 @@ -3921,11 +4144,22 @@ 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: - 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..3ad8bcbd7c765 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 */ @@ -124,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_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_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index c98569e1d64c6..5bc8c3d824c43 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -33,9 +33,14 @@ #define MAX_INSTANCE_COUNT CONFIG_LWM2M_SECURITY_INSTANCE_COUNT #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]; @@ -45,9 +50,9 @@ 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_SERVER_PK_ID, W, OPAQUE), /* TODO */ - OBJ_FIELD_DATA(SECURITY_SECRET_KEY_ID, W, OPAQUE), /* TODO */ + OBJ_FIELD_DATA(SECURITY_CLIENT_PK_ID, W, OPAQUE), + 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), @@ -87,6 +92,9 @@ 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; @@ -98,10 +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_DUMMY(res[index], i, SECURITY_CLIENT_PK_ID); - 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_CLIENT_PK_ID, + &client_identity[index], IDENTITY_LEN), + 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)); @@ -111,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; 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), }; diff --git a/subsys/net/lib/lwm2m/lwm2m_object.h b/subsys/net/lib/lwm2m/lwm2m_object.h index 22798d76c79e5..129a719ac7529 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 @@ -169,6 +166,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; @@ -230,7 +229,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; @@ -348,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_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 */ diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index 2d2953b31b26d..0b27fa0ab97bb 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,30 @@ static int do_write_op_tlv_item(struct lwm2m_engine_context *context) } if (!res) { - return -ENOENT; + /* 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; + } + + 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, @@ -826,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; } }