From 8083a0437e9c87bbef62eb232eac447461a74fa8 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Wed, 29 Mar 2017 15:44:24 -0600
Subject: [PATCH 01/12] 6loWPAN: Add beginning of some compression hooks to
 send logic.

---
 net/sixlowpan/sixlowpan_send.c | 38 ++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index ce99656770..59f26959ae 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -204,6 +204,8 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
  * Input Parameters:
  *   dev   - The IEEE802.15.4 MAC network driver interface.
  *   ipv6  - IPv6 plus TCP or UDP headers.
+ *   buf   - Data to send
+ *   len   - Length of data to send
  *   raddr - The MAC address of the destination
  *
  * Returned Value:
@@ -217,8 +219,9 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
  *
  ****************************************************************************/
 
-int sixlowpan_send(FAR struct net_driver_s *dev,
-                   FAR const struct ipv6_hdr_s *ipv6, net_ipv6addr_t raddr)
+static int sixlowpan_send(FAR struct net_driver_s *dev,
+                          FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
+                          size_t len, net_ipv6addr_t raddr)
 {
   FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev;
 
@@ -270,6 +273,33 @@ int sixlowpan_send(FAR struct net_driver_s *dev,
    * argument raddr is NULL, we are sending a broadcast packet.
    */
 
+#warning Missing logic
+
+  ninfo("Sending packet len %d\n", len);
+
+#ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6
+  if (len >= CONFIG_NET_6LOWPAN_COMPRESSION_THRESHOLD)
+    {
+      /* Try to compress the headers */
+
+#if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1)
+      sixlowpan_compresshdr_hc1(dev, &dest);
+#elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06)
+      sixlowpan_compresshdr_hc06(dev, &dest);
+#else
+#  error No compression specified
+#endif
+    }
+  else
+#endif /* !CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 */
+    {
+      /* Small.. use IPv6 dispatch (no compression) */
+
+      sixlowpan_compress_ipv6hdr(ieee, ipv6);
+    }
+
+  ninfo("Header of len %d\n", ieee->i_rime_hdrlen);
+
 #warning Missing logic
   return -ENOSYS;
 }
@@ -385,7 +415,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
    */
 
   ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp,
-                       conn->u.ipv6.raddr);
+                       buf, len, conn->u.ipv6.raddr);
   if (ret < 0)
     {
       nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
@@ -503,7 +533,7 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
    */
 
   ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp,
-                       conn->u.ipv6.raddr);
+                       buf, len, conn->u.ipv6.raddr);
   if (ret < 0)
     {
       nerr("ERROR: sixlowpan_send() failed: %d\n", ret);

From c8cb2009c82e3464355cb6ac53349a4eb35488c1 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Wed, 29 Mar 2017 17:32:12 -0600
Subject: [PATCH 02/12] 6loWPAN: Forget to add a file before last commit.

---
 net/sixlowpan/sixlowpan.h       | 27 ++---------
 net/sixlowpan/sixlowpan_send.c  |  3 +-
 net/sixlowpan/sixlowpan_utils.c | 85 +++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 26 deletions(-)
 create mode 100644 net/sixlowpan/sixlowpan_utils.c

diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h
index b003445fc6..c9fd5fd7bd 100644
--- a/net/sixlowpan/sixlowpan.h
+++ b/net/sixlowpan/sixlowpan.h
@@ -50,10 +50,13 @@
  ****************************************************************************/
 
 /* Rime addres macros */
+/* Copy a Rime address */
 
 #define rimeaddr_copy(dest,src) \
   memcpy(dest, src, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE)
 
+/* Compare two Rime addresses */
+
 #define rimeaddr_cmp(addr1,addr2) \
   (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0)
 
@@ -77,10 +80,6 @@ struct sixlowpan_rime_sniffer_s; /* Foward reference */
 extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
 #endif
 
-/* All zero rime address */
-
-extern const struct rimeaddr_s g_rimeaddr_null;
-
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -171,26 +170,6 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
                                size_t len);
 #endif
 
-/****************************************************************************
- * Name: sixlowpan_output
- *
- * Description:
- *   Process an outgoing UDP or TCP packet.  Called from UDP/TCP logic to
- *   determine if the the packet should be formatted for 6loWPAN output.
- *
- * Input Parameters:
- *   dev - The IEEE802.15.4 MAC network driver interface.
- *
- * Returned Value:
- *   Ok is returned on success; Othewise a negated errno value is returned.
- *   This function is expected to fail if the driver is not an IEEE802.15.4
- *   MAC network driver.  In that case, the UDP/TCP will fall back to normal
- *   IPv4/IPv6 formatting.
- *
- ****************************************************************************/
-
-int sixlowpan_output(FAR struct net_driver_s *dev);
-
 /****************************************************************************
  * Name: sixlowpan_hc06_initialize
  *
diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index 59f26959ae..20b567914e 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -236,8 +236,6 @@ static int sixlowpan_send(FAR struct net_driver_s *dev,
 
   /* Reset rime buffer, packet buffer metatadata */
 
-  dev->d_len = 0;
-
   sixlowpan_pktbuf_reset(ieee);
 
   ieee->i_rimeptr = &dev->d_buf[PACKETBUF_HDR_SIZE];
@@ -300,6 +298,7 @@ static int sixlowpan_send(FAR struct net_driver_s *dev,
 
   ninfo("Header of len %d\n", ieee->i_rime_hdrlen);
 
+  /* Calculate frame header length. */
 #warning Missing logic
   return -ENOSYS;
 }
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
new file mode 100644
index 0000000000..077055f081
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -0,0 +1,85 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_utils.c
+ *
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ *   Copyright (C) 2017, Gregory Nutt, all rights reserved
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Derives from logic in Contiki:
+ *
+ *   Copyright (c) 2008, Swedish Institute of Computer Science.
+ *   All rights reserved.
+ *   Authors: Adam Dunkels <adam@sics.se>
+ *            Nicolas Tsiftes <nvt@sics.se>
+ *            Niclas Finne <nfi@sics.se>
+ *            Mathilde Durvy <mdurvy@cisco.com>
+ *            Julien Abeille <jabeille@cisco.com>
+ *            Joakim Eriksson <joakime@sics.se>
+ *            Joel Hoglund <joel@sics.se>
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <string.h>
+
+#include "nuttx/net/sixlowpan.h"
+
+#include "sixlowpan/sixlowpan.h"
+
+#ifdef CONFIG_NET_6LOWPAN
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: sixlowpan_pktbuf_reset
+ *
+ * Description:
+ *   Reset all attributes and addresses in the packet buffer metadata in the
+ *   provided IEEE802.15.4 MAC driver structure.
+ *
+ ****************************************************************************/
+
+void sixlowpan_pktbuf_reset(FAR struct ieee802154_driver_s *ieee)
+{
+  ieee->i_dev.d_len = 0;
+  ieee->i_rimeptr   = 0;
+  ieee->i_hdrptr    = PACKETBUF_HDR_SIZE;
+
+  memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
+  memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
+}
+
+#endif /* CONFIG_NET_6LOWPAN */

From 2e48af78e7637a3a0a710e074ef46931e62a36f0 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Wed, 29 Mar 2017 18:07:52 -0600
Subject: [PATCH 03/12] 6loWPAN: Repartition some logic

---
 net/sixlowpan/Make.defs              |   8 +
 net/sixlowpan/sixlowpan.h            | 188 +---------------
 net/sixlowpan/sixlowpan_compressor.c |   2 +-
 net/sixlowpan/sixlowpan_globals.c    |   2 +-
 net/sixlowpan/sixlowpan_hc06.c       |   2 +-
 net/sixlowpan/sixlowpan_hc1.c        |   2 +-
 net/sixlowpan/sixlowpan_initialize.c |   1 +
 net/sixlowpan/sixlowpan_input.c      |   2 +-
 net/sixlowpan/sixlowpan_internal.h   | 307 +++++++++++++++++++++++++++
 net/sixlowpan/sixlowpan_send.c       | 290 ++-----------------------
 net/sixlowpan/sixlowpan_sniffer.c    |   2 +-
 net/sixlowpan/sixlowpan_tcpsend.c    | 180 ++++++++++++++++
 net/sixlowpan/sixlowpan_udpsend.c    | 181 ++++++++++++++++
 net/sixlowpan/sixlowpan_utils.c      |   2 +-
 14 files changed, 703 insertions(+), 466 deletions(-)
 create mode 100644 net/sixlowpan/sixlowpan_internal.h
 create mode 100644 net/sixlowpan/sixlowpan_tcpsend.c
 create mode 100644 net/sixlowpan/sixlowpan_udpsend.c

diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs
index 8494f61f3b..68b1ec5ef9 100644
--- a/net/sixlowpan/Make.defs
+++ b/net/sixlowpan/Make.defs
@@ -43,6 +43,14 @@ NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c
 NET_CSRCS += sixlowpan_input.c sixlowpan_send.c
 NET_CSRCS += sixlowpan_compressor.c
 
+ifeq ($(CONFIG_NET_TCP),y)
+NET_CSRCS += sixlowpan_tcpsend.c
+endif
+
+ifeq ($(CONFIG_NET_UDP),y)
+NET_CSRCS += sixlowpan_udpsend.c
+endif
+
 ifeq ($(CONFIG_NET_6LOWPAN_COMPRESSION_HC1),y)
 NET_CSRCS += sixlowpan_hc1.c
 endif
diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h
index c9fd5fd7bd..d3660cb2ce 100644
--- a/net/sixlowpan/sixlowpan.h
+++ b/net/sixlowpan/sixlowpan.h
@@ -1,7 +1,7 @@
 /****************************************************************************
  * net/sixlowpan/sixlowpan.h
  *
- *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gnutt@nuttx.org>
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,41 +45,6 @@
 
 #ifdef CONFIG_NET_6LOWPAN
 
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-/* Rime addres macros */
-/* Copy a Rime address */
-
-#define rimeaddr_copy(dest,src) \
-  memcpy(dest, src, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE)
-
-/* Compare two Rime addresses */
-
-#define rimeaddr_cmp(addr1,addr2) \
-  (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0)
-
-/****************************************************************************
- * Public Types
- ****************************************************************************/
-
-/****************************************************************************
- * Public Data
- ****************************************************************************/
-
-/* A pointer to the optional, architecture-specific compressor */
-
-struct sixlowpan_nhcompressor_s; /* Foward reference */
-extern FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor;
-
-#ifdef CONFIG_NET_6LOWPAN_SNIFFER
-/* Rime Sniffer support for one single listener to enable trace of IP */
-
-struct sixlowpan_rime_sniffer_s; /* Foward reference */
-extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
-#endif
-
 /****************************************************************************
  * Public Types
  ****************************************************************************/
@@ -88,10 +53,7 @@ extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
  * Public Function Prototypes
  ****************************************************************************/
 
-struct net_driver_s;         /* Forward reference */
-struct ieee802154_driver_s;  /* Forward reference */
-struct rimeaddr_s;           /* Forward reference */
-struct socket;               /* Forward reference */
+struct socket; /* Forward reference */
 
 /****************************************************************************
  * Name: sixlowpan_initialize
@@ -170,151 +132,5 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
                                size_t len);
 #endif
 
-/****************************************************************************
- * Name: sixlowpan_hc06_initialize
- *
- * Description:
- *   sixlowpan_hc06_initialize() is called during OS initialization at power-up
- *   reset.  It is called from the common sixlowpan_initialize() function.
- *   sixlowpan_hc06_initialize() configures HC06 networking data structures.
- *   It is called prior to platform-specific driver initialization so that
- *   the 6loWPAN networking subsystem is prepared to deal with network
- *   driver initialization actions.
- *
- * Input Parameters:
- *   None
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_hc06_initialize(void);
-#endif
-
-/****************************************************************************
- * Name: sixlowpan_hc06_initialize
- *
- * Description:
- *   Compress IP/UDP header
- *
- *   This function is called by the 6lowpan code to create a compressed
- *   6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
- *   uip_buf buffer.
- *
- *     HC-06 (draft-ietf-6lowpan-hc, version 6)
- *     http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06
- *
- *   NOTE: sixlowpan_compresshdr_hc06() does not support ISA100_UDP header
- *   compression
- *
- * Input Parameters:
- *   dev      - A reference to the IEE802.15.4 network device state
- *   destaddr - L2 destination address, needed to compress IP dest
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
-                                FAR struct rimeaddr_s *destaddr);
-#endif
-
-/****************************************************************************
- * Name: sixlowpan_hc06_initialize
- *
- * Description:
- *   Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
- *   sixlowpan_buf
- *
- *   This function is called by the input function when the dispatch is HC06.
- *   We process the packet in the rime buffer, uncompress the header fields,
- *   and copy the result in the sixlowpan buffer.  At the end of the
- *   decompression, g_rime_hdrlen and g_uncompressed_hdrlen are set to the
- *   appropriate values
- *
- * Input Parmeters:
- *   dev   - A reference to the IEE802.15.4 network device state
- *   iplen - Equal to 0 if the packet is not a fragment (IP length is then
- *           inferred from the L2 length), non 0 if the packet is a 1st
- *           fragment.
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
-void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
-                                  uint16_t iplen);
-#endif
-
-/****************************************************************************
- * Name: sixlowpan_compresshdr_hc1
- *
- * Description:
- *   Compress IP/UDP header using HC1 and HC_UDP
- *
- *   This function is called by the 6lowpan code to create a compressed
- *   6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
- *   uip_buf buffer.
- *
- * Input Parmeters:
- *   dev      - A reference to the IEE802.15.4 network device state
- *   destaddr - L2 destination address, needed to compress the IP
- *              destination field
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
-void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
-                               FAR struct rimeaddr_s *destaddr);
-#endif
-
-/****************************************************************************
- * Name: sixlowpan_uncompresshdr_hc1
- *
- * Description:
- *   Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf
- *
- *   This function is called by the input function when the dispatch is
- *   HC1.  It processes the packet in the rime buffer, uncompresses the
- *   header fields, and copies the result in the sixlowpan buffer.  At the
- *   end of the decompression, g_rime_hdrlen and uncompressed_hdr_len
- *   are set to the appropriate values
- *
- * Input Parameters:
- *   dev   - A reference to the IEE802.15.4 network device state
- *   iplen - Equal to 0 if the packet is not a fragment (IP length is then
- *           inferred from the L2 length), non 0 if the packet is a 1st
- *           fragment.
- *
- * Returned Value:
- *   None
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
-void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev,
-                                 uint16_t ip_len);
-#endif
-
-/****************************************************************************
- * Name: sixlowpan_pktbuf_reset
- *
- * Description:
- *   Reset all attributes and addresses in the packet buffer metadata in the
- *   provided IEEE802.15.4 MAC driver structure.
- *
- ****************************************************************************/
-
-void sixlowpan_pktbuf_reset(FAR struct ieee802154_driver_s *ieee);
-
 #endif /* CONFIG_NET_6LOWPAN */
 #endif /* _NET_SIXLOWPAN_SIXLOWPAN_H */
diff --git a/net/sixlowpan/sixlowpan_compressor.c b/net/sixlowpan/sixlowpan_compressor.c
index 3457530b79..837bad7760 100644
--- a/net/sixlowpan/sixlowpan_compressor.c
+++ b/net/sixlowpan/sixlowpan_compressor.c
@@ -42,7 +42,7 @@
 #include "nuttx/net/net.h"
 #include "nuttx/net/sixlowpan.h"
 
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 
diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c
index ce5e06b490..4be92354dd 100644
--- a/net/sixlowpan/sixlowpan_globals.c
+++ b/net/sixlowpan/sixlowpan_globals.c
@@ -41,7 +41,7 @@
 
 #include "nuttx/net/sixlowpan.h"
 
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 
diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c
index 733edc900b..b270413143 100644
--- a/net/sixlowpan/sixlowpan_hc06.c
+++ b/net/sixlowpan/sixlowpan_hc06.c
@@ -60,7 +60,7 @@
 #include <nuttx/net/netdev.h>
 #include <nuttx/net/sixlowpan.h>
 
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
 
diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c
index 3f9b93f17d..245a7465c2 100644
--- a/net/sixlowpan/sixlowpan_hc1.c
+++ b/net/sixlowpan/sixlowpan_hc1.c
@@ -49,7 +49,7 @@
 #include <nuttx/config.h>
 
 #include <nuttx/net/netdev.h>
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
 
diff --git a/net/sixlowpan/sixlowpan_initialize.c b/net/sixlowpan/sixlowpan_initialize.c
index 07e10b6a37..54e32b8401 100644
--- a/net/sixlowpan/sixlowpan_initialize.c
+++ b/net/sixlowpan/sixlowpan_initialize.c
@@ -40,6 +40,7 @@
 #include <nuttx/config.h>
 
 #include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 
diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index f28c0eafda..964d988be7 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -42,7 +42,7 @@
 #include <errno.h>
 
 #include "nuttx/net/netdev.h"
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 
diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h
new file mode 100644
index 0000000000..453d340dba
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_internal.h
@@ -0,0 +1,307 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_internal.h
+ *
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H
+#define _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+
+#include <nuttx/net/tcp.h>
+#include <nuttx/net/udp.h>
+#include <nuttx/net/icmpv6.h>
+
+#ifdef CONFIG_NET_6LOWPAN
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Rime addres macros */
+/* Copy a Rime address */
+
+#define rimeaddr_copy(dest,src) \
+  memcpy(dest, src, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE)
+
+/* Compare two Rime addresses */
+
+#define rimeaddr_cmp(addr1,addr2) \
+  (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* IPv6 + TCP header */
+
+struct ipv6tcp_hdr_s
+{
+  struct ipv6_hdr_s     ipv6;
+  struct tcp_hdr_s      tcp;
+};
+
+/* IPv6 + UDP header */
+
+struct ipv6udp_hdr_s
+{
+  struct ipv6_hdr_s     ipv6;
+  struct udp_hdr_s      udp;
+};
+
+/* IPv6 + ICMPv6 header */
+
+struct ipv6icmp_hdr_s
+{
+  struct ipv6_hdr_s     ipv6;
+  struct icmpv6_iphdr_s icmp;
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* A pointer to the optional, architecture-specific compressor */
+
+struct sixlowpan_nhcompressor_s; /* Foward reference */
+extern FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor;
+
+#ifdef CONFIG_NET_6LOWPAN_SNIFFER
+/* Rime Sniffer support for one single listener to enable trace of IP */
+
+struct sixlowpan_rime_sniffer_s; /* Foward reference */
+extern FAR struct sixlowpan_rime_sniffer_s *g_sixlowpan_sniffer;
+#endif
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+struct net_driver_s;         /* Forward reference */
+struct ieee802154_driver_s;  /* Forward reference */
+struct rimeaddr_s;           /* Forward reference */
+
+/****************************************************************************
+ * Name: sixlowpan_send
+ *
+ * Description:
+ *   Process an outgoing UDP or TCP packet.  Takes an IP packet and formats
+ *   it to be sent on an 802.15.4 network using 6lowpan.  Called from common
+ *   UDP/TCP send logic.
+ *
+ *  The payload data is in the caller 'buf' and is of length 'len'.
+ *  Compressed headers will be added and if necessary the packet is
+ *  fragmented. The resulting packet/fragments are put in dev->d_buf and
+ *  the first frame will be delivered to the 802.15.4 MAC. via ieee->i_frame.
+ *
+ * Input Parmeters:
+ *
+ * Input Parameters:
+ *   dev   - The IEEE802.15.4 MAC network driver interface.
+ *   ipv6  - IPv6 plus TCP or UDP headers.
+ *   buf   - Data to send
+ *   len   - Length of data to send
+ *   raddr - The MAC address of the destination
+ *
+ * Returned Value:
+ *   Ok is returned on success; Othewise a negated errno value is returned.
+ *   This function is expected to fail if the driver is not an IEEE802.15.4
+ *   MAC network driver.  In that case, the UDP/TCP will fall back to normal
+ *   IPv4/IPv6 formatting.
+ *
+ * Assumptions:
+ *   Called with the network locked.
+ *
+ ****************************************************************************/
+
+int sixlowpan_send(FAR struct net_driver_s *dev,
+                   FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
+                   size_t len, FAR const struct rimeaddr_s *raddr);
+
+/****************************************************************************
+ * Name: sixlowpan_hc06_initialize
+ *
+ * Description:
+ *   sixlowpan_hc06_initialize() is called during OS initialization at power-up
+ *   reset.  It is called from the common sixlowpan_initialize() function.
+ *   sixlowpan_hc06_initialize() configures HC06 networking data structures.
+ *   It is called prior to platform-specific driver initialization so that
+ *   the 6loWPAN networking subsystem is prepared to deal with network
+ *   driver initialization actions.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
+void sixlowpan_hc06_initialize(void);
+#endif
+
+/****************************************************************************
+ * Name: sixlowpan_hc06_initialize
+ *
+ * Description:
+ *   Compress IP/UDP header
+ *
+ *   This function is called by the 6lowpan code to create a compressed
+ *   6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
+ *   uip_buf buffer.
+ *
+ *     HC-06 (draft-ietf-6lowpan-hc, version 6)
+ *     http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06
+ *
+ *   NOTE: sixlowpan_compresshdr_hc06() does not support ISA100_UDP header
+ *   compression
+ *
+ * Input Parameters:
+ *   dev      - A reference to the IEE802.15.4 network device state
+ *   destaddr - L2 destination address, needed to compress IP dest
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
+void sixlowpan_compresshdr_hc06(FAR struct net_driver_s *dev,
+                                FAR struct rimeaddr_s *destaddr);
+#endif
+
+/****************************************************************************
+ * Name: sixlowpan_hc06_initialize
+ *
+ * Description:
+ *   Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in
+ *   sixlowpan_buf
+ *
+ *   This function is called by the input function when the dispatch is HC06.
+ *   We process the packet in the rime buffer, uncompress the header fields,
+ *   and copy the result in the sixlowpan buffer.  At the end of the
+ *   decompression, g_rime_hdrlen and g_uncompressed_hdrlen are set to the
+ *   appropriate values
+ *
+ * Input Parmeters:
+ *   dev   - A reference to the IEE802.15.4 network device state
+ *   iplen - Equal to 0 if the packet is not a fragment (IP length is then
+ *           inferred from the L2 length), non 0 if the packet is a 1st
+ *           fragment.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06
+void sixlowpan_uncompresshdr_hc06(FAR struct net_driver_s *dev,
+                                  uint16_t iplen);
+#endif
+
+/****************************************************************************
+ * Name: sixlowpan_compresshdr_hc1
+ *
+ * Description:
+ *   Compress IP/UDP header using HC1 and HC_UDP
+ *
+ *   This function is called by the 6lowpan code to create a compressed
+ *   6lowpan packet in the packetbuf buffer from a full IPv6 packet in the
+ *   uip_buf buffer.
+ *
+ * Input Parmeters:
+ *   dev      - A reference to the IEE802.15.4 network device state
+ *   destaddr - L2 destination address, needed to compress the IP
+ *              destination field
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
+void sixlowpan_compresshdr_hc1(FAR struct net_driver_s *dev,
+                               FAR struct rimeaddr_s *destaddr);
+#endif
+
+/****************************************************************************
+ * Name: sixlowpan_uncompresshdr_hc1
+ *
+ * Description:
+ *   Uncompress HC1 (and HC_UDP) headers and put them in sixlowpan_buf
+ *
+ *   This function is called by the input function when the dispatch is
+ *   HC1.  It processes the packet in the rime buffer, uncompresses the
+ *   header fields, and copies the result in the sixlowpan buffer.  At the
+ *   end of the decompression, g_rime_hdrlen and uncompressed_hdr_len
+ *   are set to the appropriate values
+ *
+ * Input Parameters:
+ *   dev   - A reference to the IEE802.15.4 network device state
+ *   iplen - Equal to 0 if the packet is not a fragment (IP length is then
+ *           inferred from the L2 length), non 0 if the packet is a 1st
+ *           fragment.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1
+void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev,
+                                 uint16_t ip_len);
+#endif
+
+/****************************************************************************
+ * Name: sixlowpan_pktbuf_reset
+ *
+ * Description:
+ *   Reset all attributes and addresses in the packet buffer metadata in the
+ *   provided IEEE802.15.4 MAC driver structure.
+ *
+ ****************************************************************************/
+
+void sixlowpan_pktbuf_reset(FAR struct ieee802154_driver_s *ieee);
+
+#endif /* CONFIG_NET_6LOWPAN */
+#endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */
diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index 20b567914e..d204e5eeca 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -55,38 +55,10 @@
 #include "socket/socket.h"
 #include "tcp/tcp.h"
 #include "udp/udp.h"
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 
-/****************************************************************************
- * Private Types
- ****************************************************************************/
-
-/* IPv6 + TCP header */
-
-struct ipv6tcp_hdr_s
-{
-  struct ipv6_hdr_s     ipv6;
-  struct tcp_hdr_s      tcp;
-};
-
-/* IPv6 + UDP header */
-
-struct ipv6udp_hdr_s
-{
-  struct ipv6_hdr_s     ipv6;
-  struct udp_hdr_s      udp;
-};
-
-/* IPv6 + ICMPv6 header */
-
-struct ipv6icmp_hdr_s
-{
-  struct ipv6_hdr_s     ipv6;
-  struct icmpv6_iphdr_s icmp;
-};
-
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
@@ -186,6 +158,10 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
   ieee->i_uncomp_hdrlen += IPv6_HDRLEN;
 }
 
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
 /****************************************************************************
  * Name: sixlowpan_send
  *
@@ -206,7 +182,7 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
  *   ipv6  - IPv6 plus TCP or UDP headers.
  *   buf   - Data to send
  *   len   - Length of data to send
- *   raddr - The MAC address of the destination
+ *   raddr - The IEEE802.15.4 MAC address of the destination
  *
  * Returned Value:
  *   Ok is returned on success; Othewise a negated errno value is returned.
@@ -219,9 +195,9 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
  *
  ****************************************************************************/
 
-static int sixlowpan_send(FAR struct net_driver_s *dev,
-                          FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
-                          size_t len, net_ipv6addr_t raddr)
+int sixlowpan_send(FAR struct net_driver_s *dev,
+                   FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
+                   size_t len, FAR const struct rimeaddr_s *raddr)
 {
   FAR struct ieee802154_driver_s *ieee = (FAR struct ieee802154_driver_s *)dev;
 
@@ -271,7 +247,14 @@ static int sixlowpan_send(FAR struct net_driver_s *dev,
    * argument raddr is NULL, we are sending a broadcast packet.
    */
 
-#warning Missing logic
+  if (raddr == NULL)
+    {
+      memset(&dest, 0, sizeof(struct rimeaddr_s));
+    }
+  else
+    {
+      rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)raddr);
+    }
 
   ninfo("Sending packet len %d\n", len);
 
@@ -303,243 +286,4 @@ static int sixlowpan_send(FAR struct net_driver_s *dev,
   return -ENOSYS;
 }
 
-/****************************************************************************
- * Public Functions
- ****************************************************************************/
-
-/****************************************************************************
- * Function: psock_6lowpan_tcp_send
- *
- * Description:
- *   psock_6lowpan_tcp_send() call may be used only when the TCP socket is in a
- *   connected state (so that the intended recipient is known).
- *
- * Parameters:
- *   psock - An instance of the internal socket structure.
- *   buf   - Data to send
- *   len   - Length of data to send
- *
- * Returned Value:
- *   On success, returns the number of characters sent.  On  error,
- *   -1 is returned, and errno is set appropriately.  Returned error numbers
- *   must be consistent with definition of errors reported by send() or
- *   sendto().
- *
- * Assumptions:
- *   Called with the network locked.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_TCP
-ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
-                               size_t len)
-{
-  FAR struct tcp_conn_s *conn;
-  FAR struct net_driver_s *dev;
-  struct ipv6tcp_hdr_s ipv6tcp;
-  int ret;
-
-  DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
-  DEBUGASSERT(psock->s_type == SOCK_STREAM);
-
-  /* Make sure that this is a valid socket */
-
-  if (psock != NULL || psock->s_crefs <= 0)
-    {
-      nerr("ERROR: Invalid socket\n");
-      return (ssize_t)-EBADF;
-    }
-
-  /* Make sure that this is a connected TCP socket */
-
-  if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags))
-    {
-      nerr("ERROR: Not connected\n");
-      return (ssize_t)-ENOTCONN;
-    }
-
-  /* Get the underlying TCP connection structure */
-
-  conn = (FAR struct tcp_conn_s *)psock->s_conn;
-  DEBUGASSERT(conn != NULL);
-
-#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
-  /* Ignore if not IPv6 domain */
-
-  if (conn->domain != PF_INET6)
-    {
-      nwarn("WARNING: Not IPv6\n");
-      return (ssize_t)-EPROTOTYPE;
-    }
-#endif
-
-  /* Route outgoing message to the correct device */
-
-#ifdef CONFIG_NETDEV_MULTINIC
-  dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
-  if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
-    {
-      nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#else
-  dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
-  if (dev == NULL)
-    {
-      nwarn("WARNING: Not routable\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#endif
-
-#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
-  /* Make sure that the IP address mapping is in the Neighbor Table */
-
-  ret = icmpv6_neighbor(conn->u.ipv6.raddr);
-  if (ret < 0)
-    {
-      nerr("ERROR: Not reachable\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#endif
-
-  /* Initialize the IPv6/TCP headers */
-#warning Missing logic
-
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
-  /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
-   * packet.
-   */
-
-  ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp,
-                       buf, len, conn->u.ipv6.raddr);
-  if (ret < 0)
-    {
-      nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
-    }
-
-  return ret;
-}
-#endif
-
-/****************************************************************************
- * Function: psock_6lowpan_udp_send
- *
- * Description:
- *   psock_6lowpan_udp_send() call may be used with connectionlesss UDP
- *   sockets.
- *
- * Parameters:
- *   psock - An instance of the internal socket structure.
- *   buf   - Data to send
- *   len   - Length of data to send
- *
- * Returned Value:
- *   On success, returns the number of characters sent.  On  error,
- *   -1 is returned, and errno is set appropriately.  Returned error numbers
- *   must be consistent with definition of errors reported by send() or
- *   sendto().
- *
- * Assumptions:
- *   Called with the network locked.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_UDP
-ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
-                               size_t len)
-{
-  FAR struct udp_conn_s *conn;
-  FAR struct net_driver_s *dev;
-  struct ipv6udp_hdr_s ipv6udp;
-  int ret;
-
-  DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
-  DEBUGASSERT(psock->s_type == SOCK_DGRAM);
-
-  /* Make sure that this is a valid socket */
-
-  if (psock != NULL || psock->s_crefs <= 0)
-    {
-      nerr("ERROR: Invalid socket\n");
-      return (ssize_t)-EBADF;
-    }
-
-  /* Was the UDP socket connected via connect()? */
-
-  if (psock->s_type != SOCK_DGRAM || !_SS_ISCONNECTED(psock->s_flags))
-    {
-      /* No, then it is not legal to call send() with this socket. */
-
-      return -ENOTCONN;
-    }
-
-  /* Get the underlying UDP "connection" structure */
-
-  conn = (FAR struct udp_conn_s *)psock->s_conn;
-  DEBUGASSERT(conn != NULL);
-
-#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
-  /* Ignore if not IPv6 domain */
-
-  if (conn->domain != PF_INET6)
-    {
-      nwarn("WARNING: Not IPv6\n");
-      return (ssize_t)-EPROTOTYPE;
-    }
-#endif
-
-  /* Route outgoing message to the correct device */
-
-#ifdef CONFIG_NETDEV_MULTINIC
-  dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
-  if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
-    {
-      nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#else
-  dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
-  if (dev == NULL)
-    {
-      nwarn("WARNING: Not routable\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#endif
-
-#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
-  /* Make sure that the IP address mapping is in the Neighbor Table */
-
-  ret = icmpv6_neighbor(conn->u.ipv6.raddr);
-  if (ret < 0)
-    {
-      nerr("ERROR: Not reachable\n");
-      return (ssize_t)-ENETUNREACH;
-    }
-#endif
-
-  /* Initialize the IPv6/UDP headers */
-#warning Missing logic
-
-  /* Set the socket state to sending */
-
-  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
-
-  /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
-   * packet.
-   */
-
-  ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp,
-                       buf, len, conn->u.ipv6.raddr);
-  if (ret < 0)
-    {
-      nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
-    }
-
-  return ret;
-}
-#endif
-
 #endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_sniffer.c b/net/sixlowpan/sixlowpan_sniffer.c
index f6134a86f0..32a2e3121e 100644
--- a/net/sixlowpan/sixlowpan_sniffer.c
+++ b/net/sixlowpan/sixlowpan_sniffer.c
@@ -42,7 +42,7 @@
 #include "nuttx/net/net.h"
 #include "nuttx/net/sixlowpan.h"
 
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN_SNIFFER
 
diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c
new file mode 100644
index 0000000000..9928bc3d11
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_tcpsend.c
@@ -0,0 +1,180 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_tcpsend.c
+ *
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nuttx/net/netdev.h"
+#include "nuttx/net/tcp.h"
+#include "nuttx/net/sixlowpan.h"
+
+#include "netdev/netdev.h"
+#include "socket/socket.h"
+#include "tcp/tcp.h"
+#include "sixlowpan/sixlowpan_internal.h"
+
+#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_TCP)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: psock_6lowpan_tcp_send
+ *
+ * Description:
+ *   psock_6lowpan_tcp_send() call may be used only when the TCP socket is in a
+ *   connected state (so that the intended recipient is known).
+ *
+ * Parameters:
+ *   psock - An instance of the internal socket structure.
+ *   buf   - Data to send
+ *   len   - Length of data to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   -1 is returned, and errno is set appropriately.  Returned error numbers
+ *   must be consistent with definition of errors reported by send() or
+ *   sendto().
+ *
+ * Assumptions:
+ *   Called with the network locked.
+ *
+ ****************************************************************************/
+
+ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf,
+                               size_t len)
+{
+  FAR struct tcp_conn_s *conn;
+  FAR struct net_driver_s *dev;
+  struct ipv6tcp_hdr_s ipv6tcp;
+  struct rimeaddr_s dest;
+  int ret;
+
+  DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
+  DEBUGASSERT(psock->s_type == SOCK_STREAM);
+
+  /* Make sure that this is a valid socket */
+
+  if (psock != NULL || psock->s_crefs <= 0)
+    {
+      nerr("ERROR: Invalid socket\n");
+      return (ssize_t)-EBADF;
+    }
+
+  /* Make sure that this is a connected TCP socket */
+
+  if (psock->s_type != SOCK_STREAM || !_SS_ISCONNECTED(psock->s_flags))
+    {
+      nerr("ERROR: Not connected\n");
+      return (ssize_t)-ENOTCONN;
+    }
+
+  /* Get the underlying TCP connection structure */
+
+  conn = (FAR struct tcp_conn_s *)psock->s_conn;
+  DEBUGASSERT(conn != NULL);
+
+#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
+  /* Ignore if not IPv6 domain */
+
+  if (conn->domain != PF_INET6)
+    {
+      nwarn("WARNING: Not IPv6\n");
+      return (ssize_t)-EPROTOTYPE;
+    }
+#endif
+
+  /* Route outgoing message to the correct device */
+
+#ifdef CONFIG_NETDEV_MULTINIC
+  dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
+  if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
+    {
+      nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#else
+  dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
+  if (dev == NULL)
+    {
+      nwarn("WARNING: Not routable\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#endif
+
+#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
+  /* Make sure that the IP address mapping is in the Neighbor Table */
+
+  ret = icmpv6_neighbor(conn->u.ipv6.raddr);
+  if (ret < 0)
+    {
+      nerr("ERROR: Not reachable\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#endif
+
+  /* Initialize the IPv6/TCP headers */
+#warning Missing logic
+
+  /* Set the socket state to sending */
+
+  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
+
+  /* Get the Rime MAC address of the destination */
+#warning Missing logic
+
+  /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
+   * packet.
+   */
+
+  ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp,
+                       buf, len, &dest);
+  if (ret < 0)
+    {
+      nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_TCP */
diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c
new file mode 100644
index 0000000000..9946516e00
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_udpsend.c
@@ -0,0 +1,181 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_udpsend.c
+ *
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include "nuttx/net/netdev.h"
+#include "nuttx/net/udp.h"
+#include "nuttx/net/sixlowpan.h"
+
+#include "netdev/netdev.h"
+#include "socket/socket.h"
+#include "udp/udp.h"
+#include "sixlowpan/sixlowpan_internal.h"
+
+#if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_UDP)
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: psock_6lowpan_udp_send
+ *
+ * Description:
+ *   psock_6lowpan_udp_send() call may be used with connectionlesss UDP
+ *   sockets.
+ *
+ * Parameters:
+ *   psock - An instance of the internal socket structure.
+ *   buf   - Data to send
+ *   len   - Length of data to send
+ *
+ * Returned Value:
+ *   On success, returns the number of characters sent.  On  error,
+ *   -1 is returned, and errno is set appropriately.  Returned error numbers
+ *   must be consistent with definition of errors reported by send() or
+ *   sendto().
+ *
+ * Assumptions:
+ *   Called with the network locked.
+ *
+ ****************************************************************************/
+
+ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf,
+                               size_t len)
+{
+  FAR struct udp_conn_s *conn;
+  FAR struct net_driver_s *dev;
+  struct ipv6udp_hdr_s ipv6udp;
+  struct rimeaddr_s dest;
+  int ret;
+
+  DEBUGASSERT(psock != NULL && psock->s_crefs > 0);
+  DEBUGASSERT(psock->s_type == SOCK_DGRAM);
+
+  /* Make sure that this is a valid socket */
+
+  if (psock != NULL || psock->s_crefs <= 0)
+    {
+      nerr("ERROR: Invalid socket\n");
+      return (ssize_t)-EBADF;
+    }
+
+  /* Was the UDP socket connected via connect()? */
+
+  if (psock->s_type != SOCK_DGRAM || !_SS_ISCONNECTED(psock->s_flags))
+    {
+      /* No, then it is not legal to call send() with this socket. */
+
+      return -ENOTCONN;
+    }
+
+  /* Get the underlying UDP "connection" structure */
+
+  conn = (FAR struct udp_conn_s *)psock->s_conn;
+  DEBUGASSERT(conn != NULL);
+
+#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
+  /* Ignore if not IPv6 domain */
+
+  if (conn->domain != PF_INET6)
+    {
+      nwarn("WARNING: Not IPv6\n");
+      return (ssize_t)-EPROTOTYPE;
+    }
+#endif
+
+  /* Route outgoing message to the correct device */
+
+#ifdef CONFIG_NETDEV_MULTINIC
+  dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr);
+  if (dev == NULL || dev->d_lltype != NET_LL_IEEE805154)
+    {
+      nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#else
+  dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr);
+  if (dev == NULL)
+    {
+      nwarn("WARNING: Not routable\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#endif
+
+#ifdef CONFIG_NET_ICMPv6_NEIGHBOR
+  /* Make sure that the IP address mapping is in the Neighbor Table */
+
+  ret = icmpv6_neighbor(conn->u.ipv6.raddr);
+  if (ret < 0)
+    {
+      nerr("ERROR: Not reachable\n");
+      return (ssize_t)-ENETUNREACH;
+    }
+#endif
+
+  /* Initialize the IPv6/UDP headers */
+#warning Missing logic
+
+  /* Set the socket state to sending */
+
+  psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND);
+
+  /* Get the Rime MAC address of the destination */
+#warning Missing logic
+
+  /* If routable, then call sixlowpan_send() to format and send the 6loWPAN
+   * packet.
+   */
+
+  ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp,
+                       buf, len, &dest);
+  if (ret < 0)
+    {
+      nerr("ERROR: sixlowpan_send() failed: %d\n", ret);
+    }
+
+  return ret;
+}
+
+#endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_UDP */
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
index 077055f081..5df1b3439c 100644
--- a/net/sixlowpan/sixlowpan_utils.c
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -55,7 +55,7 @@
 
 #include "nuttx/net/sixlowpan.h"
 
-#include "sixlowpan/sixlowpan.h"
+#include "sixlowpan/sixlowpan_internal.h"
 
 #ifdef CONFIG_NET_6LOWPAN
 

From 21545ab6434e78390bf29fdbfb4462bc12b9c645 Mon Sep 17 00:00:00 2001
From: Juha Niskanen <juha.niskanen@haltian.com>
Date: Thu, 30 Mar 2017 06:54:59 -0600
Subject: [PATCH 04/12] net/local: connect: Fix warning with
 gcc-arm-none-eabi-5-2016q1.  Using compiler from gcc-arm-none-eabi-5-2016q1
 toolchain:

  gcc version 5.3.1 20160307 (release) [ARM/embedded-5-branch revision 234589] (GNU Tools for ARM Embedded Processors)

gives error:

  local/local_connect.c:188:7: error: '_local_semtake' is static but used in inline function 'local_stream_connect' which is not static [-Werror]

this is due to compiler enforcing ISO/IEC 9899:1999 6.7.4.3:  "An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static storage duration, and shall not contain a reference to an identifier with internal linkage."

Fix by making inlined caller to have internal linkage as well.
---
 net/local/local_connect.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/net/local/local_connect.c b/net/local/local_connect.c
index 53dd321905..ee9a1dc2c9 100644
--- a/net/local/local_connect.c
+++ b/net/local/local_connect.c
@@ -121,9 +121,9 @@ static inline void _local_semtake(sem_t *sem)
  *
  ****************************************************************************/
 
-int inline local_stream_connect(FAR struct local_conn_s *client,
-                                FAR struct local_conn_s *server,
-                                bool nonblock)
+static int inline local_stream_connect(FAR struct local_conn_s *client,
+                                       FAR struct local_conn_s *server,
+                                       bool nonblock)
 {
   int ret;
 

From dffb8a67e3e92500651db3eca516dbcfc275311a Mon Sep 17 00:00:00 2001
From: Jussi Kivilinna <jussi.kivilinna@haltian.com>
Date: Thu, 30 Mar 2017 07:38:37 -0600
Subject: [PATCH 05/12] Add entropy pool and strong random number generator

Entropy pool gathers environmental noise from device drivers, user-space, etc., and returns good random numbers, suitable for cryptographic use. Based on entropy pool design from *BSDs and uses BLAKE2Xs algorithm for CSPRNG output.

Patch also adds /dev/urandom support for using entropy pool RNG and new 'getrandom' system call for getting randomness without file-descriptor usage (thus avoiding file-descriptor exhaustion attacks). The 'getrandom' interface is similar as 'getentropy' and 'getrandom' available on OpenBSD and Linux respectively.
---
 configs/Kconfig                  |  21 ++
 crypto/Kconfig                   |  31 ++
 crypto/Makefile                  |  14 +-
 crypto/blake2s.c                 | 606 +++++++++++++++++++++++++++++++
 crypto/random_pool.c             | 561 ++++++++++++++++++++++++++++
 drivers/Kconfig                  |   9 +
 drivers/analog/adc.c             |   5 +
 drivers/dev_urandom.c            |  72 +++-
 drivers/input/ads7843e.c         |   3 +
 drivers/input/ajoystick.c        |   3 +
 drivers/input/button_upper.c     |   3 +
 drivers/input/djoystick.c        |   3 +
 drivers/input/max11802.c         |   3 +
 drivers/input/mxt.c              |   3 +
 drivers/input/stmpe811_temp.c    |   3 +
 drivers/input/stmpe811_tsc.c     |   3 +
 drivers/input/tsc2007.c          |   5 +-
 drivers/sensors/adxl345_base.c   |   4 +
 drivers/sensors/bh1750fvi.c      |   3 +
 drivers/sensors/bmg160.c         |   5 +
 drivers/sensors/bmp180.c         |   5 +
 drivers/sensors/kxtj9.c          |   7 +
 drivers/sensors/l3gd20.c         |   5 +
 drivers/sensors/lis331dl.c       |   6 +
 drivers/sensors/lis3dsh.c        |   5 +
 drivers/sensors/lis3mdl.c        |   6 +
 drivers/sensors/lm75.c           |   3 +
 drivers/sensors/lm92.c           |   3 +
 drivers/sensors/lsm9ds1.c        |  10 +
 drivers/sensors/max31855.c       |   5 +
 drivers/sensors/max6675.c        |   5 +
 drivers/sensors/mb7040.c         |   5 +
 drivers/sensors/mcp9844.c        |   5 +
 drivers/sensors/mlx90393.c       |   6 +
 drivers/sensors/mpl115a.c        |   6 +
 drivers/sensors/ms58xx.c         |   3 +
 drivers/sensors/veml6070.c       |   5 +
 drivers/sensors/xen1210.c        |   7 +
 include/nuttx/board.h            |  16 +
 include/nuttx/crypto/blake2s.h   | 197 ++++++++++
 include/nuttx/random.h           | 171 +++++++++
 include/string.h                 |   2 +
 include/sys/random.h             |  77 ++++
 include/sys/syscall.h            |  15 +-
 libc/string/Make.defs            |   1 +
 libc/string/lib_explicit_bzero.c |  56 +++
 sched/irq/irq_dispatch.c         |   9 +-
 syscall/syscall.csv              |   1 +
 syscall/syscall_lookup.h         |   7 +
 syscall/syscall_stublookup.c     |   5 +
 50 files changed, 2005 insertions(+), 9 deletions(-)
 create mode 100644 crypto/blake2s.c
 create mode 100644 crypto/random_pool.c
 create mode 100644 include/nuttx/crypto/blake2s.h
 create mode 100644 include/nuttx/random.h
 create mode 100644 include/sys/random.h
 create mode 100644 libc/string/lib_explicit_bzero.c

diff --git a/configs/Kconfig b/configs/Kconfig
index aef29eecd6..27d98e0821 100644
--- a/configs/Kconfig
+++ b/configs/Kconfig
@@ -2015,6 +2015,27 @@ config BOARD_RESET_ON_CRASH
 		If selected the board_crashdump should reset the machine after
 		saveing the state of the machine
 
+config BOARD_ENTROPY_POOL
+	bool "Enable Board level storing of entropy pool structure"
+	default n
+	depends on CRYPTO_RANDOM_POOL
+	---help---
+		Entropy pool structure can be provided by board source.
+		Use for this is, for example, to allocate entropy pool
+		from special area of RAM which content is kept over
+		system reset.
+
+config BOARD_INITRNGSEED
+	bool "Enable Board level initial seeding of entropy pool RNG"
+	default n
+	depends on CRYPTO_RANDOM_POOL
+	---help---
+		If enabled, entropy pool random number generator will call
+		board_init_rndseed() upon initialization. This function
+		can then provide early entropy seed to the pool through
+		entropy injection APIs provided at 'nuttx/random.h'.
+#endif
+
 config LIB_BOARDCTL
 	bool "Enable boardctl() interface"
 	default n
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 022fce7a05..0c93eaaa99 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -50,4 +50,35 @@ config CRYPTO_SW_AES
 		implemenations.  This needs to support up_aesinitialize() and
 		aes_cypher() per include/nuttx/crypto/crypto.h.
 
+config CRYPTO_BLAKE2S
+	bool "BLAKE2s hash algorithm"
+	default n
+	---help---
+		Enable the BLAKE2s hash algorithm
+
+config CRYPTO_RANDOM_POOL
+	bool "Entropy pool and strong randon number generator"
+	default n
+	select CRYPTO_BLAKE2S
+	---help---
+		Entropy pool gathers environmental noise from device drivers,
+		user-space, etc., and returns good random numbers, suitable
+		for cryptographic use. Based on entropy pool design from
+		*BSDs and uses BLAKE2Xs algorithm for CSPRNG output.
+
+		NOTE: May not actually be cyptographically secure, if
+		not enough entropy is made available to the entropy pool.
+
+if CRYPTO_RANDOM_POOL
+
+config CRYPTO_RANDOM_POOL_COLLECT_IRQ_RANDOMNESS
+	bool "Use interrupts to feed timing randomness to entropy pool"
+	default y
+	---help---
+		Feed entropy pool with interrupt randomness from interrupt
+		dispatch function 'irq_dispatch'. This adds some overhead
+		for every interrupt handled.
+
+endif # CRYPTO_RANDOM_POOL
+
 endif # CRYPTO
diff --git a/crypto/Makefile b/crypto/Makefile
index 23b4cf137e..56b75b6517 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -56,6 +56,18 @@ ifeq ($(CONFIG_CRYPTO_SW_AES),y)
   CRYPTO_CSRCS += aes.c
 endif
 
+# BLAKE2s hash algorithm
+
+ifeq ($(CONFIG_CRYPTO_BLAKE2S),y)
+  CRYPTO_CSRCS += blake2s.c
+endif
+
+# Entropy pool random number generator
+
+ifeq ($(CONFIG_CRYPTO_RANDOM_POOL),y)
+  CRYPTO_CSRCS += random_pool.c
+endif
+
 endif # CONFIG_CRYPTO
 
 ASRCS = $(CRYPTO_ASRCS)
@@ -97,4 +109,4 @@ distclean: clean
 	$(call DELFILE, Make.dep)
 	$(call DELFILE, .depend)
 
--include Make.dep
\ No newline at end of file
+-include Make.dep
diff --git a/crypto/blake2s.c b/crypto/blake2s.c
new file mode 100644
index 0000000000..a88ed045c5
--- /dev/null
+++ b/crypto/blake2s.c
@@ -0,0 +1,606 @@
+/****************************************************************************
+ * crypto/blake2s.c
+ *
+ * This code is based on public-domain/CC0 BLAKE2 reference implementation
+ * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/ref
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * Copyright (C) 2017 Haltian Ltd. All rights reserved.
+ * Authors: Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <debug.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/crypto/blake2s.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const uint32_t blake2s_IV[8] =
+{
+  0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, 0x510e527ful,
+  0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul
+};
+
+static const uint8_t blake2s_sigma[10][16] =
+{
+  { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
+  { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
+  { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
+  { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
+  { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
+  { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
+  { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
+  { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
+  { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
+  { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 }
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static inline uint32_t rotr32(const uint32_t w, const unsigned int c)
+{
+  return (w >> (c & 31)) | (w << ((32 - c) & 31));
+}
+
+static void blake2_memcpy(FAR void *dst, FAR const void *src, size_t len)
+{
+#ifdef BLAKE2_UNALIGNED
+  FAR uint32_alias_t *idst = dst;
+  FAR const uint32_alias_t *isrc = src;
+  FAR uint8_t *bdst;
+  FAR const uint8_t *bsrc;
+
+  while (len >= sizeof(uint32_alias_t))
+    {
+      *idst = *isrc;
+      idst++;
+      isrc++;
+      len -= sizeof(uint32_alias_t);
+    }
+
+  bdst = (FAR uint8_t *)idst;
+  bsrc = (FAR const uint8_t *)isrc;
+  while (len)
+    {
+      *bdst = *bsrc;
+      bdst++;
+      bsrc++;
+      len--;
+    }
+#else
+  memcpy(dst, set, len);
+#endif
+}
+
+static void blake2_memset(FAR void *dst, int set, size_t len)
+{
+#ifdef BLAKE2_UNALIGNED
+  FAR uint32_alias_t *idst = dst;
+  FAR uint8_t *bdst;
+  uint32_t mset;
+
+  set &= 0xff;
+  mset = (uint32_t)set * 0x01010101UL;
+
+  while (len >= sizeof(uint32_alias_t))
+    {
+      *idst = mset;
+      idst++;
+      len -= sizeof(uint32_alias_t);
+    }
+
+  bdst = (FAR uint8_t *)idst;
+  set &= 0xff;
+  while (len)
+    {
+      *bdst = set;
+      bdst++;
+      len--;
+    }
+#else
+  memset(dst, set, len);
+#endif
+}
+
+static inline void secure_zero_memory(FAR void *v, size_t n)
+{
+  explicit_bzero(v, n);
+}
+
+/* Some helper functions, not necessarily useful */
+
+static int blake2s_is_lastblock(FAR const blake2s_state *S)
+{
+  return S->f[0] != 0;
+}
+
+static void blake2s_set_lastblock(FAR blake2s_state *S)
+{
+  S->f[0] = (uint32_t)-1;
+}
+
+static void blake2s_increment_counter(FAR blake2s_state *S, const uint32_t inc)
+{
+  S->t[0] += inc;
+  S->t[1] += (S->t[0] < inc);
+}
+
+static void blake2s_init0(FAR blake2s_state *S)
+{
+  size_t i;
+
+  blake2_memset(S, 0, sizeof(*S) - sizeof(S->buf));
+
+  for (i = 0; i < 8; ++i)
+    S->h[i] = blake2s_IV[i];
+}
+
+static void blake2s_compress(FAR blake2s_state *S,
+                             const uint8_t in[BLAKE2S_BLOCKBYTES])
+{
+  uint32_t m[16];
+  uint32_t v[16];
+  size_t i;
+  unsigned int round;
+
+  for (i = 0; i < 16; ++i)
+    {
+      m[i] = blake2_load32(in + i * sizeof(m[i]));
+    }
+
+  for (i = 0; i < 8; ++i)
+    {
+      v[i] = S->h[i];
+    }
+
+  v[8] = blake2s_IV[0];
+  v[9] = blake2s_IV[1];
+  v[10] = blake2s_IV[2];
+  v[11] = blake2s_IV[3];
+  v[12] = S->t[0] ^ blake2s_IV[4];
+  v[13] = S->t[1] ^ blake2s_IV[5];
+  v[14] = S->f[0] ^ blake2s_IV[6];
+  v[15] = S->f[1] ^ blake2s_IV[7];
+
+#define G(r,i,a,b,c,d)                      \
+  do {                                      \
+    a = a + b + m[blake2s_sigma[r][2*i+0]]; \
+    d = rotr32(d ^ a, 16);                  \
+    c = c + d;                              \
+    b = rotr32(b ^ c, 12);                  \
+    a = a + b + m[blake2s_sigma[r][2*i+1]]; \
+    d = rotr32(d ^ a, 8);                   \
+    c = c + d;                              \
+    b = rotr32(b ^ c, 7);                   \
+  } while(0)
+
+#define ROUND(r)                    \
+  do {                              \
+    G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+    G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+    G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+    G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+    G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+    G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+    G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+    G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+  } while(0)
+
+  /* Size vs performance trade-off. With unrolling, on ARMv7-M function text
+   * is ~4 KiB and without ~1 KiB. Without unrolling we take ~25% performance
+   * hit. */
+
+#if 1
+  /* Smaller, slightly slower. */
+
+  for (round = 0; round < 10; round++)
+    {
+      ROUND(round);
+    }
+#else
+  /* Larger, slightly faster. */
+
+  (void)(round=0);
+  ROUND(0);
+  ROUND(1);
+  ROUND(2);
+  ROUND(3);
+  ROUND(4);
+  ROUND(5);
+  ROUND(6);
+  ROUND(7);
+  ROUND(8);
+  ROUND(9);
+#endif
+
+#undef G
+#undef ROUND
+
+  for (i = 0; i < 8; ++i)
+    {
+      S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+    }
+}
+
+#ifdef CONFIG_BLAKE2_SELFTEST
+/* BLAKE2s self-test from RFC 7693 */
+
+static void selftest_seq(FAR uint8_t *out, size_t len, uint32_t seed)
+{
+  size_t i;
+  uint32_t t, a, b;
+
+  a = 0xDEAD4BAD * seed; /* prime */
+  b = 1;
+  /* fill the buf */
+  for (i = 0; i < len; i++)
+    {
+      t = a + b;
+      a = b;
+      b = t;
+      out[i] = (t >> 24) & 0xFF;
+    }
+}
+
+static int blake2s_selftest(void)
+{
+  /* Grand hash of hash results. */
+
+  static const uint8_t blake2s_res[32] =
+  {
+    0x6a, 0x41, 0x1f, 0x08, 0xce, 0x25, 0xad, 0xcd, 0xfb, 0x02, 0xab, 0xa6,
+    0x41, 0x45, 0x1c, 0xec, 0x53, 0xc5, 0x98, 0xb2, 0x4f, 0x4f, 0xc7, 0x87,
+    0xfb, 0xdc, 0x88, 0x79, 0x7f, 0x4c, 0x1d, 0xfe
+  };
+
+  /* Parameter sets. */
+
+  static const size_t b2s_md_len[4] = { 16, 20, 28, 32 };
+  static const size_t b2s_in_len[6] = { 0, 3, 64, 65, 255, 1024 };
+  size_t i, j, outlen, inlen;
+  FAR uint8_t *in;
+  uint8_t md[32], key[32];
+  blake2s_state ctx;
+  int ret = -1;
+
+  in = malloc(1024);
+  if (!in)
+    {
+      goto out;
+    }
+
+  /* 256-bit hash for testing. */
+
+  if (blake2s_init(&ctx, 32))
+    {
+      goto out;
+    }
+
+  for (i = 0; i < 4; i++)
+    {
+      outlen = b2s_md_len[i];
+      for (j = 0; j < 6; j++)
+        {
+          inlen = b2s_in_len[j];
+
+          selftest_seq(in, inlen, inlen);     /* unkeyed hash */
+          blake2s(md, outlen, in, inlen, NULL, 0);
+          blake2s_update(&ctx, md, outlen);   /* hash the hash */
+
+          selftest_seq(key, outlen, outlen);  /* keyed hash */
+          blake2s(md, outlen, in, inlen, key, outlen);
+          blake2s_update(&ctx, md, outlen);   /* hash the hash */
+        }
+    }
+
+  /* Compute and compare the hash of hashes. */
+
+  blake2s_final(&ctx, md, 32);
+  for (i = 0; i < 32; i++)
+    {
+      if (md[i] != blake2s_res[i])
+        goto out;
+    }
+
+  ret = 0;
+
+out:
+  free(in);
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/* init2 xors IV with input parameter block */
+
+int blake2s_init_param(FAR blake2s_state *S, FAR const blake2s_param *P)
+{
+  FAR const unsigned char *p = (FAR const unsigned char *)(P);
+  size_t i;
+#ifdef CONFIG_BLAKE2_SELFTEST
+  static bool selftest_done = false;
+  int ret;
+
+  if (!selftest_done)
+    {
+      selftest_done = true;
+      ret = blake2s_selftest();
+      DEBUGASSERT(ret == 0);
+      if (ret)
+        return -1;
+    }
+#endif
+
+  blake2s_init0(S);
+
+  /* IV XOR ParamBlock */
+
+  for (i = 0; i < 8; ++i)
+    {
+      S->h[i] ^= blake2_load32(&p[i * 4]);
+    }
+
+  S->outlen = P->digest_length;
+  return 0;
+}
+
+/* Sequential blake2s initialization */
+
+int blake2s_init(FAR blake2s_state *S, size_t outlen)
+{
+  blake2s_param P[1];
+
+  /* Move interval verification here? */
+
+  if ((!outlen) || (outlen > BLAKE2S_OUTBYTES))
+    {
+      return -1;
+    }
+
+  P->digest_length = (uint8_t)outlen;
+  P->key_length = 0;
+  P->fanout = 1;
+  P->depth = 1;
+  blake2_store32(P->leaf_length, 0);
+  blake2_store32(P->node_offset, 0);
+  blake2_store16(P->xof_length, 0);
+  P->node_depth = 0;
+  P->inner_length = 0;
+  /* memset(P->reserved, 0, sizeof(P->reserved)); */
+  blake2_memset(P->salt, 0, sizeof(P->salt));
+  blake2_memset(P->personal, 0, sizeof(P->personal));
+  return blake2s_init_param(S, P);
+}
+
+int blake2s_init_key(FAR blake2s_state *S, size_t outlen, FAR const void *key,
+                     size_t keylen)
+{
+  blake2s_param P[1];
+  uint8_t block[BLAKE2S_BLOCKBYTES];
+
+  if ((!outlen) || (outlen > BLAKE2S_OUTBYTES))
+    {
+      return -1;
+    }
+
+  if (!key || !keylen || keylen > BLAKE2S_KEYBYTES)
+    {
+      return -1;
+    }
+
+  P->digest_length = (uint8_t) outlen;
+  P->key_length = (uint8_t) keylen;
+  P->fanout = 1;
+  P->depth = 1;
+  blake2_store32(P->leaf_length, 0);
+  blake2_store32(P->node_offset, 0);
+  blake2_store16(P->xof_length, 0);
+  P->node_depth = 0;
+  P->inner_length = 0;
+  /* memset(P->reserved, 0, sizeof(P->reserved)); */
+  blake2_memset(P->salt, 0, sizeof(P->salt));
+  blake2_memset(P->personal, 0, sizeof(P->personal));
+
+  blake2s_init_param(S, P);
+
+  blake2_memset(block, 0, BLAKE2S_BLOCKBYTES);
+  blake2_memcpy(block, key, keylen);
+  blake2s_update(S, block, BLAKE2S_BLOCKBYTES);
+  secure_zero_memory(block, BLAKE2S_BLOCKBYTES); /* Burn the key from stack */
+
+  return 0;
+}
+
+int blake2s_update(FAR blake2s_state *S, FAR const void *pin, size_t inlen)
+{
+  FAR const unsigned char * in = FAR (const unsigned char *)pin;
+  size_t left, fill;
+
+  if (inlen <= 0)
+    {
+      return 0;
+    }
+
+  left = S->buflen;
+  fill = BLAKE2S_BLOCKBYTES - left;
+  if (inlen > fill)
+    {
+      S->buflen = 0;
+      if (fill)
+        {
+          blake2_memcpy(S->buf + left, in, fill); /* Fill buffer */
+        }
+
+      blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
+      blake2s_compress(S, S->buf); /* Compress */
+      in += fill;
+      inlen -= fill;
+      while (inlen > BLAKE2S_BLOCKBYTES)
+        {
+          blake2s_increment_counter(S, BLAKE2S_BLOCKBYTES);
+          blake2s_compress(S, in);
+          in += BLAKE2S_BLOCKBYTES;
+          inlen -= BLAKE2S_BLOCKBYTES;
+        }
+    }
+
+  blake2_memcpy(S->buf + S->buflen, in, inlen);
+  S->buflen += inlen;
+
+  return 0;
+}
+
+int blake2s_final(FAR blake2s_state *S, FAR void *out, size_t outlen)
+{
+  FAR uint8_t *outbuf = out;
+  uint32_t tmp = 0;
+  size_t outwords;
+  size_t padding;
+  size_t i;
+
+  if (out == NULL || outlen < S->outlen)
+    {
+      return -1;
+    }
+
+  if (blake2s_is_lastblock(S))
+    {
+      return -1;
+    }
+
+  blake2s_increment_counter(S, (uint32_t)S->buflen);
+  blake2s_set_lastblock(S);
+  padding = BLAKE2S_BLOCKBYTES - S->buflen;
+  if (padding)
+    {
+      blake2_memset(S->buf + S->buflen, 0, padding);
+    }
+  blake2s_compress(S, S->buf);
+
+  /* Output hash to out buffer */
+
+  outwords = outlen / sizeof(uint32_t);
+  outwords = (outwords < 8) ? outwords : 8;
+  for (i = 0; i < outwords; ++i)
+    {
+      /* Store full words */
+
+      blake2_store32(outbuf, S->h[i]);
+      outlen -= sizeof(uint32_t);
+      outbuf += sizeof(uint32_t);
+    }
+
+  if (outwords < 8 && outlen > 0 && outlen < sizeof(uint32_t))
+    {
+      /* Store partial word */
+
+      blake2_store32(&tmp, S->h[i]);
+      blake2_memcpy(outbuf, &tmp, outlen);
+    }
+
+  return 0;
+}
+
+int blake2s(FAR void *out, size_t outlen, FAR const void *in, size_t inlen,
+            FAR const void *key, size_t keylen)
+{
+  blake2s_state S[1];
+
+  /* Verify parameters */
+
+  if (NULL == in && inlen > 0)
+    {
+      return -1;
+    }
+
+  if (NULL == out)
+    {
+      return -1;
+    }
+
+  if (NULL == key && keylen > 0)
+    {
+      return -1;
+    }
+
+  if (!outlen || outlen > BLAKE2S_OUTBYTES)
+    {
+      return -1;
+    }
+
+  if (keylen > BLAKE2S_KEYBYTES)
+    {
+      return -1;
+    }
+
+  if (keylen > 0)
+    {
+      if (blake2s_init_key(S, outlen, key, keylen) < 0)
+        {
+          return -1;
+        }
+    }
+  else
+    {
+      if (blake2s_init(S, outlen) < 0)
+        {
+          return -1;
+        }
+    }
+
+  blake2s_update(S, (const uint8_t *)in, inlen);
+  blake2s_final(S, out, outlen);
+  return 0;
+}
diff --git a/crypto/random_pool.c b/crypto/random_pool.c
new file mode 100644
index 0000000000..fed59bd727
--- /dev/null
+++ b/crypto/random_pool.c
@@ -0,0 +1,561 @@
+/****************************************************************************
+ * crypto/random_pool.c
+ *
+ *   Copyright (C) 2015-2017 Haltian Ltd. All rights reserved.
+ *   Authors: Juha Niskanen <juha.niskanen@haltian.com>
+ *            Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <debug.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/random.h>
+#include <nuttx/board.h>
+
+#include <nuttx/crypto/blake2s.h>
+
+/****************************************************************************
+ * Definitions
+ ****************************************************************************/
+
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define ROTL_32(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#define ROTR_32(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) )
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct blake2xs_rng_s
+{
+  uint32_t out_node_offset;
+  blake2s_param param;
+  blake2s_state ctx;
+  char out_root[BLAKE2S_OUTBYTES];
+};
+
+struct rng_s
+{
+  sem_t rd_sem; /* Threads can only exclusively access the RNG */
+  volatile uint32_t rd_addptr;
+  volatile uint32_t rd_newentr;
+  volatile uint8_t rd_rotate;
+  volatile uint8_t rd_prev_time;
+  volatile uint16_t rd_prev_irq;
+  bool output_initialized;
+  struct blake2xs_rng_s blake2xs;
+};
+
+enum
+{
+  POOL_SIZE = ENTROPY_POOL_SIZE,
+  POOL_MASK = (POOL_SIZE - 1),
+
+  MIN_SEED_NEW_ENTROPY_WORDS = 128,
+  MAX_SEED_NEW_ENTROPY_WORDS = 1024
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct rng_s g_rng;
+
+#ifdef CONFIG_BOARD_ENTROPY_POOL
+/* Entropy pool structure can be provided by board source. Use for this is,
+ * for example, allocate entropy pool from special area of RAM which content
+ * is kept over system reset. */
+
+#  define entropy_pool board_entropy_pool
+#else
+static struct entropy_pool_s entropy_pool;
+#endif
+
+/* Polynomial from paper "The Linux Pseudorandom Number Generator Revisited"
+ * x^POOL_SIZE + x^104 + x^76 + x^51 + x^25 + x + 1 */
+
+static const uint32_t pool_stir[] = { POOL_SIZE, 104, 76, 51, 25, 1 };
+
+/* Derived from IEEE 802.3 CRC-32 */
+
+static const uint32_t pool_twist[8] =
+{
+  0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+  0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: addentropy
+ *
+ * Description:
+ *
+ * This function adds a number of integers into the entropy pool.
+ * The pool is stirred with a polynomial of degree POOL_SIZE over GF(2).
+ *
+ * Code is inspired by add_entropy_words() function of OpenBSD kernel.
+ *
+ * Parameters:
+ *   buf     -   Buffer of integers to be added
+ *   n       -   Number of elements in buf
+ *   inc_new -   Count element as new entry
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void addentropy(FAR const uint32_t *buf, size_t n, bool inc_new)
+{
+  /* Compile time check for that POOL_SIZE is power of two. */
+
+  static char pool_size_p2_check[1 - ((POOL_SIZE & (POOL_SIZE - 1)) * 2)];
+
+  UNUSED(pool_size_p2_check);
+
+  while (n-- > 0)
+    {
+      uint32_t rotate;
+      uint32_t w;
+      uint32_t i;
+
+      rotate = g_rng.rd_rotate;
+      w = ROTL_32(*buf, rotate);
+      i = g_rng.rd_addptr = (g_rng.rd_addptr - 1) & POOL_MASK;
+
+      /* Normal round, we add 7 bits of rotation to the pool.
+       * At the beginning of the pool, we add extra 7 bits
+       * rotation, in order for successive passes spread the
+       * input bits across the pool evenly.
+       */
+
+      g_rng.rd_rotate = (rotate + (i ? 7 : 14)) & 31;
+
+      /* XOR pool contents corresponding to polynomial terms */
+
+      w ^= entropy_pool.pool[(i + pool_stir[1]) & POOL_MASK];
+      w ^= entropy_pool.pool[(i + pool_stir[2]) & POOL_MASK];
+      w ^= entropy_pool.pool[(i + pool_stir[3]) & POOL_MASK];
+      w ^= entropy_pool.pool[(i + pool_stir[4]) & POOL_MASK];
+      w ^= entropy_pool.pool[(i + pool_stir[5]) & POOL_MASK];
+      w ^= entropy_pool.pool[i]; /* 2^POOL_SIZE */
+
+      entropy_pool.pool[i] = (w >> 3) ^ pool_twist[w & 7];
+      buf++;
+
+      if (inc_new)
+        {
+          g_rng.rd_newentr += 1;
+        }
+   }
+}
+
+/****************************************************************************
+ * Function: getentropy
+ *
+ * Description:
+ *   Hash entropy pool to BLAKE2s context. This is an internal interface for
+ *   seeding out-facing BLAKE2Xs random bit generator from entropy pool.
+ *
+ *   Code is inspired by extract_entropy() function of OpenBSD kernel.
+ *
+ *   Note that this function cannot fail, other than by asserting.
+ *
+ *   Warning: In protected kernel builds, this interface MUST NOT be
+ *   exported to userspace. This interface MUST NOT be used as a
+ *   general-purpose random bit generator!
+ *
+ * Parameters:
+ *   S  - BLAKE2s instance that will absorb entropy pool
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void getentropy(FAR blake2s_state *S)
+{
+#ifdef CONFIG_SCHED_CPULOAD
+  struct cpuload_s load;
+#endif
+  uint32_t tmp;
+
+  add_sw_randomness(g_rng.rd_newentr);
+
+  /* Absorb the entropy pool */
+
+  blake2s_update(S, (FAR const uint32_t *)entropy_pool.pool,
+                 sizeof(entropy_pool.pool));
+
+  /* Add something back so repeated calls to this function
+   * return different values.
+   */
+
+  tmp = sizeof(entropy_pool.pool);
+  tmp <<= 27;
+#ifdef CONFIG_SCHED_CPULOAD
+  clock_cpuload(0, &load);
+  tmp += load.total ^ ROTL_32(load.active, 23);
+#endif
+  add_sw_randomness(tmp);
+
+  g_rng.rd_newentr = 0;
+}
+
+/* The BLAKE2Xs based random number generator algorithm.
+ *
+ * BLAKE2X is a extensible-output function (XOF) variant of BLAKE2 hash
+ * function. One application of XOFs is use as deterministic random bit
+ * number generator (DRBG) as used here. BLAKE2 specification is available
+ * at https://blake2.net/
+ *
+ * BLAKE2Xs here  implementation is based on public-domain/CC0 BLAKE2 reference
+ * implementation by Samual Neves, at
+ *  https://github.com/BLAKE2/BLAKE2/tree/master/ref
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ */
+
+static void rng_reseed(void)
+{
+  blake2s_param P = {};
+
+  /* Reset output node counter. */
+
+  g_rng.blake2xs.out_node_offset = 0;
+
+  /* Initialize parameter block */
+
+  P.digest_length = BLAKE2S_OUTBYTES;
+  P.key_length    = 0;
+  P.fanout        = 1;
+  P.depth         = 1;
+  blake2_store32(P.leaf_length, 0);
+  blake2_store32(P.node_offset, 0);
+  blake2_store16(P.xof_length, 0xffff);
+  P.node_depth    = 0;
+  P.inner_length  = 0;
+  g_rng.blake2xs.param = P;
+
+  blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param);
+
+  /* Initialize with randomness from entropy pool */
+
+  getentropy(&g_rng.blake2xs.ctx);
+
+  /* Absorb also the previous root */
+
+  blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
+                 sizeof(g_rng.blake2xs.out_root));
+
+  /* Finalize the new root hash */
+
+  blake2s_final(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
+                BLAKE2S_OUTBYTES);
+
+  explicit_bzero(&g_rng.blake2xs.ctx, sizeof(g_rng.blake2xs.ctx));
+
+  /* Setup parameters for output phase. */
+
+  g_rng.blake2xs.param.key_length = 0;
+  g_rng.blake2xs.param.fanout = 0;
+  blake2_store32(g_rng.blake2xs.param.leaf_length, BLAKE2S_OUTBYTES);
+  g_rng.blake2xs.param.inner_length = BLAKE2S_OUTBYTES;
+  g_rng.blake2xs.param.node_depth = 0;
+
+  g_rng.output_initialized = true;
+}
+
+static void rng_buf_internal(FAR void *bytes, size_t nbytes)
+{
+  if (!g_rng.output_initialized)
+    {
+      if (g_rng.rd_newentr < MIN_SEED_NEW_ENTROPY_WORDS)
+        {
+          cryptwarn("Entropy pool RNG initialized with very low entropy. "
+                    " Consider implementing CONFIG_BOARD_INITRNGSEED!\n");
+        }
+
+      rng_reseed();
+    }
+  else if (g_rng.rd_newentr >= MAX_SEED_NEW_ENTROPY_WORDS)
+    {
+      /* Initial entropy is low. Reseed when we have accumulated more. */
+
+      rng_reseed();
+    }
+  else if (g_rng.blake2xs.out_node_offset == UINT32_MAX)
+    {
+      /* Maximum BLAKE2Xs output reached (2^32-1 output blocks, maximum 128 GiB
+       * bytes), reseed. */
+
+      rng_reseed();
+    }
+
+  /* Output phase for BLAKE2Xs. */
+
+  for (; nbytes > 0; ++g_rng.blake2xs.out_node_offset)
+    {
+      size_t block_size = MIN(nbytes, BLAKE2S_OUTBYTES);
+
+      /* Initialize state */
+
+      g_rng.blake2xs.param.digest_length = block_size;
+      blake2_store32(g_rng.blake2xs.param.node_offset,
+                     g_rng.blake2xs.out_node_offset);
+      blake2s_init_param(&g_rng.blake2xs.ctx, &g_rng.blake2xs.param);
+
+      /* Process state and output random bytes */
+
+      blake2s_update(&g_rng.blake2xs.ctx, g_rng.blake2xs.out_root,
+                     sizeof(g_rng.blake2xs.out_root));
+      blake2s_final(&g_rng.blake2xs.ctx, bytes, block_size);
+
+      bytes += block_size;
+      nbytes -= block_size;
+    }
+}
+
+static void rng_init(void)
+{
+  crypinfo("Initializing RNG\n");
+
+  memset(&g_rng, 0, sizeof(struct rng_s));
+  sem_init(&g_rng.rd_sem, 0, 1);
+
+  /* We do not initialize output here because this is called
+   * quite early in boot and there may not be enough entropy.
+   *
+   * Board level may define CONFIG_BOARD_INITRNGSEED if it implements
+   * early random seeding.
+   */
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: up_rngaddint
+ *
+ * Description:
+ *   Add one integer to entropy pool, contributing a specific kind
+ *   of entropy to pool.
+ *
+ * Parameters:
+ *   kindof  - Enumeration constant telling where val came from
+ *   val     - Integer to be added
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void up_rngaddint(enum rnd_source_t kindof, int val)
+{
+  uint32_t buf[1];
+
+  buf[0] = val;
+
+  up_rngaddentropy(kindof, buf, 1);
+}
+
+/****************************************************************************
+ * Function: up_rngaddentropy
+ *
+ * Description:
+ *   Add buffer of integers to entropy pool.
+ *
+ * Parameters:
+ *   kindof  - Enumeration constant telling where val came from
+ *   buf     - Buffer of integers to be added
+ *   n       - Number of elements in buf
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void up_rngaddentropy(enum rnd_source_t kindof, FAR const uint32_t *buf,
+                      size_t n)
+{
+  uint32_t tbuf[1];
+  struct timespec ts;
+  bool new_inc = true;
+
+  if (kindof == RND_SRC_IRQ && n > 0)
+    {
+      /* Ignore interrupt randomness if previous interrupt was from same
+       * source. */
+
+      if (buf[0] == g_rng.rd_prev_irq)
+        {
+          return;
+        }
+
+      g_rng.rd_prev_irq = buf[0];
+    }
+
+  /* We don't actually track what kind of entropy we receive,
+   * just add it all to pool. One exception is interrupt
+   * and timer randomness, where we limit rate of new pool entry
+   * counting to prevent high interrupt rate triggering RNG
+   * reseeding too fast.
+   */
+
+  (void)clock_gettime(CLOCK_REALTIME, &ts);
+  tbuf[0] = ROTL_32(ts.tv_nsec, 17) ^ ROTL_32(ts.tv_sec, 3);
+  tbuf[0] += ROTL_32(kindof, 27);
+  tbuf[0] += ROTL_32((uintptr_t)&tbuf[0], 11);
+
+  if (kindof == RND_SRC_TIME || kindof == RND_SRC_IRQ)
+    {
+      uint8_t curr_time = ts.tv_sec * 8 + ts.tv_nsec / (NSEC_PER_SEC / 8);
+
+      /* Allow interrupts/timers increase entropy counter at max rate
+       * of 8 Hz. */
+
+      if (g_rng.rd_prev_time == curr_time)
+        {
+          new_inc = false;
+        }
+      else
+        {
+          g_rng.rd_prev_time = curr_time;
+        }
+    }
+
+  if (n > 0)
+    {
+      tbuf[0] ^= buf[0];
+      buf++;
+      n--;
+    }
+
+  addentropy(tbuf, 1, new_inc);
+
+  if (n > 0)
+    {
+      addentropy(buf, n, new_inc);
+    }
+}
+
+/****************************************************************************
+ * Function: up_rngreseed
+ *
+ * Description:
+ *   Force reseeding random number generator from entropy pool
+ *
+ ****************************************************************************/
+
+void up_rngreseed(void)
+{
+  while (sem_wait(&g_rng.rd_sem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  if (g_rng.rd_newentr >= MIN_SEED_NEW_ENTROPY_WORDS)
+    {
+      rng_reseed();
+    }
+
+  sem_post(&g_rng.rd_sem);
+}
+
+/****************************************************************************
+ * Function: up_randompool_initialize
+ *
+ * Description:
+ *   Initialize entropy pool and random number generator
+ *
+ ****************************************************************************/
+
+void up_randompool_initialize(void)
+{
+  rng_init();
+
+#ifdef CONFIG_BOARD_INITRNGSEED
+  board_init_rngseed();
+#endif
+}
+
+/****************************************************************************
+ * Function: getrandom
+ *
+ * Description:
+ *   Fill a buffer of arbitrary length with randomness. This is the
+ *   preferred interface for getting random numbers. The traditional
+ *   /dev/random approach is susceptible for things like the attacker
+ *   exhausting file descriptors on purpose.
+ *
+ *   Note that this function cannot fail, other than by asserting.
+ *
+ * Parameters:
+ *   bytes  - Buffer for returned random bytes
+ *   nbytes - Number of bytes requested.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void getrandom(FAR void *bytes, size_t nbytes)
+{
+  while (sem_wait(&g_rng.rd_sem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  rng_buf_internal(bytes, nbytes);
+  sem_post(&g_rng.rd_sem);
+}
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 00adcc8f17..511d63c5f6 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -69,6 +69,15 @@ config DEV_URANDOM_CONGRUENTIAL
 
 		NOTE: Not cyptographically secure
 
+config DEV_URANDOM_RANDOM_POOL
+	bool "Entropy pool"
+	depends on CRYPTO_RANDOM_POOL
+	---help---
+		Use the entropy pool CPRNG output for urandom algorithm.
+
+		NOTE: May or may not be cyptographically secure, depending upon the
+		quality entropy available to entropy pool.
+
 config DEV_URANDOM_ARCH
 	bool "Architecture-specific"
 	depends on ARCH_HAVE_RNG
diff --git a/drivers/analog/adc.c b/drivers/analog/adc.c
index d81971f101..be1682e3cd 100644
--- a/drivers/analog/adc.c
+++ b/drivers/analog/adc.c
@@ -60,6 +60,7 @@
 #include <nuttx/arch.h>
 #include <nuttx/semaphore.h>
 #include <nuttx/analog/adc.h>
+#include <nuttx/random.h>
 
 #include <nuttx/irq.h>
 
@@ -296,6 +297,10 @@ static ssize_t adc_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
               break;
             }
 
+          /* Feed ADC data to entropy pool */
+
+          add_sensor_randomness(msg->am_data);
+
           /* Copy the message to the user buffer */
 
           if (msglen == 1)
diff --git a/drivers/dev_urandom.c b/drivers/dev_urandom.c
index e7022cb9f5..5b59736907 100644
--- a/drivers/dev_urandom.c
+++ b/drivers/dev_urandom.c
@@ -49,11 +49,13 @@
 #include <string.h>
 #include <poll.h>
 #include <errno.h>
+#include <assert.h>
 
 #include <nuttx/lib/lib.h>
 #include <nuttx/lib/xorshift128.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/drivers/drivers.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_DEV_URANDOM) && !defined(CONFIG_DEV_URANDOM_ARCH)
 
@@ -62,13 +64,18 @@
  ****************************************************************************/
 
 #if !defined(CONFIG_DEV_URANDOM_CONGRUENTIAL) && \
-    !defined(CONFIG_DEV_URANDOM_XORSHIFT128)
-#  define CONFIG_DEV_URANDOM_XORSHIFT128 1
+    !defined(CONFIG_DEV_URANDOM_XORSHIFT128) && \
+    !defined(CONFIG_DEV_URANDOM_RANDOM_POOL)
+#  ifdef CONFIG_CRYPTO_RANDOM_POOL
+#    define CONFIG_DEV_URANDOM_RANDOM_POOL 1
+#  else
+#    define CONFIG_DEV_URANDOM_XORSHIFT128 1
+#  endif
 #endif
 
 #ifdef CONFIG_DEV_URANDOM_XORSHIFT128
 #  define PRNG() do_xorshift128()
-#else /* CONFIG_DEV_URANDOM_CONGRUENTIAL */
+#elif defined(CONFIG_DEV_URANDOM_CONGRUENTIAL)
 #  define PRNG() do_congruential()
 #endif
 
@@ -158,6 +165,12 @@ static inline uint32_t do_congruential(void)
 static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer,
                              size_t len)
 {
+#ifdef CONFIG_DEV_URANDOM_RANDOM_POOL
+  if (len)
+    {
+      getrandom(buffer, len);
+    }
+#else
   size_t n;
   uint32_t rnd;
 
@@ -208,6 +221,7 @@ static ssize_t devurand_read(FAR struct file *filep, FAR char *buffer,
         }
       while (--n > 0);
     }
+#endif /* CONFIG_DEV_URANDOM_RANDOM_POOL */
 
   return len;
 }
@@ -228,6 +242,56 @@ static ssize_t devurand_write(FAR struct file *filep, FAR const char *buffer,
   memcpy(&seed, buffer, len);
   srand(seed);
   return len;
+#elif defined(CONFIG_DEV_URANDOM_RANDOM_POOL)
+  const unsigned int alignmask = sizeof(uint32_t) - 1;
+  const size_t initlen = len;
+  uint32_t tmp = 0;
+  size_t currlen;
+
+  if (!len)
+    {
+      return 0;
+    }
+
+  /* Seed entropy pool with data from user. */
+
+  if ((uintptr_t)buffer & alignmask)
+    {
+      /* Make unaligned input aligned. */
+
+      currlen = min(sizeof(uint32_t) - ((uintptr_t)buffer & alignmask), len);
+      memcpy(&tmp, buffer, currlen);
+      up_rngaddint(RND_SRC_SW, tmp);
+
+      len -= currlen;
+      buffer += currlen;
+    }
+
+  if (len >= sizeof(uint32_t))
+    {
+      /* Handle bulk aligned, word-sized data. */
+
+      DEBUGASSERT(((uintptr_t)buffer & alignmask) == 0);
+      currlen = len / sizeof(uint32_t);
+      up_rngaddentropy(RND_SRC_SW, (FAR uint32_t *)buffer, currlen);
+      buffer += currlen * sizeof(uint32_t);
+      len %= sizeof(uint32_t);
+    }
+
+  if (len > 0)
+    {
+      /* Handle trailing bytes. */
+
+      DEBUGASSERT(len < sizeof(uint32_t));
+      memcpy(&tmp, buffer, len);
+      up_rngaddint(RND_SRC_SW, tmp);
+    }
+
+  /* Reseeding of random number generator from entropy pool. */
+
+  up_rngreseed();
+
+  return initlen;
 #else
   len = min(len, sizeof(g_prng.u));
   memcpy(&g_prng.u, buffer, len);
@@ -274,6 +338,8 @@ void devurandom_register(void)
 
 #ifdef CONFIG_DEV_URANDOM_CONGRUENTIAL
   srand(10197);
+#elif defined(CONFIG_DEV_URANDOM_RANDOM_POOL)
+  up_randompool_initialize();
 #else
   g_prng.state.w = 97;
   g_prng.state.x = 101;
diff --git a/drivers/input/ads7843e.c b/drivers/input/ads7843e.c
index d9c2c3b988..6e4e9395ec 100644
--- a/drivers/input/ads7843e.c
+++ b/drivers/input/ads7843e.c
@@ -70,6 +70,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/spi/spi.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/semaphore.h>
 #include <nuttx/input/touchscreen.h>
@@ -624,6 +625,8 @@ static void ads7843e_worker(FAR void *arg)
       y = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION);
 #endif
 
+      add_ui_randomness((x << 16) | y);
+
       /* Perform a thresholding operation so that the results will be more stable.
        * If the difference from the last sample is small, then ignore the event.
        * REVISIT:  Should a large change in pressure also generate a event?
diff --git a/drivers/input/ajoystick.c b/drivers/input/ajoystick.c
index aaba021b95..6665b8fdd2 100644
--- a/drivers/input/ajoystick.c
+++ b/drivers/input/ajoystick.c
@@ -60,6 +60,7 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/input/ajoystick.h>
+#include <nuttx/random.h>
 
 #include <nuttx/irq.h>
 
@@ -321,6 +322,8 @@ static void ajoy_sample(FAR struct ajoy_upperhalf_s *priv)
   DEBUGASSERT(lower->al_buttons);
   sample = lower->al_buttons(lower);
 
+  add_ui_randomness(sample);
+
 #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS)
   /* Determine which buttons have been newly pressed and which have been
    * newly released.
diff --git a/drivers/input/button_upper.c b/drivers/input/button_upper.c
index 2c03d3de3e..b4432cbad3 100644
--- a/drivers/input/button_upper.c
+++ b/drivers/input/button_upper.c
@@ -56,6 +56,7 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/input/buttons.h>
+#include <nuttx/random.h>
 
 #include <nuttx/irq.h>
 
@@ -317,6 +318,8 @@ static void btn_sample(FAR struct btn_upperhalf_s *priv)
   DEBUGASSERT(lower->bl_buttons);
   sample = lower->bl_buttons(lower);
 
+  add_ui_randomness(sample);
+
 #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS)
   /* Determine which buttons have been newly pressed and which have been
    * newly released.
diff --git a/drivers/input/djoystick.c b/drivers/input/djoystick.c
index 1cc1b54004..bd3c9e4703 100644
--- a/drivers/input/djoystick.c
+++ b/drivers/input/djoystick.c
@@ -60,6 +60,7 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/input/djoystick.h>
+#include <nuttx/random.h>
 
 #include <nuttx/irq.h>
 
@@ -321,6 +322,8 @@ static void djoy_sample(FAR struct djoy_upperhalf_s *priv)
   DEBUGASSERT(lower->dl_sample);
   sample = lower->dl_sample(lower);
 
+  add_ui_randomness(sample);
+
 #if !defined(CONFIG_DISABLE_POLL) || !defined(CONFIG_DISABLE_SIGNALS)
   /* Determine which buttons have been newly pressed and which have been
    * newly released.
diff --git a/drivers/input/max11802.c b/drivers/input/max11802.c
index 82ad1f6689..7fb2087f06 100644
--- a/drivers/input/max11802.c
+++ b/drivers/input/max11802.c
@@ -64,6 +64,7 @@
 #include <nuttx/wqueue.h>
 #include <nuttx/fs/fs.h>
 #include <nuttx/spi/spi.h>
+#include <nuttx/random.h>
 
 #include <nuttx/semaphore.h>
 #include <nuttx/input/touchscreen.h>
@@ -628,6 +629,8 @@ static void max11802_worker(FAR void *arg)
         }
       while (readycount < 2);
 
+      add_ui_randomness((x << 16) | y);
+
       /* Continue to sample the position while the pen is down */
 
       wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1,
diff --git a/drivers/input/mxt.c b/drivers/input/mxt.c
index e115285171..01d11bc63b 100644
--- a/drivers/input/mxt.c
+++ b/drivers/input/mxt.c
@@ -64,6 +64,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/semaphore.h>
 #include <nuttx/input/touchscreen.h>
@@ -889,6 +890,8 @@ static void mxt_touch_event(FAR struct mxt_dev_s *priv,
       sample->pressure = pressure;
       sample->valid    = true;
 
+      add_ui_randomness((x << 16) ^ y ^ (area << 9) ^ (pressure << 1));
+
       /* If this is not the first touch report, then report it as a move:
        * Same contact, same ID, but with a new, updated position.
        * The CONTACT_REPORT state means that a contacted has been detected,
diff --git a/drivers/input/stmpe811_temp.c b/drivers/input/stmpe811_temp.c
index 0cb5c686c7..5bbad0d455 100644
--- a/drivers/input/stmpe811_temp.c
+++ b/drivers/input/stmpe811_temp.c
@@ -48,6 +48,7 @@
 #include <debug.h>
 
 #include <nuttx/input/stmpe811.h>
+#include <nuttx/random.h>
 
 #include "stmpe811.h"
 
@@ -139,6 +140,8 @@ uint16_t stmpe811_tempread(STMPE811_HANDLE handle)
   temp1 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2);
   temp2 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2+1);
 
+  add_sensor_randomness((temp1 << 8) | temp2);
+
   /* Scale the temperature (where Vio is assumed to be .33) */
 
   temp = ((uint32_t)(temp1 & 3) << 8) | temp2;
diff --git a/drivers/input/stmpe811_tsc.c b/drivers/input/stmpe811_tsc.c
index b58e9feebd..c49723c731 100644
--- a/drivers/input/stmpe811_tsc.c
+++ b/drivers/input/stmpe811_tsc.c
@@ -62,6 +62,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/arch.h>
 #include <nuttx/input/touchscreen.h>
@@ -534,6 +535,8 @@ static ssize_t stmpe811_read(FAR struct file *filep, FAR char *buffer, size_t le
   report->point[0].y         = sample.y;
   report->point[0].pressure  = sample.z;
 
+  add_ui_randomness((sample.x << 16) ^ (sample.y << 8) ^ sample.z);
+
   /* Report the appropriate flags */
 
   if (sample.contact == CONTACT_UP)
diff --git a/drivers/input/tsc2007.c b/drivers/input/tsc2007.c
index 8d49a2e070..fb82cc0557 100644
--- a/drivers/input/tsc2007.c
+++ b/drivers/input/tsc2007.c
@@ -68,6 +68,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/input/touchscreen.h>
 #include <nuttx/input/tsc2007.h>
@@ -619,7 +620,7 @@ static void tsc2007_worker(FAR void *arg)
        *  vertical or horizontal resistive network.  The A/D converter converts
        *  the voltage measured at the point where the panel is touched. A measurement
        *  of the Y position of the pointing device is made by connecting the X+
-       *  input to a data converter chip, turning on the Y+ and Y� drivers, and
+       *  input to a data converter chip, turning on the Y+ and Y- drivers, and
        *  digitizing the voltage seen at the X+ input ..."
        *
        * "... it is recommended that whenever the host writes to the TSC2007, the
@@ -698,6 +699,8 @@ static void tsc2007_worker(FAR void *arg)
       priv->sample.y        = y;
       priv->sample.pressure = pressure;
       priv->sample.valid    = true;
+
+      add_ui_randomness((x << 16) ^ y ^ (pressure << 9));
     }
 
   /* Note the availability of new measurements */
diff --git a/drivers/sensors/adxl345_base.c b/drivers/sensors/adxl345_base.c
index 8a92d059eb..93ebf9cf45 100644
--- a/drivers/sensors/adxl345_base.c
+++ b/drivers/sensors/adxl345_base.c
@@ -48,6 +48,7 @@
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/sensors/adxl345.h>
+#include <nuttx/random.h>
 
 #include "adxl345.h"
 
@@ -165,6 +166,9 @@ static ssize_t adxl345_read(FAR struct file *filep, FAR char *buffer, size_t len
   sample.data_z =  adxl345_getreg8(priv, ADXL345_DATAZ1);
   sample.data_z = (sample.data_z << 8) | adxl345_getreg8(priv, ADXL345_DATAZ0);
 
+  add_sensor_randomness(sample.data_x);
+  add_sensor_randomness((sample.data_z << 16) | sample.data_y);
+
   /* Return read sample */
 
   buffer = (FAR char *) &sample;
diff --git a/drivers/sensors/bh1750fvi.c b/drivers/sensors/bh1750fvi.c
index 88ba994a38..c0c2d38de0 100644
--- a/drivers/sensors/bh1750fvi.c
+++ b/drivers/sensors/bh1750fvi.c
@@ -51,6 +51,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/bh1750fvi.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_BH1750FVI)
 
@@ -250,6 +251,8 @@ static ssize_t bh1750fvi_read(FAR struct file *filep, FAR char *buffer,
   buffer[0] = lux & 0xFF;
   buffer[1] = (lux & 0xFF00) >> 8;
 
+  add_sensor_randomness(lux);
+
   return buflen;
 }
 
diff --git a/drivers/sensors/bmg160.c b/drivers/sensors/bmg160.c
index 03ad72a5d0..534985d133 100644
--- a/drivers/sensors/bmg160.c
+++ b/drivers/sensors/bmg160.c
@@ -51,6 +51,7 @@
 
 #include <nuttx/fs/fs.h>
 #include <nuttx/sensors/bmg160.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_SPI) && defined(CONFIG_BMG160)
 
@@ -243,6 +244,10 @@ static void bmg160_read_measurement_data(FAR struct bmg160_dev_s *dev)
   /* Give back the semaphore */
 
   sem_post(&dev->datasem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((x_gyr << 16) ^ (y_gyr << 8) ^ z_gyr);
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/bmp180.c b/drivers/sensors/bmp180.c
index 1a7d538c33..a0857d8e57 100644
--- a/drivers/sensors/bmp180.c
+++ b/drivers/sensors/bmp180.c
@@ -53,6 +53,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/bmp180.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_BMP180)
 
@@ -464,6 +465,10 @@ static int bmp180_getpressure(FAR struct bmp180_dev_s *priv)
 
   bmp180_read_press_temp(priv);
 
+  /* Feed raw sensor data to entropy pool */
+
+  add_sensor_randomness((priv->bmp180_utemp << 16) ^ priv->bmp180_upress);
+
   /* Calculate true temperature */
 
   x1 = ((priv->bmp180_utemp - priv->bmp180_cal_ac6) * priv->bmp180_cal_ac5) >> 15;
diff --git a/drivers/sensors/kxtj9.c b/drivers/sensors/kxtj9.c
index 70ec5ec808..875a4486b4 100644
--- a/drivers/sensors/kxtj9.c
+++ b/drivers/sensors/kxtj9.c
@@ -51,6 +51,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/kxtj9.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_SENSOR_KXTJ9)
 
@@ -459,6 +460,12 @@ static int kxtj9_read_sensor_data(FAR struct kxtj9_dev_s *priv,
 
   kxtj9_reg_read(priv, INT_REL, &data, 1);
   sem_post(&priv->exclsem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((acc_data[0] << 16) ^ (acc_data[1] << 8) ^
+                        acc_data[2]);
+
   return OK;
 }
 
diff --git a/drivers/sensors/l3gd20.c b/drivers/sensors/l3gd20.c
index d400f21308..10bcbeb77a 100644
--- a/drivers/sensors/l3gd20.c
+++ b/drivers/sensors/l3gd20.c
@@ -49,6 +49,7 @@
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/fs/fs.h>
 
@@ -257,6 +258,10 @@ static void l3gd20_read_measurement_data(FAR struct l3gd20_dev_s *dev)
   /* Give back the semaphore */
 
   sem_post(&dev->datasem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((x_gyr << 16) ^ (y_gyr << 8) ^ (z_gyr << 0));
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/lis331dl.c b/drivers/sensors/lis331dl.c
index f94a3b2ec2..deef62d705 100644
--- a/drivers/sensors/lis331dl.c
+++ b/drivers/sensors/lis331dl.c
@@ -48,6 +48,7 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/lis331dl.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_LIS331DL)
 
@@ -414,6 +415,11 @@ lis331dl_getreadings(FAR struct lis331dl_dev_s * dev)
           return NULL;
         }
 
+      /* Feed sensor data to entropy pool */
+
+      add_sensor_randomness((retval[2] << 16) ^ (retval[4] << 8) ^
+                            (retval[6] << 0));
+
       dev->a.x = retval[2];
       dev->a.y = retval[4];
       dev->a.z = retval[6];
diff --git a/drivers/sensors/lis3dsh.c b/drivers/sensors/lis3dsh.c
index 243f89874d..80db21c3f4 100644
--- a/drivers/sensors/lis3dsh.c
+++ b/drivers/sensors/lis3dsh.c
@@ -48,6 +48,7 @@
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/fs/fs.h>
 #include <nuttx/sensors/lis3dsh.h>
@@ -245,6 +246,10 @@ static void lis3dsh_read_measurement_data(FAR struct lis3dsh_dev_s *dev)
   /* Give back the semaphore */
 
   sem_post(&dev->datasem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((x_acc << 16) ^ (y_acc << 8) ^ (z_acc << 0));
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/lis3mdl.c b/drivers/sensors/lis3mdl.c
index cdb04e776e..64f33bae7a 100644
--- a/drivers/sensors/lis3mdl.c
+++ b/drivers/sensors/lis3mdl.c
@@ -47,6 +47,7 @@
 
 #include <nuttx/kmalloc.h>
 #include <nuttx/wqueue.h>
+#include <nuttx/random.h>
 
 #include <nuttx/fs/fs.h>
 #include <nuttx/sensors/lis3mdl.h>
@@ -251,6 +252,11 @@ static void lis3mdl_read_measurement_data(FAR struct lis3mdl_dev_s *dev)
   /* Give back the semaphore */
 
   sem_post(&dev->datasem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((x_mag << 16) ^ (y_mag << 10) ^ (z_mag << 2) ^
+                        temperature);
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/lm75.c b/drivers/sensors/lm75.c
index ce9445558b..6fa670e4e6 100644
--- a/drivers/sensors/lm75.c
+++ b/drivers/sensors/lm75.c
@@ -49,6 +49,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/lm75.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_I2C_LM75)
 
@@ -269,6 +270,8 @@ static int lm75_readtemp(FAR struct lm75_dev_s *priv, FAR b16_t *temp)
       return ret;
     }
 
+  add_sensor_randomness(temp16);
+
   sninfo("Centigrade: %08x\n", temp16);
 
   /* Was fahrenheit requested? */
diff --git a/drivers/sensors/lm92.c b/drivers/sensors/lm92.c
index c801e6633c..63ea40db38 100644
--- a/drivers/sensors/lm92.c
+++ b/drivers/sensors/lm92.c
@@ -51,6 +51,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/lm92.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_LM92)
 
@@ -272,6 +273,8 @@ static int lm92_readtemp(FAR struct lm92_dev_s *priv, FAR b16_t *temp)
       return ret;
     }
 
+  add_sensor_randomness(temp16);
+
   sninfo("Centigrade: %08x\n", temp16);
 
   /* Was Fahrenheit requested? */
diff --git a/drivers/sensors/lsm9ds1.c b/drivers/sensors/lsm9ds1.c
index ae69bd68c7..d54cdce379 100644
--- a/drivers/sensors/lsm9ds1.c
+++ b/drivers/sensors/lsm9ds1.c
@@ -50,6 +50,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/lsm9ds1.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_SN_LSM9DS1)
 
@@ -1244,6 +1245,7 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer,
   uint8_t                   regaddr;
   uint8_t                   lo;
   uint8_t                   hi;
+  uint32_t                  merge = 0;
 
   /* Sanity check */
 
@@ -1301,6 +1303,10 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer,
 
           data = ((uint16_t)hi << 8) | (uint16_t)lo;
 
+          /* Collect entropy */
+
+          merge += data ^ (merge >> 16);
+
           /* The value is positive */
 
           if (data < 0x8000)
@@ -1329,6 +1335,10 @@ static ssize_t lsm9ds1_read(FAR struct file *filep, FAR char *buffer,
         }
     }
 
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness(merge);
+
   return nsamples * samplesize;
 }
 
diff --git a/drivers/sensors/max31855.c b/drivers/sensors/max31855.c
index 19800a1c59..97b56f42ec 100644
--- a/drivers/sensors/max31855.c
+++ b/drivers/sensors/max31855.c
@@ -54,6 +54,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/spi/spi.h>
 #include <nuttx/sensors/max31855.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_SPI) && defined(CONFIG_MAX31855)
 
@@ -220,6 +221,10 @@ static ssize_t max31855_read(FAR struct file *filep, FAR char *buffer, size_t bu
 
   sninfo("Read from MAX31855 = 0x%08X\n", regval);
 
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness(regval);
+
   /* If negative, fix signal bits */
 
   if (regval & 0x80000000)
diff --git a/drivers/sensors/max6675.c b/drivers/sensors/max6675.c
index 0d205a049b..71a0e2d142 100644
--- a/drivers/sensors/max6675.c
+++ b/drivers/sensors/max6675.c
@@ -54,6 +54,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/spi/spi.h>
 #include <nuttx/sensors/max6675.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_SPI) && defined(CONFIG_MAX6675)
 
@@ -230,6 +231,10 @@ static ssize_t max6675_read(FAR struct file *filep, FAR char *buffer, size_t buf
       ret = -EINVAL;
     }
 
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness(regval);
+
   /* Get the temperature */
 
   *temp = (regval & MAX6675_TEMP_COUPLE) >> 3;
diff --git a/drivers/sensors/mb7040.c b/drivers/sensors/mb7040.c
index 2bdaecee0e..125825cab0 100644
--- a/drivers/sensors/mb7040.c
+++ b/drivers/sensors/mb7040.c
@@ -51,6 +51,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/mb7040.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_MB7040)
 
@@ -323,6 +324,10 @@ static int mb7040_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
           if (ret == OK)
             {
               *ptr = (int32_t)range;
+
+              /* Feed sensor data to entropy pool */
+
+              add_sensor_randomness(range);
             }
 
           sninfo("range: %04x ret: %d\n", *ptr, ret);
diff --git a/drivers/sensors/mcp9844.c b/drivers/sensors/mcp9844.c
index 77dcee773e..f895d86152 100644
--- a/drivers/sensors/mcp9844.c
+++ b/drivers/sensors/mcp9844.c
@@ -50,6 +50,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/mcp9844.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_MCP9844)
 
@@ -274,6 +275,10 @@ static int mcp9844_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
 
           if (ret == OK)
             {
+              /* Feed sensor data to entropy pool */
+
+              add_sensor_randomness(raw_temperature);
+
               /* BIT15 - 13 contain information if preset temperature values
                * have been exceeded or undercut. BIT12 is now not any longer
                * needed since we do have the sign information retrieved.
diff --git a/drivers/sensors/mlx90393.c b/drivers/sensors/mlx90393.c
index 93a53ef871..d5b27b801e 100644
--- a/drivers/sensors/mlx90393.c
+++ b/drivers/sensors/mlx90393.c
@@ -50,6 +50,7 @@
 
 #include <nuttx/fs/fs.h>
 #include <nuttx/sensors/mlx90393.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_SPI) && defined(CONFIG_MLX90393)
 
@@ -232,6 +233,11 @@ static void mlx90393_read_measurement_data(FAR struct mlx90393_dev_s *dev)
   /* Give back the semaphore */
 
   sem_post(&dev->datasem);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((x_mag << 17) ^ (y_mag << 9) ^ (z_mag << 1) ^
+                        temperature);
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/mpl115a.c b/drivers/sensors/mpl115a.c
index 38763f5c71..c23df63eaf 100644
--- a/drivers/sensors/mpl115a.c
+++ b/drivers/sensors/mpl115a.c
@@ -50,6 +50,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/spi/spi.h>
 #include <nuttx/sensors/mpl115a.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_SPI) && defined(CONFIG_MPL115A)
 
@@ -227,6 +228,11 @@ static void mpl115a_read_press_temp(FAR struct mpl115a_dev_s *priv)
   priv->mpl115a_temperature >>= 6; /* Tadc is 10bit unsigned */
 
   sninfo("Temperature = %d\n", priv->mpl115a_temperature);
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((priv->mpl115a_pressure << 16) ^
+                        priv->mpl115a_temperature);
 }
 
 /****************************************************************************
diff --git a/drivers/sensors/ms58xx.c b/drivers/sensors/ms58xx.c
index 47f04e57ca..3efdda2713 100644
--- a/drivers/sensors/ms58xx.c
+++ b/drivers/sensors/ms58xx.c
@@ -53,6 +53,7 @@
 #include <nuttx/arch.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/ms58xx.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_MS58XX)
 
@@ -725,6 +726,8 @@ static int ms58xx_measure(FAR struct ms58xx_dev_s *priv)
       return ret;
     }
 
+  add_sensor_randomness(rawpress ^ rawtemp);
+
   diff = (int32_t)rawtemp - (int32_t)priv->c5 * ((int32_t)1 << 8);
   temp = (int32_t)((int64_t)2000 +
                    (int64_t)diff * (int64_t)priv->c6 / ((int64_t)1 << 23));
diff --git a/drivers/sensors/veml6070.c b/drivers/sensors/veml6070.c
index 28030ba7ce..443782458a 100644
--- a/drivers/sensors/veml6070.c
+++ b/drivers/sensors/veml6070.c
@@ -48,6 +48,7 @@
 #include <nuttx/fs/fs.h>
 #include <nuttx/i2c/i2c_master.h>
 #include <nuttx/sensors/veml6070.h>
+#include <nuttx/random.h>
 
 #if defined(CONFIG_I2C) && defined(CONFIG_VEML6070)
 
@@ -272,6 +273,10 @@ static ssize_t veml6070_read(FAR struct file *filep, FAR char *buffer,
 
   buffer[0] = regdata;
 
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((buffer[1] << 16) ^ buffer[0]);
+
   return buflen;
 }
 
diff --git a/drivers/sensors/xen1210.c b/drivers/sensors/xen1210.c
index 0f7bfd2b1e..a14350921c 100644
--- a/drivers/sensors/xen1210.c
+++ b/drivers/sensors/xen1210.c
@@ -49,6 +49,7 @@
 #include <nuttx/kmalloc.h>
 #include <nuttx/spi/spi.h>
 #include <nuttx/sensors/xen1210.h>
+#include <nuttx/random.h>
 
 #include "xen1210.h"
 
@@ -442,6 +443,12 @@ void xen1210_getdata(FAR struct xen1210_dev_s *priv)
 #ifdef CONFIG_XEN1210_REGDEBUG
   _err("%02x->%02x\n", regaddr, regval);
 #endif
+
+  /* Feed sensor data to entropy pool */
+
+  add_sensor_randomness((priv->sample.data_x << 8) ^
+                        (priv->sample.data_y << 4) ^
+                        (priv->sample.data_z << 4));
 }
 
 /****************************************************************************
diff --git a/include/nuttx/board.h b/include/nuttx/board.h
index cd08aceddd..0525499021 100644
--- a/include/nuttx/board.h
+++ b/include/nuttx/board.h
@@ -646,4 +646,20 @@ void board_crashdump(uintptr_t currentsp, FAR void *tcb,
                      int lineno);
 #endif
 
+/****************************************************************************
+ * Name: board_initrngseed
+ *
+ * Description:
+ *   If CONFIG_BOARD_INITRNGSEED is selected then board_init_rngseed is
+ *   called at up_randompool_initialize() to feed initial random seed
+ *   to RNG. Implemenation of this functions should feed at least
+ *   MIN_SEED_NEW_ENTROPY_WORDS 32-bit random words to entropy-pool using
+ *   up_rngaddentropy() or up_rngaddint().
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_BOARD_INITRNGSEED
+void board_init_rngseed(void);
+#endif
+
 #endif /* __INCLUDE_NUTTX_BOARD_H */
diff --git a/include/nuttx/crypto/blake2s.h b/include/nuttx/crypto/blake2s.h
new file mode 100644
index 0000000000..fa6667fb6f
--- /dev/null
+++ b/include/nuttx/crypto/blake2s.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+ * include/nuttx/crypto/blake2s.h
+ *
+ * This code is based on public-domain/CC0 BLAKE2 reference implementation
+ * by Samual Neves, at https://github.com/BLAKE2/BLAKE2/tree/master/ref
+ * Copyright 2012, Samuel Neves <sneves@dei.uc.pt>
+ *
+ * Copyright (C) 2017 Haltian Ltd. All rights reserved.
+ * Authors: Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H
+#define __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+enum blake2s_constant
+{
+  BLAKE2S_BLOCKBYTES = 64,
+  BLAKE2S_OUTBYTES = 32,
+  BLAKE2S_KEYBYTES = 32,
+  BLAKE2S_SALTBYTES = 8,
+  BLAKE2S_PERSONALBYTES = 8
+};
+
+typedef struct blake2s_state__
+{
+  uint32_t h[8];
+  uint32_t t[2];
+  uint32_t f[2];
+  size_t buflen;
+  size_t outlen;
+  uint8_t buf[BLAKE2S_BLOCKBYTES];
+} blake2s_state;
+
+typedef struct blake2s_param__
+{
+  uint8_t digest_length;                        /* 1 */
+  uint8_t key_length;                           /* 2 */
+  uint8_t fanout;                               /* 3 */
+  uint8_t depth;                                /* 4 */
+  uint8_t leaf_length[4];                       /* 8 */
+  uint8_t node_offset[4];                       /* 12 */
+  uint8_t xof_length[2];                        /* 14 */
+  uint8_t node_depth;                           /* 15 */
+  uint8_t inner_length;                         /* 16 */
+  /* uint8_t  reserved[0]; */
+  uint8_t salt[BLAKE2S_SALTBYTES];              /* 24 */
+  uint8_t personal[BLAKE2S_PERSONALBYTES];      /* 32 */
+} blake2s_param;
+
+#ifdef __GNUC__ > 3
+#define BLAKE2_UNALIGNED 1
+typedef uint32_t uint32_alias_t __attribute__((may_alias, aligned(1)));
+typedef uint16_t uint16_alias_t __attribute__((may_alias, aligned(1)));
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/* Streaming API */
+
+int blake2s_init(FAR blake2s_state *S, size_t outlen);
+int blake2s_init_key(FAR blake2s_state *S, size_t outlen, FAR const void *key,
+                     size_t keylen);
+int blake2s_init_param(FAR blake2s_state *S, FAR const blake2s_param *P);
+int blake2s_update(FAR blake2s_state *S, FAR const void *in, size_t inlen);
+int blake2s_final(FAR blake2s_state *S, FAR void *out, size_t outlen);
+
+/* Simple API */
+
+int blake2s(FAR void *out, size_t outlen, FAR const void *in, size_t inlen,
+            FAR const void *key, size_t keylen);
+
+/****************************************************************************
+ * Public Inline Functions
+ ****************************************************************************/
+
+static inline uint32_t blake2_load32(FAR const void *src)
+{
+#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG)
+  return *(FAR uint32_alias_t *)src;
+#elif !defined(CONFIG_ENDIAN_BIG)
+  FAR const uint8_t *p = (FAR const uint8_t *)src;
+  return ((uint32_t)(p[0]) << 24) |
+         ((uint32_t)(p[1]) << 16) |
+         ((uint32_t)(p[2]) << 8) |
+         ((uint32_t)(p[3]) << 0);
+#else
+  FAR const uint8_t *p = (FAR const uint8_t *)src;
+  return ((uint32_t)(p[0]) << 0) |
+         ((uint32_t)(p[1]) << 8) |
+         ((uint32_t)(p[2]) << 16) |
+         ((uint32_t)(p[3]) << 24);
+#endif
+}
+
+static inline uint16_t blake2_load16(FAR const void *src)
+{
+#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG)
+  return *(FAR uint16_alias_t *)src;
+#elif !defined(CONFIG_ENDIAN_BIG)
+  const uint8_t *p = (FAR const uint8_t *)src;
+  return ((uint16_t)(p[0]) << 8) | ((uint16_t)(p[1]) << 0);
+#else
+  const uint8_t *p = (FAR const uint8_t *)src;
+  return ((uint16_t)(p[0]) << 0) | ((uint16_t)(p[1]) << 8);
+#endif
+}
+
+static inline void blake2_store16(FAR void *dst, uint16_t w)
+{
+#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG)
+  *(FAR uint16_alias_t *)dst = w;
+#elif !defined(CONFIG_ENDIAN_BIG)
+  FAR uint8_t *p = (FAR uint8_t *)dst;
+  p[1] = (uint8_t)w; w >>= 8;
+  p[0] = (uint8_t)w;
+#else
+  FAR uint8_t *p = (FAR uint8_t *)dst;
+  p[0] = (uint8_t)w; w >>= 8;
+  p[1] = (uint8_t)w;
+#endif
+}
+
+static inline void blake2_store32(FAR void *dst, uint32_t w)
+{
+#if defined(BLAKE2_UNALIGNED) && !defined(CONFIG_ENDIAN_BIG)
+  *(FAR uint32_alias_t *)dst = w;
+#elif !defined(CONFIG_ENDIAN_BIG)
+  FAR uint8_t *p = (FAR uint8_t *) dst;
+  p[0] = (uint8_t)(w >> 24);
+  p[1] = (uint8_t)(w >> 16);
+  p[2] = (uint8_t)(w >> 8);
+  p[3] = (uint8_t)(w >> 0);
+#else
+  FAR uint8_t *p = (FAR uint8_t *) dst;
+  p[0] = (uint8_t)(w >> 0);
+  p[1] = (uint8_t)(w >> 8);
+  p[2] = (uint8_t)(w >> 16);
+  p[3] = (uint8_t)(w >> 24);
+#endif
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_CRYPTO_BLAKE2S_H */
diff --git a/include/nuttx/random.h b/include/nuttx/random.h
new file mode 100644
index 0000000000..d3413e62fb
--- /dev/null
+++ b/include/nuttx/random.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+ * include/nuttx/random.h
+ *
+ *   Copyright (C) 2015-2017 Haltian Ltd. All rights reserved.
+ *   Authors: Juha Niskanen <juha.niskanen@haltian.com>
+ *            Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 __INCLUDE_NUTTX_RANDOM_H
+#define __INCLUDE_NUTTX_RANDOM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stddef.h>
+
+#include <sys/random.h> /* getrandom() */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Size of entropy pool in 32-bit integers, must be power of two */
+
+#define ENTROPY_POOL_SIZE        128
+
+#define add_irq_randomness(x)    up_rngaddint(RND_SRC_IRQ, (x))
+#define add_sensor_randomness(x) up_rngaddint(RND_SRC_SENSOR, (x))
+#define add_time_randomness(x)   up_rngaddint(RND_SRC_TIME, (x))
+#define add_hw_randomness(x)     up_rngaddint(RND_SRC_HW, (x))
+#define add_sw_randomness(x)     up_rngaddint(RND_SRC_SW, (x))
+#define add_ui_randomness(x)     up_rngaddint(RND_SRC_UI, (x))
+
+/* Allow above macros to always exist in source without ifdefs */
+
+#ifndef CONFIG_CRYPTO_RANDOM_POOL
+#  define up_rngaddint(k, x)            ((void)(k),(void)(x))
+#  define up_rngaddentropy(k, buf, n)   ((void)(k),(void)(buf),(void)(x))
+#endif
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+/* Entropy pool structure */
+
+struct entropy_pool_s
+{
+  volatile uint32_t pool[ENTROPY_POOL_SIZE];
+};
+
+/* Randomness sources */
+
+enum rnd_source_t
+{
+  RND_SRC_TIME = 0,
+  RND_SRC_IRQ,
+  RND_SRC_SENSOR,
+  RND_SRC_HW,      /* unique per HW UID or coming from factory line. */
+  RND_SRC_SW,      /* unique per SW version. */
+  RND_SRC_UI       /* buttons etc. user-visible interface elements. */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef CONFIG_BOARD_ENTROPY_POOL
+/* Entropy pool structure can be provided by board source. Use for this is,
+ * for example, allocate entropy pool from special area of RAM which content
+ * is kept over system reset. */
+
+extern struct entropy_pool_s board_entropy_pool;
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_CRYPTO_RANDOM_POOL
+
+/****************************************************************************
+ * Function: up_rngaddint
+ *
+ * Description:
+ *   Add one integer to entropy pool, contributing a specific kind
+ *   of entropy to pool.
+ *
+ * Parameters:
+ *   kindof  - Enumeration constant telling where val came from
+ *   val     - Integer to be added
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void up_rngaddint(enum rnd_source_t kindof, int val);
+
+/****************************************************************************
+ * Function: up_rngaddentropy
+ *
+ * Description:
+ *   Add buffer of integers to entropy pool.
+ *
+ * Parameters:
+ *   kindof  - Enumeration constant telling where val came from
+ *   buf     - Buffer of integers to be added
+ *   n       - Number of elements in buf
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void up_rngaddentropy(enum rnd_source_t kindof, FAR const uint32_t *buf,
+                      size_t n);
+
+/****************************************************************************
+ * Function: up_rngreseed
+ *
+ * Description:
+ *   Force reseeding random number generator from entropy pool
+ *
+ ****************************************************************************/
+
+void up_rngreseed(void);
+
+/****************************************************************************
+ * Function: up_randompool_initialize
+ *
+ * Description:
+ *   Initialize entropy pool and random number generator
+ *
+ ****************************************************************************/
+
+void up_randompool_initialize(void);
+
+#endif /* CONFIG_CRYPTO_RANDOM_POOL */
+
+#endif /* __INCLUDE_NUTTX_RANDOM_H */
diff --git a/include/string.h b/include/string.h
index 92df7f85b5..f3dbc2aaf6 100644
--- a/include/string.h
+++ b/include/string.h
@@ -93,6 +93,8 @@ FAR void  *memcpy(FAR void *dest, FAR const void *src, size_t n);
 FAR void  *memmove(FAR void *dest, FAR const void *src, size_t count);
 FAR void  *memset(FAR void *s, int c, size_t n);
 
+void explicit_bzero(FAR void *s, size_t n);
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/include/sys/random.h b/include/sys/random.h
new file mode 100644
index 0000000000..7856ca007e
--- /dev/null
+++ b/include/sys/random.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * include/sys/random.h
+ *
+ *   Copyright (C) 2015-2017 Haltian Ltd. All rights reserved.
+ *   Authors: Juha Niskanen <juha.niskanen@haltian.com>
+ *            Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 __INCLUDE_SYS_RANDOM_H
+#define __INCLUDE_SYS_RANDOM_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stddef.h>
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+#ifdef CONFIG_CRYPTO_RANDOM_POOL
+
+/****************************************************************************
+ * Function: getrandom
+ *
+ * Description:
+ *   Fill a buffer of arbitrary length with randomness. This is the
+ *   preferred interface for getting random numbers. The traditional
+ *   /dev/random approach is susceptible for things like the attacker
+ *   exhausting file descriptors on purpose.
+ *
+ *   Note that this function cannot fail, other than by asserting.
+ *
+ * Parameters:
+ *   bytes  - Buffer for returned random bytes
+ *   nbytes - Number of bytes requested.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void getrandom(FAR void *bytes, size_t nbytes);
+
+#endif /* CONFIG_CRYPTO_RANDOM_POOL */
+
+#endif /* __INCLUDE_SYS_RANDOM_H */
diff --git a/include/sys/syscall.h b/include/sys/syscall.h
index 56319b772d..6f1911c6c4 100644
--- a/include/sys/syscall.h
+++ b/include/sys/syscall.h
@@ -524,10 +524,19 @@
 /* The following is defined only if CONFIG_TASK_NAME_SIZE > 0 */
 
 #if CONFIG_TASK_NAME_SIZE > 0
-#  define SYS_prctl                    (SYS_nnetsocket+0)
-#  define SYS_maxsyscall               (SYS_nnetsocket+1)
+#  define SYS_prctl                    (SYS_nnetsocket+1)
 #else
-#  define SYS_maxsyscall               SYS_nnetsocket
+#  define SYS_prctl                    SYS_nnetsocket
+#endif
+
+/* The following is defined only if entropy pool random number generator
+ * is enabled. */
+
+#ifdef CONFIG_CRYPTO_RANDOM_POOL
+#  define SYS_getrandom                (SYS_prctl+1)
+#  define SYS_maxsyscall               (SYS_prctl+2)
+#else
+#  define SYS_maxsyscall               SYS_prctl
 #endif
 
 /* Note that the reported number of system calls does *NOT* include the
diff --git a/libc/string/Make.defs b/libc/string/Make.defs
index 72cb8354d5..0b82b6af8d 100644
--- a/libc/string/Make.defs
+++ b/libc/string/Make.defs
@@ -44,6 +44,7 @@ CSRCS += lib_strerror.c lib_strlen.c lib_strnlen.c lib_strncasecmp.c
 CSRCS += lib_strncat.c lib_strncmp.c lib_strncpy.c lib_strndup.c
 CSRCS += lib_strcasestr.c lib_strpbrk.c lib_strrchr.c lib_strspn.c
 CSRCS += lib_strstr.c lib_strtok.c lib_strtokr.c lib_strerrorr.c
+CSRCS += lib_explicit_bzero.c
 
 ifneq ($(CONFIG_LIBC_ARCH_MEMCPY),y)
 ifeq ($(CONFIG_MEMCPY_VIK),y)
diff --git a/libc/string/lib_explicit_bzero.c b/libc/string/lib_explicit_bzero.c
new file mode 100644
index 0000000000..ab862ed1a8
--- /dev/null
+++ b/libc/string/lib_explicit_bzero.c
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * libc/string/lib_explicit_bzero.c
+ *
+ *   Copyright (C) 2015,2017 Haltian Ltd. All rights reserved.
+ *   Author: Juha Niskanen <juha.niskanen@haltian.com>
+ *           Jussi Kivilinna <jussi.kivilinna@haltian.com>
+ *
+ * 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 NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <string.h>
+
+/****************************************************************************
+ * Global Functions
+ ****************************************************************************/
+
+/* memset that must not be optimized away by compiler (not even with LTO). */
+
+void explicit_bzero(FAR void *s, size_t n)
+{
+  static FAR void *(*FAR const volatile memset_v)(FAR void *, int, size_t) =
+      &memset;
+
+  memset_v(s, 0, n);
+}
diff --git a/sched/irq/irq_dispatch.c b/sched/irq/irq_dispatch.c
index b507c065b1..b311e8a2c1 100644
--- a/sched/irq/irq_dispatch.c
+++ b/sched/irq/irq_dispatch.c
@@ -42,6 +42,7 @@
 #include <debug.h>
 #include <nuttx/arch.h>
 #include <nuttx/irq.h>
+#include <nuttx/random.h>
 
 #include "irq/irq.h"
 
@@ -53,7 +54,7 @@
  * Name: irq_dispatch
  *
  * Description:
- *   This function must be called from the achitecture-specific logic in
+ *   This function must be called from the architecture-specific logic in
  *   order to dispatch an interrupt to the appropriate, registered handling
  *   logic.
  *
@@ -97,6 +98,12 @@ void irq_dispatch(int irq, FAR void *context)
   arg    = NULL;
 #endif
 
+#ifdef CONFIG_CRYPTO_RANDOM_POOL_COLLECT_IRQ_RANDOMNESS
+  /* Add interrupt timing randomness to entropy pool */
+
+  add_irq_randomness(irq);
+#endif
+
   /* Then dispatch to the interrupt handler */
 
   vector(irq, context, arg);
diff --git a/syscall/syscall.csv b/syscall/syscall.csv
index 66babafb5e..1ff6948d74 100644
--- a/syscall/syscall.csv
+++ b/syscall/syscall.csv
@@ -30,6 +30,7 @@
 "get_errno_ptr","errno.h","defined(__DIRECT_ERRNO_ACCESS)","FAR int*"
 "getenv","stdlib.h","!defined(CONFIG_DISABLE_ENVIRON)","FAR char*","FAR const char*"
 "getpid","unistd.h","","pid_t"
+"getrandom","sys/random.h","defined(CONFIG_CRYPTO_RANDOM_POOL)","void","FAR void*","size_t"
 "getsockopt","sys/socket.h","CONFIG_NSOCKET_DESCRIPTORS > 0 && defined(CONFIG_NET)","int","int","int","int","FAR void*","FAR socklen_t*"
 "insmod","nuttx/module.h","defined(CONFIG_MODULE)","FAR void *","FAR const char *","FAR const char *"
 "ioctl","sys/ioctl.h","!defined(CONFIG_LIBC_IOCTL_VARIADIC) && (CONFIG_NSOCKET_DESCRIPTORS > 0 || CONFIG_NFILE_DESCRIPTORS > 0)","int","int","int","unsigned long"
diff --git a/syscall/syscall_lookup.h b/syscall/syscall_lookup.h
index 6ed2e54e78..0719358487 100644
--- a/syscall/syscall_lookup.h
+++ b/syscall/syscall_lookup.h
@@ -379,6 +379,13 @@ SYSCALL_LOOKUP(up_assert,                  2, STUB_up_assert)
   SYSCALL_LOOKUP(prctl,                    5, STUB_prctl)
 #endif
 
+/* The following is defined only if entropy pool random number generator
+ * is enabled. */
+
+#ifdef CONFIG_CRYPTO_RANDOM_POOL
+  SYSCALL_LOOKUP(getrandom,               2, STUB_getrandom)
+#endif
+
 /****************************************************************************
  * Private Functions
  ****************************************************************************/
diff --git a/syscall/syscall_stublookup.c b/syscall/syscall_stublookup.c
index ddcffd5506..2cc52ad0a3 100644
--- a/syscall/syscall_stublookup.c
+++ b/syscall/syscall_stublookup.c
@@ -391,6 +391,11 @@ uintptr_t STUB_socket(int nbr, uintptr_t parm1, uintptr_t parm2,
 uintptr_t STUB_prctl(int nbr, uintptr_t parm1, uintptr_t parm2,
             uintptr_t parm3, uintptr_t parm4, uintptr_t parm5);
 
+/* The following is defined only if entropy pool random number generator
+ * is enabled. */
+
+uintptr_t STUB_getrandom(int nbr, uintptr_t parm1, uintptr_t parm2);
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/

From 0ded0f586606bd64adb9478fc495d7d63679bb6d Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 30 Mar 2017 08:43:07 -0600
Subject: [PATCH 06/12] Update README and comments

---
 configs/samv71-xult/README.txt   | 13 +++++++++++++
 libc/string/lib_explicit_bzero.c |  1 -
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/configs/samv71-xult/README.txt b/configs/samv71-xult/README.txt
index 5821d14b4f..9022351033 100644
--- a/configs/samv71-xult/README.txt
+++ b/configs/samv71-xult/README.txt
@@ -749,6 +749,19 @@ Selecting the GMAC peripheral
     CONFIG_NSH_NOMAC=n                   : We will get the IP address from EEPROM
                                          : Defaults should be okay for other options
 
+SAMV71 Versions
+---------------
+
+WARNING: "The newer SAMV71 have 6 GMAC queues, not 5. All queues must be
+configured for the GMAC to work correctly, even the queues that you are not
+using (you can just configure these queues with a very small ring buffer.)
+
+The older uses the Cortex-M7 core r0p1 and the newer r1p1 revisions.  The
+SAMV71 revisions are called "rev A" (or sometimes "MRLA") and "rev B"
+("MRLB"). There should be a small "A" or "B" on the chip package just below
+the reference and you can also differentiate them at runtime with the
+VERSION field in the CHIPID CIDR register."
+
 Cache-Related Issues
 --------------------
 
diff --git a/libc/string/lib_explicit_bzero.c b/libc/string/lib_explicit_bzero.c
index ab862ed1a8..b8d806508e 100644
--- a/libc/string/lib_explicit_bzero.c
+++ b/libc/string/lib_explicit_bzero.c
@@ -34,7 +34,6 @@
  *
  ****************************************************************************/
 
-
 /****************************************************************************
  * Included Files
  ****************************************************************************/

From 95cbbf552bb37ed9a4eaf20f764e3524288a3a14 Mon Sep 17 00:00:00 2001
From: Konstantin Berezenko <kpberezenko@gmail.com>
Date: Thu, 30 Mar 2017 10:36:53 -0700
Subject: [PATCH 07/12] Change STM32 tickless to use only one timer

---
 arch/arm/src/stm32/Kconfig          |  29 +-
 arch/arm/src/stm32/stm32_tickless.c | 704 ++++++++++++++++++++++++----
 2 files changed, 627 insertions(+), 106 deletions(-)

diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig
index 97f097fc65..5ae19c927a 100644
--- a/arch/arm/src/stm32/Kconfig
+++ b/arch/arm/src/stm32/Kconfig
@@ -2810,31 +2810,22 @@ menu "Timer Configuration"
 
 if SCHED_TICKLESS
 
-config STM32_ONESHOT
-	bool
-	default y
-
-config STM32_FREERUN
-	bool
-	default y
-
-config STM32_TICKLESS_ONESHOT
-	int "Tickless one-shot timer channel"
+config STM32_TICKLESS_TIMER
+	int "Tickless hardware timer"
 	default 2
 	range 1 14
-	depends on STM32_ONESHOT
 	---help---
-		If the Tickless OS feature is enabled, the one clock must be
-		assigned to provided the one-shot timer needed by the OS.
+		If the Tickless OS feature is enabled, then one clock must be
+		assigned to provided the timer needed by the OS.
 
-config STM32_TICKLESS_FREERUN
-	int "Tickless free-running timer channel"
-	default 5
-	range 1 14
-	depends on STM32_FREERUN
+config STM32_TICKLESS_CHANNEL
+	int "Tickless timer channel"
+	default 1
+	range 1 4
 	---help---
 		If the Tickless OS feature is enabled, the one clock must be
-		assigned to provided the free-running timer needed by the OS.
+		assigned to provided the free-running timer needed by the OS
+		and one channel on that clock is needed to handle intervals.
 
 endif # SCHED_TICKLESS
 
diff --git a/arch/arm/src/stm32/stm32_tickless.c b/arch/arm/src/stm32/stm32_tickless.c
index fafa9bcadf..f0baa5edee 100644
--- a/arch/arm/src/stm32/stm32_tickless.c
+++ b/arch/arm/src/stm32/stm32_tickless.c
@@ -2,7 +2,9 @@
  * arch/arm/src/stm32/stm32_tickless.c
  *
  *   Copyright (C) 2016 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *   Copyright (C) 2017 Ansync Labs. All rights reserved.
+ *   Authors: Gregory Nutt <gnutt@nuttx.org>
+ *            Konstantin Berezenko <kpberezenko@gmail.com>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -55,24 +57,19 @@
  *
  ****************************************************************************/
 /****************************************************************************
- * SAM34 Timer Usage
+ * STM32 Timer Usage
  *
- * This current implementation uses two timers:  A one-shot timer to provide
- * the timed events and a free running timer to provide the current time.
- * Since timers are a limited resource, that could be an issue on some
- * systems.
- *
- * We could do the job with a single timer if we were to keep the single
- * timer in a free-running at all times.  The STM32 timer/counters have
- * 16-bit/32-bit counters with the capability to generate a compare interrupt
- * when the timer matches a compare value but also to continue counting
- * without stopping (giving another, different interrupt when the timer
- * rolls over from 0xffffffff to zero).  So we could potentially just set
- * the compare at the number of ticks you want PLUS the current value of
- * timer.  Then you could have both with a single timer:  An interval timer
- * and a free-running counter with the same timer!
- *
- * Patches are welcome!
+ * This implementation uses one timer:  A free running timer to provide
+ * the current time and a capture/compare channel for timed-events.
+ * The STM32 has both 16-bit and 32-bit timers so to keep things consistent
+ * we limit the timer counters to a 16-bit range.  BASIC timers that
+ * are found on some STM32 chips (timers 6 and 7) are incompatible with this
+ * implementation because they don't have capture/compare channels.  There
+ * are two interrupts generated from our timer, the overflow interrupt which
+ * drives the timing handler and the capture/compare interrupt which drives
+ * the interval handler.  There are some low level timer control functions
+ * implemented here because the API of stm32_tim.c does not provide adequate
+ * control over capture/compare interrupts.
  *
  ****************************************************************************/
 
@@ -84,12 +81,15 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <errno.h>
+#include <assert.h>
 
 #include <nuttx/arch.h>
 #include <debug.h>
 
-#include "stm32_oneshot.h"
-#include "stm32_freerun.h"
+#include "up_arch.h"
+
+#include "stm32_tim.h"
 
 #ifdef CONFIG_SCHED_TICKLESS
 
@@ -97,30 +97,24 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
-#ifndef CONFIG_STM32_ONESHOT
-#  error CONFIG_STM32_ONESHOT must be selected for the Tickless OS option
-#endif
-
-#ifndef CONFIG_STM32_FREERUN
-#  error CONFIG_STM32_FREERUN must be selected for the Tickless OS option
-#endif
-
-#ifndef CONFIG_STM32_TICKLESS_FREERUN
-#  error CONFIG_STM32_TICKLESS_FREERUN must be selected for the Tickless OS option
-#endif
-
-#ifndef CONFIG_STM32_TICKLESS_ONESHOT
-#  error CONFIG_STM32_TICKLESS_ONESHOT must be selected for the Tickless OS option
-#endif
-
 /****************************************************************************
  * Private Types
  ****************************************************************************/
 
 struct stm32_tickless_s
 {
-  struct stm32_oneshot_s oneshot;
-  struct stm32_freerun_s freerun;
+  uint8_t timer;                   /* The timer/counter in use */
+  uint8_t channel;                 /* The timer channel to use for intervals */
+  FAR struct stm32_tim_dev_s *tch; /* Handle returned by stm32_tim_init() */
+  uint32_t frequency;
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+  uint64_t counter_mask;
+#else
+  uint32_t overflow;               /* Timer counter overflow */
+#endif
+  volatile bool pending;           /* True: pending task */
+  uint32_t period;                 /* Interval period */
+  uint32_t base;
 };
 
 /****************************************************************************
@@ -133,11 +127,155 @@ static struct stm32_tickless_s g_tickless;
  * Private Functions
  ****************************************************************************/
 
-/****************************************************************************
- * Name: stm32_oneshot_handler
+/************************************************************************************
+ * Name: stm32_getreg16
  *
  * Description:
- *   Called when the one shot timer expires
+ *   Get a 16-bit register value by offset
+ *
+ ************************************************************************************/
+
+static inline uint16_t stm32_getreg16(uint8_t offset)
+{
+  return getreg16(g_tickless.base + offset);
+}
+
+/************************************************************************************
+ * Name: stm32_putreg16
+ *
+ * Description:
+ *   Put a 16-bit register value by offset
+ *
+ ************************************************************************************/
+
+static inline void stm32_putreg16(uint8_t offset, uint16_t value)
+{
+  putreg16(value, g_tickless.base + offset);
+}
+
+/************************************************************************************
+ * Name: stm32_modifyreg16
+ *
+ * Description:
+ *   Modify a 16-bit register value by offset
+ *
+ ************************************************************************************/
+
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits, uint16_t setbits)
+{
+  modifyreg16(g_tickless.base + offset, clearbits, setbits);
+}
+
+/************************************************************************************
+ * Name: stm32_tickless_enableint
+ ************************************************************************************/
+
+static inline void stm32_tickless_enableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 0, 1 << channel);
+}
+
+/************************************************************************************
+ * Name: stm32_tickless_disableint
+ ************************************************************************************/
+
+static inline void stm32_tickless_disableint(int channel)
+{
+  stm32_modifyreg16(STM32_BTIM_DIER_OFFSET, 1 << channel, 0);
+}
+
+/************************************************************************************
+ * Name: stm32_tickless_ackint
+ ************************************************************************************/
+
+static inline void stm32_tickless_ackint(int channel)
+{
+  stm32_putreg16(STM32_BTIM_SR_OFFSET, ~(1 << channel));
+}
+
+/************************************************************************************
+ * Name: stm32_tickless_getint
+ ************************************************************************************/
+
+static inline uint16_t stm32_tickless_getint(void)
+{
+  return stm32_getreg16(STM32_BTIM_SR_OFFSET);
+}
+
+/************************************************************************************
+ * Name: stm32_tickless_setchannel
+ ************************************************************************************/
+
+static int stm32_tickless_setchannel(uint8_t channel)
+{
+  uint16_t ccmr_orig   = 0;
+  uint16_t ccmr_val    = 0;
+  uint16_t ccmr_mask   = 0xff;
+  uint16_t ccer_val    = stm32_getreg16(STM32_GTIM_CCER_OFFSET);
+  uint8_t  ccmr_offset = STM32_GTIM_CCMR1_OFFSET;
+
+  /* Further we use range as 0..3; if channel=0 it will also overflow here */
+
+  if (--channel > 4)
+    {
+      return -EINVAL;
+    }
+
+  /* Assume that channel is disabled and polarity is active high */
+
+  ccer_val &= ~(3 << (channel << 2));
+
+  /* This function is not supported on basic timers. To enable or
+   * disable it, simply set its clock to valid frequency or zero.
+   */
+
+#if STM32_NBTIM > 0
+  if (g_tickless.base == STM32_TIM6_BASE
+#endif
+#if STM32_NBTIM > 1
+      || g_tickless.base == STM32_TIM7_BASE
+#endif
+#if STM32_NBTIM > 0
+  )
+    {
+      return -EINVAL;
+    }
+#endif
+
+  /* frozen mode because we don't want to change the gpio, preload register disabled */
+  ccmr_val  =  (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
+        
+  /* Set polarity */
+
+  ccer_val |= ATIM_CCER_CC1P << (channel << 2);
+
+  /* Define its position (shift) and get register offset */
+
+  if (channel & 1)
+    {
+      ccmr_val  <<= 8;
+      ccmr_mask <<= 8;
+    }
+
+  if (channel > 1)
+    {
+      ccmr_offset = STM32_GTIM_CCMR2_OFFSET;
+    }
+
+  ccmr_orig  = stm32_getreg16(ccmr_offset);
+  ccmr_orig &= ~ccmr_mask;
+  ccmr_orig |= ccmr_val;
+  stm32_putreg16(ccmr_offset, ccmr_orig);
+  stm32_putreg16(STM32_GTIM_CCER_OFFSET, ccer_val);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: stm32_interval_handler
+ *
+ * Description:
+ *   Called when the timer counter matches the compare register
  *
  * Input Parameters:
  *   None
@@ -151,12 +289,76 @@ static struct stm32_tickless_s g_tickless;
  *
  ****************************************************************************/
 
-static void stm32_oneshot_handler(void *arg)
+static void stm32_interval_handler(void)
 {
   tmrinfo("Expired...\n");
+
+   /* Disable the compare interrupt now. */
+
+  stm32_tickless_disableint(g_tickless.channel);
+  stm32_tickless_ackint(g_tickless.channel);
+
+  g_tickless.pending = false;
+
   sched_timer_expiration();
 }
 
+
+/****************************************************************************
+ * Name: stm32_timing_handler
+ *
+ * Description:
+ *   Timer interrupt callback.  When the freerun timer counter overflows,
+ *   this interrupt will occur.  We will just increment an overflow count.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+static void stm32_timing_handler(void)
+{
+  g_tickless.overflow++;
+
+  STM32_TIM_ACKINT(g_tickless.tch, 0);
+}
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+
+/****************************************************************************
+ * Name: stm32_tickless_handler
+ *
+ * Description:
+ *   Generic interrupt handler for this timer.  It checks the source of the
+ *   interrupt and fires the appropriate handler.
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int stm32_tickless_handler(int irq, void *context, void *arg)
+{
+  int interrupt_flags = stm32_tickless_getint();
+
+#ifndef CONFIG_CLOCK_TIMEKEEPING
+  if (interrupt_flags & ATIM_SR_UIF)
+    stm32_timing_handler();
+#endif /* CONFIG_CLOCK_TIMEKEEPING */
+
+  if (interrupt_flags & (1 << g_tickless.channel))
+    stm32_interval_handler();
+
+  return OK;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -188,55 +390,162 @@ static void stm32_oneshot_handler(void *arg)
 
 void arm_timer_initialize(void)
 {
-#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
-  uint64_t max_delay;
+  switch (CONFIG_STM32_TICKLESS_TIMER)
+    {
+#ifdef CONFIG_STM32_TIM1
+      case 1:
+        g_tickless.base = STM32_TIM1_BASE;
+	break;
 #endif
-  int ret;
+#ifdef CONFIG_STM32_TIM2
+      case 2:
+        g_tickless.base = STM32_TIM2_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM3
+      case 3:
+        g_tickless.base = STM32_TIM3_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM4
+      case 4:
+        g_tickless.base = STM32_TIM4_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM5
+      case 5:
+        g_tickless.base = STM32_TIM5_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM6
+      case 6:
 
-  /* Initialize the one-shot timer */
+	/* Basic timers not supported by this implementation */
 
-  ret = stm32_oneshot_initialize(&g_tickless.oneshot,
-                                 CONFIG_STM32_TICKLESS_ONESHOT,
-                                 CONFIG_USEC_PER_TICK);
-  if (ret < 0)
-    {
-      tmrerr("ERROR: stm32_oneshot_initialize failed\n");
-      PANIC();
-    }
+        ASSERT(0);
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM7
+      case 7:
 
-#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
-  /* Get the maximum delay of the one-shot timer in microseconds */
+	/* Basic timers not supported by this implementation */
 
-  ret = stm32_oneshot_max_delay(&g_tickless.oneshot, &max_delay);
-  if (ret < 0)
-    {
-      tmrerr("ERROR: stm32_oneshot_max_delay failed\n");
-      PANIC();
-    }
-
-  /* Convert this to configured clock ticks for use by the OS timer logic */
-
-  max_delay /= CONFIG_USEC_PER_TICK;
-  if (max_delay > UINT32_MAX)
-    {
-      g_oneshot_maxticks = UINT32_MAX;
-    }
-  else
-    {
-      g_oneshot_maxticks = max_delay;
-    }
+        ASSERT(0);
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM8
+      case 8:
+        g_tickless.base = STM32_TIM8_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM9
+      case 9:
+        g_tickless.base = STM32_TIM9_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM10
+      case 10:
+        g_tickless.base = STM32_TIM10_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM11
+      case 11:
+        g_tickless.base = STM32_TIM11_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM12
+      case 12:
+        g_tickless.base = STM32_TIM12_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM13
+      case 13:
+        g_tickless.base = STM32_TIM13_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM14
+      case 14:
+        g_tickless.base = STM32_TIM14_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM15
+      case 15:
+        g_tickless.base = STM32_TIM15_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM16
+      case 16:
+        g_tickless.base = STM32_TIM16_BASE;
+	break;
+#endif
+#ifdef CONFIG_STM32_TIM17
+      case 17:
+        g_tickless.base = STM32_TIM17_BASE;
+	break;
 #endif
 
-  /* Initialize the free-running timer */
+      default:
+        ASSERT(0);
 
-  ret = stm32_freerun_initialize(&g_tickless.freerun,
-                                 CONFIG_STM32_TICKLESS_FREERUN,
-                                 CONFIG_USEC_PER_TICK);
-  if (ret < 0)
-    {
-      tmrerr("ERROR: stm32_freerun_initialize failed\n");
-      PANIC();
     }
+
+  /* Get the TC frequency that corresponds to the requested resolution */
+
+  g_tickless.frequency = USEC_PER_SEC / (uint32_t)CONFIG_USEC_PER_TICK;
+  g_tickless.timer     = CONFIG_STM32_TICKLESS_TIMER;
+  g_tickless.channel   = CONFIG_STM32_TICKLESS_CHANNEL;
+  g_tickless.pending   = false;
+  g_tickless.period    = 0;
+
+  tmrinfo("timer=%d channel=%d frequency=%d Hz\n",
+           g_tickless.timer, g_tickless.channel, g_tickless.frequency);
+
+  g_tickless.tch = stm32_tim_init(g_tickless.timer);
+  if (!g_tickless.tch)
+    {
+      tmrerr("ERROR: Failed to allocate TIM%d\n", g_tickless.timer);
+      ASSERT(0);
+    }
+
+  STM32_TIM_SETCLOCK(g_tickless.tch, g_tickless.frequency);
+
+#ifdef CONFIG_CLOCK_TIMEKEEPING
+
+  /* Should this be changed to 0xffff because we use 16 bit timers? */
+
+  g_tickless.counter_mask = 0xffffffffull;
+#else
+  g_tickless.overflow     = 0;
+
+  /* Set up to receive the callback when the counter overflow occurs */
+
+  STM32_TIM_SETISR(g_tickless.tch, stm32_tickless_handler, NULL, 0);
+#endif
+
+  /* Initialize interval to zero */
+
+  STM32_TIM_SETCOMPARE(g_tickless.tch, g_tickless.channel, 0);
+
+  /* Setup compare channel for the interval timing */
+
+  stm32_tickless_setchannel(g_tickless.channel);
+
+  /* Set timer period */
+
+  STM32_TIM_SETPERIOD(g_tickless.tch, UINT16_MAX);
+
+  /* Initialize the counter */
+
+  STM32_TIM_SETMODE(g_tickless.tch, STM32_TIM_MODE_UP);
+
+#ifdef CONFIG_SCHED_TICKLESS_LIMIT_MAX_SLEEP
+  g_oneshot_maxticks = UINT16_MAX;
+#endif
+
+  /* Start the timer */
+
+  STM32_TIM_ACKINT(g_tickless.tch, 0);
+  STM32_TIM_ENABLEINT(g_tickless.tch, 0);
 }
 
 /****************************************************************************
@@ -276,14 +585,84 @@ void arm_timer_initialize(void)
 
 int up_timer_gettime(FAR struct timespec *ts)
 {
-  return stm32_freerun_counter(&g_tickless.freerun, ts);
+  uint64_t usec;
+  uint32_t counter;
+  uint32_t verify;
+  uint32_t overflow;
+  uint32_t sec;
+  int pending;
+  irqstate_t flags;
+
+  DEBUGASSERT(g_tickless.tch && ts);
+
+  /* Temporarily disable the overflow counter.  NOTE that we have to be
+   * careful here because  stm32_tc_getpending() will reset the pending
+   * interrupt status.  If we do not handle the overflow here then, it will
+   * be lost.
+   */
+
+  flags    = enter_critical_section();
+
+  overflow = g_tickless.overflow;
+  counter  = STM32_TIM_GETCOUNTER(g_tickless.tch);
+  pending  = STM32_TIM_CHECKINT(g_tickless.tch, 0);
+  verify   = STM32_TIM_GETCOUNTER(g_tickless.tch);
+
+  /* If an interrupt was pending before we re-enabled interrupts,
+   * then the overflow needs to be incremented.
+   */
+
+  if (pending)
+    {
+      STM32_TIM_ACKINT(g_tickless.tch, 0);
+
+      /* Increment the overflow count and use the value of the
+       * guaranteed to be AFTER the overflow occurred.
+       */
+
+      overflow++;
+      counter = verify;
+
+      /* Update tickless overflow counter. */
+
+      g_tickless.overflow = overflow;
+    }
+
+  leave_critical_section(flags);
+
+  tmrinfo("counter=%lu (%lu) overflow=%lu, pending=%i\n",
+         (unsigned long)counter,  (unsigned long)verify,
+         (unsigned long)overflow, pending);
+  tmrinfo("frequency=%u\n", g_tickless.frequency);
+
+  /* Convert the whole thing to units of microseconds.
+   *
+   *   frequency = ticks / second
+   *   seconds   = ticks * frequency
+   *   usecs     = (ticks * USEC_PER_SEC) / frequency;
+   */
+
+  usec = ((((uint64_t)overflow << 16) + (uint64_t)counter) * USEC_PER_SEC) /
+         g_tickless.frequency;
+
+  /* And return the value of the timer */
+
+  sec         = (uint32_t)(usec / USEC_PER_SEC);
+  ts->tv_sec  = sec;
+  ts->tv_nsec = (usec - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+
+  tmrinfo("usec=%llu ts=(%u, %lu)\n",
+          usec, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+
+  return OK;
 }
 
 #else
 
 int up_timer_getcounter(FAR uint64_t *cycles)
 {
-  return stm32_freerun_counter(&g_tickless.freerun, cycles);
+  *cycles = (uint64_t)STM32_TIM_GETCOUNTER(g_tickless.tch);
+  return OK;
 }
 
 #endif /* CONFIG_CLOCK_TIMEKEEPING */
@@ -306,7 +685,7 @@ int up_timer_getcounter(FAR uint64_t *cycles)
 void up_timer_getmask(FAR uint64_t *mask)
 {
   DEBUGASSERT(mask != NULL);
-  *mask = g_tickless.freerun.counter_mask;
+  *mask = g_tickless.counter_mask;
 }
 #endif /* CONFIG_CLOCK_TIMEKEEPING */
 
@@ -348,7 +727,100 @@ void up_timer_getmask(FAR uint64_t *mask)
 
 int up_timer_cancel(FAR struct timespec *ts)
 {
-  return stm32_oneshot_cancel(&g_tickless.oneshot, ts);
+  irqstate_t flags;
+  uint64_t usec;
+  uint64_t sec;
+  uint64_t nsec;
+  uint32_t count;
+  uint32_t period;
+
+  /* Was the timer running? */
+
+  flags = enter_critical_section();
+  if (!g_tickless.pending)
+    {
+      /* No.. Just return zero timer remaining and successful cancellation.
+       * This function may execute at a high rate with no timer running
+       * (as when pre-emption is enabled and disabled).
+       */
+
+      if (ts)
+        {
+          ts->tv_sec  = 0;
+          ts->tv_nsec = 0;
+        }
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  /* Yes.. Get the timer counter and period registers and disable the compare interrupt.
+   *
+   */
+
+  tmrinfo("Cancelling...\n");
+
+  /* Disable the interrupt. */
+
+  stm32_tickless_disableint(g_tickless.channel);
+
+  count  = STM32_TIM_GETCOUNTER(g_tickless.tch);
+  period = g_tickless.period;
+
+  g_tickless.pending = false;
+  leave_critical_section(flags);
+
+  /* Did the caller provide us with a location to return the time
+   * remaining?
+   */
+
+  if (ts)
+    {
+      /* Yes.. then calculate and return the time remaining on the
+       * oneshot timer.
+       */
+
+      tmrinfo("period=%lu count=%lu\n",
+             (unsigned long)period, (unsigned long)count);
+
+      if (count > period)
+        {
+          /* Handle rollover */
+
+	  period += UINT16_MAX;
+        }
+      else if (count == period)
+        {
+          /* No time remaining */
+
+          ts->tv_sec  = 0;
+          ts->tv_nsec = 0;
+	  return OK;
+        }
+
+        /* The total time remaining is the difference.  Convert that
+         * to units of microseconds.
+         *
+         *   frequency = ticks / second
+         *   seconds   = ticks * frequency
+         *   usecs     = (ticks * USEC_PER_SEC) / frequency;
+         */
+
+        usec        = (((uint64_t)(period - count)) * USEC_PER_SEC) /
+                      g_tickless.frequency;
+
+        /* Return the time remaining in the correct form */
+
+        sec         = usec / USEC_PER_SEC;
+        nsec        = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+
+        ts->tv_sec  = (time_t)sec;
+        ts->tv_nsec = (unsigned long)nsec;
+
+      tmrinfo("remaining (%lu, %lu)\n",
+             (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+    }
+
+  return OK;
 }
 
 /****************************************************************************
@@ -378,6 +850,64 @@ int up_timer_cancel(FAR struct timespec *ts)
 
 int up_timer_start(FAR const struct timespec *ts)
 {
-  return stm32_oneshot_start(&g_tickless.oneshot, stm32_oneshot_handler, NULL, ts);
+  uint64_t usec;
+  uint64_t period;
+  uint32_t count;
+  irqstate_t flags;
+
+  tmrinfo("handler=%p arg=%p, ts=(%lu, %lu)\n",
+         handler, arg, (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
+  DEBUGASSERT(ts);
+  DEBUGASSERT(g_tickless.tch);
+
+  /* Was an interval already running? */
+
+  flags = enter_critical_section();
+  if (g_tickless.pending)
+    {
+      /* Yes.. then cancel it */
+
+      tmrinfo("Already running... cancelling\n");
+      (void)up_timer_cancel(NULL);
+    }
+
+  /* Express the delay in microseconds */
+
+  usec = (uint64_t)ts->tv_sec * USEC_PER_SEC +
+         (uint64_t)(ts->tv_nsec / NSEC_PER_USEC);
+
+  /* Get the timer counter frequency and determine the number of counts need
+   * to achieve the requested delay.
+   *
+   *   frequency = ticks / second
+   *   ticks     = seconds * frequency
+   *             = (usecs * frequency) / USEC_PER_SEC;
+   */
+
+  period = (usec * (uint64_t)g_tickless.frequency) / USEC_PER_SEC;
+  count  = STM32_TIM_GETCOUNTER(g_tickless.tch);
+
+  tmrinfo("usec=%llu period=%08llx\n", usec, period);
+  DEBUGASSERT(period <= UINT16_MAX);
+
+  /* Set interval compare value. Rollover is fine,
+   * channel will trigger on the next period.  (uint16_t) cast
+   * handles the overflow.
+   */
+
+  g_tickless.period = (uint16_t)(period + count);
+ 
+  STM32_TIM_SETCOMPARE(g_tickless.tch, g_tickless.channel, g_tickless.period);
+
+  /* Enable interrupts.  We should get the callback when the interrupt
+   * occurs.
+   */
+
+  stm32_tickless_ackint(g_tickless.channel);
+  stm32_tickless_enableint(g_tickless.channel);
+
+  g_tickless.pending = true;
+  leave_critical_section(flags);
+  return OK;
 }
 #endif /* CONFIG_SCHED_TICKLESS */

From 9e2b3da3e8451e1befa0f49393e3b6eaf04a89bb Mon Sep 17 00:00:00 2001
From: Juha Niskanen <juha.niskanen@haltian.com>
Date: Thu, 30 Mar 2017 09:34:03 -0600
Subject: [PATCH 08/12] drivers/sensors: Add driver for ST HTS221 humidity
 sensor

---
 drivers/sensors/Kconfig        |   23 +
 drivers/sensors/Make.defs      |    4 +
 drivers/sensors/hts221.c       | 1131 ++++++++++++++++++++++++++++++++
 include/nuttx/random.h         |    2 +-
 include/nuttx/sensors/hts221.h |  158 +++++
 include/nuttx/sensors/ioctl.h  |   10 +
 6 files changed, 1327 insertions(+), 1 deletion(-)
 create mode 100644 drivers/sensors/hts221.c
 create mode 100644 include/nuttx/sensors/hts221.h

diff --git a/drivers/sensors/Kconfig b/drivers/sensors/Kconfig
index 9b3e2660b2..5871c18b81 100644
--- a/drivers/sensors/Kconfig
+++ b/drivers/sensors/Kconfig
@@ -32,6 +32,29 @@ config BMP180
 	---help---
 		Enable driver support for the Bosch BMP180 barometer sensor.
 
+config HTS221
+	bool "ST HTS221 humidity sensor"
+	default n
+	select I2C
+	---help---
+		Enable driver support for the ST HTS221 humidity sensor.
+
+if HTS221
+
+config DEBUG_HTS221
+	bool "Debug support for the HTS221"
+	default n
+	---help---
+		Enables debug features for the HTS221
+
+config HTS221_NPOLLWAITERS
+	int "Number of waiters to poll"
+	default 1
+	---help---
+		Number of waiters to poll
+
+endif # HTS221
+
 config SENSORS_L3GD20
 	bool "ST L3GD20 Gyroscope Sensor support"
 	default n
diff --git a/drivers/sensors/Make.defs b/drivers/sensors/Make.defs
index c4b14ace8f..d0bb9fa650 100644
--- a/drivers/sensors/Make.defs
+++ b/drivers/sensors/Make.defs
@@ -81,6 +81,10 @@ ifeq ($(CONFIG_BMP180),y)
   CSRCS += bmp180.c
 endif
 
+ifeq ($(CONFIG_HTS221),y)
+  CSRCS += hts221.c
+endif
+
 ifeq ($(CONFIG_I2C_LM75),y)
   CSRCS += lm75.c
 endif
diff --git a/drivers/sensors/hts221.c b/drivers/sensors/hts221.c
new file mode 100644
index 0000000000..4dc9c0d2dd
--- /dev/null
+++ b/drivers/sensors/hts221.c
@@ -0,0 +1,1131 @@
+/****************************************************************************
+ * drivers/sensors/hts221.c
+ *
+ *   Copyright (C) 2014 Haltian Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <sys/types.h>
+#include <debug.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <errno.h>
+#include <nuttx/arch.h>
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/random.h>
+
+#include <nuttx/sensors/hts221.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_HTS221
+#  define hts221_dbg(x, ...)    _info(x, ##__VA_ARGS__)
+#else
+#  define hts221_dbg(x, ...)    sninfo(x, ##__VA_ARGS__)
+#endif
+
+#define HTS221_WHO_AM_I             0x0f
+#define HTS221_AV_CONF              0x10
+#define HTS221_CTRL_REG1            0x20
+#define HTS221_CTRL_REG2            0x21
+#define HTS221_CTRL_REG3            0x22
+#define HTS221_STATUS_REG           0x27
+#define HTS221_HUM_OUT_L            0x28
+#define HTS221_HUM_OUT_H            0x29
+#define HTS221_TEMP_OUT_L           0x2a
+#define HTS221_TEMP_OUT_H           0x2b
+
+/* Calibration registers */
+
+#define HTS221_CALIB_H0_RH_X2       0x30
+#define HTS221_CALIB_H1_RH_X2       0x31
+#define HTS221_CALIB_T0_DEGC_X8     0x32
+#define HTS221_CALIB_T1_DEGC_X8     0x33
+#define HTS221_CALIB_T1_T0_MSB      0x35
+#define HTS221_CALIB_H0T0_OUT_L     0x36
+#define HTS221_CALIB_H0T0_OUT_H     0x37
+#define HTS221_CALIB_H1T0_OUT_L     0x3a
+#define HTS221_CALIB_H1T0_OUT_H     0x3b
+#define HTS221_CALIB_T0_OUT_L       0x3c
+#define HTS221_CALIB_T0_OUT_H       0x3d
+#define HTS221_CALIB_T1_OUT_L       0x3e
+#define HTS221_CALIB_T1_OUT_H       0x3f
+
+/* HTS221_CTRL_REG1 */
+
+#define HTS221_CTRL_REG1_PD         (1 << 7)
+#define HTS221_CTRL_REG1_BDU        (1 << 2)
+
+/* HTS221_CTRL_REG2 */
+
+#define HTS221_CTRL_REG2_BOOT       (1 << 7)
+#define HTS221_CTRL_REG2_ONE_SHOT   (1 << 0)
+
+/* HTS221_CTRL_REG3 */
+
+#define HTS221_CTRL_REG3_DRDY_L_H   (1 << 7)
+#define HTS221_CTRL_REG3_PP_OD      (1 << 6)
+#define HTS221_CTRL_REG3_DRDY_EN    (1 << 2)
+
+/* HTS221_STATUS_REG */
+
+#define HTS221_STATUS_REG_H_DA      (1 << 1)
+#define HTS221_STATUS_REG_T_DA      (1 << 0)
+
+#define HTS221_I2C_RETRIES          10
+
+/****************************************************************************
+* Private Function Prototypes
+*****************************************************************************/
+
+static int hts221_open(FAR struct file *filep);
+static int hts221_close(FAR struct file *filep);
+static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen);
+static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen);
+static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
+#ifndef CONFIG_DISABLE_POLL
+static int hts221_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                       bool setup);
+#endif
+
+/****************************************************************************
+* Private Types
+****************************************************************************/
+
+struct hts221_dev_s
+{
+  struct i2c_master_s *i2c;
+  uint8_t addr;
+  hts221_config_t *config;
+  sem_t devsem;
+  volatile bool int_pending;
+#ifndef CONFIG_DISABLE_POLL
+  struct pollfd *fds[CONFIG_HTS221_NPOLLWAITERS];
+#endif
+  struct
+  {
+    int16_t t0_out;
+    int16_t t1_out;
+    int16_t h0_t0_out;
+    int16_t h1_t0_out;
+    unsigned int t0_x8:10;
+    unsigned int t1_x8:10;
+    uint8_t h0_x2;
+    uint8_t h1_x2;
+  } calib;
+};
+
+/****************************************************************************
+* Private Data
+****************************************************************************/
+
+static const struct file_operations g_humidityops =
+{
+  hts221_open,   /* open */
+  hts221_close,  /* close */
+  hts221_read,   /* read */
+  hts221_write,  /* write */
+  NULL,          /* seek */
+  hts221_ioctl   /* ioctl */
+#ifndef CONFIG_DISABLE_POLL
+  , hts221_poll  /* poll */
+#endif
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+  , NULL         /* unlink */
+#endif
+};
+
+static struct hts221_dev_s *g_humid_data;
+
+/****************************************************************************
+* Private Functions
+****************************************************************************/
+
+static int hts221_do_transfer(FAR struct hts221_dev_s *dev,
+                              FAR struct i2c_msg_s *msgv,
+                              size_t nmsg)
+{
+  int ret = -EIO;
+  int retries;
+
+  for (retries = 0; retries < HTS221_I2C_RETRIES; retries++)
+    {
+      ret = I2C_TRANSFER(dev->i2c, msgv, nmsg);
+      if (ret >= 0)
+        {
+          return 0;
+        }
+      else
+        {
+          /* Some error. Try to reset I2C bus and keep trying. */
+#ifdef CONFIG_I2C_RESET
+          if (retries == HTS221_I2C_RETRIES - 1)
+            {
+              break;
+            }
+
+          ret = up_i2creset(dev->i2c);
+          if (ret < 0)
+            {
+              hts221_dbg("up_i2creset failed: %d\n", ret);
+              return ret;
+            }
+#endif
+        }
+    }
+
+  hts221_dbg("xfer failed: %d\n", ret);
+  return ret;
+}
+
+static int32_t hts221_write_reg8(FAR struct hts221_dev_s *dev,
+                                 const uint8_t *command)
+{
+  struct i2c_msg_s msgv[2] =
+  {
+    {
+      .addr   = dev->addr,
+      .flags  = 0,
+      .buffer = (FAR void *)&command[0],
+      .length = 1
+    },
+    {
+      .addr   = dev->addr,
+      .flags  = I2C_M_NORESTART,
+      .buffer = (FAR void *)&command[1],
+      .length = 1
+    }
+  };
+
+  return hts221_do_transfer(dev, msgv, 2);
+}
+
+static int hts221_read_reg(FAR struct hts221_dev_s *dev,
+                           FAR const uint8_t *command, FAR uint8_t *value)
+{
+  struct i2c_msg_s msgv[2] =
+  {
+    {
+      .addr   = dev->addr,
+      .flags  = 0,
+      .buffer = (FAR void *)command,
+      .length = 1
+    },
+    {
+      .addr   = dev->addr,
+      .flags  = I2C_M_READ,
+      .buffer = value,
+      .length = 1
+    }
+  };
+
+  return hts221_do_transfer(dev, msgv, 2);
+}
+
+static int hts221_get_id(FAR struct hts221_dev_s *priv, uint8_t * value)
+{
+  int ret = OK;
+  uint8_t cmd = HTS221_WHO_AM_I;
+
+  ret = hts221_read_reg(priv, &cmd, value);
+
+  hts221_dbg("Who am I request: 0x%02X\n", *value);
+
+  return ret;
+}
+
+static int hts221_cfgr_resolution(FAR struct hts221_dev_s *priv,
+                                  FAR hts221_settings_t *settings)
+{
+  int ret;
+  uint8_t value;
+  const uint8_t addr = HTS221_AV_CONF;
+  uint8_t regval = 0;
+  uint8_t cmd[2] = { 0 };
+  const uint8_t mask = 0x3f;
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  hts221_dbg("Default resolution: 0x%02X\n", regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  value   = (uint8_t)settings->humid_resol |
+            ((uint8_t)settings->temp_resol << 3);
+  regval &= ~mask;
+  cmd[0]  = addr;
+  cmd[1]  = regval | value;
+  hts221_dbg("New resolution: 0x%02X\n", cmd[1]);
+
+  ret = hts221_write_reg8(priv, cmd);
+
+  hts221_dbg("Resolution changed: temp=%d humid=%d ret=%d\n",
+               settings->temp_resol, settings->humid_resol, ret);
+
+  return ret;
+}
+
+static int hts221_config_ctrl_reg3(FAR struct hts221_dev_s *priv,
+                                   FAR hts221_settings_t *settings)
+{
+  int ret = OK;
+  uint8_t regval = 0;
+  uint8_t addr = HTS221_CTRL_REG3;
+  const uint8_t mask = 0xc4;
+  uint8_t data_to_write[2] = { 0 };
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  hts221_dbg("CTRL_REG3: 0x%02X\n", regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  regval &= ~mask;
+  regval |= (uint8_t)(settings->is_high_edge ? 0 : HTS221_CTRL_REG3_DRDY_L_H);
+  regval |= (uint8_t)(settings->is_open_drain ? HTS221_CTRL_REG3_PP_OD : 0);
+  regval |= (uint8_t)(settings->is_data_rdy ? HTS221_CTRL_REG3_DRDY_EN : 0);
+
+  data_to_write[0] = addr;
+  data_to_write[1] = regval;
+
+  ret = hts221_write_reg8(priv, data_to_write);
+
+  return ret;
+}
+
+static int hts221_config_ctrl_reg2(FAR struct hts221_dev_s *priv,
+                                   FAR hts221_settings_t *settings)
+{
+  int ret = OK;
+  uint8_t regval = 0;
+  uint8_t addr = HTS221_CTRL_REG2;
+  const uint8_t mask = 0x80;
+  uint8_t data_to_write[2] = { 0 };
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  hts221_dbg("CTRL_REG2: 0x%02X\n", regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  regval &= ~mask;
+  regval |= (uint8_t)(settings->is_boot ? HTS221_CTRL_REG2_BOOT : 0);
+
+  data_to_write[0] = addr;
+  data_to_write[1] = regval;
+
+  ret = hts221_write_reg8(priv, data_to_write);
+
+  return ret;
+}
+
+static int hts221_config_ctrl_reg1(FAR struct hts221_dev_s *priv,
+                                   FAR hts221_settings_t * settings)
+{
+  int ret = OK;
+  uint8_t regval = 0;
+  uint8_t addr = HTS221_CTRL_REG1;
+  const uint8_t mask = 0x87;
+  uint8_t data_to_write[2] = { 0 };
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  hts221_dbg("CTRL_REG1: 0x%02X\n", regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  regval &= ~mask;
+  regval |= (uint8_t) (settings->odr & 0xFF);
+  regval |= (uint8_t) (settings->is_bdu ? HTS221_CTRL_REG1_BDU : 0);
+
+  data_to_write[0] = addr;
+  data_to_write[1] = regval;
+
+  ret = hts221_write_reg8(priv, data_to_write);
+
+  return ret;
+}
+
+static int hts221_power_on_off(FAR struct hts221_dev_s *priv, bool on)
+{
+  int ret = OK;
+  uint8_t regval = 0;
+  uint8_t addr = HTS221_CTRL_REG1;
+  uint8_t data_to_write[2];
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  hts221_dbg("CTRL_REG1: 0x%02X\n", regval);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (on)
+    {
+      regval |= HTS221_CTRL_REG1_PD;
+    }
+  else
+    {
+      regval &= ~HTS221_CTRL_REG1_PD;
+    }
+  data_to_write[0] = addr;
+  data_to_write[1] = regval;
+
+  ret = hts221_write_reg8(priv, data_to_write);
+
+  return ret;
+}
+
+static int hts221_config(FAR struct hts221_dev_s *priv,
+                         FAR hts221_settings_t * cfgr)
+{
+  int ret = OK;
+
+  ret = hts221_cfgr_resolution(priv, cfgr);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_config_ctrl_reg3(priv, cfgr);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_config_ctrl_reg2(priv, cfgr);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_config_ctrl_reg1(priv, cfgr);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  return ret;
+}
+
+static int hts221_start_conversion(FAR struct hts221_dev_s *priv)
+{
+  int ret;
+  uint8_t addr = HTS221_CTRL_REG2;
+  uint8_t data_to_write[2];
+
+  ret = hts221_power_on_off(priv, true);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  data_to_write[0] = addr;
+  data_to_write[1] = (uint8_t) HTS221_CTRL_REG2_ONE_SHOT;
+
+  ret = hts221_write_reg8(priv, data_to_write);
+  if (ret < 0)
+    {
+      hts221_dbg("Cannot start conversion\n");
+      ret = ERROR;
+    }
+
+  return ret;
+}
+
+static int hts221_check_status(FAR struct hts221_dev_s *priv,
+                               FAR hts221_status_t * status)
+{
+  int ret = OK;
+  uint8_t addr = HTS221_STATUS_REG;
+  const uint8_t humid_mask = 0x02;
+  const uint8_t temp_mask = 0x01;
+  uint8_t regval = 0;
+
+  ret = hts221_read_reg(priv, &addr, &regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  status->is_humid_ready = ((regval & humid_mask) ? true : false);
+  status->is_temp_ready = ((regval & temp_mask) ? true : false);
+
+  return ret;
+}
+
+static int hts221_read_raw_data(FAR struct hts221_dev_s *priv,
+                                FAR hts221_raw_data_t * data)
+{
+  int ret = OK;
+  uint8_t addr_humid_low = HTS221_HUM_OUT_L;
+  uint8_t addr_humid_high = HTS221_HUM_OUT_H;
+  uint8_t addr_temp_low = HTS221_TEMP_OUT_L;
+  uint8_t addr_temp_high = HTS221_TEMP_OUT_H;
+  uint32_t flags;
+
+  ret = hts221_read_reg(priv, &addr_humid_low, &data->humid_low_bits);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_read_reg(priv, &addr_humid_high, &data->humid_high_bits);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_read_reg(priv, &addr_temp_low, &data->temp_low_bits);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_read_reg(priv, &addr_temp_high, &data->temp_high_bits);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  /* Add low-order bytes to entropy pool. */
+
+  add_sensor_randomness(((uint32_t)data->humid_low_bits << 8) | data->temp_low_bits);
+
+  flags = enter_critical_section();
+  priv->int_pending = false;
+  leave_critical_section(flags);
+
+  hts221_dbg("Humid: 0x%02X, 0x%02X Temper: 0x%02X 0x%02X\n",
+               data->humid_high_bits, data->humid_low_bits,
+               data->temp_high_bits, data->temp_low_bits);
+
+  return ret;
+}
+
+static int hts221_load_calibration_data(FAR struct hts221_dev_s *priv)
+{
+  int ret;
+  uint8_t addr;
+  uint8_t t0_degc_x8   = 0;
+  uint8_t t1_degc_x8   = 0;
+  uint8_t t1_t0_msb    = 0;
+  uint8_t t0_out_lsb   = 0;
+  uint8_t t0_out_msb   = 0;
+  uint8_t t1_out_lsb   = 0;
+  uint8_t t1_out_msb   = 0;
+  uint8_t h0_rh_x2     = 0;
+  uint8_t h1_rh_x2     = 0;
+  uint8_t h0t0_out_lsb = 0;
+  uint8_t h0t0_out_msb = 0;
+  uint8_t h1t0_out_lsb = 0;
+  uint8_t h1t0_out_msb = 0;
+
+  addr = HTS221_CALIB_T0_DEGC_X8;
+  ret = hts221_read_reg(priv, &addr, &t0_degc_x8);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T1_DEGC_X8;
+  ret = hts221_read_reg(priv, &addr, &t1_degc_x8);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T1_T0_MSB;
+  ret = hts221_read_reg(priv, &addr, &t1_t0_msb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T0_OUT_L;
+  ret = hts221_read_reg(priv, &addr, &t0_out_lsb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T0_OUT_H;
+  ret = hts221_read_reg(priv, &addr, &t0_out_msb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T1_OUT_L;
+  ret = hts221_read_reg(priv, &addr, &t1_out_lsb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_T1_OUT_H;
+  ret = hts221_read_reg(priv, &addr, &t1_out_msb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H0_RH_X2;
+  ret = hts221_read_reg(priv, &addr, &h0_rh_x2);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H1_RH_X2;
+  ret = hts221_read_reg(priv, &addr, &h1_rh_x2);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H0T0_OUT_L;
+  ret = hts221_read_reg(priv, &addr, &h0t0_out_lsb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H0T0_OUT_H;
+  ret = hts221_read_reg(priv, &addr, &h0t0_out_msb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H1T0_OUT_L;
+  ret = hts221_read_reg(priv, &addr, &h1t0_out_lsb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  addr = HTS221_CALIB_H1T0_OUT_H;
+  ret = hts221_read_reg(priv, &addr, &h1t0_out_msb);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  priv->calib.t0_x8     = t0_degc_x8 | ((t1_t0_msb & 0x3) << 8);
+  priv->calib.t1_x8     = t1_degc_x8 | ((t1_t0_msb & (0x3 << 2)) << (8 - 2));
+  priv->calib.t0_out    = (uint16_t) (t0_out_lsb | (t0_out_msb << 8));
+  priv->calib.t1_out    = (uint16_t) (t1_out_lsb | (t1_out_msb << 8));
+  priv->calib.h0_x2     = h0_rh_x2;
+  priv->calib.h1_x2     = h1_rh_x2;
+  priv->calib.h0_t0_out = (uint16_t) (h0t0_out_lsb | (h0t0_out_msb << 8));
+  priv->calib.h1_t0_out = (uint16_t) (h1t0_out_lsb | (h1t0_out_msb << 8));
+
+  hts221_dbg("calib.t0_x8: %d\n", priv->calib.t0_x8);
+  hts221_dbg("calib.t1_x8: %d\n", priv->calib.t1_x8);
+  hts221_dbg("calib.t0_out: %d\n", priv->calib.t0_out);
+  hts221_dbg("calib.t1_out: %d\n", priv->calib.t1_out);
+  hts221_dbg("calib.h0_x2: %d\n", priv->calib.h0_x2);
+  hts221_dbg("calib.h1_x2: %d\n", priv->calib.h1_x2);
+  hts221_dbg("calib.h0_t0_out: %d\n", priv->calib.h0_t0_out);
+  hts221_dbg("calib.h1_t0_out: %d\n", priv->calib.h1_t0_out);
+
+  /* As calibration coefficients are unique to each sensor device,
+   * they are a good candidate to be added to entropy pool.
+   */
+
+  up_rngaddentropy(RND_SRC_HW, (uint32_t *)&priv->calib,
+                   sizeof(priv->calib) / sizeof(uint32_t));
+
+  return OK;
+}
+
+static int hts221_calculate_temperature(FAR struct hts221_dev_s *priv,
+                                        FAR int *temperature,
+                                        FAR hts221_raw_data_t *raw_data)
+{
+  int16_t t_out = (raw_data->temp_high_bits << 8) | raw_data->temp_low_bits;
+  int x0 = priv->calib.t0_out;
+  int x1 = priv->calib.t1_out;
+  int y0 = priv->calib.t0_x8;
+  int y1 = priv->calib.t1_x8;
+  int x = t_out;
+  int64_t y;
+  int x1_x0_diff;
+
+  x1_x0_diff = x1 - x0;
+
+  y = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
+  y *= HTS221_TEMPERATURE_PRECISION;
+  y /= x1_x0_diff * 8;
+
+  *temperature = (int)y;
+
+  hts221_dbg("Interpolation data temper: %d\n", *temperature);
+
+  return OK;
+}
+
+static int hts221_calculate_humidity(FAR struct hts221_dev_s *priv,
+                                     FAR unsigned int *humidity,
+                                     FAR hts221_raw_data_t *raw_data)
+{
+  int16_t h_out = (raw_data->humid_high_bits << 8) | raw_data->humid_low_bits;
+  int x0 = priv->calib.h0_t0_out;
+  int x1 = priv->calib.h1_t0_out;
+  int y0 = priv->calib.h0_x2;
+  int y1 = priv->calib.h1_x2;
+  int x = h_out;
+  int64_t y;
+  int x1_x0_diff;
+
+  x1_x0_diff = x1 - x0;
+
+  y = (y0 * x1_x0_diff + (y1 - y0) * (x - x0));
+  y *= HTS221_HUMIDITY_PRECISION;
+  y /= x1_x0_diff * 2;
+
+  *humidity = (int)y;
+
+  hts221_dbg("Interpolation data humidity: %d\n", *humidity);
+
+  return OK;
+}
+
+static int hts221_read_convert_data(FAR struct hts221_dev_s *priv,
+                                    FAR hts221_conv_data_t *data)
+{
+  int ret = OK;
+  hts221_raw_data_t raw_data;
+
+  ret = hts221_read_raw_data(priv, &raw_data);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  ret = hts221_calculate_temperature(priv, &data->temperature, &raw_data);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("Temperature calculated\n");
+
+  ret = hts221_calculate_humidity(priv, &data->humidity, &raw_data);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("Humidity calculated\n");
+  return ret;
+}
+
+#ifdef CONFIG_DEBUG_HTS221
+static int hts221_dump_registers(FAR struct hts221_dev_s *priv)
+{
+  int ret = OK;
+  uint8_t av_addr = HTS221_AV_CONF;
+  uint8_t ctrl_reg1_addr = HTS221_CTRL_REG1;
+  uint8_t ctrl_reg2_addr = HTS221_CTRL_REG2;
+  uint8_t ctrl_reg3_addr = HTS221_CTRL_REG3;
+  uint8_t regval = 0;
+
+  ret = hts221_read_reg(priv, &av_addr, &regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("AV_CONF_REG: 0x%02X\n", regval);
+
+  ret = hts221_read_reg(priv, &ctrl_reg1_addr, &regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("CTRL_REG_1: 0x%02X\n", regval);
+
+  ret = hts221_read_reg(priv, &ctrl_reg2_addr, &regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("CTRL_REG_2: 0x%02X\n", regval);
+
+  ret = hts221_read_reg(priv, &ctrl_reg3_addr, &regval);
+  if (ret < 0)
+    {
+      return ERROR;
+    }
+
+  hts221_dbg("CTRL_REG_3: 0x%02X\n", regval);
+  return ret;
+}
+#endif
+
+static int hts221_open(FAR struct file *filep)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct hts221_dev_s *priv = inode->i_private;
+
+  while (sem_wait(&priv->devsem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  priv->config->set_power(priv->config, true);
+  priv->config->irq_enable(priv->config, true);
+
+  sem_post(&priv->devsem);
+  hts221_dbg("Sensor is powered on\n");
+  return OK;
+}
+
+static int hts221_close(FAR struct file *filep)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct hts221_dev_s *priv = inode->i_private;
+  int ret = OK;
+
+  while (sem_wait(&priv->devsem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  priv->config->irq_enable(priv->config, false);
+  ret = hts221_power_on_off(priv, false);
+  priv->config->set_power(priv->config, false);
+
+  sem_post(&priv->devsem);
+  hts221_dbg("CLOSED\n");
+  return ret;
+}
+
+static ssize_t hts221_read(FAR struct file *filep, FAR char *buffer,
+                           size_t buflen)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct hts221_dev_s *priv = inode->i_private;
+  int ret = OK;
+  ssize_t length = 0;
+  hts221_conv_data_t data;
+
+  while (sem_wait(&priv->devsem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  ret = hts221_read_convert_data(priv, &data);
+  if (ret < 0)
+    {
+      hts221_dbg("cannot read data: %d\n", ret);
+    }
+  else
+    {
+      /* This interface is mainly intended for easy debugging in nsh. */
+
+      length = snprintf(buffer, buflen, "%d %u\n",
+                        data.temperature, data.humidity);
+      if (length > buflen)
+        {
+          length = buflen;
+        }
+    }
+
+  sem_post(&priv->devsem);
+  return length;
+}
+
+static ssize_t hts221_write(FAR struct file *filep, FAR const char *buffer,
+                            size_t buflen)
+{
+  ssize_t length = 0;
+  return length;
+}
+
+static int hts221_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+  FAR struct inode *inode = filep->f_inode;
+  FAR struct hts221_dev_s *priv = inode->i_private;
+  int32_t ret = 0;
+
+  while (sem_wait(&priv->devsem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  switch (cmd)
+    {
+    case SNIOC_GET_DEV_ID:
+      ret = hts221_get_id(priv, (FAR uint8_t *) arg);
+      break;
+
+    case SNIOC_CFGR:
+      ret = hts221_config(priv, (FAR hts221_settings_t *) arg);
+      break;
+
+    case SNIOC_START_CONVERSION:
+      ret = hts221_start_conversion(priv);
+      break;
+
+    case SNIOC_CHECK_STATUS_REG:
+      ret = hts221_check_status(priv, (FAR hts221_status_t *) arg);
+      break;
+
+    case SNIOC_READ_RAW_DATA:
+      ret = hts221_read_raw_data(priv, (FAR hts221_raw_data_t *) arg);
+      break;
+
+#ifdef CONFIG_DEBUG_HTS221
+    case SNIOC_DUMP_REGS:
+      ret = hts221_dump_registers(priv);
+      break;
+#endif
+
+    case SNIOC_READ_CONVERT_DATA:
+      ret = hts221_read_convert_data(priv, (FAR hts221_conv_data_t *) arg);
+      break;
+
+    default:
+      ret = -EINVAL;
+      break;
+    }
+
+  sem_post(&priv->devsem);
+  return ret;
+}
+
+#ifndef CONFIG_DISABLE_POLL
+static bool hts221_sample(FAR struct hts221_dev_s *priv)
+{
+  int ret;
+  hts221_status_t status =
+  {
+    .is_humid_ready = false,
+    .is_temp_ready = false
+  };
+
+  ret = hts221_check_status(priv, &status);
+  if (ret < 0)
+  {
+    return false;
+  }
+
+  return status.is_humid_ready || status.is_temp_ready;
+}
+
+static void hts221_notify(FAR struct hts221_dev_s *priv)
+{
+  DEBUGASSERT(priv != NULL);
+
+  int i;
+
+  /* If there are threads waiting on poll() for data to become available,
+   * then wake them up now.  NOTE: we wake up all waiting threads because we
+   * do not know that they are going to do.  If they all try to read the data,
+   * then some make end up blocking after all.
+   */
+
+  for (i = 0; i < CONFIG_HTS221_NPOLLWAITERS; i++)
+    {
+      FAR struct pollfd *fds = priv->fds[i];
+      if (fds)
+        {
+          fds->revents |= POLLIN;
+          hts221_dbg("Report events: %02x\n", fds->revents);
+          sem_post(fds->sem);
+        }
+    }
+}
+
+static int hts221_poll(FAR struct file *filep, FAR struct pollfd *fds,
+                       bool setup)
+{
+  FAR struct inode *inode;
+  FAR struct hts221_dev_s *priv;
+  int ret = OK;
+  int i;
+  uint32_t flags;
+
+  DEBUGASSERT(filep && fds);
+  inode = filep->f_inode;
+
+  DEBUGASSERT(inode && inode->i_private);
+  priv = (FAR struct hts221_dev_s *)inode->i_private;
+
+  while (sem_wait(&priv->devsem) != 0)
+    {
+      assert(errno == EINTR);
+    }
+
+  if (setup)
+    {
+      /* Ignore waits that do not include POLLIN */
+
+      if ((fds->events & POLLIN) == 0)
+        {
+          ret = -EDEADLK;
+          goto out;
+        }
+
+      /* This is a request to set up the poll.  Find an available slot for
+       * the poll structure reference.
+       */
+
+      for (i = 0; i < CONFIG_HTS221_NPOLLWAITERS; i++)
+        {
+          /* Find an available slot */
+
+          if (!priv->fds[i])
+            {
+              /* Bind the poll structure and this slot */
+
+              priv->fds[i] = fds;
+              fds->priv = &priv->fds[i];
+              break;
+            }
+        }
+
+      if (i >= CONFIG_HTS221_NPOLLWAITERS)
+        {
+          fds->priv = NULL;
+          ret = -EBUSY;
+          goto out;
+        }
+
+      flags = enter_critical_section();
+      if (priv->int_pending || hts221_sample(priv))
+        {
+          hts221_notify(priv);
+        }
+
+      leave_critical_section(flags);
+    }
+  else if (fds->priv)
+    {
+      /* This is a request to tear down the poll. */
+
+      struct pollfd **slot = (struct pollfd **)fds->priv;
+      DEBUGASSERT(slot != NULL);
+
+      /* Remove all memory of the poll setup */
+
+      *slot = NULL;
+      fds->priv = NULL;
+    }
+
+out:
+  sem_post(&priv->devsem);
+  return ret;
+}
+#endif /* !CONFIG_DISABLE_POLL */
+
+static int hts221_int_handler(int irq, FAR void *context, FAR void *arg)
+{
+  if (!g_humid_data)
+    return OK;
+
+  g_humid_data->int_pending = true;
+  hts221_dbg("Hts221 interrupt\n");
+#ifndef CONFIG_DISABLE_POLL
+  hts221_notify(g_humid_data);
+#endif
+
+  return OK;
+}
+
+int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+                    uint8_t addr, FAR hts221_config_t *config)
+{
+  int ret = 0;
+  FAR struct hts221_dev_s *priv;
+
+  priv = (struct hts221_dev_s *)kmm_zalloc(sizeof(struct hts221_dev_s));
+
+  if (!priv)
+    {
+      hts221_dbg("Memory cannot be allocated for hts221 sensor");
+      return -ENOMEM;
+    }
+
+  g_humid_data = priv;
+  priv->addr   = addr;
+  priv->i2c    = i2c;
+  priv->config = config;
+  sem_init(&priv->devsem, 0, 1);
+
+  ret = hts221_load_calibration_data(priv);
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      hts221_dbg("Cannot calibrate hts221 sensor\n");
+      return -EAGAIN;
+    }
+
+  ret = register_driver(devpath, &g_humidityops, 0666, priv);
+
+  hts221_dbg("Registered with %d\n", ret);
+
+  if (ret < 0)
+    {
+      kmm_free(priv);
+      hts221_dbg("Error occurred during the driver registering\n");
+      return ret;
+    }
+
+  if (priv->config->irq_clear)
+    {
+      priv->config->irq_clear(priv->config);
+    }
+
+  priv->config->irq_attach(priv->config, hts221_int_handler);
+  priv->config->irq_enable(priv->config, false);
+  return OK;
+}
diff --git a/include/nuttx/random.h b/include/nuttx/random.h
index d3413e62fb..4017837071 100644
--- a/include/nuttx/random.h
+++ b/include/nuttx/random.h
@@ -65,7 +65,7 @@
 
 #ifndef CONFIG_CRYPTO_RANDOM_POOL
 #  define up_rngaddint(k, x)            ((void)(k),(void)(x))
-#  define up_rngaddentropy(k, buf, n)   ((void)(k),(void)(buf),(void)(x))
+#  define up_rngaddentropy(k, buf, x)   ((void)(k),(void)(buf),(void)(x))
 #endif
 
 /****************************************************************************
diff --git a/include/nuttx/sensors/hts221.h b/include/nuttx/sensors/hts221.h
new file mode 100644
index 0000000000..47142c3f82
--- /dev/null
+++ b/include/nuttx/sensors/hts221.h
@@ -0,0 +1,158 @@
+/****************************************************************************
+ * include/nuttx/sensors/hts221.h
+ *
+ *   Copyright (C) 2014 Haltian Ltd. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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 __INCLUDE_NUTT_SENSORS_HTS221_H
+#define __INCLUDE_NUTT_SENSORS_HTS221_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/sensors/ioctl.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define HTS221_TEMPERATURE_PRECISION  100
+#define HTS221_HUMIDITY_PRECISION     10
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Number of temperature samples */
+
+typedef enum hts221_avrg_temp_e
+{
+  HTS221_AVGT2 = 0,
+  HTS221_AVGT4,
+  HTS221_AVGT8,
+  HTS221_AVGT16,              /* Default value */
+  HTS221_AVGT32,
+  HTS221_AVGT64,
+  HTS221_AVGT128,
+  HTS221_AVGT256
+} hts221_avrg_temp_t;
+
+/* Number of humidity samples */
+
+typedef enum hts221_avrg_humid_e
+{
+  HTS221_AVGH4 = 0,
+  HTS221_AVGH8,
+  HTS221_AVGH16,
+  HTS221_AVGH32,              /* Default value */
+  HTS221_AVGH64,
+  HTS221_AVGH128,
+  HTS221_AVGH256,
+  HTS221_AVGH512
+}hts221_avrg_humid_t;
+
+/* Output data rate configuration */
+
+typedef enum hts221_odr_e
+{
+  HTS221_ODR_ONESHOT = 0,
+  HTS221_ODR_1HZ,
+  HTS221_ODR_7HZ,
+  HTS221_ODR_12_5HZ
+} hts221_odr_t;
+
+/* Configuration structure */
+
+typedef struct hts221_settings_s
+{
+  hts221_avrg_temp_t temp_resol;      /* Temperature resolution. The more
+                                       * samples sensor takes, the more power
+                                       * it uses */
+  hts221_avrg_humid_t humid_resol;    /* Humidity resolution. The more
+                                       * samples sensor takes, the more power
+                                       * it uses */
+  hts221_odr_t odr;           /* Output data rate */
+  bool is_bdu;                /* If read operation is not faster than output
+                               * operation, then this variable must be set to true */
+  bool is_data_rdy;           /* Must be set to true, if interrupt needed.
+                               * Default is 0, disabled */
+  bool is_high_edge;          /* High or low interrupt signal from device.
+                               * Default is high, 0 */
+  bool is_open_drain;         /* Open drain or push-pull on data-ready pin.
+                               * Default is push-pull, 0 */
+  bool is_boot;               /* Refresh the content of the internal registers */
+} hts221_settings_t;
+
+/* Interrupt configuration data structure */
+
+typedef struct hts221_config_s
+{
+  int irq;
+  CODE int  (*irq_attach)(FAR struct hts221_config_s * state, xcpt_t isr);
+  CODE void (*irq_enable)(FAR const struct hts221_config_s * state,
+                          bool enable);
+  CODE void (*irq_clear)(FAR const struct hts221_config_s * state);
+  CODE int  (*set_power)(FAR const struct hts221_config_s *state, bool on);
+} hts221_config_t;
+
+/* Raw data structure */
+
+typedef struct hts221_raw_data_s
+{
+  uint8_t humid_low_bits;
+  uint8_t humid_high_bits;
+  uint8_t temp_low_bits;
+  uint8_t temp_high_bits;
+} hts221_raw_data_t;
+
+typedef struct hts221_conv_data_s
+{
+  int temperature;
+  unsigned int humidity;
+} hts221_conv_data_t;
+
+/* Status register data */
+
+typedef struct hts221_status_s
+{
+  bool is_humid_ready;
+  bool is_temp_ready;
+} hts221_status_t;
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+int hts221_register(FAR const char *devpath, FAR struct i2c_master_s *i2c,
+                    uint8_t addr, hts221_config_t * config);
+
+#endif /* __INCLUDE_NUTT_SENSORS_HTS221_H */
diff --git a/include/nuttx/sensors/ioctl.h b/include/nuttx/sensors/ioctl.h
index acbf31d810..231c205601 100644
--- a/include/nuttx/sensors/ioctl.h
+++ b/include/nuttx/sensors/ioctl.h
@@ -115,4 +115,14 @@
 #define SNIOC_RESET         _SNIOC(0x0028) /* Arg: None */
 #define SNIOC_OVERSAMPLING  _SNIOC(0x0029) /* Arg: uint16_t value */
 
+/* IOCTL commands unique to the HTS221 */
+
+#define SNIOC_GET_DEV_ID        _SNIOC(0x002a)
+#define SNIOC_CFGR              _SNIOC(0x002b)
+#define SNIOC_START_CONVERSION  _SNIOC(0x002c)
+#define SNIOC_CHECK_STATUS_REG  _SNIOC(0x002d)
+#define SNIOC_READ_RAW_DATA     _SNIOC(0x002e)
+#define SNIOC_READ_CONVERT_DATA _SNIOC(0x002f)
+#define SNIOC_DUMP_REGS         _SNIOC(0x0030)
+
 #endif /* __INCLUDE_NUTTX_SENSORS_IOCTL_H */

From 7b789f57ac507f6a20cd507cc453f6c60a626cd4 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 30 Mar 2017 12:28:40 -0600
Subject: [PATCH 09/12] Review of previous commit

---
 arch/arm/src/stm32/Kconfig          |   4 -
 arch/arm/src/stm32/stm32_tickless.c | 114 ++++++++++++++++------------
 2 files changed, 66 insertions(+), 52 deletions(-)

diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig
index 5ae19c927a..6927a3c054 100644
--- a/arch/arm/src/stm32/Kconfig
+++ b/arch/arm/src/stm32/Kconfig
@@ -2829,8 +2829,6 @@ config STM32_TICKLESS_CHANNEL
 
 endif # SCHED_TICKLESS
 
-if !SCHED_TICKLESS
-
 config STM32_ONESHOT
 	bool "TIM one-shot wrapper"
 	default n
@@ -2845,8 +2843,6 @@ config STM32_FREERUN
 		Enable a wrapper around the low level timer/counter functions to
 		support a free-running timer.
 
-endif # !SCHED_TICKLESS
-
 config STM32_ONESHOT_MAXTIMERS
 	int "Maximum number of oneshot timers"
 	default 1
diff --git a/arch/arm/src/stm32/stm32_tickless.c b/arch/arm/src/stm32/stm32_tickless.c
index f0baa5edee..38162ad7d7 100644
--- a/arch/arm/src/stm32/stm32_tickless.c
+++ b/arch/arm/src/stm32/stm32_tickless.c
@@ -161,7 +161,8 @@ static inline void stm32_putreg16(uint8_t offset, uint16_t value)
  *
  ************************************************************************************/
 
-static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits, uint16_t setbits)
+static inline void stm32_modifyreg16(uint8_t offset, uint16_t clearbits,
+                                     uint16_t setbits)
 {
   modifyreg16(g_tickless.base + offset, clearbits, setbits);
 }
@@ -236,14 +237,17 @@ static int stm32_tickless_setchannel(uint8_t channel)
       || g_tickless.base == STM32_TIM7_BASE
 #endif
 #if STM32_NBTIM > 0
-  )
+     )
     {
       return -EINVAL;
     }
 #endif
 
-  /* frozen mode because we don't want to change the gpio, preload register disabled */
-  ccmr_val  =  (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
+  /* Frozen mode because we don't want to change the GPIO, preload register
+   * disabled.
+   */
+
+  ccmr_val = (ATIM_CCMR_MODE_FRZN << ATIM_CCMR1_OC1M_SHIFT);
         
   /* Set polarity */
 
@@ -251,7 +255,7 @@ static int stm32_tickless_setchannel(uint8_t channel)
 
   /* Define its position (shift) and get register offset */
 
-  if (channel & 1)
+  if ((channel & 1) != 0)
     {
       ccmr_val  <<= 8;
       ccmr_mask <<= 8;
@@ -293,7 +297,7 @@ static void stm32_interval_handler(void)
 {
   tmrinfo("Expired...\n");
 
-   /* Disable the compare interrupt now. */
+  /* Disable the compare interrupt now. */
 
   stm32_tickless_disableint(g_tickless.channel);
   stm32_tickless_ackint(g_tickless.channel);
@@ -303,7 +307,6 @@ static void stm32_interval_handler(void)
   sched_timer_expiration();
 }
 
-
 /****************************************************************************
  * Name: stm32_timing_handler
  *
@@ -328,7 +331,6 @@ static void stm32_timing_handler(void)
 }
 #endif /* CONFIG_CLOCK_TIMEKEEPING */
 
-
 /****************************************************************************
  * Name: stm32_tickless_handler
  *
@@ -350,11 +352,15 @@ static int stm32_tickless_handler(int irq, void *context, void *arg)
 
 #ifndef CONFIG_CLOCK_TIMEKEEPING
   if (interrupt_flags & ATIM_SR_UIF)
-    stm32_timing_handler();
+    {
+      stm32_timing_handler();
+    }
 #endif /* CONFIG_CLOCK_TIMEKEEPING */
 
   if (interrupt_flags & (1 << g_tickless.channel))
-    stm32_interval_handler();
+    {
+      stm32_interval_handler();
+    }
 
   return OK;
 }
@@ -395,98 +401,108 @@ void arm_timer_initialize(void)
 #ifdef CONFIG_STM32_TIM1
       case 1:
         g_tickless.base = STM32_TIM1_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM2
       case 2:
         g_tickless.base = STM32_TIM2_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM3
       case 3:
         g_tickless.base = STM32_TIM3_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM4
       case 4:
         g_tickless.base = STM32_TIM4_BASE;
-	break;
+        break;
 #endif
 #ifdef CONFIG_STM32_TIM5
       case 5:
         g_tickless.base = STM32_TIM5_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM6
       case 6:
 
-	/* Basic timers not supported by this implementation */
+        /* Basic timers not supported by this implementation */
 
         ASSERT(0);
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM7
       case 7:
 
-	/* Basic timers not supported by this implementation */
+        /* Basic timers not supported by this implementation */
 
         ASSERT(0);
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM8
       case 8:
         g_tickless.base = STM32_TIM8_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM9
       case 9:
         g_tickless.base = STM32_TIM9_BASE;
-	break;
+        break;
 #endif
 #ifdef CONFIG_STM32_TIM10
       case 10:
         g_tickless.base = STM32_TIM10_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM11
       case 11:
         g_tickless.base = STM32_TIM11_BASE;
-	break;
+        break;
 #endif
 #ifdef CONFIG_STM32_TIM12
       case 12:
         g_tickless.base = STM32_TIM12_BASE;
-	break;
+        break;
 #endif
 #ifdef CONFIG_STM32_TIM13
       case 13:
         g_tickless.base = STM32_TIM13_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM14
       case 14:
         g_tickless.base = STM32_TIM14_BASE;
-	break;
+        break;
 #endif
 #ifdef CONFIG_STM32_TIM15
       case 15:
         g_tickless.base = STM32_TIM15_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM16
       case 16:
         g_tickless.base = STM32_TIM16_BASE;
-	break;
+        break;
 #endif
+
 #ifdef CONFIG_STM32_TIM17
       case 17:
         g_tickless.base = STM32_TIM17_BASE;
-	break;
+        break;
 #endif
 
       default:
         ASSERT(0);
-
     }
 
   /* Get the TC frequency that corresponds to the requested resolution */
@@ -749,6 +765,7 @@ int up_timer_cancel(FAR struct timespec *ts)
           ts->tv_sec  = 0;
           ts->tv_nsec = 0;
         }
+
       leave_critical_section(flags);
       return OK;
     }
@@ -773,7 +790,7 @@ int up_timer_cancel(FAR struct timespec *ts)
    * remaining?
    */
 
-  if (ts)
+  if (ts != NULL)
     {
       /* Yes.. then calculate and return the time remaining on the
        * oneshot timer.
@@ -786,7 +803,7 @@ int up_timer_cancel(FAR struct timespec *ts)
         {
           /* Handle rollover */
 
-	  period += UINT16_MAX;
+          period += UINT16_MAX;
         }
       else if (count == period)
         {
@@ -794,27 +811,27 @@ int up_timer_cancel(FAR struct timespec *ts)
 
           ts->tv_sec  = 0;
           ts->tv_nsec = 0;
-	  return OK;
+          return OK;
         }
 
-        /* The total time remaining is the difference.  Convert that
-         * to units of microseconds.
-         *
-         *   frequency = ticks / second
-         *   seconds   = ticks * frequency
-         *   usecs     = (ticks * USEC_PER_SEC) / frequency;
-         */
+      /* The total time remaining is the difference.  Convert that
+       * to units of microseconds.
+       *
+       *   frequency = ticks / second
+       *   seconds   = ticks * frequency
+       *   usecs     = (ticks * USEC_PER_SEC) / frequency;
+       */
 
-        usec        = (((uint64_t)(period - count)) * USEC_PER_SEC) /
-                      g_tickless.frequency;
+      usec        = (((uint64_t)(period - count)) * USEC_PER_SEC) /
+                    g_tickless.frequency;
 
-        /* Return the time remaining in the correct form */
+      /* Return the time remaining in the correct form */
 
-        sec         = usec / USEC_PER_SEC;
-        nsec        = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
+      sec         = usec / USEC_PER_SEC;
+      nsec        = ((usec) - (sec * USEC_PER_SEC)) * NSEC_PER_USEC;
 
-        ts->tv_sec  = (time_t)sec;
-        ts->tv_nsec = (unsigned long)nsec;
+      ts->tv_sec  = (time_t)sec;
+      ts->tv_nsec = (unsigned long)nsec;
 
       tmrinfo("remaining (%lu, %lu)\n",
              (unsigned long)ts->tv_sec, (unsigned long)ts->tv_nsec);
@@ -897,7 +914,8 @@ int up_timer_start(FAR const struct timespec *ts)
 
   g_tickless.period = (uint16_t)(period + count);
  
-  STM32_TIM_SETCOMPARE(g_tickless.tch, g_tickless.channel, g_tickless.period);
+  STM32_TIM_SETCOMPARE(g_tickless.tch, g_tickless.channel,
+                       g_tickless.period);
 
   /* Enable interrupts.  We should get the callback when the interrupt
    * occurs.

From c3289afa9c8d0d73ab23343403da3d231415c21c Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 30 Mar 2017 12:29:19 -0600
Subject: [PATCH 10/12] Fix error in last update to a README

---
 configs/samv71-xult/README.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/configs/samv71-xult/README.txt b/configs/samv71-xult/README.txt
index 9022351033..c963851259 100644
--- a/configs/samv71-xult/README.txt
+++ b/configs/samv71-xult/README.txt
@@ -752,7 +752,7 @@ Selecting the GMAC peripheral
 SAMV71 Versions
 ---------------
 
-WARNING: "The newer SAMV71 have 6 GMAC queues, not 5. All queues must be
+WARNING: The newer SAMV71 have 6 GMAC queues, not 3. All queues must be
 configured for the GMAC to work correctly, even the queues that you are not
 using (you can just configure these queues with a very small ring buffer.)
 
@@ -760,7 +760,7 @@ The older uses the Cortex-M7 core r0p1 and the newer r1p1 revisions.  The
 SAMV71 revisions are called "rev A" (or sometimes "MRLA") and "rev B"
 ("MRLB"). There should be a small "A" or "B" on the chip package just below
 the reference and you can also differentiate them at runtime with the
-VERSION field in the CHIPID CIDR register."
+VERSION field in the CHIPID CIDR register.
 
 Cache-Related Issues
 --------------------

From 2aca4d4ebd4a78a08c6bfbb85ab4aa21de42913e Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 30 Mar 2017 15:38:56 -0600
Subject: [PATCH 11/12] 6loWPAN:  Add a little more send logic.

---
 include/nuttx/net/sixlowpan.h      |  53 ++-
 net/sixlowpan/Kconfig              |   6 +-
 net/sixlowpan/Make.defs            |   2 +-
 net/sixlowpan/sixlowpan_framer.c   | 606 +++++++++++++++++++++++++++++
 net/sixlowpan/sixlowpan_hc06.c     |   3 +-
 net/sixlowpan/sixlowpan_internal.h | 222 +++++++++--
 net/sixlowpan/sixlowpan_send.c     | 199 ++++++++--
 net/sixlowpan/sixlowpan_utils.c    |  32 +-
 8 files changed, 1061 insertions(+), 62 deletions(-)
 create mode 100644 net/sixlowpan/sixlowpan_framer.c

diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h
index 376fbf2d9c..0d403d25bb 100644
--- a/include/nuttx/net/sixlowpan.h
+++ b/include/nuttx/net/sixlowpan.h
@@ -323,6 +323,27 @@ struct rimeaddr_s
  * manage the fragmentation.  'struct ieee802154_driver_s' is cast
  * compatible with 'struct net_driver_s' when CONFIG_NET_MULTINIC is not
  * defined or when dev->d_lltype == NET_LL_IEEE802154.
+ *
+ * The IEEE802.15.4 MAC network driver has reponsibility for initializing
+ * this structure.  In general, all fields must be set to NULL.  In
+ * addtion:
+ *
+ * 1) i_panid must be set to identify the network.  It may be set to 0xfff
+ *    if the device is not associated.
+ * 2) i_dsn must be set to a random value.  After that, it will be managed
+ *    by the network.
+ * 3) i_nodeaddr must be set after the MAC is assigned an address.
+ *
+ * Frame Organization:
+ *
+ *     Content          Offset
+ *   +----------------+ 0
+ *   | Frame Header   |
+ *   +----------------+ i_dataoffset
+ *   | Data           |
+ *   +----------------+ i_framelen
+ *   | Unused         |
+ *   +----------------+ CONFIG_NET_6LOWPAN_FRAMELEN
  */
 
 struct ieee802154_driver_s
@@ -344,7 +365,8 @@ struct ieee802154_driver_s
    * requesting new framesusing break-off fram buffers.  That frame buffer
    * management must be controlled by the IEEE802.15.4 MAC driver.
    *
-   * Driver provied frame buffers should be 16-bit aligned.
+   * Driver provided frame buffers should of size CONFIG_NET_6LOWPAN_FRAMELEN
+   * and should be 16-bit aligned.
    */
 
   FAR uint8_t *i_frame;
@@ -360,6 +382,31 @@ struct ieee802154_driver_s
 
   uint16_t i_framelen;
 
+  /* i_panid.  The PAN ID is 16-bit number that identifies the network. It
+   * must be unique to differentiate a network. All the nodes in the same
+   * network should have the same PAN ID.  This value must be provided to
+   * the network from the IEEE802.15.4 MAC driver.
+   *
+   * If this value is 0xffff, the device is not associated.
+   */
+
+  uint16_t i_panid;
+
+  /* i_node_addr.  The address assigned to this node. */
+
+  struct rimeaddr_s i_nodeaddr;
+
+  /* i_dsn.  The sequence number in the range 0x00-0xff added to the
+   * transmitted data or MAC command frame. The default is a random value
+   * within that range.
+   *
+   * This field must be initialized to a random number by the IEEE802.15.4
+   * MAC driver.  It sill be subsequently incremented on each frame by the
+   * network logic.
+   */
+
+  uint8_t i_dsn;
+
   /* The following fields are device-specific metadata used by the 6loWPAN
    * stack and should not be modified by the IEEE802.15.4 MAC network drvier.
    */
@@ -385,9 +432,9 @@ struct ieee802154_driver_s
 
   uint8_t i_rime_hdrlen;
 
-  /* Next available pointer into header */
+  /* Offset first available byte for the payload after header region. */
 
-  uint8_t i_hdrptr;
+  uint8_t i_dataoffset;
 
   /* Packet buffer metadata: Attributes and addresses */
 
diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig
index 7031f21e62..bbbdeb1b13 100644
--- a/net/sixlowpan/Kconfig
+++ b/net/sixlowpan/Kconfig
@@ -136,7 +136,7 @@ config NET_6LOWPAN_RIMEADDR_SIZE
 	---help---
 		Only the values 2 and 8 are supported
 
-config NET_SIXLOWPAN_MAXAGE
+config NET_6LOWPAN_MAXAGE
 	int "Packet reassembly timeout"
 	default 20
 	---help---
@@ -150,11 +150,11 @@ config NET_6LOWPAN_MAX_MACTRANSMITS
 		layer should resend packets if no link-layer ACK wasreceived. This
 		only makes sense with the csma_driver.
 
-config NET_SIXLOWPAN_MAXPAYLOAD
+config NET_6LOWPAN_MAXPAYLOAD
 	int "Max packet size"
 	default 102
 	---help---
-		CONFIG_NET_SIXLOWPAN_MAXPAYLOAD specifies the maximum size of packets
+		NET_6LOWPAN_MAXPAYLOAD specifies the maximum size of packets
 		before they get fragmented. The default is 127 bytes (the maximum size
 		of a 802.15.4 frame) - 25 bytes (for the 802.15.4 MAClayer header). This
 		can be increased for systems with larger packet sizes.
diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs
index 68b1ec5ef9..e0370185e6 100644
--- a/net/sixlowpan/Make.defs
+++ b/net/sixlowpan/Make.defs
@@ -40,7 +40,7 @@ ifeq ($(CONFIG_NET_6LOWPAN),y)
 # Include IEEE 802.15.4 file in the build
 
 NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c
-NET_CSRCS += sixlowpan_input.c sixlowpan_send.c
+NET_CSRCS += sixlowpan_input.c sixlowpan_send.c sixlowpan_framer.c
 NET_CSRCS += sixlowpan_compressor.c
 
 ifeq ($(CONFIG_NET_TCP),y)
diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c
new file mode 100644
index 0000000000..611e204a9f
--- /dev/null
+++ b/net/sixlowpan/sixlowpan_framer.c
@@ -0,0 +1,606 @@
+/****************************************************************************
+ * net/sixlowpan/sixlowpan_framer.c
+ *
+ *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
+ *   Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * Derives from Contiki:
+ *
+ *   Copyright (c) 2008, Swedish Institute of Computer Science.
+ *   All rights reserved.
+ *   Authors: Adam Dunkels <adam@sics.se>
+ *            Nicolas Tsiftes <nvt@sics.se>
+ *            Niclas Finne <nfi@sics.se>
+ *            Mathilde Durvy <mdurvy@cisco.com>
+ *            Julien Abeille <jabeille@cisco.com>
+ *            Joakim Eriksson <joakime@sics.se>
+ *            Joel Hoglund <joel@sics.se>
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdbool.h>
+#include <string.h>
+#include <assert.h>
+#include <debug.h>
+
+#include "nuttx/net/net.h"
+#include "nuttx/net/sixlowpan.h"
+
+#include "sixlowpan/sixlowpan_internal.h"
+
+#ifdef CONFIG_NET_6LOWPAN
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Structure that contains the lengths of the various addressing and
+ * security fields in the 802.15.4 header.
+ */
+
+struct field_length_s
+{
+  uint8_t dest_pid_len;    /**<  Length (in bytes) of destination PAN ID field */
+  uint8_t dest_addr_len;   /**<  Length (in bytes) of destination address field */
+  uint8_t src_pid_len;     /**<  Length (in bytes) of source PAN ID field */
+  uint8_t src_addr_len;    /**<  Length (in bytes) of source address field */
+  uint8_t aux_sec_len;     /**<  Length (in bytes) of aux security header field */
+};
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: sixlowpan_addrlen
+ *
+ * Description:
+ *   Return the address length associated with a 2-bit address mode
+ *
+ * Input parameters:
+ *   addrmode - The address mode
+ *
+ * Returned Value:
+ *   The address length associated with the address mode.
+ *
+ ****************************************************************************/
+
+static inline uint8_t sixlowpan_addrlen(uint8_t addrmode)
+{
+  switch (addrmode)
+    {
+    case FRAME802154_SHORTADDRMODE:  /* 16-bit address */
+      return 2;
+    case FRAME802154_LONGADDRMODE:   /* 64-bit address */
+      return 8;
+    default:
+      return 0;
+    }
+}
+
+/****************************************************************************
+ * Function: sixlowpan_isbroadcast
+ *
+ * Description:
+ *   Return the address length associated with a 2-bit address mode
+ *
+ * Input parameters:
+ *   addrmode - The address mode
+ *
+ * Returned Value:
+ *   The address length associated with the address mode.
+ *
+ ****************************************************************************/
+
+static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr)
+{
+  int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
+
+  while (i-- > 0)
+    {
+      if (addr[i] != 0xff)
+        {
+          return false;
+        }
+    }
+
+  return true;
+}
+
+/****************************************************************************
+ * Function: sixlowpan_addrnull
+ *
+ * Description:
+ *   If the output address is NULL in the Rime buf, then it is broadcast
+ *   on the 802.15.4 network.
+ *
+ * Input parameters:
+ *   addrmode - The address mode
+ *
+ * Returned Value:
+ *   The address length associated with the address mode.
+ *
+ ****************************************************************************/
+
+static bool sixlowpan_addrnull(FAR uint8_t *addr)
+{
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+  int i = 2;
+#else
+  int i = 8;
+#endif
+
+  while (i-- > 0)
+    {
+      if (addr[i] != 0x00)
+        {
+          return false;
+        }
+    }
+
+  return true;
+}
+
+
+/****************************************************************************
+ * Function: sixlowpan_fieldlengths
+ *
+ * Description:
+ *   Return the lengths associated fields of the IEEE802.15.4 header.
+ *
+ * Input parameters:
+ *   finfo - IEEE802.15.4 header info (input)
+ *   flen  - Field length info (output)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void sixlowpan_fieldlengths(FAR struct frame802154_s *finfo,
+                                   FAR struct field_length_s *flen)
+{
+  /* Initialize to all zero */
+
+  memset(flen, 0, sizeof(struct field_length_s));
+
+  /* Determine lengths of each field based on fcf and other args */
+
+  if ((finfo->fcf.dest_addr_mode & 3) != 0)
+    {
+      flen->dest_pid_len = 2;
+    }
+
+  if ((finfo->fcf.src_addr_mode & 3) != 0)
+    {
+      flen->src_pid_len = 2;
+    }
+
+  /* Set PAN ID compression bit if src pan id matches dest pan id. */
+
+  if ((finfo->fcf.dest_addr_mode & 3) != 0 &&
+      (finfo->fcf.src_addr_mode & 3) != 0 &&
+      finfo->src_pid == finfo->dest_pid)
+    {
+      finfo->fcf.panid_compression = 1;
+
+      /* Compressed header, only do dest pid */
+      /* flen->src_pid_len = 0; */
+    }
+
+  /* Determine address lengths */
+
+  flen->dest_addr_len = sixlowpan_addrlen(finfo->fcf.dest_addr_mode & 3);
+  flen->src_addr_len  = sixlowpan_addrlen(finfo->fcf.src_addr_mode & 3);
+
+  /* Aux security header */
+
+#if 0 /* TODO Aux security header not yet implemented */
+  if ((finfo->fcf.security_enabled & 1) != 0)
+    {
+      switch(finfo->aux_hdr.security_control.key_id_mode)
+        {
+        case 0:
+          flen->aux_sec_len = 5; /* Minimum value */
+          break;
+
+        case 1:
+          flen->aux_sec_len = 6;
+          break;
+
+        case 2:
+          flen->aux_sec_len = 10;
+          break;
+
+        case 3:
+          flen->aux_sec_len = 14;
+          break;
+
+        default:
+          break;
+        }
+    }
+#endif
+}
+
+/****************************************************************************
+ * Function: sixlowpan_fieldlengths
+ *
+ * Description:
+ *   Return the lengths associated fields of the IEEE802.15.4 header.
+ *
+ * Input parameters:
+ *   finfo - IEEE802.15.4 header info (input)
+ *   flen  - Field length info (output)
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int sixlowpan_flen_hdrlen(FAR const struct field_length_s *flen)
+{
+  return 3 + flen->dest_pid_len + flen->dest_addr_len +
+         flen->src_pid_len + flen->src_addr_len + flen->aux_sec_len;
+}
+
+/****************************************************************************
+ * Function: sixlowpan_802154_hdrlen
+ *
+ * Description:
+ *   Calculates the length of the frame header.  This function is meant to
+ *   be called by a higher level function, that interfaces to a MAC.
+ *
+ * Input parameters:
+ *   finfo - IEEE802.15.4 header info that specifies the frame to send.
+ *
+ * Returned Value:
+ *   The length of the frame header.
+ *
+ ****************************************************************************/
+
+static int sixlowpan_802154_hdrlen(FAR struct frame802154_s *finfo)
+{
+  struct field_length_s flen;
+
+  sixlowpan_fieldlengths(finfo, &flen);
+  return sixlowpan_flen_hdrlen(&flen);
+}
+
+/****************************************************************************
+ * Function: sixlowpan_setup_params
+ *
+ * Description:
+ *   Configure frame parmeters structure.
+ *
+ * Input parameters:
+ *   ieee       - A reference IEEE802.15.4 MAC network device structure.
+ *   params     - Where to put the parmeters
+ *   dest_panid - PAN ID of the destination.  May be 0xffff if the destination
+ *                is not associated.
+ *
+ * Returned Value:
+ *   None.
+ *
+ ****************************************************************************/
+
+static void sixlowpan_setup_params(FAR struct ieee802154_driver_s *ieee,
+                                   FAR struct frame802154_s *params,
+                                   uint16_t dest_panid)
+{
+  bool rcvrnull;
+
+  /* Initialize all prameters to all zero */
+
+  memset(&params, 0, sizeof(params));
+
+  /* Reset to an empty frame */
+
+  ieee->i_framelen   = 0;
+  ieee->i_dataoffset = 0;
+
+  /* Build the FCF (Only non-zero elements need to be initialized). */
+
+  params->fcf.frame_type    = FRAME802154_DATAFRAME;
+  params->fcf.frame_pending = ieee->i_pktattrs[PACKETBUF_ATTR_PENDING];
+
+  /* If the output address is NULL in the Rime buf, then it is broadcast
+   * on the 802.15.4 network.
+   */
+
+  rcvrnull = sixlowpan_addrnull(ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
+  if (rcvrnull)
+    {
+      params->fcf.ack_required = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_ACK];
+    }
+
+  /* Insert IEEE 802.15.4 (2003) version bit. */
+
+  params->fcf.frame_version = FRAME802154_IEEE802154_2003;
+
+  /* Increment and set the data sequence number. */
+
+  if (ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] != 0)
+    {
+      params->seq = ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO];
+    }
+  else
+    {
+      params->seq = ieee->i_dsn++;
+      ieee->i_pktattrs[PACKETBUF_ATTR_MAC_SEQNO] = params->seq;
+    }
+
+  /* Complete the addressing fields. */
+  /* Set the source and destination PAN ID. */
+
+  params->src_pid  = ieee->i_panid;
+  params->dest_pid = dest_panid;
+
+  /* If the output address is NULL in the Rime buf, then it is broadcast
+   * on the 802.15.4 network.
+   */
+
+  if (rcvrnull)
+    {
+      /* Broadcast requires short address mode. */
+
+      params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
+      params->dest_addr[0] = 0xff;
+      params->dest_addr[1] = 0xff;
+    }
+  else
+    {
+      /* Copy the destination address */
+
+      rimeaddr_copy((struct rimeaddr_s *)&params->dest_addr,
+                    ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER].u8);
+
+      /* Use short address mode if so configured */
+
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+      params->fcf.dest_addr_mode = FRAME802154_SHORTADDRMODE;
+#else
+      params->fcf.dest_addr_mode = FRAME802154_LONGADDRMODE;
+#endif
+    }
+
+  /* Set the source address to the node address assigned to the device */
+
+  rimeaddr_copy((struct rimeaddr_s *)&params->src_addr, &ieee->i_nodeaddr.u8);
+
+  /* Configure the payload address and length */
+
+  params->payload     = FRAME_DATA_START(ieee);
+  params->payload_len = FRAME_DATA_SIZE(ieee);
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: sixlowpan_hdrlen
+ *
+ * Description:
+ *   This function is before the first frame has been sent in order to
+ *   determine what the size of the IEEE802.15.4 header will be.  No frame
+ *   buffer is required to make this determination.
+ *
+ * Input parameters:
+ *   ieee       - A reference IEEE802.15.4 MAC network device structure.
+ *   dest_panid - PAN ID of the destination.  May be 0xffff if the destination
+ *                is not associated.
+ *
+ * Returned Value:
+ *   The frame header length is returnd on success; otherwise, a negated
+ *   errno value is return on failure.
+ *
+ ****************************************************************************/
+
+int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
+                     uint16_t dest_panid)
+{
+  struct frame802154_s params;
+
+  /* Set up the frame parameters */
+
+  sixlowpan_setup_params(ieee, &params, dest_panid);
+
+  /* Return the length of the header */
+
+  return sixlowpan_802154_hdrlen(&params);
+}
+
+/****************************************************************************
+ * Function: sixlowpan_802154_framecreate
+ *
+ * Description:
+ *   Creates a frame for transmission over the air.  This function is meant
+ *   to be called by a higher level function, that interfaces to a MAC.
+ *
+ * Input parameters:
+ *   finfo  - Pointer to struct EEE802.15.4 header structure that specifies
+ *            the frame to send.
+ *   buf    - Pointer to the buffer to use for the frame.
+ *   buflen - The length of the buffer to use for the frame.
+ *   finfo - I that specifies the frame to send.
+ *
+ * Returned Value:
+ *   The length of the frame header or 0 if there was insufficient space in
+ *   the buffer for the frame headers.
+ *
+ ****************************************************************************/
+
+int sixlowpan_802154_framecreate(FAR struct frame802154_s *finfo,
+                                 FAR uint8_t *buf, int buflen)
+{
+  struct field_length_s flen;
+  uint8_t pos;
+  int hdrlen;
+  int i;
+
+  sixlowpan_fieldlengths(finfo, &flen);
+
+  hdrlen = sixlowpan_flen_hdrlen(&flen);
+  if (hdrlen > buflen)
+    {
+      /* Too little space for headers. */
+
+      return 0;
+    }
+
+  /* OK, now we have field lengths.  Time to actually construct
+   * the outgoing frame, and store it in the provided buffer
+   */
+
+  buf[0] = (finfo->fcf.frame_type         & 7) |
+           ((finfo->fcf.security_enabled  & 1) << 3) |
+           ((finfo->fcf.frame_pending     & 1) << 4) |
+           ((finfo->fcf.ack_required      & 1) << 5) |
+           ((finfo->fcf.panid_compression & 1) << 6);
+  buf[1] = ((finfo->fcf.dest_addr_mode    & 3) << 2) |
+           ((finfo->fcf.frame_version     & 3) << 4) |
+           ((finfo->fcf.src_addr_mode     & 3) << 6);
+
+  /* Sequence number */
+
+  buf[2] = finfo->seq;
+  pos = 3;
+
+  /* Destination PAN ID */
+
+  if (flen.dest_pid_len == 2)
+    {
+      buf[pos++] = finfo->dest_pid & 0xff;
+      buf[pos++] = (finfo->dest_pid >> 8) & 0xff;
+    }
+
+  /* Destination address */
+
+  for (i = flen.dest_addr_len; i > 0; i--)
+    {
+     buf[pos++] = finfo->dest_addr[i - 1];
+    }
+
+  /* Source PAN ID */
+
+  if (flen.src_pid_len == 2)
+    {
+      buf[pos++] = finfo->src_pid & 0xff;
+      buf[pos++] = (finfo->src_pid >> 8) & 0xff;
+    }
+
+  /* Source address */
+
+  for (i = flen.src_addr_len; i > 0; i--)
+    {
+      buf[pos++] = finfo->src_addr[i - 1];
+    }
+
+  /* Aux header */
+
+#if 0 /* TODO Aux security header not yet implemented */
+  if (flen.aux_sec_len)
+    {
+      pos += flen.aux_sec_len;
+    }
+#endif
+
+  DEBUGASSERT(pos == hdrlen);
+  return (int)pos;
+}
+
+/****************************************************************************
+ * Function: sixlowpan_framecreate
+ *
+ * Description:
+ *   This function is called after the IEEE802.15.4 MAC driver polls for
+ *   TX data.  It creates the IEEE802.15.4 header in the frame buffer.
+ *
+ * Input parameters:
+ *   ieee       - A reference IEEE802.15.4 MAC network device structure.
+ *   dest_panid - PAN ID of the destination.  May be 0xffff if the destination
+ *                is not associated.
+ *
+ * Returned Value:
+ *   The frame header length is returnd on success; otherwise, a negated
+ *   errno value is return on failure.
+ *
+ ****************************************************************************/
+
+int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
+                          uint16_t dest_panid)
+{
+  struct frame802154_s params;
+  int len;
+  int ret;
+
+  /* Set up the frame parameters */
+
+  sixlowpan_setup_params(ieee, &params, dest_panid);
+
+  /* Get the length of the header */
+
+  len = sixlowpan_802154_hdrlen(&params);
+
+  /* Allocate space for the header in the frame buffer */
+
+  ret = sixlowpan_frame_hdralloc(ieee, len);
+  if (ret < 0)
+    {
+      wlerr("ERROR: Header too large: %u\n", len);
+      return ret;
+    }
+
+  /* Then create the frame */
+
+  sixlowpan_802154_framecreate(&params, FRAME_HDR_START(ieee), len);
+
+  wlinfo("Frame type: %02x Data len: %d %u (%u)\n",
+         params.fcf.frame_type, len, FRAME_DATA_SIZE(ieee),
+         FRAME_SIZE(ieee));
+#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2
+  wlinfo("Dest address: %02x:%02x\n",
+         params.dest_addr[0], params.dest_addr[1]);
+#else
+  wlinfo("Dest address: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+         params.dest_addr[0], params.dest_addr[1], params.dest_addr[2],
+         params.dest_addr[3], params.dest_addr[4], params.dest_addr[5],
+         params.dest_addr[6], params.dest_addr[7]);
+#endif
+
+  return len;
+}
+
+#endif /* CONFIG_NET_6LOWPAN */
diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c
index b270413143..534cb1adbf 100644
--- a/net/sixlowpan/sixlowpan_hc06.c
+++ b/net/sixlowpan/sixlowpan_hc06.c
@@ -20,6 +20,7 @@
  * 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
@@ -44,7 +45,7 @@
  ****************************************************************************/
 
 /* FOR HC-06 COMPLIANCE TODO:
- *  
+ *
  * -Add compression options to UDP, currently only supports
  *  both ports compressed or both ports elided
  * -Verify TC/FL compression works
diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h
index 453d340dba..6828c14128 100644
--- a/net/sixlowpan/sixlowpan_internal.h
+++ b/net/sixlowpan/sixlowpan_internal.h
@@ -4,9 +4,28 @@
  *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gnutt@nuttx.org>
  *
+ * Parts of this file derive from Contiki:
+ *
+ *   Copyright (c) 2008, Swedish Institute of Computer Science
+ *   All rights reserved.
+ *
+ *   Additional fixes for AVR contributed by:
+ *         Colin O'Flynn coflynn@newae.com
+ *         Eric Gnoske egnoske@gmail.com
+ *         Blake Leverett bleverett@gmail.com
+ *         Mike Vidales mavida404@gmail.com
+ *         Kevin Brown kbrown3@uccs.edu
+ *         Nate Bohlmann nate@elfwerks.com
+ *
+ *   Additional fixes for MSP430 contributed by:
+ *         Joakim Eriksson
+ *         Niclas Finne
+ *         Nicolas Tsiftes
+ *
+ *    All rights reserved.
+ *
  * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
+ * 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.
@@ -14,23 +33,21 @@
  *    notice, this list of conditions and the following disclaimer in
  *    the documentation and/or other materials provided with the
  *    distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
- *    without specific prior written permission.
+ * 3. Neither the name of the copyright holders nor the names of
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 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
+ * 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 _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H
@@ -64,11 +81,64 @@
 #define rimeaddr_cmp(addr1,addr2) \
   (memcmp(addr1, addr2, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE) == 0)
 
+/* Frame buffer helpers */
+
+#define FRAME_RESET(ieee) \
+  do \
+    { \
+      (ieee)->i_dataoffset = 0; \
+      (ieee)->i_framelen   = 0; \
+    } \
+  while (0)
+
+#define FRAME_HDR_START(ieee) \
+  ((ieee)->i_frame)
+#define FRAME_HDR_SIZE(ieee) \
+  ((ieee)->i_dataoffset)
+
+#define FRAME_DATA_START(ieee) \
+  ((FAR uint8_t *)((ieee)->i_frame) + (ieee)->i_dataoffset)
+#define FRAME_DATA_SIZE(ieee) \
+  ((ieee)->i_framelen - (ieee)->i_dataoffset)
+
+#define FRAME_REMAINING(ieee) \
+  (CONFIG_NET_6LOWPAN_FRAMELEN - (ieee)->i_framelen)
+#define FRAME_SIZE(ieee) \
+  ((ieee)->i_framelen)
+
+/* These are some definitions of element values used in the FCF.  See the
+ * IEEE802.15.4 spec for details.
+ */
+
+#define FRAME802154_BEACONFRAME         0x00
+#define FRAME802154_DATAFRAME           0x01
+#define FRAME802154_ACKFRAME            0x02
+#define FRAME802154_CMDFRAME            0x03
+
+#define FRAME802154_BEACONREQ           0x07
+
+#define FRAME802154_IEEERESERVED        0x00
+#define FRAME802154_NOADDR              0x00  /* Only valid for ACK or Beacon frames */
+#define FRAME802154_SHORTADDRMODE       0x02
+#define FRAME802154_LONGADDRMODE        0x03
+
+#define FRAME802154_NOBEACONS           0x0f
+
+#define FRAME802154_BROADCASTADDR       0xffff
+#define FRAME802154_BROADCASTPANDID     0xffff
+
+#define FRAME802154_IEEE802154_2003     0x00
+#define FRAME802154_IEEE802154_2006     0x01
+
+#define FRAME802154_SECURITY_LEVEL_NONE 0
+#define FRAME802154_SECURITY_LEVEL_128  3
+
 /****************************************************************************
  * Public Types
  ****************************************************************************/
 
-/* IPv6 + TCP header */
+/* IPv^ TCP/UDP Definitions *************************************************/
+/* IPv6 + TCP header.  Cast compatible based on IPv6 protocol field. */
 
 struct ipv6tcp_hdr_s
 {
@@ -92,6 +162,71 @@ struct ipv6icmp_hdr_s
   struct icmpv6_iphdr_s icmp;
 };
 
+/* IEEE802.15.4 Frame Definitions *******************************************/
+/* The IEEE 802.15.4 frame has a number of constant/fixed fields that can be
+ * counted to make frame construction and max payload calculations easier.
+ * These include:
+ *
+ *   1. FCF                  - 2 bytes       - Fixed
+ *   2. Sequence number      - 1 byte        - Fixed
+ *   3. Addressing fields    - 4 - 20 bytes  - Variable
+ *   4. Aux security header  - 0 - 14 bytes  - Variable
+ *   5. CRC                  - 2 bytes       - Fixed
+*/
+
+/* Defines the bitfields of the frame control field (FCF). */
+
+struct frame802154_fcf_s
+{
+  uint8_t frame_type;        /* 3 bit. Frame type field, see 802.15.4 */
+  uint8_t security_enabled;  /* 1 bit. True if security is used in this frame */
+  uint8_t frame_pending;     /* 1 bit. True if sender has more data to send */
+  uint8_t ack_required;      /* 1 bit. Is an ack frame required? */
+  uint8_t panid_compression; /* 1 bit. Is this a compressed header? */
+                             /* 3 bit. Unused bits */
+  uint8_t dest_addr_mode;    /* 2 bit. Destination address mode, see 802.15.4 */
+  uint8_t frame_version;     /* 2 bit. 802.15.4 frame version */
+  uint8_t src_addr_mode;     /* 2 bit. Source address mode, see 802.15.4 */
+};
+
+/* 802.15.4 security control bitfield.  See section 7.6.2.2.1 in 802.15.4
+ * specification.
+ */
+
+struct frame802154_scf_s
+{
+  uint8_t  security_level;   /* 3 bit. security level      */
+  uint8_t  key_id_mode;      /* 2 bit. Key identifier mode */
+  uint8_t  reserved;         /* 3 bit. Reserved bits       */
+};
+
+/* 802.15.4 Aux security header */
+
+struct frame802154_aux_hdr_s
+{
+  struct frame802154_scf_s security_control;  /* Security control bitfield */
+  uint32_t frame_counter;    /* Frame counter, used for security */
+  uint8_t  key[9];           /* The key itself, or an index to the key */
+};
+
+/* Parameters used by the frame802154_create() function.  These  parameters
+ * are used in the 802.15.4 frame header.  See the 802.15.4 specification
+ * for details.
+ */
+
+struct frame802154_s
+{
+  struct frame802154_fcf_s fcf;          /* Frame control field  */
+  uint8_t seq;               /* Sequence number */
+  uint16_t dest_pid;         /* Destination PAN ID */
+  uint8_t dest_addr[8];      /* Destination address */
+  uint16_t src_pid;          /* Source PAN ID */
+  uint8_t src_addr[8];       /* Source address */
+  struct frame802154_aux_hdr_s aux_hdr;  /* Aux security header */
+  uint8_t *payload;          /* Pointer to 802.15.4 frame payload */
+  uint8_t payload_len;       /* Length of payload field */
+};
+
 /****************************************************************************
  * Public Data
  ****************************************************************************/
@@ -157,6 +292,49 @@ int sixlowpan_send(FAR struct net_driver_s *dev,
                    FAR const struct ipv6_hdr_s *ipv6, FAR const void *buf,
                    size_t len, FAR const struct rimeaddr_s *raddr);
 
+/****************************************************************************
+ * Function: sixlowpan_hdrlen
+ *
+ * Description:
+ *   This function is before the first frame has been sent in order to
+ *   determine what the size of the IEEE802.15.4 header will be.  No frame
+ *   buffer is required to make this determination.
+ *
+ * Input parameters:
+ *   ieee       - A reference IEEE802.15.4 MAC network device structure.
+ *   dest_panid - PAN ID of the destination.  May be 0xffff if the destination
+ *                is not associated.
+ *
+ * Returned Value:
+ *   The frame header length is returnd on success; otherwise, a negated
+ *   errno value is return on failure.
+ *
+ ****************************************************************************/
+
+int sixlowpan_hdrlen(FAR struct ieee802154_driver_s *ieee,
+                     uint16_t dest_panid);
+
+/****************************************************************************
+ * Function: sixlowpan_framecreate
+ *
+ * Description:
+ *   This function is called after the IEEE802.15.4 MAC driver polls for
+ *   TX data.  It creates the IEEE802.15.4 header in the frame buffer.
+ *
+ * Input parameters:
+ *   ieee       - A reference IEEE802.15.4 MAC network device structure.
+ *   dest_panid - PAN ID of the destination.  May be 0xffff if the destination
+ *                is not associated.
+ *
+ * Returned Value:
+ *   The frame header length is returnd on success; otherwise, a negated
+ *   errno value is return on failure.
+ *
+ ****************************************************************************/
+
+int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee,
+                          uint16_t dest_panid);
+
 /****************************************************************************
  * Name: sixlowpan_hc06_initialize
  *
@@ -293,15 +471,15 @@ void sixlowpan_uncompresshdr_hc1(FAR struct net_driver_s *dev,
 #endif
 
 /****************************************************************************
- * Name: sixlowpan_pktbuf_reset
+ * Name: sixlowpan_frame_hdralloc
  *
  * Description:
- *   Reset all attributes and addresses in the packet buffer metadata in the
- *   provided IEEE802.15.4 MAC driver structure.
+ *   Allocate space for a header within the frame buffer (i_frame).
  *
  ****************************************************************************/
 
-void sixlowpan_pktbuf_reset(FAR struct ieee802154_driver_s *ieee);
+int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee,
+                             int size);
 
 #endif /* CONFIG_NET_6LOWPAN */
 #endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */
diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c
index d204e5eeca..9a7b0095cd 100644
--- a/net/sixlowpan/sixlowpan_send.c
+++ b/net/sixlowpan/sixlowpan_send.c
@@ -4,6 +4,18 @@
  *   Copyright (C) 2017 Gregory Nutt. All rights reserved.
  *   Author: Gregory Nutt <gnutt@nuttx.org>
  *
+ * Parts of this file derive from Contiki:
+ *
+ *   Copyright (c) 2008, Swedish Institute of Computer Science.
+ *   All rights reserved.
+ *   Authors: Adam Dunkels <adam@sics.se>
+ *            Nicolas Tsiftes <nvt@sics.se>
+ *            Niclas Finne <nfi@sics.se>
+ *            Mathilde Durvy <mdurvy@cisco.com>
+ *            Julien Abeille <jabeille@cisco.com>
+ *            Joakim Eriksson <joakime@sics.se>
+ *            Joel Hoglund <joel@sics.se>
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -11,25 +23,23 @@
  * 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 NuttX nor the names of its contributors may be
- *    used to endorse or promote products derived from this software
+ *    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 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.
+ * 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.
  *
  ****************************************************************************/
 
@@ -68,6 +78,7 @@
  *
  * Description:
  *   Setup some packet buffer attributes
+ *
  * Input Parameters:
  *   ieee - Pointer to IEEE802.15.4 MAC driver structure.
  *   ipv6 - Pointer to the IPv6 header to "compress"
@@ -158,6 +169,42 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee,
   ieee->i_uncomp_hdrlen += IPv6_HDRLEN;
 }
 
+/****************************************************************************
+ * Name: sixlowpan_send_frame
+ *
+ * Description:
+ *   Send one frame when the IEEE802.15.4 MAC device next polls.
+ *
+ * Input Parameters:
+ *   ieee - Pointer to IEEE802.15.4 MAC driver structure.
+ *   ipv6 - Pointer to the IPv6 header to "compress"
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static int sixlowpan_send_frame(FAR struct ieee802154_driver_s *ieee)
+{
+  /* Prepare the frame */
+#warning Missing logic
+  /* Set up for the TX poll */
+  /* When polled, then we need to call sixlowpan_framecreate() to create the
+   * frame and copy the payload data into the frame.
+   */
+#if 0 /* Just some notes of what needs to be done in interrupt handler */
+  framer_hdrlen = sixlowpan_createframe(ieee, ieee->i_panid);
+  memcpy(ieee->i_rimeptr + ieee->i_rime_hdrlen, (uint8_t *)ipv6 + ieee->i_uncomp_hdrlen, len - ieee->i_uncomp_hdrlen);
+  dev->i_framelen = len - ieee->i_uncomp_hdrlen + ieee->i_rime_hdrlen;
+#endif
+#warning Missing logic
+  /* Notify the IEEE802.14.5 MAC driver that we have data to be sent */
+#warning Missing logic
+  /* Wait for the transfer to complete */
+#warning Missing logic
+  return -ENOSYS;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -203,29 +250,49 @@ int sixlowpan_send(FAR struct net_driver_s *dev,
 
   int framer_hdrlen;       /* Framer header length */
   struct rimeaddr_s dest;  /* The MAC address of the destination of the packet */
-  uint16_t outlen;         /* Number of bytes processed. */
+  uint16_t outlen = 0;     /* Number of bytes processed. */
 
   /* Initialize device-specific data */
 
+  FRAME_RESET(ieee);
   ieee->i_uncomp_hdrlen = 0;
   ieee->i_rime_hdrlen   = 0;
+  /* REVISIT: Do I need this rimeptr? */
+  ieee->i_rimeptr = &dev->d_buf[PACKETBUF_HDR_SIZE];
 
   /* Reset rime buffer, packet buffer metatadata */
 
-  sixlowpan_pktbuf_reset(ieee);
+  memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
+  memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
 
-  ieee->i_rimeptr = &dev->d_buf[PACKETBUF_HDR_SIZE];
-  ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] = CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
+  ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
+    CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
 
 #ifdef CONFIG_NET_6LOWPAN_SNIFFER
   if (g_sixlowpan_sniffer != NULL)
     {
+      /* Reset rime buffer, packet buffer metatadata */
+
+      memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
+      memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
+
+      ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
+        CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
+
       /* Call the attribution when the callback comes, but set attributes here */
 
       sixlowpan_set_pktattrs(ieee, ipv6);
     }
 #endif
 
+  /* Reset rime buffer, packet buffer metatadata */
+
+  memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
+  memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
+
+  ieee->i_pktattrs[PACKETBUF_ATTR_MAX_MAC_TRANSMISSIONS] =
+    CONFIG_NET_6LOWPAN_MAX_MACTRANSMITS;
+
   /* Set stream mode for all TCP packets, except FIN packets. */
 
   if (ipv6->proto == IP_PROTO_TCP)
@@ -281,8 +348,94 @@ int sixlowpan_send(FAR struct net_driver_s *dev,
 
   ninfo("Header of len %d\n", ieee->i_rime_hdrlen);
 
-  /* Calculate frame header length. */
-#warning Missing logic
+  rimeaddr_copy(&ieee->i_pktaddrs[PACKETBUF_ADDR_RECEIVER], &dest);
+
+  /* Pre-calculate frame header length. */
+
+  framer_hdrlen = sixlowpan_hdrlen(ieee, ieee->i_panid);
+  if (framer_hdrlen < 0)
+    {
+      /* Failed to determine the size of the header failed. */
+ 
+      nerr("ERROR: sixlowpan_framecreate() failed: %d\n", framer_hdrlen);
+      return framer_hdrlen;
+    }
+
+  /* Check if we need to fragment the packet into several frames */
+
+  if ((int)len - (int)ieee->i_uncomp_hdrlen >
+      (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen -
+      (int)ieee->i_rime_hdrlen)
+    {
+#if CONFIG_NET_6LOWPAN_FRAG
+      /* The outbound IPv6 packet is too large to fit into a single 15.4
+       * packet, so we fragment it into multiple packets and send them.
+       * The first fragment contains frag1 dispatch, then
+       * IPv6/HC1/HC06/HC_UDP dispatchs/headers.
+       * The following fragments contain only the fragn dispatch.
+       */
+
+      ninfo("Fragmentation sending packet len %d\n", len);
+
+      /* Create 1st Fragment */
+#  warning Missing logic
+
+      /* Move HC1/HC06/IPv6 header */
+#  warning Missing logic
+
+      /* FRAG1 dispatch + header
+       * Note that the length is in units of 8 bytes
+       */
+#  warning Missing logic
+
+      /* Copy payload and send */
+#  warning Missing logic
+ 
+      /* Check TX result. */
+#  warning Missing logic
+
+      /* Set outlen to what we already sent from the IP payload */
+#  warning Missing logic
+
+      /* Create following fragments
+       * Datagram tag is already in the buffer, we need to set the
+       * FRAGN dispatch and for each fragment, the offset
+       */
+#  warning Missing logic
+
+      while (outlen < len)
+        {
+          /* Copy payload and send */
+#  warning Missing logic
+
+          ninfo("sixlowpan output: fragment offset %d, len %d, tag %d\n",
+                outlen >> 3, g_rime_payloadlen, g_mytag);
+
+#  warning Missing logic
+          sixlowpan_send_frame(ieee);
+
+          /* Check tx result. */
+#  warning Missing logic
+        }
+
+      return -ENOSYS;
+#else
+      nerr("ERROR: Packet too large: %d\n", len);
+      nerr("       Cannot to be sent without fragmentation support\n");
+      nerr("       dropping packet\n");
+
+      return -E2BIG;
+#endif
+    }
+  else
+    {
+      /* The packet does not need to be fragmented just copy the "payload"
+       * and send in one frame.
+       */
+
+      return sixlowpan_send_frame(ieee);
+    }
+
   return -ENOSYS;
 }
 
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
index 5df1b3439c..a12394407f 100644
--- a/net/sixlowpan/sixlowpan_utils.c
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -44,6 +44,17 @@
  * SUCH DAMAGE.
  *
  ****************************************************************************/
+/* Frame Organization:
+ *
+ *     Content          Offset
+ *   +----------------+ 0
+ *   | Frame Header   |
+ *   +----------------+ i_dataoffset
+ *   | Data           |
+ *   +----------------+ i_framelen
+ *   | Unused         |
+ *   +----------------+ CONFIG_NET_6LOWPAN_FRAMELEN
+ */
 
 /****************************************************************************
  * Included Files
@@ -52,6 +63,7 @@
 #include <nuttx/config.h>
 
 #include <string.h>
+#include <errno.h>
 
 #include "nuttx/net/sixlowpan.h"
 
@@ -64,22 +76,24 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: sixlowpan_pktbuf_reset
+ * Name: sixlowpan_frame_hdralloc
  *
  * Description:
- *   Reset all attributes and addresses in the packet buffer metadata in the
- *   provided IEEE802.15.4 MAC driver structure.
+ *   Allocate space for a header within the packet buffer (dev->d_buf).
  *
  ****************************************************************************/
 
-void sixlowpan_pktbuf_reset(FAR struct ieee802154_driver_s *ieee)
+int sixlowpan_frame_hdralloc(FAR struct ieee802154_driver_s *ieee,
+                             int size)
 {
-  ieee->i_dev.d_len = 0;
-  ieee->i_rimeptr   = 0;
-  ieee->i_hdrptr    = PACKETBUF_HDR_SIZE;
+  if (size <= FRAME_REMAINING(ieee))
+    {
+      ieee->i_dataoffset += size;
+      ieee->i_framelen   += size;
+      return OK;
+    }
 
-  memset(ieee->i_pktattrs, 0, PACKETBUF_NUM_ATTRS * sizeof(uint16_t));
-  memset(ieee->i_pktaddrs, 0, PACKETBUF_NUM_ADDRS * sizeof(struct rimeaddr_s));
+  return -ENOMEM;
 }
 
 #endif /* CONFIG_NET_6LOWPAN */

From 9aabb44118fe207458cd965b64259e2e11b2acb2 Mon Sep 17 00:00:00 2001
From: Gregory Nutt <gnutt@nuttx.org>
Date: Thu, 30 Mar 2017 16:30:04 -0600
Subject: [PATCH 12/12] 6loWPAN: Add some comments, move a function

---
 include/nuttx/net/sixlowpan.h    | 27 ++++++++++++++++++--------
 net/sixlowpan/sixlowpan_framer.c | 29 ----------------------------
 net/sixlowpan/sixlowpan_input.c  | 33 ++++++++++++++++++++++++++++++++
 net/sixlowpan/sixlowpan_utils.c  | 17 ++++++++--------
 4 files changed, 61 insertions(+), 45 deletions(-)

diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h
index 0d403d25bb..be3bfa7636 100644
--- a/include/nuttx/net/sixlowpan.h
+++ b/include/nuttx/net/sixlowpan.h
@@ -333,17 +333,28 @@ struct rimeaddr_s
  * 2) i_dsn must be set to a random value.  After that, it will be managed
  *    by the network.
  * 3) i_nodeaddr must be set after the MAC is assigned an address.
+ * 4) On network TX poll operations, the IEEE802.15.4 MAC needs to provide
+ *    the i_frame buffer with size greater than or equal to
+ *    CONFIG_NET_6LOWPAN_FRAMELEN.  No dev.d_buf need be provided in this
+ *    case.  The entire is TX is performed using only the i_frame buffer.
+ * 5) On network input RX oprations, both buffers must be provided.  The size
+ *    of the i_frame buffer is, again, greater than or equal to
+ *    CONFIG_NET_6LOWPAN_FRAMELEN.  The larger dev.d_buf must have a size
+ *    of at least <tbd>.  The dev.d_buf is used for de-compressing each
+ *    frame and reassembling any fragmented packets to create the full input
+ *    packet that is provided to the applicatino.
  *
  * Frame Organization:
  *
- *     Content          Offset
- *   +----------------+ 0
- *   | Frame Header   |
- *   +----------------+ i_dataoffset
- *   | Data           |
- *   +----------------+ i_framelen
- *   | Unused         |
- *   +----------------+ CONFIG_NET_6LOWPAN_FRAMELEN
+ *     Content            Offset
+ *   +------------------+ 0
+ *   | Frame Header     |
+ *   +------------------+ i_dataoffset
+ *   | Procotol Headers |
+ *   | Data Payload     |
+ *   +------------------+ i_framelen
+ *   | Unused           |
+ *   +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN
  */
 
 struct ieee802154_driver_s
diff --git a/net/sixlowpan/sixlowpan_framer.c b/net/sixlowpan/sixlowpan_framer.c
index 611e204a9f..2b528dea10 100644
--- a/net/sixlowpan/sixlowpan_framer.c
+++ b/net/sixlowpan/sixlowpan_framer.c
@@ -109,35 +109,6 @@ static inline uint8_t sixlowpan_addrlen(uint8_t addrmode)
     }
 }
 
-/****************************************************************************
- * Function: sixlowpan_isbroadcast
- *
- * Description:
- *   Return the address length associated with a 2-bit address mode
- *
- * Input parameters:
- *   addrmode - The address mode
- *
- * Returned Value:
- *   The address length associated with the address mode.
- *
- ****************************************************************************/
-
-static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr)
-{
-  int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
-
-  while (i-- > 0)
-    {
-      if (addr[i] != 0xff)
-        {
-          return false;
-        }
-    }
-
-  return true;
-}
-
 /****************************************************************************
  * Function: sixlowpan_addrnull
  *
diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c
index 964d988be7..ce520f8e5e 100644
--- a/net/sixlowpan/sixlowpan_input.c
+++ b/net/sixlowpan/sixlowpan_input.c
@@ -46,6 +46,39 @@
 
 #ifdef CONFIG_NET_6LOWPAN
 
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: sixlowpan_isbroadcast
+ *
+ * Description:
+ *   Return the address length associated with a 2-bit address mode
+ *
+ * Input parameters:
+ *   addrmode - The address mode
+ *
+ * Returned Value:
+ *   The address length associated with the address mode.
+ *
+ ****************************************************************************/
+
+static bool sixlowpan_isbroadcast(uint8_t mode, FAR uint8_t *addr)
+{
+  int i = ((mode == FRAME802154_SHORTADDRMODE) ? 2 : 8);
+
+  while (i-- > 0)
+    {
+      if (addr[i] != 0xff)
+        {
+          return false;
+        }
+    }
+
+  return true;
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c
index a12394407f..f00eaeae4c 100644
--- a/net/sixlowpan/sixlowpan_utils.c
+++ b/net/sixlowpan/sixlowpan_utils.c
@@ -46,14 +46,15 @@
  ****************************************************************************/
 /* Frame Organization:
  *
- *     Content          Offset
- *   +----------------+ 0
- *   | Frame Header   |
- *   +----------------+ i_dataoffset
- *   | Data           |
- *   +----------------+ i_framelen
- *   | Unused         |
- *   +----------------+ CONFIG_NET_6LOWPAN_FRAMELEN
+ *     Content            Offset
+ *   +------------------+ 0
+ *   | Frame Header     |
+ *   +------------------+ i_dataoffset
+ *   | Procotol Headers |
+ *   | Data Payload     |
+ *   +------------------+ i_framelen
+ *   | Unused           |
+ *   +------------------+ CONFIG_NET_6LOWPAN_FRAMELEN
  */
 
 /****************************************************************************