diff --git a/examples/lwm2m/standalone/.gitignore b/examples/lwm2m/standalone/.gitignore new file mode 100644 index 000000000..f1e834bc0 --- /dev/null +++ b/examples/lwm2m/standalone/.gitignore @@ -0,0 +1,3 @@ +*.o +oma-lwm2m-src +lwm2m-example diff --git a/examples/lwm2m/standalone/Hex2DTLS.java b/examples/lwm2m/standalone/Hex2DTLS.java new file mode 100644 index 000000000..8bb381100 --- /dev/null +++ b/examples/lwm2m/standalone/Hex2DTLS.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A Java IPv4 transport for CoAP + LWM2M + * Converts hex input to DTLS/UDP packets and incoming packets to + * hex out. + * + * Note: This needs the eclipse scandium DTLS implementation to work. + * The example use PSK and the keys according to the code. This needs + * to be configured in Leshan for it to accept the device. + * \author + * Joakim Eriksson + * Niclas Finne + */ +import javax.xml.bind.DatatypeConverter; +import java.net.DatagramSocket; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.io.IOException; +import java.util.Arrays; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.io.PrintStream; + +import org.eclipse.californium.scandium.dtls.pskstore.StaticPskStore; +import org.eclipse.californium.scandium.config.DtlsConnectorConfig; +import org.eclipse.californium.scandium.DTLSConnector; +import org.eclipse.californium.elements.RawData; +import org.eclipse.californium.elements.RawDataChannel; + + +public class Hex2DTLS { + + DTLSConnector dtlsConnector; + InetAddress address; + int port; + + Hex2DTLS(String host, int port) { + try { + DtlsConnectorConfig.Builder builder = new DtlsConnectorConfig.Builder(new InetSocketAddress(0)); + builder.setPskStore(new StaticPskStore("Client_Identity", "secretPSK".getBytes())); + builder.setClientOnly(); + dtlsConnector = new DTLSConnector(builder.build(), null); + dtlsConnector.setRawDataReceiver(new RawDataChannel() { + public void receiveData(final RawData raw) { + receive(raw.getBytes()); + } + }); + dtlsConnector.start(); + + this.address = InetAddress.getByName(host); + this.port = port; + } catch(Exception e) { + e.printStackTrace(); + } + } + + public void send(byte[] data) throws IOException { + RawData rawData = new RawData(data, address, port); + dtlsConnector.send(rawData); + } + + /* Override this to make something more sensible with the data */ + public void receive(byte[] data) { + String s = DatatypeConverter.printHexBinary(data); + System.out.println("COAPHEX:" + s); + } + + /* Loop on std in to get lines of hex to send */ + public static void main(String[] args) throws IOException { + InputStream in = System.in; + final PrintStream out; + System.err.println("Connecting to " + args[0]); + if(args.length > 1) { + Runtime rt = Runtime.getRuntime(); + Process pr = rt.exec(args[1]); + System.err.println("Started " + args[1]); + in = pr.getInputStream(); + out = new PrintStream(pr.getOutputStream()); + } else { + out = System.out; + } + + /* Create a Hex2DTLS that print on this out stream . CoAPs Port*/ + Hex2DTLS udpc = new Hex2DTLS(args[0], 5684) { + public void receive(byte[] data) { + String s = DatatypeConverter.printHexBinary(data); + out.println("COAPHEX:" + s); + out.flush(); + System.err.println("IN: " + s); + } + }; + + BufferedReader buffer = + new BufferedReader(new InputStreamReader(in)); + + /* The read loop */ + while(true) { + String line = buffer.readLine(); + if(line == null) { + /* Connection closed */ + System.err.println("*** stdin closed"); + System.exit(0); + } else if (line.startsWith("COAPHEX:")) { + byte[] data = DatatypeConverter.parseHexBinary(line.substring(8)); + udpc.send(data); + } + System.err.println("OUT:" + line); + } + } +} diff --git a/examples/lwm2m/standalone/Hex2UDP.java b/examples/lwm2m/standalone/Hex2UDP.java new file mode 100644 index 000000000..d084d7d24 --- /dev/null +++ b/examples/lwm2m/standalone/Hex2UDP.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A Java IPv4 transport for CoAP + LWM2M + * Converts hex input to UDP packets and incoming packets to hex out. + * \author + * Joakim Eriksson + * Niclas Finne + */ +import javax.xml.bind.DatatypeConverter; +import java.net.DatagramSocket; +import java.net.DatagramPacket; +import java.net.InetAddress; +import java.io.IOException; +import java.util.Arrays; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.InputStream; +import java.io.PrintStream; + +public class Hex2UDP implements Runnable { + + DatagramSocket serverSocket; + InetAddress address; + int port; + + Hex2UDP(String host, int port) { + try { + serverSocket = new DatagramSocket(); + this.address = InetAddress.getByName(host); + this.port = port; + new Thread(this).start(); + } catch(Exception e) { + /* Do good stuff here... */ + e.printStackTrace(); + } + } + + public void run() { + byte[] receiveData = new byte[1024]; + /* The receive loop */ + while(true) { + DatagramPacket receivePacket = + new DatagramPacket(receiveData, receiveData.length); + try { + /* Receive a packet */ + serverSocket.receive(receivePacket); + } catch (IOException e) { + e.printStackTrace(); + } + byte[] data2 = Arrays.copyOf(receivePacket.getData(), + receivePacket.getLength()); + receive(data2); + } + } + + public void send(byte[] data) throws IOException { + DatagramPacket sendPacket = + new DatagramPacket(data, data.length, address, port); + serverSocket.send(sendPacket); + } + + /* Override this to make something more sensible with the data */ + public void receive(byte[] data) { + String s = DatatypeConverter.printHexBinary(data); + System.out.println("COAPHEX:" + s); + } + + /* Loop on std in to get lines of hex to send */ + public static void main(String[] args) throws IOException { + InputStream in = System.in; + final PrintStream out; + System.err.println("Connecting to " + args[0]); + if(args.length > 2) { + Runtime rt = Runtime.getRuntime(); + Process pr = rt.exec(args[2]); + System.err.println("Started " + args[2]); + in = pr.getInputStream(); + out = new PrintStream(pr.getOutputStream()); + } else { + out = System.out; + } + + /* Create a Hex2UDP that print on this out stream */ + Hex2UDP udpc = new Hex2UDP(args[0], Integer.parseInt(args[1])) { + public void receive(byte[] data) { + String s = DatatypeConverter.printHexBinary(data); + out.println("COAPHEX:" + s); + out.flush(); + System.err.println("IN: " + s); + } + }; + + BufferedReader buffer = + new BufferedReader(new InputStreamReader(in)); + + /* The read loop */ + while(true) { + String line = buffer.readLine(); + if(line == null) { + /* Connection closed */ + System.err.println("*** stdin closed"); + System.exit(0); + } else if (line.startsWith("COAPHEX:")) { + byte[] data = DatatypeConverter.parseHexBinary(line.substring(8)); + udpc.send(data); + } + System.err.println("OUT:" + line); + } + } +} diff --git a/examples/lwm2m/standalone/Makefile b/examples/lwm2m/standalone/Makefile new file mode 100644 index 000000000..03a8fda23 --- /dev/null +++ b/examples/lwm2m/standalone/Makefile @@ -0,0 +1,61 @@ +PROJECT = lwm2m-example + +all: $(PROJECT) + +TARGETCDIR = oma-lwm2m-src +COREDIRS = sys lib +SOURCEDIRS = . +SOURCE_FILES = posix-main.c posix-coap-timer.c ipso-sensor-temp.c \ + ipso-control-test.c generic-object-test.c +APPSDIRS = coap lwm2m ipso-objects + +ifneq ($(MAKE_WITH_DTLS),) + CFLAGS += -DWITH_DTLS=1 + TINYDTLS_DIRS = aes ecc sha2 + APPSDIRS += tinydtls ${addprefix tinydtls/,$(TINYDTLS_DIRS)} + SOURCE_FILES += dtls-support.c + SOURCEDIRS += tinydtls-support +endif + +TARGETCDIRS += ${addprefix $(TARGETCDIR)/,$(COREDIRS) $(APPSDIRS)} +SOURCEDIRS += ${addprefix $(TARGETCDIR)/,. $(APPSDIRS)} + +CFLAGS += -Wall -Werror +CFLAGS += ${addprefix -I,$(SOURCEDIRS)} + +TRANSPORT ?= ipv4 +ifeq ($(TRANSPORT),ipv4) + TRANSPORTDIR = coap-ipv4 + CFLAGS += -DWITH_COAP_IPV4=1 -DCOAP_TRANSPORT_CONF_H=\"coap-ipv4.h\" +else ifeq ($(TRANSPORT),hex) + TRANSPORTDIR = coap-hex + CFLAGS += -DWITH_COAP_HEX=1 -DCOAP_TRANSPORT_CONF_H=\"coap-hex.h\" +else + ${error Unknown CoAP transport: $(TRANSPORT)} +endif + +SOURCEDIRS += $(TRANSPORTDIR) +SOURCE_FILES += ${notdir ${wildcard $(TRANSPORTDIR)/*.c}} + +vpath %.c $(SOURCEDIRS) + +-include Makefile.contiki + +ifndef OBJECT_FILES + SOURCE_FILES += ${wildcard ${addsuffix /*.c,$(TARGETCDIRS)} } + OBJECT_FILES = $(SOURCE_FILES:.c=.o) +endif + +$(PROJECT): $(PROJECT).c $(OBJECT_FILES) + $(CC) $(CFLAGS) -o $@ $(PROJECT).c $(OBJECT_FILES) + +lib: liblwm2m.a + +clean:: + @-rm -f $(OBJECT_FILES) *.o liblwm2m.a $(PROJECT) + +liblwm2m.a: $(OBJECT_FILES) + $(AR) rvs $@ $(OBJECT_FILES) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ diff --git a/examples/lwm2m/standalone/Makefile.contiki b/examples/lwm2m/standalone/Makefile.contiki new file mode 100644 index 000000000..ecd46311a --- /dev/null +++ b/examples/lwm2m/standalone/Makefile.contiki @@ -0,0 +1,53 @@ +CONTIKI = ../../.. +CP=cp +MKDIR=mkdir + +DTLS_PATH := $(CONTIKI)/os/net/security +CORE_FILES = sys/cc.h sys/cc-gcc.h lib/list.c lib/memb.c +COAP_FILES = ${addprefix coap/,${filter-out coap-blocking-api.% coap-uip.% coap-timer-default.%,${notdir ${wildcard $(CONTIKI)/os/net/app-layer/coap/coap*}}}} +LWM2M_FILES = ${addprefix lwm2m/,${filter-out ,${notdir ${wildcard $(CONTIKI)/os/services/lwm2m/lwm2m-*}}}} +IPSO_FILES = ${addprefix ipso-objects/,${filter-out ipso-leds-control.c ipso-objects.% ipso-temperature.% ipso-light-control.% ipso-button.c,${notdir ${wildcard $(CONTIKI)/os/services/ipso-objects/ipso-*}}}} +TARGET_FILES += ${addprefix $(TARGETCDIR)/,$(CORE_FILES) $(CORE_FILES:.c=.h) \ + $(COAP_FILES) $(LWM2M_FILES) $(IPSO_FILES)} + +ifneq ($(MAKE_WITH_DTLS),) + DTLS_FILES = ${subst $(DTLS_PATH)/,,${wildcard ${addprefix $(DTLS_PATH)/tinydtls/,*.[ch] ${addsuffix /*.[ch],$(TINYDTLS_DIRS)}}}} + TARGET_FILES += ${addprefix $(TARGETCDIR)/,$(DTLS_FILES)} +endif + +SOURCE_FILES += ${filter %.c,$(TARGET_FILES)} +OBJECT_FILES = $(SOURCE_FILES:.c=.o) + +$(TARGETCDIR): + @$(MKDIR) $@ + +$(TARGETCDIRS): $(TARGETCDIR) + @$(MKDIR) $@ + +$(TARGETCDIR)/sys/%: $(CONTIKI)/os/sys/% | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/lib/%: $(CONTIKI)/os/lib/% | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/coap/%: $(CONTIKI)/os/net/app-layer/coap/% | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/lwm2m/%: $(CONTIKI)/os/services/lwm2m/% | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/ipso-objects/%: $(CONTIKI)/os/services/ipso-objects/% | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/tinydtls/%.c: $(DTLS_PATH)/tinydtls/%.c | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(TARGETCDIR)/tinydtls/%.h: $(DTLS_PATH)/tinydtls/%.h | $(TARGETCDIRS) + @$(CP) -av $^ $@ + +$(OBJECT_FILES): $(TARGET_FILES) + +copy: $(TARGET_FILES) + +clean:: + @-rm -rf $(TARGETCDIR) diff --git a/examples/lwm2m/standalone/README.md b/examples/lwm2m/standalone/README.md new file mode 100644 index 000000000..2a582645f --- /dev/null +++ b/examples/lwm2m/standalone/README.md @@ -0,0 +1,68 @@ +OMA 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. + +The Makefile will copy necessary files from Contiki to the subfolder +```oma-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. + +### Running the OMA LWM2M example + +```bash +cd contiki/examples/oma-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. + + +### 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 + +```bash +cd contiki/examples/oma-lwm2m/standalone +make copy +``` + +Copy the example directory contents to a directory outside Contiki. +Remove the Makefile ```Makefile.contiki``` and the remaining Makefile +will compile the example independent of the Contiki source tree. + + +The Hex Transport can be tested together with DTLS using: + +```bash +make clean +make TRANSPORT=hex MAKE_WITH_DTLS=1 +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. + +(without DTLS it should be 5683 for CoAP) diff --git a/examples/lwm2m/standalone/coap-hex/coap-hex.c b/examples/lwm2m/standalone/coap-hex/coap-hex.c new file mode 100644 index 000000000..67e887619 --- /dev/null +++ b/examples/lwm2m/standalone/coap-hex/coap-hex.c @@ -0,0 +1,427 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A HEX text transport for CoAP + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "coap.h" +#include "coap-endpoint.h" +#include "coap-engine.h" +#include +#include +#include + +#define DEBUG 0 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINTEP(ep) coap_endpoint_print(ep) +#else +#define PRINTF(...) +#define PRINTEP(ep) +#endif + +#ifdef WITH_DTLS +#include "tinydtls.h" +#include "dtls.h" +#include "dtls_debug.h" +#endif /* WITH_DTLS */ + +#define BUFSIZE 1280 + +typedef union { + uint32_t u32[(BUFSIZE + 3) / 4]; + uint8_t u8[BUFSIZE]; +} coap_buf_t; + +static coap_endpoint_t last_source; +static coap_buf_t coap_aligned_buf; +static uint16_t coap_buf_len; + +#ifdef WITH_DTLS +#define PSK_DEFAULT_IDENTITY "Client_identity" +#define PSK_DEFAULT_KEY "secretPSK" + +static dtls_handler_t cb; +static dtls_context_t *dtls_context = NULL; + +/* The PSK information for DTLS */ +#define PSK_ID_MAXLEN 256 +#define PSK_MAXLEN 256 +static unsigned char psk_id[PSK_ID_MAXLEN]; +static size_t psk_id_length = 0; +static unsigned char psk_key[PSK_MAXLEN]; +static size_t psk_key_length = 0; +#endif /* WITH_DTLS */ + +/*---------------------------------------------------------------------------*/ +static const coap_endpoint_t * +coap_src_endpoint(void) +{ + return &last_source; +} +/*---------------------------------------------------------------------------*/ +void +coap_endpoint_copy(coap_endpoint_t *destination, const coap_endpoint_t *from) +{ + memcpy(destination, from, sizeof(coap_endpoint_t)); +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_cmp(const coap_endpoint_t *e1, const coap_endpoint_t *e2) +{ + return e1->addr == e2->addr; +} +/*---------------------------------------------------------------------------*/ +void +coap_endpoint_print(const coap_endpoint_t *ep) +{ + printf("%u", ep->addr); +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep) +{ + /* Hex based CoAP has no addresses, just writes data to standard out */ + ep->addr = last_source.addr; +#ifdef WITH_DTLS + ep->secure = 1; +#endif /* WITH_DTLS */ + return 1; +} +/*---------------------------------------------------------------------------*/ +uint8_t * +coap_databuf(void) +{ + return coap_aligned_buf.u8; +} +/*---------------------------------------------------------------------------*/ +uint16_t +coap_datalen() +{ + return coap_buf_len; +} +/*---------------------------------------------------------------------------*/ +static int +hextod(char c) +{ + if(c >= '0' && c <= '9') { + return c - '0'; + } + if(c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + if(c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} +/*---------------------------------------------------------------------------*/ +static void +stdin_callback(const char *line) +{ + uint8_t *buf; + int i, len, llen, v1, v2; + + if(strncmp("COAPHEX:", line, 8) != 0) { + /* Not a CoAP message */ + return; + } + + line += 8; + llen = strlen(line); + if((llen & 1) != 0) { + /* Odd number of characters - not hex */ + fprintf(stderr, "ERROR: %s\n", line); + return; + } + + buf = coap_databuf(); + for(i = 0, len = 0; i < llen; i += 2, len++) { + v1 = hextod(line[i]); + v2 = hextod(line[i + 1]); + if(v1 < 0 || v2 < 0) { + /* Not hex */ + fprintf(stderr, "ERROR: %s\n", line); + return; + } + buf[len] = (uint8_t)(((v1 << 4) | v2) & 0xff); + } + + PRINTF("RECV from "); + PRINTEP(&last_source); + PRINTF(" %u bytes\n", len); + coap_buf_len = len; + + if(DEBUG) { + int i; + uint8_t *data; + data = coap_databuf(); + printf("Received:"); + for(i = 0; i < len; i++) { + printf("%02x", data[i]); + } + printf("\n"); + } + +#ifdef WITH_DTLS + /* DTLS receive??? */ + last_source.secure = 1; + dtls_handle_message(dtls_context, (coap_endpoint_t *) coap_src_endpoint(), coap_databuf(), coap_datalen()); +#else + coap_receive(coap_src_endpoint(), coap_databuf(), coap_datalen()); +#endif /* WITH_DTLS */ +} +/*---------------------------------------------------------------------------*/ +void +coap_transport_init(void) +{ + select_set_stdin_callback(stdin_callback); + + printf("CoAP listening on standard in\n"); + +#ifdef WITH_DTLS + /* create new contet with app-data - no real app-data... */ + dtls_context = dtls_new_context(&last_source); + if (!dtls_context) { + PRINTF("DTLS: cannot create context\n"); + exit(-1); + } + +#ifdef DTLS_PSK + psk_id_length = strlen(PSK_DEFAULT_IDENTITY); + psk_key_length = strlen(PSK_DEFAULT_KEY); + memcpy(psk_id, PSK_DEFAULT_IDENTITY, psk_id_length); + memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); +#endif /* DTLS_PSK */ + PRINTF("Setting DTLS handler\n"); + dtls_set_handler(dtls_context, &cb); +#endif /* WITH_DTLS */ + +} +/*---------------------------------------------------------------------------*/ +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"); + return; + } + +#ifdef WITH_DTLS + if(coap_endpoint_is_secure(ep)) { + dtls_write(dtls_context, (session_t *)ep, (uint8_t *)data, len); + return; + } +#endif /* WITH_DTLS */ + + int i; + printf("COAPHEX:"); + for(i = 0; i < len; i++) { + printf("%02x", data[i]); + } + printf("\n"); +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_connect(coap_endpoint_t *ep) +{ + if(ep->secure == 0) { + return 1; + } +#ifdef WITH_DTLS + PRINTF("DTLS EP:"); + PRINTEP(ep); + PRINTF(" len:%d\n", ep->size); + + /* setup all address info here... should be done to connect */ + + dtls_connect(dtls_context, ep); +#endif /* WITH_DTLS */ + return 1; +} +/*---------------------------------------------------------------------------*/ +void +coap_endpoint_disconnect(coap_endpoint_t *ep) +{ +#ifdef WITH_DTLS + dtls_close(dtls_context, ep); +#endif /* WITH_DTLS */ +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_is_secure(const coap_endpoint_t *ep) +{ + return ep->secure; +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_is_connected(const coap_endpoint_t *ep) +{ + if(ep->secure) { +#ifdef WITH_DTLS + dtls_peer_t *peer; + peer = dtls_get_peer(dtls_context, ep); + if(peer != NULL) { + /* only if handshake is done! */ + PRINTF("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 "); + PRINTEP(ep); + PRINTF("\n"); + } +#endif /* WITH_DTLS */ + return 0; + } + /* Assume that the UDP socket is already up... */ + return 1; +} + +/* DTLS */ +#ifdef WITH_DTLS + +/* This is input coming from the DTLS code - e.g. de-crypted input from + the other side - peer */ +static int +input_from_peer(struct dtls_context_t *ctx, + session_t *session, uint8_t *data, size_t len) +{ + size_t i; + dtls_peer_t *peer; + + printf("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("\n"); + + /* 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) { + session->secure = 1; + } + + coap_receive(session, coap_databuf(), coap_datalen()); + + return 0; +} + +/* This is output from the DTLS code to be sent to peer (encrypted) */ +static int +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, + session->size); + + + int i; + printf("COAPHEX:"); + for(i = 0; i < len; i++) { + printf("%02x", data[i]); + } + printf("\n"); + + return len; +} + + +/* This function is the "key store" for tinyDTLS. It is called to + * retrieve a key for the given identity within this particular + * session. */ +static int +get_psk_info(struct dtls_context_t *ctx, + const session_t *session, + dtls_credentials_type_t type, + const unsigned char *id, size_t id_len, + unsigned char *result, size_t result_length) +{ + PRINTF("---===>>> Getting the Key or ID <<<===---\n"); + switch (type) { + case DTLS_PSK_IDENTITY: + if (id_len) { + dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id); + } + + if (result_length < psk_id_length) { + dtls_warn("cannot set psk_identity -- buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + memcpy(result, psk_id, psk_id_length); + return psk_id_length; + case DTLS_PSK_KEY: + if (id_len != psk_id_length || memcmp(psk_id, id, id_len) != 0) { + dtls_warn("PSK for unknown id requested, exiting\n"); + return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER); + } else if (result_length < psk_key_length) { + dtls_warn("cannot set psk -- buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + memcpy(result, psk_key, psk_key_length); + return psk_key_length; + default: + dtls_warn("unsupported request type: %d\n", type); + } + + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); +} + + +static dtls_handler_t cb = { + .write = output_to_peer, + .read = input_from_peer, + .event = NULL, +#ifdef DTLS_PSK + .get_psk_info = get_psk_info, +#endif /* DTLS_PSK */ +#ifdef DTLS_ECC + /* .get_ecdsa_key = get_ecdsa_key, */ + /* .verify_ecdsa_key = verify_ecdsa_key */ +#endif /* DTLS_ECC */ +}; + +#endif /* WITH_DTLS */ + +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/coap-hex/coap-hex.h b/examples/lwm2m/standalone/coap-hex/coap-hex.h new file mode 100644 index 000000000..b03b0f3a1 --- /dev/null +++ b/examples/lwm2m/standalone/coap-hex/coap-hex.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A HEX text transport for CoAP + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef COAP_HEX_H_ +#define COAP_HEX_H_ + +#define COAP_ENDPOINT_CUSTOM 1 + +#define LWM2M_SECURITY_CONF_REGISTER_KEY_STORE 0 + +typedef struct { + int addr; /* if we want to switch on something... */ + unsigned int size; + int secure; +} coap_endpoint_t; + +#endif /* COAP_HEX_H_ */ diff --git a/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.c b/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.c new file mode 100644 index 000000000..95659ef6f --- /dev/null +++ b/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A native IPv4 transport for CoAP + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "coap.h" +#include "coap-endpoint.h" +#include "coap-engine.h" +#include "coap-keystore.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINTEP(ep) coap_endpoint_print(ep) +#else /* DEBUG */ +#define PRINTF(...) +#define PRINTEP(ep) +#endif /* DEBUG */ + +#ifdef WITH_DTLS +#include "tinydtls.h" +#include "dtls.h" +#include "dtls_debug.h" +#endif /* WITH_DTLS */ + +#define BUFSIZE 1280 + +typedef union { + uint32_t u32[(BUFSIZE + 3) / 4]; + uint8_t u8[BUFSIZE]; +} coap_buf_t; + +static int coap_ipv4_fd = -1; + +static coap_endpoint_t last_source; +static coap_buf_t coap_aligned_buf; +static uint16_t coap_buf_len; + +#ifdef WITH_DTLS +static int dtls_ipv4_fd = -1; +static dtls_handler_t cb; +static dtls_context_t *dtls_context = NULL; + +static const coap_keystore_t *dtls_keystore = NULL; +#endif /* WITH_DTLS */ + +/*---------------------------------------------------------------------------*/ +static const coap_endpoint_t * +coap_src_endpoint(void) +{ + return &last_source; +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_is_secure(const coap_endpoint_t *ep) +{ + return ep->secure; +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_is_connected(const coap_endpoint_t *ep) +{ + if(ep->secure) { +#ifdef WITH_DTLS + dtls_peer_t *peer; + peer = dtls_get_peer(dtls_context, ep); + if(peer != NULL) { + /* only if handshake is done! */ + PRINTF("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 "); + PRINTEP(ep); + PRINTF("\n"); + } +#endif /* WITH_DTLS */ + return 0; + } + /* Assume that the UDP socket is already up... */ + return 1; +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_connect(coap_endpoint_t *ep) +{ + if(ep->secure == 0) { + return 1; + } +#ifdef WITH_DTLS + PRINTF("DTLS EP:"); + PRINTEP(ep); + PRINTF(" len:%d\n", ep->size); + + /* setup all address info here... should be done to connect */ + if(dtls_context) { + dtls_connect(dtls_context, ep); + return 1; + } +#endif /* WITH_DTLS */ + return 0; +} +/*---------------------------------------------------------------------------*/ +void +coap_endpoint_disconnect(coap_endpoint_t *ep) +{ +#ifdef WITH_DTLS + if(ep && ep->secure && dtls_context) { + dtls_close(dtls_context, ep); + } +#endif /* WITH_DTLS */ +} +/*---------------------------------------------------------------------------*/ +void +coap_endpoint_copy(coap_endpoint_t *destination, const coap_endpoint_t *from) +{ + memcpy(destination, from, sizeof(coap_endpoint_t)); +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_cmp(const coap_endpoint_t *e1, const coap_endpoint_t *e2) +{ + /* need to compare only relevant parts of sockaddr */ + switch(e1->addr.sin_family) { + case AF_INET: + return e1->addr.sin_port == e2->addr.sin_port && + e1->secure == e2->secure && + memcmp(&e1->addr.sin_addr, &e2->addr.sin_addr, + sizeof(struct in_addr)) == 0; + default: + return 0; + } +} +/*---------------------------------------------------------------------------*/ +void +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":"", + address, ntohs(ep->addr.sin_port)); + } else { + printf("<#N/A>"); + } +} +/*---------------------------------------------------------------------------*/ +int +coap_endpoint_parse(const char *text, size_t size, coap_endpoint_t *ep) +{ + /* text = format coap://host:port/... we assume */ + /* will not work for know - on the TODO */ + /* set server and port */ + char host[32]; + uint16_t port; + int hlen = 0; + int secure; + int offset = 0; + int i; + PRINTF("CoAP-IPv4: Parsing endpoint: %.*s\n", (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"); + } else { + secure = 0; + } + + for(i = offset; i < size && text[i] != ':' && text[i] != '/' && + hlen < sizeof(host) - 1; i++) { + host[hlen++] = text[i]; + } + host[hlen] = 0; + + port = secure == 0 ? COAP_DEFAULT_PORT : COAP_DEFAULT_SECURE_PORT; + if(text[i] == ':') { + /* Parse IPv4 endpoint port */ + port = atoi(&text[i + 1]); + } + + PRINTF("CoAP-IPv4: endpoint %s:%u\n", host, port); + + ep->addr.sin_family = AF_INET; + ep->addr.sin_port = htons(port); + ep->size = sizeof(ep->addr); + ep->secure = secure; + if(inet_aton(host, &ep->addr.sin_addr) == 0) { + /* Failed to parse the address */ + PRINTF("CoAP-IPv4: Failed to parse endpoint host '%s'\n", host); + return 0; + } + return 1; +} +/*---------------------------------------------------------------------------*/ +uint8_t * +coap_databuf(void) +{ + return coap_aligned_buf.u8; +} +/*---------------------------------------------------------------------------*/ +uint16_t +coap_datalen() +{ + return coap_buf_len; +} +/*---------------------------------------------------------------------------*/ +static int +read_packet_to_coapbuf(int fd) +{ + int len; + + memset(&last_source, 0, sizeof(last_source)); + last_source.size = sizeof(last_source.addr); + len = recvfrom(fd, coap_databuf(), BUFSIZE, 0, + (struct sockaddr *)&last_source.addr, &last_source.size); + if(len == -1) { + if(errno == EAGAIN) { + return 0; + } + err(1, "CoAP-IPv4: recv"); + return 0; + } + + PRINTF("RECV from "); + PRINTEP(&last_source); + PRINTF(" %u bytes\n", len); + coap_buf_len = len; + +#if 0 + if((rand() & 0xffff) < 0x1000) { + printf("*********---- PACKET LOSS ----********\n"); + return 0; + } +#endif + + return 1; +} +/*---------------------------------------------------------------------------*/ +static int +coap_ipv4_set_fd(fd_set *rset, fd_set *wset) +{ + if(coap_ipv4_fd >= 0) { + FD_SET(coap_ipv4_fd, rset); + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +static void +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 + int i; + uint8_t *data; + data = coap_databuf(); + PRINTF("Received:"); + for(i = 0; i < coap_buf_len; i++) { + PRINTF("%02x", data[i]); + } + PRINTF("\n"); +#endif /* DEBUG */ + coap_receive(coap_src_endpoint(), coap_databuf(), coap_datalen()); + } + } +} +/*---------------------------------------------------------------------------*/ +static const struct select_callback udp_callback = { + coap_ipv4_set_fd, coap_ipv4_handle_fd +}; +/*---------------------------------------------------------------------------*/ +#ifdef WITH_DTLS +static int +dtls_ipv4_set_fd(fd_set *rset, fd_set *wset) +{ + if(dtls_ipv4_fd >= 0 && dtls_context) { + FD_SET(dtls_ipv4_fd, rset); + return 1; + } + return 0; +} +#endif /* WITH_DTLS */ +/*---------------------------------------------------------------------------*/ +#ifdef WITH_DTLS +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) { + /* DTLS receive */ + last_source.secure = 1; + dtls_handle_message(dtls_context, &last_source, + coap_databuf(), coap_datalen()); + } + } +} +#endif /* WITH_DTLS */ +/*---------------------------------------------------------------------------*/ +#ifdef WITH_DTLS +static const struct select_callback dtls_callback = { + dtls_ipv4_set_fd, dtls_ipv4_handle_fd +}; +#endif /* WITH_DTLS */ +/*---------------------------------------------------------------------------*/ +void +coap_transport_init(void) +{ + static struct sockaddr_in server; + + coap_ipv4_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(coap_ipv4_fd == -1) { + fprintf(stderr, "Could not create CoAP UDP socket\n"); + exit(1); + return; + } + + memset((void *)&server, 0, sizeof(server)); + + server.sin_family = AF_INET; + server.sin_port = htons(COAP_SERVER_PORT); + 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); + exit(1); + } + + printf("CoAP server listening on port %u\n", COAP_SERVER_PORT); + select_set_callback(coap_ipv4_fd, &udp_callback); + +#ifdef WITH_DTLS + dtls_init(); + dtls_set_log_level(8); + + dtls_ipv4_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if(dtls_ipv4_fd == -1) { + fprintf(stderr, "Could not create CoAP DTLS UDP socket\n"); + exit(1); + return; + } + + memset((void *)&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = htons(COAP_DEFAULT_SECURE_PORT); + 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", + COAP_DEFAULT_SECURE_PORT); + exit(1); + } + + printf("CoAP DTLS server listening on port %u\n", COAP_DEFAULT_SECURE_PORT); + select_set_callback(dtls_ipv4_fd, &dtls_callback); + + /* create new contet with app-data */ + dtls_context = dtls_new_context(&dtls_ipv4_fd); + if(!dtls_context) { + PRINTF("DTLS: cannot create context\n"); + exit(-1); + } + + dtls_set_handler(dtls_context, &cb); +#endif /* WITH_DTLS */ +} +/*---------------------------------------------------------------------------*/ +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"); + return; + } + +#ifdef WITH_DTLS + if(coap_endpoint_is_secure(ep)) { + if(dtls_context) { + dtls_write(dtls_context, (session_t *)ep, (uint8_t *)data, len); + } + return; + } +#endif /* WITH_DTLS */ + + 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 "); + PRINTEP(ep); + PRINTF(" %u bytes: %s\n", len, strerror(errno)); + } else { + PRINTF("SENT to "); + PRINTEP(ep); + PRINTF(" %u bytes\n", len); + + if(DEBUG) { + int i; + PRINTF("Sent:"); + for(i = 0; i < len; i++) { + PRINTF("%02x", data[i]); + } + PRINTF("\n"); + } + } + } +} +/*---------------------------------------------------------------------------*/ +/* DTLS */ +#ifdef WITH_DTLS + +/* This is input coming from the DTLS code - e.g. de-crypted input from + the other side - peer */ +static int +input_from_peer(struct dtls_context_t *ctx, + session_t *session, uint8_t *data, size_t len) +{ + size_t i; + dtls_peer_t *peer; + + printf("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("\n"); + + /* 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) { + session->secure = 1; + } + + coap_receive(session, coap_databuf(), coap_datalen()); + + return 0; +} + +/* This is output from the DTLS code to be sent to peer (encrypted) */ +static int +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, + session->size); + return sendto(fd, data, len, MSG_DONTWAIT, + (struct sockaddr *)&session->addr, session->size); +} + +/* This defines the key-store set API since we hookup DTLS here */ +void +coap_set_keystore(const coap_keystore_t *keystore) +{ + dtls_keystore = keystore; +} + +/* This function is the "key store" for tinyDTLS. It is called to + * retrieve a key for the given identity within this particular + * session. */ +static int +get_psk_info(struct dtls_context_t *ctx, + const session_t *session, + dtls_credentials_type_t type, + const unsigned char *id, size_t id_len, + unsigned char *result, size_t result_length) +{ + const coap_keystore_t *keystore; + coap_keystore_psk_entry_t ks; + + keystore = dtls_keystore; + if(keystore == NULL) { + PRINTF("--- No key store available ---\n"); + return 0; + } + + memset(&ks, 0, sizeof(ks)); + PRINTF("---===>>> Getting the Key or ID <<<===---\n"); + switch(type) { + case DTLS_PSK_IDENTITY: + if(id && id_len) { + ks.identity_hint = id; + ks.identity_hint_len = id_len; + dtls_debug("got psk_identity_hint: '%.*s'\n", id_len, id); + } + + if(keystore->coap_get_psk_info) { + /* we know that session is a coap endpoint */ + keystore->coap_get_psk_info((coap_endpoint_t *)session, &ks); + } + if(ks.identity == NULL || ks.identity_len == 0) { + return 0; + } + + if(result_length < ks.identity_len) { + PRINTF("cannot set psk_identity -- buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + memcpy(result, ks.identity, ks.identity_len); + return ks.identity_len; + + case DTLS_PSK_KEY: + if(keystore->coap_get_psk_info) { + ks.identity = id; + ks.identity_len = id_len; + /* we know that session is a coap endpoint */ + keystore->coap_get_psk_info((coap_endpoint_t *)session, &ks); + } + if(ks.key == NULL || ks.key_len == 0) { + PRINTF("PSK for unknown id requested, exiting\n"); + return dtls_alert_fatal_create(DTLS_ALERT_ILLEGAL_PARAMETER); + } + + if(result_length < ks.key_len) { + PRINTF("cannot set psk -- buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + memcpy(result, ks.key, ks.key_len); + return ks.key_len; + + default: + dtls_warn("unsupported request type: %d\n", type); + } + + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); +} + +static dtls_handler_t cb = { + .write = output_to_peer, + .read = input_from_peer, + .event = NULL, +#ifdef DTLS_PSK + .get_psk_info = get_psk_info, +#endif /* DTLS_PSK */ +#ifdef DTLS_ECC + /* .get_ecdsa_key = get_ecdsa_key, */ + /* .verify_ecdsa_key = verify_ecdsa_key */ +#endif /* DTLS_ECC */ +}; + +#endif /* WITH_DTLS */ + +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.h b/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.h new file mode 100644 index 000000000..8af2e5fc6 --- /dev/null +++ b/examples/lwm2m/standalone/coap-ipv4/coap-ipv4.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * A native IPv4 transport for CoAP + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef COAP_IPV4_H_ +#define COAP_IPV4_H_ + +#include + +#define COAP_ENDPOINT_CUSTOM 1 + +typedef struct { + struct sockaddr_in addr; + unsigned int size; + int secure; +} coap_endpoint_t; + +#endif /* COAP_IPV4_H_ */ diff --git a/examples/lwm2m/standalone/contiki.h b/examples/lwm2m/standalone/contiki.h new file mode 100644 index 000000000..6149da0e3 --- /dev/null +++ b/examples/lwm2m/standalone/contiki.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * Configuration for Contiki library + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef CONTIKI_H_ +#define CONTIKI_H_ + +#include + +#include "posix-main.h" + +#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_TYPE "lwm2m-example" +#define LWM2M_DEVICE_MODEL_NUMBER "000" +#define LWM2M_DEVICE_SERIAL_NO "1" +#define LWM2M_DEVICE_FIRMWARE_VERSION "0.1" + +#ifdef COAP_TRANSPORT_CONF_H +#include COAP_TRANSPORT_CONF_H +#endif + +#define COAP_MAX_CHUNK_SIZE 256 + +#endif /* CONTIKI_H_ */ diff --git a/examples/lwm2m/standalone/generic-object-test.c b/examples/lwm2m/standalone/generic-object-test.c new file mode 100644 index 000000000..493238607 --- /dev/null +++ b/examples/lwm2m/standalone/generic-object-test.c @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2017, RISE SICS AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup lwm2m-objects + * @{ + */ + +/** + * \file + * Implementation of OMA LWM2M / Generic Object Example + * \author + * Joakim Eriksson + * Niclas Finne + */ + +#include +#include "lwm2m-object.h" +#include "lwm2m-engine.h" +#include "coap-engine.h" +#include +#include + +static lwm2m_object_t generic_object; + +#define MAX_SIZE 512 +#define NUMBER_OF_INSTANCES 50 + +#define DEBUG 0 + +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) + +#endif + +static const lwm2m_resource_id_t resources[] = + { + RO(10000), + RO(11000), + }; + +/*---------------------------------------------------------------------------*/ +static int read_data(uint8_t *buffer, int instance_id, int start, int len) +{ + int i; + int start_index; + start_index = instance_id; + /* Write len bytes into the buffer from the start-offset */ + for(i = 0; i < len; i++) { + buffer[i] = '0' + ((start_index + i) & 0x3f); + if(i + start >= MAX_SIZE) return i; + } + return i; +} + +static lwm2m_status_t +opaque_callback(lwm2m_object_instance_t *object, + lwm2m_context_t *ctx, int num_to_write) +{ + int len; + PRINTF("opaque-stream callback num_to_write: %d off: %d outlen: %d\n", + num_to_write, ctx->offset, ctx->outbuf->len); + + len = read_data(&ctx->outbuf->buffer[ctx->outbuf->len], + ctx->object_instance_id, + ctx->offset, num_to_write); + + ctx->outbuf->len += len; + + /* Do we need to write more */ + if(ctx->offset + len < MAX_SIZE) { + ctx->writer_flags |= WRITER_HAS_MORE; + } + return LWM2M_STATUS_OK; +} + +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +lwm2m_callback(lwm2m_object_instance_t *object, + lwm2m_context_t *ctx) +{ + + if(ctx->level <= 2) { + return LWM2M_STATUS_ERROR; + } + + /* Only support for read at the moment */ + if(ctx->operation == LWM2M_OP_READ) { + switch(ctx->resource_id) { + case 10000: + { + char str[30]; + snprintf(str, 30, "hello-%d", (int)ctx->object_instance_id); + lwm2m_object_write_string(ctx, str, strlen(str)); + } + break; + case 11000: + PRINTF("Preparing object write\n"); + lwm2m_object_write_opaque_stream(ctx, MAX_SIZE, opaque_callback); + break; + default: + return LWM2M_STATUS_NOT_FOUND; + } + } + return LWM2M_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +static void +setup_instance(lwm2m_object_instance_t *instance, uint16_t instance_id) +{ + instance->object_id = generic_object.impl->object_id; + instance->instance_id = instance_id; + instance->callback = lwm2m_callback; + instance->resource_ids = resources; + instance->resource_count = sizeof(resources) / sizeof(lwm2m_resource_id_t); +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t * +get_by_id(uint16_t instance_id, lwm2m_status_t *status) +{ + lwm2m_object_instance_t *instance = NULL; + if(status != NULL) { + *status = LWM2M_STATUS_OK; + } + if(instance_id < NUMBER_OF_INSTANCES) { + instance = lwm2m_engine_get_instance_buffer(); + if(instance == NULL) { + return NULL; + } + + /* We are fine - update instance variable */ + setup_instance(instance, instance_id); + } + return instance; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t * +get_first(lwm2m_status_t *status) +{ + return get_by_id(0, status); +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_instance_t * +get_next(lwm2m_object_instance_t *instance, lwm2m_status_t *status) +{ + return get_by_id(instance->instance_id + 1, status); +} +/*---------------------------------------------------------------------------*/ +static lwm2m_object_impl_t generic_object_impl = { + .object_id = 4712, + .get_first = get_first, + .get_next = get_next, + .get_by_id = get_by_id +}; + +/*---------------------------------------------------------------------------*/ +void +lwm2m_generic_object_test_init(void) +{ + generic_object.impl = &generic_object_impl; + + lwm2m_engine_add_generic_object(&generic_object); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/ipso-control-test.c b/examples/lwm2m/standalone/ipso-control-test.c new file mode 100644 index 000000000..63e6dc120 --- /dev/null +++ b/examples/lwm2m/standalone/ipso-control-test.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2016, SICS Swedish ICT AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup ipso-objects + * @{ + */ + +/** + * \file + * Implementation of OMA LWM2M / IPSO Generic Sensor + * \author + * Joakim Eriksson + * Niclas Finne + */ + +#include +#include "lwm2m-object.h" +#include "lwm2m-engine.h" +#include "coap-engine.h" +#include "ipso-sensor-template.h" +#include "ipso-control-template.h" +#include +#include + +static lwm2m_status_t set_value(uint8_t value); +static lwm2m_status_t set_light_value(uint8_t value); + +static ipso_control_t test_control = { + .reg_object.object_id = 3306, + .reg_object.instance_id = 0, + .set_value = set_value, +}; + +static ipso_control_t test_control2 = { + .reg_object.object_id = 3311, + .reg_object.instance_id = 0, + .set_value = set_light_value, +}; +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +set_value(uint8_t value) +{ + /* do something with the value! */ + printf("Value set to: %u before: %u\n", value, + ipso_control_get_value(&test_control)); + return LWM2M_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +static lwm2m_status_t +set_light_value(uint8_t value) +{ + /* do something with the value! */ + printf("Light value set to: %u before: %u\n", value, + ipso_control_get_value(&test_control2)); + return LWM2M_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +void +ipso_control_test_init(void) +{ + ipso_control_add(&test_control); + ipso_control_add(&test_control2); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/lwm2m/standalone/ipso-sensor-temp.c b/examples/lwm2m/standalone/ipso-sensor-temp.c new file mode 100644 index 000000000..010ce7ea2 --- /dev/null +++ b/examples/lwm2m/standalone/ipso-sensor-temp.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016, SICS Swedish ICT AB + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * \addtogroup ipso-objects + * @{ + */ + +/** + * \file + * Implementation of OMA LWM2M / IPSO Generic Sensor + * \author + * Joakim Eriksson + * Niclas Finne + */ + +#include +#include "lwm2m-object.h" +#include "lwm2m-engine.h" +#include "coap-engine.h" +#include "ipso-sensor-template.h" +#include + +uint32_t temp = 19000; +uint32_t hum = 30000; + +ipso_sensor_value_t temp_value; +ipso_sensor_value_t temp_value2; +ipso_sensor_value_t hum_value; + +lwm2m_status_t get_temp_value(const ipso_sensor_t *sensor, int32_t *value); +lwm2m_status_t get_hum_value(const ipso_sensor_t *sensor, int32_t *value); + +static const ipso_sensor_t temp_sensor = { + .object_id = 3303, + .sensor_value = &temp_value, + .max_range = 120000, /* milli celcius */ + .min_range = -30000, /* milli celcius */ + .get_value_in_millis = get_temp_value, + .unit = "Cel", + .update_interval = 10 +}; + +static const ipso_sensor_t temp_sensor2 = { + .object_id = 3303, + .sensor_value = &temp_value2, + .max_range = 120000, /* milli celcius */ + .min_range = -30000, /* milli celcius */ + .get_value_in_millis = get_temp_value, + .unit = "Cel", + .update_interval = 10 +}; + +/*---------------------------------------------------------------------------*/ + +static const ipso_sensor_t hum_sensor = { + .object_id = 3304, + .instance_id = 12, + .sensor_value = &hum_value, + .max_range = 100000, /* milli */ + .min_range = 0, /* milli */ + .get_value_in_millis = get_hum_value, + .unit = "%", + .update_interval = 10 +}; + +/*---------------------------------------------------------------------------*/ + +lwm2m_status_t +get_temp_value(const ipso_sensor_t *sensor, int32_t *value) +{ + *value = temp++; + return LWM2M_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ +lwm2m_status_t +get_hum_value(const ipso_sensor_t *sensor, int32_t *value) +{ + *value = temp++; + return LWM2M_STATUS_OK; +} +/*---------------------------------------------------------------------------*/ + +void +ipso_sensor_temp_init(void) +{ + ipso_sensor_add(&temp_sensor); + ipso_sensor_add(&temp_sensor2); + ipso_sensor_add(&hum_sensor); +} +/*---------------------------------------------------------------------------*/ +/** @} */ diff --git a/examples/lwm2m/standalone/lwm2m-example.c b/examples/lwm2m/standalone/lwm2m-example.c new file mode 100644 index 000000000..543539ca5 --- /dev/null +++ b/examples/lwm2m/standalone/lwm2m-example.c @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * An OMA LWM2M standalone example to demonstrate how to use + * the Contiki OMA LWM2M library from a native application. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "lwm2m-firmware.h" +#include "lwm2m-server.h" +#include "lwm2m-security.h" +#include "lwm2m-device.h" +#include "coap.h" +#include "coap-timer.h" +#include +#include +#include +#include + +#define PSK_DEFAULT_IDENTITY "Client_identity" +#define PSK_DEFAULT_KEY "secretPSK" + +#define WITH_TEST_NOTIFICATION 1 + +void ipso_sensor_temp_init(void); +void ipso_control_test_init(void); +void ipso_blockwise_test_init(void); +void lwm2m_generic_object_test_init(void); + +/* set this above zero to get auto deregister */ +static int deregister = -1; + +/*---------------------------------------------------------------------------*/ +#if WITH_TEST_NOTIFICATION +static void +callback(coap_timer_t *timer) +{ + /* Automatic notification on device timer for test!*/ + lwm2m_notify_observers("3/0/13"); + coap_timer_reset(timer, 10000); + if(deregister > 0) { + deregister--; + if(deregister == 0) { + printf("Deregistering.\n"); + lwm2m_rd_client_deregister(); + } + } +} +#endif /* WITH_TEST_NOTIFICATION */ +/*---------------------------------------------------------------------------*/ +static void +session_callback(struct lwm2m_session_info *si, int state) +{ + printf("Got Session Callback!!! %d\n", state); +} +/*---------------------------------------------------------------------------*/ +#ifndef LWM2M_DEFAULT_RD_SERVER +/* Default to leshan.eclipse.org */ +#ifdef WITH_DTLS +#define LWM2M_DEFAULT_RD_SERVER "coaps://5.39.83.206" +#else +#define LWM2M_DEFAULT_RD_SERVER "coap://5.39.83.206" +#endif +#endif /* LWM2M_DEFAULT_RD_SERVER */ +/*---------------------------------------------------------------------------*/ +void +start_application(int argc, char *argv[]) +{ + const char *default_server = LWM2M_DEFAULT_RD_SERVER; + coap_endpoint_t server_ep; + int has_server_ep = 0; + char *name = "abcde"; + + if(argc > 1) { + default_server = argv[1]; + } + if(argc > 2) { + name = argv[2]; + } + + if(default_server != NULL && *default_server != '\0') { + if(coap_endpoint_parse(default_server, strlen(default_server), &server_ep) == 0) { + fprintf(stderr, "failed to parse the server address '%s'\n", default_server); + exit(1); + } + has_server_ep = 1; + } + + /* Example using network timer */ +#if WITH_TEST_NOTIFICATION + { + static coap_timer_t nt; + coap_timer_set_callback(&nt, callback); + coap_timer_set(&nt, 10000); + } +#endif /* WITH_TEST_NOTIFICATION */ + + /* Initialize the OMA LWM2M engine */ + lwm2m_engine_init(); + + ipso_sensor_temp_init(); + ipso_control_test_init(); + ipso_blockwise_test_init(); + lwm2m_generic_object_test_init(); + + /* Register default LWM2M objects */ + + lwm2m_device_init(); + lwm2m_firmware_init(); + lwm2m_security_init(); + lwm2m_server_init(); + + if(has_server_ep) { + /* start RD client */ + printf("Starting RD client to register at "); + coap_endpoint_print(&server_ep); + printf("\n"); + +#ifdef WITH_DTLS +#if defined(PSK_DEFAULT_IDENTITY) && defined(PSK_DEFAULT_KEY) + { + lwm2m_security_server_t *server; + /* Register new server with instance id, server id, lifetime in seconds */ + if(!lwm2m_server_add(0, 1, 600)) { + printf("failed to add server object\n"); + } + + server = lwm2m_security_add_server(0, 1, + (uint8_t *)default_server, + strlen(default_server)); + if(server == NULL) { + printf("failed to add security object\n"); + } else { + if(lwm2m_security_set_server_psk(server, + (uint8_t *)PSK_DEFAULT_IDENTITY, + strlen(PSK_DEFAULT_IDENTITY), + (uint8_t *)PSK_DEFAULT_KEY, + strlen(PSK_DEFAULT_KEY))) { + printf("registered security object for endpoint %s\n", + default_server); + } else { + printf("failed to register security object\n"); + } + } + } +#endif /* defined(PSK_DEFAULT_IDENTITY) && defined(PSK_DEFAULT_KEY) */ +#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 + lwm2m_rd_client_register_with_server(&server_ep); +#endif + 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 { + fprintf(stderr, "No registration server specified.\n"); + } + printf("COAP MAX PACKET: %d (BLOCK:%d)\n", COAP_MAX_PACKET_SIZE, COAP_MAX_BLOCK_SIZE); +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/posix-coap-timer.c b/examples/lwm2m/standalone/posix-coap-timer.c new file mode 100644 index 000000000..29a0ecca6 --- /dev/null +++ b/examples/lwm2m/standalone/posix-coap-timer.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * Example posix implementation of CoAP timer driver. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "coap-timer.h" +#include + +#define DEBUG 1 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +/* The maximal time allowed to move forward between updates */ +#define MAX_TIME_CHANGE_MSEC 360000UL + +static uint64_t uptime_msec = 0; +static uint64_t last_msec; +/*---------------------------------------------------------------------------*/ +static uint64_t +uptime(void) +{ + struct timeval tv; + uint64_t t; + + if(gettimeofday(&tv, NULL)) { + PRINTF("*** failed to retrieve system time\n"); + return last_msec; + } + + t = tv.tv_sec * (uint64_t)1000; + t += tv.tv_usec / (uint64_t)1000; + + if(last_msec == 0) { + /* No update first time */ + } else if(t < last_msec) { + /* System time has moved backwards */ + PRINTF("*** system time has moved backwards %lu msec\n", + (unsigned long)(last_msec - t)); + + } else if(t - last_msec > MAX_TIME_CHANGE_MSEC) { + /* Too large jump forward in system time */ + PRINTF("*** system time has moved forward %lu msec\n", + (unsigned long)(t - last_msec)); + uptime_msec += 1000UL; + } else { + uptime_msec += t - last_msec; + } + + last_msec = t; + + return uptime_msec; +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + uptime(); +} +/*---------------------------------------------------------------------------*/ +static void +update(void) +{ +} +/*---------------------------------------------------------------------------*/ +const coap_timer_driver_t coap_timer_native_driver = { + .init = init, + .uptime = uptime, + .update = update, +}; +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/posix-main.c b/examples/lwm2m/standalone/posix-main.c new file mode 100644 index 000000000..a077eb101 --- /dev/null +++ b/examples/lwm2m/standalone/posix-main.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * Simple posix main loop with support functions. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "lwm2m-engine.h" +#include "lwm2m-rd-client.h" +#include "coap-timer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef SELECT_CONF_MAX +#define SELECT_MAX SELECT_CONF_MAX +#else +#define SELECT_MAX 8 +#endif + +static const struct select_callback *select_callback[SELECT_MAX]; +static int select_max = 0; +static int is_stdin_open = 1; +static void (* stdin_callback)(const char *line); +static char stdin_buffer[2048]; +static uint16_t stdin_count; +/*---------------------------------------------------------------------------*/ +int +select_set_callback(int fd, const struct select_callback *callback) +{ + int i; + if(fd >= 0 && fd < SELECT_MAX) { + /* Check that the callback functions are set */ + if(callback != NULL && + (callback->set_fd == NULL || callback->handle_fd == NULL)) { + callback = NULL; + } + + select_callback[fd] = callback; + + /* Update fd max */ + if(callback != NULL) { + if(fd > select_max) { + select_max = fd; + } + } else { + select_max = 0; + for(i = SELECT_MAX - 1; i > 0; i--) { + if(select_callback[i] != NULL) { + select_max = i; + break; + } + } + } + return 1; + } + fprintf(stderr, "*** failed to set callback for fd %d\n", fd); + return 0; +} +/*---------------------------------------------------------------------------*/ +void +select_set_stdin_callback(void (* line_read)(const char *line)) +{ + stdin_callback = line_read; +} +/*---------------------------------------------------------------------------*/ +static int +stdin_set_fd(fd_set *rset, fd_set *wset) +{ + if(is_stdin_open) { + FD_SET(STDIN_FILENO, rset); + } + return 1; +} +/*---------------------------------------------------------------------------*/ +static void +stdin_handle_fd(fd_set *rset, fd_set *wset) +{ + ssize_t ret; + char c; + if(is_stdin_open && FD_ISSET(STDIN_FILENO, rset)) { + ret = read(STDIN_FILENO, &c, 1); + if(ret > 0) { + if(c == '\r') { + /* Ignore CR */ + } else if(c == '\n' || stdin_count >= sizeof(stdin_buffer) - 1) { + stdin_buffer[stdin_count] = 0; + if(stdin_count > 0 && stdin_callback != NULL) { + stdin_callback(stdin_buffer); + } else { + fprintf(stderr, "STDIN: %s\n", stdin_buffer); + } + stdin_count = 0; + } else { + stdin_buffer[stdin_count++] = (char)c; + } + } else if(ret == 0) { + /* Standard in closed */ + is_stdin_open = 0; + fprintf(stderr, "*** stdin closed\n"); + stdin_count = 0; + if(stdin_callback) { + stdin_buffer[0] = 0; + stdin_callback(stdin_buffer); + } + } else if(errno != EAGAIN) { + err(1, "stdin: read"); + } + } +} +/*---------------------------------------------------------------------------*/ +const static struct select_callback stdin_fd = { + stdin_set_fd, stdin_handle_fd +}; +/*---------------------------------------------------------------------------*/ +int +main(int argc, char *argv[]) +{ + uint64_t next_time; + fd_set fdr, fdw; + int maxfd, retval, i; + struct timeval tv; + + /* Make standard output unbuffered. */ + setvbuf(stdout, (char *)NULL, _IONBF, 0); + + select_set_callback(STDIN_FILENO, &stdin_fd); + + /* Start the application */ + start_application(argc, argv); + + while(1) { + tv.tv_sec = 0; + tv.tv_usec = 250; + + next_time = coap_timer_time_to_next_expiration(); + if(next_time > 0) { + tv.tv_sec = next_time / 1000; + tv.tv_usec = (next_time % 1000) * 1000; + if(tv.tv_usec == 0 && tv.tv_sec == 0) { + /* + * CoAP timer time resolution is milliseconds. Avoid millisecond + * busy loops. + */ + tv.tv_usec = 250; + } + } + + FD_ZERO(&fdr); + FD_ZERO(&fdw); + maxfd = 0; + for(i = 0; i <= select_max; i++) { + if(select_callback[i] != NULL && select_callback[i]->set_fd(&fdr, &fdw)) { + maxfd = i; + } + } + + retval = select(maxfd + 1, &fdr, &fdw, NULL, &tv); + if(retval < 0) { + if(errno != EINTR) { + perror("select"); + } + } else if(retval > 0) { + /* timeout => retval == 0 */ + for(i = 0; i <= maxfd; i++) { + if(select_callback[i] != NULL) { + select_callback[i]->handle_fd(&fdr, &fdw); + } + } + } + + /* Process network timers */ + for(retval = 0; retval < 5 && coap_timer_run(); retval++); + } + + return 0; +} +/*---------------------------------------------------------------------------*/ diff --git a/examples/lwm2m/standalone/posix-main.h b/examples/lwm2m/standalone/posix-main.h new file mode 100644 index 000000000..c220cd9f9 --- /dev/null +++ b/examples/lwm2m/standalone/posix-main.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * Simple posix main loop with support functions. + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef POSIX_MAIN_H_ +#define POSIX_MAIN_H_ + +#include +#include + +typedef struct select_callback { + int (* set_fd)(fd_set *fdr, fd_set *fdw); + void (* handle_fd)(fd_set *fdr, fd_set *fdw); +} select_callback_t; + +int select_set_callback(int fd, const select_callback_t *callback); + +void select_set_stdin_callback(void (* line_read)(const char *text)); + +void start_application(int argc, char *argv[]); + +#endif /* POSIX_MAIN_H_ */ diff --git a/examples/lwm2m/standalone/tinydtls-support/dtls-support-conf.h b/examples/lwm2m/standalone/tinydtls-support/dtls-support-conf.h new file mode 100644 index 000000000..25e55b31d --- /dev/null +++ b/examples/lwm2m/standalone/tinydtls-support/dtls-support-conf.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * tinyDTLS support for LWM2M standalone + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#ifndef DTLS_SUPPORT_CONF_H_ +#define DTLS_SUPPORT_CONF_H_ + +#include "coap-endpoint.h" + +#include "coap-timer.h" + +typedef coap_endpoint_t session_t; + +typedef struct { + coap_timer_t retransmit_timer; +} dtls_support_context_state_t; + +#define DTLS_SUPPORT_CONF_CONTEXT_STATE dtls_support_context_state_t + +#define DTLS_TICKS_PER_SECOND 1000 + +typedef uint64_t dtls_tick_t; + +#endif /* DTLS_SUPPORT_CONF_H_ */ diff --git a/examples/lwm2m/standalone/tinydtls-support/dtls-support.c b/examples/lwm2m/standalone/tinydtls-support/dtls-support.c new file mode 100644 index 000000000..c39962d3f --- /dev/null +++ b/examples/lwm2m/standalone/tinydtls-support/dtls-support.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2017, SICS, Swedish ICT AB. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/** + * \file + * Posix support for TinyDTLS + * \author + * Niclas Finne + * Joakim Eriksson + */ + +#include "tinydtls.h" +#include "coap-timer.h" +#include + +#include +#include +#include +#include +#include + +#define DEBUG DEBUG_NONE +#include "dtls_debug.h" + +#if DEBUG +#define PRINTEP(ep) coap_endpoint_print(ep) +#else /* DEBUG */ +#define PRINTEP(ep) +#endif /* DEBUG */ + +extern char *loglevels[]; +/*---------------------------------------------------------------------------*/ +static inline size_t +print_timestamp(char *s, size_t len) +{ +#ifdef HAVE_TIME_H + time_t t; + struct tm *tmp; + t = time(NULL); + tmp = localtime(&t); + return strftime(s, len, "%b %d %H:%M:%S", tmp); +#else /* alternative implementation: just print the timestamp */ + uint64_t t; + t = coap_timer_uptime(); + return snprintf(s, len, "%u.%03u", + (unsigned int)(t / 1000), + (unsigned int)(t % 1000)); +#endif /* HAVE_TIME_H */ +} +/*---------------------------------------------------------------------------*/ +#include +static pthread_mutex_t cipher_context_mutex = PTHREAD_MUTEX_INITIALIZER; +static dtls_cipher_context_t cipher_context; +#define LOCK(P) pthread_mutex_lock(P) +#define UNLOCK(P) pthread_mutex_unlock(P) +/*---------------------------------------------------------------------------*/ +dtls_cipher_context_t * +dtls_cipher_context_acquire(void) +{ + LOCK(&cipher_context_mutex); + return &cipher_context; +} +/*---------------------------------------------------------------------------*/ +void +dtls_cipher_context_release(dtls_cipher_context_t *c) +{ + /* just one single context for now */ + UNLOCK(&cipher_context_mutex); +} +/*---------------------------------------------------------------------------*/ +dtls_context_t * +dtls_context_acquire(void) +{ + return (dtls_context_t *)malloc(sizeof(dtls_context_t)); +} +/*---------------------------------------------------------------------------*/ +void +dtls_context_release(dtls_context_t *context) +{ + free(context); +} +/*---------------------------------------------------------------------------*/ +#ifndef NDEBUG +size_t +dsrv_print_addr(const session_t *addr, char *buf, size_t len) +{ + return 0; +} +#endif /* NDEBUG */ +/*---------------------------------------------------------------------------*/ +#ifdef HAVE_VPRINTF +void +dsrv_log(log_t level, char *format, ...) +{ + static char timebuf[32]; + va_list ap; + FILE *log_fd; + + if(dtls_get_log_level() < level) { + return; + } + + log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout; + + if(print_timestamp(timebuf, sizeof(timebuf))) { + fprintf(log_fd, "%s ", timebuf); + } + + if(level <= DTLS_LOG_DEBUG) { + fprintf(log_fd, "%s ", loglevels[level]); + } + + va_start(ap, format); + vfprintf(log_fd, format, ap); + va_end(ap); + fflush(log_fd); +} +#endif /* HAVE_VPRINTF */ +/*---------------------------------------------------------------------------*/ +void +dtls_dsrv_hexdump_log(log_t level, const char *name, + const unsigned char *buf, size_t length, int extend) +{ + static char timebuf[32]; + FILE *log_fd; + int n = 0; + + if(dtls_get_log_level() < level) { + return; + } + + log_fd = level <= DTLS_LOG_CRIT ? stderr : stdout; + + if(print_timestamp(timebuf, sizeof(timebuf))) { + fprintf(log_fd, "%s ", timebuf); + } + + if(level <= DTLS_LOG_DEBUG) { + fprintf(log_fd, "%s ", loglevels[level]); + } + + if(extend) { + fprintf(log_fd, "%s: (%zu bytes):\n", name, length); + + while(length--) { + if(n % 16 == 0) { + fprintf(log_fd, "%08X ", n); + } + + fprintf(log_fd, "%02X ", *buf++); + + n++; + if(n % 8 == 0) { + if(n % 16 == 0) { + fprintf(log_fd, "\n"); + } else { + fprintf(log_fd, " "); + } + } + } + } else { + fprintf(log_fd, "%s: (%zu bytes): ", name, length); + while(length--) { + fprintf(log_fd, "%02X", *buf++); + } + } + fprintf(log_fd, "\n"); + + fflush(log_fd); +} +/*---------------------------------------------------------------------------*/ +/* --------- time support ----------- */ +void +dtls_ticks(dtls_tick_t *t) +{ + *t = coap_timer_uptime(); +} +/*---------------------------------------------------------------------------*/ +int +dtls_fill_random(uint8_t *buf, size_t len) +{ + FILE *urandom = fopen("/dev/urandom", "r"); + + if(!urandom) { + dtls_emerg("cannot initialize PRNG\n"); + return 0; + } + + if(fread(buf, 1, len, urandom) != len) { + dtls_emerg("cannot initialize PRNG\n"); + fclose(urandom); + return 0; + } + + fclose(urandom); + + return 1; +} +/*---------------------------------------------------------------------------*/ +/* message retransmission */ +/*---------------------------------------------------------------------------*/ +static void +dtls_retransmit_callback(coap_timer_t *timer) +{ + dtls_context_t *ctx; + uint64_t now; + uint64_t next; + + ctx = coap_timer_get_user_data(timer); + now = coap_timer_uptime(); + /* Just one retransmission per timer scheduling */ + dtls_check_retransmit(ctx, &next, 0); + + /* need to set timer to some value even if no nextpdu is available */ + if(next != 0) { + coap_timer_set(timer, next <= now ? 1 : next - now); + } +} +/*---------------------------------------------------------------------------*/ +void +dtls_set_retransmit_timer(dtls_context_t *ctx, unsigned int timeout) +{ + coap_timer_set_callback(&ctx->support.retransmit_timer, + dtls_retransmit_callback); + coap_timer_set_user_data(&ctx->support.retransmit_timer, ctx); + coap_timer_set(&ctx->support.retransmit_timer, timeout); +} +/*---------------------------------------------------------------------------*/ +/* Implementation of session functions */ +void +dtls_session_init(session_t *session) +{ + memset(session, 0, sizeof(session_t)); +} +/*---------------------------------------------------------------------------*/ +int +dtls_session_equals(const session_t *a, const session_t *b) +{ + coap_endpoint_t *e1 = (coap_endpoint_t *)a; + coap_endpoint_t *e2 = (coap_endpoint_t *)b; + + PRINTF(" **** EP:"); + PRINTEP(e1); + PRINTF(" =?= "); + PRINTEP(e2); + PRINTF(" => %d\n", coap_endpoint_cmp(e1, e2)); + + return coap_endpoint_cmp(e1, e2); +} +/*---------------------------------------------------------------------------*/ +void * +dtls_session_get_address(const session_t *a) +{ + /* improve this to only contain the addressing info */ + return (void *)a; +} +/*---------------------------------------------------------------------------*/ +int +dtls_session_get_address_size(const session_t *a) +{ + /* improve this to only contain the addressing info */ + return sizeof(session_t); +} +/*---------------------------------------------------------------------------*/ +void +dtls_session_print(const session_t *a) +{ + coap_endpoint_print((const coap_endpoint_t *)a); +} +/*---------------------------------------------------------------------------*/ +/* The init */ +void +dtls_support_init(void) +{ +} +/*---------------------------------------------------------------------------*/