| From 604af93d8037a18f9dabe64e947d57889da68d57 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 10 Sep 2020 07:57:04 +0000 |
| Subject: i40e: Fix flow for IPv6 next header (extension header) |
| |
| From: Slawomir Laba <slawomirx.laba@intel.com> |
| |
| [ Upstream commit 92c6058024e87087cf1b99b0389d67c0a886360e ] |
| |
| When a packet contains an IPv6 header with next header which is |
| an extension header and not a protocol one, the kernel function |
| skb_transport_header called with such sk_buff will return a |
| pointer to the extension header and not to the TCP one. |
| |
| The above explained call caused a problem with packet processing |
| for skb with encapsulation for tunnel with I40E_TX_CTX_EXT_IP_IPV6. |
| The extension header was not skipped at all. |
| |
| The ipv6_skip_exthdr function does check if next header of the IPV6 |
| header is an extension header and doesn't modify the l4_proto pointer |
| if it points to a protocol header value so its safe to omit the |
| comparison of exthdr and l4.hdr pointers. The ipv6_skip_exthdr can |
| return value -1. This means that the skipping process failed |
| and there is something wrong with the packet so it will be dropped. |
| |
| Fixes: a3fd9d8876a5 ("i40e/i40evf: Handle IPv6 extension headers in checksum offload") |
| Signed-off-by: Slawomir Laba <slawomirx.laba@intel.com> |
| Signed-off-by: Przemyslaw Patynowski <przemyslawx.patynowski@intel.com> |
| Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> |
| Tested-by: Tony Brelinski <tonyx.brelinski@intel.com> |
| Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/net/ethernet/intel/i40e/i40e_txrx.c | 9 ++++++--- |
| 1 file changed, 6 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c |
| index 2e12ccf73dba0..877b49cc9d3c3 100644 |
| --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c |
| +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c |
| @@ -2452,13 +2452,16 @@ static int i40e_tx_enable_csum(struct sk_buff *skb, u32 *tx_flags, |
| |
| l4_proto = ip.v4->protocol; |
| } else if (*tx_flags & I40E_TX_FLAGS_IPV6) { |
| + int ret; |
| + |
| tunnel |= I40E_TX_CTX_EXT_IP_IPV6; |
| |
| exthdr = ip.hdr + sizeof(*ip.v6); |
| l4_proto = ip.v6->nexthdr; |
| - if (l4.hdr != exthdr) |
| - ipv6_skip_exthdr(skb, exthdr - skb->data, |
| - &l4_proto, &frag_off); |
| + ret = ipv6_skip_exthdr(skb, exthdr - skb->data, |
| + &l4_proto, &frag_off); |
| + if (ret < 0) |
| + return -1; |
| } |
| |
| /* define outer transport */ |
| -- |
| 2.27.0 |
| |