From d6abc7e2e027956eb0b5e73bb2be5cf995b15ae6 Mon Sep 17 00:00:00 2001 From: "Ying-Chun Liu (PaulLiu)" Date: Tue, 8 Nov 2022 14:17:31 +0800 Subject: [PATCH] test: cmd: add test for wget command. Simulate a TCP HTTP server's response for testing wget command. Signed-off-by: Ying-Chun Liu (PaulLiu) Cc: Christian Gmeiner Cc: Joe Hershberger Cc: Michal Simek Cc: Ramon Fried Cc: Simon Glass Reviewed-by: Simon Glass Reviewed-by: Ramon Fried --- test/cmd/Makefile | 1 + test/cmd/wget.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 test/cmd/wget.c diff --git a/test/cmd/Makefile b/test/cmd/Makefile index 6dd6e81875..bc961df3dc 100644 --- a/test/cmd/Makefile +++ b/test/cmd/Makefile @@ -20,3 +20,4 @@ ifdef CONFIG_SANDBOX obj-$(CONFIG_CMD_SETEXPR) += setexpr.o endif obj-$(CONFIG_CMD_TEMPERATURE) += temperature.o +obj-$(CONFIG_CMD_WGET) += wget.o diff --git a/test/cmd/wget.c b/test/cmd/wget.c new file mode 100644 index 0000000000..ed83fc94a5 --- /dev/null +++ b/test/cmd/wget.c @@ -0,0 +1,206 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 Linaro + * + * (C) Copyright 2022 + * Ying-Chun Liu (PaulLiu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4) +#define LEN_B_TO_DW(x) ((x) >> 2) + +static int sb_arp_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct arp_hdr *arp = packet + ETHER_HDR_SIZE; + int ret = 0; + + if (ntohs(arp->ar_op) == ARPOP_REQUEST) { + priv->fake_host_ipaddr = net_read_ip(&arp->ar_spa); + + ret = sandbox_eth_recv_arp_req(dev); + if (ret) + return ret; + ret = sandbox_eth_arp_req_to_reply(dev, packet, len); + return ret; + } + + return -EPROTONOSUPPORT; +} + +static int sb_syn_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_tcp_hdr *tcp = packet + ETHER_HDR_SIZE; + struct ethernet_hdr *eth_send; + struct ip_tcp_hdr *tcp_send; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + eth_send = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_send->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_send->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_send->et_protlen = htons(PROT_IP); + tcp_send = (void *)eth_send + ETHER_HDR_SIZE; + tcp_send->tcp_src = tcp->tcp_dst; + tcp_send->tcp_dst = tcp->tcp_src; + tcp_send->tcp_seq = htonl(0); + tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1); + tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE)); + tcp_send->tcp_flags = TCP_SYN | TCP_ACK; + tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE); + tcp_send->tcp_xsum = 0; + tcp_send->tcp_ugr = 0; + tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send, + tcp->ip_src, + tcp->ip_dst, + TCP_HDR_SIZE, + IP_TCP_HDR_SIZE); + net_set_ip_header((uchar *)tcp_send, + tcp->ip_src, + tcp->ip_dst, + IP_TCP_HDR_SIZE, + IPPROTO_TCP); + + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + IP_TCP_HDR_SIZE; + ++priv->recv_packets; + + return 0; +} + +static int sb_ack_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct eth_sandbox_priv *priv = dev_get_priv(dev); + struct ethernet_hdr *eth = packet; + struct ip_tcp_hdr *tcp = packet + ETHER_HDR_SIZE; + struct ethernet_hdr *eth_send; + struct ip_tcp_hdr *tcp_send; + void *data; + int pkt_len; + int payload_len = 0; + const char *payload1 = "HTTP/1.1 200 OK\r\n" + "Content-Length: 30\r\n\r\n\r\n" + "Hi\r\n"; + + /* Don't allow the buffer to overrun */ + if (priv->recv_packets >= PKTBUFSRX) + return 0; + + eth_send = (void *)priv->recv_packet_buffer[priv->recv_packets]; + memcpy(eth_send->et_dest, eth->et_src, ARP_HLEN); + memcpy(eth_send->et_src, priv->fake_host_hwaddr, ARP_HLEN); + eth_send->et_protlen = htons(PROT_IP); + tcp_send = (void *)eth_send + ETHER_HDR_SIZE; + tcp_send->tcp_src = tcp->tcp_dst; + tcp_send->tcp_dst = tcp->tcp_src; + data = (void *)tcp_send + IP_TCP_HDR_SIZE; + + if (ntohl(tcp->tcp_seq) == 1 && ntohl(tcp->tcp_ack) == 1) { + tcp_send->tcp_seq = htonl(ntohl(tcp->tcp_ack)); + tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1); + payload_len = strlen(payload1); + memcpy(data, payload1, payload_len); + tcp_send->tcp_flags = TCP_ACK; + } else if (ntohl(tcp->tcp_seq) == 2) { + tcp_send->tcp_seq = htonl(ntohl(tcp->tcp_ack)); + tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1); + payload_len = 0; + tcp_send->tcp_flags = TCP_ACK | TCP_FIN; + } + + tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE)); + tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE); + tcp_send->tcp_xsum = 0; + tcp_send->tcp_ugr = 0; + pkt_len = IP_TCP_HDR_SIZE + payload_len; + tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send, + tcp->ip_src, + tcp->ip_dst, + pkt_len - IP_HDR_SIZE, + pkt_len); + net_set_ip_header((uchar *)tcp_send, + tcp->ip_src, + tcp->ip_dst, + pkt_len, + IPPROTO_TCP); + + if (ntohl(tcp->tcp_seq) == 1 || ntohl(tcp->tcp_seq) == 2) { + priv->recv_packet_length[priv->recv_packets] = + ETHER_HDR_SIZE + IP_TCP_HDR_SIZE + payload_len; + ++priv->recv_packets; + } + + return 0; +} + +static int sb_http_handler(struct udevice *dev, void *packet, + unsigned int len) +{ + struct ethernet_hdr *eth = packet; + struct ip_hdr *ip; + struct ip_tcp_hdr *tcp; + + if (ntohs(eth->et_protlen) == PROT_ARP) { + return sb_arp_handler(dev, packet, len); + } else if (ntohs(eth->et_protlen) == PROT_IP) { + ip = packet + ETHER_HDR_SIZE; + if (ip->ip_p == IPPROTO_TCP) { + tcp = packet + ETHER_HDR_SIZE; + if (tcp->tcp_flags == TCP_SYN) + return sb_syn_handler(dev, packet, len); + else if (tcp->tcp_flags & TCP_ACK && !(tcp->tcp_flags & TCP_SYN)) + return sb_ack_handler(dev, packet, len); + return 0; + } + return -EPROTONOSUPPORT; + } + + return -EPROTONOSUPPORT; +} + +static int net_test_wget(struct unit_test_state *uts) +{ + sandbox_eth_set_tx_handler(0, sb_http_handler); + sandbox_eth_set_priv(0, uts); + + env_set("ethact", "eth@10002000"); + env_set("ethrotate", "no"); + env_set("loadaddr", "0x20000"); + ut_assertok(run_command("wget ${loadaddr} 1.1.2.2:/index.html", 0)); + + sandbox_eth_set_tx_handler(0, NULL); + + ut_assertok(console_record_reset_enable()); + run_command("md5sum ${loadaddr} ${filesize}", 0); + ut_assert_nextline("md5 for 00020000 ... 0002001f ==> 234af48e94b0085060249ecb5942ab57"); + ut_assertok(ut_check_console_end(uts)); + + return 0; +} + +LIB_TEST(net_test_wget, 0);