From 5af0909275f6e55ef27a31b421e669c7c42cf06f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sat, 1 Apr 2017 15:05:38 -0600 Subject: [PATCH] 6loWPAN: A little HC1 compression logic. --- net/sixlowpan/sixlowpan_hc06.c | 5 +- net/sixlowpan/sixlowpan_hc1.c | 106 ++++++++++++++++++++++++++++- net/sixlowpan/sixlowpan_internal.h | 40 ++++++++--- net/sixlowpan/sixlowpan_utils.c | 39 +++++++++-- 4 files changed, 171 insertions(+), 19 deletions(-) diff --git a/net/sixlowpan/sixlowpan_hc06.c b/net/sixlowpan/sixlowpan_hc06.c index e0ca657c03..d6668978d9 100644 --- a/net/sixlowpan/sixlowpan_hc06.c +++ b/net/sixlowpan/sixlowpan_hc06.c @@ -203,7 +203,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 + * destaddr - L2 destination address, needed to compress the IP + * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 1285144703..3078896921 100644 --- a/net/sixlowpan/sixlowpan_hc1.c +++ b/net/sixlowpan/sixlowpan_hc1.c @@ -114,8 +114,10 @@ * * Input Parmeters: * ieee - A reference to the IEE802.15.4 network device state + * ipv6 - The IPv6 header to be compressed * destaddr - L2 destination address, needed to compress the IP * destination field + * iob - The IOB into which the compressed header should be saved. * * Returned Value: * None @@ -123,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 *destaddr, + 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, destaddr) || + (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 */ + } + } } /**************************************************************************** diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 1ec75b57f8..bd8929cbb5 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -228,7 +228,7 @@ /* 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 \ { \ @@ -396,6 +396,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 */ @@ -559,7 +560,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 + * destaddr - 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,8 +571,10 @@ 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 *destaddr, + FAR struct iob_s *iob); #endif /**************************************************************************** @@ -612,8 +618,10 @@ void sixlowpan_uncompresshdr_hc06(FAR struct ieee802154_driver_s *ieee, * * Input Parmeters: * ieee - A reference to the IEE802.15.4 network device state + * ipv6 - The IPv6 header to be compressed * destaddr - 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 +630,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 *destaddr, + FAR struct iob_s *iob); #endif /**************************************************************************** @@ -664,26 +674,34 @@ void sixlowpan_uncompresshdr_hc1(FAR struct ieee802154_driver_s *ieee, int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size); /**************************************************************************** - * Name: sixlowpan_ipfromrime and sixlowpan_rimefromip + * Name: sixlowpan_islinklocal, sixlowpan_ipfromrime, sixlowpan_rimefromip, + * and sixlowpan_ismacbased * * Description: - * sixlowpan_ipfromrime: Use stateless auto-configuration to create an IP - * address from a rime address. + * sixlowpan_ipfromrime: Create a link local IPv6 address from a rime + * address. * - * sixlowpan_rimefromip: Assume stateless auto-configuration to extrate - * the rime address from an IP 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 xxxx 0000 0000 2-byte Rime address (VALID?) + * 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_utils.c b/net/sixlowpan/sixlowpan_utils.c index 77612c82c1..fae33fe207 100644 --- a/net/sixlowpan/sixlowpan_utils.c +++ b/net/sixlowpan/sixlowpan_utils.c @@ -103,8 +103,7 @@ int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size) * Name: sixlowpan_ipfromrime * * Description: - * Use stateless auto-configuration to create an IP address from a rime - * address: + * Create a link local IPv6 address from a rime address: * * 128 112 96 80 64 48 32 16 * ---- ---- ---- ---- ---- ---- ---- ---- @@ -129,18 +128,18 @@ void sixlowpan_ipfromrime(FAR const struct rimeaddr_s *rime, */ memcpy(&ipaddr[4], rime, CONFIG_NET_6LOWPAN_RIMEADDR_SIZE); + ipaddr[4] ^= 0x0200; } /**************************************************************************** * Name: sixlowpan_rimefromip * * Description: - * Assume stateless auto-configuration to extrate the rime address from - * an IP address: + * Extract the rime address from a link local IPv6 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 0000 0000 0000 2-byte Rime address (VALID?) * fe80 0000 0000 0000 xxxx xxxx xxxx xxxx 8-byte Rime address * ****************************************************************************/ @@ -153,6 +152,36 @@ void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, 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 */