@@ -245,6 +245,62 @@ static struct sk_buff *__udpv4_gso_segment_list_csum(struct sk_buff *segs)
245
245
return segs ;
246
246
}
247
247
248
+ static void __udpv6_gso_segment_csum (struct sk_buff * seg ,
249
+ struct in6_addr * oldip ,
250
+ const struct in6_addr * newip ,
251
+ __be16 * oldport , __be16 newport )
252
+ {
253
+ struct udphdr * uh = udp_hdr (seg );
254
+
255
+ if (ipv6_addr_equal (oldip , newip ) && * oldport == newport )
256
+ return ;
257
+
258
+ if (uh -> check ) {
259
+ inet_proto_csum_replace16 (& uh -> check , seg , oldip -> s6_addr32 ,
260
+ newip -> s6_addr32 , true);
261
+
262
+ inet_proto_csum_replace2 (& uh -> check , seg , * oldport , newport ,
263
+ false);
264
+ if (!uh -> check )
265
+ uh -> check = CSUM_MANGLED_0 ;
266
+ }
267
+
268
+ * oldip = * newip ;
269
+ * oldport = newport ;
270
+ }
271
+
272
+ static struct sk_buff * __udpv6_gso_segment_list_csum (struct sk_buff * segs )
273
+ {
274
+ const struct ipv6hdr * iph ;
275
+ const struct udphdr * uh ;
276
+ struct ipv6hdr * iph2 ;
277
+ struct sk_buff * seg ;
278
+ struct udphdr * uh2 ;
279
+
280
+ seg = segs ;
281
+ uh = udp_hdr (seg );
282
+ iph = ipv6_hdr (seg );
283
+ uh2 = udp_hdr (seg -> next );
284
+ iph2 = ipv6_hdr (seg -> next );
285
+
286
+ if (!(* (const u32 * )& uh -> source ^ * (const u32 * )& uh2 -> source ) &&
287
+ ipv6_addr_equal (& iph -> saddr , & iph2 -> saddr ) &&
288
+ ipv6_addr_equal (& iph -> daddr , & iph2 -> daddr ))
289
+ return segs ;
290
+
291
+ while ((seg = seg -> next )) {
292
+ uh2 = udp_hdr (seg );
293
+ iph2 = ipv6_hdr (seg );
294
+
295
+ __udpv6_gso_segment_csum (seg , & iph2 -> saddr , & iph -> saddr ,
296
+ & uh2 -> source , uh -> source );
297
+ __udpv6_gso_segment_csum (seg , & iph2 -> daddr , & iph -> daddr ,
298
+ & uh2 -> dest , uh -> dest );
299
+ }
300
+
301
+ return segs ;
302
+ }
303
+
248
304
static struct sk_buff * __udp_gso_segment_list (struct sk_buff * skb ,
249
305
netdev_features_t features ,
250
306
bool is_ipv6 )
@@ -257,7 +313,10 @@ static struct sk_buff *__udp_gso_segment_list(struct sk_buff *skb,
257
313
258
314
udp_hdr (skb )-> len = htons (sizeof (struct udphdr ) + mss );
259
315
260
- return is_ipv6 ? skb : __udpv4_gso_segment_list_csum (skb );
316
+ if (is_ipv6 )
317
+ return __udpv6_gso_segment_list_csum (skb );
318
+ else
319
+ return __udpv4_gso_segment_list_csum (skb );
261
320
}
262
321
263
322
struct sk_buff * __udp_gso_segment (struct sk_buff * gso_skb ,
0 commit comments