Skip to content

Commit a805fc9

Browse files
author
CKI KWF Bot
committed
Merge: udp: stable backports from upstream for 10.1 phase 2
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/1127 JIRA: https://issues.redhat.com/browse/RHEL-96626 A couple of fixes addressing critical issues Signed-off-by: Paolo Abeni <pabeni@redhat.com> Approved-by: Hangbin Liu <haliu@redhat.com> Approved-by: Antoine Tenart <atenart@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
2 parents 9ab3da7 + 4aadca8 commit a805fc9

File tree

1 file changed

+65
-1
lines changed

1 file changed

+65
-1
lines changed

net/ipv4/udp_offload.c

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
247247
return segs;
248248
}
249249

250+
static void __udpv6_gso_segment_csum(struct sk_buff *seg,
251+
struct in6_addr *oldip,
252+
const struct in6_addr *newip,
253+
__be16 *oldport, __be16 newport)
254+
{
255+
struct udphdr *uh = udp_hdr(seg);
256+
257+
if (ipv6_addr_equal(oldip, newip) && *oldport == newport)
258+
return;
259+
260+
if (uh->check) {
261+
inet_proto_csum_replace16(&uh->check, seg, oldip->s6_addr32,
262+
newip->s6_addr32, true);
263+
264+
inet_proto_csum_replace2(&uh->check, seg, *oldport, newport,
265+
false);
266+
if (!uh->check)
267+
uh->check = CSUM_MANGLED_0;
268+
}
269+
270+
*oldip = *newip;
271+
*oldport = newport;
272+
}
273+
274+
static struct sk_buff *__udpv6_gso_segment_list_csum(struct sk_buff *segs)
275+
{
276+
const struct ipv6hdr *iph;
277+
const struct udphdr *uh;
278+
struct ipv6hdr *iph2;
279+
struct sk_buff *seg;
280+
struct udphdr *uh2;
281+
282+
seg = segs;
283+
uh = udp_hdr(seg);
284+
iph = ipv6_hdr(seg);
285+
uh2 = udp_hdr(seg->next);
286+
iph2 = ipv6_hdr(seg->next);
287+
288+
if (!(*(const u32 *)&uh->source ^ *(const u32 *)&uh2->source) &&
289+
ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
290+
ipv6_addr_equal(&iph->daddr, &iph2->daddr))
291+
return segs;
292+
293+
while ((seg = seg->next)) {
294+
uh2 = udp_hdr(seg);
295+
iph2 = ipv6_hdr(seg);
296+
297+
__udpv6_gso_segment_csum(seg, &iph2->saddr, &iph->saddr,
298+
&uh2->source, uh->source);
299+
__udpv6_gso_segment_csum(seg, &iph2->daddr, &iph->daddr,
300+
&uh2->dest, uh->dest);
301+
}
302+
303+
return segs;
304+
}
305+
250306
static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
251307
netdev_features_t features,
252308
bool is_ipv6)
@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
259315

260316
udp_hdr(skb)->len = htons(sizeof(struct udphdr) + mss);
261317

262-
return is_ipv6 ? skb : __udpv4_gso_segment_list_csum(skb);
318+
if (is_ipv6)
319+
return __udpv6_gso_segment_list_csum(skb);
320+
else
321+
return __udpv4_gso_segment_list_csum(skb);
263322
}
264323

265324
struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
@@ -273,6 +332,7 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
273332
bool copy_dtor;
274333
__sum16 check;
275334
__be16 newlen;
335+
int ret = 0;
276336

277337
mss = skb_shinfo(gso_skb)->gso_size;
278338
if (gso_skb->len <= sizeof(*uh) + mss)
@@ -301,6 +361,10 @@ struct sk_buff *__udp_gso_segment(struct sk_buff *gso_skb,
301361
if (skb_pagelen(gso_skb) - sizeof(*uh) == skb_shinfo(gso_skb)->gso_size)
302362
return __udp_gso_segment_list(gso_skb, features, is_ipv6);
303363

364+
ret = __skb_linearize(gso_skb);
365+
if (ret)
366+
return ERR_PTR(ret);
367+
304368
/* Setup csum, as fraglist skips this in udp4_gro_receive. */
305369
gso_skb->csum_start = skb_transport_header(gso_skb) - gso_skb->head;
306370
gso_skb->csum_offset = offsetof(struct udphdr, check);

0 commit comments

Comments
 (0)