mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
pkg/wakaama: add DTLS support
This commit is contained in:
parent
3d012bfd2c
commit
6109e588a5
@ -23,3 +23,13 @@ endif
|
||||
|
||||
# wakaama uses Sock UDP (implemented by some stack)
|
||||
USEMODULE += sock_udp
|
||||
USEMODULE += sock_async_event
|
||||
USEMODULE += sock_util
|
||||
USEMODULE += event_timeout
|
||||
USEMODULE += event_thread
|
||||
USEMODULE += event_thread_medium
|
||||
|
||||
ifneq (,$(filter wakaama_client_dtls, $(USEMODULE)))
|
||||
USEMODULE += sock_dtls
|
||||
USEMODULE += credman_load
|
||||
endif
|
||||
|
@ -18,3 +18,4 @@ ifneq (,$(or $(CONFIG_LWM2M_WITH_LOGS),$(filter -DCONFIG_LWM2M_WITH_LOGS=1,$(CFL
|
||||
endif
|
||||
|
||||
PSEUDOMODULES += wakaama
|
||||
PSEUDOMODULES += wakaama_client_dtls
|
||||
|
@ -21,9 +21,17 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "timex.h"
|
||||
|
||||
#include "liblwm2m.h"
|
||||
#include "uri_parser.h"
|
||||
#include "event/timeout.h"
|
||||
#include "event/thread.h"
|
||||
#include "net/sock/async/event.h"
|
||||
#include "net/sock/util.h"
|
||||
#include "objects/common.h"
|
||||
#include "objects/security.h"
|
||||
#include "objects/device.h"
|
||||
|
||||
#include "lwm2m_platform.h"
|
||||
#include "lwm2m_client.h"
|
||||
@ -34,26 +42,146 @@
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Determines if there has been a reboot request on the device object
|
||||
*
|
||||
* @note This function is implemented in object_device.c
|
||||
*
|
||||
* @return true Reboot has been requested
|
||||
* @return false Reboot has not been requested
|
||||
* @brief Callback for event timeout that performs a step on the LwM2M FSM.
|
||||
*/
|
||||
bool lwm2m_device_reboot_requested(void);
|
||||
static void _lwm2m_step_cb(event_t *arg);
|
||||
|
||||
/**
|
||||
* @brief Thread with the main loop for receiving packets and stepping the LwM2M
|
||||
* FSM.
|
||||
*
|
||||
* @param arg ignored
|
||||
* @brief Callback to handle UDP sock events.
|
||||
*/
|
||||
static void *_lwm2m_client_run(void *arg);
|
||||
static void _udp_event_handler(sock_udp_t *sock, sock_async_flags_t type, void *arg);
|
||||
|
||||
static char _lwm2m_client_stack[THREAD_STACKSIZE_MAIN +
|
||||
THREAD_EXTRA_STACKSIZE_PRINTF];
|
||||
static lwm2m_client_data_t *_client_data;
|
||||
/**
|
||||
* @brief Handle an incoming packet from a remote peer.
|
||||
*/
|
||||
static void _handle_packet_from_remote(const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type, uint8_t *buffer,
|
||||
size_t len);
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
/**
|
||||
* @brief Callback to handle DTLS sock events.
|
||||
*/
|
||||
static void _dtls_event_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg);
|
||||
|
||||
/**
|
||||
* @brief Try to find a server credential given an UDP endpoint.
|
||||
*
|
||||
* @param[in] ep UDP endpoint to match
|
||||
* @param[in] security_mode Security mode of the instance to find
|
||||
*
|
||||
* @return Tag of the credential to use when a suitable one is found
|
||||
* @retval CREDMAN_TAG_EMPTY otherwise
|
||||
*/
|
||||
static credman_tag_t _get_credential(const sock_udp_ep_t *ep, uint8_t security_mode);
|
||||
#endif
|
||||
|
||||
static event_t _lwm2m_step_event = { .handler = _lwm2m_step_cb };
|
||||
static event_timeout_t _lwm2m_step_event_timeout;
|
||||
static lwm2m_client_data_t *_client_data = NULL;
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
/**
|
||||
* @brief Callback registered to the client DTLS sock to select a PSK credential to use.
|
||||
*/
|
||||
static credman_tag_t _client_psk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t tags[],
|
||||
unsigned tags_len, const char *hint, size_t hint_len)
|
||||
{
|
||||
(void) sock;
|
||||
(void) tags;
|
||||
(void) tags_len;
|
||||
(void) hint;
|
||||
(void) hint_len;
|
||||
|
||||
DEBUG("[lwm2m:client:PSK] getting credential\n");
|
||||
return _get_credential(ep, LWM2M_SECURITY_MODE_PRE_SHARED_KEY);
|
||||
}
|
||||
|
||||
static credman_tag_t _client_rpk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t tags[],
|
||||
unsigned tags_len)
|
||||
{
|
||||
(void) sock;
|
||||
(void) tags;
|
||||
(void) tags_len;
|
||||
|
||||
DEBUG("[lwm2m:client:RPK] getting credential\n");
|
||||
return _get_credential(ep, LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY);
|
||||
}
|
||||
|
||||
static credman_tag_t _get_credential(const sock_udp_ep_t *ep, uint8_t security_mode)
|
||||
{
|
||||
lwm2m_object_t *sec = lwm2m_get_object_by_id(_client_data, LWM2M_SECURITY_OBJECT_ID);
|
||||
if (!sec) {
|
||||
DEBUG("[lwm2m:client] no security object found\n");
|
||||
return CREDMAN_TAG_EMPTY;
|
||||
}
|
||||
|
||||
/* prepare query */
|
||||
lwm2m_uri_t query_uri = {
|
||||
.objectId = LWM2M_SECURITY_OBJECT_ID,
|
||||
// .resourceId = LWM2M_SECURITY_URI_ID,
|
||||
.flag = LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID | LWM2M_URI_FLAG_RESOURCE_ID
|
||||
};
|
||||
|
||||
lwm2m_list_t *instance = sec->instanceList;
|
||||
|
||||
/* check all registered security object instances */
|
||||
while (instance) {
|
||||
query_uri.instanceId = instance->id;
|
||||
|
||||
/* first check the security mode */
|
||||
query_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
|
||||
int64_t mode;
|
||||
int res = lwm2m_get_int(_client_data, &query_uri, &mode);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client] could not get security mode of %" PRIu16 "\n", instance->id);
|
||||
goto check_next;
|
||||
}
|
||||
|
||||
if (mode != security_mode) {
|
||||
goto check_next;
|
||||
}
|
||||
|
||||
/* if security mode matches, check the URI */
|
||||
char uri[CONFIG_LWM2M_URI_MAX_SIZE] = { 0 };
|
||||
size_t uri_len = sizeof(uri);
|
||||
res = lwm2m_get_string(_client_data, &query_uri, uri, &uri_len);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client] could not get URI of %" PRIu16 "\n", instance->id);
|
||||
goto check_next;
|
||||
}
|
||||
|
||||
sock_udp_ep_t inst_ep;
|
||||
uri_parser_result_t parsed_uri;
|
||||
res = uri_parser_process_string(&parsed_uri, uri);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client] could not parse URI\n");
|
||||
goto check_next;
|
||||
}
|
||||
|
||||
res = sock_udp_str2ep(&inst_ep, parsed_uri.host);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client] could not convert URI to EP (%s)\n", parsed_uri.host);
|
||||
goto check_next;
|
||||
}
|
||||
|
||||
if (sock_udp_ep_equal(ep, &inst_ep)) {
|
||||
credman_tag_t tag = lwm2m_object_security_get_credential(instance->id);
|
||||
|
||||
DEBUG("[lwm2m:client:PSK] found matching EP on instance %" PRIu16 "\n", instance->id);
|
||||
DEBUG("[lwm2m:client:PSK] tag: %" PRIu16 "\n", tag);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
check_next:
|
||||
instance = instance->next;
|
||||
}
|
||||
|
||||
return CREDMAN_TAG_EMPTY;
|
||||
}
|
||||
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
||||
void lwm2m_client_init(lwm2m_client_data_t *client_data)
|
||||
{
|
||||
@ -73,11 +201,36 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
|
||||
|
||||
/* create sock for UDP server */
|
||||
_client_data->local_ep.port = atoi(CONFIG_LWM2M_LOCAL_PORT);
|
||||
if (sock_udp_create(&_client_data->sock, &_client_data->local_ep, NULL, 0)) {
|
||||
if (sock_udp_create(&_client_data->sock, &_client_data->local_ep, NULL, 0) < 0) {
|
||||
DEBUG("[lwm2m_client_run] Can't create server socket\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
/* create sock for DTLS server */
|
||||
_client_data->dtls_local_ep.family = AF_INET6;
|
||||
_client_data->dtls_local_ep.netif = SOCK_ADDR_ANY_NETIF;
|
||||
_client_data->dtls_local_ep.port = atoi(CONFIG_LWM2M_LOCAL_DTLS_PORT);
|
||||
res = sock_udp_create(&_client_data->dtls_udp_sock, &_client_data->dtls_local_ep, NULL, 0);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m_client_run] Can't create DTLS server UDP sock\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
res = sock_dtls_create(&_client_data->dtls_sock, &_client_data->dtls_udp_sock,
|
||||
CREDMAN_TAG_EMPTY, SOCK_DTLS_1_2, SOCK_DTLS_CLIENT);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m_client_run] Can't create DTLS server sock\n");
|
||||
sock_udp_close(&_client_data->dtls_udp_sock);
|
||||
sock_udp_close(&_client_data->sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* register callback for credential selection */
|
||||
sock_dtls_set_client_psk_cb(&_client_data->dtls_sock, _client_psk_cb);
|
||||
sock_dtls_set_rpk_cb(&_client_data->dtls_sock, _client_rpk_cb);
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
||||
/* initiate LwM2M */
|
||||
_client_data->lwm2m_ctx = lwm2m_init(_client_data);
|
||||
if (!_client_data->lwm2m_ctx) {
|
||||
@ -92,115 +245,200 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_client_data->pid = thread_create(_lwm2m_client_stack,
|
||||
sizeof(_lwm2m_client_stack),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
_lwm2m_client_run,
|
||||
NULL,
|
||||
"LwM2M client");
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
lwm2m_client_refresh_dtls_credentials();
|
||||
#endif
|
||||
|
||||
sock_udp_event_init(&_client_data->sock, EVENT_PRIO_MEDIUM, _udp_event_handler, NULL);
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
sock_dtls_event_init(&_client_data->dtls_sock, EVENT_PRIO_MEDIUM, _dtls_event_handler, NULL);
|
||||
#endif
|
||||
|
||||
/* periodic event to tick the wakaama state machine */
|
||||
event_timeout_init(&_lwm2m_step_event_timeout, EVENT_PRIO_MEDIUM, &_lwm2m_step_event);
|
||||
event_timeout_set(&_lwm2m_step_event_timeout, LWM2M_CLIENT_MIN_REFRESH_TIME);
|
||||
|
||||
return _client_data->lwm2m_ctx;
|
||||
}
|
||||
|
||||
static void *_lwm2m_client_run(void *arg)
|
||||
static void _handle_packet_from_remote(const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type, uint8_t *buffer,
|
||||
size_t len)
|
||||
{
|
||||
(void) arg;
|
||||
time_t reboot_time = 0;
|
||||
while (1) {
|
||||
time_t tv = LWM2M_CLIENT_MIN_REFRESH_TIME;
|
||||
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
|
||||
ssize_t rcv_len = sizeof(rcv_buf);
|
||||
sock_udp_ep_t remote;
|
||||
lwm2m_client_connection_t *conn;
|
||||
|
||||
if (lwm2m_device_reboot_requested()) {
|
||||
time_t tv_sec;
|
||||
DEBUG("[lwm2m:client] finding connection\n");
|
||||
conn = lwm2m_client_connection_find(_client_data->conn_list, remote, type);
|
||||
|
||||
tv_sec = lwm2m_gettime();
|
||||
|
||||
if (0 == reboot_time) {
|
||||
DEBUG("reboot requested; rebooting in %u seconds\n",
|
||||
LWM2M_CLIENT_REBOOT_TIME);
|
||||
reboot_time = tv_sec + LWM2M_CLIENT_REBOOT_TIME;
|
||||
}
|
||||
if (reboot_time < tv_sec) {
|
||||
DEBUG("reboot time expired, rebooting ...\n");
|
||||
pm_reboot();
|
||||
}
|
||||
else {
|
||||
tv = reboot_time - tv_sec;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function does two things:
|
||||
* - first it does the work needed by liblwm2m (eg. (re)sending some
|
||||
* packets).
|
||||
* - Secondly it adjusts the timeout value (default 60s) depending on the
|
||||
* state of the transaction
|
||||
* (eg. retransmission) and the time between the next operation
|
||||
*/
|
||||
lwm2m_step(_client_data->lwm2m_ctx, &tv);
|
||||
DEBUG(" -> State: ");
|
||||
switch (_client_data->lwm2m_ctx->state) {
|
||||
case STATE_INITIAL:
|
||||
DEBUG("STATE_INITIAL\n");
|
||||
break;
|
||||
case STATE_BOOTSTRAP_REQUIRED:
|
||||
DEBUG("STATE_BOOTSTRAP_REQUIRED\n");
|
||||
break;
|
||||
case STATE_BOOTSTRAPPING:
|
||||
DEBUG("STATE_BOOTSTRAPPING\n");
|
||||
break;
|
||||
case STATE_REGISTER_REQUIRED:
|
||||
DEBUG("STATE_REGISTER_REQUIRED\n");
|
||||
break;
|
||||
case STATE_REGISTERING:
|
||||
DEBUG("STATE_REGISTERING\n");
|
||||
break;
|
||||
case STATE_READY:
|
||||
DEBUG("STATE_READY\n");
|
||||
if (tv > LWM2M_CLIENT_MIN_REFRESH_TIME) {
|
||||
tv = LWM2M_CLIENT_MIN_REFRESH_TIME;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG("Unknown...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
sock_udp_ep_t local;
|
||||
int res = sock_udp_get_local(&_client_data->sock, &local);
|
||||
/* avoid compilation errors if NDEBUG is enabled */
|
||||
(void)res;
|
||||
assert(res >= 0);
|
||||
DEBUG("Waiting for UDP packet on port: %d\n", local.port);
|
||||
rcv_len = sock_udp_recv(&_client_data->sock, rcv_buf, sizeof(rcv_buf),
|
||||
tv * US_PER_SEC, &remote);
|
||||
DEBUG("sock_udp_recv()\n");
|
||||
if (rcv_len > 0) {
|
||||
DEBUG("Finding connection\n");
|
||||
lwm2m_client_connection_t *conn = lwm2m_client_connection_find(
|
||||
_client_data->conn_list, &remote);
|
||||
if (conn) {
|
||||
DEBUG("lwm2m_connection_handle_packet(%" PRIiSIZE ")\n", rcv_len);
|
||||
int result = lwm2m_connection_handle_packet(conn, rcv_buf,
|
||||
rcv_len,
|
||||
_client_data);
|
||||
if (0 != result) {
|
||||
DEBUG("error handling message %i\n", result);
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("Could not find incoming connection\n");
|
||||
}
|
||||
}
|
||||
else if ((rcv_len < 0) &&
|
||||
((rcv_len != -EAGAIN) && (rcv_len != -ETIMEDOUT))) {
|
||||
DEBUG("Unexpected sock_udp_recv error code %" PRIiSIZE "\n", rcv_len);
|
||||
}
|
||||
else {
|
||||
DEBUG("UDP error code: %" PRIiSIZE "\n", rcv_len);
|
||||
if (conn) {
|
||||
DEBUG("[lwm2m:client] handle packet (%i bytes)\n", (int)len);
|
||||
int result = lwm2m_connection_handle_packet(conn, buffer, len, _client_data);
|
||||
if (0 != result) {
|
||||
DEBUG("[lwm2m:client] error handling message %i\n", result);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
else {
|
||||
DEBUG("[lwm2m:client] couldn't find incoming connection\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void _udp_event_handler(sock_udp_t *sock, sock_async_flags_t type, void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
sock_udp_ep_t remote;
|
||||
|
||||
if (type & SOCK_ASYNC_MSG_RECV) {
|
||||
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
|
||||
ssize_t rcv_len = sock_udp_recv(sock, rcv_buf, sizeof(rcv_buf), 0, &remote);
|
||||
if (rcv_len <= 0) {
|
||||
DEBUG("[lwm2m:client] UDP receive failure: %i\n", (int)rcv_len);
|
||||
return;
|
||||
}
|
||||
|
||||
_handle_packet_from_remote(&remote, LWM2M_CLIENT_CONN_UDP, rcv_buf, rcv_len);
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
static void _dtls_event_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
|
||||
sock_udp_ep_t remote;
|
||||
sock_dtls_session_t dtls_remote;
|
||||
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
|
||||
|
||||
if (type & SOCK_ASYNC_MSG_RECV) {
|
||||
ssize_t rcv_len = sock_dtls_recv(sock, &dtls_remote, rcv_buf, sizeof(rcv_buf), 0);
|
||||
if (rcv_len <= 0) {
|
||||
DEBUG("[lwm2m:client] DTLS receive failure: %i\n", (int)rcv_len);
|
||||
return;
|
||||
}
|
||||
|
||||
sock_dtls_session_get_udp_ep(&dtls_remote, &remote);
|
||||
|
||||
_handle_packet_from_remote(&remote, LWM2M_CLIENT_CONN_DTLS, rcv_buf, rcv_len);
|
||||
}
|
||||
}
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
||||
static void _lwm2m_step_cb(event_t *arg)
|
||||
{
|
||||
(void) arg;
|
||||
time_t next_step = LWM2M_CLIENT_MIN_REFRESH_TIME;
|
||||
|
||||
/* check if we need to reboot */
|
||||
if (lwm2m_device_reboot_requested()) {
|
||||
DEBUG("[lwm2m:client] reboot requested, rebooting ...\n");
|
||||
pm_reboot();
|
||||
}
|
||||
|
||||
/* perform step on the LwM2M FSM */
|
||||
lwm2m_step(_client_data->lwm2m_ctx, &next_step);
|
||||
DEBUG("[lwm2m:client] state: ");
|
||||
switch (_client_data->lwm2m_ctx->state) {
|
||||
case STATE_INITIAL:
|
||||
DEBUG("STATE_INITIAL\n");
|
||||
break;
|
||||
case STATE_BOOTSTRAP_REQUIRED:
|
||||
DEBUG("STATE_BOOTSTRAP_REQUIRED\n");
|
||||
break;
|
||||
case STATE_BOOTSTRAPPING:
|
||||
DEBUG("STATE_BOOTSTRAPPING\n");
|
||||
break;
|
||||
case STATE_REGISTER_REQUIRED:
|
||||
DEBUG("STATE_REGISTER_REQUIRED\n");
|
||||
break;
|
||||
case STATE_REGISTERING:
|
||||
DEBUG("STATE_REGISTERING\n");
|
||||
break;
|
||||
case STATE_READY:
|
||||
DEBUG("STATE_READY\n");
|
||||
if (next_step > LWM2M_CLIENT_MIN_REFRESH_TIME) {
|
||||
next_step = LWM2M_CLIENT_MIN_REFRESH_TIME;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DEBUG("Unknown...\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* program next step */
|
||||
event_timeout_set(&_lwm2m_step_event_timeout, next_step * US_PER_SEC);
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
void lwm2m_client_add_credential(credman_tag_t tag)
|
||||
{
|
||||
if (!_client_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const credman_tag_t *creds;
|
||||
size_t creds_len = sock_dtls_get_credentials(&_client_data->dtls_sock, &creds);
|
||||
|
||||
DEBUG("[lwm2m:client] trying to add credential with tag %" PRIu16 "\n", tag);
|
||||
for (unsigned i = 0; i < creds_len; i++) {
|
||||
if (creds[i] == tag) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sock_dtls_add_credential(&_client_data->dtls_sock, tag);
|
||||
DEBUG("[lwm2m:client] added\n");
|
||||
}
|
||||
|
||||
void lwm2m_client_remove_credential(credman_tag_t tag)
|
||||
{
|
||||
DEBUG("[lwm2m:client] removing credential with tag %" PRIu16 "\n", tag);
|
||||
sock_dtls_remove_credential(&_client_data->dtls_sock, tag);
|
||||
}
|
||||
|
||||
void lwm2m_client_refresh_dtls_credentials(void)
|
||||
{
|
||||
if (!_client_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("[lwm2m:client:refresh_cred] refreshing DTLS credentials\n");
|
||||
|
||||
lwm2m_object_t *sec = lwm2m_get_object_by_id(_client_data, LWM2M_SECURITY_OBJECT_ID);
|
||||
if (!sec) {
|
||||
DEBUG("[lwm2m:client:refresh_cred] no security object found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* prepare query */
|
||||
lwm2m_uri_t query_uri = {
|
||||
.objectId = LWM2M_SECURITY_OBJECT_ID,
|
||||
.flag = LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID | LWM2M_URI_FLAG_RESOURCE_ID
|
||||
};
|
||||
|
||||
lwm2m_list_t *instance = sec->instanceList;
|
||||
int64_t val;
|
||||
|
||||
/* check all registered security object instances */
|
||||
do {
|
||||
/* get the security mode */
|
||||
query_uri.instanceId = instance->id;
|
||||
query_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
|
||||
|
||||
int res = lwm2m_get_int(_client_data, &query_uri, &val);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client:refresh_cred] could not get security mode of %" PRIu16 "\n",
|
||||
instance->id);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (val == LWM2M_SECURITY_MODE_PRE_SHARED_KEY ||
|
||||
val == LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY) {
|
||||
credman_tag_t tag = lwm2m_object_security_get_credential(instance->id);
|
||||
if (tag != CREDMAN_TAG_EMPTY) {
|
||||
lwm2m_client_add_credential(tag);
|
||||
}
|
||||
}
|
||||
} while ((instance = instance->next) != NULL);
|
||||
}
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
@ -39,11 +39,18 @@
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include "kernel_defines.h"
|
||||
#include "net/netif.h"
|
||||
#include "uri_parser.h"
|
||||
|
||||
#include "liblwm2m.h"
|
||||
#include "net/sock/udp.h"
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
#include "net/sock/dtls.h"
|
||||
#endif
|
||||
|
||||
#include "lwm2m_client.h"
|
||||
#include "lwm2m_client_config.h"
|
||||
#include "lwm2m_client_connection.h"
|
||||
@ -88,7 +95,7 @@ static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer,
|
||||
* @param[in] iface_len interface string length
|
||||
*
|
||||
* @return pointer to the interface to use on success
|
||||
* @return NULL on error
|
||||
* @retval NULL on error
|
||||
*/
|
||||
static netif_t *_get_interface(const char *iface, size_t len);
|
||||
|
||||
@ -97,7 +104,7 @@ void *lwm2m_connect_server(uint16_t sec_obj_inst_id, void *user_data)
|
||||
lwm2m_client_data_t *client_data = (lwm2m_client_data_t *)user_data;
|
||||
lwm2m_client_connection_t *new_conn;
|
||||
|
||||
DEBUG("[lwm2m_connect_server] Connecting to server in security instance %d\n", sec_obj_inst_id);
|
||||
DEBUG("[lwm2m_connect_server] Connecting to server in security instance %" PRIu16 "\n", sec_obj_inst_id);
|
||||
|
||||
new_conn = _connection_create(sec_obj_inst_id, client_data);
|
||||
if (new_conn) {
|
||||
@ -170,9 +177,9 @@ uint8_t lwm2m_buffer_send(void *sessionH, uint8_t *buffer, size_t length,
|
||||
return COAP_NO_ERROR;
|
||||
}
|
||||
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote)
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type)
|
||||
{
|
||||
lwm2m_client_connection_t *conn = conn_list;
|
||||
|
||||
@ -180,7 +187,7 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
uint8_t ip_len = 128;
|
||||
|
||||
ipv6_addr_to_str(ip, (ipv6_addr_t *)&remote->addr.ipv6, ip_len);
|
||||
DEBUG("Looking for connection from [%s]:%d\n", ip, remote->port);
|
||||
DEBUG("Looking for connection from [%s]:%" PRIu16 "\n", ip, remote->port);
|
||||
|
||||
if (conn_list == NULL) {
|
||||
DEBUG("Conn list is null!");
|
||||
@ -188,8 +195,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
|
||||
while (conn != NULL) {
|
||||
ipv6_addr_to_str(ip, (ipv6_addr_t *)&conn->remote.addr.ipv6, ip_len);
|
||||
DEBUG("Comparing to [%s]:%d\n", ip, conn->remote.port);
|
||||
if ((conn->remote.port == remote->port) &&
|
||||
DEBUG("Comparing to [%s]:%" PRIu16 "\n", ip, conn->remote.port);
|
||||
if ((conn->remote.port == remote->port) && conn->type == type &&
|
||||
ipv6_addr_equal((ipv6_addr_t *)&(conn->remote.addr.ipv6),
|
||||
(ipv6_addr_t *)&(remote->addr.ipv6))) {
|
||||
break;
|
||||
@ -199,9 +206,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
return conn;
|
||||
}
|
||||
|
||||
int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn,
|
||||
uint8_t *buffer, size_t num_bytes,
|
||||
lwm2m_client_data_t *client_data)
|
||||
int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn, uint8_t *buffer,
|
||||
size_t num_bytes, lwm2m_client_data_t *client_data)
|
||||
{
|
||||
lwm2m_handle_packet(client_data->lwm2m_ctx, buffer, num_bytes, conn);
|
||||
return 0;
|
||||
@ -211,12 +217,26 @@ static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer,
|
||||
size_t buffer_size,
|
||||
lwm2m_client_data_t *client_data)
|
||||
{
|
||||
ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer,
|
||||
buffer_size, &(conn->remote));
|
||||
if (sent_bytes <= 0) {
|
||||
DEBUG("[_connection_send] Could not send UDP packet: %" PRIiSIZE "\n", sent_bytes);
|
||||
return -1;
|
||||
DEBUG("[_connection_send] trying to send %" PRIiSIZE " bytes\n", buffer_size);
|
||||
if (conn->type == LWM2M_CLIENT_CONN_UDP) {
|
||||
ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer,
|
||||
buffer_size, &(conn->remote));
|
||||
if (sent_bytes <= 0) {
|
||||
DEBUG("[_connection_send] Could not send UDP packet: %i\n", (int)sent_bytes);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
else {
|
||||
ssize_t sent_bytes = sock_dtls_send(&client_data->dtls_sock, &conn->session, buffer,
|
||||
buffer_size, SOCK_NO_TIMEOUT);
|
||||
if (sent_bytes <= 0) {
|
||||
DEBUG("[_connection_send] Could not send DTLS packet: %i\n", (int)sent_bytes);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
||||
conn->last_send = lwm2m_gettime();
|
||||
return 0;
|
||||
}
|
||||
@ -225,7 +245,8 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
|
||||
{
|
||||
netif_t *netif = NULL;
|
||||
|
||||
if (iface == NULL) {
|
||||
if (!iface || !iface_len) {
|
||||
DEBUG("[lwm2m:client] no interface defined in host\n");
|
||||
/* get the number of net interfaces */
|
||||
unsigned netif_numof = 0;
|
||||
while ((netif = netif_iter(netif)) != NULL) {
|
||||
@ -240,6 +261,7 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("[lwm2m:client] getting interface by name %.*s\n", (unsigned)iface_len, iface);
|
||||
netif = netif_get_by_name_buffer(iface, iface_len);
|
||||
}
|
||||
|
||||
@ -250,7 +272,7 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
lwm2m_client_data_t *client_data)
|
||||
{
|
||||
lwm2m_client_connection_t *conn = NULL;
|
||||
char uri[MAX_URI_LENGTH];
|
||||
char uri[MAX_URI_LENGTH] = { 0 };
|
||||
size_t uri_len = ARRAY_SIZE(uri);
|
||||
uint16_t port;
|
||||
bool is_bootstrap;
|
||||
@ -299,7 +321,7 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
port = parsed_uri.port;
|
||||
}
|
||||
|
||||
DEBUG("[_connection_create] Creating connection to Host: %.*s, Port: %u\n",
|
||||
DEBUG("[_connection_create] Creating connection to Host: %.*s, Port: %" PRIu16 "\n",
|
||||
parsed_uri.ipv6addr_len, parsed_uri.ipv6addr, port);
|
||||
|
||||
/* allocate new connection */
|
||||
@ -331,7 +353,9 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
* is only one defined. */
|
||||
if (ipv6_addr_is_link_local((ipv6_addr_t *)&conn->remote.addr.ipv6)) {
|
||||
netif_t *netif = _get_interface(parsed_uri.zoneid, parsed_uri.zoneid_len);
|
||||
|
||||
if (netif == NULL) {
|
||||
DEBUG("[lwm2m:client] could not determine an interface to use\n");
|
||||
goto free_out;
|
||||
}
|
||||
else {
|
||||
@ -343,6 +367,40 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
uint8_t buf[DTLS_HANDSHAKE_BUFSIZE];
|
||||
int64_t val;
|
||||
resource_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
|
||||
res = lwm2m_get_int(client_data, &resource_uri, &val);
|
||||
if (res < 0) {
|
||||
DEBUG("[lwm2m:client] could not get security instance mode\n");
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
if (val == LWM2M_SECURITY_MODE_PRE_SHARED_KEY || val == LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY) {
|
||||
conn->type = LWM2M_CLIENT_CONN_DTLS;
|
||||
DEBUG("[lwm2m:client] DTLS session init\n");
|
||||
res = sock_dtls_session_init(&client_data->dtls_sock, &conn->remote, &conn->session);
|
||||
if (res <= 0) {
|
||||
DEBUG("[lwm2m:client] could not initiate DTLS session\n");
|
||||
goto free_out;
|
||||
}
|
||||
|
||||
DEBUG("[lwm2m:client] receiving DTLS handshake\n");
|
||||
res = sock_dtls_recv(&client_data->dtls_sock, &conn->session, buf, sizeof(buf), US_PER_SEC);
|
||||
if (res != -SOCK_DTLS_HANDSHAKE) {
|
||||
DEBUG("[lwm2m:client] error creating session: %i\n", res);
|
||||
goto free_out;
|
||||
}
|
||||
DEBUG("[lwm2m:client] connection to server successful\n");
|
||||
}
|
||||
else {
|
||||
conn->type = LWM2M_CLIENT_CONN_UDP;
|
||||
}
|
||||
#else
|
||||
conn->type = LWM2M_CLIENT_CONN_UDP;
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
|
||||
|
||||
conn->last_send = lwm2m_gettime();
|
||||
goto out;
|
||||
|
||||
|
@ -185,7 +185,7 @@ static int _get_value(lwm2m_data_t *data, lwm2m_obj_security_inst_t *instance);
|
||||
|
||||
/**
|
||||
* @brief Initialize a new instance with the given arguments.
|
||||
*
|
||||
*
|
||||
* @param instance[out] Instance to initialize.
|
||||
* @param instance_id[in] ID of the instance.
|
||||
* @param args[in] Arguments to initialize the instance with.
|
||||
|
@ -36,16 +36,32 @@ extern "C" {
|
||||
#include "periph/pm.h"
|
||||
#include "net/sock/udp.h"
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
#include "net/sock/dtls.h"
|
||||
#endif
|
||||
|
||||
#include "lwm2m_client_config.h"
|
||||
#include "liblwm2m.h"
|
||||
|
||||
/**
|
||||
* @brief Type of connection to the LwM2M server.
|
||||
*/
|
||||
typedef enum {
|
||||
LWM2M_CLIENT_CONN_UDP, /**< UDP */
|
||||
LWM2M_CLIENT_CONN_DTLS /**< DTLS over UDP */
|
||||
} lwm2m_client_connection_type_t;
|
||||
|
||||
/**
|
||||
* @brief Connection to server descriptor
|
||||
*/
|
||||
typedef struct lwm2m_client_connection {
|
||||
struct lwm2m_client_connection *next; /**< pointer to the next connection */
|
||||
sock_udp_ep_t remote; /**< remote endpoint */
|
||||
time_t last_send; /**< last sent packet to the server */
|
||||
sock_udp_ep_t remote; /**< remote endpoint */
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS) || DOXYGEN
|
||||
sock_dtls_session_t session; /**< DTLS session (needs wakaama_client_dtls module) */
|
||||
#endif
|
||||
lwm2m_client_connection_type_t type; /**< type of connection */
|
||||
time_t last_send; /**< last sent packet to the server */
|
||||
} lwm2m_client_connection_t;
|
||||
|
||||
/**
|
||||
@ -54,6 +70,11 @@ typedef struct lwm2m_client_connection {
|
||||
typedef struct {
|
||||
kernel_pid_t pid; /**< PID of the client thread */
|
||||
sock_udp_t sock; /**< UDP server sock */
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
sock_udp_t dtls_udp_sock; /**< UDP sock for DTLS */
|
||||
sock_dtls_t dtls_sock; /**< DTLS client sock */
|
||||
sock_udp_ep_t dtls_local_ep; /**< DTLS local endpoint */
|
||||
#endif
|
||||
sock_udp_ep_t local_ep; /**< Local endpoint */
|
||||
lwm2m_context_t *lwm2m_ctx; /**< LwM2M context */
|
||||
lwm2m_client_connection_t *conn_list; /**< LwM2M connections list */
|
||||
@ -114,6 +135,30 @@ static inline lwm2m_context_t *lwm2m_client_get_ctx(
|
||||
return client_data->lwm2m_ctx;
|
||||
}
|
||||
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS) || defined(DOXYGEN)
|
||||
/**
|
||||
* @brief Refreshes the client available credentials using the currently registered security objects
|
||||
* @note Only available when using the module `wakaama_client_dtls`.
|
||||
*/
|
||||
void lwm2m_client_refresh_dtls_credentials(void);
|
||||
|
||||
/**
|
||||
* @brief Adds a credential tag to be used with the LwM2M DTLS sock.
|
||||
*
|
||||
* If the tag is already available it will not be added again.
|
||||
* @note Only available when using the module `wakaama_client_dtls`.
|
||||
* @param[in] tag Tag to add.
|
||||
*/
|
||||
void lwm2m_client_add_credential(credman_tag_t tag);
|
||||
|
||||
/**
|
||||
* @brief Removes a credential tag from the available to use with the LwM2M DTLS sock.
|
||||
* @note Only available when using the module `wakaama_client_dtls`.
|
||||
* @param[in] tag Tag to remove.
|
||||
*/
|
||||
void lwm2m_client_remove_credential(credman_tag_t tag);
|
||||
#endif /* MODULE_WAKAAMA_CLIENT_DTLS || DOXYGEN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -58,13 +58,14 @@ extern "C" {
|
||||
*
|
||||
* @param[in] conn_list connections list to search
|
||||
* @param[in] remote remote UDP endpoint to compare to
|
||||
* @param[in] type type of connection to look for
|
||||
*
|
||||
* @return pointer to the connection in success
|
||||
* @return NULL otherwise
|
||||
*/
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote);
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Handles a received packet from a connection
|
||||
|
@ -229,7 +229,7 @@ enum lwm2m_device_error_codes {
|
||||
|
||||
/**
|
||||
* @brief Device binding and queue mode
|
||||
*
|
||||
*
|
||||
* @note Select using CONFIG_LWM2M_DEVICE_BINDING_*
|
||||
*/
|
||||
#if defined(CONFIG_LWM2M_DEVICE_BINDING_U)
|
||||
|
@ -74,7 +74,7 @@
|
||||
* To use this security mode the following keys are required:
|
||||
* - server public key (`SubjectPublicKeyInfo` DER encoded, according to RFC5280)
|
||||
* - own public (`SubjectPublicKeyInfo` DER encoded) and private (as a `ECPrivateKey` DER encoded
|
||||
* sequence, according to RFC5915)keys. See bellow on how they can be generated.
|
||||
* sequence, according to RFC5915)keys. See below on how they can be generated.
|
||||
*
|
||||
* It is possible that you may need to increase @ref CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP when using
|
||||
* RPK mode.
|
||||
@ -119,7 +119,7 @@
|
||||
* ~~~~~~~~~~~~~~~~~~~~
|
||||
* $ openssl ec -in keys.der -inform DER -outform DER -pubout | xxd -i
|
||||
* ~~~~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
*
|
||||
* 3. Get the private part of the key:
|
||||
* ~~~~~~~~~~~~~~~~~~~~
|
||||
* $ openssl ec -in keys.der -inform DER -no_public -outform DER | xxd -i
|
||||
@ -264,7 +264,7 @@ extern "C" {
|
||||
#define LWM2M_SECURITY_HOLD_OFF_ID 11
|
||||
|
||||
/**
|
||||
* @brief Boostrap server account timeout
|
||||
* @brief Bootstrap server account timeout
|
||||
*/
|
||||
#define LWM2M_SECURITY_BOOTSTRAP_TIMEOUT_ID 12
|
||||
/** @} */
|
||||
|
Loading…
Reference in New Issue
Block a user