net: lwm2m: migrate LwM2M library to BSD-sockets API
This commit removes the net_app layer from the LwM2M library and replaces it with BSD-sockets APIs. Signed-off-by: Michael Scott <mike@foundries.io>
This commit is contained in:
parent
d7f20f63d8
commit
d1cb39e7ce
5 changed files with 395 additions and 399 deletions
|
@ -8,7 +8,7 @@
|
||||||
#ifndef ZEPHYR_INCLUDE_NET_LWM2M_H_
|
#ifndef ZEPHYR_INCLUDE_NET_LWM2M_H_
|
||||||
#define ZEPHYR_INCLUDE_NET_LWM2M_H_
|
#define ZEPHYR_INCLUDE_NET_LWM2M_H_
|
||||||
|
|
||||||
#include <net/net_app.h>
|
#include <kernel.h>
|
||||||
#include <net/coap_sock.h>
|
#include <net/coap_sock.h>
|
||||||
|
|
||||||
/* LWM2M Objects defined by OMA */
|
/* LWM2M Objects defined by OMA */
|
||||||
|
@ -33,40 +33,19 @@
|
||||||
* @details Context structure for the LwM2M high-level API.
|
* @details Context structure for the LwM2M high-level API.
|
||||||
*
|
*
|
||||||
* @param remote_addr Stored remote IP address of the LwM2M client
|
* @param remote_addr Stored remote IP address of the LwM2M client
|
||||||
* @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.
|
|
||||||
*/
|
*/
|
||||||
struct lwm2m_ctx {
|
struct lwm2m_ctx {
|
||||||
/** destination address storage */
|
/** destination address storage */
|
||||||
struct sockaddr remote_addr;
|
struct sockaddr remote_addr;
|
||||||
|
|
||||||
/** Net app context structure */
|
|
||||||
struct net_app_ctx net_app_ctx;
|
|
||||||
s32_t net_init_timeout;
|
|
||||||
s32_t net_timeout;
|
|
||||||
|
|
||||||
/** Private CoAP and networking structures */
|
/** Private CoAP and networking structures */
|
||||||
struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING];
|
struct coap_pending pendings[CONFIG_LWM2M_ENGINE_MAX_PENDING];
|
||||||
struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES];
|
struct coap_reply replies[CONFIG_LWM2M_ENGINE_MAX_REPLIES];
|
||||||
struct k_delayed_work retransmit_work;
|
struct k_delayed_work retransmit_work;
|
||||||
|
|
||||||
#if defined(CONFIG_NET_APP_DTLS)
|
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
|
||||||
/** Pre-Shared Key Information*/
|
/** DTLS settings */
|
||||||
unsigned char *client_psk;
|
int tls_tag;
|
||||||
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;
|
|
||||||
#endif
|
#endif
|
||||||
bool use_dtls;
|
bool use_dtls;
|
||||||
|
|
||||||
|
@ -76,6 +55,9 @@ struct lwm2m_ctx {
|
||||||
|
|
||||||
/** Packet Flow Settings */
|
/** Packet Flow Settings */
|
||||||
bool handle_separate_response;
|
bool handle_separate_response;
|
||||||
|
|
||||||
|
/** Socket File Descriptor */
|
||||||
|
int sock_fd;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
|
typedef void *(*lwm2m_engine_get_data_cb_t)(u16_t obj_inst_id,
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
menuconfig LWM2M
|
menuconfig LWM2M
|
||||||
bool "OMA LWM2M protocol stack"
|
bool "OMA LWM2M protocol stack"
|
||||||
select COAP
|
select COAP
|
||||||
select NET_APP_CLIENT
|
|
||||||
select HTTP_PARSER_URL
|
select HTTP_PARSER_URL
|
||||||
|
select NET_SOCKETS
|
||||||
|
select NET_SOCKETS_POSIX_NAMES
|
||||||
help
|
help
|
||||||
This option adds logic for managing OMA LWM2M data
|
This option adds logic for managing OMA LWM2M data
|
||||||
|
|
||||||
|
@ -23,7 +24,9 @@ config LWM2M_DTLS_SUPPORT
|
||||||
bool "Enable DTLS support in the LwM2M client"
|
bool "Enable DTLS support in the LwM2M client"
|
||||||
select MBEDTLS
|
select MBEDTLS
|
||||||
select MBEDTLS_ENABLE_HEAP
|
select MBEDTLS_ENABLE_HEAP
|
||||||
select NET_APP_DTLS
|
select TLS_CREDENTIALS
|
||||||
|
select NET_SOCKETS_SOCKOPT_TLS
|
||||||
|
select NET_SOCKETS_ENABLE_DTLS
|
||||||
|
|
||||||
config LWM2M_ENGINE_STACK_SIZE
|
config LWM2M_ENGINE_STACK_SIZE
|
||||||
int "LWM2M engine stack size"
|
int "LWM2M engine stack size"
|
||||||
|
|
|
@ -33,10 +33,11 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
#include <init.h>
|
#include <init.h>
|
||||||
#include <misc/printk.h>
|
#include <misc/printk.h>
|
||||||
#include <net/net_ip.h>
|
#include <net/net_ip.h>
|
||||||
#include <net/udp.h>
|
#include <net/http_parser_url.h>
|
||||||
|
#include <net/socket.h>
|
||||||
#include <net/net_pkt.h>
|
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
|
||||||
#include <net/net_app.h>
|
#include <net/tls_credentials.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lwm2m_object.h"
|
#include "lwm2m_object.h"
|
||||||
#include "lwm2m_engine.h"
|
#include "lwm2m_engine.h"
|
||||||
|
@ -73,10 +74,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
#define REG_PREFACE ""
|
#define REG_PREFACE ""
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(CONFIG_NET_APP_DTLS)
|
|
||||||
#define INSTANCE_INFO "Zephyr DTLS LwM2M-client"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN)
|
#if defined(CONFIG_COAP_EXTENDED_OPTIONS_LEN)
|
||||||
#define COAP_OPTION_BUF_LEN (CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE + 1)
|
#define COAP_OPTION_BUF_LEN (CONFIG_COAP_EXTENDED_OPTIONS_LEN_VALUE + 1)
|
||||||
#else
|
#else
|
||||||
|
@ -131,6 +128,16 @@ static sys_slist_t engine_obj_inst_list;
|
||||||
static sys_slist_t engine_observer_list;
|
static sys_slist_t engine_observer_list;
|
||||||
static sys_slist_t engine_service_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
|
#define NUM_BLOCK1_CONTEXT CONFIG_LWM2M_NUM_BLOCK1_CONTEXT
|
||||||
|
|
||||||
/* TODO: figure out what's correct value */
|
/* TODO: figure out what's correct value */
|
||||||
|
@ -1014,7 +1021,6 @@ cleanup:
|
||||||
|
|
||||||
int lwm2m_send_message(struct lwm2m_message *msg)
|
int lwm2m_send_message(struct lwm2m_message *msg)
|
||||||
{
|
{
|
||||||
struct net_pkt *pkt;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!msg || !msg->ctx) {
|
if (!msg || !msg->ctx) {
|
||||||
|
@ -1028,30 +1034,12 @@ int lwm2m_send_message(struct lwm2m_message *msg)
|
||||||
|
|
||||||
msg->send_attempts++;
|
msg->send_attempts++;
|
||||||
|
|
||||||
pkt = net_app_get_net_pkt(&msg->ctx->net_app_ctx, AF_UNSPEC,
|
ret = send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0);
|
||||||
BUF_ALLOC_TIMEOUT);
|
|
||||||
if (!pkt) {
|
|
||||||
LOG_ERR("Unable to get TX packet, not enough memory.");
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net_pkt_append(pkt, msg->cpkt.offset, msg->cpkt.data,
|
|
||||||
BUF_ALLOC_TIMEOUT)) {
|
|
||||||
LOG_ERR("Unable to add packet data, not enough memory.");
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = net_app_send_pkt(&msg->ctx->net_app_ctx, pkt,
|
|
||||||
&msg->ctx->remote_addr,
|
|
||||||
NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
if (msg->type == COAP_TYPE_CON) {
|
if (msg->type == COAP_TYPE_CON) {
|
||||||
coap_pending_clear(msg->pending);
|
coap_pending_clear(msg->pending);
|
||||||
}
|
}
|
||||||
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1067,13 +1055,6 @@ int lwm2m_send_message(struct lwm2m_message *msg)
|
||||||
lwm2m_reset_message(msg, true);
|
lwm2m_reset_message(msg, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (pkt) {
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3458,60 +3439,20 @@ error:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
|
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)
|
udp_request_handler_cb_t udp_request_handler)
|
||||||
{
|
{
|
||||||
struct lwm2m_message *msg = NULL;
|
struct lwm2m_message *msg = NULL;
|
||||||
struct net_udp_hdr hdr, *udp_hdr;
|
|
||||||
struct coap_pending *pending;
|
struct coap_pending *pending;
|
||||||
struct coap_reply *reply;
|
struct coap_reply *reply;
|
||||||
struct coap_packet response;
|
struct coap_packet response;
|
||||||
struct sockaddr from_addr;
|
|
||||||
static u8_t in_buf[NET_IPV6_MTU];
|
|
||||||
size_t recv_len;
|
|
||||||
int r;
|
int r;
|
||||||
u8_t token[8];
|
u8_t token[8];
|
||||||
u8_t tkl;
|
u8_t tkl;
|
||||||
|
|
||||||
udp_hdr = net_udp_get_hdr(pkt, &hdr);
|
r = coap_packet_parse(&response, buf, buf_len, NULL, 0);
|
||||||
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
|
|
||||||
|
|
||||||
/* copy data from pkt */
|
|
||||||
recv_len = net_pkt_appdatalen(pkt);
|
|
||||||
if (recv_len > sizeof(in_buf)) {
|
|
||||||
recv_len = sizeof(in_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)net_frag_linearize(in_buf, recv_len, pkt,
|
|
||||||
net_pkt_appdata(pkt) - pkt->frags->data,
|
|
||||||
recv_len);
|
|
||||||
|
|
||||||
/* now that we have data, free pkt */
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
|
|
||||||
r = coap_packet_parse(&response, in_buf, recv_len, NULL, 0);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
LOG_ERR("Invalid data received (err:%d)", r);
|
LOG_ERR("Invalid data received (err:%d)", r);
|
||||||
return;
|
return;
|
||||||
|
@ -3531,8 +3472,8 @@ static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *pkt,
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG("checking for reply from [%s]",
|
LOG_DBG("checking for reply from [%s]",
|
||||||
lwm2m_sprint_ip_addr(&from_addr));
|
lwm2m_sprint_ip_addr(from_addr));
|
||||||
reply = coap_response_received(&response, &from_addr,
|
reply = coap_response_received(&response, from_addr,
|
||||||
client_ctx->replies,
|
client_ctx->replies,
|
||||||
CONFIG_LWM2M_ENGINE_MAX_REPLIES);
|
CONFIG_LWM2M_ENGINE_MAX_REPLIES);
|
||||||
if (reply) {
|
if (reply) {
|
||||||
|
@ -3611,19 +3552,8 @@ static void lwm2m_udp_receive(struct lwm2m_ctx *client_ctx, struct net_pkt *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, handle_request);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void retransmit_request(struct k_work *work)
|
static void retransmit_request(struct k_work *work)
|
||||||
{
|
{
|
||||||
struct net_pkt *pkt;
|
|
||||||
struct lwm2m_ctx *client_ctx;
|
struct lwm2m_ctx *client_ctx;
|
||||||
struct lwm2m_message *msg;
|
struct lwm2m_message *msg;
|
||||||
struct coap_pending *pending;
|
struct coap_pending *pending;
|
||||||
|
@ -3658,43 +3588,13 @@ static void retransmit_request(struct k_work *work)
|
||||||
|
|
||||||
LOG_DBG("Resending message: %p", msg);
|
LOG_DBG("Resending message: %p", msg);
|
||||||
msg->send_attempts++;
|
msg->send_attempts++;
|
||||||
|
r = send(msg->ctx->sock_fd, msg->cpkt.data, msg->cpkt.offset, 0);
|
||||||
pkt = net_app_get_net_pkt(&msg->ctx->net_app_ctx, AF_UNSPEC,
|
|
||||||
BUF_ALLOC_TIMEOUT);
|
|
||||||
if (!pkt) {
|
|
||||||
LOG_ERR("Unable to get TX packet, not enough memory.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!net_pkt_append(pkt, msg->cpkt.offset, msg->cpkt.data,
|
|
||||||
BUF_ALLOC_TIMEOUT)) {
|
|
||||||
LOG_ERR("Unable to add packet data, not enough memory.");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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, pkt,
|
|
||||||
&msg->ctx->remote_addr,
|
|
||||||
NET_SOCKADDR_MAX_SIZE, K_NO_WAIT, NULL);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
LOG_ERR("Error sending lwm2m message: %d", r);
|
LOG_ERR("Error sending lwm2m message: %d", r);
|
||||||
/* don't error here, retry until timeout */
|
/* don't error here, retry until timeout */
|
||||||
net_pkt_unref(pkt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
k_delayed_work_submit(&client_ctx->retransmit_work, pending->timeout);
|
k_delayed_work_submit(&client_ctx->retransmit_work, pending->timeout);
|
||||||
return;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (pkt) {
|
|
||||||
net_pkt_unref(pkt);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int notify_message_reply_cb(const struct coap_packet *response,
|
static int notify_message_reply_cb(const struct coap_packet *response,
|
||||||
|
@ -3926,10 +3826,16 @@ static void lwm2m_engine_service(struct k_work *work)
|
||||||
|
|
||||||
int lwm2m_engine_context_close(struct lwm2m_ctx *client_ctx)
|
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);
|
k_delayed_work_cancel(&client_ctx->retransmit_work);
|
||||||
net_app_close(&client_ctx->net_app_ctx);
|
lwm2m_socket_del(client_ctx);
|
||||||
net_app_release(&client_ctx->net_app_ctx);
|
client_ctx->sock_fd = -1;
|
||||||
return 0;
|
if (sock_fd >= 0) {
|
||||||
|
return close(sock_fd);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
|
void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
|
||||||
|
@ -3937,162 +3843,315 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx)
|
||||||
k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request);
|
k_delayed_work_init(&client_ctx->retransmit_work, retransmit_request);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_NET_APP_DTLS)
|
/* LwM2M Socket Integration */
|
||||||
static int setup_cert(struct net_app_ctx *app_ctx, void *cert)
|
|
||||||
|
int lwm2m_socket_add(struct lwm2m_ctx *ctx)
|
||||||
{
|
{
|
||||||
#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED)
|
int i;
|
||||||
struct lwm2m_ctx *client_ctx = CONTAINER_OF(app_ctx,
|
|
||||||
struct lwm2m_ctx,
|
if (sock_nfds < MAX_POLL_FD) {
|
||||||
net_app_ctx);
|
i = sock_nfds++;
|
||||||
return mbedtls_ssl_conf_psk(
|
} else {
|
||||||
&app_ctx->tls.mbedtls.conf,
|
for (i = 0; i < MAX_POLL_FD; i++) {
|
||||||
(const unsigned char *)client_ctx->client_psk,
|
if (sock_ctx[i] == NULL) {
|
||||||
client_ctx->client_psk_len,
|
goto found;
|
||||||
(const unsigned char *)client_ctx->client_psk_id,
|
}
|
||||||
client_ctx->client_psk_id_len);
|
}
|
||||||
#else
|
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
found:
|
||||||
|
sock_ctx[i] = ctx;
|
||||||
|
sock_fds[i].fd = ctx->sock_fd;
|
||||||
|
sock_fds[i].events = POLLIN;
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_NET_APP_DTLS */
|
|
||||||
|
|
||||||
int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx,
|
void lwm2m_socket_del(struct lwm2m_ctx *ctx)
|
||||||
char *peer_str, u16_t peer_port)
|
|
||||||
{
|
{
|
||||||
struct sockaddr client_addr;
|
for (int i = 0; i < sock_nfds; i++) {
|
||||||
int ret;
|
if (sock_ctx[i] == ctx) {
|
||||||
|
sock_ctx[i] = NULL;
|
||||||
/* setup the local client port */
|
sock_fds[i].fd = -1;
|
||||||
(void)memset(&client_addr, 0, sizeof(client_addr));
|
sock_nfds--;
|
||||||
#if defined(CONFIG_NET_IPV6)
|
break;
|
||||||
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
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
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
|
}
|
||||||
|
|
||||||
ret = net_app_connect(&client_ctx->net_app_ctx,
|
/* LwM2M main work loop */
|
||||||
client_ctx->net_timeout);
|
|
||||||
if (ret < 0) {
|
static void socket_receive_loop(void)
|
||||||
LOG_ERR("Cannot connect UDP (%d)", ret);
|
{
|
||||||
goto error_start;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* save remote addr */
|
|
||||||
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
|
#if defined(CONFIG_LWM2M_DTLS_SUPPORT)
|
||||||
if (client_ctx->use_dtls && client_ctx->net_app_ctx.dtls.ctx) {
|
static int load_tls_credential(struct lwm2m_ctx *client_ctx, u16_t res_id,
|
||||||
memcpy(&client_ctx->remote_addr,
|
enum tls_credential_type type)
|
||||||
&client_ctx->net_app_ctx.dtls.ctx->remote,
|
{
|
||||||
sizeof(client_ctx->remote_addr));
|
int ret = 0;
|
||||||
} else
|
void *cred = NULL;
|
||||||
#endif
|
u16_t cred_len;
|
||||||
{
|
u8_t cred_flags;
|
||||||
memcpy(&client_ctx->remote_addr,
|
char pathstr[MAX_RESOURCE_LEN];
|
||||||
&client_ctx->net_app_ctx.default_ctx->remote,
|
|
||||||
sizeof(client_ctx->remote_addr));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error_start:
|
/* ignore error value */
|
||||||
lwm2m_engine_context_close(client_ctx);
|
tls_credential_delete(client_ctx->tls_tag, type);
|
||||||
|
|
||||||
|
snprintk(pathstr, sizeof(pathstr), "0/%d/%u", client_ctx->sec_obj_inst,
|
||||||
|
res_id);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set correct PSK_ID length */
|
||||||
|
if (type == TLS_CREDENTIAL_PSK_ID) {
|
||||||
|
cred_len = strlen(cred);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tls_credential_add(client_ctx->tls_tag, type, cred, cred_len);
|
||||||
|
if (ret < 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = load_tls_credential(client_ctx, 5, TLS_CREDENTIAL_PSK);
|
||||||
|
if (ret < 0) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lwm2m_parse_peerinfo(char *url, struct sockaddr *addr, bool *use_dtls)
|
||||||
|
{
|
||||||
|
struct http_parser_url parser;
|
||||||
|
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) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx)
|
int lwm2m_engine_start(struct lwm2m_ctx *client_ctx)
|
||||||
{
|
{
|
||||||
char pathstr[MAX_RESOURCE_LEN];
|
char pathstr[MAX_RESOURCE_LEN];
|
||||||
char *data_ptr, *peer_str;
|
char *url;
|
||||||
u16_t peer_strlen;
|
u16_t url_len;
|
||||||
u8_t peer_data_flags;
|
u8_t url_data_flags;
|
||||||
int ret = 0U;
|
int ret = 0U;
|
||||||
|
|
||||||
/* get the server URL */
|
/* get the server URL */
|
||||||
snprintk(pathstr, sizeof(pathstr), "0/%d/0", client_ctx->sec_obj_inst);
|
snprintk(pathstr, sizeof(pathstr), "0/%d/0", client_ctx->sec_obj_inst);
|
||||||
ret = lwm2m_engine_get_res_data(pathstr, (void **)&data_ptr,
|
ret = lwm2m_engine_get_res_data(pathstr, (void **)&url, &url_len,
|
||||||
&peer_strlen, &peer_data_flags);
|
&url_data_flags);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: use http parser for URL to get protocol and server */
|
url[url_len] = '\0';
|
||||||
|
ret = lwm2m_parse_peerinfo(url, &client_ctx->remote_addr,
|
||||||
/* walk forward till colon shifting to lower case */
|
&client_ctx->use_dtls);
|
||||||
peer_str = data_ptr;
|
if (ret < 0) {
|
||||||
while (*peer_str != '\0' && *peer_str != ':') {
|
return ret;
|
||||||
*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);
|
lwm2m_engine_context_init(client_ctx);
|
||||||
|
return lwm2m_socket_start(client_ctx);
|
||||||
return lwm2m_net_app_start(client_ctx, peer_str,
|
|
||||||
CONFIG_LWM2M_PEER_PORT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lwm2m_engine_init(struct device *dev)
|
static int lwm2m_engine_init(struct device *dev)
|
||||||
|
@ -4100,6 +4159,18 @@ static int lwm2m_engine_init(struct device *dev)
|
||||||
(void)memset(block1_contexts, 0,
|
(void)memset(block1_contexts, 0,
|
||||||
sizeof(struct block_context) * NUM_BLOCK1_CONTEXT);
|
sizeof(struct block_context) * NUM_BLOCK1_CONTEXT);
|
||||||
|
|
||||||
|
/* 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) 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-sock-recv");
|
||||||
|
LOG_DBG("LWM2M engine socket receive thread started");
|
||||||
|
|
||||||
k_delayed_work_init(&periodic_work, lwm2m_engine_service);
|
k_delayed_work_init(&periodic_work, lwm2m_engine_service);
|
||||||
k_delayed_work_submit(&periodic_work, K_MSEC(2000));
|
k_delayed_work_submit(&periodic_work, K_MSEC(2000));
|
||||||
LOG_DBG("LWM2M engine periodic work started");
|
LOG_DBG("LWM2M engine periodic work started");
|
||||||
|
|
|
@ -109,8 +109,10 @@ void lwm2m_firmware_set_update_result(u8_t result);
|
||||||
u8_t lwm2m_firmware_get_update_result(void);
|
u8_t lwm2m_firmware_get_update_result(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Network API Layer */
|
/* Network Layer */
|
||||||
int lwm2m_net_app_start(struct lwm2m_ctx *client_ctx,
|
int lwm2m_socket_add(struct lwm2m_ctx *ctx);
|
||||||
char *peer_str, u16_t peer_port);
|
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 */
|
#endif /* LWM2M_ENGINE_H */
|
||||||
|
|
|
@ -16,7 +16,7 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <net/http_parser.h>
|
#include <net/http_parser.h>
|
||||||
#include <net/net_app.h>
|
#include <net/socket.h>
|
||||||
|
|
||||||
#include "lwm2m_object.h"
|
#include "lwm2m_object.h"
|
||||||
#include "lwm2m_engine.h"
|
#include "lwm2m_engine.h"
|
||||||
|
@ -29,7 +29,6 @@ LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
||||||
|
|
||||||
static struct k_work firmware_work;
|
static struct k_work firmware_work;
|
||||||
static char firmware_uri[URI_LEN];
|
static char firmware_uri[URI_LEN];
|
||||||
static struct http_parser_url parsed_uri;
|
|
||||||
static struct lwm2m_ctx firmware_ctx;
|
static struct lwm2m_ctx firmware_ctx;
|
||||||
static int firmware_retry;
|
static int firmware_retry;
|
||||||
static struct coap_block_context firmware_block_ctx;
|
static struct coap_block_context firmware_block_ctx;
|
||||||
|
@ -68,14 +67,11 @@ static int transfer_request(struct coap_block_context *ctx,
|
||||||
{
|
{
|
||||||
struct lwm2m_message *msg;
|
struct lwm2m_message *msg;
|
||||||
int ret;
|
int ret;
|
||||||
u16_t off;
|
|
||||||
u16_t len;
|
|
||||||
char *cursor;
|
char *cursor;
|
||||||
#if !defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
#if !defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
||||||
int i;
|
struct http_parser_url parser;
|
||||||
int path_len;
|
u16_t off, len;
|
||||||
#else
|
char *next_slash;
|
||||||
char *uri_path;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
msg = lwm2m_get_message(&firmware_ctx);
|
msg = lwm2m_get_message(&firmware_ctx);
|
||||||
|
@ -99,22 +95,11 @@ static int transfer_request(struct coap_block_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
||||||
/* if path is not available, off/len will be zero */
|
/* TODO: shift to lower case */
|
||||||
off = parsed_uri.field_data[UF_SCHEMA].off;
|
if (strncmp(firmware_uri, "http", 4) == 0) {
|
||||||
len = parsed_uri.field_data[UF_SCHEMA].len;
|
cursor = COAP2HTTP_PROXY_URI_PATH;
|
||||||
cursor = firmware_uri + off;
|
} else if (strncmp(firmware_uri, "coap", 4) == 0) {
|
||||||
|
cursor = COAP2COAP_PROXY_URI_PATH;
|
||||||
/* 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;
|
|
||||||
} else {
|
} else {
|
||||||
ret = -EPROTONOSUPPORT;
|
ret = -EPROTONOSUPPORT;
|
||||||
LOG_ERR("Unsupported schema");
|
LOG_ERR("Unsupported schema");
|
||||||
|
@ -122,50 +107,53 @@ static int transfer_request(struct coap_block_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
|
ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_PATH,
|
||||||
uri_path, strlen(uri_path));
|
cursor, strlen(cursor));
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_ERR("Error adding URI_PATH '%s'", uri_path);
|
LOG_ERR("Error adding URI_PATH '%s'", cursor);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
#else
|
#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 */
|
/* if path is not available, off/len will be zero */
|
||||||
off = parsed_uri.field_data[UF_PATH].off;
|
off = parser.field_data[UF_PATH].off;
|
||||||
len = parsed_uri.field_data[UF_PATH].len;
|
len = parser.field_data[UF_PATH].len;
|
||||||
cursor = firmware_uri + off;
|
cursor = firmware_uri + off;
|
||||||
path_len = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
/* add path portions (separated by slashes) */
|
||||||
if (firmware_uri[off + i] == '/') {
|
while (len > 0 && (next_slash = strchr(cursor, '/')) != NULL) {
|
||||||
if (path_len > 0) {
|
if (next_slash != cursor) {
|
||||||
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 */
|
|
||||||
ret = coap_packet_append_option(&msg->cpkt,
|
ret = coap_packet_append_option(&msg->cpkt,
|
||||||
COAP_OPTION_URI_PATH,
|
COAP_OPTION_URI_PATH,
|
||||||
cursor, path_len + 1);
|
cursor,
|
||||||
|
next_slash - cursor);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_ERR("Error adding URI_PATH");
|
LOG_ERR("Error adding URI_PATH");
|
||||||
goto cleanup;
|
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
|
#endif
|
||||||
|
|
||||||
|
@ -402,15 +390,9 @@ static void do_transmit_timeout_cb(struct lwm2m_message *msg)
|
||||||
|
|
||||||
static void firmware_transfer(struct k_work *work)
|
static void firmware_transfer(struct k_work *work)
|
||||||
{
|
{
|
||||||
int ret, family;
|
int ret;
|
||||||
u16_t off;
|
|
||||||
u16_t len;
|
|
||||||
char tmp;
|
|
||||||
char *server_addr;
|
char *server_addr;
|
||||||
|
|
||||||
/* Server Peer IP information */
|
|
||||||
family = AF_INET;
|
|
||||||
|
|
||||||
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
#if defined(CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_SUPPORT)
|
||||||
server_addr = CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_ADDR;
|
server_addr = CONFIG_LWM2M_FIRMWARE_UPDATE_PULL_COAP_PROXY_ADDR;
|
||||||
if (strlen(server_addr) >= URI_LEN) {
|
if (strlen(server_addr) >= URI_LEN) {
|
||||||
|
@ -426,59 +408,21 @@ static void firmware_transfer(struct k_work *work)
|
||||||
server_addr = firmware_uri;
|
server_addr = firmware_uri;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
http_parser_url_init(&parsed_uri);
|
ret = lwm2m_parse_peerinfo(server_addr, &firmware_ctx.remote_addr,
|
||||||
ret = http_parser_parse_url(server_addr,
|
&firmware_ctx.use_dtls);
|
||||||
strlen(server_addr),
|
if (ret < 0) {
|
||||||
0,
|
|
||||||
&parsed_uri);
|
|
||||||
if (ret != 0) {
|
|
||||||
LOG_ERR("Invalid firmware URI: %s", server_addr);
|
|
||||||
ret = -ENOTSUP;
|
|
||||||
goto error;
|
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';
|
|
||||||
|
|
||||||
lwm2m_engine_context_init(&firmware_ctx);
|
lwm2m_engine_context_init(&firmware_ctx);
|
||||||
firmware_ctx.handle_separate_response = true;
|
firmware_ctx.handle_separate_response = true;
|
||||||
|
ret = lwm2m_socket_start(&firmware_ctx);
|
||||||
ret = lwm2m_net_app_start(&firmware_ctx, &server_addr[off],
|
|
||||||
parsed_uri.port);
|
|
||||||
server_addr[off + len] = tmp;
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
LOG_ERR("Could not get an UDP context (err:%d)", ret);
|
LOG_ERR("Cannot start a firmware-pull connection:%d", ret);
|
||||||
ret = -ENOMSG;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INF("Connecting to server %s, port %d", server_addr + off,
|
LOG_INF("Connecting to server %s", firmware_uri);
|
||||||
parsed_uri.port);
|
|
||||||
|
|
||||||
/* reset block transfer context */
|
/* reset block transfer context */
|
||||||
coap_block_transfer_init(&firmware_block_ctx,
|
coap_block_transfer_init(&firmware_block_ctx,
|
||||||
|
@ -486,15 +430,11 @@ static void firmware_transfer(struct k_work *work)
|
||||||
ret = transfer_request(&firmware_block_ctx, coap_next_token(), 8,
|
ret = transfer_request(&firmware_block_ctx, coap_next_token(), 8,
|
||||||
do_firmware_transfer_reply_cb);
|
do_firmware_transfer_reply_cb);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto cleanup;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cleanup:
|
|
||||||
net_app_close(&firmware_ctx.net_app_ctx);
|
|
||||||
net_app_release(&firmware_ctx.net_app_ctx);
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
set_update_result_from_error(ret);
|
set_update_result_from_error(ret);
|
||||||
}
|
}
|
||||||
|
@ -507,16 +447,14 @@ int lwm2m_firmware_cancel_transfer(void)
|
||||||
|
|
||||||
int lwm2m_firmware_start_transfer(char *package_uri)
|
int lwm2m_firmware_start_transfer(char *package_uri)
|
||||||
{
|
{
|
||||||
/* free up old context */
|
/* close old socket */
|
||||||
if (firmware_ctx.net_app_ctx.is_init) {
|
if (firmware_ctx.sock_fd > 0) {
|
||||||
net_app_close(&firmware_ctx.net_app_ctx);
|
lwm2m_socket_del(&firmware_ctx);
|
||||||
net_app_release(&firmware_ctx.net_app_ctx);
|
close(firmware_ctx.sock_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
(void)memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx));
|
(void)memset(&firmware_ctx, 0, sizeof(struct lwm2m_ctx));
|
||||||
firmware_retry = 0;
|
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);
|
k_work_init(&firmware_work, firmware_transfer);
|
||||||
lwm2m_firmware_set_update_state(STATE_DOWNLOADING);
|
lwm2m_firmware_set_update_state(STATE_DOWNLOADING);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue