1
0
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:
Leandro Lanzieri 2021-11-03 17:21:45 +01:00
parent 3d012bfd2c
commit 6109e588a5
No known key found for this signature in database
GPG Key ID: F4E9A721761C7593
9 changed files with 502 additions and 149 deletions

View File

@ -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

View File

@ -18,3 +18,4 @@ ifneq (,$(or $(CONFIG_LWM2M_WITH_LOGS),$(filter -DCONFIG_LWM2M_WITH_LOGS=1,$(CFL
endif
PSEUDOMODULES += wakaama
PSEUDOMODULES += wakaama_client_dtls

View File

@ -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 */

View File

@ -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;

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
/** @} */