diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c index 7703a9a745e..b17077fd54d 100644 --- a/arch/arm/src/stm32/stm32_eth.c +++ b/arch/arm/src/stm32/stm32_eth.c @@ -90,9 +90,7 @@ # error "Logic to support multiple Ethernet interfaces is incomplete" #endif -/* If processing is not done at the interrupt level, then work queue support - * is required. - */ +/* Work queue support is required. */ #if !defined(CONFIG_SCHED_WORKQUEUE) # error Work queue support is required diff --git a/include/nuttx/net/ip.h b/include/nuttx/net/ip.h index 6a07edd585b..c7b606078b7 100644 --- a/include/nuttx/net/ip.h +++ b/include/nuttx/net/ip.h @@ -483,7 +483,7 @@ EXTERN const net_ipv6addr_t g_ipv6_llnetmask; /* Netmask for local link addres #endif /**************************************************************************** - * Function: net_ipv4addr_maskcmp and net_ipv6addr_maskcmp + * Name: net_ipv4addr_maskcmp and net_ipv6addr_maskcmp * * Description: * Compare two IP addresses under a netmask. The mask is used to mask @@ -527,7 +527,86 @@ bool net_ipv6addr_maskcmp(const net_ipv6addr_t addr1, #endif /**************************************************************************** - * Function: net_ipaddr_mask + * Name: net_ipv6addr_prefixcmp + * + * Description: + * Compare two IPv6 address prefixes. + * + ****************************************************************************/ + +#define net_ipv6addr_prefixcmp(addr1, addr2, length) \ + (memcmp(addr1, addr2, length >> 3) == 0) + +/**************************************************************************** + * Name: net_is_addr_loopback + * + * Description: + * Is Ithe Pv6 address a the loopback address? + * + ****************************************************************************/ + +#define net_is_addr_loopback(a) \ + ((a)[0] == 0 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == 0x0001) + +/**************************************************************************** + * Name: net_is_addr_unspecified + * + * Description: + * Is Ithe Pv6 address the unspecified address? + * + ****************************************************************************/ + +#define net_is_addr_unspecified(a) \ + ((a)[0] == 0 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == 0) + +/**************************************************************************** + * Name: net_is_addr_mcast + * + * Description: + * s address a multicast address? see RFC 3513. + * + ****************************************************************************/ + +#define net_is_addr_mcast(a) (((a)[0] & 0xff00) == 0xff00) + +/**************************************************************************** + * Name: net_is_addr_linklocal_allnodes_mcast + * + * Description: + * Is IPv6 address a the link local all-nodes multicast address? + * + ****************************************************************************/ + +#define net_is_addr_linklocal_allnodes_mcast(a) \ + ((a)[0] == 0xff02 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == 0x0001) + +/**************************************************************************** + * Name: net_is_addr_linklocal_allrouters_mcast + * + * Description: + * Is IPv6 address a the link local all-routers multicast address? + * + ****************************************************************************/ + +#define net_is_addr_linklocal_allrouters_mcast(a) \ + ((a)[0] == 0xff02 && (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && (a)[7] == 0x0002) + +/**************************************************************************** + * Name: net_is_addr_linklocal + * + * Description: + * Checks whether the address a is link local. + * + ****************************************************************************/ + +#define net_is_addr_linklocal(a) ((a)[0] == 0xfe80) + +/**************************************************************************** + * Name: net_ipaddr_mask * * Description: * Mask out the network part of an IP address, given the address and diff --git a/include/nuttx/net/netconfig.h b/include/nuttx/net/netconfig.h index 0e912a53523..b320e0b98f7 100644 --- a/include/nuttx/net/netconfig.h +++ b/include/nuttx/net/netconfig.h @@ -336,67 +336,51 @@ #endif #ifdef CONFIG_NET_MULTILINK -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS - # ifdef CONFIG_NET_ETHERNET -# ifdef __LAST_MIN_UDP_MSS -# define __MIN_UDP_MSS(h) MIN(ETH_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) -# define __MAX_UDP_MSS(h) MAX(ETH_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) -# else -# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) -# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) -# endif -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS -# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) -# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# define __MIN_UDP_MSS(h) ETH_UDP_MSS(h) +# define __MAX_UDP_MSS(h) ETH_UDP_MSS(h) +# define __ETH_MIN_UDP_MSS(h) ETH_UDP_MSS(h) +# define __ETH_MAX_UDP_MSS(h) ETH_UDP_MSS(h) +# else +# define __ETH_MIN_UDP_MSS(h) INT_MAX +# define __ETH_MAX_UDP_MSS(h) 0 # endif # ifdef CONFIG_NET_6LOWPAN -# ifdef __LAST_MIN_UDP_MSS -# define __MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) -# define __MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) -# else -# define __MIN_UDP_MSS(h) IEEE802154_UDP_MSS(h) -# define __MAX_UDP_MSS(h) IEEE802154_UDP_MSS(h) -# endif -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS -# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) -# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# undef __MIN_UDP_MSS +# undef __MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__ETH_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__ETH_MAX_UDP_MSS(h)) +# define __6LOWPAN_MIN_UDP_MSS(h) MIN(IEEE802154_UDP_MSS(h),__ETH_MIN_UDP_MSS(h)) +# define __6LOWPAN_MAX_UDP_MSS(h) MAX(IEEE802154_UDP_MSS(h),__ETH_MAX_UDP_MSS(h)) +# else +# define __6LOWPAN_MIN_UDP_MSS(h) __ETH_MIN_UDP_MSS(h) +# define __6LOWPAN_MAX_UDP_MSS(h) __ETH_MAX_UDP_MSS(h) # endif # ifdef CONFIG_NET_LOOPBACK -# ifdef __LAST_MIN_UDP_MSS -# define __MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) -# define __MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) -# else -# define __MIN_UDP_MSS(h) LO_UDP_MSS(h) -# define __MAX_UDP_MSS(h) LO_UDP_MSS(h) -# endif -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS -# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) -# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# undef __MIN_UDP_MSS +# undef __MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__6LOWPAN_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__6LOWPAN_MAX_UDP_MSS(h)) +# define __LOOP_MIN_UDP_MSS(h) MIN(LO_UDP_MSS(h),__6LOWPAN_MIN_UDP_MSS(h)) +# define __LOOP_MAX_UDP_MSS(h) MAX(LO_UDP_MSS(h),__6LOWPAN_MAX_UDP_MSS(h)) +# else +# define __LOOP_MIN_UDP_MSS(h) __6LOWPAN_MIN_UDP_MSS(h) +# define __LOOP_MAX_UDP_MSS(h) __6LOWPAN_MAX_UDP_MSS(h) # endif # ifdef CONFIG_NET_SLIP -# ifdef __LAST_MIN_UDP_MSS -# define __MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LAST_MIN_UDP_MSS(h)) -# define __MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LAST_MAX_UDP_MSS(h)) -# else -# define __MIN_UDP_MSS(h) SLIP_UDP_MSS(h) -# define __MAX_UDP_MSS(h) SLIP_UDP_MSS(h) -# endif -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS -# define __LAST_MIN_UDP_MSS(h) __MIN_UDP_MSS(h) -# define __LAST_MAX_UDP_MSS(h) __MAX_UDP_MSS(h) +# undef __MIN_UDP_MSS +# undef __MIN_UDP_MSS +# define __MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LOOP_MIN_UDP_MSS(h)) +# define __MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LOOP_MAX_UDP_MSS(h)) +# define __SLIP_MIN_UDP_MSS(h) MIN(SLIP_UDP_MSS(h),__LOOP_MIN_UDP_MSS(h)) +# define __SLIP_MAX_UDP_MSS(h) MAX(SLIP_UDP_MSS(h),__LOOP_MAX_UDP_MSS(h)) +# else +# define __SLIP_MIN_UDP_MSS(h) __LOOP_MIN_UDP_MSS(h) +# define __SLIP_MAX_UDP_MSS(h) __LOOP_MAX_UDP_MSS(h) # endif - -# undef __LAST_MIN_UDP_MSS -# undef __LAST_MAX_UDP_MSS #endif /* NOTE: MSS calcuation excludes the UDP_HDRLEN. */ @@ -531,67 +515,52 @@ #endif #ifdef CONFIG_NET_MULTILINK -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS # ifdef CONFIG_NET_ETHERNET -# ifdef __LAST_MIN_TCP_MSS -# define __MIN_TCP_MSS(h) MIN(ETH_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) -# define __MAX_TCP_MSS(h) MAX(ETH_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) -# else -# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) -# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) -# endif -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS -# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) -# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# define __MIN_TCP_MSS(h) ETH_TCP_MSS(h) +# define __MAX_TCP_MSS(h) ETH_TCP_MSS(h) +# define __ETH_MIN_TCP_MSS(h) ETH_TCP_MSS(h) +# define __ETH_MAX_TCP_MSS(h) ETH_TCP_MSS(h) +# else +# define __ETH_MIN_TCP_MSS(h) INT_MAX +# define __ETH_MAX_TCP_MSS(h) 0 # endif # ifdef CONFIG_NET_6LOWPAN -# ifdef __LAST_MIN_TCP_MSS -# define __MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) -# define __MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) -# else -# define __MIN_TCP_MSS(h) IEEE802154_TCP_MSS(h) -# define __MAX_TCP_MSS(h) IEEE802154_TCP_MSS(h) -# endif -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS -# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) -# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# undef __MIN_TCP_MSS +# undef __MAX_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__ETH_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__ETH_MAX_TCP_MSS(h)) +# define __6LOWPAN_MIN_TCP_MSS(h) MIN(IEEE802154_TCP_MSS(h),__ETH_MIN_TCP_MSS(h)) +# define __6LOWPAN_MAX_TCP_MSS(h) MAX(IEEE802154_TCP_MSS(h),__ETH_MAX_TCP_MSS(h)) +# else +# define __6LOWPAN_MIN_TCP_MSS(h) __ETH_MIN_TCP_MSS(h) +# define __6LOWPAN_MAX_TCP_MSS(h) __ETH_MAX_TCP_MSS(h) # endif # ifdef CONFIG_NET_LOOPBACK -# ifdef __LAST_MIN_TCP_MSS -# define __MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) -# define __MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) -# else -# define __MIN_TCP_MSS(h) LO_TCP_MSS(h) -# define __MAX_TCP_MSS(h) LO_TCP_MSS(h) -# endif -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS -# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) -# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# undef __MIN_TCP_MSS +# undef __MAX_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__6LOWPAN_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__6LOWPAN_MAX_TCP_MSS(h)) +# define __LOOP_MIN_TCP_MSS(h) MIN(LO_TCP_MSS(h),__6LOWPAN_MIN_TCP_MSS(h)) +# define __LOOP_MAX_TCP_MSS(h) MAX(LO_TCP_MSS(h),__6LOWPAN_MAX_TCP_MSS(h)) +# else +# define __LOOP_MIN_TCP_MSS(h) _6LOWPAN_MIN_TCP_MSS(h) +# define __LOOP_MAX_TCP_MSS(h) __6LOWPAN_MAX_TCP_MSS(h) # endif # ifdef CONFIG_NET_SLIP -# ifdef __LAST_MIN_TCP_MSS -# define __MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LAST_MIN_TCP_MSS(h)) -# define __MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LAST_MAX_TCP_MSS(h)) -# else -# define __MIN_TCP_MSS(h) SLIP_TCP_MSS(h) -# define __MAX_TCP_MSS(h) SLIP_TCP_MSS(h) -# endif -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS -# define __LAST_MIN_TCP_MSS(h) __MIN_TCP_MSS(h) -# define __LAST_MAX_TCP_MSS(h) __MAX_TCP_MSS(h) +# undef __MIN_TCP_MSS +# undef __MAX_TCP_MSS +# define __MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LOOP_MIN_TCP_MSS(h)) +# define __MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LOOP_MAX_TCP_MSS(h)) +# define __SLIP_MIN_TCP_MSS(h) MIN(SLIP_TCP_MSS(h),__LOOP_MIN_TCP_MSS(h)) +# define __SLIP_MAX_TCP_MSS(h) MAX(SLIP_TCP_MSS(h),__LOOP_MAX_TCP_MSS(h)) +# else +# define __SLIP_MIN_TCP_MSS(h) __LOOP_MIN_TCP_MSS(h) +# define __SLIP_MAX_TCP_MSS(h) __LOOP_MAX_TCP_MSS(h) # endif - -# undef __LAST_MIN_TCP_MSS -# undef __LAST_MAX_TCP_MSS #endif /* If IPv4 is supported, it will have the larger MSS. diff --git a/include/nuttx/net/sixlowpan.h b/include/nuttx/net/sixlowpan.h index f31c453c439..ebeb34933ac 100644 --- a/include/nuttx/net/sixlowpan.h +++ b/include/nuttx/net/sixlowpan.h @@ -53,6 +53,7 @@ #include +#include #include #include @@ -71,9 +72,13 @@ #define SIXLOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */ #define SIXLOWPAN_DISPATCH_HC1 0x42 /* 01000010 = 66 */ -#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */ + +#define SIXLOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx */ +#define SIXLOWPAN_DISPATCH_IPHC_MASK 0xe0 /* 11100000 */ + #define SIXLOWPAN_DISPATCH_FRAG1 0xc0 /* 11000xxx */ #define SIXLOWPAN_DISPATCH_FRAGN 0xe0 /* 11100xxx */ +#define SIXLOWPAN_DISPATCH_FRAG_MASK 0xf1 /* 11111000 */ /* HC1 encoding */ @@ -155,77 +160,6 @@ #define SIXLOWPAN_FRAG1_HDR_LEN 4 #define SIXLOWPAN_FRAGN_HDR_LEN 5 -/* Address compressibility test macros */ - -/* Check whether we can compress the IID in address 'a' to 16 bits. This is - * used for unicast addresses only, and is true if the address is on the - * format ::0000:00ff:fe00:XXXX - * - * NOTE: we currently assume 64-bits prefixes - */ - -#define SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(a) \ - ((((a)->u16[4]) == 0) && \ - // (((a)->u8[10]) == 0)&& \ - (((a)->u8[11]) == 0xff)&& \ - (((a)->u8[12]) == 0xfe)&& \ - (((a)->u8[13]) == 0)) - -/* Check whether the 9-bit group-id of the compressed multicast address is - * known. It is true if the 9-bit group is the all nodes or all routers - * group. Parameter 'a' is typed uint8_t * - */ - -#define SIXLOWPAN_IS_MCASTADDR_DECOMPRESSABLE(a) \ - (((*a & 0x01) == 0) && \ - ((*(a + 1) == 0x01) || (*(a + 1) == 0x02))) - -/* Check whether the 112-bit group-id of the multicast address is mappable - * to a 9-bit group-id. It is true if the group is the all nodes or all - * routers group. - */ - -#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE(a) \ - ((((a)->u16[1]) == 0) && \ - (((a)->u16[2]) == 0) && \ - (((a)->u16[3]) == 0) && \ - (((a)->u16[4]) == 0) && \ - (((a)->u16[5]) == 0) && \ - (((a)->u16[6]) == 0) && \ - (((a)->u8[14]) == 0) && \ - ((((a)->u8[15]) == 1) || (((a)->u8[15]) == 2))) - -/* FFXX::00XX:XXXX:XXXX */ - -#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(a) \ - ((((a)->u16[1]) == 0) && \ - (((a)->u16[2]) == 0) && \ - (((a)->u16[3]) == 0) && \ - (((a)->u16[4]) == 0) && \ - (((a)->u8[10]) == 0)) - -/* FFXX::00XX:XXXX */ - -#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(a) \ - ((((a)->u16[1]) == 0) && \ - (((a)->u16[2]) == 0) && \ - (((a)->u16[3]) == 0) && \ - (((a)->u16[4]) == 0) && \ - (((a)->u16[5]) == 0) && \ - (((a)->u8[12]) == 0)) - -/* FF02::00XX */ - -#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(a) \ - ((((a)->u8[1]) == 2) && \ - (((a)->u16[1]) == 0) && \ - (((a)->u16[2]) == 0) && \ - (((a)->u16[3]) == 0) && \ - (((a)->u16[4]) == 0) && \ - (((a)->u16[5]) == 0) && \ - (((a)->u16[6]) == 0) && \ - (((a)->u8[14]) == 0)) - /* This maximum size of an IEEE802.15.4 frame. Certain, non-standard * devices may exceed this value, however. */ @@ -402,6 +336,7 @@ struct ieee802154_driver_s FAR struct iob_s *i_framelist; + /* Driver Configuration ***************************************************/ /* 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 @@ -433,30 +368,42 @@ struct ieee802154_driver_s */ uint16_t i_dgramtag; -}; -/* The structure of a next header compressor. This compressor is provided - * by architecture-specific logic outside of the network stack. - * - * TODO: needs more parameters when compressing extension headers, etc. - */ - -struct sixlowpan_nhcompressor_s -{ - CODE int (*is_compressable)(uint8_t next_header); - - /* Compress next header (TCP/UDP, etc) - ptr points to next header to - * compress. +#if CONFIG_NET_6LOWPAN_FRAG + /* Fragmentation Support *************************************************/ + /* Fragementation is handled frame by frame and requires that certain + * state information be retained from frame to frame. */ - CODE int (*compress)(FAR uint8_t *compressed, FAR uint8_t *uncompressed_len); - - /* Uncompress next header (TCP/UDP, etc) - ptr points to next header to - * uncompress. + /* i_pktlen. The total length of the IPv6 packet to be re-assembled in + * d_buf. */ - CODE int (*uncompress)(FAR uint8_t *compressed, FAR uint8_t *lowpanbuf, - FAR uint8_t *uncompressed_len); + uint16_t i_pktlen; + + /* The current accumulated length of the packet being received in d_buf. + * Included IPv6 and protocol headers. + */ + + uint16_t i_accumlen; + + /* i_reasstag. Each frame in the reassembly has a tag. That tag must + * match the reassembly tag in the fragments being merged. + */ + + uint16_t i_reasstag; + + /* The source MAC address of the fragments being merged */ + + struct rimeaddr_s i_fragsrc; + + /* That time at which reassembly was started. If the elapsed time + * exceeds CONFIG_NET_6LOWPAN_MAXAGE, then the reassembly will + * be cancelled. + */ + + systime_t i_time; +#endif /* CONFIG_NET_6LOWPAN_FRAG */ }; /**************************************************************************** @@ -518,21 +465,4 @@ struct sixlowpan_nhcompressor_s int sixlowpan_input(FAR struct ieee802154_driver_s *ieee); -/**************************************************************************** - * Function: sixlowpan_set_compressor - * - * Description: - * Configure to use the architecture-specific compressor. - * - * Input parameters: - * compressor - A reference to the new compressor to be used. This may - * be a NULL value to disable the compressor. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void sixlowpan_set_compressor(FAR struct sixlowpan_nhcompressor_s *compressor); - #endif /* __INCLUDE_NUTTX_NET_SIXLOWOAN_H */ diff --git a/net/devif/ipv6_input.c b/net/devif/ipv6_input.c index 149f06d33d9..d55b0739ad1 100644 --- a/net/devif/ipv6_input.c +++ b/net/devif/ipv6_input.c @@ -95,6 +95,7 @@ #include "neighbor/neighbor.h" #include "tcp/tcp.h" #include "udp/udp.h" +#include "sixlowpan/sixlowpan.h" #include "pkt/pkt.h" #include "icmpv6/icmpv6.h" @@ -255,12 +256,45 @@ int ipv6_input(FAR struct net_driver_s *dev) { #ifdef NET_TCP_HAVE_STACK case IP_PROTO_TCP: /* TCP input */ + /* Forward the IPv6 TCP packet */ + tcp_ipv6_input(dev); - break; + +#ifdef CONFIG_NET_6LOWPAN + /* TCP output comes through two different mechansims. Either from: + * + * 1. TCP socket output. For the case of TCP output to an + * IEEE802.15.4, the TCP output is caught in the socket + * send()/sendto() logic and and redirected to 6loWPAN logic. + * 2. TCP output from the TCP state machine. That will pass + * here and can be detected if d_len > 0. It will be redirected + * to 6loWPAN logic here. + */ + +#ifdef CONFIG_NET_MULTILINK + /* Handle the case where multiple link layer protocols are supported */ + + if (dev->d_len > 0 && dev->d_lltype == CONFIG_NET_6LOWPAN) +#else + if (dev->d_len > 0) #endif + { + /* Let 6loWPAN handle the TCP output */ + + sixlowpan_tcp_send(dev); + + /* Drop the packet in the d_buf */ + + goto drop; + } +#endif /* CONFIG_NET_6LOWPAN */ + break; +#endif /* NET_TCP_HAVE_STACK */ #ifdef NET_UDP_HAVE_STACK case IP_PROTO_UDP: /* UDP input */ + /* Forward the IPv6 UDP packet */ + udp_ipv6_input(dev); break; #endif @@ -269,6 +303,8 @@ int ipv6_input(FAR struct net_driver_s *dev) #ifdef CONFIG_NET_ICMPv6 case IP_PROTO_ICMP6: /* ICMP6 input */ + /* Forward the ICMPv6 packet */ + icmpv6_input(dev); break; #endif diff --git a/net/sixlowpan/Kconfig b/net/sixlowpan/Kconfig index 4d0be0b6600..49f4756a024 100644 --- a/net/sixlowpan/Kconfig +++ b/net/sixlowpan/Kconfig @@ -132,7 +132,8 @@ config NET_6LOWPAN_MAXAGE int "Packet reassembly timeout" default 20 ---help--- - Timeout for packet reassembly at the 6lowpan layer (should be < 60s) + Timeout for packet reassembly at the 6lowpan layer in units of + seconds (should be < 60s) config NET_6LOWPAN_MAX_MACTRANSMITS int "Max MAC transmissions" diff --git a/net/sixlowpan/Make.defs b/net/sixlowpan/Make.defs index 09fc742d397..d1faae0eacc 100644 --- a/net/sixlowpan/Make.defs +++ b/net/sixlowpan/Make.defs @@ -41,7 +41,7 @@ ifeq ($(CONFIG_NET_6LOWPAN),y) NET_CSRCS += sixlowpan_initialize.c sixlowpan_globals.c sixlowpan_utils.c NET_CSRCS += sixlowpan_input.c sixlowpan_send.c sixlowpan_framer.c -NET_CSRCS += sixlowpan_framelist.c sixlowpan_compressor.c +NET_CSRCS += sixlowpan_framelist.c ifeq ($(CONFIG_NET_TCP),y) NET_CSRCS += sixlowpan_tcpsend.c diff --git a/net/sixlowpan/sixlowpan.h b/net/sixlowpan/sixlowpan.h index d3660cb2ceb..c9f54154b5e 100644 --- a/net/sixlowpan/sixlowpan.h +++ b/net/sixlowpan/sixlowpan.h @@ -53,7 +53,9 @@ * Public Function Prototypes ****************************************************************************/ -struct socket; /* Forward reference */ +struct net_driver_s; /* Forward reference */ +struct socket; /* Forward reference */ +struct sockaddr; /* Forward reference */ /**************************************************************************** * Name: sixlowpan_initialize @@ -104,6 +106,33 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, size_t len); #endif +/**************************************************************************** + * Function: sixlowpan_tcp_send + * + * Description: + * TCP output comes through two different mechansims. Either from: + * + * 1. TCP socket output. For the case of TCP output to an + * IEEE802.15.4, the TCP output is caught in the socket + * send()/sendto() logic and and redirected to psock_6lowpan_tcp_send(). + * 2. TCP output from the TCP state machine. That will occur + * during TCP packet processing by the TCP state meachine. It + * is detected there when ipv6_tcp_input() returns with d_len > 0. This + * will be redirected here. + * + * Parameters: + * dev - An instance of nework device state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +void sixlowpan_tcp_send(FAR struct net_driver_s *dev); + /**************************************************************************** * Function: psock_6lowpan_udp_send * @@ -132,5 +161,39 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, size_t len); #endif +/**************************************************************************** + * Function: psock_6lowpan_udp_sendto + * + * Description: + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. + * + * Parameters: + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * len Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure + * + * Returned Value: + * On success, returns the number of characters sent. On error, + * -1 is returned, and errno is set appropriately. Returned error + * number must be consistent with definition of errors reported by + * sendto(). + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, + FAR const void *buf, + size_t len, int flags, + FAR const struct sockaddr *to, + socklen_t tolen); + #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_H */ diff --git a/net/sixlowpan/sixlowpan_compressor.c b/net/sixlowpan/sixlowpan_compressor.c deleted file mode 100644 index 7450e408e27..00000000000 --- a/net/sixlowpan/sixlowpan_compressor.c +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** - * net/sixlowpan/sixlowpan_compressor.c - * - * Copyright (C) 2017 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt - * - * 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 "nuttx/net/net.h" - -#include "sixlowpan/sixlowpan_internal.h" - -#ifdef CONFIG_NET_6LOWPAN - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: sixlowpan_set_compressor - * - * Description: - * Configure to use the architecture-specific compressor. - * - * Input parameters: - * compressor - A reference to the new compressor to be used. This may - * be a NULL value to disable the compressor. - * - * Returned Value: - * None - * - ****************************************************************************/ - -void sixlowpan_set_compressor(FAR struct sixlowpan_nhcompressor_s *compressor) -{ - /* Make sure that the compressor is not in use */ - - net_lock(); - - /* Then instantiate the new compressor */ - - g_sixlowpan_compressor = compressor; - net_unlock(); -} - -#endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c index 35750b3ce77..62582bed1c4 100644 --- a/net/sixlowpan/sixlowpan_framelist.c +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -100,8 +100,8 @@ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Input Parameters: - * ieee - Pointer to IEEE802.15.4 MAC driver structure. - * ipv6 - Pointer to the IPv6 header to "compress" + * ieee - Pointer to IEEE802.15.4 MAC driver structure. + * destip - Pointer to the IPv6 header to "compress" * * Returned Value: * None @@ -109,7 +109,7 @@ ****************************************************************************/ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, - FAR const struct ipv6_hdr_s *ipv6) + FAR const struct ipv6_hdr_s *destip) { /* Indicate the IPv6 dispatch and length */ @@ -118,7 +118,7 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, /* Copy the IPv6 header and adjust pointers */ - memcpy(g_rimeptr + g_rime_hdrlen, ipv6, IPv6_HDRLEN); + memcpy(g_rimeptr + g_rime_hdrlen, destip, IPv6_HDRLEN); g_rime_hdrlen += IPv6_HDRLEN; g_uncomp_hdrlen += IPv6_HDRLEN; } @@ -161,12 +161,12 @@ static void sixlowpan_compress_ipv6hdr(FAR struct ieee802154_driver_s *ieee, int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *destip, - FAR const void *buf, size_t len, + FAR const void *buf, size_t len, FAR const struct rimeaddr_s *destmac) { FAR struct iob_s *iob; int framer_hdrlen; - struct rimeaddr_s dest; + struct rimeaddr_s bcastmac; uint16_t outlen = 0; /* Initialize global data. Locking the network guarantees that we have @@ -211,13 +211,24 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, if (destmac == NULL) { - memset(&dest, 0, sizeof(struct rimeaddr_s)); - } - else - { - rimeaddr_copy(&dest, (FAR const struct rimeaddr_s *)destmac); + memset(&bcastmac, 0, sizeof(struct rimeaddr_s)); + destmac = &bcastmac; } + /* Pre-allocate the IOB to hold frame or the first fragment, waiting if + * necessary. + */ + + iob = iob_alloc(false); + DEBUGASSERT(iob != NULL); + + /* Initialize the IOB */ + + iob->io_flink = NULL; + iob->io_len = 0; + iob->io_offset = 0; + iob->io_pktlen = 0; + ninfo("Sending packet len %d\n", len); #ifndef CONFIG_NET_6LOWPAN_COMPRESSION_IPv6 @@ -226,9 +237,9 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, /* Try to compress the headers */ #if defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC1) - sixlowpan_compresshdr_hc1(ieee, &dest); + sixlowpan_compresshdr_hc1(ieee, destip, destmac, iob); #elif defined(CONFIG_NET_6LOWPAN_COMPRESSION_HC06) - sixlowpan_compresshdr_hc06(ieee, &dest); + sixlowpan_compresshdr_hc06(ieee, destip, destmac, iob); #else # error No compression specified #endif @@ -243,7 +254,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, ninfo("Header of len %d\n", g_rime_hdrlen); - rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], &dest); + rimeaddr_copy(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], destmac); /* Pre-calculate frame header length. */ @@ -279,20 +290,8 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, ninfo("Fragmentation sending packet len %d\n", len); - /* Allocate an IOB to hold the first fragment, waiting if necessary. */ - - iob = iob_alloc(false); - DEBUGASSERT(iob != NULL); - - /* Initialize the IOB */ - - iob->io_flink = NULL; - iob->io_len = 0; - iob->io_offset = 0; - iob->io_pktlen = 0; - /* Create 1st Fragment */ - /* Add the frame header */ + /* Add the frame header using the pre-allocated IOB. */ verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); DEBUGASSERT(verify == framer_hdrlen); @@ -434,19 +433,7 @@ int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, * and send in one frame. */ - /* Allocate an IOB to hold the frame, waiting if necessary. */ - - iob = iob_alloc(false); - DEBUGASSERT(iob != NULL); - - /* Initialize the IOB */ - - iob->io_flink = NULL; - iob->io_len = 0; - iob->io_offset = 0; - iob->io_pktlen = 0; - - /* Add the frame header */ + /* Add the frame header to the prealloated IOB. */ verify = sixlowpan_framecreate(ieee, iob, ieee->i_panid); DEBUGASSERT(vreify == framer_hdrlen); diff --git a/net/sixlowpan/sixlowpan_globals.c b/net/sixlowpan/sixlowpan_globals.c index 6b0f5bcf74b..2f9843022ff 100644 --- a/net/sixlowpan/sixlowpan_globals.c +++ b/net/sixlowpan/sixlowpan_globals.c @@ -47,10 +47,6 @@ * Public Data ****************************************************************************/ -/* A pointer to the optional, architecture-specific compressor */ - -FAR struct sixlowpan_nhcompressor_s *g_sixlowpan_compressor; - /* The following data values are used to hold intermediate settings while * processing IEEE802.15.4 frames. These globals are shared with incoming * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c index e0ca657c036..270c6f68853 100644 --- a/net/sixlowpan/sixlowpan_hc06.c +++ b/net/sixlowpan/sixlowpan_hc06.c @@ -58,12 +58,26 @@ #include +#include +#include + #include +#include #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define IPv6BUF(ieee) \ + ((FAR struct ipv6_hdr_s *)&(ieee)->i_dev.d_buf) +#define UDPIPv6BUF(ieee) \ + ((FAR struct udp_hdr_s *)&(ieee)->i_dev.d_buf[IPv6_HDRLEN]) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -83,7 +97,12 @@ struct sixlowpan_addrcontext_s * Private Data ****************************************************************************/ -/* HC06 specific variables */ +/* HC06 specific variables **************************************************/ +/* Use of global variables simplifies the logic and is safe in the multi- + * device environment because access is serialized via the network lock. + * + * But note that state may NOT be preserved from packet-to-packet. + */ #if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 /* Addresses contexts for IPHC. */ @@ -92,6 +111,219 @@ static struct sixlowpan_addrcontext_s g_hc06_addrcontexts[CONFIG_NET_6LOWPAN_MAXADDRCONTEXT]; #endif +/* Pointer to the byte where to write next inline field. */ + +static FAR uint8_t *g_hc06ptr; + +/* Constant Data ************************************************************/ +/* Uncompression of linklocal + * + * 0 -> 16 bytes from packet + * 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet + * 2 -> 2 bytes from prefix - 0000::00ff:fe00:XXXX from packet + * 3 -> 2 bytes from prefix - infer 8 bytes from MAC address + * + * NOTE: => the uncompress function does change 0xf to 0x10 + * NOTE: 0x00 => no-autoconfig => unspecified + */ + +static const uint8_t g_unc_llconf[] = { 0x0f, 0x28, 0x22, 0x20 }; + +/* Uncompression of ctx-based + * + * 0 -> 0 bits from packet [unspecified / reserved] + * 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet + * 2 -> 8 bytes from prefix - 0000::00ff:fe00:XXXX + 2 from packet + * 3 -> 8 bytes from prefix - infer 8 bytes from MAC address + */ + +static const uint8_t g_unc_ctxconf[] = { 0x00, 0x88, 0x82, 0x80 }; + +/* Uncompression of ctx-based + * + * 0 -> 0 bits from packet + * 1 -> 2 bytes from prefix - bunch of zeroes 5 from packet + * 2 -> 2 bytes from prefix - zeroes + 3 from packet + * 3 -> 2 bytes from prefix - infer 1 bytes from MAC address + */ + +static const uint8_t g_unc_mxconf[] = { 0x0f, 0x25, 0x23, 0x21 }; + +/* Link local prefix */ + +static const uint8_t g_llprefix[] = { 0xfe, 0x80 }; + +/* TTL uncompression values */ + +static const uint8_t g_ttl_values[] = { 0, 1, 64, 255 }; + + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: find_addrcontext_bynumber + * + * Description: + * Find the address context with the given number. + * + ****************************************************************************/ + +static FAR struct sixlowpan_addrcontext_s * + find_addrcontext_bynumber(uint8_t number) +{ + /* Remove code to avoid warnings and save flash if no address context is + * used. + */ + +#if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 + int i; + + for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++) + { + if ((g_hc06_addrcontexts[i].used == 1) && + g_hc06_addrcontexts[i].number == number) + { + return &g_hc06_addrcontexts[i]; + } + } +#endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */ + + return NULL; +} + +/**************************************************************************** + * Name: find_addrcontext_bynumber + * + * Description: + * Find the address context corresponding to the prefix ipaddr. + * + ****************************************************************************/ + +static FAR struct sixlowpan_addrcontext_s * + find_addrcontext_byprefix(FAR const net_ipv6addr_t ipaddr) +{ +#if CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 + int i; + + /* Remove code to avoid warnings and save flash if no address context is used */ + + for (i = 0; i < CONFIG_NET_6LOWPAN_MAXADDRCONTEXT; i++) + { + if ((g_hc06_addrcontexts[i].used == 1) && + net_ipv6addr_prefixcmp(&g_hc06_addrcontexts[i].prefix, ipaddr, 64)) + { + return &g_hc06_addrcontexts[i]; + } + } +#endif /* CONFIG_NET_6LOWPAN_MAXADDRCONTEXT > 0 */ + + return NULL; +} + +/**************************************************************************** + * Name: uncompress_addr + * + * Description: + * Uncompress addresses based on a prefix and a postfix with zeroes in + * between. If the postfix is zero in length it will use the link address + * to configure the IP address (autoconf style). + * + * prefpost takes a byte where the first nibble specify prefix count + * and the second postfix count (NOTE: 15/0xf => 16 bytes copy). + * + ****************************************************************************/ + +static uint8_t compress_addr_64(FAR const net_ipv6addr_t ipaddr, + FAR const struct rimeaddr_s *macaddr, + uint8_t bitpos) +{ + if (sixlowpan_ismacbased(ipaddr, macaddr)) + { + return 3 << bitpos; /* 0-bits */ + } + else if (SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(ipaddr)) + { + /* Compress IID to 16 bits xxxx::0000:00ff:fe00:XXXX */ + + memcpy(g_hc06ptr, &ipaddr[7], 2); + g_hc06ptr += 2; + return 2 << bitpos; /* 16-bits */ + } + else + { + /* Do not compress IID => xxxx::IID */ + + memcpy(g_hc06ptr, &ipaddr[4], 8); + g_hc06ptr += 8; + return 1 << bitpos; /* 64-bits */ + } +} + +/**************************************************************************** + * Name: uncompress_addr + * + * Description: + * Uncompress addresses based on a prefix and a postfix with zeroes in + * between. If the postfix is zero in length it will use the link address + * to configure the IP address (autoconf style). + * + * prefpost takes a byte where the first nibble specify prefix count + * and the second postfix count (NOTE: 15/0xf => 16 bytes copy). + * + ****************************************************************************/ + +static void uncompress_addr(FAR net_ipv6addr_t ipaddr, uint8_t const prefix[], + uint8_t prefpost, FAR struct rimeaddr_s *macaddr) +{ + uint8_t prefcount = prefpost >> 4; + uint8_t postcount = prefpost & 0x0f; + + /* Full nibble 15 => 16 */ + + prefcount = prefcount == 15 ? 16 : prefcount; + postcount = postcount == 15 ? 16 : postcount; + + if (prefcount > 0) + { + memcpy(ipaddr, prefix, prefcount); + } + + if (prefcount + postcount < 16) + { + FAR uint8_t *iptr = (FAR uint8_t *)&ipaddr[0]; + + memset(&iptr[prefcount], 0, 16 - (prefcount + postcount)); + } + + if (postcount > 0) + { + FAR uint8_t *iptr = (FAR uint8_t *)&ipaddr[0]; + + memcpy(&iptr[16 - postcount], g_hc06ptr, postcount); + if (postcount == 2 && prefcount < 11) + { + /* 16 bits uncompression => 0000:00ff:fe00:XXXX */ + + iptr[11] = 0xff; + iptr[12] = 0xfe; + } + + g_hc06ptr += postcount; + } + else if (prefcount > 0) + { + /* No IID based configuration if no prefix and no data => unspec */ + + sixlowpan_ipfromrime(macaddr, ipaddr); + } + + ninfo("Uncompressing %d + %d => %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + prefcount, postcount, ipaddr[0], ipaddr[2], ipaddr[3], ipaddr[5], + ipaddr[5], ipaddr[6], ipaddr[7]); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -174,8 +406,7 @@ void sixlowpan_hc06_initialize(void) * 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. + * 6lowpan packet in the frame buffer from a full IPv6 packet. * * HC-06 (draft-ietf-6lowpan-hc, version 6) * http://tools.ietf.org/html/draft-ietf-6lowpan-hc-06 @@ -197,13 +428,16 @@ void sixlowpan_hc06_initialize(void) * | L4 data ... | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * - * NOTE: The g_addr_context number 00 is reserved for the link local prefix. - * For unicast addresses, if we cannot compress the prefix, we neither - * compress the IID. + * NOTE: The address context number 00 is reserved for the link local + * prefix. For unicast addresses, if we cannot compress the prefix, we + * neither compress the IID. * * Input Parameters: - * ieee - A reference to the IEE802.15.4 network device state - * destaddr - L2 destination address, needed to compress IP dest + * ieee - A reference to the IEE802.15.4 network device state + * ipv6 - The IPv6 header to be compressed + * destmac - L2 destination address, needed to compress the IP + * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None @@ -211,9 +445,370 @@ void sixlowpan_hc06_initialize(void) ****************************************************************************/ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, - FAR struct rimeaddr_s *destaddr) + FAR const struct ipv6_hdr_s *ipv6, + FAR const struct rimeaddr_s *destmac, + FAR struct iob_s *iob) { - /* REVISIT: To be provided */ + FAR uint8_t *iphc = RIME_IPHC_BUF; + FAR struct sixlowpan_addrcontext_s *addrcontext; + uint8_t iphc0; + uint8_t iphc1; + uint8_t tmp; + + ninfodumpbuffer("IPv6 before compression", ipv6, sizeof(ipv6_hdr_s)); + + g_hc06ptr = g_rimeptr + 2; + + /* As we copy some bit-length fields, in the IPHC encoding bytes, + * we sometimes use |= + * If the field is 0, and the current bit value in memory is 1, + * this does not work. We therefore reset the IPHC encoding here + */ + + iphc0 = SIXLOWPAN_DISPATCH_IPHC; + iphc1 = 0; + iphc[2] = 0; /* Might not be used - but needs to be cleared */ + + /* Address handling needs to be made first since it might cause an extra + * byte with [ SCI | DCI ] + */ + + /* Check if dest address context exists (for allocating third byte) + * + * TODO: fix this so that it remembers the looked up values for avoiding two + * lookups - or set the lookup values immediately + */ + + if (find_addrcontext_byprefix(ipv6->destipaddr) != NULL || + find_addrcontext_byprefix(ipv6->srcipaddr) != NULL) + { + /* set address context flag and increase g_hc06ptr */ + + ninfo("Decompressing dest or src ipaddr. Setting CID\n"); + iphc1 |= SIXLOWPAN_IPHC_CID; + g_hc06ptr++; + } + + /* Traffic class, flow label + * + * If flow label is 0, compress it. If traffic class is 0, compress it + * We have to process both in the same time as the offset of traffic class + * depends on the presence of version and flow label + */ + + /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */ + + tmp = (ipv6->vtc << 4) | (ipv6->tcf >> 4); + tmp = ((tmp & 0x03) << 6) | (tmp >> 2); + + if (((ipv6->tcf & 0x0f) == 0) && (ipv6->flow == 0)) + { + /* Flow label can be compressed */ + + iphc0 |= SIXLOWPAN_IPHC_FL_C; + if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xf0) == 0)) + { + /* Compress (elide) all */ + + iphc0 |= SIXLOWPAN_IPHC_TC_C; + } + else + { + /* Sompress only the flow label */ + + *g_hc06ptr = tmp; + g_hc06ptr += 1; + } + } + else + { + /* Flow label cannot be compressed */ + + if (((ipv6->vtc & 0x0f) == 0) && ((ipv6->tcf & 0xF0) == 0)) + { + /* Compress only traffic class */ + + iphc0 |= SIXLOWPAN_IPHC_TC_C; + *g_hc06ptr = (tmp & 0xc0) | (ipv6->tcf & 0x0f); + memcpy(g_hc06ptr + 1, &ipv6->flow, 2); + g_hc06ptr += 3; + } + else + { + /* Compress nothing */ + + memcpy(g_hc06ptr, &ipv6->vtc, 4); + + /* But replace the top byte with the new ECN | DSCP format */ + + *g_hc06ptr = tmp; + g_hc06ptr += 4; + } + } + + /* Note that the payload length is always compressed */ + + /* Next header. We compress it if UDP */ + +#if CONFIG_NET_UDP || UIP_CONF_ROUTER + if (ipv6->proto == IP_PROTO_UDP) + { + iphc0 |= SIXLOWPAN_IPHC_NH_C; + } +#endif /* CONFIG_NET_UDP */ + + if ((iphc0 & SIXLOWPAN_IPHC_NH_C) == 0) + { + *g_hc06ptr = ipv6->proto; + g_hc06ptr += 1; + } + + /* Hop limit + * + * if 1: compress, encoding is 01 + * if 64: compress, encoding is 10 + * if 255: compress, encoding is 11 + * else do not compress + */ + + switch (ipv6->ttl) + { + case 1: + iphc0 |= SIXLOWPAN_IPHC_TTL_1; + break; + + case 64: + iphc0 |= SIXLOWPAN_IPHC_TTL_64; + break; + + case 255: + iphc0 |= SIXLOWPAN_IPHC_TTL_255; + break; + + default: + *g_hc06ptr = ipv6->ttl; + g_hc06ptr += 1; + break; + } + + /* Source address - cannot be multicast */ + + if (net_is_addr_unspecified(ipv6->srcipaddr)) + { + ninfo("Compressing unspecified. Setting SAC\n"); + + iphc1 |= SIXLOWPAN_IPHC_SAC; + iphc1 |= SIXLOWPAN_IPHC_SAM_00; + } + else if ((addrcontext = find_addrcontext_byprefix(ipv6->srcipaddr)) != NULL) + { + /* Elide the prefix - indicate by CID and set address context + SAC */ + + ninfo("Compressing src with address context. Setting CID and SAC context: %d\n", + addrcontext->number); + + iphc1 |= SIXLOWPAN_IPHC_CID | SIXLOWPAN_IPHC_SAC; + iphc[2] |= addrcontext->number << 4; + + /* Compession compare with this nodes address (source) */ + + iphc1 |= compress_addr_64(ipv6->srcipaddr, &ieee->i_nodeaddr, + SIXLOWPAN_IPHC_SAM_BIT); + + /* No address context found for this address */ + } + else if (net_is_addr_linklocal(ipv6->srcipaddr) && + ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 && + ipv6->destipaddr[3] == 0) + { + iphc1 |= compress_addr_64(ipv6->srcipaddr, &ieee->i_nodeaddr, + SIXLOWPAN_IPHC_SAM_BIT); + } + else + { + /* Send the full address => SAC = 0, SAM = 00 */ + + iphc1 |= SIXLOWPAN_IPHC_SAM_00; /* 128-bits */ + memcpy(g_hc06ptr, ipv6->srcipaddr, 16); + g_hc06ptr += 16; + } + + /* Destination address */ + + if (net_is_addr_mcast(ipv6->destipaddr)) + { + /* Address is multicast, try to compress */ + + iphc1 |= SIXLOWPAN_IPHC_M; + if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(ipv6->destipaddr)) + { + iphc1 |= SIXLOWPAN_IPHC_DAM_11; + + /* Use last byte */ + + *g_hc06ptr = ipv6->destipaddr[7] & 0x00ff; + g_hc06ptr += 1; + } + else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(ipv6->destipaddr)) + { + FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr; + + iphc1 |= SIXLOWPAN_IPHC_DAM_10; + + /* Second byte + the last three */ + + *g_hc06ptr = iptr[1]; + memcpy(g_hc06ptr + 1, &iptr[13], 3); + g_hc06ptr += 4; + } + else if (SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(ipv6->destipaddr)) + { + FAR uint8_t *iptr = (FAR uint8_t *)ipv6->destipaddr; + + iphc1 |= SIXLOWPAN_IPHC_DAM_01; + + /* Second byte + the last five */ + + *g_hc06ptr = iptr[1]; + memcpy(g_hc06ptr + 1, &iptr[11], 5); + g_hc06ptr += 6; + } + else + { + iphc1 |= SIXLOWPAN_IPHC_DAM_00; + + /* Full address */ + + memcpy(g_hc06ptr, ipv6->destipaddr, 16); + g_hc06ptr += 16; + } + } + else + { + /* Address is unicast, try to compress */ + + if ((addrcontext = find_addrcontext_byprefix(ipv6->destipaddr)) != NULL) + { + /* Elide the prefix */ + + iphc1 |= SIXLOWPAN_IPHC_DAC; + iphc[2] |= addrcontext->number; + + /* Compession compare with link adress (destination) */ + + iphc1 |= compress_addr_64(ipv6->destipaddr, destmac, + SIXLOWPAN_IPHC_DAM_BIT); + + /* No address context found for this address */ + } + else if (net_is_addr_linklocal(ipv6->destipaddr) && + ipv6->destipaddr[1] == 0 && ipv6->destipaddr[2] == 0 && + ipv6->destipaddr[3] == 0) + { + iphc1 |= compress_addr_64(ipv6->destipaddr, destmac, + SIXLOWPAN_IPHC_DAM_BIT); + } + else + { + /* Send the full address */ + + iphc1 |= SIXLOWPAN_IPHC_DAM_00; /* 128-bits */ + memcpy(g_hc06ptr, ipv6->destipaddr, 16); + g_hc06ptr += 16; + } + } + + g_uncomp_hdrlen = IPv6_HDRLEN; + +#if CONFIG_NET_UDP + /* UDP header compression */ + + if (ipv6->proto == IP_PROTO_UDP) + { + FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee); + + ninfo("Uncompressed UDP ports on send side: %x, %x\n", + ntohs(udp->srcport), ntohs(udp->destport)); + + /* Mask out the last 4 bits can be used as a mask */ + + if (((ntohs(udp->srcport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN) && + ((ntohs(udp->destport) & 0xfff0) == SIXLOWPAN_UDP_4_BIT_PORT_MIN)) + { + /* We can compress 12 bits of both source and dest */ + + *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_11; + + ninfo("Remove 12b of both source & dest with prefix 0xfob\n"); + + *(g_hc06ptr + 1) = + (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN) << 4) + + (uint8_t)((ntohs(udp->destport) - SIXLOWPAN_UDP_4_BIT_PORT_MIN)); + + g_hc06ptr += 2; + } + else if ((ntohs(udp->destport) & 0xff00) == + SIXLOWPAN_UDP_8_BIT_PORT_MIN) + { + /* We can compress 8 bits of dest, leave source. */ + + *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_01; + + ninfo("Leave source, remove 8 bits of dest with prefix 0xF0\n"); + + memcpy(g_hc06ptr + 1, &udp->srcport, 2); + *(g_hc06ptr + 3) = + (uint8_t) ((ntohs(udp->destport) - + SIXLOWPAN_UDP_8_BIT_PORT_MIN)); + g_hc06ptr += 4; + } + else if ((ntohs(udp->srcport) & 0xff00) == + SIXLOWPAN_UDP_8_BIT_PORT_MIN) + { + /* We can compress 8 bits of src, leave dest. Copy compressed port */ + + *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_10; + + ninfo("Remove 8 bits of source with prefix 0xF0, leave dest. hch: %u\n", + *g_hc06ptr); + + *(g_hc06ptr + 1) = + (uint8_t)((ntohs(udp->srcport) - SIXLOWPAN_UDP_8_BIT_PORT_MIN)); + + memcpy(g_hc06ptr + 2, &udp->destport, 2); + g_hc06ptr += 4; + } + else + { + /* we cannot compress. Copy uncompressed ports, full checksum */ + + *g_hc06ptr = SIXLOWPAN_NHC_UDP_CS_P_00; + + nwarn("WARNING: Cannot compress headers\n"); + + memcpy(g_hc06ptr + 1, &udp->srcport, 4); + g_hc06ptr += 5; + } + + /* Always inline the checksum */ + + if (1) + { + memcpy(g_hc06ptr, &udp->udpchksum, 2); + g_hc06ptr += 2; + } + + g_uncomp_hdrlen += UDP_HDRLEN; + } +#endif /* CONFIG_NET_UDP */ + + /* Before the g_rime_hdrlen operation */ + + iphc[0] = iphc0; + iphc[1] = iphc1; + + g_rime_hdrlen = g_hc06ptr - g_rimeptr; + return; } /**************************************************************************** @@ -232,7 +827,7 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, * Input Parmeters: * ieee - 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 + * inferred from the L2 length), non 0 if the packet is a first * fragment. * * Returned Value: @@ -243,8 +838,346 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, uint16_t iplen) { - /* REVISIT: To be provided */ + FAR struct ipv6_hdr_s *ipv6 = IPv6BUF(ieee); + FAR uint8_t *iphc = RIME_IPHC_BUF; + uint8_t iphc0; + uint8_t iphc1; + uint8_t tmp; + + /* At least two byte will be used for the encoding */ + + g_hc06ptr = g_rimeptr + g_rime_hdrlen + 2; + + iphc0 = iphc[0]; + iphc1 = iphc[1]; + + /* Another if the CID flag is set */ + + if (iphc1 & SIXLOWPAN_IPHC_CID) + { + ninfo("IPHC: CID flag set - increase header with one\n"); + g_hc06ptr++; + } + + /* Traffic class and flow label */ + + if ((iphc0 & SIXLOWPAN_IPHC_FL_C) == 0) + { + /* Flow label are carried inline */ + + if ((iphc0 & SIXLOWPAN_IPHC_TC_C) == 0) + { + /* Traffic class is carried inline */ + + memcpy(&ipv6->tcf, g_hc06ptr + 1, 3); + tmp = *g_hc06ptr; + g_hc06ptr += 4; + + /* hc06 format of tc is ECN | DSCP , original is DSCP | ECN */ + /* set version, pick highest DSCP bits and set in vtc */ + + ipv6->vtc = 0x60 | ((tmp >> 2) & 0x0f); + + /* ECN rolled down two steps + lowest DSCP bits at top two bits */ + + ipv6->tcf = ((tmp >> 2) & 0x30) | (tmp << 6) | (ipv6->tcf & 0x0f); + } + else + { + /* Traffic class is compressed (set version and no TC) */ + + ipv6->vtc = 0x60; + + /* Highest flow label bits + ECN bits */ + + ipv6->tcf = (*g_hc06ptr & 0x0f) | ((*g_hc06ptr >> 2) & 0x30); + memcpy(&ipv6->flow, g_hc06ptr + 1, 2); + g_hc06ptr += 3; + } + } + else + { + /* Version is always 6! */ + /* Version and flow label are compressed */ + + if ((iphc0 & SIXLOWPAN_IPHC_TC_C) == 0) + { + /* Traffic class is inline */ + + ipv6->vtc = 0x60 | ((*g_hc06ptr >> 2) & 0x0f); + ipv6->tcf = ((*g_hc06ptr << 6) & 0xC0) | ((*g_hc06ptr >> 2) & 0x30); + ipv6->flow = 0; + g_hc06ptr += 1; + } + else + { + /* Traffic class is compressed */ + + ipv6->vtc = 0x60; + ipv6->tcf = 0; + ipv6->flow = 0; + } + } + + /* Next Header */ + + if ((iphc0 & SIXLOWPAN_IPHC_NH_C) == 0) + { + /* Next header is carried inline */ + + ipv6->proto = *g_hc06ptr; + ninfo("Next header inline: %d\n", ipv6->proto); + g_hc06ptr += 1; + } + + /* Hop limit */ + + if ((iphc0 & 0x03) != SIXLOWPAN_IPHC_TTL_I) + { + ipv6->ttl = g_ttl_values[iphc0 & 0x03]; + } + else + { + ipv6->ttl = *g_hc06ptr; + g_hc06ptr += 1; + } + + /* Put the source address compression mode SAM in the tmp var */ + + tmp = ((iphc1 & SIXLOWPAN_IPHC_SAM_11) >> SIXLOWPAN_IPHC_SAM_BIT) & 0x03; + + /* Address context based compression */ + + if (iphc1 & SIXLOWPAN_IPHC_SAC) + { + FAR struct sixlowpan_addrcontext_s *addrcontext; + uint8_t sci = (iphc1 & SIXLOWPAN_IPHC_CID) ? iphc[2] >> 4 : 0; + + /* Source address - check address context != NULL only if SAM bits are != 0 */ + + if (tmp != 0) + { + addrcontext = find_addrcontext_bynumber(sci); + if (addrcontext == NULL) + { + nerr("ERROR: Address context not found\n"); + return; + } + } + + /* If tmp == 0 we do not have a Address context and therefore no prefix */ + + uncompress_addr(ipv6->srcipaddr, + tmp != 0 ? addrcontext->prefix : NULL, g_unc_ctxconf[tmp], + (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]); + } + else + { + /* No compression and link local */ + + uncompress_addr(ipv6->srcipaddr, g_llprefix, g_unc_llconf[tmp], + (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_SENDER]); + } + + /* Destination address */ + /* put the destination address compression mode into tmp */ + + tmp = ((iphc1 & SIXLOWPAN_IPHC_DAM_11) >> SIXLOWPAN_IPHC_DAM_BIT) & 0x03; + + /* Multicast compression */ + + if (iphc1 & SIXLOWPAN_IPHC_M) + { + /* Address context based multicast compression */ + + if (iphc1 & SIXLOWPAN_IPHC_DAC) + { + /* TODO: implement this */ + } + else + { + /* non-address context based multicast compression + * + * DAM_00: 128 bits + * DAM_01: 48 bits FFXX::00XX:XXXX:XXXX + * DAM_10: 32 bits FFXX::00XX:XXXX + * DAM_11: 8 bits FF02::00XX + */ + + uint8_t prefix[] = { 0xff, 0x02 }; + if (tmp > 0 && tmp < 3) + { + prefix[1] = *g_hc06ptr; + g_hc06ptr++; + } + + uncompress_addr(ipv6->destipaddr, prefix, g_unc_mxconf[tmp], NULL); + } + } + else + { + /* no multicast */ + /* Context based */ + + if (iphc1 & SIXLOWPAN_IPHC_DAC) + { + FAR struct sixlowpan_addrcontext_s *addrcontext; + uint8_t dci = (iphc1 & SIXLOWPAN_IPHC_CID) ? iphc[2] & 0x0f : 0; + + addrcontext = find_addrcontext_bynumber(dci); + + /* All valid cases below need the address context! */ + + if (addrcontext == NULL) + { + ninfo("ERROR: Address context not found\n"); + return; + } + + uncompress_addr(ipv6->destipaddr, addrcontext->prefix, g_unc_ctxconf[tmp], + (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]); + } + else + { + /* Not address context based => link local M = 0, DAC = 0 - same as SAC */ + + uncompress_addr(ipv6->destipaddr, g_llprefix, g_unc_llconf[tmp], + (FAR struct rimeaddr_s *)&g_pktaddrs[PACKETBUF_ADDR_RECEIVER]); + } + } + + g_uncomp_hdrlen += IPv6_HDRLEN; + + /* Next header processing - continued */ + + if ((iphc0 & SIXLOWPAN_IPHC_NH_C)) + { + FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee); + + /* The next header is compressed, NHC is following */ + + if ((*g_hc06ptr & SIXLOWPAN_NHC_UDP_MASK) == SIXLOWPAN_NHC_UDP_ID) + { + uint8_t checksum_compressed; + + ipv6->proto = IP_PROTO_UDP; + checksum_compressed = *g_hc06ptr & SIXLOWPAN_NHC_UDP_CHECKSUMC; + + ninfo("Incoming header value: %i\n", *g_hc06ptr); + + switch (*g_hc06ptr & SIXLOWPAN_NHC_UDP_CS_P_11) + { + case SIXLOWPAN_NHC_UDP_CS_P_00: + /* 1 byte for NHC, 4 byte for ports, 2 bytes chksum */ + + memcpy(&udp->srcport, g_hc06ptr + 1, 2); + memcpy(&udp->destport, g_hc06ptr + 3, 2); + + ninfo("Uncompressed UDP ports (ptr+5): %x, %x\n", + htons(udp->srcport), htons(udp->destport)); + + g_hc06ptr += 5; + break; + + case SIXLOWPAN_NHC_UDP_CS_P_01: + /* 1 byte for NHC + source 16bit inline, dest = 0xF0 + 8 bit + * inline + */ + + ninfo("Decompressing destination\n"); + + memcpy(&udp->srcport, g_hc06ptr + 1, 2); + udp->destport = + htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 3))); + + ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n", + htons(udp->srcport), htons(udp->destport)); + + g_hc06ptr += 4; + break; + + case SIXLOWPAN_NHC_UDP_CS_P_10: + /* 1 byte for NHC + source = 0xF0 + 8bit inline, dest = 16 bit + * inline + */ + + ninfo("Decompressing source\n"); + + udp->srcport = + htons(SIXLOWPAN_UDP_8_BIT_PORT_MIN + (*(g_hc06ptr + 1))); + memcpy(&udp->destport, g_hc06ptr + 2, 2); + + ninfo("Uncompressed UDP ports (ptr+4): %x, %x\n", + htons(udp->srcport), htons(udp->destport)); + + g_hc06ptr += 4; + break; + + case SIXLOWPAN_NHC_UDP_CS_P_11: + /* 1 byte for NHC, 1 byte for ports */ + + udp->srcport = + htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN + + (*(g_hc06ptr + 1) >> 4)); + udp->destport = + htons(SIXLOWPAN_UDP_4_BIT_PORT_MIN + + ((*(g_hc06ptr + 1)) & 0x0f)); + + ninfo("Uncompressed UDP ports (ptr+2): %x, %x\n", + htons(udp->srcport), htons(udp->destport)); + + g_hc06ptr += 2; + break; + + default: + nerr("ERROR: Error unsupported UDP compression\n"); + return; + } + + if (!checksum_compressed) + { + /* Has_checksum, default */ + + memcpy(&udp->udpchksum, g_hc06ptr, 2); + g_hc06ptr += 2; + + ninfo("Checksum included\n"); + } + else + { + nwarn("WARNING: checksum *NOT* included\n"); + } + + g_uncomp_hdrlen += UDP_HDRLEN; + } + } + + g_rime_hdrlen = g_hc06ptr - g_rimeptr; + + /* IP length field. */ + + if (iplen == 0) + { + /* This is not a fragmented packet */ + + ipv6->len[0] = 0; + ipv6->len[1] = ieee->i_dev.d_len - g_rime_hdrlen + g_uncomp_hdrlen - IPv6_HDRLEN; + } + else + { + /* This is a first fragment */ + + ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8; + ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00ff; + } + + /* Length field in UDP header */ + + if (ipv6->proto == IP_PROTO_UDP) + { + FAR struct udp_hdr_s *udp = UDPIPv6BUF(ieee); + memcpy(&udp->udplen, &ipv6->len[0], 2); + } } - #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */ diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 268f0bad3e0..fd45280ea04 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -53,6 +53,17 @@ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Buffer access helpers */ + +#define IPv6BUF(dev) \ + ((FAR struct ipv6_hdr_s *)((dev)->d_buf)) +#define UDPIPv6BUF(dev) \ + ((FAR struct udp_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN]) + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -102,9 +113,11 @@ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * Input Parmeters: - * ieee - A reference to the IEE802.15.4 network device state - * destaddr - L2 destination address, needed to compress the IP - * destination field + * ieee - A reference to the IEE802.15.4 network device state + * ipv6 - The IPv6 header to be compressed + * destmac - L2 destination address, needed to compress the IP + * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None @@ -112,9 +125,109 @@ ****************************************************************************/ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, - FAR struct rimeaddr_s *destaddr) + FAR const struct ipv6_hdr_s *ipv6, + FAR const struct rimeaddr_s *destmac, + FAR struct iob_s *iob) { -/* REVISIT: To be provided */ + FAR uint8_t *hc1 = RIME_HC1_PTR; + + /* Check if all the assumptions for full compression are valid */ + + if (ipv6->vtc != 0x60 || ipv6->tcflow != 0 || ipv6->flow != 0 || + !sixlowpan_islinklocal(&ipv6->srcipaddr) || + !sixlowpan_ismacbased(&ipv6->srcipaddr, &ieee->i_rimeaddr) || + !sixlowpan_islinklocal(&ipv6->destipaddr) || + !sixlowpan_ismacbased(&ipv6->destipaddr, destmac) || + (ipv6->proto != IP_PROTO_ICMP6 && ipv6->proto != IP_PROTO_UDP && + ipv6->proto != IP_PROTO_TCP)) + { + /* IPV6 DISPATCH + * Something cannot be compressed, use IPV6 DISPATCH, + * compress nothing, copy IPv6 header in rime buffer + */ + + *g_rimeptr = SIXLOWPAN_DISPATCH_IPV6; + g_rime_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; + memcpy(g_rimeptr + g_rime_hdrlen, ipv6, IPv6_HDRLEN); + g_rime_hdrlen += IPv6_HDRLEN; + g_uncomp_hdrlen += IPv6_HDRLEN; + } + else + { + /* HC1 DISPATCH maximum compresssion: + * All fields in the IP header but Hop Limit are elided. If next + * header is UDP, we compress UDP header using HC2 + */ + + hc1[RIME_HC1_DISPATCH] = SIXLOWPAN_DISPATCH_HC1; + g_uncomp_hdrlen += IPv6_HDRLEN; + switch (ipv6->proto) + { + case IP_PROTO_ICMP6: + /* HC1 encoding and ttl */ + + hc1[RIME_HC1_ENCODING] = 0xfc; + hc1[RIME_HC1_TTL] = ipv6->ttl; + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + break; + +#if CONFIG_NET_TCP + case IP_PROTO_TCP: + /* HC1 encoding and ttl */ + + hc1[RIME_HC1_ENCODING] = 0xfe; + hc1[RIME_HC1_TTL] = ipv6->ttl; + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + break; +#endif /* CONFIG_NET_TCP */ + +#if CONFIG_NET_UDP + case IP_PROTO_UDP: + FAR struct udp_hdr_s *udp = UDPIPv6BUF(dev); + + /* Try to compress UDP header (we do only full compression). This + * is feasible if both src and dest ports are between + * SIXLOWPAN_UDP_PORT_MIN and SIXLOWPAN_UDP_PORT_MIN + 15 + */ + + ninfo("local/remote port %u/%u\n", udp->srcport, udp->destport); + + if (htons(udp->srcport) >= SIXLOWPAN_UDP_PORT_MIN && + htons(udp->srcport) < SIXLOWPAN_UDP_PORT_MAX && + htons(udp->destport) >= SIXLOWPAN_UDP_PORT_MIN && + htons(udp->destport) < SIXLOWPAN_UDP_PORT_MAX) + { + FAR uint8_t *hcudp = RIME_HC1_HC_UDP_PTR; + + /* HC1 encoding */ + + hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] = 0xfb; + + /* HC_UDP encoding, ttl, src and dest ports, checksum */ + + 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) - SIXLOWPAN_UDP_PORT_MIN) << 4) + + (uint8_t)((htons(udp->destport) - SIXLOWPAN_UDP_PORT_MIN)); + + memcpy(&hcudp[RIME_HC1_HC_UDP_CHKSUM], &udp->udpchksum, 2); + + g_rime_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN; + g_uncomp_hdrlen += UIP_UDPH_LEN; + } + else + { + /* HC1 encoding and ttl */ + + hc1[RIME_HC1_ENCODING] = 0xfa; + hc1[RIME_HC1_TTL] = ipv6->ttl; + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + } + break; +#endif /* CONFIG_NET_UDP */ + } + } } /**************************************************************************** @@ -136,14 +249,127 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, * fragment. * * Returned Value: - * None + * Zero (OK) is returned on success, on failure a negater errno value is + * returned. * ****************************************************************************/ -void sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, - uint16_t iplen) +int sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, + uint16_t iplen) { -/* REVISIT: To be provided */ + FAR struct ipv6_hdr_s *ipv6 = IPv6BUF(&ieee->i_dev); + FAR uint8_t *hc1 = RIME_HC1_PTR; + + /* Format the IPv6 header in the device d_buf */ + /* Set version, traffic clase, and flow label */ + + ipv6->vtc = 0x60; /* Bits 0-3: version, bits 4-7: traffic class (MS) */ + ipv6->tcf = 0; /* Bits 0-3: traffic class (LS), 4-bits: flow label (MS) */ + ipv6->flow = 0; /* 16-bit flow label (LS) */ + + /* Use stateless auto-configuration to set source and destination IP + * addresses. + */ + + sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_SENDER], + &ipv6->srcipaddr); + sixlowpan_ipfromrime(&g_pktaddrs[PACKETBUF_ADDR_RECEIVER], + &ipv6->destipaddr); + g_uncomp_hdrlen += IPv6_HDRLEN; + + /* len[], proto, and ttl depend on the encoding */ + + switch (hc1[RIME_HC1_ENCODING] & 0x06) + { + case SIXLOWPAN_HC1_NH_ICMP6: + ipv6->proto = IP_PROTO_ICMP6; + ipv6->ttl = hc1[RIME_HC1_TTL]; + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + break; + +#if CONFIG_NET_TCP + case SIXLOWPAN_HC1_NH_TCP: + ipv6->proto = IP_PROTO_TCP; + ipv6->ttl = hc1[RIME_HC1_TTL]; + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + break; +#endif /* CONFIG_NET_TCP */ + +#if CONFIG_NET_UDP + case SIXLOWPAN_HC1_NH_UDP: + { + FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev); + FAR uint8_t *hcudp = RIME_HC1_HC_UDP_PTR; + + ipv6->proto = IP_PROTO_UDP; + if ((hcudp[RIME_HC1_HC_UDP_HC1_ENCODING] & 0x01) != 0) + { + /* UDP header is compressed with HC_UDP */ + + if (hcudp[RIME_HC1_HC_UDP_UDP_ENCODING] != + SIXLOWPAN_HC_UDP_ALL_C) + { + nwarn("WARNING: sixlowpan (uncompress_hdr), packet not supported"); + return -EOPNOTSUPP; + } + + /* IP TTL */ + + ipv6->ttl = hcudp[RIME_HC1_HC_UDP_TTL]; + + /* UDP ports, len, checksum */ + + udp->srcport = + htons(SIXLOWPAN_UDP_PORT_MIN + (hcudp[RIME_HC1_HC_UDP_PORTS] >> 4)); + udp->destport = + htons(SIXLOWPAN_UDP_PORT_MIN + (hcudp[RIME_HC1_HC_UDP_PORTS] & 0x0F)); + + memcpy(&udp->udpchksum, &hcudp[RIME_HC1_HC_UDP_CHKSUM], 2); + + g_uncomp_hdrlen += UIP_UDPH_LEN; + g_rime_hdrlen += SIXLOWPAN_HC1_HC_UDP_HDR_LEN; + } + else + { + g_rime_hdrlen += SIXLOWPAN_HC1_HDR_LEN; + } + } + break; +#endif /* CONFIG_NET_UDP */ + + default: + return -EPROTONOSUPPORT; + } + + /* IP length field. */ + + if (iplen == 0) + { + /* This is not a fragmented packet */ + + ipv6->len[0] = 0; + ipv6->len[1] = ieee->i_dev.d_len - g_rime_hdrlen + /* REVISIT */ + g_uncomp_hdrlen - IPv6_HDRLEN; + } + else + { + /* This is a 1st fragment */ + + ipv6->len[0] = (iplen - IPv6_HDRLEN) >> 8; + ipv6->len[1] = (iplen - IPv6_HDRLEN) & 0x00FF; + } + + /* length field in UDP header */ + +#if CONFIG_NET_UDP + if (ipv6->proto == IP_PROTO_UDP) + { + FAR struct udp_hdr_s *udp = UDPIPv6BUF(&ieee->i_dev); + memcpy(&udp->udplen, &ipv6->len[0], 2); + } +#endif + + return; } #endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */ diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index 151d205f851..b89af933d85 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -1,6 +1,6 @@ /**************************************************************************** * net/sixlowpan/sixlowpan_input.c - * 6lowpan implementation (RFC4944 and draft-ietf-6lowpan-hc-06) + * 6loWPAN implementation (RFC4944 and draft-ietf-6loWPAN-hc-06) * * Copyright (C) 2017, Gregory Nutt, all rights reserved * Author: Gregory Nutt @@ -49,10 +49,15 @@ #include +#include #include #include #include +#if CONFIG_NET_6LOWPAN_FRAG +# include "nuttx/clock.h" +#endif + #include "nuttx/net/netdev.h" #include "nuttx/net/ip.h" #include "nuttx/net/sixlowpan.h" @@ -74,95 +79,18 @@ #define INPUT_PARTIAL 0 /* Frame processed successful, packet incomplete */ #define INPUT_COMPLETE 1 /* Frame processed successful, packet complete */ +/* Re-assembly timeout in clock ticks */ + +#define NET_6LOWPAN_TIMEOUT SEC2TICK(CONFIG_NET_6LOWPAN_MAXAGE) + +/* Buffer access helpers */ + +#define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf)) + /**************************************************************************** * 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; -} - -/**************************************************************************** - * Name: sixlowpan_set_pktattrs - * - * 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" - * - * Returned Value: - * None - * - ****************************************************************************/ - -static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee, - FAR const struct ipv6_hdr_s *ipv6) -{ - int attr = 0; - - /* Set protocol in NETWORK_ID */ - - g_pktattrs[PACKETBUF_ATTR_NETWORK_ID] = ipv6->proto; - - /* Assign values to the channel attribute (port or type + code) */ - - if (ipv6->proto == IP_PROTO_UDP) - { - FAR struct udp_hdr_s *udp = &((FAR struct ipv6udp_hdr_s *)ipv6)->udp; - - attr = udp->srcport; - if (udp->destport < attr) - { - attr = udp->destport; - } - } - else if (ipv6->proto == IP_PROTO_TCP) - { - FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6)->tcp; - - attr = tcp->srcport; - if (tcp->destport < attr) - { - attr = tcp->destport; - } - } - else if (ipv6->proto == IP_PROTO_ICMP6) - { - FAR struct icmpv6_iphdr_s *icmp = &((FAR struct ipv6icmp_hdr_s *)ipv6)->icmp; - - attr = icmp->type << 8 | icmp->code; - } - - g_pktattrs[PACKETBUF_ATTR_CHANNEL] = attr; -} - /**************************************************************************** * Name: sixlowpan_frame_process * @@ -185,13 +113,365 @@ static void sixlowpan_set_pktattrs(FAR struct ieee802154_driver_s *ieee, * Returned Value: * Ok is returned on success; Othewise a negated errno value is returned. * + * Assumptions: + * Network is locked + * ****************************************************************************/ static int sixlowpan_frame_process(FAR struct ieee802154_driver_s *ieee, FAR struct iob_s *iob) { - /* REVISIT: To be provided */ - return -ENOSYS; + FAR uint8_t *hc1 = RIME_HC1_PTR; + + uint16_t fragsize = 0; /* Size of the IP packet (read from fragment) */ + uint8_t fragoffset = 0; /* Offset of the fragment in the IP packet */ + bool isfrag = false; + int reqsize; /* Required buffer size */ + +#if CONFIG_NET_6LOWPAN_FRAG + bool isfirstfrag = false; + bool islastfrag = false; + uint16_t fragtag = 0; /* Tag of the fragment */ + systime_t elapsed; /* Elapsed time */ +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + + /* Initialize global data. Locking the network guarantees that we have + * exclusive use of the global values for intermediate calculations. + */ + + g_uncomp_hdrlen = 0; + g_rime_hdrlen = 0; + + /* The MAC puts the 15.4 payload inside the RIME data buffer */ + + g_rimeptr = &iob->io_data[PACKETBUF_HDR_SIZE]; + +#if CONFIG_NET_6LOWPAN_FRAG + /* If reassembly timed out, cancel it */ + + elapsed = clock_systimer() - ieee->i_time; + if (elapsed > NET_6LOWPAN_TIMEOUT) + { + nwarn("WARNING: Reassembly timed out\n"); + ieee->i_pktlen = 0; + ieee->i_accumlen = 0; + } + + /* Since we don't support the mesh and broadcast header, the first header + * we look for is the fragmentation header + */ + + switch ((GETINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0xf800) >> 8) + { + /* First fragment of new reassembly */ + + case SIXLOWPAN_DISPATCH_FRAG1: + { + /* Set up for the reassembly */ + + fragoffset = 0; + fragsize = GETINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; + fragtag = GETINT16(RIME_FRAG_PTR, RIME_FRAG_TAG); + + ninfo("FRAG1: size %d, tag %d, offset %d\n", + fragsize, fragtag, fragoffset); + + g_rime_hdrlen += SIXLOWPAN_FRAG1_HDR_LEN; + + /* Indicate the first fragment of the reassembly */ + + isfirstfrag = true; + isfrag = true; + } + break; + + case SIXLOWPAN_DISPATCH_FRAGN: + { + /* Set offset, tag, size. Offset is in units of 8 bytes. */ + + fragoffset = RIME_FRAG_PTR[RIME_FRAG_OFFSET]; + fragtag = GETINT16(RIME_FRAG_PTR, RIME_FRAG_TAG); + fragsize = GETINT16(RIME_FRAG_PTR, RIME_FRAG_DISPATCH_SIZE) & 0x07ff; + + ninfo("FRAGN: size %d, tag %d, offset %d\n", + fragsize, fragtag, fragoffset); + + g_rime_hdrlen += SIXLOWPAN_FRAGN_HDR_LEN; + + ninfo("islastfrag?: i_accumlen %d g_rime_payloadlen %d fragsize %d\n", + ieee->i_accumlen, iob->io_len - g_rime_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_rime_hdrlen >= fragsize) + { + islastfrag = true; + } + } + break; + + /* Not a fragment */ + + default: + break; + } + + /* Check if we are currently reassembling a packet */ + + if (ieee->i_accumlen > 0) + { + /* In this case what we expect is that the next frame will hold the + * next FRAGN of the sequence. We have to handle a few exeptional + * cases that we need to handle: + * + * 1. If we are currently reassembling a packet, but have just received + * the first fragment of another packet. We can either ignore it and + * hope to receive the rest of the under-reassembly packet fragments, + * or we can discard the previous packet altogether, and start + * reassembling the new packet. Here we discard the previous packet, + * and start reassembling the new packet. + * 2. The new frame is not a fragment. We should be able to handle this + * case, but we cannot because that would require two packet buffers. + * It could be handled with a more extensive design. + * 3. The fragment came from a different sender. What would this mean? + * + */ + + if (!isfrag) + { + /* Discard the partially assembled packet */ + + nwarn("WARNING: Non-fragment frame received during reassembly\n"); + ieee->i_pktlen = 0; + ieee->i_accumlen = 0; + } + + /* It is a fragment of some kind. Drop any zero length fragments */ + + else if (fragsize == 0) + { + nwarn("WARNING: Dropping zero-length 6loWPAN fragment\n"); + return OK; + } + + /* A non-zero, first fragement received while we are in the middle of + * rassembly. Discard the partially assembled packet and start over. + */ + + else if (isfirstfrag) + { + nwarn("WARNING: First fragment frame received during reassembly\n"); + ieee->i_pktlen = 0; + ieee->i_accumlen = 0; + } + + /* Verify that this fragment is part of that reassembly sequence */ + + else if (fragsize != ieee->i_pktlen || ieee->i_reasstag != fragtag || + !rimeaddr_cmp(&ieee->i_fragsrc, &g_pktaddrs[PACKETBUF_ADDR_SENDER])) + { + /* The packet is a fragment that does not belong to the packet + * being reassembled or the packet is not a fragment. + */ + + nwarn("WARNING: Dropping 6loWPAN packet that is not a fragment of " + "the packet currently being reassembled\n"); + return OK; + } + + /* Looks good. We are currently processing a reassembling sequence and + * we recieved a valid FRAGN fragment. Skip the header compression + * dispatch logic. + */ + + goto copypayload; + } + + /* There is no reassembly in progress. Check if we received a fragment */ + + else if (isfrag) + { + /* Another case that we have to handle is if a FRAGN fragment of a + * reassembly is received, but we are not currently reassembling a + * packet. I think we have no choice but to drop the packet in this + * case. + */ + + if (!isfirstfrag) + { + nwarn("WARNING: FRAGN 6loWPAN fragment while not reassembling\n"); + return OK; + } + + /* Start reassembly if we received a non-zero length, first fragment */ + + if (fragsize > 0) + { + /* 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]); + } + } +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + + /* Process next dispatch and headers */ + +#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 + if ((hc1[RIME_HC1_DISPATCH] & SIXLOWPAN_DISPATCH_IPHC_MASK) == SIXLOWPAN_DISPATCH_IPHC) + { + ninfo("IPHC Dispatch\n"); + sixlowpan_uncompresshdr_hc06(ieee, fragsize); + } + else +#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC06 */ + +#ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 + if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_HC1) + { + ninfo("HC1 Dispatch\n"); + sixlowpan_uncompresshdr_hc1(ieee, fragsize); + } + else +#endif /* CONFIG_NET_6LOWPAN_COMPRESSION_HC1 */ + if (hc1[RIME_HC1_DISPATCH] == SIXLOWPAN_DISPATCH_IPV6) + { + ninfo("IPV6 Dispatch\n"); + g_rime_hdrlen += SIXLOWPAN_IPV6_HDR_LEN; + + /* Put uncompressed IP header in d_buf. */ + + memcpy(ieee->i_dev.d_buf, g_rimeptr + g_rime_hdrlen, IPv6_HDRLEN); + + /* Update g_uncomp_hdrlen and g_rime_hdrlen. */ + + g_rime_hdrlen += IPv6_HDRLEN; + g_uncomp_hdrlen += IPv6_HDRLEN; + } + else + { + /* Unknown or unsupported header */ + + nwarn("WARNING unknown dispatch: %u\n", hc1[RIME_HC1_DISPATCH]); + return OK; + } + +#if CONFIG_NET_6LOWPAN_FRAG +copypayload: +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + + /* Copy "payload" from the rime buffer to the d_buf. If this frame is a + * first fragment or not part of a fragmented packet, we have already + * copied the compressed headers, g_uncomp_hdrlen and g_rime_hdrlen are + * non-zerio, fragoffset is. + */ + + if (ieee->i_dev.d_len < g_rime_hdrlen) + { + ninfo("SIXLOWPAN: packet dropped due to header > total packet\n"); + return OK; + } + + g_rime_payloadlen = ieee->i_dev.d_len - g_rime_hdrlen; + + /* Sanity-check size of incoming packet to avoid buffer overflow */ + + reqsize = g_uncomp_hdrlen + (uint16_t) (fragoffset << 3) + g_rime_payloadlen; + 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, + reqsize, CONFIG_NET_6LOWPAN_MTU); + return OK; + } + + memcpy((FAR uint8_t *)ieee->i_dev.d_buf + g_uncomp_hdrlen + + (int)(fragoffset << 3), g_rimeptr + g_rime_hdrlen, + g_rime_payloadlen); + +#if CONFIG_NET_6LOWPAN_FRAG + /* Update ieee->i_accumlen if the frame is a fragment, ieee->i_pktlen + * otherwise. + */ + + 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. + */ + + 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); + } + else +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + { + ieee->i_pktlen = g_rime_payloadlen + g_uncomp_hdrlen; + } + +#if CONFIG_NET_6LOWPAN_FRAG + /* 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); + + if (ieee->i_accumlen == 0 || ieee->i_accumlen == ieee->i_pktlen) + { + FAR struct ipv6_hdr_s *ipv6 = IPv6BUF(&ieee->i_dev); + + ninfo("IP packet ready (length %d)\n", ieee->i_pktlen); + + /* REVISIT -- clearly wrong. */ + memcpy((FAR uint8_t *)ipv6, (FAR uint8_t *)ipv6, ieee->i_pktlen); + + ieee->i_pktlen = 0; + ieee->i_accumlen = 0; + + } +#endif /* CONFIG_NET_6LOWPAN_FRAG */ + + ninfodumpbuffer("IPv6 header", IPv6BUF(ieee->i_dev), IPv6_HDRLEN) + return OK; } /**************************************************************************** @@ -326,7 +606,10 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) if (ieee->i_dev.d_len > 0) { FAR struct ipv6_hdr_s *ipv6hdr; + FAR uint8_t *buffer; struct rimeaddr_s destmac; + size_t hdrlen; + size_t buflen; /* The IPv6 header followed by TCP or UDP headers should * lie at the beginning of d_buf since there is no link @@ -335,13 +618,53 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) ipv6hdr = (FAR struct ipv6_hdr_s *)(ieee->i_dev.d_buf); - /* Get the Rime MAC address of the destination */ -#warning Missing logic + /* 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); + + /* The data payload should follow the IPv6 header plus + * the protocol header. + */ + + if (ipv6hdr->proto != IP_PROTO_TCP) + { + hdrlen = IPv6_HDRLEN + TCP_HDRLEN; + } + else if (ipv6hdr->proto != IP_PROTO_UDP) + { + hdrlen = IPv6_HDRLEN + UDP_HDRLEN; + } + else if (ipv6hdr->proto != IP_PROTO_ICMP6) + { + hdrlen = IPv6_HDRLEN + ICMPv6_HDRLEN; + } + else + { + nwarn("WARNING: Unsupported protoype: %u\n", + ipv6hdr->proto); + ret = -EPROTO; + goto drop; + } + + if (hdrlen < ieee->i_dev.d_len) + { + nwarn("WARNING: Packet to small: Have %u need >%u\n", + ieee->i_dev.d_len, hdrlen); + ret = -ENOBUFS; + goto drop; + } /* Convert the outgoing packet into a frame list. */ - ret = sixlowpan_queue_frames(ieee, ipv6hdr, ieee->i_dev.d_buf, - ieee->i_dev.d_len, &destmac); + buffer = ieee->i_dev.d_buf + hdrlen; + buflen = ieee->i_dev.d_len - hdrlen; + + ret = sixlowpan_queue_frames(ieee, ipv6hdr, buffer, buflen, + &destmac); +drop: ieee->i_dev.d_len = 0; } } diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 644880398f9..c6a83480d9c 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -89,7 +89,7 @@ * The fragment header is used when the payload is too large to fit in a * single IEEE 802.15.4 frame. The fragment header contains three fields: * Datagram size, datagram tag and datagram offset. - * + * * 1. Datagram size describes the total (un-fragmented) payload. * 2. Datagram tag identifies the set of fragments and is used to match * fragments of the same payload. @@ -225,10 +225,72 @@ #define FRAME_SIZE(ieee,iob) \ ((iob)->io_len) +/* Address compressibility test macros **************************************/ + +/* Check whether we can compress the IID in address 'a' to 16 bits. This is + * used for unicast addresses only, and is true if the address is on the + * format ::0000:00ff:fe00:XXXX + * + * NOTE: we currently assume 64-bits prefixes + */ + +/* Check whether we can compress the IID in address 'a' to 16 bits. This is + * used for unicast addresses only, and is true if the address is on the + * format ::0000:00ff:fe00:XXXX. + * + * NOTE: we currently assume 64-bits prefixes. Big-endian, network order is + * assumed. + */ + +#define SIXLOWPAN_IS_IID_16BIT_COMPRESSABLE(a) \ + ((((a)[4]) == 0x0000) && (((a)[5]) == 0x00ff) && (((a)[6]) == 0xfe00)) + +/* Check whether the 9-bit group-id of the compressed multicast address is + * known. It is true if the 9-bit group is the all nodes or all routers + * group. Parameter 'a' is typed uint8_t * + */ + +#define SIXLOWPAN_IS_MCASTADDR_DECOMPRESSABLE(a) \ + (((*a & 0x01) == 0) && \ + ((*(a + 1) == 0x01) || (*(a + 1) == 0x02))) + +/* Check whether the 112-bit group-id of the multicast address is mappable + * to a 9-bit group-id. It is true if the group is the all nodes or all + * routers group: + * + * XXXX:0000:0000:0000:0000:0000:0000:0001 All nodes address + * XXXX:0000:0000:0000:0000:0000:0000:0002 All routers address + */ + +#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE(a) \ + ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \ + ((a)[7] == 0x0001 || (a)[7] == 0x0002)) + +/* FFXX:0000:0000:0000:0000:00XX:XXXX:XXXX */ + +#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE48(a) \ + ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (((a)[5] & 0xff00) == 0)) + +/* FFXX:0000:0000:0000:0000:0000:00XX:XXXX */ + +#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE32(a) \ + ((a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && ((a)[6] & 0xff00) == 0) + +/* FF02:0000:0000:0000:0000:0000:0000:00XX */ + +#define SIXLOWPAN_IS_MCASTADDR_COMPRESSABLE8(a) \ + ((((a)[0] & 0x00ff) == 0x0002) && \ + (a)[1] == 0 && (a)[2] == 0 && (a)[3] == 0 && \ + (a)[4] == 0 && (a)[5] == 0 && (a)[6] == 0 && \ + (((a)[7] & 0xff00) == 0x0000)) + /* General helper macros ****************************************************/ #define GETINT16(ptr,index) \ - ((((uint16_t)((ptr)[index]) << 8)) | ((uint16_t)(((ptr)[(index) + 1])))) + ((((uint16_t)((ptr)[index])) << 8) | ((uint16_t)(((ptr)[(index) + 1])))) #define PUTINT16(ptr,index,value) \ do \ { \ @@ -335,11 +397,6 @@ struct frame802154_s * 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; - /* The following data values are used to hold intermediate settings while * processing IEEE802.15.4 frames. These globals are shared with incoming * and outgoing frame processing and possibly with mutliple IEEE802.15.4 MAC @@ -396,6 +453,7 @@ extern struct rimeaddr_s g_pktaddrs[PACKETBUF_NUM_ADDRS]; struct net_driver_s; /* Forward reference */ struct ieee802154_driver_s; /* Forward reference */ +struct ipv6_hdr_s; /* Forward reference */ struct rimeaddr_s; /* Forward reference */ struct iob_s; /* Forward reference */ @@ -407,7 +465,7 @@ struct iob_s; /* Forward reference */ * 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'. + * The payload data is in the caller 'buf' and is of length 'buflen'. * Compressed headers will be added and if necessary the packet is * fragmented. The resulting packet/fragments are put in ieee->i_framelist * and the entire list of frames will be delivered to the 802.15.4 MAC via @@ -415,9 +473,9 @@ struct iob_s; /* Forward reference */ * * Input Parameters: * dev - The IEEE802.15.4 MAC network driver interface. - * ipv6 - IPv6 plus TCP or UDP headers. + * destip - IPv6 plus TCP or UDP headers. * buf - Data to send - * len - Length of data to send + * buflen - Length of data to send * raddr - The MAC address of the destination * timeout - Send timeout in deciseconds * @@ -433,8 +491,8 @@ struct iob_s; /* Forward reference */ ****************************************************************************/ 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 const struct ipv6_hdr_s *destip, FAR const void *buf, + size_t buflen, FAR const struct rimeaddr_s *raddr, uint16_t timeout); /**************************************************************************** @@ -499,7 +557,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, * ieee - The IEEE802.15.4 MAC driver instance * ipv6hdr - IPv6 header followed by TCP or UDP header. * buf - Data to send - * len - Length of data to send + * buflen - Length of data to send * destmac - The IEEE802.15.4 MAC address of the destination * * Returned Value: @@ -515,7 +573,7 @@ int sixlowpan_framecreate(FAR struct ieee802154_driver_s *ieee, int sixlowpan_queue_frames(FAR struct ieee802154_driver_s *ieee, FAR const struct ipv6_hdr_s *ipv6hdr, - FAR const void *buf, size_t len, + FAR const void *buf, size_t buflen, FAR const struct rimeaddr_s *destmac); /**************************************************************************** @@ -542,7 +600,7 @@ void sixlowpan_hc06_initialize(void); #endif /**************************************************************************** - * Name: sixlowpan_hc06_initialize + * Name: sixlowpan_compresshdr_hc06 * * Description: * Compress IP/UDP header @@ -559,7 +617,10 @@ void sixlowpan_hc06_initialize(void); * * Input Parameters: * ieee - A reference to the IEE802.15.4 network device state - * destaddr - L2 destination address, needed to compress IP dest + * ipv6 - The IPv6 header to be compressed + * destmac - L2 destination address, needed to compress the IP + * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None @@ -567,12 +628,14 @@ void sixlowpan_hc06_initialize(void); ****************************************************************************/ #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC06 -void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *dev, - FAR struct rimeaddr_s *destaddr); +void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *ieee, + FAR const struct ipv6_hdr_s *ipv6, + FAR const struct rimeaddr_s *destmac, + FAR struct iob_s *iob); #endif /**************************************************************************** - * Name: sixlowpan_hc06_initialize + * Name: sixlowpan_uncompresshdr_hc06 * * Description: * Uncompress HC06 (i.e., IPHC and LOWPAN_UDP) headers and put them in @@ -587,7 +650,7 @@ void sixlowpan_compresshdr_hc06(FAR struct ieee802154_driver_s *dev, * Input Parmeters: * ieee - 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 + * inferred from the L2 length), non 0 if the packet is a first * fragment. * * Returned Value: @@ -611,9 +674,11 @@ void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, * uip_buf buffer. * * Input Parmeters: - * ieee - A reference to the IEE802.15.4 network device state - * destaddr - L2 destination address, needed to compress the IP - * destination field + * ieee - A reference to the IEE802.15.4 network device state + * ipv6 - The IPv6 header to be compressed + * destmac - L2 destination address, needed to compress the IP + * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None @@ -622,7 +687,9 @@ void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, #ifdef CONFIG_NET_6LOWPAN_COMPRESSION_HC1 void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, - FAR struct rimeaddr_s *destaddr); + FAR const struct ipv6_hdr_s *ipv6, + FAR const struct rimeaddr_s *destmac, + FAR struct iob_s *iob); #endif /**************************************************************************** @@ -640,7 +707,7 @@ void sixlowpan_compresshdr_hc1(FAR struct ieee802154_driver_s *ieee, * Input Parameters: * ieee - 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 + * inferred from the L2 length), non 0 if the packet is a first * fragment. * * Returned Value: @@ -663,5 +730,35 @@ void sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size); +/**************************************************************************** + * Name: sixlowpan_islinklocal, sixlowpan_ipfromrime, sixlowpan_rimefromip, + * and sixlowpan_ismacbased + * + * Description: + * sixlowpan_ipfromrime: Create a link local IPv6 address from a rime + * address. + * + * sixlowpan_rimefromip: Extract the rime address from a link local IPv6 + * address. + * + * sixlowpan_islinklocal and sixlowpan_ismacbased will return true for + * address created in this fashion. + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 xxxx 0000 0000 0000 2-byte Rime address (VALID?) + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address + * + ****************************************************************************/ + +#define sixlowpan_islinklocal(ipaddr) ((ipaddr)[0] = NTOHS(0xfe80)) + +void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime, + net_ipv6addr_t ipaddr); +void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, + FAR struct rimeaddr_s *rime); +bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, + FAR const struct rimeaddr_s *rime); + #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 cff92eeceed..f8076449b9e 100644 --- a/net/sixlowpan/sixlowpan_send.c +++ b/net/sixlowpan/sixlowpan_send.c @@ -54,6 +54,17 @@ #ifdef CONFIG_NET_6LOWPAN +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* These are temporary stubs. Something like this would be needed to + * monitor the health of a IPv6 neighbor. + */ + +#define neighbor_reachable(dev) +#define neighbor_notreachable(dev) + /**************************************************************************** * Private Types ****************************************************************************/ @@ -172,6 +183,7 @@ static uint16_t send_interrupt(FAR struct net_driver_s *dev, sinfo->s_destmac); flags &= ~WPAN_POLL; + neighbor_reachable(dev); goto end_wait; } @@ -183,6 +195,7 @@ static uint16_t send_interrupt(FAR struct net_driver_s *dev, nwarn("WARNING: SEND timeout\n"); sinfo->s_result = -ETIMEDOUT; + neighbor_notreachable(dev); goto end_wait; } diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index ba11700ab44..a7a1a90f3b5 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -39,11 +39,13 @@ #include +#include #include #include #include #include "nuttx/net/netdev.h" +#include "nuttx/net/netstats.h" #include "netdev/netdev.h" #include "socket/socket.h" @@ -66,7 +68,7 @@ * Parameters: * psock - An instance of the internal socket structure. * buf - Data to send - * len - Length of data to send + * bulen - Length of data to send * * Returned Value: * On success, returns the number of characters sent. On error, @@ -80,13 +82,14 @@ ****************************************************************************/ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, - size_t len) + size_t buflen) { FAR struct tcp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6tcp_hdr_s ipv6tcp; struct rimeaddr_s destmac; uint16_t timeout; + uint16_t iplen; int ret; DEBUGASSERT(psock != NULL && psock->s_crefs > 0); @@ -113,7 +116,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, conn = (FAR struct tcp_conn_s *)psock->s_conn; DEBUGASSERT(conn != NULL); -#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) +#ifdef CONFIG_NET_IPv4 /* Ignore if not IPv6 domain */ if (conn->domain != PF_INET6) @@ -161,14 +164,88 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, #endif /* Initialize the IPv6/TCP headers */ -#warning Missing logic + /* Initialize the IPv6/UDP headers */ + + ipv6tcp.ipv6.vtc = 0x60; + ipv6tcp.ipv6.tcf = 0x00; + ipv6tcp.ipv6.flow = 0x00; + ipv6tcp.ipv6.proto = IP_PROTO_TCP; + ipv6tcp.ipv6.ttl = IP_TTL; + + /* The IPv6 header length field does not include the size of IPv6 IP + * header. + */ + + iplen = buflen + TCP_HDRLEN; + ipv6tcp.ipv6.len[0] = (iplen >> 8); + ipv6tcp.ipv6.len[1] = (iplen & 0xff); + + /* Copy the source and destination addresses */ + + net_ipv6addr_hdrcopy(ipv6tcp.ipv6.srcipaddr, conn->u.ipv6.laddr); + net_ipv6addr_hdrcopy(ipv6tcp.ipv6.destipaddr, conn->u.ipv6.raddr); + + ninfo("IPv6 length: %d\n", ((int)ipv6->len[0] << 8) + ipv6->len[1]); + +#ifdef CONFIG_NET_STATISTICS + g_netstats.ipv6.sent++; +#endif + + /* Initialize the TCP header */ + + ipv6tcp.tcp.srcport = conn->lport; /* Local port */ + ipv6tcp.tcp.destport = conn->rport; /* Connected remote port */ + + memcpy(ipv6tcp.tcp.ackno, conn->rcvseq, 4); /* ACK number */ + memcpy(ipv6tcp.tcp.seqno, conn->sndseq, 4); /* Sequence number */ + + ipv6tcp.tcp.tcpoffset = (TCP_HDRLEN / 4) << 4; /* No optdata */ + ipv6tcp.tcp.urgp[0] = 0; /* No urgent data */ + ipv6tcp.tcp.urgp[1] = 0; + + /* Set the TCP window */ + + if (conn->tcpstateflags & TCP_STOPPED) + { + /* If the connection has issued TCP_STOPPED, we advertise a zero + * window so that the remote host will stop sending data. + */ + + ipv6tcp.tcp.wnd[0] = 0; + ipv6tcp.tcp.wnd[1] = 0; + } + else + { + ipv6tcp.tcp.wnd[0] = ((NET_DEV_RCVWNDO(dev)) >> 8); + ipv6tcp.tcp.wnd[1] = ((NET_DEV_RCVWNDO(dev)) & 0xff); + } + + /* Calculate TCP checksum. */ + + ipv6tcp.tcp.tcpchksum = 0; +#if 0 + /* REVISIT: Current checksum logic expects the IPv6 header, the UDP header, and + * the payload data to be in contiguous memory. + */ + + ipv6tcp.tcp.tcpchksum = ~tcp_ipv6_chksum(dev); +#endif + + ninfo("Outgoing TCP packet length: %d bytes\n", iplen + IOPv6_HDRLEN); + +#ifdef CONFIG_NET_STATISTICS + g_netstats.tcp.sent++; +#endif /* 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 + /* Get the Rime MAC address of the destination This assumes an encoding + * of the MAC address in the IPv6 address. + */ + + sixlowpan_rimefromip(conn->u.ipv6.raddr, &destmac); /* If routable, then call sixlowpan_send() to format and send the 6loWPAN * packet. @@ -181,7 +258,7 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, #endif ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6tcp, - buf, len, &destmac, timeout); + buf, buflen, &destmac, timeout); if (ret < 0) { nerr("ERROR: sixlowpan_send() failed: %d\n", ret); @@ -193,4 +270,86 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, return ret; } +/**************************************************************************** + * Function: sixlowpan_tcp_send + * + * Description: + * TCP output comes through two different mechansims. Either from: + * + * 1. TCP socket output. For the case of TCP output to an + * IEEE802.15.4, the TCP output is caught in the socket + * send()/sendto() logic and and redirected to psock_6lowpan_tcp_send(). + * 2. TCP output from the TCP state machine. That will occur + * during TCP packet processing by the TCP state meachine. It + * is detected there when ipv6_tcp_input() returns with d_len > 0. This + * will be redirected here. + * + * Parameters: + * dev - An instance of nework device state structure + * + * Returned Value: + * None + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +void sixlowpan_tcp_send(FAR struct net_driver_s *dev) +{ + DEBUGASSERT(dev != NULL && dev->d_len > 0); + + /* Double check */ + + if (dev != NULL && dev->d_len > 0) + { + FAR struct ipv6_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); + + /* The TCP data payload should follow the IPv6 header plus the + * protocol header. + */ + + if (ipv6hdr->proto != IP_PROTO_TCP) + { + nwarn("WARNING: Expected TCP protoype: %u\n", ipv6hdr->proto); + } + else + { + size_t hdrlen; + + hdrlen = IPv6_HDRLEN + TCP_HDRLEN; + if (hdrlen < dev->d_len) + { + nwarn("WARNING: Packet to small: Have %u need >%u\n", + dev->d_len, hdrlen); + } + else + { + struct rimeaddr_s destmac; + + /* 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); + + /* Convert the outgoing packet into a frame list. */ + + (void)sixlowpan_queue_frames( + (FAR struct ieee802154_driver_s *)dev, ipv6hdr, + dev->d_buf + hdrlen, dev->d_len - hdrlen, &destmac); + } + } + } + + dev->d_len = 0; +} + #endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_TCP */ diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 3b17d00767d..49932514c81 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -39,11 +39,14 @@ #include +#include +#include #include #include #include #include "nuttx/net/netdev.h" +#include "nuttx/net/netstats.h" #include "netdev/netdev.h" #include "socket/socket.h" @@ -57,21 +60,26 @@ ****************************************************************************/ /**************************************************************************** - * Function: psock_6lowpan_udp_send + * Function: psock_6lowpan_udp_sendto * * Description: - * psock_6lowpan_udp_send() call may be used with connectionlesss UDP - * sockets. + * If sendto() is used on a connection-mode (SOCK_STREAM, SOCK_SEQPACKET) + * socket, the parameters to and 'tolen' are ignored (and the error EISCONN + * may be returned when they are not NULL and 0), and the error ENOTCONN is + * returned when the socket was not actually connected. * * Parameters: - * psock - An instance of the internal socket structure. - * buf - Data to send - * len - Length of data to send + * psock A pointer to a NuttX-specific, internal socket structure + * buf Data to send + * buflen Length of data to send + * flags Send flags + * to Address of recipient + * tolen The length of the address structure * * 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 + * -1 is returned, and errno is set appropriately. Returned error + * number must be consistent with definition of errors reported by * sendto(). * * Assumptions: @@ -79,16 +87,215 @@ * ****************************************************************************/ -ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, - size_t len) +ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, + FAR const void *buf, + size_t buflen, int flags, + FAR const struct sockaddr *to, + socklen_t tolen) { + FAR struct sockaddr_in6 *to6 = (FAR struct sockaddr_in6 *)to; FAR struct udp_conn_s *conn; FAR struct net_driver_s *dev; struct ipv6udp_hdr_s ipv6udp; struct rimeaddr_s destmac; + uint16_t iplen; uint16_t timeout; int ret; + DEBUGASSERT(psock != NULL && psock->s_crefs > 0 && to != NULL); + DEBUGASSERT(psock->s_type == SOCK_DGRAM); + + if (psock == NULL || to == NULL) + { + return (ssize_t)-EINVAL; + } + + /* Make sure that this is a datagram valid socket */ + + if (psock->s_crefs <= 0 || psock->s_type != SOCK_DGRAM) + { + nerr("ERROR: Invalid socket\n"); + return (ssize_t)-EBADF; + } + + /* Make sure that the destination address is valid */ + + if (to6->sin6_family != AF_INET6 || tolen < sizeof(struct sockaddr_in6)) + { + nerr("ERROR: Invalid destination address\n"); + return (ssize_t)-EAFNOSUPPORT; + } + + /* Get the underlying UDP "connection" structure */ + + 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 + dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, + to6->sin6_addr.in6_u.u6_addr16); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif + { + nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); + return (ssize_t)-ENETUNREACH; + } +#else + dev = netdev_findby_ipv6addr(to6->sin6_addr.in6_u.u6_addr16); +#ifdef CONFIG_NETDEV_MULTILINK + if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) +#else + if (dev == NULL) +#endif + { + 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(to6->sin6_addr.in6_u.u6_addr16); + if (ret < 0) + { + nerr("ERROR: Not reachable\n"); + return (ssize_t)-ENETUNREACH; + } +#endif + + /* Initialize the IPv6/UDP headers */ + + ipv6udp.ipv6.vtc = 0x60; + ipv6udp.ipv6.tcf = 0x00; + ipv6udp.ipv6.flow = 0x00; + ipv6udp.ipv6.proto = IP_PROTO_UDP; + ipv6udp.ipv6.ttl = conn->ttl; + + /* The IPv6 header length field does not include the size of IPv6 IP + * header. + */ + + iplen = buflen + UDP_HDRLEN; + ipv6udp.ipv6.len[0] = (iplen >> 8); + ipv6udp.ipv6.len[1] = (iplen & 0xff); + + /* 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); + + ninfo("IPv6 length: %d\n", ((int)ipv6->len[0] << 8) + ipv6->len[1]); + +#ifdef CONFIG_NET_STATISTICS + g_netstats.ipv6.sent++; +#endif + + /* Initialize the UDP header */ + + ipv6udp.udp.srcport = conn->lport; + ipv6udp.udp.destport = to6->sin6_port; + ipv6udp.udp.udplen = htons(iplen); + ipv6udp.udp.udpchksum = 0; + + ipv6udp.udp.udpchksum = 0; + +#warning Missing logic +#if 0 /* REVISIT */ +#ifdef CONFIG_NET_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + /* REVISIT: Current checksum logic expects the IPv6 header, the UDP header, and + * the payload data to be in contiguous memory. + */ + + ipv6udp.udp.udpchksum = ~udp_ipv6_chksum(dev); + if (ipv6udp.udp.udpchksum == 0) + { + ipv6udp.udp.udpchksum = 0xffff; + } +#endif /* CONFIG_NET_UDP_CHECKSUMS */ +#endif /* REVISIT */ + + ninfo("Outgoing UDP packet length: %d\n", iplen + IPv6_HDRLEN); + +#ifdef CONFIG_NET_STATISTICS + g_netstats.udp.sent++; +#endif + + /* Set the socket state to sending */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_SEND); + + /* Get the Rime MAC address of the destination This assumes an encoding + * of the MAC address in the IPv6 address. + */ + + sixlowpan_rimefromip(to6->sin6_addr.in6_u.u6_addr16, &destmac); + + /* If routable, then call sixlowpan_send() to format and send the 6loWPAN + * packet. + */ + +#ifdef CONFIG_NET_SOCKOPTS + timeout = psock->s_sndtimeo; +#else + timeout = 0; +#endif + + ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, + buf, buflen, &destmac, timeout); + if (ret < 0) + { + nerr("ERROR: sixlowpan_send() failed: %d\n", ret); + } + + /* Set the socket state to idle */ + + psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); + return ret; +} + +/**************************************************************************** + * 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 + * buflen - 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(). + * + * Assumptions: + * Called with the network locked. + * + ****************************************************************************/ + +ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, + size_t buflen) +{ + FAR struct udp_conn_s *conn; + struct sockaddr_in6 to; + DEBUGASSERT(psock != NULL && psock->s_crefs > 0); DEBUGASSERT(psock->s_type == SOCK_DGRAM); @@ -114,7 +321,6 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, 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) @@ -122,76 +328,16 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, nwarn("WARNING: Not IPv6\n"); return (ssize_t)-EPROTOTYPE; } -#endif - /* Route outgoing message to the correct device */ + /* Create the 'to' address */ -#ifdef CONFIG_NETDEV_MULTINIC - dev = netdev_findby_ipv6addr(conn->u.ipv6.laddr, conn->u.ipv6.raddr); -#ifdef CONFIG_NETDEV_MULTILINK - if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) -#else - if (dev == NULL) -#endif - { - nwarn("WARNING: Not routable or not IEEE802.15.4 MAC\n"); - return (ssize_t)-ENETUNREACH; - } -#else - dev = netdev_findby_ipv6addr(conn->u.ipv6.raddr); -#ifdef CONFIG_NETDEV_MULTILINK - if (dev == NULL || dev->d_lltype != NET_LL_IEEE802154) -#else - if (dev == NULL) -#endif - { - nwarn("WARNING: Not routable\n"); - return (ssize_t)-ENETUNREACH; - } -#endif + to.sin6_family = AF_INET6; + to.sin6_port = conn->rport; /* Already network order */ + memcpy(to.sin6_addr.in6_u.u6_addr16, conn->u.ipv6.raddr, 16); -#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. - */ - -#ifdef CONFIG_NET_SOCKOPTS - timeout = psock->s_sndtimeo; -#else - timeout = 0; -#endif - - ret = sixlowpan_send(dev, (FAR const struct ipv6_hdr_s *)&ipv6udp, - buf, len, &destmac, timeout); - if (ret < 0) - { - nerr("ERROR: sixlowpan_send() failed: %d\n", ret); - } - - /* Set the socket state to idle */ - - psock->s_flags = _SS_SETSTATE(psock->s_flags, _SF_IDLE); - return ret; + return psock_6lowpan_udp_sendto(psock, buf, buflen, 0, + (FAR const struct sockaddr *)&to, + sizeof(struct sockaddr_in6)); } #endif /* CONFIG_NET_6LOWPAN && CONFIG_NET_UDP */ diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c index f6ad77c68b1..fae33fe2076 100644 --- a/net/sixlowpan/sixlowpan_utils.c +++ b/net/sixlowpan/sixlowpan_utils.c @@ -66,8 +66,11 @@ #include #include +#include #include +#include + #include "sixlowpan/sixlowpan_internal.h" #ifdef CONFIG_NET_6LOWPAN @@ -96,4 +99,89 @@ int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size) return -ENOMEM; } +/**************************************************************************** + * Name: sixlowpan_ipfromrime + * + * Description: + * Create a link local IPv6 address from a rime address: + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 xxxx xxxx 0000 0000 2-byte Rime address (VALID?) + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address + * + ****************************************************************************/ + +void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime, + net_ipv6addr_t ipaddr) +{ + memset(ipaddr, 0, sizeof(net_ipv6addr_t)); + ipaddr[0] = 0xfe80; + + /* We consider only links with IEEE EUI-64 identifier or IEEE 48-bit MAC + * addresses. NOTE: that CONFIG_NET_6LOWPAN_RIMEADDR_SIZE may be 2 or + * 8. In the case of 2, we treat the address like an 8 byte address with + * the lower bytes set to zero. + * + * REVISIT: This is just a guess so that I can continue making forward + * progress. What is the correct policy? + */ + + memcpy(&ipaddr[4], rime, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + ipaddr[4] ^= 0x0200; +} + +/**************************************************************************** + * Name: sixlowpan_rimefromip + * + * Description: + * Extract the rime address from a link local IPv6 address: + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 xxxx 0000 0000 0000 2-byte Rime address (VALID?) + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address + * + ****************************************************************************/ + +void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, + FAR struct rimeaddr_s *rime) +{ + /* REVISIT: See notes about 2 byte addresses in sixlowpan_ipfromrime() */ + + DEBUGASSERT(ipaddr[0] == 0xfe80); + + memcpy(rime, &ipaddr[4], CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + rime->u8[0] ^= 0x02; +} + +/**************************************************************************** + * Name: sixlowpan_ismacbased + * + * Description: + * Extract the rime address from a link local IPv6 address: + * + * 128 112 96 80 64 48 32 16 + * ---- ---- ---- ---- ---- ---- ---- ---- + * fe80 0000 0000 0000 xxxx 0000 0000 0000 2-byte Rime address (VALID?) + * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address + * + ****************************************************************************/ + +bool sixlowpan_ismacbased(const net_ipv6addr_t ipaddr, + FAR const struct rimeaddr_s *rime) +{ + FAR const uint8_t *rimeptr = rime->u8; + +#if CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 2 + return ((ipaddr[4] == (GETINT16(rimeptr, 0) ^ 0x0200)) && + ipaddr[5] == 0 && ipaddr[6] == 0 && ipaddr[7] == 0); +#else /* CONFIG_NET_6LOWPAN_RIMEADDR_SIZE == 8 */ + return ((ipaddr[4] == (GETINT16(rimeptr, 0) ^ 0x0200)) && + ipaddr[5] == GETINT16(rimeptr, 2) && + ipaddr[6] == GETINT16(rimeptr, 4) && + ipaddr[7] == GETINT16(rimeptr, 6)); +#endif +} + #endif /* CONFIG_NET_6LOWPAN */ diff --git a/net/socket/send.c b/net/socket/send.c index fb50549e86e..2e805b4eaf0 100644 --- a/net/socket/send.c +++ b/net/socket/send.c @@ -1,7 +1,7 @@ /**************************************************************************** * net/socket/send.c * - * Copyright (C) 2007-2014, 2016 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2016-2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -166,29 +166,18 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, ret = psock_6lowpan_tcp_send(psock, buf, len); -#ifdef CONFIG_NETDEV_MULTINIC +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_TCP_HAVE_STACK) if (ret < 0) { /* TCP/IP packet send */ ret = psock_tcp_send(psock, buf, len); -#ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_send(psock, buf, len); -#else - ret = -ENOSYS; -#endif } - -#endif /* CONFIG_NETDEV_MULTINIC */ -#else /* CONFIG_NET_6LOWPAN */ - - /* Only TCP/IP packet send */ - -#ifdef NET_TCP_HAVE_STACK - ret = psock_tcp_send(psock, buf, len); +#endif /* CONFIG_NETDEV_MULTINIC && NET_TCP_HAVE_STACK */ +#elif defined(NET_TCP_HAVE_STACK) + nsent = psock_tcp_send(psock, buf, len, flags, to, tolen); #else - ret = -ENOSYS; -#endif + nsent = -ENOSYS; #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_TCP */ @@ -215,34 +204,25 @@ ssize_t psock_send(FAR struct socket *psock, FAR const void *buf, size_t len, else #endif { -#ifdef CONFIG_NET_6LOWPAN +#if defined(CONFIG_NET_6LOWPAN) /* Try 6loWPAN UDP packet send */ ret = psock_6lowpan_udp_send(psock, buf, len); -#ifdef CONFIG_NETDEV_MULTINIC +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK) if (ret < 0) { /* UDP/IP packet send */ ret = psock_udp_send(psock, buf, len); -#ifdef NET_UDP_HAVE_STACK - ret = psock_udp_send(psock, buf, len); -#else - ret = -ENOSYS; -#endif } - -#endif /* CONFIG_NETDEV_MULTINIC */ -#else /* CONFIG_NET_6LOWPAN */ - +#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */ +#elif defined(NET_UDP_HAVE_STACK) /* Only UDP/IP packet send */ - -#ifdef NET_UDP_HAVE_STACK + ret = psock_udp_send(psock, buf, len); #else ret = -ENOSYS; -#endif #endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ diff --git a/net/socket/sendto.c b/net/socket/sendto.c index eba84f5cea6..4c2798cd6ca 100644 --- a/net/socket/sendto.c +++ b/net/socket/sendto.c @@ -49,6 +49,7 @@ #include #include "udp/udp.h" +#include "sixlowpan/sixlowpan.h" #include "local/local.h" #include "socket/socket.h" #include "usrsock/usrsock.h" @@ -237,11 +238,24 @@ ssize_t psock_sendto(FAR struct socket *psock, FAR const void *buf, else #endif { -#ifdef NET_UDP_HAVE_STACK +#if defined(CONFIG_NET_6LOWPAN) + /* Try 6loWPAN UDP packet sendto() */ + + nsent = psock_6lowpan_udp_sendto(psock, buf, len, flags, to, tolen); + +#if defined(CONFIG_NETDEV_MULTINIC) && defined(NET_UDP_HAVE_STACK) + if (nsent < 0) + { + /* UDP/IP packet sendto */ + + nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); + } +#endif /* CONFIG_NETDEV_MULTINIC && NET_UDP_HAVE_STACK */ +#elif defined(NET_UDP_HAVE_STACK) nsent = psock_udp_sendto(psock, buf, len, flags, to, tolen); #else nsent = -ENOSYS; -#endif +#endif /* CONFIG_NET_6LOWPAN */ } #endif /* CONFIG_NET_UDP */ diff --git a/net/tcp/tcp_input.c b/net/tcp/tcp_input.c index 184dfebb01c..1918bd34924 100644 --- a/net/tcp/tcp_input.c +++ b/net/tcp/tcp_input.c @@ -2,7 +2,7 @@ * net/tcp/tcp_input.c * Handling incoming TCP input * - * Copyright (C) 2007-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2014, 2017 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Adapted for NuttX from logic in uIP which also has a BSD-like license: