aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/odp_packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/odp_packet.c')
-rw-r--r--platform/linux-generic/odp_packet.c89
1 files changed, 84 insertions, 5 deletions
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 0986056e6..c6a50bf84 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -11,6 +11,7 @@
#include <odp/api/plat/packet_inlines.h>
#include <odp_packet_internal.h>
#include <odp_debug_internal.h>
+#include <odp_macros_internal.h>
#include <odp_chksum_internal.h>
#include <odp_errno_define.h>
#include <odp/api/hints.h>
@@ -1847,7 +1848,15 @@ static uint32_t packet_sum_crc32c(odp_packet_hdr_t *pkt_hdr,
return sum;
}
-/** Parser helper function for Ethernet packets */
+/*
+ * In the worst case we look at the Ethernet header, 8 bytes of LLC/SNAP
+ * header and two VLAN tags in the same packet.
+ */
+#define PARSE_ETH_BYTES (sizeof(_odp_ethhdr_t) + 8 + 2 * sizeof(_odp_vlanhdr_t))
+/** Parser helper function for Ethernet packets
+ *
+ * Requires up to PARSE_ETH_BYTES bytes of contiguous packet data.
+ */
static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
uint32_t *offset, uint32_t frame_len)
{
@@ -1864,7 +1873,7 @@ static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
eth = (const _odp_ethhdr_t *)*parseptr;
/* Detect jumbo frames */
- if (odp_unlikely(frame_len > _ODP_ETH_LEN_MAX))
+ if (odp_unlikely(frame_len - *offset > _ODP_ETH_LEN_MAX))
input_flags.jumbo = 1;
/* Handle Ethernet broadcast/multicast addresses */
@@ -1922,14 +1931,27 @@ static inline uint16_t parse_eth(packet_parser_t *prs, const uint8_t **parseptr,
*parseptr += sizeof(_odp_vlanhdr_t);
}
+ /*
+ * The packet was too short for what we parsed. We just give up
+ * entirely without trying to parse what fits in the packet.
+ */
+ if (odp_unlikely(*offset > frame_len)) {
+ input_flags.all = 0;
+ input_flags.l2 = 1;
+ ethtype = 0;
+ }
+
error:
prs->input_flags.all |= input_flags.all;
return ethtype;
}
+#define PARSE_IPV4_BYTES (0xfU * 4) /* max IPv4 header length with options */
/**
* Parser helper function for IPv4
+ *
+ * Requires up to PARSE_IPV4_BYTES bytes of contiguous packet data.
*/
static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
uint32_t *offset, uint32_t frame_len,
@@ -1945,6 +1967,7 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
if (odp_unlikely(ihl < _ODP_IPV4HDR_IHL_MIN ||
ver != 4 ||
+ sizeof(*ipv4) > frame_len - *offset ||
(l3_len > frame_len - *offset))) {
prs->flags.ip_err = 1;
return 0;
@@ -1987,8 +2010,15 @@ static inline uint8_t parse_ipv4(packet_parser_t *prs, const uint8_t **parseptr,
return ipv4->proto;
}
+/*
+ * Peeks 2 bytes beyond IPv6 base header without length check if there
+ * are extension headers.
+ */
+#define PARSE_IPV6_BYTES (sizeof(_odp_ipv6hdr_t) + 2)
/**
* Parser helper function for IPv6
+ *
+ * Requires at least PARSE_IPV6_BYTES bytes of contiguous packet data.
*/
static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
uint32_t *offset, uint32_t frame_len,
@@ -2003,8 +2033,9 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
_ODP_IPV6HDR_LEN;
/* Basic sanity checks on IPv6 header */
- if ((odp_be_to_cpu_32(ipv6->ver_tc_flow) >> 28) != 6 ||
- l3_len > frame_len - *offset) {
+ if (odp_unlikely((odp_be_to_cpu_32(ipv6->ver_tc_flow) >> 28) != 6 ||
+ sizeof(*ipv6) > frame_len - *offset ||
+ l3_len > frame_len - *offset)) {
prs->flags.ip_err = 1;
return 0;
}
@@ -2056,8 +2087,11 @@ static inline uint8_t parse_ipv6(packet_parser_t *prs, const uint8_t **parseptr,
return ipv6->next_hdr;
}
+#define PARSE_TCP_BYTES (sizeof(_odp_tcphdr_t))
/**
* Parser helper function for TCP
+ *
+ * Requires PARSE_TCP_BYTES bytes of contiguous packet data.
*/
static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr,
uint16_t tcp_len,
@@ -2083,8 +2117,15 @@ static inline void parse_tcp(packet_parser_t *prs, const uint8_t **parseptr,
*parseptr += len;
}
+/*
+ * In the worst case we look at the UDP header and 4 bytes of the UDP
+ * payload (the non-ESP marker to distinguish IKE packets from ESP packets).
+ */
+#define PARSE_UDP_BYTES (sizeof(_odp_udphdr_t) + 4)
/**
* Parser helper function for UDP
+ *
+ * Requires PARSE_UDP_BYTES bytes of contiguous packet data.
*/
static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr,
odp_proto_chksums_t chksums,
@@ -2129,8 +2170,11 @@ static inline void parse_udp(packet_parser_t *prs, const uint8_t **parseptr,
*parseptr += sizeof(_odp_udphdr_t);
}
+#define PARSE_SCTP_BYTES (sizeof(_odp_sctphdr_t))
/**
* Parser helper function for SCTP
+ *
+ * Requires PARSE_SCTP_BYTES bytes of contiguous packet data.
*/
static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr,
uint16_t sctp_len,
@@ -2157,6 +2201,10 @@ static inline void parse_sctp(packet_parser_t *prs, const uint8_t **parseptr,
*parseptr += sizeof(_odp_sctphdr_t);
}
+#define MAX3(a, b, c) (MAX(MAX((a), (b)), (c)))
+#define PARSE_L3_L4_BYTES (MAX(PARSE_IPV4_BYTES, PARSE_IPV6_BYTES) + \
+ MAX3(PARSE_TCP_BYTES, PARSE_UDP_BYTES, PARSE_SCTP_BYTES))
+/* Requires up to PARSE_L3_L4_BYTES bytes of contiguous packet data. */
static inline
int packet_parse_common_l3_l4(packet_parser_t *prs, const uint8_t *parseptr,
uint32_t offset,
@@ -2516,6 +2564,8 @@ 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 seg_len = 0;
+ _odp_sctphdr_t hdr_copy;
uint32_t sum = ~packet_sum_crc32c(pkt_hdr,
pkt_hdr->p.l4_offset +
_ODP_SCTPHDR_LEN,
@@ -2525,8 +2575,14 @@ static int packet_l4_chksum(odp_packet_hdr_t *pkt_hdr,
l4_part_sum);
_odp_sctphdr_t *sctp = packet_map(pkt_hdr,
pkt_hdr->p.l4_offset,
- NULL, NULL);
+ &seg_len, NULL);
+ if (odp_unlikely(seg_len < sizeof(*sctp))) {
+ odp_packet_t pkt = packet_handle(pkt_hdr);
+ sctp = &hdr_copy;
+ odp_packet_copy_to_mem(pkt, pkt_hdr->p.l4_offset,
+ sizeof(*sctp), sctp);
+ }
pkt_hdr->p.input_flags.l4_chksum_done = 1;
if (sum != sctp->chksum) {
pkt_hdr->p.flags.l4_chksum_err = 1;
@@ -2587,6 +2643,8 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
int ret;
uint16_t ethtype;
uint64_t l4_part_sum = 0;
+ const uint32_t min_seglen = PARSE_ETH_BYTES + PARSE_L3_L4_BYTES;
+ uint8_t buf[min_seglen];
if (proto == ODP_PROTO_NONE || layer == ODP_PROTO_LAYER_NONE)
return -1;
@@ -2596,6 +2654,20 @@ int odp_packet_parse(odp_packet_t pkt, uint32_t offset,
if (data == NULL)
return -1;
+ /*
+ * We must not have a packet segment boundary within the parsed
+ * packet data range. Copy enough data to a temporary buffer for
+ * parsing if necessary.
+ */
+ if (odp_unlikely(pkt_hdr->seg_count > 1) &&
+ odp_unlikely(seg_len < min_seglen)) {
+ seg_len = min_seglen;
+ if (seg_len > packet_len - offset)
+ seg_len = packet_len - offset;
+ odp_packet_copy_to_mem(pkt, offset, seg_len, buf);
+ data = buf;
+ }
+
/* Reset parser flags, keep other flags */
packet_parse_reset(pkt_hdr, 0);
@@ -2942,6 +3014,13 @@ odp_packet_reass_status(odp_packet_t pkt)
return ODP_PACKET_REASS_NONE;
}
+int odp_packet_reass_info(odp_packet_t pkt, odp_packet_reass_info_t *info)
+{
+ (void)pkt;
+ (void)info;
+ return -1;
+}
+
int
odp_packet_reass_partial_state(odp_packet_t pkt, odp_packet_t frags[],
odp_packet_reass_partial_state_t *res)