diff --git a/net/sixlowpan/sixlowpan_framelist.c b/net/sixlowpan/sixlowpan_framelist.c index 8d8900460f5..552f394b786 100644 --- a/net/sixlowpan/sixlowpan_framelist.c +++ b/net/sixlowpan/sixlowpan_framelist.c @@ -154,29 +154,37 @@ static void sixlowpan_copy_protohdr(FAR const struct ipv6_hdr_s *ipv6hdr, { #ifdef CONFIG_NET_TCP case IP_PROTO_TCP: - combined = sizeof(struct ipv6tcp_hdr_s); - protosize = sizeof(struct tcp_hdr_s); + { + FAR struct tcp_hdr_s *tcp = &((FAR struct ipv6tcp_hdr_s *)ipv6hdr)->tcp; + + /* The TCP header length is encoded in the top 4 bits of the + * tcpoffset field (in units of 32-bit words). + */ + + protosize = ((uint16_t)tcp->tcpoffset >> 4) << 2; + combined = sizeof(struct ipv6_hdr_s) + protosize; + } break; #endif #ifdef CONFIG_NET_UDP case IP_PROTO_UDP: - combined = sizeof(struct ipv6udp_hdr_s); protosize = sizeof(struct udp_hdr_s); + combined = sizeof(struct ipv6udp_hdr_s); break; #endif #ifdef CONFIG_NET_ICMPv6 case IP_PROTO_ICMP6: - combined = sizeof(struct ipv6icmp_hdr_s); protosize = sizeof(struct icmpv6_hdr_s); + combined = sizeof(struct ipv6icmp_hdr_s); break; #endif default: nwarn("WARNING: Unrecognized proto: %u\n", ipv6hdr->proto); - combined = sizeof(struct ipv6_hdr_s); protosize = 0; + combined = sizeof(struct ipv6_hdr_s); break; } diff --git a/net/sixlowpan/sixlowpan_input.c b/net/sixlowpan/sixlowpan_input.c index 7144d36e8b4..6098a58251c 100644 --- a/net/sixlowpan/sixlowpan_input.c +++ b/net/sixlowpan/sixlowpan_input.c @@ -86,6 +86,7 @@ /* Buffer access helpers */ #define IPv6BUF(dev) ((FAR struct ipv6_hdr_s *)((dev)->d_buf)) +#define TCPBUF(dev) ((FAR struct tcp_hdr_s *)&(dev)->d_buf[IPv6_HDRLEN]) /**************************************************************************** * Private Functions @@ -728,7 +729,7 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) * layer protocol header. */ - ipv6hdr = (FAR struct ipv6_hdr_s *)(ieee->i_dev.d_buf); + ipv6hdr = IPv6BUF(&ieee->i_dev); /* Get the Rime MAC address of the destination. This * assumes an encoding of the MAC address in the IPv6 @@ -743,7 +744,15 @@ int sixlowpan_input(FAR struct ieee802154_driver_s *ieee) if (ipv6hdr->proto != IP_PROTO_TCP) { - hdrlen = IPv6_HDRLEN + TCP_HDRLEN; + FAR struct tcp_hdr_s *tcp = TCPBUF(&ieee->i_dev); + uint16_t tcplen; + + /* The TCP header length is encoded in the top 4 bits + * of the tcpoffset field (in units of 32-bit words). + */ + + tcplen = ((uint16_t)tcp->tcpoffset >> 4) << 2; + hdrlen = IPv6_HDRLEN + tcplen; } else if (ipv6hdr->proto != IP_PROTO_UDP) { diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index a1a4a5847b8..3ee39e72ed6 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -88,6 +88,7 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp, FAR const uint8_t *buf, uint16_t buflen) { uint16_t upperlen; + uint16_t tcplen; uint16_t sum; /* The length reported in the IPv6 header is the length of the payload @@ -115,9 +116,14 @@ static uint16_t sixlowpan_tcp_chksum(FAR struct ipv6tcp_hdr_s *ipv6tcp, sum = chksum(sum, (FAR uint8_t *)ipv6tcp->ipv6.srcipaddr, 2 * sizeof(net_ipv6addr_t)); - /* Sum the TCP header */ + /* Sum the TCP header + * + * The TCP header length is encoded in the top 4 bits of the tcpoffset + * field (in units of 32-bit words). + */ - sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, TCP_HDRLEN); + tcplen = ((uint16_t)ipv6tcp->tcp.tcpoffset >> 4) << 2; + sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, tcplen); /* Sum payload data. */ @@ -383,43 +389,62 @@ void sixlowpan_tcp_send(FAR struct net_driver_s *dev) if (dev != NULL && dev->d_len > 0) { - FAR struct ipv6_hdr_s *ipv6hdr; + FAR struct ipv6tcp_hdr_s *ipv6hdr; /* The IPv6 header followed by a TCP headers should lie at the * beginning of d_buf since there is no link layer protocol header * and the TCP state machine should only response with TCP packets. */ - ipv6hdr = (FAR struct ipv6_hdr_s *)(dev->d_buf); + ipv6hdr = (FAR struct ipv6tcp_hdr_s *)(dev->d_buf); /* The TCP data payload should follow the IPv6 header plus the * protocol header. */ - if (ipv6hdr->proto != IP_PROTO_TCP) + if (ipv6hdr->ipv6.proto != IP_PROTO_TCP) { - nwarn("WARNING: Expected TCP protoype: %u\n", ipv6hdr->proto); + nwarn("WARNING: Expected TCP protoype: %u vs %s\n", + ipv6hdr->ipv6.proto, IP_PROTO_TCP); } else { struct rimeaddr_s destmac; FAR uint8_t *buf; - size_t buflen; + uint16_t hdrlen; + uint16_t buflen; /* Get the Rime MAC address of the destination. This assumes an * encoding of the MAC address in the IPv6 address. */ - sixlowpan_rimefromip(ipv6hdr->destipaddr, &destmac); + sixlowpan_rimefromip(ipv6hdr->ipv6.destipaddr, &destmac); - /* Convert the outgoing packet into a frame list. */ + /* Get the IPv6 + TCP combined header length. The size of the TCP + * header is encoded in the top 4 bits of the tcpoffset field (in + * units of 32-bit words). + */ - buf = dev->d_buf + sizeof(struct ipv6_hdr_s); - buflen = dev->d_len - sizeof(struct ipv6_hdr_s); + hdrlen = IPv6_HDRLEN + (((uint16_t)ipv6hdr->tcp.tcpoffset >> 4) << 2); - (void)sixlowpan_queue_frames( - (FAR struct ieee802154_driver_s *)dev, ipv6hdr, - buf, buflen, &destmac); + /* Drop the packet if the buffer length is less than this. */ + + if (hdrlen > dev->d_len) + { + nwarn("WARNING: Dropping small TCP packet: %u < %u\n", + buflen, hdrlen); + } + else + { + /* Convert the outgoing packet into a frame list. */ + + buf = dev->d_buf + hdrlen; + buflen = dev->d_len - hdrlen; + + (void)sixlowpan_queue_frames( + (FAR struct ieee802154_driver_s *)dev, &ipv6hdr->ipv6, + buf, buflen, &destmac); + } } }