diff options
author | Akihiko Odaki <akihiko.odaki@daynix.com> | 2023-02-23 19:20:17 +0900 |
---|---|---|
committer | Jason Wang <jasowang@redhat.com> | 2023-03-10 15:35:38 +0800 |
commit | 69ff5ef8474575556997dbe7f7f9bd28c4aee5de (patch) | |
tree | cd4749e26ddd2b791574e4e3d2a21e8d2d50b570 /net/eth.c | |
parent | 47399506dcda52b03b6991c57ca2a426ba8e291f (diff) |
net/eth: Report if headers are actually present
The values returned by eth_get_protocols() are used to perform RSS,
checksumming and segmentation. Even when a packet signals the use of the
protocols which these operations can be applied to, the headers for them
may not be present because of too short packet or fragmentation, for
example. In such a case, the operations cannot be applied safely.
Report the presence of headers instead of whether the use of the
protocols are indicated with eth_get_protocols(). This also makes
corresponding changes to the callers of eth_get_protocols() to match
with its new signature and to remove redundant checks for fragmentation.
Fixes: 75020a7021 ("Common definitions for VMWARE devices")
Signed-off-by: Akihiko Odaki <akihiko.odaki@daynix.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Diffstat (limited to 'net/eth.c')
-rw-r--r-- | net/eth.c | 91 |
1 files changed, 42 insertions, 49 deletions
@@ -137,8 +137,8 @@ _eth_tcp_has_data(bool is_ip4, } void eth_get_protocols(const struct iovec *iov, int iovcnt, - bool *isip4, bool *isip6, - bool *isudp, bool *istcp, + bool *hasip4, bool *hasip6, + bool *hasudp, bool *hastcp, size_t *l3hdr_off, size_t *l4hdr_off, size_t *l5hdr_off, @@ -151,8 +151,9 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, size_t l2hdr_len = eth_get_l2_hdr_length_iov(iov, iovcnt); size_t input_size = iov_size(iov, iovcnt); size_t copied; + uint8_t ip_p; - *isip4 = *isip6 = *isudp = *istcp = false; + *hasip4 = *hasip6 = *hasudp = *hastcp = false; proto = eth_get_l3_proto(iov, iovcnt, l2hdr_len); @@ -166,68 +167,60 @@ void eth_get_protocols(const struct iovec *iov, int iovcnt, } copied = iov_to_buf(iov, iovcnt, l2hdr_len, iphdr, sizeof(*iphdr)); - - *isip4 = true; - - if (copied < sizeof(*iphdr)) { + if (copied < sizeof(*iphdr) || + IP_HEADER_VERSION(iphdr) != IP_HEADER_VERSION_4) { return; } - if (IP_HEADER_VERSION(iphdr) == IP_HEADER_VERSION_4) { - if (iphdr->ip_p == IP_PROTO_TCP) { - *istcp = true; - } else if (iphdr->ip_p == IP_PROTO_UDP) { - *isudp = true; - } - } - + *hasip4 = true; + ip_p = iphdr->ip_p; ip4hdr_info->fragment = IP4_IS_FRAGMENT(iphdr); *l4hdr_off = l2hdr_len + IP_HDR_GET_LEN(iphdr); fragment = ip4hdr_info->fragment; } else if (proto == ETH_P_IPV6) { - - *isip6 = true; - if (eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, - ip6hdr_info)) { - if (ip6hdr_info->l4proto == IP_PROTO_TCP) { - *istcp = true; - } else if (ip6hdr_info->l4proto == IP_PROTO_UDP) { - *isudp = true; - } - } else { + if (!eth_parse_ipv6_hdr(iov, iovcnt, l2hdr_len, ip6hdr_info)) { return; } + *hasip6 = true; + ip_p = ip6hdr_info->l4proto; *l4hdr_off = l2hdr_len + ip6hdr_info->full_hdr_len; fragment = ip6hdr_info->fragment; + } else { + return; } - if (!fragment) { - if (*istcp) { - *istcp = _eth_copy_chunk(input_size, - iov, iovcnt, - *l4hdr_off, sizeof(l4hdr_info->hdr.tcp), - &l4hdr_info->hdr.tcp); - - if (*istcp) { - *l5hdr_off = *l4hdr_off + - TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp); - - l4hdr_info->has_tcp_data = - _eth_tcp_has_data(proto == ETH_P_IP, - &ip4hdr_info->ip4_hdr, - &ip6hdr_info->ip6_hdr, - *l4hdr_off - *l3hdr_off, - &l4hdr_info->hdr.tcp); - } - } else if (*isudp) { - *isudp = _eth_copy_chunk(input_size, - iov, iovcnt, - *l4hdr_off, sizeof(l4hdr_info->hdr.udp), - &l4hdr_info->hdr.udp); - *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp); + if (fragment) { + return; + } + + switch (ip_p) { + case IP_PROTO_TCP: + *hastcp = _eth_copy_chunk(input_size, + iov, iovcnt, + *l4hdr_off, sizeof(l4hdr_info->hdr.tcp), + &l4hdr_info->hdr.tcp); + if (*hastcp) { + *l5hdr_off = *l4hdr_off + + TCP_HEADER_DATA_OFFSET(&l4hdr_info->hdr.tcp); + + l4hdr_info->has_tcp_data = + _eth_tcp_has_data(proto == ETH_P_IP, + &ip4hdr_info->ip4_hdr, + &ip6hdr_info->ip6_hdr, + *l4hdr_off - *l3hdr_off, + &l4hdr_info->hdr.tcp); } + break; + + case IP_PROTO_UDP: + *hasudp = _eth_copy_chunk(input_size, + iov, iovcnt, + *l4hdr_off, sizeof(l4hdr_info->hdr.udp), + &l4hdr_info->hdr.udp); + *l5hdr_off = *l4hdr_off + sizeof(l4hdr_info->hdr.udp); + break; } } |