[lng-odp] [PATCH v5 2/3] helper: ip: correct ipv4 header checksum calculation

2017-08-25 Thread Github ODP bot
From: Dmitry Eremin-Solenikov 

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.

Signed-off-by: Dmitry Eremin-Solenikov 
---
/** Email created from pull request 132 (lumag:fix-checksum)
 ** https://github.com/Linaro/odp/pull/132
 ** Patch: https://github.com/Linaro/odp/pull/132.patch
 ** Base sha: 8705e548f330d23173283fcca62f4afb835a6380
 ** Merge commit sha: 7ad532c561535935fe0e51774755fcd4c5bb7ebc
 **/
 helper/include/odp/helper/ip.h | 75 +++---
 .../api/classification/odp_classification_common.c |  3 +-
 .../classification/odp_classification_test_pmr.c   |  2 +-
 .../api/classification/odp_classification_tests.c  |  9 +--
 4 files changed, 58 insertions(+), 31 deletions(-)

diff --git a/helper/include/odp/helper/ip.h b/helper/include/odp/helper/ip.h
index 91776fad..e0d5c3bf 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_tver_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), );
 
-   w = (uint16_t *)(void *)
chksum = ip.chksum;
-   ip.chksum = 0x0;
 
-   res = odph_chksum(w, nleft);
-   return (res == chksum) ? 1 : 0;
+   res = odph_ipv4_csum(pkt, offset, , _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), );
+   if (odp_unlikely(res < 0))
+   return res;
+
+   res = odph_ipv4_csum(pkt, offset, , );
+   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, );
 }
 
 /** IPv6 version */
diff --git 
a/test/common_plat/validation/api/classification/odp_classification_common.c 
b/test/common_plat/validation/api/classification/odp_classification_common.c
index de8a9327..e4c49648 100644

[lng-odp] [PATCH v5 2/3] helper: ip: correct ipv4 header checksum calculation

2017-08-24 Thread Github ODP bot
From: Dmitry Eremin-Solenikov 

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.

Signed-off-by: Dmitry Eremin-Solenikov 
---
/** Email created from pull request 132 (lumag:fix-checksum)
 ** https://github.com/Linaro/odp/pull/132
 ** Patch: https://github.com/Linaro/odp/pull/132.patch
 ** Base sha: 8705e548f330d23173283fcca62f4afb835a6380
 ** Merge commit sha: e256e0810a3feee8b1b91b8d61f21bdfdd339dff
 **/
 helper/include/odp/helper/ip.h | 75 +++---
 .../api/classification/odp_classification_common.c |  3 +-
 .../classification/odp_classification_test_pmr.c   |  2 +-
 .../api/classification/odp_classification_tests.c  |  9 +--
 4 files changed, 58 insertions(+), 31 deletions(-)

diff --git a/helper/include/odp/helper/ip.h b/helper/include/odp/helper/ip.h
index 91776fad..e0d5c3bf 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_tver_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), );
 
-   w = (uint16_t *)(void *)
chksum = ip.chksum;
-   ip.chksum = 0x0;
 
-   res = odph_chksum(w, nleft);
-   return (res == chksum) ? 1 : 0;
+   res = odph_ipv4_csum(pkt, offset, , _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), );
+   if (odp_unlikely(res < 0))
+   return res;
+
+   res = odph_ipv4_csum(pkt, offset, , );
+   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, );
 }
 
 /** IPv6 version */
diff --git 
a/test/common_plat/validation/api/classification/odp_classification_common.c 
b/test/common_plat/validation/api/classification/odp_classification_common.c
index de8a9327..e4c49648 100644