From f8b212de5f4b148f74e594a396ab3ecbca7f6117 Mon Sep 17 00:00:00 2001
From: Dong Heng <dongheng@espressif.com>
Date: Wed, 10 Oct 2018 19:12:55 +0800
Subject: [PATCH 1/2] feat(coap): Bring coap from esp-idf

Commit ID: 22da5f6d
---
 components/coap/CMakeLists.txt                |   42 +
 components/coap/Makefile.projbuild            |    1 +
 components/coap/component.mk                  |   16 +
 components/coap/libcoap/.gitignore            |   64 +
 components/coap/libcoap/.travis.yml           |   34 +
 components/coap/libcoap/AUTHORS               |    3 +
 components/coap/libcoap/CONTRIBUTE            |  219 ++
 components/coap/libcoap/COPYING               |    6 +
 components/coap/libcoap/ChangeLog             |  220 ++
 components/coap/libcoap/LICENSE.BSD           |   26 +
 components/coap/libcoap/LICENSE.GPL           |  280 ++
 components/coap/libcoap/Makefile.am           |  180 ++
 components/coap/libcoap/Makefile.libcoap      |    7 +
 components/coap/libcoap/NEWS                  |    0
 components/coap/libcoap/README                |   30 +
 components/coap/libcoap/README.md             |   30 +
 components/coap/libcoap/TODO                  |   61 +
 components/coap/libcoap/autogen.sh            |  133 +
 components/coap/libcoap/configure.ac          |  423 +++
 components/coap/libcoap/doc/Doxyfile.in       | 2354 +++++++++++++++++
 components/coap/libcoap/doc/Makefile.am       |   42 +
 components/coap/libcoap/examples/Makefile.am  |   44 +
 .../coap/libcoap/examples/README.etsi_iot     |   43 +
 components/coap/libcoap/examples/client.c     | 1305 +++++++++
 .../coap/libcoap/examples/coap-client.txt.in  |  168 ++
 components/coap/libcoap/examples/coap-rd.c    |  763 ++++++
 .../coap/libcoap/examples/coap-rd.txt.in      |   88 +
 .../coap/libcoap/examples/coap-server.c       |  550 ++++
 .../coap/libcoap/examples/coap-server.txt.in  |   88 +
 components/coap/libcoap/examples/coap_list.c  |   53 +
 components/coap/libcoap/examples/coap_list.h  |   33 +
 .../libcoap/examples/contiki/Makefile.contiki |   33 +
 .../libcoap/examples/contiki/coap-observer.c  |  185 ++
 .../examples/contiki/radvd.conf.sample        |   14 +
 .../coap/libcoap/examples/contiki/server.c    |  231 ++
 .../coap/libcoap/examples/etsi_coaptest.sh    |  210 ++
 .../coap/libcoap/examples/etsi_iot_01.c       |  759 ++++++
 .../examples/etsi_iot_01_largedata.txt        |    7 +
 .../coap/libcoap/examples/etsi_testcases.sh   |  765 ++++++
 .../coap/libcoap/examples/lwip/.gitignore     |    7 +
 components/coap/libcoap/examples/lwip/README  |   27 +
 .../coap/libcoap/examples/lwip/lwipopts.h     |   11 +
 .../coap/libcoap/examples/lwip/server-coap.c  |   24 +
 .../coap/libcoap/examples/lwip/server-coap.h  |    6 +
 .../coap/libcoap/examples/lwip/server.c       |   91 +
 components/coap/libcoap/examples/tiny.c       |  149 ++
 .../coap/libcoap/include/coap/address.h       |  152 ++
 components/coap/libcoap/include/coap/async.h  |  146 +
 components/coap/libcoap/include/coap/bits.h   |   78 +
 components/coap/libcoap/include/coap/block.h  |  137 +
 .../coap/libcoap/include/coap/coap.h.in       |   59 +
 .../coap/libcoap/include/coap/coap_io.h       |  167 ++
 .../coap/libcoap/include/coap/coap_time.h     |  142 +
 components/coap/libcoap/include/coap/debug.h  |   85 +
 components/coap/libcoap/include/coap/encode.h |   52 +
 .../coap/libcoap/include/coap/hashkey.h       |   57 +
 .../coap/libcoap/include/coap/libcoap.h       |   26 +
 .../coap/libcoap/include/coap/lwippools.h     |   57 +
 components/coap/libcoap/include/coap/mem.h    |  111 +
 components/coap/libcoap/include/coap/net.h    |  521 ++++
 components/coap/libcoap/include/coap/option.h |  410 +++
 components/coap/libcoap/include/coap/pdu.h    |  388 +++
 components/coap/libcoap/include/coap/prng.h   |  106 +
 .../coap/libcoap/include/coap/resource.h      |  408 +++
 components/coap/libcoap/include/coap/str.h    |   33 +
 .../coap/libcoap/include/coap/subscribe.h     |   72 +
 components/coap/libcoap/include/coap/uri.h    |  121 +
 components/coap/libcoap/include/coap/uthash.h |  963 +++++++
 components/coap/libcoap/include/coap/utlist.h |  757 ++++++
 components/coap/libcoap/libcoap-1.map         |  116 +
 components/coap/libcoap/libcoap-1.pc.in       |   11 +
 components/coap/libcoap/libcoap-1.sym         |  111 +
 .../coap/libcoap/m4/ax_check_compile_flag.m4  |   74 +
 .../coap/libcoap/m4/ax_check_link_flag.m4     |   74 +
 components/coap/libcoap/scripts/build.sh      |   32 +
 components/coap/libcoap/scripts/fix-cunit.sh  |   15 +
 components/coap/libcoap/src/address.c         |   63 +
 components/coap/libcoap/src/async.c           |  100 +
 components/coap/libcoap/src/block.c           |  140 +
 components/coap/libcoap/src/coap_io.c         |  621 +++++
 components/coap/libcoap/src/coap_io_lwip.c    |   98 +
 components/coap/libcoap/src/coap_time.c       |   98 +
 components/coap/libcoap/src/debug.c           |  506 ++++
 components/coap/libcoap/src/encode.c          |   48 +
 components/coap/libcoap/src/hashkey.c         |   29 +
 components/coap/libcoap/src/mem.c             |  121 +
 components/coap/libcoap/src/net.c             | 1802 +++++++++++++
 components/coap/libcoap/src/option.c          |  523 ++++
 components/coap/libcoap/src/pdu.c             |  433 +++
 components/coap/libcoap/src/resource.c        |  756 ++++++
 components/coap/libcoap/src/str.c             |   34 +
 components/coap/libcoap/src/subscribe.c       |   23 +
 components/coap/libcoap/src/uri.c             |  492 ++++
 components/coap/libcoap/tests/Makefile.am     |   36 +
 .../coap/libcoap/tests/test_error_response.c  |  374 +++
 .../coap/libcoap/tests/test_error_response.h  |   11 +
 components/coap/libcoap/tests/test_options.c  |  999 +++++++
 components/coap/libcoap/tests/test_options.h  |   11 +
 components/coap/libcoap/tests/test_pdu.c      |  694 +++++
 components/coap/libcoap/tests/test_pdu.h      |   11 +
 .../coap/libcoap/tests/test_sendqueue.c       |  367 +++
 .../coap/libcoap/tests/test_sendqueue.h       |   11 +
 components/coap/libcoap/tests/test_uri.c      |  463 ++++
 components/coap/libcoap/tests/test_uri.h      |   11 +
 .../coap/libcoap/tests/test_wellknown.c       |  331 +++
 .../coap/libcoap/tests/test_wellknown.h       |   11 +
 components/coap/libcoap/tests/testdriver.c    |   44 +
 components/coap/port/coap_io_socket.c         |  468 ++++
 components/coap/port/include/coap/coap.h      |   50 +
 components/coap/port/include/coap_config.h    |   39 +
 .../coap/port/include/coap_config_posix.h     |   41 +
 examples/protocols/coap_client/CMakeLists.txt |    8 +
 examples/protocols/coap_client/Makefile       |    9 +
 examples/protocols/coap_client/README.md      |   65 +
 .../coap_client/main/Kconfig.projbuild        |   21 +
 .../main/coap_client_example_main.c           |  205 ++
 .../protocols/coap_client/main/component.mk   |    5 +
 examples/protocols/coap_server/CMakeLists.txt |    8 +
 examples/protocols/coap_server/Makefile       |    9 +
 examples/protocols/coap_server/README.md      |   63 +
 .../coap_server/main/Kconfig.projbuild        |   15 +
 .../main/coap_server_example_main.c           |  192 ++
 .../protocols/coap_server/main/component.mk   |    5 +
 123 files changed, 25770 insertions(+)
 create mode 100644 components/coap/CMakeLists.txt
 create mode 100644 components/coap/Makefile.projbuild
 create mode 100644 components/coap/component.mk
 create mode 100644 components/coap/libcoap/.gitignore
 create mode 100644 components/coap/libcoap/.travis.yml
 create mode 100644 components/coap/libcoap/AUTHORS
 create mode 100644 components/coap/libcoap/CONTRIBUTE
 create mode 100644 components/coap/libcoap/COPYING
 create mode 100644 components/coap/libcoap/ChangeLog
 create mode 100644 components/coap/libcoap/LICENSE.BSD
 create mode 100644 components/coap/libcoap/LICENSE.GPL
 create mode 100644 components/coap/libcoap/Makefile.am
 create mode 100644 components/coap/libcoap/Makefile.libcoap
 create mode 100644 components/coap/libcoap/NEWS
 create mode 100644 components/coap/libcoap/README
 create mode 100644 components/coap/libcoap/README.md
 create mode 100644 components/coap/libcoap/TODO
 create mode 100755 components/coap/libcoap/autogen.sh
 create mode 100644 components/coap/libcoap/configure.ac
 create mode 100644 components/coap/libcoap/doc/Doxyfile.in
 create mode 100644 components/coap/libcoap/doc/Makefile.am
 create mode 100644 components/coap/libcoap/examples/Makefile.am
 create mode 100644 components/coap/libcoap/examples/README.etsi_iot
 create mode 100644 components/coap/libcoap/examples/client.c
 create mode 100644 components/coap/libcoap/examples/coap-client.txt.in
 create mode 100644 components/coap/libcoap/examples/coap-rd.c
 create mode 100644 components/coap/libcoap/examples/coap-rd.txt.in
 create mode 100644 components/coap/libcoap/examples/coap-server.c
 create mode 100644 components/coap/libcoap/examples/coap-server.txt.in
 create mode 100644 components/coap/libcoap/examples/coap_list.c
 create mode 100644 components/coap/libcoap/examples/coap_list.h
 create mode 100644 components/coap/libcoap/examples/contiki/Makefile.contiki
 create mode 100644 components/coap/libcoap/examples/contiki/coap-observer.c
 create mode 100644 components/coap/libcoap/examples/contiki/radvd.conf.sample
 create mode 100644 components/coap/libcoap/examples/contiki/server.c
 create mode 100755 components/coap/libcoap/examples/etsi_coaptest.sh
 create mode 100644 components/coap/libcoap/examples/etsi_iot_01.c
 create mode 100644 components/coap/libcoap/examples/etsi_iot_01_largedata.txt
 create mode 100644 components/coap/libcoap/examples/etsi_testcases.sh
 create mode 100644 components/coap/libcoap/examples/lwip/.gitignore
 create mode 100644 components/coap/libcoap/examples/lwip/README
 create mode 100644 components/coap/libcoap/examples/lwip/lwipopts.h
 create mode 100644 components/coap/libcoap/examples/lwip/server-coap.c
 create mode 100644 components/coap/libcoap/examples/lwip/server-coap.h
 create mode 100644 components/coap/libcoap/examples/lwip/server.c
 create mode 100644 components/coap/libcoap/examples/tiny.c
 create mode 100644 components/coap/libcoap/include/coap/address.h
 create mode 100644 components/coap/libcoap/include/coap/async.h
 create mode 100644 components/coap/libcoap/include/coap/bits.h
 create mode 100644 components/coap/libcoap/include/coap/block.h
 create mode 100644 components/coap/libcoap/include/coap/coap.h.in
 create mode 100644 components/coap/libcoap/include/coap/coap_io.h
 create mode 100644 components/coap/libcoap/include/coap/coap_time.h
 create mode 100644 components/coap/libcoap/include/coap/debug.h
 create mode 100644 components/coap/libcoap/include/coap/encode.h
 create mode 100644 components/coap/libcoap/include/coap/hashkey.h
 create mode 100644 components/coap/libcoap/include/coap/libcoap.h
 create mode 100644 components/coap/libcoap/include/coap/lwippools.h
 create mode 100644 components/coap/libcoap/include/coap/mem.h
 create mode 100644 components/coap/libcoap/include/coap/net.h
 create mode 100644 components/coap/libcoap/include/coap/option.h
 create mode 100644 components/coap/libcoap/include/coap/pdu.h
 create mode 100644 components/coap/libcoap/include/coap/prng.h
 create mode 100644 components/coap/libcoap/include/coap/resource.h
 create mode 100644 components/coap/libcoap/include/coap/str.h
 create mode 100644 components/coap/libcoap/include/coap/subscribe.h
 create mode 100644 components/coap/libcoap/include/coap/uri.h
 create mode 100644 components/coap/libcoap/include/coap/uthash.h
 create mode 100644 components/coap/libcoap/include/coap/utlist.h
 create mode 100644 components/coap/libcoap/libcoap-1.map
 create mode 100644 components/coap/libcoap/libcoap-1.pc.in
 create mode 100644 components/coap/libcoap/libcoap-1.sym
 create mode 100644 components/coap/libcoap/m4/ax_check_compile_flag.m4
 create mode 100644 components/coap/libcoap/m4/ax_check_link_flag.m4
 create mode 100755 components/coap/libcoap/scripts/build.sh
 create mode 100755 components/coap/libcoap/scripts/fix-cunit.sh
 create mode 100644 components/coap/libcoap/src/address.c
 create mode 100644 components/coap/libcoap/src/async.c
 create mode 100644 components/coap/libcoap/src/block.c
 create mode 100644 components/coap/libcoap/src/coap_io.c
 create mode 100644 components/coap/libcoap/src/coap_io_lwip.c
 create mode 100644 components/coap/libcoap/src/coap_time.c
 create mode 100644 components/coap/libcoap/src/debug.c
 create mode 100644 components/coap/libcoap/src/encode.c
 create mode 100644 components/coap/libcoap/src/hashkey.c
 create mode 100644 components/coap/libcoap/src/mem.c
 create mode 100644 components/coap/libcoap/src/net.c
 create mode 100644 components/coap/libcoap/src/option.c
 create mode 100644 components/coap/libcoap/src/pdu.c
 create mode 100644 components/coap/libcoap/src/resource.c
 create mode 100644 components/coap/libcoap/src/str.c
 create mode 100644 components/coap/libcoap/src/subscribe.c
 create mode 100644 components/coap/libcoap/src/uri.c
 create mode 100644 components/coap/libcoap/tests/Makefile.am
 create mode 100644 components/coap/libcoap/tests/test_error_response.c
 create mode 100644 components/coap/libcoap/tests/test_error_response.h
 create mode 100644 components/coap/libcoap/tests/test_options.c
 create mode 100644 components/coap/libcoap/tests/test_options.h
 create mode 100644 components/coap/libcoap/tests/test_pdu.c
 create mode 100644 components/coap/libcoap/tests/test_pdu.h
 create mode 100644 components/coap/libcoap/tests/test_sendqueue.c
 create mode 100644 components/coap/libcoap/tests/test_sendqueue.h
 create mode 100644 components/coap/libcoap/tests/test_uri.c
 create mode 100644 components/coap/libcoap/tests/test_uri.h
 create mode 100644 components/coap/libcoap/tests/test_wellknown.c
 create mode 100644 components/coap/libcoap/tests/test_wellknown.h
 create mode 100644 components/coap/libcoap/tests/testdriver.c
 create mode 100644 components/coap/port/coap_io_socket.c
 create mode 100644 components/coap/port/include/coap/coap.h
 create mode 100644 components/coap/port/include/coap_config.h
 create mode 100644 components/coap/port/include/coap_config_posix.h
 create mode 100644 examples/protocols/coap_client/CMakeLists.txt
 create mode 100644 examples/protocols/coap_client/Makefile
 create mode 100644 examples/protocols/coap_client/README.md
 create mode 100644 examples/protocols/coap_client/main/Kconfig.projbuild
 create mode 100644 examples/protocols/coap_client/main/coap_client_example_main.c
 create mode 100644 examples/protocols/coap_client/main/component.mk
 create mode 100644 examples/protocols/coap_server/CMakeLists.txt
 create mode 100644 examples/protocols/coap_server/Makefile
 create mode 100644 examples/protocols/coap_server/README.md
 create mode 100644 examples/protocols/coap_server/main/Kconfig.projbuild
 create mode 100644 examples/protocols/coap_server/main/coap_server_example_main.c
 create mode 100644 examples/protocols/coap_server/main/component.mk

diff --git a/components/coap/CMakeLists.txt b/components/coap/CMakeLists.txt
new file mode 100644
index 00000000..90b0c26e
--- /dev/null
+++ b/components/coap/CMakeLists.txt
@@ -0,0 +1,42 @@
+set(COMPONENT_ADD_INCLUDEDIRS port/include port/include/coap libcoap/include libcoap/include/coap)
+
+set(COMPONENT_SRCS
+    libcoap/src/address.c
+    libcoap/src/async.c
+    libcoap/src/block.c
+    libcoap/src/coap_time.c
+    libcoap/src/debug.c
+    libcoap/src/encode.c
+    libcoap/src/hashkey.c
+    libcoap/src/mem.c
+    libcoap/src/net.c
+    libcoap/src/option.c
+    libcoap/src/pdu.c
+    libcoap/src/resource.c
+    libcoap/src/str.c
+    libcoap/src/subscribe.c
+    libcoap/src/uri.c
+    port/coap_io_socket.c
+    )
+
+set(COMPONENT_REQUIRES lwip)
+
+register_component()
+
+# Needed for coap headers in public builds, also.
+#
+# TODO: find a way to move this to a port header
+target_compile_definitions(coap PUBLIC WITH_POSIX)
+
+set_source_files_properties(
+    libcoap/src/debug.c
+    libcoap/src/pdu.c
+    PROPERTIES COMPILE_FLAGS
+    -Wno-write-strings)
+
+# Temporary suppress "fallthrough" warnings until they are fixed in libcoap repo
+set_source_files_properties(
+    libcoap/src/option.c
+    PROPERTIES COMPILE_FLAGS
+    -Wno-implicit-fallthrough)
+
diff --git a/components/coap/Makefile.projbuild b/components/coap/Makefile.projbuild
new file mode 100644
index 00000000..e900b0f9
--- /dev/null
+++ b/components/coap/Makefile.projbuild
@@ -0,0 +1 @@
+CPPFLAGS += -DWITH_POSIX
diff --git a/components/coap/component.mk b/components/coap/component.mk
new file mode 100644
index 00000000..4b3d56f5
--- /dev/null
+++ b/components/coap/component.mk
@@ -0,0 +1,16 @@
+#
+# Component Makefile
+#
+
+COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap
+
+COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_time.o libcoap/src/debug.o libcoap/src/encode.o libcoap/src/hashkey.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o port/coap_io_socket.o
+
+COMPONENT_SRCDIRS := libcoap/src libcoap port
+
+COMPONENT_SUBMODULES += libcoap
+
+libcoap/src/debug.o: CFLAGS += -Wno-write-strings
+libcoap/src/pdu.o: CFLAGS += -Wno-write-strings
+# Temporary suppress "fallthrough" warnings until they are fixed in libcoap repo
+libcoap/src/option.o: CFLAGS += -Wno-implicit-fallthrough
diff --git a/components/coap/libcoap/.gitignore b/components/coap/libcoap/.gitignore
new file mode 100644
index 00000000..3b1d4b23
--- /dev/null
+++ b/components/coap/libcoap/.gitignore
@@ -0,0 +1,64 @@
+# .gitignore for libcoap
+
+# ignoring autogenerated files and directories by autoreconf
+INSTALL
+Makefile
+Makefile.in
+aclocal.m4
+ar-lib
+autom4te.cache/
+coap_config.h*
+compile
+config.*
+configure
+debian/
+depcomp
+install-sh
+libcoap-*.tar.bz2
+libtool
+ltmain.sh
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+missing
+stamp-h1
+
+# ignoring more files generated by the configure script or the make actions
+.libs/
+libcoap*.la
+libcoap*.pc
+src/.deps/
+src/.dirstamp
+src/.libs/
+src/*.o
+src/*.lo
+
+# the doc/ folder
+doc/Doxyfile
+doc/Makefile.in
+doc/doxyfile.stamp
+doc/doxygen_sqlite3.db
+doc/html/
+
+# the examples/ folder
+examples/.deps/
+examples/*.o
+examples/coap-client
+examples/coap-rd
+examples/coap-server
+examples/coap-client.5
+examples/coap-client.txt
+examples/coap-rd.5
+examples/coap-rd.txt
+examples/coap-server.5
+examples/coap-server.txt
+
+# the include/ folder
+include/coap/coap.h
+
+# the tests/ folder
+tests/.deps
+tests/testdriver
+tests/*.o
diff --git a/components/coap/libcoap/.travis.yml b/components/coap/libcoap/.travis.yml
new file mode 100644
index 00000000..d574e1d2
--- /dev/null
+++ b/components/coap/libcoap/.travis.yml
@@ -0,0 +1,34 @@
+sudo: required
+dist: trusty
+
+language: c
+compiler:
+  - gcc
+  - clang
+
+env:
+  - PLATFORM=posix TESTS=yes
+  - PLATFORM=contiki
+  - PLATFORM=lwip
+
+addons:
+  apt_packages:
+    - pkg-config
+    - graphviz
+    - libcunit1-dev
+    - doxygen
+    - libxml2-utils
+    - xsltproc
+    - docbook-xml
+    - docbook-xsl
+    - asciidoc
+
+branches:
+  only:
+     - master
+     - develop
+     - /^release-.*$/
+
+before_script: ./autogen.sh --clean && ./autogen.sh
+
+script: scripts/build.sh
diff --git a/components/coap/libcoap/AUTHORS b/components/coap/libcoap/AUTHORS
new file mode 100644
index 00000000..d747a4e7
--- /dev/null
+++ b/components/coap/libcoap/AUTHORS
@@ -0,0 +1,3 @@
+libcoap authors
+
+Olaf Bergmann, Universit�t Bremen <bergmann@tzi.org>
diff --git a/components/coap/libcoap/CONTRIBUTE b/components/coap/libcoap/CONTRIBUTE
new file mode 100644
index 00000000..9e6d3ee2
--- /dev/null
+++ b/components/coap/libcoap/CONTRIBUTE
@@ -0,0 +1,219 @@
+       #######################################################
+       #  Developer information for contributing to libcoap  #
+       #######################################################
+
+1. The basics
+~~~~~~~~~~~~~
+The libcoap project is a FOSS project that is dual licensed. The maintainer
+for the libcoap is Olaf Bergmann <bergmann@tzi.org>.
+Any contributions have to be made dual licensed under the terms of the
+license
+
+  * BSD 2-Clause (The BSD 2-Clause License)
+
+and
+
+  * GPL v2+ (The GNU General Public License 2.0 or later)
+
+The used VCS for libcoap is Git, the main repository is living on GitHub.
+You can clone (or fork directly on GitHub) on the repository site:
+
+  https://github.com/obgm/libcoap
+
+Please refer also to the libcoap website for additional information
+
+  https://libcoap.net/
+
+The build environment is grounded on the classical autotools, the GNU GCC and
+the LLVM C-compiler (CLang) are supported. The Windows systems are not
+currently supported (until someone is creating support for it).
+
+Doxygen is used for creating a HTML based online documentation of the
+libcoap library.
+
+2. Communications
+~~~~~~~~~~~~~~~~~
+The main discussion and development platform for libcoap is the mailing list
+on Sourceforge.
+No matter if you just have a simple question, some specific problem or
+want to discuss some patches, please write it to the mailing list. Please
+avoid personal mailings to the maintainer (or some other contributor) if
+your questions will probably be in the interest of other users too.
+You can subscribe to the list here:
+
+  https://lists.sourceforge.net/lists/listinfo/libcoap-developers
+
+The archive of the list can be found on:
+
+  https://sourceforge.net/p/libcoap/mailman/libcoap-developers
+
+3. Starting contributing
+~~~~~~~~~~~~~~~~~~~~~~~~
+As written above libcoap is maintained with the Git tools so you should be
+familiar with the various git commands.
+The libcoap project is using just two main branches, the 'master' branch is
+holding the point releases, all the development process is going on in the
+'develop' branch.
+To start any contributing you first have to clone the git tree from the main
+repository on GitHub:
+
+  git clone https://github.com/obgm/libcoap.git
+
+4. Working on the source
+~~~~~~~~~~~~~~~~~~~~~~~~
+As one golden rule you should work on improvements within *your* own local
+development branch! To do so you have to first checkout the 'develop' branch
+as local branch and then start on top on this branch your own branch. So
+create (or better say checkout) the local 'develop' branch:
+
+  cd libcoap
+  git checkout develop origin/develop
+
+Now you can simply start your own local branch (for example 'my-develop')
+with the 'origin/develop' as parent so you can later create the patches
+against the the upstream development branch:
+
+  git checkout -b my-develop
+
+At this point you can now work as known with git, modify the source, commit
+the changes, amend if needed and test your work.
+At some point you will have to generate patches to post them on the mailing
+list (and/or push your changes into your public Git tree). It's a good idea to
+post your patch series on the mailing list so other contributors will see your
+work and give further suggestions or discuss your work.
+
+To be able to send a patch series you will now create the series itself as
+single patches, this will be going easy with the 'git format-patch' command
+against the 'develop' branch, remind this is the upstream main development
+branch.
+To not mix up your series with probably unrelated patches let git place the
+patches within a defined directory. Also, while create the patches, tell git to
+create a cover letter patch so you can append some introducing words that will
+hold probably explanations why you create the patches in the way you have done.
+
+  git format-patch --cover-letter -o ../patches4libcoap
+
+This command will create a patch series in ../patches4libcoap where you find a
+patch named '0000-cover-letter.patch'. Please modify this patch with some
+useful information's for the mailing list. After finish this you now can send
+your patches to libcoap-developers@lists.sourceforge.net
+
+  git send-email ../patches4libcoap/* --to=libcoap-developers@lists.sourceforge.net
+
+5. Coding rules
+~~~~~~~~~~~~~~~
+As every FOSS project the libcoap project needs also some rules for coding.
+There are loss but the main of them are important!
+
+5.1 License and Copyright
+-------------------------
+Every new file must contain a license and the copyright holder(s). Please
+take a look into existing files and adopt the needed changes to your new
+file(s).
+
+5.2 Source Code Indentation
+---------------------------
+* For better reading the indentation is set to 2 characters as spaces, this
+  is depended on the often used nested functions like 'if-else'. Don't use
+  TABs any there! Avoid trailing white spaces at the end of a line.
+  It's appropriate to set up a modline like this one at first line within
+  the source file:
+
+--8<----
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 * -*- */
+--->8--
+
+* Single lines within the source code should not be longer then 78
+  characters.
+
+* If there a functions with a lot of parameters that do not fit into the above
+  rule split the declaration (in the *.h) and the implementation (in the *.c)
+  into single lines per parameter. For example like this (from src/block.c):
+
+--8<----
+int
+coap_add_block(coap_pdu_t *pdu,
+               unsigned int len,
+               const unsigned char *data,
+               unsigned int block_num,
+               unsigned char block_szx);
+--->8--
+
+5.3 Source Code Documentation
+-----------------------------
+* A useful source code documentation is mandatory. Mostly to be done within the
+  source code files, but more complex description should be done in extra
+  README files.
+
+* Please set up/adjust the doxygen documentation if you create new functions or
+  change existing functions. The doxygen documentation has to be done in the
+  header files as they are the public part of the libcoap and only use the
+  @-syntax for doxygen commands (akin to javadoc).
+
+5.4 API Changes
+---------------
+* Never break the API!
+  Don't remove old functions and if there some changes are needed in some kind
+  always provide a wrapper for the old call to let the library be backward
+  compatible and mark the old function as @deprecated in the doxygen comment.
+  Please discuss needed changes on the mailing list.
+
+5.5 Patches and Commits
+-----------------------
+* Git commits must be atomic and contain a declarative subject line (max 50
+  characters if possible) and a body for a statement if needed.
+  Use the possibility to write a good explanation why your patch/commit is
+  handle the changes in the way you have done. Remind that other user can
+  read your code but not necessary understand why the code is written this
+  way. Don't use something to generic like "bugfix commit".
+
+* A patch/commit or a series of patches/commits have to ensure that the
+  whole project is able to build up every thing, in short: Do not break
+  any make target and test your work.
+
+* Every patch/commit should handle one single logical change. If more than
+  one patch/commit is needed for a change explain it, respect the point
+  above. If your subject line become much larger than 50 characters then
+  typically your patch is to big for one single commit.
+
+* Commit message should begin with a submodule or unit the commit is for. By
+  this your commit message helps to find thematic other changes. If you have
+  to search and find something with 'git log | grep [foo]' you will see why
+  this is useful. Examples:
+
+    rd.c: Fixed type-specifier warning
+    Makefile.am: Added missing src/address.c
+    address.[hc]: make coap_address_equals() not inline on POSIX
+
+6. Where to start contributing?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+There are various things you could starting on to contribute, the best
+is you simply pick up an issue you blindly see and just improve the
+situation. Please take also a look into the file TODO and choose a point
+from there or point the maintainer to add other things here too.
+
+* Documentation
+We are always lacking on a better documentation on the source code, so
+maybe you can improve the doxygen documentation.
+Also a good documentation on the usage of the libcoap and the example
+binaries is always improvable. So we appreciate any help on this.
+
+* Man Pages
+The source is providing some example binaries which originally just should show
+how the libcoap can be used. Right now these binaries are fully usable and
+quite more than simple examples on a system. There are man pages for these
+binaries available, if you found there is a improvement needed please do so and
+write to the mailing list explained in section 2.
+Maybe you can write up some good HowTo's on the usage for these binaries. A man
+page for the library itself would be also a improvement.
+
+* HowTo's
+The libcoap library has now a lot of functions you can use.
+Unfortunately there is no good user guide on how to use the libcoap in
+any external project. This means there is no HowTo or CheatSheet for a
+programming person available. You want to write up something?
+
+* missed Functionality
+There are some features that are still missing inside the libcoap. For
+example some DTLS implementations and proxy functionality.
+
diff --git a/components/coap/libcoap/COPYING b/components/coap/libcoap/COPYING
new file mode 100644
index 00000000..6f0c0fd2
--- /dev/null
+++ b/components/coap/libcoap/COPYING
@@ -0,0 +1,6 @@
+libcoap is published as open-source software without any warranty of any kind.
+
+Use is permitted under the terms of the GNU General Public License (GPL),
+Version 2 or higher, OR the simplified BSD license.
+
+The respective license file are shipped as LICENSE.BSD and LICENSE.GPL.
diff --git a/components/coap/libcoap/ChangeLog b/components/coap/libcoap/ChangeLog
new file mode 100644
index 00000000..477be8df
--- /dev/null
+++ b/components/coap/libcoap/ChangeLog
@@ -0,0 +1,220 @@
+2016-02-16  Olaf Bergmann  <bergmann@tzi.org>
+
+	* Fixed build for Contiki3 and LwIP
+	* .travis.yml: Enabled continuous integration for platforms
+	  POSIX and Contiki
+
+2015-03-11  Olaf Bergmann  <bergmann@tzi.org>
+
+	* include/coap/resource.h: Replaced custom list structures by
+	utlist macros.
+
+2015-03-09  Olaf Bergmann  <bergmann@tzi.org>
+
+	* src/uri.c (coap_split_path): Fixed URI parser bug and
+	removed broken parse iterator.
+
+2015-03-05  Olaf Bergmann  <bergmann@tzi.org>
+
+	* src/coap_time.c (coap_ticks): Changed POSIX implementation
+	to fixed point arithmetic and removed clock_offset.
+
+2015-02-21  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_send_confirmed): Use fixed point arithmetic
+	to calculate retransmission timeout.
+
+2015-02-20  Olaf Bergmann  <bergmann@tzi.org>
+
+	* coap_list.[hc]: Moved old list implementation into
+	sub-directory examples and replaced by linked lists
+	from utlist.h. As a result, the list must be sorted
+	explicitly with LL_SORT).
+
+2015-02-19  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_send_confirmed): Fixed retransmission timeout
+	calculation and renamed transmission parameters according to
+	Section 4.8 of RFC 7252.
+
+2015-02-17  Olaf Bergmann  <bergmann@tzi.org>
+
+	* major rework to get Contiki and lwip running
+	* many fixed bugs and warnings
+
+2014-06-18  Olaf Bergmann  <bergmann@tzi.org>
+
+	* mem.c (coap_malloc_type): New functions for allocating memory.
+	On POSIX systems, coap_malloc_type() and coap_free_type() are just
+	wrapper functions for malloc() and free(), while on Contiki and
+	LWIP distinct arrays are used for each type.
+
+2014-03-09  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_cancel): Removed 7.31 again and implemented new
+	method for cancelling observe relationships.
+
+2014-02-25  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_cancel): Handling of 7.31 responses to cancel
+	notifications (see Section 4.6 of draft-ietf-core-observe-12)
+
+2014-02-04  Olaf Bergmann  <bergmann@tzi.org>
+
+	* resource.c (coap_print_link): This function now takes an offset
+	where printing starts. This is used for generating blocks on the
+	fly.
+
+	* net.c (wellknown_response): Added support for Block2 options
+	when generating a response for .well-known/core.
+
+	* block.h (coap_opt_block_num): Fixed handling of zero-length
+	options. COAP_OPT_BLOCK_LAST now returns NULL when the option
+	value's length is zero.
+
+2014-01-07  Olaf Bergmann  <bergmann@tzi.org>
+
+	* resource.c (coap_print_link): Output partial resource
+	descriptions. The function now provides a sliding window over the
+	textual representation of the resource. Output starts at the given
+	offset and ends at the buffer's upper bound. The meaning of the
+	return value has changed to allow distinguishing whether or not
+	the resource description has been truncated at the buffer's upper
+	bound.
+	(print_wellknown): Support for the new coap_print_link(). An
+	additional parameter now is used to provide the offset into the
+	resource description. The meaning of the return value has been
+	adjusted accordingly.
+
+2013-12-23  Olaf Bergmann  <bergmann@tzi.org>
+
+	* configure.in: merged with LWIP port from chrysn
+	<https://git.gitorious.org/coap-lwip/coap-lwip.git>. This
+	introduces new compiler flags WITH_POSIX and WITH_LWIP to
+	distinguish target platforms.
+
+2013-09-03  Olaf Bergmann  <bergmann@tzi.org>
+
+	* option.h (coap_option_setb): increased size of option type
+	argument
+
+	* tests/test_error_response.c (t_init_error_response_tests): new
+	tests for error response generation
+
+	* tests/test_pdu.c (t_encode_pdu5): fixed number for option Accept
+
+	* net.c (coap_new_error_response): fixed option size calculation
+
+2013-07-04  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_new_context): register critical Accept option
+
+	* pdu.c: option codes for Accept and Size1 according to coap-18
+
+2013-02-01  Olaf Bergmann  <bergmann@tzi.org>
+
+	* coap_time.h (coap_clock_init_impl): fix invalid preprocessor
+	directive. #warning is now only used for gcc only (close sf bug #15)
+
+	* net.c (wellknown_response): applied patch from chrysn to
+	fix bug in generation of .well-known/core representation
+
+2013-01-21  Olaf Bergmann  <bergmann@tzi.org>
+
+	* option.h: renamed option field in coap_opt_iterator_t to
+	next_option to detect erroneous use in old code
+
+2013-01-18  Olaf Bergmann  <bergmann@tzi.org>
+
+	* configure.in: new option --with-tests to enable unit tests
+
+	* tests/testdriver.c: unit tests for parser functions
+
+	* pdu.c (coap_pdu_parse): new PDU parser for Klaus-encoding
+	according to coap-13
+
+	* net.c (coap_read): call coap_pdu_parse() to check PDU integrity
+
+	* option.c: Klaus-encoding for coap-13, including new option
+	iterator interface
+
+2012-11-20  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (next_option_safe): made option parsing more robust in
+	presence of option jumps
+
+	* pdu.h: new option codes from draft-ietf-core-coap-12
+
+	* option.c (coap_opt_setlength): new function to set option length
+
+	* uri.c (make_decoded_option): use coap_opt_setlength() instead of
+	obsolete macro COAP_OPT_SETLENGTH.
+
+2012-11-19  Olaf Bergmann  <bergmann@tzi.org>
+
+	* uri.c (make_decoded_option): use coap_opt_encode() instead of writing
+
+2012-11-03  Olaf Bergmann  <bergmann@tzi.org>
+
+	* net.c (coap_read): read new option encoding
+
+2012-11-01  Olaf Bergmann  <bergmann@tzi.org>
+
+	* option.c (coap_opt_size, coap_opt_value, coap_opt_length):
+	several functions to access fields of options (possibly preceeded
+	by option jump)
+
+2012-10-25  Olaf Bergmann  <bergmann@tzi.org>
+
+	* option.c (coap_opt_encode): new function for option encoding
+	with option jumps
+
+2012-03-23  Olaf Bergmann  <bergmann@tzi.org>
+
+	* examples/client.c (clear_obs): clear observation relationship after
+	user-specified duration
+
+2012-03-21  Olaf Bergmann  <bergmann@tzi.org>
+
+	* resource.c (print_wellknown): filtering by attributes
+
+2012-03-19  Olaf Bergmann  <bergmann@tzi.org>
+
+	* pdu.c (coap_add_option): allow more than 15 options.
+
+2012-03-15  Olaf Bergmann  <bergmann@tzi.org>
+
+	* examples/client.c (cmdline_uri): split path and query here to
+	make it easier to include these options in subsequent requests for
+	block transfer.
+
+2012-03-14  Olaf Bergmann  <bergmann@tzi.org>
+
+	* examples/etsi_iot_01.c: Support for POST, PUT, DELETE on /test
+
+2012-03-13  Olaf Bergmann  <bergmann@tzi.org>
+
+	* encode.c (coap_encode_var_bytes): more efficient coding for 0
+
+2012-03-11  Olaf Bergmann  <bergmann@tzi.org>
+
+	* examples/etsi_iot_01.c: Test cases for 1st ETSI CoAP Plugtest,
+	March 24/25, 2012 in Paris, France.
+
+2012-03-10  Olaf Bergmann  <bergmann@tzi.org>
+
+	* block.c: support for block transfer.
+
+2012-03-07  Olaf Bergmann  <bergmann@tzi.org>
+
+	* examples/client.c (usage): new command line options
+	-B to set timeout after which the main loop is left.
+	-e to specify a payload (incompatible with -f)
+	(message_handler): bugfixes
+
+	* resource.h: (coap_method_handler_t): new API for method handlers.
+
+
+Copyright 2012 Olaf Bergmann, TZI
+Copying and distribution of this file, with or without modification, are
+permitted provided the copyright notice and this notice are preserved.
diff --git a/components/coap/libcoap/LICENSE.BSD b/components/coap/libcoap/LICENSE.BSD
new file mode 100644
index 00000000..b3d19496
--- /dev/null
+++ b/components/coap/libcoap/LICENSE.BSD
@@ -0,0 +1,26 @@
+Copyright (c) 2010--2015, Olaf Bergmann
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  o Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  o 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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
diff --git a/components/coap/libcoap/LICENSE.GPL b/components/coap/libcoap/LICENSE.GPL
new file mode 100644
index 00000000..d8cf7d46
--- /dev/null
+++ b/components/coap/libcoap/LICENSE.GPL
@@ -0,0 +1,280 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
diff --git a/components/coap/libcoap/Makefile.am b/components/coap/libcoap/Makefile.am
new file mode 100644
index 00000000..15e4881a
--- /dev/null
+++ b/components/coap/libcoap/Makefile.am
@@ -0,0 +1,180 @@
+# Makefile.am for libcoap
+#
+# Copyright (C) 2010-2015 Olaf Bergmann <bergmann@tzi.org>
+#           (C) 2015-2016 Carsten Schoenert <c.schoenert@t-online.de>
+#
+# This file is part of the CoAP C library libcoap. Please see README and
+# COPYING for terms of use.
+
+## Place generated object files (.o) into the same directory as their source
+## files, in order to avoid collisions when non-recursive make is used.
+AUTOMAKE_OPTIONS = subdir-objects
+
+ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4
+
+## Additional files for the distribution archive
+EXTRA_DIST = \
+  CONTRIBUTE \
+  TODO \
+  $(pkgconfig_DATA).in \
+  libcoap-$(LIBCOAP_API_VERSION).map \
+  libcoap-$(LIBCOAP_API_VERSION).sym \
+  examples/coap_list.h \
+  tests/test_options.h \
+  tests/test_pdu.h \
+  tests/test_error_response.h \
+  tests/test_sendqueue.h \
+  tests/test_uri.h \
+  tests/test_wellknown.h
+
+AM_CFLAGS = -I$(top_builddir)/include/coap -I$(top_srcdir)/include/coap $(WARNING_CFLAGS) -std=c99
+
+SUBDIRS = . $(DOC_DIR) tests examples
+
+## Define a libtool archive target "libcoap-@LIBCOAP_API_VERSION@.la", with
+## @LIBCOAP_API_VERSION@ substituted into the generated Makefile at configure
+## time.
+## The libtool archive file (.la) will be installed into the directory named
+## by the predefined variable $(bindir), along with the actual shared library
+## file (.so).
+lib_LTLIBRARIES = libcoap-@LIBCOAP_API_VERSION@.la
+
+libcoap_@LIBCOAP_API_VERSION@_la_CFLAGS = \
+  -fPIC \
+  -fPIE \
+  $(AM_CFLAGS)
+
+## Define the source file list for the "libcoap.la" target.
+## Note that it is not necessary to list header files which are already listed
+## elsewhere in a _HEADERS variable assignment.
+libcoap_@LIBCOAP_API_VERSION@_la_SOURCES = \
+  src/address.c \
+  src/async.c \
+  src/block.c \
+  src/coap_io.c \
+  src/coap_time.c \
+  src/debug.c \
+  src/encode.c \
+  src/hashkey.c \
+  src/mem.c \
+  src/net.c \
+  src/option.c \
+  src/pdu.c \
+  src/resource.c \
+  src/str.c \
+  src/subscribe.c \
+  src/uri.c
+
+## Define the list of public header files and their install location.
+## The list defined here will be used within the include/Makefile.am
+## and is only a variable because the content is needed also for the
+## generating of the symbol mapping file.
+libcoap_includedir = $(includedir)/coap/
+libcoap_include_HEADERS = \
+  $(top_srcdir)/include/coap/address.h \
+  $(top_srcdir)/include/coap/async.h \
+  $(top_srcdir)/include/coap/bits.h \
+  $(top_srcdir)/include/coap/block.h \
+  $(top_builddir)/include/coap/coap.h \
+  $(top_srcdir)/include/coap/coap_io.h \
+  $(top_srcdir)/include/coap/coap_time.h \
+  $(top_srcdir)/include/coap/debug.h \
+  $(top_srcdir)/include/coap/encode.h \
+  $(top_srcdir)/include/coap/hashkey.h \
+  $(top_srcdir)/include/coap/libcoap.h \
+  $(top_srcdir)/include/coap/mem.h \
+  $(top_srcdir)/include/coap/net.h \
+  $(top_srcdir)/include/coap/option.h \
+  $(top_srcdir)/include/coap/pdu.h \
+  $(top_srcdir)/include/coap/prng.h \
+  $(top_srcdir)/include/coap/resource.h \
+  $(top_srcdir)/include/coap/str.h \
+  $(top_srcdir)/include/coap/subscribe.h \
+  $(top_srcdir)/include/coap/uri.h \
+  $(top_srcdir)/include/coap/uthash.h \
+  $(top_srcdir)/include/coap/utlist.h
+
+# If there is a API change to something $(LIBCOAP_API_VERSION) > 1 the install
+# prefix for the header files has to change to not conflict the older version
+# if the user want's to install both versions. There will be something used like
+# libcoap_include_HEADERS = \
+#  $(top_srcdir)/include/coap-$(LIBCOAP_API_VERSION)/*
+
+
+## Instruct libtool to include API version information in the generated shared
+## library file (.so). The library ABI version will later defined in configure.ac,
+## so that all version information is kept in one place.
+libcoap_@LIBCOAP_API_VERSION@_la_LDFLAGS =					\
+  -version-info $(LT_LIBCOAP_CURRENT):$(LT_LIBCOAP_REVISION):$(LT_LIBCOAP_AGE)	\
+  @libcoap_SYMBOLS@ \
+  -pie
+
+## Collect symbols here we want to ignore while building the helper files
+## libcoap-$(LIBCOAP_API_VERSION).{map,sym} for the linker.
+CTAGS_IGNORE=-I "coap_packet_extract_pbuf coap_pdu_from_pbuf"
+
+# This helper is called by libcoap-$(LIBCOAP_API_VERSION).{map,sym} to see if
+# configure has detected a usable version of the ctags program and aborts if not.
+check_ctags:
+	@if [ "$(CTAGS_PROG)" = "" ]; then \
+		echo ;\
+		echo "There was no ctags program found by the configure script!" ;\
+		echo "ctags is needed for running this target! Please note the warning about the missed ctags program of the configure script." ;\
+		echo ;\
+		exit 1;\
+	fi
+
+## Helper target to generate the symbol table needed by libtool.
+## The .map format is used when ld supports linker scripts, otherwise
+## it must fall back to a plain symbol file.
+update-map-file: libcoap-$(LIBCOAP_API_VERSION).map libcoap-$(LIBCOAP_API_VERSION).sym
+
+libcoap-$(LIBCOAP_API_VERSION).map: check_ctags $(libcoap_include_HEADERS)
+	( echo "VER_$(LIBCOAP_API_VERSION) {" ; \
+	echo "global:" ; \
+	$(CTAGS_PROG) $(CTAGS_IGNORE) -f - --c-kinds=p $(libcoap_include_HEADERS) | awk '/^coap_/ { print "  " $$1 ";" }' | sort ; \
+	echo "local:" ; \
+	echo "  *;" ; \
+	echo "};" ) > $@.new
+	mv $@.new $@
+
+libcoap-$(LIBCOAP_API_VERSION).sym: check_ctags $(libcoap_include_HEADERS)
+	( $(CTAGS_PROG) $(CTAGS_IGNORE) -f - --c-kinds=p $(libcoap_include_HEADERS) | awk '/^coap_/ { print $$1 }' | sort ) \
+	> $@.new
+	mv $@.new $@
+
+## Install the generated pkg-config file (.pc) into the expected location for
+## architecture-dependent package configuration information.  Occasionally,
+## pkg-config files are also used for architecture-independent data packages,
+## in which case the correct install location would be $(datadir)/pkgconfig.
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libcoap-$(LIBCOAP_API_VERSION).pc
+
+## Define an independent executable script for inclusion in the distribution
+## archive.  However, it will not be installed on an end user's system due to
+## the noinst_ prefix.
+dist_noinst_SCRIPTS = autogen.sh
+
+## various *-local targets
+## Remove the helper files for the linker and the pkg-config file if there
+## is 'make distclean' called. NOTE: To re create the *.{map,sym} files you
+## need to call the target update-map-file after the configure script was
+## running!
+distclean-local:
+	rm -f libcoap-$(LIBCOAP_API_VERSION).map
+	rm -f libcoap-$(LIBCOAP_API_VERSION).sym
+	rm -f libcoap-$(LIBCOAP_API_VERSION).pc
+	@echo
+	@echo "     ---> Please note the following important advice! <---"
+	@echo "     The files libcoap-$(LIBCOAP_API_VERSION).{map,sym} are removed by the distclean target!"
+	@echo "     To regenerate this two files you need to call 'make update-map-file' first before any"
+	@echo "     other Make target. Otherwise the build of libcoap will fail!"
+	@echo
+
+## Ensure we have actual *.{map,sym} files if we create a release tarball.
+dist-local: update-map-file
+
+## Finaly some phony targets, just to ensure those targets are always buildable
+## no matter if the user has created same called files.
+.PHONY: update-map-file check_ctags
+
diff --git a/components/coap/libcoap/Makefile.libcoap b/components/coap/libcoap/Makefile.libcoap
new file mode 100644
index 00000000..122e0faa
--- /dev/null
+++ b/components/coap/libcoap/Makefile.libcoap
@@ -0,0 +1,7 @@
+libcoap_src = pdu.c net.c debug.c encode.c uri.c subscribe.c resource.c hashkey.c str.c option.c async.c block.c mem.c coap_io.c
+
+libcoap_dir := $(filter %libcoap,$(APPDS))
+vpath %c $(libcoap_dir)/src
+
+# set include path for coap sources
+CFLAGS += -I$(libcoap_dir)/include/coap -DCOAP_RESOURCES_NOHASH
diff --git a/components/coap/libcoap/NEWS b/components/coap/libcoap/NEWS
new file mode 100644
index 00000000..e69de29b
diff --git a/components/coap/libcoap/README b/components/coap/libcoap/README
new file mode 100644
index 00000000..a582dbfe
--- /dev/null
+++ b/components/coap/libcoap/README
@@ -0,0 +1,30 @@
+libcoap: A C implementation of IETF Constrained Application Protocol (RFC 7252)
+
+Copyright (C) 2010--2015 by Olaf Bergmann <bergmann@tzi.org>
+
+ABOUT LIBCOAP
+=============
+
+libcoap is a C implementation of a lightweight application-protocol
+for devices that are constrained their resources such as computing
+power, RF range, memory, bandwith, or network packet sizes. This
+protocol, CoAP, is standardized by the IETF as RFC 7252. For further
+information related to CoAP, see <http://coap.technology>.
+
+PACKAGE CONTENTS
+================
+
+This directory contains a protocol parser and basic networking
+functions for platform with support for malloc() and BSD-style
+sockets. The examples directory contains a client and a server to
+demonstrate the use of this library. 
+
+LICENSE INFORMATION
+===================
+
+This library is published as open-source software without any warranty
+of any kind. Use is permitted under the terms of the GNU General
+Public License (GPL), Version 2 or higher, OR the simplified BSD
+license. Please refer to LICENSE.GPL oder LICENSE.BSD for further
+details.
+
diff --git a/components/coap/libcoap/README.md b/components/coap/libcoap/README.md
new file mode 100644
index 00000000..a582dbfe
--- /dev/null
+++ b/components/coap/libcoap/README.md
@@ -0,0 +1,30 @@
+libcoap: A C implementation of IETF Constrained Application Protocol (RFC 7252)
+
+Copyright (C) 2010--2015 by Olaf Bergmann <bergmann@tzi.org>
+
+ABOUT LIBCOAP
+=============
+
+libcoap is a C implementation of a lightweight application-protocol
+for devices that are constrained their resources such as computing
+power, RF range, memory, bandwith, or network packet sizes. This
+protocol, CoAP, is standardized by the IETF as RFC 7252. For further
+information related to CoAP, see <http://coap.technology>.
+
+PACKAGE CONTENTS
+================
+
+This directory contains a protocol parser and basic networking
+functions for platform with support for malloc() and BSD-style
+sockets. The examples directory contains a client and a server to
+demonstrate the use of this library. 
+
+LICENSE INFORMATION
+===================
+
+This library is published as open-source software without any warranty
+of any kind. Use is permitted under the terms of the GNU General
+Public License (GPL), Version 2 or higher, OR the simplified BSD
+license. Please refer to LICENSE.GPL oder LICENSE.BSD for further
+details.
+
diff --git a/components/coap/libcoap/TODO b/components/coap/libcoap/TODO
new file mode 100644
index 00000000..503ea7a0
--- /dev/null
+++ b/components/coap/libcoap/TODO
@@ -0,0 +1,61 @@
+This is a simple file for all kinds of stuff related on devlopment for
+libcoap. Please append (and remove) any issue you think its worthy.
+
+Classification of issues:
+ Critical -> Break the library in some kind or a missing feature, maybe not 
+             directly but later
+ Serious  -> No regression on the user side, more likly on the libcoap
+             development
+ Minor    -> Things that are nice to have, but they are not time critical
+
+=================
+* CRITICAL ISSUES
+=================
+-> Remove the #include "coap_config.h" directive from the public header files.
+-> Remove #ifdef HAVE_ASSERT_H and so on from the public headers.
+-> Use coap.h as the only header to include from the public view.
+-> DTLS functionality
+ -> Adding DTLS functions based on openssl
+  -> Bill Benett has starting some improvements here, please contact him 
+     first before starting something
+-> Proxy functionality
+ -> A coap-server should be able to act as proxy server
+
+================
+* SERIOUS ISSUES
+================
+-> Create some development rules like:
+    --> How to submit patches? What about pull requests?
+	--> How to implement/change platform related code?
+-> Adding some documentation for classical users on how to use the libcoap
+-> Clean up the various inclusion for #ifdef __cplusplus #extern "C" {}
+-> Adding additional config options (like --with-pdu-size)
+-> Split of the platform related code into [foo]_platform.c files
+-> In general, improving the online doxygen documentation like creating some 
+   additional information for doxygen (startpage, development information, 
+   ...)
+-> In special, improving ...
+  Adding prams and return explanation in:
+   include/coap/coap_io.h
+   include/coap/option.h
+   include/coap/net.h
+   include/coap/resource.h
+   include/coap/str.h
+   include/coap/subscribe.h
+   include/coap/uri.h
+  Adding @brief directive
+   include/coap/block.h
+   include/coap/coap_io.h
+   include/coap/debug.h
+   include/coap/encode.h
+   include/coap/net.h
+   include/coap/str.h
+   include/coap/subscribe.h
+   include/coap/uri.h
+
+==============
+* MINOR ISSUES
+==============
+-> Remove the not needed Makefile.in.old files
+-> Adding a logo for libcoap
+
diff --git a/components/coap/libcoap/autogen.sh b/components/coap/libcoap/autogen.sh
new file mode 100755
index 00000000..0b8694e9
--- /dev/null
+++ b/components/coap/libcoap/autogen.sh
@@ -0,0 +1,133 @@
+#!/bin/sh -e
+
+# uncomment the set command for debugging
+#set -x
+
+# function to check for needed helper tools
+check_helper() {
+#echo "Checking for $1 ..."
+TOOL=`which "$1" || echo none`
+
+if [ "$TOOL" = "none" ]; then
+    echo
+    echo "Couldn't find '$1'!"
+    RET=1
+else
+    RET=0
+fi
+}
+
+PROJECT="libcoap"
+
+AUTOGEN_FILES="
+INSTALL
+aclocal.m4 ar-lib
+coap_config.h coap_config.h.in* compile config.guess config.h* config.log config.status config.sub configure
+depcomp
+doc/Doxyfile doc/doxyfile.stamp doc/doxygen_sqlite3.db doc/Makefile doc/Makefile.in
+examples/*.o  examples/coap-client examples/coap-server examples/coap-rd
+examples/coap-*.5 examples/coap-*.txt examples/Makefile.in
+include/coap/coap.h
+install-sh
+libcoap-1.pc libtool ltmain.sh
+missing
+Makefile Makefile.in
+stamp-h1 src/.dirstamp libcoap*.la* src/*.*o
+tests/*.o tests/Makefile tests/testdriver
+m4/libtool.m4 m4/lt~obsolete.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4
+"
+
+AUTOGEN_DIRS="
+.deps
+.libs autom4te.cache/
+doc/html/
+examples/.deps/ examples/.libs
+src/.deps/ src/.libs/
+tests/.deps/
+"
+
+# checking for cleaner argument
+echo
+if [ "$1" = "--clean" ]; then
+    echo "removing autogerated files ..."
+    rm -rf $AUTOGEN_FILES $AUTOGEN_DIRS
+    echo "done"
+    exit
+else
+    echo "[HINT] You can run 'autogen.sh --clean' to remove all generated files by the autotools."
+    echo
+fi
+
+# checking for autoreconf
+check_helper autoconf
+if [ "$RET" = "1" ]; then
+    echo "You probably need to install the package 'autoconf'."
+    ERROR=1
+else
+    echo "Found 'autoconf'."
+fi
+
+# checking for aclocal
+check_helper aclocal
+if [ "$RET" = "1" ]; then
+    echo "You probably need to install the package 'automake'."
+    ERROR=1
+else
+    echo "Found 'aclocal'."
+fi
+
+# checking for pkg-config
+check_helper pkg-config
+if [ "$RET" = "1" ]; then
+    echo "You probably need to install the package 'pkg-config|pkgconf'."
+    ERROR=1
+else
+    echo "Found 'pkg-config'."
+fi
+
+# checking for libtool
+# The libtool helper maybe installed as 'libtoolize', checking for 'libtool' first.
+check_helper libtool
+if [ "$RET" = "1" ]; then
+    # O.k. libtool not found, searching for libtoolize.
+    check_helper libtoolize
+    if [ "$RET" = "1" ]; then
+        echo "You probably need to install the package 'libtool'."
+        # That's bad, we found nothing!
+        ERROR=1
+    else
+        echo "Found 'libtoolize'."
+        break
+    fi
+else
+    echo "Found 'libtool'."
+fi
+
+# exit if one tool isn't available
+if [ "$ERROR" = "1" ]; then
+    echo
+    echo "One or more needed tools are missing, exiting ..."
+    echo "Please install the needed software packages and restart 'autogen.sh' again."
+    echo
+    exit 1
+fi
+
+echo
+echo "  --->  Found all needed tools! That's fine."
+echo
+
+# countinue otherwise
+test -n "$srcdir" || srcdir=`dirname "$0"`
+test -n "$srcdir" || srcdir=.
+
+# Creating the directory m4 before calling autoreconf to
+# not struggle with old versions of aclocal.
+mkdir -p $srcdir/m4
+
+echo "Generating needed autotools files for $PROJECT by running autoreconf ..."
+autoreconf --force --install --verbose "$srcdir"
+
+echo
+echo "You can now run 'configure --help' to see possible configuration options."
+echo "Otherwise process the configure script to create the makefiles and generated helper files."
+echo
diff --git a/components/coap/libcoap/configure.ac b/components/coap/libcoap/configure.ac
new file mode 100644
index 00000000..8ae8840e
--- /dev/null
+++ b/components/coap/libcoap/configure.ac
@@ -0,0 +1,423 @@
+# configure.ac for the libcoap package
+#
+# Copyright (C) 2010-2015 Olaf Bergmann <bergmann@tzi.org>
+#           (C) 2015-2016 Carsten Schoenert <c.schoenert@t-online.de>
+#
+# Please run 'autogen.sh' to let autoconf produce a configure script.
+
+# Define the libcoap software version here. Note! The libtool versions are
+# defined later.
+m4_define([libcoap_major_version], [4])
+m4_define([libcoap_minor_version], [1])
+m4_define([libcoap_micro_version], [2])
+
+m4_define([libcoap_version],[libcoap_major_version.libcoap_minor_version.libcoap_micro_version])
+
+AC_INIT([libcoap], [libcoap_version], [libcoap-developers@lists.sourceforge.net], [libcoap], [https://libcoap.net/])
+AC_PREREQ([2.64])
+AM_INIT_AUTOMAKE([1.10 -Wall no-define no-dist-gzip dist-bzip2])
+PKG_PROG_PKG_CONFIG([0.20])
+
+# Generate one configuration header file for building the library itself with
+# an autogenerated template. We need later a second one (include/libcoap.h)
+# that will be installed alongside the library.
+AC_CONFIG_HEADERS([coap_config.h])
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_SED
+AC_CONFIG_MACRO_DIR([m4])
+m4_pattern_allow([AM_PROG_AR])
+AM_PROG_AR
+
+AC_C_BIGENDIAN
+
+# enable the automatically build of shared and static libraries, the unit
+# tests needs the static library
+LT_INIT([shared static])
+
+# Setting the libtool versioning
+###################################################################################
+#                                                                                 #
+#  To set the version of the library, libtool provides the -version-info          #
+#  parameter, which accepts three numbers, separated by colons, that are called   #
+#  respectively, current, revision and age. Both their name and their behaviour,  #
+#  nowadays, have to be considered fully arbitrary, as the explanation provided   #
+#  in the official documentation is confusing to say the least, and can be, in    #
+#  some cases, considered completely wrong.                                       #
+#  https://autotools.io/libtool/version.html                                      #
+#                                                                                 #
+###################################################################################
+#
+# How to work with the libtool versioning?
+#
+# Follow the followings steps from top to bottom. This means allways start at point 1
+# if you plan to make a release and change the values.
+# Every new library starts with a version 'current'  (short 'c') = 0
+#                                         'revision' (short 'r') = 0
+#                                         'age'      (short 'a') = 0
+#
+# Update the libtool versioning only immediately before a public release of libcoap.
+#
+# 1. If the library source code has changed at all since the last update, then
+#    increment revision (c:r:a becomes c:r+1:a).
+#  --> Increase the 'LT_LIBCOAP_REVISION' value with *everey* new software release.
+#
+# 2. If any interfaces [exported functions or data] have been added, removed, or
+#    changed since the last update, increment current, and set revision to 0
+#    (c:r:a becomes c+1:r=0:a).
+#  --> Increase the 'LT_LIBCOAP_CURRENT' value whenever as an interface has been added,
+#      removed or changed. This implies also a API change! You mostly have to change
+#      the 'libcoap_major_version' then too!
+#  --> Set 'LT_LIBCOAP_REVISION' to 0.
+#
+# 3. If any interfaces have been added since the last public release, then increment
+#    age (c:r:a becomes c:r:a+1). Adding new interfaces will make the library allways
+#    backwards compatable.
+#  --> Increase the 'LT_LIBCOAP_AGE' value only if the changes made to the ABI are
+#      backward compatible.
+#
+# 4. If any interfaces whitin the library have been removed since the last public
+#    release, then set age to 0.
+#  --> Set 'LT_LIBCOAP_AGE' to 0.
+
+LT_LIBCOAP_CURRENT=0
+LT_LIBCOAP_REVISION=0
+LT_LIBCOAP_AGE=0
+LIBCOAP_SO_VERSION=$LT_LIBCOAP_CURRENT.$LT_LIBCOAP_REVISION.$LT_LIBCOAP_AGE
+
+# Announce the libtool version
+AC_SUBST(LT_LIBCOAP_CURRENT)
+AC_SUBST(LT_LIBCOAP_REVISION)
+AC_SUBST(LT_LIBCOAP_AGE)
+AC_SUBST(LIBCOAP_SO_VERSION)
+
+# Defining the API Version
+LIBCOAP_API_VERSION=1
+AC_SUBST(LIBCOAP_API_VERSION)
+
+# Adding some default warning options for code QS
+# see https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
+# and http://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
+WARNING_CFLAGS="\
+-pedantic \
+-Wall \
+-Wextra \
+-Wformat-security \
+-Winline \
+-Wmissing-declarations \
+-Wmissing-prototypes \
+-Wnested-externs \
+-Wpointer-arith \
+-Wshadow \
+-Wstrict-prototypes \
+-Wswitch-default \
+-Wswitch-enum \
+-Wunused \
+"
+
+# check whether or not the compiler supports -Wlogical-op (clang does not...)
+AX_CHECK_COMPILE_FLAG([-Wlogical-op], [WARNING_CFLAGS="$WARNING_CFLAGS -Wlogical-op"],,[-Werror])
+AX_CHECK_COMPILE_FLAG([-fdiagnostics-color], [CFLAGS="$CFLAGS -fdiagnostics-color"],,[-Werror])
+AX_CHECK_COMPILE_FLAG([-Wunused-result], [WARNING_CFLAGS="$WARNING_CFLAGS -Wunused-result"])
+
+AC_SUBST([WARNING_CFLAGS])
+
+AX_CHECK_LINK_FLAG([-Wl,--version-script=./libcoap-${LIBCOAP_API_VERSION}.map],
+                   [libcoap_SYMBOLS="-Wl,--version-script=\$(srcdir)/libcoap-\$(LIBCOAP_API_VERSION).map"],
+                   [libcoap_SYMBOLS="-export-symbols \$(srcdir)/libcoap-\$(LIBCOAP_API_VERSION).sym"])
+
+AC_SUBST(libcoap_SYMBOLS)
+
+# configure options
+# __documentation__
+AC_ARG_ENABLE([documentation],
+              [AC_HELP_STRING([--enable-documentation],
+              [Enable building the documentation [default=yes]])],
+              [build_documentation="$enableval"],
+              [build_documentation="yes"])
+
+if test "x$build_documentation" = "xyes"; then
+    # Check for doxygen
+    AC_PATH_PROGS([DOXYGEN], [doxygen])
+    if test -z "$DOXYGEN"; then
+        if test "x$build_documentation" = "xyes"; then
+            AC_MSG_WARN([==> Doxygen not found - continuing without Doxygen support])
+            AC_MSG_WARN([==> The libcoap html documentation will not be build!])
+            doxygen_version="not found"
+        fi
+    else
+        AC_MSG_CHECKING([for compatible doxygen version (>= 1.7.0)])
+                        doxygen_version=`$DOXYGEN --version`
+                        AS_VERSION_COMPARE([$doxygen_version], [1.7.0],
+                        [AC_MSG_RESULT([no])
+                         DOXYGEN=""],
+                        [AC_MSG_RESULT([yes $doxygen_version])],
+                        [AC_MSG_RESULT([yes $doxygen_version])])
+        if test "x$DOXYGEN" = "x" -a "x$build_documentation" = "xyes"; then
+            AC_MSG_ERROR([==> Doxygen $doxygen_version too old. Doxygen 1.7+ required for documentation build.])
+            AC_MSG_ERROR([==> Install required doxygen version or disable the documentation using --disable-documentation])
+        else
+            # we found doxygen and the version is valid
+            DOC_DIR=doc
+            AC_SUBST(DOC_DIR)
+            # now checking dot (needed for graphics)
+            AC_PATH_PROG([DOT], [dot])
+            if test "x$DOT" = "x"; then
+                AC_MSG_WARN([==> dot not found - continuing without DOT support])
+                AC_MSG_WARN([==> The libcoap html documentation will be build without DOT graphics!])
+                HAVE_DOT="NO"
+                USE_CALL_GRAPH="NO"
+            else
+                AC_MSG_CHECKING([for compatible dot version (>= 2.26.0)])
+                case $host in
+                    *-freebsd1*)
+                    # csh and tcsh have a different output redirection than more recent shells
+                    # cmd >& file   # Redirect both stdout and stderr to file.
+                    # cmd >>& file  # Append both stdout and stderr to file.
+                    # cmd1 | cmd2   # pipe stdout to cmd2
+                    # cmd1 |& cmd2  # pipe stdout and stderr to cmd2
+                    # Using a explicit call with the default always available C-shell on FreeBSD,
+                    # the user may have installed another shell from a port which we don't know here
+                    dot_version=`export DOT=$DOT && csh -c '$DOT -V |& cut -f5 -d" "'`
+                    ;;
+
+                    *)
+                    dot_version=`$DOT -V 2>&1 | cut -f5 -d" "`
+                    ;;
+
+                esac
+                AS_VERSION_COMPARE([$dot_version], [2.26.0],
+                                   [AC_MSG_RESULT([no])
+                                    DOT=""],
+                                   [AC_MSG_RESULT([yes $dot_version])],
+                                   [AC_MSG_RESULT([yes $dot_version])])
+                if test "x$DOT" = "x" -a "x$build_documentation" = "xyes"; then
+                        AC_MSG_WARN([==> Graphviz dot $dot_version too old. Graphviz 2.26+ required for documentation build.])
+                        AC_MSG_ERROR([==> Install required graphviz version or disable the documentation using --disable-documentation])
+                fi
+                # we found dot and the version is valid
+                HAVE_DOT="YES"
+                # let doxygen create caller graphics
+                # see http://www.stack.nl/~dimitri/doxygen/manual/config.html#cfg_call_graph
+                USE_CALL_GRAPH="YES"
+                # exporting the tests to doc/Doxygen(.in)
+                AC_SUBST(HAVE_DOT)
+                AC_SUBST(USE_CALL_GRAPH)
+            fi
+        fi
+    fi
+fi
+AM_CONDITIONAL(BUILD_DOCUMENTATION, [test "x$build_documentation" = "xyes"])
+
+AM_CONDITIONAL([HAVE_DOXYGEN],
+    [test -n "$DOXYGEN"])AM_COND_IF([HAVE_DOXYGEN],
+    [AC_CONFIG_FILES([doc/Doxyfile])])
+
+# configure options
+# __tests__
+AC_ARG_ENABLE([tests],
+              [AC_HELP_STRING([--enable-tests],
+              [Enable building the binary testsuite [default=no]])],
+              [build_tests="$enableval"],
+              [build_tests="no"])
+
+if test "x$build_tests" = "xyes"; then
+    PKG_CHECK_MODULES([CUNIT],
+                      [cunit],
+                      [have_cunit=yes
+                       AC_DEFINE(HAVE_LIBCUNIT, [1], [Define if the system has libcunit])],
+                      [have_cunit=no
+                       AC_MSG_WARN([==> You want to build the testing binary but the pkg-config file cunit.pc could not be found or installed CUnit version is too old!])
+                       AC_MSG_ERROR([==> Install the package(s) containing the development files for CUnit or disable the testing binary using --disable-tests.])
+                      ])
+fi
+AM_CONDITIONAL(HAVE_CUNIT, [test "x$CUNIT_LIBS" != "x"])
+
+# configure options
+# __examples__
+AC_ARG_ENABLE([examples],
+              [AC_HELP_STRING([--enable-examples],
+              [Enable building the example binaries [default=yes]])],
+              [build_examples="$enableval"],
+              [build_examples="yes"])
+
+if test "x$build_examples" = "xyes" -a "x$build_documentation" = "xyes"; then
+    AC_ARG_VAR([A2X], [a2x command])
+    AC_PATH_PROG([A2X], [a2x])
+    if test "x$A2X" = "x"; then
+        AC_MSG_WARN([==> You want to build the examples binaries, that is also including the respective manpages but a2x was not found!])
+        AC_MSG_ERROR([==> Install the package containg a2x (mostly asciidoc) or disable the build of the examples using --disable-examples.])
+    fi
+    build_examples="yes"
+fi
+AM_CONDITIONAL(BUILD_EXAMPLES, [test "x$build_examples" = "xyes"])
+
+# end configure options
+#######################
+
+##########################################
+# from configure options independed checks
+
+# Check for (ex)ctags binary
+# The needed ctags binary name differs on FreeBSD and Linux, on Linux
+# systems we search for 'ctags', on FreeBSD for 'exctags'
+case $host in
+    # FreeBSD has exctags from the ctags port
+    *-freebsd1*)
+    AC_ARG_VAR([CTAGS_PROG],[the 'exctags' program to use for make target 'update-map-file'])
+    AC_PATH_PROG([CTAGS_PROG],[exctags],[HAVE_CTAGS=no])
+    ;;
+
+    *)
+    # Linux distributions have exuberant-ctags
+    AC_ARG_VAR([CTAGS_PROG],[the 'ctags' program to use for make target 'update-map-file'])
+    AC_PATH_PROG([CTAGS_PROG],[ctags],[HAVE_CTAGS=no])
+    ;;
+
+esac
+
+if test "x$HAVE_CTAGS" = "xno"; then
+    AC_MSG_NOTICE([==> Note: '(ex)ctags' command not found!])
+    AC_MSG_WARN([==> Without ctags you will be unable to run the target 'update-map-file'!])
+    AC_MSG_WARN([==> This is no problem if you just want to build the library libcoap.])
+else
+    if test "`$CTAGS_PROG --help | grep '\--<LANG>-kinds'`" = ""; then
+        AC_MSG_NOTICE([==> Note: Your ctags binary does not support '--c-kinds'!])
+        AC_MSG_NOTICE([==> Most likely, you are using the GNU Emacs ctag and not exuberant ctag.])
+        AC_MSG_WARN([==> This option is required for the target 'update-map-file'.])
+        AC_MSG_WARN([==> which is not a problem if you just want to build the library libcoap.])
+    fi
+fi
+
+# Checks for header files.
+AC_CHECK_HEADERS([assert.h arpa/inet.h limits.h netdb.h netinet/in.h \
+                  stdlib.h string.h strings.h sys/socket.h sys/time.h \
+                  time.h unistd.h sys/unistd.h syslog.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_TYPE_SIZE_T
+AC_TYPE_SSIZE_T
+
+# Checks for library functions.
+AC_CHECK_FUNCS([memset select socket strcasecmp strrchr getaddrinfo \
+                strnlen malloc])
+
+# Check if -lsocket -lnsl is required (specifically Solaris)
+AC_SEARCH_LIBS([socket], [socket])
+AC_SEARCH_LIBS([inet_ntop], [nsl])
+
+# Check if clock_gettime() requires librt, when available
+AC_SEARCH_LIBS([clock_gettime], [rt])
+
+AC_MSG_CHECKING([operating system])
+
+# Set up here some extra platform depended defines and variables.
+# The "ADDITIONAL_CFLAGS" is need as this stand-alone definition
+# for the doxygen part.
+case $host in
+    *-linux* | *-uclinux*)
+    AC_MSG_RESULT([Linux])
+    ADDITIONAL_CFLAGS="-D_GNU_SOURCE -DWITH_POSIX"
+
+    # Not yet needed but if some code definitions have to depend on the platform.
+    #AC_DEFINE(OS_LINUX, 1, [Linux backend])
+    #AC_SUBST(OS_LINUX)
+    ;;
+
+    *-solaris*)
+    AC_MSG_RESULT([Solaris])
+    # set _XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED to enable XPG4v2 (POSIX 2004)
+    # set __EXTENSION__ to shut up feature test macros that restrict -std=c99
+    # to only C99 (and nothing newer)
+    ADDITIONAL_CFLAGS="-D_XOPEN_SOURCE=600 -D_XOPEN_SOURCE_EXTENDED=600 -D__EXTENSIONS__=1 -DWITH_POSIX"
+    ;;
+
+    *-darwin*)
+    AC_MSG_RESULT([Darwin])
+    ADDITIONAL_CFLAGS="-D_GNU_SOURCE -DWITH_POSIX"
+
+    AC_DEFINE(__APPLE_USE_RFC_3542, 1, [Define this to 1 for ancillary data on MacOS])
+
+    # Not yet needed but if some code definitions have to depend on the platform.
+    #AC_DEFINE(OS_MACOS, 1, [MacOS backend])
+    #AC_SUBST(OS_MACOS)
+    ;;
+
+    *-freebsd1*)
+    AC_MSG_RESULT([FreeBSD-1x])
+    ADDITIONAL_CFLAGS="-D_GNU_SOURCE -DWITH_POSIX"
+    ;;
+
+    *kfreebsd*)
+    AC_MSG_RESULT([kFreeBSD])
+    ADDITIONAL_CFLAGS="-D_GNU_SOURCE -DWITH_POSIX"
+    ;;
+
+    *)
+    AC_MSG_WARN([==> Currently unsupported operating system '${host}' !])
+    AC_MSG_ERROR([==> If you can provide patches to support your operating system please write to 'libcoap-developers@lists.sourceforge.net'.])
+esac
+
+# Exporting the PREDEFINED_CFLAGS definition
+PREDEFINED_CFLAGS=`echo $ADDITIONAL_CFLAGS | $SED -e 's/-D//g'`
+AC_SUBST(PREDEFINED_CFLAGS)
+
+# And finaly combining the CFLAGS together ...
+CFLAGS="$CFLAGS $ADDITIONAL_CFLAGS"
+
+# Override the various template files, currently just makefiles and the
+# pkgconfig *.pc file.
+# Later if the API version is changing dont forget to change the
+# libcoap-$LIBCOAP_API_VERSION.pc.in file too!! You will have to change
+# the 'Cflags' variable to something like
+#     Cflags: -I${includedir}/coap-@LIBCOAP_API_VERSION@
+#
+AC_CONFIG_FILES([
+Makefile
+doc/Makefile
+examples/Makefile
+examples/coap-client.txt
+examples/coap-server.txt
+examples/coap-rd.txt
+include/coap/coap.h
+tests/Makefile
+libcoap-$LIBCOAP_API_VERSION.pc:libcoap-$LIBCOAP_API_VERSION.pc.in
+])
+
+AC_OUTPUT
+
+AC_MSG_RESULT([
+libcoap configuration summary:
+      libcoap package version : "$PACKAGE_VERSION"
+      libcoap library version : "$LIBCOAP_SO_VERSION"
+      libcoap API version     : "$LIBCOAP_API_VERSION"
+      host system             : "$host"]);
+if test "x$build_documentation" = "xyes" -a "x$DOXYGEN" != "x"; then
+    AC_MSG_RESULT([      build documentation     : "yes"])
+    AC_MSG_RESULT([          --> Doxygen around  : "yes" ($DOXYGEN $doxygen_version)])
+    if test "x$DOT" = "x"; then
+        AC_MSG_RESULT([             -->  dot around  : "no" (DOT not found!)])
+    else
+        AC_MSG_RESULT([             -->  dot around  : "yes" ($DOT $dot_version)])
+    fi
+else
+    if test "x$build_documentation" = "xno"; then
+        AC_MSG_RESULT([      build documentation     : "no"])
+    fi
+fi
+if test "x$build_tests" = "xyes"; then
+    AC_MSG_RESULT([      build unit test binary  : "yes"])
+else
+    AC_MSG_RESULT([      build unit test binary  : "no"])
+fi
+if test "x$build_examples" = "xyes"; then
+    AC_MSG_RESULT([      build examples          : "yes"])
+    if test "x$A2X" != "x"; then
+        AC_MSG_RESULT([             -->  use a2x     : "yes" ($A2X)])
+    else
+        AC_MSG_RESULT([             -->  use a2x     : "no"])
+    fi
+else
+    AC_MSG_RESULT([      build examples          : "no"])
+fi
diff --git a/components/coap/libcoap/doc/Doxyfile.in b/components/coap/libcoap/doc/Doxyfile.in
new file mode 100644
index 00000000..e7639ff6
--- /dev/null
+++ b/components/coap/libcoap/doc/Doxyfile.in
@@ -0,0 +1,2354 @@
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME           = @PACKAGE_NAME@
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER         = @PACKAGE_VERSION@
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       =
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS         = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES    = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES        = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC  = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS               = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT                  = @top_srcdir@/src \
+                         @top_srcdir@/include/coap
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                = @top_srcdir@/src/coap_io_lwip.c \
+                         @top_srcdir@/include/coap/lwippools.h
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER         = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS        = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS       = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX     = NO
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET        = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME  = libcoap build system
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP      = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE               =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION           =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI           = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING     =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS     =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE       =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empy string,
+# for the replacement values of the other commands the user is refered to
+# HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER           =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES      =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE        = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES     = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION          = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR             =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT             = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK       = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT         = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED             = @PREDEFINED_CFLAGS@
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS        = YES
+
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES         = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS         = @HAVE_DOT@
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH               =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT               = @HAVE_DOT@
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS        = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME           =
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH          = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH             = @USE_CALL_GRAPH@
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH           = @USE_CALL_GRAPH@
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT       = svg
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG        = @HAVE_DOT@
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS           =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS           =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH      =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP            = YES
diff --git a/components/coap/libcoap/doc/Makefile.am b/components/coap/libcoap/doc/Makefile.am
new file mode 100644
index 00000000..27cb237a
--- /dev/null
+++ b/components/coap/libcoap/doc/Makefile.am
@@ -0,0 +1,42 @@
+# doc/Makefile.am
+#
+# Copyright (C)      2015 Carsten Schoenert <c.schoenert@t-online.de>
+#
+# This file is part of the CoAP C library libcoap. Please see README and
+# COPYING for terms of use.
+
+
+# We can only perfom the targets in this directory if doxygen is present.
+
+if HAVE_DOXYGEN
+
+CLEANFILES = \
+  doxygen_sqlite3.db
+
+
+# This target has no check for automated install data! It's simply assumed that
+# that the 'all' target is running before, in short: the user has to run first
+# 'make' before running 'make install'!
+install-data-am:
+	@if [ ! -d $(top_builddir)/doc/html ]; then \
+		echo ;\
+		echo "     No install data in '$(top_builddir)/doc/html'found! Please run 'make all' first." ;\
+		echo ;\
+		exit 1 ;\
+	fi
+	$(MKDIR_P) $(DESTDIR)$(htmldir)/html || exit 1
+	cp -a $(top_builddir)/doc/html $(DESTDIR)$(htmldir)
+	find $(DESTDIR)$(htmldir) -type f -name "*.md5" -exec rm {} \;
+
+uninstall-am:
+	-rm -rf $(DESTDIR)$(htmldir)/html
+
+all:
+	$(DOXYGEN) Doxyfile
+
+clean-local:
+	rm -rf $(top_builddir)/doc/html
+
+distclean-local: clean-local
+
+endif # HAVE_DOXYGEN
diff --git a/components/coap/libcoap/examples/Makefile.am b/components/coap/libcoap/examples/Makefile.am
new file mode 100644
index 00000000..087aef4b
--- /dev/null
+++ b/components/coap/libcoap/examples/Makefile.am
@@ -0,0 +1,44 @@
+# examples/Makefile.am
+#
+# Copyright (C)      2015 Carsten Schoenert <c.schoenert@t-online.de>
+#
+# This file is part of the CoAP C library libcoap. Please see README and
+# COPYING for terms of use.
+
+# just do nothing if 'BUILD_EXAMPLES' isn't defined
+if BUILD_EXAMPLES
+
+# picking up the default warning CFLAGS into AM_CFLAGS
+AM_CFLAGS = -isystem$(top_builddir)/include/coap -I$(top_srcdir)/include/coap $(WARNING_CFLAGS) -std=c99
+
+# etsi_iot_01 and tiny are missing
+bin_PROGRAMS = coap-client coap-server coap-rd
+
+coap_client_SOURCES = client.c coap_list.c
+coap_client_LDADD = $(top_builddir)/.libs/libcoap-$(LIBCOAP_API_VERSION).la
+
+coap_server_SOURCES = coap-server.c
+coap_server_LDADD = $(top_builddir)/.libs/libcoap-$(LIBCOAP_API_VERSION).la
+
+coap_rd_SOURCES = coap-rd.c
+coap_rd_LDADD = $(top_builddir)/.libs/libcoap-$(LIBCOAP_API_VERSION).la
+
+# build manuals only if 'BUILD_DOCUMENTATION' is defined
+if BUILD_DOCUMENTATION
+
+# building the manpages
+TXT5 = coap-client.txt \
+       coap-rd.txt \
+       coap-server.txt
+
+MAN5 = $(TXT5:%.txt=%.5)
+
+man5_MANS = $(MAN5)
+
+.txt.5:
+	$(A2X) --doctype manpage --format manpage $<
+
+CLEANFILES = *.5
+endif # BUILD_DOCUMENTATION
+
+endif # BUILD_EXAMPLES
diff --git a/components/coap/libcoap/examples/README.etsi_iot b/components/coap/libcoap/examples/README.etsi_iot
new file mode 100644
index 00000000..9a5a58f4
--- /dev/null
+++ b/components/coap/libcoap/examples/README.etsi_iot
@@ -0,0 +1,43 @@
+This README documents the test cases supported for the 1st ETSI CoAP
+plugtest on March 24/25 in Paris, France.
+<http://www.etsi.org/plugtests/coap/coap.htm>
+
+Legend: 
+  [+] full support
+  [o] partial support
+  [-] no support
+  [?] needs check
+  [ ] has open issues
+
+Mandatory Tests
+
+[+] TD_COAP_CORE_01 Perform GET transaction (CON mode)
+[+] TD_COAP_CORE_02 Perform POST transaction (CON mode)
+[+] TD_COAP_CORE_03 Perform PUT transaction (CON mode)
+[+] TD_COAP_CORE_04 Perform DELETE transaction (CON mode)
+[+] TD_COAP_CORE_05 Perform GET transaction (NON mode)
+[+] TD_COAP_CORE_06 Perform POST transaction (NON mode)
+[+] TD_COAP_CORE_07 Perform PUT transaction (NON mode)
+[+] TD_COAP_CORE_08 Perform DELETE transaction (NON mode)
+[+] TD_COAP_CORE_09 Perform GET transaction with delayed response (CON mode, no piggyback)
+[+] TD_COAP_CORE_10 Handle request containing Token option
+[+] TD_COAP_CORE_11 Handle request not containing Token option
+[+] TD_COAP_CORE_12 Handle request containing several Uri-Path options
+[+] TD_COAP_CORE_13 Handle request containing several Uri-Query options
+[?] TD_COAP_CORE_14 Interoperate in lossy context (CON mode, piggybacked response)
+[?] TD_COAP_CORE_15 Interoperate in lossy context (CON mode, delayed response)
+
+Optional Tests
+
+[ ] TD_COAP_LINK_01 Access to well-known interface for resource discovery
+[-] TD_COAP_LINK_02 Use filtered requests for limiting discovery results
+[+] TD_COAP_BLOCK_01 Handle GET blockwise transfer for large resource (early negotiation)
+[+] TD_COAP_BLOCK_02 Handle GET blockwise transfer for large resource (late negotiation)
+[-] TD_COAP_BLOCK_03 Handle PUT blockwise transfer for large resource
+[-] TD_COAP_BLOCK_04 Handle POST blockwise transfer for large resource
+[-] TD_COAP_OBS_01 Handle resource observation
+[-] TD_COAP_OBS_02 Stop resource observation
+[-] TD_COAP_OBS_03 Client detection of deregistration (Max-Age)
+[-] TD_COAP_OBS_04 Server detection of deregistration (client OFF)
+[-] TD_COAP_OBS_05 Server detection of deregistration (explicit RST)
+
diff --git a/components/coap/libcoap/examples/client.c b/components/coap/libcoap/examples/client.c
new file mode 100644
index 00000000..c5457a7a
--- /dev/null
+++ b/components/coap/libcoap/examples/client.c
@@ -0,0 +1,1305 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+
+/* coap-client -- simple CoAP client
+ *
+ * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms of
+ * use.
+ */
+
+#include "coap_config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "coap.h"
+#include "coap_list.h"
+
+int flags = 0;
+
+static unsigned char _token_data[8];
+str the_token = { 0, _token_data };
+
+#define FLAGS_BLOCK 0x01
+
+static coap_list_t *optlist = NULL;
+/* Request URI.
+ * TODO: associate the resources with transaction id and make it expireable */
+static coap_uri_t uri;
+static str proxy = { 0, NULL };
+static unsigned short proxy_port = COAP_DEFAULT_PORT;
+
+/* reading is done when this flag is set */
+static int ready = 0;
+
+static str output_file = { 0, NULL };   /* output file name */
+static FILE *file = NULL;               /* output file stream */
+
+static str payload = { 0, NULL };       /* optional payload to send */
+
+unsigned char msgtype = COAP_MESSAGE_CON; /* usually, requests are sent confirmable */
+
+typedef unsigned char method_t;
+method_t method = 1;                    /* the method we are using in our requests */
+
+coap_block_t block = { .num = 0, .m = 0, .szx = 6 };
+
+unsigned int wait_seconds = 90;         /* default timeout in seconds */
+coap_tick_t max_wait;                   /* global timeout (changed by set_timeout()) */
+
+unsigned int obs_seconds = 30;          /* default observe time */
+coap_tick_t obs_wait = 0;               /* timeout for current subscription */
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+static inline void
+set_timeout(coap_tick_t *timer, const unsigned int seconds) {
+  coap_ticks(timer);
+  *timer += seconds * COAP_TICKS_PER_SECOND;
+}
+
+static int
+append_to_output(const unsigned char *data, size_t len) {
+  size_t written;
+
+  if (!file) {
+    if (!output_file.s || (output_file.length && output_file.s[0] == '-'))
+      file = stdout;
+    else {
+      if (!(file = fopen((char *)output_file.s, "w"))) {
+        perror("fopen");
+        return -1;
+      }
+    }
+  }
+
+  do {
+    written = fwrite(data, 1, len, file);
+    len -= written;
+    data += written;
+  } while ( written && len );
+  fflush(file);
+
+  return 0;
+}
+
+static void
+close_output(void) {
+  if (file) {
+
+    /* add a newline before closing in case were writing to stdout */
+    if (!output_file.s || (output_file.length && output_file.s[0] == '-'))
+      fwrite("\n", 1, 1, file);
+
+    fflush(file);
+    fclose(file);
+  }
+}
+
+static int
+order_opts(void *a, void *b) {
+  coap_option *o1, *o2;
+
+  if (!a || !b)
+    return a < b ? -1 : 1;
+
+  o1 = (coap_option *)(((coap_list_t *)a)->data);
+  o2 = (coap_option *)(((coap_list_t *)b)->data);
+
+  return (COAP_OPTION_KEY(*o1) < COAP_OPTION_KEY(*o2))
+    ? -1
+    : (COAP_OPTION_KEY(*o1) != COAP_OPTION_KEY(*o2));
+}
+
+static coap_pdu_t *
+coap_new_request(coap_context_t *ctx,
+                 method_t m,
+                 coap_list_t **options,
+                 unsigned char *data,
+                 size_t length) {
+  coap_pdu_t *pdu;
+  coap_list_t *opt;
+
+  if ( ! ( pdu = coap_new_pdu() ) )
+    return NULL;
+
+  pdu->hdr->type = msgtype;
+  pdu->hdr->id = coap_new_message_id(ctx);
+  pdu->hdr->code = m;
+
+  pdu->hdr->token_length = the_token.length;
+  if ( !coap_add_token(pdu, the_token.length, the_token.s)) {
+    debug("cannot add token to request\n");
+  }
+
+  coap_show_pdu(pdu);
+
+  if (options) {
+    /* sort options for delta encoding */
+    LL_SORT((*options), order_opts);
+
+    LL_FOREACH((*options), opt) {
+      coap_option *o = (coap_option *)(opt->data);
+      coap_add_option(pdu,
+                      COAP_OPTION_KEY(*o),
+                      COAP_OPTION_LENGTH(*o),
+                      COAP_OPTION_DATA(*o));
+    }
+  }
+
+  if (length) {
+    if ((flags & FLAGS_BLOCK) == 0)
+      coap_add_data(pdu, length, data);
+    else
+      coap_add_block(pdu, length, data, block.num, block.szx);
+  }
+
+  return pdu;
+}
+
+static coap_tid_t
+clear_obs(coap_context_t *ctx,
+          const coap_endpoint_t *local_interface,
+          const coap_address_t *remote) {
+  coap_pdu_t *pdu;
+  coap_list_t *option;
+  coap_tid_t tid = COAP_INVALID_TID;
+  unsigned char buf[2];
+
+  /* create bare PDU w/o any option  */
+  pdu = coap_pdu_init(msgtype,
+                      COAP_REQUEST_GET,
+                      coap_new_message_id(ctx),
+                      COAP_MAX_PDU_SIZE);
+
+  if (!pdu) {
+    return tid;
+  }
+
+  if (!coap_add_token(pdu, the_token.length, the_token.s)) {
+    coap_log(LOG_CRIT, "cannot add token");
+    goto error;
+  }
+
+  for (option = optlist; option; option = option->next ) {
+    coap_option *o = (coap_option *)(option->data);
+    if (COAP_OPTION_KEY(*o) == COAP_OPTION_URI_HOST) {
+      if (!coap_add_option(pdu,
+          COAP_OPTION_KEY(*o),
+          COAP_OPTION_LENGTH(*o),
+          COAP_OPTION_DATA(*o))) {
+        goto error;
+      }
+      break;
+    }
+  }
+
+  if (!coap_add_option(pdu,
+      COAP_OPTION_OBSERVE,
+      coap_encode_var_bytes(buf, COAP_OBSERVE_CANCEL),
+      buf)) {
+    coap_log(LOG_CRIT, "cannot add option Observe: %u", COAP_OBSERVE_CANCEL);
+    goto error;
+  }
+
+  for (option = optlist; option; option = option->next ) {
+    coap_option *o = (coap_option *)(option->data);
+    switch (COAP_OPTION_KEY(*o)) {
+    case COAP_OPTION_URI_PORT :
+    case COAP_OPTION_URI_PATH :
+    case COAP_OPTION_URI_QUERY :
+      if (!coap_add_option (pdu,
+                            COAP_OPTION_KEY(*o),
+                            COAP_OPTION_LENGTH(*o),
+                            COAP_OPTION_DATA(*o))) {
+        goto error;
+      }
+      break;
+      default:
+      ;
+    }
+  }
+
+  coap_show_pdu(pdu);
+
+  if (pdu->hdr->type == COAP_MESSAGE_CON)
+    tid = coap_send_confirmed(ctx, local_interface, remote, pdu);
+  else
+    tid = coap_send(ctx, local_interface, remote, pdu);
+
+  if (tid == COAP_INVALID_TID) {
+    debug("clear_obs: error sending new request");
+    coap_delete_pdu(pdu);
+  } else if (pdu->hdr->type != COAP_MESSAGE_CON)
+    coap_delete_pdu(pdu);
+
+  return tid;
+ error:
+
+  coap_delete_pdu(pdu);
+  return tid;
+}
+
+static int
+resolve_address(const str *server, struct sockaddr *dst) {
+
+  struct addrinfo *res, *ainfo;
+  struct addrinfo hints;
+  static char addrstr[256];
+  int error, len=-1;
+
+  memset(addrstr, 0, sizeof(addrstr));
+  if (server->length)
+    memcpy(addrstr, server->s, server->length);
+  else
+    memcpy(addrstr, "localhost", 9);
+
+  memset ((char *)&hints, 0, sizeof(hints));
+  hints.ai_socktype = SOCK_DGRAM;
+  hints.ai_family = AF_UNSPEC;
+
+  error = getaddrinfo(addrstr, NULL, &hints, &res);
+
+  if (error != 0) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
+    return error;
+  }
+
+  for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
+    switch (ainfo->ai_family) {
+    case AF_INET6:
+    case AF_INET:
+      len = ainfo->ai_addrlen;
+      memcpy(dst, ainfo->ai_addr, len);
+      goto finish;
+    default:
+      ;
+    }
+  }
+
+ finish:
+  freeaddrinfo(res);
+  return len;
+}
+
+#define HANDLE_BLOCK1(Pdu)                                        \
+  ((method == COAP_REQUEST_PUT || method == COAP_REQUEST_POST) && \
+   ((flags & FLAGS_BLOCK) == 0) &&                                \
+   ((Pdu)->hdr->code == COAP_RESPONSE_CODE(201) ||                \
+    (Pdu)->hdr->code == COAP_RESPONSE_CODE(204)))
+
+static inline int
+check_token(coap_pdu_t *received) {
+  return received->hdr->token_length == the_token.length &&
+    memcmp(received->hdr->token, the_token.s, the_token.length) == 0;
+}
+
+static void
+message_handler(struct coap_context_t *ctx,
+                const coap_endpoint_t *local_interface,
+                const coap_address_t *remote,
+                coap_pdu_t *sent,
+                coap_pdu_t *received,
+                const coap_tid_t id UNUSED_PARAM) {
+
+  coap_pdu_t *pdu = NULL;
+  coap_opt_t *block_opt;
+  coap_opt_iterator_t opt_iter;
+  unsigned char buf[4];
+  coap_list_t *option;
+  size_t len;
+  unsigned char *databuf;
+  coap_tid_t tid;
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+    debug("** process incoming %d.%02d response:\n",
+          (received->hdr->code >> 5), received->hdr->code & 0x1F);
+    coap_show_pdu(received);
+  }
+#endif
+
+  /* check if this is a response to our original request */
+  if (!check_token(received)) {
+    /* drop if this was just some message, or send RST in case of notification */
+    if (!sent && (received->hdr->type == COAP_MESSAGE_CON ||
+                  received->hdr->type == COAP_MESSAGE_NON))
+      coap_send_rst(ctx, local_interface, remote, received);
+    return;
+  }
+
+  if (received->hdr->type == COAP_MESSAGE_RST) {
+    info("got RST\n");
+    return;
+  }
+
+  /* output the received data, if any */
+  if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) {
+
+    /* set obs timer if we have successfully subscribed a resource */
+    if (sent && coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter)) {
+      debug("observation relationship established, set timeout to %d\n", obs_seconds);
+      set_timeout(&obs_wait, obs_seconds);
+    }
+
+    /* Got some data, check if block option is set. Behavior is undefined if
+     * both, Block1 and Block2 are present. */
+    block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
+    if (block_opt) { /* handle Block2 */
+      unsigned short blktype = opt_iter.type;
+
+      /* TODO: check if we are looking at the correct block number */
+      if (coap_get_data(received, &len, &databuf))
+        append_to_output(databuf, len);
+
+      if(COAP_OPT_BLOCK_MORE(block_opt)) {
+        /* more bit is set */
+        debug("found the M bit, block size is %u, block nr. %u\n",
+              COAP_OPT_BLOCK_SZX(block_opt),
+              coap_opt_block_num(block_opt));
+
+        /* create pdu with request for next block */
+        pdu = coap_new_request(ctx, method, NULL, NULL, 0); /* first, create bare PDU w/o any option  */
+        if ( pdu ) {
+          /* add URI components from optlist */
+          for (option = optlist; option; option = option->next ) {
+            coap_option *o = (coap_option *)(option->data);
+            switch (COAP_OPTION_KEY(*o)) {
+              case COAP_OPTION_URI_HOST :
+              case COAP_OPTION_URI_PORT :
+              case COAP_OPTION_URI_PATH :
+              case COAP_OPTION_URI_QUERY :
+                coap_add_option (pdu,
+                                 COAP_OPTION_KEY(*o),
+                                 COAP_OPTION_LENGTH(*o),
+                                 COAP_OPTION_DATA(*o));
+                break;
+              default:
+                ;     /* skip other options */
+            }
+          }
+
+          /* finally add updated block option from response, clear M bit */
+          /* blocknr = (blocknr & 0xfffffff7) + 0x10; */
+          debug("query block %d\n", (coap_opt_block_num(block_opt) + 1));
+          coap_add_option(pdu,
+                          blktype,
+                          coap_encode_var_bytes(buf,
+                                 ((coap_opt_block_num(block_opt) + 1) << 4) |
+                                  COAP_OPT_BLOCK_SZX(block_opt)), buf);
+
+          if (pdu->hdr->type == COAP_MESSAGE_CON)
+            tid = coap_send_confirmed(ctx, local_interface, remote, pdu);
+          else
+            tid = coap_send(ctx, local_interface, remote, pdu);
+
+          if (tid == COAP_INVALID_TID) {
+            debug("message_handler: error sending new request");
+            coap_delete_pdu(pdu);
+          } else {
+            set_timeout(&max_wait, wait_seconds);
+            if (pdu->hdr->type != COAP_MESSAGE_CON)
+              coap_delete_pdu(pdu);
+          }
+
+          return;
+        }
+      }
+    } else { /* no Block2 option */
+      block_opt = coap_check_option(received, COAP_OPTION_BLOCK1, &opt_iter);
+
+      if (block_opt) { /* handle Block1 */
+        unsigned int szx = COAP_OPT_BLOCK_SZX(block_opt);
+        unsigned int num = coap_opt_block_num(block_opt);
+        debug("found Block1 option, block size is %u, block nr. %u\n", szx, num);
+        if (szx != block.szx) {
+          unsigned int bytes_sent = ((block.num + 1) << (block.szx + 4));
+          if (bytes_sent % (1 << (szx + 4)) == 0) {
+            /* Recompute the block number of the previous packet given the new block size */
+            block.num = (bytes_sent >> (szx + 4)) - 1;
+            block.szx = szx;
+            debug("new Block1 size is %u, block number %u completed\n", (1 << (block.szx + 4)), block.num);
+          } else {
+            debug("ignoring request to increase Block1 size, "
+            "next block is not aligned on requested block size boundary. "
+            "(%u x %u mod %u = %u != 0)\n",
+                  block.num + 1, (1 << (block.szx + 4)), (1 << (szx + 4)),
+                  bytes_sent % (1 << (szx + 4)));
+          }
+        }
+
+        if (payload.length <= (block.num+1) * (1 << (block.szx + 4))) {
+          debug("upload ready\n");
+          ready = 1;
+          return;
+        }
+
+        /* create pdu with request for next block */
+        pdu = coap_new_request(ctx, method, NULL, NULL, 0); /* first, create bare PDU w/o any option  */
+        if (pdu) {
+
+          /* add URI components from optlist */
+          for (option = optlist; option; option = option->next ) {
+            coap_option *o = (coap_option *)(option->data);
+            switch (COAP_OPTION_KEY(*o)) {
+              case COAP_OPTION_URI_HOST :
+              case COAP_OPTION_URI_PORT :
+              case COAP_OPTION_URI_PATH :
+              case COAP_OPTION_CONTENT_FORMAT :
+              case COAP_OPTION_URI_QUERY :
+                coap_add_option (pdu,
+                                 COAP_OPTION_KEY(*o),
+                                 COAP_OPTION_LENGTH(*o),
+                                 COAP_OPTION_DATA(*o));
+                break;
+              default:
+              ;     /* skip other options */
+            }
+          }
+
+          /* finally add updated block option from response, clear M bit */
+          /* blocknr = (blocknr & 0xfffffff7) + 0x10; */
+          block.num++;
+          block.m = ((block.num+1) * (1 << (block.szx + 4)) < payload.length);
+
+          debug("send block %d\n", block.num);
+          coap_add_option(pdu,
+                          COAP_OPTION_BLOCK1,
+                          coap_encode_var_bytes(buf,
+                          (block.num << 4) | (block.m << 3) | block.szx), buf);
+
+          coap_add_block(pdu,
+                         payload.length,
+                         payload.s,
+                         block.num,
+                         block.szx);
+          coap_show_pdu(pdu);
+          if (pdu->hdr->type == COAP_MESSAGE_CON)
+            tid = coap_send_confirmed(ctx, local_interface, remote, pdu);
+          else
+            tid = coap_send(ctx, local_interface, remote, pdu);
+
+          if (tid == COAP_INVALID_TID) {
+            debug("message_handler: error sending new request");
+            coap_delete_pdu(pdu);
+          } else {
+            set_timeout(&max_wait, wait_seconds);
+            if (pdu->hdr->type != COAP_MESSAGE_CON)
+              coap_delete_pdu(pdu);
+          }
+
+          return;
+        }
+      } else {
+        /* There is no block option set, just read the data and we are done. */
+        if (coap_get_data(received, &len, &databuf))
+        append_to_output(databuf, len);
+      }
+    }
+  } else {      /* no 2.05 */
+
+    /* check if an error was signaled and output payload if so */
+    if (COAP_RESPONSE_CLASS(received->hdr->code) >= 4) {
+      fprintf(stderr, "%d.%02d",
+              (received->hdr->code >> 5), received->hdr->code & 0x1F);
+      if (coap_get_data(received, &len, &databuf)) {
+        fprintf(stderr, " ");
+        while(len--)
+        fprintf(stderr, "%c", *databuf++);
+      }
+      fprintf(stderr, "\n");
+    }
+
+  }
+
+  /* finally send new request, if needed */
+  if (pdu && coap_send(ctx, local_interface, remote, pdu) == COAP_INVALID_TID) {
+    debug("message_handler: error sending response");
+  }
+  coap_delete_pdu(pdu);
+
+  /* our job is done, we can exit at any time */
+  ready = coap_check_option(received, COAP_OPTION_SUBSCRIPTION, &opt_iter) == NULL;
+}
+
+static void
+usage( const char *program, const char *version) {
+  const char *p;
+
+  p = strrchr( program, '/' );
+  if ( p )
+    program = ++p;
+
+  fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
+     "(c) 2010-2015 Olaf Bergmann <bergmann@tzi.org>\n\n"
+     "usage: %s [-A type...] [-t type] [-b [num,]size] [-B seconds] [-e text]\n"
+     "\t\t[-m method] [-N] [-o file] [-P addr[:port]] [-p port]\n"
+     "\t\t[-s duration] [-O num,text] [-T string] [-v num] [-a addr] [-U] URI\n\n"
+     "\tURI can be an absolute or relative coap URI,\n"
+     "\t-a addr\tthe local interface address to use\n"
+     "\t-A type...\taccepted media types as comma-separated list of\n"
+     "\t\t\tsymbolic or numeric values\n"
+     "\t-t type\t\tcontent format for given resource for PUT/POST\n"
+     "\t-b [num,]size\tblock size to be used in GET/PUT/POST requests\n"
+     "\t       \t\t(value must be a multiple of 16 not larger than 1024)\n"
+     "\t       \t\tIf num is present, the request chain will start at\n"
+     "\t       \t\tblock num\n"
+     "\t-B seconds\tbreak operation after waiting given seconds\n"
+     "\t\t\t(default is %d)\n"
+     "\t-e text\t\tinclude text as payload (use percent-encoding for\n"
+     "\t\t\tnon-ASCII characters)\n"
+     "\t-f file\t\tfile to send with PUT/POST (use '-' for STDIN)\n"
+     "\t-m method\trequest method (get|put|post|delete), default is 'get'\n"
+     "\t-N\t\tsend NON-confirmable message\n"
+     "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n"
+     "\t-p port\t\tlisten on specified port\n"
+     "\t-s duration\tsubscribe for given duration [s]\n"
+     "\t-v num\t\tverbosity level (default: 3)\n"
+     "\t-O num,text\tadd option num with contents text to request\n"
+     "\t-P addr[:port]\tuse proxy (automatically adds Proxy-Uri option to\n"
+     "\t\t\trequest)\n"
+     "\t-T token\tinclude specified token\n"
+     "\t-U\t\tnever include Uri-Host or Uri-Port options\n"
+     "\n"
+     "examples:\n"
+     "\tcoap-client -m get coap://[::1]/\n"
+     "\tcoap-client -m get coap://[::1]/.well-known/core\n"
+     "\tcoap-client -m get -T cafe coap://[::1]/time\n"
+     "\techo 1000 | coap-client -m put -T cafe coap://[::1]/time -f -\n"
+     ,program, version, program, wait_seconds);
+}
+
+static coap_list_t *
+new_option_node(unsigned short key, unsigned int length, unsigned char *data) {
+  coap_list_t *node;
+
+  node = coap_malloc(sizeof(coap_list_t) + sizeof(coap_option) + length);
+
+  if (node) {
+    coap_option *option;
+    option = (coap_option *)(node->data);
+    COAP_OPTION_KEY(*option) = key;
+    COAP_OPTION_LENGTH(*option) = length;
+    memcpy(COAP_OPTION_DATA(*option), data, length);
+  } else {
+    coap_log(LOG_DEBUG, "new_option_node: malloc\n");
+  }
+
+  return node;
+}
+
+typedef struct {
+  unsigned char code;
+  char *media_type;
+} content_type_t;
+
+static void
+cmdline_content_type(char *arg, unsigned short key) {
+  static content_type_t content_types[] = {
+    {  0, "plain" },
+    {  0, "text/plain" },
+    { 40, "link" },
+    { 40, "link-format" },
+    { 40, "application/link-format" },
+    { 41, "xml" },
+    { 41, "application/xml" },
+    { 42, "binary" },
+    { 42, "octet-stream" },
+    { 42, "application/octet-stream" },
+    { 47, "exi" },
+    { 47, "application/exi" },
+    { 50, "json" },
+    { 50, "application/json" },
+    { 60, "cbor" },
+    { 60, "application/cbor" },
+    { 255, NULL }
+  };
+  coap_list_t *node;
+  unsigned char i, value[10];
+  int valcnt = 0;
+  unsigned char buf[2];
+  char *p, *q = arg;
+
+  while (q && *q) {
+    p = strchr(q, ',');
+
+    if (isdigit(*q)) {
+      if (p)
+        *p = '\0';
+      value[valcnt++] = atoi(q);
+    } else {
+      for (i=0;
+           content_types[i].media_type &&
+           strncmp(q, content_types[i].media_type, p ? (size_t)(p-q) : strlen(q)) != 0 ;
+           ++i)
+      ;
+
+      if (content_types[i].media_type) {
+        value[valcnt] = content_types[i].code;
+        valcnt++;
+      } else {
+        warn("W: unknown content-format '%s'\n",arg);
+      }
+    }
+
+    if (!p || key == COAP_OPTION_CONTENT_TYPE)
+      break;
+
+    q = p+1;
+  }
+
+  for (i = 0; i < valcnt; ++i) {
+    node = new_option_node(key, coap_encode_var_bytes(buf, value[i]), buf);
+    if (node) {
+      LL_PREPEND(optlist, node);
+    }
+  }
+}
+
+/**
+ * Sets global URI options according to the URI passed as @p arg.
+ * This function returns 0 on success or -1 on error.
+ *
+ * @param arg             The URI string.
+ * @param create_uri_opts Flags that indicate whether Uri-Host and
+ *                        Uri-Port should be suppressed.
+ * @return 0 on success, -1 otherwise
+ */
+static int
+cmdline_uri(char *arg, int create_uri_opts) {
+  unsigned char portbuf[2];
+#define BUFSIZE 40
+  unsigned char _buf[BUFSIZE];
+  unsigned char *buf = _buf;
+  size_t buflen;
+  int res;
+
+  if (proxy.length) {   /* create Proxy-Uri from argument */
+    size_t len = strlen(arg);
+    while (len > 270) {
+      coap_insert(&optlist,
+                  new_option_node(COAP_OPTION_PROXY_URI,
+                  270,
+                  (unsigned char *)arg));
+
+      len -= 270;
+      arg += 270;
+    }
+
+    coap_insert(&optlist,
+                new_option_node(COAP_OPTION_PROXY_URI,
+                len,
+                (unsigned char *)arg));
+
+  } else {      /* split arg into Uri-* options */
+    if (coap_split_uri((unsigned char *)arg, strlen(arg), &uri) < 0) {
+      return -1;
+    }
+
+    if (uri.port != COAP_DEFAULT_PORT && create_uri_opts) {
+      coap_insert(&optlist,
+                  new_option_node(COAP_OPTION_URI_PORT,
+                  coap_encode_var_bytes(portbuf, uri.port),
+                  portbuf));
+    }
+
+    if (uri.path.length) {
+      buflen = BUFSIZE;
+      res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+
+      while (res--) {
+        coap_insert(&optlist,
+                    new_option_node(COAP_OPTION_URI_PATH,
+                    COAP_OPT_LENGTH(buf),
+                    COAP_OPT_VALUE(buf)));
+
+        buf += COAP_OPT_SIZE(buf);
+      }
+    }
+
+    if (uri.query.length) {
+      buflen = BUFSIZE;
+      buf = _buf;
+      res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+
+      while (res--) {
+        coap_insert(&optlist,
+                    new_option_node(COAP_OPTION_URI_QUERY,
+                    COAP_OPT_LENGTH(buf),
+                    COAP_OPT_VALUE(buf)));
+
+        buf += COAP_OPT_SIZE(buf);
+      }
+    }
+  }
+
+  return 0;
+}
+
+static int
+cmdline_blocksize(char *arg) {
+  unsigned short size;
+
+  again:
+  size = 0;
+  while(*arg && *arg != ',')
+    size = size * 10 + (*arg++ - '0');
+
+  if (*arg == ',') {
+    arg++;
+    block.num = size;
+    goto again;
+  }
+
+  if (size)
+    block.szx = (coap_fls(size >> 4) - 1) & 0x07;
+
+  flags |= FLAGS_BLOCK;
+  return 1;
+}
+
+/* Called after processing the options from the commandline to set
+ * Block1 or Block2 depending on method. */
+static void
+set_blocksize(void) {
+  static unsigned char buf[4];	/* hack: temporarily take encoded bytes */
+  unsigned short opt;
+  unsigned int opt_length;
+
+  if (method != COAP_REQUEST_DELETE) {
+    opt = method == COAP_REQUEST_GET ? COAP_OPTION_BLOCK2 : COAP_OPTION_BLOCK1;
+
+    block.m = (opt == COAP_OPTION_BLOCK1) &&
+      ((1u << (block.szx + 4)) < payload.length);
+
+    opt_length = coap_encode_var_bytes(buf,
+          (block.num << 4 | block.m << 3 | block.szx));
+
+    coap_insert(&optlist, new_option_node(opt, opt_length, buf));
+  }
+}
+
+static void
+cmdline_subscribe(char *arg) {
+  obs_seconds = atoi(arg);
+  coap_insert(&optlist, new_option_node(COAP_OPTION_SUBSCRIPTION, 0, NULL));
+}
+
+static int
+cmdline_proxy(char *arg) {
+  char *proxy_port_str = strrchr((const char *)arg, ':'); /* explicit port ? */
+  if (proxy_port_str) {
+    char *ipv6_delimiter = strrchr((const char *)arg, ']');
+    if (!ipv6_delimiter) {
+      if (proxy_port_str == strchr((const char *)arg, ':')) {
+        /* host:port format - host not in ipv6 hexadecimal string format */
+        *proxy_port_str++ = '\0'; /* split */
+        proxy_port = atoi(proxy_port_str);
+      }
+    } else {
+      arg = strchr((const char *)arg, '[');
+      if (!arg) return 0;
+      arg++;
+      *ipv6_delimiter = '\0'; /* split */
+      if (ipv6_delimiter + 1 == proxy_port_str++) {
+        /* [ipv6 address]:port */
+        proxy_port = atoi(proxy_port_str);
+      }
+    }
+  }
+
+  proxy.length = strlen(arg);
+  if ( (proxy.s = coap_malloc(proxy.length + 1)) == NULL) {
+    proxy.length = 0;
+    return 0;
+  }
+
+  memcpy(proxy.s, arg, proxy.length+1);
+  return 1;
+}
+
+static inline void
+cmdline_token(char *arg) {
+  strncpy((char *)the_token.s, arg, min(sizeof(_token_data), strlen(arg)));
+  the_token.length = strlen(arg);
+}
+
+static void
+cmdline_option(char *arg) {
+  unsigned int num = 0;
+
+  while (*arg && *arg != ',') {
+    num = num * 10 + (*arg - '0');
+    ++arg;
+  }
+  if (*arg == ',')
+    ++arg;
+
+  coap_insert(&optlist,
+              new_option_node(num, strlen(arg), (unsigned char *)arg));
+}
+
+/**
+ * Calculates decimal value from hexadecimal ASCII character given in
+ * @p c. The caller must ensure that @p c actually represents a valid
+ * heaxdecimal character, e.g. with isxdigit(3).
+ *
+ * @hideinitializer
+ */
+#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
+
+/**
+ * Decodes percent-encoded characters while copying the string @p seg
+ * of size @p length to @p buf. The caller of this function must
+ * ensure that the percent-encodings are correct (i.e. the character
+ * '%' is always followed by two hex digits. and that @p buf provides
+ * sufficient space to hold the result. This function is supposed to
+ * be called by make_decoded_option() only.
+ *
+ * @param seg     The segment to decode and copy.
+ * @param length  Length of @p seg.
+ * @param buf     The result buffer.
+ */
+static void
+decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
+
+  while (length--) {
+
+    if (*seg == '%') {
+      *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
+
+      seg += 2; length -= 2;
+    } else {
+      *buf = *seg;
+    }
+
+    ++buf; ++seg;
+  }
+}
+
+/**
+ * Runs through the given path (or query) segment and checks if
+ * percent-encodings are correct. This function returns @c -1 on error
+ * or the length of @p s when decoded.
+ */
+static int
+check_segment(const unsigned char *s, size_t length) {
+
+  size_t n = 0;
+
+  while (length) {
+    if (*s == '%') {
+      if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
+        return -1;
+
+      s += 2;
+      length -= 2;
+    }
+
+    ++s; ++n; --length;
+  }
+
+  return n;
+}
+
+static int
+cmdline_input(char *text, str *buf) {
+  int len;
+  len = check_segment((unsigned char *)text, strlen(text));
+
+  if (len < 0)
+    return 0;
+
+  buf->s = (unsigned char *)coap_malloc(len);
+  if (!buf->s)
+    return 0;
+
+  buf->length = len;
+  decode_segment((unsigned char *)text, strlen(text), buf->s);
+  return 1;
+}
+
+static int
+cmdline_input_from_file(char *filename, str *buf) {
+  FILE *inputfile = NULL;
+  ssize_t len;
+  int result = 1;
+  struct stat statbuf;
+
+  if (!filename || !buf)
+    return 0;
+
+  if (filename[0] == '-' && !filename[1]) { /* read from stdin */
+    buf->length = 20000;
+    buf->s = (unsigned char *)coap_malloc(buf->length);
+    if (!buf->s)
+      return 0;
+
+    inputfile = stdin;
+  } else {
+    /* read from specified input file */
+    inputfile = fopen(filename, "r");
+    if ( !inputfile ) {
+      perror("cmdline_input_from_file: fopen");
+      return 0;
+    }
+
+    if (fstat(fileno(inputfile), &statbuf) < 0) {
+      perror("cmdline_input_from_file: stat");
+      fclose(inputfile);
+      return 0;
+    }
+
+    buf->length = statbuf.st_size;
+    buf->s = (unsigned char *)coap_malloc(buf->length);
+    if (!buf->s) {
+      fclose(inputfile);
+      return 0;
+    }
+  }
+
+  len = fread(buf->s, 1, buf->length, inputfile);
+
+  if (len < 0 || ((size_t)len < buf->length)) {
+    if (ferror(inputfile) != 0) {
+      perror("cmdline_input_from_file: fread");
+      coap_free(buf->s);
+      buf->length = 0;
+      buf->s = NULL;
+      result = 0;
+    } else {
+      buf->length = len;
+    }
+  }
+
+  if (inputfile != stdin)
+    fclose(inputfile);
+
+  return result;
+}
+
+static method_t
+cmdline_method(char *arg) {
+  static char *methods[] =
+    { 0, "get", "post", "put", "delete", 0};
+  unsigned char i;
+
+  for (i=1; methods[i] && strcasecmp(arg,methods[i]) != 0 ; ++i)
+    ;
+
+  return i;     /* note that we do not prevent illegal methods */
+}
+
+static coap_context_t *
+get_context(const char *node, const char *port) {
+  coap_context_t *ctx = NULL;
+  int s;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
+
+  s = getaddrinfo(node, port, &hints, &result);
+  if ( s != 0 ) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+    return NULL;
+  }
+
+  /* iterate through results until success */
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    coap_address_t addr;
+
+    if (rp->ai_addrlen <= sizeof(addr.addr)) {
+      coap_address_init(&addr);
+      addr.size = rp->ai_addrlen;
+      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
+
+      ctx = coap_new_context(&addr);
+      if (ctx) {
+        /* TODO: output address:port for successful binding */
+        goto finish;
+      }
+    }
+  }
+
+  fprintf(stderr, "no context available for interface '%s'\n", node);
+
+  finish:
+  freeaddrinfo(result);
+  return ctx;
+}
+
+int
+main(int argc, char **argv) {
+  coap_context_t  *ctx = NULL;
+  coap_address_t dst;
+  static char addr[INET6_ADDRSTRLEN];
+  void *addrptr = NULL;
+  fd_set readfds;
+  struct timeval tv;
+  int result;
+  coap_tick_t now;
+  coap_queue_t *nextpdu;
+  coap_pdu_t  *pdu;
+  static str server;
+  unsigned short port = COAP_DEFAULT_PORT;
+  char port_str[NI_MAXSERV] = "0";
+  char node_str[NI_MAXHOST] = "";
+  int opt, res;
+  coap_log_t log_level = LOG_WARNING;
+  coap_tid_t tid = COAP_INVALID_TID;
+  int create_uri_opts = 1;
+
+  while ((opt = getopt(argc, argv, "Na:b:e:f:g:m:p:s:t:o:v:A:B:O:P:T:U")) != -1) {
+    switch (opt) {
+    case 'a' :
+      strncpy(node_str, optarg, NI_MAXHOST-1);
+      node_str[NI_MAXHOST - 1] = '\0';
+      break;
+    case 'b' :
+      cmdline_blocksize(optarg);
+      break;
+    case 'B' :
+      wait_seconds = atoi(optarg);
+      break;
+    case 'e' :
+      if (!cmdline_input(optarg,&payload))
+        payload.length = 0;
+      break;
+    case 'f' :
+      if (!cmdline_input_from_file(optarg,&payload))
+        payload.length = 0;
+      break;
+    case 'p' :
+      strncpy(port_str, optarg, NI_MAXSERV-1);
+      port_str[NI_MAXSERV - 1] = '\0';
+      break;
+    case 'm' :
+      method = cmdline_method(optarg);
+      break;
+    case 'N' :
+      msgtype = COAP_MESSAGE_NON;
+      break;
+    case 's' :
+      cmdline_subscribe(optarg);
+      break;
+    case 'o' :
+      output_file.length = strlen(optarg);
+      output_file.s = (unsigned char *)coap_malloc(output_file.length + 1);
+
+      if (!output_file.s) {
+        fprintf(stderr, "cannot set output file: insufficient memory\n");
+        exit(-1);
+      } else {
+        /* copy filename including trailing zero */
+        memcpy(output_file.s, optarg, output_file.length + 1);
+      }
+      break;
+    case 'A' :
+      cmdline_content_type(optarg,COAP_OPTION_ACCEPT);
+      break;
+    case 't' :
+      cmdline_content_type(optarg,COAP_OPTION_CONTENT_TYPE);
+      break;
+    case 'O' :
+      cmdline_option(optarg);
+      break;
+    case 'P' :
+      if (!cmdline_proxy(optarg)) {
+        fprintf(stderr, "error specifying proxy address\n");
+        exit(-1);
+      }
+      break;
+    case 'T' :
+      cmdline_token(optarg);
+      break;
+    case 'U' :
+      create_uri_opts = 0;
+      break;
+    case 'v' :
+      log_level = strtol(optarg, NULL, 10);
+      break;
+    default:
+      usage( argv[0], PACKAGE_VERSION );
+      exit( 1 );
+    }
+  }
+
+  coap_set_log_level(log_level);
+
+  if (optind < argc) {
+    if (cmdline_uri(argv[optind], create_uri_opts) < 0) {
+      coap_log(LOG_ERR, "invalid CoAP URI\n");
+      exit(1);
+    }
+  } else {
+    usage( argv[0], PACKAGE_VERSION );
+    exit( 1 );
+  }
+
+  if (proxy.length) {
+    server = proxy;
+    port = proxy_port;
+  } else {
+    server = uri.host;
+    port = uri.port;
+  }
+
+  /* resolve destination address where server should be sent */
+  res = resolve_address(&server, &dst.addr.sa);
+
+  if (res < 0) {
+    fprintf(stderr, "failed to resolve address\n");
+    exit(-1);
+  }
+
+  dst.size = res;
+  dst.addr.sin.sin_port = htons(port);
+
+  /* add Uri-Host if server address differs from uri.host */
+
+  switch (dst.addr.sa.sa_family) {
+  case AF_INET:
+    addrptr = &dst.addr.sin.sin_addr;
+
+    /* create context for IPv4 */
+    ctx = get_context(node_str[0] == 0 ? "0.0.0.0" : node_str, port_str);
+    break;
+  case AF_INET6:
+    addrptr = &dst.addr.sin6.sin6_addr;
+
+    /* create context for IPv6 */
+    ctx = get_context(node_str[0] == 0 ? "::" : node_str, port_str);
+    break;
+  default:
+    ;
+  }
+
+  if (!ctx) {
+    coap_log(LOG_EMERG, "cannot create context\n");
+    return -1;
+  }
+
+  coap_register_option(ctx, COAP_OPTION_BLOCK2);
+  coap_register_response_handler(ctx, message_handler);
+
+  /* construct CoAP message */
+
+  if (!proxy.length && addrptr
+      && (inet_ntop(dst.addr.sa.sa_family, addrptr, addr, sizeof(addr)) != 0)
+      && (strlen(addr) != uri.host.length
+      || memcmp(addr, uri.host.s, uri.host.length) != 0)
+      && create_uri_opts) {
+        /* add Uri-Host */
+
+        coap_insert(&optlist,
+                    new_option_node(COAP_OPTION_URI_HOST,
+                    uri.host.length,
+                    uri.host.s));
+  }
+
+  /* set block option if requested at commandline */
+  if (flags & FLAGS_BLOCK)
+    set_blocksize();
+
+  if (! (pdu = coap_new_request(ctx, method, &optlist, payload.s, payload.length)))
+    return -1;
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+    debug("sending CoAP request:\n");
+    coap_show_pdu(pdu);
+  }
+#endif
+
+  if (pdu->hdr->type == COAP_MESSAGE_CON)
+    tid = coap_send_confirmed(ctx, ctx->endpoint, &dst, pdu);
+  else
+    tid = coap_send(ctx, ctx->endpoint, &dst, pdu);
+
+  if (pdu->hdr->type != COAP_MESSAGE_CON || tid == COAP_INVALID_TID)
+    coap_delete_pdu(pdu);
+
+  set_timeout(&max_wait, wait_seconds);
+  debug("timeout is set to %d seconds\n", wait_seconds);
+
+  while ( !(ready && coap_can_exit(ctx)) ) {
+    FD_ZERO(&readfds);
+    FD_SET( ctx->sockfd, &readfds );
+
+    nextpdu = coap_peek_next( ctx );
+
+    coap_ticks(&now);
+    while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
+      coap_retransmit( ctx, coap_pop_next( ctx ));
+      nextpdu = coap_peek_next( ctx );
+    }
+
+    if (nextpdu && nextpdu->t < min(obs_wait ? obs_wait : max_wait, max_wait) - now) {
+      /* set timeout if there is a pdu to send */
+      tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+      tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
+    } else {
+      /* check if obs_wait fires before max_wait */
+      if (obs_wait && obs_wait < max_wait) {
+        tv.tv_usec = ((obs_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+        tv.tv_sec = (obs_wait - now) / COAP_TICKS_PER_SECOND;
+      } else {
+        tv.tv_usec = ((max_wait - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+        tv.tv_sec = (max_wait - now) / COAP_TICKS_PER_SECOND;
+      }
+    }
+
+    result = select(ctx->sockfd + 1, &readfds, 0, 0, &tv);
+
+    if ( result < 0 ) {   /* error */
+      perror("select");
+    } else if ( result > 0 ) {  /* read from socket */
+      if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
+        coap_read( ctx );       /* read received data */
+        /* coap_dispatch( ctx );  /\* and dispatch PDUs from receivequeue *\/ */
+      }
+    } else { /* timeout */
+      coap_ticks(&now);
+      if (max_wait <= now) {
+        info("timeout\n");
+        break;
+      }
+      if (obs_wait && obs_wait <= now) {
+        debug("clear observation relationship\n");
+        clear_obs(ctx, ctx->endpoint, &dst); /* FIXME: handle error case COAP_TID_INVALID */
+
+        /* make sure that the obs timer does not fire again */
+        obs_wait = 0;
+        obs_seconds = 0;
+      }
+    }
+  }
+
+  close_output();
+
+  coap_delete_list(optlist);
+  coap_free_context( ctx );
+
+  return 0;
+}
diff --git a/components/coap/libcoap/examples/coap-client.txt.in b/components/coap/libcoap/examples/coap-client.txt.in
new file mode 100644
index 00000000..ee0f7ac5
--- /dev/null
+++ b/components/coap/libcoap/examples/coap-client.txt.in
@@ -0,0 +1,168 @@
+// -*- mode:doc; -*-
+// vim: set syntax=asciidoc,tw=0:
+
+coap-client(5)
+==============
+:doctype: manpage
+:man source:   coap-client
+:man version:  @PACKAGE_VERSION@
+:man manual:   coap-client Manual
+
+NAME
+-----
+coap-client - CoAP Client based on libcoap
+
+SYNOPSIS
+--------
+*coap-client* [*-A* type1, _type2_ ,...] [*-t* type] [*-b* [num,]size]
+              [*-B* seconds] [*-e* text] [*-f* file] [*-m* method] [*-N*]
+              [*-o* file] [*-P* addr[:port]] [*-p* port] [*-s* duration]
+              [*-O* num,text] [*-T* token] [*-v* num] [*-a* addr] [*-U*] URI
+
+DESCRIPTION
+-----------
+*coap-client* is a CoAP client to communicate with 6LoWPAN devices via
+the protocol CoAP (RFC 7252) using the URI given as argument on the
+command line. The URI must have the scheme 'coap' (or 'coaps' when
+coap-client was built with support for secure communication). The URI's
+host part may be a DNS name or a literal IP address. Note that, for
+IPv6 address references, angle brackets are required (c.f. EXAMPLES).
+
+
+OPTIONS
+-------
+*-a* addr::
+   The local address of the interface that has to be used.
+
+*-b* [num,]size::
+   The block size to be used in GET/PUT/POST requests (value must be a
+   multiple of 16 not larger than 1024 as libcoap uses a fixed maximum
+   PDU size of 1400 bytes). If 'num' is present, the request
+   chain will start at block 'num'. When the server includes a Block2
+   option in its response to a GET request, coap-client will automatically
+   retrieve the subsequent block from the server until there are no more
+   outstanding blocks for the requested content.
+
+*-e* text::
+   Include text as payload (use percent-encoding for non-ASCII characters).
+
+*-f* file::
+   File to send with PUT/POST (use '-' for STDIN).
+
+*-m* method::
+   The request method for action (get|put|post|delete), default is 'get'.
+   (Note that the string passed to *-m* is compared case-insensitive.)
+
+*-o* file::
+   A filename to store data retrieved with GET.
+
+*-p* port::
+   The port to listen on.
+
+*-s* duration::
+   Subscribe to the resource specified by URI for the given 'duration' in
+   seconds.
+
+*-t* type::
+   Content format for given resource for PUT/POST. 'type' must be either
+   a numeric value reflecting a valid CoAP content format or a string
+   describing a registered format. The following registered content format
+   descriptors are supported, with alternative shortcuts given in
+   parentheses:
+
+     text/plain (plain)
+     application/link-format (link, link-format)
+     application/xml (xml)
+     application/octet-stream (binary, octet-stream)
+     application/exi (exi)
+     application/json (json)
+     application/cbor (cbor)
+
+*-v* num::
+   The verbosity level to use (default: 3, maximum is 9).
+
+*-A* type::
+   Accepted media types as comma-separated list of symbolic or numeric
+   values, there are multiple arguments as comma separated list
+   possible. 'type' must be either a numeric value reflecting a valid
+   CoAP content format or a string that specifies a registered format as
+   described for option *-t*.
+
+*-B* seconds::
+   Break operation after waiting given seconds (default is 90).
+
+*-N* ::
+   Send NON-confirmable message. If option *-N* is not specified, a
+   confirmable message will be sent.
+
+*-O* num,text::
+   Add option 'num' with contents of 'text' to the request.
+
+*-P* addr[:port]::
+   Address (and port) for proxy to use (automatically adds Proxy-Uri option
+   to request).
+
+*-T* token::
+   Include the 'token' to the request.
+
+*-U* ::
+   Never include Uri-Host or Uri-Port options.
+
+EXAMPLES
+--------
+* Example
+----
+coap-client coap://coap.me
+----
+Query resource '/' from server 'coap.me' (via the GET method).
+
+* Example
+----
+coap-client -m get coap://[::1]/
+----
+Query on localhost via the 'GET' method.
+
+* Example
+----
+coap-client -m get coap://[::1]/.well-known/core
+----
+Quite the same, except on the resource '.well-known/core' on localhost.
+
+* Example
+----
+echo -n "mode=on" | coap-client -m put \
+coap://[2001:db8:c001:f00d:221:2eff:ff00:2704]:5683/actuators/leds?color=r -f-
+----
+Send text 'mode=on' to resource 'actuators/leds?color=r' on the endpoint with
+address '2001:db8:c001:f00d:221:2eff:ff00:2704' and port '5683'. Note that the
+port '5683' is the default port and isn't really needed to append.
+
+* Example
+----
+coap-client -m put coap://[fec0::3]/ck -T 3a -t binary -f to_upload
+----
+Put the contents of file 'to_upload' with content type 'binary' (i.e.
+application/octet-stream) into resource 'ck' on 'fec0::3' by usage of a token
+'3a' via the 'PUT' method.
+
+FILES
+------
+There are no configuration files.
+
+EXIT STATUS
+-----------
+*0*::
+   Success
+
+*1*::
+   Failure (syntax or usage error; configuration error; document
+   processing failure; unexpected error)
+
+BUGS
+-----
+Please report bugs on the mailing list for libcoap:
+libcoap-developers@lists.sourceforge.net
+
+AUTHORS
+-------
+The libcoap project <libcoap-developers@lists.sourceforge.net>
diff --git a/components/coap/libcoap/examples/coap-rd.c b/components/coap/libcoap/examples/coap-rd.c
new file mode 100644
index 00000000..64f156f2
--- /dev/null
+++ b/components/coap/libcoap/examples/coap-rd.c
@@ -0,0 +1,763 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 * -*- */
+
+/* coap -- simple implementation of the Constrained Application Protocol (CoAP)
+ *         as defined in RFC 7252
+ *
+ * Copyright (C) 2010--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms of
+ * use.
+ */
+
+
+/**
+ * @file rd.c
+ * @brief CoRE resource directory
+ *
+ * @see http://tools.ietf.org/id/draft-shelby-core-resource-directory
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "coap_config.h"
+#include "utlist.h"
+#include "resource.h"
+#include "coap.h"
+
+#define COAP_RESOURCE_CHECK_TIME 2
+
+#define RD_ROOT_STR   ((unsigned char *)"rd")
+#define RD_ROOT_SIZE  2
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+typedef struct rd_t {
+  UT_hash_handle hh;      /**< hash handle (for internal use only) */
+  coap_key_t key;         /**< the actual key bytes for this resource */
+
+  size_t etag_len;        /**< actual length of @c etag */
+  unsigned char etag[8];  /**< ETag for current description */
+
+  str data;               /**< points to the resource description  */
+} rd_t;
+
+rd_t *resources = NULL;
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+static inline rd_t *
+rd_new(void) {
+  rd_t *rd;
+  rd = (rd_t *)coap_malloc(sizeof(rd_t));
+  if (rd)
+    memset(rd, 0, sizeof(rd_t));
+
+  return rd;
+}
+
+static inline void
+rd_delete(rd_t *rd) {
+  if (rd) {
+    coap_free(rd->data.s);
+    coap_free(rd);
+  }
+}
+
+/* temporary storage for dynamic resource representations */
+static int quit = 0;
+
+/* SIGINT handler: set quit to 1 for graceful termination */
+static void
+handle_sigint(int signum UNUSED_PARAM) {
+  quit = 1;
+}
+
+static void
+hnd_get_resource(coap_context_t  *ctx UNUSED_PARAM,
+                 struct coap_resource_t *resource,
+                 const coap_endpoint_t *local_interface UNUSED_PARAM,
+                 coap_address_t *peer UNUSED_PARAM,
+                 coap_pdu_t *request UNUSED_PARAM,
+                 str *token UNUSED_PARAM,
+                 coap_pdu_t *response) {
+  rd_t *rd = NULL;
+  unsigned char buf[3];
+
+  HASH_FIND(hh, resources, resource->key, sizeof(coap_key_t), rd);
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response,
+                  COAP_OPTION_CONTENT_TYPE,
+                  coap_encode_var_bytes(buf,
+                                        COAP_MEDIATYPE_APPLICATION_LINK_FORMAT),
+                                        buf);
+
+  if (rd && rd->etag_len)
+    coap_add_option(response, COAP_OPTION_ETAG, rd->etag_len, rd->etag);
+
+  if (rd && rd->data.s)
+    coap_add_data(response, rd->data.length, rd->data.s);
+}
+
+static void
+hnd_put_resource(coap_context_t  *ctx UNUSED_PARAM,
+                 struct coap_resource_t *resource UNUSED_PARAM,
+                 const coap_endpoint_t *local_interface UNUSED_PARAM,
+                 coap_address_t *peer UNUSED_PARAM,
+                 coap_pdu_t *request UNUSED_PARAM,
+                 str *token UNUSED_PARAM,
+                 coap_pdu_t *response) {
+#if 1
+  response->hdr->code = COAP_RESPONSE_CODE(501);
+#else /* FIXME */
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *token, *etag;
+  coap_pdu_t *response;
+  size_t size = sizeof(coap_hdr_t);
+  int type = (request->hdr->type == COAP_MESSAGE_CON)
+    ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON;
+  rd_t *rd = NULL;
+  unsigned char code;     /* result code */
+  unsigned char *data;
+  str tmp;
+
+  HASH_FIND(hh, resources, resource->key, sizeof(coap_key_t), rd);
+  if (rd) {
+    /* found resource object, now check Etag */
+    etag = coap_check_option(request, COAP_OPTION_ETAG, &opt_iter);
+    if (!etag || (COAP_OPT_LENGTH(etag) != rd->etag_len)
+        || memcmp(COAP_OPT_VALUE(etag), rd->etag, rd->etag_len) != 0) {
+
+      if (coap_get_data(request, &tmp.length, &data)) {
+
+        tmp.s = (unsigned char *)coap_malloc(tmp.length);
+        if (!tmp.s) {
+          debug("hnd_put_rd: cannot allocate storage for new rd\n");
+          code = COAP_RESPONSE_CODE(503);
+          goto finish;
+        }
+
+        coap_free(rd->data.s);
+        rd->data.s = tmp.s;
+        rd->data.length = tmp.length;
+        memcpy(rd->data.s, data, rd->data.length);
+      }
+    }
+
+    if (etag) {
+      rd->etag_len = min(COAP_OPT_LENGTH(etag), sizeof(rd->etag));
+      memcpy(rd->etag, COAP_OPT_VALUE(etag), rd->etag_len);
+    }
+
+    code = COAP_RESPONSE_CODE(204);
+    /* FIXME: update lifetime */
+
+    } else {
+
+    code = COAP_RESPONSE_CODE(503);
+  }
+
+  finish:
+  /* FIXME: do not create a new response but use the old one instead */
+  response = coap_pdu_init(type, code, request->hdr->id, size);
+
+  if (!response) {
+    debug("cannot create response for message %d\n", request->hdr->id);
+    return;
+  }
+
+  if (request->hdr->token_length)
+    coap_add_token(response, request->hdr->token_length, request->hdr->token);
+
+  if (coap_send(ctx, peer, response) == COAP_INVALID_TID) {
+    debug("hnd_get_rd: cannot send response for message %d\n",
+    request->hdr->id);
+  }
+  coap_delete_pdu(response);
+#endif
+}
+
+static void
+hnd_delete_resource(coap_context_t  *ctx,
+                    struct coap_resource_t *resource,
+                    const coap_endpoint_t *local_interface UNUSED_PARAM,
+                    coap_address_t *peer UNUSED_PARAM,
+                    coap_pdu_t *request UNUSED_PARAM,
+                    str *token UNUSED_PARAM,
+                    coap_pdu_t *response) {
+  rd_t *rd = NULL;
+
+  HASH_FIND(hh, resources, resource->key, sizeof(coap_key_t), rd);
+  if (rd) {
+    HASH_DELETE(hh, resources, rd);
+    rd_delete(rd);
+  }
+  /* FIXME: link attributes for resource have been created dynamically
+   * using coap_malloc() and must be released. */
+  coap_delete_resource(ctx, resource->key);
+
+  response->hdr->code = COAP_RESPONSE_CODE(202);
+}
+
+static void
+hnd_get_rd(coap_context_t  *ctx UNUSED_PARAM,
+           struct coap_resource_t *resource UNUSED_PARAM,
+           const coap_endpoint_t *local_interface UNUSED_PARAM,
+           coap_address_t *peer UNUSED_PARAM,
+           coap_pdu_t *request UNUSED_PARAM,
+           str *token UNUSED_PARAM,
+           coap_pdu_t *response) {
+  unsigned char buf[3];
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response,
+                  COAP_OPTION_CONTENT_TYPE,
+                  coap_encode_var_bytes(buf,
+                                        COAP_MEDIATYPE_APPLICATION_LINK_FORMAT),
+                                        buf);
+
+  coap_add_option(response,
+                  COAP_OPTION_MAXAGE,
+                  coap_encode_var_bytes(buf, 0x2ffff), buf);
+}
+
+static int
+parse_param(unsigned char *search,
+            size_t search_len,
+            unsigned char *data,
+            size_t data_len,
+            str *result) {
+
+  if (result)
+    memset(result, 0, sizeof(str));
+
+  if (!search_len)
+    return 0;
+
+  while (search_len <= data_len) {
+
+    /* handle parameter if found */
+    if (memcmp(search, data, search_len) == 0) {
+      data += search_len;
+      data_len -= search_len;
+
+      /* key is only valid if we are at end of string or delimiter follows */
+      if (!data_len || *data == '=' || *data == '&') {
+        while (data_len && *data != '=') {
+          ++data; --data_len;
+        }
+
+        if (data_len > 1 && result) {
+          /* value begins after '=' */
+
+          result->s = ++data;
+          while (--data_len && *data != '&') {
+            ++data; result->length++;
+          }
+        }
+
+        return 1;
+      }
+    }
+
+    /* otherwise proceed to next */
+    while (--data_len && *data++ != '&')
+      ;
+  }
+
+  return 0;
+}
+
+static void
+add_source_address(struct coap_resource_t *resource,
+                   coap_address_t *peer) {
+#define BUFSIZE 64
+  char *buf;
+  size_t n = 1;
+
+  buf = (char *)coap_malloc(BUFSIZE);
+  if (!buf)
+    return;
+
+  buf[0] = '"';
+
+  switch(peer->addr.sa.sa_family) {
+
+  case AF_INET:
+    /* FIXME */
+    break;
+
+  case AF_INET6:
+    n += snprintf(buf + n, BUFSIZE - n,
+      "[%02x%02x:%02x%02x:%02x%02x:%02x%02x" \
+      ":%02x%02x:%02x%02x:%02x%02x:%02x%02x]",
+      peer->addr.sin6.sin6_addr.s6_addr[0],
+      peer->addr.sin6.sin6_addr.s6_addr[1],
+      peer->addr.sin6.sin6_addr.s6_addr[2],
+      peer->addr.sin6.sin6_addr.s6_addr[3],
+      peer->addr.sin6.sin6_addr.s6_addr[4],
+      peer->addr.sin6.sin6_addr.s6_addr[5],
+      peer->addr.sin6.sin6_addr.s6_addr[6],
+      peer->addr.sin6.sin6_addr.s6_addr[7],
+      peer->addr.sin6.sin6_addr.s6_addr[8],
+      peer->addr.sin6.sin6_addr.s6_addr[9],
+      peer->addr.sin6.sin6_addr.s6_addr[10],
+      peer->addr.sin6.sin6_addr.s6_addr[11],
+      peer->addr.sin6.sin6_addr.s6_addr[12],
+      peer->addr.sin6.sin6_addr.s6_addr[13],
+      peer->addr.sin6.sin6_addr.s6_addr[14],
+      peer->addr.sin6.sin6_addr.s6_addr[15]);
+
+    if (peer->addr.sin6.sin6_port != htons(COAP_DEFAULT_PORT)) {
+      n +=
+      snprintf(buf + n, BUFSIZE - n, ":%d", peer->addr.sin6.sin6_port);
+    }
+    break;
+    default:
+    ;
+  }
+
+  if (n < BUFSIZE)
+    buf[n++] = '"';
+
+  coap_add_attr(resource,
+                (unsigned char *)"A",
+                1,
+                (unsigned char *)buf,
+                n,
+                COAP_ATTR_FLAGS_RELEASE_VALUE);
+#undef BUFSIZE
+}
+
+static rd_t *
+make_rd(coap_address_t *peer UNUSED_PARAM, coap_pdu_t *pdu) {
+  rd_t *rd;
+  unsigned char *data;
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *etag;
+
+  rd = rd_new();
+
+  if (!rd) {
+    debug("hnd_get_rd: cannot allocate storage for rd\n");
+    return NULL;
+  }
+
+  if (coap_get_data(pdu, &rd->data.length, &data)) {
+    rd->data.s = (unsigned char *)coap_malloc(rd->data.length);
+    if (!rd->data.s) {
+      debug("hnd_get_rd: cannot allocate storage for rd->data\n");
+      rd_delete(rd);
+      return NULL;
+    }
+    memcpy(rd->data.s, data, rd->data.length);
+  }
+
+  etag = coap_check_option(pdu, COAP_OPTION_ETAG, &opt_iter);
+  if (etag) {
+    rd->etag_len = min(COAP_OPT_LENGTH(etag), sizeof(rd->etag));
+    memcpy(rd->etag, COAP_OPT_VALUE(etag), rd->etag_len);
+  }
+
+  return rd;
+}
+
+static void
+hnd_post_rd(coap_context_t  *ctx,
+            struct coap_resource_t *resource UNUSED_PARAM,
+            const coap_endpoint_t *local_interface UNUSED_PARAM,
+            coap_address_t *peer,
+            coap_pdu_t *request,
+            str *token UNUSED_PARAM,
+            coap_pdu_t *response) {
+  coap_resource_t *r;
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *query;
+#define LOCSIZE 68
+  unsigned char *loc;
+  size_t loc_size;
+  str h = {0, NULL}, ins = {0, NULL}, rt = {0, NULL}, lt = {0, NULL}; /* store query parameters */
+  unsigned char *buf;
+
+  loc = (unsigned char *)coap_malloc(LOCSIZE);
+  if (!loc) {
+    response->hdr->code = COAP_RESPONSE_CODE(500);
+    return;
+  }
+  memcpy(loc, RD_ROOT_STR, RD_ROOT_SIZE);
+
+  loc_size = RD_ROOT_SIZE;
+  loc[loc_size++] = '/';
+
+  /* store query parameters for later use */
+  query = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
+  if (query) {
+    parse_param((unsigned char *)"h", 1,
+    COAP_OPT_VALUE(query), COAP_OPT_LENGTH(query), &h);
+    parse_param((unsigned char *)"ins", 3,
+    COAP_OPT_VALUE(query), COAP_OPT_LENGTH(query), &ins);
+    parse_param((unsigned char *)"lt", 2,
+    COAP_OPT_VALUE(query), COAP_OPT_LENGTH(query), &lt);
+    parse_param((unsigned char *)"rt", 2,
+    COAP_OPT_VALUE(query), COAP_OPT_LENGTH(query), &rt);
+  }
+
+  if (h.length) {   /* client has specified a node name */
+    memcpy(loc + loc_size, h.s, min(h.length, LOCSIZE - loc_size - 1));
+    loc_size += min(h.length, LOCSIZE - loc_size - 1);
+
+    if (ins.length && loc_size > 1) {
+      loc[loc_size++] = '-';
+      memcpy((char *)(loc + loc_size),
+      ins.s, min(ins.length, LOCSIZE - loc_size - 1));
+      loc_size += min(ins.length, LOCSIZE - loc_size - 1);
+    }
+
+  } else {      /* generate node identifier */
+    loc_size +=
+      snprintf((char *)(loc + loc_size), LOCSIZE - loc_size - 1,
+               "%x", request->hdr->id);
+
+    if (loc_size > 1) {
+      if (ins.length) {
+        loc[loc_size++] = '-';
+        memcpy((char *)(loc + loc_size),
+                ins.s,
+                min(ins.length, LOCSIZE - loc_size - 1));
+        loc_size += min(ins.length, LOCSIZE - loc_size - 1);
+      } else {
+        coap_tick_t now;
+        coap_ticks(&now);
+
+        loc_size += snprintf((char *)(loc + loc_size),
+                             LOCSIZE - loc_size - 1,
+                             "-%x",
+                             (unsigned int)(now & (unsigned int)-1));
+      }
+    }
+  }
+
+  /* TODO:
+   *   - use lt to check expiration
+   */
+
+  r = coap_resource_init(loc, loc_size, COAP_RESOURCE_FLAGS_RELEASE_URI);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource);
+  coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_resource);
+  coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_resource);
+
+  if (ins.s) {
+    buf = (unsigned char *)coap_malloc(ins.length + 2);
+    if (buf) {
+      /* add missing quotes */
+      buf[0] = '"';
+      memcpy(buf + 1, ins.s, ins.length);
+      buf[ins.length + 1] = '"';
+      coap_add_attr(r,
+                    (unsigned char *)"ins",
+                    3,
+                    buf,
+                    ins.length + 2,
+                    COAP_ATTR_FLAGS_RELEASE_VALUE);
+    }
+  }
+
+  if (rt.s) {
+    buf = (unsigned char *)coap_malloc(rt.length + 2);
+    if (buf) {
+      /* add missing quotes */
+      buf[0] = '"';
+      memcpy(buf + 1, rt.s, rt.length);
+      buf[rt.length + 1] = '"';
+      coap_add_attr(r,
+                    (unsigned char *)"rt",
+                    2,
+                    buf,
+                    rt.length + 2,COAP_ATTR_FLAGS_RELEASE_VALUE);
+    }
+  }
+
+  add_source_address(r, peer);
+
+  {
+    rd_t *rd;
+    rd = make_rd(peer, request);
+    if (rd) {
+      coap_hash_path(loc, loc_size, rd->key);
+      HASH_ADD(hh, resources, key, sizeof(coap_key_t), rd);
+    } else {
+      /* FIXME: send error response and delete r */
+    }
+  }
+
+  coap_add_resource(ctx, r);
+
+
+  /* create response */
+
+  response->hdr->code = COAP_RESPONSE_CODE(201);
+
+  { /* split path into segments and add Location-Path options */
+    unsigned char _b[LOCSIZE];
+    unsigned char *b = _b;
+    size_t buflen = sizeof(_b);
+    int nseg;
+
+    nseg = coap_split_path(loc, loc_size, b, &buflen);
+    while (nseg--) {
+      coap_add_option(response,
+                      COAP_OPTION_LOCATION_PATH,
+                      COAP_OPT_LENGTH(b),
+                      COAP_OPT_VALUE(b));
+      b += COAP_OPT_SIZE(b);
+    }
+  }
+}
+
+static void
+init_resources(coap_context_t *ctx) {
+  coap_resource_t *r;
+
+  r = coap_resource_init(RD_ROOT_STR, RD_ROOT_SIZE, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_rd);
+  coap_register_handler(r, COAP_REQUEST_POST, hnd_post_rd);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"40", 2, 0);
+  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"core.rd\"", 9, 0);
+  coap_add_attr(r, (unsigned char *)"ins", 2, (unsigned char *)"\"default\"", 9, 0);
+
+  coap_add_resource(ctx, r);
+
+}
+
+static void
+usage( const char *program, const char *version) {
+  const char *p;
+
+  p = strrchr( program, '/' );
+  if ( p )
+    program = ++p;
+
+  fprintf( stderr, "%s v%s -- CoRE Resource Directory implementation\n"
+     "(c) 2011-2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
+     "usage: %s [-A address] [-p port]\n\n"
+     "\t-A address\tinterface address to bind to\n"
+     "\t-p port\t\tlisten on specified port\n"
+     "\t-v num\t\tverbosity level (default: 3)\n",
+     program, version, program );
+}
+
+static coap_context_t *
+get_context(const char *node, const char *port) {
+  coap_context_t *ctx = NULL;
+  int s;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+  s = getaddrinfo(node, port, &hints, &result);
+  if ( s != 0 ) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+    return NULL;
+  }
+
+  /* iterate through results until success */
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    coap_address_t addr;
+
+    if (rp->ai_addrlen <= sizeof(addr.addr)) {
+      coap_address_init(&addr);
+      addr.size = rp->ai_addrlen;
+      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
+
+      ctx = coap_new_context(&addr);
+      if (ctx) {
+        /* TODO: output address:port for successful binding */
+        goto finish;
+      }
+    }
+  }
+
+  fprintf(stderr, "no context available for interface '%s'\n", node);
+
+ finish:
+  freeaddrinfo(result);
+  return ctx;
+}
+
+static int
+join(coap_context_t *ctx, char *group_name) {
+  struct ipv6_mreq mreq;
+  struct addrinfo   *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
+  int result = -1;
+
+  /* we have to resolve the link-local interface to get the interface id */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET6;
+  hints.ai_socktype = SOCK_DGRAM;
+
+  result = getaddrinfo("::", NULL, &hints, &reslocal);
+  if ( result < 0 ) {
+    perror("join: cannot resolve link-local interface");
+    goto finish;
+  }
+
+  /* get the first suitable interface identifier */
+  for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
+    if ( ainfo->ai_family == AF_INET6 ) {
+      mreq.ipv6mr_interface =
+              ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
+      break;
+    }
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET6;
+  hints.ai_socktype = SOCK_DGRAM;
+
+  /* resolve the multicast group address */
+  result = getaddrinfo(group_name, NULL, &hints, &resmulti);
+
+  if ( result < 0 ) {
+    perror("join: cannot resolve multicast address");
+    goto finish;
+  }
+
+  for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
+    if ( ainfo->ai_family == AF_INET6 ) {
+      mreq.ipv6mr_multiaddr =
+        ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
+      break;
+    }
+  }
+
+  result = setsockopt(ctx->sockfd,
+                      IPPROTO_IPV6, IPV6_JOIN_GROUP,
+                      (char *)&mreq, sizeof(mreq) );
+  if ( result < 0 )
+    perror("join: setsockopt");
+
+ finish:
+  freeaddrinfo(resmulti);
+  freeaddrinfo(reslocal);
+
+  return result;
+}
+
+int
+main(int argc, char **argv) {
+  coap_context_t  *ctx;
+  fd_set readfds;
+  struct timeval tv, *timeout;
+  int result;
+  coap_tick_t now;
+  coap_queue_t *nextpdu;
+  char addr_str[NI_MAXHOST] = "::";
+  char port_str[NI_MAXSERV] = "5683";
+  char *group = NULL;
+  int opt;
+  coap_log_t log_level = LOG_WARNING;
+
+  while ((opt = getopt(argc, argv, "A:g:p:v:")) != -1) {
+    switch (opt) {
+    case 'A' :
+      strncpy(addr_str, optarg, NI_MAXHOST-1);
+      addr_str[NI_MAXHOST - 1] = '\0';
+      break;
+    case 'g' :
+      group = optarg;
+      break;
+    case 'p' :
+      strncpy(port_str, optarg, NI_MAXSERV-1);
+      port_str[NI_MAXSERV - 1] = '\0';
+      break;
+    case 'v' :
+      log_level = strtol(optarg, NULL, 10);
+      break;
+    default:
+      usage( argv[0], PACKAGE_VERSION );
+      exit( 1 );
+    }
+  }
+
+  coap_set_log_level(log_level);
+
+  ctx = get_context(addr_str, port_str);
+  if (!ctx)
+    return -1;
+
+  if (group)
+    join(ctx, group);
+
+  init_resources(ctx);
+
+  signal(SIGINT, handle_sigint);
+
+  while ( !quit ) {
+    FD_ZERO(&readfds);
+    FD_SET( ctx->sockfd, &readfds );
+
+    nextpdu = coap_peek_next( ctx );
+
+    coap_ticks(&now);
+    while ( nextpdu && nextpdu->t <= now ) {
+      coap_retransmit( ctx, coap_pop_next( ctx ) );
+      nextpdu = coap_peek_next( ctx );
+    }
+
+    if ( nextpdu && nextpdu->t <= now + COAP_RESOURCE_CHECK_TIME ) {
+      /* set timeout if there is a pdu to send before our automatic
+         timeout occurs */
+      tv.tv_usec = ((nextpdu->t - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+      tv.tv_sec = (nextpdu->t - now) / COAP_TICKS_PER_SECOND;
+      timeout = &tv;
+    } else {
+      tv.tv_usec = 0;
+      tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
+      timeout = &tv;
+    }
+    result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
+
+    if ( result < 0 ) {     /* error */
+      if (errno != EINTR)
+        perror("select");
+      } else if ( result > 0 ) {  /* read from socket */
+        if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
+          coap_read( ctx ); /* read received data */
+          /* coap_dispatch( ctx );  /\* and dispatch PDUs from receivequeue *\/ */
+        }
+      } else {            /* timeout */
+        /* coap_check_resource_list( ctx ); */
+    }
+  }
+
+  coap_free_context( ctx );
+
+  return 0;
+}
diff --git a/components/coap/libcoap/examples/coap-rd.txt.in b/components/coap/libcoap/examples/coap-rd.txt.in
new file mode 100644
index 00000000..762609cf
--- /dev/null
+++ b/components/coap/libcoap/examples/coap-rd.txt.in
@@ -0,0 +1,88 @@
+// -*- mode:doc; -*-
+// vim: set syntax=asciidoc,tw=0:
+
+coap-rd(5)
+==========
+:doctype: manpage
+:man source:   coap-rd
+:man version:  @PACKAGE_VERSION@
+:man manual:   coap-rd Manual
+
+NAME
+-----
+coap-rd - A CoAP Resource Directory based on libcoap
+
+SYNOPSIS
+--------
+*coap-rd* [*-A* addr] [*-g* group] [*-p* port] [*-v* num]
+
+DESCRIPTION
+-----------
+*coap-rd* is a simple CoAP Resource Directory server that can handle resource
+registrations using the protocol CoAP (RFC 7252).
+
+OPTIONS
+-------
+*-A* addr::
+   The local address of the interface which the server has to listen.
+
+*-g* group::
+   Join specified multicast 'group' on startup.
+
+*-p* port::
+   The 'port' on the given address the server will be waitung for connections.
+   The default port is 5683 if not given any other value.
+
+*-v* num::
+   The verbosity level to use (default: 3, maximum is 9).
+
+EXAMPLES
+--------
+* Example
+----
+coap-rd -A ::1
+----
+Let the server listen on localhost (port 5683).
+
+* Example
+----
+coap-rd -A ::1 -p 13011
+----
+Quite the same, except listening port is '13011' (and not the default port
+5683).
+
+* Example
+----
+coap-rd -A 2001:db8:81a8:0:6ef0:dead:feed:beef  -v 5
+----
+The listening address is set to '2001:db8:81a8:0:6ef0:dead:feed:beef' and the
+verbosity level is set to '5'.
+
+* Example
+----
+coap-rd -A 2001:db8:81a8:0:6ef0:dead:feed:beef  -g FF02:FD
+----
+Set listening address to '2001:db8:81a8:0:6ef0:dead:feed:beef' and join the
+All CoAP Nodes multicast group 'FF02:FD'.
+
+FILES
+------
+There are no configuration files.
+
+EXIT STATUS
+-----------
+*0*::
+   Success
+
+*1*::
+   Failure (syntax or usage error; configuration error; document
+   processing failure; unexpected error)
+
+BUGS
+-----
+Please report bugs on the mailing list for libcoap:
+libcoap-developers@lists.sourceforge.net
+
+AUTHORS
+-------
+The libcoap project <libcoap-developers@lists.sourceforge.net>
diff --git a/components/coap/libcoap/examples/coap-server.c b/components/coap/libcoap/examples/coap-server.c
new file mode 100644
index 00000000..aa29db31
--- /dev/null
+++ b/components/coap/libcoap/examples/coap-server.c
@@ -0,0 +1,550 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 * -*- */
+
+/* coap -- simple implementation of the Constrained Application Protocol (CoAP)
+ *         as defined in RFC 7252
+ *
+ * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "coap_config.h"
+#include "resource.h"
+#include "coap.h"
+
+#define COAP_RESOURCE_CHECK_TIME 2
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* temporary storage for dynamic resource representations */
+static int quit = 0;
+
+/* changeable clock base (see handle_put_time()) */
+static time_t clock_offset;
+static time_t my_clock_base = 0;
+
+struct coap_resource_t *time_resource = NULL;
+
+#ifndef WITHOUT_ASYNC
+/* This variable is used to mimic long-running tasks that require
+ * asynchronous responses. */
+static coap_async_state_t *async = NULL;
+#endif /* WITHOUT_ASYNC */
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+/* SIGINT handler: set quit to 1 for graceful termination */
+static void
+handle_sigint(int signum UNUSED_PARAM) {
+  quit = 1;
+}
+
+#define INDEX "This is a test server made with libcoap (see https://libcoap.net)\n" \
+              "Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>\n\n"
+
+static void
+hnd_get_index(coap_context_t *ctx UNUSED_PARAM,
+              struct coap_resource_t *resource UNUSED_PARAM,
+              const coap_endpoint_t *local_interface UNUSED_PARAM,
+              coap_address_t *peer UNUSED_PARAM,
+              coap_pdu_t *request UNUSED_PARAM,
+              str *token UNUSED_PARAM,
+              coap_pdu_t *response) {
+  unsigned char buf[3];
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response,
+                  COAP_OPTION_CONTENT_TYPE,
+                  coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_add_option(response,
+                  COAP_OPTION_MAXAGE,
+                  coap_encode_var_bytes(buf, 0x2ffff), buf);
+
+  coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
+}
+
+static void
+hnd_get_time(coap_context_t  *ctx,
+             struct coap_resource_t *resource,
+             const coap_endpoint_t *local_interface UNUSED_PARAM,
+             coap_address_t *peer,
+             coap_pdu_t *request,
+             str *token,
+             coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  unsigned char buf[40];
+  size_t len;
+  time_t now;
+  coap_tick_t t;
+
+  /* FIXME: return time, e.g. in human-readable by default and ticks
+   * when query ?ticks is given. */
+
+  /* if my_clock_base was deleted, we pretend to have no such resource */
+  response->hdr->code =
+    my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
+
+  if (coap_find_observer(resource, peer, token)) {
+    /* FIXME: need to check for resource->dirty? */
+    coap_add_option(response,
+                    COAP_OPTION_OBSERVE,
+                    coap_encode_var_bytes(buf, ctx->observe), buf);
+  }
+
+  if (my_clock_base)
+    coap_add_option(response,
+                    COAP_OPTION_CONTENT_FORMAT,
+                    coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_add_option(response,
+                  COAP_OPTION_MAXAGE,
+                  coap_encode_var_bytes(buf, 0x01), buf);
+
+  if (my_clock_base) {
+
+    /* calculate current time */
+    coap_ticks(&t);
+    now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
+
+    if (request != NULL
+        && (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
+        && memcmp(COAP_OPT_VALUE(option), "ticks",
+        min(5, COAP_OPT_LENGTH(option))) == 0) {
+          /* output ticks */
+          len = snprintf((char *)buf,
+                         min(sizeof(buf),
+                             response->max_size - response->length),
+                             "%u", (unsigned int)now);
+          coap_add_data(response, len, buf);
+
+    } else {      /* output human-readable time */
+      struct tm *tmp;
+      tmp = gmtime(&now);
+      len = strftime((char *)buf,
+                     min(sizeof(buf),
+                     response->max_size - response->length),
+                     "%b %d %H:%M:%S", tmp);
+      coap_add_data(response, len, buf);
+    }
+  }
+}
+
+static void
+hnd_put_time(coap_context_t *ctx UNUSED_PARAM,
+             struct coap_resource_t *resource UNUSED_PARAM,
+             const coap_endpoint_t *local_interface UNUSED_PARAM,
+             coap_address_t *peer UNUSED_PARAM,
+             coap_pdu_t *request,
+             str *token UNUSED_PARAM,
+             coap_pdu_t *response) {
+  coap_tick_t t;
+  size_t size;
+  unsigned char *data;
+
+  /* FIXME: re-set my_clock_base to clock_offset if my_clock_base == 0
+   * and request is empty. When not empty, set to value in request payload
+   * (insist on query ?ticks). Return Created or Ok.
+   */
+
+  /* if my_clock_base was deleted, we pretend to have no such resource */
+  response->hdr->code =
+    my_clock_base ? COAP_RESPONSE_CODE(204) : COAP_RESPONSE_CODE(201);
+
+  resource->dirty = 1;
+
+  /* coap_get_data() sets size to 0 on error */
+  (void)coap_get_data(request, &size, &data);
+
+  if (size == 0)        /* re-init */
+    my_clock_base = clock_offset;
+  else {
+    my_clock_base = 0;
+    coap_ticks(&t);
+    while(size--)
+      my_clock_base = my_clock_base * 10 + *data++;
+    my_clock_base -= t / COAP_TICKS_PER_SECOND;
+  }
+}
+
+static void
+hnd_delete_time(coap_context_t *ctx UNUSED_PARAM,
+                struct coap_resource_t *resource UNUSED_PARAM,
+                const coap_endpoint_t *local_interface UNUSED_PARAM,
+                coap_address_t *peer UNUSED_PARAM,
+                coap_pdu_t *request UNUSED_PARAM,
+                str *token UNUSED_PARAM,
+                coap_pdu_t *response UNUSED_PARAM) {
+  my_clock_base = 0;    /* mark clock as "deleted" */
+
+  /* type = request->hdr->type == COAP_MESSAGE_CON  */
+  /*   ? COAP_MESSAGE_ACK : COAP_MESSAGE_NON; */
+}
+
+#ifndef WITHOUT_ASYNC
+static void
+hnd_get_async(coap_context_t *ctx,
+              struct coap_resource_t *resource UNUSED_PARAM,
+              const coap_endpoint_t *local_interface UNUSED_PARAM,
+              coap_address_t *peer,
+              coap_pdu_t *request,
+              str *token UNUSED_PARAM,
+              coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  unsigned long delay = 5;
+  size_t size;
+
+  if (async) {
+    if (async->id != request->hdr->id) {
+      coap_opt_filter_t f;
+      coap_option_filter_clear(f);
+      response->hdr->code = COAP_RESPONSE_CODE(503);
+    }
+    return;
+  }
+
+  option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
+  if (option) {
+    unsigned char *p = COAP_OPT_VALUE(option);
+
+    delay = 0;
+    for (size = COAP_OPT_LENGTH(option); size; --size, ++p)
+      delay = delay * 10 + (*p - '0');
+  }
+
+  async = coap_register_async(ctx,
+                              peer,
+                              request,
+                              COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM,
+                              (void *)(COAP_TICKS_PER_SECOND * delay));
+}
+
+static void
+check_async(coap_context_t *ctx,
+            const coap_endpoint_t *local_if,
+            coap_tick_t now) {
+  coap_pdu_t *response;
+  coap_async_state_t *tmp;
+
+  size_t size = sizeof(coap_hdr_t) + 13;
+
+  if (!async || now < async->created + (unsigned long)async->appdata)
+    return;
+
+  response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM
+             ? COAP_MESSAGE_CON
+             : COAP_MESSAGE_NON,
+             COAP_RESPONSE_CODE(205), 0, size);
+  if (!response) {
+    debug("check_async: insufficient memory, we'll try later\n");
+    async->appdata =
+      (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
+    return;
+  }
+
+  response->hdr->id = coap_new_message_id(ctx);
+
+  if (async->tokenlen)
+    coap_add_token(response, async->tokenlen, async->token);
+
+  coap_add_data(response, 4, (unsigned char *)"done");
+
+  if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) {
+    debug("check_async: cannot send response for message %d\n",
+    response->hdr->id);
+  }
+  coap_delete_pdu(response);
+  coap_remove_async(ctx, async->id, &tmp);
+  coap_free_async(async);
+  async = NULL;
+}
+#endif /* WITHOUT_ASYNC */
+
+static void
+init_resources(coap_context_t *ctx) {
+  coap_resource_t *r;
+
+  r = coap_resource_init(NULL, 0, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
+  coap_add_resource(ctx, r);
+
+  /* store clock base to use in /time */
+  my_clock_base = clock_offset;
+
+  r = coap_resource_init((unsigned char *)"time", 4, COAP_RESOURCE_FLAGS_NOTIFY_CON);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
+  coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
+  coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0);
+  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0);
+  r->observable = 1;
+  coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
+
+  coap_add_resource(ctx, r);
+  time_resource = r;
+
+#ifndef WITHOUT_ASYNC
+  r = coap_resource_init((unsigned char *)"async", 5, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_resource(ctx, r);
+#endif /* WITHOUT_ASYNC */
+}
+
+static void
+usage( const char *program, const char *version) {
+  const char *p;
+
+  p = strrchr( program, '/' );
+  if ( p )
+    program = ++p;
+
+  fprintf( stderr, "%s v%s -- a small CoAP implementation\n"
+     "(c) 2010,2011,2015 Olaf Bergmann <bergmann@tzi.org>\n\n"
+     "usage: %s [-A address] [-p port]\n\n"
+     "\t-A address\tinterface address to bind to\n"
+     "\t-g group\tjoin the given multicast group\n"
+     "\t-p port\t\tlisten on specified port\n"
+     "\t-v num\t\tverbosity level (default: 3)\n",
+     program, version, program );
+}
+
+static coap_context_t *
+get_context(const char *node, const char *port) {
+  coap_context_t *ctx = NULL;
+  int s;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+  s = getaddrinfo(node, port, &hints, &result);
+  if ( s != 0 ) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+    return NULL;
+  }
+
+  /* iterate through results until success */
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    coap_address_t addr;
+
+    if (rp->ai_addrlen <= sizeof(addr.addr)) {
+      coap_address_init(&addr);
+      addr.size = rp->ai_addrlen;
+      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
+
+      ctx = coap_new_context(&addr);
+      if (ctx) {
+        /* TODO: output address:port for successful binding */
+        goto finish;
+      }
+    }
+  }
+
+  fprintf(stderr, "no context available for interface '%s'\n", node);
+
+  finish:
+  freeaddrinfo(result);
+  return ctx;
+}
+
+static int
+join(coap_context_t *ctx, char *group_name){
+  struct ipv6_mreq mreq;
+  struct addrinfo   *reslocal = NULL, *resmulti = NULL, hints, *ainfo;
+  int result = -1;
+
+  /* we have to resolve the link-local interface to get the interface id */
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET6;
+  hints.ai_socktype = SOCK_DGRAM;
+
+  result = getaddrinfo("::", NULL, &hints, &reslocal);
+  if (result < 0) {
+    fprintf(stderr, "join: cannot resolve link-local interface: %s\n",
+            gai_strerror(result));
+    goto finish;
+  }
+
+  /* get the first suitable interface identifier */
+  for (ainfo = reslocal; ainfo != NULL; ainfo = ainfo->ai_next) {
+    if (ainfo->ai_family == AF_INET6) {
+      mreq.ipv6mr_interface =
+                ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_scope_id;
+      break;
+    }
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = AF_INET6;
+  hints.ai_socktype = SOCK_DGRAM;
+
+  /* resolve the multicast group address */
+  result = getaddrinfo(group_name, NULL, &hints, &resmulti);
+
+  if (result < 0) {
+    fprintf(stderr, "join: cannot resolve multicast address: %s\n",
+            gai_strerror(result));
+    goto finish;
+  }
+
+  for (ainfo = resmulti; ainfo != NULL; ainfo = ainfo->ai_next) {
+    if (ainfo->ai_family == AF_INET6) {
+      mreq.ipv6mr_multiaddr =
+                ((struct sockaddr_in6 *)ainfo->ai_addr)->sin6_addr;
+      break;
+    }
+  }
+
+  result = setsockopt(ctx->sockfd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+          (char *)&mreq, sizeof(mreq));
+  if (result < 0)
+    perror("join: setsockopt");
+
+ finish:
+  freeaddrinfo(resmulti);
+  freeaddrinfo(reslocal);
+
+  return result;
+}
+
+int
+main(int argc, char **argv) {
+  coap_context_t  *ctx;
+  char *group = NULL;
+  fd_set readfds;
+  struct timeval tv, *timeout;
+  int result;
+  coap_tick_t now;
+  coap_queue_t *nextpdu;
+  char addr_str[NI_MAXHOST] = "::";
+  char port_str[NI_MAXSERV] = "5683";
+  int opt;
+  coap_log_t log_level = LOG_WARNING;
+
+  clock_offset = time(NULL);
+
+  while ((opt = getopt(argc, argv, "A:g:p:v:")) != -1) {
+    switch (opt) {
+    case 'A' :
+      strncpy(addr_str, optarg, NI_MAXHOST-1);
+      addr_str[NI_MAXHOST - 1] = '\0';
+      break;
+    case 'g' :
+      group = optarg;
+      break;
+    case 'p' :
+      strncpy(port_str, optarg, NI_MAXSERV-1);
+      port_str[NI_MAXSERV - 1] = '\0';
+      break;
+    case 'v' :
+      log_level = strtol(optarg, NULL, 10);
+      break;
+    default:
+      usage( argv[0], PACKAGE_VERSION );
+      exit( 1 );
+    }
+  }
+
+  coap_set_log_level(log_level);
+
+  ctx = get_context(addr_str, port_str);
+  if (!ctx)
+    return -1;
+
+  init_resources(ctx);
+
+  /* join multicast group if requested at command line */
+  if (group)
+    join(ctx, group);
+
+  signal(SIGINT, handle_sigint);
+
+  while ( !quit ) {
+    FD_ZERO(&readfds);
+    FD_SET( ctx->sockfd, &readfds );
+
+    nextpdu = coap_peek_next( ctx );
+
+    coap_ticks(&now);
+    while (nextpdu && nextpdu->t <= now - ctx->sendqueue_basetime) {
+      coap_retransmit( ctx, coap_pop_next( ctx ) );
+      nextpdu = coap_peek_next( ctx );
+    }
+
+    if ( nextpdu && nextpdu->t <= COAP_RESOURCE_CHECK_TIME ) {
+      /* set timeout if there is a pdu to send before our automatic timeout occurs */
+      tv.tv_usec = ((nextpdu->t) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+      tv.tv_sec = (nextpdu->t) / COAP_TICKS_PER_SECOND;
+      timeout = &tv;
+    } else {
+      tv.tv_usec = 0;
+      tv.tv_sec = COAP_RESOURCE_CHECK_TIME;
+      timeout = &tv;
+    }
+    result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
+
+    if ( result < 0 ) {         /* error */
+      if (errno != EINTR)
+        perror("select");
+    } else if ( result > 0 ) {  /* read from socket */
+      if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
+        coap_read( ctx );       /* read received data */
+        /* coap_dispatch( ctx );  /\* and dispatch PDUs from receivequeue *\/ */
+      }
+    } else {      /* timeout */
+      if (time_resource) {
+        time_resource->dirty = 1;
+      }
+    }
+
+#ifndef WITHOUT_ASYNC
+    /* check if we have to send asynchronous responses */
+    check_async(ctx, ctx->endpoint, now);
+#endif /* WITHOUT_ASYNC */
+
+#ifndef WITHOUT_OBSERVE
+    /* check if we have to send observe notifications */
+    coap_check_notify(ctx);
+#endif /* WITHOUT_OBSERVE */
+  }
+
+  coap_free_context(ctx);
+
+  return 0;
+}
diff --git a/components/coap/libcoap/examples/coap-server.txt.in b/components/coap/libcoap/examples/coap-server.txt.in
new file mode 100644
index 00000000..c15741ef
--- /dev/null
+++ b/components/coap/libcoap/examples/coap-server.txt.in
@@ -0,0 +1,88 @@
+// -*- mode:doc; -*-
+// vim: set syntax=asciidoc,tw=0:
+
+coap-server(5)
+==============
+:doctype: manpage
+:man source:   coap-server
+:man version:  @PACKAGE_VERSION@
+:man manual:   coap-server Manual
+
+NAME
+-----
+coap-server - CoAP Server based on libcoap
+
+SYNOPSIS
+--------
+*coap-server* [*-A* addr] [*-g* group] [*-p* port] [*-v* num]
+
+DESCRIPTION
+-----------
+*coap-server* is a CoAP server which simulate 6LoWPAN devices which can be
+addressed via the CoAP protocol.
+
+OPTIONS
+-------
+*-A* addr::
+   The local address of the interface which the server has to listen.
+
+*-g* group::
+   Join specified multicast 'group' on startup.
+
+*-p* port::
+   The 'port' on the given address the server will be waitung for connections.
+   The default port is 5683 if not given any other value.
+
+*-v* num::
+   The verbosity level to use (default: 3, maximum is 9).
+
+EXAMPLES
+--------
+* Example
+----
+coap-server -A ::1
+----
+Let the server listen on localhost (port 5683).
+
+* Example
+----
+coap-server -A ::1 -p 13011
+----
+Quite the same, except listening port is '13011' (and not the default port
+5683).
+
+* Example
+----
+coap-server -A 2001:db8:81a8:0:6ef0:dead:feed:beef  -v 5
+----
+The listening address is set to '2001:db8:81a8:0:6ef0:dead:feed:beef' and the
+verbosity level is set to '5'.
+
+* Example
+----
+coap-server -A 2001:db8:81a8:0:6ef0:dead:feed:beef  -g FF02:FD
+----
+Set listening address to '2001:db8:81a8:0:6ef0:dead:feed:beef' and join the
+All CoAP Nodes multicast group 'FF02:FD'.
+
+FILES
+------
+There are no configuration files.
+
+EXIT STATUS
+-----------
+*0*::
+   Success
+
+*1*::
+   Failure (syntax or usage error; configuration error; document
+   processing failure; unexpected error)
+
+BUGS
+-----
+Please report bugs on the mailing list for libcoap:
+libcoap-developers@lists.sourceforge.net
+
+AUTHORS
+-------
+The libcoap project <libcoap-developers@lists.sourceforge.net>
diff --git a/components/coap/libcoap/examples/coap_list.c b/components/coap/libcoap/examples/coap_list.c
new file mode 100644
index 00000000..06e59168
--- /dev/null
+++ b/components/coap/libcoap/examples/coap_list.c
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 * -*- */
+
+/* coap_list.c -- CoAP list structures
+ *
+ * Copyright (C) 2010,2011,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms of
+ * use.
+ */
+
+/* #include "coap_config.h" */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "debug.h"
+#include "mem.h"
+#include "coap_list.h"
+
+
+int
+coap_insert(coap_list_t **head, coap_list_t *node) {
+  if (!node) {
+    coap_log(LOG_WARNING, "cannot create option Proxy-Uri\n");
+  } else {
+    /* must append at the list end to avoid re-ordering of
+     * options during sort */
+    LL_APPEND((*head), node);
+  }
+
+  return node != NULL;
+}
+
+int
+coap_delete(coap_list_t *node) {
+  if (node) {
+    coap_free(node);
+  }
+  return 1;
+}
+
+void
+coap_delete_list(coap_list_t *queue) {
+  coap_list_t *elt, *tmp;
+
+  if (!queue)
+    return;
+
+  LL_FOREACH_SAFE(queue, elt, tmp) {
+    coap_delete(elt);
+  }
+}
+
diff --git a/components/coap/libcoap/examples/coap_list.h b/components/coap/libcoap/examples/coap_list.h
new file mode 100644
index 00000000..14a68a30
--- /dev/null
+++ b/components/coap/libcoap/examples/coap_list.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 * -*- */
+
+/* coap_list.h -- CoAP list structures
+ *
+ * Copyright (C) 2010,2011,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms of
+ * use.
+ */
+
+#ifndef _COAP_LIST_H_
+#define _COAP_LIST_H_
+
+#include "utlist.h"
+
+typedef struct coap_list_t {
+  struct coap_list_t *next;
+  char data[];
+} coap_list_t;
+
+/**
+ * Adds node to given queue, ordered by specified order function. Returns 1
+ * when insert was successful, 0 otherwise.
+ */
+int coap_insert(coap_list_t **queue, coap_list_t *node);
+
+/* destroys specified node */
+int coap_delete(coap_list_t *node);
+
+/* removes all items from given queue and frees the allocated storage */
+void coap_delete_list(coap_list_t *queue);
+
+#endif /* _COAP_LIST_H_ */
diff --git a/components/coap/libcoap/examples/contiki/Makefile.contiki b/components/coap/libcoap/examples/contiki/Makefile.contiki
new file mode 100644
index 00000000..9df292a2
--- /dev/null
+++ b/components/coap/libcoap/examples/contiki/Makefile.contiki
@@ -0,0 +1,33 @@
+########################################################################
+# platform-specific options
+
+ifeq ($(TARGET), econotag)
+CONTIKI_WITH_RPL=0
+CFLAGS += -DUIP_CONF_TCP=0 -DCOAP_MAX_BLOCK_SZX=1
+endif
+
+ifeq ($(TARGET), mbxxx)
+CFLAGS += -DUIP_CONF_TCP=0  -DCOAP_MAX_BLOCK_SZX=1 -DHAVE_ASSERT_H -DHAVE_LIMITS_H
+STM32W_CPUREV=CC
+#STM32W_CPUREV=xB
+endif
+
+# usually, you should not need changing anything beyond this line
+########################################################################
+
+CONTIKI?=../../../..
+
+ifneq ($(NODE_ADDR),)
+      CFLAGS += -DNODE_ADDR=$(NODE_ADDR)
+endif
+
+all: server
+
+CFLAGS += -Os -ffunction-sections
+LDFLAGS += -Wl,--gc-sections,--undefined=_reset_vector__,--undefined=InterruptVectors,--undefined=_copy_data_init__,--undefined=_clear_bss_init__,--undefined=_end_of_init__
+
+CFLAGS += #-DSHORT_ERROR_RESPONSE -DNDEBUG
+
+APPS += libcoap 
+
+include $(CONTIKI)/Makefile.include
diff --git a/components/coap/libcoap/examples/contiki/coap-observer.c b/components/coap/libcoap/examples/contiki/coap-observer.c
new file mode 100644
index 00000000..6e30d329
--- /dev/null
+++ b/components/coap/libcoap/examples/contiki/coap-observer.c
@@ -0,0 +1,185 @@
+/* coap-server.c -- Example CoAP server using Contiki and libcoap
+ *
+ * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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.
+ *
+ * This file is part of the Contiki operating system.
+ *
+ */
+
+#include "coap_config.h"
+#include "net/uip-debug.h"
+
+#include <string.h>
+
+#include "debug.h"
+#include "coap.h"
+
+static coap_context_t *coap_context;
+
+/* Where the resource to subscribe is hosted */
+static coap_address_t dst;
+
+/* The resource to observe */
+static char resource[] = "/s/light";
+
+/* when did the last notify arrive? (0 == never) */
+static coap_tick_t last_seen = 0;
+
+PROCESS(coap_server_process, "CoAP server process");
+AUTOSTART_PROCESSES(&coap_server_process);
+/*---------------------------------------------------------------------------*/
+void
+init_coap() {
+  coap_address_t listen_addr;
+  
+  coap_address_init(&listen_addr);
+  listen_addr.port = UIP_HTONS(COAP_DEFAULT_PORT);
+
+#ifdef WITH_CONTIKI
+  /* initialize uIP address for SLAAC */
+  uip_ip6addr(&listen_addr.addr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
+  uip_ds6_set_addr_iid(&listen_addr.addr, &uip_lladdr);
+  uip_ds6_addr_add(&listen_addr.addr, 0, ADDR_AUTOCONF);
+
+  uip_debug_lladdr_print(&uip_lladdr);
+  printf("\r\n");
+  uip_debug_ipaddr_print(&listen_addr.addr);
+  printf("\r\n");
+#endif /* WITH_CONTIKI */
+
+#ifdef WITH_CONTIKI
+  printf("tentative address: [%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%d\r\n",
+	 listen_addr.addr.u8[0], listen_addr.addr.u8[1], 
+	 listen_addr.addr.u8[2], listen_addr.addr.u8[3], 
+	 listen_addr.addr.u8[4], listen_addr.addr.u8[5], 
+	 listen_addr.addr.u8[6], listen_addr.addr.u8[7], 
+	 listen_addr.addr.u8[8], listen_addr.addr.u8[9], 
+	 listen_addr.addr.u8[10], listen_addr.addr.u8[11], 
+	 listen_addr.addr.u8[12], listen_addr.addr.u8[13], 
+	 listen_addr.addr.u8[14], listen_addr.addr.u8[15] ,
+	 uip_ntohs(listen_addr.port));
+#endif
+
+  coap_context = coap_new_context(&listen_addr);
+
+  coap_set_log_level(LOG_DEBUG);
+
+  if (!coap_context)
+    coap_log(LOG_CRIT, "cannot create CoAP context\r\n");
+}
+
+void
+message_handler(struct coap_context_t  *ctx, 
+		const coap_address_t *remote, 
+		coap_pdu_t *sent,
+		coap_pdu_t *received,
+		const coap_tid_t id) {
+  /* send ACK if received message is confirmable (i.e. a separate response) */
+  coap_send_ack(ctx, remote, received);
+
+  debug("** process incoming %d.%02d response:\n",
+	(received->hdr->code >> 5), received->hdr->code & 0x1F);
+  coap_show_pdu(received);
+
+  coap_ticks(&last_seen);
+}
+
+/*---------------------------------------------------------------------------*/
+PROCESS_THREAD(coap_server_process, ev, data)
+{
+  coap_pdu_t *request;
+  coap_uri_t uri;
+  PROCESS_BEGIN();
+
+  init_coap();
+
+  if (!coap_context) {
+    coap_log(LOG_EMERG, "cannot create context\n");
+    PROCESS_EXIT();
+  }
+
+  coap_register_response_handler(coap_context, message_handler);
+
+  /* setup subscription request */
+
+  coap_address_init(&dst);
+  dst.port = uip_htons(COAP_DEFAULT_PORT);
+  uip_ip6addr(&dst.addr, 0xaaaa, 0, 0, 0, 0x206, 0x98ff, 0xfe00, 0x232);
+  /* uip_ip6addr(&dst.addr, 0xfe80, 0, 0, 0, 0x206, 0x98ff, 0xfe00, 0x232); */
+
+  request = coap_pdu_init(COAP_MESSAGE_CON, COAP_REQUEST_GET, 
+			  coap_new_message_id(coap_context), 
+			  COAP_MAX_PDU_SIZE);
+  
+  coap_split_uri((unsigned char *)resource, strlen(resource), &uri);
+
+  if (uri.port != COAP_DEFAULT_PORT) {
+    unsigned char portbuf[2];
+    coap_add_option(request, COAP_OPTION_URI_PORT,
+		    coap_encode_var_bytes(portbuf, uri.port), portbuf);
+  }
+
+  if (uri.path.length) {
+#define BUFSIZE 20
+    unsigned char _buf[BUFSIZE];
+    unsigned char *buf = _buf;
+    size_t buflen;
+    int res;
+
+    buflen = BUFSIZE;
+#undef BUFSIZE
+    res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+
+    while (res--) {
+      coap_add_option(request, COAP_OPTION_URI_PATH, 
+		      COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
+
+      buf += COAP_OPT_SIZE(buf);      
+    }
+  }
+
+  coap_add_option(request, COAP_OPTION_SUBSCRIPTION, 0, NULL);
+  {
+    unsigned char buf[2];
+    prng(buf, 2);
+    coap_add_option(request, COAP_OPTION_TOKEN, 2, buf);
+  }
+
+  if (COAP_INVALID_TID == coap_send_confirmed(coap_context, &dst, request))
+    coap_delete_pdu(request);
+
+  while(1) {
+    PROCESS_YIELD();
+    if(ev == tcpip_event) {
+      coap_read(coap_context);	/* read received data */
+      coap_dispatch(coap_context); /* and dispatch PDUs from receivequeue */
+    }
+  }
+
+  PROCESS_END();
+}
+/*---------------------------------------------------------------------------*/
diff --git a/components/coap/libcoap/examples/contiki/radvd.conf.sample b/components/coap/libcoap/examples/contiki/radvd.conf.sample
new file mode 100644
index 00000000..26c218ba
--- /dev/null
+++ b/components/coap/libcoap/examples/contiki/radvd.conf.sample
@@ -0,0 +1,14 @@
+interface tap0
+{
+   AdvSendAdvert on;
+   MinRtrAdvInterval 3;
+   MaxRtrAdvInterval 20;
+
+   prefix aaaa::/64
+   {
+  	AdvOnLink on; 
+        AdvAutonomous on; 
+        AdvRouterAddr on; 
+
+   };
+};   
diff --git a/components/coap/libcoap/examples/contiki/server.c b/components/coap/libcoap/examples/contiki/server.c
new file mode 100644
index 00000000..7d33235b
--- /dev/null
+++ b/components/coap/libcoap/examples/contiki/server.c
@@ -0,0 +1,231 @@
+/* coap-server.c -- Example CoAP server using Contiki and libcoap
+ *
+ * Copyright (C) 2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * 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.
+ *
+ * This file is part of the Contiki operating system.
+ *
+ */
+
+#include "coap_config.h"
+
+#define DEBUG DEBUG_PRINT
+#include "net/ip/uip-debug.h"
+#include "net/net-debug.h"
+
+#include <string.h>
+
+#include "debug.h"
+#include "coap.h"
+
+static coap_context_t *coap_context;
+
+static clock_time_t clock_offset;
+/* changeable clock base (see handle_put_time()) */
+static clock_time_t my_clock_base = 0;
+static coap_resource_t *time_resource = NULL; /* just for testing */
+
+PROCESS(coap_server_process, "CoAP server process");
+AUTOSTART_PROCESSES(&coap_server_process);
+/*---------------------------------------------------------------------------*/
+void
+init_coap_server(coap_context_t **ctx) {
+  coap_address_t listen_addr;
+  uip_ipaddr_t gw_addr;
+
+  assert(ctx);
+
+  coap_set_log_level(LOG_DEBUG);
+  
+  coap_address_init(&listen_addr);
+  listen_addr.port = UIP_HTONS(COAP_DEFAULT_PORT);
+
+  uip_ip6addr(&listen_addr.addr, 0xaaaa, 0, 0, 0, 0, 0, 0, NODE_ADDR);
+#ifndef CONTIKI_TARGET_MINIMAL_NET
+  uip_ds6_prefix_add(&listen_addr.addr, 64, 0, 0, 0, 0);
+#endif /* not CONTIKI_TARGET_MINIMAL_NET */
+  
+  uip_ds6_addr_add(&listen_addr.addr, 0, ADDR_MANUAL);
+
+  /* set default route to gateway aaaa::1 */
+  uip_ip6addr(&gw_addr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0x0001);
+  uip_ds6_defrt_add(&gw_addr, 0);
+
+  PRINTLLADDR(&uip_lladdr);
+  printf("\r\n");
+  PRINT6ADDR(&listen_addr.addr);
+  printf("\r\n");
+
+  *ctx = coap_new_context(&listen_addr);
+
+  if (!*ctx) {
+    coap_log(LOG_CRIT, "cannot create CoAP context\r\n");
+  }
+}
+
+/*---------------------------------------------------------------------------*/
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+void 
+hnd_get_time(coap_context_t  *ctx, struct coap_resource_t *resource,
+	     const coap_endpoint_t *local_interface,
+	     coap_address_t *peer, coap_pdu_t *request, str *token, 
+	     coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  unsigned char buf[40];
+  size_t len;
+  coap_tick_t now;
+  coap_tick_t t;
+
+  /* FIXME: return time, e.g. in human-readable by default and ticks
+   * when query ?ticks is given. */
+
+  /* if my_clock_base was deleted, we pretend to have no such resource */
+  response->hdr->code = 
+    my_clock_base ? COAP_RESPONSE_CODE(205) : COAP_RESPONSE_CODE(404);
+
+  if (coap_find_observer(resource, peer, token)) {
+    /* FIXME: need to check for resource->dirty? */
+    coap_add_option(response, COAP_OPTION_OBSERVE, 
+		    coap_encode_var_bytes(buf, ctx->observe), buf);
+  }
+
+  if (my_clock_base)
+    coap_add_option(response, COAP_OPTION_CONTENT_FORMAT,
+		    coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_add_option(response, COAP_OPTION_MAXAGE,
+	  coap_encode_var_bytes(buf, 0x01), buf);
+
+  if (my_clock_base) {
+
+    /* calculate current time */
+    coap_ticks(&t);
+    now = my_clock_base + (t / COAP_TICKS_PER_SECOND);
+    
+    if (request != NULL
+	&& (option = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter))
+	&& memcmp(COAP_OPT_VALUE(option), "ticks",
+		  min(5, COAP_OPT_LENGTH(option))) == 0) {
+      /* output ticks */
+      len = snprintf((char *)buf, 
+	   min(sizeof(buf), response->max_size - response->length),
+		     "%u", (unsigned int)now);
+      coap_add_data(response, len, buf);
+
+    }
+  }
+}
+
+void
+init_coap_resources(coap_context_t *ctx) {
+  coap_resource_t *r;
+#if 0
+  r = coap_resource_init(NULL, 0, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_index);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"General Info\"", 14, 0);
+  coap_add_resource(ctx, r);
+#endif
+  /* store clock base to use in /time */
+  my_clock_base = clock_offset;
+
+  r = coap_resource_init((unsigned char *)"time", 4, 0);
+  if (!r)
+    goto error;
+
+  r->observable = 1;
+  time_resource = r;
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_time);
+#if 0
+  coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_time);
+  coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_time);
+#endif
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  /* coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"Internal Clock\"", 16, 0); */
+  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"\"Ticks\"", 7, 0);
+  coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"clock\"", 7, 0);
+
+  coap_add_resource(ctx, r);
+#if 0
+#ifndef WITHOUT_ASYNC
+  r = coap_resource_init((unsigned char *)"async", 5, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_async);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_resource(ctx, r);
+#endif /* WITHOUT_ASYNC */
+#endif
+
+  return;
+ error:
+  coap_log(LOG_CRIT, "cannot create resource\n");
+}
+
+/* struct etimer notify_timer; */
+struct etimer dirty_timer;
+
+/*---------------------------------------------------------------------------*/
+PROCESS_THREAD(coap_server_process, ev, data)
+{
+  PROCESS_BEGIN();
+
+  clock_offset = clock_time();
+  init_coap_server(&coap_context);
+
+  if (!coap_context) {
+    coap_log(LOG_EMERG, "cannot create context\n");
+    PROCESS_EXIT();
+  }
+
+  init_coap_resources(coap_context);
+
+  if (!coap_context) {
+    coap_log(LOG_EMERG, "cannot create context\n");
+    PROCESS_EXIT();
+  }
+
+  /* etimer_set(&notify_timer, 5 * CLOCK_SECOND); */
+  etimer_set(&dirty_timer, 30 * CLOCK_SECOND);
+
+  while(1) {
+    PROCESS_YIELD();
+    if(ev == tcpip_event) {
+      coap_read(coap_context);	/* read received data */
+      /* coap_dispatch(coap_context); /\* and dispatch PDUs from receivequeue *\/ */
+    } else if (ev == PROCESS_EVENT_TIMER && etimer_expired(&dirty_timer)) {
+      time_resource->dirty = 1;
+      etimer_reset(&dirty_timer);
+    }
+  }
+
+  PROCESS_END();
+}
+/*---------------------------------------------------------------------------*/
diff --git a/components/coap/libcoap/examples/etsi_coaptest.sh b/components/coap/libcoap/examples/etsi_coaptest.sh
new file mode 100755
index 00000000..3226a254
--- /dev/null
+++ b/components/coap/libcoap/examples/etsi_coaptest.sh
@@ -0,0 +1,210 @@
+#!/bin/bash
+
+# test coap implementation for the ETSI CoAP Plugtest in March 2012
+# with test cases described in Plugtests Guide First Draft V0.0.16
+
+COAP_CLIENT=./coap-client
+tcpdump=/usr/sbin/tcpdump
+DEFAULTPORT=5683
+CLIENTPORT=61701
+# directory for logging
+LOGDIR=logs
+# set client's verbose level
+callopts=" -v 5"
+longtimeout=180
+clienttimeout=$longtimeout
+timeoutcmd=/usr/bin/timeout
+
+#URIREGEX=.*\/.*
+# resembles approximately an ip address
+IPADDRREGEX="^[1-2]?[0-9]{1,2}\.[1-2]?[0-9]{1,2}\.[1-2]?[0-9]{1,2}\.[1-2]?[0-9]{1,2}"
+# FIXME IPV6 address
+IP6REGEX=".*:.*:.*"
+
+# Testcase groups
+CORE=( TD_COAP_CORE_01 TD_COAP_CORE_02 TD_COAP_CORE_03
+TD_COAP_CORE_04 TD_COAP_CORE_05 TD_COAP_CORE_06 TD_COAP_CORE_07
+TD_COAP_CORE_08 TD_COAP_CORE_09 TD_COAP_CORE_10 TD_COAP_CORE_11
+TD_COAP_CORE_12 TD_COAP_CORE_13 TD_COAP_CORE_14 TD_COAP_CORE_15 )
+LINK=( TD_COAP_LINK_01 TD_COAP_LINK_02 )
+BLOCK=( TD_COAP_BLOCK_01 TD_COAP_BLOCK_02 TD_COAP_BLOCK_03 TD_COAP_BLOCK_04 )
+OBS=( TD_COAP_OBS_01 TD_COAP_OBS_02 TD_COAP_OBS_03 TD_COAP_OBS_04 TD_COAP_OBS_05 )
+
+testgroups=( CORE LINK BLOCK OBS )
+
+# if no test cases are specified, we want to run all tests
+testnumber=-1
+group=''
+
+source etsi_testcases.sh
+
+function usage {
+echo "Usage:  `basename $0` [-n testnumber] [-g groupname] [-t timeout] [-P server_port] [-p client port] [-d logdir] [-v] -i interface server_address" 1>&2
+echo "-n test case to be accomplished" 1>&2
+echo "-g group to be tested" 1>&2
+echo "-t time in seconds until timout for single test" 1>&2
+echo "-i interface to use for tcpdump" 1>&2
+echo "-P port of server" 1>&2
+echo "-p port client listens on" 1>&2
+echo "-d directory for logfiles" 1>&2
+echo "-v verbose level" 1>&2
+}
+
+function run_test {
+  tn=$1
+  clientopts=''
+  if [ -z $1 ]; then
+    echo "missing argument for run_test"
+    exit 1
+  fi
+  echo -e "running test: $tn"
+  if [ $(type -t $tn) ] ; then
+    $tn $tn
+    echo
+  else
+    echo "not implemented"
+    echo
+  fi
+}
+
+while getopts "n:g:t:i:P:p:d:v" OPTION;
+do
+# A missing argument for an option leads getopts to take the next
+# option as the parameter. We want to prevent that.
+case $OPTARG in
+-*) echo "Missing argument for option \"-$OPTION\"."
+echo $USAGE
+exit 1
+;;
+esac
+
+case $OPTION in
+n) # number of test case
+testnumber=$((OPTARG-1))
+;;
+
+g) # name of test group
+# is there a group with that name?
+for i in "${testgroups[@]}"
+  do 
+  # group doesn't have to be case sensitive
+  tmpgroup=$(echo $OPTARG | tr '[:lower:]' '[:upper:]')
+  if [  $i == $tmpgroup ] ; then
+    group=$tmpgroup
+    break
+  fi
+done
+if [ -z $group ] ; then
+  echo "No such group:" $OPTARG". Available groups are: ${testgroups[@]}"
+  exit 1
+fi
+;;
+
+t)
+# add timeout to client parameters
+clienttimeout=$((OPTARG))
+callopts="$callopts -B $clienttimeout"
+;;
+
+i)
+# interface tcpdump listens on
+INTERFACE=$OPTARG
+;;
+
+P)
+# port the server listens on
+SERVERPORT=$((OPTARG))
+;;
+
+p)
+# port the client listens on
+CLIENTPORT=$((OPTARG))
+;;
+
+d)
+# directory tcpdump writes the logfiles into
+LOGDIR=$OPTARG
+;;
+
+v)
+verbose=1
+;;
+
+?)
+# any other option is invalid
+echo -e $USAGE 1>&2
+exit 1
+;;
+esac
+done
+
+# catch last argument: server address
+ARGS=$(($#+1))
+SERVERADDRESS=${@: -1}
+
+if [[ ! $((ARGS-OPTIND)) -eq 1 ]]; then
+  echo -e "\nno server address specified"
+  usage
+  exit 1
+fi
+
+# if no port number was specified by user, the server address for the
+# coap-client is $SERVERADDRESS
+
+if [ -z $SERVERPORT ]; then
+  SERVERPORT=$DEFAULTPORT
+  if [[ $SERVERADDRESS =~ $IP6REGEX ]]; then
+    SERVERTUP=\[$SERVERADDRESS\]
+  else
+    SERVERTUP=$SERVERADDRESS
+  fi
+else
+   if [[ $SERVERADDRESS =~ $IP6REGEX ]]; then
+    SERVERTUP=\[$SERVERADDRESS\]:$SERVERPORT
+  else
+    SERVERTUP=$SERVERADDRESS:$SERVERPORT
+  fi
+fi
+
+# create directory for logging, if it's not already there
+if [[ ! -e $LOGDIR ]]; then
+  mkdir -p $LOGDIR
+  if [ $? ]; then
+    echo created directory \""$LOGDIR"\" for logging
+  fi
+fi
+
+# the interface for tcpdump is mandatory
+if [ -z $INTERFACE ]; then
+  echo -e "\nno interface given"
+  exit 1
+fi
+
+# determine which tests to run
+if [ -n "$group" ] ; then
+  echo group: $group
+  if [[ ! $testnumber -eq -1 ]] ; then
+    groupsize=$(eval "echo \${#$(echo $group)[@]}")
+    # is there a testcase with number $testnumber in group $group
+    if [ $testnumber -ge $groupsize -o $testnumber -lt 0 ] ; then
+      echo "No such testcase number: $OPTARG. Test cases numbers are 1 to" $groupsize
+      exit 1
+    else
+      # run test with group $group and number $testnumber
+      run_test $(eval "echo \${$(echo $group)[$testnumber]}")
+    fi
+  else
+    # if no testnumber was specified, we want to run all tests in that group
+    for i in $(eval "echo \${$(echo $group)[@]}") ; do
+      run_test $i
+    done
+  fi
+else
+    # run all tests of all groups
+    for j in ${testgroups[@]} ; do
+      echo "group: $j"
+      for k in $(eval "echo \${$(echo $j)[@]}") ; do
+        run_test $k
+      done
+    done
+fi
diff --git a/components/coap/libcoap/examples/etsi_iot_01.c b/components/coap/libcoap/examples/etsi_iot_01.c
new file mode 100644
index 00000000..0edc8a93
--- /dev/null
+++ b/components/coap/libcoap/examples/etsi_iot_01.c
@@ -0,0 +1,759 @@
+/* CoAP server for first ETSI CoAP plugtest, March 2012
+ *
+ * Copyright (C) 2012--2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "config.h"
+#include "uthash.h"
+#include "coap.h"
+
+#define COAP_RESOURCE_CHECK_TIME_SEC  1
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+/* temporary storage for dynamic resource representations */
+static int quit = 0;
+
+#define COAP_OPT_BLOCK_SZX_MAX 6 /**< allowed maximum for block szx value */
+
+#define REQUIRE_ETAG 0x01 	/* flag for coap_payload_t: require ETag option  */
+typedef struct {
+  UT_hash_handle hh;
+  coap_key_t resource_key;	/* foreign key that points into resource space */
+  unsigned int flags;		/* some flags to control behavior */
+  size_t max_data;		/* maximum size allocated for @p data */
+  uint16_t media_type;		/* media type for this object */
+  size_t length;		/* length of data */
+  unsigned char data[];		/* the actual contents */
+} coap_payload_t;
+
+coap_payload_t *test_resources = NULL;
+
+/** 
+ * This structure is used to store URIs for dynamically allocated
+ * resources, usually by POST or PUT.
+ */
+typedef struct {
+  UT_hash_handle hh;
+  coap_key_t resource_key;	/* foreign key that points into resource space */
+  size_t length;		/* length of data */
+  unsigned char data[];		/* the actual contents */
+} coap_dynamic_uri_t;
+
+coap_dynamic_uri_t *test_dynamic_uris = NULL;
+
+/* This variable is used to mimic long-running tasks that require
+ * asynchronous responses. */
+static coap_async_state_t *async = NULL;
+
+/* SIGINT handler: set quit to 1 for graceful termination */
+void
+handle_sigint(int signum) {
+  quit = 1;
+}
+
+#define INDEX "libcoap server for ETSI CoAP Plugtest, March 2012, Paris\n" \
+   	      "Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
+
+coap_payload_t *
+coap_new_payload(size_t size) {
+  coap_payload_t *p;
+  p = (coap_payload_t *)coap_malloc(sizeof(coap_payload_t) + size);
+  if (p) {
+    memset(p, 0, sizeof(coap_payload_t));
+    p->max_data = size;
+  }
+
+  return p;
+}
+
+static inline coap_payload_t *
+coap_find_payload(const coap_key_t key) {
+  coap_payload_t *p;
+  HASH_FIND(hh, test_resources, key, sizeof(coap_key_t), p);
+  return p;
+}
+
+static inline void
+coap_add_payload(const coap_key_t key, coap_payload_t *payload,
+		 coap_dynamic_uri_t *uri) {
+  assert(payload);
+  
+  memcpy(payload->resource_key, key, sizeof(coap_key_t));
+  HASH_ADD(hh, test_resources, resource_key, sizeof(coap_key_t), payload);
+
+  if (uri) {
+    memcpy(uri->resource_key, key, sizeof(coap_key_t));
+    HASH_ADD(hh, test_dynamic_uris, resource_key, sizeof(coap_key_t), uri);
+  }
+}
+
+static inline void
+coap_delete_payload(coap_payload_t *payload) {
+  if (payload) {
+    coap_dynamic_uri_t *uri;
+    HASH_FIND(hh, test_dynamic_uris, 
+	      payload->resource_key, sizeof(coap_key_t), uri);
+    if (uri) {
+      HASH_DELETE(hh, test_dynamic_uris, uri);
+      coap_free(uri);
+    }
+  }
+
+  HASH_DELETE(hh, test_resources, payload);
+  coap_free(payload);
+}
+
+void 
+hnd_get_index(coap_context_t  *ctx, struct coap_resource_t *resource, 
+	      coap_address_t *peer, coap_pdu_t *request, str *token,
+	      coap_pdu_t *response) {
+  unsigned char buf[3];
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
+	  coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_add_option(response, COAP_OPTION_MAXAGE,
+	  coap_encode_var_bytes(buf, 0x2ffff), buf);
+    
+  coap_add_data(response, strlen(INDEX), (unsigned char *)INDEX);
+}
+
+
+void 
+hnd_get_resource(coap_context_t  *ctx, struct coap_resource_t *resource, 
+		 coap_address_t *peer, coap_pdu_t *request, str *token,
+		 coap_pdu_t *response) {
+  coap_key_t etag;
+  unsigned char buf[2];
+  coap_payload_t *test_payload;
+  coap_block_t block;
+
+  test_payload = coap_find_payload(resource->key);
+  if (!test_payload) {
+    response->hdr->code = COAP_RESPONSE_CODE(500);
+    
+    return;
+  }
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
+	  coap_encode_var_bytes(buf, test_payload->media_type), buf);
+
+  /* add etag for the resource */
+  if (test_payload->flags & REQUIRE_ETAG) {
+    memset(etag, 0, sizeof(etag));
+    coap_hash(test_payload->data, test_payload->length, etag);
+    coap_add_option(response, COAP_OPTION_ETAG, sizeof(etag), etag);
+  }
+      
+  if (request) {
+    int res;
+
+    if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
+      res = coap_write_block_opt(&block, COAP_OPTION_BLOCK2, response,
+				 test_payload->length);
+
+      switch (res) {
+      case -2:			/* illegal block */
+	response->hdr->code = COAP_RESPONSE_CODE(400);
+	goto error;
+      case -1:			/* should really not happen */
+	assert(0);
+	/* fall through if assert is a no-op */
+      case -3:			/* cannot handle request */
+	response->hdr->code = COAP_RESPONSE_CODE(500);
+	goto error;
+      default:			/* everything is good */
+	;
+      }
+      
+      coap_add_block(response, test_payload->length, test_payload->data,
+		     block.num, block.szx);
+    } else {
+      if (!coap_add_data(response, test_payload->length, test_payload->data)) {
+	/* set initial block size, will be lowered by
+	 * coap_write_block_opt) automatically */
+	block.szx = 6;
+	coap_write_block_opt(&block, COAP_OPTION_BLOCK2, response,
+			     test_payload->length);
+	
+	coap_add_block(response, test_payload->length, test_payload->data,
+		       block.num, block.szx);	
+      }
+    }    
+  } else {		      /* this is a notification, block is 0 */
+    /* FIXME: need to store block size with subscription */
+  }
+  
+  return;
+
+ error:
+  coap_add_data(response, 
+		strlen(coap_response_phrase(response->hdr->code)),
+		(unsigned char *)coap_response_phrase(response->hdr->code));
+}
+
+/* DELETE handler for dynamic resources created by POST /test */
+void 
+hnd_delete_resource(coap_context_t  *ctx, struct coap_resource_t *resource, 
+		coap_address_t *peer, coap_pdu_t *request, str *token,
+		coap_pdu_t *response) {
+  coap_payload_t *payload;
+
+  payload = coap_find_payload(resource->key);
+
+  if (payload)
+    coap_delete_payload(payload);
+
+  coap_delete_resource(ctx, resource->key);
+
+  response->hdr->code = COAP_RESPONSE_CODE(202);
+}
+
+void 
+hnd_post_test(coap_context_t  *ctx, struct coap_resource_t *resource, 
+	      coap_address_t *peer, coap_pdu_t *request, str *token,
+	      coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  coap_payload_t *test_payload;
+  size_t len;
+  size_t l = 6 + sizeof(void *);
+  coap_dynamic_uri_t *uri;
+  unsigned char *data;
+
+#define BUFSIZE 20
+  int res;
+  unsigned char _buf[BUFSIZE];
+  unsigned char *buf = _buf;
+  size_t buflen = BUFSIZE;
+
+  coap_get_data(request, &len, &data);
+
+  /* allocate storage for resource and to hold URI */
+  test_payload = coap_new_payload(len);
+  uri = (coap_dynamic_uri_t *)coap_malloc(sizeof(coap_dynamic_uri_t) + l);
+  if (!(test_payload && uri)) {
+    coap_log(LOG_CRIT, "cannot allocate new resource under /test");
+    response->hdr->code = COAP_RESPONSE_CODE(500);    
+    coap_free(test_payload);
+    coap_free(uri);
+  } else {
+    coap_resource_t *r;
+
+    memset(uri, 0, sizeof(coap_dynamic_uri_t));
+    uri->length = min(l, snprintf((char *)uri->data, l, "test/%p", test_payload));
+    test_payload->length = len;
+
+    memcpy(test_payload->data, data, len);
+
+    r = coap_resource_init(uri->data, uri->length, 0);
+    coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource);
+    coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_resource);
+
+    /* set media_type if available */
+    option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter);
+    if (option) {
+      test_payload->media_type = 
+	coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
+    }
+
+    coap_add_resource(ctx, r);
+    coap_add_payload(r->key, test_payload, uri);
+
+    /* add Location-Path */
+    res = coap_split_path(uri->data, uri->length, buf, &buflen);
+
+    while (res--) {
+      coap_add_option(response, COAP_OPTION_LOCATION_PATH,
+		      COAP_OPT_LENGTH(buf), COAP_OPT_VALUE(buf));
+      
+      buf += COAP_OPT_SIZE(buf);      
+    }
+
+    response->hdr->code = COAP_RESPONSE_CODE(201);
+  }
+
+}
+
+void 
+hnd_put_test(coap_context_t  *ctx, struct coap_resource_t *resource, 
+	      coap_address_t *peer, coap_pdu_t *request, str *token,
+	      coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  coap_payload_t *payload;
+  size_t len;
+  unsigned char *data;
+
+  response->hdr->code = COAP_RESPONSE_CODE(204);
+
+  coap_get_data(request, &len, &data);
+
+  payload = coap_find_payload(resource->key);
+  if (payload && payload->max_data < len) { /* need more storage */
+    coap_delete_payload(payload);
+    payload = NULL;
+    /* bug: when subsequent coap_new_payload() fails, our old contents
+       is gone */
+  }
+
+  if (!payload) {		/* create new payload */
+    payload = coap_new_payload(len);
+    if (!payload)
+      goto error;
+
+    coap_add_payload(resource->key, payload, NULL);
+  } 
+  payload->length = len;
+  memcpy(payload->data, data, len);
+
+  option = coap_check_option(request, COAP_OPTION_CONTENT_TYPE, &opt_iter);
+  if (option) {
+    /* set media type given in request */
+    payload->media_type = 
+      coap_decode_var_bytes(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option));
+  } else {
+    /* set default value */
+    payload->media_type = COAP_MEDIATYPE_TEXT_PLAIN;
+  }
+  /* FIXME: need to change attribute ct of resource. 
+     To do so, we need dynamic management of the attribute value
+  */
+
+  return;
+ error:
+  warn("cannot modify resource\n");
+  response->hdr->code = COAP_RESPONSE_CODE(500);
+}
+
+void 
+hnd_delete_test(coap_context_t  *ctx, struct coap_resource_t *resource, 
+		coap_address_t *peer, coap_pdu_t *request, str *token,
+		coap_pdu_t *response) {
+  /* the ETSI validation tool does not like empty resources... */
+#if 0
+  coap_payload_t *payload;
+  payload = coap_find_payload(resource->key);
+
+  if (payload)
+    payload->length = 0;
+#endif
+
+  response->hdr->code = COAP_RESPONSE_CODE(202);
+}
+
+void 
+hnd_get_query(coap_context_t  *ctx, struct coap_resource_t *resource, 
+	      coap_address_t *peer, coap_pdu_t *request, str *token,
+	      coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_filter_t f;
+  coap_opt_t *q;
+  size_t len, L;
+  unsigned char buf[70];
+
+  response->hdr->code = COAP_RESPONSE_CODE(205);
+
+  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
+	  coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_option_filter_clear(f);
+  coap_option_setb(f, COAP_OPTION_URI_QUERY);
+  
+  coap_option_iterator_init(request, &opt_iter, f);
+  
+  len = 0;
+  while ((len < sizeof(buf)) && (q = coap_option_next(&opt_iter))) {
+    L = min(sizeof(buf) - len, 11);
+    memcpy(buf + len, "Uri-Query: ", L);
+    len += L;
+
+    L = min(sizeof(buf) - len, COAP_OPT_LENGTH(q));
+    memcpy(buf + len, COAP_OPT_VALUE(q), L);
+    len += L;
+    
+    if (len < sizeof(buf))
+      buf[len++] = '\n';
+  }
+  
+  coap_add_data(response, len, buf);
+}
+
+/* handler for TD_COAP_CORE_16 */
+void 
+hnd_get_separate(coap_context_t  *ctx, struct coap_resource_t *resource, 
+		 coap_address_t *peer, coap_pdu_t *request, str *token,
+		 coap_pdu_t *response) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  coap_opt_filter_t f;
+  unsigned long delay = 5;
+
+  if (async) {
+    if (async->id != request->hdr->id) {
+      coap_opt_filter_t f;
+      coap_option_filter_clear(f);
+      response->hdr->code = COAP_RESPONSE_CODE(503);
+    }
+    return;
+  }
+
+  /* search for option delay in query list */
+  coap_option_filter_clear(f);
+  coap_option_setb(f, COAP_OPTION_URI_QUERY);
+  
+  coap_option_iterator_init(request, &opt_iter, f);
+  
+  while ((option = coap_option_next(&opt_iter))) {
+    if (strncmp("delay=", (char *)COAP_OPT_VALUE(option), 6) == 0) {
+      int i;
+      unsigned long d = 0;
+      
+      for (i = 6; i < COAP_OPT_LENGTH(option); ++i)
+	d = d * 10 + COAP_OPT_VALUE(option)[i] - '0';
+
+      /* don't allow delay to be less than COAP_RESOURCE_CHECK_TIME*/
+      delay = d < COAP_RESOURCE_CHECK_TIME_SEC 
+	? COAP_RESOURCE_CHECK_TIME_SEC
+	: d;
+      debug("set delay to %lu\n", delay);
+      break;
+    }
+  }
+
+  async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE,
+			      (void *)(COAP_TICKS_PER_SECOND * delay));
+}
+
+void 
+check_async(coap_context_t  *ctx, coap_tick_t now) {
+  coap_pdu_t *response;
+  coap_async_state_t *tmp;
+  unsigned char buf[2];
+  size_t size = sizeof(coap_hdr_t) + 8;
+
+  if (!async || now < async->created + (unsigned long)async->appdata) 
+    return;
+
+  size += async->tokenlen;
+
+  response = coap_pdu_init(async->flags & COAP_ASYNC_CONFIRM 
+			   ? COAP_MESSAGE_CON
+			   : COAP_MESSAGE_NON, 
+			   COAP_RESPONSE_CODE(205), 0, size);
+  if (!response) {
+    debug("check_async: insufficient memory, we'll try later\n");
+    async->appdata = 
+      (void *)((unsigned long)async->appdata + 15 * COAP_TICKS_PER_SECOND);
+    return;
+  }
+  
+  response->hdr->id = coap_new_message_id(ctx);
+
+  if (async->tokenlen)
+    coap_add_token(response, async->tokenlen, async->token);
+
+  coap_add_option(response, COAP_OPTION_CONTENT_TYPE,
+		  coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+
+  coap_add_data(response, 4, (unsigned char *)"done");
+
+  if (coap_send(ctx, &async->peer, response) == COAP_INVALID_TID) {
+    debug("check_async: cannot send response for message %d\n", 
+	  response->hdr->id);
+  }
+  coap_delete_pdu(response);
+  
+  coap_remove_async(ctx, async->id, &tmp);
+  coap_free_async(async);
+  async = NULL;
+}
+
+coap_payload_t *
+make_large(char *filename) {
+  coap_payload_t *payload;
+  FILE *inputfile = NULL;
+  struct stat statbuf;
+
+  if (!filename)
+    return NULL;
+
+  /* read from specified input file */
+  if (stat(filename, &statbuf) < 0) {
+    warn("cannot stat file %s\n", filename);
+    return NULL;
+  }
+
+  payload = coap_new_payload(statbuf.st_size);
+  if (!payload)
+    return NULL;
+
+  inputfile = fopen(filename, "r");
+  if ( !inputfile ) {
+    warn("cannot read file %s\n", filename);
+    coap_free(payload);
+    return NULL;
+  }
+
+  payload->length = fread(payload->data, 1, statbuf.st_size, inputfile);
+  payload->media_type = 41;
+
+  fclose(inputfile);
+
+  return payload;
+}
+
+void
+init_resources(coap_context_t *ctx) {
+  coap_resource_t *r;
+  coap_payload_t *test_payload;
+
+  test_payload = coap_new_payload(200);
+  if (!test_payload)
+    coap_log(LOG_CRIT, "cannot allocate resource /test");
+  else {
+    test_payload->length = 13;
+    memcpy(test_payload->data, "put data here", test_payload->length);
+    /* test_payload->media_type is 0 anyway */
+
+    r = coap_resource_init((unsigned char *)"test", 4, 0);
+    coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource);
+    coap_register_handler(r, COAP_REQUEST_POST, hnd_post_test);
+    coap_register_handler(r, COAP_REQUEST_PUT, hnd_put_test);
+    coap_register_handler(r, COAP_REQUEST_DELETE, hnd_delete_test);
+
+    coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+    coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"test", 4, 0);
+    coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"core#b", 6, 0);
+#if 0
+    coap_add_attr(r, (unsigned char *)"obs", 3, NULL, 0, 0);
+#endif
+    coap_add_resource(ctx, r);
+    coap_add_payload(r->key, test_payload, NULL);
+  }
+
+  /* TD_COAP_BLOCK_01 
+   * TD_COAP_BLOCK_02 */
+  test_payload = make_large("etsi_iot_01_largedata.txt");
+  if (!test_payload)
+    coap_log(LOG_CRIT, "cannot allocate resource /large\n");
+  else {
+    r = coap_resource_init((unsigned char *)"large", 5, 0);
+    coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource);
+
+    coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"41", 2, 0);
+    coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"large", 5, 0);
+    coap_add_resource(ctx, r);
+
+    test_payload->flags |= REQUIRE_ETAG;
+
+    coap_add_payload(r->key, test_payload, NULL);
+  }
+
+  /* For TD_COAP_CORE_12 */
+  test_payload = coap_new_payload(20);
+  if (!test_payload)
+    coap_log(LOG_CRIT, "cannot allocate resource /seg1/seg2/seg3\n");
+  else {
+    test_payload->length = 10;
+    memcpy(test_payload->data, "segsegseg!", test_payload->length);
+    /* test_payload->media_type is 0 anyway */
+
+    r = coap_resource_init((unsigned char *)"seg1/seg2/seg3", 14, 0);
+    coap_register_handler(r, COAP_REQUEST_GET, hnd_get_resource);
+
+    coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+    coap_add_resource(ctx, r);
+
+    coap_add_payload(r->key, test_payload, NULL);
+  }
+
+  /* For TD_COAP_CORE_13 */
+  r = coap_resource_init((unsigned char *)"query", 5, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_query);
+  
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_resource(ctx, r);
+  
+  /* For TD_COAP_CORE_16 */
+  r = coap_resource_init((unsigned char *)"separate", 8, 0);
+  coap_register_handler(r, COAP_REQUEST_GET, hnd_get_separate);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_attr(r, (unsigned char *)"rt", 2, (unsigned char *)"separate", 8, 0);
+  coap_add_resource(ctx, r);
+}
+
+void
+usage( const char *program, const char *version) {
+  const char *p;
+
+  p = strrchr( program, '/' );
+  if ( p )
+    program = ++p;
+
+  fprintf( stderr, "%s v%s -- ETSI CoAP plugtest server\n"
+	   "(c) 2012 Olaf Bergmann <bergmann@tzi.org>\n\n"
+	   "usage: %s [-A address] [-p port]\n\n"
+	   "\t-A address\tinterface address to bind to\n"
+	   "\t-p port\t\tlisten on specified port\n"
+	   "\t-v num\t\tverbosity level (default: 3)\n",
+	   program, version, program );
+}
+
+coap_context_t *
+get_context(const char *node, const char *port) {
+  coap_context_t *ctx = NULL;  
+  int s;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+  
+  s = getaddrinfo(node, port, &hints, &result);
+  if ( s != 0 ) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+    return NULL;
+  } 
+
+  /* iterate through results until success */
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    coap_address_t addr;
+
+    if (rp->ai_addrlen <= sizeof(addr.addr)) {
+      coap_address_init(&addr);
+      addr.size = rp->ai_addrlen;
+      memcpy(&addr.addr, rp->ai_addr, rp->ai_addrlen);
+
+      ctx = coap_new_context(&addr);
+      if (ctx) {
+	/* TODO: output address:port for successful binding */
+	goto finish;
+      }
+    }
+  }
+  
+  fprintf(stderr, "no context available for interface '%s'\n", node);
+
+ finish:
+  freeaddrinfo(result);
+  return ctx;
+}
+
+int
+main(int argc, char **argv) {
+  coap_context_t  *ctx;
+  fd_set readfds;
+  struct timeval tv, *timeout;
+  int result;
+  coap_tick_t now;
+  coap_queue_t *nextpdu;
+  char addr_str[NI_MAXHOST] = "::";
+  char port_str[NI_MAXSERV] = "5683";
+  int opt;
+  coap_log_t log_level = LOG_WARNING;
+
+  while ((opt = getopt(argc, argv, "A:p:v:")) != -1) {
+    switch (opt) {
+    case 'A' :
+      strncpy(addr_str, optarg, NI_MAXHOST-1);
+      addr_str[NI_MAXHOST - 1] = '\0';
+      break;
+    case 'p' :
+      strncpy(port_str, optarg, NI_MAXSERV-1);
+      port_str[NI_MAXSERV - 1] = '\0';
+      break;
+    case 'v' :
+      log_level = strtol(optarg, NULL, 10);
+      break;
+    default:
+      usage( argv[0], PACKAGE_VERSION );
+      exit( 1 );
+    }
+  }
+
+  coap_set_log_level(log_level);
+
+  ctx = get_context(addr_str, port_str);
+  if (!ctx)
+    return -1;
+
+  coap_register_option(ctx, COAP_OPTION_BLOCK2);
+
+  init_resources(ctx);
+
+  signal(SIGINT, handle_sigint);
+
+  while ( !quit ) {
+    FD_ZERO(&readfds);
+    FD_SET( ctx->sockfd, &readfds );
+
+    nextpdu = coap_peek_next( ctx );
+
+    coap_ticks(&now);
+    while ( nextpdu && nextpdu->t <= now ) {
+      coap_retransmit( ctx, coap_pop_next( ctx ) );
+      nextpdu = coap_peek_next( ctx );
+    }
+
+    if ( nextpdu && nextpdu->t <= now + COAP_RESOURCE_CHECK_TIME_SEC ) {
+      /* set timeout if there is a pdu to send before our automatic timeout occurs */
+      tv.tv_usec = ((nextpdu->t - now) % COAP_TICKS_PER_SECOND) * 1000000 / COAP_TICKS_PER_SECOND;
+      tv.tv_sec = (nextpdu->t - now) / COAP_TICKS_PER_SECOND;
+      timeout = &tv;
+    } else {
+      tv.tv_usec = 0;
+      tv.tv_sec = COAP_RESOURCE_CHECK_TIME_SEC;
+      timeout = &tv;
+    }
+    result = select( FD_SETSIZE, &readfds, 0, 0, timeout );
+
+    if ( result < 0 ) {		/* error */
+      if (errno != EINTR)
+	perror("select");
+    } else if ( result > 0 ) {	/* read from socket */
+      if ( FD_ISSET( ctx->sockfd, &readfds ) ) {
+	coap_read( ctx );	/* read received data */
+	coap_dispatch( ctx );	/* and dispatch PDUs from receivequeue */
+      }
+    } else {			/* timeout */
+      /* coap_check_resource_list( ctx ); */
+    }
+
+    /* check if we have to send asynchronous responses */
+    check_async(ctx, now);
+  }
+
+  coap_free_context( ctx );
+
+  return 0;
+}
diff --git a/components/coap/libcoap/examples/etsi_iot_01_largedata.txt b/components/coap/libcoap/examples/etsi_iot_01_largedata.txt
new file mode 100644
index 00000000..9f808f39
--- /dev/null
+++ b/components/coap/libcoap/examples/etsi_iot_01_largedata.txt
@@ -0,0 +1,7 @@
+<large>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec sit amet sapien ac leo bibendum suscipit at sed ipsum. Aliquam in mauris nec felis dictum lobortis a et erat. Pellentesque tempus urna vulputate purus faucibus ac pretium massa volutpat. Maecenas at tellus neque, quis elementum ante. Morbi molestie, elit placerat rhoncus faucibus, urna nunc accumsan diam, vel porta eros sem vel augue. Proin metus dolor, tristique a accumsan eget, suscipit vel ante. Suspendisse feugiat, nisl non viverra convallis, ante nibh congue lectus, sodales ultrices turpis massa sed elit.
+
+Praesent posuere laoreet nulla eu accumsan. Vestibulum consequat molestie erat, ut laoreet arcu mattis non. Maecenas viverra elementum mauris, vitae pretium elit ultrices sit amet. Sed sit amet elit sit amet dui imperdiet consequat. Donec viverra leo mollis lorem varius lacinia mollis nulla posuere. Phasellus felis odio, tempor et sodales non, facilisis fermentum eros. Duis dignissim massa at ante euismod vel laoreet mi tristique. Nulla libero dolor, pretium vitae vulputate eget, luctus at sapien. Praesent aliquam nisl ut urna pretium eu rhoncus ipsum eleifend. Sed lobortis vestibulum est eu eleifend. Sed vitae luctus erat. Sed vel dolor quam, tempor venenatis dolor.
+
+Vivamus a est a neque condimentum fermentum sed quis dui. Maecenas rhoncus imperdiet tortor, vitae viverra lectus ornare vulputate. Nam congue pulvinar faucibus. Vivamus id mauris at tortor porta volutpat. Donec non velit a tellus placerat iaculis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Suspendisse at felis ligula, vel euismod velit. Aliquam in odio urna.
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ac risus ipsum. Donec vel purus risus, eu molestie nisi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Suspendisse consequat libero eu augue ornare volutpat mollis sed dui. Ut sed. </large>
diff --git a/components/coap/libcoap/examples/etsi_testcases.sh b/components/coap/libcoap/examples/etsi_testcases.sh
new file mode 100644
index 00000000..693a8c70
--- /dev/null
+++ b/components/coap/libcoap/examples/etsi_testcases.sh
@@ -0,0 +1,765 @@
+#!/bin/bash
+
+function start_tcpdump {
+  testfunc=$1
+  logfile=$LOGDIR/"$testfunc"_$(date +%s).dump
+  tcpdumpcmd="$tcpdump -i $INTERFACE host $SERVERADDRESS and (udp port $SERVERPORT or icmp) -s0 -n -w $logfile"
+  if [ $verbose ]; then
+    echo "$tcpdumpcmd"
+    $tcpdumpcmd&
+  else
+    $tcpdumpcmd 2>/dev/null&
+  fi
+  tcpdumppid=$!
+  # wait until tcpdump is ready to write
+  for t in {0..20} ; do
+    if [ ! -e $logfile ] ; then
+      sleep 0.1
+    else
+      sleep 1
+      if [ $verbose ]; then
+        echo "tcpdump started"
+      fi
+      break
+    fi
+  done
+}
+
+function kill_tcpdump {
+  kill $tcpdumppid 2>/dev/null || ERROR=1
+  if [ $ERROR ]; then
+    echo "tcpdump failed."
+    exit 1
+  fi
+}
+
+function start_coap_test {
+  if [ -z $1 ]; then
+    echo "missing argument for start_coap_test"
+    exit 1
+  fi
+  start_tcpdump $1
+  if [ $verbose ]; then
+      echo "client command: $COAP_CLIENT $clientopts $testaddress"
+  fi
+  echo -e "\nOutput of client:"
+  # for OBS
+  if [[ ! -z $2 ]]; then
+    testfifo=/tmp/tmpfifo$(date +%s)
+    mkfifo $testfifo
+    $COAP_CLIENT $clientopts "$testaddress" &> $testfifo &
+    clientpid=$!
+    ($timeoutcmd $clienttimeout cat $testfifo | if read -n 1 char; then echo "output: $char" ; fi) 2>/dev/null
+    # when client has written an output to fifo, kill client
+    kill $clientpid
+    rm $testfifo
+    if [[ $2 == "wait" ]] ; then
+      echo "Client killed. Waiting.."
+      sleep $longtimeout
+    fi
+  else
+    $COAP_CLIENT $clientopts "$testaddress"
+  fi
+  kill_tcpdump
+}
+
+
+##
+# Perform GET (CON mode) on resource /test
+#
+# pre: resource /test exists and can handle GET with arbitrary payload
+#
+# client sends GET request with Type=0(CON) and Code=1(GET) 
+#
+# check if sent request contains Type value indicating 0 and Code
+# value indicating 1
+#
+# check if server sends response containing Code = 69(2.05 Content),
+# the same Message ID as that of previous request, content type option
+#
+# verify that server displays received information
+#
+function TD_COAP_CORE_01 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform GET (CON mode) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform POST transaction (CON mode) on resource /test: create
+# resource /test
+#
+# pre: resource /test doesn't exist but can be created on /test
+#
+# client sends POST with Type=0(CON), Code=2(POST), arbitrary payload,
+# Content type option
+#
+# check: client sends request containing Type value indicating 0 and
+# Code value indicating 2
+#
+# verify: Server displays received information
+#
+# check: server sends response containing Code=69(2.01 Created), same
+# message ID as that of the previous request, Content type option
+#
+# verify: client displays received information
+#
+function TD_COAP_CORE_02 {
+  # -t 0: content type text/plain
+  clientopts="$callopts -m post -t 0 -e sometext"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform POST (CON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform PUT transaction (CON mode) on resource /test
+#
+# pre: resource /test exists which can handle PUT
+#
+# Client sends a PUT request with Type=0(CON), Code=3(PUT), arbitrary
+# payload, content type option
+#
+# check: sent request contains Type value indicating 0 and Code value
+# indicating 3
+#
+# verify: server displays received information
+#
+# check: Server sends response containing Code=68(2.04 Changed), same
+# Message ID as that of the previous request
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_03 {
+  clientopts="$callopts -m put -t 0 -e sometext"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform PUT (CON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform DELETE transaction (CON mode) on resource /test
+#
+# pre: resource /test exists which can handle DELETE
+#
+# Client sends a DELETE request with Type=0(CON), Code=4(DELETE)
+#
+# check: sent request contains Type value indicating 0 and Code value
+# indicating 4
+#
+# check: Server sends response containing Code=66(2.02 Deleted), same
+# Message ID as that of the previous request
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_04 {
+  clientopts="$callopts -m delete"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform DELETE (CON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction (NON mode) on resource /test
+#
+# pre: resource /test exits which can handle GET
+#
+# Client sends a GET request with Type=1(NON), Code=1(GET)
+#
+# check: sent request contains Type value indicating 1 and Code value
+# indicating 1
+#
+# check: Server sends response containing Type=1(NON), Code=69(2.05
+# Content), content type option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_05 {
+  # -N: send non-confirmable message
+  clientopts="$callopts -m get -N"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform GET (NON mode) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform POST transaction (NON mode), create resource on /test
+#
+# pre: resource on /test doesn't exist but can be created
+#
+# Client sends a POST request with Type=1(NON), Code=2(POST),
+# arbitrary payload, content type option
+#
+# check: sent request contains Type value indicating 1 and Code value
+# indicating 2
+#
+# verify: Server displays the received information
+#
+# check: Server sends response containing Type=1(NON), Code=65(2.01
+# Created)
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_06 {
+  clientopts="$callopts -m post -t 0 -e sometext -N"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform POST (NON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform PUT transaction (NON mode) on resource /test
+#
+# pre: /test exists and can handle PUT
+#
+# Client sends a PUT request with Type=1(NON), Code=3(PUT),
+# arbitrary payload, content type option
+#
+# check: sent request contains Type value indicating 1 and Code value
+# indicating 3
+#
+# verify: Server displays the received information
+#
+# check: Server sends response containing Type=1(NON), Code=68(2.04
+# Changed)
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_07 {
+  clientopts="$callopts -m put -t 0 -e sometext -N"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform PUT (NON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform DELETE transaction (NON mode) on resource /test
+#
+# pre: /test exists and can handle DELETE
+#
+# Client sends a DELETE request with Type=1(NON), Code=4(DELETE)
+#
+# check: sent request contains Type value indicating 1 and Code value
+# indicating 4
+#
+# check: Server sends response containing Type=1(NON), Code=66(2.02
+# Deleted)
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_08 {
+  clientopts="$callopts -m delete -N"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform DELETE (NON) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction with a separate response on resource /separate
+#
+# pre: resource /separate exists which cannot be served immediately and which
+# cannot be acknowledged in a piggy-backed way
+#
+# Client sends a confirmable GET request to server's resource
+#
+# check: sent request contains Type=0(CON), Code=1(GET), client
+# generated Message ID
+#
+# check: Server sends response containing Type=2(ACK), message ID same
+# as the request, empty Payload
+#
+# check: Server sends response containing Type=0(CON), Code=69(2.05
+# content), Payload=Content of the requested resource, Content type option
+#
+# check: Client sends response containing Type=2(ACK), message ID same
+# as the response, empty Payload
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_09 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/separate
+  echo "perform GET (CON) on resource $testaddress which cannot be served immediately"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction with Token on resource /test
+#
+# pre: resource /test exists which can handle GET requests
+#
+# Client sends a confirmable GET request to server's resource
+# including Token option
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), client
+# generated Token value, length of the token which should be between 1
+# to 8 B, Option Type=Token
+#
+# check: Server sends response containing Code=69(2.05 content),
+# length of the token should be between 1 to 8 B, Token value same as
+# the requested, Payload=Content of the requested resource, Content
+# type option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_10 {
+  clientopts="$callopts -m get -T sometok"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform GET (CON) on resource $testaddress with Token"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction without Token on resource /test
+#
+# pre: resource /test exists which can handle GET requests
+#
+# Client sends a confirmable GET request to server's resource
+# not containing Token option
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), no Token
+# option
+#
+# check: Server sends response containing Code=69(2.05 content), no
+# Token option, Payload=Content of the requested resource, Content
+# type option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_11 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/test
+  echo "perform GET (CON mode) without Token on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction to resource /seg1/seg2/seg3
+#
+# pre: resource /seg1/seg2/seg3 exists on server
+#
+# Client sends a confirmable GET request to server's resource
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), Option
+# type=URI-Path (one for each path segment)
+#
+# check: Server sends response containing Code=69(2.05 content),
+# Payload=Content of the requested resource, Content type option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_12 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/seg1/seg2/seg3
+  echo "perform GET (CON mode) on resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction to resource /query
+#
+# pre: resource /query exists on server
+#
+# Client sends a confirmable GET request with three Query parameters
+# (e.g. ?first=1&second=2&third=3) to server's resource
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), Option
+# type=URI-Query (More than one query parameter)
+#
+# check: Server sends response containing Type=0/2(Con/ACK),
+# Code=69(2.05 content), Payload=Content of the requested resource,
+# Content type option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_13 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/query
+  query="?first=1&second=2&third=3"
+  echo -e "perform GET (CON mode) on resource $testaddress with query $query"
+  testaddress=$testaddress$query
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction to resource /test in lossy context
+#
+# pre: gateway is introduced and configured to produce packet loss,
+# resource /test exists on server
+#
+# Configuration=CoAP_CFG_02
+#
+# observe: One dropped request, one dropped request ACK, one dropped
+# response, one dropped response ACK and its retransmission, test
+# sequence should be executed several times
+#
+# Client sends a confirmable GET request to server's resource
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), Client
+# generated Message ID
+#
+# check: Server sends response containing Type=2(ACK), Code=69(2.05
+# content), Payload=Content of the requested resource, Content type
+# option
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_14 {
+  clientopts="$callopts -m get"
+  #FIXME: address for lossy context?
+  testaddress=coap://$SERVERTUP/test
+  echo "perform GET (CON mode) on resource $testaddress in lossy context"
+  start_coap_test $1
+}
+
+##
+# Perform GET transaction to resource /separate in lossy context
+#
+# pre: gateway is introduced and configured to produce packet loss,
+# resource /separate exists which cannot be served immediately and
+# which cannot be acknowledged in a piggy-backed way
+#
+# Configuration=CoAP_CFG_02
+#
+# observe: One dropped request, one dropped request ACK, one dropped
+# response, one dropped response ACK and its retransmission, test
+# sequence should be executed several times
+#
+# Client sends a confirmable GET request to server's resource
+#
+# check: sent request contains Type=0(CON) and Code=1(GET), Client
+# generated Message ID
+#
+# check: server sends response containing Type=2(ACK), Message ID same
+# as the request, empty Payload
+#
+# check: Server sends response containing Type=0(CON), Code=69(2.05
+# content), Payload=Content of the requested resource, Content type
+# option
+#
+# check: Client sends response containing Type=2(ACK), message ID same
+# as the response, empty Payload
+#
+# verify: client displays received response
+#
+function TD_COAP_CORE_15 {
+  clientopts="$callopts -m get"
+  #FIXME: address for lossy context?
+  testaddress=coap://$SERVERTUP/separate
+  echo "perform GET (CON mode) on resource $testaddress in lossy context"
+  start_coap_test $1
+}
+
+### LINK ###
+
+##
+# Access to well-known interface for resource discovery
+#
+# Pre: client supports CoRE Link Format, server supports
+# /.well-known/core resource and the CoRE Link Format
+#
+# Client retrieves Server's list of resource
+#
+# check: client sends GET request for /.well-known/core resource
+#
+# check: server sends response containing content-type option
+# indicating 40 (application/link-format), payload indicating all the
+# links available on Server
+#
+# client displays the list of resources available on Server
+#
+function TD_COAP_LINK_01 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/.well-known/core
+  echo "retrieve server's list of resource"
+  start_tcpdump $1
+  if [ $verbose ]; then 
+    echo "client command: $COAP_CLIENT $clientopts $testaddress"
+  fi
+  clientoutput=$($COAP_CLIENT $clientopts "$testaddress")
+  if [[ ! $(echo $clientoutput | grep rt) ]] ; then
+    echo "no resource with attribute rt found on server"
+  else
+    rt="${clientoutput##*rt=\"}"
+    rt="${rt%%\";*}"
+  fi
+  echo -e "\nOutput of client:"
+  echo -e $clientoutput
+  echo
+  kill_tcpdump
+}
+
+##
+# Use filtered requests for limiting discovery results
+#
+# Pre: client supports CoRE Link Format, server supports CoRE Link
+# Format and offers different types of resources (Type 1, Type 2
+# (extracted from /.well-knwon/core resource
+#
+# Client retrieves Server's list of resource of a specific Type 1
+#
+# check: client sends GET request for /.well-known/core resource
+# containing URI-Query indicating "rt=Type1"
+#
+# check: server sends response containing content-type option
+# indicating 40 (application/link-format), payload indicating only the
+# links of type Type1 available on server
+#
+# client displays the list of resources of type Type1 available on Server
+#
+function TD_COAP_LINK_02 {
+  clientopts="$callopts -m get"
+  echo "retrieve server's list of resource for appropriate type"
+  if [[ ! -z $rt ]]; then
+    testaddress="coap://$SERVERTUP/.well-known/core?rt=$rt"
+  else
+    echo "no appropriate resource found. Skipping test"
+    return
+  fi
+  start_coap_test $1
+}
+
+### BLOCK ###
+
+##
+# Perform GET blockwise transfer for large resource (early negotiation)
+#
+# pre: Client supports Block transfers, Server supports Block
+# transfers, Server offers a large resource /large, client knows
+# /large requires block transfer
+#
+# Client is requested to retrieve resource /large
+#
+# check: client sends a GET request containing Block2 option indicating block
+# number 0 and desired block size
+#
+# check: Each request contains Block2 option indicating block number
+# of the next block and size of the last received block
+#
+# check: server sends further responses containing Block2 option
+# indicating block number and size
+#
+# verify: client displays received response
+#
+function TD_COAP_BLOCK_01 {
+  clientopts="$callopts -m get -b 1024"
+  testaddress=coap://$SERVERTUP/large
+  echo "perform GET on large resource $testaddress (early negotiation)"
+  start_coap_test $1
+}
+
+##
+# Perform GET blockwise transfer for large resource (late negotiation)
+#
+# pre: Client supports Block transfers, Server supports Block
+# transfers, Server offers a large resource /large, client does not
+# know /large requires block transfer
+#
+# Client is requested to retrieve resource /large
+#
+# check: client sends a GET request not containing Block2 option
+#
+# check: server sends response containing Block2 option indicating
+# block number and size
+#
+# check: Each request contains Block2 option indicating block number
+# of the next block and size of the last received block or the desired
+# size of the next block
+#
+# check: server sends further responses containing Block2 option
+# indicating block number and size
+#
+# verify: client displays received response
+#
+function TD_COAP_BLOCK_02 {
+  clientopts="$callopts -m get"
+  testaddress=coap://$SERVERTUP/large
+  echo "perform GET blockwise transfer for large resource (late negotiation) on resource $testaddress"
+  start_coap_test $1 stop
+}
+
+##
+# Perform PUT blockwise transfer for large resource
+#
+# pre: Client supports Block transfers, Server supports Block
+# transfers, Server offers a large updatable resource /large-update
+#
+# Client is requested to retrieve resource /large-update on server
+#
+# check: client sends a PUT request containing Block1 option
+# indicating block number 0 and block size
+#
+# check: client sends further request containing Block1 option
+# indicating block number and size
+#
+# verify: server indicates presence of the complete updated resource
+# /large-update
+#
+function TD_COAP_BLOCK_03 {
+  clientopts="$callopts -m put -b 1024"
+  testaddress=coap://$SERVERTUP/large-update
+  echo "perform PUT on large resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Perform POST blockwise transfer for large resource
+#
+# pre: Client supports Block transfers, Server supports Block
+# transfers, Server accepts creation of new resources on /large-create
+#
+# Client is requested to create a new resource on server
+#
+# check: client sends a POST request containing Block1 option
+# indicating block number 0 and block size
+#
+# check: client sends further requests containing Block1 option
+# indicating block number and size
+#
+# verify: server indicates presence of the complete new resource
+#
+function TD_COAP_BLOCK_04 {
+  clientopts="$callopts -m post -b 1024"
+  testaddress=coap://$SERVERTUP/large-create
+  echo "perform POST on large resource $testaddress"
+  start_coap_test $1
+}
+
+# # OBS
+
+##
+# Handle observe option
+#
+# pre: client supports Observe option, server supports observe option,
+# server offers an observable resource /obs which changes periodically
+# (e.g. every 5s.)
+#
+# client is requested to observe resource /obs on server
+#
+# check: client sends a GET request containing observe option
+#
+# verify: client displays the received information
+#
+# check: server sends response containing observe option indicating
+# increasing values, as resource changes
+#
+# verify: client displays the updated information
+#
+function TD_COAP_OBS_01 {
+  # we need some time to verify the correct behavior
+  clientopts="$callopts -s 0" #"-v 5 -B $longtimeout -s 0"
+  testaddress=coap://$SERVERTUP/obs
+  echo "observe resource $testaddress"
+  start_coap_test $1
+}
+
+##
+# Stop resource observation
+#
+# pre: client supports Observe option, server supports observe option,
+# server offers an observable resource /obs which changes periodically
+# (e.g. every 5s.), client is observing /obs on server
+#
+# client is requested to stop observing resource /obs on server
+#
+# check: client sends a GET request not containing observe option
+#
+# verify: client displays the received information
+#
+# check: server does not send further response
+#
+# verify: client does not display the updated information
+#
+# function TD_COAP_OBS_02 {
+#   #FIXME: client does not support stopping yet
+  # we need some time to verify the correct behavior
+#   clientopts="-v 5 -B $longtimeout -s 1"
+#   testaddress=coap://$SERVERTUP/obs
+#   echo "stop observing resource $testaddress"
+#   start_coap_test $1
+# }
+
+##
+# client detection of deregistration (Max-Age)
+#
+# pre: client supports Observe option, server supports observe option,
+# server offers an observable resource /obs which changes periodically
+# (e.g. every 5s.), client is observing /obs on server
+#
+# Server is rebooted
+#
+# check: Server does not send notifications
+#
+# verify: Client does not display updated information
+#
+# verify: After Max-Age expiration, client sends a new GET with observe
+# option for Server's observable resource
+#
+# check: Sent request contains Observe option indicating 0
+#
+# check: Server sends response containing Observe option
+#
+# verify: client displays the received information
+#
+# check: Server sends response containing Observe option indicating
+# increasing values, as resource changes
+#
+# verify: Client displays the updated information
+#
+function TD_COAP_OBS_03 {
+  clientopts="$callopts -s 0"#"-v5 -B $longtimeout -s 0"
+  testaddress=coap://$SERVERTUP/obs
+  echo "client detection of deregistration (Max-Age)"
+  start_coap_test $1
+}
+
+##
+# Server detection of deregistration (client OFF)
+#
+# pre: client supports Observe option, server supports observe option,
+# server offers an observable resource /obs which changes periodically
+# (e.g. every 5s.), client is observing /obs on server
+#
+# Client is switched off
+#
+# check: Server’s confirmable responses are not acknowledged
+#
+# verify: After some delay, Server does not send further responses
+#
+function TD_COAP_OBS_04 {
+  clientopts="$callopts -s 0"
+#"-v 5 -B $longtimeout -s 0"
+  testaddress=coap://$SERVERTUP/obs
+  echo "server detection of deregistration (client off)"
+  start_coap_test $1 wait
+}
+
+##
+# Server detection of deregistration (explicit RST)
+#
+# pre: client supports Observe option, server supports observe option,
+# server offers an observable resource /obs which changes periodically
+# (e.g. every 5s.), client is observing /obs on server
+#
+# Client is rebooted
+#
+# check: Server sends response containing Observe option
+#
+# verify: Client discards response and does not display information
+#
+# check: Client sends RST to Server
+#
+# check: Server does not send further response
+#
+function TD_COAP_OBS_05 {
+  clientopts="$callopts -s 0 -p $CLIENTPORT" 
+#"-v 5 -B $longtimeout -p $CLIENTPORT -s 0"
+  testaddress=coap://$SERVERTUP/obs
+  echo "server detection of deregistration (explicit RST)"
+  start_coap_test $1 stop
+  clientopts="$callopts -p $CLIENTPORT -s 0 -N" 
+#"-v 5 -B $clienttimeout -p $CLIENTPORT -s 0 -N"
+  testaddress=coap://[::1]/obs
+  start_coap_test $1
+}
\ No newline at end of file
diff --git a/components/coap/libcoap/examples/lwip/.gitignore b/components/coap/libcoap/examples/lwip/.gitignore
new file mode 100644
index 00000000..7905765c
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/.gitignore
@@ -0,0 +1,7 @@
+# not going for submodules here to keep things easy
+lwip
+lwip-contrib
+
+# never objects, and not the resulting binary
+*.o
+server
diff --git a/components/coap/libcoap/examples/lwip/README b/components/coap/libcoap/examples/lwip/README
new file mode 100644
index 00000000..776cd36b
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/README
@@ -0,0 +1,27 @@
+Example of libcoap running on lwIP
+==================================
+
+To run the example, do
+
+    $ make
+    $ sudo ./server
+
+(and in a second terminal)
+
+    $ sudo ip a a dev tap0 192.168.0.1/24
+
+and query `coap://192.168.0.2/` with any coap tool.
+
+This will
+
+* download lwip and lwip-contrib from the upstream git sources
+* apply a required patch to lwip
+* build the server application
+* run the server application, creating a virtual network device tap0 (unless
+  that exists)
+* configure your network interface to make the server accessible.
+
+The server does not create any resources (it exposes an empty
+`.well-known/core`), but the work flow for adding more resources does not
+differ from regular libcoap usage. If you seem to run out of memory creating
+the resources, tweak the number of pre-allocated resources in `lwippools.h`.
diff --git a/components/coap/libcoap/examples/lwip/lwipopts.h b/components/coap/libcoap/examples/lwip/lwipopts.h
new file mode 100644
index 00000000..0182c598
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/lwipopts.h
@@ -0,0 +1,11 @@
+#define NO_SYS                          1
+
+/* they'd require NO_SYS=0, but are enabled by default */
+#define LWIP_SOCKET                     0
+#define LWIP_NETCONN                    0
+
+#define LWIP_IPV6                       1
+#define LWIP_IPV6_REASS                 0
+
+
+#define MEMP_USE_CUSTOM_POOLS 1
diff --git a/components/coap/libcoap/examples/lwip/server-coap.c b/components/coap/libcoap/examples/lwip/server-coap.c
new file mode 100644
index 00000000..978648f5
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/server-coap.c
@@ -0,0 +1,24 @@
+#include "coap_config.h"
+#include <coap.h>
+
+coap_context_t *main_coap_context;
+
+void server_coap_init(void)
+{
+	coap_address_t listenaddress;
+
+	coap_address_init(&listenaddress);
+
+	/* looks like a server address, but is used as end point for clients too */
+	listenaddress.addr = *(IP_ANY_TYPE);
+	listenaddress.port = COAP_DEFAULT_PORT;
+
+	main_coap_context = coap_new_context(&listenaddress);
+
+	LWIP_ASSERT("Failed to initialize context", main_coap_context != NULL);
+}
+
+void server_coap_poll(void)
+{
+	coap_check_notify(main_coap_context);
+}
diff --git a/components/coap/libcoap/examples/lwip/server-coap.h b/components/coap/libcoap/examples/lwip/server-coap.h
new file mode 100644
index 00000000..e45e263b
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/server-coap.h
@@ -0,0 +1,6 @@
+#include "coap_config.h"
+#include <coap.h>
+
+void server_coap_init(void);
+/* call this when you think that resources could be dirty */
+void server_coap_poll(void);
diff --git a/components/coap/libcoap/examples/lwip/server.c b/components/coap/libcoap/examples/lwip/server.c
new file mode 100644
index 00000000..9f806782
--- /dev/null
+++ b/components/coap/libcoap/examples/lwip/server.c
@@ -0,0 +1,91 @@
+/*
+ * Demo for libcoap on lwIP
+ *
+ * partially copied from lwip-contrib/ports/unix/proj/minimal/main.c
+ *
+ *
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * 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. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ * RT timer modifications by Christiaan Simons
+ * lwip adaptions: chrysn <chrysn@fsfe.org>
+ * also, https://savannah.nongnu.org/bugs/?40245 was applied */
+
+#include "server-coap.h"
+
+#include <lwip/init.h>
+#include <lwip/timers.h>
+
+#include <netif/etharp.h>
+#include <netif/tapif.h>
+
+#include <signal.h>
+
+static ip4_addr_t ipaddr, netmask, gw;
+
+int
+main(int argc, char **argv)
+{
+	struct netif netif;
+
+	/* startup defaults (may be overridden by one or more opts). this is
+	 * hard-coded v4 even in presence of v6, which does auto-discovery and
+	 * should thus wind up with an address of fe80::12:34ff:fe56:78ab%tap0
+	 * */
+	IP4_ADDR(&gw, 192,168,0,1);
+	IP4_ADDR(&ipaddr, 192,168,0,2);
+	IP4_ADDR(&netmask, 255,255,255,0);
+
+	lwip_init();
+
+	printf("TCP/IP initialized.\n");
+
+	netif_add(&netif, &ipaddr, &netmask, &gw, NULL, tapif_init, ethernet_input);
+	netif.flags |= NETIF_FLAG_ETHARP;
+	netif_set_default(&netif);
+	netif_set_up(&netif);
+#if LWIP_IPV6
+	netif_create_ip6_linklocal_address(&netif, 1);
+#endif 
+
+	/* start applications here */
+
+	server_coap_init();
+
+	printf("Applications started.\n");
+
+
+	while (1) {
+		/* poll netif, pass packet to lwIP */
+		tapif_select(&netif);
+
+		sys_check_timeouts();
+
+		server_coap_poll();
+	}
+
+	return 0;
+}
diff --git a/components/coap/libcoap/examples/tiny.c b/components/coap/libcoap/examples/tiny.c
new file mode 100644
index 00000000..86cef841
--- /dev/null
+++ b/components/coap/libcoap/examples/tiny.c
@@ -0,0 +1,149 @@
+/* tiny -- tiny sender
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "../coap.h"
+
+static coap_tid_t id;
+
+coap_pdu_t *
+make_pdu( unsigned int value ) {
+  coap_pdu_t *pdu;
+  unsigned char enc;
+  static unsigned char buf[20];
+  int len, ls;
+
+  if ( ! ( pdu = coap_new_pdu() ) )
+    return NULL;
+
+  pdu->hdr->type = COAP_MESSAGE_NON;
+  pdu->hdr->code = COAP_REQUEST_POST;
+  pdu->hdr->id = htons(id++);
+
+  enc = COAP_PSEUDOFP_ENCODE_8_4_DOWN(value,ls);
+  coap_add_data( pdu, 1, &enc);
+
+  len = sprintf((char *)buf, "%u", COAP_PSEUDOFP_DECODE_8_4(enc));
+  if ( len > 0 ) {
+    coap_add_data( pdu, len, buf );
+  }
+
+  return pdu;
+}
+
+void
+usage( const char *program ) {
+  const char *p;
+
+  p = strrchr( program, '/' );
+  if ( p )
+    program = ++p;
+
+  fprintf( stderr, "%s -- tiny fake sensor\n"
+	   "(c) 2010 Olaf Bergmann <bergmann@tzi.org>\n\n"
+	   "usage: %s [group address]\n"
+	   "\n\nSends some fake sensor values to specified multicast group\n",
+	   program, program );
+}
+
+coap_context_t *
+get_context(const char *node, const char *port) {
+  coap_context_t *ctx = NULL;  
+  int s;
+  struct addrinfo hints;
+  struct addrinfo *result, *rp;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+  hints.ai_socktype = SOCK_DGRAM; /* Coap uses UDP */
+  hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_ALL;
+  
+  s = getaddrinfo(node, port, &hints, &result);
+  if ( s != 0 ) {
+    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+    return NULL;
+  } 
+
+  /* iterate through results until success */
+  for (rp = result; rp != NULL; rp = rp->ai_next) {
+    ctx = coap_new_context(rp->ai_addr, rp->ai_addrlen);
+    if (ctx) {
+      /* TODO: output address:port for successful binding */
+      goto finish;
+    }
+  }
+  
+  fprintf(stderr, "no context available for interface '%s'\n", node);
+
+ finish:
+  freeaddrinfo(result);
+  return ctx;
+}
+
+int
+main(int argc, char **argv) {
+  coap_context_t  *ctx;
+  struct timeval tv;
+  coap_pdu_t  *pdu;
+  struct sockaddr_in6 dst;
+  int hops = 16;
+
+  if ( argc > 1 && strncmp(argv[1], "-h", 2) == 0 ) {
+    usage( argv[0] );
+    exit( 1 );
+  }
+
+  ctx = get_context("::", NULL);
+  if ( !ctx )
+    return -1;
+
+  id = rand() & INT_MAX;
+
+  memset(&dst, 0, sizeof(struct sockaddr_in6 ));
+  dst.sin6_family = AF_INET6;
+  inet_pton( AF_INET6, argc > 1 ? argv[1] : "::1", &dst.sin6_addr );
+  dst.sin6_port = htons( COAP_DEFAULT_PORT );
+
+  if ( IN6_IS_ADDR_MULTICAST(&dst.sin6_addr) ) {
+    /* set socket options for multicast */
+
+    if ( setsockopt( ctx->sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
+		     (char *)&hops, sizeof(hops) ) < 0 )
+      perror("setsockopt: IPV6_MULTICAST_HOPS");
+
+  }
+
+  while ( 1 ) {
+
+    if (! (pdu = make_pdu( rand() & 0xfff ) ) )
+      return -1;
+
+    coap_send( ctx, (struct sockaddr *)&dst, sizeof(dst), pdu );
+    coap_delete_pdu(pdu);
+
+    tv.tv_sec = 5; tv.tv_usec = 0;
+
+    select( 0, 0, 0, 0, &tv );
+
+  }
+
+  coap_free_context( ctx );
+
+  return 0;
+}
diff --git a/components/coap/libcoap/include/coap/address.h b/components/coap/libcoap/include/coap/address.h
new file mode 100644
index 00000000..85db2046
--- /dev/null
+++ b/components/coap/libcoap/include/coap/address.h
@@ -0,0 +1,152 @@
+/*
+ * address.h -- representation of network addresses
+ *
+ * Copyright (C) 2010-2011,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file address.h
+ * @brief Representation of network addresses
+ */
+
+#ifndef _COAP_ADDRESS_H_
+#define _COAP_ADDRESS_H_
+
+#include <assert.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include "libcoap.h"
+
+#ifdef WITH_LWIP
+#include <lwip/ip_addr.h>
+
+typedef struct coap_address_t {
+  uint16_t port;
+  ip_addr_t addr;
+} coap_address_t;
+
+#define _coap_address_equals_impl(A, B)   (!!ip_addr_cmp(&(A)->addr,&(B)->addr))
+
+#define _coap_address_isany_impl(A)  ip_addr_isany(&(A)->addr)
+
+#define _coap_is_mcast_impl(Address) ip_addr_ismulticast(&(Address)->addr)
+#endif /* WITH_LWIP */
+
+#ifdef WITH_CONTIKI
+#include "uip.h"
+
+typedef struct coap_address_t {
+  uip_ipaddr_t addr;
+  unsigned short port;
+} coap_address_t;
+
+#define _coap_address_equals_impl(A,B) \
+        ((A)->port == (B)->port        \
+        && uip_ipaddr_cmp(&((A)->addr),&((B)->addr)))
+
+/** @todo implementation of _coap_address_isany_impl() for Contiki */
+#define _coap_address_isany_impl(A)  0
+
+#define _coap_is_mcast_impl(Address) uip_is_addr_mcast(&((Address)->addr))
+#endif /* WITH_CONTIKI */
+
+#ifdef WITH_POSIX
+/** multi-purpose address abstraction */
+typedef struct coap_address_t {
+  socklen_t size;           /**< size of addr */
+  union {
+    struct sockaddr         sa;
+    struct sockaddr_storage st;
+    struct sockaddr_in      sin;
+    struct sockaddr_in6     sin6;
+  } addr;
+} coap_address_t;
+
+/**
+ * Compares given address objects @p a and @p b. This function returns @c 1 if
+ * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be
+ * @c NULL;
+ */
+int coap_address_equals(const coap_address_t *a, const coap_address_t *b);
+
+static inline int
+_coap_address_isany_impl(const coap_address_t *a) {
+  /* need to compare only relevant parts of sockaddr_in6 */
+  switch (a->addr.sa.sa_family) {
+  case AF_INET:
+    return a->addr.sin.sin_addr.s_addr == INADDR_ANY;
+  case AF_INET6:
+    return memcmp(&in6addr_any,
+                  &a->addr.sin6.sin6_addr,
+                  sizeof(in6addr_any)) == 0;
+  default:
+    ;
+  }
+
+  return 0;
+}
+#endif /* WITH_POSIX */
+
+/**
+ * Resets the given coap_address_t object @p addr to its default values. In
+ * particular, the member size must be initialized to the available size for
+ * storing addresses.
+ *
+ * @param addr The coap_address_t object to initialize.
+ */
+static inline void
+coap_address_init(coap_address_t *addr) {
+  assert(addr);
+  memset(addr, 0, sizeof(coap_address_t));
+#ifdef WITH_POSIX
+  /* lwip and Contiki have constant address sizes and doesn't need the .size part */
+  addr->size = sizeof(addr->addr);
+#endif
+}
+
+#ifndef WITH_POSIX
+/**
+ * Compares given address objects @p a and @p b. This function returns @c 1 if
+ * addresses are equal, @c 0 otherwise. The parameters @p a and @p b must not be
+ * @c NULL;
+ */
+static inline int
+coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
+  assert(a); assert(b);
+  return _coap_address_equals_impl(a, b);
+}
+#endif
+
+/**
+ * Checks if given address object @p a denotes the wildcard address. This
+ * function returns @c 1 if this is the case, @c 0 otherwise. The parameters @p
+ * a must not be @c NULL;
+ */
+static inline int
+coap_address_isany(const coap_address_t *a) {
+  assert(a);
+  return _coap_address_isany_impl(a);
+}
+
+#ifdef WITH_POSIX
+/**
+ * Checks if given address @p a denotes a multicast address. This function
+ * returns @c 1 if @p a is multicast, @c 0 otherwise.
+ */
+int coap_is_mcast(const coap_address_t *a);
+#else /* WITH_POSIX */
+/**
+ * Checks if given address @p a denotes a multicast address. This function
+ * returns @c 1 if @p a is multicast, @c 0 otherwise.
+ */
+static inline int
+coap_is_mcast(const coap_address_t *a) {
+  return a && _coap_is_mcast_impl(a);
+}
+#endif /* WITH_POSIX */
+
+#endif /* _COAP_ADDRESS_H_ */
diff --git a/components/coap/libcoap/include/coap/async.h b/components/coap/libcoap/include/coap/async.h
new file mode 100644
index 00000000..0c36defa
--- /dev/null
+++ b/components/coap/libcoap/include/coap/async.h
@@ -0,0 +1,146 @@
+/*
+ * async.h -- state management for asynchronous messages
+ *
+ * Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file async.h
+ * @brief State management for asynchronous messages
+ */
+
+#ifndef _COAP_ASYNC_H_
+#define _COAP_ASYNC_H_
+
+#include "net.h"
+
+#ifndef WITHOUT_ASYNC
+
+/**
+ * @defgroup coap_async Asynchronous Messaging
+ * @{
+ * Structure for managing asynchronous state of CoAP resources. A
+ * coap_resource_t object holds a list of coap_async_state_t objects that can be
+ * used to generate a separate response in case a result of an operation cannot
+ * be delivered in time, or the resource has been explicitly subscribed to with
+ * the option @c observe.
+ */
+typedef struct coap_async_state_t {
+  unsigned char flags;  /**< holds the flags to control behaviour */
+
+  /**
+   * Holds the internal time when the object was registered with a
+   * resource. This field will be updated whenever
+   * coap_register_async() is called for a specific resource.
+   */
+  coap_tick_t created;
+
+  /**
+   * This field can be used to register opaque application data with the
+   * asynchronous state object.
+   */
+  void *appdata;
+  unsigned short message_id;       /**< id of last message seen */
+  coap_tid_t id;                   /**< transaction id */
+  struct coap_async_state_t *next; /**< internally used for linking */
+  coap_address_t peer;             /**< the peer to notify */
+  size_t tokenlen;                 /**< length of the token */
+  unsigned char token[];           /**< the token to use in a response */
+} coap_async_state_t;
+
+/* Definitions for Async Status Flags These flags can be used to control the
+ * behaviour of asynchronous response generation.
+ */
+#define COAP_ASYNC_CONFIRM   0x01  /**< send confirmable response */
+#define COAP_ASYNC_SEPARATE  0x02  /**< send separate response */
+#define COAP_ASYNC_OBSERVED  0x04  /**< the resource is being observed */
+
+/** release application data on destruction */
+#define COAP_ASYNC_RELEASE_DATA  0x08
+
+/**
+ * Allocates a new coap_async_state_t object and fills its fields according to
+ * the given @p request. The @p flags are used to control generation of empty
+ * ACK responses to stop retransmissions and to release registered @p data when
+ * the resource is deleted by coap_free_async(). This function returns a pointer
+ * to the registered coap_async_t object or @c NULL on error. Note that this
+ * function will return @c NULL in case that an object with the same identifier
+ * is already registered.
+ *
+ * @param context  The context to use.
+ * @param peer     The remote peer that is to be asynchronously notified.
+ * @param request  The request that is handled asynchronously.
+ * @param flags    Flags to control state management.
+ * @param data     Opaque application data to register. Note that the
+ *                 storage occupied by @p data is released on destruction
+ *                 only if flag COAP_ASYNC_RELEASE_DATA is set.
+ *
+ * @return         A pointer to the registered coap_async_state_t object or @c
+ *                 NULL in case of an error.
+ */
+coap_async_state_t *
+coap_register_async(coap_context_t *context,
+                    coap_address_t *peer,
+                    coap_pdu_t *request,
+                    unsigned char flags,
+                    void *data);
+
+/**
+ * Removes the state object identified by @p id from @p context. The removed
+ * object is returned in @p s, if found. Otherwise, @p s is undefined. This
+ * function returns @c 1 if the object was removed, @c 0 otherwise. Note that
+ * the storage allocated for the stored object is not released by this
+ * functions. You will have to call coap_free_async() to do so.
+ *
+ * @param context The context where the async object is registered.
+ * @param id      The identifier of the asynchronous transaction.
+ * @param s       Will be set to the object identified by @p id after removal.
+ *
+ * @return        @c 1 if object was removed and @p s updated, or @c 0 if no
+ *                object was found with the given id. @p s is valid only if the
+ *                return value is @c 1.
+ */
+int coap_remove_async(coap_context_t *context,
+                      coap_tid_t id,
+                      coap_async_state_t **s);
+
+/**
+ * Releases the memory that was allocated by coap_async_state_init() for the
+ * object @p s. The registered application data will be released automatically
+ * if COAP_ASYNC_RELEASE_DATA is set.
+ *
+ * @param state The object to delete.
+ */
+void
+coap_free_async(coap_async_state_t *state);
+
+/**
+ * Retrieves the object identified by @p id from the list of asynchronous
+ * transactions that are registered with @p context. This function returns a
+ * pointer to that object or @c NULL if not found.
+ *
+ * @param context The context where the asynchronous objects are registered
+ *                with.
+ * @param id      The id of the object to retrieve.
+ *
+ * @return        A pointer to the object identified by @p id or @c NULL if
+ *                not found.
+ */
+coap_async_state_t *coap_find_async(coap_context_t *context, coap_tid_t id);
+
+/**
+ * Updates the time stamp of @p s.
+ *
+ * @param s The state object to update.
+ */
+static inline void
+coap_touch_async(coap_async_state_t *s) { coap_ticks(&s->created); }
+
+/** @} */
+
+#endif /*  WITHOUT_ASYNC */
+
+#endif /* _COAP_ASYNC_H_ */
diff --git a/components/coap/libcoap/include/coap/bits.h b/components/coap/libcoap/include/coap/bits.h
new file mode 100644
index 00000000..0b269166
--- /dev/null
+++ b/components/coap/libcoap/include/coap/bits.h
@@ -0,0 +1,78 @@
+/*
+ * bits.h -- bit vector manipulation
+ *
+ * Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file bits.h
+ * @brief Bit vector manipulation
+ */
+
+#ifndef _COAP_BITS_H_
+#define _COAP_BITS_H_
+
+#include <stdint.h>
+
+/**
+ * Sets the bit @p bit in bit-vector @p vec. This function returns @c 1 if bit
+ * was set or @c -1 on error (i.e. when the given bit does not fit in the
+ * vector).
+ *
+ * @param vec  The bit-vector to change.
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to set in @p vec.
+ *
+ * @return     @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
+ */
+inline static int
+bits_setb(uint8_t *vec, size_t size, uint8_t bit) {
+  if (size <= (bit >> 3))
+    return -1;
+
+  *(vec + (bit >> 3)) |= (uint8_t)(1 << (bit & 0x07));
+  return 1;
+}
+
+/**
+ * Clears the bit @p bit from bit-vector @p vec. This function returns @c 1 if
+ * bit was cleared or @c -1 on error (i.e. when the given bit does not fit in
+ * the vector).
+ *
+ * @param vec  The bit-vector to change.
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to clear from @p vec.
+ *
+ * @return     @c -1 if @p bit does not fit into @p vec, @c 1 otherwise.
+ */
+inline static int
+bits_clrb(uint8_t *vec, size_t size, uint8_t bit) {
+  if (size <= (bit >> 3))
+    return -1;
+
+  *(vec + (bit >> 3)) &= (uint8_t)(~(1 << (bit & 0x07)));
+  return 1;
+}
+
+/**
+ * Gets the status of bit @p bit from bit-vector @p vec. This function returns
+ * @c 1 if the bit is set, @c 0 otherwise (even in case of an error).
+ *
+ * @param vec  The bit-vector to read from.
+ * @param size The size of @p vec in bytes.
+ * @param bit  The bit to get from @p vec.
+ *
+ * @return     @c 1 if the bit is set, @c 0 otherwise.
+ */
+inline static int
+bits_getb(const uint8_t *vec, size_t size, uint8_t bit) {
+  if (size <= (bit >> 3))
+    return -1;
+
+  return (*(vec + (bit >> 3)) & (1 << (bit & 0x07))) != 0;
+}
+
+#endif /* _COAP_BITS_H_ */
diff --git a/components/coap/libcoap/include/coap/block.h b/components/coap/libcoap/include/coap/block.h
new file mode 100644
index 00000000..9ce00311
--- /dev/null
+++ b/components/coap/libcoap/include/coap/block.h
@@ -0,0 +1,137 @@
+/*
+ * block.h -- block transfer
+ *
+ * Copyright (C) 2010-2012,2014-2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_BLOCK_H_
+#define _COAP_BLOCK_H_
+
+#include "encode.h"
+#include "option.h"
+#include "pdu.h"
+
+/**
+ * @defgroup block Block Transfer
+ * @{
+ */
+
+#ifndef COAP_MAX_BLOCK_SZX
+/**
+ * The largest value for the SZX component in a Block option. Note that
+ * 1 << (COAP_MAX_BLOCK_SZX + 4) should not exceed COAP_MAX_PDU_SIZE.
+ */
+#define COAP_MAX_BLOCK_SZX      4
+#endif /* COAP_MAX_BLOCK_SZX */
+
+/**
+ * Structure of Block options.
+ */
+typedef struct {
+  unsigned int num;       /**< block number */
+  unsigned int m:1;       /**< 1 if more blocks follow, 0 otherwise */
+  unsigned int szx:3;     /**< block size */
+} coap_block_t;
+
+/**
+ * Returns the value of the least significant byte of a Block option @p opt.
+ * For zero-length options (i.e. num == m == szx == 0), COAP_OPT_BLOCK_LAST
+ * returns @c NULL.
+ */
+#define COAP_OPT_BLOCK_LAST(opt) \
+  (COAP_OPT_LENGTH(opt) ? (COAP_OPT_VALUE(opt) + (COAP_OPT_LENGTH(opt)-1)) : 0)
+
+/** Returns the value of the More-bit of a Block option @p opt. */
+#define COAP_OPT_BLOCK_MORE(opt) \
+  (COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x08) : 0)
+
+/** Returns the value of the SZX-field of a Block option @p opt. */
+#define COAP_OPT_BLOCK_SZX(opt)  \
+  (COAP_OPT_LENGTH(opt) ? (*COAP_OPT_BLOCK_LAST(opt) & 0x07) : 0)
+
+/**
+ * Returns the value of field @c num in the given block option @p block_opt.
+ */
+unsigned int coap_opt_block_num(const coap_opt_t *block_opt);
+
+/**
+ * Checks if more than @p num blocks are required to deliver @p data_len
+ * bytes of data for a block size of 1 << (@p szx + 4).
+ */
+static inline int
+coap_more_blocks(size_t data_len, unsigned int num, unsigned short szx) {
+  return ((num+1) << (szx + 4)) < data_len;
+}
+
+/** Sets the More-bit in @p block_opt */
+static inline void
+coap_opt_block_set_m(coap_opt_t *block_opt, int m) {
+  if (m)
+    *(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) |= 0x08;
+  else
+    *(COAP_OPT_VALUE(block_opt) + (COAP_OPT_LENGTH(block_opt) - 1)) &= ~0x08;
+}
+
+/**
+ * Initializes @p block from @p pdu. @p type must be either COAP_OPTION_BLOCK1
+ * or COAP_OPTION_BLOCK2. When option @p type was found in @p pdu, @p block is
+ * initialized with values from this option and the function returns the value
+ * @c 1. Otherwise, @c 0 is returned.
+ *
+ * @param pdu   The pdu to search for option @p type.
+ * @param type  The option to search for (must be COAP_OPTION_BLOCK1 or
+ *              COAP_OPTION_BLOCK2).
+ * @param block The block structure to initilize.
+ *
+ * @return      @c 1 on success, @c 0 otherwise.
+ */
+int coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block);
+
+/**
+ * Writes a block option of type @p type to message @p pdu. If the requested
+ * block size is too large to fit in @p pdu, it is reduced accordingly. An
+ * exception is made for the final block when less space is required. The actual
+ * length of the resource is specified in @p data_length.
+ *
+ * This function may change *block to reflect the values written to @p pdu. As
+ * the function takes into consideration the remaining space @p pdu, no more
+ * options should be added after coap_write_block_opt() has returned.
+ *
+ * @param block       The block structure to use. On return, this object is
+ *                    updated according to the values that have been written to
+ *                    @p pdu.
+ * @param type        COAP_OPTION_BLOCK1 or COAP_OPTION_BLOCK2.
+ * @param pdu         The message where the block option should be written.
+ * @param data_length The length of the actual data that will be added the @p
+ *                    pdu by calling coap_add_block().
+ *
+ * @return            @c 1 on success, or a negative value on error.
+ */
+int coap_write_block_opt(coap_block_t *block,
+                         unsigned short type,
+                         coap_pdu_t *pdu,
+                         size_t data_length);
+
+/**
+ * Adds the @p block_num block of size 1 << (@p block_szx + 4) from source @p
+ * data to @p pdu.
+ *
+ * @param pdu       The message to add the block.
+ * @param len       The length of @p data.
+ * @param data      The source data to fill the block with.
+ * @param block_num The actual block number.
+ * @param block_szx Encoded size of block @p block_number.
+ *
+ * @return          @c 1 on success, @c 0 otherwise.
+ */
+int coap_add_block(coap_pdu_t *pdu,
+                   unsigned int len,
+                   const unsigned char *data,
+                   unsigned int block_num,
+                   unsigned char block_szx);
+/**@}*/
+
+#endif /* _COAP_BLOCK_H_ */
diff --git a/components/coap/libcoap/include/coap/coap.h.in b/components/coap/libcoap/include/coap/coap.h.in
new file mode 100644
index 00000000..76ebc5eb
--- /dev/null
+++ b/components/coap/libcoap/include/coap/coap.h.in
@@ -0,0 +1,59 @@
+/*
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_H_
+#define _COAP_H_
+
+#include "libcoap.h"
+
+/* Define the address where bug reports for libcoap should be sent. */
+#define LIBCOAP_PACKAGE_BUGREPORT @PACKAGE_BUGREPORT@
+
+/* Define the full name of libcoap. */
+#define LIBCOAP_PACKAGE_NAME @PACKAGE_NAME@
+
+/* Define the full name and version of libcoap. */
+#define LIBCOAP_PACKAGE_STRING @PACKAGE_STRING@
+
+/* Define the home page for libcoap. */
+#define LIBCOAP_PACKAGE_URL @PACKAGE_URL@
+
+/* Define the version of libcoap this file belongs to. */
+#define LIBCOAP_PACKAGE_VERSION @PACKAGE_VERSION@
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "address.h"
+#include "async.h"
+#include "bits.h"
+#include "block.h"
+#include "coap_io.h"
+#include "coap_time.h"
+#include "debug.h"
+#include "encode.h"
+#include "mem.h"
+#include "net.h"
+#include "option.h"
+#include "pdu.h"
+#include "prng.h"
+#include "resource.h"
+#include "str.h"
+#include "subscribe.h"
+#include "uri.h"
+#include "uthash.h"
+#include "utlist.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COAP_H_ */
diff --git a/components/coap/libcoap/include/coap/coap_io.h b/components/coap/libcoap/include/coap/coap_io.h
new file mode 100644
index 00000000..7a48b319
--- /dev/null
+++ b/components/coap/libcoap/include/coap/coap_io.h
@@ -0,0 +1,167 @@
+/*
+ * coap_io.h -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_IO_H_
+#define _COAP_IO_H_
+
+#include <assert.h>
+#include <sys/types.h>
+
+#include "address.h"
+
+/**
+ * Abstract handle that is used to identify a local network interface.
+ */
+typedef int coap_if_handle_t;
+
+/** Invalid interface handle */
+#define COAP_IF_INVALID -1
+
+struct coap_packet_t;
+typedef struct coap_packet_t coap_packet_t;
+
+struct coap_context_t;
+
+/**
+ * Abstraction of virtual endpoint that can be attached to coap_context_t. The
+ * tuple (handle, addr) must uniquely identify this endpoint.
+ */
+typedef struct coap_endpoint_t {
+#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
+  union {
+    int fd;       /**< on POSIX systems */
+    void *conn;   /**< opaque connection (e.g. uip_conn in Contiki) */
+  } handle;       /**< opaque handle to identify this endpoint */
+#endif /* WITH_POSIX or WITH_CONTIKI */
+
+#ifdef WITH_LWIP
+  struct udp_pcb *pcb;
+ /**< @FIXME --chrysn
+  * this was added in a hurry, not sure it confirms to the overall model */
+  struct coap_context_t *context;
+#endif /* WITH_LWIP */
+
+  coap_address_t addr; /**< local interface address */
+  int ifindex;
+  int flags;
+} coap_endpoint_t;
+
+#define COAP_ENDPOINT_NOSEC 0x00
+#define COAP_ENDPOINT_DTLS  0x01
+
+coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags);
+
+void coap_free_endpoint(coap_endpoint_t *ep);
+
+/**
+ * Function interface for data transmission. This function returns the number of
+ * bytes that have been transmitted, or a value less than zero on error.
+ *
+ * @param context          The calling CoAP context.
+ * @param local_interface  The local interface to send the data.
+ * @param dst              The address of the receiver.
+ * @param data             The data to send.
+ * @param datalen          The actual length of @p data.
+ *
+ * @return                 The number of bytes written on success, or a value
+ *                         less than zero on error.
+ */
+ssize_t coap_network_send(struct coap_context_t *context,
+                          const coap_endpoint_t *local_interface,
+                          const coap_address_t *dst,
+                          unsigned char *data, size_t datalen);
+
+/**
+ * Function interface for reading data. This function returns the number of
+ * bytes that have been read, or a value less than zero on error. In case of an
+ * error, @p *packet is set to NULL.
+ *
+ * @param ep     The endpoint that is used for reading data from the network.
+ * @param packet A result parameter where a pointer to the received packet
+ *               structure is stored. The caller must call coap_free_packet to
+ *               release the storage used by this packet.
+ *
+ * @return       The number of bytes received on success, or a value less than
+ *               zero on error.
+ */
+ssize_t coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet);
+
+#ifndef coap_mcast_interface
+# define coap_mcast_interface(Local) 0
+#endif
+
+/**
+ * Releases the storage allocated for @p packet.
+ */
+void coap_free_packet(coap_packet_t *packet);
+
+/**
+ * Populate the coap_endpoint_t *target from the incoming packet's destination
+ * data.
+ *
+ * This is usually used to copy a packet's data into a node's local_if member.
+ */
+void coap_packet_populate_endpoint(coap_packet_t *packet,
+                                   coap_endpoint_t *target);
+
+/**
+ * Given an incoming packet, copy its source address into an address struct.
+ */
+void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target);
+
+/**
+ * Given a packet, set msg and msg_len to an address and length of the packet's
+ * data in memory.
+ * */
+void coap_packet_get_memmapped(coap_packet_t *packet,
+                               unsigned char **address,
+                               size_t *length);
+
+#ifdef WITH_LWIP
+/**
+ * Get the pbuf of a packet. The caller takes over responsibility for freeing
+ * the pbuf.
+ */
+struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet);
+#endif
+
+#ifdef WITH_CONTIKI
+/*
+ * This is only included in coap_io.h instead of .c in order to be available for
+ * sizeof in mem.c.
+ */
+struct coap_packet_t {
+  coap_if_handle_t hnd;         /**< the interface handle */
+  coap_address_t src;           /**< the packet's source address */
+  coap_address_t dst;           /**< the packet's destination address */
+  const coap_endpoint_t *interface;
+  int ifindex;
+  void *session;                /**< opaque session data */
+  size_t length;                /**< length of payload */
+  unsigned char payload[];      /**< payload */
+};
+#endif
+
+#ifdef WITH_LWIP
+/*
+ * This is only included in coap_io.h instead of .c in order to be available for
+ * sizeof in lwippools.h.
+ * Simple carry-over of the incoming pbuf that is later turned into a node.
+ *
+ * Source address data is currently side-banded via ip_current_dest_addr & co
+ * as the packets have limited lifetime anyway.
+ */
+struct coap_packet_t {
+  struct pbuf *pbuf;
+  const coap_endpoint_t *local_interface;
+  uint16_t srcport;
+};
+#endif
+
+#endif /* _COAP_IO_H_ */
diff --git a/components/coap/libcoap/include/coap/coap_time.h b/components/coap/libcoap/include/coap/coap_time.h
new file mode 100644
index 00000000..9357e5ff
--- /dev/null
+++ b/components/coap/libcoap/include/coap/coap_time.h
@@ -0,0 +1,142 @@
+/*
+ * coap_time.h -- Clock Handling
+ *
+ * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file coap_time.h
+ * @brief Clock Handling
+ */
+
+#ifndef _COAP_TIME_H_
+#define _COAP_TIME_H_
+
+/**
+ * @defgroup clock Clock Handling
+ * Default implementation of internal clock.
+ * @{
+ */
+
+#ifdef WITH_LWIP
+
+#include <stdint.h>
+#include <lwip/sys.h>
+
+/* lwIP provides ms in sys_now */
+#define COAP_TICKS_PER_SECOND 1000
+
+typedef uint32_t coap_tick_t;
+typedef uint32_t coap_time_t;
+typedef int32_t coap_tick_diff_t;
+
+static inline void coap_ticks_impl(coap_tick_t *t) {
+  *t = sys_now();
+}
+
+static inline void coap_clock_init_impl(void) {
+}
+
+#define coap_clock_init coap_clock_init_impl
+#define coap_ticks coap_ticks_impl
+
+static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
+  return t / COAP_TICKS_PER_SECOND;
+}
+#endif
+
+#ifdef WITH_CONTIKI
+#include "clock.h"
+
+typedef clock_time_t coap_tick_t;
+typedef clock_time_t coap_time_t;
+
+/**
+ * This data type is used to represent the difference between two clock_tick_t
+ * values. This data type must have the same size in memory as coap_tick_t to
+ * allow wrapping.
+ */
+typedef int coap_tick_diff_t;
+
+#define COAP_TICKS_PER_SECOND CLOCK_SECOND
+
+static inline void coap_clock_init(void) {
+  clock_init();
+}
+
+static inline void coap_ticks(coap_tick_t *t) {
+  *t = clock_time();
+}
+
+static inline coap_time_t coap_ticks_to_rt(coap_tick_t t) {
+  return t / COAP_TICKS_PER_SECOND;
+}
+#endif /* WITH_CONTIKI */
+
+#ifdef WITH_POSIX
+/**
+ * This data type represents internal timer ticks with COAP_TICKS_PER_SECOND
+ * resolution.
+ */
+typedef unsigned long coap_tick_t;
+
+/**
+ * CoAP time in seconds since epoch.
+ */
+typedef time_t coap_time_t;
+
+/**
+ * This data type is used to represent the difference between two clock_tick_t
+ * values. This data type must have the same size in memory as coap_tick_t to
+ * allow wrapping.
+ */
+typedef long coap_tick_diff_t;
+
+/** Use ms resolution on POSIX systems */
+#define COAP_TICKS_PER_SECOND 1000
+
+/**
+ * Initializes the internal clock.
+ */
+void coap_clock_init(void);
+
+/**
+ * Sets @p t to the internal time with COAP_TICKS_PER_SECOND resolution.
+ */
+void coap_ticks(coap_tick_t *t);
+
+/**
+ * Helper function that converts coap ticks to wallclock time. On POSIX, this
+ * function returns the number of seconds since the epoch. On other systems, it
+ * may be the calculated number of seconds since last reboot or so.
+ *
+ * @param t Internal system ticks.
+ *
+ * @return  The number of seconds that has passed since a specific reference
+ *          point (seconds since epoch on POSIX).
+ */
+coap_time_t coap_ticks_to_rt(coap_tick_t t);
+#endif /* WITH_POSIX */
+
+/**
+ * Returns @c 1 if and only if @p a is less than @p b where less is defined on a
+ * signed data type.
+ */
+static inline int coap_time_lt(coap_tick_t a, coap_tick_t b) {
+  return ((coap_tick_diff_t)(a - b)) < 0;
+}
+
+/**
+ * Returns @c 1 if and only if @p a is less than or equal @p b where less is
+ * defined on a signed data type.
+ */
+static inline int coap_time_le(coap_tick_t a, coap_tick_t b) {
+  return a == b || coap_time_lt(a,b);
+}
+
+/** @} */
+
+#endif /* _COAP_TIME_H_ */
diff --git a/components/coap/libcoap/include/coap/debug.h b/components/coap/libcoap/include/coap/debug.h
new file mode 100644
index 00000000..e7c86aff
--- /dev/null
+++ b/components/coap/libcoap/include/coap/debug.h
@@ -0,0 +1,85 @@
+/*
+ * debug.h -- debug utilities
+ *
+ * Copyright (C) 2010-2011,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_DEBUG_H_
+#define _COAP_DEBUG_H_
+
+#ifndef COAP_DEBUG_FD
+#define COAP_DEBUG_FD stdout
+#endif
+
+#ifndef COAP_ERR_FD
+#define COAP_ERR_FD stderr
+#endif
+
+#ifdef HAVE_SYSLOG_H
+#include <syslog.h>
+typedef short coap_log_t;
+#else
+/** Pre-defined log levels akin to what is used in \b syslog. */
+typedef enum {
+  LOG_EMERG=0,
+  LOG_ALERT,
+  LOG_CRIT,
+  LOG_ERR,
+  LOG_WARNING,
+  LOG_NOTICE,
+  LOG_INFO,
+  LOG_DEBUG
+} coap_log_t;
+#endif
+
+/** Returns the current log level. */
+coap_log_t coap_get_log_level(void);
+
+/** Sets the log level to the specified value. */
+void coap_set_log_level(coap_log_t level);
+
+/** Returns a zero-terminated string with the name of this library. */
+const char *coap_package_name(void);
+
+/** Returns a zero-terminated string with the library version. */
+const char *coap_package_version(void);
+
+/**
+ * Writes the given text to @c COAP_ERR_FD (for @p level <= @c LOG_CRIT) or @c
+ * COAP_DEBUG_FD (for @p level >= @c LOG_WARNING). The text is output only when
+ * @p level is below or equal to the log level that set by coap_set_log_level().
+ */
+void coap_log_impl(coap_log_t level, const char *format, ...);
+
+#ifndef coap_log
+#define coap_log(...) coap_log_impl(__VA_ARGS__)
+#endif
+
+#ifndef NDEBUG
+
+/* A set of convenience macros for common log levels. */
+#define info(...) coap_log(LOG_INFO, __VA_ARGS__)
+#define warn(...) coap_log(LOG_WARNING, __VA_ARGS__)
+#define debug(...) coap_log(LOG_DEBUG, __VA_ARGS__)
+
+#include "pdu.h"
+void coap_show_pdu(const coap_pdu_t *);
+
+struct coap_address_t;
+size_t coap_print_addr(const struct coap_address_t *, unsigned char *, size_t);
+
+#else
+
+#define debug(...)
+#define info(...)
+#define warn(...)
+
+#define coap_show_pdu(x)
+#define coap_print_addr(...)
+
+#endif /* NDEBUG */
+
+#endif /* _COAP_DEBUG_H_ */
diff --git a/components/coap/libcoap/include/coap/encode.h b/components/coap/libcoap/include/coap/encode.h
new file mode 100644
index 00000000..a5d290c4
--- /dev/null
+++ b/components/coap/libcoap/include/coap/encode.h
@@ -0,0 +1,52 @@
+/*
+ * encode.h -- encoding and decoding of CoAP data types
+ *
+ * Copyright (C) 2010-2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_ENCODE_H_
+#define _COAP_ENCODE_H_
+
+#if (BSD >= 199103) || defined(WITH_CONTIKI)
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#define Nn 8  /* duplicate definition of N if built on sky motes */
+#define ENCODE_HEADER_SIZE 4
+#define HIBIT (1 << (Nn - 1))
+#define EMASK ((1 << ENCODE_HEADER_SIZE) - 1)
+#define MMASK ((1 << Nn) - 1 - EMASK)
+#define MAX_VALUE ( (1 << Nn) - (1 << ENCODE_HEADER_SIZE) ) * (1 << ((1 << ENCODE_HEADER_SIZE) - 1))
+
+#define COAP_PSEUDOFP_DECODE_8_4(r) (r < HIBIT ? r : (r & MMASK) << (r & EMASK))
+
+#ifndef HAVE_FLS
+/* include this only if fls() is not available */
+extern int coap_fls(unsigned int i);
+#else
+#define coap_fls(i) fls(i)
+#endif
+
+/* ls and s must be integer variables */
+#define COAP_PSEUDOFP_ENCODE_8_4_DOWN(v,ls) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (v >> ls) & MMASK) + ls)
+#define COAP_PSEUDOFP_ENCODE_8_4_UP(v,ls,s) (v < HIBIT ? v : (ls = coap_fls(v) - Nn, (s = (((v + ((1<<ENCODE_HEADER_SIZE<<ls)-1)) >> ls) & MMASK)), s == 0 ? HIBIT + ls + 1 : s + ls))
+
+/**
+ * Decodes multiple-length byte sequences. buf points to an input byte sequence
+ * of length len. Returns the decoded value.
+ */
+unsigned int coap_decode_var_bytes(unsigned char *buf,unsigned int len);
+
+/**
+ * Encodes multiple-length byte sequences. buf points to an output buffer of
+ * sufficient length to store the encoded bytes. val is the value to encode.
+ * Returns the number of bytes used to encode val or 0 on error.
+ */
+unsigned int coap_encode_var_bytes(unsigned char *buf, unsigned int val);
+
+#endif /* _COAP_ENCODE_H_ */
diff --git a/components/coap/libcoap/include/coap/hashkey.h b/components/coap/libcoap/include/coap/hashkey.h
new file mode 100644
index 00000000..5cff67d2
--- /dev/null
+++ b/components/coap/libcoap/include/coap/hashkey.h
@@ -0,0 +1,57 @@
+/*
+ * hashkey.h -- definition of hash key type and helper functions
+ *
+ * Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file hashkey.h
+ * @brief definition of hash key type and helper functions
+ */
+
+#ifndef _COAP_HASHKEY_H_
+#define _COAP_HASHKEY_H_
+
+#include "str.h"
+
+typedef unsigned char coap_key_t[4];
+
+#ifndef coap_hash
+/**
+ * Calculates a fast hash over the given string @p s of length @p len and stores
+ * the result into @p h. Depending on the exact implementation, this function
+ * cannot be used as one-way function to check message integrity or simlar.
+ *
+ * @param s   The string used for hash calculation.
+ * @param len The length of @p s.
+ * @param h   The result buffer to store the calculated hash key.
+ */
+void coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h);
+
+#define coap_hash(String,Length,Result) \
+  coap_hash_impl((String),(Length),(Result))
+
+/* This is used to control the pre-set hash-keys for resources. */
+#define __COAP_DEFAULT_HASH
+#else
+#undef __COAP_DEFAULT_HASH
+#endif /* coap_hash */
+
+/**
+ * Calls coap_hash() with given @c str object as parameter.
+ *
+ * @param Str Must contain a pointer to a coap string object.
+ * @param H   A coap_key_t object to store the result.
+ *
+ * @hideinitializer
+ */
+#define coap_str_hash(Str,H) {               \
+    assert(Str);                             \
+    memset((H), 0, sizeof(coap_key_t));      \
+    coap_hash((Str)->s, (Str)->length, (H)); \
+  }
+
+#endif /* _COAP_HASHKEY_H_ */
diff --git a/components/coap/libcoap/include/coap/libcoap.h b/components/coap/libcoap/include/coap/libcoap.h
new file mode 100644
index 00000000..214b9e23
--- /dev/null
+++ b/components/coap/libcoap/include/coap/libcoap.h
@@ -0,0 +1,26 @@
+/*
+ * libcoap.h -- platform specific header file for CoAP stack
+ *
+ * Copyright (C) 2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _LIBCOAP_H_
+#define _LIBCOAP_H_
+
+/* The non posix embedded platforms like Contiki, TinyOS, RIOT, ... doesn't have
+ * a POSIX compatible header structure so we have to slightly do some platform
+ * related things. Currently there is only Contiki available so we check for a
+ * CONTIKI environment and do *not* include the POSIX related network stuff. If
+ * there are other platforms in future there need to be analogous environments.
+ *
+ * The CONTIKI variable is within the Contiki build environment! */
+
+#if !defined (CONTIKI) 
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif /* CONTIKI */
+
+#endif /* _LIBCOAP_H_ */
diff --git a/components/coap/libcoap/include/coap/lwippools.h b/components/coap/libcoap/include/coap/lwippools.h
new file mode 100644
index 00000000..0bfb3f52
--- /dev/null
+++ b/components/coap/libcoap/include/coap/lwippools.h
@@ -0,0 +1,57 @@
+/*
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/** Memory pool definitions for the libcoap when used with lwIP (which has its
+ * own mechanism for quickly allocating chunks of data with known sizes). Has
+ * to be findable by lwIP (ie. an #include <lwippools.h> must either directly
+ * include this or include something more generic which includes this), and
+ * MEMP_USE_CUSTOM_POOLS has to be set in lwipopts.h. */
+
+#include "coap_config.h"
+#include <net.h>
+#include <resource.h>
+#include <subscribe.h>
+
+#ifndef MEMP_NUM_COAPCONTEXT
+#define MEMP_NUM_COAPCONTEXT 1
+#endif
+
+#ifndef MEMP_NUM_COAPENDPOINT
+#define MEMP_NUM_COAPENDPOINT 1
+#endif
+
+/* 1 is sufficient as this is very short-lived */
+#ifndef MEMP_NUM_COAPPACKET
+#define MEMP_NUM_COAPPACKET 1
+#endif
+
+#ifndef MEMP_NUM_COAPNODE
+#define MEMP_NUM_COAPNODE 4
+#endif
+
+#ifndef MEMP_NUM_COAPPDU
+#define MEMP_NUM_COAPPDU MEMP_NUM_COAPNODE
+#endif
+
+#ifndef MEMP_NUM_COAP_SUBSCRIPTION
+#define MEMP_NUM_COAP_SUBSCRIPTION 4
+#endif
+
+#ifndef MEMP_NUM_COAPRESOURCE
+#define MEMP_NUM_COAPRESOURCE 10
+#endif
+
+#ifndef MEMP_NUM_COAPRESOURCEATTR
+#define MEMP_NUM_COAPRESOURCEATTR 20
+#endif
+
+LWIP_MEMPOOL(COAP_CONTEXT, MEMP_NUM_COAPCONTEXT, sizeof(coap_context_t), "COAP_CONTEXT")
+LWIP_MEMPOOL(COAP_ENDPOINT, MEMP_NUM_COAPENDPOINT, sizeof(coap_endpoint_t), "COAP_ENDPOINT")
+LWIP_MEMPOOL(COAP_PACKET, MEMP_NUM_COAPPACKET, sizeof(coap_packet_t), "COAP_PACKET")
+LWIP_MEMPOOL(COAP_NODE, MEMP_NUM_COAPNODE, sizeof(coap_queue_t), "COAP_NODE")
+LWIP_MEMPOOL(COAP_PDU, MEMP_NUM_COAPPDU, sizeof(coap_pdu_t), "COAP_PDU")
+LWIP_MEMPOOL(COAP_subscription, MEMP_NUM_COAP_SUBSCRIPTION, sizeof(coap_subscription_t), "COAP_subscription")
+LWIP_MEMPOOL(COAP_RESOURCE, MEMP_NUM_COAPRESOURCE, sizeof(coap_resource_t), "COAP_RESOURCE")
+LWIP_MEMPOOL(COAP_RESOURCEATTR, MEMP_NUM_COAPRESOURCEATTR, sizeof(coap_attr_t), "COAP_RESOURCEATTR")
diff --git a/components/coap/libcoap/include/coap/mem.h b/components/coap/libcoap/include/coap/mem.h
new file mode 100644
index 00000000..fd3c69aa
--- /dev/null
+++ b/components/coap/libcoap/include/coap/mem.h
@@ -0,0 +1,111 @@
+/*
+ * mem.h -- CoAP memory handling
+ *
+ * Copyright (C) 2010-2011,2014-2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_MEM_H_
+#define _COAP_MEM_H_
+
+#include <stdlib.h>
+
+#ifndef WITH_LWIP
+/**
+ * Initializes libcoap's memory management.
+ * This function must be called once before coap_malloc() can be used on
+ * constrained devices.
+ */
+void coap_memory_init(void);
+#endif /* WITH_LWIP */
+
+/**
+ * Type specifiers for coap_malloc_type(). Memory objects can be typed to
+ * facilitate arrays of type objects to be used instead of dynamic memory
+ * management on constrained devices.
+ */
+typedef enum {
+  COAP_STRING,
+  COAP_ATTRIBUTE_NAME,
+  COAP_ATTRIBUTE_VALUE,
+  COAP_PACKET,
+  COAP_NODE,
+  COAP_CONTEXT,
+  COAP_ENDPOINT,
+  COAP_PDU,
+  COAP_PDU_BUF,
+  COAP_RESOURCE,
+  COAP_RESOURCEATTR
+} coap_memory_tag_t;
+
+#ifndef WITH_LWIP
+
+/**
+ * Allocates a chunk of @p size bytes and returns a pointer to the newly
+ * allocated memory. The @p type is used to select the appropriate storage
+ * container on constrained devices. The storage allocated by coap_malloc_type()
+ * must be released with coap_free_type().
+ *
+ * @param type The type of object to be stored.
+ * @param size The number of bytes requested.
+ * @return     A pointer to the allocated storage or @c NULL on error.
+ */
+void *coap_malloc_type(coap_memory_tag_t type, size_t size);
+
+/**
+ * Releases the memory that was allocated by coap_malloc_type(). The type tag @p
+ * type must be the same that was used for allocating the object pointed to by
+ * @p .
+ *
+ * @param type The type of the object to release.
+ * @param p    A pointer to memory that was allocated by coap_malloc_type().
+ */
+void coap_free_type(coap_memory_tag_t type, void *p);
+
+/**
+ * Wrapper function to coap_malloc_type() for backwards compatibility.
+ */
+static inline void *coap_malloc(size_t size) {
+  return coap_malloc_type(COAP_STRING, size);
+}
+
+/**
+ * Wrapper function to coap_free_type() for backwards compatibility.
+ */
+static inline void coap_free(void *object) {
+  coap_free_type(COAP_STRING, object);
+}
+
+#endif /* not WITH_LWIP */
+
+#ifdef WITH_LWIP
+
+#include <lwip/memp.h>
+
+/* no initialization needed with lwip (or, more precisely: lwip must be
+ * completely initialized anyway by the time coap gets active)  */
+static inline void coap_memory_init(void) {}
+
+/* It would be nice to check that size equals the size given at the memp
+ * declaration, but i currently don't see a standard way to check that without
+ * sourcing the custom memp pools and becoming dependent of its syntax
+ */
+#define coap_malloc_type(type, size) memp_malloc(MEMP_ ## type)
+#define coap_free_type(type, p) memp_free(MEMP_ ## type, p)
+
+/* Those are just here to make uri.c happy where string allocation has not been
+ * made conditional.
+ */
+static inline void *coap_malloc(size_t size) {
+  LWIP_ASSERT("coap_malloc must not be used in lwIP", 0);
+}
+
+static inline void coap_free(void *pointer) {
+  LWIP_ASSERT("coap_free must not be used in lwIP", 0);
+}
+
+#endif /* WITH_LWIP */
+
+#endif /* _COAP_MEM_H_ */
diff --git a/components/coap/libcoap/include/coap/net.h b/components/coap/libcoap/include/coap/net.h
new file mode 100644
index 00000000..014b4903
--- /dev/null
+++ b/components/coap/libcoap/include/coap/net.h
@@ -0,0 +1,521 @@
+/*
+ * net.h -- CoAP network interface
+ *
+ * Copyright (C) 2010-2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_NET_H_
+#define _COAP_NET_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#ifdef WITH_LWIP
+#include <lwip/ip_addr.h>
+#endif
+
+#include "coap_io.h"
+#include "coap_time.h"
+#include "option.h"
+#include "pdu.h"
+#include "prng.h"
+
+struct coap_queue_t;
+
+typedef struct coap_queue_t {
+  struct coap_queue_t *next;
+  coap_tick_t t;                /**< when to send PDU for the next time */
+  unsigned char retransmit_cnt; /**< retransmission counter, will be removed
+                                 *    when zero */
+  unsigned int timeout;         /**< the randomized timeout value */
+  coap_endpoint_t local_if;     /**< the local address interface */
+  coap_address_t remote;        /**< remote address */
+  coap_tid_t id;                /**< unique transaction id */
+  coap_pdu_t *pdu;              /**< the CoAP PDU to send */
+} coap_queue_t;
+
+/** Adds node to given queue, ordered by node->t. */
+int coap_insert_node(coap_queue_t **queue, coap_queue_t *node);
+
+/** Destroys specified node. */
+int coap_delete_node(coap_queue_t *node);
+
+/** Removes all items from given queue and frees the allocated storage. */
+void coap_delete_all(coap_queue_t *queue);
+
+/** Creates a new node suitable for adding to the CoAP sendqueue. */
+coap_queue_t *coap_new_node(void);
+
+struct coap_resource_t;
+struct coap_context_t;
+#ifndef WITHOUT_ASYNC
+struct coap_async_state_t;
+#endif
+
+/** Message handler that is used as call-back in coap_context_t */
+typedef void (*coap_response_handler_t)(struct coap_context_t  *,
+                                        const coap_endpoint_t *local_interface,
+                                        const coap_address_t *remote,
+                                        coap_pdu_t *sent,
+                                        coap_pdu_t *received,
+                                        const coap_tid_t id);
+
+#define COAP_MID_CACHE_SIZE 3
+typedef struct {
+  unsigned char flags[COAP_MID_CACHE_SIZE];
+  coap_key_t item[COAP_MID_CACHE_SIZE];
+} coap_mid_cache_t;
+
+/** The CoAP stack's global state is stored in a coap_context_t object */
+typedef struct coap_context_t {
+  coap_opt_filter_t known_options;
+  struct coap_resource_t *resources; /**< hash table or list of known resources */
+
+#ifndef WITHOUT_ASYNC
+  /**
+   * list of asynchronous transactions */
+  struct coap_async_state_t *async_state;
+#endif /* WITHOUT_ASYNC */
+
+  /**
+   * The time stamp in the first element of the sendqeue is relative
+   * to sendqueue_basetime. */
+  coap_tick_t sendqueue_basetime;
+  coap_queue_t *sendqueue;
+  coap_endpoint_t *endpoint;      /**< the endpoint used for listening  */
+
+#ifdef WITH_POSIX
+  int sockfd;                     /**< send/receive socket */
+#endif /* WITH_POSIX */
+
+#ifdef WITH_CONTIKI
+  struct uip_udp_conn *conn;      /**< uIP connection object */
+  struct etimer retransmit_timer; /**< fires when the next packet must be sent */
+  struct etimer notify_timer;     /**< used to check resources periodically */
+#endif /* WITH_CONTIKI */
+
+#ifdef WITH_LWIP
+  uint8_t timer_configured;       /**< Set to 1 when a retransmission is
+                                   *   scheduled using lwIP timers for this
+                                   *   context, otherwise 0. */
+#endif /* WITH_LWIP */
+
+  /**
+   * The last message id that was used is stored in this field. The initial
+   * value is set by coap_new_context() and is usually a random value. A new
+   * message id can be created with coap_new_message_id().
+   */
+  unsigned short message_id;
+
+  /**
+   * The next value to be used for Observe. This field is global for all
+   * resources and will be updated when notifications are created.
+   */
+  unsigned int observe;
+
+  coap_response_handler_t response_handler;
+
+  ssize_t (*network_send)(struct coap_context_t *context,
+                          const coap_endpoint_t *local_interface,
+                          const coap_address_t *dst,
+                          unsigned char *data, size_t datalen);
+
+  ssize_t (*network_read)(coap_endpoint_t *ep, coap_packet_t **packet);
+
+} coap_context_t;
+
+/**
+ * Registers a new message handler that is called whenever a response was
+ * received that matches an ongoing transaction.
+ *
+ * @param context The context to register the handler for.
+ * @param handler The response handler to register.
+ */
+static inline void
+coap_register_response_handler(coap_context_t *context,
+                               coap_response_handler_t handler) {
+  context->response_handler = handler;
+}
+
+/**
+ * Registers the option type @p type with the given context object @p ctx.
+ *
+ * @param ctx  The context to use.
+ * @param type The option type to register.
+ */
+inline static void
+coap_register_option(coap_context_t *ctx, unsigned char type) {
+  coap_option_setb(ctx->known_options, type);
+}
+
+/**
+ * Set sendqueue_basetime in the given context object @p ctx to @p now. This
+ * function returns the number of elements in the queue head that have timed
+ * out.
+ */
+unsigned int coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now);
+
+/**
+ * Returns the next pdu to send without removing from sendqeue.
+ */
+coap_queue_t *coap_peek_next( coap_context_t *context );
+
+/**
+ * Returns the next pdu to send and removes it from the sendqeue.
+ */
+coap_queue_t *coap_pop_next( coap_context_t *context );
+
+/**
+ * Creates a new coap_context_t object that will hold the CoAP stack status.
+ */
+coap_context_t *coap_new_context(const coap_address_t *listen_addr);
+
+/**
+ * Returns a new message id and updates @p context->message_id accordingly. The
+ * message id is returned in network byte order to make it easier to read in
+ * tracing tools.
+ *
+ * @param context The current coap_context_t object.
+ *
+ * @return        Incremented message id in network byte order.
+ */
+static inline unsigned short
+coap_new_message_id(coap_context_t *context) {
+  context->message_id++;
+#ifndef WITH_CONTIKI
+  return htons(context->message_id);
+#else /* WITH_CONTIKI */
+  return uip_htons(context->message_id);
+#endif
+}
+
+/**
+ * CoAP stack context must be released with coap_free_context(). This function
+ * clears all entries from the receive queue and send queue and deletes the
+ * resources that have been registered with @p context, and frees the attached
+ * endpoints.
+ */
+void coap_free_context(coap_context_t *context);
+
+
+/**
+ * Sends a confirmed CoAP message to given destination. The memory that is
+ * allocated by pdu will not be released by coap_send_confirmed(). The caller
+ * must release the memory.
+ *
+ * @param context         The CoAP context to use.
+ * @param local_interface The local network interface where the outbound
+ *                        packet is sent.
+ * @param dst             The address to send to.
+ * @param pdu             The CoAP PDU to send.
+ *
+ * @return                The message id of the sent message or @c
+ *                        COAP_INVALID_TID on error.
+ */
+coap_tid_t coap_send_confirmed(coap_context_t *context,
+                               const coap_endpoint_t *local_interface,
+                               const coap_address_t *dst,
+                               coap_pdu_t *pdu);
+
+/**
+ * Creates a new ACK PDU with specified error @p code. The options specified by
+ * the filter expression @p opts will be copied from the original request
+ * contained in @p request. Unless @c SHORT_ERROR_RESPONSE was defined at build
+ * time, the textual reason phrase for @p code will be added as payload, with
+ * Content-Type @c 0.
+ * This function returns a pointer to the new response message, or @c NULL on
+ * error. The storage allocated for the new message must be relased with
+ * coap_free().
+ *
+ * @param request Specification of the received (confirmable) request.
+ * @param code    The error code to set.
+ * @param opts    An option filter that specifies which options to copy from
+ *                the original request in @p node.
+ *
+ * @return        A pointer to the new message or @c NULL on error.
+ */
+coap_pdu_t *coap_new_error_response(coap_pdu_t *request,
+                                    unsigned char code,
+                                    coap_opt_filter_t opts);
+
+/**
+ * Sends a non-confirmed CoAP message to given destination. The memory that is
+ * allocated by pdu will not be released by coap_send().
+ * The caller must release the memory.
+ *
+ * @param context         The CoAP context to use.
+ * @param local_interface The local network interface where the outbound packet
+ *                        is sent.
+ * @param dst             The address to send to.
+ * @param pdu             The CoAP PDU to send.
+ *
+ * @return                The message id of the sent message or @c
+ *                        COAP_INVALID_TID on error.
+ */
+coap_tid_t coap_send(coap_context_t *context,
+                     const coap_endpoint_t *local_interface,
+                     const coap_address_t *dst,
+                     coap_pdu_t *pdu);
+
+/**
+ * Sends an error response with code @p code for request @p request to @p dst.
+ * @p opts will be passed to coap_new_error_response() to copy marked options
+ * from the request. This function returns the transaction id if the message was
+ * sent, or @c COAP_INVALID_TID otherwise.
+ *
+ * @param context         The context to use.
+ * @param request         The original request to respond to.
+ * @param local_interface The local network interface where the outbound packet
+ *                        is sent.
+ * @param dst             The remote peer that sent the request.
+ * @param code            The response code.
+ * @param opts            A filter that specifies the options to copy from the
+ *                        @p request.
+ *
+ * @return                The transaction id if the message was sent, or @c
+ *                        COAP_INVALID_TID otherwise.
+ */
+coap_tid_t coap_send_error(coap_context_t *context,
+                           coap_pdu_t *request,
+                           const coap_endpoint_t *local_interface,
+                           const coap_address_t *dst,
+                           unsigned char code,
+                           coap_opt_filter_t opts);
+
+/**
+ * Helper funktion to create and send a message with @p type (usually ACK or
+ * RST). This function returns @c COAP_INVALID_TID when the message was not
+ * sent, a valid transaction id otherwise.
+ *
+ * @param  context        The CoAP context.
+ * @param local_interface The local network interface where the outbound packet
+ *                        is sent.
+ * @param dst             Where to send the context.
+ * @param request         The request that should be responded to.
+ * @param type            Which type to set.
+ * @return                transaction id on success or @c COAP_INVALID_TID
+ *                        otherwise.
+ */
+coap_tid_t
+coap_send_message_type(coap_context_t *context,
+                       const coap_endpoint_t *local_interface,
+                       const coap_address_t *dst,
+                       coap_pdu_t *request,
+                       unsigned char type);
+
+/**
+ * Sends an ACK message with code @c 0 for the specified @p request to @p dst.
+ * This function returns the corresponding transaction id if the message was
+ * sent or @c COAP_INVALID_TID on error.
+ *
+ * @param context         The context to use.
+ * @param local_interface The local network interface where the outbound packet
+ *                        is sent.
+ * @param dst             The destination address.
+ * @param request         The request to be acknowledged.
+ *
+ * @return                The transaction id if ACK was sent or @c
+ *                        COAP_INVALID_TID on error.
+ */
+coap_tid_t coap_send_ack(coap_context_t *context,
+                         const coap_endpoint_t *local_interface,
+                         const coap_address_t *dst,
+                         coap_pdu_t *request);
+
+/**
+ * Sends an RST message with code @c 0 for the specified @p request to @p dst.
+ * This function returns the corresponding transaction id if the message was
+ * sent or @c COAP_INVALID_TID on error.
+ *
+ * @param context         The context to use.
+ * @param local_interface The local network interface where the outbound packet
+ *                        is sent.
+ * @param dst             The destination address.
+ * @param request         The request to be reset.
+ *
+ * @return                The transaction id if RST was sent or @c
+ *                        COAP_INVALID_TID on error.
+ */
+static inline coap_tid_t
+coap_send_rst(coap_context_t *context,
+              const coap_endpoint_t *local_interface,
+              const coap_address_t *dst,
+              coap_pdu_t *request) {
+  return coap_send_message_type(context,
+                                local_interface,
+                                dst, request,
+                                COAP_MESSAGE_RST);
+}
+
+/**
+ * Handles retransmissions of confirmable messages
+ */
+coap_tid_t coap_retransmit(coap_context_t *context, coap_queue_t *node);
+
+/**
+ * Reads data from the network and tries to parse as CoAP PDU. On success, 0 is
+ * returned and a new node with the parsed PDU is added to the receive queue in
+ * the specified context object.
+ */
+int coap_read(coap_context_t *context);
+
+/**
+ * Parses and interprets a CoAP message with context @p ctx. This function
+ * returns @c 0 if the message was handled, or a value less than zero on
+ * error.
+ *
+ * @param ctx    The current CoAP context.
+ * @param packet The received packet.
+ *
+ * @return       @c 0 if message was handled successfully, or less than zero on
+ *               error.
+ */
+int coap_handle_message(coap_context_t *ctx,
+                        coap_packet_t *packet);
+
+/**
+ * Calculates a unique transaction id from given arguments @p peer and @p pdu.
+ * The id is returned in @p id.
+ *
+ * @param peer The remote party who sent @p pdu.
+ * @param pdu  The message that initiated the transaction.
+ * @param id   Set to the new id.
+ */
+void coap_transaction_id(const coap_address_t *peer,
+                         const coap_pdu_t *pdu,
+                         coap_tid_t *id);
+
+/**
+ * This function removes the element with given @p id from the list given list.
+ * If @p id was found, @p node is updated to point to the removed element. Note
+ * that the storage allocated by @p node is @b not released. The caller must do
+ * this manually using coap_delete_node(). This function returns @c 1 if the
+ * element with id @p id was found, @c 0 otherwise. For a return value of @c 0,
+ * the contents of @p node is undefined.
+ *
+ * @param queue The queue to search for @p id.
+ * @param id    The node id to look for.
+ * @param node  If found, @p node is updated to point to the removed node. You
+ *              must release the storage pointed to by @p node manually.
+ *
+ * @return      @c 1 if @p id was found, @c 0 otherwise.
+ */
+int coap_remove_from_queue(coap_queue_t **queue,
+                           coap_tid_t id,
+                           coap_queue_t **node);
+
+/**
+ * Removes the transaction identified by @p id from given @p queue. This is a
+ * convenience function for coap_remove_from_queue() with automatic deletion of
+ * the removed node.
+ *
+ * @param queue The queue to search for @p id.
+ * @param id    The transaction id.
+ *
+ * @return      @c 1 if node was found, removed and destroyed, @c 0 otherwise.
+ */
+inline static int
+coap_remove_transaction(coap_queue_t **queue, coap_tid_t id) {
+  coap_queue_t *node;
+  if (!coap_remove_from_queue(queue, id, &node))
+    return 0;
+
+  coap_delete_node(node);
+  return 1;
+}
+
+/**
+ * Retrieves transaction from the queue.
+ *
+ * @param queue The transaction queue to be searched.
+ * @param id    Unique key of the transaction to find.
+ *
+ * @return      A pointer to the transaction object or NULL if not found.
+ */
+coap_queue_t *coap_find_transaction(coap_queue_t *queue, coap_tid_t id);
+
+/**
+ * Cancels all outstanding messages for peer @p dst that have the specified
+ * token.
+ *
+ * @param context      The context in use.
+ * @param dst          Destination address of the messages to remove.
+ * @param token        Message token.
+ * @param token_length Actual length of @p token.
+ */
+void coap_cancel_all_messages(coap_context_t *context,
+                              const coap_address_t *dst,
+                              const unsigned char *token,
+                              size_t token_length);
+
+/**
+ * Dispatches the PDUs from the receive queue in given context.
+ */
+void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd);
+
+/**
+ * Returns 1 if there are no messages to send or to dispatch in the context's
+ * queues. */
+int coap_can_exit(coap_context_t *context);
+
+/**
+ * Returns the current value of an internal tick counter. The counter counts \c
+ * COAP_TICKS_PER_SECOND ticks every second.
+ */
+void coap_ticks(coap_tick_t *);
+
+/**
+ * Verifies that @p pdu contains no unknown critical options. Options must be
+ * registered at @p ctx, using the function coap_register_option(). A basic set
+ * of options is registered automatically by coap_new_context(). This function
+ * returns @c 1 if @p pdu is ok, @c 0 otherwise. The given filter object @p
+ * unknown will be updated with the unknown options. As only @c COAP_MAX_OPT
+ * options can be signalled this way, remaining options must be examined
+ * manually.
+ *
+ * @code
+  coap_opt_filter_t f = COAP_OPT_NONE;
+  coap_opt_iterator_t opt_iter;
+
+  if (coap_option_check_critical(ctx, pdu, f) == 0) {
+    coap_option_iterator_init(pdu, &opt_iter, f);
+
+    while (coap_option_next(&opt_iter)) {
+      if (opt_iter.type & 0x01) {
+        ... handle unknown critical option in opt_iter ...
+      }
+    }
+  }
+ * @endcode
+ *
+ * @param ctx      The context where all known options are registered.
+ * @param pdu      The PDU to check.
+ * @param unknown  The output filter that will be updated to indicate the
+ *                 unknown critical options found in @p pdu.
+ *
+ * @return         @c 1 if everything was ok, @c 0 otherwise.
+ */
+int coap_option_check_critical(coap_context_t *ctx,
+                               coap_pdu_t *pdu,
+                               coap_opt_filter_t unknown);
+
+/**
+ * Creates a new response for given @p request with the contents of @c
+ * .well-known/core. The result is NULL on error or a newly allocated PDU that
+ * must be released by coap_delete_pdu().
+ *
+ * @param context The current coap context to use.
+ * @param request The request for @c .well-known/core .
+ *
+ * @return        A new 2.05 response for @c .well-known/core or NULL on error.
+ */
+coap_pdu_t *coap_wellknown_response(coap_context_t *context,
+                                    coap_pdu_t *request);
+
+#endif /* _COAP_NET_H_ */
diff --git a/components/coap/libcoap/include/coap/option.h b/components/coap/libcoap/include/coap/option.h
new file mode 100644
index 00000000..ace2b81c
--- /dev/null
+++ b/components/coap/libcoap/include/coap/option.h
@@ -0,0 +1,410 @@
+/*
+ * option.h -- helpers for handling options in CoAP PDUs
+ *
+ * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file option.h
+ * @brief Helpers for handling options in CoAP PDUs
+ */
+
+#ifndef _COAP_OPTION_H_
+#define _COAP_OPTION_H_
+
+#include "bits.h"
+#include "pdu.h"
+
+/**
+ * Use byte-oriented access methods here because sliding a complex struct
+ * coap_opt_t over the data buffer may cause bus error on certain platforms.
+ */
+typedef unsigned char coap_opt_t;
+#define PCHAR(p) ((coap_opt_t *)(p))
+
+/** Representation of CoAP options. */
+typedef struct {
+  unsigned short delta;
+  size_t length;
+  unsigned char *value;
+} coap_option_t;
+
+/**
+ * Parses the option pointed to by @p opt into @p result. This function returns
+ * the number of bytes that have been parsed, or @c 0 on error. An error is
+ * signaled when illegal delta or length values are encountered or when option
+ * parsing would result in reading past the option (i.e. beyond opt + length).
+ *
+ * @param opt    The beginning of the option to parse.
+ * @param length The maximum length of @p opt.
+ * @param result A pointer to the coap_option_t structure that is filled with
+ *               actual values iff coap_opt_parse() > 0.
+ * @return       The number of bytes parsed or @c 0 on error.
+ */
+size_t coap_opt_parse(const coap_opt_t *opt,
+                      size_t length,
+                      coap_option_t *result);
+
+/**
+ * Returns the size of the given option, taking into account a possible option
+ * jump.
+ *
+ * @param opt An option jump or the beginning of the option.
+ * @return    The number of bytes between @p opt and the end of the option
+ *            starting at @p opt. In case of an error, this function returns
+ *            @c 0 as options need at least one byte storage space.
+ */
+size_t coap_opt_size(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_size() instead. } */
+#define COAP_OPT_SIZE(opt) coap_opt_size(opt)
+
+/**
+ * Calculates the beginning of the PDU's option section.
+ *
+ * @param pdu The PDU containing the options.
+ * @return    A pointer to the first option if available, or @c NULL otherwise.
+ */
+coap_opt_t *options_start(coap_pdu_t *pdu);
+
+/**
+ * Interprets @p opt as pointer to a CoAP option and advances to
+ * the next byte past this option.
+ * @hideinitializer
+ */
+#define options_next(opt) \
+  ((coap_opt_t *)((unsigned char *)(opt) + COAP_OPT_SIZE(opt)))
+
+/**
+ * @defgroup opt_filter Option Filters
+ * @{
+ */
+
+/**
+ * The number of option types below 256 that can be stored in an
+ * option filter. COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG must be
+ * at most 16. Each coap_option_filter_t object reserves
+ * ((COAP_OPT_FILTER_SHORT + 1) / 2) * 2 bytes for short options.
+ */
+#define COAP_OPT_FILTER_SHORT 6
+
+/**
+ * The number of option types above 255 that can be stored in an
+ * option filter. COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG must be
+ * at most 16. Each coap_option_filter_t object reserves
+ * COAP_OPT_FILTER_LONG * 2 bytes for short options.
+ */
+#define COAP_OPT_FILTER_LONG  2
+
+/* Ensure that COAP_OPT_FILTER_SHORT and COAP_OPT_FILTER_LONG are set
+ * correctly. */
+#if (COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG > 16)
+#error COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG must be less or equal 16
+#endif /* (COAP_OPT_FILTER_SHORT + COAP_OPT_FILTER_LONG > 16) */
+
+/** The number of elements in coap_opt_filter_t. */
+#define COAP_OPT_FILTER_SIZE					\
+  (((COAP_OPT_FILTER_SHORT + 1) >> 1) + COAP_OPT_FILTER_LONG) +1
+
+/**
+ * Fixed-size vector we use for option filtering. It is large enough
+ * to hold COAP_OPT_FILTER_SHORT entries with an option number between
+ * 0 and 255, and COAP_OPT_FILTER_LONG entries with an option number
+ * between 256 and 65535. Its internal structure is
+ *
+ * @code
+struct {
+  uint16_t mask;
+  uint16_t long_opts[COAP_OPT_FILTER_LONG];
+  uint8_t short_opts[COAP_OPT_FILTER_SHORT];
+}
+ * @endcode
+ *
+ * The first element contains a bit vector that indicates which fields
+ * in the remaining array are used. The first COAP_OPT_FILTER_LONG
+ * bits correspond to the long option types that are stored in the
+ * elements from index 1 to COAP_OPT_FILTER_LONG. The next
+ * COAP_OPT_FILTER_SHORT bits correspond to the short option types
+ * that are stored in the elements from index COAP_OPT_FILTER_LONG + 1
+ * to COAP_OPT_FILTER_LONG + COAP_OPT_FILTER_SHORT. The latter
+ * elements are treated as bytes.
+ */
+typedef uint16_t coap_opt_filter_t[COAP_OPT_FILTER_SIZE];
+
+/** Pre-defined filter that includes all options. */
+#define COAP_OPT_ALL NULL
+
+/**
+ * Clears filter @p f.
+ *
+ * @param f The filter to clear.
+ */
+static inline void
+coap_option_filter_clear(coap_opt_filter_t f) {
+  memset(f, 0, sizeof(coap_opt_filter_t));
+}
+
+/**
+ * Sets the corresponding entry for @p type in @p filter. This
+ * function returns @c 1 if bit was set or @c 0 on error (i.e. when
+ * the given type does not fit in the filter).
+ *
+ * @param filter The filter object to change.
+ * @param type   The type for which the bit should be set.
+ *
+ * @return       @c 1 if bit was set, @c 0 otherwise.
+ */
+int coap_option_filter_set(coap_opt_filter_t filter, unsigned short type);
+
+/**
+ * Clears the corresponding entry for @p type in @p filter. This
+ * function returns @c 1 if bit was set or @c 0 on error (i.e. when
+ * the given type does not fit in the filter).
+ *
+ * @param filter The filter object to change.
+ * @param type   The type that should be cleared from the filter.
+ *
+ * @return       @c 1 if bit was set, @c 0 otherwise.
+ */
+int coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type);
+
+/**
+ * Checks if @p type is contained in @p filter. This function returns
+ * @c 1 if found, @c 0 if not, or @c -1 on error (i.e. when the given
+ * type does not fit in the filter).
+ *
+ * @param filter The filter object to search.
+ * @param type   The type to search for.
+ *
+ * @return       @c 1 if @p type was found, @c 0 otherwise, or @c -1 on error.
+ */
+int coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type);
+
+/**
+ * Sets the corresponding bit for @p type in @p filter. This function returns @c
+ * 1 if bit was set or @c -1 on error (i.e. when the given type does not fit in
+ * the filter).
+ *
+ * @deprecated Use coap_option_filter_set() instead.
+ *
+ * @param filter The filter object to change.
+ * @param type   The type for which the bit should be set.
+ *
+ * @return       @c 1 if bit was set, @c -1 otherwise.
+ */
+inline static int
+coap_option_setb(coap_opt_filter_t filter, unsigned short type) {
+  return coap_option_filter_set(filter, type) ? 1 : -1;
+}
+
+/**
+ * Clears the corresponding bit for @p type in @p filter. This function returns
+ * @c 1 if bit was cleared or @c -1 on error (i.e. when the given type does not
+ * fit in the filter).
+ *
+ * @deprecated Use coap_option_filter_unset() instead.
+ *
+ * @param filter The filter object to change.
+ * @param type   The type for which the bit should be cleared.
+ *
+ * @return       @c 1 if bit was set, @c -1 otherwise.
+ */
+inline static int
+coap_option_clrb(coap_opt_filter_t filter, unsigned short type) {
+  return coap_option_filter_unset(filter, type) ? 1 : -1;
+}
+
+/**
+ * Gets the corresponding bit for @p type in @p filter. This function returns @c
+ * 1 if the bit is set @c 0 if not, or @c -1 on error (i.e. when the given type
+ * does not fit in the filter).
+ *
+ * @deprecated Use coap_option_filter_get() instead.
+ *
+ * @param filter The filter object to read bit from.
+ * @param type   The type for which the bit should be read.
+ *
+ * @return       @c 1 if bit was set, @c 0 if not, @c -1 on error.
+ */
+inline static int
+coap_option_getb(const coap_opt_filter_t filter, unsigned short type) {
+  return coap_option_filter_get(filter, type);
+}
+
+/**
+ * Iterator to run through PDU options. This object must be
+ * initialized with coap_option_iterator_init(). Call
+ * coap_option_next() to walk through the list of options until
+ * coap_option_next() returns @c NULL.
+ *
+ * @code
+ * coap_opt_t *option;
+ * coap_opt_iterator_t opt_iter;
+ * coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
+ *
+ * while ((option = coap_option_next(&opt_iter))) {
+ *   ... do something with option ...
+ * }
+ * @endcode
+ */
+typedef struct {
+  size_t length;                /**< remaining length of PDU */
+  unsigned short type;          /**< decoded option type */
+  unsigned int bad:1;           /**< iterator object is ok if not set */
+  unsigned int filtered:1;      /**< denotes whether or not filter is used */
+  coap_opt_t *next_option;      /**< pointer to the unparsed next option */
+  coap_opt_filter_t filter;     /**< option filter */
+} coap_opt_iterator_t;
+
+/**
+ * Initializes the given option iterator @p oi to point to the beginning of the
+ * @p pdu's option list. This function returns @p oi on success, @c NULL
+ * otherwise (i.e. when no options exist). Note that a length check on the
+ * option list must be performed before coap_option_iterator_init() is called.
+ *
+ * @param pdu    The PDU the options of which should be walked through.
+ * @param oi     An iterator object that will be initilized.
+ * @param filter An optional option type filter.
+ *               With @p type != @c COAP_OPT_ALL, coap_option_next()
+ *               will return only options matching this bitmask.
+ *               Fence-post options @c 14, @c 28, @c 42, ... are always
+ *               skipped.
+ *
+ * @return       The iterator object @p oi on success, @c NULL otherwise.
+ */
+coap_opt_iterator_t *coap_option_iterator_init(coap_pdu_t *pdu,
+                                               coap_opt_iterator_t *oi,
+                                               const coap_opt_filter_t filter);
+
+/**
+ * Updates the iterator @p oi to point to the next option. This function returns
+ * a pointer to that option or @c NULL if no more options exist. The contents of
+ * @p oi will be updated. In particular, @c oi->n specifies the current option's
+ * ordinal number (counted from @c 1), @c oi->type is the option's type code,
+ * and @c oi->option points to the beginning of the current option itself. When
+ * advanced past the last option, @c oi->option will be @c NULL.
+ *
+ * Note that options are skipped whose corresponding bits in the filter
+ * specified with coap_option_iterator_init() are @c 0. Options with type codes
+ * that do not fit in this filter hence will always be returned.
+ *
+ * @param oi The option iterator to update.
+ *
+ * @return   The next option or @c NULL if no more options exist.
+ */
+coap_opt_t *coap_option_next(coap_opt_iterator_t *oi);
+
+/**
+ * Retrieves the first option of type @p type from @p pdu. @p oi must point to a
+ * coap_opt_iterator_t object that will be initialized by this function to
+ * filter only options with code @p type. This function returns the first option
+ * with this type, or @c NULL if not found.
+ *
+ * @param pdu  The PDU to parse for options.
+ * @param type The option type code to search for.
+ * @param oi   An iterator object to use.
+ *
+ * @return     A pointer to the first option of type @p type, or @c NULL if
+ *             not found.
+ */
+coap_opt_t *coap_check_option(coap_pdu_t *pdu,
+                              unsigned short type,
+                              coap_opt_iterator_t *oi);
+
+/**
+ * Encodes the given delta and length values into @p opt. This function returns
+ * the number of bytes that were required to encode @p delta and @p length or @c
+ * 0 on error. Note that the result indicates by how many bytes @p opt must be
+ * advanced to encode the option value.
+ *
+ * @param opt    The option buffer space where @p delta and @p length are
+ *               written.
+ * @param maxlen The maximum length of @p opt.
+ * @param delta  The actual delta value to encode.
+ * @param length The actual length value to encode.
+ *
+ * @return       The number of bytes used or @c 0 on error.
+ */
+size_t coap_opt_setheader(coap_opt_t *opt,
+                          size_t maxlen,
+                          unsigned short delta,
+                          size_t length);
+
+/**
+ * Encodes option with given @p delta into @p opt. This function returns the
+ * number of bytes written to @p opt or @c 0 on error. This happens especially
+ * when @p opt does not provide sufficient space to store the option value,
+ * delta, and option jumps when required.
+ *
+ * @param opt    The option buffer space where @p val is written.
+ * @param n      Maximum length of @p opt.
+ * @param delta  The option delta.
+ * @param val    The option value to copy into @p opt.
+ * @param length The actual length of @p val.
+ *
+ * @return       The number of bytes that have been written to @p opt or @c 0 on
+ *               error. The return value will always be less than @p n.
+ */
+size_t coap_opt_encode(coap_opt_t *opt,
+                       size_t n,
+                       unsigned short delta,
+                       const unsigned char *val,
+                       size_t length);
+
+/**
+ * Decodes the delta value of the next option. This function returns the number
+ * of bytes read or @c 0 on error. The caller of this function must ensure that
+ * it does not read over the boundaries of @p opt (e.g. by calling
+ * coap_opt_check_delta().
+ *
+ * @param opt The option to examine.
+ *
+ * @return    The number of bytes read or @c 0 on error.
+ */
+unsigned short coap_opt_delta(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_delta() instead. } */
+#define COAP_OPT_DELTA(opt) coap_opt_delta(opt)
+
+/** @deprecated { Use coap_opt_encode() instead. } */
+#define COAP_OPT_SETDELTA(opt,val) \
+  coap_opt_encode((opt), COAP_MAX_PDU_SIZE, (val), NULL, 0)
+
+/**
+ * Returns the length of the given option. @p opt must point to an option jump
+ * or the beginning of the option. This function returns @c 0 when @p opt is not
+ * an option or the actual length of @p opt (which can be @c 0 as well).
+ *
+ * @note {The rationale for using @c 0 in case of an error is that in most
+ * contexts, the result of this function is used to skip the next
+ * coap_opt_length() bytes.}
+ *
+ * @param opt  The option whose length should be returned.
+ *
+ * @return     The option's length or @c 0 when undefined.
+ */
+unsigned short coap_opt_length(const coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_length() instead. } */
+#define COAP_OPT_LENGTH(opt) coap_opt_length(opt)
+
+/**
+ * Returns a pointer to the value of the given option. @p opt must point to an
+ * option jump or the beginning of the option. This function returns @c NULL if
+ * @p opt is not a valid option.
+ *
+ * @param opt The option whose value should be returned.
+ *
+ * @return    A pointer to the option value or @c NULL on error.
+ */
+unsigned char *coap_opt_value(coap_opt_t *opt);
+
+/** @deprecated { Use coap_opt_value() instead. } */
+#define COAP_OPT_VALUE(opt) coap_opt_value((coap_opt_t *)opt)
+
+/** @} */
+
+#endif /* _OPTION_H_ */
diff --git a/components/coap/libcoap/include/coap/pdu.h b/components/coap/libcoap/include/coap/pdu.h
new file mode 100644
index 00000000..7ed482de
--- /dev/null
+++ b/components/coap/libcoap/include/coap/pdu.h
@@ -0,0 +1,388 @@
+/*
+ * pdu.h -- CoAP message structure
+ *
+ * Copyright (C) 2010-2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file pdu.h
+ * @brief Pre-defined constants that reflect defaults for CoAP
+ */
+
+#ifndef _COAP_PDU_H_
+#define _COAP_PDU_H_
+
+#include "uri.h"
+
+#ifdef WITH_LWIP
+#include <lwip/pbuf.h>
+#endif
+
+#define COAP_DEFAULT_PORT      5683 /* CoAP default UDP port */
+#define COAP_DEFAULT_MAX_AGE     60 /* default maximum object lifetime in seconds */
+#ifndef COAP_MAX_PDU_SIZE
+#define COAP_MAX_PDU_SIZE      1400 /* maximum size of a CoAP PDU */
+#endif /* COAP_MAX_PDU_SIZE */
+
+#define COAP_DEFAULT_VERSION      1 /* version of CoAP supported */
+#define COAP_DEFAULT_SCHEME  "coap" /* the default scheme for CoAP URIs */
+
+/** well-known resources URI */
+#define COAP_DEFAULT_URI_WELLKNOWN ".well-known/core"
+
+#ifdef __COAP_DEFAULT_HASH
+/* pre-calculated hash key for the default well-known URI */
+#define COAP_DEFAULT_WKC_HASHKEY   "\345\130\144\245"
+#endif
+
+/* CoAP message types */
+
+#define COAP_MESSAGE_CON       0 /* confirmable message (requires ACK/RST) */
+#define COAP_MESSAGE_NON       1 /* non-confirmable message (one-shot message) */
+#define COAP_MESSAGE_ACK       2 /* used to acknowledge confirmable messages */
+#define COAP_MESSAGE_RST       3 /* indicates error in received messages */
+
+/* CoAP request methods */
+
+#define COAP_REQUEST_GET       1
+#define COAP_REQUEST_POST      2
+#define COAP_REQUEST_PUT       3
+#define COAP_REQUEST_DELETE    4
+
+/* CoAP option types (be sure to update check_critical when adding options */
+
+#define COAP_OPTION_IF_MATCH        1 /* C, opaque, 0-8 B, (none) */
+#define COAP_OPTION_URI_HOST        3 /* C, String, 1-255 B, destination address */
+#define COAP_OPTION_ETAG            4 /* E, opaque, 1-8 B, (none) */
+#define COAP_OPTION_IF_NONE_MATCH   5 /* empty, 0 B, (none) */
+#define COAP_OPTION_URI_PORT        7 /* C, uint, 0-2 B, destination port */
+#define COAP_OPTION_LOCATION_PATH   8 /* E, String, 0-255 B, - */
+#define COAP_OPTION_URI_PATH       11 /* C, String, 0-255 B, (none) */
+#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
+#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
+#define COAP_OPTION_MAXAGE         14 /* E, uint, 0--4 B, 60 Seconds */
+#define COAP_OPTION_URI_QUERY      15 /* C, String, 1-255 B, (none) */
+#define COAP_OPTION_ACCEPT         17 /* C, uint,   0-2 B, (none) */
+#define COAP_OPTION_LOCATION_QUERY 20 /* E, String,   0-255 B, (none) */
+#define COAP_OPTION_PROXY_URI      35 /* C, String, 1-1034 B, (none) */
+#define COAP_OPTION_PROXY_SCHEME   39 /* C, String, 1-255 B, (none) */
+#define COAP_OPTION_SIZE1          60 /* E, uint, 0-4 B, (none) */
+
+/* option types from RFC 7641 */
+
+#define COAP_OPTION_OBSERVE         6 /* E, empty/uint, 0 B/0-3 B, (none) */
+#define COAP_OPTION_SUBSCRIPTION  COAP_OPTION_OBSERVE
+
+/* selected option types from RFC 7959 */
+
+#define COAP_OPTION_BLOCK2         23 /* C, uint, 0--3 B, (none) */
+#define COAP_OPTION_BLOCK1         27 /* C, uint, 0--3 B, (none) */
+
+/* selected option types from RFC 7967 */
+
+#define COAP_OPTION_NORESPONSE    258 /* N, uint, 0--1 B, 0 */
+
+#define COAP_MAX_OPT            65535 /**< the highest option number we know */
+
+/* CoAP result codes (HTTP-Code / 100 * 40 + HTTP-Code % 100) */
+
+/* As of draft-ietf-core-coap-04, response codes are encoded to base
+ * 32, i.e.  the three upper bits determine the response class while
+ * the remaining five fine-grained information specific to that class.
+ */
+#define COAP_RESPONSE_CODE(N) (((N)/100 << 5) | (N)%100)
+
+/* Determines the class of response code C */
+#define COAP_RESPONSE_CLASS(C) (((C) >> 5) & 0xFF)
+
+#ifndef SHORT_ERROR_RESPONSE
+/**
+ * Returns a human-readable response phrase for the specified CoAP response @p
+ * code. This function returns @c NULL if not found.
+ *
+ * @param code The response code for which the literal phrase should be
+ *             retrieved.
+ *
+ * @return     A zero-terminated string describing the error, or @c NULL if not
+ *             found.
+ */
+char *coap_response_phrase(unsigned char code);
+
+#define COAP_ERROR_PHRASE_LENGTH   32 /**< maximum length of error phrase */
+
+#else
+#define coap_response_phrase(x) ((char *)NULL)
+
+#define COAP_ERROR_PHRASE_LENGTH    0 /**< maximum length of error phrase */
+#endif /* SHORT_ERROR_RESPONSE */
+
+/* The following definitions exist for backwards compatibility */
+#if 0 /* this does not exist any more */
+#define COAP_RESPONSE_100      40 /* 100 Continue */
+#endif
+#define COAP_RESPONSE_200      COAP_RESPONSE_CODE(200)  /* 2.00 OK */
+#define COAP_RESPONSE_201      COAP_RESPONSE_CODE(201)  /* 2.01 Created */
+#define COAP_RESPONSE_304      COAP_RESPONSE_CODE(203)  /* 2.03 Valid */
+#define COAP_RESPONSE_400      COAP_RESPONSE_CODE(400)  /* 4.00 Bad Request */
+#define COAP_RESPONSE_404      COAP_RESPONSE_CODE(404)  /* 4.04 Not Found */
+#define COAP_RESPONSE_405      COAP_RESPONSE_CODE(405)  /* 4.05 Method Not Allowed */
+#define COAP_RESPONSE_415      COAP_RESPONSE_CODE(415)  /* 4.15 Unsupported Media Type */
+#define COAP_RESPONSE_500      COAP_RESPONSE_CODE(500)  /* 5.00 Internal Server Error */
+#define COAP_RESPONSE_501      COAP_RESPONSE_CODE(501)  /* 5.01 Not Implemented */
+#define COAP_RESPONSE_503      COAP_RESPONSE_CODE(503)  /* 5.03 Service Unavailable */
+#define COAP_RESPONSE_504      COAP_RESPONSE_CODE(504)  /* 5.04 Gateway Timeout */
+#if 0  /* these response codes do not have a valid code any more */
+#  define COAP_RESPONSE_X_240    240   /* Token Option required by server */
+#  define COAP_RESPONSE_X_241    241   /* Uri-Authority Option required by server */
+#endif
+#define COAP_RESPONSE_X_242    COAP_RESPONSE_CODE(402)  /* Critical Option not supported */
+
+/* CoAP media type encoding */
+
+#define COAP_MEDIATYPE_TEXT_PLAIN                 0 /* text/plain (UTF-8) */
+#define COAP_MEDIATYPE_APPLICATION_LINK_FORMAT   40 /* application/link-format */
+#define COAP_MEDIATYPE_APPLICATION_XML           41 /* application/xml */
+#define COAP_MEDIATYPE_APPLICATION_OCTET_STREAM  42 /* application/octet-stream */
+#define COAP_MEDIATYPE_APPLICATION_RDF_XML       43 /* application/rdf+xml */
+#define COAP_MEDIATYPE_APPLICATION_EXI           47 /* application/exi  */
+#define COAP_MEDIATYPE_APPLICATION_JSON          50 /* application/json  */
+#define COAP_MEDIATYPE_APPLICATION_CBOR          60 /* application/cbor  */
+
+/* Note that identifiers for registered media types are in the range 0-65535. We
+ * use an unallocated type here and hope for the best. */
+#define COAP_MEDIATYPE_ANY                         0xff /* any media type */
+
+/**
+ * coap_tid_t is used to store CoAP transaction id, i.e. a hash value
+ * built from the remote transport address and the message id of a
+ * CoAP PDU.  Valid transaction ids are greater or equal zero.
+ */
+typedef int coap_tid_t;
+
+/** Indicates an invalid transaction id. */
+#define COAP_INVALID_TID -1
+
+/**
+ * Indicates that a response is suppressed. This will occur for error
+ * responses if the request was received via IP multicast.
+ */
+#define COAP_DROPPED_RESPONSE -2
+
+#ifdef WORDS_BIGENDIAN
+typedef struct {
+  unsigned int version:2;      /* protocol version */
+  unsigned int type:2;         /* type flag */
+  unsigned int token_length:4; /* length of Token */
+  unsigned int code:8;         /* request method (value 1--10) or response
+                                  code (value 40-255) */
+  unsigned short id;           /* message id */
+  unsigned char token[];       /* the actual token, if any */
+} coap_hdr_t;
+#else
+typedef struct {
+  unsigned int token_length:4; /* length of Token */
+  unsigned int type:2;         /* type flag */
+  unsigned int version:2;      /* protocol version */
+  unsigned int code:8;         /* request method (value 1--10) or response
+                                  code (value 40-255) */
+  unsigned short id;           /* transaction id (network byte order!) */
+  unsigned char token[];       /* the actual token, if any */
+} coap_hdr_t;
+#endif
+
+#define COAP_MESSAGE_IS_EMPTY(MSG)    ((MSG)->code == 0)
+#define COAP_MESSAGE_IS_REQUEST(MSG)  (!COAP_MESSAGE_IS_EMPTY(MSG) \
+                                       && ((MSG)->code < 32))
+#define COAP_MESSAGE_IS_RESPONSE(MSG) ((MSG)->code >= 64)
+
+#define COAP_OPT_LONG 0x0F      /* OC == 0b1111 indicates that the option list
+                                 * in a CoAP message is limited by 0b11110000
+                                 * marker */
+
+#define COAP_OPT_END 0xF0       /* end marker */
+
+#define COAP_PAYLOAD_START 0xFF /* payload marker */
+
+/**
+ * Structures for more convenient handling of options. (To be used with ordered
+ * coap_list_t.) The option's data will be added to the end of the coap_option
+ * structure (see macro COAP_OPTION_DATA).
+ */
+typedef struct {
+  unsigned short key;           /* the option key (no delta coding) */
+  unsigned int length;
+} coap_option;
+
+#define COAP_OPTION_KEY(option) (option).key
+#define COAP_OPTION_LENGTH(option) (option).length
+#define COAP_OPTION_DATA(option) ((unsigned char *)&(option) + sizeof(coap_option))
+
+/**
+ * Header structure for CoAP PDUs
+ */
+
+typedef struct {
+  size_t max_size;          /**< allocated storage for options and data */
+  coap_hdr_t *hdr;          /**< Address of the first byte of the CoAP message.
+                             *   This may or may not equal (coap_hdr_t*)(pdu+1)
+                             *   depending on the memory management
+                             *   implementation. */
+  unsigned short max_delta; /**< highest option number */
+  unsigned short length;    /**< PDU length (including header, options, data) */
+  unsigned char *data;      /**< payload */
+
+#ifdef WITH_LWIP
+  struct pbuf *pbuf;        /**< lwIP PBUF. The package data will always reside
+                             *    inside the pbuf's payload, but this pointer
+                             *    has to be kept because no exact offset can be
+                             *    given. This field must not be accessed from
+                             *    outside, because the pbuf's reference count
+                             *    is checked to be 1 when the pbuf is assigned
+                             *    to the pdu, and the pbuf stays exclusive to
+                             *    this pdu. */
+#endif
+} coap_pdu_t;
+
+/**
+ * Options in coap_pdu_t are accessed with the macro COAP_OPTION.
+ */
+#define COAP_OPTION(node) ((coap_option *)(node)->options)
+
+#ifdef WITH_LWIP
+/**
+ * Creates a CoAP PDU from an lwIP @p pbuf, whose reference is passed on to this
+ * function.
+ *
+ * The pbuf is checked for being contiguous, and for having only one reference.
+ * The reference is stored in the PDU and will be freed when the PDU is freed.
+ *
+ * (For now, these are fatal errors; in future, a new pbuf might be allocated,
+ * the data copied and the passed pbuf freed).
+ *
+ * This behaves like coap_pdu_init(0, 0, 0, pbuf->tot_len), and afterwards
+ * copying the contents of the pbuf to the pdu.
+ *
+ * @return A pointer to the new PDU object or @c NULL on error.
+ */
+coap_pdu_t * coap_pdu_from_pbuf(struct pbuf *pbuf);
+#endif
+
+/**
+ * Creates a new CoAP PDU of given @p size (must be large enough to hold the
+ * basic CoAP message header (coap_hdr_t). The function returns a pointer to the
+ * node coap_pdu_t object on success, or @c NULL on error. The storage allocated
+ * for the result must be released with coap_delete_pdu().
+ *
+ * @param type The type of the PDU (one of COAP_MESSAGE_CON, COAP_MESSAGE_NON,
+ *             COAP_MESSAGE_ACK, COAP_MESSAGE_RST).
+ * @param code The message code.
+ * @param id   The message id to set or COAP_INVALID_TID if unknown.
+ * @param size The number of bytes to allocate for the actual message.
+ *
+ * @return     A pointer to the new PDU object or @c NULL on error.
+ */
+coap_pdu_t *
+coap_pdu_init(unsigned char type,
+              unsigned char code,
+              unsigned short id,
+              size_t size);
+
+/**
+ * Clears any contents from @p pdu and resets @c version field, @c
+ * length and @c data pointers. @c max_size is set to @p size, any
+ * other field is set to @c 0. Note that @p pdu must be a valid
+ * pointer to a coap_pdu_t object created e.g. by coap_pdu_init().
+ */
+void coap_pdu_clear(coap_pdu_t *pdu, size_t size);
+
+/**
+ * Creates a new CoAP PDU.
+ * The object is created on the heap and must be released using
+ * coap_delete_pdu();
+ *
+ * @deprecated This function allocates the maximum storage for each
+ * PDU. Use coap_pdu_init() instead.
+ */
+coap_pdu_t *coap_new_pdu(void);
+
+void coap_delete_pdu(coap_pdu_t *);
+
+/**
+ * Parses @p data into the CoAP PDU structure given in @p result.
+ * This function returns @c 0 on error or a number greater than zero on success.
+ *
+ * @param data   The raw data to parse as CoAP PDU.
+ * @param length The actual size of @p data.
+ * @param result The PDU structure to fill. Note that the structure must
+ *               provide space for at least @p length bytes to hold the
+ *               entire CoAP PDU.
+ *
+ * @return       A value greater than zero on success or @c 0 on error.
+ */
+int coap_pdu_parse(unsigned char *data,
+                   size_t length,
+                   coap_pdu_t *result);
+
+/**
+ * Adds token of length @p len to @p pdu.
+ * Adding the token destroys any following contents of the pdu. Hence options
+ * and data must be added after coap_add_token() has been called. In @p pdu,
+ * length is set to @p len + @c 4, and max_delta is set to @c 0. This funtion
+ * returns @c 0 on error or a value greater than zero on success.
+ *
+ * @param pdu  The PDU where the token is to be added.
+ * @param len  The length of the new token.
+ * @param data The token to add.
+ *
+ * @return     A value greater than zero on success, or @c 0 on error.
+ */
+int coap_add_token(coap_pdu_t *pdu,
+                  size_t len,
+                  const unsigned char *data);
+
+/**
+ * Adds option of given type to pdu that is passed as first
+ * parameter.
+ * coap_add_option() destroys the PDU's data, so coap_add_data() must be called
+ * after all options have been added. As coap_add_token() destroys the options
+ * following the token, the token must be added before coap_add_option() is
+ * called. This function returns the number of bytes written or @c 0 on error.
+ */
+size_t coap_add_option(coap_pdu_t *pdu,
+                       unsigned short type,
+                       unsigned int len,
+                       const unsigned char *data);
+
+/**
+ * Adds option of given type to pdu that is passed as first parameter, but does
+ * not write a value. It works like coap_add_option with respect to calling
+ * sequence (i.e. after token and before data). This function returns a memory
+ * address to which the option data has to be written before the PDU can be
+ * sent, or @c NULL on error.
+ */
+unsigned char *coap_add_option_later(coap_pdu_t *pdu,
+                                     unsigned short type,
+                                     unsigned int len);
+
+/**
+ * Adds given data to the pdu that is passed as first parameter. Note that the
+ * PDU's data is destroyed by coap_add_option(). coap_add_data() must be called
+ * only once per PDU, otherwise the result is undefined.
+ */
+int coap_add_data(coap_pdu_t *pdu,
+                  unsigned int len,
+                  const unsigned char *data);
+
+/**
+ * Retrieves the length and data pointer of specified PDU. Returns 0 on error or
+ * 1 if *len and *data have correct values. Note that these values are destroyed
+ * with the pdu.
+ */
+int coap_get_data(coap_pdu_t *pdu,
+                  size_t *len,
+                  unsigned char **data);
+
+#endif /* _COAP_PDU_H_ */
diff --git a/components/coap/libcoap/include/coap/prng.h b/components/coap/libcoap/include/coap/prng.h
new file mode 100644
index 00000000..da6d9534
--- /dev/null
+++ b/components/coap/libcoap/include/coap/prng.h
@@ -0,0 +1,106 @@
+/*
+ * prng.h -- Pseudo Random Numbers
+ *
+ * Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file prng.h
+ * @brief Pseudo Random Numbers
+ */
+
+#ifndef _COAP_PRNG_H_
+#define _COAP_PRNG_H_
+
+/**
+ * @defgroup prng Pseudo Random Numbers
+ * @{
+ */
+
+#if defined(WITH_POSIX) || (defined(WITH_LWIP) && !defined(LWIP_RAND))
+#include <stdlib.h>
+
+/**
+ * Fills \p buf with \p len random bytes. This is the default implementation for
+ * prng(). You might want to change prng() to use a better PRNG on your specific
+ * platform.
+ */
+static inline int
+coap_prng_impl(unsigned char *buf, size_t len) {
+  while (len--)
+    *buf++ = rand() & 0xFF;
+  return 1;
+}
+#endif /* WITH_POSIX */
+
+#ifdef WITH_CONTIKI
+#include <string.h>
+
+/**
+ * Fills \p buf with \p len random bytes. This is the default implementation for
+ * prng(). You might want to change prng() to use a better PRNG on your specific
+ * platform.
+ */
+static inline int
+contiki_prng_impl(unsigned char *buf, size_t len) {
+  unsigned short v = random_rand();
+  while (len > sizeof(v)) {
+    memcpy(buf, &v, sizeof(v));
+    len -= sizeof(v);
+    buf += sizeof(v);
+    v = random_rand();
+  }
+
+  memcpy(buf, &v, len);
+  return 1;
+}
+
+#define prng(Buf,Length) contiki_prng_impl((Buf), (Length))
+#define prng_init(Value) random_init((unsigned short)(Value))
+#endif /* WITH_CONTIKI */
+
+#if defined(WITH_LWIP) && defined(LWIP_RAND)
+static inline int
+lwip_prng_impl(unsigned char *buf, size_t len) {
+  u32_t v = LWIP_RAND();
+  while (len > sizeof(v)) {
+    memcpy(buf, &v, sizeof(v));
+    len -= sizeof(v);
+    buf += sizeof(v);
+    v = LWIP_RAND();
+  }
+
+  memcpy(buf, &v, len);
+  return 1;
+}
+
+#define prng(Buf,Length) lwip_prng_impl((Buf), (Length))
+#define prng_init(Value)
+
+#endif /* WITH_LWIP */
+
+#ifndef prng
+/**
+ * Fills \p Buf with \p Length bytes of random data.
+ *
+ * @hideinitializer
+ */
+#define prng(Buf,Length) coap_prng_impl((Buf), (Length))
+#endif
+
+#ifndef prng_init
+/**
+ * Called to set the PRNG seed. You may want to re-define this to allow for a
+ * better PRNG.
+ *
+ * @hideinitializer
+ */
+#define prng_init(Value) srand((unsigned long)(Value))
+#endif
+
+/** @} */
+
+#endif /* _COAP_PRNG_H_ */
diff --git a/components/coap/libcoap/include/coap/resource.h b/components/coap/libcoap/include/coap/resource.h
new file mode 100644
index 00000000..dbb19a8d
--- /dev/null
+++ b/components/coap/libcoap/include/coap/resource.h
@@ -0,0 +1,408 @@
+/*
+ * resource.h -- generic resource handling
+ *
+ * Copyright (C) 2010,2011,2014,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+/**
+ * @file resource.h
+ * @brief Generic resource handling
+ */
+
+#ifndef _COAP_RESOURCE_H_
+#define _COAP_RESOURCE_H_
+
+# include <assert.h>
+
+#ifndef COAP_RESOURCE_CHECK_TIME
+/** The interval in seconds to check if resources have changed. */
+#define COAP_RESOURCE_CHECK_TIME 2
+#endif /* COAP_RESOURCE_CHECK_TIME */
+
+#ifdef COAP_RESOURCES_NOHASH
+#  include "utlist.h"
+#else
+#  include "uthash.h"
+#endif
+
+#include "hashkey.h"
+#include "async.h"
+#include "str.h"
+#include "pdu.h"
+#include "net.h"
+#include "subscribe.h"
+
+/**
+ * Definition of message handler function (@sa coap_resource_t).
+ */
+typedef void (*coap_method_handler_t)
+  (coap_context_t  *,
+   struct coap_resource_t *,
+   const coap_endpoint_t *,
+   coap_address_t *,
+   coap_pdu_t *,
+   str * /* token */,
+   coap_pdu_t * /* response */);
+
+#define COAP_ATTR_FLAGS_RELEASE_NAME  0x1
+#define COAP_ATTR_FLAGS_RELEASE_VALUE 0x2
+
+typedef struct coap_attr_t {
+  struct coap_attr_t *next;
+  str name;
+  str value;
+  int flags;
+} coap_attr_t;
+
+/** The URI passed to coap_resource_init() is free'd by coap_delete_resource(). */
+#define COAP_RESOURCE_FLAGS_RELEASE_URI 0x1
+
+/**
+ * Notifications will be sent non-confirmable by default. RFC 7641 Section 4.5
+ * https://tools.ietf.org/html/rfc7641#section-4.5
+ */
+#define COAP_RESOURCE_FLAGS_NOTIFY_NON  0x0
+
+/**
+ * Notifications will be sent confirmable by default. RFC 7641 Section 4.5
+ * https://tools.ietf.org/html/rfc7641#section-4.5
+ */
+#define COAP_RESOURCE_FLAGS_NOTIFY_CON  0x2
+
+typedef struct coap_resource_t {
+  unsigned int dirty:1;          /**< set to 1 if resource has changed */
+  unsigned int partiallydirty:1; /**< set to 1 if some subscribers have not yet
+                                  *   been notified of the last change */
+  unsigned int observable:1;     /**< can be observed */
+  unsigned int cacheable:1;      /**< can be cached */
+
+  /**
+   * Used to store handlers for the four coap methods @c GET, @c POST, @c PUT,
+   * and @c DELETE. coap_dispatch() will pass incoming requests to the handler
+   * that corresponds to its request method or generate a 4.05 response if no
+   * handler is available.
+   */
+  coap_method_handler_t handler[4];
+
+  coap_key_t key;                /**< the actual key bytes for this resource */
+
+#ifdef COAP_RESOURCES_NOHASH
+  struct coap_resource_t *next;
+#else
+  UT_hash_handle hh;
+#endif
+
+  coap_attr_t *link_attr; /**< attributes to be included with the link format */
+  coap_subscription_t *subscribers;  /**< list of observers for this resource */
+
+  /**
+   * Request URI for this resource. This field will point into the static
+   * memory.
+   */
+  str uri;
+  int flags;
+
+} coap_resource_t;
+
+/**
+ * Creates a new resource object and initializes the link field to the string
+ * of length @p len. This function returns the new coap_resource_t object.
+ *
+ * @param uri    The URI path of the new resource.
+ * @param len    The length of @p uri.
+ * @param flags  Flags for memory management (in particular release of memory).
+ *
+ * @return       A pointer to the new object or @c NULL on error.
+ */
+coap_resource_t *coap_resource_init(const unsigned char *uri,
+                                    size_t len, int flags);
+
+
+/**
+ * Sets the notification message type of resource @p r to given
+ * @p mode which must be one of @c COAP_RESOURCE_FLAGS_NOTIFY_NON
+ * or @c COAP_RESOURCE_FLAGS_NOTIFY_CON.
+ */
+static inline void
+coap_resource_set_mode(coap_resource_t *r, int mode) {
+  r->flags = (r->flags & !COAP_RESOURCE_FLAGS_NOTIFY_CON) | mode;
+}
+
+/**
+ * Registers the given @p resource for @p context. The resource must have been
+ * created by coap_resource_init(), the storage allocated for the resource will
+ * be released by coap_delete_resource().
+ *
+ * @param context  The context to use.
+ * @param resource The resource to store.
+ */
+void coap_add_resource(coap_context_t *context, coap_resource_t *resource);
+
+/**
+ * Deletes a resource identified by @p key. The storage allocated for that
+ * resource is freed.
+ *
+ * @param context  The context where the resources are stored.
+ * @param key      The unique key for the resource to delete.
+ *
+ * @return         @c 1 if the resource was found (and destroyed),
+ *                 @c 0 otherwise.
+ */
+int coap_delete_resource(coap_context_t *context, coap_key_t key);
+
+/**
+ * Deletes all resources from given @p context and frees their storage.
+ *
+ * @param context The CoAP context with the resources to be deleted.
+ */
+void coap_delete_all_resources(coap_context_t *context);
+
+/**
+ * Registers a new attribute with the given @p resource. As the
+ * attributes str fields will point to @p name and @p val the
+ * caller must ensure that these pointers are valid during the
+ * attribute's lifetime.
+ *
+ * @param resource The resource to register the attribute with.
+ * @param name     The attribute's name.
+ * @param nlen     Length of @p name.
+ * @param val      The attribute's value or @c NULL if none.
+ * @param vlen     Length of @p val if specified.
+ * @param flags    Flags for memory management (in particular release of
+ *                 memory).
+ *
+ * @return         A pointer to the new attribute or @c NULL on error.
+ */
+coap_attr_t *coap_add_attr(coap_resource_t *resource,
+                           const unsigned char *name,
+                           size_t nlen,
+                           const unsigned char *val,
+                           size_t vlen,
+                           int flags);
+
+/**
+ * Returns @p resource's coap_attr_t object with given @p name if found, @c NULL
+ * otherwise.
+ *
+ * @param resource The resource to search for attribute @p name.
+ * @param name     Name of the requested attribute.
+ * @param nlen     Actual length of @p name.
+ * @return         The first attribute with specified @p name or @c NULL if none
+ *                 was found.
+ */
+coap_attr_t *coap_find_attr(coap_resource_t *resource,
+                            const unsigned char *name,
+                            size_t nlen);
+
+/**
+ * Deletes an attribute.
+ *
+ * @param attr Pointer to a previously created attribute.
+ *
+ */
+void coap_delete_attr(coap_attr_t *attr);
+
+/**
+ * Status word to encode the result of conditional print or copy operations such
+ * as coap_print_link(). The lower 28 bits of coap_print_status_t are used to
+ * encode the number of characters that has actually been printed, bits 28 to 31
+ * encode the status.  When COAP_PRINT_STATUS_ERROR is set, an error occurred
+ * during output. In this case, the other bits are undefined.
+ * COAP_PRINT_STATUS_TRUNC indicates that the output is truncated, i.e. the
+ * printing would have exceeded the current buffer.
+ */
+typedef unsigned int coap_print_status_t;
+
+#define COAP_PRINT_STATUS_MASK  0xF0000000u
+#define COAP_PRINT_OUTPUT_LENGTH(v) ((v) & ~COAP_PRINT_STATUS_MASK)
+#define COAP_PRINT_STATUS_ERROR 0x80000000u
+#define COAP_PRINT_STATUS_TRUNC 0x40000000u
+
+/**
+ * Writes a description of this resource in link-format to given text buffer. @p
+ * len must be initialized to the maximum length of @p buf and will be set to
+ * the number of characters actually written if successful. This function
+ * returns @c 1 on success or @c 0 on error.
+ *
+ * @param resource The resource to describe.
+ * @param buf      The output buffer to write the description to.
+ * @param len      Must be initialized to the length of @p buf and
+ *                 will be set to the length of the printed link description.
+ * @param offset   The offset within the resource description where to
+ *                 start writing into @p buf. This is useful for dealing
+ *                 with the Block2 option. @p offset is updated during
+ *                 output as it is consumed.
+ *
+ * @return If COAP_PRINT_STATUS_ERROR is set, an error occured. Otherwise,
+ *         the lower 28 bits will indicate the number of characters that
+ *         have actually been output into @p buffer. The flag
+ *         COAP_PRINT_STATUS_TRUNC indicates that the output has been
+ *         truncated.
+ */
+coap_print_status_t coap_print_link(const coap_resource_t *resource,
+                                    unsigned char *buf,
+                                    size_t *len,
+                                    size_t *offset);
+
+/**
+ * Registers the specified @p handler as message handler for the request type @p
+ * method
+ *
+ * @param resource The resource for which the handler shall be registered.
+ * @param method   The CoAP request method to handle.
+ * @param handler  The handler to register with @p resource.
+ */
+static inline void
+coap_register_handler(coap_resource_t *resource,
+                      unsigned char method,
+                      coap_method_handler_t handler) {
+  assert(resource);
+  assert(method > 0 && (size_t)(method-1) < sizeof(resource->handler)/sizeof(coap_method_handler_t));
+  resource->handler[method-1] = handler;
+}
+
+/**
+ * Returns the resource identified by the unique string @p key. If no resource
+ * was found, this function returns @c NULL.
+ *
+ * @param context  The context to look for this resource.
+ * @param key      The unique key of the resource.
+ *
+ * @return         A pointer to the resource or @c NULL if not found.
+ */
+coap_resource_t *coap_get_resource_from_key(coap_context_t *context,
+                                            coap_key_t key);
+
+/**
+ * Calculates the hash key for the resource requested by the Uri-Options of @p
+ * request. This function calls coap_hash() for every path segment.
+ *
+ * @param request The requesting pdu.
+ * @param key     The resulting hash is stored in @p key.
+ */
+void coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key);
+
+/**
+ * @addtogroup observe
+ */
+
+/**
+ * Adds the specified peer as observer for @p resource. The subscription is
+ * identified by the given @p token. This function returns the registered
+ * subscription information if the @p observer has been added, or @c NULL on
+ * error.
+ *
+ * @param resource        The observed resource.
+ * @param local_interface The local network interface where the observer is
+ *                        attached to.
+ * @param observer        The remote peer that wants to received status updates.
+ * @param token           The token that identifies this subscription.
+ * @return                A pointer to the added/updated subscription
+ *                        information or @c NULL on error.
+ */
+coap_subscription_t *coap_add_observer(coap_resource_t *resource,
+                                       const coap_endpoint_t *local_interface,
+                                       const coap_address_t *observer,
+                                       const str *token);
+
+/**
+ * Returns a subscription object for given @p peer.
+ *
+ * @param resource The observed resource.
+ * @param peer     The address to search for.
+ * @param token    The token that identifies this subscription or @c NULL for
+ *                 any token.
+ * @return         A valid subscription if exists or @c NULL otherwise.
+ */
+coap_subscription_t *coap_find_observer(coap_resource_t *resource,
+                                        const coap_address_t *peer,
+                                        const str *token);
+
+/**
+ * Marks an observer as alive.
+ *
+ * @param context  The CoAP context to use.
+ * @param observer The transport address of the observer.
+ * @param token    The corresponding token that has been used for the
+ *                 subscription.
+ */
+void coap_touch_observer(coap_context_t *context,
+                         const coap_address_t *observer,
+                         const str *token);
+
+/**
+ * Removes any subscription for @p observer from @p resource and releases the
+ * allocated storage. The result is @c 1 if an observation relationship with @p
+ * observer and @p token existed, @c 0 otherwise.
+ *
+ * @param resource The observed resource.
+ * @param observer The observer's address.
+ * @param token    The token that identifies this subscription or @c NULL for
+ *                 any token.
+ * @return         @c 1 if the observer has been deleted, @c 0 otherwise.
+ */
+int coap_delete_observer(coap_resource_t *resource,
+                         const coap_address_t *observer,
+                         const str *token);
+
+/**
+ * Checks for all known resources, if they are dirty and notifies subscribed
+ * observers.
+ */
+void coap_check_notify(coap_context_t *context);
+
+#ifdef COAP_RESOURCES_NOHASH
+
+#define RESOURCES_ADD(r, obj) \
+  LL_PREPEND((r), (obj))
+
+#define RESOURCES_DELETE(r, obj) \
+  LL_DELETE((r), (obj))
+
+#define RESOURCES_ITER(r,tmp) \
+  coap_resource_t *tmp;       \
+  LL_FOREACH((r), tmp)
+
+#define RESOURCES_FIND(r, k, res) {                         \
+    coap_resource_t *tmp;                                   \
+    (res) = tmp = NULL;                                     \
+    LL_FOREACH((r), tmp) {                                  \
+      if (memcmp((k), tmp->key, sizeof(coap_key_t)) == 0) { \
+        (res) = tmp;                                        \
+        break;                                              \
+      }                                                     \
+    }                                                       \
+  }
+#else /* COAP_RESOURCES_NOHASH */
+
+#define RESOURCES_ADD(r, obj) \
+  HASH_ADD(hh, (r), key, sizeof(coap_key_t), (obj))
+
+#define RESOURCES_DELETE(r, obj) \
+  HASH_DELETE(hh, (r), (obj))
+
+#define RESOURCES_ITER(r,tmp)  \
+  coap_resource_t *tmp, *rtmp; \
+  HASH_ITER(hh, (r), tmp, rtmp)
+
+#define RESOURCES_FIND(r, k, res) {                     \
+    HASH_FIND(hh, (r), (k), sizeof(coap_key_t), (res)); \
+  }
+
+#endif /* COAP_RESOURCES_NOHASH */
+
+/** @} */
+
+coap_print_status_t coap_print_wellknown(coap_context_t *,
+                                         unsigned char *,
+                                         size_t *, size_t,
+                                         coap_opt_t *);
+
+void coap_handle_failed_notify(coap_context_t *,
+                               const coap_address_t *,
+                               const str *);
+
+#endif /* _COAP_RESOURCE_H_ */
diff --git a/components/coap/libcoap/include/coap/str.h b/components/coap/libcoap/include/coap/str.h
new file mode 100644
index 00000000..3dfa6731
--- /dev/null
+++ b/components/coap/libcoap/include/coap/str.h
@@ -0,0 +1,33 @@
+/*
+ * str.h -- strings to be used in the CoAP library
+ *
+ * Copyright (C) 2010-2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_STR_H_
+#define _COAP_STR_H_
+
+#include <string.h>
+
+typedef struct {
+  size_t length;    /* length of string */
+  unsigned char *s; /* string data */
+} str;
+
+#define COAP_SET_STR(st,l,v) { (st)->length = (l), (st)->s = (v); }
+
+/**
+ * Returns a new string object with at least size bytes storage allocated. The
+ * string must be released using coap_delete_string();
+ */
+str *coap_new_string(size_t size);
+
+/**
+ * Deletes the given string and releases any memory allocated.
+ */
+void coap_delete_string(str *);
+
+#endif /* _COAP_STR_H_ */
diff --git a/components/coap/libcoap/include/coap/subscribe.h b/components/coap/libcoap/include/coap/subscribe.h
new file mode 100644
index 00000000..52068642
--- /dev/null
+++ b/components/coap/libcoap/include/coap/subscribe.h
@@ -0,0 +1,72 @@
+/*
+ * subscribe.h -- subscription handling for CoAP
+ *                see draft-ietf-core-observe-16
+ *
+ * Copyright (C) 2010-2012,2014-2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+
+#ifndef _COAP_SUBSCRIBE_H_
+#define _COAP_SUBSCRIBE_H_
+
+#include "address.h"
+#include "coap_io.h"
+
+/**
+ * @defgroup observe Resource observation
+ * @{
+ */
+
+/**
+ * The value COAP_OBSERVE_ESTABLISH in a GET request indicates a new observe
+ * relationship for (sender address, token) is requested.
+ */
+#define COAP_OBSERVE_ESTABLISH 0
+
+/**
+ * The value COAP_OBSERVE_CANCEL in a GET request indicates that the observe
+ * relationship for (sender address, token) must be cancelled.
+ */
+#define COAP_OBSERVE_CANCEL 1
+
+#ifndef COAP_OBS_MAX_NON
+/**
+ * Number of notifications that may be sent non-confirmable before a confirmable
+ * message is sent to detect if observers are alive. The maximum allowed value
+ * here is @c 15.
+ */
+#define COAP_OBS_MAX_NON   5
+#endif /* COAP_OBS_MAX_NON */
+
+#ifndef COAP_OBS_MAX_FAIL
+/**
+ * Number of confirmable notifications that may fail (i.e. time out without
+ * being ACKed) before an observer is removed. The maximum value for
+ * COAP_OBS_MAX_FAIL is @c 3.
+ */
+#define COAP_OBS_MAX_FAIL  3
+#endif /* COAP_OBS_MAX_FAIL */
+
+/** Subscriber information */
+typedef struct coap_subscription_t {
+  struct coap_subscription_t *next; /**< next element in linked list */
+  coap_endpoint_t local_if;         /**< local communication interface */
+  coap_address_t subscriber;        /**< address and port of subscriber */
+
+  unsigned int non_cnt:4;  /**< up to 15 non-confirmable notifies allowed */
+  unsigned int fail_cnt:2; /**< up to 3 confirmable notifies can fail */
+  unsigned int dirty:1;    /**< set if the notification temporarily could not be
+                            *   sent (in that case, the resource's partially
+                            *   dirty flag is set too) */
+  size_t token_length;     /**< actual length of token */
+  unsigned char token[8];  /**< token used for subscription */
+} coap_subscription_t;
+
+void coap_subscription_init(coap_subscription_t *);
+
+/** @} */
+
+#endif /* _COAP_SUBSCRIBE_H_ */
diff --git a/components/coap/libcoap/include/coap/uri.h b/components/coap/libcoap/include/coap/uri.h
new file mode 100644
index 00000000..2340a7a6
--- /dev/null
+++ b/components/coap/libcoap/include/coap/uri.h
@@ -0,0 +1,121 @@
+/*
+ * uri.h -- helper functions for URI treatment
+ *
+ * Copyright (C) 2010-2011,2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_URI_H_
+#define _COAP_URI_H_
+
+#include "hashkey.h"
+#include "str.h"
+
+/**
+ * Representation of parsed URI. Components may be filled from a string with
+ * coap_split_uri() and can be used as input for option-creation functions.
+ */
+typedef struct {
+  str host;             /**< host part of the URI */
+  unsigned short port;  /**< The port in host byte order */
+  str path;             /**< Beginning of the first path segment. 
+                             Use coap_split_path() to create Uri-Path options */
+  str query;            /**<  The query part if present */
+} coap_uri_t;
+
+/**
+ * Creates a new coap_uri_t object from the specified URI. Returns the new
+ * object or NULL on error. The memory allocated by the new coap_uri_t
+ * must be released using coap_free().
+ *
+ * @param uri The URI path to copy.
+ * @param length The length of uri.
+ *
+ * @return New URI object or NULL on error.
+ */
+coap_uri_t *coap_new_uri(const unsigned char *uri, unsigned int length);
+
+/**
+ * Clones the specified coap_uri_t object. Thie function allocates sufficient
+ * memory to hold the coap_uri_t structure and its contents. The object must
+ * be released with coap_free(). */
+coap_uri_t *coap_clone_uri(const coap_uri_t *uri);
+
+/**
+ * Calculates a hash over the given path and stores the result in 
+ * @p key. This function returns @c 0 on error or @c 1 on success.
+ * 
+ * @param path The URI path to generate hash for.
+ * @param len  The length of @p path.
+ * @param key  The output buffer.
+ * 
+ * @return @c 1 if @p key was set, @c 0 otherwise.
+ */
+int coap_hash_path(const unsigned char *path, size_t len, coap_key_t key);
+
+/**
+ * @defgroup uri_parse URI Parsing Functions
+ *
+ * CoAP PDUs contain normalized URIs with their path and query split into
+ * multiple segments. The functions in this module help splitting strings.
+ * @{
+ */
+
+/**
+ * Parses a given string into URI components. The identified syntactic
+ * components are stored in the result parameter @p uri. Optional URI
+ * components that are not specified will be set to { 0, 0 }, except for the
+ * port which is set to @c COAP_DEFAULT_PORT. This function returns @p 0 if
+ * parsing succeeded, a value less than zero otherwise.
+ * 
+ * @param str_var The string to split up.
+ * @param len     The actual length of @p str_var
+ * @param uri     The coap_uri_t object to store the result.
+ * @return        @c 0 on success, or < 0 on error.
+ *
+ */
+int coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri);
+
+/**
+ * Splits the given URI path into segments. Each segment is preceded
+ * by an option pseudo-header with delta-value 0 and the actual length
+ * of the respective segment after percent-decoding.
+ * 
+ * @param s      The path string to split. 
+ * @param length The actual length of @p s.
+ * @param buf    Result buffer for parsed segments. 
+ * @param buflen Maximum length of @p buf. Will be set to the actual number
+ *               of bytes written into buf on success.
+ * 
+ * @return       The number of segments created or @c -1 on error.
+ */
+int coap_split_path(const unsigned char *s,
+                    size_t length,
+                    unsigned char *buf,
+                    size_t *buflen);
+
+/** 
+ * Splits the given URI query into segments. Each segment is preceded
+ * by an option pseudo-header with delta-value 0 and the actual length
+ * of the respective query term.
+ * 
+ * @param s      The query string to split. 
+ * @param length The actual length of @p s.
+ * @param buf    Result buffer for parsed segments. 
+ * @param buflen Maximum length of @p buf. Will be set to the actual number
+ *               of bytes written into buf on success.
+ * 
+ * @return       The number of segments created or @c -1 on error.
+ *
+ * @bug This function does not reserve additional space for delta > 12.
+ */
+int coap_split_query(const unsigned char *s,
+                     size_t length,
+                     unsigned char *buf,
+                     size_t *buflen);
+
+/** @} */
+
+#endif /* _COAP_URI_H_ */
diff --git a/components/coap/libcoap/include/coap/uthash.h b/components/coap/libcoap/include/coap/uthash.h
new file mode 100644
index 00000000..32b7a81c
--- /dev/null
+++ b/components/coap/libcoap/include/coap/uthash.h
@@ -0,0 +1,963 @@
+/*
+Copyright (c) 2003-2014, Troy D. Hanson     http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER
+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.
+*/
+
+#ifndef UTHASH_H
+#define UTHASH_H
+
+#include <string.h>   /* memcmp,strlen */
+#include <stddef.h>   /* ptrdiff_t */
+#include <stdlib.h>   /* exit() */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ source) this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#if defined(_MSC_VER)   /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define DECLTYPE(x) (decltype(x))
+#else                   /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#endif
+#elif defined(__BORLANDC__) || defined(__LCC__) || defined(__WATCOMC__)
+#define NO_DECLTYPE
+#define DECLTYPE(x)
+#else                   /* GNU, Sun and other compilers */
+#define DECLTYPE(x) (__typeof(x))
+#endif
+
+#ifdef NO_DECLTYPE
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  char **_da_dst = (char**)(&(dst));                                             \
+  *_da_dst = (char*)(src);                                                       \
+} while(0)
+#else
+#define DECLTYPE_ASSIGN(dst,src)                                                 \
+do {                                                                             \
+  (dst) = DECLTYPE(dst)(src);                                                    \
+} while(0)
+#endif
+
+/* a number of the hash function use uint32_t which isn't defined on Pre VS2010 */
+#if defined (_WIN32)
+#if defined(_MSC_VER) && _MSC_VER >= 1600
+#include <stdint.h>
+#elif defined(__WATCOMC__)
+#include <stdint.h>
+#else
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+#endif
+#else
+#include <stdint.h>
+#endif
+
+#define UTHASH_VERSION 1.9.9
+
+#ifndef uthash_fatal
+#define uthash_fatal(msg) exit(-1)        /* fatal error (out of memory,etc) */
+#endif
+#ifndef uthash_malloc
+#define uthash_malloc(sz) malloc(sz)      /* malloc fcn                      */
+#endif
+#ifndef uthash_free
+#define uthash_free(ptr,sz) free(ptr)     /* free fcn                        */
+#endif
+
+#ifndef uthash_noexpand_fyi
+#define uthash_noexpand_fyi(tbl)          /* can be defined to log noexpand  */
+#endif
+#ifndef uthash_expand_fyi
+#define uthash_expand_fyi(tbl)            /* can be defined to log expands   */
+#endif
+
+/* initial number of buckets */
+#define HASH_INITIAL_NUM_BUCKETS 32      /* initial number of buckets        */
+#define HASH_INITIAL_NUM_BUCKETS_LOG2 5  /* lg2 of initial number of buckets */
+#define HASH_BKT_CAPACITY_THRESH 10      /* expand when bucket count reaches */
+
+/* calculate the element whose hash handle address is hhe */
+#define ELMT_FROM_HH(tbl,hhp) ((void*)(((char*)(hhp)) - ((tbl)->hho)))
+
+#define HASH_FIND(hh,head,keyptr,keylen,out)                                     \
+do {                                                                             \
+  out=NULL;                                                                      \
+  if (head) {                                                                    \
+     unsigned _hf_bkt,_hf_hashv;                                                 \
+     HASH_FCN(keyptr,keylen, (head)->hh.tbl->num_buckets, _hf_hashv, _hf_bkt);   \
+     if (HASH_BLOOM_TEST((head)->hh.tbl, _hf_hashv)) {                           \
+       HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ],  \
+                        keyptr,keylen,out);                                      \
+     }                                                                           \
+  }                                                                              \
+} while (0)
+
+#ifdef HASH_BLOOM
+#define HASH_BLOOM_BITLEN (1ULL << HASH_BLOOM)
+#define HASH_BLOOM_BYTELEN (HASH_BLOOM_BITLEN/8) + ((HASH_BLOOM_BITLEN%8) ? 1:0)
+#define HASH_BLOOM_MAKE(tbl)                                                     \
+do {                                                                             \
+  (tbl)->bloom_nbits = HASH_BLOOM;                                               \
+  (tbl)->bloom_bv = (uint8_t*)uthash_malloc(HASH_BLOOM_BYTELEN);                 \
+  if (!((tbl)->bloom_bv))  { uthash_fatal( "out of memory"); }                   \
+  memset((tbl)->bloom_bv, 0, HASH_BLOOM_BYTELEN);                                \
+  (tbl)->bloom_sig = HASH_BLOOM_SIGNATURE;                                       \
+} while (0)
+
+#define HASH_BLOOM_FREE(tbl)                                                     \
+do {                                                                             \
+  uthash_free((tbl)->bloom_bv, HASH_BLOOM_BYTELEN);                              \
+} while (0)
+
+#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8] |= (1U << ((idx)%8)))
+#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8] & (1U << ((idx)%8)))
+
+#define HASH_BLOOM_ADD(tbl,hashv)                                                \
+  HASH_BLOOM_BITSET((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#define HASH_BLOOM_TEST(tbl,hashv)                                               \
+  HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1)))
+
+#else
+#define HASH_BLOOM_MAKE(tbl)
+#define HASH_BLOOM_FREE(tbl)
+#define HASH_BLOOM_ADD(tbl,hashv)
+#define HASH_BLOOM_TEST(tbl,hashv) (1)
+#define HASH_BLOOM_BYTELEN 0
+#endif
+
+#define HASH_MAKE_TABLE(hh,head)                                                 \
+do {                                                                             \
+  (head)->hh.tbl = (UT_hash_table*)uthash_malloc(                                \
+                  sizeof(UT_hash_table));                                        \
+  if (!((head)->hh.tbl))  { uthash_fatal( "out of memory"); }                    \
+  memset((head)->hh.tbl, 0, sizeof(UT_hash_table));                              \
+  (head)->hh.tbl->tail = &((head)->hh);                                          \
+  (head)->hh.tbl->num_buckets = HASH_INITIAL_NUM_BUCKETS;                        \
+  (head)->hh.tbl->log2_num_buckets = HASH_INITIAL_NUM_BUCKETS_LOG2;              \
+  (head)->hh.tbl->hho = (char*)(&(head)->hh) - (char*)(head);                    \
+  (head)->hh.tbl->buckets = (UT_hash_bucket*)uthash_malloc(                      \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  if (! (head)->hh.tbl->buckets) { uthash_fatal( "out of memory"); }             \
+  memset((head)->hh.tbl->buckets, 0,                                             \
+          HASH_INITIAL_NUM_BUCKETS*sizeof(struct UT_hash_bucket));               \
+  HASH_BLOOM_MAKE((head)->hh.tbl);                                               \
+  (head)->hh.tbl->signature = HASH_SIGNATURE;                                    \
+} while(0)
+
+#define HASH_ADD(hh,head,fieldname,keylen_in,add)                                \
+        HASH_ADD_KEYPTR(hh,head,&((add)->fieldname),keylen_in,add)
+
+#define HASH_REPLACE(hh,head,fieldname,keylen_in,add,replaced)                   \
+do {                                                                             \
+  replaced=NULL;                                                                 \
+  HASH_FIND(hh,head,&((add)->fieldname),keylen_in,replaced);                     \
+  if (replaced!=NULL) {                                                          \
+     HASH_DELETE(hh,head,replaced);                                              \
+  };                                                                             \
+  HASH_ADD(hh,head,fieldname,keylen_in,add);                                     \
+} while(0)
+
+#define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add)                            \
+do {                                                                             \
+ unsigned _ha_bkt;                                                               \
+ (add)->hh.next = NULL;                                                          \
+ (add)->hh.key = (char*)(keyptr);                                                \
+ (add)->hh.keylen = (unsigned)(keylen_in);                                       \
+ if (!(head)) {                                                                  \
+    head = (add);                                                                \
+    (head)->hh.prev = NULL;                                                      \
+    HASH_MAKE_TABLE(hh,head);                                                    \
+ } else {                                                                        \
+    (head)->hh.tbl->tail->next = (add);                                          \
+    (add)->hh.prev = ELMT_FROM_HH((head)->hh.tbl, (head)->hh.tbl->tail);         \
+    (head)->hh.tbl->tail = &((add)->hh);                                         \
+ }                                                                               \
+ (head)->hh.tbl->num_items++;                                                    \
+ (add)->hh.tbl = (head)->hh.tbl;                                                 \
+ HASH_FCN(keyptr,keylen_in, (head)->hh.tbl->num_buckets,                         \
+         (add)->hh.hashv, _ha_bkt);                                              \
+ HASH_ADD_TO_BKT((head)->hh.tbl->buckets[_ha_bkt],&(add)->hh);                   \
+ HASH_BLOOM_ADD((head)->hh.tbl,(add)->hh.hashv);                                 \
+ HASH_EMIT_KEY(hh,head,keyptr,keylen_in);                                        \
+ HASH_FSCK(hh,head);                                                             \
+} while(0)
+
+#define HASH_TO_BKT( hashv, num_bkts, bkt )                                      \
+do {                                                                             \
+  bkt = ((hashv) & ((num_bkts) - 1));                                            \
+} while(0)
+
+/* delete "delptr" from the hash table.
+ * "the usual" patch-up process for the app-order doubly-linked-list.
+ * The use of _hd_hh_del below deserves special explanation.
+ * These used to be expressed using (delptr) but that led to a bug
+ * if someone used the same symbol for the head and deletee, like
+ *  HASH_DELETE(hh,users,users);
+ * We want that to work, but by changing the head (users) below
+ * we were forfeiting our ability to further refer to the deletee (users)
+ * in the patch-up process. Solution: use scratch space to
+ * copy the deletee pointer, then the latter references are via that
+ * scratch pointer rather than through the repointed (users) symbol.
+ */
+#define HASH_DELETE(hh,head,delptr)                                              \
+do {                                                                             \
+    struct UT_hash_handle *_hd_hh_del;                                           \
+    if ( ((delptr)->hh.prev == NULL) && ((delptr)->hh.next == NULL) )  {         \
+        uthash_free((head)->hh.tbl->buckets,                                     \
+                    (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+        HASH_BLOOM_FREE((head)->hh.tbl);                                         \
+        uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                      \
+        head = NULL;                                                             \
+    } else {                                                                     \
+        unsigned _hd_bkt;                                                        \
+        _hd_hh_del = &((delptr)->hh);                                            \
+        if ((delptr) == ELMT_FROM_HH((head)->hh.tbl,(head)->hh.tbl->tail)) {     \
+            (head)->hh.tbl->tail =                                               \
+                (UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +               \
+                (head)->hh.tbl->hho);                                            \
+        }                                                                        \
+        if ((delptr)->hh.prev) {                                                 \
+            ((UT_hash_handle*)((ptrdiff_t)((delptr)->hh.prev) +                  \
+                    (head)->hh.tbl->hho))->next = (delptr)->hh.next;             \
+        } else {                                                                 \
+            DECLTYPE_ASSIGN(head,(delptr)->hh.next);                             \
+        }                                                                        \
+        if (_hd_hh_del->next) {                                                  \
+            ((UT_hash_handle*)((ptrdiff_t)_hd_hh_del->next +                     \
+                    (head)->hh.tbl->hho))->prev =                                \
+                    _hd_hh_del->prev;                                            \
+        }                                                                        \
+        HASH_TO_BKT( _hd_hh_del->hashv, (head)->hh.tbl->num_buckets, _hd_bkt);   \
+        HASH_DEL_IN_BKT(hh,(head)->hh.tbl->buckets[_hd_bkt], _hd_hh_del);        \
+        (head)->hh.tbl->num_items--;                                             \
+    }                                                                            \
+    HASH_FSCK(hh,head);                                                          \
+} while (0)
+
+
+/* convenience forms of HASH_FIND/HASH_ADD/HASH_DEL */
+#define HASH_FIND_STR(head,findstr,out)                                          \
+    HASH_FIND(hh,head,findstr,(unsigned)strlen(findstr),out)
+#define HASH_ADD_STR(head,strfield,add)                                          \
+    HASH_ADD(hh,head,strfield[0],strlen(add->strfield),add)
+#define HASH_REPLACE_STR(head,strfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,strfield[0],(unsigned)strlen(add->strfield),add,replaced)
+#define HASH_FIND_INT(head,findint,out)                                          \
+    HASH_FIND(hh,head,findint,sizeof(int),out)
+#define HASH_ADD_INT(head,intfield,add)                                          \
+    HASH_ADD(hh,head,intfield,sizeof(int),add)
+#define HASH_REPLACE_INT(head,intfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,intfield,sizeof(int),add,replaced)
+#define HASH_FIND_PTR(head,findptr,out)                                          \
+    HASH_FIND(hh,head,findptr,sizeof(void *),out)
+#define HASH_ADD_PTR(head,ptrfield,add)                                          \
+    HASH_ADD(hh,head,ptrfield,sizeof(void *),add)
+#define HASH_REPLACE_PTR(head,ptrfield,add,replaced)                             \
+    HASH_REPLACE(hh,head,ptrfield,sizeof(void *),add,replaced)
+#define HASH_DEL(head,delptr)                                                    \
+    HASH_DELETE(hh,head,delptr)
+
+/* HASH_FSCK checks hash integrity on every add/delete when HASH_DEBUG is defined.
+ * This is for uthash developer only; it compiles away if HASH_DEBUG isn't defined.
+ */
+#ifdef HASH_DEBUG
+#define HASH_OOPS(...) do { fprintf(stderr,__VA_ARGS__); exit(-1); } while (0)
+#define HASH_FSCK(hh,head)                                                       \
+do {                                                                             \
+    struct UT_hash_handle *_thh;                                                 \
+    if (head) {                                                                  \
+        unsigned _bkt_i;                                                         \
+        unsigned _count;                                                         \
+        char *_prev;                                                             \
+        _count = 0;                                                              \
+        for( _bkt_i = 0; _bkt_i < (head)->hh.tbl->num_buckets; _bkt_i++) {       \
+            unsigned _bkt_count = 0;                                             \
+            _thh = (head)->hh.tbl->buckets[_bkt_i].hh_head;                      \
+            _prev = NULL;                                                        \
+            while (_thh) {                                                       \
+               if (_prev != (char*)(_thh->hh_prev)) {                            \
+                   HASH_OOPS("invalid hh_prev %p, actual %p\n",                  \
+                    _thh->hh_prev, _prev );                                      \
+               }                                                                 \
+               _bkt_count++;                                                     \
+               _prev = (char*)(_thh);                                            \
+               _thh = _thh->hh_next;                                             \
+            }                                                                    \
+            _count += _bkt_count;                                                \
+            if ((head)->hh.tbl->buckets[_bkt_i].count !=  _bkt_count) {          \
+               HASH_OOPS("invalid bucket count %u, actual %u\n",                 \
+                (head)->hh.tbl->buckets[_bkt_i].count, _bkt_count);              \
+            }                                                                    \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid hh item count %u, actual %u\n",                   \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+        /* traverse hh in app order; check next/prev integrity, count */         \
+        _count = 0;                                                              \
+        _prev = NULL;                                                            \
+        _thh =  &(head)->hh;                                                     \
+        while (_thh) {                                                           \
+           _count++;                                                             \
+           if (_prev !=(char*)(_thh->prev)) {                                    \
+              HASH_OOPS("invalid prev %p, actual %p\n",                          \
+                    _thh->prev, _prev );                                         \
+           }                                                                     \
+           _prev = (char*)ELMT_FROM_HH((head)->hh.tbl, _thh);                    \
+           _thh = ( _thh->next ?  (UT_hash_handle*)((char*)(_thh->next) +        \
+                                  (head)->hh.tbl->hho) : NULL );                 \
+        }                                                                        \
+        if (_count != (head)->hh.tbl->num_items) {                               \
+            HASH_OOPS("invalid app item count %u, actual %u\n",                  \
+                (head)->hh.tbl->num_items, _count );                             \
+        }                                                                        \
+    }                                                                            \
+} while (0)
+#else
+#define HASH_FSCK(hh,head)
+#endif
+
+/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to
+ * the descriptor to which this macro is defined for tuning the hash function.
+ * The app can #include <unistd.h> to get the prototype for write(2). */
+#ifdef HASH_EMIT_KEYS
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)                                   \
+do {                                                                             \
+    unsigned _klen = fieldlen;                                                   \
+    write(HASH_EMIT_KEYS, &_klen, sizeof(_klen));                                \
+    write(HASH_EMIT_KEYS, keyptr, fieldlen);                                     \
+} while (0)
+#else
+#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen)
+#endif
+
+/* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */
+#ifdef HASH_FUNCTION
+#define HASH_FCN HASH_FUNCTION
+#else
+#define HASH_FCN HASH_JEN
+#endif
+
+/* The Bernstein hash function, used in Perl prior to v5.6. Note (x<<5+x)=x*33. */
+#define HASH_BER(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hb_keylen=keylen;                                                    \
+  char *_hb_key=(char*)(key);                                                    \
+  (hashv) = 0;                                                                   \
+  while (_hb_keylen--)  { (hashv) = (((hashv) << 5) + (hashv)) + *_hb_key++; }   \
+  bkt = (hashv) & (num_bkts-1);                                                  \
+} while (0)
+
+
+/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
+ * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
+#define HASH_SAX(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _sx_i;                                                                \
+  char *_hs_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_sx_i=0; _sx_i < keylen; _sx_i++)                                          \
+      hashv ^= (hashv << 5) + (hashv >> 2) + _hs_key[_sx_i];                     \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while (0)
+/* FNV-1a variation */
+#define HASH_FNV(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _fn_i;                                                                \
+  char *_hf_key=(char*)(key);                                                    \
+  hashv = 2166136261UL;                                                          \
+  for(_fn_i=0; _fn_i < keylen; _fn_i++) {                                        \
+      hashv = hashv ^ _hf_key[_fn_i];                                            \
+      hashv = hashv * 16777619;                                                  \
+  }                                                                              \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+#define HASH_OAT(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _ho_i;                                                                \
+  char *_ho_key=(char*)(key);                                                    \
+  hashv = 0;                                                                     \
+  for(_ho_i=0; _ho_i < keylen; _ho_i++) {                                        \
+      hashv += _ho_key[_ho_i];                                                   \
+      hashv += (hashv << 10);                                                    \
+      hashv ^= (hashv >> 6);                                                     \
+  }                                                                              \
+  hashv += (hashv << 3);                                                         \
+  hashv ^= (hashv >> 11);                                                        \
+  hashv += (hashv << 15);                                                        \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+#define HASH_JEN_MIX(a,b,c)                                                      \
+do {                                                                             \
+  a -= b; a -= c; a ^= ( c >> 13 );                                              \
+  b -= c; b -= a; b ^= ( a << 8 );                                               \
+  c -= a; c -= b; c ^= ( b >> 13 );                                              \
+  a -= b; a -= c; a ^= ( c >> 12 );                                              \
+  b -= c; b -= a; b ^= ( a << 16 );                                              \
+  c -= a; c -= b; c ^= ( b >> 5 );                                               \
+  a -= b; a -= c; a ^= ( c >> 3 );                                               \
+  b -= c; b -= a; b ^= ( a << 10 );                                              \
+  c -= a; c -= b; c ^= ( b >> 15 );                                              \
+} while (0)
+
+#define HASH_JEN(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned _hj_i,_hj_j,_hj_k;                                                    \
+  unsigned char *_hj_key=(unsigned char*)(key);                                  \
+  hashv = 0xfeedbeef;                                                            \
+  _hj_i = _hj_j = 0x9e3779b9;                                                    \
+  _hj_k = (unsigned)(keylen);                                                    \
+  while (_hj_k >= 12) {                                                          \
+    _hj_i +=    (_hj_key[0] + ( (unsigned)_hj_key[1] << 8 )                      \
+        + ( (unsigned)_hj_key[2] << 16 )                                         \
+        + ( (unsigned)_hj_key[3] << 24 ) );                                      \
+    _hj_j +=    (_hj_key[4] + ( (unsigned)_hj_key[5] << 8 )                      \
+        + ( (unsigned)_hj_key[6] << 16 )                                         \
+        + ( (unsigned)_hj_key[7] << 24 ) );                                      \
+    hashv += (_hj_key[8] + ( (unsigned)_hj_key[9] << 8 )                         \
+        + ( (unsigned)_hj_key[10] << 16 )                                        \
+        + ( (unsigned)_hj_key[11] << 24 ) );                                     \
+                                                                                 \
+     HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                          \
+                                                                                 \
+     _hj_key += 12;                                                              \
+     _hj_k -= 12;                                                                \
+  }                                                                              \
+  hashv += keylen;                                                               \
+  switch ( _hj_k ) {                                                             \
+     case 11: hashv += ( (unsigned)_hj_key[10] << 24 );                          \
+     case 10: hashv += ( (unsigned)_hj_key[9] << 16 );                           \
+     case 9:  hashv += ( (unsigned)_hj_key[8] << 8 );                            \
+     case 8:  _hj_j += ( (unsigned)_hj_key[7] << 24 );                           \
+     case 7:  _hj_j += ( (unsigned)_hj_key[6] << 16 );                           \
+     case 6:  _hj_j += ( (unsigned)_hj_key[5] << 8 );                            \
+     case 5:  _hj_j += _hj_key[4];                                               \
+     case 4:  _hj_i += ( (unsigned)_hj_key[3] << 24 );                           \
+     case 3:  _hj_i += ( (unsigned)_hj_key[2] << 16 );                           \
+     case 2:  _hj_i += ( (unsigned)_hj_key[1] << 8 );                            \
+     case 1:  _hj_i += _hj_key[0];                                               \
+     /* case 0: nothing left to add */                                           \
+     default: /* make gcc -Wswitch-default happy */                              \
+       ;                                                                         \
+  }                                                                              \
+  HASH_JEN_MIX(_hj_i, _hj_j, hashv);                                             \
+  bkt = hashv & (num_bkts-1);                                                    \
+} while(0)
+
+/* The Paul Hsieh hash function */
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__)             \
+  || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+#define get16bits(d) (*((const uint16_t *) (d)))
+#endif
+
+#if !defined (get16bits)
+#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)             \
+                       +(uint32_t)(((const uint8_t *)(d))[0]) )
+#endif
+#define HASH_SFH(key,keylen,num_bkts,hashv,bkt)                                  \
+do {                                                                             \
+  unsigned char *_sfh_key=(unsigned char*)(key);                                 \
+  uint32_t _sfh_tmp, _sfh_len = keylen;                                          \
+                                                                                 \
+  int _sfh_rem = _sfh_len & 3;                                                   \
+  _sfh_len >>= 2;                                                                \
+  hashv = 0xcafebabe;                                                            \
+                                                                                 \
+  /* Main loop */                                                                \
+  for (;_sfh_len > 0; _sfh_len--) {                                              \
+    hashv    += get16bits (_sfh_key);                                            \
+    _sfh_tmp       = (uint32_t)(get16bits (_sfh_key+2)) << 11  ^ hashv;          \
+    hashv     = (hashv << 16) ^ _sfh_tmp;                                        \
+    _sfh_key += 2*sizeof (uint16_t);                                             \
+    hashv    += hashv >> 11;                                                     \
+  }                                                                              \
+                                                                                 \
+  /* Handle end cases */                                                         \
+  switch (_sfh_rem) {                                                            \
+    case 3: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 16;                                                \
+            hashv ^= (uint32_t)(_sfh_key[sizeof (uint16_t)] << 18);              \
+            hashv += hashv >> 11;                                                \
+            break;                                                               \
+    case 2: hashv += get16bits (_sfh_key);                                       \
+            hashv ^= hashv << 11;                                                \
+            hashv += hashv >> 17;                                                \
+            break;                                                               \
+    case 1: hashv += *_sfh_key;                                                  \
+            hashv ^= hashv << 10;                                                \
+            hashv += hashv >> 1;                                                 \
+  }                                                                              \
+                                                                                 \
+    /* Force "avalanching" of final 127 bits */                                  \
+    hashv ^= hashv << 3;                                                         \
+    hashv += hashv >> 5;                                                         \
+    hashv ^= hashv << 4;                                                         \
+    hashv += hashv >> 17;                                                        \
+    hashv ^= hashv << 25;                                                        \
+    hashv += hashv >> 6;                                                         \
+    bkt = hashv & (num_bkts-1);                                                  \
+} while(0)
+
+#ifdef HASH_USING_NO_STRICT_ALIASING
+/* The MurmurHash exploits some CPU's (x86,x86_64) tolerance for unaligned reads.
+ * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error.
+ * MurmurHash uses the faster approach only on CPU's where we know it's safe.
+ *
+ * Note the preprocessor built-in defines can be emitted using:
+ *
+ *   gcc -m64 -dM -E - < /dev/null                  (on gcc)
+ *   cc -## a.c (where a.c is a simple test file)   (Sun Studio)
+ */
+#if (defined(__i386__) || defined(__x86_64__)  || defined(_M_IX86))
+#define MUR_GETBLOCK(p,i) p[i]
+#else /* non intel */
+#define MUR_PLUS0_ALIGNED(p) (((unsigned long)p & 0x3) == 0)
+#define MUR_PLUS1_ALIGNED(p) (((unsigned long)p & 0x3) == 1)
+#define MUR_PLUS2_ALIGNED(p) (((unsigned long)p & 0x3) == 2)
+#define MUR_PLUS3_ALIGNED(p) (((unsigned long)p & 0x3) == 3)
+#define WP(p) ((uint32_t*)((unsigned long)(p) & ~3UL))
+#if (defined(__BIG_ENDIAN__) || defined(SPARC) || defined(__ppc__) || defined(__ppc64__))
+#define MUR_THREE_ONE(p) ((((*WP(p))&0x00ffffff) << 8) | (((*(WP(p)+1))&0xff000000) >> 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0x0000ffff) <<16) | (((*(WP(p)+1))&0xffff0000) >> 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0x000000ff) <<24) | (((*(WP(p)+1))&0xffffff00) >>  8))
+#else /* assume little endian non-intel */
+#define MUR_THREE_ONE(p) ((((*WP(p))&0xffffff00) >> 8) | (((*(WP(p)+1))&0x000000ff) << 24))
+#define MUR_TWO_TWO(p)   ((((*WP(p))&0xffff0000) >>16) | (((*(WP(p)+1))&0x0000ffff) << 16))
+#define MUR_ONE_THREE(p) ((((*WP(p))&0xff000000) >>24) | (((*(WP(p)+1))&0x00ffffff) <<  8))
+#endif
+#define MUR_GETBLOCK(p,i) (MUR_PLUS0_ALIGNED(p) ? ((p)[i]) :           \
+                            (MUR_PLUS1_ALIGNED(p) ? MUR_THREE_ONE(p) : \
+                             (MUR_PLUS2_ALIGNED(p) ? MUR_TWO_TWO(p) :  \
+                                                      MUR_ONE_THREE(p))))
+#endif
+#define MUR_ROTL32(x,r) (((x) << (r)) | ((x) >> (32 - (r))))
+#define MUR_FMIX(_h) \
+do {                 \
+  _h ^= _h >> 16;    \
+  _h *= 0x85ebca6b;  \
+  _h ^= _h >> 13;    \
+  _h *= 0xc2b2ae35l; \
+  _h ^= _h >> 16;    \
+} while(0)
+
+#define HASH_MUR(key,keylen,num_bkts,hashv,bkt)                        \
+do {                                                                   \
+  const uint8_t *_mur_data = (const uint8_t*)(key);                    \
+  const int _mur_nblocks = (keylen) / 4;                               \
+  uint32_t _mur_h1 = 0xf88D5353;                                       \
+  uint32_t _mur_c1 = 0xcc9e2d51;                                       \
+  uint32_t _mur_c2 = 0x1b873593;                                       \
+  uint32_t _mur_k1 = 0;                                                \
+  const uint8_t *_mur_tail;                                            \
+  const uint32_t *_mur_blocks = (const uint32_t*)(_mur_data+_mur_nblocks*4); \
+  int _mur_i;                                                          \
+  for(_mur_i = -_mur_nblocks; _mur_i; _mur_i++) {                      \
+    _mur_k1 = MUR_GETBLOCK(_mur_blocks,_mur_i);                        \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+                                                                       \
+    _mur_h1 ^= _mur_k1;                                                \
+    _mur_h1 = MUR_ROTL32(_mur_h1,13);                                  \
+    _mur_h1 = _mur_h1*5+0xe6546b64;                                    \
+  }                                                                    \
+  _mur_tail = (const uint8_t*)(_mur_data + _mur_nblocks*4);            \
+  _mur_k1=0;                                                           \
+  switch((keylen) & 3) {                                               \
+    case 3: _mur_k1 ^= _mur_tail[2] << 16;                             \
+    case 2: _mur_k1 ^= _mur_tail[1] << 8;                              \
+    case 1: _mur_k1 ^= _mur_tail[0];                                   \
+    _mur_k1 *= _mur_c1;                                                \
+    _mur_k1 = MUR_ROTL32(_mur_k1,15);                                  \
+    _mur_k1 *= _mur_c2;                                                \
+    _mur_h1 ^= _mur_k1;                                                \
+  }                                                                    \
+  _mur_h1 ^= (keylen);                                                 \
+  MUR_FMIX(_mur_h1);                                                   \
+  hashv = _mur_h1;                                                     \
+  bkt = hashv & (num_bkts-1);                                          \
+} while(0)
+#endif  /* HASH_USING_NO_STRICT_ALIASING */
+
+/* key comparison function; return 0 if keys equal */
+#define HASH_KEYCMP(a,b,len) memcmp(a,b,len)
+
+/* iterate over items in a known bucket to find desired item */
+#define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out)                       \
+do {                                                                             \
+ if (head.hh_head) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,head.hh_head));          \
+ else out=NULL;                                                                  \
+ while (out) {                                                                   \
+    if ((out)->hh.keylen == keylen_in) {                                           \
+        if ((HASH_KEYCMP((out)->hh.key,keyptr,keylen_in)) == 0) break;             \
+    }                                                                            \
+    if ((out)->hh.hh_next) DECLTYPE_ASSIGN(out,ELMT_FROM_HH(tbl,(out)->hh.hh_next)); \
+    else out = NULL;                                                             \
+ }                                                                               \
+} while(0)
+
+/* add an item to a bucket  */
+#define HASH_ADD_TO_BKT(head,addhh)                                              \
+do {                                                                             \
+ head.count++;                                                                   \
+ (addhh)->hh_next = head.hh_head;                                                \
+ (addhh)->hh_prev = NULL;                                                        \
+ if (head.hh_head) { (head).hh_head->hh_prev = (addhh); }                        \
+ (head).hh_head=addhh;                                                           \
+ if (head.count >= ((head.expand_mult+1) * HASH_BKT_CAPACITY_THRESH)             \
+     && (addhh)->tbl->noexpand != 1) {                                           \
+       HASH_EXPAND_BUCKETS((addhh)->tbl);                                        \
+ }                                                                               \
+} while(0)
+
+/* remove an item from a given bucket */
+#define HASH_DEL_IN_BKT(hh,head,hh_del)                                          \
+    (head).count--;                                                              \
+    if ((head).hh_head == hh_del) {                                              \
+      (head).hh_head = hh_del->hh_next;                                          \
+    }                                                                            \
+    if (hh_del->hh_prev) {                                                       \
+        hh_del->hh_prev->hh_next = hh_del->hh_next;                              \
+    }                                                                            \
+    if (hh_del->hh_next) {                                                       \
+        hh_del->hh_next->hh_prev = hh_del->hh_prev;                              \
+    }
+
+/* Bucket expansion has the effect of doubling the number of buckets
+ * and redistributing the items into the new buckets. Ideally the
+ * items will distribute more or less evenly into the new buckets
+ * (the extent to which this is true is a measure of the quality of
+ * the hash function as it applies to the key domain).
+ *
+ * With the items distributed into more buckets, the chain length
+ * (item count) in each bucket is reduced. Thus by expanding buckets
+ * the hash keeps a bound on the chain length. This bounded chain
+ * length is the essence of how a hash provides constant time lookup.
+ *
+ * The calculation of tbl->ideal_chain_maxlen below deserves some
+ * explanation. First, keep in mind that we're calculating the ideal
+ * maximum chain length based on the *new* (doubled) bucket count.
+ * In fractions this is just n/b (n=number of items,b=new num buckets).
+ * Since the ideal chain length is an integer, we want to calculate
+ * ceil(n/b). We don't depend on floating point arithmetic in this
+ * hash, so to calculate ceil(n/b) with integers we could write
+ *
+ *      ceil(n/b) = (n/b) + ((n%b)?1:0)
+ *
+ * and in fact a previous version of this hash did just that.
+ * But now we have improved things a bit by recognizing that b is
+ * always a power of two. We keep its base 2 log handy (call it lb),
+ * so now we can write this with a bit shift and logical AND:
+ *
+ *      ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0)
+ *
+ */
+#define HASH_EXPAND_BUCKETS(tbl)                                                 \
+do {                                                                             \
+    unsigned _he_bkt;                                                            \
+    unsigned _he_bkt_i;                                                          \
+    struct UT_hash_handle *_he_thh, *_he_hh_nxt;                                 \
+    UT_hash_bucket *_he_new_buckets, *_he_newbkt;                                \
+    _he_new_buckets = (UT_hash_bucket*)uthash_malloc(                            \
+             2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));              \
+    if (!_he_new_buckets) { uthash_fatal( "out of memory"); }                    \
+    memset(_he_new_buckets, 0,                                                   \
+            2 * tbl->num_buckets * sizeof(struct UT_hash_bucket));               \
+    tbl->ideal_chain_maxlen =                                                    \
+       (tbl->num_items >> (tbl->log2_num_buckets+1)) +                           \
+       ((tbl->num_items & ((tbl->num_buckets*2)-1)) ? 1 : 0);                    \
+    tbl->nonideal_items = 0;                                                     \
+    for(_he_bkt_i = 0; _he_bkt_i < tbl->num_buckets; _he_bkt_i++)                \
+    {                                                                            \
+        _he_thh = tbl->buckets[ _he_bkt_i ].hh_head;                             \
+        while (_he_thh) {                                                        \
+           _he_hh_nxt = _he_thh->hh_next;                                        \
+           HASH_TO_BKT( _he_thh->hashv, tbl->num_buckets*2, _he_bkt);            \
+           _he_newbkt = &(_he_new_buckets[ _he_bkt ]);                           \
+           if (++(_he_newbkt->count) > tbl->ideal_chain_maxlen) {                \
+             tbl->nonideal_items++;                                              \
+             _he_newbkt->expand_mult = _he_newbkt->count /                       \
+                                        tbl->ideal_chain_maxlen;                 \
+           }                                                                     \
+           _he_thh->hh_prev = NULL;                                              \
+           _he_thh->hh_next = _he_newbkt->hh_head;                               \
+           if (_he_newbkt->hh_head) _he_newbkt->hh_head->hh_prev =               \
+                _he_thh;                                                         \
+           _he_newbkt->hh_head = _he_thh;                                        \
+           _he_thh = _he_hh_nxt;                                                 \
+        }                                                                        \
+    }                                                                            \
+    uthash_free( tbl->buckets, tbl->num_buckets*sizeof(struct UT_hash_bucket) ); \
+    tbl->num_buckets *= 2;                                                       \
+    tbl->log2_num_buckets++;                                                     \
+    tbl->buckets = _he_new_buckets;                                              \
+    tbl->ineff_expands = (tbl->nonideal_items > (tbl->num_items >> 1)) ?         \
+        (tbl->ineff_expands+1) : 0;                                              \
+    if (tbl->ineff_expands > 1) {                                                \
+        tbl->noexpand=1;                                                         \
+        uthash_noexpand_fyi(tbl);                                                \
+    }                                                                            \
+    uthash_expand_fyi(tbl);                                                      \
+} while(0)
+
+
+/* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */
+/* Note that HASH_SORT assumes the hash handle name to be hh.
+ * HASH_SRT was added to allow the hash handle name to be passed in. */
+#define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn)
+#define HASH_SRT(hh,head,cmpfcn)                                                 \
+do {                                                                             \
+  unsigned _hs_i;                                                                \
+  unsigned _hs_looping,_hs_nmerges,_hs_insize,_hs_psize,_hs_qsize;               \
+  struct UT_hash_handle *_hs_p, *_hs_q, *_hs_e, *_hs_list, *_hs_tail;            \
+  if (head) {                                                                    \
+      _hs_insize = 1;                                                            \
+      _hs_looping = 1;                                                           \
+      _hs_list = &((head)->hh);                                                  \
+      while (_hs_looping) {                                                      \
+          _hs_p = _hs_list;                                                      \
+          _hs_list = NULL;                                                       \
+          _hs_tail = NULL;                                                       \
+          _hs_nmerges = 0;                                                       \
+          while (_hs_p) {                                                        \
+              _hs_nmerges++;                                                     \
+              _hs_q = _hs_p;                                                     \
+              _hs_psize = 0;                                                     \
+              for ( _hs_i = 0; _hs_i  < _hs_insize; _hs_i++ ) {                  \
+                  _hs_psize++;                                                   \
+                  _hs_q = (UT_hash_handle*)((_hs_q->next) ?                      \
+                          ((void*)((char*)(_hs_q->next) +                        \
+                          (head)->hh.tbl->hho)) : NULL);                         \
+                  if (! (_hs_q) ) break;                                         \
+              }                                                                  \
+              _hs_qsize = _hs_insize;                                            \
+              while ((_hs_psize > 0) || ((_hs_qsize > 0) && _hs_q )) {           \
+                  if (_hs_psize == 0) {                                          \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  } else if ( (_hs_qsize == 0) || !(_hs_q) ) {                   \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p){                                                \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next) ?                \
+                                ((void*)((char*)(_hs_p->next) +                  \
+                                (head)->hh.tbl->hho)) : NULL);                   \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else if ((                                                   \
+                      cmpfcn(DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_p)), \
+                             DECLTYPE(head)(ELMT_FROM_HH((head)->hh.tbl,_hs_q))) \
+                             ) <= 0) {                                           \
+                      _hs_e = _hs_p;                                             \
+                      if (_hs_p){                                                \
+                        _hs_p = (UT_hash_handle*)((_hs_p->next) ?                \
+                               ((void*)((char*)(_hs_p->next) +                   \
+                               (head)->hh.tbl->hho)) : NULL);                    \
+                       }                                                         \
+                      _hs_psize--;                                               \
+                  } else {                                                       \
+                      _hs_e = _hs_q;                                             \
+                      _hs_q = (UT_hash_handle*)((_hs_q->next) ?                  \
+                              ((void*)((char*)(_hs_q->next) +                    \
+                              (head)->hh.tbl->hho)) : NULL);                     \
+                      _hs_qsize--;                                               \
+                  }                                                              \
+                  if ( _hs_tail ) {                                              \
+                      _hs_tail->next = ((_hs_e) ?                                \
+                            ELMT_FROM_HH((head)->hh.tbl,_hs_e) : NULL);          \
+                  } else {                                                       \
+                      _hs_list = _hs_e;                                          \
+                  }                                                              \
+                  if (_hs_e) {                                                   \
+                  _hs_e->prev = ((_hs_tail) ?                                    \
+                     ELMT_FROM_HH((head)->hh.tbl,_hs_tail) : NULL);              \
+                  }                                                              \
+                  _hs_tail = _hs_e;                                              \
+              }                                                                  \
+              _hs_p = _hs_q;                                                     \
+          }                                                                      \
+          if (_hs_tail){                                                         \
+            _hs_tail->next = NULL;                                               \
+          }                                                                      \
+          if ( _hs_nmerges <= 1 ) {                                              \
+              _hs_looping=0;                                                     \
+              (head)->hh.tbl->tail = _hs_tail;                                   \
+              DECLTYPE_ASSIGN(head,ELMT_FROM_HH((head)->hh.tbl, _hs_list));      \
+          }                                                                      \
+          _hs_insize *= 2;                                                       \
+      }                                                                          \
+      HASH_FSCK(hh,head);                                                        \
+ }                                                                               \
+} while (0)
+
+/* This function selects items from one hash into another hash.
+ * The end result is that the selected items have dual presence
+ * in both hashes. There is no copy of the items made; rather
+ * they are added into the new hash through a secondary hash
+ * hash handle that must be present in the structure. */
+#define HASH_SELECT(hh_dst, dst, hh_src, src, cond)                              \
+do {                                                                             \
+  unsigned _src_bkt, _dst_bkt;                                                   \
+  void *_last_elt=NULL, *_elt;                                                   \
+  UT_hash_handle *_src_hh, *_dst_hh, *_last_elt_hh=NULL;                         \
+  ptrdiff_t _dst_hho = ((char*)(&(dst)->hh_dst) - (char*)(dst));                 \
+  if (src) {                                                                     \
+    for(_src_bkt=0; _src_bkt < (src)->hh_src.tbl->num_buckets; _src_bkt++) {     \
+      for(_src_hh = (src)->hh_src.tbl->buckets[_src_bkt].hh_head;                \
+          _src_hh;                                                               \
+          _src_hh = _src_hh->hh_next) {                                          \
+          _elt = ELMT_FROM_HH((src)->hh_src.tbl, _src_hh);                       \
+          if (cond(_elt)) {                                                      \
+            _dst_hh = (UT_hash_handle*)(((char*)_elt) + _dst_hho);               \
+            _dst_hh->key = _src_hh->key;                                         \
+            _dst_hh->keylen = _src_hh->keylen;                                   \
+            _dst_hh->hashv = _src_hh->hashv;                                     \
+            _dst_hh->prev = _last_elt;                                           \
+            _dst_hh->next = NULL;                                                \
+            if (_last_elt_hh) { _last_elt_hh->next = _elt; }                     \
+            if (!dst) {                                                          \
+              DECLTYPE_ASSIGN(dst,_elt);                                         \
+              HASH_MAKE_TABLE(hh_dst,dst);                                       \
+            } else {                                                             \
+              _dst_hh->tbl = (dst)->hh_dst.tbl;                                  \
+            }                                                                    \
+            HASH_TO_BKT(_dst_hh->hashv, _dst_hh->tbl->num_buckets, _dst_bkt);    \
+            HASH_ADD_TO_BKT(_dst_hh->tbl->buckets[_dst_bkt],_dst_hh);            \
+            (dst)->hh_dst.tbl->num_items++;                                      \
+            _last_elt = _elt;                                                    \
+            _last_elt_hh = _dst_hh;                                              \
+          }                                                                      \
+      }                                                                          \
+    }                                                                            \
+  }                                                                              \
+  HASH_FSCK(hh_dst,dst);                                                         \
+} while (0)
+
+#define HASH_CLEAR(hh,head)                                                      \
+do {                                                                             \
+  if (head) {                                                                    \
+    uthash_free((head)->hh.tbl->buckets,                                         \
+                (head)->hh.tbl->num_buckets*sizeof(struct UT_hash_bucket));      \
+    HASH_BLOOM_FREE((head)->hh.tbl);                                             \
+    uthash_free((head)->hh.tbl, sizeof(UT_hash_table));                          \
+    (head)=NULL;                                                                 \
+  }                                                                              \
+} while(0)
+
+#define HASH_OVERHEAD(hh,head)                                                   \
+ ((head) ? (                                                                     \
+ (size_t)((((head)->hh.tbl->num_items   * sizeof(UT_hash_handle))   +            \
+           ((head)->hh.tbl->num_buckets * sizeof(UT_hash_bucket))   +            \
+            (sizeof(UT_hash_table))                                 +            \
+            (HASH_BLOOM_BYTELEN)))) : 0)
+
+#ifdef NO_DECLTYPE
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL);       \
+  el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL))
+#else
+#define HASH_ITER(hh,head,el,tmp)                                                \
+for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL);                 \
+  el; (el)=(tmp),(tmp)=DECLTYPE(el)((tmp)?(tmp)->hh.next:NULL))
+#endif
+
+/* obtain a count of items in the hash */
+#define HASH_COUNT(head) HASH_CNT(hh,head)
+#define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0)
+
+typedef struct UT_hash_bucket {
+   struct UT_hash_handle *hh_head;
+   unsigned count;
+
+   /* expand_mult is normally set to 0. In this situation, the max chain length
+    * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If
+    * the bucket's chain exceeds this length, bucket expansion is triggered).
+    * However, setting expand_mult to a non-zero value delays bucket expansion
+    * (that would be triggered by additions to this particular bucket)
+    * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH.
+    * (The multiplier is simply expand_mult+1). The whole idea of this
+    * multiplier is to reduce bucket expansions, since they are expensive, in
+    * situations where we know that a particular bucket tends to be overused.
+    * It is better to let its chain length grow to a longer yet-still-bounded
+    * value, than to do an O(n) bucket expansion too often.
+    */
+   unsigned expand_mult;
+
+} UT_hash_bucket;
+
+/* random signature used only to find hash tables in external analysis */
+#define HASH_SIGNATURE 0xa0111fe1
+#define HASH_BLOOM_SIGNATURE 0xb12220f2
+
+typedef struct UT_hash_table {
+   UT_hash_bucket *buckets;
+   unsigned num_buckets, log2_num_buckets;
+   unsigned num_items;
+   struct UT_hash_handle *tail; /* tail hh in app order, for fast append    */
+   ptrdiff_t hho; /* hash handle offset (byte pos of hash handle in element */
+
+   /* in an ideal situation (all buckets used equally), no bucket would have
+    * more than ceil(#items/#buckets) items. that's the ideal chain length. */
+   unsigned ideal_chain_maxlen;
+
+   /* nonideal_items is the number of items in the hash whose chain position
+    * exceeds the ideal chain maxlen. these items pay the penalty for an uneven
+    * hash distribution; reaching them in a chain traversal takes >ideal steps */
+   unsigned nonideal_items;
+
+   /* ineffective expands occur when a bucket doubling was performed, but
+    * afterward, more than half the items in the hash had nonideal chain
+    * positions. If this happens on two consecutive expansions we inhibit any
+    * further expansion, as it's not helping; this happens when the hash
+    * function isn't a good fit for the key domain. When expansion is inhibited
+    * the hash will still work, albeit no longer in constant time. */
+   unsigned ineff_expands, noexpand;
+
+   uint32_t signature; /* used only to find hash tables in external analysis */
+#ifdef HASH_BLOOM
+   uint32_t bloom_sig; /* used only to test bloom exists in external analysis */
+   uint8_t *bloom_bv;
+   char bloom_nbits;
+#endif
+
+} UT_hash_table;
+
+typedef struct UT_hash_handle {
+   struct UT_hash_table *tbl;
+   void *prev;                       /* prev element in app order      */
+   void *next;                       /* next element in app order      */
+   struct UT_hash_handle *hh_prev;   /* previous hh in bucket order    */
+   struct UT_hash_handle *hh_next;   /* next hh in bucket order        */
+   void *key;                        /* ptr to enclosing struct's key  */
+   unsigned keylen;                  /* enclosing struct's key len     */
+   unsigned hashv;                   /* result of hash-fcn(key)        */
+} UT_hash_handle;
+
+#endif /* UTHASH_H */
diff --git a/components/coap/libcoap/include/coap/utlist.h b/components/coap/libcoap/include/coap/utlist.h
new file mode 100644
index 00000000..b5f3f04c
--- /dev/null
+++ b/components/coap/libcoap/include/coap/utlist.h
@@ -0,0 +1,757 @@
+/*
+Copyright (c) 2007-2014, Troy D. Hanson   http://troydhanson.github.com/uthash/
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 OWNER
+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.
+*/
+
+#ifndef UTLIST_H
+#define UTLIST_H
+
+#define UTLIST_VERSION 1.9.9
+
+#include <assert.h>
+
+/*
+ * This file contains macros to manipulate singly and doubly-linked lists.
+ *
+ * 1. LL_ macros:  singly-linked lists.
+ * 2. DL_ macros:  doubly-linked lists.
+ * 3. CDL_ macros: circular doubly-linked lists.
+ *
+ * To use singly-linked lists, your structure must have a "next" pointer.
+ * To use doubly-linked lists, your structure must "prev" and "next" pointers.
+ * Either way, the pointer to the head of the list must be initialized to NULL.
+ *
+ * ----------------.EXAMPLE -------------------------
+ * struct item {
+ *      int id;
+ *      struct item *prev, *next;
+ * }
+ *
+ * struct item *list = NULL:
+ *
+ * int main() {
+ *      struct item *item;
+ *      ... allocate and populate item ...
+ *      DL_APPEND(list, item);
+ * }
+ * --------------------------------------------------
+ *
+ * For doubly-linked lists, the append and delete macros are O(1)
+ * For singly-linked lists, append and delete are O(n) but prepend is O(1)
+ * The sort macro is O(n log(n)) for all types of single/double/circular lists.
+ */
+
+/* These macros use decltype or the earlier __typeof GNU extension.
+   As decltype is only available in newer compilers (VS2010 or gcc 4.3+
+   when compiling c++ code), this code uses whatever method is needed
+   or, for VS2008 where neither is available, uses casting workarounds. */
+#ifdef _MSC_VER            /* MS compiler */
+#if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */
+#define LDECLTYPE(x) decltype(x)
+#else                     /* VS2008 or older (or VS2010 in C mode) */
+#define NO_DECLTYPE
+#define LDECLTYPE(x) char*
+#endif
+#elif defined(__ICCARM__)
+#define NO_DECLTYPE
+#define LDECLTYPE(x) char*
+#else                      /* GNU, Sun and other compilers */
+#define LDECLTYPE(x) __typeof(x)
+#endif
+
+/* for VS2008 we use some workarounds to get around the lack of decltype,
+ * namely, we always reassign our tmp variable to the list head if we need
+ * to dereference its prev/next pointers, and save/restore the real head.*/
+#ifdef NO_DECLTYPE
+#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); }
+#define _NEXT(elt,list,next) ((char*)((list)->next))
+#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); }
+/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */
+#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); }
+#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; }
+#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); }
+#else
+#define _SV(elt,list)
+#define _NEXT(elt,list,next) ((elt)->next)
+#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to)
+/* #define _PREV(elt,list,prev) ((elt)->prev) */
+#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to)
+#define _RS(list)
+#define _CASTASGN(a,b) (a)=(b)
+#endif
+
+/******************************************************************************
+ * The sort macro is an adaptation of Simon Tatham's O(n log(n)) mergesort    *
+ * Unwieldy variable names used here to avoid shadowing passed-in variables.  *
+ *****************************************************************************/
+#define LL_SORT(list, cmp)                                                                     \
+    LL_SORT2(list, cmp, next)
+
+#define LL_SORT2(list, cmp, next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      if (_ls_tail) {                                                                          \
+        _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                     \
+      }                                                                                        \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+
+#define DL_SORT(list, cmp)                                                                     \
+    DL_SORT2(list, cmp, prev, next)
+
+#define DL_SORT2(list, cmp, prev, next)                                                        \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev, _ls_tail);                                                         \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                       \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+#define CDL_SORT(list, cmp)                                                                    \
+    CDL_SORT2(list, cmp, prev, next)
+
+#define CDL_SORT2(list, cmp, prev, next)                                                       \
+do {                                                                                           \
+  LDECLTYPE(list) _ls_p;                                                                       \
+  LDECLTYPE(list) _ls_q;                                                                       \
+  LDECLTYPE(list) _ls_e;                                                                       \
+  LDECLTYPE(list) _ls_tail;                                                                    \
+  LDECLTYPE(list) _ls_oldhead;                                                                 \
+  LDECLTYPE(list) _tmp;                                                                        \
+  int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \
+  if (list) {                                                                                  \
+    _ls_insize = 1;                                                                            \
+    _ls_looping = 1;                                                                           \
+    while (_ls_looping) {                                                                      \
+      _CASTASGN(_ls_p,list);                                                                   \
+      _CASTASGN(_ls_oldhead,list);                                                             \
+      list = NULL;                                                                             \
+      _ls_tail = NULL;                                                                         \
+      _ls_nmerges = 0;                                                                         \
+      while (_ls_p) {                                                                          \
+        _ls_nmerges++;                                                                         \
+        _ls_q = _ls_p;                                                                         \
+        _ls_psize = 0;                                                                         \
+        for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \
+          _ls_psize++;                                                                         \
+          _SV(_ls_q,list);                                                                     \
+          if (_NEXT(_ls_q,list,next) == _ls_oldhead) {                                         \
+            _ls_q = NULL;                                                                      \
+          } else {                                                                             \
+            _ls_q = _NEXT(_ls_q,list,next);                                                    \
+          }                                                                                    \
+          _RS(list);                                                                           \
+          if (!_ls_q) break;                                                                   \
+        }                                                                                      \
+        _ls_qsize = _ls_insize;                                                                \
+        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \
+          if (_ls_psize == 0) {                                                                \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          } else if (_ls_qsize == 0 || !_ls_q) {                                               \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \
+            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \
+              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \
+            if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \
+          } else {                                                                             \
+            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \
+              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \
+            if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \
+          }                                                                                    \
+          if (_ls_tail) {                                                                      \
+            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \
+          } else {                                                                             \
+            _CASTASGN(list,_ls_e);                                                             \
+          }                                                                                    \
+          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \
+          _ls_tail = _ls_e;                                                                    \
+        }                                                                                      \
+        _ls_p = _ls_q;                                                                         \
+      }                                                                                        \
+      _CASTASGN(list->prev,_ls_tail);                                                          \
+      _CASTASGN(_tmp,list);                                                                    \
+      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list);                       \
+      if (_ls_nmerges <= 1) {                                                                  \
+        _ls_looping=0;                                                                         \
+      }                                                                                        \
+      _ls_insize *= 2;                                                                         \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+/******************************************************************************
+ * singly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define LL_PREPEND(head,add)                                                                   \
+    LL_PREPEND2(head,add,next)
+
+#define LL_PREPEND2(head,add,next)                                                             \
+do {                                                                                           \
+  (add)->next = head;                                                                          \
+  head = add;                                                                                  \
+} while (0)
+
+#define LL_CONCAT(head1,head2)                                                                 \
+    LL_CONCAT2(head1,head2,next)
+
+#define LL_CONCAT2(head1,head2,next)                                                           \
+do {                                                                                           \
+  LDECLTYPE(head1) _tmp;                                                                       \
+  if (head1) {                                                                                 \
+    _tmp = head1;                                                                              \
+    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+    _tmp->next=(head2);                                                                        \
+  } else {                                                                                     \
+    (head1)=(head2);                                                                           \
+  }                                                                                            \
+} while (0)
+
+#define LL_APPEND(head,add)                                                                    \
+    LL_APPEND2(head,add,next)
+
+#define LL_APPEND2(head,add,next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  (add)->next=NULL;                                                                            \
+  if (head) {                                                                                  \
+    _tmp = head;                                                                               \
+    while (_tmp->next) { _tmp = _tmp->next; }                                                  \
+    _tmp->next=(add);                                                                          \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+} while (0)
+
+#define LL_DELETE(head,del)                                                                    \
+    LL_DELETE2(head,del,next)
+
+#define LL_DELETE2(head,del,next)                                                              \
+do {                                                                                           \
+  LDECLTYPE(head) _tmp;                                                                        \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    _tmp = head;                                                                               \
+    while (_tmp->next && (_tmp->next != (del))) {                                              \
+      _tmp = _tmp->next;                                                                       \
+    }                                                                                          \
+    if (_tmp->next) {                                                                          \
+      _tmp->next = ((del)->next);                                                              \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */
+#define LL_APPEND_VS2008(head,add)                                                             \
+    LL_APPEND2_VS2008(head,add,next)
+
+#define LL_APPEND2_VS2008(head,add,next)                                                       \
+do {                                                                                           \
+  if (head) {                                                                                  \
+    (add)->next = head;     /* use add->next as a temp variable */                             \
+    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \
+    (add)->next->next=(add);                                                                   \
+  } else {                                                                                     \
+    (head)=(add);                                                                              \
+  }                                                                                            \
+  (add)->next=NULL;                                                                            \
+} while (0)
+
+#define LL_DELETE_VS2008(head,del)                                                             \
+    LL_DELETE2_VS2008(head,del,next)
+
+#define LL_DELETE2_VS2008(head,del,next)                                                       \
+do {                                                                                           \
+  if ((head) == (del)) {                                                                       \
+    (head)=(head)->next;                                                                       \
+  } else {                                                                                     \
+    char *_tmp = (char*)(head);                                                                \
+    while ((head)->next && ((head)->next != (del))) {                                          \
+      head = (head)->next;                                                                     \
+    }                                                                                          \
+    if ((head)->next) {                                                                        \
+      (head)->next = ((del)->next);                                                            \
+    }                                                                                          \
+    {                                                                                          \
+      char **_head_alias = (char**)&(head);                                                    \
+      *_head_alias = _tmp;                                                                     \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+#ifdef NO_DECLTYPE
+#undef LL_APPEND
+#define LL_APPEND LL_APPEND_VS2008
+#undef LL_DELETE
+#define LL_DELETE LL_DELETE_VS2008
+#undef LL_DELETE2
+#define LL_DELETE2 LL_DELETE2_VS2008
+#undef LL_APPEND2
+#define LL_APPEND2 LL_APPEND2_VS2008
+#undef LL_CONCAT /* no LL_CONCAT_VS2008 */
+#undef DL_CONCAT /* no DL_CONCAT_VS2008 */
+#endif
+/* end VS2008 replacements */
+
+#define LL_COUNT(head,el,counter)                                                              \
+    LL_COUNT2(head,el,counter,next)                                                            \
+
+#define LL_COUNT2(head,el,counter,next)                                                        \
+{                                                                                              \
+    counter = 0;                                                                               \
+    LL_FOREACH2(head,el,next){ ++counter; }                                                    \
+}
+
+#define LL_FOREACH(head,el)                                                                    \
+    LL_FOREACH2(head,el,next)
+
+#define LL_FOREACH2(head,el,next)                                                              \
+    for(el=head;el;el=(el)->next)
+
+#define LL_FOREACH_SAFE(head,el,tmp)                                                           \
+    LL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define LL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+#define LL_SEARCH_SCALAR(head,out,field,val)                                                   \
+    LL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define LL_SEARCH_SCALAR2(head,out,field,val,next)                                             \
+do {                                                                                           \
+    LL_FOREACH2(head,out,next) {                                                               \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0)
+
+#define LL_SEARCH(head,out,elt,cmp)                                                            \
+    LL_SEARCH2(head,out,elt,cmp,next)
+
+#define LL_SEARCH2(head,out,elt,cmp,next)                                                      \
+do {                                                                                           \
+    LL_FOREACH2(head,out,next) {                                                               \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0)
+
+#define LL_REPLACE_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ LDECLTYPE(head) _tmp;                                                                         \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el)->next;                                                                     \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  _tmp = head;                                                                                 \
+  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+   _tmp = _tmp->next;                                                                          \
+  }                                                                                            \
+  if (_tmp->next) {                                                                            \
+    _tmp->next = (add);                                                                        \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define LL_PREPEND_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ LDECLTYPE(head) _tmp;                                                                         \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  _tmp = head;                                                                                 \
+  while (_tmp->next && (_tmp->next != (el))) {                                                 \
+   _tmp = _tmp->next;                                                                          \
+  }                                                                                            \
+  if (_tmp->next) {                                                                            \
+    _tmp->next = (add);                                                                        \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+
+/******************************************************************************
+ * doubly linked list macros (non-circular)                                   *
+ *****************************************************************************/
+#define DL_PREPEND(head,add)                                                                   \
+    DL_PREPEND2(head,add,prev,next)
+
+#define DL_PREPEND2(head,add,prev,next)                                                        \
+do {                                                                                           \
+ (add)->next = head;                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (head)->prev = (add);                                                                       \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+ }                                                                                             \
+ (head) = (add);                                                                               \
+} while (0)
+
+#define DL_APPEND(head,add)                                                                    \
+    DL_APPEND2(head,add,prev,next)
+
+#define DL_APPEND2(head,add,prev,next)                                                         \
+do {                                                                                           \
+  if (head) {                                                                                  \
+      (add)->prev = (head)->prev;                                                              \
+      (head)->prev->next = (add);                                                              \
+      (head)->prev = (add);                                                                    \
+      (add)->next = NULL;                                                                      \
+  } else {                                                                                     \
+      (head)=(add);                                                                            \
+      (head)->prev = (head);                                                                   \
+      (head)->next = NULL;                                                                     \
+  }                                                                                            \
+} while (0)
+
+#define DL_CONCAT(head1,head2)                                                                 \
+    DL_CONCAT2(head1,head2,prev,next)
+
+#define DL_CONCAT2(head1,head2,prev,next)                                                      \
+do {                                                                                           \
+  LDECLTYPE(head1) _tmp;                                                                       \
+  if (head2) {                                                                                 \
+    if (head1) {                                                                               \
+        _tmp = (head2)->prev;                                                                  \
+        (head2)->prev = (head1)->prev;                                                         \
+        (head1)->prev->next = (head2);                                                         \
+        (head1)->prev = _tmp;                                                                  \
+    } else {                                                                                   \
+        (head1)=(head2);                                                                       \
+    }                                                                                          \
+  }                                                                                            \
+} while (0)
+
+#define DL_DELETE(head,del)                                                                    \
+    DL_DELETE2(head,del,prev,next)
+
+#define DL_DELETE2(head,del,prev,next)                                                         \
+do {                                                                                           \
+  assert((del)->prev != NULL);                                                                 \
+  if ((del)->prev == (del)) {                                                                  \
+      (head)=NULL;                                                                             \
+  } else if ((del)==(head)) {                                                                  \
+      (del)->next->prev = (del)->prev;                                                         \
+      (head) = (del)->next;                                                                    \
+  } else {                                                                                     \
+      (del)->prev->next = (del)->next;                                                         \
+      if ((del)->next) {                                                                       \
+          (del)->next->prev = (del)->prev;                                                     \
+      } else {                                                                                 \
+          (head)->prev = (del)->prev;                                                          \
+      }                                                                                        \
+  }                                                                                            \
+} while (0)
+
+#define DL_COUNT(head,el,counter)                                                              \
+    DL_COUNT2(head,el,counter,next)                                                            \
+
+#define DL_COUNT2(head,el,counter,next)                                                        \
+{                                                                                              \
+    counter = 0;                                                                               \
+    DL_FOREACH2(head,el,next){ ++counter; }                                                    \
+}
+
+#define DL_FOREACH(head,el)                                                                    \
+    DL_FOREACH2(head,el,next)
+
+#define DL_FOREACH2(head,el,next)                                                              \
+    for(el=head;el;el=(el)->next)
+
+/* this version is safe for deleting the elements during iteration */
+#define DL_FOREACH_SAFE(head,el,tmp)                                                           \
+    DL_FOREACH_SAFE2(head,el,tmp,next)
+
+#define DL_FOREACH_SAFE2(head,el,tmp,next)                                                     \
+  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp)
+
+/* these are identical to their singly-linked list counterparts */
+#define DL_SEARCH_SCALAR LL_SEARCH_SCALAR
+#define DL_SEARCH LL_SEARCH
+#define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2
+#define DL_SEARCH2 LL_SEARCH2
+
+#define DL_REPLACE_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+  (add)->next = (el)->next;                                                                    \
+  if ((el)->next == NULL) {                                                                    \
+   (add)->prev = (add);                                                                        \
+  } else {                                                                                     \
+   (add)->prev = (el)->prev;                                                                   \
+   (add)->next->prev = (add);                                                                  \
+  }                                                                                            \
+ } else {                                                                                      \
+  (add)->next = (el)->next;                                                                    \
+  (add)->prev = (el)->prev;                                                                    \
+  (add)->prev->next = (add);                                                                   \
+  if ((el)->next == NULL) {                                                                    \
+   (head)->prev = (add);                                                                       \
+  } else {                                                                                     \
+   (add)->next->prev = (add);                                                                  \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define DL_PREPEND_ELEM(head, el, add)                                                         \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ (add)->prev = (el)->prev;                                                                     \
+ (el)->prev = (add);                                                                           \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  (add)->prev->next = (add);                                                                   \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+
+/******************************************************************************
+ * circular doubly linked list macros                                         *
+ *****************************************************************************/
+#define CDL_PREPEND(head,add)                                                                  \
+    CDL_PREPEND2(head,add,prev,next)
+
+#define CDL_PREPEND2(head,add,prev,next)                                                       \
+do {                                                                                           \
+ if (head) {                                                                                   \
+   (add)->prev = (head)->prev;                                                                 \
+   (add)->next = (head);                                                                       \
+   (head)->prev = (add);                                                                       \
+   (add)->prev->next = (add);                                                                  \
+ } else {                                                                                      \
+   (add)->prev = (add);                                                                        \
+   (add)->next = (add);                                                                        \
+ }                                                                                             \
+(head)=(add);                                                                                  \
+} while (0)
+
+#define CDL_DELETE(head,del)                                                                   \
+    CDL_DELETE2(head,del,prev,next)
+
+#define CDL_DELETE2(head,del,prev,next)                                                        \
+do {                                                                                           \
+  if ( ((head)==(del)) && ((head)->next == (head))) {                                          \
+      (head) = 0L;                                                                             \
+  } else {                                                                                     \
+     (del)->next->prev = (del)->prev;                                                          \
+     (del)->prev->next = (del)->next;                                                          \
+     if ((del) == (head)) (head)=(del)->next;                                                  \
+  }                                                                                            \
+} while (0)
+
+#define CDL_COUNT(head,el,counter)                                                             \
+    CDL_COUNT2(head,el,counter,next)                                                           \
+
+#define CDL_COUNT2(head, el, counter,next)                                                     \
+{                                                                                              \
+    counter = 0;                                                                               \
+    CDL_FOREACH2(head,el,next){ ++counter; }                                                   \
+}
+
+#define CDL_FOREACH(head,el)                                                                   \
+    CDL_FOREACH2(head,el,next)
+
+#define CDL_FOREACH2(head,el,next)                                                             \
+    for(el=head;el;el=((el)->next==head ? 0L : (el)->next))
+
+#define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \
+    CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)
+
+#define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)                                         \
+  for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \
+      (el) && ((tmp2)=(el)->next, 1);                                                          \
+      ((el) = (((el)==(tmp1)) ? 0L : (tmp2))))
+
+#define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \
+    CDL_SEARCH_SCALAR2(head,out,field,val,next)
+
+#define CDL_SEARCH_SCALAR2(head,out,field,val,next)                                            \
+do {                                                                                           \
+    CDL_FOREACH2(head,out,next) {                                                              \
+      if ((out)->field == (val)) break;                                                        \
+    }                                                                                          \
+} while(0)
+
+#define CDL_SEARCH(head,out,elt,cmp)                                                           \
+    CDL_SEARCH2(head,out,elt,cmp,next)
+
+#define CDL_SEARCH2(head,out,elt,cmp,next)                                                     \
+do {                                                                                           \
+    CDL_FOREACH2(head,out,next) {                                                              \
+      if ((cmp(out,elt))==0) break;                                                            \
+    }                                                                                          \
+} while(0)
+
+#define CDL_REPLACE_ELEM(head, el, add)                                                        \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ if ((el)->next == (el)) {                                                                     \
+  (add)->next = (add);                                                                         \
+  (add)->prev = (add);                                                                         \
+  (head) = (add);                                                                              \
+ } else {                                                                                      \
+  (add)->next = (el)->next;                                                                    \
+  (add)->prev = (el)->prev;                                                                    \
+  (add)->next->prev = (add);                                                                   \
+  (add)->prev->next = (add);                                                                   \
+  if ((head) == (el)) {                                                                        \
+   (head) = (add);                                                                             \
+  }                                                                                            \
+ }                                                                                             \
+} while (0)
+
+#define CDL_PREPEND_ELEM(head, el, add)                                                        \
+do {                                                                                           \
+ assert(head != NULL);                                                                         \
+ assert(el != NULL);                                                                           \
+ assert(add != NULL);                                                                          \
+ (add)->next = (el);                                                                           \
+ (add)->prev = (el)->prev;                                                                     \
+ (el)->prev = (add);                                                                           \
+ (add)->prev->next = (add);                                                                    \
+ if ((head) == (el)) {                                                                         \
+  (head) = (add);                                                                              \
+ }                                                                                             \
+} while (0)                                                                                    \
+
+#endif /* UTLIST_H */
+
diff --git a/components/coap/libcoap/libcoap-1.map b/components/coap/libcoap/libcoap-1.map
new file mode 100644
index 00000000..b065371d
--- /dev/null
+++ b/components/coap/libcoap/libcoap-1.map
@@ -0,0 +1,116 @@
+VER_1 {
+global:
+  coap_add_attr;
+  coap_add_block;
+  coap_add_data;
+  coap_add_observer;
+  coap_add_option;
+  coap_add_option_later;
+  coap_add_resource;
+  coap_address_equals;
+  coap_add_token;
+  coap_adjust_basetime;
+  coap_cancel_all_messages;
+  coap_can_exit;
+  coap_check_notify;
+  coap_check_option;
+  coap_clock_init;
+  coap_clone_uri;
+  coap_decode_var_bytes;
+  coap_delete_all;
+  coap_delete_all_resources;
+  coap_delete_attr;
+  coap_delete_node;
+  coap_delete_observer;
+  coap_delete_pdu;
+  coap_delete_resource;
+  coap_delete_string;
+  coap_dispatch;
+  coap_encode_var_bytes;
+  coap_find_async;
+  coap_find_attr;
+  coap_find_observer;
+  coap_find_transaction;
+  coap_fls;
+  coap_free_async;
+  coap_free_context;
+  coap_free_endpoint;
+  coap_free_packet;
+  coap_free_type;
+  coap_get_block;
+  coap_get_data;
+  coap_get_log_level;
+  coap_get_resource_from_key;
+  coap_handle_failed_notify;
+  coap_handle_message;
+  coap_hash_impl;
+  coap_hash_path;
+  coap_hash_request_uri;
+  coap_insert_node;
+  coap_log_impl;
+  coap_malloc_type;
+  coap_memory_init;
+  coap_network_read;
+  coap_network_send;
+  coap_new_context;
+  coap_new_endpoint;
+  coap_new_error_response;
+  coap_new_node;
+  coap_new_pdu;
+  coap_new_string;
+  coap_new_uri;
+  coap_opt_block_num;
+  coap_opt_delta;
+  coap_opt_encode;
+  coap_option_check_critical;
+  coap_option_filter_get;
+  coap_option_filter_set;
+  coap_option_filter_unset;
+  coap_option_iterator_init;
+  coap_option_next;
+  coap_opt_length;
+  coap_opt_parse;
+  coap_opt_setheader;
+  coap_opt_size;
+  coap_opt_value;
+  coap_package_name;
+  coap_package_version;
+  coap_packet_copy_source;
+  coap_packet_get_memmapped;
+  coap_packet_populate_endpoint;
+  coap_pdu_clear;
+  coap_pdu_init;
+  coap_pdu_parse;
+  coap_peek_next;
+  coap_pop_next;
+  coap_print_addr;
+  coap_print_link;
+  coap_print_wellknown;
+  coap_read;
+  coap_register_async;
+  coap_remove_async;
+  coap_remove_from_queue;
+  coap_resource_init;
+  coap_response_phrase;
+  coap_retransmit;
+  coap_send;
+  coap_send_ack;
+  coap_send_confirmed;
+  coap_send_error;
+  coap_send_message_type;
+  coap_set_log_level;
+  coap_show_pdu;
+  coap_split_path;
+  coap_split_query;
+  coap_split_uri;
+  coap_subscription_init;
+  coap_ticks;
+  coap_ticks;
+  coap_ticks_to_rt;
+  coap_touch_observer;
+  coap_transaction_id;
+  coap_wellknown_response;
+  coap_write_block_opt;
+local:
+  *;
+};
diff --git a/components/coap/libcoap/libcoap-1.pc.in b/components/coap/libcoap/libcoap-1.pc.in
new file mode 100644
index 00000000..8d1f3134
--- /dev/null
+++ b/components/coap/libcoap/libcoap-1.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Description: C-Implementation of CoAP.
+Version: @PACKAGE_VERSION@
+URL: @PACKAGE_URL@
+Libs: -L${libdir} -lcoap-@LIBCOAP_API_VERSION@
+Cflags: -I${includedir}/coap
diff --git a/components/coap/libcoap/libcoap-1.sym b/components/coap/libcoap/libcoap-1.sym
new file mode 100644
index 00000000..7f465feb
--- /dev/null
+++ b/components/coap/libcoap/libcoap-1.sym
@@ -0,0 +1,111 @@
+coap_add_attr
+coap_add_block
+coap_add_data
+coap_add_observer
+coap_add_option
+coap_add_option_later
+coap_add_resource
+coap_address_equals
+coap_add_token
+coap_adjust_basetime
+coap_cancel_all_messages
+coap_can_exit
+coap_check_notify
+coap_check_option
+coap_clock_init
+coap_clone_uri
+coap_decode_var_bytes
+coap_delete_all
+coap_delete_all_resources
+coap_delete_attr
+coap_delete_node
+coap_delete_observer
+coap_delete_pdu
+coap_delete_resource
+coap_delete_string
+coap_dispatch
+coap_encode_var_bytes
+coap_find_async
+coap_find_attr
+coap_find_observer
+coap_find_transaction
+coap_fls
+coap_free_async
+coap_free_context
+coap_free_endpoint
+coap_free_packet
+coap_free_type
+coap_get_block
+coap_get_data
+coap_get_log_level
+coap_get_resource_from_key
+coap_handle_failed_notify
+coap_handle_message
+coap_hash_impl
+coap_hash_path
+coap_hash_request_uri
+coap_insert_node
+coap_log_impl
+coap_malloc_type
+coap_memory_init
+coap_network_read
+coap_network_send
+coap_new_context
+coap_new_endpoint
+coap_new_error_response
+coap_new_node
+coap_new_pdu
+coap_new_string
+coap_new_uri
+coap_opt_block_num
+coap_opt_delta
+coap_opt_encode
+coap_option_check_critical
+coap_option_filter_get
+coap_option_filter_set
+coap_option_filter_unset
+coap_option_iterator_init
+coap_option_next
+coap_opt_length
+coap_opt_parse
+coap_opt_setheader
+coap_opt_size
+coap_opt_value
+coap_package_name
+coap_package_version
+coap_packet_copy_source
+coap_packet_get_memmapped
+coap_packet_populate_endpoint
+coap_pdu_clear
+coap_pdu_init
+coap_pdu_parse
+coap_peek_next
+coap_pop_next
+coap_print_addr
+coap_print_link
+coap_print_wellknown
+coap_read
+coap_register_async
+coap_remove_async
+coap_remove_from_queue
+coap_resource_init
+coap_response_phrase
+coap_retransmit
+coap_send
+coap_send_ack
+coap_send_confirmed
+coap_send_error
+coap_send_message_type
+coap_set_log_level
+coap_show_pdu
+coap_split_path
+coap_split_query
+coap_split_uri
+coap_subscription_init
+coap_ticks
+coap_ticks
+coap_ticks_to_rt
+coap_touch_observer
+coap_transaction_id
+coap_wellknown_response
+coap_write_block_opt
diff --git a/components/coap/libcoap/m4/ax_check_compile_flag.m4 b/components/coap/libcoap/m4/ax_check_compile_flag.m4
new file mode 100644
index 00000000..ca363971
--- /dev/null
+++ b/components/coap/libcoap/m4/ax_check_compile_flag.m4
@@ -0,0 +1,74 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   Check whether the given FLAG works with the current language's compiler
+#   or gives an error.  (Warnings, however, are ignored)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+#   If EXTRA-FLAGS is defined, it is added to the current language's default
+#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
+#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
+#   force the compiler to issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 4
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+    [AS_VAR_SET(CACHEVAR,[yes])],
+    [AS_VAR_SET(CACHEVAR,[no])])
+  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/components/coap/libcoap/m4/ax_check_link_flag.m4 b/components/coap/libcoap/m4/ax_check_link_flag.m4
new file mode 100644
index 00000000..eb01a6ce
--- /dev/null
+++ b/components/coap/libcoap/m4/ax_check_link_flag.m4
@@ -0,0 +1,74 @@
+# ===========================================================================
+#    http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   Check whether the given FLAG works with the linker or gives an error.
+#   (Warnings, however, are ignored)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+#   If EXTRA-FLAGS is defined, it is added to the linker's default flags
+#   when the check is done.  The check is thus made with the flags: "LDFLAGS
+#   EXTRA-FLAGS FLAG".  This can for example be used to force the linker to
+#   issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_LINK_IFELSE.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+#   macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 4
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+  ax_check_save_flags=$LDFLAGS
+  LDFLAGS="$LDFLAGS $4 $1"
+  AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+    [AS_VAR_SET(CACHEVAR,[yes])],
+    [AS_VAR_SET(CACHEVAR,[no])])
+  LDFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
diff --git a/components/coap/libcoap/scripts/build.sh b/components/coap/libcoap/scripts/build.sh
new file mode 100755
index 00000000..8bc0e390
--- /dev/null
+++ b/components/coap/libcoap/scripts/build.sh
@@ -0,0 +1,32 @@
+#! /bin/sh
+
+if test "x$TESTS" = "xyes" -o "x$TESTS" = "xtrue" ; then
+    WITH_TESTS="`scripts/fix-cunit.sh` --enable-tests"
+    test -f `pwd`/cunit.pc && echo cat `pwd`/cunit.pc
+fi
+     
+config() {
+    echo "./configure $*"
+    ./configure $* || cat config.log
+}
+
+case "${PLATFORM}" in
+    contiki) config "--disable-tests --disable-documentation --disable-examples" && \
+               make -C examples/contiki
+             ;;
+    lwip)    config "--disable-tests --disable-documentation --disable-examples" && \
+               make -C examples/lwip lwip lwip-contrib
+               make -C examples/lwip LDLIBS=`grep ac_cv_search_clock_gettime=- config.log|cut -d= -f2`
+             ;;
+    posix|*) config "$WITH_TESTS --enable-documentation --enable-examples" && \
+               make
+             ;;
+esac
+
+err=$?
+if test $err = 0 -a -n "$WITH_TESTS" ; then
+    tests/testdriver
+    err=$?
+fi
+
+exit $err
diff --git a/components/coap/libcoap/scripts/fix-cunit.sh b/components/coap/libcoap/scripts/fix-cunit.sh
new file mode 100755
index 00000000..05ab658e
--- /dev/null
+++ b/components/coap/libcoap/scripts/fix-cunit.sh
@@ -0,0 +1,15 @@
+#! /bin/sh
+
+# only continue if `pkgconfig cunit` fails
+pkg-config cunit 2>/dev/null && exit 0
+
+# Check if the system has a cunit.pc.
+# If not, exit with success (the configure script will raise
+# a more descriptive error).
+CUNIT_PC=`dpkg -L libcunit1-dev 2>/dev/null|grep cunit.pc`
+if test "x$CUNIT_PC" != "x"; then
+    grep -q Version: $CUNIT_PC || (dpkg -l|sed -ne 's/^ii\s\+libcunit1-dev\s\+\([0-9]\+.[0-9]\+-[0-9]\+\).*$/Version: \1/p; T; q'|cat - $CUNIT_PC |sed -e 's/={exec_prefix/=${exec_prefix/' >`pwd`/cunit.pc)
+fi
+
+# output location of generated cunit.pc
+echo PKG_CONFIG_PATH=`pwd`
diff --git a/components/coap/libcoap/src/address.c b/components/coap/libcoap/src/address.c
new file mode 100644
index 00000000..b4db76f0
--- /dev/null
+++ b/components/coap/libcoap/src/address.c
@@ -0,0 +1,63 @@
+/* address.c -- representation of network addresses
+ *
+ * Copyright (C) 2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifdef WITH_POSIX
+#include <assert.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include "address.h"
+
+int 
+coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
+  assert(a); assert(b);
+
+  if (a->size != b->size || a->addr.sa.sa_family != b->addr.sa.sa_family)
+    return 0;
+  
+  /* need to compare only relevant parts of sockaddr_in6 */
+ switch (a->addr.sa.sa_family) {
+ case AF_INET:
+   return 
+     a->addr.sin.sin_port == b->addr.sin.sin_port && 
+     memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, 
+	    sizeof(struct in_addr)) == 0;
+ case AF_INET6:
+   return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && 
+     memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, 
+	    sizeof(struct in6_addr)) == 0;
+ default: /* fall through and signal error */
+   ;
+ }
+ return 0;
+}
+
+int coap_is_mcast(const coap_address_t *a) {
+  if (!a)
+    return 0;
+
+ switch (a->addr.sa.sa_family) {
+ case AF_INET:
+   return IN_MULTICAST(ntohl(a->addr.sin.sin_addr.s_addr));
+ case  AF_INET6:
+   return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr);
+ default:  /* fall through and signal error */
+   ;
+  }
+ return 0;
+}
+#else /* WITH_POSIX */
+
+/* make compilers happy that do not like empty modules */
+static inline void dummy()
+{
+}
+
+#endif /* not WITH_POSIX */
+
diff --git a/components/coap/libcoap/src/async.c b/components/coap/libcoap/src/async.c
new file mode 100644
index 00000000..b311bf8e
--- /dev/null
+++ b/components/coap/libcoap/src/async.c
@@ -0,0 +1,100 @@
+/* async.c -- state management for asynchronous messages
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+/** 
+ * @file async.c
+ * @brief state management for asynchronous messages
+ */
+
+#ifndef WITHOUT_ASYNC
+
+#include "coap_config.h"
+#include "coap.h"
+#include "async.h"
+#include "debug.h"
+#include "mem.h"
+#include "utlist.h"
+
+coap_async_state_t *
+coap_register_async(coap_context_t *context, coap_address_t *peer,
+		    coap_pdu_t *request, unsigned char flags, void *data) {
+  coap_async_state_t *s;
+  coap_tid_t id;
+
+  coap_transaction_id(peer, request, &id);
+  LL_SEARCH_SCALAR(context->async_state,s,id,id);
+
+  if (s != NULL) {
+    /* We must return NULL here as the caller must know that he is
+     * responsible for releasing @p data. */
+    debug("asynchronous state for transaction %d already registered\n", id);
+    return NULL;
+  }
+
+  /* store information for handling the asynchronous task */
+  s = (coap_async_state_t *)coap_malloc(sizeof(coap_async_state_t) + 
+					request->hdr->token_length);
+  if (!s) {
+    coap_log(LOG_CRIT, "coap_register_async: insufficient memory\n");
+    return NULL;
+  }
+
+  memset(s, 0, sizeof(coap_async_state_t) + request->hdr->token_length);
+
+  /* set COAP_ASYNC_CONFIRM according to request's type */
+  s->flags = flags & ~COAP_ASYNC_CONFIRM;
+  if (request->hdr->type == COAP_MESSAGE_CON)
+    s->flags |= COAP_ASYNC_CONFIRM;
+
+  s->appdata = data;
+
+  memcpy(&s->peer, peer, sizeof(coap_address_t));
+
+  if (request->hdr->token_length) {
+    s->tokenlen = request->hdr->token_length;
+    memcpy(s->token, request->hdr->token, request->hdr->token_length);
+  }
+    
+  memcpy(&s->id, &id, sizeof(coap_tid_t));
+
+  coap_touch_async(s);
+
+  LL_PREPEND(context->async_state, s);
+
+  return s;
+}
+
+coap_async_state_t *
+coap_find_async(coap_context_t *context, coap_tid_t id) {
+  coap_async_state_t *tmp;
+  LL_SEARCH_SCALAR(context->async_state,tmp,id,id);  
+  return tmp;
+}
+
+int
+coap_remove_async(coap_context_t *context, coap_tid_t id, 
+		  coap_async_state_t **s) {
+  coap_async_state_t *tmp = coap_find_async(context, id);
+
+  if (tmp)
+    LL_DELETE(context->async_state,tmp);
+
+  *s = tmp;
+  return tmp != NULL;
+}
+
+void 
+coap_free_async(coap_async_state_t *s) {
+  if (s && (s->flags & COAP_ASYNC_RELEASE_DATA) != 0)
+    coap_free(s->appdata);
+  coap_free(s); 
+}
+
+#else
+void does_not_exist();	/* make some compilers happy */
+#endif /* WITHOUT_ASYNC */
diff --git a/components/coap/libcoap/src/block.c b/components/coap/libcoap/src/block.c
new file mode 100644
index 00000000..0e2cf482
--- /dev/null
+++ b/components/coap/libcoap/src/block.c
@@ -0,0 +1,140 @@
+/* block.c -- block transfer
+ *
+ * Copyright (C) 2010--2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include "debug.h"
+#include "block.h"
+
+#if (COAP_MAX_PDU_SIZE - 6) < (1 << (COAP_MAX_BLOCK_SZX + 4))
+#error "COAP_MAX_BLOCK_SZX too large"
+#endif
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+#ifndef WITHOUT_BLOCK
+unsigned int
+coap_opt_block_num(const coap_opt_t *block_opt) {
+  unsigned int num = 0;
+  unsigned short len;
+  
+  len = coap_opt_length(block_opt);
+
+  if (len == 0) {
+    return 0;
+  }
+  
+  if (len > 1) {
+    num = coap_decode_var_bytes(COAP_OPT_VALUE(block_opt), 
+				COAP_OPT_LENGTH(block_opt) - 1);
+  }
+  
+  return (num << 4) | ((*COAP_OPT_BLOCK_LAST(block_opt) & 0xF0) >> 4);
+}
+
+int
+coap_get_block(coap_pdu_t *pdu, unsigned short type, coap_block_t *block) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+
+  assert(block);
+  memset(block, 0, sizeof(coap_block_t));
+
+  if (pdu && (option = coap_check_option(pdu, type, &opt_iter))) {
+    unsigned int num;
+
+    block->szx = COAP_OPT_BLOCK_SZX(option);
+    if (COAP_OPT_BLOCK_MORE(option))
+      block->m = 1;
+
+    /* The block number is at most 20 bits, so values above 2^20 - 1
+     * are illegal. */
+    num = coap_opt_block_num(option);
+    if (num > 0xFFFFF) {
+      return 0;
+    }
+    block->num = num;
+    return 1;
+  }
+
+  return 0;
+}
+
+int
+coap_write_block_opt(coap_block_t *block, unsigned short type,
+		     coap_pdu_t *pdu, size_t data_length) {
+  size_t start, want, avail;
+  unsigned char buf[4];
+
+  assert(pdu);
+
+  start = block->num << (block->szx + 4);
+  if (data_length <= start) {
+    debug("illegal block requested\n");
+    return -2;
+  }
+  
+  avail = pdu->max_size - pdu->length - 4;
+  want = 1 << (block->szx + 4);
+
+  /* check if entire block fits in message */
+  if (want <= avail) {
+    block->m = want < data_length - start;
+  } else {
+    /* Sender has requested a block that is larger than the remaining
+     * space in pdu. This is ok if the remaining data fits into the pdu
+     * anyway. The block size needs to be adjusted only if there is more
+     * data left that cannot be delivered in this message. */
+
+    if (data_length - start <= avail) {
+
+      /* it's the final block and everything fits in the message */
+      block->m = 0;
+    } else {
+      unsigned char szx;
+
+      /* we need to decrease the block size */
+      if (avail < 16) { 	/* bad luck, this is the smallest block size */
+	debug("not enough space, even the smallest block does not fit");
+	return -3;
+      }
+      debug("decrease block size for %zu to %d\n", avail, coap_fls(avail) - 5);
+      szx = block->szx;
+      block->szx = coap_fls(avail) - 5;
+      block->m = 1;
+      block->num <<= szx - block->szx;
+    }
+  }
+
+  /* to re-encode the block option */
+  coap_add_option(pdu, type, coap_encode_var_bytes(buf, ((block->num << 4) | 
+							 (block->m << 3) | 
+							 block->szx)), 
+		  buf);
+
+  return 1;
+}
+
+int 
+coap_add_block(coap_pdu_t *pdu, unsigned int len, const unsigned char *data,
+	       unsigned int block_num, unsigned char block_szx) {
+  size_t start;
+  start = block_num << (block_szx + 4);
+
+  if (len <= start)
+    return 0;
+  
+  return coap_add_data(pdu, 
+		       min(len - start, (unsigned int)(1 << (block_szx + 4))),
+		       data + start);
+}
+#endif /* WITHOUT_BLOCK  */
diff --git a/components/coap/libcoap/src/coap_io.c b/components/coap/libcoap/src/coap_io.c
new file mode 100644
index 00000000..a91ec54e
--- /dev/null
+++ b/components/coap/libcoap/src/coap_io.c
@@ -0,0 +1,621 @@
+/* coap_io.h -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#ifdef HAVE_STDIO_H
+#  include <stdio.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif 
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif 
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif 
+#include <errno.h>
+
+#ifdef WITH_CONTIKI
+# include "uip.h"
+#endif
+
+#include "debug.h"
+#include "mem.h"
+#include "coap_io.h"
+
+#ifdef WITH_POSIX
+/* define generic PKTINFO for IPv4 */
+#if defined(IP_PKTINFO)
+#  define GEN_IP_PKTINFO IP_PKTINFO
+#elif defined(IP_RECVDSTADDR)
+#  define GEN_IP_PKTINFO IP_RECVDSTADDR
+#else
+#  error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
+#endif /* IP_PKTINFO */
+
+/* define generic KTINFO for IPv6 */
+#ifdef IPV6_RECVPKTINFO
+#  define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
+#elif defined(IPV6_PKTINFO)
+#  define GEN_IPV6_PKTINFO IPV6_PKTINFO
+#else
+#  error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
+#endif /* IPV6_RECVPKTINFO */
+
+struct coap_packet_t {
+  coap_if_handle_t hnd;	      /**< the interface handle */
+  coap_address_t src;	      /**< the packet's source address */
+  coap_address_t dst;	      /**< the packet's destination address */
+  const coap_endpoint_t *interface;
+
+  int ifindex;
+  void *session;		/**< opaque session data */
+
+  size_t length;		/**< length of payload */
+  unsigned char payload[];	/**< payload */
+};
+#endif
+
+#ifndef CUSTOM_COAP_NETWORK_ENDPOINT
+
+#ifdef WITH_CONTIKI
+static int ep_initialized = 0;
+
+static inline struct coap_endpoint_t *
+coap_malloc_contiki_endpoint() {
+  static struct coap_endpoint_t ep;
+
+  if (ep_initialized) {
+    return NULL;
+  } else {
+    ep_initialized = 1;
+    return &ep;
+  }
+}
+
+static inline void
+coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
+  ep_initialized = 0;
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
+
+  if (ep) {
+    memset(ep, 0, sizeof(struct coap_endpoint_t));
+    ep->handle.conn = udp_new(NULL, 0, NULL);
+
+    if (!ep->handle.conn) {
+      coap_free_endpoint(ep);
+      return NULL;
+    }
+
+    coap_address_init(&ep->addr);
+    uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
+    ep->addr.port = addr->port;
+    udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
+  }
+  return ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if (ep) {
+    if (ep->handle.conn) {
+      uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
+    }
+    coap_free_contiki_endpoint(ep);
+  }
+}
+
+#else /* WITH_CONTIKI */
+static inline struct coap_endpoint_t *
+coap_malloc_posix_endpoint(void) {
+  return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
+}
+
+static inline void
+coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
+  coap_free(ep);
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
+  int on = 1;
+  struct coap_endpoint_t *ep;
+
+  if (sockfd < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: socket");
+    return NULL;
+  }
+
+  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
+
+  on = 1;
+  switch(addr->addr.sa.sa_family) {
+  case AF_INET:
+    if (setsockopt(sockfd, IPPROTO_IP, GEN_IP_PKTINFO, &on, sizeof(on)) < 0)
+      coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IP_PKTINFO\n");
+    break;
+  case AF_INET6:
+  if (setsockopt(sockfd, IPPROTO_IPV6, GEN_IPV6_PKTINFO, &on, sizeof(on)) < 0)
+    coap_log(LOG_ALERT, "coap_new_endpoint: setsockopt IPV6_PKTINFO\n");
+  break;
+  default:
+    coap_log(LOG_ALERT, "coap_new_endpoint: unsupported sa_family\n");
+  }
+
+  if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: bind");
+    close (sockfd);
+    return NULL;
+  }
+
+  ep = coap_malloc_posix_endpoint();
+  if (!ep) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
+    close(sockfd);
+    return NULL;
+  }
+
+  memset(ep, 0, sizeof(struct coap_endpoint_t));
+  ep->handle.fd = sockfd;
+  ep->flags = flags;
+
+  ep->addr.size = addr->size;
+  if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
+    close (sockfd);
+    return NULL;
+  }
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+    unsigned char addr_str[INET6_ADDRSTRLEN+8];
+
+    if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
+      debug("created %sendpoint %s\n", 
+	    ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
+	    addr_str);
+    }
+  }
+#endif /* NDEBUG */
+
+  return (coap_endpoint_t *)ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if(ep) {
+    if (ep->handle.fd >= 0)
+      close(ep->handle.fd);
+    coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
+  }
+}
+
+#endif /* WITH_CONTIKI */
+#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
+
+#ifndef CUSTOM_COAP_NETWORK_SEND
+
+#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
+/* define struct in6_pktinfo and struct in_pktinfo if not available
+   FIXME: check with configure 
+*/
+struct in6_pktinfo {
+  struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
+  unsigned int ipi6_ifindex;	/* send/recv interface index */
+};
+
+struct in_pktinfo {
+  int ipi_ifindex;
+  struct in_addr ipi_spec_dst;
+  struct in_addr ipi_addr;
+};
+#endif
+
+#if defined(WITH_POSIX) && !defined(SOL_IP)
+/* Solaris expects level IPPROTO_IP for ancillary data. */
+#define SOL_IP IPPROTO_IP
+#endif
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+ssize_t
+coap_network_send(struct coap_context_t *context UNUSED_PARAM,
+		  const coap_endpoint_t *local_interface,
+		  const coap_address_t *dst,
+		  unsigned char *data,
+		  size_t datalen) {
+
+  struct coap_endpoint_t *ep = 
+    (struct coap_endpoint_t *)local_interface;
+
+#ifndef WITH_CONTIKI
+  /* a buffer large enough to hold all protocol address types */
+  char buf[CMSG_LEN(sizeof(struct sockaddr_storage))];
+  struct msghdr mhdr;
+  struct iovec iov[1];
+
+  assert(local_interface);
+
+  iov[0].iov_base = data;
+  iov[0].iov_len = datalen;
+
+  memset(&mhdr, 0, sizeof(struct msghdr));
+  mhdr.msg_name = (void *)&dst->addr;
+  mhdr.msg_namelen = dst->size;
+
+  mhdr.msg_iov = iov;
+  mhdr.msg_iovlen = 1;
+
+  switch (dst->addr.sa.sa_family) {
+  case AF_INET6: {
+    struct cmsghdr *cmsg;
+    struct in6_pktinfo *pktinfo;
+
+    mhdr.msg_control = buf;
+    mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+
+    cmsg = CMSG_FIRSTHDR(&mhdr);
+    cmsg->cmsg_level = IPPROTO_IPV6;
+    cmsg->cmsg_type = IPV6_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+  
+    pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(struct in6_pktinfo));
+  
+    pktinfo->ipi6_ifindex = ep->ifindex;
+    if (coap_is_mcast(&local_interface->addr)) {
+      /* We cannot send with multicast address as source address
+       * and hence let the kernel pick the outgoing interface. */
+      pktinfo->ipi6_ifindex = 0;
+      memset(&pktinfo->ipi6_addr, 0, sizeof(pktinfo->ipi6_addr));
+    } else {
+      pktinfo->ipi6_ifindex = ep->ifindex;
+      memcpy(&pktinfo->ipi6_addr,
+	     &local_interface->addr.addr.sin6.sin6_addr,
+	     local_interface->addr.size);
+    }
+    break;
+  }
+  case AF_INET: {
+#if defined(IP_PKTINFO)
+    struct cmsghdr *cmsg;
+    struct in_pktinfo *pktinfo;
+
+    mhdr.msg_control = buf;
+    mhdr.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+    cmsg = CMSG_FIRSTHDR(&mhdr);
+    cmsg->cmsg_level = SOL_IP;
+    cmsg->cmsg_type = IP_PKTINFO;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+    pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
+    memset(pktinfo, 0, sizeof(struct in_pktinfo));
+
+    if (coap_is_mcast(&local_interface->addr)) {
+      /* We cannot send with multicast address as source address
+       * and hence let the kernel pick the outgoing interface. */
+      pktinfo->ipi_ifindex = 0;
+      memset(&pktinfo->ipi_spec_dst, 0, sizeof(pktinfo->ipi_spec_dst));
+    } else {
+      pktinfo->ipi_ifindex = ep->ifindex;
+      memcpy(&pktinfo->ipi_spec_dst,
+	     &local_interface->addr.addr.sin.sin_addr,
+	     local_interface->addr.size);
+    }
+#endif /* IP_PKTINFO */
+    break;
+  }
+  default:
+    /* error */
+    coap_log(LOG_WARNING, "protocol not supported\n");
+    return -1;
+  }
+
+  return sendmsg(ep->handle.fd, &mhdr, 0);
+#else /* WITH_CONTIKI */
+  /* FIXME: untested */
+  /* FIXME: is there a way to check if send was successful? */
+  uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen, 
+			&dst->addr, dst->port);
+  return datalen;
+#endif /* WITH_CONTIKI */
+}
+
+#endif /* CUSTOM_COAP_NETWORK_SEND */
+
+#ifndef CUSTOM_COAP_NETWORK_READ
+
+#define SIN6(A) ((struct sockaddr_in6 *)(A))
+
+#ifdef WITH_POSIX
+static coap_packet_t *
+coap_malloc_packet(void) {
+  coap_packet_t *packet;
+  const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
+
+  packet = (coap_packet_t *)coap_malloc(need);
+  if (packet) {
+    memset(packet, 0, need);
+  }
+  return packet;
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free(packet);
+}
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+static inline coap_packet_t *
+coap_malloc_packet(void) {
+  return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free_type(COAP_PACKET, packet);
+}
+#endif /* WITH_CONTIKI */
+
+static inline size_t
+coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
+  return COAP_MAX_PDU_SIZE;
+}
+
+void
+coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
+{
+  target->handle = packet->interface->handle;
+  memcpy(&target->addr, &packet->dst, sizeof(target->addr));
+  target->ifindex = packet->ifindex;
+  target->flags = 0; /* FIXME */
+}
+void
+coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
+{
+  memcpy(target, &packet->src, sizeof(coap_address_t));
+}
+void
+coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
+{
+	*address = packet->payload;
+	*length = packet->length;
+}
+
+/**
+ * Checks if a message with destination address @p dst matches the
+ * local interface with address @p local. This function returns @c 1
+ * if @p dst is a valid match, and @c 0 otherwise.
+ */
+static inline int
+is_local_if(const coap_address_t *local, const coap_address_t *dst) {
+  return coap_address_isany(local) || coap_address_equals(dst, local) ||
+    coap_is_mcast(dst);
+}
+
+ssize_t
+coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
+  ssize_t len = -1;
+
+#ifdef WITH_POSIX
+  char msg_control[CMSG_LEN(sizeof(struct sockaddr_storage))]; 
+  struct msghdr mhdr;
+  struct iovec iov[1];
+#endif /* WITH_POSIX */
+
+  assert(ep);
+  assert(packet);
+
+  *packet = coap_malloc_packet();
+  
+  if (!*packet) {
+    warn("coap_network_read: insufficient memory, drop packet\n");
+    return -1;
+  }
+
+  coap_address_init(&(*packet)->dst); /* the local interface address */
+  coap_address_init(&(*packet)->src); /* the remote peer */
+
+#ifdef WITH_POSIX
+  iov[0].iov_base = (*packet)->payload;
+  iov[0].iov_len = coap_get_max_packetlength(*packet);
+
+  memset(&mhdr, 0, sizeof(struct msghdr));
+
+  mhdr.msg_name = &(*packet)->src.addr.st;
+  mhdr.msg_namelen = sizeof((*packet)->src.addr.st);
+
+  mhdr.msg_iov = iov;
+  mhdr.msg_iovlen = 1;
+  
+  mhdr.msg_control = msg_control;
+  mhdr.msg_controllen = sizeof(msg_control);
+  assert(sizeof(msg_control) == CMSG_LEN(sizeof(struct sockaddr_storage)));
+
+  len = recvmsg(ep->handle.fd, &mhdr, 0);
+
+  if (len < 0) {
+    coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
+    goto error;
+  } else {
+    struct cmsghdr *cmsg;
+
+    coap_log(LOG_DEBUG, "received %d bytes on fd %d\n", (int)len, ep->handle.fd);
+
+    /* use getsockname() to get the local port */
+    (*packet)->dst.size = sizeof((*packet)->dst.addr);
+    if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
+      coap_log(LOG_DEBUG, "cannot determine local port\n");
+      goto error;
+    }
+
+    (*packet)->length = len;
+
+    /* Walk through ancillary data records until the local interface
+     * is found where the data was received. */
+    for (cmsg = CMSG_FIRSTHDR(&mhdr); cmsg; cmsg = CMSG_NXTHDR(&mhdr, cmsg)) {
+      
+      /* get the local interface for IPv6 */
+      if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
+	union {
+	  unsigned char *c;
+	  struct in6_pktinfo *p;
+	} u;
+	u.c = CMSG_DATA(cmsg);
+	(*packet)->ifindex = (int)(u.p->ipi6_ifindex);
+
+	memcpy(&(*packet)->dst.addr.sin6.sin6_addr, 
+	       &u.p->ipi6_addr, sizeof(struct in6_addr));
+
+	(*packet)->src.size = sizeof(struct sockaddr_in6);
+        if ((*packet)->src.size != mhdr.msg_namelen) {
+          coap_log(LOG_DEBUG, "wrong IPv6 address length detected, dropped packet\n");
+          goto error;
+        }
+
+	(*packet)->src.addr.sin6.sin6_family = SIN6(mhdr.msg_name)->sin6_family;
+	(*packet)->src.addr.sin6.sin6_addr = SIN6(mhdr.msg_name)->sin6_addr;
+	(*packet)->src.addr.sin6.sin6_port = SIN6(mhdr.msg_name)->sin6_port;
+
+	break;
+      }
+
+      /* local interface for IPv4 */
+#if defined(IP_PKTINFO)
+      if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
+	union {
+	  unsigned char *c;
+	  struct in_pktinfo *p;
+	} u;
+
+	u.c = CMSG_DATA(cmsg);
+	(*packet)->ifindex = u.p->ipi_ifindex;
+
+	memcpy(&(*packet)->dst.addr.sin.sin_addr, 
+	       &u.p->ipi_addr, sizeof(struct in_addr));
+
+	(*packet)->src.size = sizeof(struct sockaddr_in);
+        if ((*packet)->src.size != mhdr.msg_namelen) {
+          coap_log(LOG_DEBUG, "wrong IPv4 address length detected, dropped packet\n");
+          goto error;
+        }
+
+	assert(memcmp(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size) == 0);
+
+	break;
+      }
+#elif defined(IP_RECVDSTADDR)
+      if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) {
+	(*packet)->ifindex = 0;
+
+	memcpy(&(*packet)->dst.addr.sin.sin_addr,
+	       CMSG_DATA(cmsg), sizeof(struct in_addr));
+
+	(*packet)->src.size = sizeof(struct sockaddr_in);
+        if ((*packet)->src.size != mhdr.msg_namelen) {
+          coap_log(LOG_DEBUG, "wrong IPv4 address length detected, dropped packet\n");
+          goto error;
+        }
+
+	assert(memcmp(&(*packet)->src.addr.st, mhdr.msg_name, (*packet)->src.size) == 0);
+
+	break;
+      }
+#endif /* IP_PKTINFO */
+    }
+
+    if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+      coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+      goto error;
+    }
+  }
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+  /* FIXME: untested, make this work */
+#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
+
+  if(uip_newdata()) {
+    uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
+    (*packet)->src.port = UIP_UDP_BUF->srcport;
+    uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
+    (*packet)->dst.port = UIP_UDP_BUF->destport;
+
+    if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+      coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+      goto error;
+    }
+
+    len = uip_datalen();
+    
+    if (len > coap_get_max_packetlength(*packet)) {
+      /* FIXME: we might want to send back a response */
+      warn("discarded oversized packet\n");
+      return -1;
+    }
+
+    ((char *)uip_appdata)[len] = 0;
+#ifndef NDEBUG
+    if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+      unsigned char addr_str[INET6_ADDRSTRLEN+8];
+      
+      if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
+	debug("received %zd bytes from %s\n", len, addr_str);
+      }
+    }
+#endif /* NDEBUG */
+
+    (*packet)->length = len;
+    memcpy(&(*packet)->payload, uip_appdata, len);
+  }
+
+#undef UIP_IP_BUF
+#undef UIP_UDP_BUF
+#endif /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+#error "coap_network_read() not implemented on this platform"
+#endif
+
+  (*packet)->interface = ep;
+
+  return len;
+ error:
+  coap_free_packet(*packet);
+  *packet = NULL;
+  return -1;
+}
+
+#undef SIN6
+
+#endif /*  CUSTOM_COAP_NETWORK_READ */
diff --git a/components/coap/libcoap/src/coap_io_lwip.c b/components/coap/libcoap/src/coap_io_lwip.c
new file mode 100644
index 00000000..8ae3b57e
--- /dev/null
+++ b/components/coap/libcoap/src/coap_io_lwip.c
@@ -0,0 +1,98 @@
+/* coap_io_lwip.h -- Network I/O functions for libcoap on lwIP
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *               2014 chrysn <chrysn@fsfe.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include "mem.h"
+#include "coap_io.h"
+#include <lwip/udp.h>
+
+void coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
+{
+	printf("FIXME no endpoint populated\n");
+}
+void coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
+{
+	target->port = packet->srcport;
+	memcpy(&target->addr, ip_current_src_addr(), sizeof(ip_addr_t));
+}
+void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
+{
+	LWIP_ASSERT("Can only deal with contiguous PBUFs to read the initial details", packet->pbuf->tot_len == packet->pbuf->len);
+	*address = packet->pbuf->payload;
+	*length = packet->pbuf->tot_len;
+}
+void coap_free_packet(coap_packet_t *packet)
+{
+	if (packet->pbuf)
+		pbuf_free(packet->pbuf);
+	coap_free_type(COAP_PACKET, packet);
+}
+
+struct pbuf *coap_packet_extract_pbuf(coap_packet_t *packet)
+{
+	struct pbuf *ret = packet->pbuf;
+	packet->pbuf = NULL;
+	return ret;
+}
+
+
+/** Callback from lwIP when a package was received.
+ *
+ * The current implemntation deals this to coap_handle_message immedately, but
+ * other mechanisms (as storing the package in a queue and later fetching it
+ * when coap_read is called) can be envisioned.
+ *
+ * It handles everything coap_read does on other implementations.
+ */
+static void coap_recv(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+	coap_endpoint_t *ep = (coap_endpoint_t*)arg;
+	coap_packet_t *packet = coap_malloc_type(COAP_PACKET, sizeof(coap_packet_t));
+	/* this is fatal because due to the short life of the packet, never should there be more than one coap_packet_t required */
+	LWIP_ASSERT("Insufficient coap_packet_t resources.", packet != NULL);
+	packet->pbuf = p;
+	packet->srcport = port;
+
+	/** FIXME derive the context without changing endopint definition */
+	coap_handle_message(ep->context, packet);
+
+	coap_free_packet(packet);
+}
+
+coap_endpoint_t *coap_new_endpoint(const coap_address_t *addr, int flags) {
+	coap_endpoint_t *result;
+	err_t err;
+
+	LWIP_ASSERT("Flags not supported for LWIP endpoints", flags == COAP_ENDPOINT_NOSEC);
+
+	result = coap_malloc_type(COAP_ENDPOINT, sizeof(coap_endpoint_t));
+	if (!result) return NULL;
+
+	result->pcb = udp_new_ip_type(IPADDR_TYPE_ANY);
+	if (result->pcb == NULL) goto error;
+
+	udp_recv(result->pcb, coap_recv, (void*)result);
+	err = udp_bind(result->pcb, &addr->addr, addr->port);
+	if (err) {
+		udp_remove(result->pcb);
+		goto error;
+	}
+
+	return result;
+
+error:
+	coap_free_type(COAP_ENDPOINT, result);
+	return NULL;
+}
+
+void coap_free_endpoint(coap_endpoint_t *ep)
+{
+	udp_remove(ep->pcb);
+	coap_free_type(COAP_ENDPOINT, ep);
+}
diff --git a/components/coap/libcoap/src/coap_time.c b/components/coap/libcoap/src/coap_time.c
new file mode 100644
index 00000000..1f991755
--- /dev/null
+++ b/components/coap/libcoap/src/coap_time.c
@@ -0,0 +1,98 @@
+/* coap_time.c -- Clock Handling
+ *
+ * Copyright (C) 2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#ifdef WITH_POSIX
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>  /* _POSIX_TIMERS */
+
+#include "coap_config.h"
+#include "coap_time.h"
+
+static coap_time_t coap_clock_offset = 0;
+
+#if _POSIX_TIMERS && !defined(__APPLE__)
+  /* _POSIX_TIMERS is > 0 when clock_gettime() is available */
+
+  /* Use real-time clock for correct timestamps in coap_log(). */  
+#define COAP_CLOCK CLOCK_REALTIME
+#endif
+
+void
+coap_clock_init(void) {
+#ifdef COAP_CLOCK
+  struct timespec tv;
+  clock_gettime(COAP_CLOCK, &tv);
+#else /* _POSIX_TIMERS */
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+#endif /* not _POSIX_TIMERS */
+
+  coap_clock_offset = tv.tv_sec;
+}
+
+/* creates a Qx.frac from fval */
+#define Q(frac,fval) ((coap_tick_t)(((1 << (frac)) * (fval))))
+
+/* number of frac bits for sub-seconds */
+#define FRAC 10
+
+/* rounds val up and right shifts by frac positions */
+#define SHR_FP(val,frac) (((val) + (1 << ((frac) - 1))) >> (frac))
+
+void
+coap_ticks(coap_tick_t *t) {
+  unsigned long tmp;
+
+#ifdef COAP_CLOCK
+  struct timespec tv;
+  clock_gettime(COAP_CLOCK, &tv);
+  /* Possible errors are (see clock_gettime(2)):
+   *  EFAULT tp points outside the accessible address space.
+   *  EINVAL The clk_id specified is not supported on this system.
+   * Both cases should not be possible here.
+   */
+
+  tmp = SHR_FP(tv.tv_nsec * Q(FRAC, (COAP_TICKS_PER_SECOND/1000000000.0)), FRAC);
+#else /* _POSIX_TIMERS */
+  /* Fall back to gettimeofday() */
+
+  struct timeval tv;
+  gettimeofday(&tv, NULL);
+  /* Possible errors are (see gettimeofday(2)):
+   *  EFAULT One of tv or tz pointed outside the accessible address space.
+   *  EINVAL Timezone (or something else) is invalid.
+   * Both cases should not be possible here.
+   */
+
+  tmp = SHR_FP(tv.tv_usec * Q(FRAC, (COAP_TICKS_PER_SECOND/1000000.0)), FRAC);
+#endif /* not _POSIX_TIMERS */
+
+  /* Finally, convert temporary FP representation to multiple of
+   * COAP_TICKS_PER_SECOND */
+  *t = tmp + (tv.tv_sec - coap_clock_offset) * COAP_TICKS_PER_SECOND;
+}
+
+coap_time_t
+coap_ticks_to_rt(coap_tick_t t) {
+  return coap_clock_offset + (t / COAP_TICKS_PER_SECOND);
+}
+
+#undef Q
+#undef FRAC
+#undef SHR_FP
+
+#else /* WITH_POSIX */
+
+/* make compilers happy that do not like empty modules */
+static inline void dummy()
+{
+}
+
+#endif /* not WITH_POSIX */
+
diff --git a/components/coap/libcoap/src/debug.c b/components/coap/libcoap/src/debug.c
new file mode 100644
index 00000000..d68438b7
--- /dev/null
+++ b/components/coap/libcoap/src/debug.c
@@ -0,0 +1,506 @@
+/* debug.c -- debug utilities
+ *
+ * Copyright (C) 2010--2012,2014--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE)
+#define _GNU_SOURCE 1
+#endif
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "block.h"
+#include "debug.h"
+#include "encode.h"
+#include "net.h"
+
+#ifdef WITH_LWIP
+# define fprintf(fd, ...) LWIP_PLATFORM_DIAG((__VA_ARGS__))
+# define fflush(...)
+#endif
+
+#ifdef WITH_CONTIKI
+# ifndef DEBUG
+#  define DEBUG DEBUG_PRINT
+# endif /* DEBUG */
+#include "net/ip/uip-debug.h"
+#endif
+
+static coap_log_t maxlog = LOG_WARNING;	/* default maximum log level */
+
+const char *coap_package_name(void) {
+  return PACKAGE_NAME;
+}
+
+const char *coap_package_version(void) {
+  return PACKAGE_STRING;
+}
+
+coap_log_t 
+coap_get_log_level(void) {
+  return maxlog;
+}
+
+void
+coap_set_log_level(coap_log_t level) {
+  maxlog = level;
+}
+
+/* this array has the same order as the type log_t */
+static char *loglevels[] = {
+  "EMRG", "ALRT", "CRIT", "ERR", "WARN", "NOTE", "INFO", "DEBG" 
+};
+
+#ifdef HAVE_TIME_H
+
+static inline size_t
+print_timestamp(char *s, size_t len, coap_tick_t t) {
+  struct tm *tmp;
+  time_t now = coap_ticks_to_rt(t);
+  tmp = localtime(&now);
+  return strftime(s, len, "%b %d %H:%M:%S", tmp);
+}
+
+#else /* alternative implementation: just print the timestamp */
+
+static inline size_t
+print_timestamp(char *s, size_t len, coap_tick_t t) {
+#ifdef HAVE_SNPRINTF
+  return snprintf(s, len, "%u.%03u", 
+		  (unsigned int)coap_ticks_to_rt(t),
+		  (unsigned int)(t % COAP_TICKS_PER_SECOND));
+#else /* HAVE_SNPRINTF */
+  /* @todo do manual conversion of timestamp */
+  return 0;
+#endif /* HAVE_SNPRINTF */
+}
+
+#endif /* HAVE_TIME_H */
+
+#ifndef NDEBUG
+
+#ifndef HAVE_STRNLEN
+/** 
+ * A length-safe strlen() fake. 
+ * 
+ * @param s      The string to count characters != 0.
+ * @param maxlen The maximum length of @p s.
+ * 
+ * @return The length of @p s.
+ */
+static inline size_t
+strnlen(const char *s, size_t maxlen) {
+  size_t n = 0;
+  while(*s++ && n < maxlen)
+    ++n;
+  return n;
+}
+#endif /* HAVE_STRNLEN */
+
+static unsigned int
+print_readable( const unsigned char *data, unsigned int len,
+		unsigned char *result, unsigned int buflen, int encode_always ) {
+  const unsigned char hex[] = "0123456789ABCDEF";
+  unsigned int cnt = 0;
+  assert(data || len == 0);
+
+  if (buflen == 0) { /* there is nothing we can do here but return */
+    return 0;
+  }
+
+  while (len) {
+    if (!encode_always && isprint(*data)) {
+      if (cnt+1 < buflen) { /* keep one byte for terminating zero */
+      *result++ = *data;
+      ++cnt;
+      } else {
+	break;
+      }
+    } else {
+      if (cnt+4 < buflen) { /* keep one byte for terminating zero */
+	*result++ = '\\';
+	*result++ = 'x';
+	*result++ = hex[(*data & 0xf0) >> 4];
+	*result++ = hex[*data & 0x0f];
+	cnt += 4;
+      } else
+	break;
+    }
+
+    ++data; --len;
+  }
+
+  *result = '\0'; /* add a terminating zero */
+  return cnt;
+}
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+size_t
+coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) {
+#ifdef HAVE_ARPA_INET_H
+  const void *addrptr = NULL;
+  in_port_t port;
+  unsigned char *p = buf;
+
+  switch (addr->addr.sa.sa_family) {
+  case AF_INET: 
+    addrptr = &addr->addr.sin.sin_addr;
+    port = ntohs(addr->addr.sin.sin_port);
+    break;
+  case AF_INET6:
+    if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
+      return 0;
+
+    *p++ = '[';
+
+    addrptr = &addr->addr.sin6.sin6_addr;
+    port = ntohs(addr->addr.sin6.sin6_port);
+
+    break;
+  default:
+    memcpy(buf, "(unknown address type)", min(22, len));
+    return min(22, len);
+  }
+
+  if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p, len) == 0) {
+    perror("coap_print_addr");
+    return 0;
+  }
+
+  p += strnlen((char *)p, len);
+
+  if (addr->addr.sa.sa_family == AF_INET6) {
+    if (p < buf + len) {
+      *p++ = ']';
+    } else 
+      return 0;
+  }
+
+  p += snprintf((char *)p, buf + len - p + 1, ":%d", port);
+
+  return buf + len - p;
+#else /* HAVE_ARPA_INET_H */
+# if WITH_CONTIKI
+  unsigned char *p = buf;
+  uint8_t i;
+#  if NETSTACK_CONF_WITH_IPV6
+  const unsigned char hex[] = "0123456789ABCDEF";
+
+  if (len < 41)
+    return 0;
+
+  *p++ = '[';
+
+  for (i=0; i < 16; i += 2) {
+    if (i) {
+      *p++ = ':';
+    }
+    *p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
+    *p++ = hex[(addr->addr.u8[i] & 0x0f)];
+    *p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
+    *p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
+  }
+  *p++ = ']';
+#  else /* WITH_UIP6 */
+#   warning "IPv4 network addresses will not be included in debug output"
+
+  if (len < 21)
+    return 0;
+#  endif /* WITH_UIP6 */
+  if (buf + len - p < 6)
+    return 0;
+
+#ifdef HAVE_SNPRINTF
+  p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
+#else /* HAVE_SNPRINTF */
+  /* @todo manual conversion of port number */
+#endif /* HAVE_SNPRINTF */
+
+  return p - buf;
+# else /* WITH_CONTIKI */
+  /* TODO: output addresses manually */
+#   warning "inet_ntop() not available, network addresses will not be included in debug output"
+# endif /* WITH_CONTIKI */
+  return 0;
+#endif
+}
+
+#ifdef WITH_CONTIKI
+# define fprintf(fd, ...) PRINTF(__VA_ARGS__)
+# define fflush(...)
+
+# ifdef HAVE_VPRINTF
+#  define vfprintf(fd, ...) vprintf(__VA_ARGS__)
+# else /* HAVE_VPRINTF */
+#  define vfprintf(fd, ...) PRINTF(__VA_ARGS__)
+# endif /* HAVE_VPRINTF */
+#endif /* WITH_CONTIKI */
+
+/** Returns a textual description of the message type @p t. */
+static const char *
+msg_type_string(uint8_t t) {
+  static char *types[] = { "CON", "NON", "ACK", "RST", "???" };
+
+  return types[min(t, sizeof(types)/sizeof(char *) - 1)];
+}
+
+/** Returns a textual description of the method or response code. */
+static const char *
+msg_code_string(uint8_t c) {
+  static char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE", "PATCH" };
+  static char buf[5];
+
+  if (c < sizeof(methods)/sizeof(char *)) {
+    return methods[c];
+  } else {
+    snprintf(buf, sizeof(buf), "%u.%02u", c >> 5, c & 0x1f);
+    return buf;
+  }
+}
+
+/** Returns a textual description of the option name. */
+static const char *
+msg_option_string(uint16_t option_type) {
+  struct option_desc_t {
+    uint16_t type;
+    const char *name;
+  };
+
+  static struct option_desc_t options[] = {
+    { COAP_OPTION_IF_MATCH, "If-Match" },
+    { COAP_OPTION_URI_HOST, "Uri-Host" },
+    { COAP_OPTION_ETAG, "ETag" },
+    { COAP_OPTION_IF_NONE_MATCH, "If-None-Match" },
+    { COAP_OPTION_OBSERVE, "Observe" },
+    { COAP_OPTION_URI_PORT, "Uri-Port" },
+    { COAP_OPTION_LOCATION_PATH, "Location-Path" },
+    { COAP_OPTION_URI_PATH, "Uri-Path" },
+    { COAP_OPTION_CONTENT_FORMAT, "Content-Format" },
+    { COAP_OPTION_MAXAGE, "Max-Age" },
+    { COAP_OPTION_URI_QUERY, "Uri-Query" },
+    { COAP_OPTION_ACCEPT, "Accept" },
+    { COAP_OPTION_LOCATION_QUERY, "Location-Query" },
+    { COAP_OPTION_BLOCK2, "Block2" },
+    { COAP_OPTION_BLOCK1, "Block1" },
+    { COAP_OPTION_PROXY_URI, "Proxy-Uri" },
+    { COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" },
+    { COAP_OPTION_SIZE1, "Size1" },
+    { COAP_OPTION_NORESPONSE, "No-Response" }
+  };
+
+  static char buf[6];
+  size_t i;
+
+  /* search option_type in list of known options */
+  for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) {
+    if (option_type == options[i].type) {
+      return options[i].name;
+    }
+  }
+
+  /* unknown option type, just print to buf */
+  snprintf(buf, sizeof(buf), "%u", option_type);
+  return buf;
+}
+
+static unsigned int
+print_content_format(unsigned int format_type,
+		     unsigned char *result, unsigned int buflen) {
+  struct desc_t {
+    unsigned int type;
+    const char *name;
+  };
+
+  static struct desc_t formats[] = {
+    { COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" },
+    { COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" },
+    { COAP_MEDIATYPE_APPLICATION_XML, "application/xml" },
+    { COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" },
+    { COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" },
+    { COAP_MEDIATYPE_APPLICATION_JSON, "application/json" },
+    { COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" }
+  };
+
+  size_t i;
+
+  /* search format_type in list of known content formats */
+  for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) {
+    if (format_type == formats[i].type) {
+      return snprintf((char *)result, buflen, "%s", formats[i].name);
+    }
+  }
+
+  /* unknown content format, just print numeric value to buf */
+  return snprintf((char *)result, buflen, "%d", format_type);
+}
+
+/**
+ * Returns 1 if the given @p content_format is either unknown or known
+ * to carry binary data. The return value @c 0 hence indicates
+ * printable data which is also assumed if @p content_format is @c 01.
+ */
+static inline int
+is_binary(int content_format) {
+  return !(content_format == -1 ||
+	   content_format == COAP_MEDIATYPE_TEXT_PLAIN ||
+	   content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT ||
+	   content_format == COAP_MEDIATYPE_APPLICATION_XML ||
+	   content_format == COAP_MEDIATYPE_APPLICATION_JSON);
+}
+
+void
+coap_show_pdu(const coap_pdu_t *pdu) {
+  unsigned char buf[COAP_MAX_PDU_SIZE]; /* need some space for output creation */
+  size_t buf_len = 0; /* takes the number of bytes written to buf */
+  int encode = 0, have_options = 0, i;
+  coap_opt_iterator_t opt_iter;
+  coap_opt_t *option;
+  int content_format = -1;
+  size_t data_len;
+  unsigned char *data;
+
+  fprintf(COAP_DEBUG_FD, "v:%d t:%s c:%s i:%04x {",
+	  pdu->hdr->version, msg_type_string(pdu->hdr->type),
+	  msg_code_string(pdu->hdr->code), ntohs(pdu->hdr->id));
+
+  for (i = 0; i < pdu->hdr->token_length; i++) {
+    fprintf(COAP_DEBUG_FD, "%02x", pdu->hdr->token[i]);
+  }
+  fprintf(COAP_DEBUG_FD, "}");
+
+  /* show options, if any */
+  coap_option_iterator_init((coap_pdu_t *)pdu, &opt_iter, COAP_OPT_ALL);
+
+  fprintf(COAP_DEBUG_FD, " [");
+  while ((option = coap_option_next(&opt_iter))) {
+    if (!have_options) {
+      have_options = 1;
+    } else {
+      fprintf(COAP_DEBUG_FD, ",");
+    }
+
+    switch (opt_iter.type) {
+    case COAP_OPTION_CONTENT_FORMAT:
+      content_format = (int)coap_decode_var_bytes(COAP_OPT_VALUE(option),
+						  COAP_OPT_LENGTH(option));
+
+      buf_len = print_content_format(content_format, buf, sizeof(buf));
+      break;
+
+    case COAP_OPTION_BLOCK1:
+    case COAP_OPTION_BLOCK2:
+      /* split block option into number/more/size where more is the
+       * letter M if set, the _ otherwise */
+      buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u",
+			 coap_opt_block_num(option), /* block number */
+			 COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
+			 (1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */
+
+      break;
+
+    case COAP_OPTION_URI_PORT:
+    case COAP_OPTION_MAXAGE:
+    case COAP_OPTION_OBSERVE:
+    case COAP_OPTION_SIZE1:
+      /* show values as unsigned decimal value */
+      buf_len = snprintf((char *)buf, sizeof(buf), "%u",
+			 coap_decode_var_bytes(COAP_OPT_VALUE(option),
+					       COAP_OPT_LENGTH(option)));
+      break;
+
+    default:
+      /* generic output function for all other option types */
+      if (opt_iter.type == COAP_OPTION_URI_PATH ||
+	  opt_iter.type == COAP_OPTION_PROXY_URI ||
+	  opt_iter.type == COAP_OPTION_URI_HOST ||
+	  opt_iter.type == COAP_OPTION_LOCATION_PATH ||
+	  opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
+	  opt_iter.type == COAP_OPTION_URI_QUERY) {
+	encode = 0;
+      } else {
+	encode = 1;
+      }
+
+      buf_len = print_readable(COAP_OPT_VALUE(option),
+			       COAP_OPT_LENGTH(option),
+			       buf, sizeof(buf), encode);
+    }
+
+    fprintf(COAP_DEBUG_FD, " %s:%.*s", msg_option_string(opt_iter.type),
+	    (int)buf_len, buf);
+  }
+
+  fprintf(COAP_DEBUG_FD, " ]");
+  
+  if (coap_get_data((coap_pdu_t *)pdu, &data_len, &data)) {
+
+    fprintf(COAP_DEBUG_FD, " :: ");
+
+    if (is_binary(content_format)) {
+      fprintf(COAP_DEBUG_FD, "<<");
+      while (data_len--) {
+	fprintf(COAP_DEBUG_FD, "%02x", *data++);
+      }
+      fprintf(COAP_DEBUG_FD, ">>");
+    } else {
+      if (print_readable(data, data_len, buf, sizeof(buf), 0)) {
+	fprintf(COAP_DEBUG_FD, "'%s'", buf);
+      }
+    }
+  }
+
+  fprintf(COAP_DEBUG_FD, "\n");
+  fflush(COAP_DEBUG_FD);
+}
+
+
+#endif /* NDEBUG */
+
+void 
+coap_log_impl(coap_log_t level, const char *format, ...) {
+  char timebuf[32];
+  coap_tick_t now;
+  va_list ap;
+  FILE *log_fd;
+
+  if (maxlog < level)
+    return;
+  
+  log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
+
+  coap_ticks(&now);
+  if (print_timestamp(timebuf,sizeof(timebuf), now))
+    fprintf(log_fd, "%s ", timebuf);
+
+  if (level <= LOG_DEBUG)
+    fprintf(log_fd, "%s ", loglevels[level]);
+
+  va_start(ap, format);
+  vfprintf(log_fd, format, ap);
+  va_end(ap);
+  fflush(log_fd);
+}
+
diff --git a/components/coap/libcoap/src/encode.c b/components/coap/libcoap/src/encode.c
new file mode 100644
index 00000000..10c0c6c9
--- /dev/null
+++ b/components/coap/libcoap/src/encode.c
@@ -0,0 +1,48 @@
+/* encode.c -- encoding and decoding of CoAP data types
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#ifndef NDEBUG
+#  include <stdio.h>
+#endif
+
+#include "coap_config.h"
+#include "encode.h"
+
+/* Carsten suggested this when fls() is not available: */
+int coap_fls(unsigned int i) {
+  int n;
+  for (n = 0; i; n++)
+    i >>= 1;
+  return n;
+}
+
+unsigned int
+coap_decode_var_bytes(unsigned char *buf,unsigned int len) {
+  unsigned int i, n = 0;
+  for (i = 0; i < len; ++i)
+    n = (n << 8) + buf[i];
+
+  return n;
+}
+
+unsigned int
+coap_encode_var_bytes(unsigned char *buf, unsigned int val) {
+  unsigned int n, i;
+
+  for (n = 0, i = val; i && n < sizeof(val); ++n)
+    i >>= 8;
+
+  i = n;
+  while (i--) {
+    buf[i] = val & 0xff;
+    val >>= 8;
+  }
+
+  return n;
+}
+
diff --git a/components/coap/libcoap/src/hashkey.c b/components/coap/libcoap/src/hashkey.c
new file mode 100644
index 00000000..828b5194
--- /dev/null
+++ b/components/coap/libcoap/src/hashkey.c
@@ -0,0 +1,29 @@
+/* hashkey.c -- definition of hash key type and helper functions
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "hashkey.h"
+
+/* Caution: When changing this, update COAP_DEFAULT_WKC_HASHKEY
+ * accordingly (see int coap_hash_path());
+ */
+void
+coap_hash_impl(const unsigned char *s, unsigned int len, coap_key_t h) {
+  size_t j;
+
+  while (len--) {
+    j = sizeof(coap_key_t)-1;
+  
+    while (j) {
+      h[j] = ((h[j] << 7) | (h[j-1] >> 1)) + h[j];
+      --j;
+    }
+
+    h[0] = (h[0] << 7) + h[0] + *s++;
+  }
+}
+
diff --git a/components/coap/libcoap/src/mem.c b/components/coap/libcoap/src/mem.c
new file mode 100644
index 00000000..95950c92
--- /dev/null
+++ b/components/coap/libcoap/src/mem.c
@@ -0,0 +1,121 @@
+/* mem.c -- CoAP memory handling
+ *
+ * Copyright (C) 2014--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+
+#include "coap_config.h"
+#include "mem.h"
+#include "debug.h"
+
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#else /* HAVE_ASSERT_H */
+#define assert(...)
+#endif /* HAVE_ASSERT_H */
+
+#ifdef HAVE_MALLOC
+#include <stdlib.h>
+
+void
+coap_memory_init(void) {
+}
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__((unused))
+#else
+#define UNUSED_PARAM
+#endif /* __GNUC__ */
+
+void *
+coap_malloc_type(coap_memory_tag_t type UNUSED_PARAM, size_t size) {
+  return malloc(size);
+}
+
+void
+coap_free_type(coap_memory_tag_t type UNUSED_PARAM, void *p) {
+  free(p);
+}
+
+#else /* HAVE_MALLOC */
+
+#ifdef WITH_CONTIKI
+
+#define COAP_MAX_STRING_SIZE 12
+#define COAP_MAX_STRINGS      8
+
+struct coap_string_t {
+  char data[COAP_MAX_STRING_SIZE];
+};
+
+#include "coap_config.h"
+#include "net.h"
+#include "pdu.h"
+#include "coap_io.h"
+#include "resource.h"
+
+#define COAP_MAX_PACKET_SIZE (sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE)
+#define COAP_MAX_PACKETS     2
+
+typedef union {
+  coap_pdu_t packet; /* try to convince the compiler to word-align this structure  */
+  char buf[COAP_MAX_PACKET_SIZE];
+} coap_packetbuf_t;
+
+MEMB(string_storage, struct coap_string_t, COAP_MAX_STRINGS);
+MEMB(packet_storage, coap_packetbuf_t, COAP_MAX_PACKETS);
+MEMB(node_storage, coap_queue_t, COAP_PDU_MAXCNT);
+MEMB(pdu_storage, coap_pdu_t, COAP_PDU_MAXCNT);
+MEMB(pdu_buf_storage, coap_packetbuf_t, COAP_PDU_MAXCNT);
+MEMB(resource_storage, coap_resource_t, COAP_MAX_RESOURCES);
+MEMB(attribute_storage, coap_attr_t, COAP_MAX_ATTRIBUTES);
+
+static struct memb *
+get_container(coap_memory_tag_t type) {
+  switch(type) {
+  case COAP_PACKET: return &packet_storage;
+  case COAP_NODE:   return &node_storage;
+  case COAP_PDU:     return &pdu_storage;
+  case COAP_PDU_BUF: return &pdu_buf_storage;
+  case COAP_RESOURCE: return &resource_storage;
+  case COAP_RESOURCEATTR: return &attribute_storage;
+  default:
+    return &string_storage;
+  }
+}
+
+void
+coap_memory_init(void) {
+  memb_init(&string_storage);
+  memb_init(&packet_storage);
+  memb_init(&node_storage);
+  memb_init(&pdu_storage);
+  memb_init(&pdu_buf_storage);
+  memb_init(&resource_storage);
+  memb_init(&attribute_storage);
+}
+
+void *
+coap_malloc_type(coap_memory_tag_t type, size_t size) {
+  struct memb *container =  get_container(type);
+  
+  assert(container);
+
+  if (size > container->size) {
+    debug("coap_malloc_type: Requested memory exceeds maximum object size\n");
+    return NULL;
+  }
+
+  return memb_alloc(container);
+}
+
+void
+coap_free_type(coap_memory_tag_t type, void *object) {
+  memb_free(get_container(type), object);
+}
+#endif /* WITH_CONTIKI */
+
+#endif /* HAVE_MALLOC */
diff --git a/components/coap/libcoap/src/net.c b/components/coap/libcoap/src/net.c
new file mode 100644
index 00000000..e08aaa43
--- /dev/null
+++ b/components/coap/libcoap/src/net.c
@@ -0,0 +1,1802 @@
+/* net.c -- CoAP network interface
+ *
+ * Copyright (C) 2010--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#elif HAVE_SYS_UNISTD_H
+#include <sys/unistd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef WITH_LWIP
+#include <lwip/pbuf.h>
+#include <lwip/udp.h>
+#include <lwip/timers.h>
+#endif
+
+#include "debug.h"
+#include "mem.h"
+#include "str.h"
+#include "async.h"
+#include "resource.h"
+#include "option.h"
+#include "encode.h"
+#include "block.h"
+#include "net.h"
+
+/**
+ * @defgroup cc Rate Control
+ * The transmission parameters for CoAP rate control ("Congestion
+ * Control" in stream-oriented protocols) are defined in
+ * https://tools.ietf.org/html/rfc7252#section-4.8
+ * @{
+ */
+
+#ifndef COAP_DEFAULT_ACK_TIMEOUT
+/**
+ * Number of seconds when to expect an ACK or a response to an
+ * outstanding CON message.
+ */
+#define COAP_DEFAULT_ACK_TIMEOUT  2 /* see RFC 7252, Section 4.8 */
+#endif
+
+#ifndef COAP_DEFAULT_ACK_RANDOM_FACTOR
+/**
+ * A factor that is used to randomize the wait time before a message
+ * is retransmitted to prevent synchronization effects.
+ */
+#define COAP_DEFAULT_ACK_RANDOM_FACTOR  1.5 /* see RFC 7252, Section 4.8 */
+#endif
+
+#ifndef COAP_DEFAULT_MAX_RETRANSMIT
+/**
+ * Number of message retransmissions before message sending is stopped
+ */
+#define COAP_DEFAULT_MAX_RETRANSMIT  4 /* see RFC 7252, Section 4.8 */
+#endif
+
+#ifndef COAP_DEFAULT_NSTART
+/**
+ * The number of simultaneous outstanding interactions that a client
+ * maintains to a given server.
+ */
+#define COAP_DEFAULT_NSTART 1 /* see RFC 7252, Section 4.8 */
+#endif
+
+/** @} */
+
+/**
+ * The number of bits for the fractional part of ACK_TIMEOUT and
+ * ACK_RANDOM_FACTOR. Must be less or equal 8.
+ */
+#define FRAC_BITS 6
+
+/**
+ * The maximum number of bits for fixed point integers that are used
+ * for retransmission time calculation. Currently this must be @c 8.
+ */
+#define MAX_BITS 8
+
+#if FRAC_BITS > 8
+#error FRAC_BITS must be less or equal 8
+#endif
+
+/** creates a Qx.frac from fval */
+#define Q(frac,fval) ((unsigned short)(((1 << (frac)) * (fval))))
+
+/** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_RANDOM_FACTOR */
+#define ACK_RANDOM_FACTOR					\
+  Q(FRAC_BITS, COAP_DEFAULT_ACK_RANDOM_FACTOR)
+
+/** creates a Qx.FRAC_BITS from COAP_DEFAULT_ACK_TIMEOUT */
+#define ACK_TIMEOUT Q(FRAC_BITS, COAP_DEFAULT_ACK_TIMEOUT)
+
+#if defined(WITH_POSIX)
+
+time_t clock_offset;
+
+static inline coap_queue_t *
+coap_malloc_node(void) {
+  return (coap_queue_t *)coap_malloc_type(COAP_NODE, sizeof(coap_queue_t));
+}
+
+static inline void
+coap_free_node(coap_queue_t *node) {
+  coap_free_type(COAP_NODE, node);
+}
+#endif /* WITH_POSIX */
+#ifdef WITH_LWIP
+
+#include <lwip/memp.h>
+
+static void coap_retransmittimer_execute(void *arg);
+static void coap_retransmittimer_restart(coap_context_t *ctx);
+
+static inline coap_queue_t *
+coap_malloc_node() {
+	return (coap_queue_t *)memp_malloc(MEMP_COAP_NODE);
+}
+
+static inline void
+coap_free_node(coap_queue_t *node) {
+	memp_free(MEMP_COAP_NODE, node);
+}
+
+#endif /* WITH_LWIP */
+#ifdef WITH_CONTIKI
+# ifndef DEBUG
+#  define DEBUG DEBUG_PRINT
+# endif /* DEBUG */
+
+#include "mem.h"
+#include "net/ip/uip-debug.h"
+
+clock_time_t clock_offset;
+
+#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
+
+void coap_resources_init();
+
+unsigned char initialized = 0;
+coap_context_t the_coap_context;
+
+PROCESS(coap_retransmit_process, "message retransmit process");
+
+static inline coap_queue_t *
+coap_malloc_node() {
+  return (coap_queue_t *)coap_malloc_type(COAP_NODE, 0);
+}
+
+static inline void
+coap_free_node(coap_queue_t *node) {
+  coap_free_type(COAP_NODE, node);
+}
+#endif /* WITH_CONTIKI */
+
+unsigned int
+coap_adjust_basetime(coap_context_t *ctx, coap_tick_t now) {
+  unsigned int result = 0;
+  coap_tick_diff_t delta = now - ctx->sendqueue_basetime;
+
+  if (ctx->sendqueue) {
+    /* delta < 0 means that the new time stamp is before the old. */
+    if (delta <= 0) {
+      ctx->sendqueue->t -= delta;
+    } else {
+      /* This case is more complex: The time must be advanced forward,
+       * thus possibly leading to timed out elements at the queue's
+       * start. For every element that has timed out, its relative
+       * time is set to zero and the result counter is increased. */
+
+      coap_queue_t *q = ctx->sendqueue;
+      coap_tick_t t = 0;
+      while (q && (t + q->t < (coap_tick_t)delta)) {
+	t += q->t;
+	q->t = 0;
+	result++;
+	q = q->next;
+      }
+
+      /* finally adjust the first element that has not expired */
+      if (q) {
+	q->t = (coap_tick_t)delta - t;
+      }
+    }
+  }
+
+  /* adjust basetime */
+  ctx->sendqueue_basetime += delta;
+
+  return result;
+}
+
+int
+coap_insert_node(coap_queue_t **queue, coap_queue_t *node) {
+  coap_queue_t *p, *q;
+  if ( !queue || !node )
+    return 0;
+
+  /* set queue head if empty */
+  if ( !*queue ) {
+    *queue = node;
+    return 1;
+  }
+
+  /* replace queue head if PDU's time is less than head's time */
+  q = *queue;
+  if (node->t < q->t) {
+    node->next = q;
+    *queue = node;
+    q->t -= node->t;		/* make q->t relative to node->t */
+    return 1;
+  }
+
+  /* search for right place to insert */
+  do {
+    node->t -= q->t;		/* make node-> relative to q->t */
+    p = q;
+    q = q->next;
+  } while (q && q->t <= node->t);
+
+  /* insert new item */
+  if (q) {
+    q->t -= node->t;		/* make q->t relative to node->t */
+  }
+  node->next = q;
+  p->next = node;
+  return 1;
+}
+
+int
+coap_delete_node(coap_queue_t *node) {
+  if ( !node )
+    return 0;
+
+  coap_delete_pdu(node->pdu);
+  coap_free_node(node);
+
+  return 1;
+}
+
+void
+coap_delete_all(coap_queue_t *queue) {
+  if ( !queue )
+    return;
+
+  coap_delete_all( queue->next );
+  coap_delete_node( queue );
+}
+
+coap_queue_t *
+coap_new_node(void) {
+  coap_queue_t *node;
+  node = coap_malloc_node();
+
+  if ( ! node ) {
+#ifndef NDEBUG
+    coap_log(LOG_WARNING, "coap_new_node: malloc\n");
+#endif
+    return NULL;
+  }
+
+  memset(node, 0, sizeof(*node));
+  return node;
+}
+
+coap_queue_t *
+coap_peek_next( coap_context_t *context ) {
+  if ( !context || !context->sendqueue )
+    return NULL;
+
+  return context->sendqueue;
+}
+
+coap_queue_t *
+coap_pop_next( coap_context_t *context ) {
+  coap_queue_t *next;
+
+  if ( !context || !context->sendqueue )
+    return NULL;
+
+  next = context->sendqueue;
+  context->sendqueue = context->sendqueue->next;
+  if (context->sendqueue) {
+    context->sendqueue->t += next->t;
+  }
+  next->next = NULL;
+  return next;
+}
+
+#ifdef COAP_DEFAULT_WKC_HASHKEY
+/** Checks if @p Key is equal to the pre-defined hash key for.well-known/core. */
+#define is_wkc(Key)							\
+  (memcmp((Key), COAP_DEFAULT_WKC_HASHKEY, sizeof(coap_key_t)) == 0)
+#else
+/* Implements a singleton to store a hash key for the .wellknown/core
+ * resources. */
+int
+is_wkc(coap_key_t k) {
+  static coap_key_t wkc;
+  static unsigned char _initialized = 0;
+  if (!_initialized) {
+    _initialized = coap_hash_path((unsigned char *)COAP_DEFAULT_URI_WELLKNOWN, 
+				 sizeof(COAP_DEFAULT_URI_WELLKNOWN) - 1, wkc);
+  }
+  return memcmp(k, wkc, sizeof(coap_key_t)) == 0;
+}
+#endif
+
+coap_context_t *
+coap_new_context(
+  const coap_address_t *listen_addr) {
+  coap_context_t *c;
+
+  if (!listen_addr) {
+    coap_log(LOG_EMERG, "no listen address specified\n");
+    return NULL;
+  }
+#ifdef WITH_CONTIKI
+  if (initialized)
+    return NULL;
+#endif /* WITH_CONTIKI */
+#ifndef WITH_CONTIKI
+  c = coap_malloc_type(COAP_CONTEXT, sizeof(coap_context_t));
+#endif /* not WITH_CONTIKI */
+
+  coap_clock_init();
+#ifdef WITH_LWIP
+  prng_init(LWIP_RAND());
+#endif /* WITH_LWIP */
+#ifdef WITH_CONTIKI
+  prng_init((ptrdiff_t)listen_addr ^ clock_offset);
+#endif /* WITH_LWIP */
+#ifdef WITH_POSIX
+  prng_init((unsigned long)listen_addr ^ clock_offset);
+#endif /* WITH_POSIX */
+
+#ifndef WITH_CONTIKI
+  if (!c) {
+#ifndef NDEBUG
+    coap_log(LOG_EMERG, "coap_init: malloc:\n");
+#endif
+    return NULL;
+  }
+#endif /* not WITH_CONTIKI */
+#ifdef WITH_CONTIKI
+  coap_resources_init();
+  coap_memory_init();
+
+  c = &the_coap_context;
+  initialized = 1;
+#endif /* WITH_CONTIKI */
+
+  memset(c, 0, sizeof( coap_context_t ) );
+
+  /* initialize message id */
+  prng((unsigned char *)&c->message_id, sizeof(unsigned short));
+
+  c->endpoint = coap_new_endpoint(listen_addr, COAP_ENDPOINT_NOSEC);
+  if (c->endpoint == NULL) {
+    goto onerror;
+  }
+#ifdef WITH_LWIP
+  c->endpoint->context = c;
+#endif
+
+#ifdef WITH_POSIX
+  c->sockfd = c->endpoint->handle.fd;
+#endif /* WITH_POSIX */
+
+#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
+  c->network_send = coap_network_send;
+  c->network_read = coap_network_read;
+#endif /* WITH_POSIX or WITH_CONTIKI */
+
+#ifdef WITH_CONTIKI
+  process_start(&coap_retransmit_process, (char *)c);
+
+  PROCESS_CONTEXT_BEGIN(&coap_retransmit_process);
+#ifndef WITHOUT_OBSERVE
+  etimer_set(&c->notify_timer, COAP_RESOURCE_CHECK_TIME * COAP_TICKS_PER_SECOND);
+#endif /* WITHOUT_OBSERVE */
+  /* the retransmit timer must be initialized to some large value */
+  etimer_set(&the_coap_context.retransmit_timer, 0xFFFF);
+  PROCESS_CONTEXT_END(&coap_retransmit_process);
+#endif /* WITH_CONTIKI */
+
+  return c;
+
+ onerror:
+  coap_free_type(COAP_CONTEXT, c);
+  return NULL;
+}
+
+void
+coap_free_context(coap_context_t *context) {
+
+  if (!context)
+    return;
+
+  coap_delete_all(context->sendqueue);
+
+#ifdef WITH_LWIP
+  context->sendqueue = NULL;
+  coap_retransmittimer_restart(context);
+#endif
+
+  coap_delete_all_resources(context);
+
+  coap_free_endpoint(context->endpoint);
+#ifndef WITH_CONTIKI
+  coap_free_type(COAP_CONTEXT, context);
+#endif/* not WITH_CONTIKI */
+#ifdef WITH_CONTIKI
+  memset(&the_coap_context, 0, sizeof(coap_context_t));
+  initialized = 0;
+#endif /* WITH_CONTIKI */
+}
+
+int
+coap_option_check_critical(coap_context_t *ctx, 
+			   coap_pdu_t *pdu,
+			   coap_opt_filter_t unknown) {
+
+  coap_opt_iterator_t opt_iter;
+  int ok = 1;
+  
+  coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
+
+  while (coap_option_next(&opt_iter)) {
+
+    /* The following condition makes use of the fact that
+     * coap_option_getb() returns -1 if type exceeds the bit-vector
+     * filter. As the vector is supposed to be large enough to hold
+     * the largest known option, we know that everything beyond is
+     * bad.
+     */
+    if (opt_iter.type & 0x01) {
+      /* first check the built-in critical options */
+      switch (opt_iter.type) {
+      case COAP_OPTION_IF_MATCH:
+      case COAP_OPTION_URI_HOST:
+      case COAP_OPTION_IF_NONE_MATCH:
+      case COAP_OPTION_URI_PORT:
+      case COAP_OPTION_URI_PATH:
+      case COAP_OPTION_URI_QUERY:
+      case COAP_OPTION_ACCEPT:
+      case COAP_OPTION_PROXY_URI:
+      case COAP_OPTION_PROXY_SCHEME:
+      case COAP_OPTION_BLOCK2:
+      case COAP_OPTION_BLOCK1:
+	break;
+      default:
+	if (coap_option_filter_get(ctx->known_options, opt_iter.type) <= 0) {
+	  debug("unknown critical option %d\n", opt_iter.type);
+	  ok = 0;
+
+	  /* When opt_iter.type is beyond our known option range,
+	   * coap_option_filter_set() will return -1 and we are safe to leave
+	   * this loop. */
+	  if (coap_option_filter_set(unknown, opt_iter.type) == -1) {
+	    break;
+	  }
+	}
+      }
+    }
+  }
+
+  return ok;
+}
+
+void
+coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu, 
+		    coap_tid_t *id) {
+  coap_key_t h;
+
+  memset(h, 0, sizeof(coap_key_t));
+
+  /* Compare the transport address. */
+
+#ifdef WITH_POSIX
+  switch (peer->addr.sa.sa_family) {
+  case AF_INET:
+    coap_hash((const unsigned char *)&peer->addr.sin.sin_port,
+	      sizeof(peer->addr.sin.sin_port), h);
+    coap_hash((const unsigned char *)&peer->addr.sin.sin_addr,
+	      sizeof(peer->addr.sin.sin_addr), h);
+    break;
+  case AF_INET6:
+    coap_hash((const unsigned char *)&peer->addr.sin6.sin6_port,
+	      sizeof(peer->addr.sin6.sin6_port), h);
+    coap_hash((const unsigned char *)&peer->addr.sin6.sin6_addr,
+	      sizeof(peer->addr.sin6.sin6_addr), h);
+    break;
+  default:
+    return;
+  }
+#endif
+#if defined(WITH_LWIP) || defined(WITH_CONTIKI)
+    /* FIXME: with lwip, we can do better */
+    coap_hash((const unsigned char *)&peer->port, sizeof(peer->port), h);
+    coap_hash((const unsigned char *)&peer->addr, sizeof(peer->addr), h);  
+#endif /* WITH_LWIP || WITH_CONTIKI */
+
+  coap_hash((const unsigned char *)&pdu->hdr->id, sizeof(unsigned short), h);
+
+  *id = (((h[0] << 8) | h[1]) ^ ((h[2] << 8) | h[3])) & INT_MAX;
+}
+
+coap_tid_t
+coap_send_ack(coap_context_t *context, 
+	      const coap_endpoint_t *local_interface,
+	      const coap_address_t *dst,
+	      coap_pdu_t *request) {
+  coap_pdu_t *response;
+  coap_tid_t result = COAP_INVALID_TID;
+
+  if (request && request->hdr->type == COAP_MESSAGE_CON) {
+    response = coap_pdu_init(COAP_MESSAGE_ACK, 0, request->hdr->id, 
+			     sizeof(coap_pdu_t)); 
+    if (response) {
+      result = coap_send(context, local_interface, dst, response);
+      coap_delete_pdu(response);
+    }
+  }
+  return result;
+}
+
+#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
+static coap_tid_t
+coap_send_impl(coap_context_t *context, 
+	       const coap_endpoint_t *local_interface,
+	       const coap_address_t *dst,
+	       coap_pdu_t *pdu) {
+  ssize_t bytes_written;
+  coap_tid_t id = COAP_INVALID_TID;
+
+  if ( !context || !dst || !pdu )
+    return id;
+
+  /* Do not send error responses for requests that were received via
+   * IP multicast. 
+   * FIXME: If No-Response option indicates interest, these responses
+   *        must not be dropped. */
+  if (coap_is_mcast(&local_interface->addr) &&
+      COAP_RESPONSE_CLASS(pdu->hdr->code) > 2) {
+    return COAP_DROPPED_RESPONSE;
+  }
+
+  bytes_written = context->network_send(context, local_interface, dst, 
+				    (unsigned char *)pdu->hdr, pdu->length);
+
+  if (bytes_written >= 0) {
+    coap_transaction_id(dst, pdu, &id);
+  } else {
+    coap_log(LOG_CRIT, "coap_send_impl: %s\n", strerror(errno));
+  }
+
+  return id;
+}
+#endif /* WITH_POSIX */
+#ifdef WITH_LWIP
+coap_tid_t
+coap_send_impl(coap_context_t *context,
+	       const coap_endpoint_t *local_interface,
+	       const coap_address_t *dst,
+	       coap_pdu_t *pdu) {
+  coap_tid_t id = COAP_INVALID_TID;
+
+  if ( !context || !dst || !pdu )
+  {
+    return id;
+  }
+
+  /* FIXME: we can't check this here with the existing infrastructure, but we
+   * should actually check that the pdu is not held by anyone but us. the
+   * respective pbuf is already exclusively owned by the pdu. */
+
+  pbuf_realloc(pdu->pbuf, pdu->length);
+
+  coap_transaction_id(dst, pdu, &id);
+
+  udp_sendto(context->endpoint->pcb, pdu->pbuf,
+			&dst->addr, dst->port);
+
+  return id;
+}
+#endif /* WITH_LWIP */
+
+coap_tid_t 
+coap_send(coap_context_t *context, 
+	  const coap_endpoint_t *local_interface,
+	  const coap_address_t *dst, 
+	  coap_pdu_t *pdu) {
+  return coap_send_impl(context, local_interface, dst, pdu);
+}
+
+coap_tid_t
+coap_send_error(coap_context_t *context, 
+		coap_pdu_t *request,
+		const coap_endpoint_t *local_interface,
+		const coap_address_t *dst,
+		unsigned char code,
+		coap_opt_filter_t opts) {
+  coap_pdu_t *response;
+  coap_tid_t result = COAP_INVALID_TID;
+
+  assert(request);
+  assert(dst);
+
+  response = coap_new_error_response(request, code, opts);
+  if (response) {
+    result = coap_send(context, local_interface, dst, response);
+    coap_delete_pdu(response);
+  }
+  
+  return result;
+}
+
+coap_tid_t
+coap_send_message_type(coap_context_t *context, 
+		       const coap_endpoint_t *local_interface,
+		       const coap_address_t *dst, 
+		       coap_pdu_t *request,
+		       unsigned char type) {
+  coap_pdu_t *response;
+  coap_tid_t result = COAP_INVALID_TID;
+
+  if (request) {
+    response = coap_pdu_init(type, 0, request->hdr->id, sizeof(coap_pdu_t)); 
+    if (response) {
+      result = coap_send(context, local_interface, dst, response);
+      coap_delete_pdu(response);
+    }
+  }
+  return result;
+}
+
+/**
+ * Calculates the initial timeout based on the global CoAP transmission
+ * parameters ACK_TIMEOUT, ACK_RANDOM_FACTOR, and COAP_TICKS_PER_SECOND.
+ * The calculation requires ACK_TIMEOUT and ACK_RANDOM_FACTOR to be in
+ * Qx.FRAC_BITS fixed point notation, whereas the passed parameter @p r
+ * is interpreted as the fractional part of a Q0.MAX_BITS random value.
+ *
+ * @param r  random value as fractional part of a Q0.MAX_BITS fixed point
+ *           value
+ * @return   COAP_TICKS_PER_SECOND * ACK_TIMEOUT * (1 + (ACK_RANDOM_FACTOR - 1) * r)
+ */
+static inline unsigned int
+calc_timeout(unsigned char r) {
+  unsigned int result;
+
+  /* The integer 1.0 as a Qx.FRAC_BITS */
+#define FP1 Q(FRAC_BITS, 1)
+
+  /* rounds val up and right shifts by frac positions */
+#define SHR_FP(val,frac) (((val) + (1 << ((frac) - 1))) >> (frac))
+
+  /* Inner term: multiply ACK_RANDOM_FACTOR by Q0.MAX_BITS[r] and
+   * make the result a rounded Qx.FRAC_BITS */
+  result = SHR_FP((ACK_RANDOM_FACTOR - FP1) * r, MAX_BITS);
+
+  /* Add 1 to the inner term and multiply with ACK_TIMEOUT, then
+   * make the result a rounded Qx.FRAC_BITS */
+  result = SHR_FP(((result + FP1) * ACK_TIMEOUT), FRAC_BITS);
+
+  /* Multiply with COAP_TICKS_PER_SECOND to yield system ticks
+   * (yields a Qx.FRAC_BITS) and shift to get an integer */
+  return SHR_FP((COAP_TICKS_PER_SECOND * result), FRAC_BITS);
+
+#undef FP1
+#undef SHR_FP
+}
+
+coap_tid_t
+coap_send_confirmed(coap_context_t *context, 
+		    const coap_endpoint_t *local_interface,
+		    const coap_address_t *dst,
+		    coap_pdu_t *pdu) {
+  coap_queue_t *node;
+  coap_tick_t now;
+  unsigned char r;
+
+  node = coap_new_node();
+  if (!node) {
+    debug("coap_send_confirmed: insufficient memory\n");
+    return COAP_INVALID_TID;
+  }
+
+  node->id = coap_send_impl(context, local_interface, dst, pdu);
+  if (COAP_INVALID_TID == node->id) {
+    debug("coap_send_confirmed: error sending pdu\n");
+    coap_free_node(node);
+    return COAP_INVALID_TID;
+  }
+  
+  prng((unsigned char *)&r,sizeof(r));
+
+  /* add timeout in range [ACK_TIMEOUT...ACK_TIMEOUT * ACK_RANDOM_FACTOR] */
+  node->timeout = calc_timeout(r);
+
+  node->local_if = *local_interface;
+  memcpy(&node->remote, dst, sizeof(coap_address_t));
+  node->pdu = pdu;
+
+  /* Set timer for pdu retransmission. If this is the first element in
+   * the retransmission queue, the base time is set to the current
+   * time and the retransmission time is node->timeout. If there is
+   * already an entry in the sendqueue, we must check if this node is
+   * to be retransmitted earlier. Therefore, node->timeout is first
+   * normalized to the base time and then inserted into the queue with
+   * an adjusted relative time.
+   */
+  coap_ticks(&now);
+  if (context->sendqueue == NULL) {
+    node->t = node->timeout;
+    context->sendqueue_basetime = now;
+  } else {
+    /* make node->t relative to context->sendqueue_basetime */
+    node->t = (now - context->sendqueue_basetime) + node->timeout;
+  }
+
+  coap_insert_node(&context->sendqueue, node);
+
+#ifdef WITH_LWIP
+  if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
+    coap_retransmittimer_restart(context);
+#endif
+
+#ifdef WITH_CONTIKI
+  {			    /* (re-)initialize retransmission timer */
+    coap_queue_t *nextpdu;
+
+    nextpdu = coap_peek_next(context);
+    assert(nextpdu);		/* we have just inserted a node */
+
+    /* must set timer within the context of the retransmit process */
+    PROCESS_CONTEXT_BEGIN(&coap_retransmit_process);
+    etimer_set(&context->retransmit_timer, nextpdu->t);
+    PROCESS_CONTEXT_END(&coap_retransmit_process);
+  }
+#endif /* WITH_CONTIKI */
+
+  return node->id;
+}
+
+coap_tid_t
+coap_retransmit(coap_context_t *context, coap_queue_t *node) {
+  if (!context || !node)
+    return COAP_INVALID_TID;
+
+  /* re-initialize timeout when maximum number of retransmissions are not reached yet */
+  if (node->retransmit_cnt < COAP_DEFAULT_MAX_RETRANSMIT) {
+    node->retransmit_cnt++;
+    node->t = node->timeout << node->retransmit_cnt;
+    coap_insert_node(&context->sendqueue, node);
+#ifdef WITH_LWIP
+    if (node == context->sendqueue) /* don't bother with timer stuff if there are earlier retransmits */
+      coap_retransmittimer_restart(context);
+#endif
+
+    debug("** retransmission #%d of transaction %d\n",
+	  node->retransmit_cnt, ntohs(node->pdu->hdr->id));
+
+    node->id = coap_send_impl(context, &node->local_if, 
+			      &node->remote, node->pdu);
+    return node->id;
+  }
+
+  /* no more retransmissions, remove node from system */
+
+#ifndef WITH_CONTIKI
+  debug("** removed transaction %d\n", ntohs(node->id));
+#endif
+
+#ifndef WITHOUT_OBSERVE
+  /* Check if subscriptions exist that should be canceled after
+     COAP_MAX_NOTIFY_FAILURES */
+  if (node->pdu->hdr->code >= 64) {
+    str token = { 0, NULL };
+
+    token.length = node->pdu->hdr->token_length;
+    token.s = node->pdu->hdr->token;
+
+    coap_handle_failed_notify(context, &node->remote, &token);
+  }
+#endif /* WITHOUT_OBSERVE */
+
+  /* And finally delete the node */
+  coap_delete_node( node );
+  return COAP_INVALID_TID;
+}
+
+void coap_dispatch(coap_context_t *context, coap_queue_t *rcvd);
+
+#ifndef WITH_LWIP
+/* WITH_LWIP, this is handled by coap_recv in a different way */
+int
+coap_read( coap_context_t *ctx ) {
+  ssize_t bytes_read = -1;
+  coap_packet_t *packet;
+  coap_address_t src;
+  int result = -1;		/* the value to be returned */
+
+  coap_address_init(&src);
+
+  bytes_read = ctx->network_read(ctx->endpoint, &packet);
+
+  if ( bytes_read < 0 ) {
+    warn("coap_read: recvfrom");
+  } else {
+    result = coap_handle_message(ctx, packet);
+  }
+
+  coap_free_packet(packet);
+
+  return result;
+}
+#endif /* not WITH_LWIP */
+
+int
+coap_handle_message(coap_context_t *ctx,
+		    coap_packet_t *packet) {
+		    /* const coap_address_t *remote,  */
+		    /* unsigned char *msg, size_t msg_len) { */
+  unsigned char *msg;
+  size_t msg_len;
+  coap_queue_t *node;
+
+  /* the negated result code */
+  enum result_t { RESULT_OK, RESULT_ERR_EARLY, RESULT_ERR };
+  int result = RESULT_ERR_EARLY;
+
+  coap_packet_get_memmapped(packet, &msg, &msg_len);
+
+  if (msg_len < sizeof(coap_hdr_t)) {
+    debug("coap_handle_message: discarded invalid frame\n" );
+    goto error_early;
+  }
+
+  /* check version identifier */
+  if (((*msg >> 6) & 0x03) != COAP_DEFAULT_VERSION) {
+    debug("coap_handle_message: unknown protocol version %d\n", (*msg >> 6) & 0x03);
+    goto error_early;
+  }
+
+  node = coap_new_node();
+  if (!node) {
+    goto error_early;
+  }
+
+  /* from this point, the result code indicates that */
+  result = RESULT_ERR;
+  
+#ifdef WITH_LWIP
+  node->pdu = coap_pdu_from_pbuf(coap_packet_extract_pbuf(packet));
+#else
+  node->pdu = coap_pdu_init(0, 0, 0, msg_len);
+#endif
+  if (!node->pdu) {
+    goto error;
+  }
+
+  if (!coap_pdu_parse(msg, msg_len, node->pdu)) {
+    warn("discard malformed PDU\n");
+    goto error;
+  }
+
+  coap_ticks(&node->t);
+
+  coap_packet_populate_endpoint(packet, &node->local_if);
+  coap_packet_copy_source(packet, &node->remote);
+
+  /* and add new node to receive queue */
+  coap_transaction_id(&node->remote, node->pdu, &node->id);
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+    /** @FIXME get debug to work again **
+    unsigned char addr[INET6_ADDRSTRLEN+8], localaddr[INET6_ADDRSTRLEN+8];
+    if (coap_print_addr(remote, addr, INET6_ADDRSTRLEN+8) &&
+	coap_print_addr(&packet->dst, localaddr, INET6_ADDRSTRLEN+8) )
+      debug("** received %d bytes from %s on interface %s:\n",
+	    (int)msg_len, addr, localaddr);
+    
+	    */
+    coap_show_pdu(node->pdu);
+  }
+#endif
+
+  coap_dispatch(ctx, node);
+  return -RESULT_OK;
+
+ error:
+  /* FIXME: send back RST? */
+  coap_delete_node(node);
+  return -result;
+
+ error_early:
+  return -result;
+}
+
+int
+coap_remove_from_queue(coap_queue_t **queue, coap_tid_t id, coap_queue_t **node) {
+  coap_queue_t *p, *q;
+
+  if ( !queue || !*queue)
+    return 0;
+
+  /* replace queue head if PDU's time is less than head's time */
+
+  if ( id == (*queue)->id ) { /* found transaction */
+    *node = *queue;
+    *queue = (*queue)->next;
+    if (*queue) {	  /* adjust relative time of new queue head */
+      (*queue)->t += (*node)->t;
+    }
+    (*node)->next = NULL;
+    /* coap_delete_node( q ); */
+    debug("*** removed transaction %u\n", id);
+    return 1;
+  }
+
+  /* search transaction to remove (only first occurence will be removed) */
+  q = *queue;
+  do {
+    p = q;
+    q = q->next;
+  } while ( q && id != q->id );
+
+  if ( q ) {			/* found transaction */
+    p->next = q->next;
+    if (p->next) {		/* must update relative time of p->next */
+      p->next->t += q->t;
+    }
+    q->next = NULL;
+    *node = q;
+    /* coap_delete_node( q ); */
+    debug("*** removed transaction %u\n", id);
+    return 1;
+  }
+
+  return 0;
+
+}
+
+static inline int
+token_match(const unsigned char *a, size_t alen, 
+	    const unsigned char *b, size_t blen) {
+  return alen == blen && (alen == 0 || memcmp(a, b, alen) == 0);
+}
+
+void
+coap_cancel_all_messages(coap_context_t *context, const coap_address_t *dst,
+			 const unsigned char *token, size_t token_length) {
+  /* cancel all messages in sendqueue that are for dst 
+   * and use the specified token */
+  coap_queue_t *p, *q;
+  
+  while (context->sendqueue && 
+	 coap_address_equals(dst, &context->sendqueue->remote) &&
+	 token_match(token, token_length, 
+		     context->sendqueue->pdu->hdr->token, 
+		     context->sendqueue->pdu->hdr->token_length)) {
+    q = context->sendqueue; 
+    context->sendqueue = q->next;
+    debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+    coap_delete_node(q);
+  }
+
+  if (!context->sendqueue)
+    return;
+
+  p = context->sendqueue;
+  q = p->next;
+  
+  /* when q is not NULL, it does not match (dst, token), so we can skip it */
+  while (q) {
+    if (coap_address_equals(dst, &q->remote) &&
+	token_match(token, token_length,
+		    q->pdu->hdr->token, q->pdu->hdr->token_length)) {
+      p->next = q->next;
+      debug("**** removed transaction %d\n", ntohs(q->pdu->hdr->id));
+      coap_delete_node(q);
+      q = p->next;
+    } else {
+      p = q;
+      q = q->next;
+    }
+  }
+}
+
+coap_queue_t *
+coap_find_transaction(coap_queue_t *queue, coap_tid_t id) {
+  while (queue && queue->id != id)
+    queue = queue->next;
+
+  return queue;
+}
+
+coap_pdu_t *
+coap_new_error_response(coap_pdu_t *request, unsigned char code, 
+			coap_opt_filter_t opts) {
+  coap_opt_iterator_t opt_iter;
+  coap_pdu_t *response;
+  size_t size = sizeof(coap_hdr_t) + request->hdr->token_length;
+  int type; 
+  coap_opt_t *option;
+  unsigned short opt_type = 0;	/* used for calculating delta-storage */
+
+#if COAP_ERROR_PHRASE_LENGTH > 0
+  char *phrase = coap_response_phrase(code);
+
+  /* Need some more space for the error phrase and payload start marker */
+  if (phrase)
+    size += strlen(phrase) + 1;
+#endif
+
+  assert(request);
+
+  /* cannot send ACK if original request was not confirmable */
+  type = request->hdr->type == COAP_MESSAGE_CON 
+    ? COAP_MESSAGE_ACK
+    : COAP_MESSAGE_NON;
+
+  /* Estimate how much space we need for options to copy from
+   * request. We always need the Token, for 4.02 the unknown critical
+   * options must be included as well. */
+  coap_option_clrb(opts, COAP_OPTION_CONTENT_TYPE); /* we do not want this */
+
+  coap_option_iterator_init(request, &opt_iter, opts);
+
+  /* Add size of each unknown critical option. As known critical
+     options as well as elective options are not copied, the delta
+     value might grow.
+   */
+  while((option = coap_option_next(&opt_iter))) {
+    unsigned short delta = opt_iter.type - opt_type;
+    /* calculate space required to encode (opt_iter.type - opt_type) */
+    if (delta < 13) {
+      size++;
+    } else if (delta < 269) {
+      size += 2;
+    } else {
+      size += 3;
+    }
+
+    /* add coap_opt_length(option) and the number of additional bytes
+     * required to encode the option length */
+    
+    size += coap_opt_length(option);
+    switch (*option & 0x0f) {
+    case 0x0e:
+      size++;
+      /* fall through */
+    case 0x0d:
+      size++;
+      break;
+    default:
+      ;
+    }
+
+    opt_type = opt_iter.type;
+  }
+
+  /* Now create the response and fill with options and payload data. */
+  response = coap_pdu_init(type, code, request->hdr->id, size);
+  if (response) {
+    /* copy token */
+    if (!coap_add_token(response, request->hdr->token_length, 
+			request->hdr->token)) {
+      debug("cannot add token to error response\n");
+      coap_delete_pdu(response);
+      return NULL;
+    }
+
+    /* copy all options */
+    coap_option_iterator_init(request, &opt_iter, opts);
+    while((option = coap_option_next(&opt_iter)))
+      coap_add_option(response, opt_iter.type, 
+		      COAP_OPT_LENGTH(option),
+		      COAP_OPT_VALUE(option));
+
+#if COAP_ERROR_PHRASE_LENGTH > 0
+    /* note that diagnostic messages do not need a Content-Format option. */
+    if (phrase)
+      coap_add_data(response, strlen(phrase), (unsigned char *)phrase);
+#endif
+  }
+
+  return response;
+}
+
+/**
+ * Quick hack to determine the size of the resource description for
+ * .well-known/core.
+ */
+static inline size_t
+get_wkc_len(coap_context_t *context, coap_opt_t *query_filter) {
+  unsigned char buf[1];
+  size_t len = 0;
+
+  if (coap_print_wellknown(context, buf, &len, UINT_MAX, query_filter)
+      & COAP_PRINT_STATUS_ERROR) {
+    warn("cannot determine length of /.well-known/core\n");
+    return 0;
+  }
+
+  debug("get_wkc_len: coap_print_wellknown() returned %zu\n", len);
+
+  return len;
+}
+
+#define SZX_TO_BYTES(SZX) ((size_t)(1 << ((SZX) + 4)))
+
+coap_pdu_t *
+coap_wellknown_response(coap_context_t *context, coap_pdu_t *request) {
+  coap_pdu_t *resp;
+  coap_opt_iterator_t opt_iter;
+  size_t len, wkc_len;
+  unsigned char buf[2];
+  int result = 0;
+  int need_block2 = 0;	   /* set to 1 if Block2 option is required */
+  coap_block_t block;
+  coap_opt_t *query_filter;
+  size_t offset = 0;
+
+  resp = coap_pdu_init(request->hdr->type == COAP_MESSAGE_CON 
+		       ? COAP_MESSAGE_ACK 
+		       : COAP_MESSAGE_NON,
+		       COAP_RESPONSE_CODE(205),
+		       request->hdr->id, COAP_MAX_PDU_SIZE);
+  if (!resp) {
+    debug("coap_wellknown_response: cannot create PDU\n");
+    return NULL;
+  }
+  
+  if (!coap_add_token(resp, request->hdr->token_length, request->hdr->token)) {
+    debug("coap_wellknown_response: cannot add token\n");
+    goto error;
+  }
+
+  query_filter = coap_check_option(request, COAP_OPTION_URI_QUERY, &opt_iter);
+  wkc_len = get_wkc_len(context, query_filter);
+
+  /* The value of some resources is undefined and get_wkc_len will return 0.*/
+  if (wkc_len == 0){
+    debug("coap_wellknown_response: undefined resource\n");
+    /* set error code 4.00 Bad Request*/
+    resp->hdr->code = COAP_RESPONSE_CODE(400);
+    resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length;
+    return resp;
+  }
+
+  /* check whether the request contains the Block2 option */
+  if (coap_get_block(request, COAP_OPTION_BLOCK2, &block)) {
+    debug("create block\n");
+    offset = block.num << (block.szx + 4);
+    if (block.szx > 6) {  /* invalid, MUST lead to 4.00 Bad Request */
+      resp->hdr->code = COAP_RESPONSE_CODE(400);
+      return resp;
+    } else if (block.szx > COAP_MAX_BLOCK_SZX) {
+      block.szx = COAP_MAX_BLOCK_SZX;
+      block.num = offset >> (block.szx + 4);
+    }
+
+    need_block2 = 1;
+  }
+
+  /* Check if there is sufficient space to add Content-Format option 
+   * and data. We do this before adding the Content-Format option to
+   * avoid sending error responses with that option but no actual
+   * content. */
+  if (resp->max_size <= (size_t)resp->length + 3) {
+    debug("coap_wellknown_response: insufficient storage space\n");
+    goto error;
+  }
+
+  /* Add Content-Format. As we have checked for available storage,
+   * nothing should go wrong here. */
+  assert(coap_encode_var_bytes(buf, 
+		    COAP_MEDIATYPE_APPLICATION_LINK_FORMAT) == 1);
+  coap_add_option(resp, COAP_OPTION_CONTENT_FORMAT,
+		  coap_encode_var_bytes(buf, 
+			COAP_MEDIATYPE_APPLICATION_LINK_FORMAT), buf);
+
+  /* check if Block2 option is required even if not requested */
+  if (!need_block2 && (resp->max_size - (size_t)resp->length < wkc_len)) {
+    assert(resp->length <= resp->max_size);
+    const size_t payloadlen = resp->max_size - resp->length;
+    /* yes, need block-wise transfer */
+    block.num = 0;
+    block.m = 0;      /* the M bit is set by coap_write_block_opt() */
+    block.szx = COAP_MAX_BLOCK_SZX;
+    while (payloadlen < SZX_TO_BYTES(block.szx)) {
+      if (block.szx == 0) {
+	debug("coap_wellknown_response: message to small even for szx == 0\n");
+	goto error;
+      } else {
+	block.szx--;
+      }
+    }
+
+    need_block2 = 1;
+  }
+
+  /* write Block2 option if necessary */
+  if (need_block2) {
+    if (coap_write_block_opt(&block, COAP_OPTION_BLOCK2, resp, wkc_len) < 0) {
+      debug("coap_wellknown_response: cannot add Block2 option\n");
+      goto error;
+    }
+  }
+
+  /* Manually set payload of response to let print_wellknown() write,
+   * into our buffer without copying data. */
+
+  resp->data = (unsigned char *)resp->hdr + resp->length;
+  *resp->data = COAP_PAYLOAD_START;
+  resp->data++;
+  resp->length++;
+  len = need_block2 ? SZX_TO_BYTES(block.szx) : resp->max_size - resp->length;
+
+  result = coap_print_wellknown(context, resp->data, &len, offset, query_filter);
+  if ((result & COAP_PRINT_STATUS_ERROR) != 0) {
+    debug("coap_print_wellknown failed\n");
+    goto error;
+  } 
+  
+  resp->length += COAP_PRINT_OUTPUT_LENGTH(result);
+  return resp;
+
+ error:
+  /* set error code 5.03 and remove all options and data from response */
+  resp->hdr->code = COAP_RESPONSE_CODE(503);
+  resp->length = sizeof(coap_hdr_t) + resp->hdr->token_length;
+  return resp;
+}
+
+/**
+ * This function cancels outstanding messages for the remote peer and
+ * token specified in @p sent. Any observation relationship for
+ * sent->remote and the token are removed. Calling this function is
+ * required when receiving an RST message (usually in response to a
+ * notification) or a GET request with the Observe option set to 1.
+ *
+ * This function returns @c 0 when the token is unknown with this
+ * peer, or a value greater than zero otherwise.
+ */
+static int
+coap_cancel(coap_context_t *context, const coap_queue_t *sent) {
+#ifndef WITHOUT_OBSERVE
+  str token = { 0, NULL };
+  int num_cancelled = 0;    /* the number of observers cancelled */
+
+  /* remove observer for this resource, if any 
+   * get token from sent and try to find a matching resource. Uh!
+   */
+
+  COAP_SET_STR(&token, sent->pdu->hdr->token_length, sent->pdu->hdr->token);
+
+  RESOURCES_ITER(context->resources, r) {
+    num_cancelled += coap_delete_observer(r, &sent->remote, &token);
+    coap_cancel_all_messages(context, &sent->remote, token.s, token.length);
+  }
+
+  return num_cancelled;
+#else /* WITOUT_OBSERVE */  
+  return 0;
+#endif /* WITOUT_OBSERVE */  
+}
+
+/**
+ * Internal flags to control the treatment of responses (specifically
+ * in presence of the No-Response option).
+ */
+enum respond_t { RESPONSE_DEFAULT, RESPONSE_DROP, RESPONSE_SEND };
+
+/**
+ * Checks for No-Response option in given @p request and
+ * returns @c 1 if @p response should be suppressed
+ * according to RFC 7967.
+ * 
+ * The value of the No-Response option is encoded as
+ * follows:
+ *
+ *  +-------+-----------------------+-----------------------------------+
+ *  | Value | Binary Representation |          Description              |
+ *  +-------+-----------------------+-----------------------------------+
+ *  |   0   |      <empty>          | Interested in all responses.      |
+ *  +-------+-----------------------+-----------------------------------+
+ *  |   2   |      00000010         | Not interested in 2.xx responses. |
+ *  +-------+-----------------------+-----------------------------------+
+ *  |   8   |      00001000         | Not interested in 4.xx responses. |
+ *  +-------+-----------------------+-----------------------------------+
+ *  |  16   |      00010000         | Not interested in 5.xx responses. |
+ *  +-------+-----------------------+-----------------------------------+
+ *
+ * @param request  The CoAP request to check for the No-Response option.
+ *                 This parameter must not be NULL.
+ * @param response The response that is potentially suppressed.
+ *                 This parameter must not be NULL.
+ * @return RESPONSE_DEFAULT when no special treatment is requested,
+ *         RESPONSE_DROP    when the response must be discarded, or
+ *         RESPONSE_SEND    when the response must be sent.
+ */
+static enum respond_t
+no_response(coap_pdu_t *request, coap_pdu_t *response) {
+  coap_opt_t *nores;
+  coap_opt_iterator_t opt_iter;
+  uint8_t val = 0;
+
+  assert(request);
+  assert(response);
+
+  if (COAP_RESPONSE_CLASS(response->hdr->code) > 0) {
+    nores = coap_check_option(request, COAP_OPTION_NORESPONSE, &opt_iter);
+
+    if (nores) {
+      val = coap_decode_var_bytes(coap_opt_value(nores), coap_opt_length(nores));
+
+      /* The response should be dropped when the bit corresponding to
+       * the response class is set (cf. table in funtion
+       * documentation). When a No-Response option is present and the
+       * bit is not set, the sender explicitly indicates interest in
+       * this response. */
+      if (((1 << (COAP_RESPONSE_CLASS(response->hdr->code) - 1)) & val) > 0) {
+        return RESPONSE_DROP;
+      } else {
+        return RESPONSE_SEND;
+      }
+    }
+  }
+
+  /* Default behavior applies when we are not dealing with a response
+   * (class == 0) or the request did not contain a No-Response option.
+   */
+  return RESPONSE_DEFAULT;
+}
+
+#define WANT_WKC(Pdu,Key)					\
+  (((Pdu)->hdr->code == COAP_REQUEST_GET) && is_wkc(Key))
+
+static void
+handle_request(coap_context_t *context, coap_queue_t *node) {      
+  coap_method_handler_t h = NULL;
+  coap_pdu_t *response = NULL;
+  coap_opt_filter_t opt_filter;
+  coap_resource_t *resource;
+  coap_key_t key;
+  /* The respond field indicates whether a response must be treated
+   * specially due to a No-Response option that declares disinterest
+   * or interest in a specific response class. DEFAULT indicates that
+   * No-Response has not been specified. */
+  enum respond_t respond = RESPONSE_DEFAULT;
+
+  coap_option_filter_clear(opt_filter);
+  
+  /* try to find the resource from the request URI */
+  coap_hash_request_uri(node->pdu, key);
+  resource = coap_get_resource_from_key(context, key);
+  
+  if (!resource) {
+    /* The resource was not found. Check if the request URI happens to
+     * be the well-known URI. In that case, we generate a default
+     * response, otherwise, we return 4.04 */
+
+    if (is_wkc(key)) {	/* request for .well-known/core */
+      if (node->pdu->hdr->code == COAP_REQUEST_GET) { /* GET */
+	info("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN);
+	response = coap_wellknown_response(context, node->pdu);
+      } else {
+        debug("method not allowed for .well-known/core\n");
+	response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), 
+					   opt_filter);
+      }
+    } else { /* request for any another resource, return 4.04 */
+
+      debug("request for unknown resource 0x%02x%02x%02x%02x, return 4.04\n",
+            key[0], key[1], key[2], key[3]);
+      response =
+        coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(404),
+                                opt_filter);
+    }
+      
+    if (response
+        && (no_response(node->pdu, response) != RESPONSE_DROP)
+        && (coap_send(context, &node->local_if,
+                      &node->remote, response) == COAP_INVALID_TID)) {
+      warn("cannot send response for transaction %u\n", node->id);
+    }
+    coap_delete_pdu(response);
+    response = NULL;
+
+    return;
+  }
+  
+  /* the resource was found, check if there is a registered handler */
+  if ((size_t)node->pdu->hdr->code - 1 <
+      sizeof(resource->handler)/sizeof(coap_method_handler_t))
+    h = resource->handler[node->pdu->hdr->code - 1];
+  
+  if (h) {
+    debug("call custom handler for resource 0x%02x%02x%02x%02x\n", 
+	  key[0], key[1], key[2], key[3]);
+    response = coap_pdu_init(node->pdu->hdr->type == COAP_MESSAGE_CON 
+			     ? COAP_MESSAGE_ACK
+			     : COAP_MESSAGE_NON,
+			     0, node->pdu->hdr->id, COAP_MAX_PDU_SIZE);
+    
+    /* Implementation detail: coap_add_token() immediately returns 0
+       if response == NULL */
+    if (coap_add_token(response, node->pdu->hdr->token_length,
+		       node->pdu->hdr->token)) {
+      str token = { node->pdu->hdr->token_length, node->pdu->hdr->token };
+      coap_opt_iterator_t opt_iter;
+      coap_opt_t *observe = NULL;
+      int observe_action = COAP_OBSERVE_CANCEL;
+
+      /* check for Observe option */
+      if (resource->observable) {
+	observe = coap_check_option(node->pdu, COAP_OPTION_OBSERVE, &opt_iter);
+	if (observe) {
+	  observe_action =
+	    coap_decode_var_bytes(coap_opt_value(observe),
+				  coap_opt_length(observe));
+	 
+	  if ((observe_action & COAP_OBSERVE_CANCEL) == 0) {
+	    coap_subscription_t *subscription;
+
+	    coap_log(LOG_DEBUG, "create new subscription\n");
+	    subscription = coap_add_observer(resource, &node->local_if, 
+					     &node->remote, &token);
+	    if (subscription) {
+	      coap_touch_observer(context, &node->remote, &token);
+	    }
+	  } else {
+            coap_log(LOG_DEBUG, "removed observer\n");
+            coap_delete_observer(resource,  &node->remote, &token);
+          }
+	}
+      }
+
+      h(context, resource, &node->local_if, &node->remote,
+	node->pdu, &token, response);
+
+      respond = no_response(node->pdu, response);
+      if (respond != RESPONSE_DROP) {
+        if (observe && (COAP_RESPONSE_CLASS(response->hdr->code) > 2)) {
+          coap_log(LOG_DEBUG, "removed observer\n");
+          coap_delete_observer(resource,  &node->remote, &token);
+        }
+
+      /* If original request contained a token, and the registered
+       * application handler made no changes to the response, then
+       * this is an empty ACK with a token, which is a malformed
+       * PDU */
+      if ((response->hdr->type == COAP_MESSAGE_ACK)
+	  && (response->hdr->code == 0)) {
+	/* Remove token from otherwise-empty acknowledgment PDU */
+	response->hdr->token_length = 0;
+	response->length = sizeof(coap_hdr_t);
+      }
+
+      if ((respond == RESPONSE_SEND)
+          || /* RESPOND_DEFAULT */
+          (response->hdr->type != COAP_MESSAGE_NON ||
+           (response->hdr->code >= 64
+            && !coap_mcast_interface(&node->local_if)))) {
+
+	if (coap_send(context, &node->local_if, 
+		      &node->remote, response) == COAP_INVALID_TID) {
+	  debug("cannot send response for message %d\n", node->pdu->hdr->id);
+	  }
+      }
+      }
+      coap_delete_pdu(response);
+      response = NULL;
+    } else {
+      warn("cannot generate response\r\n");
+    }
+  } else {
+    if (WANT_WKC(node->pdu, key)) {
+      debug("create default response for %s\n", COAP_DEFAULT_URI_WELLKNOWN);
+      response = coap_wellknown_response(context, node->pdu);
+      debug("have wellknown response %p\n", (void *)response);
+    } else
+      response = coap_new_error_response(node->pdu, COAP_RESPONSE_CODE(405), 
+					 opt_filter);
+
+    if (response && (no_response(node->pdu, response) != RESPONSE_DROP)) {
+      if (coap_send(context, &node->local_if, &node->remote,
+                    response) == COAP_INVALID_TID) {
+        debug("cannot send response for transaction %u\n", node->id);
+      }
+    }
+    coap_delete_pdu(response);
+    response = NULL;
+  }
+
+  assert(response == NULL);
+}
+
+static inline void
+handle_response(coap_context_t *context, 
+		coap_queue_t *sent, coap_queue_t *rcvd) {
+
+  coap_send_ack(context, &rcvd->local_if, &rcvd->remote, rcvd->pdu);
+  
+  /* In a lossy context, the ACK of a separate response may have
+   * been lost, so we need to stop retransmitting requests with the
+   * same token.
+   */
+  coap_cancel_all_messages(context, &rcvd->remote,
+			   rcvd->pdu->hdr->token, 
+			   rcvd->pdu->hdr->token_length);
+
+  /* Call application-specific response handler when available. */
+  if (context->response_handler) {
+    context->response_handler(context, &rcvd->local_if,
+			      &rcvd->remote, sent ? sent->pdu : NULL, 
+			      rcvd->pdu, rcvd->id);
+  }
+}
+
+static inline int
+#ifdef __GNUC__
+handle_locally(coap_context_t *context __attribute__ ((unused)), 
+	       coap_queue_t *node __attribute__ ((unused))) {
+#else /* not a GCC */
+handle_locally(coap_context_t *context, coap_queue_t *node) {
+#endif /* GCC */
+  /* this function can be used to check if node->pdu is really for us */
+  return 1;
+}
+
+void
+coap_dispatch(coap_context_t *context, coap_queue_t *rcvd) {
+  coap_queue_t *sent = NULL;
+  coap_pdu_t *response;
+  coap_opt_filter_t opt_filter;
+
+  if (!context)
+    return;
+
+  memset(opt_filter, 0, sizeof(coap_opt_filter_t));
+
+  {
+    /* version has been checked in coap_handle_message() */
+    /* if ( rcvd->pdu->hdr->version != COAP_DEFAULT_VERSION ) { */
+    /*   debug("dropped packet with unknown version %u\n", rcvd->pdu->hdr->version); */
+    /*   goto cleanup; */
+    /* } */
+    
+    switch (rcvd->pdu->hdr->type) {
+    case COAP_MESSAGE_ACK:
+      /* find transaction in sendqueue to stop retransmission */
+      coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
+
+      if (rcvd->pdu->hdr->code == 0)
+	goto cleanup;
+
+      /* if sent code was >= 64 the message might have been a 
+       * notification. Then, we must flag the observer to be alive
+       * by setting obs->fail_cnt = 0. */
+      if (sent && COAP_RESPONSE_CLASS(sent->pdu->hdr->code) == 2) {
+	const str token = 
+	  { sent->pdu->hdr->token_length, sent->pdu->hdr->token };
+	coap_touch_observer(context, &sent->remote, &token);
+      }
+      break;
+
+    case COAP_MESSAGE_RST :
+      /* We have sent something the receiver disliked, so we remove
+       * not only the transaction but also the subscriptions we might
+       * have. */
+
+#ifndef WITH_CONTIKI
+      coap_log(LOG_ALERT, "got RST for message %u\n", ntohs(rcvd->pdu->hdr->id));
+#else /* WITH_CONTIKI */
+      coap_log(LOG_ALERT, "got RST for message %u\n", uip_ntohs(rcvd->pdu->hdr->id));
+#endif /* WITH_CONTIKI */
+
+      /* find transaction in sendqueue to stop retransmission */
+      coap_remove_from_queue(&context->sendqueue, rcvd->id, &sent);
+
+      if (sent)
+	coap_cancel(context, sent);
+      goto cleanup;
+
+    case COAP_MESSAGE_NON :	/* check for unknown critical options */
+      if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0)
+	goto cleanup;
+      break;
+
+    case COAP_MESSAGE_CON :	/* check for unknown critical options */
+      if (coap_option_check_critical(context, rcvd->pdu, opt_filter) == 0) {
+
+	/* FIXME: send response only if we have received a request. Otherwise, 
+	 * send RST. */
+	response = 
+	  coap_new_error_response(rcvd->pdu, COAP_RESPONSE_CODE(402), opt_filter);
+
+	if (!response)
+	  warn("coap_dispatch: cannot create error response\n");
+	else {
+	  if (coap_send(context, &rcvd->local_if, &rcvd->remote, response) 
+	      == COAP_INVALID_TID) {
+	    warn("coap_dispatch: error sending response\n");
+	  }
+          coap_delete_pdu(response);
+	}	 
+	
+	goto cleanup;
+      }
+    default: break;
+    }
+   
+    /* Pass message to upper layer if a specific handler was
+     * registered for a request that should be handled locally. */
+    if (handle_locally(context, rcvd)) {
+      if (COAP_MESSAGE_IS_REQUEST(rcvd->pdu->hdr))
+	handle_request(context, rcvd);
+      else if (COAP_MESSAGE_IS_RESPONSE(rcvd->pdu->hdr))
+	handle_response(context, sent, rcvd);
+      else {
+	debug("dropped message with invalid code (%d.%02d)\n", 
+	      COAP_RESPONSE_CLASS(rcvd->pdu->hdr->code),
+	      rcvd->pdu->hdr->code & 0x1f);
+
+	if (!coap_is_mcast(&rcvd->local_if.addr)) {
+	  coap_send_message_type(context, &rcvd->local_if, &rcvd->remote,
+				 rcvd->pdu, COAP_MESSAGE_RST);
+	}
+      }
+    }
+    
+  cleanup:
+    coap_delete_node(sent);
+    coap_delete_node(rcvd);
+  }
+}
+
+int
+coap_can_exit( coap_context_t *context ) {
+  return !context || (context->sendqueue == NULL);
+}
+
+#ifdef WITH_CONTIKI
+
+/*---------------------------------------------------------------------------*/
+/* CoAP message retransmission */
+/*---------------------------------------------------------------------------*/
+PROCESS_THREAD(coap_retransmit_process, ev, data)
+{
+  coap_tick_t now;
+  coap_queue_t *nextpdu;
+
+  PROCESS_BEGIN();
+
+  debug("Started retransmit process\r\n");
+
+  while(1) {
+    PROCESS_YIELD();
+    if (ev == PROCESS_EVENT_TIMER) {
+      if (etimer_expired(&the_coap_context.retransmit_timer)) {
+	
+	nextpdu = coap_peek_next(&the_coap_context);
+	
+	coap_ticks(&now);
+	while (nextpdu && nextpdu->t <= now) {
+	  coap_retransmit(&the_coap_context, coap_pop_next(&the_coap_context));
+	  nextpdu = coap_peek_next(&the_coap_context);
+	}
+
+	/* need to set timer to some value even if no nextpdu is available */
+	etimer_set(&the_coap_context.retransmit_timer, 
+		   nextpdu ? nextpdu->t - now : 0xFFFF);
+      } 
+#ifndef WITHOUT_OBSERVE
+      if (etimer_expired(&the_coap_context.notify_timer)) {
+	coap_check_notify(&the_coap_context);
+	etimer_reset(&the_coap_context.notify_timer);
+      }
+#endif /* WITHOUT_OBSERVE */
+    }
+  }
+  
+  PROCESS_END();
+}
+/*---------------------------------------------------------------------------*/
+
+#endif /* WITH_CONTIKI */
+
+#ifdef WITH_LWIP
+/* FIXME: retransmits that are not required any more due to incoming packages
+ * do *not* get cleared at the moment, the wakeup when the transmission is due
+ * is silently accepted. this is mainly due to the fact that the required
+ * checks are similar in two places in the code (when receiving ACK and RST)
+ * and that they cause more than one patch chunk, as it must be first checked
+ * whether the sendqueue item to be dropped is the next one pending, and later
+ * the restart function has to be called. nothing insurmountable, but it can
+ * also be implemented when things have stabilized, and the performance
+ * penality is minimal
+ *
+ * also, this completely ignores COAP_RESOURCE_CHECK_TIME.
+ * */
+
+static void coap_retransmittimer_execute(void *arg)
+{
+	coap_context_t *ctx = (coap_context_t*)arg;
+	coap_tick_t now;
+	coap_tick_t elapsed;
+	coap_queue_t *nextinqueue;
+
+	ctx->timer_configured = 0;
+
+	coap_ticks(&now);
+
+	elapsed = now - ctx->sendqueue_basetime; /* that's positive for sure, and unless we haven't been called for a complete wrapping cycle, did not wrap */
+
+	nextinqueue = coap_peek_next(ctx);
+	while (nextinqueue != NULL)
+	{
+		if (nextinqueue->t > elapsed) {
+			nextinqueue->t -= elapsed;
+			break;
+		} else {
+			elapsed -= nextinqueue->t;
+			coap_retransmit(ctx, coap_pop_next(ctx));
+			nextinqueue = coap_peek_next(ctx);
+		}
+	}
+
+	ctx->sendqueue_basetime = now;
+
+	coap_retransmittimer_restart(ctx);
+}
+
+static void coap_retransmittimer_restart(coap_context_t *ctx)
+{
+	coap_tick_t now, elapsed, delay;
+
+	if (ctx->timer_configured)
+	{
+		printf("clearing\n");
+		sys_untimeout(coap_retransmittimer_execute, (void*)ctx);
+		ctx->timer_configured = 0;
+	}
+	if (ctx->sendqueue != NULL)
+	{
+		coap_ticks(&now);
+		elapsed = now - ctx->sendqueue_basetime;
+		if (ctx->sendqueue->t >= elapsed) {
+			delay = ctx->sendqueue->t - elapsed;
+		} else {
+			/* a strange situation, but not completely impossible.
+			 *
+			 * this happens, for example, right after
+			 * coap_retransmittimer_execute, when a retransmission
+			 * was *just not yet* due, and the clock ticked before
+			 * our coap_ticks was called.
+			 *
+			 * not trying to retransmit anything now, as it might
+			 * cause uncontrollable recursion; let's just try again
+			 * with the next main loop run.
+			 * */
+			delay = 0;
+		}
+
+		printf("scheduling for %d ticks\n", delay);
+		sys_timeout(delay, coap_retransmittimer_execute, (void*)ctx);
+		ctx->timer_configured = 1;
+	}
+}
+#endif
diff --git a/components/coap/libcoap/src/option.c b/components/coap/libcoap/src/option.c
new file mode 100644
index 00000000..60c0788d
--- /dev/null
+++ b/components/coap/libcoap/src/option.c
@@ -0,0 +1,523 @@
+/*
+ * option.c -- helpers for handling options in CoAP PDUs
+ *
+ * Copyright (C) 2010-2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+
+#include "coap_config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "option.h"
+#include "encode.h"		/* for coap_fls() */
+#include "debug.h"
+
+coap_opt_t *
+options_start(coap_pdu_t *pdu) {
+
+  if (pdu && pdu->hdr && 
+      (pdu->hdr->token + pdu->hdr->token_length 
+       < (unsigned char *)pdu->hdr + pdu->length)) {
+
+    coap_opt_t *opt = pdu->hdr->token + pdu->hdr->token_length;
+    return (*opt == COAP_PAYLOAD_START) ? NULL : opt;
+  
+  } else 
+    return NULL;
+}
+
+size_t
+coap_opt_parse(const coap_opt_t *opt, size_t length, coap_option_t *result) {
+
+  const coap_opt_t *opt_start = opt; /* store where parsing starts  */
+
+  assert(opt); assert(result);
+
+#define ADVANCE_OPT(o,e,step) if ((e) < step) {			\
+    debug("cannot advance opt past end\n");			\
+    return 0;							\
+  } else {							\
+    (e) -= step;						\
+    (o) = ((unsigned char *)(o)) + step;			\
+  }
+
+  if (length < 1)
+    return 0;
+
+  result->delta = (*opt & 0xf0) >> 4;
+  result->length = *opt & 0x0f;
+
+  switch(result->delta) {
+  case 15:
+    if (*opt != COAP_PAYLOAD_START) {
+      debug("ignored reserved option delta 15\n");
+    }
+    return 0;
+  case 14:
+    /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
+     * After that, the option pointer is advanced to the LSB which is handled
+     * just like case delta == 13. */
+    ADVANCE_OPT(opt,length,1);
+    result->delta = ((*opt & 0xff) << 8) + 269;
+    if (result->delta < 269) {
+      debug("delta too large\n");
+      return 0;
+    }
+    /* fall through */
+  case 13:
+    ADVANCE_OPT(opt,length,1);
+    result->delta += *opt & 0xff;
+    break;
+    
+  default:
+    ;
+  }
+
+  switch(result->length) {
+  case 15:
+    debug("found reserved option length 15\n");
+    return 0;
+  case 14:
+    /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
+     * After that, the option pointer is advanced to the LSB which is handled
+     * just like case delta == 13. */
+    ADVANCE_OPT(opt,length,1);
+    result->length = ((*opt & 0xff) << 8) + 269;
+    /* fall through */
+  case 13:
+    ADVANCE_OPT(opt,length,1);
+    result->length += *opt & 0xff;
+    break;
+    
+  default:
+    ;
+  }
+
+  ADVANCE_OPT(opt,length,1);
+  /* opt now points to value, if present */
+
+  result->value = (unsigned char *)opt;
+  if (length < result->length) {
+    debug("invalid option length\n");
+    return 0;
+  }
+
+#undef ADVANCE_OPT
+
+  return (opt + result->length) - opt_start;
+}
+
+coap_opt_iterator_t *
+coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi,
+			  const coap_opt_filter_t filter) {
+  assert(pdu); 
+  assert(pdu->hdr);
+  assert(oi);
+  
+  memset(oi, 0, sizeof(coap_opt_iterator_t));
+
+  oi->next_option = (unsigned char *)pdu->hdr + sizeof(coap_hdr_t)
+    + pdu->hdr->token_length;
+  if ((unsigned char *)pdu->hdr + pdu->length <= oi->next_option) {
+    oi->bad = 1;
+    return NULL;
+  }
+
+  assert((sizeof(coap_hdr_t) + pdu->hdr->token_length) <= pdu->length);
+
+  oi->length = pdu->length - (sizeof(coap_hdr_t) + pdu->hdr->token_length);
+
+  if (filter) {
+    memcpy(oi->filter, filter, sizeof(coap_opt_filter_t));
+    oi->filtered = 1;
+  }
+  return oi;
+}
+
+static inline int
+opt_finished(coap_opt_iterator_t *oi) {
+  assert(oi);
+
+  if (oi->bad || oi->length == 0 || 
+      !oi->next_option || *oi->next_option == COAP_PAYLOAD_START) {
+    oi->bad = 1;
+  }
+
+  return oi->bad;
+}
+
+coap_opt_t *
+coap_option_next(coap_opt_iterator_t *oi) {
+  coap_option_t option;
+  coap_opt_t *current_opt = NULL;
+  size_t optsize;
+  int b;		   /* to store result of coap_option_getb() */
+
+  assert(oi);
+
+  if (opt_finished(oi))
+    return NULL;
+
+  while (1) {
+    /* oi->option always points to the next option to deliver; as
+     * opt_finished() filters out any bad conditions, we can assume that
+     * oi->option is valid. */
+    current_opt = oi->next_option;
+    
+    /* Advance internal pointer to next option, skipping any option that
+     * is not included in oi->filter. */
+    optsize = coap_opt_parse(oi->next_option, oi->length, &option);
+    if (optsize) {
+      assert(optsize <= oi->length);
+      
+      oi->next_option += optsize;
+      oi->length -= optsize;
+      
+      oi->type += option.delta;
+    } else {			/* current option is malformed */
+      oi->bad = 1;
+      return NULL;
+    }
+
+    /* Exit the while loop when:
+     *   - no filtering is done at all
+     *   - the filter matches for the current option
+     *   - the filter is too small for the current option number 
+     */
+    if (!oi->filtered ||
+	(b = coap_option_getb(oi->filter, oi->type)) > 0)
+      break;
+    else if (b < 0) {		/* filter too small, cannot proceed */
+      oi->bad = 1;
+      return NULL;
+    }
+  }
+
+  return current_opt;
+}
+
+coap_opt_t *
+coap_check_option(coap_pdu_t *pdu, unsigned short type, 
+		  coap_opt_iterator_t *oi) {
+  coap_opt_filter_t f;
+  
+  coap_option_filter_clear(f);
+  coap_option_setb(f, type);
+
+  coap_option_iterator_init(pdu, oi, f);
+
+  return coap_option_next(oi);
+}
+
+unsigned short
+coap_opt_delta(const coap_opt_t *opt) {
+  unsigned short n;
+
+  n = (*opt++ & 0xf0) >> 4;
+
+  switch (n) {
+  case 15: /* error */
+    warn("coap_opt_delta: illegal option delta\n");
+
+    /* This case usually should not happen, hence we do not have a
+     * proper way to indicate an error. */
+    return 0;
+  case 14: 
+    /* Handle two-byte value: First, the MSB + 269 is stored as delta value.
+     * After that, the option pointer is advanced to the LSB which is handled
+     * just like case delta == 13. */
+    n = ((*opt++ & 0xff) << 8) + 269;
+    /* fall through */
+  case 13:
+    n += *opt & 0xff;
+    break;
+  default: /* n already contains the actual delta value */
+    ;
+  }
+
+  return n;
+}
+
+unsigned short
+coap_opt_length(const coap_opt_t *opt) {
+  unsigned short length;
+
+  length = *opt & 0x0f;
+  switch (*opt & 0xf0) {
+  case 0xf0:
+    debug("illegal option delta\n");
+    return 0;
+  case 0xe0:
+    ++opt;
+    /* fall through to skip another byte */
+  case 0xd0:
+    ++opt;
+    /* fall through to skip another byte */
+  default:
+    ++opt;
+  }
+
+  switch (length) {
+  case 0x0f:
+    debug("illegal option length\n");
+    return 0;
+  case 0x0e:
+    length = (*opt++ << 8) + 269;
+    /* fall through */
+  case 0x0d:
+    length += *opt++;
+    break;
+  default:
+    ;
+  }
+  return length;
+}
+
+unsigned char *
+coap_opt_value(coap_opt_t *opt) {
+  size_t ofs = 1;
+
+  switch (*opt & 0xf0) {
+  case 0xf0:
+    debug("illegal option delta\n");
+    return 0;
+  case 0xe0:
+    ++ofs;
+    /* fall through */
+  case 0xd0:
+    ++ofs;
+    break;
+  default:
+    ;
+  }
+
+  switch (*opt & 0x0f) {
+  case 0x0f:
+    debug("illegal option length\n");
+    return 0;
+  case 0x0e:
+    ++ofs;
+    /* fall through */
+  case 0x0d:
+    ++ofs;
+    break;
+  default:
+    ;
+  }
+
+  return (unsigned char *)opt + ofs;
+}
+
+size_t
+coap_opt_size(const coap_opt_t *opt) {
+  coap_option_t option;
+
+  /* we must assume that opt is encoded correctly */
+  return coap_opt_parse(opt, (size_t)-1, &option);
+}
+
+size_t
+coap_opt_setheader(coap_opt_t *opt, size_t maxlen, 
+		   unsigned short delta, size_t length) {
+  size_t skip = 0;
+
+  assert(opt);
+
+  if (maxlen == 0)		/* need at least one byte */
+    return 0;
+
+  if (delta < 13) {
+    opt[0] = delta << 4;
+  } else if (delta < 270) {
+    if (maxlen < 2) {
+      debug("insufficient space to encode option delta %d\n", delta);
+      return 0;
+    }
+
+    opt[0] = 0xd0;
+    opt[++skip] = delta - 13;
+  } else {
+    if (maxlen < 3) {
+      debug("insufficient space to encode option delta %d\n", delta);
+      return 0;
+    }
+
+    opt[0] = 0xe0;
+    opt[++skip] = ((delta - 269) >> 8) & 0xff;
+    opt[++skip] = (delta - 269) & 0xff;    
+  }
+    
+  if (length < 13) {
+    opt[0] |= length & 0x0f;
+  } else if (length < 270) {
+    if (maxlen < skip + 2) {
+      debug("insufficient space to encode option length %zu\n", length);
+      return 0;
+    }
+    
+    opt[0] |= 0x0d;
+    opt[++skip] = length - 13;
+  } else {
+    if (maxlen < skip + 3) {
+      debug("insufficient space to encode option delta %d\n", delta);
+      return 0;
+    }
+
+    opt[0] |= 0x0e;
+    opt[++skip] = ((length - 269) >> 8) & 0xff;
+    opt[++skip] = (length - 269) & 0xff;    
+  }
+
+  return skip + 1;
+}
+
+size_t
+coap_opt_encode(coap_opt_t *opt, size_t maxlen, unsigned short delta,
+		const unsigned char *val, size_t length) {
+  size_t l = 1;
+
+  l = coap_opt_setheader(opt, maxlen, delta, length);
+  assert(l <= maxlen);
+  
+  if (!l) {
+    debug("coap_opt_encode: cannot set option header\n");
+    return 0;
+  }
+  
+  maxlen -= l;
+  opt += l;
+
+  if (maxlen < length) {
+    debug("coap_opt_encode: option too large for buffer\n");
+    return 0;
+  }
+
+  if (val)			/* better be safe here */
+    memcpy(opt, val, length);
+
+  return l + length;
+}
+
+/* coap_opt_filter_t has the following internal structure: */
+typedef struct {
+  uint16_t mask;
+
+#define LONG_MASK ((1 << COAP_OPT_FILTER_LONG) - 1)
+#define SHORT_MASK \
+  (~LONG_MASK & ((1 << (COAP_OPT_FILTER_LONG + COAP_OPT_FILTER_SHORT)) - 1))
+
+  uint16_t long_opts[COAP_OPT_FILTER_LONG];
+  uint8_t short_opts[COAP_OPT_FILTER_SHORT];
+} opt_filter;
+
+/** Returns true iff @p type denotes an option type larger than 255. */
+static inline int
+is_long_option(unsigned short type) { return type > 255; }
+
+/** Operation specifiers for coap_filter_op(). */
+enum filter_op_t { FILTER_SET, FILTER_CLEAR, FILTER_GET };
+
+/**
+ * Applies @p op on @p filter with respect to @p type. The following
+ * operations are defined:
+ *
+ * FILTER_SET: Store @p type into an empty slot in @p filter. Returns
+ * @c 1 on success, or @c 0 if no spare slot was available.
+ *
+ * FILTER_CLEAR: Remove @p type from filter if it exists.
+ *
+ * FILTER_GET: Search for @p type in @p filter. Returns @c 1 if found,
+ * or @c 0 if not found.
+ *
+ * @param filter The filter object.
+ * @param type   The option type to set, get or clear in @p filter.
+ * @param op     The operation to apply to @p filter and @p type.
+ *
+ * @return 1 on success, and 0 when FILTER_GET yields no
+ * hit or no free slot is available to store @p type with FILTER_SET.
+ */
+static int
+coap_option_filter_op(coap_opt_filter_t filter,
+		      unsigned short type,
+		      enum filter_op_t op) {
+  size_t index = 0;
+  opt_filter *of = (opt_filter *)filter;
+  uint16_t nr, mask = 0;
+
+  if (is_long_option(type)) {
+    mask = LONG_MASK;
+
+    for (nr = 1; index < COAP_OPT_FILTER_LONG; nr <<= 1, index++) {
+
+      if (((of->mask & nr) > 0) && (of->long_opts[index] == type)) {
+	if (op == FILTER_CLEAR) {
+	  of->mask &= ~nr;
+	}
+
+	return 1;
+      }
+    }
+  } else {
+    mask = SHORT_MASK;
+
+    for (nr = 1 << COAP_OPT_FILTER_LONG; index < COAP_OPT_FILTER_SHORT;
+	 nr <<= 1, index++) {
+
+      if (((of->mask & nr) > 0) && (of->short_opts[index] == (type & 0xff))) {
+	if (op == FILTER_CLEAR) {
+	  of->mask &= ~nr;
+	}
+
+	return 1;
+      }
+    }
+  }
+
+  /* type was not found, so there is nothing to do if op is CLEAR or GET */
+  if ((op == FILTER_CLEAR) || (op == FILTER_GET)) {
+    return 0;
+  }
+
+  /* handle FILTER_SET: */
+
+  index = coap_fls(~of->mask & mask);
+  if (!index) {
+    return 0;
+  }
+
+  if (is_long_option(type)) {
+    of->long_opts[index - 1] = type;
+  } else {
+    of->short_opts[index - COAP_OPT_FILTER_LONG - 1] = type;
+  }
+
+  of->mask |= 1 << (index - 1);
+
+  return 1;
+}
+
+int
+coap_option_filter_set(coap_opt_filter_t filter, unsigned short type) {
+  return coap_option_filter_op(filter, type, FILTER_SET);
+}
+
+int
+coap_option_filter_unset(coap_opt_filter_t filter, unsigned short type) {
+  return coap_option_filter_op(filter, type, FILTER_CLEAR);
+}
+
+int
+coap_option_filter_get(const coap_opt_filter_t filter, unsigned short type) {
+  /* Ugly cast to make the const go away (FILTER_GET wont change filter
+   * but as _set and _unset do, the function does not take a const). */
+  return coap_option_filter_op((uint16_t *)filter, type, FILTER_GET);
+}
diff --git a/components/coap/libcoap/src/pdu.c b/components/coap/libcoap/src/pdu.c
new file mode 100644
index 00000000..ff73d6ab
--- /dev/null
+++ b/components/coap/libcoap/src/pdu.c
@@ -0,0 +1,433 @@
+/* pdu.c -- CoAP message structure
+ *
+ * Copyright (C) 2010--2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "debug.h"
+#include "pdu.h"
+#include "option.h"
+#include "encode.h"
+#include "mem.h"
+
+void
+coap_pdu_clear(coap_pdu_t *pdu, size_t size) {
+  assert(pdu);
+
+#ifdef WITH_LWIP
+  /* the pdu itself is not wiped as opposed to the other implementations,
+   * because we have to rely on the pbuf to be set there. */
+  pdu->hdr = pdu->pbuf->payload;
+#else
+  pdu->max_delta = 0;
+  pdu->data = NULL;
+#endif
+  memset(pdu->hdr, 0, size);
+  pdu->max_size = size;
+  pdu->hdr->version = COAP_DEFAULT_VERSION;
+
+  /* data is NULL unless explicitly set by coap_add_data() */
+  pdu->length = sizeof(coap_hdr_t);
+}
+
+#ifdef WITH_LWIP
+coap_pdu_t *
+coap_pdu_from_pbuf(struct pbuf *pbuf)
+{
+  if (pbuf == NULL) return NULL;
+
+  LWIP_ASSERT("Can only deal with contiguous PBUFs", pbuf->tot_len == pbuf->len);
+  LWIP_ASSERT("coap_read needs to receive an exclusive copy of the incoming pbuf", pbuf->ref == 1);
+
+  coap_pdu_t *result = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
+  if (!result) {
+	  pbuf_free(pbuf);
+	  return NULL;
+  }
+
+  memset(result, 0, sizeof(coap_pdu_t));
+
+  result->max_size = pbuf->tot_len;
+  result->length = pbuf->tot_len;
+  result->hdr = pbuf->payload;
+  result->pbuf = pbuf;
+
+  return result;
+}
+#endif
+
+coap_pdu_t *
+coap_pdu_init(unsigned char type, unsigned char code, 
+	      unsigned short id, size_t size) {
+  coap_pdu_t *pdu;
+#ifdef WITH_LWIP
+    struct pbuf *p;
+#endif
+
+  assert(size <= COAP_MAX_PDU_SIZE);
+  /* Size must be large enough to fit the header. */
+  if (size < sizeof(coap_hdr_t) || size > COAP_MAX_PDU_SIZE)
+    return NULL;
+
+  /* size must be large enough for hdr */
+#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
+  pdu = coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
+  if (!pdu) return NULL;
+  pdu->hdr = coap_malloc_type(COAP_PDU_BUF, size);
+  if (pdu->hdr == NULL) {
+    coap_free_type(COAP_PDU, pdu);
+    pdu = NULL;
+  }
+#endif /* WITH_POSIX or WITH_CONTIKI */
+#ifdef WITH_LWIP
+  pdu = (coap_pdu_t*)coap_malloc_type(COAP_PDU, sizeof(coap_pdu_t));
+  if (!pdu) return NULL;
+  p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);
+  if (p == NULL) {
+    coap_free_type(COAP_PDU, pdu);
+    pdu = NULL;
+  }
+#endif
+  if (pdu) {
+#ifdef WITH_LWIP
+    pdu->pbuf = p;
+#endif
+    coap_pdu_clear(pdu, size);
+    pdu->hdr->id = id;
+    pdu->hdr->type = type;
+    pdu->hdr->code = code;
+  } 
+  return pdu;
+}
+
+coap_pdu_t *
+coap_new_pdu(void) {
+  coap_pdu_t *pdu;
+  
+#ifndef WITH_CONTIKI
+  pdu = coap_pdu_init(0, 0, ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+#else /* WITH_CONTIKI */
+  pdu = coap_pdu_init(0, 0, uip_ntohs(COAP_INVALID_TID), COAP_MAX_PDU_SIZE);
+#endif /* WITH_CONTIKI */
+
+#ifndef NDEBUG
+  if (!pdu)
+    coap_log(LOG_CRIT, "coap_new_pdu: cannot allocate memory for new PDU\n");
+#endif
+  return pdu;
+}
+
+void
+coap_delete_pdu(coap_pdu_t *pdu) {
+#if defined(WITH_POSIX) || defined(WITH_CONTIKI)
+  if (pdu != NULL) {
+    if (pdu->hdr != NULL) {
+      coap_free_type(COAP_PDU_BUF, pdu->hdr);
+    }
+    coap_free_type(COAP_PDU, pdu);
+  }
+#endif
+#ifdef WITH_LWIP
+  if (pdu != NULL) /* accepting double free as the other implementation accept that too */
+    pbuf_free(pdu->pbuf);
+  coap_free_type(COAP_PDU, pdu);
+#endif
+}
+
+int
+coap_add_token(coap_pdu_t *pdu, size_t len, const unsigned char *data) {
+  const size_t HEADERLENGTH = len + 4;
+  /* must allow for pdu == NULL as callers may rely on this */
+  if (!pdu || len > 8 || pdu->max_size < HEADERLENGTH)
+    return 0;
+
+  pdu->hdr->token_length = len;
+  if (len)
+    memcpy(pdu->hdr->token, data, len);
+  pdu->max_delta = 0;
+  pdu->length = HEADERLENGTH;
+  pdu->data = NULL;
+
+  return 1;
+}
+
+/** @FIXME de-duplicate code with coap_add_option_later */
+size_t
+coap_add_option(coap_pdu_t *pdu, unsigned short type, unsigned int len, const unsigned char *data) {
+  size_t optsize;
+  coap_opt_t *opt;
+  
+  assert(pdu);
+  pdu->data = NULL;
+
+  if (type < pdu->max_delta) {
+    warn("coap_add_option: options are not in correct order\n");
+    return 0;
+  }
+
+  opt = (unsigned char *)pdu->hdr + pdu->length;
+
+  /* encode option and check length */
+  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length, 
+			    type - pdu->max_delta, data, len);
+
+  if (!optsize) {
+    warn("coap_add_option: cannot add option\n");
+    /* error */
+    return 0;
+  } else {
+    pdu->max_delta = type;
+    pdu->length += optsize;
+  }
+
+  return optsize;
+}
+
+/** @FIXME de-duplicate code with coap_add_option */
+unsigned char*
+coap_add_option_later(coap_pdu_t *pdu, unsigned short type, unsigned int len) {
+  size_t optsize;
+  coap_opt_t *opt;
+
+  assert(pdu);
+  pdu->data = NULL;
+
+  if (type < pdu->max_delta) {
+    warn("coap_add_option: options are not in correct order\n");
+    return NULL;
+  }
+
+  opt = (unsigned char *)pdu->hdr + pdu->length;
+
+  /* encode option and check length */
+  optsize = coap_opt_encode(opt, pdu->max_size - pdu->length,
+			    type - pdu->max_delta, NULL, len);
+
+  if (!optsize) {
+    warn("coap_add_option: cannot add option\n");
+    /* error */
+    return NULL;
+  } else {
+    pdu->max_delta = type;
+    pdu->length += optsize;
+  }
+
+  return ((unsigned char*)opt) + optsize - len;
+}
+
+int
+coap_add_data(coap_pdu_t *pdu, unsigned int len, const unsigned char *data) {
+  assert(pdu);
+  assert(pdu->data == NULL);
+
+  if (len == 0)
+    return 1;
+
+  if (pdu->length + len + 1 > pdu->max_size) {
+    warn("coap_add_data: cannot add: data too large for PDU\n");
+    assert(pdu->data == NULL);
+    return 0;
+  }
+
+  pdu->data = (unsigned char *)pdu->hdr + pdu->length;
+  *pdu->data = COAP_PAYLOAD_START;
+  pdu->data++;
+
+  memcpy(pdu->data, data, len);
+  pdu->length += len + 1;
+  return 1;
+}
+
+int
+coap_get_data(coap_pdu_t *pdu, size_t *len, unsigned char **data) {
+  assert(pdu);
+  assert(len);
+  assert(data);
+
+  if (pdu->data) {
+    *len = (unsigned char *)pdu->hdr + pdu->length - pdu->data;
+    *data = pdu->data;
+  } else {			/* no data, clear everything */
+    *len = 0;
+    *data = NULL;
+  }
+
+  return *data != NULL;
+}
+
+#ifndef SHORT_ERROR_RESPONSE
+typedef struct {
+  unsigned char code;
+  char *phrase;
+} error_desc_t;
+
+/* if you change anything here, make sure, that the longest string does not 
+ * exceed COAP_ERROR_PHRASE_LENGTH. */
+error_desc_t coap_error[] = {
+  { COAP_RESPONSE_CODE(201), "Created" },
+  { COAP_RESPONSE_CODE(202), "Deleted" },
+  { COAP_RESPONSE_CODE(203), "Valid" },
+  { COAP_RESPONSE_CODE(204), "Changed" },
+  { COAP_RESPONSE_CODE(205), "Content" },
+  { COAP_RESPONSE_CODE(231), "Continue" },
+  { COAP_RESPONSE_CODE(400), "Bad Request" },
+  { COAP_RESPONSE_CODE(401), "Unauthorized" },
+  { COAP_RESPONSE_CODE(402), "Bad Option" },
+  { COAP_RESPONSE_CODE(403), "Forbidden" },
+  { COAP_RESPONSE_CODE(404), "Not Found" },
+  { COAP_RESPONSE_CODE(405), "Method Not Allowed" },
+  { COAP_RESPONSE_CODE(406), "Not Acceptable" },
+  { COAP_RESPONSE_CODE(408), "Request Entity Incomplete" },
+  { COAP_RESPONSE_CODE(412), "Precondition Failed" },
+  { COAP_RESPONSE_CODE(413), "Request Entity Too Large" },
+  { COAP_RESPONSE_CODE(415), "Unsupported Content-Format" },
+  { COAP_RESPONSE_CODE(500), "Internal Server Error" },
+  { COAP_RESPONSE_CODE(501), "Not Implemented" },
+  { COAP_RESPONSE_CODE(502), "Bad Gateway" },
+  { COAP_RESPONSE_CODE(503), "Service Unavailable" },
+  { COAP_RESPONSE_CODE(504), "Gateway Timeout" },
+  { COAP_RESPONSE_CODE(505), "Proxying Not Supported" },
+  { 0, NULL }			/* end marker */
+};
+
+char *
+coap_response_phrase(unsigned char code) {
+  int i;
+  for (i = 0; coap_error[i].code; ++i) {
+    if (coap_error[i].code == code)
+      return coap_error[i].phrase;
+  }
+  return NULL;
+}
+#endif
+
+/**
+ * Advances *optp to next option if still in PDU. This function 
+ * returns the number of bytes opt has been advanced or @c 0
+ * on error.
+ */
+static size_t
+next_option_safe(coap_opt_t **optp, size_t *length) {
+  coap_option_t option;
+  size_t optsize;
+
+  assert(optp); assert(*optp); 
+  assert(length);
+
+  optsize = coap_opt_parse(*optp, *length, &option);
+  if (optsize) {
+    assert(optsize <= *length);
+
+    *optp += optsize;
+    *length -= optsize;
+  }
+
+  return optsize;
+}
+
+int
+coap_pdu_parse(unsigned char *data, size_t length, coap_pdu_t *pdu) {
+  coap_opt_t *opt;
+
+  assert(data);
+  assert(pdu);
+
+  if (pdu->max_size < length) {
+    debug("insufficient space to store parsed PDU\n");
+    return 0;
+  }
+
+  if (length < sizeof(coap_hdr_t)) {
+    debug("discarded invalid PDU\n");
+  }
+
+#ifdef WITH_LWIP
+  /* this verifies that with the classical copy-at-parse-time and lwip's
+   * zerocopy-into-place approaches, both share the same idea of destination
+   * addresses */
+  LWIP_ASSERT("coap_pdu_parse with unexpected addresses", data == (void*)pdu->hdr);
+  LWIP_ASSERT("coap_pdu_parse with unexpected length", length == pdu->length);
+#else
+
+  pdu->hdr->version = data[0] >> 6;
+  pdu->hdr->type = (data[0] >> 4) & 0x03;
+  pdu->hdr->token_length = data[0] & 0x0f;
+  pdu->hdr->code = data[1];
+#endif
+  pdu->data = NULL;
+
+  /* sanity checks */
+  if (pdu->hdr->code == 0) {
+    if (length != sizeof(coap_hdr_t) || pdu->hdr->token_length) {
+      debug("coap_pdu_parse: empty message is not empty\n");
+      goto discard;
+    }
+  }
+
+  if (length < sizeof(coap_hdr_t) + pdu->hdr->token_length
+      || pdu->hdr->token_length > 8) {
+    debug("coap_pdu_parse: invalid Token\n");
+    goto discard;
+  }
+
+#ifndef WITH_LWIP
+  /* Copy message id in network byte order, so we can easily write the
+   * response back to the network. */
+  memcpy(&pdu->hdr->id, data + 2, 2);
+
+  /* Append data (including the Token) to pdu structure, if any. */
+  if (length > sizeof(coap_hdr_t)) {
+    memcpy(pdu->hdr + 1, data + sizeof(coap_hdr_t), length - sizeof(coap_hdr_t));
+  }
+  pdu->length = length;
+ 
+  /* Finally calculate beginning of data block and thereby check integrity
+   * of the PDU structure. */
+#endif
+
+  /* skip header + token */
+  length -= (pdu->hdr->token_length + sizeof(coap_hdr_t));
+  opt = (unsigned char *)(pdu->hdr + 1) + pdu->hdr->token_length;
+
+  while (length && *opt != COAP_PAYLOAD_START) {
+    if (!next_option_safe(&opt, (size_t *)&length)) {
+      debug("coap_pdu_parse: drop\n");
+      goto discard;
+    }
+  }
+
+  /* end of packet or start marker */
+  if (length) {
+    assert(*opt == COAP_PAYLOAD_START);
+    opt++; length--;
+
+    if (!length) {
+      debug("coap_pdu_parse: message ending in payload start marker\n");
+      goto discard;
+    }
+
+    debug("set data to %p (pdu ends at %p)\n", (unsigned char *)opt, 
+	  (unsigned char *)pdu->hdr + pdu->length);
+    pdu->data = (unsigned char *)opt;
+  }
+
+  return 1;
+
+ discard:
+  return 0;
+}
diff --git a/components/coap/libcoap/src/resource.c b/components/coap/libcoap/src/resource.c
new file mode 100644
index 00000000..61ab87ca
--- /dev/null
+++ b/components/coap/libcoap/src/resource.c
@@ -0,0 +1,756 @@
+/* resource.c -- generic resource handling
+ *
+ * Copyright (C) 2010--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include "coap.h"
+#include "debug.h"
+#include "mem.h"
+#include "net.h"
+#include "resource.h"
+#include "subscribe.h"
+#include "utlist.h"
+
+#ifdef WITH_LWIP
+/* mem.h is only needed for the string free calls for
+ * COAP_ATTR_FLAGS_RELEASE_NAME / COAP_ATTR_FLAGS_RELEASE_VALUE /
+ * COAP_RESOURCE_FLAGS_RELEASE_URI. not sure what those lines should actually
+ * do on lwip. */
+
+#include <lwip/memp.h>
+
+#define COAP_MALLOC_TYPE(Type) \
+  ((coap_##Type##_t *)memp_malloc(MEMP_COAP_##Type))
+#define COAP_FREE_TYPE(Type, Object) memp_free(MEMP_COAP_##Type, Object)
+
+#endif
+
+#ifdef WITH_POSIX
+
+#define COAP_MALLOC_TYPE(Type) \
+  ((coap_##Type##_t *)coap_malloc(sizeof(coap_##Type##_t)))
+#define COAP_FREE_TYPE(Type, Object) coap_free(Object)
+
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+#include "memb.h"
+
+#define COAP_MALLOC_TYPE(Type) \
+  ((coap_##Type##_t *)memb_alloc(&(Type##_storage)))
+#define COAP_FREE_TYPE(Type, Object) memb_free(&(Type##_storage), (Object))
+
+MEMB(subscription_storage, coap_subscription_t, COAP_MAX_SUBSCRIBERS);
+
+void
+coap_resources_init() {
+  memb_init(&subscription_storage);
+}
+
+static inline coap_subscription_t *
+coap_malloc_subscription() {
+  return memb_alloc(&subscription_storage);
+}
+
+static inline void
+coap_free_subscription(coap_subscription_t *subscription) {
+  memb_free(&subscription_storage, subscription);
+}
+
+#endif /* WITH_CONTIKI */
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/* Helper functions for conditional output of character sequences into
+ * a given buffer. The first Offset characters are skipped.
+ */
+
+/**
+ * Adds Char to Buf if Offset is zero. Otherwise, Char is not written
+ * and Offset is decremented.
+ */
+#define PRINT_WITH_OFFSET(Buf,Offset,Char)		\
+  if ((Offset) == 0) {					\
+    (*(Buf)++) = (Char);				\
+  } else {						\
+    (Offset)--;						\
+  }							\
+
+/**
+ * Adds Char to Buf if Offset is zero and Buf is less than Bufend.
+ */
+#define PRINT_COND_WITH_OFFSET(Buf,Bufend,Offset,Char,Result) {		\
+    if ((Buf) < (Bufend)) {						\
+      PRINT_WITH_OFFSET(Buf,Offset,Char);				\
+    }									\
+    (Result)++;								\
+  }
+
+/**
+ * Copies at most Length characters of Str to Buf. The first Offset
+ * characters are skipped. Output may be truncated to Bufend - Buf
+ * characters.
+ */
+#define COPY_COND_WITH_OFFSET(Buf,Bufend,Offset,Str,Length,Result) {	\
+    size_t i;								\
+    for (i = 0; i < (Length); i++) {					\
+      PRINT_COND_WITH_OFFSET((Buf), (Bufend), (Offset), (Str)[i], (Result)); \
+    }									\
+  }
+ 
+static int
+match(const str *text, const str *pattern, int match_prefix, int match_substring) {
+  assert(text); assert(pattern);
+  
+  if (text->length < pattern->length)
+    return 0;
+
+  if (match_substring) {
+    unsigned char *next_token = text->s;
+    size_t remaining_length = text->length;
+    while (remaining_length) {
+      size_t token_length;
+      unsigned char *token = next_token;
+      next_token = memchr(token, ' ', remaining_length);
+
+      if (next_token) {
+        token_length = next_token - token;
+        remaining_length -= (token_length + 1);
+        next_token++;
+      } else {
+        token_length = remaining_length;
+        remaining_length = 0;
+      }
+      
+      if ((match_prefix || pattern->length == token_length) &&
+            memcmp(token, pattern->s, pattern->length) == 0)
+        return 1;
+    }
+    return 0;
+  }
+
+  return (match_prefix || pattern->length == text->length) &&
+    memcmp(text->s, pattern->s, pattern->length) == 0;
+}
+
+/** 
+ * Prints the names of all known resources to @p buf. This function
+ * sets @p buflen to the number of bytes actually written and returns
+ * @c 1 on succes. On error, the value in @p buflen is undefined and
+ * the return value will be @c 0.
+ * 
+ * @param context The context with the resource map.
+ * @param buf     The buffer to write the result.
+ * @param buflen  Must be initialized to the maximum length of @p buf and will be
+ *                set to the length of the well-known response on return.
+ * @param offset  The offset in bytes where the output shall start and is
+ *                shifted accordingly with the characters that have been
+ *                processed. This parameter is used to support the block 
+ *                option. 
+ * @param query_filter A filter query according to <a href="http://tools.ietf.org/html/draft-ietf-core-link-format-11#section-4.1">Link Format</a>
+ * 
+ * @return COAP_PRINT_STATUS_ERROR on error. Otherwise, the lower 28 bits are
+ *         set to the number of bytes that have actually been written to
+ *         @p buf. COAP_PRINT_STATUS_TRUNC is set when the output has been
+ *         truncated.
+ */
+#if defined(__GNUC__) && defined(WITHOUT_QUERY_FILTER)
+coap_print_status_t
+coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen,
+		size_t offset,
+		coap_opt_t *query_filter __attribute__ ((unused))) {
+#else /* not a GCC */
+coap_print_status_t
+coap_print_wellknown(coap_context_t *context, unsigned char *buf, size_t *buflen,
+		size_t offset, coap_opt_t *query_filter) {
+#endif /* GCC */
+  unsigned char *p = buf;
+  const unsigned char *bufend = buf + *buflen;
+  size_t left, written = 0;
+  coap_print_status_t result;
+  const size_t old_offset = offset;
+  int subsequent_resource = 0;
+#ifndef WITHOUT_QUERY_FILTER
+  str resource_param = { 0, NULL }, query_pattern = { 0, NULL };
+  int flags = 0; /* MATCH_SUBSTRING, MATCH_PREFIX, MATCH_URI */
+#define MATCH_URI       0x01
+#define MATCH_PREFIX    0x02
+#define MATCH_SUBSTRING 0x04
+  static const str _rt_attributes[] = {
+    {2, (unsigned char *)"rt"},
+    {2, (unsigned char *)"if"},
+    {3, (unsigned char *)"rel"},
+    {0, NULL}};
+#endif /* WITHOUT_QUERY_FILTER */
+
+#ifndef WITHOUT_QUERY_FILTER
+  /* split query filter, if any */
+  if (query_filter) {
+    resource_param.s = COAP_OPT_VALUE(query_filter);
+    while (resource_param.length < COAP_OPT_LENGTH(query_filter)
+	   && resource_param.s[resource_param.length] != '=')
+      resource_param.length++;
+    
+    if (resource_param.length < COAP_OPT_LENGTH(query_filter)) {
+      const str *rt_attributes;
+      if (resource_param.length == 4 && 
+	  memcmp(resource_param.s, "href", 4) == 0)
+	flags |= MATCH_URI;
+
+      for (rt_attributes = _rt_attributes; rt_attributes->s; rt_attributes++) {
+        if (resource_param.length == rt_attributes->length && 
+            memcmp(resource_param.s, rt_attributes->s, rt_attributes->length) == 0) {
+          flags |= MATCH_SUBSTRING;
+          break;
+        }
+      }
+
+      /* rest is query-pattern */
+      query_pattern.s = 
+	COAP_OPT_VALUE(query_filter) + resource_param.length + 1;
+
+      assert((resource_param.length + 1) <= COAP_OPT_LENGTH(query_filter));
+      query_pattern.length = 
+	COAP_OPT_LENGTH(query_filter) - (resource_param.length + 1);
+
+     if ((query_pattern.s[0] == '/') && ((flags & MATCH_URI) == MATCH_URI)) {
+       query_pattern.s++;
+       query_pattern.length--;
+      }
+
+      if (query_pattern.length && 
+	  query_pattern.s[query_pattern.length-1] == '*') {
+	query_pattern.length--;
+	flags |= MATCH_PREFIX;
+      }      
+    }
+  }
+#endif /* WITHOUT_QUERY_FILTER */
+
+  RESOURCES_ITER(context->resources, r) {
+
+#ifndef WITHOUT_QUERY_FILTER
+    if (resource_param.length) { /* there is a query filter */
+      
+      if (flags & MATCH_URI) {	/* match resource URI */
+	if (!match(&r->uri, &query_pattern, (flags & MATCH_PREFIX) != 0, (flags & MATCH_SUBSTRING) != 0))
+	  continue;
+      } else {			/* match attribute */
+	coap_attr_t *attr;
+        str unquoted_val;
+	attr = coap_find_attr(r, resource_param.s, resource_param.length);
+        if (!attr) continue;
+        if (attr->value.s[0] == '"') {          /* if attribute has a quoted value, remove double quotes */
+          unquoted_val.length = attr->value.length - 2;
+          unquoted_val.s = attr->value.s + 1;
+        } else {
+          unquoted_val = attr->value;
+        }
+	if (!(match(&unquoted_val, &query_pattern, 
+                    (flags & MATCH_PREFIX) != 0,
+                    (flags & MATCH_SUBSTRING) != 0)))
+	  continue;
+      }
+    }
+#endif /* WITHOUT_QUERY_FILTER */
+
+    if (!subsequent_resource) {	/* this is the first resource  */
+      subsequent_resource = 1;
+    } else {
+      PRINT_COND_WITH_OFFSET(p, bufend, offset, ',', written);
+    }
+
+    left = bufend - p; /* calculate available space */
+    result = coap_print_link(r, p, &left, &offset);
+
+    if (result & COAP_PRINT_STATUS_ERROR) {
+      break;
+    }
+
+    /* coap_print_link() returns the number of characters that
+     * where actually written to p. Now advance to its end. */
+    p += COAP_PRINT_OUTPUT_LENGTH(result);
+    written += left;
+  }
+
+  *buflen = written;
+  result = p - buf;
+  if (result + old_offset - offset < *buflen) {
+    result |= COAP_PRINT_STATUS_TRUNC;
+  }
+  return result;
+}
+
+coap_resource_t *
+coap_resource_init(const unsigned char *uri, size_t len, int flags) {
+  coap_resource_t *r;
+
+#ifdef WITH_LWIP
+  r = (coap_resource_t *)memp_malloc(MEMP_COAP_RESOURCE);
+#endif
+#ifndef WITH_LWIP
+  r = (coap_resource_t *)coap_malloc_type(COAP_RESOURCE, sizeof(coap_resource_t));
+#endif
+  if (r) {
+    memset(r, 0, sizeof(coap_resource_t));
+
+    r->uri.s = (unsigned char *)uri;
+    r->uri.length = len;
+    
+    coap_hash_path(r->uri.s, r->uri.length, r->key);
+
+    r->flags = flags;
+  } else {
+    debug("coap_resource_init: no memory left\n");
+  }
+  
+  return r;
+}
+
+coap_attr_t *
+coap_add_attr(coap_resource_t *resource, 
+	      const unsigned char *name, size_t nlen,
+	      const unsigned char *val, size_t vlen,
+              int flags) {
+  coap_attr_t *attr;
+
+  if (!resource || !name)
+    return NULL;
+
+#ifdef WITH_LWIP
+  attr = (coap_attr_t *)memp_malloc(MEMP_COAP_RESOURCEATTR);
+#endif
+#ifndef WITH_LWIP
+  attr = (coap_attr_t *)coap_malloc_type(COAP_RESOURCEATTR, sizeof(coap_attr_t));
+#endif
+
+  if (attr) {
+    attr->name.length = nlen;
+    attr->value.length = val ? vlen : 0;
+
+    attr->name.s = (unsigned char *)name;
+    attr->value.s = (unsigned char *)val;
+
+    attr->flags = flags;
+
+    /* add attribute to resource list */
+    LL_PREPEND(resource->link_attr, attr);
+  } else {
+    debug("coap_add_attr: no memory left\n");
+  }
+  
+  return attr;
+}
+
+coap_attr_t *
+coap_find_attr(coap_resource_t *resource, 
+	       const unsigned char *name, size_t nlen) {
+  coap_attr_t *attr;
+
+  if (!resource || !name)
+    return NULL;
+
+  LL_FOREACH(resource->link_attr, attr) {
+    if (attr->name.length == nlen &&
+	memcmp(attr->name.s, name, nlen) == 0)
+      return attr;
+  }
+
+  return NULL;
+}
+
+void
+coap_delete_attr(coap_attr_t *attr) {
+  if (!attr)
+    return;
+  if (attr->flags & COAP_ATTR_FLAGS_RELEASE_NAME)
+    coap_free(attr->name.s);
+  if (attr->flags & COAP_ATTR_FLAGS_RELEASE_VALUE)
+    coap_free(attr->value.s);
+
+#ifdef WITH_LWIP
+  memp_free(MEMP_COAP_RESOURCEATTR, attr);
+#endif
+#ifndef WITH_LWIP
+  coap_free_type(COAP_RESOURCEATTR, attr);
+#endif
+}
+
+void
+coap_hash_request_uri(const coap_pdu_t *request, coap_key_t key) {
+  coap_opt_iterator_t opt_iter;
+  coap_opt_filter_t filter;
+  coap_opt_t *option;
+
+  memset(key, 0, sizeof(coap_key_t));
+
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, COAP_OPTION_URI_PATH);
+
+  coap_option_iterator_init((coap_pdu_t *)request, &opt_iter, filter);
+  while ((option = coap_option_next(&opt_iter)))
+    coap_hash(COAP_OPT_VALUE(option), COAP_OPT_LENGTH(option), key);
+}
+
+void
+coap_add_resource(coap_context_t *context, coap_resource_t *resource) {
+  RESOURCES_ADD(context->resources, resource);
+}
+
+static void
+coap_free_resource(coap_resource_t *resource) {
+  coap_attr_t *attr, *tmp;
+  coap_subscription_t *obs, *otmp;
+
+  assert(resource);
+
+  /* delete registered attributes */
+  LL_FOREACH_SAFE(resource->link_attr, attr, tmp) coap_delete_attr(attr);
+
+  if (resource->flags & COAP_RESOURCE_FLAGS_RELEASE_URI)
+    coap_free(resource->uri.s);
+
+  /* free all elements from resource->subscribers */
+  LL_FOREACH_SAFE(resource->subscribers, obs, otmp) COAP_FREE_TYPE(subscription, obs);
+
+#ifdef WITH_LWIP
+  memp_free(MEMP_COAP_RESOURCE, resource);
+#endif
+#ifndef WITH_LWIP
+  coap_free_type(COAP_RESOURCE, resource);
+#endif /* WITH_CONTIKI */
+}
+ 
+int
+coap_delete_resource(coap_context_t *context, coap_key_t key) {
+  coap_resource_t *resource;
+
+  if (!context)
+    return 0;
+
+  resource = coap_get_resource_from_key(context, key);
+
+  if (!resource) 
+    return 0;
+
+  /* remove resource from list */
+  RESOURCES_DELETE(context->resources, resource);
+
+  /* and free its allocated memory */
+  coap_free_resource(resource);
+
+  return 1;
+}
+
+void
+coap_delete_all_resources(coap_context_t *context) {
+  coap_resource_t *res;
+  coap_resource_t *rtmp;
+
+  /* Cannot call RESOURCES_ITER because coap_free_resource() releases
+   * the allocated storage. */
+
+#ifdef COAP_RESOURCES_NOHASH
+  LL_FOREACH_SAFE(context->resources, res, rtmp) {
+#else
+  HASH_ITER(hh, context->resources, res, rtmp) {
+    HASH_DELETE(hh, context->resources, res);
+#endif
+    coap_free_resource(res);
+  }
+
+  context->resources = NULL;
+}
+
+coap_resource_t *
+coap_get_resource_from_key(coap_context_t *context, coap_key_t key) {
+  coap_resource_t *result;
+
+  RESOURCES_FIND(context->resources, key, result);
+
+  return result;
+}
+
+coap_print_status_t
+coap_print_link(const coap_resource_t *resource, 
+		unsigned char *buf, size_t *len, size_t *offset) {
+  unsigned char *p = buf;
+  const unsigned char *bufend = buf + *len;
+  coap_attr_t *attr;
+  coap_print_status_t result = 0;
+  const size_t old_offset = *offset;
+  
+  *len = 0;
+  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '<', *len);
+  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '/', *len);
+
+  COPY_COND_WITH_OFFSET(p, bufend, *offset, 
+			resource->uri.s, resource->uri.length, *len);
+  
+  PRINT_COND_WITH_OFFSET(p, bufend, *offset, '>', *len);
+
+  LL_FOREACH(resource->link_attr, attr) {
+
+    PRINT_COND_WITH_OFFSET(p, bufend, *offset, ';', *len);
+
+    COPY_COND_WITH_OFFSET(p, bufend, *offset,
+			  attr->name.s, attr->name.length, *len);
+
+    if (attr->value.s) {
+      PRINT_COND_WITH_OFFSET(p, bufend, *offset, '=', *len);
+
+      COPY_COND_WITH_OFFSET(p, bufend, *offset,
+			    attr->value.s, attr->value.length, *len);
+    }
+
+  }
+  if (resource->observable) {
+    COPY_COND_WITH_OFFSET(p, bufend, *offset, ";obs", 4, *len);
+  }
+
+  result = p - buf;
+  if (result + old_offset - *offset < *len) {
+    result |= COAP_PRINT_STATUS_TRUNC;
+  }
+
+  return result;
+}
+
+#ifndef WITHOUT_OBSERVE
+coap_subscription_t *
+coap_find_observer(coap_resource_t *resource, const coap_address_t *peer,
+		     const str *token) {
+  coap_subscription_t *s;
+
+  assert(resource);
+  assert(peer);
+
+  LL_FOREACH(resource->subscribers, s) {
+    if (coap_address_equals(&s->subscriber, peer)
+	&& (!token || (token->length == s->token_length 
+		       && memcmp(token->s, s->token, token->length) == 0)))
+      return s;
+  }
+  
+  return NULL;
+}
+
+coap_subscription_t *
+coap_add_observer(coap_resource_t *resource, 
+		  const coap_endpoint_t *local_interface,
+		  const coap_address_t *observer,
+		  const str *token) {
+  coap_subscription_t *s;
+  
+  assert(observer);
+
+  /* Check if there is already a subscription for this peer. */
+  s = coap_find_observer(resource, observer, token);
+
+  /* We are done if subscription was found. */
+  if (s)
+    return s;
+
+  /* s points to a different subscription, so we have to create
+   * another one. */
+  s = COAP_MALLOC_TYPE(subscription);
+
+  if (!s)
+    return NULL;
+
+  coap_subscription_init(s);
+  s->local_if = *local_interface;
+  memcpy(&s->subscriber, observer, sizeof(coap_address_t));
+  
+  if (token && token->length) {
+    s->token_length = token->length;
+    memcpy(s->token, token->s, min(s->token_length, 8));
+  }
+
+  /* add subscriber to resource */
+  LL_PREPEND(resource->subscribers, s);
+
+  return s;
+}
+
+void
+coap_touch_observer(coap_context_t *context, const coap_address_t *observer,
+		    const str *token) {
+  coap_subscription_t *s;
+
+  RESOURCES_ITER(context->resources, r) {
+    s = coap_find_observer(r, observer, token);
+    if (s) {
+      s->fail_cnt = 0;
+    }
+  }
+}
+
+int
+coap_delete_observer(coap_resource_t *resource, const coap_address_t *observer,
+		     const str *token) {
+  coap_subscription_t *s;
+
+  s = coap_find_observer(resource, observer, token);
+
+  if (resource->subscribers && s) {
+    LL_DELETE(resource->subscribers, s);
+
+    COAP_FREE_TYPE(subscription,s);
+  }
+
+  return s != NULL;
+}
+
+static void
+coap_notify_observers(coap_context_t *context, coap_resource_t *r) {
+  coap_method_handler_t h;
+  coap_subscription_t *obs;
+  str token;
+  coap_pdu_t *response;
+
+  if (r->observable && (r->dirty || r->partiallydirty)) {
+    r->partiallydirty = 0;
+
+    /* retrieve GET handler, prepare response */
+    h = r->handler[COAP_REQUEST_GET - 1];
+    assert(h);		/* we do not allow subscriptions if no
+			 * GET handler is defined */
+
+    LL_FOREACH(r->subscribers, obs) {
+      if (r->dirty == 0 && obs->dirty == 0)
+        /* running this resource due to partiallydirty, but this observation's notification was already enqueued */
+        continue;
+
+      coap_tid_t tid = COAP_INVALID_TID;
+      obs->dirty = 0;
+      /* initialize response */
+      response = coap_pdu_init(COAP_MESSAGE_CON, 0, 0, COAP_MAX_PDU_SIZE);
+      if (!response) {
+        obs->dirty = 1;
+        r->partiallydirty = 1;
+	debug("coap_check_notify: pdu init failed, resource stays partially dirty\n");
+	continue;
+      }
+
+      if (!coap_add_token(response, obs->token_length, obs->token)) {
+        obs->dirty = 1;
+        r->partiallydirty = 1;
+	debug("coap_check_notify: cannot add token, resource stays partially dirty\n");
+	coap_delete_pdu(response);
+	continue;
+      }
+
+      token.length = obs->token_length;
+      token.s = obs->token;
+
+      response->hdr->id = coap_new_message_id(context);
+      if ((r->flags & COAP_RESOURCE_FLAGS_NOTIFY_CON) == 0
+	  && obs->non_cnt < COAP_OBS_MAX_NON) {
+	response->hdr->type = COAP_MESSAGE_NON;
+      } else {
+	response->hdr->type = COAP_MESSAGE_CON;
+      }
+      /* fill with observer-specific data */
+      h(context, r, &obs->local_if, &obs->subscriber, NULL, &token, response);
+
+      /* TODO: do not send response and remove observer when 
+       *  COAP_RESPONSE_CLASS(response->hdr->code) > 2
+       */
+      if (response->hdr->type == COAP_MESSAGE_CON) {
+	tid = coap_send_confirmed(context, &obs->local_if, &obs->subscriber, response);
+	obs->non_cnt = 0;
+      } else {
+	tid = coap_send(context, &obs->local_if, &obs->subscriber, response);
+	obs->non_cnt++;
+      }
+
+      if (COAP_INVALID_TID == tid || response->hdr->type != COAP_MESSAGE_CON)
+	coap_delete_pdu(response);
+      if (COAP_INVALID_TID == tid)
+      {
+	debug("coap_check_notify: sending failed, resource stays partially dirty\n");
+        obs->dirty = 1;
+        r->partiallydirty = 1;
+      }
+
+    }
+
+    /* Increment value for next Observe use. */
+    context->observe++;
+  }
+  r->dirty = 0;
+}
+
+void
+coap_check_notify(coap_context_t *context) {
+
+  RESOURCES_ITER(context->resources, r) {
+    coap_notify_observers(context, r);
+  }
+}
+
+/**
+ * Checks the failure counter for (peer, token) and removes peer from
+ * the list of observers for the given resource when COAP_OBS_MAX_FAIL
+ * is reached.
+ *
+ * @param context  The CoAP context to use
+ * @param resource The resource to check for (peer, token)
+ * @param peer     The observer's address
+ * @param token    The token that has been used for subscription.
+ */
+static void
+coap_remove_failed_observers(coap_context_t *context,
+			     coap_resource_t *resource,
+			     const coap_address_t *peer,
+			     const str *token) {
+  coap_subscription_t *obs, *otmp;
+
+  LL_FOREACH_SAFE(resource->subscribers, obs, otmp) {
+    if (coap_address_equals(peer, &obs->subscriber) &&
+	token->length == obs->token_length &&
+	memcmp(token->s, obs->token, token->length) == 0) {
+      
+      /* count failed notifies and remove when
+       * COAP_MAX_FAILED_NOTIFY is reached */
+      if (obs->fail_cnt < COAP_OBS_MAX_FAIL)
+	obs->fail_cnt++;
+      else {
+	LL_DELETE(resource->subscribers, obs);
+	obs->fail_cnt = 0;
+	
+#ifndef NDEBUG
+	if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+	  unsigned char addr[INET6_ADDRSTRLEN+8];
+
+	  if (coap_print_addr(&obs->subscriber, addr, INET6_ADDRSTRLEN+8))
+	    debug("** removed observer %s\n", addr);
+	}
+#endif
+	coap_cancel_all_messages(context, &obs->subscriber, 
+				 obs->token, obs->token_length);
+
+	COAP_FREE_TYPE(subscription, obs);
+      }
+    }
+    break;			/* break loop if observer was found */
+  }
+}
+
+void
+coap_handle_failed_notify(coap_context_t *context, 
+			  const coap_address_t *peer, 
+			  const str *token) {
+
+  RESOURCES_ITER(context->resources, r) {
+	coap_remove_failed_observers(context, r, peer, token);
+  }
+}
+#endif /* WITHOUT_NOTIFY */
diff --git a/components/coap/libcoap/src/str.c b/components/coap/libcoap/src/str.c
new file mode 100644
index 00000000..f5800c25
--- /dev/null
+++ b/components/coap/libcoap/src/str.c
@@ -0,0 +1,34 @@
+/* str.c -- strings to be used in the CoAP library
+ *
+ * Copyright (C) 2010,2011 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#include <stdio.h>
+
+#include "debug.h"
+#include "mem.h"
+#include "str.h"
+
+str *coap_new_string(size_t size) {
+  str *s = coap_malloc(sizeof(str) + size + 1);
+  if ( !s ) {
+#ifndef NDEBUG
+    coap_log(LOG_CRIT, "coap_new_string: malloc\n");
+#endif
+    return NULL;
+  }
+
+  memset(s, 0, sizeof(str));
+  s->s = ((unsigned char *)s) + sizeof(str);
+  return s;
+}
+
+void coap_delete_string(str *s) {
+  coap_free(s);
+}
+
diff --git a/components/coap/libcoap/src/subscribe.c b/components/coap/libcoap/src/subscribe.c
new file mode 100644
index 00000000..860b8daf
--- /dev/null
+++ b/components/coap/libcoap/src/subscribe.c
@@ -0,0 +1,23 @@
+/* subscribe.c -- subscription handling for CoAP
+ *                see draft-ietf-coap-observe-16
+ *
+ * Copyright (C) 2010--2013,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include "coap.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include "subscribe.h"
+
+void
+coap_subscription_init(coap_subscription_t *s) {
+  assert(s);
+  memset(s, 0, sizeof(coap_subscription_t));
+}
diff --git a/components/coap/libcoap/src/uri.c b/components/coap/libcoap/src/uri.c
new file mode 100644
index 00000000..73732b8b
--- /dev/null
+++ b/components/coap/libcoap/src/uri.c
@@ -0,0 +1,492 @@
+/* uri.c -- helper functions for URI treatment
+ *
+ * Copyright (C) 2010--2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+
+#if defined(HAVE_ASSERT_H) && !defined(assert)
+# include <assert.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "mem.h"
+#include "debug.h"
+#include "pdu.h"
+#include "option.h"
+#include "uri.h"
+
+/** 
+ * A length-safe version of strchr(). This function returns a pointer
+ * to the first occurrence of @p c  in @p s, or @c NULL if not found.
+ * 
+ * @param s   The string to search for @p c.
+ * @param len The length of @p s.
+ * @param c   The character to search.
+ * 
+ * @return A pointer to the first occurence of @p c, or @c NULL 
+ * if not found.
+ */
+static inline unsigned char *
+strnchr(unsigned char *s, size_t len, unsigned char c) {
+  while (len && *s++ != c)
+    --len;
+  
+  return len ? s : NULL;
+}
+
+#define ISEQUAL_CI(a,b) \
+  ((a) == (b) || (islower(b) && ((a) == ((b) - 0x20))))
+
+int
+coap_split_uri(const unsigned char *str_var, size_t len, coap_uri_t *uri) {
+  const unsigned char *p, *q;
+  int secure = 0, res = 0;
+
+  if (!str_var || !uri)
+    return -1;
+
+  memset(uri, 0, sizeof(coap_uri_t));
+  uri->port = COAP_DEFAULT_PORT;
+
+  /* search for scheme */
+  p = str_var;
+  if (*p == '/') {
+    q = p;
+    goto path;
+  }
+
+  q = (unsigned char *)COAP_DEFAULT_SCHEME;
+  while (len && *q && ISEQUAL_CI(*p, *q)) {
+    ++p; ++q; --len;
+  }
+  
+  /* If q does not point to the string end marker '\0', the schema
+   * identifier is wrong. */
+  if (*q) {
+    res = -1;
+    goto error;
+  }
+
+  /* There might be an additional 's', indicating the secure version: */
+  if (len && (secure = *p == 's')) {
+    ++p; --len;
+  }
+
+  q = (unsigned char *)"://";
+  while (len && *q && *p == *q) {
+    ++p; ++q; --len;
+  }
+
+  if (*q) {
+    res = -2;
+    goto error;
+  }
+
+  /* p points to beginning of Uri-Host */
+  q = p;
+  if (len && *p == '[') {	/* IPv6 address reference */
+    ++p;
+    
+    while (len && *q != ']') {
+      ++q; --len;
+    }
+
+    if (!len || *q != ']' || p == q) {
+      res = -3;
+      goto error;
+    } 
+
+    COAP_SET_STR(&uri->host, q - p, (unsigned char *)p);
+    ++q; --len;
+  } else {			/* IPv4 address or FQDN */
+    while (len && *q != ':' && *q != '/' && *q != '?') {
+      ++q;
+      --len;
+    }
+
+    if (p == q) {
+      res = -3;
+      goto error;
+    }
+
+    COAP_SET_STR(&uri->host, q - p, (unsigned char *)p);
+  }
+
+  /* check for Uri-Port */
+  if (len && *q == ':') {
+    p = ++q;
+    --len;
+    
+    while (len && isdigit(*q)) {
+      ++q;
+      --len;
+    }
+
+    if (p < q) {		/* explicit port number given */
+      int uri_port = 0;
+    
+      while (p < q)
+	uri_port = uri_port * 10 + (*p++ - '0');
+
+      /* check if port number is in allowed range */
+      if (uri_port > 65535) {
+	res = -4;
+	goto error;
+      }
+
+      uri->port = uri_port;
+    } 
+  }
+  
+ path:		 /* at this point, p must point to an absolute path */
+
+  if (!len)
+    goto end;
+  
+  if (*q == '/') {
+    p = ++q;
+    --len;
+
+    while (len && *q != '?') {
+      ++q;
+      --len;
+    }
+  
+    if (p < q) {
+      COAP_SET_STR(&uri->path, q - p, (unsigned char *)p);
+      p = q;
+    }
+  }
+
+  /* Uri_Query */
+  if (len && *p == '?') {
+    ++p;
+    --len;
+    COAP_SET_STR(&uri->query, len, (unsigned char *)p);
+    len = 0;
+  }
+
+  end:
+  return len ? -1 : 0;
+  
+  error:
+  return res;
+}
+
+/** 
+ * Calculates decimal value from hexadecimal ASCII character given in
+ * @p c. The caller must ensure that @p c actually represents a valid
+ * heaxdecimal character, e.g. with isxdigit(3). 
+ *
+ * @hideinitializer
+ */
+#define hexchar_to_dec(c) ((c) & 0x40 ? ((c) & 0x0F) + 9 : ((c) & 0x0F))
+
+/** 
+ * Decodes percent-encoded characters while copying the string @p seg
+ * of size @p length to @p buf. The caller of this function must
+ * ensure that the percent-encodings are correct (i.e. the character
+ * '%' is always followed by two hex digits. and that @p buf provides
+ * sufficient space to hold the result. This function is supposed to
+ * be called by make_decoded_option() only.
+ * 
+ * @param seg     The segment to decode and copy.
+ * @param length  Length of @p seg.
+ * @param buf     The result buffer.
+ */
+static void
+decode_segment(const unsigned char *seg, size_t length, unsigned char *buf) {
+
+  while (length--) {
+
+    if (*seg == '%') {
+      *buf = (hexchar_to_dec(seg[1]) << 4) + hexchar_to_dec(seg[2]);
+      
+      seg += 2; length -= 2;
+    } else {
+      *buf = *seg;
+    }
+    
+    ++buf; ++seg;
+  }
+}
+
+/**
+ * Runs through the given path (or query) segment and checks if
+ * percent-encodings are correct. This function returns @c -1 on error
+ * or the length of @p s when decoded.
+ */
+static int
+check_segment(const unsigned char *s, size_t length) {
+
+  size_t n = 0;
+
+  while (length) {
+    if (*s == '%') {
+      if (length < 2 || !(isxdigit(s[1]) && isxdigit(s[2])))
+	return -1;
+      
+      s += 2;
+      length -= 2;
+    }
+
+    ++s; ++n; --length;
+  }
+  
+  return n;
+}
+	 
+/** 
+ * Writes a coap option from given string @p s to @p buf. @p s should
+ * point to a (percent-encoded) path or query segment of a coap_uri_t
+ * object.  The created option will have type @c 0, and the length
+ * parameter will be set according to the size of the decoded string.
+ * On success, this function returns the option's size, or a value
+ * less than zero on error. This function must be called from
+ * coap_split_path_impl() only.
+ * 
+ * @param s       The string to decode.
+ * @param length  The size of the percent-encoded string @p s.
+ * @param buf     The buffer to store the new coap option.
+ * @param buflen  The maximum size of @p buf.
+ * 
+ * @return The option's size, or @c -1 on error.
+ *
+ * @bug This function does not split segments that are bigger than 270
+ * bytes.
+ */
+static int
+make_decoded_option(const unsigned char *s, size_t length, 
+		    unsigned char *buf, size_t buflen) {
+  int res;
+  size_t written;
+
+  if (!buflen) {
+    debug("make_decoded_option(): buflen is 0!\n");
+    return -1;
+  }
+
+  res = check_segment(s, length);
+  if (res < 0)
+    return -1;
+
+  /* write option header using delta 0 and length res */
+  written = coap_opt_setheader(buf, buflen, 0, res);
+
+  assert(written <= buflen);
+
+  if (!written)			/* encoding error */
+    return -1;
+
+  buf += written;		/* advance past option type/length */
+  buflen -= written;
+
+  if (buflen < (size_t)res) {
+    debug("buffer too small for option\n");
+    return -1;
+  }
+
+  decode_segment(s, length, buf);
+
+  return written + res;
+}
+
+
+#ifndef min
+#define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+typedef void (*segment_handler_t)(unsigned char *, size_t, void *);
+
+/**
+ * Checks if path segment @p s consists of one or two dots.
+ */
+static inline int
+dots(unsigned char *s, size_t len) {
+  return *s == '.' && (len == 1 || (*(s+1) == '.' && len == 2));
+}
+
+/** 
+ * Splits the given string into segments. You should call one of the
+ * macros coap_split_path() or coap_split_query() instead.
+ * 
+ * @param s      The URI string to be tokenized.
+ * @param length The length of @p s.
+ * @param h      A handler that is called with every token.
+ * @param data   Opaque data that is passed to @p h when called.
+ * 
+ * @return The number of characters that have been parsed from @p s.
+ */
+static size_t
+coap_split_path_impl(const unsigned char *s, size_t length,
+		     segment_handler_t h, void *data) {
+
+  const unsigned char *p, *q;
+
+  p = q = s;
+  while (length > 0 && !strnchr((unsigned char *)"?#", 2, *q)) {
+    if (*q == '/') {		/* start new segment */
+
+      if (!dots((unsigned char *)p, q - p)) {
+	h((unsigned char *)p, q - p, data);
+      }
+
+      p = q + 1;
+    }
+
+    q++;
+    length--;
+  }
+
+  /* write last segment */
+  if (!dots((unsigned char *)p, q - p)) {
+    h((unsigned char *)p, q - p, data);
+  }
+
+  return q - s;
+}
+
+struct cnt_str {
+  str buf;
+  int n;
+};
+
+static void
+write_option(unsigned char *s, size_t len, void *data) {
+  struct cnt_str *state = (struct cnt_str *)data;
+  int res;
+  assert(state);
+
+  res = make_decoded_option(s, len, state->buf.s, state->buf.length);
+  if (res > 0) {
+    state->buf.s += res;
+    state->buf.length -= res;
+    state->n++;
+  }
+}
+
+int
+coap_split_path(const unsigned char *s, size_t length, 
+		unsigned char *buf, size_t *buflen) {
+  struct cnt_str tmp = { { *buflen, buf }, 0 };
+
+  coap_split_path_impl(s, length, write_option, &tmp);
+
+  *buflen = *buflen - tmp.buf.length;
+
+  return tmp.n;
+}
+
+int
+coap_split_query(const unsigned char *s, size_t length, 
+		unsigned char *buf, size_t *buflen) {
+  struct cnt_str tmp = { { *buflen, buf }, 0 };
+  const unsigned char *p;
+
+  p = s;
+  while (length > 0 && *s != '#') {
+    if (*s == '&') {		/* start new query element */
+      write_option((unsigned char *)p, s - p, &tmp);
+      p = s + 1;
+    }
+
+    s++;
+    length--;
+  }
+
+  /* write last query element */
+  write_option((unsigned char *)p, s - p, &tmp);
+
+  *buflen = *buflen - tmp.buf.length;
+  return tmp.n;
+}
+
+#define URI_DATA(uriobj) ((unsigned char *)(uriobj) + sizeof(coap_uri_t))
+
+coap_uri_t *
+coap_new_uri(const unsigned char *uri, unsigned int length) {
+  unsigned char *result;
+
+  result = coap_malloc(length + 1 + sizeof(coap_uri_t));
+
+  if (!result)
+    return NULL;
+
+  memcpy(URI_DATA(result), uri, length);
+  URI_DATA(result)[length] = '\0'; /* make it zero-terminated */
+
+  if (coap_split_uri(URI_DATA(result), length, (coap_uri_t *)result) < 0) {
+    coap_free(result);
+    return NULL;
+  }
+  return (coap_uri_t *)result;
+}
+
+coap_uri_t *
+coap_clone_uri(const coap_uri_t *uri) {
+  coap_uri_t *result;
+
+  if ( !uri )
+    return  NULL;
+
+  result = (coap_uri_t *)coap_malloc( uri->query.length + uri->host.length +
+				      uri->path.length + sizeof(coap_uri_t) + 1);
+
+  if ( !result )
+    return NULL;
+
+  memset( result, 0, sizeof(coap_uri_t) );
+
+  result->port = uri->port;
+
+  if ( uri->host.length ) {
+    result->host.s = URI_DATA(result);
+    result->host.length = uri->host.length;
+
+    memcpy(result->host.s, uri->host.s, uri->host.length);
+  }
+
+  if ( uri->path.length ) {
+    result->path.s = URI_DATA(result) + uri->host.length;
+    result->path.length = uri->path.length;
+
+    memcpy(result->path.s, uri->path.s, uri->path.length);
+  }
+
+  if ( uri->query.length ) {
+    result->query.s = URI_DATA(result) + uri->host.length + uri->path.length;
+    result->query.length = uri->query.length;
+
+    memcpy(result->query.s, uri->query.s, uri->query.length);
+  }
+
+  return result;
+}
+
+/* hash URI path segments */
+
+/* The function signature of coap_hash() is different from
+ * segment_handler_t hence we use this wrapper as safe typecast. */
+static inline void
+hash_segment(unsigned char *s, size_t len, void *data) {
+  coap_hash(s, len, data);
+}
+
+int
+coap_hash_path(const unsigned char *path, size_t len, coap_key_t key) {
+  if (!path)
+    return 0;
+
+  memset(key, 0, sizeof(coap_key_t));
+
+  coap_split_path_impl(path, len, hash_segment, key);
+
+  return 1;
+}
diff --git a/components/coap/libcoap/tests/Makefile.am b/components/coap/libcoap/tests/Makefile.am
new file mode 100644
index 00000000..140d0437
--- /dev/null
+++ b/components/coap/libcoap/tests/Makefile.am
@@ -0,0 +1,36 @@
+# doc/Makefile.am
+#
+# Copyright (C) 2015-2016 Carsten Schoenert <c.schoenert@t-online.de>
+#
+# This file is part of the CoAP C library libcoap. Please see README and
+# COPYING for terms of use.
+
+# just do anything if 'HAVE_CUNIT' is defined
+if HAVE_CUNIT
+
+# picking up the default warning CFLAGS
+AM_CFLAGS = -I$(top_srcdir)/include/coap -I$(top_builddir)/include/coap $(WARNING_CFLAGS) $(CUNIT_CFLAGS) -std=c99
+
+noinst_PROGRAMS = \
+ testdriver
+
+testdriver_SOURCES = \
+ testdriver.c \
+ test_error_response.c \
+ test_options.c \
+ test_pdu.c \
+ test_sendqueue.c \
+ test_uri.c \
+ test_wellknown.c
+
+testdriver_LDADD = $(CUNIT_LIBS) $(top_builddir)/.libs/libcoap-$(LIBCOAP_API_VERSION).la
+
+# If there is a API change to something $(LIBCOAP_API_VERSION) > 1 there is
+# nothing to adopt here. No needed to implement something here because the test
+# unit will always be build againts the actual header files!
+
+CLEANFILES = testdriver
+
+all-am: testdriver
+
+endif # HAVE_CUNIT
diff --git a/components/coap/libcoap/tests/test_error_response.c b/components/coap/libcoap/tests/test_error_response.c
new file mode 100644
index 00000000..37afba47
--- /dev/null
+++ b/components/coap/libcoap/tests/test_error_response.c
@@ -0,0 +1,374 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+#include "test_error_response.h"
+
+#include <coap.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+coap_pdu_t *pdu;	      /* Holds the request PDU for most tests */
+coap_opt_filter_t opts;	      /* option filter used for generating responses */
+
+/************************************************************************
+ ** PDU decoder
+ ************************************************************************/
+
+/* FIXME: handle COAP_ERROR_PHRASE_LENGTH == 0 */
+
+static void
+t_error_response1(void) {
+  uint8_t teststr[] = {
+    0x60, 0x80, 0x12, 0x34, 0xff, 'B', 'a', 'd',
+    ' ', 'R', 'e', 'q', 'u', 'e', 's', 't'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  pdu->hdr->id = htons(0x1234);
+
+  /* result = coap_add_token(pdu, 5, (unsigned char *)"token"); */
+  coap_option_filter_clear(opts);
+  response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(400), opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 0);
+  CU_ASSERT(response->hdr->code == 0x80);
+  CU_ASSERT(pdu->hdr->id == htons(0x1234));
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response2(void) {
+  uint8_t teststr[] = {
+    0x55, 0x84, 0x12, 0x34, 't', 'o', 'k', 'e',
+    'n', 0xff, 'N', 'o', 't', ' ', 'F', 'o',
+    'u', 'n', 'd'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_NON;
+  pdu->hdr->id = htons(0x1234);
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (unsigned char *)"time");
+
+  coap_option_filter_clear(opts);
+  response = coap_new_error_response(pdu, COAP_RESPONSE_CODE(404), opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_NON);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == 0x84);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response3(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(402);
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00, 't', 'o', 'k', 'e',
+    'n', 0x90, 0xff, 'B', 'a', 'd', ' ', 'O',
+    'p', 't', 'i', 'o', 'n'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (unsigned char *)"time"); */
+
+  /* unknown critical option 9 */
+  coap_add_option(pdu, 9, 0, NULL);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 9);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response4(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(402);
+  unsigned char optval[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b
+  };
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
+     'n', 0x9c, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+    0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0xff,  'B',
+     'a',  'd',  ' ',  'O',  'p',  't',  'i',  'o',
+     'n'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (unsigned char *)"time"); */
+
+  /* unknown critical option 9 */
+  coap_add_option(pdu, 9, sizeof(optval), optval);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 9);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response5(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(402);
+  unsigned char optval[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12
+  };
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
+     'n', 0x9d, 0x06, 0x00, 0x01, 0x02, 0x03, 0x04,
+    0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+    0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,  'B',
+     'a',  'd',  ' ',  'O',  'p',  't',  'i',  'o',
+     'n'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (unsigned char *)"time"); */
+
+  /* unknown critical option 9 */
+  coap_add_option(pdu, 9, sizeof(optval), optval);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 9);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response6(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(402);
+  unsigned char optval[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12
+  };
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
+     'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
+    0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
+     'B',  'a',  'd',  ' ',  'O',  'p',  't',  'i',
+     'o',  'n'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* coap_add_option(pdu, COAP_OPTION_URI_HOST, 4, (unsigned char *)"time"); */
+
+  /* unknown critical option 23 */
+  coap_add_option(pdu, 23, sizeof(optval), optval);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 23);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response7(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(402);
+  unsigned char optval[] = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+    0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12
+  };
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
+     'n', 0xdd, 0x0a, 0x06, 0x00, 0x01, 0x02, 0x03,
+    0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0xff,
+     'B',  'a',  'd',  ' ',  'O',  'p',  't',  'i',
+     'o',  'n'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* known option 11 */
+  coap_add_option(pdu, 11, 4, (unsigned char *)"time");
+
+  /* unknown critical option 23 */
+  coap_add_option(pdu, 23, sizeof(optval), optval);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 23);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static void
+t_error_response8(void) {
+  const unsigned char code = COAP_RESPONSE_CODE(503);
+  uint8_t teststr[] = {
+    0x65, code, 0x00, 0x00,  't',  'o',  'k',  'e',
+     'n', 0xe0, 0x02, 0xdc, 0xd0, 0x00, 0xff,  'S',
+     'e',  'r',  'v',  'i',  'c',  'e',  ' ',  'U',
+     'n',  'a',  'v',  'a',  'i',  'l',  'a',  'b',
+     'l',  'e'
+  };
+  coap_pdu_t *response;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  coap_add_token(pdu, 5, (unsigned char *)"token");
+  /* known option 1000 */
+  coap_add_option(pdu, 1000, 0, NULL);
+
+  /* unknown options 1001 and 1014 */
+  coap_add_option(pdu, 1001, 0, NULL);
+  coap_add_option(pdu, 1014, 0, NULL);
+
+  /* known option 2000 */
+  coap_add_option(pdu, 2000, 0, NULL);
+
+  coap_option_filter_clear(opts);
+  coap_option_setb(opts, 1001);
+  coap_option_setb(opts, 1014);
+  response = coap_new_error_response(pdu, code, opts);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(response->length == sizeof(teststr));
+  CU_ASSERT(response->hdr->version == 1);
+  CU_ASSERT(response->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(response->hdr->token_length == 5);
+  CU_ASSERT(response->hdr->code == code);
+
+  CU_ASSERT(memcmp(response->hdr, teststr, sizeof(teststr)) == 0);
+  coap_delete_pdu(response);
+}
+
+static int
+t_error_response_tests_create(void) {
+  pdu = coap_pdu_init(0, 0, 0, COAP_MAX_PDU_SIZE);
+
+  return pdu == NULL;
+}
+
+static int
+t_error_response_tests_remove(void) {
+  coap_delete_pdu(pdu);
+  return 0;
+}
+
+CU_pSuite
+t_init_error_response_tests(void) {
+  CU_pSuite suite[1];
+
+  suite[0] = CU_add_suite("error response generator",
+			  t_error_response_tests_create,
+			  t_error_response_tests_remove);
+  if (!suite[0]) {			/* signal error */
+    fprintf(stderr, "W: cannot add error response generator test suite (%s)\n",
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define ERROR_RESPONSE_TEST(s,t)					\
+  if (!CU_ADD_TEST(s,t)) {						\
+    fprintf(stderr, "W: cannot add error response generator test (%s)\n", \
+	    CU_get_error_msg());					\
+  }
+
+  ERROR_RESPONSE_TEST(suite[0], t_error_response1);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response2);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response3);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response4);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response5);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response6);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response7);
+  ERROR_RESPONSE_TEST(suite[0], t_error_response8);
+
+  return suite[0];
+}
+
diff --git a/components/coap/libcoap/tests/test_error_response.h b/components/coap/libcoap/tests/test_error_response.h
new file mode 100644
index 00000000..2bab63c9
--- /dev/null
+++ b/components/coap/libcoap/tests/test_error_response.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_error_response_tests(void);
diff --git a/components/coap/libcoap/tests/test_options.c b/components/coap/libcoap/tests/test_options.c
new file mode 100644
index 00000000..5bb51f4d
--- /dev/null
+++ b/components/coap/libcoap/tests/test_options.c
@@ -0,0 +1,999 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include "test_options.h"
+
+#include <coap.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/************************************************************************
+ ** decoder tests
+ ************************************************************************/
+
+static void
+t_parse_option1(void) {
+  /* delta == 0, length == 0, value == 0 */
+  str teststr = {  1, (unsigned char *)"" };
+
+  size_t result;
+  coap_option_t option;
+
+  /* result = coap_opt_parse(teststr.s, teststr.s + teststr.length, &option); */
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 1);
+  CU_ASSERT(option.delta == 0);
+  CU_ASSERT(option.length == 0);
+  /* FIXME: value? */
+}
+
+static void
+t_parse_option2(void) {
+  /* delta == 12, length == 1, value == 0 */
+  str teststr = {  2, (unsigned char *)"\xc1" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 2);
+  CU_ASSERT(option.delta == 12);
+  CU_ASSERT(option.length == 1);
+  CU_ASSERT(option.value == teststr.s + 1);
+}
+
+static void
+t_parse_option3(void) {
+  /* delta == 3, length == 12, value == 0 */
+  str teststr = { 13, (unsigned char *)"\x3c\x00\x01\x02\x03\x04"
+		                       "\x05\x06\x07\x08\x09\x0a\x0b" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 13);
+  CU_ASSERT(option.delta == 3);
+  CU_ASSERT(option.length == 12);
+  CU_ASSERT(option.value == teststr.s + 1);
+  /* CU_ASSERT(memcmp(option.value, teststr.s + 1, 12) == 0); */
+}
+
+static void
+t_parse_option4(void) {
+  /* delta == 15, length == 3, value == 0 */
+  str teststr = {  2, (unsigned char *)"\xf3" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option5(void) {
+  /* delta == 3, length == 15, value == 0 */
+  str teststr = {  2, (unsigned char *)"\x3f" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option6(void) {
+  /* delta == 15, length == 15 */
+  str teststr = {  1, (unsigned char *)"\xff" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option7(void) {
+  /* delta == 20, length == 0 */
+  str teststr = {  2, (unsigned char *)"\xd0\x07" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 2);
+  CU_ASSERT(option.delta == 20);
+  CU_ASSERT(option.length == 0);
+}
+
+static void
+t_parse_option8(void) {
+  /* delta == 780, length == 0 */
+  str teststr = {  3, (unsigned char *)"\xe0\x01\xff" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 3);
+  CU_ASSERT(option.delta == 780);
+  CU_ASSERT(option.length == 0);
+}
+
+static void
+t_parse_option9(void) {
+  /* delta == 65535, length == 0 */
+  str teststr = {  3, (unsigned char *)"\xe0\xfe\xf2" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 3);
+  CU_ASSERT(option.delta == 65535);
+}
+
+static void
+t_parse_option10(void) {
+  /* delta > 65535 (illegal), length == 0 */
+  str teststr = {  3, (unsigned char *)"\xe0\xff\xff" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option11(void) {
+  /* illegal delta value (option too short) */
+  str teststr = {  1, (unsigned char *)"\xd0" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option12(void) {
+  /* delta == 280, length == 500 */
+  str teststr = {  3, (unsigned char *)"\xee\xff\x0b" };
+
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_option13(void) {
+  /* delta == 280, length == 500 */
+  unsigned char _data[505];
+  str teststr = {  sizeof(_data), _data };
+  teststr.s[0] = 0xee;
+  teststr.s[1] = 0x00;
+  teststr.s[2] = 0x0b;
+  teststr.s[3] = 0x00;
+  teststr.s[4] = 0xe7;
+  
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(teststr.s, teststr.length, &option);
+  CU_ASSERT(result == sizeof(_data));
+  CU_ASSERT(option.delta == 280);
+  CU_ASSERT(option.length == 500);
+  CU_ASSERT(option.value == &_data[5]);
+}
+
+static void
+t_parse_option14(void) {
+  /* delta == 268, length == 65535 */
+  unsigned char *data;
+  unsigned int length = 4 + 65535;
+
+  data = (unsigned char *)malloc(length);
+  if (!data) {
+    CU_FAIL("internal error in test framework -- insufficient memory\n");
+    return;
+  }
+
+  data[0] = 0xde;
+  data[1] = 0xff;
+  data[2] = 0xfe;
+  data[3] = 0xf2;
+  
+  size_t result;
+  coap_option_t option;
+
+  result = coap_opt_parse(data, length, &option);
+  CU_ASSERT(result == length);
+  CU_ASSERT(option.delta == 268);
+  CU_ASSERT(option.length == 65535);
+  CU_ASSERT(option.value == &data[4]);
+}
+
+/************************************************************************
+ ** encoder tests
+ ************************************************************************/
+
+static void
+t_encode_option1(void) {
+  char teststr[] = { 0x00 };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 0, 0);
+  CU_ASSERT(result == sizeof(teststr));
+  
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option2(void) {
+  uint8_t teststr[] = { 0x5d, 0xff };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 5, 268);
+  CU_ASSERT(result == sizeof(teststr));
+  
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option3(void) {
+  uint8_t teststr[] = { 0xd1, 0x01 };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 14, 1);
+  CU_ASSERT(result == sizeof(teststr));
+
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option4(void) {
+  uint8_t teststr[] = { 0xdd, 0xff, 0xab };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 268, 184);
+  CU_ASSERT(result == sizeof(teststr));
+
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option5(void) {
+  uint8_t teststr[] = { 0xed, 0x13, 0x00, 0xff };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 5133, 268);
+  CU_ASSERT(result == sizeof(teststr));
+
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option6(void) {
+  uint8_t teststr[] = { 0xee, 0xfe, 0xf2, 0xfe, 0xf2 };
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_setheader((coap_opt_t *)buf, sizeof(buf), 65535, 65535);
+  CU_ASSERT(result == sizeof(teststr));
+
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option7(void) {
+  uint8_t teststr[] = { 0x35, 'v', 'a', 'l', 'u', 'e' };
+  const size_t valoff = 1;
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_encode((coap_opt_t *)buf, sizeof(buf), 3, 
+			   (unsigned char *)teststr + valoff, 
+			   sizeof(teststr) - valoff);
+
+  CU_ASSERT(result == sizeof(teststr));
+
+  CU_ASSERT(memcmp(buf, teststr, result) == 0);
+}
+
+static void
+t_encode_option8(void) {
+  /* value does not fit in message buffer */
+  unsigned char buf[40];
+  size_t result;
+  
+  result = coap_opt_encode((coap_opt_t *)buf, 8, 15, 
+			   (unsigned char *)"something", 9);
+
+  CU_ASSERT(result == 0);
+
+  result = coap_opt_encode((coap_opt_t *)buf, 1, 15, 
+			   (unsigned char *)"something", 9);
+
+  CU_ASSERT(result == 0);
+}
+
+/************************************************************************
+ ** accessor tests
+ ************************************************************************/
+
+static void
+t_access_option1(void) {
+  const uint8_t teststr[] = { 0x12, 'a', 'b' };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 1);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 2);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), teststr + 1);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == sizeof(teststr));
+}
+
+static void
+t_access_option2(void) {
+  const uint8_t teststr[] = { 0xe2, 0x18, 0xfd, 'a', 'b' };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 6666);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 2);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), teststr + 3);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == sizeof(teststr));
+}
+
+static void
+t_access_option3(void) {
+  const uint8_t teststr[] = { 0xed, 0x18, 0x0a, 0x00, 'a', 'b', 'c', 'd', 
+			   'e',  'f',  'g',  'h',  'i', 'j', 'k', 'l',
+			   'm'
+  };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 6423);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 13);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), teststr + 4);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == sizeof(teststr));
+}
+
+static void
+t_access_option4(void) {
+  const uint8_t teststr[] = { 0xde, 0xff, 0xfe, 0xf2, 'a', 'b', 'c' };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 268);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 65535);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), teststr + 4);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == 65535 + 4);
+}
+
+static void
+t_access_option5(void) {
+  const uint8_t teststr[] = { 0xee, 0xfe, 0xf2, 0x00, 0xdd, 'a', 'b', 'c' };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 65535);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 490);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), teststr + 5);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == 495);
+}
+
+static void
+t_access_option6(void) {
+  coap_log_t level = coap_get_log_level();
+  const uint8_t teststr[] = { 0xf2, 'a', 'b' };
+
+  coap_set_log_level(LOG_CRIT);
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 0);
+  coap_set_log_level(level);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 0);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), NULL);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == 0);
+}
+
+static void
+t_access_option7(void) {
+  const uint8_t teststr[] = { 0x2f, 'a', 'b' };
+
+  CU_ASSERT(coap_opt_delta((coap_opt_t *)teststr) == 2);
+  CU_ASSERT(coap_opt_length((coap_opt_t *)teststr) == 0);
+  CU_ASSERT_PTR_EQUAL(coap_opt_value((coap_opt_t *)teststr), NULL);
+  CU_ASSERT(coap_opt_size((coap_opt_t *)teststr) == 0);
+}
+
+/************************************************************************
+ ** accessor tests
+ ************************************************************************/
+
+#define TEST_MAX_SIZE 1000
+
+static void
+t_iterate_option1(void) {
+  /* CoAP PDU without token, options, or data */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00 
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+
+  result = coap_option_iterator_init(&pdu, &oi, COAP_OPT_ALL);
+
+  CU_ASSERT(result == NULL);
+  CU_ASSERT(oi.bad == 1);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT(option == NULL);
+}
+
+static void
+t_iterate_option2(void) {
+  /* CoAP PDU with token but without options and data */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x03, 0x00, 0x00, 0x00, 't', 'o', 'k'
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+
+  result = coap_option_iterator_init(&pdu, &oi, COAP_OPT_ALL);
+
+  CU_ASSERT(result == NULL);
+  CU_ASSERT(oi.bad == 1);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT(option == NULL);
+}
+
+static void
+t_iterate_option3(void) {
+  /* CoAP PDU with token and options */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x03, 0x00, 0x00, 0x00, 't', 'o', 'k', 0x13, 
+    'o',  'p',  't',  0x00, 0xd1, 0x10, 'x'
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+
+  result = coap_option_iterator_init(&pdu, &oi, COAP_OPT_ALL);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 1);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 7);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 1);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 11);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 30);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 12);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option4(void) {
+  /* CoAP PDU with token, options, and data */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x03, 0x00, 0x00, 0x00, 't', 'o', 'k', 0x13, 
+    'o',  'p',  't',  0x00, 0xd1, 0x10, 'x', 0xff,
+    'd',  'a',  't',  'a'
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+
+  result = coap_option_iterator_init(&pdu, &oi, COAP_OPT_ALL);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 1);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 7);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 1);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 11);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 30);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 12);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option5(void) {
+  /* CoAP PDU with malformed option */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x52, 'o', 'p', 0xee, 
+    0x12, 0x03, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+
+  result = coap_option_iterator_init(&pdu, &oi, COAP_OPT_ALL);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 5);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 4);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option6(void) {
+  /* option filter */
+  /* CoAP PDU with token, options, and data */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+    0xc0, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+  coap_opt_filter_t filter;
+
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, 10);	/* option nr 10 only */
+  result = coap_option_iterator_init(&pdu, &oi, filter);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 10);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 5);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 10);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 6);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 10);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 7);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option7(void) {
+  /* option filter */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+    0xc0, 0x00, 0x10, 0x10, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+  coap_opt_filter_t filter;
+
+  /* search options nr 8 and 22 */
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, 8);
+  coap_option_setb(filter, 22);
+  result = coap_option_iterator_init(&pdu, &oi, filter);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 8);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 4);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 22);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 8);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT(oi.type == 22);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 9);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option8(void) {
+  /* option filter */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+    0xc0, 0x00, 0x10, 0x10, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+  coap_opt_filter_t filter;
+
+  /* search option nr 36 */
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, 36);
+  result = coap_option_iterator_init(&pdu, &oi, filter);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option9(void) {
+  /* options filter: option number too large for filter */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+    0xc0, 0x00, 0x10, 0x10, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+  coap_opt_filter_t filter;
+
+  /* search option nr 100 */
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, 100);
+  result = coap_option_iterator_init(&pdu, &oi, filter);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+static void
+t_iterate_option10(void) {
+  /* options filter: option numbers in PDU exceed filter size */
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00,
+    0xd0, 0x26, 0xe0, 0x10, 0x00
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = TEST_MAX_SIZE,
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+  coap_opt_iterator_t oi, *result;
+  coap_opt_t *option;
+  coap_opt_filter_t filter;
+
+  /* search option nr 61 */
+  coap_option_filter_clear(filter);
+  coap_option_setb(filter, 61);
+  result = coap_option_iterator_init(&pdu, &oi, filter);
+
+  CU_ASSERT_PTR_EQUAL(result, &oi);
+  CU_ASSERT(oi.bad == 0);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 0);
+  CU_ASSERT_PTR_EQUAL(option, teststr + 8);
+
+  option = coap_option_next(&oi);
+  CU_ASSERT(oi.bad == 1);
+  CU_ASSERT_PTR_EQUAL(option, NULL);
+}
+
+/************************************************************************
+ ** filter tests
+ ************************************************************************/
+
+static void
+t_filter_option1(void) {
+  coap_opt_filter_t filter;
+
+  coap_option_filter_clear(filter);
+
+  CU_ASSERT(coap_option_filter_set(filter, 0) == 1);
+  CU_ASSERT(coap_option_filter_set(filter, 37) == 1);
+  CU_ASSERT(coap_option_filter_set(filter, 37) == 1);
+  CU_ASSERT(coap_option_filter_set(filter, 43) == 1);
+  CU_ASSERT(coap_option_filter_set(filter, 290) == 1);
+  CU_ASSERT(coap_option_filter_set(filter, 65535) == 1);
+
+  CU_ASSERT(coap_option_filter_get(filter, 0) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 37) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 43) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 290) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 65535) == 1);
+
+  CU_ASSERT(coap_option_filter_unset(filter, 37) == 1);
+
+  CU_ASSERT(coap_option_filter_get(filter, 0) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 43) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 290) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 65535) == 1);
+
+  CU_ASSERT(coap_option_filter_get(filter, 37) == 0);
+  CU_ASSERT(coap_option_filter_get(filter, 89) == 0);
+}
+
+static void
+t_filter_option2(void) {
+  coap_opt_filter_t filter;
+  int s;
+
+  coap_option_filter_clear(filter);
+
+  /* fill all COAP_OPT_FILTER_SHORT slots */
+  for (s = 0; s < COAP_OPT_FILTER_SHORT; s++) {
+    CU_ASSERT(coap_option_filter_set(filter, s));
+  }
+
+  /* adding a short option type must fail */
+  CU_ASSERT(coap_option_filter_set(filter, COAP_OPT_FILTER_SHORT) == 0);
+
+  /* adding a long option type must succeed */
+  CU_ASSERT(coap_option_filter_set(filter, 256) == 1);
+}
+
+static void
+t_filter_option3(void) {
+  coap_opt_filter_t filter;
+  int l;
+
+  coap_option_filter_clear(filter);
+
+  /* set COAP_OPT_FILTER_LONG long filters */
+  for (l = 0; l < COAP_OPT_FILTER_LONG; l++) {
+    CU_ASSERT(coap_option_filter_set(filter, 256 + l) == 1);
+  }
+
+  /* the next must fail and must not be found */
+  CU_ASSERT(coap_option_filter_set(filter, 256 + COAP_OPT_FILTER_LONG) == 0);
+  CU_ASSERT(coap_option_filter_get(filter, 256 + COAP_OPT_FILTER_LONG) == 0);
+
+  /* remove one item */
+  CU_ASSERT(coap_option_filter_unset(filter, 256) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 256) == 0);
+
+  /* now, storing a new filter must succeed */
+  CU_ASSERT(coap_option_filter_set(filter, 256 + COAP_OPT_FILTER_LONG) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 256 + COAP_OPT_FILTER_LONG) == 1);
+
+  /* and all other items must be available as well */
+  for (l = 0; l < COAP_OPT_FILTER_LONG; l++) {
+    CU_ASSERT(coap_option_filter_get(filter, 256 + l + 1) == 1);
+  }
+
+  /* set COAP_OPT_FILTER_SHORT short filters */
+  for (l = 0; l < COAP_OPT_FILTER_SHORT; l++) {
+    CU_ASSERT(coap_option_filter_set(filter, l) == 1);
+  }
+
+  /* the next must fail and must not be found */
+  CU_ASSERT(coap_option_filter_set(filter, COAP_OPT_FILTER_SHORT) == 0);
+  CU_ASSERT(coap_option_filter_get(filter, COAP_OPT_FILTER_SHORT) == 0);
+
+  /* remove one item */
+  CU_ASSERT(coap_option_filter_unset(filter, 0) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, 0) == 0);
+
+  /* now, storing a new filter must succeed */
+  CU_ASSERT(coap_option_filter_set(filter, COAP_OPT_FILTER_SHORT) == 1);
+  CU_ASSERT(coap_option_filter_get(filter, COAP_OPT_FILTER_SHORT) == 1);
+
+  /* and all other items must be available as well */
+  for (l = 0; l < COAP_OPT_FILTER_SHORT; l++) {
+    CU_ASSERT(coap_option_filter_get(filter, l + 1) == 1);
+  }
+}
+
+/************************************************************************
+ ** initialization 
+ ************************************************************************/
+
+CU_pSuite
+t_init_option_tests(void) {
+  CU_pSuite suite[5];
+
+  suite[0] = CU_add_suite("option parser", NULL, NULL);
+  if (!suite[0]) {			/* signal error */
+    fprintf(stderr, "W: cannot add option parser test suite (%s)\n", 
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define OPTION_TEST(n,s)						      \
+  if (!CU_add_test(suite[0], s, t_parse_option##n)) {	      \
+    fprintf(stderr, "W: cannot add option parser test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+
+  OPTION_TEST(1, "parse option #1");
+  OPTION_TEST(2, "parse option #2");
+  OPTION_TEST(3, "parse option #3");
+  OPTION_TEST(4, "parse option #4");
+  OPTION_TEST(5, "parse option #5");
+  OPTION_TEST(6, "parse option #6");
+  OPTION_TEST(7, "parse option #7");
+  OPTION_TEST(8, "parse option #8");
+  OPTION_TEST(9, "parse option #9");
+  OPTION_TEST(10, "parse option #10");
+  OPTION_TEST(11, "parse option #11");
+  OPTION_TEST(12, "parse option #12");
+  OPTION_TEST(13, "parse option #13");
+  OPTION_TEST(14, "parse option #14");
+
+  if ((suite[1] = CU_add_suite("option encoder", NULL, NULL))) {
+#define OPTION_ENCODER_TEST(n,s)			      \
+    if (!CU_add_test(suite[1], s, t_encode_option##n)) {		      \
+      fprintf(stderr, "W: cannot add option encoder test (%s)\n",     \
+	      CU_get_error_msg());				      \
+    }
+
+    OPTION_ENCODER_TEST(1, "encode option #1");
+    OPTION_ENCODER_TEST(2, "encode option #2");
+    OPTION_ENCODER_TEST(3, "encode option #3");
+    OPTION_ENCODER_TEST(4, "encode option #4");
+    OPTION_ENCODER_TEST(5, "encode option #5");
+    OPTION_ENCODER_TEST(6, "encode option #6");
+    OPTION_ENCODER_TEST(7, "encode option #7");
+    OPTION_ENCODER_TEST(8, "encode option #8");
+    
+  } else {
+    fprintf(stderr, "W: cannot add option encoder test suite (%s)\n", 
+	    CU_get_error_msg());
+  }
+
+  if ((suite[2] = CU_add_suite("option accessors", NULL, NULL))) {
+#define OPTION_ACCESSOR_TEST(n,s)			      \
+    if (!CU_add_test(suite[2], s, t_access_option##n)) {		      \
+      fprintf(stderr, "W: cannot add option accessor function test (%s)\n",     \
+	      CU_get_error_msg());				      \
+    }
+
+    OPTION_ACCESSOR_TEST(1, "access option #1");
+    OPTION_ACCESSOR_TEST(2, "access option #2");
+    OPTION_ACCESSOR_TEST(3, "access option #3");
+    OPTION_ACCESSOR_TEST(4, "access option #4");
+    OPTION_ACCESSOR_TEST(5, "access option #5");
+    OPTION_ACCESSOR_TEST(6, "access option #6");
+    OPTION_ACCESSOR_TEST(7, "access option #7");
+    
+  } else {
+    fprintf(stderr, "W: cannot add option acessor function test suite (%s)\n", 
+	    CU_get_error_msg());
+  }
+
+  if ((suite[3] = CU_add_suite("option iterator", NULL, NULL))) {
+#define OPTION_ITERATOR_TEST(n,s)			      \
+    if (!CU_add_test(suite[3], s, t_iterate_option##n)) {		      \
+      fprintf(stderr, "W: cannot add option iterator test (%s)\n",     \
+	      CU_get_error_msg());				      \
+    }
+
+    OPTION_ITERATOR_TEST(1, "option iterator #1");
+    OPTION_ITERATOR_TEST(2, "option iterator #2");
+    OPTION_ITERATOR_TEST(3, "option iterator #3");
+    OPTION_ITERATOR_TEST(4, "option iterator #4");
+    OPTION_ITERATOR_TEST(5, "option iterator #5");
+    OPTION_ITERATOR_TEST(6, "option iterator #6");
+    OPTION_ITERATOR_TEST(7, "option iterator #7");
+    OPTION_ITERATOR_TEST(8, "option iterator #8");
+    OPTION_ITERATOR_TEST(9, "option iterator #9");
+    OPTION_ITERATOR_TEST(10, "option iterator #10");
+    
+  } else {
+    fprintf(stderr, "W: cannot add option iterator test suite (%s)\n", 
+	    CU_get_error_msg());
+  }
+
+  if ((suite[4] = CU_add_suite("option filter", NULL, NULL))) {
+#define OPTION_FILTER_TEST(n,s)			      \
+    if (!CU_add_test(suite[4], s, t_filter_option##n)) {		      \
+      fprintf(stderr, "W: cannot add option filter test (%s)\n",     \
+	      CU_get_error_msg());				      \
+    }
+
+    OPTION_FILTER_TEST(1, "option filter #1");
+    OPTION_FILTER_TEST(2, "option filter #2");
+    OPTION_FILTER_TEST(3, "option filter #3");
+
+  } else {
+    fprintf(stderr, "W: cannot add option filter test suite (%s)\n",
+	    CU_get_error_msg());
+  }
+
+  return suite[0];
+}
+
diff --git a/components/coap/libcoap/tests/test_options.h b/components/coap/libcoap/tests/test_options.h
new file mode 100644
index 00000000..3ffcefe3
--- /dev/null
+++ b/components/coap/libcoap/tests/test_options.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_option_tests(void);
diff --git a/components/coap/libcoap/tests/test_pdu.c b/components/coap/libcoap/tests/test_pdu.c
new file mode 100644
index 00000000..13608308
--- /dev/null
+++ b/components/coap/libcoap/tests/test_pdu.c
@@ -0,0 +1,694 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+#include "test_pdu.h"
+
+#include <coap.h>
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+coap_pdu_t *pdu;	      /* Holds the parsed PDU for most tests */
+
+/************************************************************************
+ ** PDU decoder
+ ************************************************************************/
+
+static void
+t_parse_pdu1(void) {
+  uint8_t teststr[] = {  0x40, 0x01, 0x93, 0x34 };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_CON);
+  CU_ASSERT(pdu->hdr->token_length == 0);
+  CU_ASSERT(pdu->hdr->code == COAP_REQUEST_GET);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+  CU_ASSERT_PTR_NULL(pdu->data);
+}
+
+static void
+t_parse_pdu2(void) {
+  uint8_t teststr[] = {  0x55, 0x69, 0x12, 0x34, 't', 'o', 'k', 'e', 'n' };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_NON);
+  CU_ASSERT(pdu->hdr->token_length == 5);
+  CU_ASSERT(pdu->hdr->code == 0x69);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+  CU_ASSERT(memcmp(pdu->hdr->token, teststr + 4, 5) == 0);
+  CU_ASSERT_PTR_NULL(pdu->data);
+}
+
+static void
+t_parse_pdu3(void) {
+  uint8_t teststr[] = {  0x53, 0x69, 0x12, 0x34, 't', 'o', 'k', 'e', 'n' };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu4(void) {
+  /* illegal token length */
+  uint8_t teststr[] = {  0x59, 0x69, 0x12, 0x34,
+		      't', 'o', 'k', 'e', 'n', '1', '2', '3', '4' };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+
+  teststr[0] = 0x5f;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu5(void) {
+  /* PDU with options */
+  uint8_t teststr[] = {  0x55, 0x73, 0x12, 0x34, 't', 'o', 'k', 'e',
+		      'n',  0x00, 0xc1, 0x00
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_NON);
+  CU_ASSERT(pdu->hdr->token_length == 5);
+  CU_ASSERT(pdu->hdr->code == 0x73);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+  CU_ASSERT(memcmp(pdu->hdr->token, teststr + 4, 5) == 0);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  /* FIXME: check options */
+}
+
+static void
+t_parse_pdu6(void) {
+  /* PDU with options that exceed the PDU */
+  uint8_t teststr[] = {  0x55, 0x73, 0x12, 0x34, 't', 'o', 'k', 'e',
+		      'n',  0x00, 0xc1, 0x00, 0xae, 0xf0, 0x03
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu7(void) {
+  /* PDU with options and payload */
+  uint8_t teststr[] = {  0x55, 0x73, 0x12, 0x34, 't', 'o', 'k', 'e',
+		      'n',  0x00, 0xc1, 0x00, 0xff, 'p', 'a', 'y',
+		      'l', 'o', 'a', 'd'
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_NON);
+  CU_ASSERT(pdu->hdr->token_length == 5);
+  CU_ASSERT(pdu->hdr->code == 0x73);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+  CU_ASSERT(memcmp(pdu->hdr->token, teststr + 4, 5) == 0);
+
+  /* FIXME: check options */
+
+  CU_ASSERT(pdu->data == (unsigned char *)pdu->hdr + 13);
+  CU_ASSERT(memcmp(pdu->data, teststr + 13, 7) == 0);
+}
+
+static void
+t_parse_pdu8(void) {
+  /* PDU without options but with payload */
+  uint8_t teststr[] = {  0x50, 0x73, 0x12, 0x34,
+		      0xff, 'p', 'a', 'y', 'l', 'o', 'a',
+		      'd'
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_NON);
+  CU_ASSERT(pdu->hdr->token_length == 0);
+  CU_ASSERT(pdu->hdr->code == 0x73);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+
+  /* FIXME: check options */
+
+  CU_ASSERT(pdu->data == (unsigned char *)pdu->hdr + 5);
+  CU_ASSERT(memcmp(pdu->data, teststr + 5, 7) == 0);
+}
+
+static void
+t_parse_pdu9(void) {
+  /* PDU without options and payload but with payload start marker */
+  uint8_t teststr[] = {  0x70, 0x00, 0x12, 0x34, 0xff };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu10(void) {
+  /* PDU without payload but with options and payload start marker */
+  uint8_t teststr[] = {  0x53, 0x73, 0x12, 0x34, 't', 'o', 'k',
+		      0x30, 0xc1, 0x00, 0xff
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu11(void) {
+  uint8_t teststr[] = {  0x60, 0x00, 0x12, 0x34 };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_ACK);
+  CU_ASSERT(pdu->hdr->token_length == 0);
+  CU_ASSERT(pdu->hdr->code == 0);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+}
+
+static void
+t_parse_pdu12(void) {
+  /* RST */
+  uint8_t teststr[] = {  0x70, 0x00, 0x12, 0x34 };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(pdu->hdr->version == 1);
+  CU_ASSERT(pdu->hdr->type == COAP_MESSAGE_RST);
+  CU_ASSERT(pdu->hdr->token_length == 0);
+  CU_ASSERT(pdu->hdr->code == 0);
+  CU_ASSERT(memcmp(&pdu->hdr->id, teststr + 2, 2) == 0);
+}
+
+static void
+t_parse_pdu13(void) {
+  /* RST with content */
+  uint8_t teststr[] = {  0x70, 0x00, 0x12, 0x34,
+		      0xff, 'c', 'o', 'n', 't', 'e', 'n', 't'
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_pdu14(void) {
+  /* ACK with content */
+  uint8_t teststr[] = {  0x60, 0x00, 0x12, 0x34,
+		      0xff, 'c', 'o', 'n', 't', 'e', 'n', 't'
+  };
+  int result;
+
+  result = coap_pdu_parse((unsigned char *)teststr, sizeof(teststr), pdu);
+  CU_ASSERT(result == 0);
+}
+
+/************************************************************************
+ ** PDU encoder
+ ************************************************************************/
+
+static void
+t_encode_pdu1(void) {
+  uint8_t teststr[] = { 0x45, 0x01, 0x12, 0x34, 't', 'o', 'k', 'e', 'n' };
+  int result;
+
+  coap_pdu_clear(pdu, pdu->max_size);
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  pdu->hdr->code = COAP_REQUEST_GET;
+  pdu->hdr->id = htons(0x1234);
+
+  result = coap_add_token(pdu, 5, (unsigned char *)"token");
+
+  CU_ASSERT(result == 1);
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT_PTR_NULL(pdu->data);
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu2(void) {
+  size_t old_max = pdu->max_size;
+  int result;
+
+  coap_pdu_clear(pdu, 7);	/* set very small PDU size */
+
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  pdu->hdr->code = COAP_REQUEST_GET;
+  pdu->hdr->id = htons(0x1234);
+
+  result = coap_add_token(pdu, 5, (unsigned char *)"token");
+
+  CU_ASSERT(result == 0);
+
+  coap_pdu_clear(pdu, old_max);	/* restore PDU size */
+}
+
+static void
+t_encode_pdu3(void) {
+  int result;
+
+  result = coap_add_token(pdu, 9, (unsigned char *)"123456789");
+
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_encode_pdu4(void) {
+  /* PDU with options */
+  uint8_t teststr[] = { 0x60, 0x99, 0x12, 0x34, 0x3d, 0x05, 0x66, 0x61,
+		     0x6e, 0x63, 0x79, 0x70, 0x72, 0x6f, 0x78, 0x79,
+		     0x2e, 0x63, 0x6f, 0x61, 0x70, 0x2e, 0x6d, 0x65,
+		     0x84, 0x70, 0x61, 0x74, 0x68, 0x00, 0xe8, 0x1e,
+		     0x28, 0x66, 0x61, 0x6e, 0x63, 0x79, 0x6f, 0x70,
+		     0x74
+  };
+  int result;
+
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_ACK;
+  pdu->hdr->code = 0x99;
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_option(pdu, COAP_OPTION_URI_HOST,
+       18, (unsigned char *)"fancyproxy.coap.me");
+
+  CU_ASSERT(result == 20);
+  CU_ASSERT(pdu->max_delta == 3);
+  CU_ASSERT(pdu->length == 24);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_URI_PATH,
+			   4, (unsigned char *)"path");
+
+  CU_ASSERT(result == 5);
+  CU_ASSERT(pdu->max_delta == 11);
+  CU_ASSERT(pdu->length == 29);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_URI_PATH, 0, NULL);
+
+  CU_ASSERT(result == 1);
+  CU_ASSERT(pdu->max_delta == 11);
+  CU_ASSERT(pdu->length == 30);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, 8000, 8, (unsigned char *)"fancyopt");
+
+  CU_ASSERT(result == 11);
+  CU_ASSERT(pdu->max_delta == 8000);
+  CU_ASSERT(pdu->length == 41);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu5(void) {
+  /* PDU with token and options */
+  uint8_t teststr[] = { 0x68, 0x84, 0x12, 0x34, '1',  '2',  '3',  '4',
+                     '5',  '6',  '7',  '8',  0x18, 0x41, 0x42, 0x43,
+		     0x44, 0x45, 0x46, 0x47, 0x48, 0xd1, 0x03, 0x12
+  };
+  int result;
+
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_ACK;
+  pdu->hdr->code = COAP_RESPONSE_CODE(404);
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_token(pdu, 8, (unsigned char *)"12345678");
+
+  CU_ASSERT(pdu->length == 12);
+
+  result = coap_add_option(pdu, COAP_OPTION_IF_MATCH,
+			   8, (unsigned char *)"ABCDEFGH");
+
+  CU_ASSERT(result == 9);
+  CU_ASSERT(pdu->max_delta == 1);
+  CU_ASSERT(pdu->length == 21);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_ACCEPT,
+			   1, (unsigned char *)"\x12");
+
+  CU_ASSERT(result == 3);
+  CU_ASSERT(pdu->max_delta == 17);
+  CU_ASSERT(pdu->length == 24);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu6(void) {
+  /* PDU with data */
+  uint8_t teststr[] = { 0x50, 0x02, 0x12, 0x34, 0xff, '1',  '2',  '3',
+		     '4', '5',  '6',  '7',  '8'
+  };
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_NON;
+  pdu->hdr->code = COAP_REQUEST_POST;
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  coap_add_data(pdu, 8, (unsigned char *)"12345678");
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu7(void) {
+  /* PDU with empty data */
+  uint8_t teststr[] = { 0x40, 0x43, 0x12, 0x34 };
+  int result;
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  pdu->hdr->code = COAP_RESPONSE_CODE(203);
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_data(pdu, 0, NULL);
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT(pdu->length == 4);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu8(void) {
+  /* PDU with token and data */
+  uint8_t teststr[] = { 0x42, 0x43, 0x12, 0x34, 0x00, 0x01, 0xff, 0x00 };
+  int result;
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_CON;
+  pdu->hdr->code = COAP_RESPONSE_CODE(203);
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_token(pdu, 2, (unsigned char *)"\x00\x01");
+
+  CU_ASSERT(result > 0);
+
+  result = coap_add_data(pdu, 1, (unsigned char *)"\0");
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT(pdu->length == 8);
+  CU_ASSERT(pdu->data == (unsigned char *)pdu->hdr + 7);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu9(void) {
+  /* PDU with options and data */
+  uint8_t teststr[] = { 0x60, 0x44, 0x12, 0x34, 0x48, 's',  'o',  'm',
+		     'e',  'e',  't',  'a',  'g',  0x10, 0xdd, 0x11,
+		     0x04, 's',  'o',  'm',  'e',  'r',  'a',  't',
+		     'h',  'e',  'r',  'l',  'o',  'n',  'g',  'u',
+		     'r',  'i',  0xff, 'd',  'a',  't',  'a'
+  };
+  int result;
+
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_ACK;
+  pdu->hdr->code = COAP_RESPONSE_CODE(204);
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_option(pdu, COAP_OPTION_ETAG, 8, (unsigned char *)"someetag");
+
+  CU_ASSERT(result == 9);
+  CU_ASSERT(pdu->max_delta == 4);
+  CU_ASSERT(pdu->length == 13);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_IF_NONE_MATCH, 0, NULL);
+
+  CU_ASSERT(result == 1);
+  CU_ASSERT(pdu->max_delta == 5);
+  CU_ASSERT(pdu->length == 14);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_PROXY_URI,
+			   17, (unsigned char *)"someratherlonguri");
+
+  CU_ASSERT(result == 20);
+  CU_ASSERT(pdu->max_delta == 35);
+  CU_ASSERT(pdu->length == 34);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_data(pdu, 4, (unsigned char *)"data");
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT(pdu->length == 39);
+  CU_ASSERT(pdu->data == (unsigned char *)pdu->hdr + 35);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu10(void) {
+  /* PDU with token, options and data */
+  uint8_t teststr[] = { 0x62, 0x44, 0x12, 0x34, 0x00, 0x00, 0x8d, 0xf2,
+		     'c',  'o',  'a',  'p',  ':',  '/',  '/',  'e',
+		     'x',  'a',  'm',  'p',  'l',  'e',  '.',  'c',
+		     'o',  'm',  '/',  '1',  '2',  '3',  '4',  '5',
+		     '/',  '%',  '3',  'F',  'x',  'y',  'z',  '/',
+		     '3',  '0',  '4',  '8',  '2',  '3',  '4',  '2',
+		     '3',  '4',  '/',  '2',  '3',  '4',  '0',  '2',
+		     '3',  '4',  '8',  '2',  '3',  '4',  '/',  '2',
+		     '3',  '9',  '0',  '8',  '4',  '2',  '3',  '4',
+		     '-',  '2',  '3',  '/',  '%',  'A',  'B',  '%',
+		     '3',  '0',  '%',  'a',  'f',  '/',  '+',  '1',
+		     '2',  '3',  '/',  'h',  'f',  'k',  's',  'd',
+		     'h',  '/',  '2',  '3',  '4',  '8',  '0',  '-',
+		     '2',  '3',  '4',  '-',  '9',  '8',  '2',  '3',
+		     '5',  '/',  '1',  '2',  '0',  '4',  '/',  '2',
+		     '4',  '3',  '5',  '4',  '6',  '3',  '4',  '5',
+		     '3',  '4',  '5',  '2',  '4',  '3',  '/',  '0',
+		     '1',  '9',  '8',  's',  'd',  'n',  '3',  '-',
+		     'a',  '-',  '3',  '/',  '/',  '/',  'a',  'f',
+		     'f',  '0',  '9',  '3',  '4',  '/',  '9',  '7',
+		     'u',  '2',  '1',  '4',  '1',  '/',  '0',  '0',
+		     '0',  '2',  '/',  '3',  '9',  '3',  '2',  '4',
+		     '2',  '3',  '5',  '3',  '2',  '/',  '5',  '6',
+		     '2',  '3',  '4',  '0',  '2',  '3',  '/',  '-',
+		     '-',  '-',  '-',  '/',  '=',  '1',  '2',  '3',
+		     '4',  '=',  '/',  '0',  '9',  '8',  '1',  '4',
+		     '1',  '-',  '9',  '5',  '6',  '4',  '6',  '4',
+		     '3',  '/',  '2',  '1',  '9',  '7',  '0',  '-',
+		     '-',  '-',  '-',  '-',  '/',  '8',  '2',  '3',
+		     '6',  '4',  '9',  '2',  '3',  '4',  '7',  '2',
+		     'w',  'e',  'r',  'e',  'r',  'e',  'w',  'r',
+		     '0',  '-',  '9',  '2',  '1',  '-',  '3',  '9',
+		     '1',  '2',  '3',  '-',  '3',  '4',  '/',  0x0d,
+		     0x01, '/',  '/',  '4',  '9',  '2',  '4',  '0',
+		     '3',  '-',  '-',  '0',  '9',  '8',  '/',  0xc1,
+		     '*',  0xff, 'd',  'a',  't',  'a'
+  };
+  int result;
+
+  coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+  pdu->hdr->type = COAP_MESSAGE_ACK;
+  pdu->hdr->code = COAP_RESPONSE_CODE(204);
+  pdu->hdr->id = htons(0x1234);
+
+  CU_ASSERT(pdu->length == 4);
+
+  result = coap_add_token(pdu, 2, (unsigned char *)"\0\0");
+
+  CU_ASSERT(result > 0);
+  result = coap_add_option(pdu, COAP_OPTION_LOCATION_PATH, 255,
+			   (unsigned char *)"coap://example.com/12345/%3Fxyz/3048234234/23402348234/239084234-23/%AB%30%af/+123/hfksdh/23480-234-98235/1204/243546345345243/0198sdn3-a-3///aff0934/97u2141/0002/3932423532/56234023/----/=1234=/098141-9564643/21970-----/82364923472wererewr0-921-39123-34/");
+
+  CU_ASSERT(result == 257);
+  CU_ASSERT(pdu->max_delta == 8);
+  CU_ASSERT(pdu->length == 263);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_LOCATION_PATH, 14,
+			   (unsigned char *)"//492403--098/");
+
+  CU_ASSERT(result == 16);
+  CU_ASSERT(pdu->max_delta == 8);
+  CU_ASSERT(pdu->length == 279);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_option(pdu, COAP_OPTION_LOCATION_QUERY,
+			   1, (unsigned char *)"*");
+
+  CU_ASSERT(result == 2);
+  CU_ASSERT(pdu->max_delta == 20);
+  CU_ASSERT(pdu->length == 281);
+  CU_ASSERT_PTR_NULL(pdu->data);
+
+  result = coap_add_data(pdu, 4, (unsigned char *)"data");
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT(pdu->length == 286);
+  CU_ASSERT(pdu->data == (unsigned char *)pdu->hdr + 282);
+
+  CU_ASSERT(pdu->length == sizeof(teststr));
+  CU_ASSERT(memcmp(pdu->hdr, teststr, sizeof(teststr)) == 0);
+}
+
+static void
+t_encode_pdu11(void) {
+  coap_log_t level = coap_get_log_level();
+  /* data too long for PDU */
+  size_t old_max = pdu->max_size;
+  int result;
+
+  coap_pdu_clear(pdu, 8);	/* clear PDU, with small maximum */
+
+  CU_ASSERT(pdu->data == NULL);
+  coap_set_log_level(LOG_CRIT);
+  result = coap_add_data(pdu, 10, (unsigned char *)"0123456789");
+  coap_set_log_level(level);
+
+  CU_ASSERT(result == 0);
+  CU_ASSERT(pdu->data == NULL);
+
+  pdu->max_size = old_max;
+}
+
+static int
+t_pdu_tests_create(void) {
+  pdu = coap_pdu_init(0, 0, 0, COAP_MAX_PDU_SIZE);
+
+  return pdu == NULL;
+}
+
+static int
+t_pdu_tests_remove(void) {
+  coap_delete_pdu(pdu);
+  return 0;
+}
+
+CU_pSuite
+t_init_pdu_tests(void) {
+  CU_pSuite suite[2];
+
+  suite[0] = CU_add_suite("pdu parser", t_pdu_tests_create, t_pdu_tests_remove);
+  if (!suite[0]) {			/* signal error */
+    fprintf(stderr, "W: cannot add pdu parser test suite (%s)\n",
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define PDU_TEST(s,t)						      \
+  if (!CU_ADD_TEST(s,t)) {					      \
+    fprintf(stderr, "W: cannot add pdu parser test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+
+  PDU_TEST(suite[0], t_parse_pdu1);
+  PDU_TEST(suite[0], t_parse_pdu2);
+  PDU_TEST(suite[0], t_parse_pdu3);
+  PDU_TEST(suite[0], t_parse_pdu4);
+  PDU_TEST(suite[0], t_parse_pdu5);
+  PDU_TEST(suite[0], t_parse_pdu6);
+  PDU_TEST(suite[0], t_parse_pdu7);
+  PDU_TEST(suite[0], t_parse_pdu8);
+  PDU_TEST(suite[0], t_parse_pdu9);
+  PDU_TEST(suite[0], t_parse_pdu10);
+  PDU_TEST(suite[0], t_parse_pdu11);
+  PDU_TEST(suite[0], t_parse_pdu12);
+  PDU_TEST(suite[0], t_parse_pdu13);
+  PDU_TEST(suite[0], t_parse_pdu14);
+
+  suite[1] = CU_add_suite("pdu encoder", t_pdu_tests_create, t_pdu_tests_remove);
+  if (suite[1]) {
+#define PDU_ENCODER_TEST(s,t)						      \
+  if (!CU_ADD_TEST(s,t)) {					      \
+    fprintf(stderr, "W: cannot add pdu encoder test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu1);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu2);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu3);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu4);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu5);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu6);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu7);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu8);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu9);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu10);
+    PDU_ENCODER_TEST(suite[1], t_encode_pdu11);
+
+  } else 			/* signal error */
+    fprintf(stderr, "W: cannot add pdu parser test suite (%s)\n",
+	    CU_get_error_msg());
+
+  return suite[0];
+}
+
diff --git a/components/coap/libcoap/tests/test_pdu.h b/components/coap/libcoap/tests/test_pdu.h
new file mode 100644
index 00000000..992b3772
--- /dev/null
+++ b/components/coap/libcoap/tests/test_pdu.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_pdu_tests(void);
diff --git a/components/coap/libcoap/tests/test_sendqueue.c b/components/coap/libcoap/tests/test_sendqueue.c
new file mode 100644
index 00000000..82d69d20
--- /dev/null
+++ b/components/coap/libcoap/tests/test_sendqueue.c
@@ -0,0 +1,367 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+#include "test_sendqueue.h"
+
+#include <coap.h>
+
+#include <stdio.h>
+
+static coap_queue_t *sendqueue;
+
+/* timestamps for tests. The first element in this array denotes the
+ * base time in ticks, the following elements are timestamps relative
+ * to this basetime.
+ */
+static coap_tick_t timestamp[] = {
+  0, 100, 200, 30, 160
+};
+
+/* nodes for testing. node[0] is left empty */
+coap_queue_t *node[5];
+
+static coap_tick_t
+add_timestamps(coap_queue_t *queue, size_t num) {
+  coap_tick_t t = 0;
+  while (queue && num--) {
+    t += queue->t;
+    queue = queue->next;
+  }
+
+  return t;
+}
+
+static void
+t_sendqueue1(void) {
+  int result = coap_insert_node(&sendqueue, node[1]);
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT_PTR_NOT_NULL(sendqueue);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
+  CU_ASSERT(node[1]->t == timestamp[1]);
+}
+
+static void
+t_sendqueue2(void) {
+  int result;
+
+  result = coap_insert_node(&sendqueue, node[2]);
+
+  CU_ASSERT(result > 0);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next, node[2]);
+
+  CU_ASSERT(sendqueue->t == timestamp[1]);
+  CU_ASSERT(node[2]->t == timestamp[2] - timestamp[1]);
+}
+
+/* insert new node as first element in queue */
+static void
+t_sendqueue3(void) {
+  int result;
+  result = coap_insert_node(&sendqueue, node[3]);
+
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
+  CU_ASSERT(node[3]->t == timestamp[3]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next);
+
+  CU_ASSERT(sendqueue->next->t == timestamp[1] - timestamp[3]);
+  CU_ASSERT(sendqueue->next->next->t == timestamp[2] - timestamp[1]);
+}
+
+/* insert new node as fourth element in queue */
+static void
+t_sendqueue4(void) {
+  int result;
+
+  result = coap_insert_node(&sendqueue, node[4]);
+
+  CU_ASSERT(result > 0);
+
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next, node[1]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next->next, node[4]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next->next->next);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next->next->next, node[2]);
+
+  CU_ASSERT(sendqueue->next->t == timestamp[1] - timestamp[3]);
+  CU_ASSERT(add_timestamps(sendqueue, 1) == timestamp[3]);
+  CU_ASSERT(add_timestamps(sendqueue, 2) == timestamp[1]);
+  CU_ASSERT(add_timestamps(sendqueue, 3) == timestamp[4]);
+  CU_ASSERT(add_timestamps(sendqueue, 4) == timestamp[2]);
+}
+
+static void
+t_sendqueue5(void) {
+  const coap_tick_diff_t delta1 = 20, delta2 = 130;
+  unsigned int result;
+  coap_tick_t now;
+  struct coap_context_t ctx;
+
+  /* space for saving the current node timestamps */
+  static coap_tick_t times[sizeof(timestamp)/sizeof(coap_tick_t)];
+  coap_queue_t *p;
+  int i;
+
+  /* save timestamps of nodes in the sendqueue in their actual order */
+  memset(times, 0, sizeof(times));
+  for (p = sendqueue, i = 0; p; p = p->next, i++) {
+    times[i] = p->t;
+  }
+
+  coap_ticks(&now);
+  ctx.sendqueue = sendqueue;
+  ctx.sendqueue_basetime = now;
+
+  now -= delta1;
+  result = coap_adjust_basetime(&ctx, now);
+
+  CU_ASSERT(result == 0);
+  CU_ASSERT_PTR_NOT_NULL(ctx.sendqueue);
+  CU_ASSERT(ctx.sendqueue_basetime == now);
+  CU_ASSERT(ctx.sendqueue->t == timestamp[3] + delta1);
+
+  now += delta2;
+  result = coap_adjust_basetime(&ctx, now);
+  CU_ASSERT(result == 2);
+  CU_ASSERT(ctx.sendqueue_basetime == now);
+  CU_ASSERT_PTR_NOT_NULL(ctx.sendqueue);
+  CU_ASSERT(ctx.sendqueue->t == 0);
+
+  CU_ASSERT_PTR_NOT_NULL(ctx.sendqueue->next);
+  CU_ASSERT(ctx.sendqueue->next->t == 0);
+
+  CU_ASSERT_PTR_NOT_NULL(ctx.sendqueue->next->next);
+  CU_ASSERT(ctx.sendqueue->next->next->t == delta2 - delta1 - timestamp[1]);
+
+  /* restore timestamps of nodes in the sendqueue */
+  for (p = sendqueue, i = 0; p; p = p->next, i++) {
+    p->t = times[i];
+  }
+}
+
+static void
+t_sendqueue6(void) {
+  unsigned int result;
+  coap_tick_t now;
+  const coap_tick_diff_t delta = 20;
+  struct coap_context_t ctx;
+
+  /* space for saving the current node timestamps */
+  static coap_tick_t times[sizeof(timestamp)/sizeof(coap_tick_t)];
+  coap_queue_t *p;
+  int i;
+
+  /* save timestamps of nodes in the sendqueue in their actual order */
+  memset(times, 0, sizeof(times));
+  for (p = sendqueue, i = 0; p; p = p->next, i++) {
+    times[i] = p->t;
+  }
+
+  coap_ticks(&now);
+  ctx.sendqueue = NULL;
+  ctx.sendqueue_basetime = now;
+
+  result = coap_adjust_basetime(&ctx, now + delta);
+
+  CU_ASSERT(result == 0);
+  CU_ASSERT(ctx.sendqueue_basetime == now + delta);
+
+  /* restore timestamps of nodes in the sendqueue */
+  for (p = sendqueue, i = 0; p; p = p->next, i++) {
+    p->t = times[i];
+  }
+}
+
+static void
+t_sendqueue7(void) {
+  int result;
+  coap_queue_t *tmp_node;
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[3]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next, node[1]);
+
+  result = coap_remove_from_queue(&sendqueue, 3, &tmp_node);
+
+  CU_ASSERT(result == 1);
+  CU_ASSERT_PTR_NOT_NULL(tmp_node);
+  CU_ASSERT_PTR_EQUAL(tmp_node, node[3]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
+
+  CU_ASSERT(sendqueue->t == timestamp[1]);
+}
+
+static void
+t_sendqueue8(void) {
+  int result;
+  coap_queue_t *tmp_node;
+
+  result = coap_remove_from_queue(&sendqueue, 4, &tmp_node);
+
+  CU_ASSERT(result == 1);
+  CU_ASSERT_PTR_NOT_NULL(tmp_node);
+  CU_ASSERT_PTR_EQUAL(tmp_node, node[4]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[1]);
+  CU_ASSERT(sendqueue->t == timestamp[1]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue->next);
+  CU_ASSERT_PTR_EQUAL(sendqueue->next, node[2]);
+  CU_ASSERT(sendqueue->next->t == timestamp[2] - timestamp[1]);
+
+  CU_ASSERT_PTR_NULL(sendqueue->next->next);
+}
+
+static void
+t_sendqueue9(void) {
+  coap_queue_t *tmp_node;
+  struct coap_context_t ctx;
+
+  /* Initialize a fake context that points to our global sendqueue
+   * Note that all changes happen on ctx.sendqueue. */
+  ctx.sendqueue = sendqueue;
+  tmp_node = coap_peek_next(&ctx);
+  sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
+
+  CU_ASSERT_PTR_NOT_NULL(tmp_node);
+  CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
+  CU_ASSERT_PTR_EQUAL(tmp_node, ctx.sendqueue);
+
+  tmp_node = coap_pop_next(&ctx);
+  sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
+
+  CU_ASSERT_PTR_NOT_NULL(tmp_node);
+  CU_ASSERT_PTR_EQUAL(tmp_node, node[1]);
+
+  CU_ASSERT_PTR_NOT_NULL(sendqueue);
+  CU_ASSERT_PTR_EQUAL(sendqueue, node[2]);
+
+  CU_ASSERT(tmp_node->t == timestamp[1]);
+  CU_ASSERT(sendqueue->t == timestamp[2]);
+
+  CU_ASSERT_PTR_NULL(sendqueue->next);
+}
+
+static void
+t_sendqueue10(void) {
+  coap_queue_t *tmp_node;
+  struct coap_context_t ctx;
+
+  /* Initialize a fake context that points to our global sendqueue
+   * Note that all changes happen on ctx.sendqueue. */
+  ctx.sendqueue = sendqueue;
+
+  tmp_node = coap_pop_next(&ctx);
+  sendqueue = ctx.sendqueue;	/* must update global sendqueue for correct result */
+
+  CU_ASSERT_PTR_NOT_NULL(tmp_node);
+  CU_ASSERT_PTR_EQUAL(tmp_node, node[2]);
+
+  CU_ASSERT_PTR_NULL(sendqueue);
+
+  CU_ASSERT(tmp_node->t == timestamp[2]);
+}
+
+/* This function creates a set of nodes for testing. These nodes
+ * will exist for all tests and are modified by coap_insert_node()
+ * and coap_remove_from_queue().
+ */
+static int
+t_sendqueue_tests_create(void) {
+  size_t n, error = 0;
+  sendqueue = NULL;
+  coap_ticks(&timestamp[0]);
+
+  memset(node, 0, sizeof(node));
+  for (n = 1; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
+    node[n] = coap_new_node();
+    if (!node[n]) {
+      error = 1;
+      break;
+    }
+
+    node[n]->id = n;
+    node[n]->t = timestamp[n];
+  }
+
+  if (error) {
+    /* destroy all test nodes and set entry to zero */
+    for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
+      if (node[n]) {
+	coap_delete_node(node[n]);
+	node[n] = NULL;
+      }
+    }
+  }
+
+  return error;
+}
+
+static int
+t_sendqueue_tests_remove(void) {
+  size_t n;
+
+  /* destroy all test nodes */
+  for (n = 0; n < sizeof(node)/sizeof(coap_queue_t *); n++) {
+    if (node[n]) {
+      coap_delete_node(node[n]);
+    }
+  }
+
+  return 0;
+}
+
+CU_pSuite
+t_init_sendqueue_tests(void) {
+  CU_pSuite suite;
+
+  suite = CU_add_suite("sendqueue",
+		       t_sendqueue_tests_create, t_sendqueue_tests_remove);
+  if (!suite) {			/* signal error */
+    fprintf(stderr, "W: cannot add sendqueue test suite (%s)\n",
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define SENDQUEUE_TEST(s,t)					      \
+  if (!CU_ADD_TEST(s,t)) {					      \
+    fprintf(stderr, "W: cannot add sendqueue test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+
+  SENDQUEUE_TEST(suite, t_sendqueue1);
+  SENDQUEUE_TEST(suite, t_sendqueue2);
+  SENDQUEUE_TEST(suite, t_sendqueue3);
+  SENDQUEUE_TEST(suite, t_sendqueue4);
+  SENDQUEUE_TEST(suite, t_sendqueue5);
+  SENDQUEUE_TEST(suite, t_sendqueue6);
+  SENDQUEUE_TEST(suite, t_sendqueue7);
+  SENDQUEUE_TEST(suite, t_sendqueue8);
+  SENDQUEUE_TEST(suite, t_sendqueue9);
+  SENDQUEUE_TEST(suite, t_sendqueue10);
+
+  return suite;
+}
+
diff --git a/components/coap/libcoap/tests/test_sendqueue.h b/components/coap/libcoap/tests/test_sendqueue.h
new file mode 100644
index 00000000..56f3c1ed
--- /dev/null
+++ b/components/coap/libcoap/tests/test_sendqueue.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_sendqueue_tests(void);
diff --git a/components/coap/libcoap/tests/test_uri.c b/components/coap/libcoap/tests/test_uri.c
new file mode 100644
index 00000000..004cbd6a
--- /dev/null
+++ b/components/coap/libcoap/tests/test_uri.c
@@ -0,0 +1,463 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012,2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include "coap_config.h"
+#include "test_uri.h"
+
+#include <coap.h>
+
+#include <stdio.h>
+
+static void
+t_parse_uri1(void) {
+  char teststr[] = "coap://[::1]/.well-known/core";
+
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 3);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "::1", 3);
+
+    CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
+
+    CU_ASSERT(uri.path.length == 16);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
+
+    CU_ASSERT(uri.query.length == 0);    
+    CU_ASSERT(uri.query.s == NULL);    
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri2(void) {
+  char teststr[] = "coap://[::1]:8000/.well-known/core";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 3);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "::1", 3);
+
+    CU_ASSERT(uri.port == 8000);
+
+    CU_ASSERT(uri.path.length == 16);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
+
+    CU_ASSERT(uri.query.length == 0);    
+    CU_ASSERT(uri.query.s == NULL);    
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri3(void) {
+  char teststr[] = "coap://localhost/?foo&bla=fasel";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 9);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "localhost", 9);
+
+    CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
+
+    CU_ASSERT(uri.path.length == 0);
+
+    CU_ASSERT(uri.query.length == 13);    
+    CU_ASSERT_NSTRING_EQUAL(uri.query.s, "foo&bla=fasel", 13);
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri4(void) {
+  char teststr[] = "coap://:100000";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  CU_ASSERT(result < 0);
+}
+
+static void
+t_parse_uri5(void) {
+  char teststr[] = "coap://foo:100000";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 3);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "foo", 3);
+
+    CU_ASSERT(uri.path.length == 0);
+    CU_ASSERT(uri.path.s == NULL);
+
+    CU_ASSERT(uri.query.length == 0);
+    CU_ASSERT(uri.query.s == NULL);
+
+    CU_FAIL("invalid port not detected");
+  } else {
+    CU_PASS("detected invalid port");
+  }
+}
+
+static void
+t_parse_uri6(void) {
+  char teststr[] = "coap://134.102.218.2/.well-known/core";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 13);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "134.102.218.2", 13);
+
+    CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
+
+    CU_ASSERT(uri.path.length == 16);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, ".well-known/core", 16);
+
+    CU_ASSERT(uri.query.length == 0);    
+    CU_ASSERT(uri.query.s == NULL);    
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri7(void) {
+  char teststr[] = "coap://foo.bar:5683/some_resource/with/multiple/segments";
+  int result;
+  coap_uri_t uri;
+  unsigned char buf[40];
+  size_t buflen = sizeof(buf);
+
+  /* The list of path segments to check against. Each segment is
+     preceded by a dummy option indicating that holds the (dummy)
+     delta value 0 and the actual segment length. */
+  const unsigned char checkbuf[] = {
+    0x0d, 0x00, 's', 'o', 'm', 'e', '_', 'r', 'e', 's', 'o', 'u', 'r', 'c', 'e',
+    0x04, 'w', 'i', 't', 'h',
+    0x08, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e',
+    0x08, 's', 'e', 'g', 'm', 'e', 'n', 't', 's'
+  };
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 7);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "foo.bar", 7);
+
+    CU_ASSERT(uri.port == 5683);
+
+    CU_ASSERT(uri.path.length == 36);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, "some_resource/with/multiple/segments", 36);
+
+    CU_ASSERT(uri.query.length == 0);
+    CU_ASSERT(uri.query.s == NULL);    
+
+    /* check path segments */
+    result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+    CU_ASSERT(result == 4);
+    CU_ASSERT(buflen == sizeof(checkbuf));
+    CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen);
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri8(void) {
+  char teststr[] = "http://example.com/%7E%AB%13";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result < 0) {
+    CU_PASS("detected non-coap URI");
+  } else {
+    CU_FAIL("non-coap URI not recognized");
+  }
+}
+
+static void
+t_parse_uri9(void) {
+  char teststr[] = "http://example.com/%x";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result < 0) {
+    CU_PASS("detected non-coap URI");
+  } else {
+    CU_FAIL("non-coap URI not recognized");
+  }
+}
+
+static void
+t_parse_uri10(void) {
+  char teststr[] = "/absolute/path";
+  int result;
+  coap_uri_t uri;
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 0);
+    CU_ASSERT(uri.host.s == NULL);
+
+    CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
+
+    CU_ASSERT(uri.path.length == 13);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, "absolute/path", 13);
+
+    CU_ASSERT(uri.query.length == 0);    
+    CU_ASSERT(uri.query.s == NULL);    
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri11(void) {
+  char teststr[] = 
+    "coap://xn--18j4d.example/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF";
+  int result;
+  coap_uri_t uri;
+  unsigned char buf[40];
+  size_t buflen = sizeof(buf);
+
+  /* The list of path segments to check against. Each segment is
+     preceded by a dummy option indicating that holds the (dummy)
+     delta value 0 and the actual segment length. */
+  const unsigned char checkbuf[] = {
+    0x0d, 0x02, 0xE3, 0x81, 0x93, 0xE3, 0x82, 0x93, 
+    0xE3, 0x81, 0xAB, 0xE3, 0x81, 0xA1, 0xE3, 0x81, 
+    0xAF
+  };
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 17);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "xn--18j4d.example", 17);
+
+    CU_ASSERT(uri.port == COAP_DEFAULT_PORT);
+
+    CU_ASSERT(uri.path.length == 45);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, 
+			    "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF", 45);
+
+    CU_ASSERT(uri.query.length == 0);    
+    CU_ASSERT(uri.query.s == NULL);    
+    
+    /* check path segments */
+    result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+    CU_ASSERT(result == 1);
+    CU_ASSERT(buflen == sizeof(checkbuf));
+    CU_ASSERT_NSTRING_EQUAL(buf, checkbuf, buflen);
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri12(void) {
+  char teststr[] = "coap://198.51.100.1:61616//%2F//?%2F%2F&?%26";
+  int result;
+  coap_uri_t uri;
+  unsigned char buf[40];
+  size_t buflen = sizeof(buf);
+
+  /* The list of path segments to check against. Each segment is
+     preceded by a dummy option indicating that holds the (dummy)
+     delta value 0 and the actual segment length. */
+  const unsigned char uricheckbuf[] = { 0x00, 0x01, 0x2f, 0x00, 0x00 };
+  const unsigned char querycheckbuf[] = { 0x02, 0x2f, 0x2f, 0x02, 0x3f, 0x26 };
+
+  result = coap_split_uri((unsigned char *)teststr, strlen(teststr), &uri);
+  if (result == 0) {
+    CU_ASSERT(uri.host.length == 12);
+    CU_ASSERT_NSTRING_EQUAL(uri.host.s, "198.51.100.1", 12);
+
+    CU_ASSERT(uri.port == 61616);
+
+    CU_ASSERT(uri.path.length == 6);
+    CU_ASSERT_NSTRING_EQUAL(uri.path.s, "/%2F//", 6);
+
+    CU_ASSERT(uri.query.length == 11);
+    CU_ASSERT_NSTRING_EQUAL(uri.query.s, "%2F%2F&?%26", 11);
+
+    /* check path segments */
+    result = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
+    CU_ASSERT(result == 4);
+    CU_ASSERT(buflen == sizeof(uricheckbuf));
+    CU_ASSERT_NSTRING_EQUAL(buf, uricheckbuf, buflen);
+
+    /* check query segments */
+    buflen = sizeof(buf);
+    result = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
+    CU_ASSERT(result == 2);
+    CU_ASSERT(buflen == sizeof(querycheckbuf));
+    CU_ASSERT_NSTRING_EQUAL(buf, querycheckbuf, buflen);
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri13(void) {
+  uint8_t teststr[] __attribute__ ((aligned (8))) = { 
+    0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 'f',  'o',
+    'o',  0x3b, '.',  'w',  'e',  'l',  'l',  '-',  
+    'k',  'n',  'o',  'w',  'n',  0x04,  'c', 'o',  
+    'r',  'e'
+  };
+
+  coap_pdu_t pdu = { 
+    .max_size = sizeof(teststr),
+    .hdr = (coap_hdr_t *)teststr,
+    .length = sizeof(teststr)
+  };
+
+  coap_key_t key;
+
+  coap_hash_request_uri(&pdu, key);
+  
+  CU_ASSERT(sizeof(key) == sizeof(COAP_DEFAULT_WKC_HASHKEY) - 1);
+  CU_ASSERT_NSTRING_EQUAL(key, COAP_DEFAULT_WKC_HASHKEY, sizeof(key));
+}
+
+static void
+t_parse_uri14(void) {
+  char teststr[] =
+    "longerthan13lessthan270=0123456789012345678901234567890123456789";
+  int result;
+
+  /* buf is large enough to hold sizeof(teststr) - 1 bytes content and
+   * 2 bytes for the option header. */
+  unsigned char buf[sizeof(teststr) + 1];
+  size_t buflen = sizeof(buf);
+
+  result = coap_split_query((unsigned char *)teststr, strlen(teststr),
+                            buf, &buflen);
+  if (result >= 0) {
+    CU_ASSERT(buf[0] == 0x0d);
+    CU_ASSERT(buf[1] == strlen(teststr) - 13);
+
+    CU_ASSERT_NSTRING_EQUAL(buf+2, teststr, strlen(teststr));
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+static void
+t_parse_uri15(void) {
+  char teststr[] =
+    "longerthan13lessthan270=0123456789012345678901234567890123456789";
+  int result;
+
+  /* buf is too small to hold sizeof(teststr) - 1 bytes content and 2
+   * bytes for the option header. */
+  unsigned char buf[sizeof(teststr) - 1];
+  size_t buflen = sizeof(buf);
+
+  result = coap_split_query((unsigned char *)teststr, strlen(teststr),
+                            buf, &buflen);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_uri16(void) {
+  char teststr[] =
+    "longerthan13lessthan270=0123456789012345678901234567890123456789";
+  int result;
+
+  /* buf is too small to hold the option header. */
+  unsigned char buf[1];
+  size_t buflen = sizeof(buf);
+
+  result = coap_split_query((unsigned char *)teststr, strlen(teststr),
+                            buf, &buflen);
+  CU_ASSERT(result == 0);
+}
+
+static void
+t_parse_uri17(void) {
+  char teststr[] =
+    "thisislongerthan269="
+    "01234567890123456789012345678901234567890123456789"
+    "01234567890123456789012345678901234567890123456789"
+    "01234567890123456789012345678901234567890123456789"
+    "01234567890123456789012345678901234567890123456789"
+    "01234567890123456789012345678901234567890123456789";
+  int result;
+
+  /* buf is large enough to hold sizeof(teststr) - 1 bytes content and
+   * 3 bytes for the option header. */
+  unsigned char buf[sizeof(teststr) + 2];
+  size_t buflen = sizeof(buf);
+
+  result = coap_split_query((unsigned char *)teststr, strlen(teststr),
+                            buf, &buflen);
+  if (result >= 0) {
+    CU_ASSERT(buf[0] == 0x0e);
+    CU_ASSERT(buf[1] == (((strlen(teststr) - 269) >> 8) & 0xff));
+    CU_ASSERT(buf[2] == ((strlen(teststr) - 269) & 0xff));
+
+    CU_ASSERT_NSTRING_EQUAL(buf+3, teststr, strlen(teststr));
+  } else {
+    CU_FAIL("uri parser error");
+  }
+}
+
+CU_pSuite
+t_init_uri_tests(void) {
+  CU_pSuite suite;
+
+  suite = CU_add_suite("uri parser", NULL, NULL);
+  if (!suite) {			/* signal error */
+    fprintf(stderr, "W: cannot add uri parser test suite (%s)\n", 
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define URI_TEST(s,t)						      \
+  if (!CU_ADD_TEST(s,t)) {					      \
+    fprintf(stderr, "W: cannot add uri parser test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+
+  URI_TEST(suite, t_parse_uri1);
+  URI_TEST(suite, t_parse_uri2);
+  URI_TEST(suite, t_parse_uri3);
+  URI_TEST(suite, t_parse_uri4);
+  URI_TEST(suite, t_parse_uri5);
+  URI_TEST(suite, t_parse_uri6);
+  URI_TEST(suite, t_parse_uri7);
+  URI_TEST(suite, t_parse_uri8);
+  URI_TEST(suite, t_parse_uri9);
+  URI_TEST(suite, t_parse_uri10);
+  URI_TEST(suite, t_parse_uri11);
+  URI_TEST(suite, t_parse_uri12);
+  URI_TEST(suite, t_parse_uri13);
+  URI_TEST(suite, t_parse_uri14);
+  URI_TEST(suite, t_parse_uri15);
+  URI_TEST(suite, t_parse_uri16);
+  URI_TEST(suite, t_parse_uri17);
+
+  return suite;
+}
+
diff --git a/components/coap/libcoap/tests/test_uri.h b/components/coap/libcoap/tests/test_uri.h
new file mode 100644
index 00000000..165fad3f
--- /dev/null
+++ b/components/coap/libcoap/tests/test_uri.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2012 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_uri_tests(void);
diff --git a/components/coap/libcoap/tests/test_wellknown.c b/components/coap/libcoap/tests/test_wellknown.c
new file mode 100644
index 00000000..57a4db7a
--- /dev/null
+++ b/components/coap/libcoap/tests/test_wellknown.c
@@ -0,0 +1,331 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013--2015 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+#include "test_wellknown.h"
+
+#include <coap.h>
+
+#include <assert.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define TEST_PDU_SIZE 120
+#define TEST_URI_LEN    4
+
+coap_context_t *ctx;	   /* Holds the coap context for most tests */
+coap_pdu_t *pdu;	   /* Holds the parsed PDU for most tests */
+
+static void
+t_wellknown1(void) {
+  coap_print_status_t result;
+  coap_resource_t *r;
+  unsigned char buf[40];
+  size_t buflen, offset, ofs;
+
+  char teststr[] = {  /* </>;title="some attribute";ct=0 (31 chars) */
+    '<', '/', '>', ';', 't', 'i', 't', 'l',
+    'e', '=', '"', 's', 'o', 'm', 'e', ' ',
+    'a', 't', 't', 'r', 'i', 'b', 'u', 't',
+    'e', '"', ';', 'c', 't', '=', '0'
+  };
+
+  r = coap_resource_init(NULL, 0, 0);
+
+  coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+  coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"some attribute\"", 16, 0);
+
+  coap_add_resource(ctx, r);
+
+  for (offset = 0; offset < sizeof(teststr); offset++) {
+    ofs = offset;
+    buflen = sizeof(buf);
+
+    result = coap_print_link(r, buf, &buflen, &ofs);
+
+    CU_ASSERT(result == sizeof(teststr) - offset);
+    CU_ASSERT(buflen == sizeof(teststr));
+    CU_ASSERT(memcmp(buf, teststr + offset, sizeof(teststr) - offset) == 0);
+  }
+
+  /* offset points behind teststr */
+  ofs = offset;
+  buflen = sizeof(buf);
+  result = coap_print_link(r, buf, &buflen, &ofs);
+
+  CU_ASSERT(result == 0);
+    CU_ASSERT(buflen == sizeof(teststr));
+
+  /* offset exceeds buffer */
+  buflen = sizeof(buf);
+  ofs = buflen;
+  result = coap_print_link(r, buf, &buflen, &ofs);
+
+  CU_ASSERT(result == 0);
+  CU_ASSERT(buflen == sizeof(teststr));
+}
+
+static void
+t_wellknown2(void) {
+  coap_print_status_t result;
+  coap_resource_t *r;
+  unsigned char buf[10];	/* smaller than teststr */
+  size_t buflen, offset, ofs;
+
+  char teststr[] = {  /* ,</abcd>;if="one";obs (21 chars) */
+    '<', '/', 'a', 'b', 'c', 'd', '>', ';',
+    'i', 'f', '=', '"', 'o', 'n', 'e', '"',
+    ';', 'o', 'b', 's'
+  };
+
+  r = coap_resource_init((unsigned char *)"abcd", 4, 0);
+  r->observable = 1;
+  coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"one\"", 5, 0);
+
+  coap_add_resource(ctx, r);
+
+  for (offset = 0; offset < sizeof(teststr) - sizeof(buf); offset++) {
+    ofs = offset;
+    buflen = sizeof(buf);
+
+    result = coap_print_link(r, buf, &buflen, &ofs);
+
+    CU_ASSERT(result == (COAP_PRINT_STATUS_TRUNC | sizeof(buf)));
+    CU_ASSERT(buflen == sizeof(teststr));
+    CU_ASSERT(ofs == 0);
+    CU_ASSERT(memcmp(buf, teststr + offset, sizeof(buf)) == 0);
+  }
+
+  /* from here on, the resource description fits into buf */
+  for (; offset < sizeof(teststr); offset++) {
+    ofs = offset;
+    buflen = sizeof(buf);
+    result = coap_print_link(r, buf, &buflen, &ofs);
+
+    CU_ASSERT(result == sizeof(teststr) - offset);
+    CU_ASSERT(buflen == sizeof(teststr));
+    CU_ASSERT(ofs == 0);
+    CU_ASSERT(memcmp(buf, teststr + offset,
+		     COAP_PRINT_OUTPUT_LENGTH(result)) == 0);
+  }
+
+  /* offset exceeds buffer */
+  buflen = sizeof(buf);
+  ofs = offset;
+  result = coap_print_link(r, buf, &buflen, &ofs);
+  CU_ASSERT(result == 0);
+  CU_ASSERT(buflen == sizeof(teststr));
+  CU_ASSERT(ofs == offset - sizeof(teststr));
+}
+
+static void
+t_wellknown3(void) {
+  coap_print_status_t result;
+  int j;
+  coap_resource_t *r;
+  static char uris[2 * COAP_MAX_PDU_SIZE];
+  unsigned char *uribuf = (unsigned char *)uris;
+  unsigned char buf[40];
+  size_t buflen = sizeof(buf);
+  size_t offset;
+  const unsigned short num_resources = (sizeof(uris) / TEST_URI_LEN) - 1;
+
+  /* ,</0000> (TEST_URI_LEN + 4 chars) */
+  for (j = 0; j < num_resources; j++) {
+    int len = snprintf((char *)uribuf, TEST_URI_LEN + 1,
+		       "%0*d", TEST_URI_LEN, j);
+    r = coap_resource_init(uribuf, len, 0);
+    coap_add_resource(ctx, r);
+    uribuf += TEST_URI_LEN;
+  }
+
+  /* the following test assumes that the first two resources from
+   * t_wellknown1() and t_wellknown2() need more than buflen
+   * characters. Otherwise, CU_ASSERT(result > 0) will fail.
+   */
+  offset = num_resources * (TEST_URI_LEN + 4);
+  result = coap_print_wellknown(ctx, buf, &buflen, offset, NULL);
+  CU_ASSERT((result & COAP_PRINT_STATUS_ERROR) == 0 );
+  CU_ASSERT(COAP_PRINT_OUTPUT_LENGTH(result) > 0);
+}
+
+/* Create wellknown response for request without Block-option. */
+static void
+t_wellknown4(void) {
+  coap_pdu_t *response;
+  coap_block_t block;
+
+  response = coap_wellknown_response(ctx, pdu);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
+
+  CU_ASSERT(block.num == 0);
+  CU_ASSERT(block.m == 1);
+  CU_ASSERT(1 << (block.szx + 4)
+    == (unsigned char *)response->hdr + response->length - response->data);
+
+  coap_delete_pdu(response);
+}
+
+/* Create wellknown response for request with Block2-option and an szx
+ * value smaller than COAP_MAX_BLOCK_SZX.
+ */
+static void
+t_wellknown5(void) {
+  coap_pdu_t *response;
+  coap_block_t inblock = { .num = 1, .m = 0, .szx = 1 };
+  coap_block_t block;
+  unsigned char buf[3];
+
+  if (!coap_add_option(pdu, COAP_OPTION_BLOCK2,
+		       coap_encode_var_bytes(buf, ((inblock.num << 4) |
+						   (inblock.m << 3) |
+						   inblock.szx)), buf)) {
+    CU_FAIL("cannot add Block2 option");
+    return;
+  }
+
+  response = coap_wellknown_response(ctx, pdu);
+
+  CU_ASSERT_PTR_NOT_NULL(response);
+
+  CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
+
+  CU_ASSERT(block.num == inblock.num);
+  CU_ASSERT(block.m == 1);
+  CU_ASSERT(1 << (block.szx + 4)
+    == (unsigned char *)response->hdr + response->length - response->data);
+
+  coap_delete_pdu(response);
+}
+
+static void
+t_wellknown6(void) {
+  coap_pdu_t *response;
+  coap_block_t block = { .num = 0, .szx = 6 };
+  unsigned char buf[TEST_PDU_SIZE];
+
+
+  do {
+    coap_pdu_clear(pdu, pdu->max_size);	/* clear PDU */
+
+    pdu->hdr->type = COAP_MESSAGE_NON;
+    pdu->hdr->code = COAP_REQUEST_GET;
+    pdu->hdr->id = htons(0x1234);
+
+    CU_ASSERT_PTR_NOT_NULL(pdu);
+
+    if (!pdu || !coap_add_option(pdu, COAP_OPTION_BLOCK2,
+				 coap_encode_var_bytes(buf,
+				       ((block.num << 4) | block.szx)), buf)) {
+      CU_FAIL("cannot create request");
+      return;
+    }
+
+    response = coap_wellknown_response(ctx, pdu);
+
+    CU_ASSERT_PTR_NOT_NULL(response);
+
+    /* coap_show_pdu(response); */
+
+    CU_ASSERT(coap_get_block(response, COAP_OPTION_BLOCK2, &block) != 0);
+
+    block.num++;
+    coap_delete_pdu(response);
+  } while (block.m == 1);
+}
+
+static int
+t_wkc_tests_create(void) {
+  coap_address_t addr;
+
+  coap_address_init(&addr);
+
+  addr.size = sizeof(struct sockaddr_in6);
+  addr.addr.sin6.sin6_family = AF_INET6;
+  addr.addr.sin6.sin6_addr = in6addr_any;
+  addr.addr.sin6.sin6_port = htons(COAP_DEFAULT_PORT);
+
+  ctx = coap_new_context(&addr);
+
+  pdu = coap_pdu_init(0, 0, 0, TEST_PDU_SIZE);
+#if 0
+  /* add resources to coap context */
+  if (ctx && pdu) {
+    coap_resource_t *r;
+    static char _buf[2 * COAP_MAX_PDU_SIZE];
+    unsigned char *buf = (unsigned char *)_buf;
+    int i;
+
+    /* </>;title="some attribute";ct=0 (31 chars) */
+    r = coap_resource_init(NULL, 0, 0);
+
+    coap_add_attr(r, (unsigned char *)"ct", 2, (unsigned char *)"0", 1, 0);
+    coap_add_attr(r, (unsigned char *)"title", 5, (unsigned char *)"\"some attribute\"", 16, 0);
+    coap_add_resource(ctx, r);
+
+    /* ,</abcd>;if="one";obs (21 chars) */
+    r = coap_resource_init((unsigned char *)"abcd", 4, 0);
+    r->observable = 1;
+    coap_add_attr(r, (unsigned char *)"if", 2, (unsigned char *)"\"one\"", 5, 0);
+
+    coap_add_resource(ctx, r);
+
+    /* ,</0000> (TEST_URI_LEN + 4 chars) */
+    for (i = 0; i < sizeof(_buf) / (TEST_URI_LEN + 4); i++) {
+      int len = snprintf((char *)buf, TEST_URI_LEN + 1,
+			 "%0*d", TEST_URI_LEN, i);
+      r = coap_resource_init(buf, len, 0);
+      coap_add_resource(ctx, r);
+      buf += TEST_URI_LEN + 1;
+    }
+
+  }
+#endif
+  return ctx == NULL || pdu == NULL;
+}
+
+static int
+t_wkc_tests_remove(void) {
+  coap_delete_pdu(pdu);
+  coap_free_context(ctx);
+  return 0;
+}
+
+CU_pSuite
+t_init_wellknown_tests(void) {
+  CU_pSuite suite;
+
+  suite = CU_add_suite(".well-known/core", t_wkc_tests_create, t_wkc_tests_remove);
+  if (!suite) {			/* signal error */
+    fprintf(stderr, "W: cannot add .well-known/core test suite (%s)\n",
+	    CU_get_error_msg());
+
+    return NULL;
+  }
+
+#define WKC_TEST(s,t)						      \
+  if (!CU_ADD_TEST(s,t)) {					      \
+    fprintf(stderr, "W: cannot add .well-known/core test (%s)\n",	      \
+	    CU_get_error_msg());				      \
+  }
+
+  WKC_TEST(suite, t_wellknown1);
+  WKC_TEST(suite, t_wellknown2);
+  WKC_TEST(suite, t_wellknown3);
+  WKC_TEST(suite, t_wellknown4);
+  WKC_TEST(suite, t_wellknown5);
+  WKC_TEST(suite, t_wellknown6);
+
+  return suite;
+}
+
diff --git a/components/coap/libcoap/tests/test_wellknown.h b/components/coap/libcoap/tests/test_wellknown.h
new file mode 100644
index 00000000..47f20b34
--- /dev/null
+++ b/components/coap/libcoap/tests/test_wellknown.h
@@ -0,0 +1,11 @@
+/* libcoap unit tests
+ *
+ * Copyright (C) 2013 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use. 
+ */
+
+#include <CUnit/CUnit.h>
+
+CU_pSuite t_init_wellknown_tests(void);
diff --git a/components/coap/libcoap/tests/testdriver.c b/components/coap/libcoap/tests/testdriver.c
new file mode 100644
index 00000000..b65dd618
--- /dev/null
+++ b/components/coap/libcoap/tests/testdriver.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+
+#include <CUnit/CUnit.h>
+#include <CUnit/Basic.h>
+
+/* #include <coap.h> */
+
+#include "test_uri.h"
+#include "test_options.h"
+#include "test_pdu.h"
+#include "test_error_response.h"
+#include "test_sendqueue.h"
+#include "test_wellknown.h"
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+int
+main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) {
+  CU_ErrorCode result;
+  CU_BasicRunMode run_mode = CU_BRM_VERBOSE;
+
+  if (CU_initialize_registry() != CUE_SUCCESS) {
+    fprintf(stderr, "E: test framework initialization failed\n");
+    return -2;
+  }
+
+  t_init_uri_tests();
+  t_init_option_tests();
+  t_init_pdu_tests();
+  t_init_error_response_tests();
+  t_init_sendqueue_tests();
+  t_init_wellknown_tests();
+
+  CU_basic_set_mode(run_mode);
+  result = CU_basic_run_tests();
+
+  CU_cleanup_registry();
+
+  return result;
+}
diff --git a/components/coap/port/coap_io_socket.c b/components/coap/port/coap_io_socket.c
new file mode 100644
index 00000000..4c3f85b4
--- /dev/null
+++ b/components/coap/port/coap_io_socket.c
@@ -0,0 +1,468 @@
+/*
+ * Network function implementation with socket for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * network operations are in use.
+ *
+ * coap_io.h -- Default network I/O functions for libcoap
+ *
+ * Copyright (C) 2012,2014 Olaf Bergmann <bergmann@tzi.org>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see
+ * README for terms of use.
+ */
+
+#include "coap_config.h"
+
+#ifdef HAVE_STDIO_H
+#  include <stdio.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <errno.h>
+
+#ifdef WITH_CONTIKI
+# include "uip.h"
+#endif
+
+#include "pdu.h"
+#include "debug.h"
+#include "mem.h"
+#include "coap_io.h"
+
+#ifdef WITH_POSIX
+/* define generic PKTINFO for IPv4 */
+#if defined(IP_PKTINFO)
+#  define GEN_IP_PKTINFO IP_PKTINFO
+#elif defined(IP_RECVDSTADDR)
+#  define GEN_IP_PKTINFO IP_RECVDSTADDR
+#else
+#  error "Need IP_PKTINFO or IP_RECVDSTADDR to request ancillary data from OS."
+#endif /* IP_PKTINFO */
+
+/* define generic KTINFO for IPv6 */
+#ifdef IPV6_RECVPKTINFO
+#  define GEN_IPV6_PKTINFO IPV6_RECVPKTINFO
+#elif defined(IPV6_PKTINFO)
+#  define GEN_IPV6_PKTINFO IPV6_PKTINFO
+#else
+#  error "Need IPV6_PKTINFO or IPV6_RECVPKTINFO to request ancillary data from OS."
+#endif /* IPV6_RECVPKTINFO */
+
+struct coap_packet_t {
+  coap_if_handle_t hnd;	      /**< the interface handle */
+  coap_address_t src;	      /**< the packet's source address */
+  coap_address_t dst;	      /**< the packet's destination address */
+  const coap_endpoint_t *interface;
+
+  int ifindex;
+  void *session;		/**< opaque session data */
+
+  size_t length;		/**< length of payload */
+  unsigned char payload[];	/**< payload */
+};
+#endif
+
+#ifdef CUSTOM_COAP_NETWORK_ENDPOINT
+
+#ifdef WITH_CONTIKI
+static int ep_initialized = 0;
+
+static inline struct coap_endpoint_t *
+coap_malloc_contiki_endpoint() {
+  static struct coap_endpoint_t ep;
+
+  if (ep_initialized) {
+    return NULL;
+  } else {
+    ep_initialized = 1;
+    return &ep;
+  }
+}
+
+static inline void
+coap_free_contiki_endpoint(struct coap_endpoint_t *ep) {
+  ep_initialized = 0;
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  struct coap_endpoint_t *ep = coap_malloc_contiki_endpoint();
+
+  if (ep) {
+    memset(ep, 0, sizeof(struct coap_endpoint_t));
+    ep->handle.conn = udp_new(NULL, 0, NULL);
+
+    if (!ep->handle.conn) {
+      coap_free_endpoint(ep);
+      return NULL;
+    }
+
+    coap_address_init(&ep->addr);
+    uip_ipaddr_copy(&ep->addr.addr, &addr->addr);
+    ep->addr.port = addr->port;
+    udp_bind((struct uip_udp_conn *)ep->handle.conn, addr->port);
+  }
+  return ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if (ep) {
+    if (ep->handle.conn) {
+      uip_udp_remove((struct uip_udp_conn *)ep->handle.conn);
+    }
+    coap_free_contiki_endpoint(ep);
+  }
+}
+
+#else /* WITH_CONTIKI */
+static inline struct coap_endpoint_t *
+coap_malloc_posix_endpoint(void) {
+  return (struct coap_endpoint_t *)coap_malloc(sizeof(struct coap_endpoint_t));
+}
+
+static inline void
+coap_free_posix_endpoint(struct coap_endpoint_t *ep) {
+  coap_free(ep);
+}
+
+coap_endpoint_t *
+coap_new_endpoint(const coap_address_t *addr, int flags) {
+  int sockfd = socket(addr->addr.sa.sa_family, SOCK_DGRAM, 0);
+  int on = 1;
+  struct coap_endpoint_t *ep;
+
+  if (sockfd < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: socket");
+    return NULL;
+  }
+
+  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
+    coap_log(LOG_WARNING, "coap_new_endpoint: setsockopt SO_REUSEADDR");
+
+  if (bind(sockfd, &addr->addr.sa, addr->size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: bind");
+    close (sockfd);
+    return NULL;
+  }
+
+  ep = coap_malloc_posix_endpoint();
+  if (!ep) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: malloc");
+    close(sockfd);
+    return NULL;
+  }
+
+  memset(ep, 0, sizeof(struct coap_endpoint_t));
+  ep->handle.fd = sockfd;
+  ep->flags = flags;
+
+  ep->addr.size = addr->size;
+  if (getsockname(sockfd, &ep->addr.addr.sa, &ep->addr.size) < 0) {
+    coap_log(LOG_WARNING, "coap_new_endpoint: cannot determine local address");
+    close (sockfd);
+    return NULL;
+  }
+
+#ifndef NDEBUG
+  if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+    unsigned char addr_str[INET6_ADDRSTRLEN+8];
+
+    if (coap_print_addr(&ep->addr, addr_str, INET6_ADDRSTRLEN+8)) {
+      debug("created %sendpoint %s\n",
+	    ep->flags & COAP_ENDPOINT_DTLS ? "DTLS " : "",
+	    addr_str);
+    }
+  }
+#endif /* NDEBUG */
+
+  return (coap_endpoint_t *)ep;
+}
+
+void
+coap_free_endpoint(coap_endpoint_t *ep) {
+  if(ep) {
+    if (ep->handle.fd >= 0)
+      close(ep->handle.fd);
+    coap_free_posix_endpoint((struct coap_endpoint_t *)ep);
+  }
+}
+
+#endif /* WITH_CONTIKI */
+#endif /* CUSTOM_COAP_NETWORK_ENDPOINT */
+
+#ifdef CUSTOM_COAP_NETWORK_SEND
+
+#if defined(WITH_POSIX) != defined(HAVE_NETINET_IN_H)
+/* define struct in6_pktinfo and struct in_pktinfo if not available
+   FIXME: check with configure
+*/
+struct in6_pktinfo {
+  struct in6_addr ipi6_addr;	/* src/dst IPv6 address */
+  unsigned int ipi6_ifindex;	/* send/recv interface index */
+};
+
+struct in_pktinfo {
+  int ipi_ifindex;
+  struct in_addr ipi_spec_dst;
+  struct in_addr ipi_addr;
+};
+#endif
+
+#if defined(WITH_POSIX) && !defined(SOL_IP)
+/* Solaris expects level IPPROTO_IP for ancillary data. */
+#define SOL_IP IPPROTO_IP
+#endif
+
+#ifdef __GNUC__
+#define UNUSED_PARAM __attribute__ ((unused))
+#else /* not a GCC */
+#define UNUSED_PARAM
+#endif /* GCC */
+
+ssize_t
+coap_network_send(struct coap_context_t *context UNUSED_PARAM,
+		  const coap_endpoint_t *local_interface,
+		  const coap_address_t *dst,
+		  unsigned char *data,
+		  size_t datalen) {
+
+  struct coap_endpoint_t *ep =
+    (struct coap_endpoint_t *)local_interface;
+
+#ifndef WITH_CONTIKI
+  return sendto(ep->handle.fd, data, datalen, 0, (struct sockaddr*)&dst->addr.sa, sizeof(struct sockaddr));
+#else /* WITH_CONTIKI */
+  /* FIXME: untested */
+  /* FIXME: is there a way to check if send was successful? */
+  uip_udp_packet_sendto((struct uip_udp_conn *)ep->handle.conn, data, datalen,
+			&dst->addr, dst->port);
+  return datalen;
+#endif /* WITH_CONTIKI */
+}
+
+#endif /* CUSTOM_COAP_NETWORK_SEND */
+
+#ifdef CUSTOM_COAP_NETWORK_READ
+
+#define SIN6(A) ((struct sockaddr_in6 *)(A))
+
+#ifdef WITH_POSIX
+static coap_packet_t *
+coap_malloc_packet(void) {
+  coap_packet_t *packet;
+  const size_t need = sizeof(coap_packet_t) + COAP_MAX_PDU_SIZE;
+
+  packet = (coap_packet_t *)coap_malloc(need);
+  if (packet) {
+    memset(packet, 0, need);
+  }
+  return packet;
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free(packet);
+}
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+static inline coap_packet_t *
+coap_malloc_packet(void) {
+  return (coap_packet_t *)coap_malloc_type(COAP_PACKET, 0);
+}
+
+void
+coap_free_packet(coap_packet_t *packet) {
+  coap_free_type(COAP_PACKET, packet);
+}
+#endif /* WITH_CONTIKI */
+
+static inline size_t
+coap_get_max_packetlength(const coap_packet_t *packet UNUSED_PARAM) {
+  return COAP_MAX_PDU_SIZE;
+}
+
+void
+coap_packet_populate_endpoint(coap_packet_t *packet, coap_endpoint_t *target)
+{
+  target->handle = packet->interface->handle;
+  memcpy(&target->addr, &packet->dst, sizeof(target->addr));
+  target->ifindex = packet->ifindex;
+  target->flags = 0; /* FIXME */
+}
+void
+coap_packet_copy_source(coap_packet_t *packet, coap_address_t *target)
+{
+  memcpy(target, &packet->src, sizeof(coap_address_t));
+}
+void
+coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
+{
+	*address = packet->payload;
+	*length = packet->length;
+}
+
+/**
+ * Checks if a message with destination address @p dst matches the
+ * local interface with address @p local. This function returns @c 1
+ * if @p dst is a valid match, and @c 0 otherwise.
+ */
+static inline int
+is_local_if(const coap_address_t *local, const coap_address_t *dst) {
+  return coap_address_isany(local) || coap_address_equals(dst, local) ||
+    coap_is_mcast(dst);
+}
+
+ssize_t
+coap_network_read(coap_endpoint_t *ep, coap_packet_t **packet) {
+  ssize_t len = -1;
+
+#ifdef WITH_POSIX
+  #define SOC_APPDATA_LEN 1460
+  char *soc_appdata = NULL;
+  struct sockaddr_in soc_srcipaddr;
+  socklen_t soc_srcsize = sizeof(struct sockaddr_in);
+#endif /* WITH_POSIX */
+
+  assert(ep);
+  assert(packet);
+
+  *packet = coap_malloc_packet();
+
+  if (!*packet) {
+    warn("coap_network_read: insufficient memory, drop packet\n");
+    return -1;
+  }
+
+  coap_address_init(&(*packet)->dst); /* the local interface address */
+  coap_address_init(&(*packet)->src); /* the remote peer */
+
+#ifdef WITH_POSIX
+  soc_appdata = coap_malloc(SOC_APPDATA_LEN);
+  if (soc_appdata){
+	  len = recvfrom(ep->handle.fd, soc_appdata, SOC_APPDATA_LEN, 0, (struct sockaddr *)&soc_srcipaddr, (socklen_t *)&soc_srcsize);
+
+	  if (len < 0){
+		  coap_log(LOG_WARNING, "coap_network_read: %s\n", strerror(errno));
+		  goto error;
+	  } else {
+		  /* use getsockname() to get the local port */
+	      (*packet)->dst.size = sizeof((*packet)->dst.addr);
+	      if (getsockname(ep->handle.fd, &(*packet)->dst.addr.sa, &(*packet)->dst.size) < 0) {
+	         coap_log(LOG_DEBUG, "cannot determine local port\n");
+	         goto error;
+	      }
+
+	      /* local interface for IPv4 */
+	      (*packet)->src.size = sizeof((*packet)->src.addr.sa);
+	      memcpy(&((*packet)->src.addr.sa), &soc_srcipaddr, (*packet)->src.size);
+
+	      if (len > coap_get_max_packetlength(*packet)) {
+	         /* FIXME: we might want to send back a response */
+	         warn("discarded oversized packet\n");
+	         goto error;
+	      }
+
+	      if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+	      	 coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+	      	printf("error 3\n");
+	      	 goto error;
+	      }
+
+	      (*packet)->length = len;
+
+	      memcpy(&(*packet)->payload, soc_appdata, len);
+	  }
+
+	  coap_free(soc_appdata);
+	  soc_appdata = NULL;
+  } else {
+	  goto error;
+  }
+#endif /* WITH_POSIX */
+#ifdef WITH_CONTIKI
+  /* FIXME: untested, make this work */
+#define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
+
+  if(uip_newdata()) {
+    uip_ipaddr_copy(&(*packet)->src.addr, &UIP_IP_BUF->srcipaddr);
+    (*packet)->src.port = UIP_UDP_BUF->srcport;
+    uip_ipaddr_copy(&(*packet)->dst.addr, &UIP_IP_BUF->destipaddr);
+    (*packet)->dst.port = UIP_UDP_BUF->destport;
+
+    if (!is_local_if(&ep->addr, &(*packet)->dst)) {
+      coap_log(LOG_DEBUG, "packet received on wrong interface, dropped\n");
+      goto error;
+    }
+
+    len = uip_datalen();
+
+    if (len > coap_get_max_packetlength(*packet)) {
+      /* FIXME: we might want to send back a response */
+      warn("discarded oversized packet\n");
+      return -1;
+    }
+
+    ((char *)uip_appdata)[len] = 0;
+#ifndef NDEBUG
+    if (LOG_DEBUG <= coap_get_log_level()) {
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 40
+#endif
+      unsigned char addr_str[INET6_ADDRSTRLEN+8];
+
+      if (coap_print_addr(&(*packet)->src, addr_str, INET6_ADDRSTRLEN+8)) {
+	debug("received %zd bytes from %s\n", len, addr_str);
+      }
+    }
+#endif /* NDEBUG */
+
+    (*packet)->length = len;
+    memcpy(&(*packet)->payload, uip_appdata, len);
+  }
+
+#undef UIP_IP_BUF
+#undef UIP_UDP_BUF
+#endif /* WITH_CONTIKI */
+#ifdef WITH_LWIP
+#error "coap_network_read() not implemented on this platform"
+#endif
+
+  (*packet)->interface = ep;
+
+  return len;
+ error:
+#ifdef WITH_POSIX
+ 	if (soc_appdata)
+ 		coap_free(soc_appdata);
+ 	soc_appdata = NULL;
+#endif
+  coap_free_packet(*packet);
+  *packet = NULL;
+  return -1;
+}
+
+#undef SIN6
+
+#endif /*  CUSTOM_COAP_NETWORK_READ */
diff --git a/components/coap/port/include/coap/coap.h b/components/coap/port/include/coap/coap.h
new file mode 100644
index 00000000..cbdc9dfc
--- /dev/null
+++ b/components/coap/port/include/coap/coap.h
@@ -0,0 +1,50 @@
+/* Modify head file implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * define operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _COAP_H_
+#define _COAP_H_
+
+#include "libcoap.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "address.h"
+#include "async.h"
+#include "bits.h"
+#include "block.h"
+#include "coap_io.h"
+#include "coap_time.h"
+#include "debug.h"
+#include "encode.h"
+#include "mem.h"
+#include "net.h"
+#include "option.h"
+#include "pdu.h"
+#include "prng.h"
+#include "resource.h"
+#include "str.h"
+#include "subscribe.h"
+#include "uri.h"
+#include "uthash.h"
+#include "utlist.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COAP_H_ */
diff --git a/components/coap/port/include/coap_config.h b/components/coap/port/include/coap_config.h
new file mode 100644
index 00000000..db314f2d
--- /dev/null
+++ b/components/coap/port/include/coap_config.h
@@ -0,0 +1,39 @@
+/*
+ * libcoap configure implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * configure operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#ifdef WITH_POSIX
+#include "coap_config_posix.h"
+#endif
+
+#define HAVE_STDIO_H
+#define HAVE_ASSERT_H
+
+#define PACKAGE_STRING PACKAGE_NAME PACKAGE_VERSION
+
+/* it's just provided by libc. i hope we don't get too many of those, as
+ * actually we'd need autotools again to find out what environment we're
+ * building in */
+#define HAVE_STRNLEN 1
+
+#define HAVE_LIMITS_H
+
+#define COAP_RESOURCES_NOHASH
+
+#endif /* _CONFIG_H_ */
diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h
new file mode 100644
index 00000000..a77e97f0
--- /dev/null
+++ b/components/coap/port/include/coap_config_posix.h
@@ -0,0 +1,41 @@
+/*
+ * libcoap configure implementation for ESP32 platform.
+ *
+ * Uses libcoap software implementation for failover when concurrent
+ * configure operations are in use.
+ *
+ * coap.h -- main header file for CoAP stack of libcoap
+ *
+ * Copyright (C) 2010-2012,2015-2016 Olaf Bergmann <bergmann@tzi.org>
+ *               2015 Carsten Schoenert <c.schoenert@t-online.de>
+ *
+ * Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+ *
+ * This file is part of the CoAP library libcoap. Please see README for terms
+ * of use.
+ */
+
+#ifndef COAP_CONFIG_POSIX_H_
+#define COAP_CONFIG_POSIX_H_
+
+#ifdef WITH_POSIX
+
+#include <sys/socket.h>
+
+#define HAVE_SYS_SOCKET_H
+#define HAVE_MALLOC
+#define HAVE_ARPA_INET_H
+
+#define IP_PKTINFO   IP_MULTICAST_IF
+#define IPV6_PKTINFO IPV6_V6ONLY
+
+#define PACKAGE_NAME "libcoap-posix"
+#define PACKAGE_VERSION "?"
+
+#define CUSTOM_COAP_NETWORK_ENDPOINT
+#define CUSTOM_COAP_NETWORK_SEND
+#define CUSTOM_COAP_NETWORK_READ
+
+#endif
+
+#endif /* COAP_CONFIG_POSIX_H_ */
diff --git a/examples/protocols/coap_client/CMakeLists.txt b/examples/protocols/coap_client/CMakeLists.txt
new file mode 100644
index 00000000..43378b8b
--- /dev/null
+++ b/examples/protocols/coap_client/CMakeLists.txt
@@ -0,0 +1,8 @@
+# The following four lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+set(MAIN_SRCS main/coap_client_example_main.c)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(coap_client)
diff --git a/examples/protocols/coap_client/Makefile b/examples/protocols/coap_client/Makefile
new file mode 100644
index 00000000..c9a25d11
--- /dev/null
+++ b/examples/protocols/coap_client/Makefile
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := coap_client
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/protocols/coap_client/README.md b/examples/protocols/coap_client/README.md
new file mode 100644
index 00000000..81b589d6
--- /dev/null
+++ b/examples/protocols/coap_client/README.md
@@ -0,0 +1,65 @@
+
+# CoAP client example
+
+(See the README.md file in the upper level 'examples' directory for more information about examples.)
+this CoAP client example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example.
+
+CoAP client example would connect your ESP32 device to any CoAP server, fetch data from CoAP server and upstream data to CoAP server.
+
+The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things.   
+The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation.
+
+please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
+
+## How to use example
+
+### Configure the project
+
+```
+make menuconfig
+```
+
+* Set serial port under Serial Flasher config
+* Set Target Uri under Example Configuration
+* Set WiFi SSID under Example Configuration
+* Set WiFi Password under Example Configuration
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+```
+make -j4 flash monitor
+```
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+Prerequisite: we startup a CoAP server on coap server example.  
+
+and you could receive data from CoAP server if succeed,  
+such as the following log:
+
+```
+...
+I (332) wifi: mode : sta (30:ae:a4:04:1b:7c)
+I (1672) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1
+I (1672) wifi: state: init -> auth (b0)
+I (1682) wifi: state: auth -> assoc (0)
+I (1692) wifi: state: assoc -> run (10)
+I (1692) wifi: connected with huawei_cw, channel 11
+I (1692) wifi: pm start, type: 1
+
+I (2582) event: sta ip: 192.168.3.89, mask: 255.255.255.0, gw: 192.168.3.1
+I (2582) CoAP_client: Connected to AP
+I (2582) CoAP_client: DNS lookup succeeded. IP=192.168.3.84
+Received: Hello World!
+E (8102) CoAP_client: select timeout
+E (13102) CoAP_client: select timeout
+...
+```
+
+## Troubleshooting
+* Please make sure Target Url includes valid `host`, `port`, `path`, and begins with `coap://`  
diff --git a/examples/protocols/coap_client/main/Kconfig.projbuild b/examples/protocols/coap_client/main/Kconfig.projbuild
new file mode 100644
index 00000000..045137a0
--- /dev/null
+++ b/examples/protocols/coap_client/main/Kconfig.projbuild
@@ -0,0 +1,21 @@
+menu "Example Configuration"
+
+config TARGET_DOMAIN_URI
+    string "Target Uri"
+    default "coap://californium.eclipse.org"
+    help
+        Target uri for the example to use.
+
+config WIFI_SSID
+    string "WiFi SSID"
+    default "myssid"
+    help
+        SSID (network name) for the example to connect to.
+
+config WIFI_PASSWORD
+    string "WiFi Password"
+    default "mypassword"
+    help
+        WiFi password (WPA or WPA2) for the example to use.
+
+endmenu
\ No newline at end of file
diff --git a/examples/protocols/coap_client/main/coap_client_example_main.c b/examples/protocols/coap_client/main/coap_client_example_main.c
new file mode 100644
index 00000000..98f003e1
--- /dev/null
+++ b/examples/protocols/coap_client/main/coap_client_example_main.c
@@ -0,0 +1,205 @@
+/* CoAP client Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <string.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+
+#include "esp_log.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+
+#include "nvs_flash.h"
+
+#include "coap.h"
+
+/* The examples use simple WiFi configuration that you can set via
+   'make menuconfig'.
+
+   If you'd rather not, just change the below entries to strings with
+   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
+#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
+
+#define COAP_DEFAULT_TIME_SEC 5
+#define COAP_DEFAULT_TIME_USEC 0
+
+/* The examples use uri "coap://californium.eclipse.org" that
+   you can set via 'make menuconfig'.
+
+   If you'd rather not, just change the below entries to strings with
+   the config you want - ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org"
+*/
+#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI
+
+static EventGroupHandle_t wifi_event_group;
+
+/* The event group allows multiple bits for each event,
+   but we only care about one event - are we connected
+   to the AP with an IP? */
+const static int CONNECTED_BIT = BIT0;
+
+const static char *TAG = "CoAP_client";
+
+static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote,
+              coap_pdu_t *sent, coap_pdu_t *received,
+                const coap_tid_t id)
+{
+    unsigned char* data = NULL;
+    size_t data_len;
+    if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) {
+        if (coap_get_data(received, &data_len, &data)) {
+            printf("Received: %s\n", data);
+        }
+    }
+}
+
+static void coap_example_task(void *p)
+{
+    struct hostent *hp;
+    struct ip4_addr *ip4_addr;
+
+    coap_context_t*   ctx = NULL;
+    coap_address_t    dst_addr, src_addr;
+    static coap_uri_t uri;
+    fd_set            readfds;
+    struct timeval    tv;
+    int flags, result;
+    coap_pdu_t*       request = NULL;
+    const char*       server_uri = COAP_DEFAULT_DEMO_URI;
+    uint8_t     get_method = 1;
+
+    while (1) {
+        /* Wait for the callback to set the CONNECTED_BIT in the
+           event group.
+        */
+        xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
+                            false, true, portMAX_DELAY);
+        ESP_LOGI(TAG, "Connected to AP");
+
+        if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1) {
+            ESP_LOGE(TAG, "CoAP server uri error");
+            break;
+        }
+
+        hp = gethostbyname((const char *)uri.host.s);
+
+        if (hp == NULL) {
+            ESP_LOGE(TAG, "DNS lookup failed");
+            vTaskDelay(1000 / portTICK_PERIOD_MS);
+            continue;
+        }
+
+        /* Code to print the resolved IP.
+
+           Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
+        ip4_addr = (struct ip4_addr *)hp->h_addr;
+        ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*ip4_addr));
+
+        coap_address_init(&src_addr);
+        src_addr.addr.sin.sin_family      = AF_INET;
+        src_addr.addr.sin.sin_port        = htons(0);
+        src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
+
+        ctx = coap_new_context(&src_addr);
+        if (ctx) {
+            coap_address_init(&dst_addr);
+            dst_addr.addr.sin.sin_family      = AF_INET;
+            dst_addr.addr.sin.sin_port        = htons(COAP_DEFAULT_PORT);
+            dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
+
+            request            = coap_new_pdu();
+            if (request){
+                request->hdr->type = COAP_MESSAGE_CON;
+                request->hdr->id   = coap_new_message_id(ctx);
+                request->hdr->code = get_method;
+                coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
+
+                coap_register_response_handler(ctx, message_handler);
+                coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request);
+
+                flags = fcntl(ctx->sockfd, F_GETFL, 0);
+                fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
+
+                tv.tv_usec = COAP_DEFAULT_TIME_USEC;
+                tv.tv_sec = COAP_DEFAULT_TIME_SEC;
+
+                for(;;) {
+                    FD_ZERO(&readfds);
+                    FD_CLR( ctx->sockfd, &readfds );
+                    FD_SET( ctx->sockfd, &readfds );
+                    result = select( ctx->sockfd+1, &readfds, 0, 0, &tv );
+                    if (result > 0) {
+                        if (FD_ISSET( ctx->sockfd, &readfds ))
+                            coap_read(ctx);
+                    } else if (result < 0) {
+                        break;
+                    } else {
+                        ESP_LOGE(TAG, "select timeout");
+                    }
+                }
+            }
+            coap_free_context(ctx);
+        }
+    }
+
+    vTaskDelete(NULL);
+}
+
+static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
+{
+    switch(event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        esp_wifi_connect();
+        break;
+    case SYSTEM_EVENT_STA_GOT_IP:
+        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    case SYSTEM_EVENT_STA_DISCONNECTED:
+        /* This is a workaround as ESP32 WiFi libs don't currently
+           auto-reassociate. */
+        esp_wifi_connect();
+        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+static void wifi_conn_init(void)
+{
+    tcpip_adapter_init();
+    wifi_event_group = xEventGroupCreate();
+    ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) );
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
+    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = EXAMPLE_WIFI_SSID,
+            .password = EXAMPLE_WIFI_PASS,
+        },
+    };
+    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
+    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
+    ESP_ERROR_CHECK( esp_wifi_start() );
+}
+
+void app_main(void)
+{
+    ESP_ERROR_CHECK( nvs_flash_init() );
+    wifi_conn_init();
+    xTaskCreate(coap_example_task, "coap", 2048, NULL, 5, NULL);
+}
diff --git a/examples/protocols/coap_client/main/component.mk b/examples/protocols/coap_client/main/component.mk
new file mode 100644
index 00000000..0b9d7585
--- /dev/null
+++ b/examples/protocols/coap_client/main/component.mk
@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+
diff --git a/examples/protocols/coap_server/CMakeLists.txt b/examples/protocols/coap_server/CMakeLists.txt
new file mode 100644
index 00000000..8495b857
--- /dev/null
+++ b/examples/protocols/coap_server/CMakeLists.txt
@@ -0,0 +1,8 @@
+# The following four lines of boilerplate have to be in your project's CMakeLists
+# in this exact order for cmake to work correctly
+cmake_minimum_required(VERSION 3.5)
+
+set(MAIN_SRCS main/coap_server_example_main.c)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+project(coap_server)
diff --git a/examples/protocols/coap_server/Makefile b/examples/protocols/coap_server/Makefile
new file mode 100644
index 00000000..f82e5fc2
--- /dev/null
+++ b/examples/protocols/coap_server/Makefile
@@ -0,0 +1,9 @@
+#
+# This is a project Makefile. It is assumed the directory this Makefile resides in is a
+# project subdirectory.
+#
+
+PROJECT_NAME := coap_server
+
+include $(IDF_PATH)/make/project.mk
+
diff --git a/examples/protocols/coap_server/README.md b/examples/protocols/coap_server/README.md
new file mode 100644
index 00000000..56087363
--- /dev/null
+++ b/examples/protocols/coap_server/README.md
@@ -0,0 +1,63 @@
+
+# CoAP server example
+
+(See the README.md file in the upper level 'examples' directory for more information about examples.)  
+This CoAP server example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example.
+
+CoAP server example would startup a daemon task, receive data from CoAP client and transmit data to CoAP client.
+
+The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things.   
+The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation.
+
+please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
+
+## How to use example
+
+### Configure the project
+
+```
+make menuconfig
+```
+
+* Set default serial port under Serial Flasher config
+* Set WiFi SSID under Example Configuration
+* Set WiFi Password under Example Configuration
+
+### Build and Flash
+
+Build the project and flash it to the board, then run monitor tool to view serial output:
+
+```
+make -j4 flash monitor
+```
+
+(To exit the serial monitor, type ``Ctrl-]``.)
+
+See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
+
+## Example Output
+current CoAP server would startup a daemon task,   
+and the log is such as the following:  
+
+```
+...
+I (332) wifi: mode : sta (30:ae:a4:04:1b:7c)
+I (1672) wifi: n:11 0, o:1 0, ap:255 255, sta:11 0, prof:1
+I (1672) wifi: state: init -> auth (b0)
+I (1682) wifi: state: auth -> assoc (0)
+I (1692) wifi: state: assoc -> run (10)
+I (1692) wifi: connected with huawei_cw, channel 11
+I (1692) wifi: pm start, type: 1
+
+I (2622) event: sta ip: 192.168.3.84, mask: 255.255.255.0, gw: 192.168.3.1
+I (2622) CoAP_server: Connected to AP
+E (7622) CoAP_server: select timeout
+E (12622) CoAP_server: select timeout
+E (17622) CoAP_server: select timeout
+...
+```
+
+if a CoAP client query `/Espressif` resource, CoAP server would return `"Hello World!"`  
+
+## Troubleshooting
+* Please make sure CoAP client fetchs data under path: `/Espressif`
diff --git a/examples/protocols/coap_server/main/Kconfig.projbuild b/examples/protocols/coap_server/main/Kconfig.projbuild
new file mode 100644
index 00000000..7a9cb97a
--- /dev/null
+++ b/examples/protocols/coap_server/main/Kconfig.projbuild
@@ -0,0 +1,15 @@
+menu "Example Configuration"
+
+config WIFI_SSID
+    string "WiFi SSID"
+    default "myssid"
+    help
+        SSID (network name) for the example to connect to.
+
+config WIFI_PASSWORD
+    string "WiFi Password"
+    default "mypassword"
+    help
+        WiFi password (WPA or WPA2) for the example to use.
+
+endmenu
\ No newline at end of file
diff --git a/examples/protocols/coap_server/main/coap_server_example_main.c b/examples/protocols/coap_server/main/coap_server_example_main.c
new file mode 100644
index 00000000..b3ea7030
--- /dev/null
+++ b/examples/protocols/coap_server/main/coap_server_example_main.c
@@ -0,0 +1,192 @@
+/* CoAP server Example
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <string.h>
+#include <sys/socket.h>
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "freertos/event_groups.h"
+
+#include "esp_log.h"
+#include "esp_wifi.h"
+#include "esp_event_loop.h"
+
+#include "nvs_flash.h"
+
+#include "coap.h"
+
+/* The examples use simple WiFi configuration that you can set via
+   'make menuconfig'.
+
+   If you'd rather not, just change the below entries to strings with
+   the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
+*/
+#define EXAMPLE_WIFI_SSID            CONFIG_WIFI_SSID
+#define EXAMPLE_WIFI_PASS            CONFIG_WIFI_PASSWORD
+
+#define COAP_DEFAULT_TIME_SEC 5
+#define COAP_DEFAULT_TIME_USEC 0
+
+static EventGroupHandle_t wifi_event_group;
+
+/* The event group allows multiple bits for each event,
+   but we only care about one event - are we connected
+   to the AP with an IP? */
+const static int CONNECTED_BIT = BIT0;
+
+const static char *TAG = "CoAP_server";
+
+static coap_async_state_t *async = NULL;
+
+static void
+send_async_response(coap_context_t *ctx, const coap_endpoint_t *local_if)
+{
+    coap_pdu_t *response;
+    unsigned char buf[3];
+    const char* response_data     = "Hello World!";
+    size_t size = sizeof(coap_hdr_t) + 20;
+    response = coap_pdu_init(async->flags & COAP_MESSAGE_CON, COAP_RESPONSE_CODE(205), 0, size);
+    response->hdr->id = coap_new_message_id(ctx);
+    if (async->tokenlen)
+        coap_add_token(response, async->tokenlen, async->token);
+    coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
+    coap_add_data  (response, strlen(response_data), (unsigned char *)response_data);
+
+    if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) {
+
+    }
+    coap_delete_pdu(response);
+    coap_async_state_t *tmp;
+    coap_remove_async(ctx, async->id, &tmp);
+    coap_free_async(async);
+    async = NULL;
+}
+
+/*
+ * The resource handler
+ */
+static void
+async_handler(coap_context_t *ctx, struct coap_resource_t *resource,
+              const coap_endpoint_t *local_interface, coap_address_t *peer,
+              coap_pdu_t *request, str *token, coap_pdu_t *response)
+{
+    async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data");
+}
+
+static void coap_example_thread(void *p)
+{
+    coap_context_t*  ctx = NULL;
+    coap_address_t   serv_addr;
+    coap_resource_t* resource = NULL;
+    fd_set           readfds;
+    struct timeval tv;
+    int flags = 0;
+
+    while (1) {
+        /* Wait for the callback to set the CONNECTED_BIT in the
+           event group.
+        */
+        xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT,
+                            false, true, portMAX_DELAY);
+        ESP_LOGI(TAG, "Connected to AP");
+
+        /* Prepare the CoAP server socket */
+        coap_address_init(&serv_addr);
+        serv_addr.addr.sin.sin_family      = AF_INET;
+        serv_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
+        serv_addr.addr.sin.sin_port        = htons(COAP_DEFAULT_PORT);
+        ctx                                = coap_new_context(&serv_addr);
+        if (ctx) {
+            flags = fcntl(ctx->sockfd, F_GETFL, 0);
+            fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
+
+            tv.tv_usec = COAP_DEFAULT_TIME_USEC;
+            tv.tv_sec = COAP_DEFAULT_TIME_SEC;
+            /* Initialize the resource */
+            resource = coap_resource_init((unsigned char *)"Espressif", 9, 0);
+            if (resource){
+                coap_register_handler(resource, COAP_REQUEST_GET, async_handler);
+                coap_add_resource(ctx, resource);
+                /*For incoming connections*/
+                for (;;) {
+                    FD_ZERO(&readfds);
+                    FD_CLR( ctx->sockfd, &readfds);
+                    FD_SET( ctx->sockfd, &readfds);
+
+                    int result = select( ctx->sockfd+1, &readfds, 0, 0, &tv );
+                    if (result > 0){
+                        if (FD_ISSET( ctx->sockfd, &readfds ))
+                            coap_read(ctx);
+                    } else if (result < 0){
+                        break;
+                    } else {
+                        ESP_LOGE(TAG, "select timeout");
+                    }
+
+                    if (async) {
+                        send_async_response(ctx, ctx->endpoint);
+                    }
+                }
+            }
+
+            coap_free_context(ctx);
+        }
+    }
+
+    vTaskDelete(NULL);
+}
+
+static esp_err_t wifi_event_handler(void *ctx, system_event_t *event)
+{
+    switch(event->event_id) {
+    case SYSTEM_EVENT_STA_START:
+        esp_wifi_connect();
+        break;
+    case SYSTEM_EVENT_STA_GOT_IP:
+        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    case SYSTEM_EVENT_STA_DISCONNECTED:
+        /* This is a workaround as ESP32 WiFi libs don't currently
+           auto-reassociate. */
+        esp_wifi_connect();
+        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
+        break;
+    default:
+        break;
+    }
+    return ESP_OK;
+}
+
+static void wifi_conn_init(void)
+{
+    tcpip_adapter_init();
+    wifi_event_group = xEventGroupCreate();
+    ESP_ERROR_CHECK( esp_event_loop_init(wifi_event_handler, NULL) );
+    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
+    ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
+    ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
+    wifi_config_t wifi_config = {
+        .sta = {
+            .ssid = EXAMPLE_WIFI_SSID,
+            .password = EXAMPLE_WIFI_PASS,
+        },
+    };
+    ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
+    ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
+    ESP_ERROR_CHECK( esp_wifi_start() );
+}
+
+void app_main(void)
+{
+    ESP_ERROR_CHECK( nvs_flash_init() );
+    wifi_conn_init();
+
+    xTaskCreate(coap_example_thread, "coap", 2048, NULL, 5, NULL);
+}
diff --git a/examples/protocols/coap_server/main/component.mk b/examples/protocols/coap_server/main/component.mk
new file mode 100644
index 00000000..0b9d7585
--- /dev/null
+++ b/examples/protocols/coap_server/main/component.mk
@@ -0,0 +1,5 @@
+#
+# "main" pseudo-component makefile.
+#
+# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
+

From 919a5bf9ea9bf15a6bec677eb88477378af8637c Mon Sep 17 00:00:00 2001
From: Dong Heng <dongheng@espressif.com>
Date: Wed, 10 Oct 2018 19:25:47 +0800
Subject: [PATCH 2/2] feat(coap): Add define "COAP_IPV6" to enable/disable IPv6
 function

---
 components/coap/libcoap/include/coap/address.h   | 4 ++++
 components/coap/libcoap/src/address.c            | 4 ++++
 components/coap/libcoap/src/debug.c              | 2 ++
 components/coap/libcoap/src/net.c                | 2 ++
 components/coap/port/include/coap_config_posix.h | 2 ++
 5 files changed, 14 insertions(+)

diff --git a/components/coap/libcoap/include/coap/address.h b/components/coap/libcoap/include/coap/address.h
index 85db2046..b45e81e6 100644
--- a/components/coap/libcoap/include/coap/address.h
+++ b/components/coap/libcoap/include/coap/address.h
@@ -62,7 +62,9 @@ typedef struct coap_address_t {
     struct sockaddr         sa;
     struct sockaddr_storage st;
     struct sockaddr_in      sin;
+#if COAP_IPV6
     struct sockaddr_in6     sin6;
+#endif
   } addr;
 } coap_address_t;
 
@@ -79,10 +81,12 @@ _coap_address_isany_impl(const coap_address_t *a) {
   switch (a->addr.sa.sa_family) {
   case AF_INET:
     return a->addr.sin.sin_addr.s_addr == INADDR_ANY;
+#if COAP_IPV6
   case AF_INET6:
     return memcmp(&in6addr_any,
                   &a->addr.sin6.sin6_addr,
                   sizeof(in6addr_any)) == 0;
+#endif
   default:
     ;
   }
diff --git a/components/coap/libcoap/src/address.c b/components/coap/libcoap/src/address.c
index b4db76f0..acb9ba3c 100644
--- a/components/coap/libcoap/src/address.c
+++ b/components/coap/libcoap/src/address.c
@@ -28,10 +28,12 @@ coap_address_equals(const coap_address_t *a, const coap_address_t *b) {
      a->addr.sin.sin_port == b->addr.sin.sin_port && 
      memcmp(&a->addr.sin.sin_addr, &b->addr.sin.sin_addr, 
 	    sizeof(struct in_addr)) == 0;
+#if COAP_IPV6
  case AF_INET6:
    return a->addr.sin6.sin6_port == b->addr.sin6.sin6_port && 
      memcmp(&a->addr.sin6.sin6_addr, &b->addr.sin6.sin6_addr, 
 	    sizeof(struct in6_addr)) == 0;
+#endif
  default: /* fall through and signal error */
    ;
  }
@@ -45,8 +47,10 @@ int coap_is_mcast(const coap_address_t *a) {
  switch (a->addr.sa.sa_family) {
  case AF_INET:
    return IN_MULTICAST(ntohl(a->addr.sin.sin_addr.s_addr));
+#if COAP_IPV6
  case  AF_INET6:
    return IN6_IS_ADDR_MULTICAST(&a->addr.sin6.sin6_addr);
+#endif
  default:  /* fall through and signal error */
    ;
   }
diff --git a/components/coap/libcoap/src/debug.c b/components/coap/libcoap/src/debug.c
index d68438b7..e1afda60 100644
--- a/components/coap/libcoap/src/debug.c
+++ b/components/coap/libcoap/src/debug.c
@@ -170,6 +170,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le
     addrptr = &addr->addr.sin.sin_addr;
     port = ntohs(addr->addr.sin.sin_port);
     break;
+#if COAP_IPV6
   case AF_INET6:
     if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
       return 0;
@@ -180,6 +181,7 @@ coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t le
     port = ntohs(addr->addr.sin6.sin6_port);
 
     break;
+#endif
   default:
     memcpy(buf, "(unknown address type)", min(22, len));
     return min(22, len);
diff --git a/components/coap/libcoap/src/net.c b/components/coap/libcoap/src/net.c
index e08aaa43..7ebe48ad 100644
--- a/components/coap/libcoap/src/net.c
+++ b/components/coap/libcoap/src/net.c
@@ -508,12 +508,14 @@ coap_transaction_id(const coap_address_t *peer, const coap_pdu_t *pdu,
     coap_hash((const unsigned char *)&peer->addr.sin.sin_addr,
 	      sizeof(peer->addr.sin.sin_addr), h);
     break;
+#if COAP_IPV6
   case AF_INET6:
     coap_hash((const unsigned char *)&peer->addr.sin6.sin6_port,
 	      sizeof(peer->addr.sin6.sin6_port), h);
     coap_hash((const unsigned char *)&peer->addr.sin6.sin6_addr,
 	      sizeof(peer->addr.sin6.sin6_addr), h);
     break;
+#endif
   default:
     return;
   }
diff --git a/components/coap/port/include/coap_config_posix.h b/components/coap/port/include/coap_config_posix.h
index a77e97f0..a925b8d2 100644
--- a/components/coap/port/include/coap_config_posix.h
+++ b/components/coap/port/include/coap_config_posix.h
@@ -36,6 +36,8 @@
 #define CUSTOM_COAP_NETWORK_SEND
 #define CUSTOM_COAP_NETWORK_READ
 
+#define COAP_IPV6 LWIP_IPV6
+
 #endif
 
 #endif /* COAP_CONFIG_POSIX_H_ */