From c52ad2df9e9b2f4584a482a53576cb386902089a Mon Sep 17 00:00:00 2001 From: Leandro Lanzieri Date: Fri, 29 Nov 2019 17:54:08 +0100 Subject: [PATCH] pkg/wakaama: Add LwM2M Client implementation --- makefiles/pseudomodules.inc.mk | 1 + pkg/wakaama/Makefile | 21 +- pkg/wakaama/Makefile.dep | 17 + pkg/wakaama/Makefile.include | 5 +- pkg/wakaama/contrib/Makefile | 5 + pkg/wakaama/contrib/lwm2m_client.c | 200 ++++++++ pkg/wakaama/contrib/lwm2m_client_connection.c | 452 ++++++++++++++++++ pkg/wakaama/contrib/lwm2m_client_objects.c | 71 +++ pkg/wakaama/contrib/lwm2m_platform.c | 122 +++++ pkg/wakaama/contrib/objects/Makefile | 5 + pkg/wakaama/contrib/objects/device.c | 312 ++++++++++++ pkg/wakaama/include/lwm2m_client.h | 124 +++++ pkg/wakaama/include/lwm2m_client_config.h | 190 ++++++++ pkg/wakaama/include/lwm2m_client_connection.h | 89 ++++ pkg/wakaama/include/lwm2m_client_objects.h | 95 ++++ pkg/wakaama/include/lwm2m_platform.h | 54 +++ pkg/wakaama/include/objects/device.h | 105 ++++ pkg/wakaama/include/objects/doc.txt | 8 + 18 files changed, 1866 insertions(+), 10 deletions(-) create mode 100644 pkg/wakaama/Makefile.dep create mode 100644 pkg/wakaama/contrib/Makefile create mode 100644 pkg/wakaama/contrib/lwm2m_client.c create mode 100644 pkg/wakaama/contrib/lwm2m_client_connection.c create mode 100644 pkg/wakaama/contrib/lwm2m_client_objects.c create mode 100644 pkg/wakaama/contrib/lwm2m_platform.c create mode 100644 pkg/wakaama/contrib/objects/Makefile create mode 100644 pkg/wakaama/contrib/objects/device.c create mode 100644 pkg/wakaama/include/lwm2m_client.h create mode 100644 pkg/wakaama/include/lwm2m_client_config.h create mode 100644 pkg/wakaama/include/lwm2m_client_connection.h create mode 100644 pkg/wakaama/include/lwm2m_client_objects.h create mode 100644 pkg/wakaama/include/lwm2m_platform.h create mode 100644 pkg/wakaama/include/objects/device.h create mode 100644 pkg/wakaama/include/objects/doc.txt diff --git a/makefiles/pseudomodules.inc.mk b/makefiles/pseudomodules.inc.mk index f6b7c6b123..492068a06e 100644 --- a/makefiles/pseudomodules.inc.mk +++ b/makefiles/pseudomodules.inc.mk @@ -88,6 +88,7 @@ PSEUDOMODULES += stdio_ethos PSEUDOMODULES += stdio_cdc_acm PSEUDOMODULES += stdio_uart_rx PSEUDOMODULES += suit_% +PSEUDOMODULES += wakaama_objects_% # handle suit_v4 being a distinct module NO_PSEUDOMODULES += suit_v4 diff --git a/pkg/wakaama/Makefile b/pkg/wakaama/Makefile index a49bb8d815..1a94ddee31 100644 --- a/pkg/wakaama/Makefile +++ b/pkg/wakaama/Makefile @@ -6,17 +6,20 @@ PKG_LICENSE=EDL-1.0,EPL-1.0 .PHONY: all all: patch - "$(MAKE)" -C $(PKG_BUILDDIR)/riotbuild + "$(MAKE)" -C $(PKG_BUILDDIR) patch: git-download - mkdir -p "$(PKG_BUILDDIR)/riotbuild" - cp $(PKG_BUILDDIR)/core/*.c $(PKG_BUILDDIR)/core/*.h $(PKG_BUILDDIR)/riotbuild - cp $(PKG_BUILDDIR)/core/er-coap-13/*.c $(PKG_BUILDDIR)/core/er-coap-13/*.h $(PKG_BUILDDIR)/riotbuild - cp $(PKG_BUILDDIR)/examples/client/object_server.c $(PKG_BUILDDIR)/riotbuild - cp $(PKG_BUILDDIR)/examples/client/object_security.c $(PKG_BUILDDIR)/riotbuild - cp $(PKG_BUILDDIR)/examples/client/object_access_control.c $(PKG_BUILDDIR)/riotbuild + mkdir -p "$(PKG_BUILDDIR)" + # copy the Wakaama core files + cp $(PKG_BUILDDIR)/core/*.c $(PKG_BUILDDIR)/core/*.h $(PKG_BUILDDIR) + # copy the coap implementation from Wakaama + cp $(PKG_BUILDDIR)/core/er-coap-13/*.c $(PKG_BUILDDIR)/core/er-coap-13/*.h $(PKG_BUILDDIR) + # copy the mandatory objects, implemented on Wakaama examples + cp $(PKG_BUILDDIR)/examples/client/object_server.c $(PKG_BUILDDIR) + cp $(PKG_BUILDDIR)/examples/client/object_security.c $(PKG_BUILDDIR) + cp $(PKG_BUILDDIR)/examples/client/object_access_control.c $(PKG_BUILDDIR) - echo 'MODULE:=wakaama' > $(PKG_BUILDDIR)/riotbuild/Makefile - echo 'include $$(RIOTBASE)/Makefile.base' >> $(PKG_BUILDDIR)/riotbuild/Makefile + echo 'MODULE:=wakaama' > $(PKG_BUILDDIR)/Makefile + echo 'include $$(RIOTBASE)/Makefile.base' >> $(PKG_BUILDDIR)/Makefile include $(RIOTBASE)/pkg/pkg.mk diff --git a/pkg/wakaama/Makefile.dep b/pkg/wakaama/Makefile.dep new file mode 100644 index 0000000000..ece9421cd0 --- /dev/null +++ b/pkg/wakaama/Makefile.dep @@ -0,0 +1,17 @@ +# include contrib code (platform adaption and client implementation) +USEMODULE += wakaama_contrib + +# this allows us to include our own objects, implemented in the 'objects' +# folder, by adding 'wakaama_objects_' modules +USEMODULE += wakaama_objects + +# include the 'device' object implementation (mandatory) +USEMODULE += wakaama_objects_device + +USEMODULE += xtimer +USEPKG += tlsf + +# If logs for the package are active, we need fmt +ifneq (,$(filter -DLWM2M_WITH_LOGS,$(CFLAGS))) + USEMODULE += fmt +endif diff --git a/pkg/wakaama/Makefile.include b/pkg/wakaama/Makefile.include index 7c3de093bb..394a90e994 100644 --- a/pkg/wakaama/Makefile.include +++ b/pkg/wakaama/Makefile.include @@ -1 +1,4 @@ -INCLUDES += -I$(PKGDIRBASE)/wakaama/riotbuild +DIRS += $(RIOTBASE)/pkg/wakaama/contrib + +INCLUDES += -I$(RIOTBASE)/pkg/wakaama/include +INCLUDES += -I$(PKGDIRBASE)/wakaama diff --git a/pkg/wakaama/contrib/Makefile b/pkg/wakaama/contrib/Makefile new file mode 100644 index 0000000000..08034f3b48 --- /dev/null +++ b/pkg/wakaama/contrib/Makefile @@ -0,0 +1,5 @@ +MODULE := wakaama_contrib + +DIRS += $(RIOTBASE)/pkg/wakaama/contrib/objects + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/wakaama/contrib/lwm2m_client.c b/pkg/wakaama/contrib/lwm2m_client.c new file mode 100644 index 0000000000..f5aadb2925 --- /dev/null +++ b/pkg/wakaama/contrib/lwm2m_client.c @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * @ingroup lwm2m_client + * + * @file + * @brief LwM2M client implementation using Wakaama + * + * @author Christian Manal + * @author Leandro Lanzieri + * @} + */ + +#include + +#include "liblwm2m.h" + +#include "lwm2m_platform.h" +#include "lwm2m_client.h" +#include "lwm2m_client_config.h" +#include "lwm2m_client_connection.h" + +#define ENABLE_DEBUG (0) +#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 + */ +bool lwm2m_device_reboot_requested(void); + +/** + * @brief Thread with the main loop for receiving packets and stepping the LwM2M + * FSM. + * + * @param arg ignored + */ +static void *_lwm2m_client_run(void *arg); + + +static char _lwm2m_client_stack[THREAD_STACKSIZE_MAIN + + THREAD_EXTRA_STACKSIZE_PRINTF]; +static lwm2m_client_data_t *_client_data; + +void lwm2m_client_init(lwm2m_client_data_t *client_data) +{ + (void)client_data; + lwm2m_platform_init(); +} + +lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data, + lwm2m_object_t *obj_list[], + uint16_t obj_numof) +{ + int res; + + _client_data = client_data; + _client_data->local_ep.family = AF_INET6; + _client_data->local_ep.netif = SOCK_ADDR_ANY_NETIF; + + /* create sock for UDP server */ + _client_data->local_ep.port = atoi(LWM2M_LOCAL_PORT); + if (sock_udp_create(&_client_data->sock, &_client_data->local_ep, NULL, 0)) { + DEBUG("[lwm2m_client_run] Can't create server socket\n"); + return NULL; + } + + /* initiate LwM2M */ + _client_data->lwm2m_ctx = lwm2m_init(_client_data); + if (!_client_data->lwm2m_ctx) { + DEBUG("[lwm2m_client_run] Failed to initiate LwM2M\n"); + return NULL; + } + + res = lwm2m_configure(_client_data->lwm2m_ctx, LWM2M_DEVICE_NAME, NULL, + LWM2M_ALT_PATH, obj_numof, obj_list); + if (res) { + DEBUG("[lwm2m_client_run] Failed to configure LwM2M\n"); + 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"); + return _client_data->lwm2m_ctx; +} + +static void *_lwm2m_client_run(void *arg) +{ + (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; + + if (lwm2m_device_reboot_requested()) { + time_t tv_sec; + + 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; + } + + DEBUG("Waiting for UDP packet on port: %d\n", _client_data->sock.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(%d)\n", rcv_len); + int result = lwm2m_connection_handle_packet(conn, rcv_buf, + rcv_len, + _client_data); + if (0 != result) { + DEBUG("error handling message %d\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 %i\n", rcv_len); + } + else { + DEBUG("UDP error code: %d\n", rcv_len); + } + } + return NULL; +} diff --git a/pkg/wakaama/contrib/lwm2m_client_connection.c b/pkg/wakaama/contrib/lwm2m_client_connection.c new file mode 100644 index 0000000000..4e294ec59c --- /dev/null +++ b/pkg/wakaama/contrib/lwm2m_client_connection.c @@ -0,0 +1,452 @@ +/******************************************************************************* +* +* Copyright (c) 2015 Intel Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* and Eclipse Distribution License v1.0 which accompany this distribution. +* +* The Eclipse Public License is available at +* http://www.eclipse.org/legal/epl-v10.html +* The Eclipse Distribution License is available at +* http://www.eclipse.org/org/documents/edl-v10.php. +* +* Contributors: +* David Navarro, Intel Corporation - initial API and implementation +* Christian Renz - Please refer to git log +* Christian Manal - Ported to RIOT OS +* +*******************************************************************************/ + +/* + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * @ingroup lwm2m_client + * + * @file + * @brief Connection handle for LwM2M client implementation using Wakaama + * + * @author Christian Manal + * @author Leandro Lanzieri + * @} + */ + +#include +#include "kernel_defines.h" +#include "net/netif.h" + +#include "liblwm2m.h" +#include "lwm2m_client.h" +#include "lwm2m_client_config.h" +#include "lwm2m_client_connection.h" + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#define URI_LENGTH 256 + +/** + * @brief Creates a new connection object based on the security instance + * represented by @p instance_id. + * + * @param[in] instance_id ID number of the instance of security object + * @param[in, out] client_data LwM2M client data + * + * @return Pointer to the new connection + */ +static lwm2m_client_connection_t *_connection_create(int instance_id, + lwm2m_client_data_t *client_data); + +/** + * @brief Gets the URI from an @p instance_id of a @p obj security object + * + * @param[in] obj security object + * @param[in] instance_id ID number of the instance of security object + * @param[out] uri_buffer buffer to place the URI + * @param[in] buffer_size size of @p uri_buffer + * + * @return Pointer to the URI in success + * @return NULL otherwise + */ +static char *_get_uri_from_security_obj(lwm2m_object_t *obj, int instance_id, + char *uri_buffer, int buffer_size); + +/** + * @brief Sends data with a specified connection @p conn + * + * @param[in] conn connection to use to send data + * @param[in] buffer data to send + * @param[in] buffer_size size of @p buffer + * @param[in] client_data LwM2M client data + * + * @return 0 on success + * @return -1 otherwise + */ +static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer, + size_t buffer_size, + lwm2m_client_data_t *client_data); + +/** + * @brief Parses the schema of a given URI and sets the default port for the + * found valid schema + * @param[in] uri URI string to parse + * @param[out] port will point to the default port string + * @param[in] instance_id instance ID of the connection + * + * @return pointer to the character after the schema, if found + * @return NULL if no valid schema found + */ +static char *_parse_schema(char *uri, char **port, int instance_id); + +/** + * @brief Parses the host and the port part after the schema + * + * @param[in, out] host pointer to the beginning of the host + * @param[out] port pointer to store the position of the port + * @param[in] default_port default port + */ +static void _parse_host_and_port(char **host, char **port, char *default_port); + +/** + * @brief Tries to find an interface in the host string. If not, it will check + * if there only exists one interface, and will use it + * @param[in] host host string + * + * @return pointer to the interface to use on success + * @return NULL on error + */ +static netif_t *_get_interface(char *host); + +/** + * @brief Sets a given interface to a given UDP endpoint + * + * @param[out] ep UDP endpoint + * @param[in] netif Network interface to assign + */ +static void _set_interface(sock_udp_ep_t *ep, const netif_t *netif); + +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_list_t *instance; + lwm2m_client_connection_t *new_conn = NULL; + + /* get the security object instance */ + instance = LWM2M_LIST_FIND(client_data->obj_security->instanceList, + sec_obj_inst_id); + if (instance == NULL) { + DEBUG("[lwm2m_connect_server] Could not find sec object instance\n"); + return NULL; + } + + new_conn = _connection_create(instance->id, client_data); + if (new_conn) { + DEBUG("[lwm2m_connect_server] Connection created\n"); + /* if the connections list is empty this is the first node, if not + * attach to the last one */ + if (!client_data->conn_list) { + client_data->conn_list = new_conn; + } + else { + lwm2m_client_connection_t *last = client_data->conn_list; + while (last->next != NULL) { + last = last->next; + } + last->next = new_conn; + } + } + + return new_conn; +} + +void lwm2m_close_connection(void *sessionH, void *user_data) +{ + lwm2m_client_connection_t *conn = (lwm2m_client_connection_t *) sessionH; + lwm2m_client_data_t *client_data = (lwm2m_client_data_t *) user_data; + + if (conn == client_data->conn_list) { + client_data->conn_list = conn->next; + } + else { + lwm2m_client_connection_t *prev = client_data->conn_list; + + while(prev != NULL && prev->next != conn) { + prev = prev->next; + } + if (prev != NULL) { + prev->next = conn->next; + lwm2m_free(conn); + } + } +} + +bool lwm2m_session_is_equal(void *session1, void *session2, void *user_data) +{ + (void)user_data; + lwm2m_client_connection_t *conn_1 = (lwm2m_client_connection_t *)session1; + lwm2m_client_connection_t *conn_2 = (lwm2m_client_connection_t *)session2; + + return ((conn_1->remote.port == conn_2->remote.port) && + ipv6_addr_equal((ipv6_addr_t *)&(conn_1->remote.addr.ipv6), + (ipv6_addr_t *)&(conn_2->remote.addr.ipv6))); +} + +uint8_t lwm2m_buffer_send(void *sessionH, uint8_t *buffer, size_t length, + void *userdata) +{ + lwm2m_client_data_t *client_data = (lwm2m_client_data_t *)userdata; + lwm2m_client_connection_t *conn = (lwm2m_client_connection_t *)sessionH; + + if (!conn) { + DEBUG("[lwm2m_buffer_send] Failed to send, missing connection\n"); + return COAP_500_INTERNAL_SERVER_ERROR; + } + + if (_connection_send(conn, buffer, length, client_data)) { + DEBUG("[lwm2m_buffer_send] Failed to send\n"); + return COAP_500_INTERNAL_SERVER_ERROR; + } + + 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 *conn = conn_list; + + char ip[128]; + 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); + + if (conn_list == NULL) { + DEBUG("Conn list is null!"); + } + + 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) && + ipv6_addr_equal((ipv6_addr_t *)&(conn->remote.addr.ipv6), + (ipv6_addr_t *)&(remote->addr.ipv6))) { + break; + } + conn = conn->next; + } + 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) +{ + lwm2m_handle_packet(client_data->lwm2m_ctx, buffer, num_bytes, conn); + return 0; +} + +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: %d\n", sent_bytes); + return -1; + } + conn->last_send = lwm2m_gettime(); + return 0; +} + +static char *_parse_schema(char *uri, char **port, int instance_id) +{ + char *host = NULL; + if (!uri) { + DEBUG("[_parse_schema] Could not get URI of instance\n"); + goto out; + } + + /* parse the URI in the form "coaps://[host]:port" */ + if (!strncmp(uri, SCHEME_COAPS, sizeof(SCHEME_COAPS) - 1)) { + host = uri + sizeof(SCHEME_COAPS) - 1; + } + else if (!strncmp(uri, SCHEME_COAP, sizeof(SCHEME_COAP) - 1)) { + host = uri + sizeof(SCHEME_COAP) - 1; + } + + *port = (IS_ACTIVE(LWM2M_BOOTSTRAP) && !instance_id) ? + LWM2M_BSSERVER_PORT : LWM2M_STANDARD_PORT; +out: + return host; +} + +static void _parse_host_and_port(char **host, char **port, char *default_port) +{ + char *_port = NULL; + char *pos = *host; + + if (pos[0] == '[') { + (*host)++; + pos = strrchr(pos, ']'); + } + + _port = strrchr(pos, ':'); + if (!_port) { + *pos = '\0'; + DEBUG("[_parse_port] No port specified, using default\n"); + _port = default_port; + } + else { + *(_port - 1) = '\0'; + _port++; + } + *port = _port; +} + +static void _set_interface(sock_udp_ep_t *ep, const netif_t *netif) +{ + if (netif == NULL || ep == NULL) { + return; + } + + /* currently there is no way to assign a network interface to a sock + * endpoint by means of a generic API, so we need to check */ + if (IS_USED(MODULE_GNRC_NETIF)) { + const gnrc_netif_t *gnrc_netif = (gnrc_netif_t *)netif; + ep->netif = (uint16_t)gnrc_netif->pid; + } +} + +static netif_t *_get_interface(char *host) +{ + netif_t *netif = NULL; + char *iface = ipv6_addr_split_iface(host); + + if (iface == NULL) { + /* get the number of net interfaces */ + unsigned netif_numof = 0; + while ((netif = netif_iter(netif)) != NULL) { + netif_numof++; + } + /* if we only have one interface use that one */ + if (netif_numof == 1) { + netif = netif_iter(NULL); + } + else { + DEBUG("[_connection_create] No iface for link-local address\n"); + } + } + else { + netif = netif_get_by_name(iface); + } + + return netif; +} + +static lwm2m_client_connection_t *_connection_create(int instance_id, + lwm2m_client_data_t *client_data) +{ + lwm2m_client_connection_t *conn = NULL; + char *default_port; + char *host; + char *port; + char *uri; + char uri_buf[URI_LENGTH + 1]; + + memset(uri_buf, 0, sizeof(uri_buf)); + DEBUG("Creating connection\n"); + /* get the server URI from the requested instance */ + uri = _get_uri_from_security_obj(client_data->obj_security, instance_id, + uri_buf, sizeof(uri_buf) - 1); + + host = _parse_schema(uri, &default_port, instance_id); + if (!host) { + DEBUG("[_connection_create] Could not parse URI schema\n"); + goto free_out; + } + + _parse_host_and_port(&host, &port, default_port); + DEBUG("[_connection_create] Creating connection to Host: %s, Port: %s\n", + host, port); + + /* allocate new connection */ + conn = lwm2m_malloc(sizeof(lwm2m_client_connection_t)); + if (!conn) { + DEBUG("[_connection_create] Could not allocate new connection\n"); + goto out; + } + conn->next = client_data->conn_list; + + /* configure to any IPv6 */ + conn->remote.family = AF_INET6; + conn->remote.netif = SOCK_ADDR_ANY_NETIF; + conn->remote.port = atoi(port); + + if (!ipv6_addr_from_str((ipv6_addr_t *)&conn->remote.addr.ipv6, host)) { + DEBUG("[_connection_create] IPv6 address malformed\n"); + goto free_out; + } + + if (ipv6_addr_is_unspecified((const ipv6_addr_t *)&conn->remote.addr.ipv6)) { + DEBUG("[_connection_create] Invalid server address ([::])\n"); + goto free_out; + } + + /* If the address is a link-local one first check if interface is specified, + * if not, check the number of interfaces and default to the first if there + * is only one defined. */ + if (ipv6_addr_is_link_local((ipv6_addr_t *)&conn->remote.addr.ipv6)) { + netif_t *netif = _get_interface(host); + if (netif == NULL) { + goto free_out; + } + else { + _set_interface(&conn->remote, netif); + } + } + + conn->last_send = lwm2m_gettime(); + goto out; + +free_out: + lwm2m_free(conn); + conn = NULL; +out: + return conn; +} + +static char *_get_uri_from_security_obj(lwm2m_object_t *obj, int instance_id, + char *uri_buffer, int buffer_size) +{ + int size = 1; + char *res = NULL; + + /* allocate a data instance */ + lwm2m_data_t *data = lwm2m_data_new(size); + + /* get the uri from the security object */ + data->id = 0; + obj->readFunc(instance_id, &size, &data, obj); + + if (data != NULL && data->type == LWM2M_TYPE_STRING && + data->value.asBuffer.length > 0) { + if ((size_t)buffer_size > data->value.asBuffer.length) { + strncpy(uri_buffer, (char *)data->value.asBuffer.buffer, + data->value.asBuffer.length); + res = uri_buffer; + } + } + + lwm2m_data_free(size, data); + return res; +} diff --git a/pkg/wakaama/contrib/lwm2m_client_objects.c b/pkg/wakaama/contrib/lwm2m_client_objects.c new file mode 100644 index 0000000000..1842d61af5 --- /dev/null +++ b/pkg/wakaama/contrib/lwm2m_client_objects.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @{ + * @ingroup lwm2m_client + * + * @file + * @brief Helper functions to interact with the basic objects provided by + * Wakaama from a LwM2M client. + * + * @author Leandro Lanzieri + * @} + */ + +#include "kernel_defines.h" + +#include "lwm2m_client.h" +#include "lwm2m_client_config.h" +#include "lwm2m_client_objects.h" + +/* These functions are defined by the objects (object_security.c and + * object_server.c are implemented by the Wakaama package. device.c can be + * found in 'contrib/objects') */ +lwm2m_object_t *get_security_object(int server_id, const char *server_uri, + char *bs_psk_id, char *psk, + uint16_t psk_len, bool is_bootstrap); +lwm2m_object_t *get_server_object(int server_id, const char *binding, + int lifetime, bool storing); +lwm2m_object_t *lwm2m_get_object_device(void); + +lwm2m_object_t *lwm2m_client_get_security_object( + lwm2m_client_data_t *client_data) +{ + lwm2m_object_t *ret; + char *server_uri = LWM2M_SERVER_URI; + int server_id = LWM2M_SERVER_ID; + uint16_t psk_len = -1; + char *psk_buffer = NULL; + char *psk_id = NULL; + + ret = get_security_object(server_id, server_uri, psk_id, psk_buffer, + psk_len, IS_ACTIVE(LWM2M_BOOTSTRAP)); + + client_data->obj_security = ret; + return ret; +} + +lwm2m_object_t *lwm2m_client_get_server_object( + lwm2m_client_data_t *client_data) +{ + (void)client_data; + lwm2m_object_t *ret; + int server_id = LWM2M_SERVER_ID; + int lifetime = LWM2M_DEVICE_TTL; + + ret = get_server_object(server_id, LWM2M_DEVICE_BINDINGS, lifetime, false); + return ret; +} + +lwm2m_object_t *lwm2m_client_get_device_object( + lwm2m_client_data_t *client_data) +{ + (void)client_data; + return lwm2m_get_object_device(); +} diff --git a/pkg/wakaama/contrib/lwm2m_platform.c b/pkg/wakaama/contrib/lwm2m_platform.c new file mode 100644 index 0000000000..2ffc646742 --- /dev/null +++ b/pkg/wakaama/contrib/lwm2m_platform.c @@ -0,0 +1,122 @@ +/******************************************************************************* +* +* Copyright (c) 2013, 2014, 2015 Intel Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* and Eclipse Distribution License v1.0 which accompany this distribution. +* +* The Eclipse Public License is available at +* http://www.eclipse.org/legal/epl-v10.html +* The Eclipse Distribution License is available at +* http://www.eclipse.org/org/documents/edl-v10.php. +* +* Contributors: +* David Navarro, Intel Corporation - initial API and implementation +* Christian Manal - Ported to RIOT OS +*******************************************************************************/ +/** + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * 2019 HAW Hamburg + * @{ + * @ingroup pkg_wakaama + * + * @file + * @brief Platform adaption for Wakaama package + * + * @author Christian Manal + * @author Leandro Lanzieri + * @} + */ + +#include +#include +#include +#include +#include + +#include "xtimer.h" +#include "tlsf.h" + +#include "lwm2m_platform.h" +#include "lwm2m_client_config.h" + +static uint32_t _tlsf_heap[(LWM2M_TLSF_BUFFER / sizeof(uint32_t))]; +static tlsf_t _tlsf; + +typedef struct { + unsigned free; /**< total free size */ + unsigned used; /**< total used size */ +} _tlsf_size_container_t; + + static void _tlsf_size_walker(void* ptr, size_t size, int used, void* user) +{ + printf("\t%p %s size: %u (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, ptr); + + if (used) { + ((_tlsf_size_container_t *)user)->used += (unsigned int)size; + } + else { + ((_tlsf_size_container_t *)user)->free += (unsigned int)size; + } +} + +void lwm2m_tlsf_status(void) +{ + puts("\nTLSF usage:"); + _tlsf_size_container_t sizes = { .free = 0, .used = 0 }; + tlsf_walk_pool(tlsf_get_pool(_tlsf), _tlsf_size_walker, &sizes); + printf("\tTotal free size: %u\n", sizes.free); + printf("\tTotal used size: %u\n", sizes.used); +} + +void lwm2m_platform_init(void) +{ + _tlsf = tlsf_create_with_pool(_tlsf_heap, sizeof(_tlsf_heap)); +} + +void *lwm2m_malloc(size_t s) +{ + return tlsf_malloc(_tlsf, s); +} + +void lwm2m_free(void *p) +{ + tlsf_free(_tlsf, p); +} + +char *lwm2m_strdup(const char *str) +{ + size_t len = strlen(str) + 1; + void *new = lwm2m_malloc(len); + + if (new == NULL) { + return NULL; + } + + return strncpy(new, str, len); +} + +int lwm2m_strncmp(const char *s1, const char *s2, size_t n) +{ + return strncmp(s1, s2, n); +} + +time_t lwm2m_gettime(void) +{ + return (time_t)(xtimer_now_usec64() / US_PER_SEC); +} + +/* For clang we need to specify that the first argument will be a format string + * for print + */ +__attribute__((__format__ (__printf__, 1, 0))) +void lwm2m_printf(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + + vfprintf(stderr, format, ap); + + va_end(ap); +} diff --git a/pkg/wakaama/contrib/objects/Makefile b/pkg/wakaama/contrib/objects/Makefile new file mode 100644 index 0000000000..8be4d2479b --- /dev/null +++ b/pkg/wakaama/contrib/objects/Makefile @@ -0,0 +1,5 @@ +MODULE := wakaama_objects + +SUBMODULES = 1 + +include $(RIOTBASE)/Makefile.base diff --git a/pkg/wakaama/contrib/objects/device.c b/pkg/wakaama/contrib/objects/device.c new file mode 100644 index 0000000000..c22a5e7f29 --- /dev/null +++ b/pkg/wakaama/contrib/objects/device.c @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ +/** + * @{ + * @ingroup lwm2m_objects_device + * + * @file + * @brief Device object implementation for LwM2M client using Wakaama + * + * @author Christian Manal + * @} + */ + +#include +#include +#include + +#include "liblwm2m.h" +#include "objects/device.h" +#include "lwm2m_client_config.h" + +/* Set to true if reboot requested. */ +static bool reboot; + +/* Lookup table for static resources of device object */ +static const char *_static_resources[] = { + [LWM2M_RES_MANUFACTURER] = LWM2M_DEVICE_MANUFACTURER, + [LWM2M_RES_MODEL_NO] = LWM2M_DEVICE_MODEL, + [LWM2M_RES_SERIAL] = LWM2M_DEVICE_SERIAL, + [LWM2M_RES_FW_VER] = LWM2M_DEVICE_FW_VERSION, + [LWM2M_RES_BINDINGS] = LWM2M_DEVICE_BINDINGS, + [LWM2M_RES_TYPE] = LWM2M_DEVICE_TYPE, + [LWM2M_RES_HW_VERSION] = LWM2M_DEVICE_HW_VERSION, + [LWM2M_RES_SW_VERSION] = LWM2M_DEVICE_SW_VERSION, + [LWM2M_DEVICE_RESOURCES] = NULL +}; + +/*Descriptor of a LwM2M device object instance */ +typedef struct { + uint8_t *power_sources; /**< types of power sources (0-7) */ + uint16_t *power_voltage; /**< voltage of power sources in mV */ + uint16_t *power_current; /**< current of power sources in mA */ + uint8_t battery_status; /**< battery status (0-6) */ + uint32_t mem_total; /**< amount of memory on the device in kB */ + uint16_t(*ext_dev_info)[2]; /**< external devices information */ + uint8_t ext_dev_info_len; /**< amount of external devices information */ + uint8_t error_code[7]; /**< error codes */ + uint8_t error_code_used; /**< amount of error codes used */ +} dev_data_t; + +static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP, + lwm2m_data_t **data_arrayP, + lwm2m_object_t *objectP) +{ + uint8_t result; + int i; + + (void)objectP; + + if (instance_id != 0) { + return COAP_404_NOT_FOUND; + } + + result = COAP_205_CONTENT; + + if (*num_dataP == 0) { + /* This list must contain all available resources */ + uint16_t res[] = { + LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL, + LWM2M_RES_FW_VER, LWM2M_RES_REBOOT, LWM2M_RES_ERROR_CODE, + /* LWM2M_RES_ERROR_CODE_RESET, TODO */ + LWM2M_RES_BINDINGS, LWM2M_RES_TYPE, LWM2M_RES_HW_VERSION, + LWM2M_RES_SW_VERSION, + }; + int len = sizeof(res) / sizeof(uint16_t); + + *data_arrayP = lwm2m_data_new(len); + if (*data_arrayP == NULL) { + return COAP_500_INTERNAL_SERVER_ERROR; + } + *num_dataP = len; + for (i = 0; i < len; i++) { + (*data_arrayP)[i].id = res[i]; + } + } + else { + /* Check if each given resource is present */ + for (i = 0; i < *num_dataP && result == COAP_205_CONTENT; i++) { + switch ((*data_arrayP)[i].id) { + case LWM2M_RES_MANUFACTURER: + case LWM2M_RES_MODEL_NO: + case LWM2M_RES_SERIAL: + case LWM2M_RES_FW_VER: + case LWM2M_RES_REBOOT: + case LWM2M_RES_ERROR_CODE: + /* case LWM2M_RES_ERROR_CODE_RESET: TODO */ + case LWM2M_RES_BINDINGS: + case LWM2M_RES_TYPE: + case LWM2M_RES_HW_VERSION: + case LWM2M_RES_SW_VERSION: + break; + default: + result = COAP_404_NOT_FOUND; + } + } + } + + return result; +} + +static uint8_t prv_device_read(uint16_t instance_id, int *num_dataP, + lwm2m_data_t **data_arrayP, + lwm2m_object_t *objectP) +{ + int i; + uint8_t result = COAP_404_NOT_FOUND; + dev_data_t *data = (dev_data_t *)objectP->userData; + + (void)data; + + /* Single instance object */ + if (instance_id != 0) { + goto out; + } + + /* Full object requested */ + if (*num_dataP == 0) { + /* This list must contain all readable resources */ + uint16_t resList[] = { + LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL, + LWM2M_RES_FW_VER, LWM2M_RES_HW_VERSION, LWM2M_RES_SW_VERSION, + LWM2M_RES_BINDINGS, LWM2M_RES_TYPE, LWM2M_RES_ERROR_CODE, + }; + int cnt = sizeof(resList) / sizeof(uint16_t); + *data_arrayP = lwm2m_data_new(cnt); + if (*data_arrayP == NULL) { + result = COAP_500_INTERNAL_SERVER_ERROR; + goto out; + } + *num_dataP = cnt; + for (i = 0; i < cnt; i++) { + (*data_arrayP)[i].id = resList[i]; + } + } + + for (i = 0; i < *num_dataP; i++) { + switch ((*data_arrayP)[i].id) { + /* Exec resources */ + case LWM2M_RES_REBOOT: + case LWM2M_RES_FRESET: + case LWM2M_RES_ERROR_CODE_RESET: + result = COAP_405_METHOD_NOT_ALLOWED; + goto out; + break; + case LWM2M_RES_ERROR_CODE: + /* TODO: Here some error reporting should be implemented. */ + lwm2m_data_encode_int(LWM2M_DEVICE_ERR_NO_ERR, *data_arrayP + i); + result = COAP_205_CONTENT; + break; + /* The rest are either static or not defined resources */ + default: + if (_static_resources[(*data_arrayP)[i].id]) { + lwm2m_data_encode_string( + _static_resources[(*data_arrayP)[i].id], + *data_arrayP + i); + result = COAP_205_CONTENT; + } + else { + result = COAP_404_NOT_FOUND; + goto out; + } + } + } + +out: + return result; +} + +static uint8_t prv_device_write(uint16_t instance_id, int num_data, + lwm2m_data_t *data_array, + lwm2m_object_t *objectP) +{ + dev_data_t *data = (dev_data_t *)objectP->userData; + + (void)data; + (void)instance_id; + (void)num_data; + (void)data_array; + + if (data_array[0].id < LWM2M_DEVICE_RESOURCES) { + /* for now not writing resources */ + return COAP_405_METHOD_NOT_ALLOWED; + } + else { + return COAP_404_NOT_FOUND; + } +} + +static uint8_t prv_device_execute(uint16_t instance_id, uint16_t resource_id, + uint8_t *buffer, int length, + lwm2m_object_t *objectP) +{ + uint8_t result; + dev_data_t *data = (dev_data_t *)objectP->userData; + + (void)data; + + (void)buffer; + (void)length; + (void)objectP; + + /* single instance object */ + if (instance_id != 0) { + result = COAP_404_NOT_FOUND; + goto err_out; + } + + if (length != 0) { + result = COAP_400_BAD_REQUEST; + goto err_out; + } + + switch (resource_id) { + case LWM2M_RES_REBOOT: + reboot = true; + result = COAP_204_CHANGED; + break; + case LWM2M_RES_ERROR_CODE_RESET: + /* TODO */ + case LWM2M_RES_FRESET: + /* TODO Callback? */ + default: + result = COAP_405_METHOD_NOT_ALLOWED; + } + +err_out: + return result; +} + +/* + * Call this from the main loop to check whether a reboot was requested. + */ +bool lwm2m_device_reboot_requested(void) +{ + return reboot; +} + +lwm2m_object_t *lwm2m_get_object_device(void) +{ + lwm2m_object_t *obj; + + obj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t)); + + if (obj == NULL) { + goto err_out; + } + + memset(obj, 0, sizeof(lwm2m_object_t)); + obj->instanceList = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t)); + + if (obj->instanceList == NULL) { + goto free_obj; + } + + memset(obj->instanceList, 0, sizeof(lwm2m_list_t)); + + obj->objID = LWM2M_DEVICE_OBJECT_ID; + + obj->readFunc = prv_device_read; + obj->writeFunc = prv_device_write; + obj->executeFunc = prv_device_execute; + obj->discoverFunc = prv_device_discover; + + /* Don't allocate memory for stuff that isn't used at the moment */ + /* obj->userData = lwm2m_malloc(sizeof(dev_data_t)); */ + /* if (obj->userData == NULL) { */ + /* goto free_ilist; */ + /* } */ + /* */ + /* memset(obj->userData, 0, sizeof(dev_data_t)); */ + /* INT USER DATA HERE */ + + return obj; + +/* free_ilist: */ +/* lwm2m_free(obj->instanceList); */ + +free_obj: + lwm2m_free(obj); + +err_out: + return NULL; +} + +void lwm2m_free_object_device(lwm2m_object_t *obj) +{ + if (obj == NULL) { + return; + } + if (obj->userData) { + lwm2m_free(obj->userData); + } + if (obj->instanceList) { + lwm2m_free(obj->instanceList); + } + lwm2m_free(obj); +} diff --git a/pkg/wakaama/include/lwm2m_client.h b/pkg/wakaama/include/lwm2m_client.h new file mode 100644 index 0000000000..de5d9b25fb --- /dev/null +++ b/pkg/wakaama/include/lwm2m_client.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_wakaama + * @defgroup lwm2m_client LwM2M Client using Wakaama + * @brief Wakaama adaption to RIOT for implementing a LwM2M client + * @{ + * @file + * @brief Definitions and public API for a LwM2M client using Wakaama + * + * @author Leandro Lanzieri + */ + +#ifndef LWM2M_CLIENT_H +#define LWM2M_CLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "periph/pm.h" +#include "net/sock/udp.h" + +#include "lwm2m_client_config.h" +#include "liblwm2m.h" + +/** + * @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 */ +} lwm2m_client_connection_t; + +/** + * @brief LwM2M client descriptor + */ +typedef struct { + kernel_pid_t pid; /**< PID of the client thread */ + sock_udp_t sock; /**< UDP server sock */ + sock_udp_ep_t local_ep; /**< Local endpoint */ + lwm2m_context_t *lwm2m_ctx; /**< LwM2M context */ + lwm2m_object_t *obj_security; /**< LwM2M security object */ + lwm2m_client_connection_t *conn_list; /**< LwM2M connections list */ +} lwm2m_client_data_t; + +/** + * @brief Size of the buffer for the UDP packet reception + */ +#define LWM2M_CLIENT_RCV_BUFFER_SIZE (200) + +/** + * @brief Time in seconds to wait until reboot after a server + * request + */ +#define LWM2M_CLIENT_REBOOT_TIME (5) + +/** + * @brief Time in seconds to wait until LwM2M is refreshed. + * + * @note This time is used as the timeout for receiving UDP packets and will be + * the maximum time to wait between calls to wakaama core. + */ +#define LWM2M_CLIENT_MIN_REFRESH_TIME (1) + +/** + * @brief Starts a LwM2M client + * + * @param[in, out] client_data Pointer to a LwM2M client data descriptor + * @param[in] obj_list List of LwM2M objects to be registered + * @param[in] obj_numof Number of objects in @p obj_list + * + * @return Context of the LwM2M client + */ +lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data, + lwm2m_object_t *obj_list[], + uint16_t obj_numof); + +/** + * @brief Initializes a LwM2M client + * + * @note This functions initializes the memory allocation and is needed before + * calling any object creation (i.e. any call to lwm2m_malloc). + * + * @param[in] client_data Pointer to a LwM2M client data descriptor + */ +void lwm2m_client_init(lwm2m_client_data_t *client_data); + +/** + * @brief Returns the LwM2M context of a LwM2M client + * + * @param[in] client_data pointer to the LwM2M client descriptor + * + * @return Pointer to the LwM2M context + */ +static inline lwm2m_context_t *lwm2m_client_get_ctx( + lwm2m_client_data_t *client_data) +{ + return client_data->lwm2m_ctx; +} + +#ifdef __cplusplus +} +#endif + +#endif /* LWM2M_CLIENT_H */ +/** @} */ diff --git a/pkg/wakaama/include/lwm2m_client_config.h b/pkg/wakaama/include/lwm2m_client_config.h new file mode 100644 index 0000000000..247fdb586e --- /dev/null +++ b/pkg/wakaama/include/lwm2m_client_config.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_wakaama + * @ingroup config + * @defgroup lwm2m_client_config Wakaama LwM2M Client configuration + * + * @brief Configuration options for the LwM2M client implementation + * based on the Wakaama package. + * @{ + * + * @file + * @brief LwM2M client configurations + * + * @author Christian Manal + * @author Leandro Lanzieri + */ + + +#ifndef LWM2M_CLIENT_CONFIG_H +#define LWM2M_CLIENT_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief CoAP default port of the LwM2M server + */ +#ifndef LWM2M_STANDARD_PORT +#define LWM2M_STANDARD_PORT "5683" +#endif + +/** + * @brief CoAPS default port of the LwM2M server + */ +#ifndef LWM2M_DTLS_PORT +#define LWM2M_DTLS_PORT "5684" +#endif + +/** + * @brief CoAP default port of the LwM2M bootstrap server + */ +#ifndef LWM2M_BSSERVER_PORT +#define LWM2M_BSSERVER_PORT "5685" +#endif + +/** + * @brief Default port for the local LwM2M instance + */ +#ifndef LWM2M_LOCAL_PORT +#define LWM2M_LOCAL_PORT "5683" +#endif + +/** + * @brief Device name used to register at the LwM2M server + */ +#ifndef LWM2M_DEVICE_NAME +#define LWM2M_DEVICE_NAME "testRIOTDevice" +#endif + +/** + * @brief Lifetime of the device object on the LwM2M server + */ +#ifndef LWM2M_DEVICE_TTL +#define LWM2M_DEVICE_TTL 300 +#endif + +/** + * @brief LwM2M server URI to register/bootstrap with + * + * @note The host part of the URI MUST be a valid IPv6 address. Host names can + * not be resolved at this time. + */ +#ifndef LWM2M_SERVER_URI +#define LWM2M_SERVER_URI "coap://[fd00:dead:beef::1]" +#endif + +/** + * @brief Numeric ID of LWM2M_SERVER_URI + */ +#ifndef LWM2M_SERVER_ID +#define LWM2M_SERVER_ID 10 +#endif + +/** + * @brief Alternate path to place LwM2M resources + */ +#ifndef LWM2M_ALT_PATH +#define LWM2M_ALT_PATH NULL +#endif + +/** + * @brief Define to 1 to specify that @ref LWM2M_SERVER_URI is a bootstrap server + * + * To define just add it to your `CFLAGS` in your application's Makefile: + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk} + * CFLAGS += -DLWM2M_BOOTSTRAP=1 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#ifdef DOXYGEN +#define LWM2M_BOOTSTRAP +#endif + +/** + * @brief Device object manufacturer string + */ +#ifndef LWM2M_DEVICE_MANUFACTURER +#define LWM2M_DEVICE_MANUFACTURER "A RIOT maker" +#endif + +/** + * @brief Device object model. + * + * @note Defaults to the board name + */ +#ifndef LWM2M_DEVICE_MODEL +#define LWM2M_DEVICE_MODEL RIOT_BOARD +#endif + +/** + * @brief Device object serial number + */ +#ifndef LWM2M_DEVICE_SERIAL +#define LWM2M_DEVICE_SERIAL "undefined" +#endif + +/** + * @brief Device object firmware version + * + * @note Defaults to the running RIOT version + */ +#ifndef LWM2M_DEVICE_FW_VERSION +#define LWM2M_DEVICE_FW_VERSION RIOT_VERSION +#endif + +/** + * @brief Device object binding and queue mode + * + * Valid values are: + * - U: UDP + * - UQ: UDP with Queue mode + * - S: SMS + * - SQ: SMS with Queue mode + * - US: UDP and SMS + * - UQS: UDP with Queue mode and SMS + */ +#ifndef LWM2M_DEVICE_BINDINGS +#define LWM2M_DEVICE_BINDINGS "U" +#endif + +/** + * @brief Device object device type + */ +#ifndef LWM2M_DEVICE_TYPE +#define LWM2M_DEVICE_TYPE "RIOT device" +#endif + +/** + * @brief Device object hardware version + * + * @note Defaults to the board name + */ +#ifndef LWM2M_DEVICE_HW_VERSION +#define LWM2M_DEVICE_HW_VERSION RIOT_BOARD +#endif + +/** + * @brief Device object software version + * + * @note Defaults to the running RIOT version + */ +#ifndef LWM2M_DEVICE_SW_VERSION +#define LWM2M_DEVICE_SW_VERSION RIOT_VERSION +#endif +/** @} */ + +#ifdef __cplusplus +} +#endif +/** @} */ +#endif /* LWM2M_CLIENT_CONFIG_H */ diff --git a/pkg/wakaama/include/lwm2m_client_connection.h b/pkg/wakaama/include/lwm2m_client_connection.h new file mode 100644 index 0000000000..f58f94260f --- /dev/null +++ b/pkg/wakaama/include/lwm2m_client_connection.h @@ -0,0 +1,89 @@ +/******************************************************************************* +* +* Copyright (c) 2015 Intel Corporation and others. +* All rights reserved. This program and the accompanying materials +* are made available under the terms of the Eclipse Public License v1.0 +* and Eclipse Distribution License v1.0 which accompany this distribution. +* +* The Eclipse Public License is available at +* http://www.eclipse.org/legal/epl-v10.html +* The Eclipse Distribution License is available at +* http://www.eclipse.org/org/documents/edl-v10.php. +* +* Contributors: +* Simon Bernard - initial API and implementation +* Christian Renz - Please refer to git log +* Christian Manal - Ported to RIOT OS +* +*******************************************************************************/ +/* + * Copyright (C) 2018 Beduino Master Projekt - University of Bremen + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup lwm2m_client + * @brief Public API and definitions of the connection handle for + * LwM2M client implementation using Wakaama + * @{ + * + * @file + * + * @author Christian Manal + * @author Leandro Lanzieri + */ + +#ifndef LWM2M_CLIENT_CONNECTION_H +#define LWM2M_CLIENT_CONNECTION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "net/ipv6/addr.h" +#include "net/sock/udp.h" + +#include "lwm2m_client.h" +#include "lwm2m_client_config.h" + +#define SCHEME_COAPS "coaps://" +#define SCHEME_COAP "coap://" + +/** + * @brief Tries to find an existing connection based on a remote UDP endpoint + * + * @param[in] conn_list connections list to search + * @param[in] remote remote UDP endpoint to compare to + * + * @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); + +/** + * @brief Handles a received packet from a connection + * + * @param[in] conn connection from where the packet came from + * @param[in] buffer received packet + * @param[in] num_bytes size of the packet + * @param[in] client_data LwM2M client data + * + * @return 0 on success + * @return non-zero otherwise + */ +int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn, + uint8_t *buffer, size_t num_bytes, + lwm2m_client_data_t *client_data); + +#ifdef __cplusplus +} +#endif + +#endif /* LWM2M_CLIENT_CONNECTION_H */ +/** @} */ diff --git a/pkg/wakaama/include/lwm2m_client_objects.h b/pkg/wakaama/include/lwm2m_client_objects.h new file mode 100644 index 0000000000..20aec5f481 --- /dev/null +++ b/pkg/wakaama/include/lwm2m_client_objects.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup lwm2m_client + * @{ + * @brief Public API and definitions for the helper functions to + * interact with basic objects from a LwM2M client. + * + * @file + * @author Leandro Lanzieri + */ + +#ifndef LWM2M_CLIENT_OBJECTS_H +#define LWM2M_CLIENT_OBJECTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lwm2m_client.h" + +/** + * @name Access Control Bits + * @brief Bit definitions for the ACL property of the LwM2M Access Control + * Object. + * + * @see http://www.openmobilealliance.org/tech/profiles/LWM2M_Access_Control-v1_0_3.xml + * @{ + */ +#define LWM2M_ACC_CTRL_READ (1 << 0) /**< Read access */ +#define LWM2M_ACC_CTRL_WRITE (1 << 1) /**< Write access */ +#define LWM2M_ACC_CTRL_EXECUTE (1 << 2) /**< Execution access */ +#define LWM2M_ACC_CTRL_DELETE (1 << 3) /**< Deletion access */ +#define LWM2M_ACC_CTRL_CREATE (1 << 4) /**< Creation access */ +/** @} */ + +/** + * @brief Creates a LwM2M security object with the default configuration from + * net/lwm2m.h + * + * @param[in, out] client_data Pointer to a LwM2M client data descriptor + * + * @return Pointer to the created object in success + * @return NULL otherwise + */ +lwm2m_object_t *lwm2m_client_get_security_object( + lwm2m_client_data_t *client_data); + +/** + * @brief Creates a LwM2M server object with the default configuration from + * net/lwm2m.h + * + * @param[in, out] client_data Pointer to a LwM2M client data descriptor + * + * @return Pointer to the created object + * @return NULL otherwise + */ +lwm2m_object_t *lwm2m_client_get_server_object( + lwm2m_client_data_t *client_data); + +/** + * @brief Creates a LwM2M device object with the default configuration from + * net/lwm2m.h + * @param[in, out] client_data Pointer to a LwM2M client data descriptor + * + * @return Pointer to the created object + * @return NULL otherwise + */ +lwm2m_object_t *lwm2m_client_get_device_object( + lwm2m_client_data_t *client_data); + +/** + * @brief Creates a LwM2M access control object with the default configuration + * + * @param[in] client_data Pointer to a LwM2M client data descriptor + * + * @return Pointer to the created object + * @return NULL otherwise + */ +lwm2m_object_t *lwm2m_client_get_acc_ctrl_object( + lwm2m_client_data_t *client_data); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWM2M_CLIENT_OBJECTS_H */ +/** @} */ diff --git a/pkg/wakaama/include/lwm2m_platform.h b/pkg/wakaama/include/lwm2m_platform.h new file mode 100644 index 0000000000..026d67c3a4 --- /dev/null +++ b/pkg/wakaama/include/lwm2m_platform.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup pkg_wakaama + * @defgroup lwm2m_platform Platform adaption for Wakaama package + * @brief Adaption of Wakaama LwM2M package to RIOT + * @{ + * @file + * @brief Definitions and public API for Wakaama adaption layer + * + * @author Leandro Lanzieri + */ +#ifndef LWM2M_PLATFORM_H +#define LWM2M_PLATFORM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup lwm2m_platform_conf Wakaama LwM2M platform adaption + * @ingroup config + * @brief Compile-time configuration options for the Wakaama LwM2M platform + * adaption layer. + * @{ + */ +/** @brief Size of allocation buffer in bytes */ +#ifndef LWM2M_TLSF_BUFFER +#define LWM2M_TLSF_BUFFER 5120 +#endif +/** @} */ + +/** + * @brief Initializes the platform adaption for Wakaama LwM2M + */ +void lwm2m_platform_init(void); + +/** + * @brief Prints the status of TLSF allocation buffer, for development use. + */ +void lwm2m_tlsf_status(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWM2M_PLATFORM_H */ +/** @} */ diff --git a/pkg/wakaama/include/objects/device.h b/pkg/wakaama/include/objects/device.h new file mode 100644 index 0000000000..2b2be1629b --- /dev/null +++ b/pkg/wakaama/include/objects/device.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup lwm2m_objects + * @defgroup lwm2m_objects_device Device LwM2M object + * @brief Device object implementation for LwM2M client using Wakaama + * @{ + * + * @file + * + * @author Leandro Lanzieri + */ + +#ifndef OBJECTS_DEVICE_H +#define OBJECTS_DEVICE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#include "liblwm2m.h" +#include "lwm2m_client_config.h" + +/** + * @brief Resources of the LwM2M device object instance + * + * @see http://www.openmobilealliance.org/tech/profiles/LWM2M_Device-v1_0_3.xml + */ +enum lwm2m_device_resources { + LWM2M_RES_MANUFACTURER = 0, /**< Human readable manufacturer name */ + LWM2M_RES_MODEL_NO, /**< Model identifier (manufacturer specified string) */ + LWM2M_RES_SERIAL, /**< Serial number */ + LWM2M_RES_FW_VER, /**< Current firmware version of the device */ + LWM2M_RES_REBOOT, /**< Reboot the device */ + LWM2M_RES_FRESET, /**< Perform a factory reset of the device */ + LWM2M_RES_POWER_SRC, /**< Available power sources */ + LWM2M_RES_POWER_VOL, /**< Present voltage for each power source */ + LWM2M_RES_POWER_AMP, /**< Present current for each power source */ + LWM2M_RES_BATTERY_LEVEL, /**< Current battery level as a percentage */ + LWM2M_RES_MEM_FREE, /**< Estimated current available storage (kB) */ + LWM2M_RES_ERROR_CODE, /**< Last error code */ + LWM2M_RES_ERROR_CODE_RESET, /**< Delete all error code instances */ + LWM2M_RES_TIME, /**< Current UNIX time of the client */ + LWM2M_RES_TIME_OFFSET, /**< Indicated the UTC offset for the device */ + LWM2M_RES_TIME_ZONE, /**< Indicates the time zone of the device */ + LWM2M_RES_BINDINGS, /**< Indicates supported bindings and modes on the client */ + LWM2M_RES_TYPE, /**< Type of device */ + LWM2M_RES_HW_VERSION, /**< Current hardware version of the device */ + LWM2M_RES_SW_VERSION, /**< Current software version on the device */ + LWM2M_RES_BATTERY_STATUS, /**< Battery status when internal battery is present */ + LWM2M_RES_MEM_TOTAL, /**< Total amount of storage space in the device (kB*/ + LWM2M_RES_EXT_DEV_INFO, /**< External device object instance */ + LWM2M_DEVICE_RESOURCES /**< Number of resources */ +}; + +/** + * @brief Error codes for the + * @ref lwm2m_device_resources::LWM2M_RES_ERROR_CODE "Error" resource in the + * device object of LwM2M + */ +enum lwm2m_device_error_codes { + LWM2M_DEVICE_ERR_NO_ERR = 0, /**< No error */ + LWM2M_DEVICE_ERR_LOW_BATT = 1, /**< Low battery power */ + LWM2M_DEVICE_ERR_EXT_OFF = 2, /**< External power supply off */ + LWM2M_DEVICE_ERR_GPS_ERR = 3, /**< GPS module failure */ + LWM2M_DEVICE_ERR_LOW_SIGNAL = 4, /**< Low received signal strength */ + LWM2M_DEVICE_ERR_NO_MEM = 5, /**< Out of memory */ + LWM2M_DEVICE_ERR_SMS_ERR = 6, /**< SMS failure */ + LWM2M_DEVICE_ERR_IP_ERR = 7, /**< IP connectivity failure */ + LWM2M_DEVICE_ERR_PERIPH_ERR = 8 /**< Peripheral malfunction */ +}; + +/** + * @brief Frees the memory of @p obj device object + * + * @param[in] obj pointer to the device object + */ +void lwm2m_free_object_device(lwm2m_object_t *obj); + +/** + * @brief Determines if a reboot request has been issued to the device by a + * server. + * + * @return true reboot has been requested + * @return false reboot has not been requested + */ +bool lwm2m_device_reboot_requested(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* OBJECTS_DEVICE_H */ +/** @} */ diff --git a/pkg/wakaama/include/objects/doc.txt b/pkg/wakaama/include/objects/doc.txt new file mode 100644 index 0000000000..f1c5be774d --- /dev/null +++ b/pkg/wakaama/include/objects/doc.txt @@ -0,0 +1,8 @@ +/** + * @defgroup lwm2m_objects LwM2M Object implementations + * @ingroup pkg_wakaama + * @brief Implementations of LwM2M objects using Wakaama. For a complete + list of the objects supported by the LwM2M protocol check the + object registry: + * @see http://www.openmobilealliance.org/wp/OMNA/LwM2M/LwM2MRegistry.html + */