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, ®val); + 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, ®val); + 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, ®val); + 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, ®val); + 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, ®val); + 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, ®val); + 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, ®val); + if (ret < 0) + { + return ERROR; + } + + hts221_dbg("AV_CONF_REG: 0x%02X\n", regval); + + ret = hts221_read_reg(priv, &ctrl_reg1_addr, ®val); + if (ret < 0) + { + return ERROR; + } + + hts221_dbg("CTRL_REG_1: 0x%02X\n", regval); + + ret = hts221_read_reg(priv, &ctrl_reg2_addr, ®val); + if (ret < 0) + { + return ERROR; + } + + hts221_dbg("CTRL_REG_2: 0x%02X\n", regval); + + ret = hts221_read_reg(priv, &ctrl_reg3_addr, ®val); + 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(¶ms, 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 *)¶ms->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 *)¶ms->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, ¶ms, dest_panid); + + /* Return the length of the header */ + + return sixlowpan_802154_hdrlen(¶ms); +} + +/**************************************************************************** + * 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, ¶ms, dest_panid); + + /* Get the length of the header */ + + len = sixlowpan_802154_hdrlen(¶ms); + + /* 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(¶ms, 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 */ /****************************************************************************