Skip to content

Commit a44940d

Browse files
Jiawen Wukuba-moo
authored andcommitted
net: libwx: fix Tx descriptor content for some tunnel packets
The length of skb header was incorrectly calculated when transmit a tunnel packet with outer IPv6 extension header, or a IP over IP packet which has inner IPv6 header. Thus the correct Tx context descriptor cannot be composed, resulting in Tx ring hang. Fixes: 3403960 ("net: wangxun: libwx add tx offload functions") Signed-off-by: Jiawen Wu <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent bf2986f commit a44940d

File tree

1 file changed

+37
-24
lines changed
  • drivers/net/ethernet/wangxun/libwx

1 file changed

+37
-24
lines changed

drivers/net/ethernet/wangxun/libwx/wx_lib.c

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1082,26 +1082,6 @@ static void wx_tx_ctxtdesc(struct wx_ring *tx_ring, u32 vlan_macip_lens,
10821082
context_desc->mss_l4len_idx = cpu_to_le32(mss_l4len_idx);
10831083
}
10841084

1085-
static void wx_get_ipv6_proto(struct sk_buff *skb, int offset, u8 *nexthdr)
1086-
{
1087-
struct ipv6hdr *hdr = (struct ipv6hdr *)(skb->data + offset);
1088-
1089-
*nexthdr = hdr->nexthdr;
1090-
offset += sizeof(struct ipv6hdr);
1091-
while (ipv6_ext_hdr(*nexthdr)) {
1092-
struct ipv6_opt_hdr _hdr, *hp;
1093-
1094-
if (*nexthdr == NEXTHDR_NONE)
1095-
return;
1096-
hp = skb_header_pointer(skb, offset, sizeof(_hdr), &_hdr);
1097-
if (!hp)
1098-
return;
1099-
if (*nexthdr == NEXTHDR_FRAGMENT)
1100-
break;
1101-
*nexthdr = hp->nexthdr;
1102-
}
1103-
}
1104-
11051085
union network_header {
11061086
struct iphdr *ipv4;
11071087
struct ipv6hdr *ipv6;
@@ -1112,6 +1092,8 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
11121092
{
11131093
u8 tun_prot = 0, l4_prot = 0, ptype = 0;
11141094
struct sk_buff *skb = first->skb;
1095+
unsigned char *exthdr, *l4_hdr;
1096+
__be16 frag_off;
11151097

11161098
if (skb->encapsulation) {
11171099
union network_header hdr;
@@ -1122,14 +1104,18 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
11221104
ptype = WX_PTYPE_TUN_IPV4;
11231105
break;
11241106
case htons(ETH_P_IPV6):
1125-
wx_get_ipv6_proto(skb, skb_network_offset(skb), &tun_prot);
1107+
l4_hdr = skb_transport_header(skb);
1108+
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
1109+
tun_prot = ipv6_hdr(skb)->nexthdr;
1110+
if (l4_hdr != exthdr)
1111+
ipv6_skip_exthdr(skb, exthdr - skb->data, &tun_prot, &frag_off);
11261112
ptype = WX_PTYPE_TUN_IPV6;
11271113
break;
11281114
default:
11291115
return ptype;
11301116
}
11311117

1132-
if (tun_prot == IPPROTO_IPIP) {
1118+
if (tun_prot == IPPROTO_IPIP || tun_prot == IPPROTO_IPV6) {
11331119
hdr.raw = (void *)inner_ip_hdr(skb);
11341120
ptype |= WX_PTYPE_PKT_IPIP;
11351121
} else if (tun_prot == IPPROTO_UDP) {
@@ -1166,7 +1152,11 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
11661152
l4_prot = hdr.ipv4->protocol;
11671153
break;
11681154
case 6:
1169-
wx_get_ipv6_proto(skb, skb_inner_network_offset(skb), &l4_prot);
1155+
l4_hdr = skb_inner_transport_header(skb);
1156+
exthdr = skb_inner_network_header(skb) + sizeof(struct ipv6hdr);
1157+
l4_prot = inner_ipv6_hdr(skb)->nexthdr;
1158+
if (l4_hdr != exthdr)
1159+
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
11701160
ptype |= WX_PTYPE_PKT_IPV6;
11711161
break;
11721162
default:
@@ -1179,7 +1169,11 @@ static u8 wx_encode_tx_desc_ptype(const struct wx_tx_buffer *first)
11791169
ptype = WX_PTYPE_PKT_IP;
11801170
break;
11811171
case htons(ETH_P_IPV6):
1182-
wx_get_ipv6_proto(skb, skb_network_offset(skb), &l4_prot);
1172+
l4_hdr = skb_transport_header(skb);
1173+
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
1174+
l4_prot = ipv6_hdr(skb)->nexthdr;
1175+
if (l4_hdr != exthdr)
1176+
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
11831177
ptype = WX_PTYPE_PKT_IP | WX_PTYPE_PKT_IPV6;
11841178
break;
11851179
default:
@@ -1269,13 +1263,20 @@ static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
12691263

12701264
/* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */
12711265
if (enc) {
1266+
unsigned char *exthdr, *l4_hdr;
1267+
__be16 frag_off;
1268+
12721269
switch (first->protocol) {
12731270
case htons(ETH_P_IP):
12741271
tun_prot = ip_hdr(skb)->protocol;
12751272
first->tx_flags |= WX_TX_FLAGS_OUTER_IPV4;
12761273
break;
12771274
case htons(ETH_P_IPV6):
1275+
l4_hdr = skb_transport_header(skb);
1276+
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
12781277
tun_prot = ipv6_hdr(skb)->nexthdr;
1278+
if (l4_hdr != exthdr)
1279+
ipv6_skip_exthdr(skb, exthdr - skb->data, &tun_prot, &frag_off);
12791280
break;
12801281
default:
12811282
break;
@@ -1298,6 +1299,7 @@ static int wx_tso(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
12981299
WX_TXD_TUNNEL_LEN_SHIFT);
12991300
break;
13001301
case IPPROTO_IPIP:
1302+
case IPPROTO_IPV6:
13011303
tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) -
13021304
(char *)ip_hdr(skb)) >> 2) <<
13031305
WX_TXD_OUTER_IPLEN_SHIFT;
@@ -1341,6 +1343,8 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
13411343
vlan_macip_lens = skb_network_offset(skb) <<
13421344
WX_TXD_MACLEN_SHIFT;
13431345
} else {
1346+
unsigned char *exthdr, *l4_hdr;
1347+
__be16 frag_off;
13441348
u8 l4_prot = 0;
13451349
union {
13461350
struct iphdr *ipv4;
@@ -1362,7 +1366,12 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
13621366
tun_prot = ip_hdr(skb)->protocol;
13631367
break;
13641368
case htons(ETH_P_IPV6):
1369+
l4_hdr = skb_transport_header(skb);
1370+
exthdr = skb_network_header(skb) + sizeof(struct ipv6hdr);
13651371
tun_prot = ipv6_hdr(skb)->nexthdr;
1372+
if (l4_hdr != exthdr)
1373+
ipv6_skip_exthdr(skb, exthdr - skb->data,
1374+
&tun_prot, &frag_off);
13661375
break;
13671376
default:
13681377
return;
@@ -1386,6 +1395,7 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
13861395
WX_TXD_TUNNEL_LEN_SHIFT);
13871396
break;
13881397
case IPPROTO_IPIP:
1398+
case IPPROTO_IPV6:
13891399
tunhdr_eiplen_tunlen = (((char *)inner_ip_hdr(skb) -
13901400
(char *)ip_hdr(skb)) >> 2) <<
13911401
WX_TXD_OUTER_IPLEN_SHIFT;
@@ -1408,7 +1418,10 @@ static void wx_tx_csum(struct wx_ring *tx_ring, struct wx_tx_buffer *first,
14081418
break;
14091419
case 6:
14101420
vlan_macip_lens |= (transport_hdr.raw - network_hdr.raw) >> 1;
1421+
exthdr = network_hdr.raw + sizeof(struct ipv6hdr);
14111422
l4_prot = network_hdr.ipv6->nexthdr;
1423+
if (transport_hdr.raw != exthdr)
1424+
ipv6_skip_exthdr(skb, exthdr - skb->data, &l4_prot, &frag_off);
14121425
break;
14131426
default:
14141427
break;

0 commit comments

Comments
 (0)