[U-Boot] [PATCH v2 09/10] test: eth: Add a test for the target being pinged
Joe Hershberger
joe.hershberger at ni.com
Wed Sep 26 21:49:01 UTC 2018
The target will respond to pings while doing other network handling.
Make sure that the response happens and is correct.
This currently corrupts the ongoing operation of the device if it
happens to be awaiting an ARP reply of its own to whatever serverip it
is attempting to communicate with. In the test, add an expectation that
the user operation (ping, in this case) will fail. A later patch will
address this problem.
Signed-off-by: Joe Hershberger <joe.hershberger at ni.com>
Reviewed-by: Simon Glass <sjg at chromium.org>
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>
---
Changes in v2:
- add comments as to the use of the uts variable
- check the return of the injection handler and pass on overflow error
- return an error instead of 0 / 1
arch/sandbox/include/asm/eth.h | 10 +++++
drivers/net/sandbox.c | 51 +++++++++++++++++++++++++
test/dm/eth.c | 86 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 147 insertions(+)
diff --git a/arch/sandbox/include/asm/eth.h b/arch/sandbox/include/asm/eth.h
index d068486f0b..477fa00fad 100644
--- a/arch/sandbox/include/asm/eth.h
+++ b/arch/sandbox/include/asm/eth.h
@@ -49,6 +49,16 @@ int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
*/
int sandbox_eth_recv_arp_req(struct udevice *dev);
+/*
+ * sandbox_eth_recv_ping_req()
+ *
+ * Inject a ping request for this target
+ *
+ * @dev: device that received the packet
+ * @return 0 if injected, -EOVERFLOW if not
+ */
+int sandbox_eth_recv_ping_req(struct udevice *dev);
+
/**
* A packet handler
*
diff --git a/drivers/net/sandbox.c b/drivers/net/sandbox.c
index 81f0764fa6..decce2fa59 100644
--- a/drivers/net/sandbox.c
+++ b/drivers/net/sandbox.c
@@ -202,6 +202,57 @@ int sandbox_eth_recv_arp_req(struct udevice *dev)
}
/*
+ * sandbox_eth_recv_ping_req()
+ *
+ * Inject a ping request for this target
+ *
+ * returns 0 if injected, -EOVERFLOW if not
+ */
+int sandbox_eth_recv_ping_req(struct udevice *dev)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+ struct ethernet_hdr *eth_recv;
+ struct ip_udp_hdr *ipr;
+ struct icmp_hdr *icmpr;
+
+ /* Don't allow the buffer to overrun */
+ if (priv->recv_packets >= PKTBUFSRX)
+ return -EOVERFLOW;
+
+ /* Formulate a fake ping */
+ eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
+
+ memcpy(eth_recv->et_dest, net_ethaddr, ARP_HLEN);
+ memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
+ eth_recv->et_protlen = htons(PROT_IP);
+
+ ipr = (void *)eth_recv + ETHER_HDR_SIZE;
+ ipr->ip_hl_v = 0x45;
+ ipr->ip_len = htons(IP_ICMP_HDR_SIZE);
+ ipr->ip_off = htons(IP_FLAGS_DFRAG);
+ ipr->ip_p = IPPROTO_ICMP;
+ ipr->ip_sum = 0;
+ net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr);
+ net_write_ip(&ipr->ip_dst, net_ip);
+ ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
+
+ icmpr = (struct icmp_hdr *)&ipr->udp_src;
+
+ icmpr->type = ICMP_ECHO_REQUEST;
+ icmpr->code = 0;
+ icmpr->checksum = 0;
+ icmpr->un.echo.id = 0;
+ icmpr->un.echo.sequence = htons(1);
+ icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
+
+ priv->recv_packet_length[priv->recv_packets] =
+ ETHER_HDR_SIZE + IP_ICMP_HDR_SIZE;
+ ++priv->recv_packets;
+
+ return 0;
+}
+
+/*
* sb_default_handler()
*
* perform typical responses to simple ping
diff --git a/test/dm/eth.c b/test/dm/eth.c
index 9e52d5cdfe..86482e9755 100644
--- a/test/dm/eth.c
+++ b/test/dm/eth.c
@@ -344,3 +344,89 @@ static int dm_test_eth_async_arp_reply(struct unit_test_state *uts)
}
DM_TEST(dm_test_eth_async_arp_reply, DM_TESTF_SCAN_FDT);
+
+static int sb_check_ping_reply(struct udevice *dev, void *packet,
+ unsigned int len)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+ struct ethernet_hdr *eth = packet;
+ struct ip_udp_hdr *ip;
+ struct icmp_hdr *icmp;
+ /* Used by all of the ut_assert macros */
+ struct unit_test_state *uts = priv->priv;
+
+ if (ntohs(eth->et_protlen) != PROT_IP)
+ return 0;
+
+ ip = packet + ETHER_HDR_SIZE;
+
+ if (ip->ip_p != IPPROTO_ICMP)
+ return 0;
+
+ icmp = (struct icmp_hdr *)&ip->udp_src;
+
+ if (icmp->type != ICMP_ECHO_REPLY)
+ return 0;
+
+ /* This test would be worthless if we are not waiting */
+ ut_assert(arp_is_waiting());
+
+ /* Validate response */
+ ut_assert(memcmp(eth->et_src, net_ethaddr, ARP_HLEN) == 0);
+ ut_assert(memcmp(eth->et_dest, priv->fake_host_hwaddr, ARP_HLEN) == 0);
+ ut_assert(eth->et_protlen == htons(PROT_IP));
+
+ ut_assert(net_read_ip(&ip->ip_src).s_addr == net_ip.s_addr);
+ ut_assert(net_read_ip(&ip->ip_dst).s_addr ==
+ string_to_ip("1.1.2.4").s_addr);
+
+ return 0;
+}
+
+static int sb_with_async_ping_handler(struct udevice *dev, void *packet,
+ unsigned int len)
+{
+ struct eth_sandbox_priv *priv = dev_get_priv(dev);
+ struct ethernet_hdr *eth = packet;
+ struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
+ int ret;
+
+ /*
+ * If we are about to generate a reply to ARP, first inject a request
+ * from another host
+ */
+ if (ntohs(eth->et_protlen) == PROT_ARP &&
+ ntohs(arp->ar_op) == ARPOP_REQUEST) {
+ /* Make sure sandbox_eth_recv_arp_req() knows who is asking */
+ priv->fake_host_ipaddr = string_to_ip("1.1.2.4");
+
+ ret = sandbox_eth_recv_ping_req(dev);
+ if (ret)
+ return ret;
+ }
+
+ sandbox_eth_arp_req_to_reply(dev, packet, len);
+ sandbox_eth_ping_req_to_reply(dev, packet, len);
+
+ return sb_check_ping_reply(dev, packet, len);
+}
+
+static int dm_test_eth_async_ping_reply(struct unit_test_state *uts)
+{
+ net_ping_ip = string_to_ip("1.1.2.2");
+
+ sandbox_eth_set_tx_handler(0, sb_with_async_ping_handler);
+ /* Used by all of the ut_assert macros in the tx_handler */
+ sandbox_eth_set_priv(0, uts);
+ sandbox_eth_skip_timeout();
+
+ env_set("ethact", "eth at 10002000");
+ ut_assert(net_loop(PING) == -ETIMEDOUT);
+ ut_asserteq_str("eth at 10002000", env_get("ethact"));
+
+ sandbox_eth_set_tx_handler(0, NULL);
+
+ return 0;
+}
+
+DM_TEST(dm_test_eth_async_ping_reply, DM_TESTF_SCAN_FDT);
--
2.11.0
More information about the U-Boot
mailing list