xref: /openbmc/u-boot/test/dm/eth.c (revision 68489ed037530ec29fc0bc452ad6e4b0c5db02ec)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
2bfacad7dSJoe Hershberger /*
3bfacad7dSJoe Hershberger  * Copyright (c) 2015 National Instruments
4bfacad7dSJoe Hershberger  *
5bfacad7dSJoe Hershberger  * (C) Copyright 2015
6bfacad7dSJoe Hershberger  * Joe Hershberger <joe.hershberger@ni.com>
7bfacad7dSJoe Hershberger  */
8bfacad7dSJoe Hershberger 
9bfacad7dSJoe Hershberger #include <common.h>
10bfacad7dSJoe Hershberger #include <dm.h>
11bfacad7dSJoe Hershberger #include <fdtdec.h>
12bfacad7dSJoe Hershberger #include <malloc.h>
13bfacad7dSJoe Hershberger #include <net.h>
14e721b882SJoe Hershberger #include <dm/test.h>
156d9764c2SBin Meng #include <dm/device-internal.h>
166d9764c2SBin Meng #include <dm/uclass-internal.h>
177ece1c61SJoe Hershberger #include <asm/eth.h>
18e721b882SJoe Hershberger #include <test/ut.h>
19bfacad7dSJoe Hershberger 
206d9764c2SBin Meng #define DM_TEST_ETH_NUM		4
216d9764c2SBin Meng 
dm_test_eth(struct unit_test_state * uts)22e721b882SJoe Hershberger static int dm_test_eth(struct unit_test_state *uts)
23bfacad7dSJoe Hershberger {
24049a95a7SJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
25bfacad7dSJoe Hershberger 
26382bee57SSimon Glass 	env_set("ethact", "eth@10002000");
27bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
2800caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
29bfacad7dSJoe Hershberger 
30382bee57SSimon Glass 	env_set("ethact", "eth@10003000");
31bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
3200caae6dSSimon Glass 	ut_asserteq_str("eth@10003000", env_get("ethact"));
33bfacad7dSJoe Hershberger 
34382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
35bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
3600caae6dSSimon Glass 	ut_asserteq_str("eth@10004000", env_get("ethact"));
37bfacad7dSJoe Hershberger 
38bfacad7dSJoe Hershberger 	return 0;
39bfacad7dSJoe Hershberger }
40bfacad7dSJoe Hershberger DM_TEST(dm_test_eth, DM_TESTF_SCAN_FDT);
41e58780dcSJoe Hershberger 
dm_test_eth_alias(struct unit_test_state * uts)42e721b882SJoe Hershberger static int dm_test_eth_alias(struct unit_test_state *uts)
43e58780dcSJoe Hershberger {
44049a95a7SJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
45382bee57SSimon Glass 	env_set("ethact", "eth0");
46bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
4700caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
48e58780dcSJoe Hershberger 
49382bee57SSimon Glass 	env_set("ethact", "eth1");
50bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
5100caae6dSSimon Glass 	ut_asserteq_str("eth@10004000", env_get("ethact"));
52e58780dcSJoe Hershberger 
53e58780dcSJoe Hershberger 	/* Expected to fail since eth2 is not defined in the device tree */
54382bee57SSimon Glass 	env_set("ethact", "eth2");
55bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
5600caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
57e58780dcSJoe Hershberger 
58382bee57SSimon Glass 	env_set("ethact", "eth5");
59bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
6000caae6dSSimon Glass 	ut_asserteq_str("eth@10003000", env_get("ethact"));
61e58780dcSJoe Hershberger 
62e58780dcSJoe Hershberger 	return 0;
63e58780dcSJoe Hershberger }
64e58780dcSJoe Hershberger DM_TEST(dm_test_eth_alias, DM_TESTF_SCAN_FDT);
656536b9bbSJoe Hershberger 
dm_test_eth_prime(struct unit_test_state * uts)66e721b882SJoe Hershberger static int dm_test_eth_prime(struct unit_test_state *uts)
676536b9bbSJoe Hershberger {
68049a95a7SJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
696536b9bbSJoe Hershberger 
706536b9bbSJoe Hershberger 	/* Expected to be "eth@10003000" because of ethprime variable */
71382bee57SSimon Glass 	env_set("ethact", NULL);
72382bee57SSimon Glass 	env_set("ethprime", "eth5");
73bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
7400caae6dSSimon Glass 	ut_asserteq_str("eth@10003000", env_get("ethact"));
756536b9bbSJoe Hershberger 
766536b9bbSJoe Hershberger 	/* Expected to be "eth@10002000" because it is first */
77382bee57SSimon Glass 	env_set("ethact", NULL);
78382bee57SSimon Glass 	env_set("ethprime", NULL);
79bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
8000caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
816536b9bbSJoe Hershberger 
826536b9bbSJoe Hershberger 	return 0;
836536b9bbSJoe Hershberger }
846536b9bbSJoe Hershberger DM_TEST(dm_test_eth_prime, DM_TESTF_SCAN_FDT);
857d104eabSJoe Hershberger 
866d9764c2SBin Meng /**
876d9764c2SBin Meng  * This test case is trying to test the following scenario:
886d9764c2SBin Meng  *	- All ethernet devices are not probed
896d9764c2SBin Meng  *	- "ethaddr" for all ethernet devices are not set
906d9764c2SBin Meng  *	- "ethact" is set to a valid ethernet device name
916d9764c2SBin Meng  *
926d9764c2SBin Meng  * With Sandbox default test configuration, all ethernet devices are
936d9764c2SBin Meng  * probed after power-up, so we have to manually create such scenario:
946d9764c2SBin Meng  *	- Remove all ethernet devices
956d9764c2SBin Meng  *	- Remove all "ethaddr" environment variables
966d9764c2SBin Meng  *	- Set "ethact" to the first ethernet device
976d9764c2SBin Meng  *
986d9764c2SBin Meng  * Do a ping test to see if anything goes wrong.
996d9764c2SBin Meng  */
dm_test_eth_act(struct unit_test_state * uts)1006d9764c2SBin Meng static int dm_test_eth_act(struct unit_test_state *uts)
1016d9764c2SBin Meng {
1026d9764c2SBin Meng 	struct udevice *dev[DM_TEST_ETH_NUM];
1036d9764c2SBin Meng 	const char *ethname[DM_TEST_ETH_NUM] = {"eth@10002000", "eth@10003000",
1046d9764c2SBin Meng 						"sbe5", "eth@10004000"};
1056d9764c2SBin Meng 	const char *addrname[DM_TEST_ETH_NUM] = {"ethaddr", "eth5addr",
1066d9764c2SBin Meng 						 "eth3addr", "eth1addr"};
1076d9764c2SBin Meng 	char ethaddr[DM_TEST_ETH_NUM][18];
1086d9764c2SBin Meng 	int i;
1096d9764c2SBin Meng 
110e2e6daedSTom Rini 	memset(ethaddr, '\0', sizeof(ethaddr));
1116d9764c2SBin Meng 	net_ping_ip = string_to_ip("1.1.2.2");
1126d9764c2SBin Meng 
1136d9764c2SBin Meng 	/* Prepare the test scenario */
1146d9764c2SBin Meng 	for (i = 0; i < DM_TEST_ETH_NUM; i++) {
1156d9764c2SBin Meng 		ut_assertok(uclass_find_device_by_name(UCLASS_ETH,
1166d9764c2SBin Meng 						       ethname[i], &dev[i]));
117706865afSStefan Roese 		ut_assertok(device_remove(dev[i], DM_REMOVE_NORMAL));
1186d9764c2SBin Meng 
1196d9764c2SBin Meng 		/* Invalidate MAC address */
120e2e6daedSTom Rini 		strncpy(ethaddr[i], env_get(addrname[i]), 17);
1216d9764c2SBin Meng 		/* Must disable access protection for ethaddr before clearing */
122382bee57SSimon Glass 		env_set(".flags", addrname[i]);
123382bee57SSimon Glass 		env_set(addrname[i], NULL);
1246d9764c2SBin Meng 	}
1256d9764c2SBin Meng 
1266d9764c2SBin Meng 	/* Set ethact to "eth@10002000" */
127382bee57SSimon Glass 	env_set("ethact", ethname[0]);
1286d9764c2SBin Meng 
1296d9764c2SBin Meng 	/* Segment fault might happen if something is wrong */
1306d9764c2SBin Meng 	ut_asserteq(-ENODEV, net_loop(PING));
1316d9764c2SBin Meng 
1326d9764c2SBin Meng 	for (i = 0; i < DM_TEST_ETH_NUM; i++) {
1336d9764c2SBin Meng 		/* Restore the env */
134382bee57SSimon Glass 		env_set(".flags", addrname[i]);
135382bee57SSimon Glass 		env_set(addrname[i], ethaddr[i]);
1366d9764c2SBin Meng 
1376d9764c2SBin Meng 		/* Probe the device again */
1386d9764c2SBin Meng 		ut_assertok(device_probe(dev[i]));
1396d9764c2SBin Meng 	}
140382bee57SSimon Glass 	env_set(".flags", NULL);
141382bee57SSimon Glass 	env_set("ethact", NULL);
1426d9764c2SBin Meng 
1436d9764c2SBin Meng 	return 0;
1446d9764c2SBin Meng }
1456d9764c2SBin Meng DM_TEST(dm_test_eth_act, DM_TESTF_SCAN_FDT);
1466d9764c2SBin Meng 
14709129becSJoe Hershberger /* The asserts include a return on fail; cleanup in the caller */
_dm_test_eth_rotate1(struct unit_test_state * uts)14809129becSJoe Hershberger static int _dm_test_eth_rotate1(struct unit_test_state *uts)
1497d104eabSJoe Hershberger {
1507d104eabSJoe Hershberger 	/* Make sure that the default is to rotate to the next interface */
151382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
152bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
15300caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
1547d104eabSJoe Hershberger 
1557d104eabSJoe Hershberger 	/* If ethrotate is no, then we should fail on a bad MAC */
156382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
157382bee57SSimon Glass 	env_set("ethrotate", "no");
158bc0571fcSJoe Hershberger 	ut_asserteq(-EINVAL, net_loop(PING));
15900caae6dSSimon Glass 	ut_asserteq_str("eth@10004000", env_get("ethact"));
1607d104eabSJoe Hershberger 
16109129becSJoe Hershberger 	return 0;
16209129becSJoe Hershberger }
16309129becSJoe Hershberger 
_dm_test_eth_rotate2(struct unit_test_state * uts)16409129becSJoe Hershberger static int _dm_test_eth_rotate2(struct unit_test_state *uts)
16509129becSJoe Hershberger {
16609129becSJoe Hershberger 	/* Make sure we can skip invalid devices */
167382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
16809129becSJoe Hershberger 	ut_assertok(net_loop(PING));
16900caae6dSSimon Glass 	ut_asserteq_str("eth@10004000", env_get("ethact"));
17009129becSJoe Hershberger 
17171d7971fSBin Meng 	/* Make sure we can handle device name which is not eth# */
172382bee57SSimon Glass 	env_set("ethact", "sbe5");
17371d7971fSBin Meng 	ut_assertok(net_loop(PING));
17400caae6dSSimon Glass 	ut_asserteq_str("sbe5", env_get("ethact"));
17571d7971fSBin Meng 
17609129becSJoe Hershberger 	return 0;
17709129becSJoe Hershberger }
17809129becSJoe Hershberger 
dm_test_eth_rotate(struct unit_test_state * uts)17909129becSJoe Hershberger static int dm_test_eth_rotate(struct unit_test_state *uts)
18009129becSJoe Hershberger {
18109129becSJoe Hershberger 	char ethaddr[18];
18209129becSJoe Hershberger 	int retval;
18309129becSJoe Hershberger 
18409129becSJoe Hershberger 	/* Set target IP to mock ping */
18509129becSJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
18609129becSJoe Hershberger 
18709129becSJoe Hershberger 	/* Invalidate eth1's MAC address */
188e2e6daedSTom Rini 	memset(ethaddr, '\0', sizeof(ethaddr));
189e2e6daedSTom Rini 	strncpy(ethaddr, env_get("eth1addr"), 17);
19009129becSJoe Hershberger 	/* Must disable access protection for eth1addr before clearing */
191382bee57SSimon Glass 	env_set(".flags", "eth1addr");
192382bee57SSimon Glass 	env_set("eth1addr", NULL);
19309129becSJoe Hershberger 
19409129becSJoe Hershberger 	retval = _dm_test_eth_rotate1(uts);
19509129becSJoe Hershberger 
1967d104eabSJoe Hershberger 	/* Restore the env */
197382bee57SSimon Glass 	env_set("eth1addr", ethaddr);
198382bee57SSimon Glass 	env_set("ethrotate", NULL);
1997d104eabSJoe Hershberger 
20009129becSJoe Hershberger 	if (!retval) {
2017d104eabSJoe Hershberger 		/* Invalidate eth0's MAC address */
202e2e6daedSTom Rini 		strncpy(ethaddr, env_get("ethaddr"), 17);
20373c2bbeeSJoe Hershberger 		/* Must disable access protection for ethaddr before clearing */
204382bee57SSimon Glass 		env_set(".flags", "ethaddr");
205382bee57SSimon Glass 		env_set("ethaddr", NULL);
2067d104eabSJoe Hershberger 
20709129becSJoe Hershberger 		retval = _dm_test_eth_rotate2(uts);
2087d104eabSJoe Hershberger 
2097d104eabSJoe Hershberger 		/* Restore the env */
210382bee57SSimon Glass 		env_set("ethaddr", ethaddr);
21109129becSJoe Hershberger 	}
21209129becSJoe Hershberger 	/* Restore the env */
213382bee57SSimon Glass 	env_set(".flags", NULL);
2147d104eabSJoe Hershberger 
21509129becSJoe Hershberger 	return retval;
2167d104eabSJoe Hershberger }
2177d104eabSJoe Hershberger DM_TEST(dm_test_eth_rotate, DM_TESTF_SCAN_FDT);
2187ece1c61SJoe Hershberger 
21909129becSJoe Hershberger /* The asserts include a return on fail; cleanup in the caller */
_dm_test_net_retry(struct unit_test_state * uts)22009129becSJoe Hershberger static int _dm_test_net_retry(struct unit_test_state *uts)
2217ece1c61SJoe Hershberger {
2227ece1c61SJoe Hershberger 	/*
2237ece1c61SJoe Hershberger 	 * eth1 is disabled and netretry is yes, so the ping should succeed and
2247ece1c61SJoe Hershberger 	 * the active device should be eth0
2257ece1c61SJoe Hershberger 	 */
2267ece1c61SJoe Hershberger 	sandbox_eth_disable_response(1, true);
227382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
228382bee57SSimon Glass 	env_set("netretry", "yes");
229172a31bfSJoe Hershberger 	sandbox_eth_skip_timeout();
230bc0571fcSJoe Hershberger 	ut_assertok(net_loop(PING));
23100caae6dSSimon Glass 	ut_asserteq_str("eth@10002000", env_get("ethact"));
2327ece1c61SJoe Hershberger 
2337ece1c61SJoe Hershberger 	/*
2347ece1c61SJoe Hershberger 	 * eth1 is disabled and netretry is no, so the ping should fail and the
2357ece1c61SJoe Hershberger 	 * active device should be eth1
2367ece1c61SJoe Hershberger 	 */
237382bee57SSimon Glass 	env_set("ethact", "eth@10004000");
238382bee57SSimon Glass 	env_set("netretry", "no");
239172a31bfSJoe Hershberger 	sandbox_eth_skip_timeout();
240*a735e6e9SThomas RIENOESSL 	ut_asserteq(-ENONET, net_loop(PING));
24100caae6dSSimon Glass 	ut_asserteq_str("eth@10004000", env_get("ethact"));
2427ece1c61SJoe Hershberger 
24309129becSJoe Hershberger 	return 0;
24409129becSJoe Hershberger }
24509129becSJoe Hershberger 
dm_test_net_retry(struct unit_test_state * uts)24609129becSJoe Hershberger static int dm_test_net_retry(struct unit_test_state *uts)
24709129becSJoe Hershberger {
24809129becSJoe Hershberger 	int retval;
24909129becSJoe Hershberger 
25009129becSJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
25109129becSJoe Hershberger 
25209129becSJoe Hershberger 	retval = _dm_test_net_retry(uts);
25309129becSJoe Hershberger 
2547ece1c61SJoe Hershberger 	/* Restore the env */
255382bee57SSimon Glass 	env_set("netretry", NULL);
2567ece1c61SJoe Hershberger 	sandbox_eth_disable_response(1, false);
2577ece1c61SJoe Hershberger 
25809129becSJoe Hershberger 	return retval;
2597ece1c61SJoe Hershberger }
2607ece1c61SJoe Hershberger DM_TEST(dm_test_net_retry, DM_TESTF_SCAN_FDT);
26145988daeSJoe Hershberger 
sb_check_arp_reply(struct udevice * dev,void * packet,unsigned int len)26245988daeSJoe Hershberger static int sb_check_arp_reply(struct udevice *dev, void *packet,
26345988daeSJoe Hershberger 			      unsigned int len)
26445988daeSJoe Hershberger {
26545988daeSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
26645988daeSJoe Hershberger 	struct ethernet_hdr *eth = packet;
26745988daeSJoe Hershberger 	struct arp_hdr *arp;
26845988daeSJoe Hershberger 	/* Used by all of the ut_assert macros */
26945988daeSJoe Hershberger 	struct unit_test_state *uts = priv->priv;
27045988daeSJoe Hershberger 
27145988daeSJoe Hershberger 	if (ntohs(eth->et_protlen) != PROT_ARP)
27245988daeSJoe Hershberger 		return 0;
27345988daeSJoe Hershberger 
27445988daeSJoe Hershberger 	arp = packet + ETHER_HDR_SIZE;
27545988daeSJoe Hershberger 
27645988daeSJoe Hershberger 	if (ntohs(arp->ar_op) != ARPOP_REPLY)
27745988daeSJoe Hershberger 		return 0;
27845988daeSJoe Hershberger 
27945988daeSJoe Hershberger 	/* This test would be worthless if we are not waiting */
28045988daeSJoe Hershberger 	ut_assert(arp_is_waiting());
28145988daeSJoe Hershberger 
28245988daeSJoe Hershberger 	/* Validate response */
28345988daeSJoe Hershberger 	ut_assert(memcmp(eth->et_src, net_ethaddr, ARP_HLEN) == 0);
28445988daeSJoe Hershberger 	ut_assert(memcmp(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN) == 0);
28545988daeSJoe Hershberger 	ut_assert(eth->et_protlen == htons(PROT_ARP));
28645988daeSJoe Hershberger 
28745988daeSJoe Hershberger 	ut_assert(arp->ar_hrd == htons(ARP_ETHER));
28845988daeSJoe Hershberger 	ut_assert(arp->ar_pro == htons(PROT_IP));
28945988daeSJoe Hershberger 	ut_assert(arp->ar_hln == ARP_HLEN);
29045988daeSJoe Hershberger 	ut_assert(arp->ar_pln == ARP_PLEN);
29145988daeSJoe Hershberger 	ut_assert(memcmp(&arp->ar_sha, net_ethaddr, ARP_HLEN) == 0);
29245988daeSJoe Hershberger 	ut_assert(net_read_ip(&arp->ar_spa).s_addr == net_ip.s_addr);
29345988daeSJoe Hershberger 	ut_assert(memcmp(&arp->ar_tha, priv->fake_host_hwaddr, ARP_HLEN) == 0);
29445988daeSJoe Hershberger 	ut_assert(net_read_ip(&arp->ar_tpa).s_addr ==
29545988daeSJoe Hershberger 		  string_to_ip("1.1.2.4").s_addr);
29645988daeSJoe Hershberger 
29745988daeSJoe Hershberger 	return 0;
29845988daeSJoe Hershberger }
29945988daeSJoe Hershberger 
sb_with_async_arp_handler(struct udevice * dev,void * packet,unsigned int len)30045988daeSJoe Hershberger static int sb_with_async_arp_handler(struct udevice *dev, void *packet,
30145988daeSJoe Hershberger 				     unsigned int len)
30245988daeSJoe Hershberger {
30345988daeSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
30445988daeSJoe Hershberger 	struct ethernet_hdr *eth = packet;
30545988daeSJoe Hershberger 	struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
30645988daeSJoe Hershberger 	int ret;
30745988daeSJoe Hershberger 
30845988daeSJoe Hershberger 	/*
30945988daeSJoe Hershberger 	 * If we are about to generate a reply to ARP, first inject a request
31045988daeSJoe Hershberger 	 * from another host
31145988daeSJoe Hershberger 	 */
31245988daeSJoe Hershberger 	if (ntohs(eth->et_protlen) == PROT_ARP &&
31345988daeSJoe Hershberger 	    ntohs(arp->ar_op) == ARPOP_REQUEST) {
31445988daeSJoe Hershberger 		/* Make sure sandbox_eth_recv_arp_req() knows who is asking */
31545988daeSJoe Hershberger 		priv->fake_host_ipaddr = string_to_ip("1.1.2.4");
31645988daeSJoe Hershberger 
31745988daeSJoe Hershberger 		ret = sandbox_eth_recv_arp_req(dev);
31845988daeSJoe Hershberger 		if (ret)
31945988daeSJoe Hershberger 			return ret;
32045988daeSJoe Hershberger 	}
32145988daeSJoe Hershberger 
32245988daeSJoe Hershberger 	sandbox_eth_arp_req_to_reply(dev, packet, len);
32345988daeSJoe Hershberger 	sandbox_eth_ping_req_to_reply(dev, packet, len);
32445988daeSJoe Hershberger 
32545988daeSJoe Hershberger 	return sb_check_arp_reply(dev, packet, len);
32645988daeSJoe Hershberger }
32745988daeSJoe Hershberger 
dm_test_eth_async_arp_reply(struct unit_test_state * uts)32845988daeSJoe Hershberger static int dm_test_eth_async_arp_reply(struct unit_test_state *uts)
32945988daeSJoe Hershberger {
33045988daeSJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
33145988daeSJoe Hershberger 
33245988daeSJoe Hershberger 	sandbox_eth_set_tx_handler(0, sb_with_async_arp_handler);
33345988daeSJoe Hershberger 	/* Used by all of the ut_assert macros in the tx_handler */
33445988daeSJoe Hershberger 	sandbox_eth_set_priv(0, uts);
33545988daeSJoe Hershberger 
33645988daeSJoe Hershberger 	env_set("ethact", "eth@10002000");
337ac3f26ccSJoe Hershberger 	ut_assertok(net_loop(PING));
33845988daeSJoe Hershberger 	ut_asserteq_str("eth@10002000", env_get("ethact"));
33945988daeSJoe Hershberger 
34045988daeSJoe Hershberger 	sandbox_eth_set_tx_handler(0, NULL);
34145988daeSJoe Hershberger 
34245988daeSJoe Hershberger 	return 0;
34345988daeSJoe Hershberger }
34445988daeSJoe Hershberger 
34545988daeSJoe Hershberger DM_TEST(dm_test_eth_async_arp_reply, DM_TESTF_SCAN_FDT);
34672ff0042SJoe Hershberger 
sb_check_ping_reply(struct udevice * dev,void * packet,unsigned int len)34772ff0042SJoe Hershberger static int sb_check_ping_reply(struct udevice *dev, void *packet,
34872ff0042SJoe Hershberger 			       unsigned int len)
34972ff0042SJoe Hershberger {
35072ff0042SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
35172ff0042SJoe Hershberger 	struct ethernet_hdr *eth = packet;
35272ff0042SJoe Hershberger 	struct ip_udp_hdr *ip;
35372ff0042SJoe Hershberger 	struct icmp_hdr *icmp;
35472ff0042SJoe Hershberger 	/* Used by all of the ut_assert macros */
35572ff0042SJoe Hershberger 	struct unit_test_state *uts = priv->priv;
35672ff0042SJoe Hershberger 
35772ff0042SJoe Hershberger 	if (ntohs(eth->et_protlen) != PROT_IP)
35872ff0042SJoe Hershberger 		return 0;
35972ff0042SJoe Hershberger 
36072ff0042SJoe Hershberger 	ip = packet + ETHER_HDR_SIZE;
36172ff0042SJoe Hershberger 
36272ff0042SJoe Hershberger 	if (ip->ip_p != IPPROTO_ICMP)
36372ff0042SJoe Hershberger 		return 0;
36472ff0042SJoe Hershberger 
36572ff0042SJoe Hershberger 	icmp = (struct icmp_hdr *)&ip->udp_src;
36672ff0042SJoe Hershberger 
36772ff0042SJoe Hershberger 	if (icmp->type != ICMP_ECHO_REPLY)
36872ff0042SJoe Hershberger 		return 0;
36972ff0042SJoe Hershberger 
37072ff0042SJoe Hershberger 	/* This test would be worthless if we are not waiting */
37172ff0042SJoe Hershberger 	ut_assert(arp_is_waiting());
37272ff0042SJoe Hershberger 
37372ff0042SJoe Hershberger 	/* Validate response */
37472ff0042SJoe Hershberger 	ut_assert(memcmp(eth->et_src, net_ethaddr, ARP_HLEN) == 0);
37572ff0042SJoe Hershberger 	ut_assert(memcmp(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN) == 0);
37672ff0042SJoe Hershberger 	ut_assert(eth->et_protlen == htons(PROT_IP));
37772ff0042SJoe Hershberger 
37872ff0042SJoe Hershberger 	ut_assert(net_read_ip(&ip->ip_src).s_addr == net_ip.s_addr);
37972ff0042SJoe Hershberger 	ut_assert(net_read_ip(&ip->ip_dst).s_addr ==
38072ff0042SJoe Hershberger 		  string_to_ip("1.1.2.4").s_addr);
38172ff0042SJoe Hershberger 
38272ff0042SJoe Hershberger 	return 0;
38372ff0042SJoe Hershberger }
38472ff0042SJoe Hershberger 
sb_with_async_ping_handler(struct udevice * dev,void * packet,unsigned int len)38572ff0042SJoe Hershberger static int sb_with_async_ping_handler(struct udevice *dev, void *packet,
38672ff0042SJoe Hershberger 				      unsigned int len)
38772ff0042SJoe Hershberger {
38872ff0042SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
38972ff0042SJoe Hershberger 	struct ethernet_hdr *eth = packet;
39072ff0042SJoe Hershberger 	struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
39172ff0042SJoe Hershberger 	int ret;
39272ff0042SJoe Hershberger 
39372ff0042SJoe Hershberger 	/*
39472ff0042SJoe Hershberger 	 * If we are about to generate a reply to ARP, first inject a request
39572ff0042SJoe Hershberger 	 * from another host
39672ff0042SJoe Hershberger 	 */
39772ff0042SJoe Hershberger 	if (ntohs(eth->et_protlen) == PROT_ARP &&
39872ff0042SJoe Hershberger 	    ntohs(arp->ar_op) == ARPOP_REQUEST) {
39972ff0042SJoe Hershberger 		/* Make sure sandbox_eth_recv_arp_req() knows who is asking */
40072ff0042SJoe Hershberger 		priv->fake_host_ipaddr = string_to_ip("1.1.2.4");
40172ff0042SJoe Hershberger 
40272ff0042SJoe Hershberger 		ret = sandbox_eth_recv_ping_req(dev);
40372ff0042SJoe Hershberger 		if (ret)
40472ff0042SJoe Hershberger 			return ret;
40572ff0042SJoe Hershberger 	}
40672ff0042SJoe Hershberger 
40772ff0042SJoe Hershberger 	sandbox_eth_arp_req_to_reply(dev, packet, len);
40872ff0042SJoe Hershberger 	sandbox_eth_ping_req_to_reply(dev, packet, len);
40972ff0042SJoe Hershberger 
41072ff0042SJoe Hershberger 	return sb_check_ping_reply(dev, packet, len);
41172ff0042SJoe Hershberger }
41272ff0042SJoe Hershberger 
dm_test_eth_async_ping_reply(struct unit_test_state * uts)41372ff0042SJoe Hershberger static int dm_test_eth_async_ping_reply(struct unit_test_state *uts)
41472ff0042SJoe Hershberger {
41572ff0042SJoe Hershberger 	net_ping_ip = string_to_ip("1.1.2.2");
41672ff0042SJoe Hershberger 
41772ff0042SJoe Hershberger 	sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler);
41872ff0042SJoe Hershberger 	/* Used by all of the ut_assert macros in the tx_handler */
41972ff0042SJoe Hershberger 	sandbox_eth_set_priv(0, uts);
42072ff0042SJoe Hershberger 
42172ff0042SJoe Hershberger 	env_set("ethact", "eth@10002000");
422ac3f26ccSJoe Hershberger 	ut_assertok(net_loop(PING));
42372ff0042SJoe Hershberger 	ut_asserteq_str("eth@10002000", env_get("ethact"));
42472ff0042SJoe Hershberger 
42572ff0042SJoe Hershberger 	sandbox_eth_set_tx_handler(0, NULL);
42672ff0042SJoe Hershberger 
42772ff0042SJoe Hershberger 	return 0;
42872ff0042SJoe Hershberger }
42972ff0042SJoe Hershberger 
43072ff0042SJoe Hershberger DM_TEST(dm_test_eth_async_ping_reply, DM_TESTF_SCAN_FDT);
431