aboutsummaryrefslogtreecommitdiff
path: root/helper/include
diff options
context:
space:
mode:
authorDmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org>2017-08-18 03:21:43 +0300
committerMaxim Uvarov <maxim.uvarov@linaro.org>2017-08-29 00:25:07 +0300
commit87fbe7fbf2debf8bc44bfffc3d3a2d1827208452 (patch)
tree309ed6eca0d41a462ad2cc46f187a29521b74bb6 /helper/include
parenta7463a692a4e2dc311c2d383595adafd01433fa4 (diff)
helper: ip: correct ipv4 header checksum calculation
Current code for IPv4 header checksum calculation assumes that packet data is aligned on 2-byte boundary, that there are no optional headers, etc. Rewrite checksumming code to properly copy & process headers. https://bugs.linaro.org/show_bug.cgi?id=2976 Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsolenikov@linaro.org> Signed-off-by: Bill Fischofer <bill.fischofer@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'helper/include')
-rw-r--r--helper/include/odp/helper/ip.h75
1 files changed, 53 insertions, 22 deletions
diff --git a/helper/include/odp/helper/ip.h b/helper/include/odp/helper/ip.h
index 91776fad6..e0d5c3bfb 100644
--- a/helper/include/odp/helper/ip.h
+++ b/helper/include/odp/helper/ip.h
@@ -74,6 +74,9 @@ extern "C" {
/** @internal Returns true if IPv4 packet is a fragment */
#define ODPH_IPV4HDR_IS_FRAGMENT(frag_offset) ((frag_offset) & 0x3fff)
+/** @internal Checksum offset in IPv4 header */
+#define ODPH_IPV4HDR_CSUM_OFFSET 10
+
/** IPv4 header */
typedef struct ODP_PACKED {
uint8_t ver_ihl; /**< Version / Header length */
@@ -92,6 +95,28 @@ typedef struct ODP_PACKED {
ODP_STATIC_ASSERT(sizeof(odph_ipv4hdr_t) == ODPH_IPV4HDR_LEN,
"ODPH_IPV4HDR_T__SIZE_ERROR");
+static inline int odph_ipv4_csum(odp_packet_t pkt,
+ uint32_t offset,
+ odph_ipv4hdr_t *ip,
+ odp_u16sum_t *chksum)
+{
+ int nleft = ODPH_IPV4HDR_IHL(ip->ver_ihl) * 4;
+ uint16_t buf[nleft / 2];
+ int res;
+
+ ip->chksum = 0;
+ memcpy(buf, ip, sizeof(*ip));
+ res = odp_packet_copy_to_mem(pkt, offset + sizeof(*ip),
+ nleft - sizeof(*ip),
+ buf + sizeof(*ip) / 2);
+ if (odp_unlikely(res < 0))
+ return res;
+
+ *chksum = odph_chksum(buf, nleft);
+
+ return 0;
+}
+
/**
* Check if IPv4 checksum is valid
*
@@ -102,11 +127,9 @@ ODP_STATIC_ASSERT(sizeof(odph_ipv4hdr_t) == ODPH_IPV4HDR_LEN,
static inline int odph_ipv4_csum_valid(odp_packet_t pkt)
{
uint32_t offset;
- odp_u16be_t res = 0;
- uint16_t *w;
- int nleft = sizeof(odph_ipv4hdr_t);
+ int res;
odph_ipv4hdr_t ip;
- odp_u16be_t chksum;
+ odp_u16sum_t chksum, cur_chksum;
offset = odp_packet_l3_offset(pkt);
if (offset == ODP_PACKET_OFFSET_INVALID)
@@ -114,37 +137,45 @@ static inline int odph_ipv4_csum_valid(odp_packet_t pkt)
odp_packet_copy_to_mem(pkt, offset, sizeof(odph_ipv4hdr_t), &ip);
- w = (uint16_t *)(void *)&ip;
chksum = ip.chksum;
- ip.chksum = 0x0;
- res = odph_chksum(w, nleft);
- return (res == chksum) ? 1 : 0;
+ res = odph_ipv4_csum(pkt, offset, &ip, &cur_chksum);
+ if (odp_unlikely(res < 0))
+ return 0;
+
+ return (cur_chksum == chksum) ? 1 : 0;
}
/**
* Calculate and fill in IPv4 checksum
*
- * @note when using this api to populate data destined for the wire
- * odp_cpu_to_be_16() can be used to remove sparse warnings
- *
* @param pkt ODP packet
*
- * @return IPv4 checksum in host cpu order, or 0 on failure
+ * @retval 0 on success
+ * @retval <0 on failure
*/
-static inline odp_u16sum_t odph_ipv4_csum_update(odp_packet_t pkt)
+static inline int odph_ipv4_csum_update(odp_packet_t pkt)
{
- uint16_t *w;
- odph_ipv4hdr_t *ip;
- int nleft = sizeof(odph_ipv4hdr_t);
+ uint32_t offset;
+ odph_ipv4hdr_t ip;
+ odp_u16sum_t chksum;
+ int res;
- ip = (odph_ipv4hdr_t *)odp_packet_l3_ptr(pkt, NULL);
- if (ip == NULL)
- return 0;
+ offset = odp_packet_l3_offset(pkt);
+ if (offset == ODP_PACKET_OFFSET_INVALID)
+ return -1;
+
+ res = odp_packet_copy_to_mem(pkt, offset, sizeof(ip), &ip);
+ if (odp_unlikely(res < 0))
+ return res;
+
+ res = odph_ipv4_csum(pkt, offset, &ip, &chksum);
+ if (odp_unlikely(res < 0))
+ return res;
- w = (uint16_t *)(void *)ip;
- ip->chksum = odph_chksum(w, nleft);
- return ip->chksum;
+ return odp_packet_copy_from_mem(pkt,
+ offset + ODPH_IPV4HDR_CSUM_OFFSET,
+ 2, &chksum);
}
/** IPv6 version */