1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #11036 from leandrolanzieri/pr/pkg/wakaama_rework

pkg/wakaama: Add basic LWM2M client implementation
This commit is contained in:
Ken Bannister 2019-11-29 16:21:05 -05:00 committed by GitHub
commit 353c0e91d0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 2195 additions and 10 deletions

49
examples/wakaama/Makefile Normal file
View File

@ -0,0 +1,49 @@
# name of your application
APPLICATION = wakaama
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../..
# Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += gnrc_netdev_default
USEMODULE += auto_init_gnrc_netif
# Specify the mandatory networking modules
USEMODULE += gnrc_ipv6_router_default
USEMODULE += gnrc_sock_udp
# Additional networking modules that can be dropped if not needed
USEMODULE += gnrc_icmpv6_echo
# Add also the shell, some shell commands
USEMODULE += shell
USEMODULE += shell_commands
USEMODULE += ps
# Comment this out to disable code in RIOT that does safety checking
# which is not needed in a production environment but helps in the
# development process:
DEVELHELP ?= 1
# Specific the server URI address (NOTE: Domain names not supported yet)
SERVER_URI ?= '"coap://[fd00:dead:beef::1]"'
ifneq (,$(SERVER_URI))
CFLAGS += -DLWM2M_SERVER_URI=$(SERVER_URI)
endif
# NOTE: Add the package for wakaama
USEPKG += wakaama
# Uncomment to enable Wakaama debug log
#CFLAGS += -DLWM2M_WITH_LOGS
# Uncomment to indicate that the server is a LwM2M bootstrap server
# CFLAGS += -DLWM2M_BOOTSTRAP=1
# NOTE: Use wakaama in client mode
CFLAGS += -DLWM2M_CLIENT_MODE
include $(RIOTBASE)/Makefile.include

View File

@ -0,0 +1,60 @@
BOARD_BLACKLIST := \
arduino-duemilanove \
arduino-leonardo \
arduino-mega2560 \
arduino-nano \
arduino-uno \
atmega1284p \
atmega256rfr2-xpro \
atmega328p \
avr-rss2 \
chronos \
derfmega128 \
derfmega256 \
mega-xplained \
microduino-corerf \
msb-430 \
msb-430h \
pic32-clicker \
pic32-wifire \
telosb \
waspmote-pro \
wsn430-v1_3b \
wsn430-v1_4 \
z1
BOARD_INSUFFICIENT_MEMORY := \
airfy-beacon \
b-l072z-lrwan1 \
blackpill \
bluepill \
calliope-mini \
cc2650-launchpad \
cc2650stk \
hifive1 \
hifive1b \
i-nucleo-lrwan1 \
lsn50 \
maple-mini \
microbit \
nrf51dongle \
nrf6310 \
nucleo-f030r8 \
nucleo-f031k6 \
nucleo-f302r8 \
nucleo-f303k8 \
nucleo-f042k6 \
nucleo-f070rb \
nucleo-f072rb \
nucleo-f302r8 \
nucleo-f334r8 \
nucleo-l031k6 \
nucleo-l053r8 \
opencm904 \
saml10-xpro \
saml11-xpro \
spark-core \
stm32f030f4-demo \
stm32f0discovery \
stm32l0538-disco \
yunjia-nrf51822

View File

