@@ -247,6 +247,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
247
247
return segs ;
248
248
}
249
249
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
+
250
306
static struct sk_buff * __udp_gso_segment_list (struct sk_buff * skb ,
251
307
netdev_features_t features ,
252
308
bool is_ipv6 )
@@ -259,7 +315,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
259
315
260
316
udp_hdr (skb )-> len = htons (sizeof (struct udphdr ) + mss );
261
317
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 );
263
322
}
264
323
265
324
struct sk_buff * __udp_gso_segment (struct sk_buff * gso_skb ,
0 commit comments