diff --git a/include/net/lwm2m.h b/include/net/lwm2m.h index 62cdc066cf8..f517f0a32fa 100644 --- a/include/net/lwm2m.h +++ b/include/net/lwm2m.h @@ -68,6 +68,13 @@ struct lwm2m_ctx { k_thread_stack_t *dtls_stack; size_t dtls_stack_len; #endif + bool use_dtls; + + /** Current security object index */ + int sec_obj_inst; + + /** Packet Flow Settings */ + bool handle_separate_response; }; typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id, @@ -220,8 +227,7 @@ 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 */ @@ -242,9 +248,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/src/lwm2m-client.c b/samples/net/lwm2m_client/src/lwm2m-client.c index d6badb48b0b..f2bda401086 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) @@ -207,8 +216,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; + } + + /* TODO: add server port to URL */ + snprintk(server_url, server_url_len, "coap%s//%s", + IS_ENABLED(CONFIG_LWM2M_DTLS_SUPPORT) ? "s:" : ":", + 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 */ @@ -362,22 +398,7 @@ void main(void) #endif /* CONFIG_NET_APP_DTLS */ #endif /* CONFIG_LWM2M_DTLS_SUPPORT */ -#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; -#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/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index c12fe3033e2..9aeae0d2c1e 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -15,8 +15,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 @@ -3406,9 +3404,8 @@ error: 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, struct net_pkt *pkt, + udp_request_handler_cb_t udp_request_handler) { struct lwm2m_message *msg = NULL; struct net_udp_hdr hdr, *udp_hdr; @@ -3495,7 +3492,7 @@ 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"); return; @@ -3567,7 +3564,7 @@ static void udp_receive(struct net_app_ctx *app_ctx, struct net_pkt *pkt, struct lwm2m_ctx, net_app_ctx); - lwm2m_udp_receive(client_ctx, pkt, false, handle_request); + lwm2m_udp_receive(client_ctx, pkt, handle_request); } static void retransmit_request(struct k_work *work) @@ -3902,13 +3899,11 @@ static int setup_cert(struct net_app_ctx *app_ctx, void *cert) } #endif /* CONFIG_NET_APP_DTLS */ -int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, - char *peer_str, u16_t peer_port) +int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx, + char *peer_str, u16_t peer_port) { struct sockaddr client_addr; - int ret = 0; - - /* TODO: use security object for initial setup */ + int ret; /* setup the local client port */ (void)memset(&client_addr, 0, sizeof(client_addr)); @@ -3931,8 +3926,6 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, goto error_start; } - lwm2m_engine_context_init(client_ctx); - /* set net_app callbacks */ ret = net_app_set_cb(&client_ctx->net_app_ctx, NULL, udp_receive, NULL, NULL); @@ -3942,20 +3935,22 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, } #if defined(CONFIG_NET_APP_DTLS) - ret = net_app_client_tls(&client_ctx->net_app_ctx, - client_ctx->dtls_result_buf, - client_ctx->dtls_result_buf_len, - INSTANCE_INFO, - strlen(INSTANCE_INFO), - setup_cert, - client_ctx->cert_host, - NULL, - client_ctx->dtls_pool, - client_ctx->dtls_stack, - client_ctx->dtls_stack_len); - if (ret < 0) { - LOG_ERR("Cannot init DTLS (%d)", ret); - goto error_start; + if (client_ctx->use_dtls) { + ret = net_app_client_tls(&client_ctx->net_app_ctx, + client_ctx->dtls_result_buf, + client_ctx->dtls_result_buf_len, + INSTANCE_INFO, + strlen(INSTANCE_INFO), + setup_cert, + client_ctx->cert_host, + NULL, + client_ctx->dtls_pool, + client_ctx->dtls_stack, + client_ctx->dtls_stack_len); + if (ret < 0) { + LOG_ERR("Cannot init DTLS (%d)", ret); + goto error_start; + } } #endif @@ -3968,7 +3963,7 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, /* save remote addr */ #if defined(CONFIG_LWM2M_DTLS_SUPPORT) - if (client_ctx->net_app_ctx.dtls.ctx) { + if (client_ctx->use_dtls && client_ctx->net_app_ctx.dtls.ctx) { memcpy(&client_ctx->remote_addr, &client_ctx->net_app_ctx.dtls.ctx->remote, sizeof(client_ctx->remote_addr)); @@ -3979,7 +3974,6 @@ int lwm2m_engine_start(struct lwm2m_ctx *client_ctx, &client_ctx->net_app_ctx.default_ctx->remote, sizeof(client_ctx->remote_addr)); } - return 0; error_start: @@ -3988,6 +3982,63 @@ error_start: return ret; } +int lwm2m_engine_start(struct lwm2m_ctx *client_ctx) +{ + char pathstr[MAX_RESOURCE_LEN]; + char *data_ptr, *peer_str; + u16_t peer_strlen; + u8_t peer_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 **)&data_ptr, + &peer_strlen, &peer_data_flags); + if (ret < 0) { + return ret; + } + + /* TODO: use http parser for URL to get protocol and server */ + + /* walk forward till colon shifting to lower case */ + peer_str = data_ptr; + while (*peer_str != '\0' && *peer_str != ':') { + *peer_str = tolower(*peer_str); + peer_str += 1; + } + + /* check to make sure there was a colon */ + if (*peer_str != ':') { + return -EINVAL; + } + + if (strncmp(data_ptr, "coap:", 5) != 0 && + strncmp(data_ptr, "coaps:", 6) != 0) { + return -EPROTONOSUPPORT; + } + + client_ctx->use_dtls = false; + if (strncmp(data_ptr, "coaps:", 6) == 0) { +#if defined(CONFIG_LWM2M_DTLS_SUPPORT) + client_ctx->use_dtls = true; +#else + return -EPROTONOSUPPORT; +#endif /* CONFIG_LWM2M_DTLS_SUPPORT */ + } + + /* skip the colons and slashes */ + while (*peer_str == ':' || *peer_str == '/') { + peer_str += 1; + } + + LOG_DBG("URL: %s", data_ptr); + + lwm2m_engine_context_init(client_ctx); + + return lwm2m_net_app_start(client_ctx, peer_str, + CONFIG_LWM2M_PEER_PORT); +} + static int lwm2m_engine_init(struct device *dev) { (void)memset(block1_contexts, 0, diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 592f6f70529..2c85404dd10 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -88,10 +88,6 @@ 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); @@ -112,4 +108,8 @@ void lwm2m_firmware_set_update_result(u8_t result); u8_t lwm2m_firmware_get_update_result(void); #endif +/* Network API Layer */ +int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx, + char *peer_str, u16_t peer_port); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c index 201fb1ea473..d2c38fee0ce 100644 --- a/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c +++ b/subsys/net/lib/lwm2m/lwm2m_obj_firmware_pull.c @@ -43,13 +43,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) { @@ -409,7 +402,6 @@ 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; @@ -473,22 +465,11 @@ static void firmware_transfer(struct k_work *work) 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 + lwm2m_engine_context_init(&firmware_ctx); + firmware_ctx.handle_separate_response = true; - 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); + ret = lwm2m_net_app_start(&firmware_ctx, &server_addr[off], + parsed_uri.port); server_addr[off + len] = tmp; if (ret < 0) { LOG_ERR("Could not get an UDP context (err:%d)", ret); @@ -499,38 +480,6 @@ static void firmware_transfer(struct k_work *work) 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); - if (ret < 0) { - LOG_ERR("Could not set receive callback (err:%d)", ret); - /* make sure this sets RESULT_CONNECTION_LOST */ - ret = -ENOMSG; - goto cleanup; - } - - 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; - } - - /* save remote addr */ -#if defined(CONFIG_LWM2M_DTLS_SUPPORT) - if (firmware_ctx.net_app_ctx.dtls.ctx) { - memcpy(&firmware_ctx.remote_addr, - &firmware_ctx.net_app_ctx.dtls.ctx->remote, - sizeof(firmware_ctx.remote_addr)); - } else -#endif - { - memcpy(&firmware_ctx.remote_addr, - &firmware_ctx.net_app_ctx.default_ctx->remote, - sizeof(firmware_ctx.remote_addr)); - } /* reset block transfer context */ coap_block_transfer_init(&firmware_block_ctx, lwm2m_default_block_size(), 0); diff --git a/subsys/net/lib/lwm2m/lwm2m_rd_client.c b/subsys/net/lib/lwm2m/lwm2m_rd_client.c index 3eb757a6a9a..cb7e8b794b4 100644 --- a/subsys/net/lib/lwm2m/lwm2m_rd_client.c +++ b/subsys/net/lib/lwm2m/lwm2m_rd_client.c @@ -89,7 +89,7 @@ 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; @@ -360,6 +360,69 @@ static void do_deregister_timeout_cb(struct lwm2m_message *msg) sm_handle_timeout_state(msg, ENGINE_INIT); } +static int sm_select_next_sec_inst(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 (temp == false) { + 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) @@ -590,9 +653,29 @@ static int sm_do_registration(void) { int ret = 0; - if (client.use_registration && - !sm_is_registered() && - client.has_registration_info) { + /* TODO: clear out connection data? */ + + ret = sm_select_next_sec_inst(&client.ctx->sec_obj_inst, + &client.lifetime); + if (ret < 0) { + set_sm_state(ENGINE_INIT); + return -EINVAL; + } + + if (client.lifetime == 0) { + client.lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME; + } + + 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); @@ -735,27 +818,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; - } - - /* 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)