@ -0,0 +1,96 @@
# Wakaama LwM2M example client
This application starts a
[LwM2M](https://wiki.openmobilealliance.org/display/TOOL/What+is+LwM2M) client
on the node with instances of the following objects:
- [Security object](http://www.openmobilealliance.org/tech/profiles/LWM2M_Security-v1_0.xml)
- [Server object](http://www.openmobilealliance.org/tech/profiles/LWM2M_Server-v1_0.xml)
- [Device object](http://www.openmobilealliance.org/tech/profiles/LWM2M_Device-v1_0_3.xml)
The application is based on the Eclipse Wakaama
[example client](https://github.com/eclipse/wakaama/tree/master/examples/client)
.
## Usage
### Setting up a LwM2M Test Server
To test the client a LwM2M server where to register is needed.
[Eclipse Leshan](https://github.com/eclipse/leshan) demo is a good option for
running one locally.
To run the demo server:
```shell
wget https://hudson.eclipse.org/leshan/job/leshan/lastSuccessfulBuild/artifact/leshan-server-demo.jar
java -jar ./leshan-server-demo.jar
```
It will output the addresses where it is listening:
```
INFO LeshanServer - LWM2M server started at coap://0.0.0.0/0.0.0.0:5683 coaps://0.0.0.0/0.0.0.0:5684
INFO LeshanServerDemo - Web server started at http://0.0.0.0:8080/.
```
#### Bootstrap server
LwM2M provides a bootstrapping mechanism to provide the clients with information
to register to one or more servers. To test this mechanism both the previous server and a bootstrap server should be running. Eclipse Leshan also provides a bootstrap server demo.
By default the bootstrap server option is disabled, it can be enabled by defining
`LWM2M_BOOTSTRAP` as 1 (see the Makefile in this application).
To run the bootstrap server, make sure that the ports it uses are different
from the ones of previous server (default are 5683 for CoAP, 5684 for CoAPs,
and 8080 for the webserver), and that it corresponds to the one set in
`lwm2m.h` as `LWM2M_BSSERVER_PORT`:
```shell
# download demo
wget https://hudson.eclipse.org/leshan/job/leshan/lastSuccessfulBuild/artifact/leshan-bsserver-demo.jar
# set CoAP, CoAPs and webserver ports for bootstrap server
BS_COAPPORT=5685
BS_COAPSPORT=5686
BS_WEBPORT=8888
# run the server
java -jar ./leshan-bsserver-demo.jar --coapport ${BS_COAPPORT} \
--coapsport ${BS_COAPSPORT} --webport ${BS_WEBPORT}
```
To set up the configuration of the node and the server:
1. Click the `Add new client bootstrap configuration` button.
2. Fill in the name of the device, it **should** match the one set in
`lwm2m.h` as `LWM2M_DEVICE_NAME`.
3. Using the `LWM2M Server` tab enter the address where the LwM2M server is
listening. For now only `No security` mode can be used.
### Running the client
The address set in `lwm2m.h` as `LWM2M_SERVER_URI` should be reachable
from the node, e.g. either running on native with a tap interface or as a mote
connected to a
[border router](https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_border_router).
Also, if a bootstrap server is being used the macro `LWM2M_BOOTSTRAP` should be
defined as 1.
The server URI for the example is being defined using the variable `SERVER_URI`
in the Makefile, and can be changed when compiling.
#### Compile and run
For debugging purposes there are two types of messages that can be enabled:
- The lwm2m client adaptation debug can be enabled by setting `ENABLE_DEBUG` in
`lwm2m_client.c` and `lwm2m_client_connection.c` to 1
- The wakaama internal logging can be enabled by adding `LWM2M_WITH_LOGS` to the
CFLAGS (`CFLAGS += -DLWM2M_WITH_LOGS`)
For memory allocation the TLSF package is being used, with a private heap. If
memory usage has to be tweaked the heap size can be modified via the macro
`LWM2M_TLSF_BUFFER`.
To compile run:
```shell
BOARD=<board> make clean all flash term
```
#### Shell commands
- `lwm2m start`: Starts the LwM2M by configuring the module and registering to
the server.

View File

@ -0,0 +1,74 @@
/*
* 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 examples
* @{
*
* @file
* @brief Wakaama LwM2M Client CLI support
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include "kernel_defines.h"
#include "lwm2m_client.h"
#include "lwm2m_client_objects.h"
#include "lwm2m_platform.h"
#define OBJ_COUNT (3)
uint8_t connected = 0;
lwm2m_object_t *obj_list[OBJ_COUNT];
lwm2m_client_data_t client_data;
void lwm2m_cli_init(void)
{
/* this call is needed before creating any objects */
lwm2m_client_init(&client_data);
/* add objects that will be registered */
obj_list[0] = lwm2m_client_get_security_object(&client_data);
obj_list[1] = lwm2m_client_get_server_object(&client_data);
obj_list[2] = lwm2m_client_get_device_object(&client_data);
if (!obj_list[0] || !obj_list[1] || !obj_list[2]) {
puts("Could not create mandatory objects");
}
}
int lwm2m_cli_cmd(int argc, char **argv)
{
if (argc == 1) {
goto help_error;
}
if (!strcmp(argv[1], "start")) {
/* run the LwM2M client */
if (!connected && lwm2m_client_run(&client_data, obj_list, OBJ_COUNT)) {
connected = 1;
}
return 0;
}
if (IS_ACTIVE(DEVELHELP) && !strcmp(argv[1],"mem")) {
lwm2m_tlsf_status();
return 0;
}
help_error:
if (IS_ACTIVE(DEVELHELP)) {
printf("usage: %s <start|mem>\n", argv[0]);
}
else {
printf("usage: %s <start>\n", argv[0]);
}
return 1;
}

50
examples/wakaama/main.c Normal file
View File

@ -0,0 +1,50 @@
/*
* 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 examples
* @{
*
* @file
* @brief Example application for Eclipse Wakaama LwM2M Client
*
* @author Christian Manal <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include "board.h"
#include "msg.h"
#include "shell.h"
#define SHELL_QUEUE_SIZE (8)
static msg_t _shell_queue[SHELL_QUEUE_SIZE];
extern void lwm2m_cli_init(void);
extern int lwm2m_cli_cmd(int argc, char **argv);
static const shell_command_t my_commands[] = {
{ "lwm2m", "Start LwM2M client", lwm2m_cli_cmd },
{ NULL, NULL, NULL }
};
int main(void)
{
/* initiates LwM2M client */
lwm2m_cli_init();
msg_init_queue(_shell_queue, SHELL_QUEUE_SIZE);
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(my_commands, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}

View File

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

View File

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

17
pkg/wakaama/Makefile.dep Normal file
View File

@ -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_<objectName>' 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

View File

@ -1 +1,4 @@
INCLUDES += -I$(PKGDIRBASE)/wakaama/riotbuild
DIRS += $(RIOTBASE)/pkg/wakaama/contrib
INCLUDES += -I$(RIOTBASE)/pkg/wakaama/include
INCLUDES += -I$(PKGDIRBASE)/wakaama

View File

@ -0,0 +1,5 @@
MODULE := wakaama_contrib
DIRS += $(RIOTBASE)/pkg/wakaama/contrib/objects
include $(RIOTBASE)/Makefile.base

View File

@ -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 <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include <string.h>
#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;
}

View File

@ -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 <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include <stddef.h>
#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;
}

View File

@ -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 <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#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();
}

View File

@ -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 <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include <liblwm2m.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

View File

@ -0,0 +1,5 @@
MODULE := wakaama_objects
SUBMODULES = 1
include $(RIOTBASE)/Makefile.base

View File

@ -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 <manal@uni-bremen.de>
* @}
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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);
}

View File

@ -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 <leandro.lanzieri@haw-hamburg.de>
*/
#ifndef LWM2M_CLIENT_H
#define LWM2M_CLIENT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/time.h>
#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 */
/** @} */

View File

@ -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 <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#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 */

View File

@ -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 <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#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 */
/** @} */

View File

@ -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 <leandro.lanzieri@haw-hamburg.de>
*/
#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 */
/** @} */

View File

@ -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 <leandro.lanzieri@haw-hamburg.de>
*/
#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 */
/** @} */

View File

@ -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 <leandro.lanzieri@haw-hamburg.de>
*/
#ifndef OBJECTS_DEVICE_H
#define OBJECTS_DEVICE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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 */
/** @} */

View File

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