diff --git a/net/sixlowpan/sixlowpan_tcpsend.c b/net/sixlowpan/sixlowpan_tcpsend.c index a7a1a90f3b5..2b0ce15cb33 100644 --- a/net/sixlowpan/sixlowpan_tcpsend.c +++ b/net/sixlowpan/sixlowpan_tcpsend.c @@ -50,10 +50,73 @@ #include "netdev/netdev.h" #include "socket/socket.h" #include "tcp/tcp.h" +#include "utils/utils.h" #include "sixlowpan/sixlowpan_internal.h" #if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_TCP) +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_tcp_chksum + * + * Description: + * Perform the checksum calcaultion over the IPv6, protocol headers, and + * data payload as necessary. + * + * Input Parameters: + * ipv6tcp - A reference to a structure containing the IPv6 and TCP headers. + * buf - The beginning of the payload data + * buflen - The length of the payload data. + * + * Returned Value: + * The calculated checksum + * + ****************************************************************************/ + +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 sum; + + /* The length reported in the IPv6 header is the length of the payload + * that follows the header. + */ + + upperlen = ((uint16_t)ipv6tcp->ipv6.len[0] << 8) + ipv6tcp->ipv6.len[1]; + + /* Verify some minimal assumptions */ + + if (upperlen > CONFIG_NET_6LOWPAN_MTU) + { + return 0; + } + + /* The checksum is calculated starting with a pseudo-header of IPv6 header + * fields according to the IPv6 standard, which consists of the source + * and destination addresses, the packet length and the next header field. + */ + + sum = upperlen + ipv6tcp->ipv6.proto; + + /* Sum IP source and destination addresses. */ + + sum = chksum(sum, (FAR uint8_t *)ipv6tcp->ipv6.srcipaddr, + 2 * sizeof(net_ipv6addr_t)); + + /* Sum the TCP header */ + + sum = chksum(sum, (FAR uint8_t *)&ipv6tcp->tcp, TCP_HDRLEN); + + /* Sum payload data. */ + + sum = chksum(sum, buf, buflen); + return (sum == 0) ? 0xffff : htons(sum); +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -224,19 +287,14 @@ ssize_t psock_6lowpan_tcp_send(FAR struct socket *psock, FAR const void *buf, /* 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 + ipv6tcp.tcp.tcpchksum = ~sixlowpan_tcp_chksum(&ipv6tcp, buf, buflen); 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); diff --git a/net/sixlowpan/sixlowpan_udpsend.c b/net/sixlowpan/sixlowpan_udpsend.c index 49932514c81..61fbe3b237a 100644 --- a/net/sixlowpan/sixlowpan_udpsend.c +++ b/net/sixlowpan/sixlowpan_udpsend.c @@ -51,10 +51,75 @@ #include "netdev/netdev.h" #include "socket/socket.h" #include "udp/udp.h" +#include "utils/utils.h" #include "sixlowpan/sixlowpan_internal.h" #if defined(CONFIG_NET_6LOWPAN) && defined(CONFIG_NET_UDP) +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sixlowpan_udp_chksum + * + * Description: + * Perform the checksum calcaultion over the IPv6, protocol headers, and + * data payload as necessary. + * + * Input Parameters: + * ipv6udp - A reference to a structure containing the IPv6 and UDP headers. + * buf - The beginning of the payload data + * buflen - The length of the payload data. + * + * Returned Value: + * The calculated checksum + * + ****************************************************************************/ + +#ifdef CONFIG_NET_UDP_CHECKSUMS +static uint16_t sixlowpan_udp_chksum(FAR struct ipv6udp_hdr_s *ipv6udp, + FAR const uint8_t *buf, uint16_t buflen) +{ + uint16_t upperlen; + uint16_t sum; + + /* The length reported in the IPv6 header is the length of the payload + * that follows the header. + */ + + upperlen = ((uint16_t)ipv6udp->ipv6.len[0] << 8) + ipv6udp->ipv6.len[1]; + + /* Verify some minimal assumptions */ + + if (upperlen > CONFIG_NET_6LOWPAN_MTU) + { + return 0; + } + + /* The checksum is calculated starting with a pseudo-header of IPv6 header + * fields according to the IPv6 standard, which consists of the source + * and destination addresses, the packet length and the next header field. + */ + + sum = upperlen + ipv6udp->ipv6.proto; + + /* Sum IP source and destination addresses. */ + + sum = chksum(sum, (FAR uint8_t *)ipv6udp->ipv6.srcipaddr, + 2 * sizeof(net_ipv6addr_t)); + + /* Sum the UDP header */ + + sum = chksum(sum, (FAR uint8_t *)&ipv6udp->udp, UDP_HDRLEN); + + /* Sum payload data. */ + + sum = chksum(sum, buf, buflen); + return (sum == 0) ? 0xffff : htons(sum); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -211,23 +276,13 @@ ssize_t psock_6lowpan_udp_sendto(FAR struct socket *psock, 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); + ipv6udp.udp.udpchksum = ~sixlowpan_udp_chksum(ipv6udp, buf, buflen); 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); diff --git a/net/utils/Make.defs b/net/utils/Make.defs index 270b80bbbe8..daad84805ea 100644 --- a/net/utils/Make.defs +++ b/net/utils/Make.defs @@ -1,7 +1,7 @@ ############################################################################ # net/utils/Make.defs # -# Copyright (C) 2014 Gregory Nutt. All rights reserved. +# Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -36,7 +36,7 @@ # Common utilities NET_CSRCS += net_dsec2tick.c net_dsec2timeval.c net_timeval2dsec.c -NET_CSRCS += net_chksum.c net_lock.c +NET_CSRCS += net_chksum.c net_ipchksum.c net_incr32.c net_lock.c # IPv6 utilities @@ -44,6 +44,26 @@ ifeq ($(CONFIG_NET_IPv6),y) NET_CSRCS += net_ipv6_maskcmp.c net_ipv6_mask2pref.c net_ipv6_pref2mask.c endif +# TCP utilities + +ifeq ($(CONFIG_NET_TCP),y) +NET_CSRCS += net_tcpchksum.c +endif + +# UDP utilities + +ifeq ($(CONFIG_NET_UDP),y) +NET_CSRCS += net_udpchksum.c +endif + +# ICMP utilities + +ifeq ($(CONFIG_NET_ICMP),y) +NET_CSRCS += net_icmpchksum.c +else ifeq ($(CONFIG_NET_ICMPv6),y) +NET_CSRCS += net_icmpchksum.c +endif + # Include utility build support DEPPATH += --dep-path utils diff --git a/net/utils/net_chksum.c b/net/utils/net_chksum.c index 9f4055c7564..65272387759 100644 --- a/net/utils/net_chksum.c +++ b/net/utils/net_chksum.c @@ -56,19 +56,31 @@ #define IPv4BUF ((struct ipv4_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) #define IPv6BUF ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define ICMPBUF ((struct icmp_iphdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) -#define ICMPv6BUF ((struct icmp_ipv6hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)]) /**************************************************************************** - * Private Functions + * Public Functions ****************************************************************************/ /**************************************************************************** * Name: chksum + * + * Description: + * Calculate the raw change some over the memory region described by + * data and len. + * + * Input Parameters: + * sum - Partial calculations carried over from a previous call to chksum(). + * This should be zero on the first time that check sum is called. + * data - Beginning of the data to include in the checksum. + * len - Length of the data to include in the checksum. + * + * Returned Value: + * The updated checksum value. + * ****************************************************************************/ #ifndef CONFIG_NET_ARCH_CHKSUM -static uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len) +uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len) { FAR const uint8_t *dataptr; FAR const uint8_t *last_byte; @@ -107,158 +119,6 @@ static uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len) } #endif /* CONFIG_NET_ARCH_CHKSUM */ -/**************************************************************************** - * Name: ipv4_upperlayer_chksum - ****************************************************************************/ - -#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv4) -static uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, - uint8_t proto) -{ - FAR struct ipv4_hdr_s *ipv4 = IPv4BUF; - uint16_t upperlen; - uint16_t sum; - - /* The length reported in the IPv4 header is the length of both the IPv4 - * header and the payload that follows the header. We need to subtract - * the size of the IPv4 header to get the size of the payload. - */ - - upperlen = (((uint16_t)(ipv4->len[0]) << 8) + ipv4->len[1]) - IPv4_HDRLEN; - - /* Verify some minimal assumptions */ - - if (upperlen > NET_DEV_MTU(dev)) - { - return 0; - } - - /* First sum pseudo-header. */ - /* IP protocol and length fields. This addition cannot carry. */ - - sum = upperlen + proto; - - /* Sum IP source and destination addresses. */ - - sum = chksum(sum, (FAR uint8_t *)&ipv4->srcipaddr, 2 * sizeof(in_addr_t)); - - /* Sum IP payload data. */ - - sum = chksum(sum, &dev->d_buf[IPv4_HDRLEN + NET_LL_HDRLEN(dev)], upperlen); - return (sum == 0) ? 0xffff : htons(sum); -} -#endif /* CONFIG_NET_ARCH_CHKSUM */ - -/**************************************************************************** - * Name: ipv6_upperlayer_chksum - ****************************************************************************/ - -#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv6) -static uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, - uint8_t proto) -{ - FAR struct ipv6_hdr_s *ipv6 = IPv6BUF; - uint16_t upperlen; - uint16_t sum; - - /* The length reported in the IPv6 header is the length of the payload - * that follows the header. - */ - - upperlen = ((uint16_t)ipv6->len[0] << 8) + ipv6->len[1]; - - /* Verify some minimal assumptions */ - - if (upperlen > NET_DEV_MTU(dev)) - { - return 0; - } - - /* The checksum is calculated starting with a pseudo-header of IPv6 header - * fields according to the IPv6 standard, which consists of the source - * and destination addresses, the packet length and the next header field. - */ - - sum = upperlen + proto; - - /* Sum IP source and destination addresses. */ - - sum = chksum(sum, (FAR uint8_t *)&ipv6->srcipaddr, 2 * sizeof(net_ipv6addr_t)); - - /* Sum IP payload data. */ - - sum = chksum(sum, &dev->d_buf[IPv6_HDRLEN + NET_LL_HDRLEN(dev)], upperlen); - return (sum == 0) ? 0xffff : htons(sum); -} -#endif /* CONFIG_NET_ARCH_CHKSUM */ - -/**************************************************************************** - * Name: net_carry32 - * - * Description: - * Calculate the Internet checksum over a buffer. - * - ****************************************************************************/ - -#ifndef CONFIG_NET_ARCH_INCR32 -static inline void net_carry32(FAR uint8_t *sum, uint16_t op16) -{ - if (sum[2] < (op16 >> 8)) - { - ++sum[1]; - if (sum[1] == 0) - { - ++sum[0]; - } - } - - if (sum[3] < (op16 & 0xff)) - { - ++sum[2]; - if (sum[2] == 0) - { - ++sum[1]; - if (sum[1] == 0) - { - ++sum[0]; - } - } - } -} -#endif /* CONFIG_NET_ARCH_INCR32 */ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: net_incr32 - * - * Description: - * - * Carry out a 32-bit addition. - * - * By defining CONFIG_NET_ARCH_INCR32, the architecture can replace - * net_incr32 with hardware assisted solutions. - * - * Input Parameters: - * op32 - A pointer to a 4-byte array representing a 32-bit integer in - * network byte order (big endian). This value may not be word - * aligned. The value pointed to by op32 is modified in place - * - * op16 - A 16-bit integer in host byte order. - * - ****************************************************************************/ - -#ifndef CONFIG_NET_ARCH_INCR32 -void net_incr32(FAR uint8_t *op32, uint16_t op16) -{ - op32[3] += (op16 & 0xff); - op32[2] += (op16 >> 8); - net_carry32(op32, op16); -} -#endif /* CONFIG_NET_ARCH_INCR32 */ - /**************************************************************************** * Name: net_chksum * @@ -291,141 +151,4 @@ uint16_t net_chksum(FAR uint16_t *data, uint16_t len) } #endif /* CONFIG_NET_ARCH_CHKSUM */ -/**************************************************************************** - * Name: ipv4_chksum - * - * Description: - * Calculate the IPv4 header checksum of the packet header in d_buf. - * - * The IPv4 header checksum is the Internet checksum of the 20 bytes of - * the IPv4 header. - * - * If CONFIG_NET_ARCH_CHKSUM is defined, then this function must be - * provided by architecture-specific logic. - * - * Returned Value: - * The IPv4 header checksum of the IPv4 header in the d_buf buffer. - * - ****************************************************************************/ - -#if defined(CONFIG_NET_IPv4) && !defined(CONFIG_NET_ARCH_CHKSUM) -uint16_t ipv4_chksum(FAR struct net_driver_s *dev) -{ - uint16_t sum; - - sum = chksum(0, &dev->d_buf[NET_LL_HDRLEN(dev)], IPv4_HDRLEN); - return (sum == 0) ? 0xffff : htons(sum); -} -#endif /* CONFIG_NET_ARCH_CHKSUM */ - -/**************************************************************************** - * Name: tcp_chksum, tcp_ipv4_chksum, and tcp_ipv6_chksum - * - * Description: - * Calculate the TCP checksum of the packet in d_buf and d_appdata. - * - * The TCP checksum is the Internet checksum of data contents of the - * TCP segment, and a pseudo-header as defined in RFC793. - * - * Note: The d_appdata pointer that points to the packet data may - * point anywhere in memory, so it is not possible to simply calculate - * the Internet checksum of the contents of the d_buf buffer. - * - * Returned Value: - * The TCP checksum of the TCP segment in d_buf and pointed to by - * d_appdata. - * - ****************************************************************************/ - -#ifndef CONFIG_NET_ARCH_CHKSUM -#ifdef CONFIG_NET_IPv4 -uint16_t tcp_ipv4_chksum(FAR struct net_driver_s *dev) -{ - return ipv4_upperlayer_chksum(dev, IP_PROTO_TCP); -} -#endif /* CONFIG_NET_IPv4 */ - -#ifdef CONFIG_NET_IPv6 -uint16_t tcp_ipv6_chksum(FAR struct net_driver_s *dev) -{ - return ipv6_upperlayer_chksum(dev, IP_PROTO_TCP); -} -#endif /* CONFIG_NET_IPv6 */ -#endif /* !CONFIG_NET_ARCH_CHKSUM */ - -#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6) -uint16_t tcp_chksum(FAR struct net_driver_s *dev) -{ - if (IFF_IS_IPv6(dev->d_flags)) - { - return tcp_ipv6_chksum(dev); - } - else - { - return tcp_ipv4_chksum(dev); - } -} -#endif - -/**************************************************************************** - * Name: udp_ipv4_chksum - * - * Description: - * Calculate the UDP/IPv4 checksum of the packet in d_buf and d_appdata. - * - ****************************************************************************/ - -#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv4) -uint16_t udp_ipv4_chksum(FAR struct net_driver_s *dev) -{ - return ipv4_upperlayer_chksum(dev, IP_PROTO_UDP); -} -#endif - -/**************************************************************************** - * Name: udp_ipv6_chksum - * - * Description: - * Calculate the UDP/IPv6 checksum of the packet in d_buf and d_appdata. - * - ****************************************************************************/ - -#if defined(CONFIG_NET_UDP_CHECKSUMS) && defined(CONFIG_NET_IPv6) -uint16_t udp_ipv6_chksum(FAR struct net_driver_s *dev) -{ - return ipv6_upperlayer_chksum(dev, IP_PROTO_UDP); -} -#endif - -/**************************************************************************** - * Name: icmp_chksum - * - * Description: - * Calculate the checksum of the ICMP message - * - ****************************************************************************/ - -#if defined(CONFIG_NET_ICMP) && defined(CONFIG_NET_ICMP_PING) -uint16_t icmp_chksum(FAR struct net_driver_s *dev, int len) -{ - FAR struct icmp_iphdr_s *icmp = ICMPBUF; - return net_chksum((FAR uint16_t *)&icmp->type, len); -} -#endif /* CONFIG_NET_ICMP && CONFIG_NET_ICMP_PING */ - -/**************************************************************************** - * Name: icmpv6_chksum - * - * Description: - * Calculate the checksum of the ICMPv6 message - * - ****************************************************************************/ - -#ifdef CONFIG_NET_ICMPv6 -uint16_t icmpv6_chksum(FAR struct net_driver_s *dev) -{ - return ipv6_upperlayer_chksum(dev, IP_PROTO_ICMP6); -} -#endif - #endif /* CONFIG_NET */ diff --git a/net/utils/utils.h b/net/utils/utils.h index 6e33b72a83b..ffeca8c3f69 100644 --- a/net/utils/utils.h +++ b/net/utils/utils.h @@ -191,6 +191,99 @@ uint8_t net_ipv6_mask2pref(FAR const uint16_t *mask); void net_ipv6_pref2mask(uint8_t preflen, net_ipv6addr_t mask); #endif +/**************************************************************************** + * Name: chksum + * + * Description: + * Calculate the raw change some over the memory region described by + * data and len. + * + * Input Parameters: + * sum - Partial calculations carried over from a previous call to chksum(). + * This should be zero on the first time that check sum is called. + * data - Beginning of the data to include in the checksum. + * len - Length of the data to include in the checksum. + * + * Returned Value: + * The updated checksum value. + * + ****************************************************************************/ + +#ifndef CONFIG_NET_ARCH_CHKSUM +uint16_t chksum(uint16_t sum, FAR const uint8_t *data, uint16_t len); +#endif + +/**************************************************************************** + * Name: net_chksum + * + * Description: + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's complement + * sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * If CONFIG_NET_ARCH_CHKSUM is defined, then this function must be + * provided by architecture-specific logic. + * + * Input Parameters: + * + * buf - A pointer to the buffer over which the checksum is to be computed. + * + * len - The length of the buffer over which the checksum is to be computed. + * + * Returned Value: + * The Internet checksum of the buffer. + * + ****************************************************************************/ + +#ifndef CONFIG_NET_ARCH_CHKSUM +uint16_t net_chksum(FAR uint16_t *data, uint16_t len); +#endif + +/**************************************************************************** + * Name: ipv4_upperlayer_chksum + * + * Description: + * Perform the checksum calcaultion over the IPv4, protocol headers, and + * data payload as necessary. + * + * Input Parameters: + * dev - The network driver instance. The packet data is in the d_buf + * of the device. + * proto - The protocol being supported + * + * Returned Value: + * The calculated checksum + * + ****************************************************************************/ + +#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv4) +uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto); +#endif + +/**************************************************************************** + * Name: ipv6_upperlayer_chksum + * + * Description: + * Perform the checksum calcaultion over the IPv6, protocol headers, and + * data payload as necessary. + * + * Input Parameters: + * dev - The network driver instance. The packet data is in the d_buf + * of the device. + * proto - The protocol being supported + * + * Returned Value: + * The calculated checksum + * + ****************************************************************************/ + +#if !defined(CONFIG_NET_ARCH_CHKSUM) && defined(CONFIG_NET_IPv6) +uint16_t ipv6_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto); +#endif + /**************************************************************************** * Name: tcp_chksum, tcp_ipv4_chksum, and tcp_ipv6_chksum *