blob: ede59bbe8876581abd863395f8986508f960d895 [file] [log] [blame]
/*
* Copyright (c) 2017 Linaro Limited
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* Copyright (c) 2015, Yanzi Networks AB.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Original authors:
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
* Joel Hoglund <joel@sics.se>
*/
#define SYS_LOG_DOMAIN "lib/lwm2m_rd_client"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_LWM2M_LEVEL
#include <logging/sys_log.h>
#include <zephyr/types.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <init.h>
#include <misc/printk.h>
#include <net/net_pkt.h>
#include <net/zoap.h>
#include <net/lwm2m.h>
#include "lwm2m_object.h"
#include "lwm2m_engine.h"
#define LWM2M_RD_CLIENT_URI "rd"
#define SECONDS_TO_UPDATE_EARLY 2
#define STATE_MACHINE_UPDATE_INTERVAL 500
#define LWM2M_PEER_PORT CONFIG_LWM2M_PEER_PORT
#define LWM2M_BOOTSTRAP_PORT CONFIG_LWM2M_BOOTSTRAP_PORT
/* Leave room for 32 hexadeciaml digits (UUID) + NULL */
#define CLIENT_EP_LEN 33
/* The states for the RD client state machine */
/*
* When node is unregistered it ends up in UNREGISTERED
* and this is going to be there until use X or Y kicks it
* back into INIT again
*/
enum sm_engine_state {
ENGINE_INIT,
ENGINE_DO_BOOTSTRAP,
ENGINE_BOOTSTRAP_SENT,
ENGINE_BOOTSTRAP_DONE,
ENGINE_DO_REGISTRATION,
ENGINE_REGISTRATION_SENT,
ENGINE_REGISTRATION_DONE,
ENGINE_UPDATE_SENT,
ENGINE_DEREGISTER,
ENGINE_DEREGISTER_SENT,
ENGINE_DEREGISTER_FAILED,
ENGINE_DEREGISTERED
};
struct lwm2m_rd_client_info {
u16_t lifetime;
struct net_context *net_ctx;
struct sockaddr bs_server;
struct sockaddr reg_server;
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 registered;
u8_t bootstrapped; /* bootstrap done */
u8_t trigger_update;
s64_t last_update;
char ep_name[CLIENT_EP_LEN];
char server_ep[CLIENT_EP_LEN];
};
static K_THREAD_STACK_DEFINE(lwm2m_rd_client_thread_stack,
CONFIG_LWM2M_RD_CLIENT_STACK_SIZE);
struct k_thread lwm2m_rd_client_thread_data;
/* HACK: remove when engine transactions are ready */
#define NUM_PENDINGS CONFIG_LWM2M_ENGINE_MAX_PENDING
#define NUM_REPLIES CONFIG_LWM2M_ENGINE_MAX_REPLIES
extern struct zoap_pending pendings[NUM_PENDINGS];
extern struct zoap_reply replies[NUM_REPLIES];
extern struct k_delayed_work retransmit_work;
/* buffers */
static char query_buffer[64]; /* allocate some data for queries and updates */
static u8_t client_data[256]; /* allocate some data for the RD */
#define CLIENT_INSTANCE_COUNT CONFIG_LWM2M_RD_CLIENT_INSTANCE_COUNT
static struct lwm2m_rd_client_info clients[CLIENT_INSTANCE_COUNT];
static int client_count;
static void set_sm_state(int index, u8_t state)
{
/* TODO: add locking? */
clients[index].engine_state = state;
}
static u8_t get_sm_state(int index)
{
/* TODO: add locking? */
return clients[index].engine_state;
}
static int find_clients_index(const struct sockaddr *addr,
bool check_bs_server)
{
int index = -1, i;
for (i = 0; i < client_count; i++) {
if (check_bs_server) {
if (memcmp(addr, &clients[i].bs_server,
sizeof(addr)) == 0) {
index = i;
break;
}
} else {
if (memcmp(addr, &clients[i].reg_server,
sizeof(addr)) == 0) {
index = i;
break;
}
}
}
return index;
}
/* force re-update with remote peer(s) */
void engine_trigger_update(void)
{
int index;
for (index = 0; index < client_count; index++) {
/* TODO: add locking? */
clients[index].trigger_update = 1;
}
}
/* state machine reply callbacks */
static int do_bootstrap_reply_cb(const struct zoap_packet *response,
struct zoap_reply *reply,
const struct sockaddr *from)
{
u8_t code;
int index;
code = zoap_header_get_code(response);
SYS_LOG_DBG("Bootstrap callback (code:%u.%u)",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
index = find_clients_index(from, true);
if (index < 0) {
SYS_LOG_ERR("Bootstrap client index not found.");
return 0;
}
if (code == ZOAP_RESPONSE_CODE_CHANGED) {
SYS_LOG_DBG("Considered done!");
set_sm_state(index, ENGINE_BOOTSTRAP_DONE);
} else if (code == ZOAP_RESPONSE_CODE_NOT_FOUND) {
SYS_LOG_ERR("Failed: NOT_FOUND. Not Retrying.");
set_sm_state(index, ENGINE_DO_REGISTRATION);
} else if (code == ZOAP_RESPONSE_CODE_FORBIDDEN) {
SYS_LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying.");
set_sm_state(index, ENGINE_DO_REGISTRATION);
} else {
/* TODO: Read payload for error message? */
SYS_LOG_ERR("Failed with code %u.%u. Retrying ...",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
set_sm_state(index, ENGINE_INIT);
}
return 0;
}
static int do_registration_reply_cb(const struct zoap_packet *response,
struct zoap_reply *reply,
const struct sockaddr *from)
{
struct zoap_option options[2];
u8_t code;
int ret, index;
code = zoap_header_get_code(response);
SYS_LOG_DBG("Registration callback (code:%u.%u)",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
index = find_clients_index(from, false);
if (index < 0) {
SYS_LOG_ERR("Registration client index not found.");
return 0;
}
/* check state and possibly set registration to done */
if (code == ZOAP_RESPONSE_CODE_CREATED) {
ret = zoap_find_options(response, ZOAP_OPTION_LOCATION_PATH,
options, 2);
if (ret < 0) {
return ret;
}
if (ret < 2) {
SYS_LOG_ERR("Unexpected endpoint data returned.");
return -EINVAL;
}
/* option[0] should be "rd" */
if (options[1].len + 1 > sizeof(clients[index].server_ep)) {
SYS_LOG_ERR("Unexpected length of query: "
"%u (expected %zu)\n",
options[1].len,
sizeof(clients[index].server_ep));
return -EINVAL;
}
memcpy(clients[index].server_ep, options[1].value,
options[1].len);
clients[index].server_ep[options[1].len] = '\0';
set_sm_state(index, ENGINE_REGISTRATION_DONE);
clients[index].registered = 1;
SYS_LOG_INF("Registration Done (EP='%s')",
clients[index].server_ep);
return 0;
} else if (code == ZOAP_RESPONSE_CODE_NOT_FOUND) {
SYS_LOG_ERR("Failed: NOT_FOUND. Not Retrying.");
set_sm_state(index, ENGINE_REGISTRATION_DONE);
return 0;
} else if (code == ZOAP_RESPONSE_CODE_FORBIDDEN) {
SYS_LOG_ERR("Failed: 4.03 - Forbidden. Not Retrying.");
set_sm_state(index, ENGINE_REGISTRATION_DONE);
return 0;
}
/* TODO: Read payload for error message? */
/* Possible error response codes: 4.00 Bad request */
SYS_LOG_ERR("failed with code %u.%u. Re-init network",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
set_sm_state(index, ENGINE_INIT);
return 0;
}
static int do_update_reply_cb(const struct zoap_packet *response,
struct zoap_reply *reply,
const struct sockaddr *from)
{
u8_t code;
int index;
code = zoap_header_get_code(response);
SYS_LOG_DBG("Update callback (code:%u.%u)",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
index = find_clients_index(from, false);
if (index < 0) {
SYS_LOG_ERR("Registration client index not found.");
return 0;
}
/* If NOT_FOUND just continue on */
if ((code == ZOAP_RESPONSE_CODE_CHANGED) ||
(code == ZOAP_RESPONSE_CODE_CREATED)) {
set_sm_state(index, ENGINE_REGISTRATION_DONE);
SYS_LOG_DBG("Update Done");
return 0;
}
/* TODO: Read payload for error message? */
/* Possible error response codes: 4.00 Bad request & 4.04 Not Found */
SYS_LOG_ERR("Failed with code %u.%u. Retrying registration",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
clients[index].registered = 0;
set_sm_state(index, ENGINE_DO_REGISTRATION);
return 0;
}
static int do_deregister_reply_cb(const struct zoap_packet *response,
struct zoap_reply *reply,
const struct sockaddr *from)
{
u8_t code;
int index;
code = zoap_header_get_code(response);
SYS_LOG_DBG("Deregister callback (code:%u.%u)",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
index = find_clients_index(from, false);
if (index < 0) {
SYS_LOG_ERR("Registration clients index not found.");
return 0;
}
if (code == ZOAP_RESPONSE_CODE_DELETED) {
clients[index].registered = 0;
SYS_LOG_DBG("Deregistration success");
set_sm_state(index, ENGINE_DEREGISTERED);
} else {
SYS_LOG_ERR("failed with code %u.%u",
ZOAP_RESPONSE_CODE_CLASS(code),
ZOAP_RESPONSE_CODE_DETAIL(code));
if (get_sm_state(index) == ENGINE_DEREGISTER_SENT) {
set_sm_state(index, ENGINE_DEREGISTER_FAILED);
}
}
return 0;
}
/* state machine step functions */
static int sm_do_init(int index)
{
SYS_LOG_DBG("RD Client started with endpoint "
"'%s' and client lifetime %d",
clients[index].ep_name,
clients[index].lifetime);
/* Zephyr has joined network already */
clients[index].has_registration_info = 1;
clients[index].registered = 0;
clients[index].bootstrapped = 0;
clients[index].trigger_update = 0;
#if defined(CONFIG_LWM2M_BOOTSTRAP_SERVER)
clients[index].use_bootstrap = 1;
#else
clients[index].use_registration = 1;
#endif
if (clients[index].lifetime == 0) {
clients[index].lifetime = CONFIG_LWM2M_ENGINE_DEFAULT_LIFETIME;
}
/* Do bootstrap or registration */
if (clients[index].use_bootstrap) {
set_sm_state(index, ENGINE_DO_BOOTSTRAP);
} else {
set_sm_state(index, ENGINE_DO_REGISTRATION);
}
return 0;
}
static int sm_do_bootstrap(int index)
{
struct zoap_packet request;
struct net_pkt *pkt = NULL;
struct zoap_pending *pending = NULL;
struct zoap_reply *reply = NULL;
int ret = 0;
if (clients[index].use_bootstrap &&
clients[index].bootstrapped == 0 &&
clients[index].has_bs_server_info) {
ret = lwm2m_init_message(clients[index].net_ctx,
&request, &pkt, ZOAP_TYPE_CON,
ZOAP_METHOD_POST, 0, NULL, 0);
if (ret) {
goto cleanup;
}
zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
"bs", strlen("bs"));
snprintf(query_buffer, sizeof(query_buffer) - 1,
"ep=%s", clients[index].ep_name);
zoap_add_option(&request, ZOAP_OPTION_URI_QUERY,
query_buffer, strlen(query_buffer));
pending = lwm2m_init_message_pending(&request,
&clients[index].bs_server,
pendings, NUM_PENDINGS);
if (!pending) {
ret = -ENOMEM;
goto cleanup;
}
reply = zoap_reply_next_unused(replies, NUM_REPLIES);
if (!reply) {
SYS_LOG_ERR("No resources for waiting for replies.");
ret = -ENOMEM;
goto cleanup;
}
zoap_reply_init(reply, &request);
reply->reply = do_bootstrap_reply_cb;
/* log the bootstrap attempt */
SYS_LOG_DBG("Register ID with bootstrap server [%s] as '%s'",
lwm2m_sprint_ip_addr(&clients[index].bs_server),
query_buffer);
ret = lwm2m_udp_sendto(pkt, &clients[index].bs_server);
if (ret < 0) {
SYS_LOG_ERR("Error sending LWM2M packet (err:%d).",
ret);
goto cleanup;
}
zoap_pending_cycle(pending);
k_delayed_work_submit(&retransmit_work, pending->timeout);
set_sm_state(index, ENGINE_BOOTSTRAP_SENT);
}
return ret;
cleanup:
lwm2m_init_message_cleanup(pkt, pending, reply);
return ret;
}
static int sm_bootstrap_done(int index)
{
/* TODO: Fix this */
/* check that we should still use bootstrap */
if (clients[index].use_bootstrap) {
#ifdef CONFIG_LWM2M_SECURITY_OBJ_SUPPORT
int i;
SYS_LOG_DBG("*** Bootstrap - checking for server info ...");
/* get the server URI */
if (sec_data->server_uri_len > 0) {
/* TODO: Write endpoint parsing function */
#if 0
if (!parse_endpoint(sec_data->server_uri,
sec_data->server_uri_len,
&clients[index].reg_server)) {
#else
if (true) {
#endif
SYS_LOG_ERR("Failed to parse URI!");
} else {
clients[index].has_registration_info = 1;
clients[index].registered = 0;
clients[index].bootstrapped++;
}
} else {
SYS_LOG_ERR("** failed to parse URI");
}
/* if we did not register above - then fail this and restart */
if (clients[index].bootstrapped == 0) {
/* Not ready - Retry with the bootstrap server again */
set_sm_state(index, ENGINE_DO_BOOTSTRAP);
} else {
set_sm_state(index, ENGINE_DO_REGISTRATION);
}
} else {
#endif
set_sm_state(index, ENGINE_DO_REGISTRATION);
}
return 0;
}
static int sm_send_registration(int index, bool send_obj_support_data,
zoap_reply_t reply_cb)
{
struct zoap_packet request;
struct net_pkt *pkt = NULL;
struct zoap_pending *pending = NULL;
struct zoap_reply *reply = NULL;
u8_t *payload;
u16_t client_data_len, len;
int ret = 0;
/* remember the last reg time */
clients[index].last_update = k_uptime_get();
ret = lwm2m_init_message(clients[index].net_ctx,
&request, &pkt, ZOAP_TYPE_CON,
ZOAP_METHOD_POST, 0, NULL, 0);
if (ret) {
goto cleanup;
}
zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
LWM2M_RD_CLIENT_URI,
strlen(LWM2M_RD_CLIENT_URI));
if (!clients[index].registered) {
/* include client endpoint in URI QUERY on 1st registration */
snprintf(query_buffer, sizeof(query_buffer) - 1,
"ep=%s", clients[index].ep_name);
zoap_add_option(&request, ZOAP_OPTION_URI_QUERY,
query_buffer, strlen(query_buffer));
} else {
/* include server endpoint in URI PATH otherwise */
zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
clients[index].server_ep,
strlen(clients[index].server_ep));
}
snprintf(query_buffer, sizeof(query_buffer) - 1,
"lt=%d", clients[index].lifetime);
zoap_add_option(&request, ZOAP_OPTION_URI_QUERY,
query_buffer, strlen(query_buffer));
/* TODO: add supported binding query string */
if (send_obj_support_data) {
/* generate the rd data */
client_data_len = lwm2m_get_rd_data(client_data,
sizeof(client_data));
payload = zoap_packet_get_payload(&request, &len);
if (!payload) {
ret = -EINVAL;
goto cleanup;
}
memcpy(payload, client_data, client_data_len);
ret = zoap_packet_set_used(&request, client_data_len);
if (ret) {
goto cleanup;
}
}
pending = lwm2m_init_message_pending(&request,
&clients[index].reg_server,
pendings, NUM_PENDINGS);
if (!pending) {
ret = -ENOMEM;
goto cleanup;
}
reply = zoap_reply_next_unused(replies, NUM_REPLIES);
if (!reply) {
SYS_LOG_ERR("No resources for waiting for replies.");
ret = -ENOMEM;
goto cleanup;
}
zoap_reply_init(reply, &request);
reply->reply = reply_cb;
/* log the registration attempt */
SYS_LOG_DBG("registration sent [%s]",
lwm2m_sprint_ip_addr(&clients[index].reg_server));
ret = lwm2m_udp_sendto(pkt, &clients[index].reg_server);
if (ret < 0) {
SYS_LOG_ERR("Error sending LWM2M packet (err:%d).",
ret);
goto cleanup;
}
zoap_pending_cycle(pending);
k_delayed_work_submit(&retransmit_work, pending->timeout);
return ret;
cleanup:
lwm2m_init_message_cleanup(pkt, pending, reply);
return ret;
}
static int sm_do_registration(int index)
{
int ret = 0;
if (clients[index].use_registration &&
!clients[index].registered &&
clients[index].has_registration_info) {
ret = sm_send_registration(index, true,
do_registration_reply_cb);
if (!ret) {
set_sm_state(index, ENGINE_REGISTRATION_SENT);
} else {
SYS_LOG_ERR("Registration err: %d", ret);
}
}
return ret;
}
static int sm_registration_done(int index)
{
int ret = 0;
bool forced_update;
/* check for lifetime seconds - 1 so that we can update early */
if (clients[index].registered &&
(clients[index].trigger_update ||
((clients[index].lifetime - SECONDS_TO_UPDATE_EARLY) <=
(k_uptime_get() - clients[index].last_update) / 1000))) {
forced_update = clients[index].trigger_update;
clients[index].trigger_update = 0;
ret = sm_send_registration(index, forced_update,
do_update_reply_cb);
if (!ret) {
set_sm_state(index, ENGINE_UPDATE_SENT);
} else {
SYS_LOG_ERR("Registration update err: %d", ret);
}
}
return ret;
}
static int sm_do_deregister(int index)
{
struct zoap_packet request;
struct net_pkt *pkt = NULL;
struct zoap_pending *pending = NULL;
struct zoap_reply *reply = NULL;
int ret;
ret = lwm2m_init_message(clients[index].net_ctx,
&request, &pkt, ZOAP_TYPE_CON,
ZOAP_METHOD_DELETE, 0, NULL, 0);
if (ret) {
goto cleanup;
}
zoap_add_option(&request, ZOAP_OPTION_URI_PATH,
clients[index].server_ep,
strlen(clients[index].server_ep));
pending = lwm2m_init_message_pending(&request,
&clients[index].reg_server,
pendings, NUM_PENDINGS);
if (!pending) {
ret = -ENOMEM;
goto cleanup;
}
reply = zoap_reply_next_unused(replies, NUM_REPLIES);
if (!reply) {
SYS_LOG_ERR("No resources for waiting for replies.");
ret = -ENOMEM;
goto cleanup;
}
zoap_reply_init(reply, &request);
reply->reply = do_deregister_reply_cb;
SYS_LOG_INF("Deregister from '%s'", clients[index].server_ep);
ret = lwm2m_udp_sendto(pkt, &clients[index].reg_server);
if (ret < 0) {
SYS_LOG_ERR("Error sending LWM2M packet (err:%d).",
ret);
goto cleanup;
}
zoap_pending_cycle(pending);
k_delayed_work_submit(&retransmit_work, pending->timeout);
set_sm_state(index, ENGINE_DEREGISTER_SENT);
return ret;
cleanup:
lwm2m_init_message_cleanup(pkt, pending, reply);
return ret;
}
static void lwm2m_rd_client_service(void)
{
int index;
while (true) {
for (index = 0; index < client_count; index++) {
switch (get_sm_state(index)) {
case ENGINE_INIT:
sm_do_init(index);
break;
case ENGINE_DO_BOOTSTRAP:
sm_do_bootstrap(index);
break;
case ENGINE_BOOTSTRAP_SENT:
/* wait for bootstrap to be done */
break;
case ENGINE_BOOTSTRAP_DONE:
sm_bootstrap_done(index);
break;
case ENGINE_DO_REGISTRATION:
sm_do_registration(index);
break;
case ENGINE_REGISTRATION_SENT:
/* wait registration to be done */
break;
case ENGINE_REGISTRATION_DONE:
sm_registration_done(index);
break;
case ENGINE_UPDATE_SENT:
/* wait update to be done */
break;
case ENGINE_DEREGISTER:
sm_do_deregister(index);
break;
case ENGINE_DEREGISTER_SENT:
break;
case ENGINE_DEREGISTER_FAILED:
break;
case ENGINE_DEREGISTERED:
break;
default:
SYS_LOG_ERR("Unhandled state: %d",
get_sm_state(index));
}
k_yield();
}
/*
* TODO: calculate the diff between the start of the loop
* and subtract that from the update interval
*/
k_sleep(K_MSEC(STATE_MACHINE_UPDATE_INTERVAL));
}
}
static bool peer_addr_exist(struct sockaddr *peer_addr)
{
bool ret = false;
int i;
/* look for duplicate peer_addr */
for (i = 0; i < client_count; i++) {
#if defined(CONFIG_NET_IPV6)
if (peer_addr->family == AF_INET6 && net_ipv6_addr_cmp(
&net_sin6(&clients[i].bs_server)->sin6_addr,
&net_sin6(peer_addr)->sin6_addr)) {
ret = true;
break;
}
if (peer_addr->family == AF_INET6 && net_ipv6_addr_cmp(
&net_sin6(&clients[i].reg_server)->sin6_addr,
&net_sin6(peer_addr)->sin6_addr)) {
ret = true;
break;
}
#endif
#if defined(CONFIG_NET_IPV4)
if (peer_addr->family == AF_INET && net_ipv4_addr_cmp(
&net_sin(&clients[i].bs_server)->sin_addr,
&net_sin(peer_addr)->sin_addr)) {
ret = true;
break;
}
if (peer_addr->family == AF_INET && net_ipv4_addr_cmp(
&net_sin(&clients[i].reg_server)->sin_addr,
&net_sin(peer_addr)->sin_addr)) {
ret = true;
break;
}
#endif
}
return ret;
}
static void set_ep_ports(int index)
{
#if defined(CONFIG_NET_IPV6)
if (clients[index].bs_server.family == AF_INET6) {
net_sin6(&clients[index].bs_server)->sin6_port =
htons(LWM2M_BOOTSTRAP_PORT);
}
if (clients[index].reg_server.family == AF_INET6) {
net_sin6(&clients[index].reg_server)->sin6_port =
htons(LWM2M_PEER_PORT);
}
#endif
#if defined(CONFIG_NET_IPV4)
if (clients[index].bs_server.family == AF_INET) {
net_sin(&clients[index].bs_server)->sin_port =
htons(LWM2M_BOOTSTRAP_PORT);
}
if (clients[index].reg_server.family == AF_INET) {
net_sin(&clients[index].reg_server)->sin_port =
htons(LWM2M_PEER_PORT);
}
#endif
}
int lwm2m_rd_client_start(struct net_context *net_ctx,
struct sockaddr *peer_addr,
const char *ep_name)
{
int index;
if (client_count + 1 > CLIENT_INSTANCE_COUNT) {
return -ENOMEM;
}
if (peer_addr_exist(peer_addr)) {
return -EEXIST;
}
/* Server Peer IP information */
/* TODO: use server URI data from security */
index = client_count;
client_count++;
clients[index].net_ctx = net_ctx;
memcpy(&clients[index].reg_server, peer_addr, sizeof(struct sockaddr));
memcpy(&clients[index].bs_server, peer_addr, sizeof(struct sockaddr));
set_ep_ports(index);
set_sm_state(index, ENGINE_INIT);
strncpy(clients[index].ep_name, ep_name, CLIENT_EP_LEN - 1);
SYS_LOG_INF("LWM2M Client: %s", clients[index].ep_name);
return 0;
}
static int lwm2m_rd_client_init(struct device *dev)
{
k_thread_create(&lwm2m_rd_client_thread_data,
&lwm2m_rd_client_thread_stack[0],
K_THREAD_STACK_SIZEOF(lwm2m_rd_client_thread_stack),
(k_thread_entry_t) lwm2m_rd_client_service,
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
SYS_LOG_DBG("LWM2M RD client thread started");
return 0;
}
SYS_INIT(lwm2m_rd_client_init, APPLICATION,
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);