From: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>

Verify SCTP packet checksums. Use CRC32-c as requied by RFC3309 instead
of original Adler-32.

Signed-off-by: Dmitry Eremin-Solenikov <dmitry.ereminsoleni...@linaro.org>
---
/** Email created from pull request 674 (lumag:sctp-checksum)
 ** https://github.com/Linaro/odp/pull/674
 ** Patch: https://github.com/Linaro/odp/pull/674.patch
 ** Base sha: dc28824415ea510e3ef62e47f7640bf4a8420fde
 ** Merge commit sha: b482f9618a6edb2a2f2491ee5a7af757eab93b24
 **/
 .../odp/api/plat/packet_inline_types.h        |  7 +--
 platform/linux-generic/odp_packet.c           | 54 +++++++++++++++++++
 2 files changed, 58 insertions(+), 3 deletions(-)

diff --git a/platform/linux-generic/include/odp/api/plat/packet_inline_types.h 
b/platform/linux-generic/include/odp/api/plat/packet_inline_types.h
index 9a285fe4a..255102988 100644
--- a/platform/linux-generic/include/odp/api/plat/packet_inline_types.h
+++ b/platform/linux-generic/include/odp/api/plat/packet_inline_types.h
@@ -111,7 +111,7 @@ typedef union {
        uint32_t all_flags;
 
        struct {
-               uint32_t reserved1:     11;
+               uint32_t reserved1:     10;
 
        /*
         * Init flags
@@ -135,6 +135,7 @@ typedef union {
                uint32_t l3_chksum_err:  1; /* L3 checksum error */
                uint32_t tcp_err:        1; /* TCP error */
                uint32_t udp_err:        1; /* UDP error */
+               uint32_t sctp_err:       1; /* SCTP error */
                uint32_t l4_chksum_err:  1; /* L4 checksum error */
                uint32_t ipsec_err:      1; /* IPsec error */
                uint32_t crypto_err:     1; /* Crypto packet operation error */
@@ -142,9 +143,9 @@ typedef union {
 
        /* Flag groups */
        struct {
-               uint32_t reserved2:     11;
+               uint32_t reserved2:     10;
                uint32_t other:         13; /* All other flags */
-               uint32_t error:          8; /* All error flags */
+               uint32_t error:          9; /* All error flags */
        } all;
 
 } _odp_packet_flags_t;
diff --git a/platform/linux-generic/odp_packet.c 
b/platform/linux-generic/odp_packet.c
index 11f8bd43d..885aec8d8 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -22,6 +22,7 @@
 
 #include <protocols/eth.h>
 #include <protocols/ip.h>
+#include <protocols/sctp.h>
 #include <protocols/tcp.h>
 #include <protocols/udp.h>
 
@@ -2298,6 +2299,34 @@ static inline void parse_udp(packet_parser_t *prs, const 
uint8_t **parseptr,
        *parseptr += sizeof(_odp_udphdr_t);
 }
 
+/**
+ * Parser helper function for SCTP
+ */
+static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr,
+                             uint16_t sctp_len,
+                             odp_proto_chksums_t chksums,
+                             uint32_t *l4_part_sum)
+{
+       if (odp_unlikely(sctp_len < sizeof(_odp_sctphdr_t))) {
+               prs->flags.sctp_err = 1;
+               return;
+       }
+
+       if (chksums.chksum.sctp &&
+           !prs->input_flags.ipfrag) {
+               const _odp_sctphdr_t *sctp =
+                       (const _odp_sctphdr_t *)*parseptr;
+               uint32_t crc = ~0;
+               uint32_t zero = 0;
+
+               crc = odp_hash_crc32c(sctp, sizeof(*sctp) - 4, crc);
+               crc = odp_hash_crc32c(&zero, 4, crc);
+               *l4_part_sum = crc;
+       }
+
+       *parseptr += sizeof(_odp_sctphdr_t);
+}
+
 static inline
 int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
                              uint32_t offset,
@@ -2388,6 +2417,8 @@ int packet_parse_common_l3_l4(packet_parser_t *prs, const 
uint8_t *parseptr,
 
        case _ODP_IPPROTO_SCTP:
                prs->input_flags.sctp = 1;
+               parse_sctp(prs, &parseptr, frame_len - prs->l4_offset, chksums,
+                          l4_part_sum);
                break;
 
        case _ODP_IPPROTO_NO_NEXT:
@@ -2626,6 +2657,29 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr,
                }
        }
 
+       if (chksums.chksum.sctp &&
+           pkt_hdr->p.input_flags.sctp &&
+           !pkt_hdr->p.input_flags.ipfrag) {
+               uint32_t sum = ~packet_sum_crc32c(pkt_hdr,
+                                                pkt_hdr->p.l4_offset +
+                                                _ODP_SCTPHDR_LEN,
+                                                pkt_hdr->frame_len -
+                                                pkt_hdr->p.l4_offset -
+                                                _ODP_SCTPHDR_LEN,
+                                                l4_part_sum);
+               _odp_sctphdr_t *sctp = packet_map(pkt_hdr,
+                                                 pkt_hdr->p.l4_offset,
+                                                 NULL, NULL);
+
+               pkt_hdr->p.input_flags.l4_chksum_done = 1;
+               if (sum != sctp->chksum) {
+                       pkt_hdr->p.flags.l4_chksum_err = 1;
+                       pkt_hdr->p.flags.sctp_err = 1;
+                       ODP_DBG("SCTP chksum fail (%x/%x)!\n", sum,
+                               sctp->chksum);
+               }
+       }
+
        return pkt_hdr->p.flags.all_flags != 0;
 }
 

Reply via email to