diff --git a/net/sixlowpan/sixlowpan_hc1.c b/net/sixlowpan/sixlowpan_hc1.c index 268f0bad3e..1285144703 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 ****************************************************************************/ @@ -136,14 +147,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 18e499f0d5..882af91708 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -700,8 +700,12 @@ 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); /* Convert the outgoing packet into a frame list. */ diff --git a/net/sixlowpan/sixlowpan_internal.h b/net/sixlowpan/sixlowpan_internal.h index 644880398f..1ec75b57f8 100644 --- a/net/sixlowpan/sixlowpan_internal.h +++ b/net/sixlowpan/sixlowpan_internal.h @@ -663,5 +663,27 @@ 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 + * + * Description: + * sixlowpan_ipfromrime: Use stateless auto-configuration to create an IP + * address from a rime address. + * + * sixlowpan_rimefromip: Assume stateless auto-configuration to extrate + * the rime address from an IP 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); +void sixlowpan_rimefromip(const net_ipv6addr_t ipaddr, + FAR struct rimeaddr_s *rime); + #endif /* CONFIG_NET_6LOWPAN */ #endif /* _NET_SIXLOWPAN_SIXLOWPAN_INTERNAL_H */ diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index ba11700ab4..ae581b150a 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -167,8 +167,11 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, 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. diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 3b17d00767..c0c3148b90 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -168,8 +168,11 @@ ssize_t psock_6lowpan_udp_send(FAR struct socket *psock, FAR const void *buf, 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. diff --git a/net/sixlowpan/sixlowpan_utils.c b/net/sixlowpan/sixlowpan_utils.c index f6ad77c68b..77612c82c1 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,60 @@ int sixlowpan_frame_hdralloc(FAR struct iob_s *iob, int size) return -ENOMEM; } +/**************************************************************************** + * Name: sixlowpan_ipfromrime + * + * Description: + * Use stateless auto-configuration to create an IP 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); +} + +/**************************************************************************** + * Name: sixlowpan_rimefromip + * + * Description: + * Assume stateless auto-configuration to extrate the rime address from + * an IP 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_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); +} + #endif /* CONFIG_NET_6LOWPAN */