diff --git a/arch/arm/src/efm32/efm32_i2c.c b/arch/arm/src/efm32/efm32_i2c.c index 59ad3aa2f84..a52cd05ead5 100644 --- a/arch/arm/src/efm32/efm32_i2c.c +++ b/arch/arm/src/efm32/efm32_i2c.c @@ -553,7 +553,7 @@ static inline int efm32_i2c_sem_waitdone(FAR struct efm32_i2c_priv_s *priv) #ifdef CONFIG_EFM32_I2C_DYNTIMEO abstime.tv_nsec += 1000 * efm32_i2c_tousecs(priv->msgc, priv->msgv); - if (abstime.tv_nsec > 1000 * 1000 * 1000) + if (abstime.tv_nsec >= 1000 * 1000 * 1000) { abstime.tv_sec++; abstime.tv_nsec -= 1000 * 1000 * 1000; @@ -561,7 +561,7 @@ static inline int efm32_i2c_sem_waitdone(FAR struct efm32_i2c_priv_s *priv) #elif CONFIG_EFM32_I2CTIMEOMS > 0 abstime.tv_nsec += CONFIG_EFM32_I2CTIMEOMS * 1000 * 1000; - if (abstime.tv_nsec > 1000 * 1000 * 1000) + if (abstime.tv_nsec >= 1000 * 1000 * 1000) { abstime.tv_sec++; abstime.tv_nsec -= 1000 * 1000 * 1000; diff --git a/configs/stm32f103-minimum/usbnsh/defconfig b/configs/stm32f103-minimum/usbnsh/defconfig index e5319a27eb3..312a2e8505d 100644 --- a/configs/stm32f103-minimum/usbnsh/defconfig +++ b/configs/stm32f103-minimum/usbnsh/defconfig @@ -744,7 +744,7 @@ CONFIG_ARCH_HAVE_SPI_BITORDER=y # CONFIG_SENSORS is not set CONFIG_SERIAL=y CONFIG_SERIAL_REMOVABLE=y -CONFIG_SERIAL_CONSOLE=y +# CONFIG_SERIAL_CONSOLE is not set # CONFIG_16550_UART is not set # CONFIG_UART_SERIALDRIVER is not set # CONFIG_UART0_SERIALDRIVER is not set @@ -774,9 +774,9 @@ CONFIG_STANDARD_SERIAL=y # CONFIG_SERIAL_OFLOWCONTROL is not set # CONFIG_SERIAL_DMA is not set CONFIG_ARCH_HAVE_SERIAL_TERMIOS=y -CONFIG_USART1_SERIAL_CONSOLE=y +# CONFIG_USART1_SERIAL_CONSOLE is not set # CONFIG_OTHER_SERIAL_CONSOLE is not set -# CONFIG_NO_SERIAL_CONSOLE is not set +CONFIG_NO_SERIAL_CONSOLE=y # # USART1 Configuration diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index 0211d17ce6f..04b69da6048 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -80,7 +80,7 @@ #define SIXLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx */ #define SIXLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx */ -#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf1 /* 11111000 */ +#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf8 /* 11111000 */ /* HC1 encoding */ @@ -398,6 +398,12 @@ struct ieee802154_driver_s uint16_t i_reasstag; + /* i_boffset. Offset to the beginning of data in d_buf. As each fragment + * is received, data is placed at an appriate offset added to this. + */ + + uint16_t i_boffset; + /* The source MAC address of the fragments being merged */ struct rimeaddr_s i_fragsrc; diff --git a/include/pthread.h b/include/pthread.h index af6ef51e23e..a75cd9e9015 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -337,6 +337,27 @@ typedef struct pthread_barrier_s pthread_barrier_t; typedef bool pthread_once_t; #define __PTHREAD_ONCE_T_DEFINED 1 +struct pthread_rwlock_s +{ + pthread_mutex_t lock; + pthread_cond_t cv; + unsigned int num_readers; + unsigned int num_writers; + bool write_in_progress; +}; + +typedef struct pthread_rwlock_s pthread_rwlock_t; + +typedef int pthread_rwlockattr_t; + +#define PTHREAD_RWLOCK_INITIALIZER {PTHREAD_MUTEX_INITIALIZER, \ + PTHREAD_COND_INITIALIZER, \ + 0, 0} + +#define PTHREAD_MUTEX_INITIALIZER {NULL, SEM_INITIALIZER(1), -1, \ + __PTHREAD_MUTEX_DEFAULT_FLAGS, \ + PTHREAD_MUTEX_DEFAULT, 0} + #ifdef CONFIG_PTHREAD_CLEANUP /* This type describes the pthread cleanup callback (non-standard) */ @@ -539,8 +560,8 @@ int pthread_barrierattr_setpshared(FAR pthread_barrierattr_t *attr, int pthread_barrier_destroy(FAR pthread_barrier_t *barrier); int pthread_barrier_init(FAR pthread_barrier_t *barrier, - FAR const pthread_barrierattr_t *attr, - unsigned int count); + FAR const pthread_barrierattr_t *attr, + unsigned int count); int pthread_barrier_wait(FAR pthread_barrier_t *barrier); /* Pthread initialization */ @@ -548,6 +569,21 @@ int pthread_barrier_wait(FAR pthread_barrier_t *barrier); int pthread_once(FAR pthread_once_t *once_control, CODE void (*init_routine)(void)); +/* Pthread rwlock */ + +int pthread_rwlock_destroy(FAR pthread_rwlock_t *rw_lock); +int pthread_rwlock_init(FAR pthread_rwlock_t *rw_lock, + FAR const pthread_rwlockattr_t *attr); +int pthread_rwlock_rdlock(pthread_rwlock_t *lock); +int pthread_rwlock_timedrdlock(FAR pthread_rwlock_t *lock, + FAR const struct timespec *abstime); +int pthread_rwlock_tryrdlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_wrlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *lock, + FAR const struct timespec *abstime); +int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *lock); +int pthread_rwlock_unlock(FAR pthread_rwlock_t *lock); + /* Pthread signal management APIs */ int pthread_kill(pthread_t thread, int sig); diff --git a/libc/pthread/Make.defs b/libc/pthread/Make.defs index b8be2927d2f..291dfdfd4e6 100644 --- a/libc/pthread/Make.defs +++ b/libc/pthread/Make.defs @@ -52,6 +52,7 @@ CSRCS += pthread_mutexattr_settype.c pthread_mutexattr_gettype.c CSRCS += pthread_mutexattr_setrobust.c pthread_mutexattr_getrobust.c CSRCS += pthread_setcancelstate.c pthread_setcanceltype.c CSRCS += pthread_testcancel.c +CSRCS += pthread_rwlock.c pthread_rwlock_rdlock.c pthread_rwlock_wrlock.c ifeq ($(CONFIG_SMP),y) CSRCS += pthread_attr_getaffinity.c pthread_attr_setaffinity.c diff --git a/libc/pthread/pthread_rwlock.c b/libc/pthread/pthread_rwlock.c new file mode 100644 index 00000000000..b40b655b26d --- /dev/null +++ b/libc/pthread/pthread_rwlock.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlock.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * 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 + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int pthread_rwlock_init(FAR pthread_rwlock_t *lock, + FAR const pthread_rwlockattr_t *attr) +{ + int err; + + if (attr != NULL) + { + return -ENOSYS; + } + + lock->num_readers = 0; + lock->num_writers = 0; + lock->write_in_progress = false; + + err = pthread_cond_init(&lock->cv, NULL); + if (err != 0) + { + return err; + } + + err = pthread_mutex_init(&lock->lock, NULL); + if (err != 0) + { + pthread_cond_destroy(&lock->cv); + return err; + } + + return err; +} + +int pthread_rwlock_destroy(FAR pthread_rwlock_t *lock) +{ + int cond_err = pthread_cond_destroy(&lock->cv); + int mutex_err = pthread_mutex_destroy(&lock->lock); + + if (mutex_err) + { + return mutex_err; + } + + return cond_err; +} + +int pthread_rwlock_unlock(FAR pthread_rwlock_t *rw_lock) +{ + int err; + + err = pthread_mutex_lock(&rw_lock->lock); + if (err != 0) + { + return err; + } + + if (rw_lock->num_readers > 0) + { + rw_lock->num_readers--; + + if (rw_lock->num_readers == 0) + { + err = pthread_cond_broadcast(&rw_lock->cv); + } + } + else if (rw_lock->write_in_progress) + { + rw_lock->write_in_progress = false; + + err = pthread_cond_broadcast(&rw_lock->cv); + } + else + { + err = EINVAL; + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} diff --git a/libc/pthread/pthread_rwlock_rdlock.c b/libc/pthread/pthread_rwlock_rdlock.c new file mode 100644 index 00000000000..9fd461a758e --- /dev/null +++ b/libc/pthread/pthread_rwlock_rdlock.c @@ -0,0 +1,143 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlockread.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * 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 + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int tryrdlock(FAR pthread_rwlock_t *rw_lock) +{ + int err; + + if (rw_lock->num_writers > 0 || rw_lock->write_in_progress) + { + err = EBUSY; + } + else if (rw_lock->num_readers == UINT_MAX) + { + err = EAGAIN; + } + else + { + rw_lock->num_readers++; + err = OK; + } + + return err; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_rwlock_rdlock + * + * Description: + * Locks a read/write lock for reading + * + * Parameters: + * None + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int pthread_rwlock_tryrdlock(FAR pthread_rwlock_t *rw_lock) +{ + int err = pthread_mutex_trylock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + err = tryrdlock(rw_lock); + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_timedrdlock(FAR pthread_rwlock_t *rw_lock, + FAR const struct timespec *ts) +{ + int err = pthread_mutex_lock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + while ((err = tryrdlock(rw_lock)) == EBUSY) + { + if (ts != NULL) + { + err = pthread_cond_timedwait(&rw_lock->cv, &rw_lock->lock, ts); + } + else + { + err = pthread_cond_wait(&rw_lock->cv, &rw_lock->lock); + } + + if (err != 0) + { + break; + } + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_rdlock(FAR pthread_rwlock_t * rw_lock) +{ + return pthread_rwlock_timedrdlock(rw_lock, NULL); +} diff --git a/libc/pthread/pthread_rwlock_wrlock.c b/libc/pthread/pthread_rwlock_wrlock.c new file mode 100644 index 00000000000..ecda4cb25be --- /dev/null +++ b/libc/pthread/pthread_rwlock_wrlock.c @@ -0,0 +1,148 @@ +/**************************************************************************** + * libc/pthread/pthread_rwlockwrite.c + * + * Copyright (C) 2017 Mark Schulte. All rights reserved. + * Author: Mark Schulte + * + * 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 + +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_rwlock_rdlock + * + * Description: + * Locks a read/write lock for reading + * + * Parameters: + * None + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +int pthread_rwlock_trywrlock(FAR pthread_rwlock_t *rw_lock) +{ + int err = pthread_mutex_trylock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + if (rw_lock->num_readers > 0 || rw_lock->write_in_progress) + { + err = EBUSY; + } + else + { + rw_lock->write_in_progress = true; + } + + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_timedwrlock(FAR pthread_rwlock_t *rw_lock, + FAR const struct timespec *ts) +{ + int err = pthread_mutex_lock(&rw_lock->lock); + + if (err != 0) + { + return err; + } + + if (rw_lock->num_writers == UINT_MAX) + { + err = EAGAIN; + goto exit_with_mutex; + } + + rw_lock->num_writers++; + + while (rw_lock->write_in_progress || rw_lock->num_readers > 0) + { + if (ts != NULL) + { + err = pthread_cond_timedwait(&rw_lock->cv, &rw_lock->lock, ts); + } + else + { + err = pthread_cond_wait(&rw_lock->cv, &rw_lock->lock); + } + + if (err != 0) + { + break; + } + } + + if (err == 0) + { + rw_lock->write_in_progress = true; + } + + else + { + /* In case of error, notify any blocked readers. */ + + (void) pthread_cond_broadcast(&rw_lock->cv); + } + + rw_lock->num_writers--; + +exit_with_mutex: + pthread_mutex_unlock(&rw_lock->lock); + return err; +} + +int pthread_rwlock_wrlock(FAR pthread_rwlock_t *rw_lock) +{ + return pthread_rwlock_timedwrlock(rw_lock, NULL); +} diff --git a/net/netdev/netdev_ioctl.c b/net/netdev/netdev_ioctl.c index a9a70191fdb..413a5d10fc8 100644 --- a/net/netdev/netdev_ioctl.c +++ b/net/netdev/netdev_ioctl.c @@ -59,6 +59,10 @@ #include #include +#ifdef CONFIG_NET_6LOWPAN +# include +#endif + #ifdef CONFIG_NET_IGMP # include # include @@ -702,16 +706,47 @@ static int netdev_ifrioctl(FAR struct socket *psock, int cmd, /* MAC address operations only make sense if Ethernet is supported */ -#ifdef CONFIG_NET_ETHERNET +#if defined(CONFIG_NET_ETHERNET) || defined(CONFIG_NET_6LOWPAN) case SIOCGIFHWADDR: /* Get hardware address */ { dev = netdev_ifrdev(req); if (dev) { - req->ifr_hwaddr.sa_family = AF_INETX; - memcpy(req->ifr_hwaddr.sa_data, - dev->d_mac.ether_addr_octet, IFHWADDRLEN); - ret = OK; +#ifdef CONFIG_NET_ETHERNET +#ifdef CONFIG_NET_MULTILINK + if (dev->d_lltype == NET_LL_ETHERNET) +#else + if (true) +#endif + { + req->ifr_hwaddr.sa_family = AF_INETX; + memcpy(req->ifr_hwaddr.sa_data, + dev->d_mac.ether_addr_octet, IFHWADDRLEN); + ret = OK; + } + else +#endif + +#ifdef CONFIG_NET_6LOWPAN +#ifdef CONFIG_NET_MULTILINK + if (dev->d_lltype == NET_LL_IEEE802154) +#else + if (true) +#endif + { + FAR struct ieee802154_driver_s *ieee = + (FAR struct ieee802154_driver_s *)dev; + + req->ifr_hwaddr.sa_family = AF_INETX; + memcpy(req->ifr_hwaddr.sa_data, ieee->i_nodeaddr.u8, + CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + ret = OK; + } + else +#endif + { + nerr("Unsupported link layer\n"); + } } } break; @@ -721,9 +756,40 @@ static int netdev_ifrioctl(FAR struct socket *psock, int cmd, dev = netdev_ifrdev(req); if (dev) { - memcpy(dev->d_mac.ether_addr_octet, - req->ifr_hwaddr.sa_data, IFHWADDRLEN); - ret = OK; +#ifdef CONFIG_NET_ETHERNET +#ifdef CONFIG_NET_MULTILINK + if (dev->d_lltype == NET_LL_ETHERNET) +#else + if (true) +#endif + { + memcpy(dev->d_mac.ether_addr_octet, + req->ifr_hwaddr.sa_data, IFHWADDRLEN); + ret = OK; + } + else +#endif + +#ifdef CONFIG_NET_6LOWPAN +#ifdef CONFIG_NET_MULTILINK + if (dev->d_lltype == NET_LL_IEEE802154) +#else + if (true) +#endif + { + FAR struct ieee802154_driver_s *ieee = + (FAR struct ieee802154_driver_s *)dev; + + req->ifr_hwaddr.sa_family = AF_INETX; + memcpy(ieee->i_nodeaddr.u8, req->ifr_hwaddr.sa_data, + CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + ret = OK; + } + else +#endif + { + nerr("Unsupported link layer\n"); + } } } break; diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c index bd4dd2e8eb6..552f394b786 100644 --- a/net/sixlowpan/sixlowpan_framelist.c +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -101,17 +101,15 @@ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Input Parameters: - * ieee - Pointer to IEEE802.15.4 MAC driver structure. - * destip - Pointer to the IPv6 header to "compress" - * fptr - Pointer to the beginning of the frame under construction + * ipv6hdr - Pointer to the IPv6 header to "compress" + * fptr - Pointer to the beginning of the frame under construction * * Returned Value: * None * ****************************************************************************/ -static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, - FAR const struct ipv6_hdr_s *destip, +static void sixlowpan_compress_ipv6hdr(FAR const struct ipv6_hdr_s *ipv6hdr, FAR uint8_t *fptr) { /* Indicate the IPv6 dispatch and length */ @@ -121,11 +119,101 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, /* Copy the IPv6 header and adjust pointers */ - memcpy(&fptr[g_frame_hdrlen] , destip, IPv6_HDRLEN); + memcpy(&fptr[g_frame_hdrlen] , ipv6hdr, IPv6_HDRLEN); g_frame_hdrlen += IPv6_HDRLEN; g_uncomp_hdrlen += IPv6_HDRLEN; } +/**************************************************************************** + * Name: sixlowpan_copy_protohdr + * + * Description: + * The IPv6 header should have already been processed (as reflected in the + * g_uncomphdrlen). But we probably still need to copy the following + * protocol header. + * + * Input Parameters: + * ipv6hdr - Pointer to the IPv6 header to "compress" + * fptr - Pointer to the beginning of the frame under construction + * + * Returned Value: + * None. But g_frame_hdrlen and g_uncomp_hdrlen updated. + * + ****************************************************************************/ + +static void sixlowpan_copy_protohdr(FAR const struct ipv6_hdr_s *ipv6hdr, + FAR uint8_t *fptr) +{ + uint16_t combined; + uint16_t protosize; + uint16_t copysize; + + /* What is the total size of the IPv6 + protocol header? */ + + switch (ipv6hdr->proto) + { +#ifdef CONFIG_NET_TCP + case IP_PROTO_TCP: + { + FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6hdr)->tcp; + + /* The TCP header length is encoded in the top 4 bits of the + * tcpoffset field (in units of 32-bit words). + */ + + protosize = ((uint16_t)tcp->tcpoffset >> 4) << 2; + combined = sizeof(struct ipv6_hdr_s) + protosize; + } + break; +#endif + +#ifdef CONFIG_NET_UDP + case IP_PROTO_UDP: + protosize = sizeof(struct udp_hdr_s); + combined = sizeof(struct ipv6udp_hdr_s); + break; +#endif + +#ifdef CONFIG_NET_ICMPv6 + case IP_PROTO_ICMP6: + protosize = sizeof(struct icmpv6_hdr_s); + combined = sizeof(struct ipv6icmp_hdr_s); + break; +#endif + + default: + nwarn("WARNING: Unrecognized proto: %u\n", ipv6hdr->proto); + protosize = 0; + combined = sizeof(struct ipv6_hdr_s); + break; + } + + /* Copy the remaining protocol header. */ + + if (g_uncomp_hdrlen > IPv6_HDRLEN) + { + nwarn("WARNING: Protocol header not copied: " + "g_uncomp_hdren=%u IPv6_HDRLEN=%u\n", + g_uncomp_hdrlen, IPv6_HDRLEN); + return; + } + + copysize = combined - g_uncomp_hdrlen; + if (copysize != protosize) + { + nwarn("WARNING: Protocol header size mismatch: " + "g_uncomp_hdren=%u copysize=%u protosize=%u\n", + g_uncomp_hdrlen, copysize, protosize); + return; + } + + memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)ipv6hdr + g_uncomp_hdrlen, + copysize); + + g_frame_hdrlen += copysize; + g_uncomp_hdrlen += copysize; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -146,7 +234,7 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, * * Input Parameters: * ieee - The IEEE802.15.4 MAC driver instance - * ipv6hdr - IPv6 header followed by TCP or UDP header. + * ipv6hdr - IPv6 header followed by TCP, UDP, or ICMPv6 header. * buf - Beginning of the packet packet to send (with IPv6 + protocol * headers) * buflen - Length of data to send (include IPv6 and protocol headers) @@ -172,6 +260,8 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, FAR uint8_t *fptr; int framer_hdrlen; struct rimeaddr_s bcastmac; + uint16_t pktlen; + uint16_t paysize; #ifdef CONFIG_NET_6LOWPAN_FRAG uint16_t outlen = 0; #endif @@ -267,7 +357,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, { /* Small.. use IPv6 dispatch (no compression) */ - sixlowpan_compress_ipv6hdr(ieee, destip, fptr); + sixlowpan_compress_ipv6hdr(destip, fptr); } ninfo("Header of length %d\n", g_frame_hdrlen); @@ -276,9 +366,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Check if we need to fragment the packet into several frames */ - if ((int)buflen - (int)g_uncomp_hdrlen > - (int)CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - - (int)g_frame_hdrlen) + if (buflen > (CONFIG_NET_6LOWPAN_MAXPAYLOAD - g_frame_hdrlen)) { #ifdef CONFIG_NET_6LOWPAN_FRAG /* ieee->i_framelist will hold the generated frames; frames will be @@ -286,6 +374,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, */ FAR struct iob_s *qtail; + FAR uint8_t *frame1; int verify; /* The outbound IPv6 packet is too large to fit into a single 15.4 @@ -295,7 +384,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, * The following fragments contain only the fragn dispatch. */ - ninfo("Fragmentation sending packet length %d\n", buflen); + ninfo("Sending fragmented packet length %d\n", buflen); /* Create 1st Fragment */ /* Add the frame header using the pre-allocated IOB. */ @@ -304,7 +393,9 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, DEBUGASSERT(verify == framer_hdrlen); UNUSED(verify); - /* Move HC1/HC06/IPv6 header */ + /* Move HC1/HC06/IPv6 header to make space for the FRAG1 header at the + * beginning of the frame. + */ memmove(fptr + SIXLOWPAN_FRAG1_HDR_LEN, fptr, g_frame_hdrlen); @@ -323,27 +414,31 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, * bytes for all subsequent headers. */ + pktlen = buflen + g_uncomp_hdrlen; PUTINT16(fptr, RIME_FRAG_DISPATCH_SIZE, - ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | buflen)); + ((SIXLOWPAN_DISPATCH_FRAG1 << 8) | pktlen)); PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag); - ieee->i_dgramtag++; - /* Copy payload and enqueue */ + g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; - g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; - g_rime_payloadlen = - (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8; + /* Copy protocol header that follows the IPv6 header */ - memcpy(fptr + g_frame_hdrlen, - (FAR uint8_t *)destip + g_uncomp_hdrlen, g_rime_payloadlen); - iob->io_len += g_rime_payloadlen + g_frame_hdrlen; + sixlowpan_copy_protohdr(destip, fptr); + + /* Copy payload and enqueue. NOTE that the size is a multiple of eight + * bytes. + */ + + paysize = (CONFIG_NET_6LOWPAN_MAXPAYLOAD - g_frame_hdrlen) & ~7; + memcpy(fptr + g_frame_hdrlen, buf, paysize); /* Set outlen to what we already sent from the IP payload */ - outlen = g_rime_payloadlen + g_uncomp_hdrlen; + iob->io_len = paysize + g_frame_hdrlen; + outlen = paysize; ninfo("First fragment: length %d, tag %d\n", - g_rime_payloadlen, ieee->i_dgramtag); + paysize, ieee->i_dgramtag); sixlowpan_dumpbuffer("Outgoing frame", (FAR const uint8_t *)iob->io_data, iob->io_len); @@ -358,10 +453,11 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Create following fragments */ - g_frame_hdrlen = SIXLOWPAN_FRAGN_HDR_LEN; - + frame1 = iob->io_data; while (outlen < buflen) { + uint16_t fragn_hdrlen; + /* Allocate an IOB to hold the next fragment, waiting if * necessary. */ @@ -377,47 +473,45 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, iob->io_pktlen = 0; fptr = iob->io_data; - /* Add the frame header */ + /* Copy the frame header from first frame, into the correct + * location after the FRAGN header. + */ - verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); - DEBUGASSERT(verify == framer_hdrlen); - UNUSED(verify); + memmove(fptr + SIXLOWPAN_FRAGN_HDR_LEN, + frame1 + SIXLOWPAN_FRAG1_HDR_LEN, + framer_hdrlen); + fragn_hdrlen = framer_hdrlen; - /* Move HC1/HC06/IPv6 header */ - - memmove(fptr + SIXLOWPAN_FRAGN_HDR_LEN, fptr, g_frame_hdrlen); - - /* Setup up the fragment header */ + /* Setup up the FRAGN header at the beginning of the frame */ PUTINT16(fptr, RIME_FRAG_DISPATCH_SIZE, - ((SIXLOWPAN_DISPATCH_FRAGN << 8) | buflen)); + ((SIXLOWPAN_DISPATCH_FRAGN << 8) | pktlen)); PUTINT16(fptr, RIME_FRAG_TAG, ieee->i_dgramtag); fptr[RIME_FRAG_OFFSET] = outlen >> 3; + fragn_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; + /* Copy payload and enqueue */ + /* Check for the last fragment */ - if (buflen - outlen < g_rime_payloadlen) + paysize = (CONFIG_NET_6LOWPAN_MAXPAYLOAD - fragn_hdrlen) & + SIXLOWPAN_DISPATCH_FRAG_MASK; + if (buflen - outlen < paysize) { - /* Last fragment */ + /* Last fragment, truncate to the correct length */ - g_rime_payloadlen = buflen - outlen; - } - else - { - g_rime_payloadlen = - (CONFIG_NET_6LOWPAN_MAXPAYLOAD - framer_hdrlen - g_frame_hdrlen) & 0xf8; + paysize = buflen - outlen; } - memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + outlen, - g_rime_payloadlen); - iob->io_len = g_rime_payloadlen + g_frame_hdrlen; + memcpy(fptr + fragn_hdrlen, buf + outlen, paysize); /* Set outlen to what we already sent from the IP payload */ - outlen += (g_rime_payloadlen + g_uncomp_hdrlen); + iob->io_len = paysize + fragn_hdrlen; + outlen += paysize; - ninfo("sixlowpan output: fragment offset %d, length %d, tag %d\n", - outlen >> 3, g_rime_payloadlen, ieee->i_dgramtag); + ninfo("Fragment offset=%d, paysize=%d, i_dgramtag=%d\n", + outlen >> 3, paysize, ieee->i_dgramtag); sixlowpan_dumpbuffer("Outgoing frame", (FAR const uint8_t *)iob->io_data, iob->io_len); @@ -425,11 +519,16 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Add the next frame to the tail of the IOB queue */ qtail->io_flink = iob; + qtail = iob; /* Keep track of the total amount of data queue */ ieee->i_framelist->io_pktlen += iob->io_len; } + + /* Update the datagram TAG value */ + + ieee->i_dgramtag++; #else nerr("ERROR: Packet too large: %d\n", buflen); nerr(" Cannot to be sent without fragmentation support\n"); @@ -452,11 +551,14 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, DEBUGASSERT(verify == framer_hdrlen); UNUSED(verify); + /* Copy protocol header that follows the IPv6 header */ + + sixlowpan_copy_protohdr(destip, fptr); + /* Copy the payload and queue */ - memcpy(fptr + g_frame_hdrlen, (FAR uint8_t *)destip + g_uncomp_hdrlen, - buflen - g_uncomp_hdrlen); - iob->io_len = buflen - g_uncomp_hdrlen + g_frame_hdrlen; + memcpy(fptr + g_frame_hdrlen, buf, buflen); + iob->io_len = buflen + g_frame_hdrlen; ninfo("Non-fragmented: length %d\n", iob->io_len); sixlowpan_dumpbuffer("Outgoing frame", diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c index 8f48ade9f2f..aac17f7eb9c 100644 --- a/net/sixlowpan/sixlowpan_globals.c +++ b/net/sixlowpan/sixlowpan_globals.c @@ -54,15 +54,6 @@ * during that processing */ -/* The length of the payload in the Rime buffer. - * - * The payload is what comes after the compressed or uncompressed headers - * (can be the IP payload if the IP header only is compressed or the UDP - * payload if the UDP header is also compressed) - */ - -uint8_t g_rime_payloadlen; - /* g_uncomp_hdrlen is the length of the headers before compression (if HC2 * is used this includes the UDP header in addition to the IP header). */ diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index a7040d5bcb3..6626501363c 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -116,7 +116,8 @@ * * Input Parmeters: * ieee - A reference to the IEE802.15.4 network device state - * ipv6 - The IPv6 header to be compressed + * ipv6 - The IPv6 header followd by TCP, UDP, or ICMPv6 header to be + * compressed * destmac - L2 destination address, needed to compress the IP * destination field * fptr - Pointer to frame to be compressed. @@ -189,7 +190,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, #if CONFIG_NET_UDP case IP_PROTO_UDP: { - FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev); + FAR struct udp_hdr_s *udp = + &(((FAR struct ipv6udp_hdr_s *)ipv6)->udp); /* Try to compress UDP header (we do only full compression). * This is feasible if both src and dest ports are between @@ -199,10 +201,10 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, ninfo("local/remote port %u/%u\n", udp->srcport, udp->destport); - if (htons(udp->srcport) >= CONFIG_NET_6LOWPAN_MINPORT && - htons(udp->srcport) < (CONFIG_NET_6LOWPAN_MINPORT + 16) && - htons(udp->destport) >= CONFIG_NET_6LOWPAN_MINPORT && - htons(udp->destport) < (CONFIG_NET_6LOWPAN_MINPORT + 16)) + if (ntohs(udp->srcport) >= CONFIG_NET_6LOWPAN_MINPORT && + ntohs(udp->srcport) < (CONFIG_NET_6LOWPAN_MINPORT + 16) && + ntohs(udp->destport) >= CONFIG_NET_6LOWPAN_MINPORT && + ntohs(udp->destport) < (CONFIG_NET_6LOWPAN_MINPORT + 16)) { FAR uint8_t *hcudp = fptr + g_frame_hdrlen; @@ -215,8 +217,8 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] = 0xe0; hcudp[RIME_HC1_HC_UDP_TTL] = ipv6->ttl; hcudp[RIME_HC1_HC_UDP_PORTS] = - (uint8_t)((htons(udp->srcport) - CONFIG_NET_6LOWPAN_MINPORT) << 4) + - (uint8_t)((htons(udp->destport) - CONFIG_NET_6LOWPAN_MINPORT)); + (uint8_t)((ntohs(udp->srcport) - CONFIG_NET_6LOWPAN_MINPORT) << 4) + + (uint8_t)((ntohs(udp->destport) - CONFIG_NET_6LOWPAN_MINPORT)); memcpy(&hcudp[RIME_HC1_HC_UDP_CHKSUM], &udp->udpchksum, 2); diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index 257e7b48c9e..6098a58251c 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -86,6 +86,7 @@ /* Buffer access helpers */ #define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf)) +#define TCPBUF(dev) ((FAR struct tcp_hdr_s *)&(dev)->d_buf[IPv6_HDRLEN]) /**************************************************************************** * Private Functions @@ -111,12 +112,26 @@ int sixlowpan_recv_hdrlen(FAR const uint8_t *fptr) { - uint16_t hdrlen; + uint16_t hdrlen = 0; uint8_t addrmode; + uint8_t tmp; + + /* Check for a fragment header preceding the IEEE802.15.4 FCF */ + + tmp = *fptr & SIXLOWPAN_DISPATCH_FRAG_MASK; + if (tmp == SIXLOWPAN_DISPATCH_FRAG1) + { + hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; + } + else if (tmp == SIXLOWPAN_DISPATCH_FRAGN) + { + hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; + } /* Minimum header: 2 byte FCF + 1 byte sequence number */ - hdrlen = 3; + fptr += hdrlen; + hdrlen += 3; /* Account for destination address size */ @@ -209,10 +224,9 @@ int sixlowpan_recv_hdrlen(FAR const uint8_t *fptr) static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, FAR struct iob_s *iob) { - FAR uint8_t *payptr; /* Pointer to the frame payload */ FAR uint8_t *hc1; /* Convenience pointer to HC1 data */ - uint16_t fragsize = 0; /* Size of the IP packet (read from fragment) */ + uint16_t paysize; /* Size of the data payload */ uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */ int reqsize; /* Required buffer size */ int hdrsize; /* Size of the IEEE802.15.4 header */ @@ -220,12 +234,13 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, #ifdef CONFIG_NET_6LOWPAN_FRAG bool isfrag = false; bool isfirstfrag = false; - bool islastfrag = false; uint16_t fragtag = 0; /* Tag of the fragment */ systime_t elapsed; /* Elapsed time */ #endif /* CONFIG_NET_6LOWPAN_FRAG */ - /* Get a pointer to the payload following the IEEE802.15.4 frame header. */ + /* Get a pointer to the payload following the IEEE802.15.4 frame header(s). + * This size includes both fragmentation and FCF headers. + */ hdrsize = sixlowpan_recv_hdrlen(iob->io_data); if (hdrsize < 0) @@ -241,16 +256,13 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, g_uncomp_hdrlen = 0; g_frame_hdrlen = hdrsize; - /* Payload starts after the IEEE802.15.4 header */ - - payptr = &iob->io_data[hdrsize]; - #ifdef CONFIG_NET_6LOWPAN_FRAG /* Since we don't support the mesh and broadcast header, the first header - * we look for is the fragmentation header + * we look for is the fragmentation header. NOTE that g_frame_hdrlen + * already includes the fragementation header, if presetn. */ - switch ((GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) + switch ((GETINT16(iob->io_data, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) { /* First fragment of new reassembly */ @@ -258,15 +270,12 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, { /* Set up for the reassembly */ - fragoffset = 0; - fragsize = GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; - fragtag = GETINT16(payptr, RIME_FRAG_TAG); + fragsize = GETINT16(iob->io_data, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; + fragtag = GETINT16(iob->io_data, RIME_FRAG_TAG); - ninfo("FRAG1: size %d, tag %d, offset %d\n", + ninfo("FRAG1: fragsize=%d fragtag=%d fragoffset=%d\n", fragsize, fragtag, fragoffset); - g_frame_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; - /* Indicate the first fragment of the reassembly */ isfirstfrag = true; @@ -278,32 +287,18 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, { /* Set offset, tag, size. Offset is in units of 8 bytes. */ - fragoffset = payptr[RIME_FRAG_OFFSET]; - fragtag = GETINT16(payptr, RIME_FRAG_TAG); - fragsize = GETINT16(payptr, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; + fragoffset = iob->io_data[RIME_FRAG_OFFSET]; + fragtag = GETINT16(iob->io_data, RIME_FRAG_TAG); + fragsize = GETINT16(iob->io_data, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; - ninfo("FRAGN: size %d, tag %d, offset %d\n", + ninfo("FRAGN: fragsize=%d fragtag=%d fragoffset=%d\n", fragsize, fragtag, fragoffset); - - g_frame_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; - - ninfo("FRAGN: i_accumlen %d g_rime_payloadlen %d fragsize %d\n", + ninfo("FRAGN: i_accumlen=%d paysize=%u fragsize=%u\n", ieee->i_accumlen, iob->io_len - g_frame_hdrlen, fragsize); /* Indicate that this frame is a another fragment for reassembly */ isfrag = true; - - /* Check if it is the last fragement to be processed. - * - * If this is the last fragment, we may shave off any extrenous - * bytes at the end. We must be liberal in what we accept. - */ - - if (ieee->i_accumlen + iob->io_len - g_frame_hdrlen >= fragsize) - { - islastfrag = true; - } } break; @@ -392,6 +387,7 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, * compression dispatch logic. */ + g_uncomp_hdrlen = ieee->i_boffset; goto copypayload; } } @@ -412,29 +408,22 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, return OK; } - /* Start reassembly if we received a non-zero length, first fragment */ + /* Drop the packet if it cannot fit into the d_buf */ - if (fragsize > 0) + if (fragsize > CONFIG_NET_6LOWPAN_MTU) { - /* Drop the packet if it cannot fit into the d_buf */ - - if (fragsize > CONFIG_NET_6LOWPAN_MTU) - { - nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n"); - return OK; - } - - /* Set up for the reassembly */ - - ieee->i_pktlen = fragsize; - ieee->i_reasstag = fragtag; - ieee->i_time = clock_systimer(); - - ninfo("Starting reassembly: i_pktlen %d, i_pktlen %d\n", - ieee->i_pktlen, ieee->i_reasstag); - - rimeaddr_copy(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER]); + nwarn("WARNING: Reassembled packet size exeeds CONFIG_NET_6LOWPAN_MTU\n"); + return OK; } + + ieee->i_pktlen = fragsize; + ieee->i_reasstag = fragtag; + ieee->i_time = clock_systimer(); + + ninfo("Starting reassembly: i_pktlen %u, i_reasstag %d\n", + ieee->i_pktlen, ieee->i_reasstag); + + rimeaddr_copy(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER]); } #endif /* CONFIG_NET_6LOWPAN_FRAG */ @@ -445,7 +434,13 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 if ((hc1[RIME_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) == SIXLOWPAN_DISPATCH_IPHC) { + FAR uint8_t *payptr; + ninfo("IPHC Dispatch\n"); + + /* Payload starts after the IEEE802.15.4 header(s) */ + + payptr = &iob->io_data[g_frame_hdrlen]; sixlowpan_uncompresshdr_hc06(ieee, fragsize, iob, payptr); } else @@ -454,7 +449,13 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1) { + FAR uint8_t *payptr; + ninfo("HC1 Dispatch\n"); + + /* Payload starts after the IEEE802.15.4 header(s) */ + + payptr = &iob->io_data[g_frame_hdrlen]; sixlowpan_uncompresshdr_hc1(ieee, fragsize, iob, payptr); } else @@ -467,16 +468,9 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, ninfo("IPv6 Dispatch\n"); g_frame_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; - /* payptr was set up to begin just after the IPHC bytes. However, - * those bytes are not present for the case of IPv6 dispatch. Just - * reset back to the begnning of the buffer. - */ - - payptr = iob->io_data; - /* Put uncompressed IP header in d_buf. */ - memcpy(ipv6, payptr + g_frame_hdrlen, IPv6_HDRLEN); + memcpy(ipv6, iob->io_data + g_frame_hdrlen, IPv6_HDRLEN); /* Update g_uncomp_hdrlen and g_frame_hdrlen. */ @@ -492,6 +486,18 @@ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, } #ifdef CONFIG_NET_6LOWPAN_FRAG + /* Non-fragmented and FRAG1 frames pass through here. Remember the + * offset from the beginning of d_buf where be begin placing the data + * payload. + */ + + if (isfirstfrag) + { + ieee->i_boffset = g_uncomp_hdrlen; + } + + /* We branch to here on all good FRAGN frames */ + copypayload: #endif /* CONFIG_NET_6LOWPAN_FRAG */ @@ -501,28 +507,28 @@ copypayload: * and g_frame_hdrlen are non-zerio, fragoffset is. */ - g_rime_payloadlen = iob->io_len - g_frame_hdrlen; - if (g_rime_payloadlen > CONFIG_NET_6LOWPAN_MTU) + paysize = iob->io_len - g_frame_hdrlen; + if (paysize > CONFIG_NET_6LOWPAN_MTU) { nwarn("WARNING: Packet dropped due to payload (%u) > packet buffer (%u)\n", - g_rime_payloadlen, CONFIG_NET_6LOWPAN_MTU); + paysize, CONFIG_NET_6LOWPAN_MTU); return OK; } /* Sanity-check size of incoming packet to avoid buffer overflow */ - reqsize = g_uncomp_hdrlen + (uint16_t) (fragoffset << 3) + g_rime_payloadlen; + reqsize = g_uncomp_hdrlen + (fragoffset << 3) + paysize; if (reqsize > CONFIG_NET_6LOWPAN_MTU) { - ninfo("Required buffer size: %d+%d+%d=%d Available: %d\n", - g_uncomp_hdrlen, (int)(fragoffset << 3), g_rime_payloadlen, + ninfo("Required buffer size: %u+%u+%u=%u Available=%u\n", + g_uncomp_hdrlen, (fragoffset << 3), paysize, reqsize, CONFIG_NET_6LOWPAN_MTU); return -ENOMEM; } - memcpy((FAR uint8_t *)ieee->i_dev.d_buf + g_uncomp_hdrlen + - (int)(fragoffset << 3), payptr + g_frame_hdrlen, - g_rime_payloadlen); + memcpy(ieee->i_dev.d_buf + g_uncomp_hdrlen + (fragoffset << 3), + iob->io_data + g_frame_hdrlen, + paysize); #ifdef CONFIG_NET_6LOWPAN_FRAG /* Update ieee->i_accumlen if the frame is a fragment, ieee->i_pktlen @@ -531,42 +537,27 @@ copypayload: if (isfrag) { - /* Add the size of the header only for the first fragment. */ - - if (isfirstfrag) - { - ieee->i_accumlen += g_uncomp_hdrlen; - } - - /* For the last fragment, we are OK if there is extraneous bytes at the - * end of the packet. + /* Check if it is the last fragment to be processed. + * + * If this is the last fragment, we may shave off any extrenous + * bytes at the end. We must be liberal in what we accept. */ - if (islastfrag) - { - ieee->i_accumlen = fragsize; - } - else - { - ieee->i_accumlen += g_rime_payloadlen; - } - - ninfo("i_accumlen %d, g_rime_payloadlen %d\n", - ieee->i_accumlen, g_rime_payloadlen); + ieee->i_accumlen = g_uncomp_hdrlen + (fragoffset << 3) + paysize; } else { - ieee->i_pktlen = g_rime_payloadlen + g_uncomp_hdrlen; + ieee->i_pktlen = paysize + g_uncomp_hdrlen; } /* If we have a full IP packet in sixlowpan_buf, deliver it to * the IP stack */ - ninfo("sixlowpan_init i_accumlen %d, ieee->i_pktlen %d\n", - ieee->i_accumlen, ieee->i_pktlen); + ninfo("i_accumlen=%d i_pktlen=%d paysize=%d\n", + ieee->i_accumlen, ieee->i_pktlen, paysize); - if (ieee->i_accumlen == 0 || ieee->i_accumlen == ieee->i_pktlen) + if (ieee->i_accumlen == 0 || ieee->i_accumlen >= ieee->i_pktlen) { ninfo("IP packet ready (length %d)\n", ieee->i_pktlen); @@ -580,7 +571,7 @@ copypayload: #else /* Deliver the packet to the IP stack */ - ieee->i_dev.d_len = g_rime_payloadlen + g_uncomp_hdrlen; + ieee->i_dev.d_len = paysize + g_uncomp_hdrlen; return INPUT_COMPLETE; #endif /* CONFIG_NET_6LOWPAN_FRAG */ } @@ -706,6 +697,10 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) ret = sixlowpan_frame_process(ieee, iob); + /* Free the IOB the held the consumed frame */ + + iob_free(iob); + /* Was the frame successfully processed? Is the packet in d_buf fully * reassembled? */ @@ -734,7 +729,7 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) * layer protocol header. */ - ipv6hdr = (FAR struct ipv6_hdr_s *)(ieee->i_dev.d_buf); + ipv6hdr = IPv6BUF(&ieee->i_dev); /* Get the Rime MAC address of the destination. This * assumes an encoding of the MAC address in the IPv6 @@ -749,7 +744,15 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) if (ipv6hdr->proto != IP_PROTO_TCP) { - hdrlen = IPv6_HDRLEN + TCP_HDRLEN; + FAR struct tcp_hdr_s *tcp = TCPBUF(&ieee->i_dev); + uint16_t tcplen; + + /* The TCP header length is encoded in the top 4 bits + * of the tcpoffset field (in units of 32-bit words). + */ + + tcplen = ((uint16_t)tcp->tcpoffset >> 4) << 2; + hdrlen = IPv6_HDRLEN + tcplen; } else if (ipv6hdr->proto != IP_PROTO_UDP) { diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 8f3e52dfd39..bd366c884ec 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -409,15 +409,6 @@ struct frame802154_s extern FAR uint8_t *g_rimeptr; -/* The length of the payload in the Rime buffer. - * - * The payload is what comes after the compressed or uncompressed headers - * (can be the IP payload if the IP header only is compressed or the UDP - * payload if the UDP header is also compressed) - */ - -extern uint8_t g_rime_payloadlen; - /* g_uncomp_hdrlen is the length of the headers before compression (if HC2 * is used this includes the UDP header in addition to the IP header). */ @@ -446,6 +437,7 @@ extern struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; struct net_driver_s; /* Forward reference */ struct ieee802154_driver_s; /* Forward reference */ +struct devif_callback_s; /* Forward reference */ struct ipv6_hdr_s; /* Forward reference */ struct rimeaddr_s; /* Forward reference */ struct iob_s; /* Forward reference */ @@ -466,7 +458,8 @@ struct iob_s; /* Forward reference */ * * Input Parameters: * dev - The IEEE802.15.4 MAC network driver interface. - * destip - IPv6 plus TCP or UDP headers. + * list - Head of callback list for send interrupt + * ipv6hdr - IPv6 plus TCP or UDP headers. * buf - Data to send * buflen - Length of data to send * raddr - The MAC address of the destination @@ -484,7 +477,8 @@ struct iob_s; /* Forward reference */ ****************************************************************************/ int sixlowpan_send(FAR struct net_driver_s *dev, - FAR const struct ipv6_hdr_s *destip, FAR const void *buf, + FAR struct devif_callback_s **list, + FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, size_t buflen, FAR const struct rimeaddr_s *raddr, uint16_t timeout); diff --git a/net/sixlowpan/sixlowpan_send.c b/net/sixlowpan/sixlowpan_send.c index 98cc577f5f5..8338a413473 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -176,7 +176,7 @@ static uint16_t send_interrupt(FAR struct net_driver_s *dev, { DEBUGASSERT((flags & WPAN_POLL) != 0); - /* Transfer the frame listto the IEEE802.15.4 MAC device */ + /* Transfer the frame list to the IEEE802.15.4 MAC device */ sinfo->s_result = sixlowpan_queue_frames((FAR struct ieee802154_driver_s *)dev, @@ -237,6 +237,7 @@ end_wait: * * Input Parameters: * dev - The IEEE802.15.4 MAC network driver interface. + * list - Head of callback list for send interrupt * ipv6hdr - IPv6 header followed by TCP or UDP header. * buf - Data to send * len - Length of data to send @@ -255,6 +256,7 @@ end_wait: ****************************************************************************/ int sixlowpan_send(FAR struct net_driver_s *dev, + FAR struct devif_callback_s **list, FAR const struct ipv6_hdr_s *ipv6hdr, FAR const void *buf, size_t len, FAR const struct rimeaddr_s *destmac, uint16_t timeout) @@ -283,7 +285,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, * device related events, no connect-related events. */ - sinfo.s_cb = devif_callback_alloc(dev, NULL); + sinfo.s_cb = devif_callback_alloc(dev, list); if (sinfo.s_cb != NULL) { int ret; @@ -312,7 +314,7 @@ int sixlowpan_send(FAR struct net_driver_s *dev, /* Make sure that no further interrupts are processed */ - devif_dev_callback_free(dev, sinfo.s_cb); + devif_conn_callback_free(dev, sinfo.s_cb, list); } } diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index 1ad8068a317..3ee39e72ed6 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -88,6 +88,7 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp, FAR const uint8_t *buf, uint16_t buflen) { uint16_t upperlen; + uint16_t tcplen; uint16_t sum; /* The length reported in the IPv6 header is the length of the payload @@ -115,9 +116,14 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp, sum = chksum(sum, (FAR uint8_t *)ipv6tcp->ipv6.srcipaddr, 2 * sizeof(net_ipv6addr_t)); - /* Sum the TCP header */ + /* Sum the TCP header + * + * The TCP header length is encoded in the top 4 bits of the tcpoffset + * field (in units of 32-bit words). + */ - sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, TCP_HDRLEN); + tcplen = ((uint16_t)ipv6tcp->tcp.tcpoffset >> 4) << 2; + sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, tcplen); /* Sum payload data. */ @@ -327,7 +333,8 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, timeout = 0; #endif - ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp, + ret = sixlowpan_send(dev, &conn->list, + (FAR const struct ipv6_hdr_s *)&ipv6tcp, buf, buflen, &destmac, timeout); if (ret < 0) { @@ -382,38 +389,62 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev) if (dev != NULL && dev->d_len > 0) { - FAR struct ipv6_hdr_s *ipv6hdr; + FAR struct ipv6tcp_hdr_s *ipv6hdr; /* The IPv6 header followed by a TCP headers should lie at the * beginning of d_buf since there is no link layer protocol header * and the TCP state machine should only response with TCP packets. */ - ipv6hdr = (FAR struct ipv6_hdr_s *)(dev->d_buf); + ipv6hdr = (FAR struct ipv6tcp_hdr_s *)(dev->d_buf); /* The TCP data payload should follow the IPv6 header plus the * protocol header. */ - if (ipv6hdr->proto != IP_PROTO_TCP) + if (ipv6hdr->ipv6.proto != IP_PROTO_TCP) { - nwarn("WARNING: Expected TCP protoype: %u\n", ipv6hdr->proto); + nwarn("WARNING: Expected TCP protoype: %u vs %s\n", + ipv6hdr->ipv6.proto, IP_PROTO_TCP); } else { struct rimeaddr_s destmac; + FAR uint8_t *buf; + uint16_t hdrlen; + uint16_t buflen; /* Get the Rime MAC address of the destination. This assumes an * encoding of the MAC address in the IPv6 address. */ - sixlowpan_rimefromip(ipv6hdr->destipaddr, &destmac); + sixlowpan_rimefromip(ipv6hdr->ipv6.destipaddr, &destmac); - /* Convert the outgoing packet into a frame list. */ + /* Get the IPv6 + TCP combined header length. The size of the TCP + * header is encoded in the top 4 bits of the tcpoffset field (in + * units of 32-bit words). + */ - (void)sixlowpan_queue_frames( - (FAR struct ieee802154_driver_s *)dev, ipv6hdr, - dev->d_buf, dev->d_len, &destmac); + hdrlen = IPv6_HDRLEN + (((uint16_t)ipv6hdr->tcp.tcpoffset >> 4) << 2); + + /* Drop the packet if the buffer length is less than this. */ + + if (hdrlen > dev->d_len) + { + nwarn("WARNING: Dropping small TCP packet: %u < %u\n", + buflen, hdrlen); + } + else + { + /* Convert the outgoing packet into a frame list. */ + + buf = dev->d_buf + hdrlen; + buflen = dev->d_len - hdrlen; + + (void)sixlowpan_queue_frames( + (FAR struct ieee802154_driver_s *)dev, &ipv6hdr->ipv6, + buf, buflen, &destmac); + } } } diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 717df424a27..f8f62e528b1 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -191,8 +191,9 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, if (to6->sin6_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) { - nerr("ERROR: Invalid destination address\n"); - return (ssize_t)-EAFNOSUPPORT; + nerr("ERROR: Invalid destination address: sin6_family=%u tolen = %u\n", + to6->sin6_family, tolen); + return (ssize_t)-EPROTOTYPE; } /* Get the underlying UDP "connection" structure */ @@ -200,14 +201,6 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, conn = (FAR struct udp_conn_s *)psock->s_conn; DEBUGASSERT(conn != NULL); - /* Ignore if not IPv6 domain */ - - if (conn->domain != PF_INET6) - { - nwarn("WARNING: Not IPv6\n"); - return (ssize_t)-EPROTOTYPE; - } - /* Route outgoing message to the correct device */ #ifdef CONFIG_NETDEV_MULTINIC @@ -264,8 +257,8 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, /* Copy the source and destination addresses */ - net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, to6->sin6_addr.in6_u.u6_addr16); - net_ipv6addr_hdrcopy(ipv6udp.ipv6.destipaddr, conn->u.ipv6.raddr); + net_ipv6addr_hdrcopy(ipv6udp.ipv6.destipaddr, to6->sin6_addr.in6_u.u6_addr16); + net_ipv6addr_hdrcopy(ipv6udp.ipv6.srcipaddr, conn->u.ipv6.laddr); ninfo("IPv6 length: %d\n", ((int)ipv6udp.ipv6.len[0] << 8) + ipv6udp.ipv6.len[1]); @@ -315,7 +308,8 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, timeout = 0; #endif - ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, + ret = sixlowpan_send(dev, &conn->list, + (FAR const struct ipv6_hdr_s *)&ipv6udp, buf, buflen, &destmac, timeout); if (ret < 0) { diff --git a/wireless/ieee802154/mac802154_loopback.c b/wireless/ieee802154/mac802154_loopback.c index 1f8dc4e8c38..9cb9f096413 100644 --- a/wireless/ieee802154/mac802154_loopback.c +++ b/wireless/ieee802154/mac802154_loopback.c @@ -185,23 +185,25 @@ static int lo_txpoll(FAR struct net_driver_s *dev) /* Find the tail of the IOB queue */ for (tail = NULL, iob = head; - iob != NULL; - tail = iob, iob = iob->io_flink); + iob != NULL; + tail = iob, iob = iob->io_flink); /* Loop while there frames to be sent, i.e., while the IOB list is not * emtpy. Sending, of course, just means relaying back through the network * for this driver. */ - while (!FRAME_IOB_EMPTY(&priv->lo_ieee)) + while (head != NULL) { /* Remove the IOB from the queue */ - FRAME_IOB_REMOVE(&priv->lo_ieee, iob); + iob = head; + head = iob->io_flink; + iob->io_flink = NULL; /* Is the queue now empty? */ - if (FRAME_IOB_EMPTY(&priv->lo_ieee)) + if (head == NULL) { tail = NULL; } @@ -239,8 +241,8 @@ static int lo_txpoll(FAR struct net_driver_s *dev) /* Find the new tail of the IOB queue */ for (tail = iob, iob = iob->io_flink; - iob != NULL; - tail = iob, iob = iob->io_flink); + iob != NULL; + tail = iob, iob = iob->io_flink); } priv->lo_txdone = true;