diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 8c4678c17ad2a..b3af5086dac62 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -8,8 +8,8 @@ #ifndef ZEPHYR_INCLUDE_NET_LWM2M_H_ #define ZEPHYR_INCLUDE_NET_LWM2M_H_ -#include -#include +#include +#include /* LWM2M Objects defined by OMA */ @@ -32,38 +32,32 @@ * * @details Context structure for the LwM2M high-level API. * - * @param net_app_ctx Related network application context. - * @param net_init_timeout Used if the net_app API needs to do some time - * consuming operation, like resolving DNS address. - * @param net_timeout How long to wait for the network connection before - * giving up. + * @param remote_addr Stored remote IP address of the LwM2M client */ struct lwm2m_ctx { - /** Net app context structure */ - struct net_app_ctx net_app_ctx; - s32_t net_init_timeout; - s32_t net_timeout; + /** destination address storage */ + struct sockaddr remote_addr; /** Private CoAP and networking structures */ struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING]; 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; - - /** DTLS support structures */ - char *cert_host; - u8_t *dtls_result_buf; - size_t dtls_result_buf_len; - struct k_mem_pool *dtls_pool; - k_thread_stack_t *dtls_stack; - size_t dtls_stack_len; +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + /** DTLS settings */ + int tls_tag; #endif + bool use_dtls; + + /** Current security object index */ + int sec_obj_inst; + bool bootstrap_mode; + + /** Packet Flow Settings */ + bool handle_separate_response; + + /** Socket File Descriptor */ + int sock_fd; }; typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id, @@ -216,16 +210,16 @@ int lwm2m_engine_set_res_data(char *pathstr, void *data_ptr, u16_t data_len, int lwm2m_engine_get_res_data(char *pathstr, void **data_ptr, u16_t *data_len, u8_t *data_flags); -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); /* 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, @@ -238,9 +232,7 @@ enum lwm2m_rd_client_event { 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); +void lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, const char *ep_name, + lwm2m_ctx_event_cb_t event_cb); #endif /* ZEPHYR_INCLUDE_NET_LWM2M_H_ */ diff --git a/samples/net/lwm2m_client/overlay-dtls.conf b/samples/net/lwm2m_client/overlay-dtls.conf index eb1c154537c8c..f545ee1a0f410 100644 --- a/samples/net/lwm2m_client/overlay-dtls.conf +++ b/samples/net/lwm2m_client/overlay-dtls.conf @@ -1,8 +1,19 @@ -CONFIG_NET_APP_DTLS=y +CONFIG_LWM2M_DTLS_SUPPORT=y +CONFIG_LWM2M_PEER_PORT=5684 -CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_ENABLE_HEAP=y +# Special MbedTLS changes CONFIG_MBEDTLS_HEAP_SIZE=8192 -CONFIG_MBEDTLS_CFG_FILE="config-coap.h" -CONFIG_LWM2M_PEER_PORT=5684 +CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=1500 +CONFIG_MBEDTLS_CIPHER_CCM_ENABLED=y + +# Disable RSA, we don't parse certs: saves flash/memory +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=n +# Enable PSK instead +CONFIG_MBEDTLS_KEY_EXCHANGE_PSK_ENABLED=y + +CONFIG_NET_SOCKETS_SOCKOPT_TLS=y +CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS=4 +CONFIG_NET_SOCKETS_ENABLE_DTLS=y + +# MbedTLS needs a larger stack +CONFIG_MAIN_STACK_SIZE=2048 diff --git a/samples/net/lwm2m_client/overlay-wncm14a2a.conf b/samples/net/lwm2m_client/overlay-wncm14a2a.conf index 89192d23a4205..c8ef0a411738c 100644 --- a/samples/net/lwm2m_client/overlay-wncm14a2a.conf +++ b/samples/net/lwm2m_client/overlay-wncm14a2a.conf @@ -8,7 +8,6 @@ CONFIG_NET_CONFIG_PEER_IPV4_ADDR="5.39.83.206" # extend retry timing to 20 seconds for LTE/LTE-M CONFIG_COAP_INIT_ACK_TIMEOUT_MS=20000 -CONFIG_COAP_NET_PKT=y # Hack: disable IPv6 for now CONFIG_NET_IPV6=n diff --git a/samples/net/lwm2m_client/prj.conf b/samples/net/lwm2m_client/prj.conf index 2fae06f9786ee..210fdaad1cf42 100644 --- a/samples/net/lwm2m_client/prj.conf +++ b/samples/net/lwm2m_client/prj.conf @@ -16,10 +16,9 @@ CONFIG_NET_BUF_RX_COUNT=10 CONFIG_NET_BUF_TX_COUNT=10 CONFIG_NET_MAX_CONTEXTS=5 +CONFIG_NET_LOG=y CONFIG_NET_SHELL=y -CONFIG_COAP=y -CONFIG_COAP_NET_PKT=y CONFIG_NET_CONFIG_NEED_IPV6=y CONFIG_NET_CONFIG_NEED_IPV4=y CONFIG_NET_CONFIG_SETTINGS=y diff --git a/samples/net/lwm2m_client/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index 17a4905c2a863..51ce31c36ace5 100644 --- a/samples/net/lwm2m_client/src/lwm2m-client.c +++ b/samples/net/lwm2m_client/src/lwm2m-client.c @@ -25,6 +25,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define CONFIG_NET_CONFIG_PEER_IPV6_ADDR "" #endif +#if defined(CONFIG_NET_IPV6) +#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV6_ADDR +#elif defined(CONFIG_NET_IPV4) +#define SERVER_ADDR CONFIG_NET_CONFIG_PEER_IPV4_ADDR +#else +#error LwM2M requires either IPV6 or IPV4 support +#endif + + #define WAIT_TIME K_SECONDS(10) #define CONNECT_TIME K_SECONDS(10) @@ -61,21 +70,8 @@ static u32_t led_state; static struct lwm2m_ctx client; -#if defined(CONFIG_NET_APP_DTLS) -#if !defined(CONFIG_NET_APP_TLS_STACK_SIZE) -#define CONFIG_NET_APP_TLS_STACK_SIZE 30000 -#endif /* CONFIG_NET_APP_TLS_STACK_SIZE */ - -#define HOSTNAME "localhost" /* for cert verification if that is enabled */ - -/* The result buf size is set to large enough so that we can receive max size - * buf back. Note that mbedtls needs also be configured to have equal size - * value for its buffer size. See MBEDTLS_SSL_MAX_CONTENT_LEN option in DTLS - * config file. - */ -#define RESULT_BUF_SIZE 1500 - -NET_APP_TLS_POOL_DEFINE(dtls_pool, 10); +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#define TLS_TAG 1 /* "000102030405060708090a0b0c0d0e0f" */ static unsigned char client_psk[] = { @@ -84,11 +80,7 @@ static unsigned char client_psk[] = { }; static const char client_psk_id[] = "Client_identity"; - -static u8_t dtls_result[RESULT_BUF_SIZE]; -NET_STACK_DEFINE(NET_APP_DTLS, net_app_dtls_stack, - CONFIG_NET_APP_TLS_STACK_SIZE, CONFIG_NET_APP_TLS_STACK_SIZE); -#endif /* CONFIG_NET_APP_DTLS */ +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ static struct k_sem quit_lock; @@ -205,8 +197,35 @@ 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, "coap%s//%s%s%s", + IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? "s:" : ":", + strchr(SERVER_ADDR, ':') ? "[" : "", SERVER_ADDR, + strchr(SERVER_ADDR, ':') ? "]" : ""); + + /* Security Mode */ + lwm2m_engine_set_u8("0/0/2", + IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? 0 : 3); +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + lwm2m_engine_set_string("0/0/3", (char *)client_psk_id); + lwm2m_engine_set_opaque("0/0/5", + (void *)client_psk, sizeof(client_psk)); +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + /* setup SERVER object */ /* setup DEVICE object */ @@ -292,12 +311,16 @@ static void rd_client_event(struct lwm2m_ctx *client, /* do nothing */ break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_FAILURE: - LOG_DBG("Bootstrap failure!"); + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_FAILURE: + LOG_DBG("Bootstrap registration failure!"); + break; + + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_REG_COMPLETE: + LOG_DBG("Bootstrap registration complete"); break; - case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_COMPLETE: - LOG_DBG("Bootstrap complete"); + case LWM2M_RD_CLIENT_EVENT_BOOTSTRAP_TRANSFER_COMPLETE: + LOG_DBG("Bootstrap transfer complete"); break; case LWM2M_RD_CLIENT_EVENT_REGISTRATION_FAILURE: @@ -342,38 +365,11 @@ void main(void) } (void)memset(&client, 0x0, sizeof(client)); - client.net_init_timeout = WAIT_TIME; - client.net_timeout = CONNECT_TIME; - -#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; - client.dtls_result_buf_len = RESULT_BUF_SIZE; - client.dtls_stack = net_app_dtls_stack; - 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_CONFIG_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_CONFIG_PEER_IPV4_ADDR, - CONFIG_LWM2M_PEER_PORT, CONFIG_BOARD, - rd_client_event); -#else - LOG_ERR("LwM2M client requires IPv4 or IPv6."); - ret = -EPROTONOSUPPORT; +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + client.tls_tag = TLS_TAG; #endif - if (ret < 0) { - LOG_ERR("LWM2M init LWM2M RD client error (%d)", ret); - return; - } + /* client.sec_obj_inst is 0 as a starting point */ + lwm2m_rd_client_start(&client, CONFIG_BOARD, rd_client_event); k_sem_take(&quit_lock, K_FOREVER); } diff --git a/subsys/net/lib/lwm2m/Kconfig b/subsys/net/lib/lwm2m/Kconfig index b6164ed66c464..3b500a433f079 100644 --- a/subsys/net/lib/lwm2m/Kconfig +++ b/subsys/net/lib/lwm2m/Kconfig @@ -6,9 +6,10 @@ menuconfig LWM2M bool "OMA LWM2M protocol stack" - depends on COAP_NET_PKT - select NET_APP_CLIENT + select COAP select HTTP_PARSER_URL + select NET_SOCKETS + select NET_SOCKETS_POSIX_NAMES help This option adds logic for managing OMA LWM2M data @@ -19,6 +20,14 @@ module-dep = LOG module-str = Log level for LWM2M library source "subsys/net/Kconfig.template.log_config.net" +config LWM2M_DTLS_SUPPORT + bool "Enable DTLS support in the LwM2M client" + select MBEDTLS + select MBEDTLS_ENABLE_HEAP + select TLS_CREDENTIALS + select NET_SOCKETS_SOCKOPT_TLS + select NET_SOCKETS_ENABLE_DTLS + config LWM2M_ENGINE_STACK_SIZE int "LWM2M engine stack size" default 1536 if NET_LOG @@ -33,6 +42,21 @@ config LWM2M_ENGINE_MAX_MESSAGES help Set the maximum message objects for the LWM2M library client +config LWM2M_COAP_BLOCK_SIZE + int "LWM2M CoAP block-wise transfer size" + default 256 + range 64 1024 + help + CoAP block size used by LWM2M when performing block-wise + transfers. Possible values: 16, 32, 64, 128, 256, 512 and 1024. + +config LWM2M_ENGINE_MESSAGE_HEADER_SIZE + int "Room for CoAP header data" + default 48 + range 24 128 + help + Extra room allocated to handle CoAP header data + config LWM2M_ENGINE_MAX_PENDING int "LWM2M engine max. pending objects" default 5 @@ -71,11 +95,20 @@ 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 @@ -91,12 +124,17 @@ 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" + 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 default 5683 help - This is the server port to connect to for LWM2M communication + This is the default server port to connect to for LWM2M communication config LWM2M_FIRMWARE_UPDATE_OBJ_SUPPORT bool "Firmware Update object support" @@ -123,16 +161,6 @@ config LWM2M_FIRMWARE_UPDATE_PULL_LOCAL_PORT setting of 0 sets a random port for the client to be used for outgoing communication. -config LWM2M_COAP_BLOCK_SIZE - int "LWM2M CoAP block-wise transfer size" - default 64 if NET_L2_BT - default 64 if NET_L2_IEEE802154 - default 256 - range 16 1024 - help - CoAP block size used by LWM2M when performing block-wise - transfers. Possible values: 16, 32, 64, 128, 256, 512 and 1024. - config LWM2M_NUM_BLOCK1_CONTEXT int "Maximum # of LWM2M block1 contexts" default 3 diff --git a/subsys/net/lib/lwm2m/buf_util.h b/subsys/net/lib/lwm2m/buf_util.h new file mode 100644 index 0000000000000..df384426ffda4 --- /dev/null +++ b/subsys/net/lib/lwm2m/buf_util.h @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2018 Foundries.io + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_BUF_UTIL_H_ +#define ZEPHYR_INCLUDE_BUF_UTIL_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* append */ +static inline int buf_append(u8_t *dst, u16_t *dst_len, u16_t dst_size, + u8_t *src, u16_t src_len) +{ + if (!dst || !src) { + return -EINVAL; + } + + if (*dst_len + src_len > dst_size) { + return -ENOMEM; + } + + memcpy(dst + *dst_len, src, src_len); + *dst_len += src_len; + return 0; +} + +/* insert */ +static inline int buf_insert(u8_t *dst, u16_t *dst_len, u16_t dst_size, + u16_t offset, u8_t *src, u16_t src_len) +{ + if (!dst || !src) { + return -EINVAL; + } + + if (*dst_len + src_len > dst_size) { + return -ENOMEM; + } + + /* shift everything in fbuf after offset by len */ + memmove(dst + offset + src_len, dst + offset, *dst_len - offset); + + /* copy src into fbuf at offset */ + memcpy(dst + offset, src, src_len); + *dst_len += src_len; + return 0; +} + +/* read */ +static inline int buf_read(u8_t *dst, u16_t len, u8_t *src, u16_t src_len, + u16_t *offset) +{ + if (!src) { + return -EINVAL; + } + + if (*offset + len > src_len) { + return -ENOMEM; + } + + if (dst) { + /* copy data at offset into dst */ + memcpy(dst, src + *offset, len); + } + + *offset += len; + return 0; +} + +static inline int buf_skip(u16_t len, u8_t *src, u16_t src_len, u16_t *offset) +{ + return buf_read(NULL, len, src, src_len, offset); +} + +static inline int buf_read_u8(u8_t *value, u8_t *src, u16_t src_len, + u16_t *offset) +{ + return buf_read(value, sizeof(u8_t), src, src_len, offset); +} + +static inline int buf_read_u16(u16_t *value, u8_t *src, u16_t src_len, + u16_t *offset) +{ + return buf_read((u8_t *)value, sizeof(u16_t), src, src_len, offset); +} + +static inline int buf_read_be16(u16_t *value, u8_t *src, u16_t src_len, + u16_t *offset) +{ + int ret; + u8_t v16[2]; + + ret = buf_read(v16, sizeof(u16_t), src, src_len, offset); + *value = v16[0] << 8 | v16[1]; + + return ret; +} + +static inline int buf_read_u32(u32_t *value, u8_t *src, u16_t src_len, + u16_t *offset) +{ + return buf_read((u8_t *)value, sizeof(u32_t), src, src_len, offset); +} + +static inline int buf_read_be32(u32_t *value, u8_t *src, u16_t src_len, + u16_t *offset) +{ + int ret; + u8_t v32[4]; + + ret = buf_read(v32, sizeof(u32_t), src, src_len, offset); + *value = v32[0] << 24 | v32[1] << 16 | v32[2] << 8 | v32[3]; + + return ret; +} + +#ifdef __cplusplus +} +#endif + +#endif /* ZEPHYR_INCLUDE_BUF_UTIL_H_ */ diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index a31f2f327ea1f..daff9f22b7c51 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -14,11 +14,6 @@ /* * TODO: - * - * - Use server / security object instance 0 for initial connection - * - Add DNS support for security uri parsing - * - BOOTSTRAP/DTLS cleanup - * - Handle WRITE_ATTRIBUTES (pmin=10&pmax=60) * - Handle Resource ObjLink type */ @@ -37,12 +32,15 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include #include -#include -#include -#include -#include +#include +#include +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +#include +#endif +#if defined(CONFIG_DNS_RESOLVER) +#include +#endif #include "lwm2m_object.h" #include "lwm2m_engine.h" @@ -79,10 +77,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define REG_PREFACE "" #endif -#if defined(CONFIG_NET_APP_DTLS) -#define INSTANCE_INFO "Zephyr DTLS LwM2M-client" -#endif - #if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN) #define COAP_OPTION_BUF_LEN (CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE + 1) #else @@ -125,7 +119,7 @@ static struct observe_node observe_node_data[CONFIG_LWM2M_ENGINE_MAX_OBSERVER]; struct service_node { sys_snode_t node; - void (*service_fn)(void); + struct k_work service_work; u32_t min_call_period; u64_t last_timestamp; }; @@ -137,6 +131,16 @@ static sys_slist_t engine_obj_inst_list; static sys_slist_t engine_observer_list; static sys_slist_t engine_service_list; +static K_THREAD_STACK_DEFINE(engine_thread_stack, + CONFIG_LWM2M_ENGINE_STACK_SIZE); +static struct k_thread engine_thread_data; + +#define MAX_POLL_FD CONFIG_NET_SOCKETS_POLL_MAX + +static struct lwm2m_ctx *sock_ctx[MAX_POLL_FD]; +static struct pollfd sock_fds[MAX_POLL_FD]; +static int sock_nfds; + #define NUM_BLOCK1_CONTEXT CONFIG_LWM2M_NUM_BLOCK1_CONTEXT /* TODO: figure out what's correct value */ @@ -162,10 +166,7 @@ static const u8_t LWM2M_ATTR_LEN[] = { 4, 4, 2, 2, 2 }; static struct lwm2m_attr write_attr_pool[CONFIG_LWM2M_NUM_ATTR]; -/* periodic / notify / observe handling stack */ -static K_THREAD_STACK_DEFINE(engine_thread_stack, - CONFIG_LWM2M_ENGINE_STACK_SIZE); -static struct k_thread engine_thread_data; +static struct k_delayed_work periodic_work; static struct lwm2m_engine_obj *get_engine_obj(int obj_id); static struct lwm2m_engine_obj_inst *get_engine_obj_inst(int obj_id, @@ -415,7 +416,6 @@ static int engine_add_observer(struct lwm2m_message *msg, struct lwm2m_engine_obj_field *obj_field = NULL; struct lwm2m_engine_obj_inst *obj_inst = NULL; struct observe_node *obs; - struct sockaddr *addr; struct notification_attrs attrs = { .flags = BIT(LWM2M_ATTR_PMIN) || BIT(LWM2M_ATTR_PMAX), .pmin = DEFAULT_SERVER_PMIN, @@ -434,9 +434,6 @@ static int engine_add_observer(struct lwm2m_message *msg, return -EINVAL; } - /* remote addr */ - addr = &msg->ctx->net_app_ctx.default_ctx->remote; - /* TODO: get server object for default pmin/pmax * and observe dup checking */ @@ -453,7 +450,7 @@ static int engine_add_observer(struct lwm2m_message *msg, LOG_DBG("OBSERVER DUPLICATE %u/%u/%u(%u) [%s]", msg->path.obj_id, msg->path.obj_inst_id, msg->path.res_id, msg->path.level, - lwm2m_sprint_ip_addr(addr)); + lwm2m_sprint_ip_addr(&msg->ctx->remote_addr)); return 0; } @@ -553,7 +550,8 @@ static int engine_add_observer(struct lwm2m_message *msg, LOG_DBG("OBSERVER ADDED %u/%u/%u(%u) token:'%s' addr:%s", msg->path.obj_id, msg->path.obj_inst_id, msg->path.res_id, msg->path.level, - sprint_token(token, tkl), lwm2m_sprint_ip_addr(addr)); + sprint_token(token, tkl), + lwm2m_sprint_ip_addr(&msg->ctx->remote_addr)); return 0; } @@ -748,9 +746,6 @@ int lwm2m_create_obj_inst(u16_t obj_id, u16_t obj_inst_id, } } -#ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT - engine_trigger_update(); -#endif return 0; } @@ -795,9 +790,6 @@ int lwm2m_delete_obj_inst(u16_t obj_id, u16_t obj_inst_id) clear_attrs(obj_inst); (void)memset(obj_inst, 0, sizeof(struct lwm2m_engine_obj_inst)); -#ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT - engine_trigger_update(); -#endif return ret; } @@ -949,10 +941,6 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release) if (release) { (void)memset(msg, 0, sizeof(*msg)); } else { - if (msg->cpkt.pkt) { - net_pkt_unref(msg->cpkt.pkt); - } - msg->message_timeout_cb = NULL; (void)memset(&msg->cpkt, 0, sizeof(msg->cpkt)); } @@ -960,9 +948,6 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release) int lwm2m_init_message(struct lwm2m_message *msg) { - struct net_pkt *pkt; - struct net_app_ctx *app_ctx; - struct net_buf *frag; u8_t tokenlen = 0U; u8_t *token = NULL; int r = 0; @@ -972,20 +957,6 @@ int lwm2m_init_message(struct lwm2m_message *msg) return -EINVAL; } - app_ctx = &msg->ctx->net_app_ctx; - pkt = net_app_get_net_pkt(app_ctx, AF_UNSPEC, BUF_ALLOC_TIMEOUT); - if (!pkt) { - LOG_ERR("Unable to get TX packet, not enough memory."); - return -ENOMEM; - } - - frag = net_app_get_net_buf(app_ctx, pkt, BUF_ALLOC_TIMEOUT); - if (!frag) { - LOG_ERR("Unable to get DATA buffer, not enough memory."); - r = -ENOMEM; - goto cleanup; - } - /* * msg->tkl == 0 is for a new TOKEN * msg->tkl == LWM2M_MSG_TOKEN_LEN_SKIP means dont set @@ -998,8 +969,8 @@ int lwm2m_init_message(struct lwm2m_message *msg) token = msg->token; } - r = coap_packet_init(&msg->cpkt, pkt, 1, msg->type, - tokenlen, token, msg->code, + r = coap_packet_init(&msg->cpkt, msg->msg_data, sizeof(msg->msg_data), + 1, msg->type, tokenlen, token, msg->code, (msg->mid > 0 ? msg->mid : coap_next_id())); if (r < 0) { LOG_ERR("coap packet init error (err:%d)", r); @@ -1021,8 +992,7 @@ int lwm2m_init_message(struct lwm2m_message *msg) goto cleanup; } - r = coap_pending_init(msg->pending, &msg->cpkt, - &app_ctx->default_ctx->remote); + r = coap_pending_init(msg->pending, &msg->cpkt, &msg->ctx->remote_addr); if (r < 0) { LOG_ERR("Unable to initialize a pending " "retransmission (err:%d).", r); @@ -1048,9 +1018,6 @@ int lwm2m_init_message(struct lwm2m_message *msg) cleanup: lwm2m_reset_message(msg, true); - if (pkt) { - net_pkt_unref(pkt); - } return r; } @@ -1065,17 +1032,12 @@ int lwm2m_send_message(struct lwm2m_message *msg) } if (msg->type == COAP_TYPE_CON) { - /* - * Increase packet ref count to avoid being unref after - * net_app_send_pkt() - */ coap_pending_cycle(msg->pending); } msg->send_attempts++; - ret = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->cpkt.pkt, - &msg->ctx->net_app_ctx.default_ctx->remote, - NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); + + ret = send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); if (ret < 0) { if (msg->type == COAP_TYPE_CON) { coap_pending_clear(msg->pending); @@ -1209,6 +1171,13 @@ static int select_reader(struct lwm2m_input_context *in, u16_t format) in->reader = &oma_tlv_reader; break; +#ifdef CONFIG_LWM2M_RW_JSON_SUPPORT + case LWM2M_FORMAT_OMA_JSON: + case LWM2M_FORMAT_OMA_OLD_JSON: + in->reader = &json_reader; + break; +#endif + default: LOG_WRN("Unknown content type %u", format); return -ENOMSG; @@ -2090,9 +2059,8 @@ size_t lwm2m_engine_get_opaque_more(struct lwm2m_input_context *in, *last_block = true; } - in->frag = net_frag_read(in->frag, in->offset, &in->offset, in_len, - buf); - if (!in->frag && in->offset == 0xffff) { + if (buf_read(buf, in_len, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { *last_block = true; return 0; } @@ -2114,6 +2082,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, @@ -2145,17 +2118,17 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_obj_field *obj_field, struct lwm2m_message *msg) { - s64_t temp64 = 0; - s32_t temp32 = 0; + struct block_context *block_ctx = NULL; void *data_ptr = NULL; size_t data_len = 0; size_t len = 0; size_t total_size = 0; + s64_t temp64 = 0; + s32_t temp32 = 0; int ret = 0; - u8_t tkl = 0U; u8_t token[8]; + u8_t tkl = 0U; bool last_block = true; - struct block_context *block_ctx = NULL; if (!obj_inst || !res || !obj_field || !msg) { return -EINVAL; @@ -2658,12 +2631,20 @@ static int lwm2m_exec_handler(struct lwm2m_engine_obj *obj, static int lwm2m_delete_handler(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg) { + int ret; + if (!msg) { return -EINVAL; } - return lwm2m_delete_obj_inst(msg->path.obj_id, - msg->path.obj_inst_id); + ret = lwm2m_delete_obj_inst(msg->path.obj_id, msg->path.obj_inst_id); +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT) + if (!ret && !msg->ctx->bootstrap_mode) { + engine_trigger_update(); + } +#endif + + return ret; } static int do_read_op(struct lwm2m_engine_obj *obj, @@ -2701,7 +2682,6 @@ int lwm2m_perform_read_op(struct lwm2m_engine_obj *obj, struct lwm2m_engine_obj_field *obj_field; struct lwm2m_obj_path temp_path; int ret = 0, index; - u16_t temp_len; u8_t num_read = 0U; if (msg->path.level >= 2) { @@ -2733,10 +2713,6 @@ int lwm2m_perform_read_op(struct lwm2m_engine_obj *obj, /* store original path values so we can change them during processing */ memcpy(&temp_path, &msg->path, sizeof(temp_path)); - msg->out.frag = coap_packet_get_payload(msg->out.out_cpkt, - &msg->out.offset, - &temp_len); - msg->out.offset++; engine_put_begin(&msg->out, &msg->path); while (obj_inst) { @@ -2832,10 +2808,11 @@ int lwm2m_perform_read_op(struct lwm2m_engine_obj *obj, return ret; } -static int print_attr(struct net_pkt *pkt, char *buf, u16_t buflen, void *ref) +static int print_attr(struct lwm2m_output_context *out, + u8_t *buf, u16_t buflen, void *ref) { struct lwm2m_attr *attr; - int i, used, base; + int i, used, base, ret; u8_t digit; s32_t fraction; @@ -2865,8 +2842,9 @@ static int print_attr(struct net_pkt *pkt, char *buf, u16_t buflen, void *ref) base /= 10; } - if (!net_pkt_append_all(pkt, used, buf, BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, used); + if (ret < 0) { + return ret; } } @@ -2879,14 +2857,13 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) struct lwm2m_engine_obj *obj; struct lwm2m_engine_obj_inst *obj_inst; int ret; - 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 (!msg->ctx->bootstrap_mode && !well_known && (msg->path.level == 0 || (msg->path.level > 0 && msg->path.obj_id == LWM2M_OBJECT_SECURITY_ID))) { @@ -2907,45 +2884,44 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) return ret; } - msg->out.frag = coap_packet_get_payload(msg->out.out_cpkt, &msg->out.offset, - &temp_len); - msg->out.offset++; - /* Handle CoAP .well-known/core discover */ if (well_known) { /* */ - if (!net_pkt_append_all(msg->out.out_cpkt->pkt, - strlen(WELL_KNOWN_CORE_PATH), - WELL_KNOWN_CORE_PATH, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), + WELL_KNOWN_CORE_PATH, + strlen(WELL_KNOWN_CORE_PATH)); + if (ret < 0) { + return ret; } SYS_SLIST_FOR_EACH_CONTAINER(&engine_obj_list, obj, node) { snprintk(disc_buf, sizeof(disc_buf), ",", obj->obj_id); - if (!net_pkt_append_all(msg->out.out_cpkt->pkt, - strlen(disc_buf), disc_buf, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + + ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), + disc_buf, strlen(disc_buf)); + if (ret < 0) { + return ret; } } return 0; } - /* TODO: 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" + /* + * lwm2m spec 20170208-A sec 5.2.7.3 bootstrap discover on "/" + * - (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 ((!msg->ctx->bootstrap_mode && + obj_inst->obj->obj_id == LWM2M_OBJECT_SECURITY_ID) || obj_inst->obj->obj_id != msg->path.obj_id) { continue; } @@ -2954,15 +2930,15 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) snprintk(disc_buf, sizeof(disc_buf), "%s", reported ? "," : "", obj_inst->obj->obj_id); - if (!net_pkt_append_all(msg->out.out_cpkt->pkt, - strlen(disc_buf), disc_buf, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + + ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), + disc_buf, strlen(disc_buf)); + if (ret < 0) { + return ret; } /* report object attrs (5.4.2) */ - ret = print_attr(msg->out.out_cpkt->pkt, - disc_buf, sizeof(disc_buf), + ret = print_attr(&msg->out, disc_buf, sizeof(disc_buf), obj_inst->obj); if (ret < 0) { return ret; @@ -2981,15 +2957,15 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) snprintk(disc_buf, sizeof(disc_buf), "%s", reported ? "," : "", obj_inst->obj->obj_id, obj_inst->obj_inst_id); - if (!net_pkt_append_all(msg->out.out_cpkt->pkt, - strlen(disc_buf), disc_buf, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + + ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), + disc_buf, strlen(disc_buf)); + if (ret < 0) { + return ret; } /* report object instance attrs (5.4.2) */ - ret = print_attr(msg->out.out_cpkt->pkt, - disc_buf, sizeof(disc_buf), + ret = print_attr(&msg->out, disc_buf, sizeof(disc_buf), obj_inst); if (ret < 0) { return ret; @@ -2998,6 +2974,11 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) reported = true; } + /* don't return resource info for bootstrap discovery */ + if (msg->ctx->bootstrap_mode) { + continue; + } + for (int i = 0; i < obj_inst->resource_count; i++) { /* skip unrelated resources */ if (msg->path.level == 3 && @@ -3011,15 +2992,16 @@ static int do_discover_op(struct lwm2m_message *msg, bool well_known) obj_inst->obj->obj_id, obj_inst->obj_inst_id, obj_inst->resources[i].res_id); - if (!net_pkt_append_all(msg->out.out_cpkt->pkt, - strlen(disc_buf), disc_buf, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + + ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), + disc_buf, strlen(disc_buf)); + if (ret < 0) { + return ret; } /* report resource attrs when path > 1 (5.4.2) */ if (msg->path.level > 1) { - ret = print_attr(msg->out.out_cpkt->pkt, + ret = print_attr(&msg->out, disc_buf, sizeof(disc_buf), &obj_inst->resources[i]); if (ret < 0) { @@ -3058,6 +3040,12 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg, if (created) { *created = 1U; } + +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT) + if (!msg->ctx->bootstrap_mode) { + engine_trigger_update(); + } +#endif } return ret; @@ -3091,6 +3079,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) { @@ -3105,6 +3116,7 @@ static int handle_request(struct coap_packet *request, bool well_known = false; struct block_context *block_ctx = NULL; enum coap_block_size block_size; + u16_t payload_len = 0U; bool last_block = false; /* set CoAP request / message */ @@ -3128,14 +3140,31 @@ static int handle_request(struct coap_packet *request, r = coap_find_options(msg->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 (msg->ctx->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; + } } /* check for .well-known/core URI query (DISCOVER) */ @@ -3250,9 +3279,8 @@ static int handle_request(struct coap_packet *request, } /* setup incoming data */ - msg->in.frag = coap_packet_get_payload(msg->in.in_cpkt, - &msg->in.offset, - &msg->in.payload_len); + msg->in.offset = msg->in.in_cpkt->hdr_len + msg->in.in_cpkt->opt_len; + coap_packet_get_payload(msg->in.in_cpkt, &payload_len); /* Check for block transfer */ r = get_option_int(msg->in.in_cpkt, COAP_OPTION_BLOCK1); @@ -3262,8 +3290,7 @@ static int handle_request(struct coap_packet *request, /* RFC7252: 4.6. Message Size */ block_size = GET_BLOCK_SIZE(r); if (!last_block && - coap_block_size_to_bytes(block_size) > - msg->in.payload_len) { + coap_block_size_to_bytes(block_size) > payload_len) { LOG_DBG("Trailing payload is discarded!"); r = -EFBIG; goto error; @@ -3415,49 +3442,23 @@ static int handle_request(struct coap_packet *request, return 0; } -void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, - bool handle_separate_response, - udp_request_handler_cb_t udp_request_handler) +static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, + u8_t *buf, u16_t buf_len, + struct sockaddr *from_addr, + udp_request_handler_cb_t udp_request_handler) { struct lwm2m_message *msg = NULL; - struct net_udp_hdr hdr, *udp_hdr; struct coap_pending *pending; struct coap_reply *reply; struct coap_packet response; - struct sockaddr from_addr; int r; u8_t token[8]; u8_t tkl; - udp_hdr = net_udp_get_hdr(pkt, &hdr); - if (!udp_hdr) { - LOG_ERR("Invalid UDP data"); - return; - } - - /* Save the from address */ -#if defined(CONFIG_NET_IPV6) - if (net_pkt_family(pkt) == AF_INET6) { - net_ipaddr_copy(&net_sin6(&from_addr)->sin6_addr, - &NET_IPV6_HDR(pkt)->src); - net_sin6(&from_addr)->sin6_port = udp_hdr->src_port; - net_sin6(&from_addr)->sin6_family = AF_INET6; - } -#endif - -#if defined(CONFIG_NET_IPV4) - if (net_pkt_family(pkt) == AF_INET) { - net_ipaddr_copy(&net_sin(&from_addr)->sin_addr, - &NET_IPV4_HDR(pkt)->src); - net_sin(&from_addr)->sin_port = udp_hdr->src_port; - net_sin(&from_addr)->sin_family = AF_INET; - } -#endif - - r = coap_packet_parse(&response, pkt, NULL, 0); + r = coap_packet_parse(&response, buf, buf_len, NULL, 0); if (r < 0) { LOG_ERR("Invalid data received (err:%d)", r); - goto cleanup; + return; } tkl = coap_header_get_token(&response, token); @@ -3471,14 +3472,11 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, */ if (pending) { msg = find_msg(pending, NULL); - if (msg) { - msg->pending = NULL; - } } LOG_DBG("checking for reply from [%s]", - lwm2m_sprint_ip_addr(&from_addr)); - reply = coap_response_received(&response, &from_addr, + lwm2m_sprint_ip_addr(from_addr)); + reply = coap_response_received(&response, from_addr, client_ctx->replies, CONFIG_LWM2M_ENGINE_MAX_REPLIES); if (reply) { @@ -3492,10 +3490,10 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, * token id for all notifications), we have to use an * additional flag to decide when to clear the reply callback. */ - if (handle_separate_response && !tkl && + if (client_ctx->handle_separate_response && !tkl && coap_header_get_type(&response) == COAP_TYPE_ACK) { LOG_DBG("separated response, not removing reply"); - goto cleanup; + return; } if (!msg) { @@ -3509,7 +3507,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, /* reset reply->user_data for next time */ reply->user_data = (void *)COAP_REPLY_STATUS_NONE; LOG_DBG("reply %p NOT removed", reply); - goto cleanup; + return; } /* free up msg resources */ @@ -3518,7 +3516,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, } LOG_DBG("reply %p handled and removed", reply); - goto cleanup; + return; } /* @@ -3531,7 +3529,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, msg = lwm2m_get_message(client_ctx); if (!msg) { LOG_ERR("Unable to get a lwm2m message!"); - goto cleanup; + return; } /* Create a response message if we reach this point */ @@ -3544,7 +3542,7 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, /* process the response to this request */ r = udp_request_handler(&response, msg); if (r < 0) { - goto cleanup; + return; } r = lwm2m_send_message(msg); @@ -3555,21 +3553,6 @@ void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, } else { LOG_ERR("No handler for response"); } - -cleanup: - if (pkt) { - net_pkt_unref(pkt); - } -} - -static void udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, - int status, void *user_data) -{ - struct lwm2m_ctx *client_ctx = CONTAINER_OF(app_ctx, - struct lwm2m_ctx, - net_app_ctx); - - lwm2m_udp_receive(client_ctx, pkt, false, handle_request); } static void retransmit_request(struct k_work *work) @@ -3608,20 +3591,10 @@ static void retransmit_request(struct k_work *work) LOG_DBG("Resending message: %p", msg); msg->send_attempts++; - /* - * Don't use lwm2m_send_message() because it calls - * coap_pending_cycle() / coap_pending_cycle() in a different order - * and under different circumstances. It also does it's own ref / - * unref of the net_pkt. Keep it simple and call net_app_send_pkt() - * directly here. - */ - r = net_app_send_pkt(&msg->ctx->net_app_ctx, msg->cpkt.pkt, - &msg->ctx->net_app_ctx.default_ctx->remote, - NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL); + r = send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0); if (r < 0) { LOG_ERR("Error sending lwm2m message: %d", r); /* don't error here, retry until timeout */ - net_pkt_unref(msg->cpkt.pkt); } k_delayed_work_submit(&client_ctx->retransmit_work, pending->timeout); @@ -3687,8 +3660,7 @@ static int generate_notify_message(struct observe_node *obs, obs->path.res_id, obs->path.level, sprint_token(obs->token, obs->tkl), - lwm2m_sprint_ip_addr( - &obs->ctx->net_app_ctx.default_ctx->remote), + lwm2m_sprint_ip_addr(&obs->ctx->remote_addr), k_uptime_get()); obj_inst = get_engine_obj_inst(obs->path.obj_id, @@ -3754,10 +3726,6 @@ s32_t engine_next_service_timeout_ms(u32_t max_timeout) u32_t timeout = max_timeout; SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - if (!srv->service_fn) { - continue; - } - time_left_ms = srv->last_timestamp + K_MSEC(srv->min_call_period); @@ -3776,13 +3744,13 @@ s32_t engine_next_service_timeout_ms(u32_t max_timeout) return timeout; } -int lwm2m_engine_add_service(void (*service)(void), u32_t period_ms) +int lwm2m_engine_add_service(k_work_handler_t service, u32_t period_ms) { int i; /* find an unused service index node */ for (i = 0; i < MAX_PERIODIC_SERVICE; i++) { - if (!service_node_data[i].service_fn) { + if (!service_node_data[i].service_work.handler) { break; } } @@ -3791,9 +3759,9 @@ int lwm2m_engine_add_service(void (*service)(void), u32_t period_ms) return -ENOMEM; } - service_node_data[i].service_fn = service; + k_work_init(&service_node_data[i].service_work, service); service_node_data[i].min_call_period = period_ms; - service_node_data[i].last_timestamp = 0U; + service_node_data[i].last_timestamp = 0; sys_slist_append(&engine_service_list, &service_node_data[i].node); @@ -3801,62 +3769,75 @@ int lwm2m_engine_add_service(void (*service)(void), u32_t period_ms) return 0; } -/* TODO: this needs to be triggered via work_queue */ -static void lwm2m_engine_service(void) +static void lwm2m_engine_service(struct k_work *work) { struct observe_node *obs; struct service_node *srv; s64_t timestamp, service_due_timestamp; + s32_t sleep_ms; + int ret; - while (true) { + /* + * 1. scan the observer list + * 2. For each notify event found, scan the observer list + * 3. For each observer match, generate a NOTIFY message, + * attaching the notify response handler + */ + timestamp = k_uptime_get(); + SYS_SLIST_FOR_EACH_CONTAINER(&engine_observer_list, obs, node) { /* - * 1. scan the observer list - * 2. For each notify event found, scan the observer list - * 3. For each observer match, generate a NOTIFY message, - * attaching the notify response handler + * manual notify requirements: + * - event_timestamp > last_timestamp + * - current timestamp > last_timestamp + min_period_sec */ - timestamp = k_uptime_get(); - SYS_SLIST_FOR_EACH_CONTAINER(&engine_observer_list, obs, node) { - /* - * manual notify requirements: - * - event_timestamp > last_timestamp - * - current timestamp > last_timestamp + min_period_sec - */ - if (obs->event_timestamp > obs->last_timestamp && - timestamp > obs->last_timestamp + - K_SECONDS(obs->min_period_sec)) { - obs->last_timestamp = k_uptime_get(); - generate_notify_message(obs, true); - - /* - * automatic time-based notify requirements: - * - current timestamp > last_timestamp + max_period_sec - */ - } else if (timestamp > obs->last_timestamp + - K_SECONDS(obs->min_period_sec)) { - obs->last_timestamp = k_uptime_get(); - generate_notify_message(obs, false); - } + if (obs->event_timestamp > obs->last_timestamp && + timestamp > obs->last_timestamp + + K_SECONDS(obs->min_period_sec)) { + obs->last_timestamp = k_uptime_get(); + generate_notify_message(obs, true); + /* + * automatic time-based notify requirements: + * - current timestamp > last_timestamp + max_period_sec + */ + } else if (timestamp > obs->last_timestamp + + K_SECONDS(obs->min_period_sec)) { + obs->last_timestamp = k_uptime_get(); + generate_notify_message(obs, false); } - timestamp = k_uptime_get(); - SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { - if (!srv->service_fn) { - continue; - } + } - service_due_timestamp = srv->last_timestamp + - K_MSEC(srv->min_call_period); - /* service is due */ - if (timestamp > service_due_timestamp) { - srv->last_timestamp = k_uptime_get(); - srv->service_fn(); - } + timestamp = k_uptime_get(); + SYS_SLIST_FOR_EACH_CONTAINER(&engine_service_list, srv, node) { + service_due_timestamp = srv->last_timestamp + + K_MSEC(srv->min_call_period); + /* service is due */ + if (timestamp > service_due_timestamp) { + srv->last_timestamp = k_uptime_get(); + k_work_submit(&srv->service_work); } + } - /* calculate how long to sleep till the next service */ - k_sleep(engine_next_service_timeout_ms(ENGINE_UPDATE_INTERVAL)); + /* calculate how long to sleep till the next service */ + sleep_ms = engine_next_service_timeout_ms(ENGINE_UPDATE_INTERVAL); + ret = k_delayed_work_submit(&periodic_work, sleep_ms); + if (ret < 0) { + LOG_ERR("Work submit error:%d", ret); + } +} + +int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx) +{ + int sock_fd = client_ctx->sock_fd; + + k_delayed_work_cancel(&client_ctx->retransmit_work); + lwm2m_socket_del(client_ctx); + client_ctx->sock_fd = -1; + if (sock_fd >= 0) { + return close(sock_fd); + } else { + return 0; } } @@ -3865,114 +3846,363 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request); } -#if defined(CONFIG_NET_APP_DTLS) -static int setup_cert(struct net_app_ctx *app_ctx, void *cert) +/* LwM2M Socket Integration */ + +int lwm2m_socket_add(struct lwm2m_ctx *ctx) { -#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) - struct lwm2m_ctx *client_ctx = CONTAINER_OF(app_ctx, - struct lwm2m_ctx, - net_app_ctx); - 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); -#else + int i; + + if (sock_nfds < MAX_POLL_FD) { + i = sock_nfds++; + } else { + for (i = 0; i < MAX_POLL_FD; i++) { + if (sock_ctx[i] == NULL) { + goto found; + } + } + + return -ENOMEM; + } + +found: + sock_ctx[i] = ctx; + sock_fds[i].fd = ctx->sock_fd; + sock_fds[i].events = POLLIN; return 0; -#endif } -#endif /* CONFIG_NET_APP_DTLS */ -int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port) +void lwm2m_socket_del(struct lwm2m_ctx *ctx) +{ + for (int i = 0; i < sock_nfds; i++) { + if (sock_ctx[i] == ctx) { + sock_ctx[i] = NULL; + sock_fds[i].fd = -1; + sock_nfds--; + break; + } + } +} + +/* LwM2M main work loop */ + +static void socket_receive_loop(void) +{ + static u8_t in_buf[NET_IPV6_MTU]; + static struct sockaddr from_addr; + socklen_t from_addr_len; + ssize_t len; + int i; + + from_addr_len = sizeof(from_addr); + while (1) { + /* wait for sockets */ + if (sock_nfds < 1) { + k_sleep(ENGINE_UPDATE_INTERVAL); + continue; + } + + /* + * FIXME: Currently we timeout and restart poll in case fds + * were modified. + */ + if (poll(sock_fds, sock_nfds, ENGINE_UPDATE_INTERVAL) < 0) { + LOG_ERR("Error in poll:%d", errno); + errno = 0; + k_sleep(ENGINE_UPDATE_INTERVAL); + continue; + } + + for (i = 0; i < sock_nfds; i++) { + if (sock_fds[i].revents & POLLERR) { + LOG_ERR("Error in poll.. waiting a moment."); + k_sleep(ENGINE_UPDATE_INTERVAL); + continue; + } + + if (!(sock_fds[i].revents & POLLIN) || + sock_ctx[i] == NULL) { + sock_fds[i].revents = 0; + continue; + } + + sock_fds[i].revents = 0; + len = recvfrom(sock_ctx[i]->sock_fd, in_buf, + sizeof(in_buf) - 1, 0, + &from_addr, &from_addr_len); + if (errno) { + LOG_ERR("Sock RECV error: %d", errno); + /* TODO: handle error? */ + continue; + } + + if (len < 0) { + LOG_ERR("Error reading response: %d", errno); + continue; + } + + if (len == 0) { + LOG_ERR("Zero length recv"); + continue; + } + + in_buf[len] = 0; + + lwm2m_udp_receive(sock_ctx[i], in_buf, len, &from_addr, + handle_request); + } + } +} + +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) +static int load_tls_credential(struct lwm2m_ctx *client_ctx, u16_t res_id, + enum tls_credential_type type) { - struct sockaddr client_addr; int ret = 0; + void *cred = NULL; + u16_t cred_len; + u8_t cred_flags; + char pathstr[MAX_RESOURCE_LEN]; - /* TODO: use security object for initial setup */ + /* ignore error value */ + tls_credential_delete(client_ctx->tls_tag, type); - /* setup the local client port */ - (void)memset(&client_addr, 0, sizeof(client_addr)); -#if defined(CONFIG_NET_IPV6) - client_addr.sa_family = AF_INET6; - net_sin6(&client_addr)->sin6_port = htons(CONFIG_LWM2M_LOCAL_PORT); -#elif defined(CONFIG_NET_IPV4) - client_addr.sa_family = AF_INET; - net_sin(&client_addr)->sin_port = htons(CONFIG_LWM2M_LOCAL_PORT); -#endif + snprintk(pathstr, sizeof(pathstr), "0/%d/%u", client_ctx->sec_obj_inst, + res_id); - ret = net_app_init_udp_client(&client_ctx->net_app_ctx, - &client_addr, NULL, - peer_str, - peer_port, - client_ctx->net_init_timeout, - client_ctx); - if (ret) { - LOG_ERR("net_app_init_udp_client err:%d", ret); - goto error_start; + ret = lwm2m_engine_get_res_data(pathstr, &cred, &cred_len, &cred_flags); + if (ret < 0) { + LOG_ERR("Unable to get resource data for '%s'", pathstr); + return ret; } - lwm2m_engine_context_init(client_ctx); + /* Set correct PSK_ID length */ + if (type == TLS_CREDENTIAL_PSK_ID) { + cred_len = strlen(cred); + } - /* set net_app callbacks */ - ret = net_app_set_cb(&client_ctx->net_app_ctx, - NULL, udp_receive, NULL, NULL); - if (ret) { - LOG_ERR("Could not set receive callback (err:%d)", ret); - goto error_start; - } - -#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); + ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len); if (ret < 0) { - LOG_ERR("Cannot init DTLS (%d)", ret); - goto error_start; + LOG_ERR("Unable to get resource data for '%s'", pathstr); + } + + return ret; +} +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + +int lwm2m_socket_start(struct lwm2m_ctx *client_ctx) +{ +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + int ret; + + ret = load_tls_credential(client_ctx, 3, TLS_CREDENTIAL_PSK_ID); + if (ret < 0) { + return ret; } -#endif - ret = net_app_connect(&client_ctx->net_app_ctx, - client_ctx->net_timeout); + ret = load_tls_credential(client_ctx, 5, TLS_CREDENTIAL_PSK); if (ret < 0) { - LOG_ERR("Cannot connect UDP (%d)", ret); - goto error_start; + return ret; + } + + if (client_ctx->use_dtls) { + client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family, + SOCK_DGRAM, IPPROTO_DTLS_1_2); + } else +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + { + client_ctx->sock_fd = socket(client_ctx->remote_addr.sa_family, + SOCK_DGRAM, IPPROTO_UDP); } + if (client_ctx->sock_fd < 0) { + LOG_ERR("Failed to create socket: %d", errno); + return -errno; + } + +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + if (client_ctx->use_dtls) { + sec_tag_t tls_tag_list[] = { + client_ctx->tls_tag, + }; + + ret = setsockopt(client_ctx->sock_fd, SOL_TLS, TLS_SEC_TAG_LIST, + tls_tag_list, sizeof(tls_tag_list)); + if (ret < 0) { + LOG_ERR("Failed to set TLS_SEC_TAG_LIST option: %d", + errno); + lwm2m_engine_context_close(client_ctx); + return -errno; + } + } +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + + if (connect(client_ctx->sock_fd, &client_ctx->remote_addr, + NET_SOCKADDR_MAX_SIZE) < 0) { + LOG_ERR("Cannot connect UDP (-%d)", errno); + lwm2m_engine_context_close(client_ctx); + return -errno; + } + + lwm2m_socket_add(client_ctx); return 0; +} -error_start: - net_app_close(&client_ctx->net_app_ctx); - net_app_release(&client_ctx->net_app_ctx); +int lwm2m_parse_peerinfo(char *url, struct sockaddr *addr, bool *use_dtls) +{ + struct http_parser_url parser; +#if defined(CONFIG_DNS_RESOLVER) + struct addrinfo hints, *res; +#endif + int ret; + u16_t off, len; + u8_t tmp; + + http_parser_url_init(&parser); + ret = http_parser_parse_url(url, strlen(url), 0, &parser); + if (ret < 0) { + LOG_ERR("Invalid url: %s", url); + return -ENOTSUP; + } + + off = parser.field_data[UF_SCHEMA].off; + len = parser.field_data[UF_SCHEMA].len; + + /* check for supported protocol */ + if (strncmp(url + off, "coaps", len) != 0) { + return -EPROTONOSUPPORT; + } + + /* check for DTLS requirement */ + *use_dtls = false; + if (len == 5 && strncmp(url + off, "coaps", len) == 0) { +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + *use_dtls = true; +#else + return -EPROTONOSUPPORT; +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + } + + if (!(parser.field_set & (1 << UF_PORT))) { + /* Set to default port of CoAP */ + parser.port = CONFIG_LWM2M_PEER_PORT; + } + + off = parser.field_data[UF_HOST].off; + len = parser.field_data[UF_HOST].len; + + /* truncate host portion */ + tmp = url[off + len]; + url[off + len] = '\0'; + + /* initialize addr */ + (void)memset(addr, 0, sizeof(*addr)); + + /* try and set IP address directly */ + ret = -EINVAL; + +#if defined(CONFIG_NET_IPV6) + addr->sa_family = AF_INET6; + ret = net_addr_pton(AF_INET6, url + off, + &((struct sockaddr_in6 *)addr)->sin6_addr); +#endif /* CONFIG_NET_IPV6 */ + +#if defined(CONFIG_NET_IPV4) + if (ret < 0) { + addr->sa_family = AF_INET; + ret = net_addr_pton(AF_INET, url + off, + &((struct sockaddr_in *)addr)->sin_addr); + } +#endif /* CONFIG_NET_IPV4 */ + + if (ret < 0) { +#if defined(CONFIG_DNS_RESOLVER) +#if defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4) + hints.ai_family = AF_UNSPEC; +#elif defined(CONFIG_NET_IPV6) + hints.ai_family = AF_INET6; +#else + hints.ai_family = AF_INET; +#endif /* defined(CONFIG_NET_IPV6) && defined(CONFIG_NET_IPV4) */ + hints.ai_socktype = SOCK_DGRAM; + ret = getaddrinfo(url + off, NULL, &hints, &res); + if (ret != 0) { + LOG_ERR("Unable to resolve address"); + /* DNS error codes don't align with normal errors */ + ret = -ENOENT; + goto cleanup; + } + + memcpy(addr, res->ai_addr, sizeof(*addr)); + addr->sa_family = res->ai_family; + free(res); +#else + goto cleanup; +#endif /* CONFIG_DNS_RESOLVER */ + } + + /* set port */ + if (addr->sa_family == AF_INET6) { + net_sin6(addr)->sin6_port = htons(parser.port); + } else if (addr->sa_family == AF_INET) { + net_sin(addr)->sin_port = htons(parser.port); + } else { + ret = -EPROTONOSUPPORT; + } + +cleanup: + /* restore host separator */ + url[off + len] = tmp; return ret; } +int lwm2m_engine_start(struct lwm2m_ctx *client_ctx) +{ + char pathstr[MAX_RESOURCE_LEN]; + char *url; + u16_t url_len; + u8_t url_data_flags; + int ret = 0U; + + /* get the server URL */ + snprintk(pathstr, sizeof(pathstr), "0/%d/0", client_ctx->sec_obj_inst); + ret = lwm2m_engine_get_res_data(pathstr, (void **)&url, &url_len, + &url_data_flags); + if (ret < 0) { + return ret; + } + + url[url_len] = '\0'; + ret = lwm2m_parse_peerinfo(url, &client_ctx->remote_addr, + &client_ctx->use_dtls); + if (ret < 0) { + return ret; + } + + lwm2m_engine_context_init(client_ctx); + return lwm2m_socket_start(client_ctx); +} + static int lwm2m_engine_init(struct device *dev) { (void)memset(block1_contexts, 0, sizeof(struct block_context) * NUM_BLOCK1_CONTEXT); - /* start thread to handle OBSERVER / NOTIFY events */ + /* start sock receive thread */ k_thread_create(&engine_thread_data, &engine_thread_stack[0], K_THREAD_STACK_SIZEOF(engine_thread_stack), - (k_thread_entry_t) lwm2m_engine_service, + (k_thread_entry_t) socket_receive_loop, NULL, NULL, NULL, /* Lowest priority cooperative thread */ K_PRIO_COOP(CONFIG_NUM_COOP_PRIORITIES - 1), 0, K_NO_WAIT); - k_thread_name_set(&engine_thread_data, "lwm2m"); + k_thread_name_set(&engine_thread_data, "lwm2m-sock-recv"); + LOG_DBG("LWM2M engine socket receive thread started"); + + k_delayed_work_init(&periodic_work, lwm2m_engine_service); + k_delayed_work_submit(&periodic_work, K_MSEC(2000)); + LOG_DBG("LWM2M engine periodic work started"); - LOG_DBG("LWM2M engine thread started"); return 0; } diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index be8cd25f299e5..5fa3ff4d83467 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -66,8 +66,13 @@ int lwm2m_get_or_create_engine_obj(struct lwm2m_message *msg, 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); +/* Message buffer functions */ +u8_t *lwm2m_get_message_buf(void); +int lwm2m_put_message_buf(u8_t *buf); + /* LwM2M message functions */ struct lwm2m_message *lwm2m_get_message(struct lwm2m_ctx *client_ctx); void lwm2m_reset_message(struct lwm2m_message *msg, bool release); @@ -84,13 +89,9 @@ int lwm2m_write_handler(struct lwm2m_engine_obj_inst *obj_inst, struct lwm2m_engine_obj_field *obj_field, struct lwm2m_message *msg); -void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt, - bool handle_separate_response, - udp_request_handler_cb_t udp_request_handler); - enum coap_block_size lwm2m_default_block_size(void); -int lwm2m_engine_add_service(void (*service)(void), u32_t period_ms); +int lwm2m_engine_add_service(k_work_handler_t service, u32_t period_ms); int lwm2m_engine_get_resource(char *pathstr, struct lwm2m_engine_res_inst **res); @@ -98,6 +99,9 @@ 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); +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); @@ -105,4 +109,10 @@ void lwm2m_firmware_set_update_result(u8_t result); u8_t lwm2m_firmware_get_update_result(void); #endif +/* Network Layer */ +int lwm2m_socket_add(struct lwm2m_ctx *ctx); +void lwm2m_socket_del(struct lwm2m_ctx *ctx); +int lwm2m_socket_start(struct lwm2m_ctx *client_ctx); +int lwm2m_parse_peerinfo(char *url, struct sockaddr *addr, bool *use_dtls); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_device.c b/subsys/net/lib/lwm2m/lwm2m_obj_device.c index 4fd06148e1919..b5277f4d2486f 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_device.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_device.c @@ -268,7 +268,7 @@ int lwm2m_device_add_err(u8_t error_code) return -ENOMEM; } -static void device_periodic_service(void) +static void device_periodic_service(struct k_work *work) { NOTIFY_OBSERVER(LWM2M_OBJECT_DEVICE_ID, 0, DEVICE_CURRENT_TIME_ID); } diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c index cd04ccaebfadf..7cd066a5f696a 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2018-2019 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ @@ -10,7 +11,6 @@ #include LOG_MODULE_REGISTER(LOG_MODULE_NAME); -#include #include #include @@ -156,12 +156,13 @@ void lwm2m_firmware_set_update_result(u8_t result) lwm2m_firmware_set_update_state(STATE_IDLE); break; case RESULT_UPDATE_FAILED: - if (update_state != STATE_UPDATING) { + if (update_state != STATE_DOWNLOADING && + update_state != STATE_UPDATING) { error = true; state = update_state; } - /* Next state could be idle or downloaded */ + lwm2m_firmware_set_update_state(STATE_IDLE); break; default: LOG_ERR("Unhandled result: %u", result); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index f8d0306eaf871..5e54aaab018a0 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2018-2019 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,26 +14,21 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include -#include -#include + #include -#include -#include +#include #include "lwm2m_object.h" #include "lwm2m_engine.h" #define URI_LEN 255 -#define BUF_ALLOC_TIMEOUT K_SECONDS(1) #define NETWORK_INIT_TIMEOUT K_SECONDS(10) #define NETWORK_CONNECT_TIMEOUT K_SECONDS(10) #define PACKET_TRANSFER_RETRY_MAX 3 static struct k_work firmware_work; static char firmware_uri[URI_LEN]; -static struct http_parser_url parsed_uri; static struct lwm2m_ctx firmware_ctx; static int firmware_retry; static struct coap_block_context firmware_block_ctx; @@ -46,13 +42,6 @@ static char proxy_uri[URI_LEN]; static void do_transmit_timeout_cb(struct lwm2m_message *msg); -static void -firmware_udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, - int status, void *user_data) -{ - lwm2m_udp_receive(&firmware_ctx, pkt, true, NULL); -} - static void set_update_result_from_error(int error_code) { if (error_code == -ENOMEM) { @@ -78,14 +67,11 @@ static int transfer_request(struct coap_block_context *ctx, { struct lwm2m_message *msg; int ret; - u16_t off; - u16_t len; char *cursor; #if !defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) - int i; - int path_len; -#else - char *uri_path; + struct http_parser_url parser; + u16_t off, len; + char *next_slash; #endif msg = lwm2m_get_message(&firmware_ctx); @@ -109,22 +95,11 @@ static int transfer_request(struct coap_block_context *ctx, } #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) - /* if path is not available, off/len will be zero */ - off = parsed_uri.field_data[UF_SCHEMA].off; - len = parsed_uri.field_data[UF_SCHEMA].len; - cursor = firmware_uri + off; - - /* TODO: convert to lower case */ - if (len < 4 || len > 5) { - ret = -EPROTONOSUPPORT; - LOG_ERR("Unsupported schema"); - goto cleanup; - } - - if (strncmp(cursor, (len == 4 ? "http" : "https"), len) == 0) { - uri_path = COAP2HTTP_PROXY_URI_PATH; - } else if (strncmp(cursor, (len == 4 ? "coap" : "coaps"), len) == 0) { - uri_path = COAP2COAP_PROXY_URI_PATH; + /* TODO: shift to lower case */ + if (strncmp(firmware_uri, "http", 4) == 0) { + cursor = COAP2HTTP_PROXY_URI_PATH; + } else if (strncmp(firmware_uri, "coap", 4) == 0) { + cursor = COAP2COAP_PROXY_URI_PATH; } else { ret = -EPROTONOSUPPORT; LOG_ERR("Unsupported schema"); @@ -132,50 +107,53 @@ static int transfer_request(struct coap_block_context *ctx, } ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - uri_path, strlen(uri_path)); + cursor, strlen(cursor)); if (ret < 0) { - LOG_ERR("Error adding URI_PATH '%s'", uri_path); + LOG_ERR("Error adding URI_PATH '%s'", cursor); goto cleanup; } #else + http_parser_url_init(&parser); + ret = http_parser_parse_url(firmware_uri, strlen(firmware_uri), 0, + &parser); + if (ret < 0) { + LOG_ERR("Invalid firmware url: %s", firmware_uri); + ret = -ENOTSUP; + goto cleanup; + } + /* if path is not available, off/len will be zero */ - off = parsed_uri.field_data[UF_PATH].off; - len = parsed_uri.field_data[UF_PATH].len; + off = parser.field_data[UF_PATH].off; + len = parser.field_data[UF_PATH].len; cursor = firmware_uri + off; - path_len = 0; - - for (i = 0; i < len; i++) { - if (firmware_uri[off + i] == '/') { - if (path_len > 0) { - ret = coap_packet_append_option(&msg->cpkt, - COAP_OPTION_URI_PATH, - cursor, path_len); - if (ret < 0) { - LOG_ERR("Error adding URI_PATH"); - goto cleanup; - } - - cursor += path_len + 1; - path_len = 0; - } else { - /* skip current slash */ - cursor += 1; - } - continue; - } - if (i == len - 1) { - /* flush the rest */ + /* add path portions (separated by slashes) */ + while (len > 0 && (next_slash = strchr(cursor, '/')) != NULL) { + if (next_slash != cursor) { ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - cursor, path_len + 1); + cursor, + next_slash - cursor); if (ret < 0) { LOG_ERR("Error adding URI_PATH"); goto cleanup; } - break; } - path_len += 1; + + /* skip slash */ + len -= (next_slash - cursor) + 1; + cursor = next_slash + 1; + } + + if (len > 0) { + /* flush the rest */ + ret = coap_packet_append_option(&msg->cpkt, + COAP_OPTION_URI_PATH, + cursor, len); + if (ret < 0) { + LOG_ERR("Error adding URI_PATH"); + goto cleanup; + } } #endif @@ -258,7 +236,6 @@ do_firmware_transfer_reply_cb(const struct coap_packet *response, u8_t token[8]; u8_t tkl; u16_t payload_len, payload_offset, len; - struct net_buf *payload_frag; struct coap_packet *check_response = (struct coap_packet *)response; struct lwm2m_engine_res_inst *res = NULL; lwm2m_engine_set_data_cb_t write_cb; @@ -319,8 +296,8 @@ do_firmware_transfer_reply_cb(const struct coap_packet *response, last_block = !coap_next_block(check_response, &firmware_block_ctx); /* Process incoming data */ - payload_frag = coap_packet_get_payload(check_response, &payload_offset, - &payload_len); + payload_offset = response->hdr_len + response->opt_len; + coap_packet_get_payload(response, &payload_len); if (payload_len > 0) { LOG_DBG("total: %zd, current: %zd", firmware_block_ctx.total_size, @@ -348,20 +325,16 @@ do_firmware_transfer_reply_cb(const struct coap_packet *response, len = (payload_len > write_buflen) ? write_buflen : payload_len; payload_len -= len; - payload_frag = net_frag_read(payload_frag, - payload_offset, - &payload_offset, - len, - write_buf); /* check for end of packet */ - if (!payload_frag && payload_offset == 0xffff) { + if (buf_read(write_buf, len, + CPKT_BUF_READ(response), + &payload_offset) < 0) { /* malformed packet */ ret = -EFAULT; goto error; } - ret = write_cb(0, write_buf, len, - !payload_frag && last_block, + ret = write_cb(0, write_buf, len, last_block, firmware_block_ctx.total_size); if (ret < 0) { goto error; @@ -417,16 +390,9 @@ static void do_transmit_timeout_cb(struct lwm2m_message *msg) static void firmware_transfer(struct k_work *work) { - struct sockaddr client_addr; - int ret, family; - u16_t off; - u16_t len; - char tmp; + int ret; char *server_addr; - /* Server Peer IP information */ - family = AF_INET; - #if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT) server_addr = CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_ADDR; if (strlen(server_addr) >= URI_LEN) { @@ -442,89 +408,21 @@ static void firmware_transfer(struct k_work *work) server_addr = firmware_uri; #endif - http_parser_url_init(&parsed_uri); - ret = http_parser_parse_url(server_addr, - strlen(server_addr), - 0, - &parsed_uri); - if (ret != 0) { - LOG_ERR("Invalid firmware URI: %s", server_addr); - ret = -ENOTSUP; - goto error; - } - - /* Check schema and only support coap for now */ - if (!(parsed_uri.field_set & (1 << UF_SCHEMA))) { - LOG_ERR("No schema in package uri"); - ret = -ENOTSUP; - goto error; - } - - /* TODO: enable coaps when DTLS is ready */ - off = parsed_uri.field_data[UF_SCHEMA].off; - len = parsed_uri.field_data[UF_SCHEMA].len; - if (len != 4 || memcmp(server_addr + off, "coap", 4)) { - LOG_ERR("Unsupported schema"); - ret = -EPROTONOSUPPORT; - goto error; - } - - if (!(parsed_uri.field_set & (1 << UF_PORT))) { - /* Set to default port of CoAP */ - parsed_uri.port = 5683; - } - - off = parsed_uri.field_data[UF_HOST].off; - len = parsed_uri.field_data[UF_HOST].len; - - /* truncate host portion */ - tmp = server_addr[off + len]; - server_addr[off + len] = '\0'; - - /* setup the local firmware download client port */ - (void)memset(&client_addr, 0, sizeof(client_addr)); -#if defined(CONFIG_NET_IPV6) - client_addr.sa_family = AF_INET6; - net_sin6(&client_addr)->sin6_port = - htons(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_LOCAL_PORT); -#elif defined(CONFIG_NET_IPV4) - client_addr.sa_family = AF_INET; - net_sin(&client_addr)->sin_port = - htons(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_LOCAL_PORT); -#endif - - ret = net_app_init_udp_client(&firmware_ctx.net_app_ctx, - &client_addr, NULL, - &server_addr[off], parsed_uri.port, - firmware_ctx.net_init_timeout, NULL); - server_addr[off + len] = tmp; + ret = lwm2m_parse_peerinfo(server_addr, &firmware_ctx.remote_addr, + &firmware_ctx.use_dtls); if (ret < 0) { - LOG_ERR("Could not get an UDP context (err:%d)", ret); - ret = -ENOMSG; goto error; } - LOG_INF("Connecting to server %s, port %d", server_addr + off, - parsed_uri.port); - lwm2m_engine_context_init(&firmware_ctx); - - /* set net_app callbacks */ - ret = net_app_set_cb(&firmware_ctx.net_app_ctx, NULL, - firmware_udp_receive, NULL, NULL); + firmware_ctx.handle_separate_response = true; + ret = lwm2m_socket_start(&firmware_ctx); if (ret < 0) { - LOG_ERR("Could not set receive callback (err:%d)", ret); - /* make sure this sets RESULT_CONNECTION_LOST */ - ret = -ENOMSG; - goto cleanup; + LOG_ERR("Cannot start a firmware-pull connection:%d", ret); + goto error; } - ret = net_app_connect(&firmware_ctx.net_app_ctx, - firmware_ctx.net_timeout); - if (ret < 0) { - LOG_ERR("Cannot connect UDP (%d)", ret); - goto cleanup; - } + LOG_INF("Connecting to server %s", firmware_uri); /* reset block transfer context */ coap_block_transfer_init(&firmware_block_ctx, @@ -532,15 +430,11 @@ static void firmware_transfer(struct k_work *work) ret = transfer_request(&firmware_block_ctx, coap_next_token(), 8, do_firmware_transfer_reply_cb); if (ret < 0) { - goto cleanup; + goto error; } return; -cleanup: - net_app_close(&firmware_ctx.net_app_ctx); - net_app_release(&firmware_ctx.net_app_ctx); - error: set_update_result_from_error(ret); } @@ -553,16 +447,14 @@ int lwm2m_firmware_cancel_transfer(void) int lwm2m_firmware_start_transfer(char *package_uri) { - /* free up old context */ - if (firmware_ctx.net_app_ctx.is_init) { - net_app_close(&firmware_ctx.net_app_ctx); - net_app_release(&firmware_ctx.net_app_ctx); + /* close old socket */ + if (firmware_ctx.sock_fd > 0) { + lwm2m_socket_del(&firmware_ctx); + close(firmware_ctx.sock_fd); } (void)memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx)); firmware_retry = 0; - firmware_ctx.net_init_timeout = NETWORK_INIT_TIMEOUT; - firmware_ctx.net_timeout = NETWORK_CONNECT_TIMEOUT; k_work_init(&firmware_work, firmware_transfer); lwm2m_firmware_set_update_state(STATE_DOWNLOADING); diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_security.c b/subsys/net/lib/lwm2m/lwm2m_obj_security.c index 2c78e6a0ea885..eae2a54df081d 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_security.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_security.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2018-2019 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ @@ -36,9 +37,14 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #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]; @@ -48,9 +54,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), @@ -90,9 +96,10 @@ 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] = 0U; - short_server_id[index] = 0U; + security_mode[index] = 0; + short_server_id[index] = 0; /* initialize instance resource data */ INIT_OBJ_RES_DATA(res[index], i, SECURITY_SERVER_URI_ID, @@ -101,10 +108,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)); @@ -114,6 +123,33 @@ 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 fcb1380d5f578..4378ce859a671 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_server.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_server.c @@ -53,15 +53,20 @@ 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), + /* Mark Transport Binding is RO but BOOTSTRAP needs to write it */ + 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 3a5ce59be0b30..32984927dca65 100644 --- a/subsys/net/lib/lwm2m/lwm2m_object.h +++ b/subsys/net/lib/lwm2m/lwm2m_object.h @@ -53,9 +53,11 @@ #include #include -#include +#include #include +#include "buf_util.h" + /* #####/###/#####/### + NULL */ #define MAX_RESOURCE_LEN 20 @@ -127,6 +129,13 @@ #define WRITER_OUTPUT_VALUE 1 #define WRITER_RESOURCE_INSTANCE 2 +#define MAX_PACKET_SIZE (CONFIG_LWM2M_COAP_BLOCK_SIZE + \ + CONFIG_LWM2M_ENGINE_MESSAGE_HEADER_SIZE) + +/* buffer util macros */ +#define CPKT_BUF_WRITE(cpkt) (cpkt)->data, &(cpkt)->offset, (cpkt)->max_len +#define CPKT_BUF_READ(cpkt) (cpkt)->data, (cpkt)->max_len + struct lwm2m_engine_obj; struct lwm2m_message; @@ -260,12 +269,6 @@ struct lwm2m_output_context { const struct lwm2m_writer *writer; struct coap_packet *out_cpkt; - /* current write fragment in net_buf chain */ - struct net_buf *frag; - - /* current write position in net_buf chain */ - u16_t offset; - /* private output data */ void *user_data; }; @@ -274,15 +277,14 @@ struct lwm2m_input_context { const struct lwm2m_reader *reader; struct coap_packet *in_cpkt; - /* current read position in net_buf chain */ - struct net_buf *frag; + /* current position in buffer */ u16_t offset; - /* length of incoming coap/lwm2m payload */ - u16_t payload_len; - /* length of incoming opaque */ u16_t opaque_len; + + /* private output data */ + void *user_data; }; /* Establish a message timeout callback */ @@ -303,6 +305,9 @@ struct lwm2m_message { /** CoAP packet data related to the outgoing message */ struct coap_packet cpkt; + /** Buffer data related outgoing message */ + u8_t msg_data[MAX_PACKET_SIZE]; + /** Message transmission handling for TYPE_CON */ struct coap_pending *pending; struct coap_reply *reply; @@ -406,6 +411,23 @@ engine_clear_out_user_data(struct lwm2m_output_context *out) out->user_data = NULL; } +static inline void engine_set_in_user_data(struct lwm2m_input_context *in, + void *user_data) +{ + in->user_data = user_data; +} + +static inline void *engine_get_in_user_data(struct lwm2m_input_context *in) +{ + return in->user_data; +} + +static inline void +engine_clear_in_user_data(struct lwm2m_input_context *in) +{ + in->user_data = NULL; +} + /* inline multi-format write / read functions */ static inline size_t engine_put_begin(struct lwm2m_output_context *out, diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 5234f1b7b44a3..ce7acff370056 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited - * Copyright (c) 2017 Foundries.io + * Copyright (c) 2017-2019 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ @@ -55,9 +55,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include #include #include -#include -#include -#include #include "lwm2m_object.h" #include "lwm2m_engine.h" @@ -92,14 +89,10 @@ enum sm_engine_state { }; struct lwm2m_rd_client_info { - u16_t lifetime; + u32_t lifetime; struct lwm2m_ctx *ctx; 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; @@ -119,16 +112,21 @@ 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 && - sm_state == ENGINE_REGISTRATION_DONE) { +#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; + } else +#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; } @@ -158,9 +156,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; @@ -186,6 +187,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) @@ -198,12 +200,14 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, COAP_RESPONSE_CODE_DETAIL(code)); if (code == COAP_RESPONSE_CODE_CHANGED) { - LOG_DBG("Considered done!"); - set_sm_state(ENGINE_BOOTSTRAP_DONE); + 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? */ 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? */ LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying."); set_sm_state(ENGINE_DO_REGISTRATION); } else { @@ -211,19 +215,28 @@ static int do_bootstrap_reply_cb(const struct coap_packet *response, LOG_ERR("Failed with code %u.%u. Retrying ...", COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code)); + lwm2m_engine_context_close(client.ctx); set_sm_state(ENGINE_INIT); } return 0; } -static void do_bootstrap_timeout_cb(struct lwm2m_message *msg) +static void do_bootstrap_reg_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Bootstrap Timeout"); + /* close down context resources */ + lwm2m_engine_context_close(msg->ctx); + + /* 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, @@ -280,6 +293,7 @@ static int do_registration_reply_cb(const struct coap_packet *response, LOG_ERR("failed with code %u.%u. Re-init network", COAP_RESPONSE_CODE_CLASS(code), COAP_RESPONSE_CODE_DETAIL(code)); + set_sm_state(ENGINE_INIT); return 0; } @@ -288,6 +302,9 @@ static void do_registration_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("Registration Timeout"); + /* close down context resources */ + lwm2m_engine_context_close(msg->ctx); + /* Restart from scratch */ sm_handle_timeout_state(msg, ENGINE_INIT); } @@ -359,163 +376,210 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) { LOG_WRN("De-Registration Timeout"); + /* close down context resources */ + lwm2m_engine_context_close(msg->ctx); + /* Abort de-registration and start from scratch */ sm_handle_timeout_state(msg, ENGINE_INIT); } +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 temp; + + /* 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, &temp); + if (ret < 0) { + continue; + } + +#if defined(CONFIG_LWM2M_RD_CLIENT_SUPPORT_BOOTSTRAP) + if (temp == bootstrap_server) { +#else + if (temp == 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; + LOG_DBG("Using default lifetime: %u", *lifetime); + } + } + + if (*sec_obj_inst < 0) { + /* no servers found */ + LOG_DBG("sec_obj_inst: NOT_FOUND"); + return -ENOENT; + } + + LOG_DBG("sec_obj_inst: %d", *sec_obj_inst); + return 0; +} + /* state machine step functions */ static int sm_do_init(void) { - 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 = 1U; - client.bootstrapped = 0U; client.trigger_update = 0U; + client.lifetime = 0U; + + /* Do bootstrap or registration */ #if defined(CONFIG_LWM2M_BOOTSTRAP_SERVER) - client.use_bootstrap = 1U; + set_sm_state(ENGINE_DO_BOOTSTRAP); #else - client.use_registration = 1U; + 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) { - LOG_ERR("Unable to get a lwm2m message!"); - return -ENOMEM; - } - msg->type = COAP_TYPE_CON; - msg->code = COAP_METHOD_POST; - msg->mid = 0U; - msg->reply_cb = do_bootstrap_reply_cb; - msg->message_timeout_cb = do_bootstrap_timeout_cb; + /* TODO: clear out connection data? */ - ret = lwm2m_init_message(msg); - if (ret) { - goto cleanup; - } + client.ctx->bootstrap_mode = true; + ret = sm_select_next_sec_inst(client.ctx->bootstrap_mode, + &client.ctx->sec_obj_inst, + &client.lifetime); + if (ret < 0) { + /* try again */ + return ret; + } - /* TODO: handle return error */ - coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH, - "bs", strlen("bs")); + if (client.lifetime == 0U) { + client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_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)); + LOG_INF("Bootstrap started with endpoint '%s' with client lifetime %d", + client.ep_name, client.lifetime); - /* log the bootstrap attempt */ -#if defined(CONFIG_NET_APP_DTLS) - if (app_ctx->dtls.ctx) { - remote = &app_ctx->dtls.ctx->remote; - } -#endif + ret = lwm2m_engine_start(client.ctx); + if (ret < 0) { + LOG_ERR("Cannot init LWM2M engine (%d)", ret); + return ret; + } - if (!remote) { - remote = &app_ctx->default_ctx->remote; - } + msg = lwm2m_get_message(client.ctx); + if (!msg) { + LOG_ERR("Unable to get a lwm2m message!"); + ret = -ENOMEM; + goto cleanup_engine; + } - LOG_DBG("Register ID with bootstrap server [%s] as '%s'", - lwm2m_sprint_ip_addr(remote), - query_buffer); + msg->type = COAP_TYPE_CON; + msg->code = COAP_METHOD_POST; + msg->mid = 0U; + msg->reply_cb = do_bootstrap_reply_cb; + msg->message_timeout_cb = do_bootstrap_reg_timeout_cb; - ret = lwm2m_send_message(msg); - if (ret < 0) { - LOG_ERR("Error sending LWM2M packet (err:%d).", ret); - goto cleanup; - } + 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")); - set_sm_state(ENGINE_BOOTSTRAP_SENT); + 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 */ + LOG_DBG("Register ID with bootstrap server as '%s'", + query_buffer); + + ret = lwm2m_send_message(msg); + if (ret < 0) { + 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); +cleanup_engine: + lwm2m_engine_context_close(client.ctx); return ret; } -static int sm_bootstrap_done(void) +static int sm_bootstrap_reg_done(void) { - /* TODO: Fix this */ - /* check that we should still use bootstrap */ - if (client.use_bootstrap) { -#ifdef CONFIG_LWM2M_SECURITY_OBJ_SUPPORT - int i; - - 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 - LOG_ERR("Failed to parse URI!"); - } else { - client.has_registration_info = 1U; - client.bootstrapped++; - } - } else { - LOG_ERR("** failed to parse URI"); - } + LOG_INF("Bootstrap registration done."); + 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) +{ + LOG_INF("Bootstrap data transfer done!"); + set_sm_state(ENGINE_BOOTSTRAP_TRANS_DONE); +} + +static int sm_bootstrap_trans_done(void) +{ + /* close down context resources */ + 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, lwm2m_message_timeout_cb_t timeout_cb) { - struct net_app_ctx *app_ctx = NULL; struct lwm2m_message *msg; u16_t client_data_len; int ret; - struct sockaddr *remote = NULL; - app_ctx = &client.ctx->net_app_ctx; msg = lwm2m_get_message(client.ctx); if (!msg) { LOG_ERR("Unable to get a lwm2m message!"); @@ -580,10 +644,9 @@ static int sm_send_registration(bool send_obj_support_data, /* generate the rd data */ client_data_len = lwm2m_get_rd_data(client_data, sizeof(client_data)); - - if (!net_pkt_append_all(msg->cpkt.pkt, client_data_len, - client_data, BUF_ALLOC_TIMEOUT)) { - ret = -ENOMEM; + ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), client_data, + client_data_len); + if (ret < 0) { goto cleanup; } } @@ -595,18 +658,8 @@ static int sm_send_registration(bool send_obj_support_data, } /* log the registration attempt */ -#if defined(CONFIG_NET_APP_DTLS) - if (app_ctx->dtls.ctx) { - remote = &app_ctx->dtls.ctx->remote; - } -#endif - - if (!remote) { - remote = &app_ctx->default_ctx->remote; - } - LOG_DBG("registration sent [%s]", - lwm2m_sprint_ip_addr(remote)); + lwm2m_sprint_ip_addr(&client.ctx->remote_addr)); return 0; @@ -619,9 +672,32 @@ 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? */ + + client.ctx->bootstrap_mode = false; + ret = sm_select_next_sec_inst(client.ctx->bootstrap_mode, + &client.ctx->sec_obj_inst, + &client.lifetime); + if (ret < 0) { + LOG_ERR("Unable to find a valid security instance."); + set_sm_state(ENGINE_INIT); + return -EINVAL; + } + + if (client.lifetime == 0U) { + client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + } + + LOG_INF("RD Client started with endpoint '%s' with client lifetime %d", + client.ep_name, client.lifetime); + + ret = lwm2m_engine_start(client.ctx); + if (ret < 0) { + LOG_ERR("Cannot init LWM2M engine (%d)", ret); + return ret; + } + + if (!sm_is_registered()) { ret = sm_send_registration(true, do_registration_reply_cb, do_registration_timeout_cb); @@ -629,6 +705,8 @@ static int sm_do_registration(void) set_sm_state(ENGINE_REGISTRATION_SENT); } else { LOG_ERR("Registration err: %d", ret); + lwm2m_engine_context_close(client.ctx); + /* exit and try again */ } } @@ -657,6 +735,9 @@ static int sm_registration_done(void) set_sm_state(ENGINE_UPDATE_SENT); } else { LOG_ERR("Registration update err: %d", ret); + lwm2m_engine_context_close(client.ctx); + /* perform full registration */ + set_sm_state(ENGINE_REGISTRATION_SENT); } } @@ -665,11 +746,9 @@ static int sm_registration_done(void) static int sm_do_deregister(void) { - struct net_app_ctx *app_ctx = NULL; struct lwm2m_message *msg; int ret; - app_ctx = &client.ctx->net_app_ctx; msg = lwm2m_get_message(client.ctx); if (!msg) { LOG_ERR("Unable to get a lwm2m message!"); @@ -705,10 +784,11 @@ static int sm_do_deregister(void) cleanup: lwm2m_reset_message(msg, true); + lwm2m_engine_context_close(client.ctx); return ret; } -static void lwm2m_rd_client_service(void) +static void lwm2m_rd_client_service(struct k_work *work) { if (client.ctx) { switch (get_sm_state()) { @@ -717,17 +797,24 @@ 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_REG_SENT: + /* wait for bootstrap registration done */ break; - case ENGINE_BOOTSTRAP_SENT: - /* wait for bootstrap to be done or timeout */ + case ENGINE_BOOTSTRAP_REG_DONE: + sm_bootstrap_reg_done(); + /* wait for transfer done */ break; - case ENGINE_BOOTSTRAP_DONE: - sm_bootstrap_done(); + case ENGINE_BOOTSTRAP_TRANS_DONE: + sm_bootstrap_trans_done(); break; +#endif case ENGINE_DO_REGISTRATION: sm_do_registration(); @@ -766,32 +853,15 @@ 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) +void lwm2m_rd_client_start(struct lwm2m_ctx *client_ctx, 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) { - LOG_ERR("Cannot init LWM2M engine (%d)", ret); - return ret; - } - - if (!client_ctx->net_app_ctx.default_ctx) { - 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); strncpy(client.ep_name, ep_name, CLIENT_EP_LEN - 1); LOG_INF("LWM2M Client: %s", client.ep_name); - - return 0; } 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..344e7d05e89dc 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.h +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2017 Linaro Limited + * Copyright (c) 2018-2019 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ @@ -38,5 +39,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_json.c b/subsys/net/lib/lwm2m/lwm2m_rw_json.c index d67952ff910a3..b64889ba404a1 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_json.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_json.c @@ -74,12 +74,11 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_rw_plain_text.h" #include "lwm2m_engine.h" -#define T_NONE 0 -#define T_STRING_B 1 -#define T_STRING 2 -#define T_NAME 3 -#define T_OBJ 4 -#define T_VAL 5 +#define T_OBJECT_BEGIN BIT(0) +#define T_OBJECT_END BIT(1) +#define T_STRING_BEGIN BIT(2) +#define T_STRING_END BIT(3) +#define T_VALUE BIT(4) #define SEPARATOR(f) ((f & WRITER_OUTPUT_VALUE) ? "," : "") @@ -91,64 +90,104 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #define TOKEN_BUF_LEN 64 -struct json_data { - u8_t name[TOKEN_BUF_LEN]; - u8_t value[TOKEN_BUF_LEN]; - u8_t name_len; - u8_t value_len; -}; - struct json_out_formatter_data { - struct net_buf *mark_frag_ri; + /* offset position storage */ u16_t mark_pos_ri; + + /* flags */ u8_t writer_flags; + + /* path storage */ u8_t path_level; }; +struct json_in_formatter_data { + /* name info */ + u16_t name_offset; + u16_t name_len; + + /* value info */ + u16_t value_offset; + u16_t value_len; + + /* state */ + u16_t offset; + + /* flags */ + u8_t json_flags; +}; + /* some temporary buffer space for format conversions */ -static char json_buffer[64]; +static char json_buffer[TOKEN_BUF_LEN]; -static void json_add_char(struct json_data *json, u8_t c, u8_t json_type) +static void json_add_char(struct lwm2m_input_context *in, + struct json_in_formatter_data *fd) { - if (json_type == T_STRING_B) { - json->name[json->name_len++] = c; - } else if (json_type == T_STRING_B) { - json->value[json->value_len++] = c; + if ((fd->json_flags & T_VALUE) || + ((fd->json_flags & T_STRING_BEGIN) && + !(fd->json_flags & T_STRING_END))) { + if (fd->json_flags & T_VALUE) { + fd->value_len++; + if (fd->value_len == 1) { + fd->value_offset = fd->offset; + } + } else { + fd->name_len++; + if (fd->name_len == 1) { + fd->name_offset = fd->offset; + } + } } } /* Simlified JSON style reader for reading in values from a LWM2M JSON string */ static int json_next_token(struct lwm2m_input_context *in, - struct json_data *json) + struct json_in_formatter_data *fd) { - u8_t json_type = T_NONE; - u8_t cont; - u8_t c; + u8_t cont, c; bool escape = false; - (void)memset(json, 0, sizeof(struct json_data)); + (void)memset(fd, 0, sizeof(*fd)); cont = 1U; /* We will be either at start, or at a specific position */ - while (in->frag && in->offset != 0xffff && cont) { - in->frag = net_frag_read_u8(in->frag, in->offset, &in->offset, - &c); - if (!in->frag && in->offset == 0xffff) { + while (in->offset < in->in_cpkt->offset && cont) { + fd->offset = in->offset; + if (buf_read_u8(&c, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { break; } if (c == '\\') { escape = true; + /* Keep track of the escape codes */ + json_add_char(in, fd); continue; } switch (c) { + case '[': + if (!escape) { + fd->json_flags |= T_OBJECT_BEGIN; + cont = 0; + } else { + json_add_char(in, fd); + } + break; + case ']': + if (!escape) { + fd->json_flags |= T_OBJECT_END; + cont = 0; + } else { + json_add_char(in, fd); + } + break; case '{': if (!escape) { - json_type = T_OBJ; + fd->json_flags |= T_OBJECT_BEGIN; } else { - json_add_char(json, c, json_type); + json_add_char(in, fd); } break; @@ -156,36 +195,34 @@ static int json_next_token(struct lwm2m_input_context *in, case '}': case ',': if (!escape) { - if (json_type == T_VAL || - json_type == T_STRING) { - json->value[json->value_len] = '\0'; - json_type = T_NONE; - cont = 0U; - } + cont = 0; } else { - json_add_char(json, c, json_type); + json_add_char(in, fd); } break; case '"': - if (!escape && json_type == T_STRING_B) { - json->name[json->name_len] = '\0'; - json_type = T_STRING; - } else if (!escape) { - json_type = T_STRING_B; - json->name_len = 0U; + if (!escape) { + if (fd->json_flags & T_STRING_BEGIN) { + fd->json_flags &= ~T_STRING_BEGIN; + fd->json_flags |= T_STRING_END; + } else { + fd->json_flags &= ~T_STRING_END; + fd->json_flags |= T_STRING_BEGIN; + } } else { - json_add_char(json, c, json_type); + json_add_char(in, fd); } break; case ':': - if (json_type == T_STRING) { - json_type = T_VAL; + if (!escape) { + fd->json_flags &= ~T_STRING_END; + fd->json_flags |= T_VALUE; } else { - json_add_char(json, c, json_type); + json_add_char(in, fd); } break; @@ -194,14 +231,14 @@ static int json_next_token(struct lwm2m_input_context *in, case ' ': case '\n': case '\t': - if (json_type != T_STRING_B) { + if (!(fd->json_flags & T_STRING_BEGIN)) { break; } /* fallthrough */ default: - json_add_char(json, c, json_type); + json_add_char(in, fd); } @@ -234,10 +271,8 @@ static size_t put_begin(struct lwm2m_output_context *out, return 0; } - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, len, json_buffer, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), json_buffer, len) < 0) { /* TODO: Generate error? */ return 0; } @@ -248,10 +283,7 @@ static size_t put_begin(struct lwm2m_output_context *out, static size_t put_end(struct lwm2m_output_context *out, struct lwm2m_obj_path *path) { - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, 2, "]}", - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), "]}", 2) < 0) { /* TODO: Generate error? */ return 0; } @@ -287,6 +319,17 @@ static size_t put_end_ri(struct lwm2m_output_context *out, return 0; } +static size_t put_char(struct lwm2m_output_context *out, + char c) +{ + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), &c, sizeof(c)) < 0) { + /* TODO: Generate error? */ + return 0; + } + + return 1; +} + static size_t put_json_prefix(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, const char *format) @@ -331,10 +374,7 @@ static size_t put_json_prefix(struct lwm2m_output_context *out, return 0; } - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, len, json_buffer, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), json_buffer, len) < 0) { /* TODO: Generate error? */ return 0; } @@ -351,10 +391,7 @@ static size_t put_json_postfix(struct lwm2m_output_context *out) return 0; } - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, 1, "}", - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + if (put_char(out, '}') < 0) { /* TODO: Generate error? */ return 0; } @@ -398,20 +435,6 @@ static size_t put_s64(struct lwm2m_output_context *out, return (size_t)len; } -static size_t put_char(struct lwm2m_output_context *out, - char c) -{ - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, 1, &c, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { - /* TODO: Generate error? */ - return 0; - } - - return 1; -} - static size_t put_string(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf, size_t buflen) @@ -441,11 +464,8 @@ static size_t put_string(struct lwm2m_output_context *out, return 0; } - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, - res, json_buffer, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), + json_buffer, res) < 0) { /* TODO: Generate error? */ return 0; } @@ -507,6 +527,156 @@ static size_t put_bool(struct lwm2m_output_context *out, return (size_t)len; } +static size_t read_number(struct lwm2m_input_context *in, + s64_t *value1, s64_t *value2, + bool accept_sign, bool accept_dot) +{ + struct json_in_formatter_data *fd; + s64_t *counter = value1; + u8_t *buf; + size_t i = 0; + bool neg = false; + bool dot_found = false; + char c; + + /* initialize values to 0 */ + value1 = 0; + if (value2) { + value2 = 0; + } + + fd = engine_get_in_user_data(in); + if (!fd) { + return 0; + } + + buf = in->in_cpkt->data + fd->value_offset; + while (*(buf + i) && i < fd->value_len) { + c = *(buf + i); + if (c == '-' && accept_sign && i == 0) { + neg = true; + } else if (c == '.' && i > 0 && accept_dot && !dot_found && + value2) { + dot_found = true; + counter = value2; + } else if (isdigit(c)) { + *counter = *counter * 10 + (c - '0'); + } else { + /* anything else stop reading */ + break; + } + + i++; + } + + if (neg) { + *value1 = -*value1; + } + + return i; +} + +static size_t get_s64(struct lwm2m_input_context *in, s64_t *value) +{ + return read_number(in, value, NULL, true, true); +} + +static size_t get_s32(struct lwm2m_input_context *in, s32_t *value) +{ + s64_t tmp = 0; + size_t len = 0; + + len = read_number(in, &tmp, NULL, true, true); + if (len > 0) { + *value = (s32_t)tmp; + } + + return len; +} + +static size_t get_string(struct lwm2m_input_context *in, + u8_t *buf, size_t buflen) +{ + struct json_in_formatter_data *fd; + int ret; + + fd = engine_get_in_user_data(in); + if (!fd) { + return 0; + } + + if (fd->value_len > buflen) { + /* TODO: generate warning? */ + fd->value_len = buflen - 1; + } + + /* TODO: Handle escape codes */ + ret = buf_read(buf, fd->value_len, CPKT_BUF_READ(in->in_cpkt), + &fd->value_offset); + if (ret < 0) { + return 0; + } + + return fd->value_len; +} + +static size_t get_float32fix(struct lwm2m_input_context *in, + float32_value_t *value) +{ + s64_t tmp1, tmp2; + size_t len; + + len = read_number(in, &tmp1, &tmp2, true, true); + if (len > 0) { + value->val1 = (s32_t)tmp1; + value->val2 = (s32_t)tmp2; + } + + return len; +} + +static size_t get_float64fix(struct lwm2m_input_context *in, + float64_value_t *value) +{ + s64_t tmp1, tmp2; + size_t len; + + len = read_number(in, &tmp1, &tmp2, true, true); + if (len > 0) { + value->val1 = tmp1; + value->val2 = tmp2; + } + + return len; +} + +static size_t get_bool(struct lwm2m_input_context *in, bool *value) +{ + struct json_in_formatter_data *fd; + + fd = engine_get_in_user_data(in); + if (!fd) { + return 0; + } + + if (strncmp(in->in_cpkt->data + fd->value_offset, + "true", 4) == 0) { + *value = true; + } else if (strncmp(in->in_cpkt->data + fd->value_offset, + "false", 5) == 0) { + *value = false; + } + + return fd->value_len; +} + +static size_t get_opaque(struct lwm2m_input_context *in, + u8_t *value, size_t buflen, bool *last_block) +{ + /* TODO */ + return 0; +} + const struct lwm2m_writer json_writer = { .put_begin = put_begin, .put_end = put_end, @@ -522,6 +692,16 @@ const struct lwm2m_writer json_writer = { .put_bool = put_bool, }; +const struct lwm2m_reader json_reader = { + .get_s32 = get_s32, + .get_s64 = get_s64, + .get_string = get_string, + .get_float32fix = get_float32fix, + .get_float64fix = get_float64fix, + .get_bool = get_bool, + .get_opaque = get_opaque, +}; + int do_read_op_json(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg, int content_format) { @@ -546,6 +726,7 @@ static int parse_path(const u8_t *buf, u16_t buflen, u16_t val; u8_t c = 0U; + (void)memset(path, 0, sizeof(*path)); do { val = 0U; c = buf[pos]; @@ -555,11 +736,11 @@ static int parse_path(const u8_t *buf, u16_t buflen, c = buf[++pos]; } - /* - * Slash will mote thing forward - * and the end will be when pos == pl - */ - if (c == '/' || pos == buflen) { + /* slash will mote thing forward */ + if (pos == 0 && c == '/') { + /* skip leading slashes */ + pos++; + } else if (c == '/' || pos == buflen) { LOG_DBG("Setting %u = %u", ret, val); if (ret == 0) { path->obj_id = val; @@ -586,88 +767,134 @@ int do_write_op_json(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg) struct lwm2m_engine_obj_field *obj_field; struct lwm2m_engine_obj_inst *obj_inst = NULL; struct lwm2m_engine_res_inst *res = NULL; - struct json_data json; - u8_t olv = 0U; + struct lwm2m_obj_path orig_path; + struct json_in_formatter_data fd; + int ret = 0, index; + u8_t value[TOKEN_BUF_LEN]; + u8_t base_name[MAX_RESOURCE_LEN]; + u8_t full_name[MAX_RESOURCE_LEN]; u8_t created; - int i, r; - u8_t mode = MODE_NONE; - - olv = msg->path.level; - - while (json_next_token(&msg->in, &json)) { - i = 0; - created = 0U; - if (json.name[0] == 'n') { - msg->path.level = parse_path(json.value, - json.value_len, - &msg->path); - if (i > 0) { - r = lwm2m_get_or_create_engine_obj(msg, - &obj_inst, - &created); - if (r < 0) { - return r; - } - mode |= MODE_INSTANCE; - } - } else { - /* HACK: assume value node: can it be anything else? */ - mode |= MODE_VALUE; - /* FIXME swap msg->in.cpkt.pkt->frag w/ value buffer */ + + (void)memset(&fd, 0, sizeof(fd)); + engine_set_in_user_data(&msg->in, &fd); + + /* store a copy of the original path */ + memcpy(&orig_path, &msg->path, sizeof(msg->path)); + + /* PARSE base name "bn" */ + json_next_token(&msg->in, &fd); + /* TODO: validate name == "bn" */ + if (buf_read(base_name, fd.value_len, + CPKT_BUF_READ(msg->in.in_cpkt), + &fd.value_offset) < 0) { + LOG_ERR("Error parsing base name!"); + return -EINVAL; + } + + /* skip to elements */ + json_next_token(&msg->in, &fd); + /* TODO: validate name == "bv" */ + + while (json_next_token(&msg->in, &fd)) { + + if (!(fd.json_flags & T_VALUE)) { + continue; + } + + if (buf_read(value, fd.name_len, + CPKT_BUF_READ(msg->in.in_cpkt), + &fd.name_offset) < 0) { + LOG_ERR("Error parsing name!"); + continue; } - if (mode == MODE_READY) { - if (!obj_inst) { - return -EINVAL; + /* handle resource name */ + if (value[0] == 'n') { + /* reset values */ + created = 0; + + /* get value for relative path */ + if (buf_read(value, fd.value_len, + CPKT_BUF_READ(msg->in.in_cpkt), + &fd.value_offset) < 0) { + LOG_ERR("Error parsing relative path!"); + continue; + } + + /* combine base_name + name */ + snprintf(full_name, TOKEN_BUF_LEN, "%s%s", + base_name, value); + + /* parse full_name into path */ + ret = parse_path(full_name, strlen(full_name), + &msg->path); + if (ret < 0) { + break; + } + + /* if valid, use the return value as level */ + msg->path.level = ret; + + ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, + &created); + if (ret < 0) { + break; } - obj_field = lwm2m_get_engine_obj_field(obj, - msg->path.res_id); + obj_field = lwm2m_get_engine_obj_field( + obj, msg->path.res_id); /* * if obj_field is not found, * treat as an optional resource */ if (!obj_field) { - /* - * TODO: support BOOTSTRAP WRITE where optional - * resources are ignored - */ - if (msg->operation != LWM2M_OP_CREATE) { - return -ENOENT; - } - - goto skip_optional; + ret = -ENOENT; + break; } + /* + * TODO: support BOOTSTRAP WRITE where optional + * resources are ignored + */ + if (!LWM2M_HAS_PERM(obj_field, LWM2M_PERM_W)) { - return -EPERM; + ret = -EPERM; + break; } if (!obj_inst->resources || - obj_inst->resource_count == 0) { - return -EINVAL; + obj_inst->resource_count == 0) { + ret = -EINVAL; + break; } - for (i = 0; i < obj_inst->resource_count; i++) { - if (obj_inst->resources[i].res_id == - msg->path.res_id) { - res = &obj_inst->resources[i]; + for (index = 0; index < obj_inst->resource_count; + index++) { + if (obj_inst->resources[index].res_id == + msg->path.res_id) { + res = &obj_inst->resources[index]; break; } } if (!res) { - return -ENOENT; + ret = -ENOENT; + break; } - - lwm2m_write_handler(obj_inst, res, obj_field, msg); - -skip_optional: - mode = MODE_NONE; - /* FIXME: swap back original msg->in.cpkt.pkt->frag */ - msg->path.level = olv; + } else if (res) { + /* handle value assignment */ + ret = lwm2m_write_handler(obj_inst, res, obj_field, + msg); + if (orig_path.level == 3 && ret < 0) { + /* return errors on a single write */ + break; + } + } else { + /* complain about error? */ } } - return 0; + engine_clear_in_user_data(&msg->in); + + return ret; } diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_json.h b/subsys/net/lib/lwm2m/lwm2m_rw_json.h index 4e6a2ef587bcc..e520ab4b63779 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_json.h +++ b/subsys/net/lib/lwm2m/lwm2m_rw_json.h @@ -46,6 +46,7 @@ #include "lwm2m_object.h" extern const struct lwm2m_writer json_writer; +extern const struct lwm2m_reader json_reader; int do_read_op_json(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg, int content_format); diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c index fff6db5423f93..f002702ae3125 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_oma_tlv.c @@ -69,6 +69,9 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME); #include "lwm2m_rw_oma_tlv.h" #include "lwm2m_engine.h" +#ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT +#include "lwm2m_rd_client.h" +#endif enum { OMA_TLV_TYPE_OBJECT_INSTANCE = 0, @@ -84,9 +87,9 @@ struct oma_tlv { }; struct tlv_out_formatter_data { - struct net_buf *mark_frag_oi; + /* offset position storage */ + u16_t mark_pos; u16_t mark_pos_oi; - struct net_buf *mark_frag_ri; u16_t mark_pos_ri; u8_t writer_flags; }; @@ -129,20 +132,26 @@ static void tlv_setup(struct oma_tlv *tlv, u8_t type, u16_t id, static int oma_tlv_put_u8(struct lwm2m_output_context *out, u8_t value, bool insert) { + struct tlv_out_formatter_data *fd; + int ret; + if (insert) { - if (!net_pkt_insert(out->out_cpkt->pkt, out->frag, - out->offset, 1, &value, - BUF_ALLOC_TIMEOUT)) { - return -ENOMEM; + fd = engine_get_out_user_data(out); + if (!fd) { + return 0; + } + + ret = buf_insert(CPKT_BUF_WRITE(out->out_cpkt), + fd->mark_pos, &value, 1); + if (ret < 0) { + return ret; } - out->offset++; + fd->mark_pos++; } else { - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, 1, &value, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { - return -ENOMEM; + ret = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &value, 1); + if (ret < 0) { + return ret; } } @@ -209,11 +218,8 @@ static size_t oma_tlv_put(const struct oma_tlv *tlv, /* finally add the value */ if (value != NULL && tlv->length > 0 && !insert) { - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, - tlv->length, value, - BUF_ALLOC_TIMEOUT); - if (!out->frag && out->offset == 0xffff) { + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), + value, tlv->length) < 0) { /* TODO: Generate error? */ return 0; } @@ -226,18 +232,14 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, struct lwm2m_input_context *in, bool dont_advance) { - struct net_buf *tmp_frag; u8_t len_type; u8_t len_pos = 1U; size_t tlv_len; u16_t tmp_offset; u8_t buf[2]; - tmp_frag = in->frag; tmp_offset = in->offset; - tmp_frag = net_frag_read_u8(tmp_frag, tmp_offset, &tmp_offset, &buf[0]); - - if (!tmp_frag && tmp_offset == 0xffff) { + if (buf_read_u8(&buf[0], CPKT_BUF_READ(in->in_cpkt), &tmp_offset) < 0) { goto error; } @@ -245,8 +247,7 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, len_type = (buf[0] >> 3) & 3; len_pos = 1 + (((buf[0] & (1 << 5)) != 0) ? 2 : 1); - tmp_frag = net_frag_read_u8(tmp_frag, tmp_offset, &tmp_offset, &buf[1]); - if (!tmp_frag && tmp_offset == 0xffff) { + if (buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt), &tmp_offset) < 0) { return 0; } @@ -254,9 +255,8 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, /* if len_pos > 2 it means that there are more ID to read */ if (len_pos > 2) { - tmp_frag = net_frag_read_u8(tmp_frag, tmp_offset, - &tmp_offset, &buf[1]); - if (!tmp_frag && tmp_offset == 0xffff) { + if (buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt), + &tmp_offset) < 0) { goto error; } @@ -269,9 +269,8 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, /* read the length */ tlv_len = 0; while (len_type > 0) { - tmp_frag = net_frag_read_u8(tmp_frag, tmp_offset, - &tmp_offset, &buf[1]); - if (!tmp_frag && tmp_offset == 0xffff) { + if (buf_read_u8(&buf[1], CPKT_BUF_READ(in->in_cpkt), + &tmp_offset) < 0) { goto error; } @@ -285,7 +284,6 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, tlv->length = tlv_len; if (!dont_advance) { - in->frag = tmp_frag; in->offset = tmp_offset; } @@ -294,15 +292,13 @@ static size_t oma_tlv_get(struct oma_tlv *tlv, error: /* TODO: Generate error? */ if (!dont_advance) { - in->frag = tmp_frag; in->offset = tmp_offset; } return 0; } -static size_t put_begin_tlv(struct lwm2m_output_context *out, - struct net_buf **mark_frag, u16_t *mark_pos, +static size_t put_begin_tlv(struct lwm2m_output_context *out, u16_t *mark_pos, u8_t *writer_flags, int writer_flag) { /* set flags */ @@ -311,42 +307,35 @@ static size_t put_begin_tlv(struct lwm2m_output_context *out, /* * store position for inserting TLV when we know the length */ - *mark_frag = out->frag; - *mark_pos = out->offset; + *mark_pos = out->out_cpkt->offset; return 0; } -static size_t put_end_tlv(struct lwm2m_output_context *out, - struct net_buf *mark_frag, u16_t mark_pos, +static size_t put_end_tlv(struct lwm2m_output_context *out, u16_t mark_pos, u8_t *writer_flags, u8_t writer_flag, int tlv_type, int tlv_id) { + struct tlv_out_formatter_data *fd; struct oma_tlv tlv; - struct net_buf *tmp_frag; - u16_t tmp_pos; u32_t len = 0U; - *writer_flags &= ~writer_flag; + fd = engine_get_out_user_data(out); + if (!fd) { + return 0; + } - len = net_buf_frags_len(mark_frag) - mark_pos; + *writer_flags &= ~writer_flag; - /* backup out location */ - tmp_frag = out->frag; - tmp_pos = out->offset; + len = out->out_cpkt->offset - mark_pos; /* use stored location */ - out->frag = mark_frag; - out->offset = mark_pos; + fd->mark_pos = mark_pos; /* set instance length */ tlv_setup(&tlv, tlv_type, tlv_id, len); len = oma_tlv_put(&tlv, out, NULL, true) - tlv.length; - /* restore out location + newly inserted */ - out->frag = tmp_frag; - out->offset = tmp_pos + len; - return 0; } @@ -360,8 +349,7 @@ static size_t put_begin_oi(struct lwm2m_output_context *out, return 0; } - return put_begin_tlv(out, &fd->mark_frag_oi, &fd->mark_pos_oi, - &fd->writer_flags, 0); + return put_begin_tlv(out, &fd->mark_pos_oi, &fd->writer_flags, 0); } static size_t put_end_oi(struct lwm2m_output_context *out, @@ -374,8 +362,7 @@ static size_t put_end_oi(struct lwm2m_output_context *out, return 0; } - return put_end_tlv(out, fd->mark_frag_oi, fd->mark_pos_oi, - &fd->writer_flags, 0, + return put_end_tlv(out, fd->mark_pos_oi, &fd->writer_flags, 0, OMA_TLV_TYPE_OBJECT_INSTANCE, path->obj_inst_id); } @@ -389,8 +376,8 @@ static size_t put_begin_ri(struct lwm2m_output_context *out, return 0; } - return put_begin_tlv(out, &fd->mark_frag_ri, &fd->mark_pos_ri, - &fd->writer_flags, WRITER_RESOURCE_INSTANCE); + return put_begin_tlv(out, &fd->mark_pos_ri, &fd->writer_flags, + WRITER_RESOURCE_INSTANCE); } static size_t put_end_ri(struct lwm2m_output_context *out, @@ -403,8 +390,8 @@ static size_t put_end_ri(struct lwm2m_output_context *out, return 0; } - return put_end_tlv(out, fd->mark_frag_ri, fd->mark_pos_ri, - &fd->writer_flags, WRITER_RESOURCE_INSTANCE, + return put_end_tlv(out, fd->mark_pos_ri, &fd->writer_flags, + WRITER_RESOURCE_INSTANCE, OMA_TLV_TYPE_MULTI_RESOURCE, path->res_id); } @@ -615,9 +602,8 @@ static size_t get_number(struct lwm2m_input_context *in, s64_t *value, return 0; } - in->frag = net_frag_read(in->frag, in->offset, &in->offset, - tlv.length, (u8_t *)&temp); - if (!in->frag && in->offset == 0xffff) { + if (buf_read((u8_t *)&temp, tlv.length, + CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) { /* TODO: Generate error? */ return 0; } @@ -675,9 +661,8 @@ static size_t get_string(struct lwm2m_input_context *in, return 0; } - in->frag = net_frag_read(in->frag, in->offset, &in->offset, - tlv.length, buf); - if (!in->frag && in->offset == 0xffff) { + if (buf_read(buf, tlv.length, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { /* TODO: Generate error? */ return 0; } @@ -702,9 +687,8 @@ static size_t get_float32fix(struct lwm2m_input_context *in, if (size > 0) { /* TLV needs to be 4 bytes */ - in->frag = net_frag_read(in->frag, in->offset, &in->offset, - 4, values); - if (!in->frag && in->offset == 0xffff) { + if (buf_read(values, 4, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { /* TODO: Generate error? */ return 0; } @@ -831,9 +815,11 @@ static int do_write_op_tlv_dummy_read(struct lwm2m_message *msg) u8_t read_char; oma_tlv_get(&tlv, &msg->in, false); - while (msg->in.frag && tlv.length--) { - msg->in.frag = net_frag_read_u8(msg->in.frag, msg->in.offset, - &msg->in.offset, &read_char); + while (tlv.length--) { + if (buf_read_u8(&read_char, CPKT_BUF_READ(msg->in.in_cpkt), + &msg->in.offset) < 0) { + break; + } } return 0; @@ -877,8 +863,9 @@ static int do_write_op_tlv_item(struct lwm2m_message *msg) } if (!res) { - /* if OPTIONAL and OP_CREATE use ENOTSUP */ - if (msg->operation == LWM2M_OP_CREATE && + /* if OPTIONAL and BOOTSTRAP-WRITE or CREATE use ENOTSUP */ + if ((msg->ctx->bootstrap_mode || + msg->operation == LWM2M_OP_CREATE) && LWM2M_HAS_PERM(obj_field, BIT(LWM2M_FLAG_OPTIONAL))) { ret = -ENOTSUP; goto error; @@ -935,25 +922,34 @@ int do_write_op_tlv(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg) if (ret < 0) { return ret; } + +#ifdef CONFIG_LWM2M_RD_CLIENT_SUPPORT + if (!msg->ctx->bootstrap_mode) { + engine_trigger_update(); + } +#endif } while (pos < tlv.length && (len2 = oma_tlv_get(&tlv2, &msg->in, true))) { - if (tlv2.type == OMA_TLV_TYPE_RESOURCE) { - msg->path.res_id = tlv2.id; - msg->path.level = 3; - ret = do_write_op_tlv_item(msg); - /* - * ignore errors for CREATE op - * TODO: support BOOTSTRAP WRITE where - * optional resources are ignored - */ - if (ret < 0 && - (msg->operation != - LWM2M_OP_CREATE || - ret != -ENOTSUP)) { - return ret; - } + if (tlv2.type != OMA_TLV_TYPE_RESOURCE) { + pos += len2; + continue; + } + + msg->path.res_id = tlv2.id; + msg->path.level = 3; + ret = do_write_op_tlv_item(msg); + /* + * ignore errors for CREATE op + * for OP_CREATE and BOOTSTRAP WRITE: errors on + * optional resources are ignored (ENOTSUP) + */ + if (ret < 0 && + !((ret == -ENOTSUP) && + (msg->ctx->bootstrap_mode || + msg->operation == LWM2M_OP_CREATE))) { + return ret; } pos += len2; @@ -964,11 +960,13 @@ int do_write_op_tlv(struct lwm2m_engine_obj *obj, struct lwm2m_message *msg) ret = do_write_op_tlv_item(msg); /* * 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 && (msg->operation != LWM2M_OP_CREATE || - ret != -ENOTSUP)) { + if (ret < 0 && + !((ret == -ENOTSUP) && + (msg->ctx->bootstrap_mode || + msg->operation == LWM2M_OP_CREATE))) { return ret; } } diff --git a/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c b/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c index f4efea97bf48d..065de5d1afe4c 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c +++ b/subsys/net/lib/lwm2m/lwm2m_rw_plain_text.c @@ -89,15 +89,12 @@ size_t plain_text_put_format(struct lwm2m_output_context *out, return 0; } - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, - strlen(pt_buffer), pt_buffer, - BUF_ALLOC_TIMEOUT); - if (!out->frag) { + n = strlen(pt_buffer); + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), pt_buffer, n) < 0) { return 0; } - return strlen(pt_buffer); + return (size_t)n; } static size_t put_s32(struct lwm2m_output_context *out, @@ -144,12 +141,8 @@ static size_t put_string(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, char *buf, size_t buflen) { - out->frag = net_pkt_write(out->out_cpkt->pkt, out->frag, - out->offset, &out->offset, - buflen, buf, - BUF_ALLOC_TIMEOUT); - if (!out->frag) { - return -ENOMEM; + if (buf_append(CPKT_BUF_WRITE(out->out_cpkt), buf, buflen) < 0) { + return 0; } return buflen; @@ -166,17 +159,9 @@ static size_t put_bool(struct lwm2m_output_context *out, } } -static int pkt_length_left(struct lwm2m_input_context *in) +static int get_length_left(struct lwm2m_input_context *in) { - struct net_buf *frag = in->frag; - int total_left = -in->offset; - - while (frag) { - total_left += frag->len; - frag = frag->frags; - } - - return total_left; + return in->in_cpkt->offset - in->offset; } static size_t plain_text_read_number(struct lwm2m_input_context *in, @@ -196,10 +181,9 @@ static size_t plain_text_read_number(struct lwm2m_input_context *in, value2 = 0; } - while (in->frag && in->offset != 0xffff) { - in->frag = net_frag_read_u8(in->frag, in->offset, &in->offset, - &tmp); - if (!in->frag && in->offset == 0xffff) { + while (in->offset < in->in_cpkt->offset) { + if (buf_read_u8(&tmp, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { break; } @@ -248,15 +232,15 @@ static size_t get_s64(struct lwm2m_input_context *in, s64_t *value) static size_t get_string(struct lwm2m_input_context *in, u8_t *value, size_t buflen) { - u16_t in_len = pkt_length_left(in); + u16_t in_len = get_length_left(in); if (in_len > buflen) { /* TODO: generate warning? */ in_len = buflen - 1; } - in->frag = net_frag_read(in->frag, in->offset, &in->offset, - in_len, value); - if (!in->frag && in->offset == 0xffff) { + + if (buf_read(value, in_len, CPKT_BUF_READ(in->in_cpkt), + &in->offset) < 0) { value[0] = '\0'; return 0; } @@ -292,8 +276,7 @@ static size_t get_bool(struct lwm2m_input_context *in, { u8_t tmp; - in->frag = net_frag_read_u8(in->frag, in->offset, &in->offset, &tmp); - if (!in->frag && in->offset == 0xffff) { + if (buf_read_u8(&tmp, CPKT_BUF_READ(in->in_cpkt), &in->offset) < 0) { return 0; } @@ -308,7 +291,7 @@ static size_t get_bool(struct lwm2m_input_context *in, static size_t get_opaque(struct lwm2m_input_context *in, u8_t *value, size_t buflen, bool *last_block) { - in->opaque_len = pkt_length_left(in); + in->opaque_len = get_length_left(in); return lwm2m_engine_get_opaque_more(in, value, buflen, last_block); }