@@ -27,6 +27,7 @@ struct net_packet_attrs {
27
27
int max_size ;
28
28
u8 id ;
29
29
u16 queue_mapping ;
30
+ bool bad_csum ;
30
31
};
31
32
32
33
struct net_test_priv {
@@ -165,6 +166,20 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev,
165
166
thdr -> check = ~tcp_v4_check (l4len , ihdr -> saddr , ihdr -> daddr , 0 );
166
167
skb -> csum_start = skb_transport_header (skb ) - skb -> head ;
167
168
skb -> csum_offset = offsetof(struct tcphdr , check );
169
+
170
+ if (attr -> bad_csum ) {
171
+ /* Force mangled checksum */
172
+ if (skb_checksum_help (skb )) {
173
+ kfree_skb (skb );
174
+ return NULL ;
175
+ }
176
+
177
+ if (thdr -> check != CSUM_MANGLED_0 )
178
+ thdr -> check = CSUM_MANGLED_0 ;
179
+ else
180
+ thdr -> check = csum16_sub (thdr -> check ,
181
+ cpu_to_be16 (1 ));
182
+ }
168
183
} else {
169
184
udp4_hwcsum (skb , ihdr -> saddr , ihdr -> daddr );
170
185
}
@@ -239,7 +254,11 @@ static int net_test_loopback_validate(struct sk_buff *skb,
239
254
if (tpriv -> packet -> id != shdr -> id )
240
255
goto out ;
241
256
242
- tpriv -> ok = true;
257
+ if (tpriv -> packet -> bad_csum && skb -> ip_summed == CHECKSUM_UNNECESSARY )
258
+ tpriv -> ok = - EIO ;
259
+ else
260
+ tpriv -> ok = true;
261
+
243
262
complete (& tpriv -> comp );
244
263
out :
245
264
kfree_skb (skb );
@@ -285,7 +304,12 @@ static int __net_test_loopback(struct net_device *ndev,
285
304
attr -> timeout = NET_LB_TIMEOUT ;
286
305
287
306
wait_for_completion_timeout (& tpriv -> comp , attr -> timeout );
288
- ret = tpriv -> ok ? 0 : - ETIMEDOUT ;
307
+ if (tpriv -> ok < 0 )
308
+ ret = tpriv -> ok ;
309
+ else if (!tpriv -> ok )
310
+ ret = - ETIMEDOUT ;
311
+ else
312
+ ret = 0 ;
289
313
290
314
cleanup :
291
315
dev_remove_pack (& tpriv -> pt );
@@ -345,6 +369,42 @@ static int net_test_phy_loopback_tcp(struct net_device *ndev)
345
369
return __net_test_loopback (ndev , & attr );
346
370
}
347
371
372
+ /**
373
+ * net_test_phy_loopback_tcp_bad_csum - PHY loopback test with a deliberately
374
+ * corrupted TCP checksum
375
+ * @ndev: the network device to test
376
+ *
377
+ * Builds the same minimal Ethernet/IPv4/TCP frame as
378
+ * net_test_phy_loopback_tcp(), then flips the least-significant bit of the TCP
379
+ * checksum so the resulting value is provably invalid (neither 0 nor 0xFFFF).
380
+ * The frame is transmitted through the device’s internal PHY loopback path:
381
+ *
382
+ * test code -> MAC driver -> MAC HW -> xMII -> PHY ->
383
+ * internal PHY loopback -> xMII -> MAC HW -> MAC driver -> test code
384
+ *
385
+ * Result interpretation
386
+ * ---------------------
387
+ * 0 The frame is delivered to the stack and the driver reports
388
+ * ip_summed as CHECKSUM_NONE or CHECKSUM_COMPLETE - both are
389
+ * valid ways to indicate “bad checksum, let the stack verify.”
390
+ * -ETIMEDOUT The MAC/PHY silently dropped the frame; hardware checksum
391
+ * verification filtered it out before the driver saw it.
392
+ * -EIO The driver returned the frame with ip_summed ==
393
+ * CHECKSUM_UNNECESSARY, falsely claiming a valid checksum and
394
+ * indicating a serious RX-path defect.
395
+ *
396
+ * Return: 0 on success or a negative error code on failure.
397
+ */
398
+ static int net_test_phy_loopback_tcp_bad_csum (struct net_device * ndev )
399
+ {
400
+ struct net_packet_attrs attr = { };
401
+
402
+ attr .dst = ndev -> dev_addr ;
403
+ attr .tcp = true;
404
+ attr .bad_csum = true;
405
+ return __net_test_loopback (ndev , & attr );
406
+ }
407
+
348
408
static const struct net_test {
349
409
char name [ETH_GSTRING_LEN ];
350
410
int (* fn )(struct net_device * ndev );
@@ -368,6 +428,9 @@ static const struct net_test {
368
428
}, {
369
429
.name = "PHY internal loopback, TCP " ,
370
430
.fn = net_test_phy_loopback_tcp ,
431
+ }, {
432
+ .name = "PHY loopback, bad TCP csum " ,
433
+ .fn = net_test_phy_loopback_tcp_bad_csum ,
371
434
}, {
372
435
/* This test should be done after all PHY loopback test */
373
436
.name = "PHY internal loopback, disable" ,
0 commit comments