Various updates in LWM2M standalone example

* Use LWM2M security object as DTLS keystore by default
* Mark endpoint as secure regardless if DTLS peer exists or not
* Somewhat less debug output by default
This commit is contained in:
Niclas Finne 2017-11-07 18:23:21 +01:00
parent 6fe4026686
commit 4a82bda543
8 changed files with 111 additions and 83 deletions

View File

@ -1,3 +1,3 @@
*.o
oma-lwm2m-src
lwm2m-example
/lwm2m-src
/lwm2m-example

View File

@ -2,7 +2,7 @@ PROJECT = lwm2m-example
all: $(PROJECT)
TARGETCDIR = oma-lwm2m-src
TARGETCDIR = lwm2m-src
COREDIRS = sys lib
SOURCEDIRS = .
SOURCE_FILES = posix-main.c posix-coap-timer.c ipso-sensor-temp.c \

View File

@ -10,7 +10,11 @@ IPSO_FILES = ${addprefix ipso-objects/,${filter-out ipso-leds-control.c ipso-obj
TARGET_FILES += ${addprefix $(TARGETCDIR)/,$(CORE_FILES) $(CORE_FILES:.c=.h) \
$(COAP_FILES) $(LWM2M_FILES) $(IPSO_FILES)}
ifneq ($(MAKE_WITH_DTLS),)
ifeq ($(MAKE_WITH_DTLS),1)
ifeq (${wildcard $(DTLS_PATH)/tinydtls/Makefile},)
${error Could not find the tinyDTLS submodule. Please run "git submodule update --init" and try again}
endif
DTLS_FILES = ${subst $(DTLS_PATH)/,,${wildcard ${addprefix $(DTLS_PATH)/tinydtls/,*.[ch] ${addsuffix /*.[ch],$(TINYDTLS_DIRS)}}}}
TARGET_FILES += ${addprefix $(TARGETCDIR)/,$(DTLS_FILES)}
endif

View File

@ -1,58 +1,68 @@
OMA LWM2M Standalone Example
LWM2M Standalone Example
====================================
This is an example of how to make use of the OMA LWM2M and CoAP
implementation from Contiki in a native application.
implementation from Contiki-NG in a native application.
The Makefile will copy necessary files from Contiki to the subfolder
```oma-lwm2m-src``` and then compile the example ```lwm2m-example```
The Makefile will copy necessary files from Contiki-NG to the subfolder
```lwm2m-src``` and then compile the example ```lwm2m-example```
as a native application. By copying only the needed source files,
the example can be used outside the Contiki source tree.
the example can be used outside the Contiki-NG source tree.
### Running the OMA LWM2M example
### Running the LWM2M example
```bash
cd contiki/examples/oma-lwm2m/standalone
cd contiki/examples/lwm2m/standalone
make
./lwm2m-example
```
The example application will start a CoAP server listening on
localhost port 5683 with an example OMA LWM2M device object.
The example application will start a CoAP server listening on localhost port
5683 with some example LWM2M objects. By default, the example application will
also register itself with the Leshan server at leshan.eclipse.org. To specify
a different LWM2M server:
`./lwm2m-example coap://<server host address> <endpoint name>`.
### Testing the OMA LWM2M example
The Copper (Cu) Firefox addon can be used to access the LWM2M example.
1. Start the OMA LWM2M example as described above.
2. Get the Copper (Cu) CoAP user-agent from
[https://addons.mozilla.org/en-US/firefox/addon/copper-270430](https://addons.mozilla.org/en-US/firefox/addon/copper-270430).
3. Start Copper and discover resources at coap://127.0.0.1:5683/
It should find three objects named 0, 1, and 3.
4. Browse to the device type resource at coap://127.0.0.1:5683/3/0/17
(object 3, instance 0, resource 17) and then click ```GET```.
As device type the LWM2M example should return the text "lwm2m-example".
5. Browse to the time resource at coap://127.0.0.1:5683/3/0/13
Every time you click ```GET```, it should return the number of seconds
since the example application was started.
### Moving the example outside Contiki
For example to connect to a locally running LWM2M server:
```bash
cd contiki/examples/oma-lwm2m/standalone
./lwm2m-example coap://127.0.0.1/ example-endpoint-name
```
### Running the LWM2M example with DTLS
The example currently only supports PSK and the default credentials can be
changed in the file `lwm2m-example.c`.
```c
#define PSK_DEFAULT_IDENTITY "Client_identity"
#define PSK_DEFAULT_KEY "secretPSK"
```
To compile with DTLS support and connect to a local LWM2M server with matching
credentials configured:
```bash
cd contiki/examples/lwm2m/standalone
make clean
make MAKE_WITH_DTLS=1
./lwm2m-example coaps://127.0.0.1
```
### Moving the example outside Contiki-NG
```bash
cd contiki/examples/lwm2m/standalone
make copy
```
Copy the example directory contents to a directory outside Contiki.
Copy the example directory contents to a directory outside Contiki-NG.
Remove the Makefile ```Makefile.contiki``` and the remaining Makefile
will compile the example independent of the Contiki source tree.
will compile the example independent of the Contiki-NG source tree.
### Running the LWM2M examle with HEX transport
The Hex Transport can be tested together with DTLS using:
```bash
@ -62,7 +72,6 @@ javac Hex2UDP.java
java Hex2UDP leshan.eclipse.org 5684 ./lwm2m-example
```
Note that you need to configure the Leshan server with the correct
key and ID.
Note that you need to configure the Leshan server with the correct key and ID.
(without DTLS it should be 5683 for CoAP)
(without DTLS it should be 5683 for CoAP).

View File

@ -51,6 +51,7 @@
#include <stdlib.h>
#define DEBUG 1
#define DEBUG_VERBOSE ((DEBUG) && 0)
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#define PRINTEP(ep) coap_endpoint_print(ep)
@ -108,12 +109,12 @@ coap_endpoint_is_connected(const coap_endpoint_t *ep)
peer = dtls_get_peer(dtls_context, ep);
if(peer != NULL) {
/* only if handshake is done! */
PRINTF("peer state for ");
PRINTF("DTLS peer state for ");
PRINTEP(ep);
PRINTF(" is %d %d\n", peer->state, dtls_peer_is_connected(peer));
return dtls_peer_is_connected(peer);
} else {
PRINTF("Did not find peer ");
PRINTF("DTLS did not find peer ");
PRINTEP(ep);
PRINTF("\n");
}
@ -130,8 +131,9 @@ coap_endpoint_connect(coap_endpoint_t *ep)
if(ep->secure == 0) {
return 1;
}
#ifdef WITH_DTLS
PRINTF("DTLS EP:");
PRINTF("DTLS connect to ");
PRINTEP(ep);
PRINTF(" len:%d\n", ep->size);
@ -141,6 +143,7 @@ coap_endpoint_connect(coap_endpoint_t *ep)
return 1;
}
#endif /* WITH_DTLS */
return 0;
}
/*---------------------------------------------------------------------------*/
@ -181,7 +184,7 @@ coap_endpoint_print(const coap_endpoint_t *ep)
const char *address;
address = inet_ntoa(ep->addr.sin_addr);
if(address != NULL) {
printf("coap%s://%s:%u",ep->secure ? "s":"",
printf("coap%s://%s:%u", ep->secure ? "s" : "",
address, ntohs(ep->addr.sin_port));
} else {
printf("<#N/A>");
@ -200,15 +203,14 @@ coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep)
int secure;
int offset = 0;
int i;
PRINTF("CoAP-IPv4: Parsing endpoint: %.*s\n", (int)size, text);
PRINTF("CoAP-IPv4: parsing endpoint %.*s => ", (int)size, text);
if(strncmp("coap://", text, 7) == 0) {
secure = 0;
offset = 7;
PRINTF("COAP found\n");
} else if(strncmp("coaps://", text, 8) == 0) {
secure = 1;
offset = 8;
PRINTF("COAPS found\n");
PRINTF("secure ");
} else {
secure = 0;
}
@ -225,7 +227,7 @@ coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep)
port = atoi(&text[i + 1]);
}
PRINTF("CoAP-IPv4: endpoint %s:%u\n", host, port);
PRINTF("endpoint at %s:%u\n", host, port);
ep->addr.sin_family = AF_INET;
ep->addr.sin_port = htons(port);
@ -252,7 +254,7 @@ coap_datalen()
}
/*---------------------------------------------------------------------------*/
static int
read_packet_to_coapbuf(int fd)
read_packet_to_coapbuf(int fd, int is_secure)
{
int len;
@ -268,7 +270,9 @@ read_packet_to_coapbuf(int fd)
return 0;
}
PRINTF("RECV from ");
last_source.secure = is_secure;
PRINTF("CoAP-IPv4: RECV from ");
PRINTEP(&last_source);
PRINTF(" %u bytes\n", len);
coap_buf_len = len;
@ -298,8 +302,8 @@ coap_ipv4_handle_fd(fd_set *rset, fd_set *wset)
{
if(coap_ipv4_fd >= 0 && FD_ISSET(coap_ipv4_fd, rset)) {
if(read_packet_to_coapbuf(coap_ipv4_fd)) {
#if DEBUG
if(read_packet_to_coapbuf(coap_ipv4_fd, 0)) {
#if DEBUG_VERBOSE
int i;
uint8_t *data;
data = coap_databuf();
@ -308,7 +312,7 @@ coap_ipv4_handle_fd(fd_set *rset, fd_set *wset)
PRINTF("%02x", data[i]);
}
PRINTF("\n");
#endif /* DEBUG */
#endif /* DEBUG_VERBOSE */
coap_receive(coap_src_endpoint(), coap_databuf(), coap_datalen());
}
}
@ -335,9 +339,8 @@ static void
dtls_ipv4_handle_fd(fd_set *rset, fd_set *wset)
{
if(dtls_ipv4_fd >= 0 && FD_ISSET(dtls_ipv4_fd, rset)) {
if(read_packet_to_coapbuf(dtls_ipv4_fd) && dtls_context) {
if(read_packet_to_coapbuf(dtls_ipv4_fd, 1) && dtls_context) {
/* DTLS receive */
last_source.secure = 1;
dtls_handle_message(dtls_context, &last_source,
coap_databuf(), coap_datalen());
}
@ -370,7 +373,7 @@ coap_transport_init(void)
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(coap_ipv4_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
PRINTF("Could not bind CoAP UDP port to %u\n", COAP_SERVER_PORT);
fprintf(stderr, "Could not bind CoAP UDP port to %u\n", COAP_SERVER_PORT);
exit(1);
}
@ -394,7 +397,7 @@ coap_transport_init(void)
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(dtls_ipv4_fd, (struct sockaddr *)&server, sizeof(server)) == -1) {
PRINTF("Could not bind CoAP DTLS UDP port to %u\n",
fprintf(stderr, "Could not bind CoAP DTLS UDP port to %u\n",
COAP_DEFAULT_SECURE_PORT);
exit(1);
}
@ -405,7 +408,7 @@ coap_transport_init(void)
/* create new contet with app-data */
dtls_context = dtls_new_context(&dtls_ipv4_fd);
if(!dtls_context) {
PRINTF("DTLS: cannot create context\n");
fprintf(stderr, "DTLS: cannot create context\n");
exit(-1);
}
@ -417,7 +420,9 @@ void
coap_send_message(const coap_endpoint_t *ep, const uint8_t *data, uint16_t len)
{
if(!coap_endpoint_is_connected(ep)) {
PRINTF("CoAP endpoint not connected\n");
PRINTF("CoAP-IPv4: endpoint ");
PRINTEP(ep);
PRINTF(" not connected - dropping packet\n");
return;
}
@ -433,15 +438,15 @@ coap_send_message(const coap_endpoint_t *ep, const uint8_t *data, uint16_t len)
if(coap_ipv4_fd >= 0) {
if(sendto(coap_ipv4_fd, data, len, 0,
(struct sockaddr *)&ep->addr, ep->size) < 1) {
PRINTF("failed to send to ");
PRINTF("CoAP-IPv4: failed to send to ");
PRINTEP(ep);
PRINTF(" %u bytes: %s\n", len, strerror(errno));
} else {
PRINTF("SENT to ");
PRINTF("CoAP-IPv4: SENT to ");
PRINTEP(ep);
PRINTF(" %u bytes\n", len);
if(DEBUG) {
if(DEBUG_VERBOSE) {
int i;
PRINTF("Sent:");
for(i = 0; i < len; i++) {
@ -462,28 +467,26 @@ static int
input_from_peer(struct dtls_context_t *ctx,
session_t *session, uint8_t *data, size_t len)
{
#if DEBUG_VERBOSE
size_t i;
dtls_peer_t *peer;
printf("received data:");
for (i = 0; i < len; i++) {
printf("%c", data[i]);
PRINTF("DTLS received data:");
for(i = 0; i < len; i++) {
PRINTF("%c", data[i]);
}
printf("\nHex:");
for (i = 0; i < len; i++) {
printf("%02x", data[i]);
PRINTF("\nHex:");
for(i = 0; i < len; i++) {
PRINTF("%02x", data[i]);
}
printf("\n");
PRINTF("\n");
#endif /* DEBUG_VERBOSE */
/* Send this into coap-input */
memmove(coap_databuf(), data, len);
coap_buf_len = len;
peer = dtls_get_peer(ctx, session);
/* If we have a peer then ensure that the endpoint is tagged as secure */
if(peer) {
/* Ensure that the endpoint is tagged as secure */
session->secure = 1;
}
coap_receive(session, coap_databuf(), coap_datalen());
@ -496,8 +499,10 @@ output_to_peer(struct dtls_context_t *ctx,
session_t *session, uint8_t *data, size_t len)
{
int fd = *(int *)dtls_get_app_data(ctx);
printf("output_to_peer len:%d %d (s-size: %d)\n", (int)len, fd,
#if DEBUG_VERBOSE
PRINTF("DTLS output_to_peer len:%d %d (s-size: %d)\n", (int)len, fd,
session->size);
#endif /* DEBUG_VERBOSE */
return sendto(fd, data, len, MSG_DONTWAIT,
(struct sockaddr *)&session->addr, session->size);
}
@ -543,14 +548,16 @@ get_psk_info(struct dtls_context_t *ctx,
keystore->coap_get_psk_info((coap_endpoint_t *)session, &ks);
}
if(ks.identity == NULL || ks.identity_len == 0) {
PRINTF("no psk_identity found\n");
return 0;
}
if(result_length < ks.identity_len) {
PRINTF("cannot set psk_identity -- buffer too small\n");
PRINTF("cannot return psk_identity -- buffer too small\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
memcpy(result, ks.identity, ks.identity_len);
PRINTF("psk_identity with %u bytes found\n", ks.identity_len);
return ks.identity_len;
case DTLS_PSK_KEY:
@ -566,10 +573,11 @@ get_psk_info(struct dtls_context_t *ctx,
}
if(result_length < ks.key_len) {
PRINTF("cannot set psk -- buffer too small\n");
PRINTF("cannot return psk -- buffer too small\n");
return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
}
memcpy(result, ks.key, ks.key_len);
PRINTF("psk with %u bytes found\n", ks.key_len);
return ks.key_len;
default:

View File

@ -45,16 +45,21 @@
#define COAP_TIMER_CONF_DRIVER coap_timer_native_driver
#define LWM2M_ENGINE_CLIENT_ENDPOINT_NAME "lwm2m-ex"
#define LWM2M_DEVICE_MANUFACTURER "SICS, Swedish ICT AB"
#define LWM2M_DEVICE_MANUFACTURER "RISE SICS"
#define LWM2M_DEVICE_TYPE "lwm2m-example"
#define LWM2M_DEVICE_MODEL_NUMBER "000"
#define LWM2M_DEVICE_SERIAL_NO "1"
#define LWM2M_DEVICE_FIRMWARE_VERSION "0.1"
/* Use LWM2M as DTLS keystore */
#define COAP_DTLS_KEYSTORE_CONF_WITH_LWM2M 1
#ifdef COAP_TRANSPORT_CONF_H
#include COAP_TRANSPORT_CONF_H
#endif
#ifndef COAP_MAX_CHUNK_SIZE
#define COAP_MAX_CHUNK_SIZE 256
#endif /* COAP_MAX_CHUNK_SIZE */
#endif /* CONTIKI_H_ */

View File

@ -149,6 +149,7 @@ start_application(int argc, char *argv[])
printf("\n");
#ifdef WITH_DTLS
#if COAP_DTLS_KEYSTORE_CONF_WITH_LWM2M
#if defined(PSK_DEFAULT_IDENTITY) && defined(PSK_DEFAULT_KEY)
{
lwm2m_security_server_t *server;
@ -176,20 +177,20 @@ start_application(int argc, char *argv[])
}
}
#endif /* defined(PSK_DEFAULT_IDENTITY) && defined(PSK_DEFAULT_KEY) */
#endif /* COAP_DTLS_KEYSTORE_CONF_WITH_LWM2M */
#endif /* WITH_DTLS */
#define BOOTSTRAP 0
#if BOOTSTRAP
lwm2m_rd_client_register_with_bootstrap_server(&server_ep);
lwm2m_rd_client_use_bootstrap_server(1);
#else
#else /* BOOTSTRAP */
lwm2m_rd_client_register_with_server(&server_ep);
#endif
#endif /* BOOTSTRAP */
lwm2m_rd_client_use_registration_server(1);
lwm2m_rd_client_init(name);
printf("Callback: %p\n", session_callback);
lwm2m_rd_client_set_session_callback(session_callback);
} else {

View File

@ -39,6 +39,7 @@
#include "coap-timer.h"
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <stdarg.h>