@@ -27,6 +27,7 @@ struct net_packet_attrs {
2727 int max_size ;
2828 u8 id ;
2929 u16 queue_mapping ;
30+ bool bad_csum ;
3031};
3132
3233struct net_test_priv {
@@ -165,6 +166,20 @@ static struct sk_buff *net_test_get_skb(struct net_device *ndev,
165166 thdr -> check = ~tcp_v4_check (l4len , ihdr -> saddr , ihdr -> daddr , 0 );
166167 skb -> csum_start = skb_transport_header (skb ) - skb -> head ;
167168 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+ }
168183 } else {
169184 udp4_hwcsum (skb , ihdr -> saddr , ihdr -> daddr );
170185 }
@@ -239,7 +254,11 @@ static int net_test_loopback_validate(struct sk_buff *skb,
239254 if (tpriv -> packet -> id != shdr -> id )
240255 goto out ;
241256
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+
243262 complete (& tpriv -> comp );
244263out :
245264 kfree_skb (skb );
@@ -285,7 +304,12 @@ static int __net_test_loopback(struct net_device *ndev,
285304 attr -> timeout = NET_LB_TIMEOUT ;
286305
287306 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 ;
289313
290314cleanup :
291315 dev_remove_pack (& tpriv -> pt );
@@ -345,6 +369,42 @@ static int net_test_phy_loopback_tcp(struct net_device *ndev)
345369 return __net_test_loopback (ndev , & attr );
346370}
347371
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+
348408static const struct net_test {
349409 char name [ETH_GSTRING_LEN ];
350410 int (* fn )(struct net_device * ndev );
@@ -368,6 +428,9 @@ static const struct net_test {
368428 }, {
369429 .name = "PHY internal loopback, TCP " ,
370430 .fn = net_test_phy_loopback_tcp ,
431+ }, {
432+ .name = "PHY loopback, bad TCP csum " ,
433+ .fn = net_test_phy_loopback_tcp_bad_csum ,
371434 }, {
372435 /* This test should be done after all PHY loopback test */
373436 .name = "PHY internal loopback, disable" ,
0 commit comments