blob: ed83fc94a5e21522b54c14b46f1b81a0201ad32e [file] [log] [blame]
Ying-Chun Liu (PaulLiu)d6abc7e2022-11-08 14:17:31 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2022 Linaro
4 *
5 * (C) Copyright 2022
6 * Ying-Chun Liu (PaulLiu) <paul.liu@linaro.org>
7 */
8
9#include <common.h>
10#include <command.h>
11#include <dm.h>
12#include <env.h>
13#include <fdtdec.h>
14#include <log.h>
15#include <malloc.h>
16#include <net.h>
17#include <net/tcp.h>
18#include <net/wget.h>
19#include <asm/eth.h>
20#include <dm/test.h>
21#include <dm/device-internal.h>
22#include <dm/uclass-internal.h>
23#include <test/lib.h>
24#include <test/test.h>
25#include <test/ut.h>
26
27#define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4)
28#define LEN_B_TO_DW(x) ((x) >> 2)
29
30static int sb_arp_handler(struct udevice *dev, void *packet,
31 unsigned int len)
32{
33 struct eth_sandbox_priv *priv = dev_get_priv(dev);
34 struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
35 int ret = 0;
36
37 if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
38 priv->fake_host_ipaddr = net_read_ip(&arp->ar_spa);
39
40 ret = sandbox_eth_recv_arp_req(dev);
41 if (ret)
42 return ret;
43 ret = sandbox_eth_arp_req_to_reply(dev, packet, len);
44 return ret;
45 }
46
47 return -EPROTONOSUPPORT;
48}
49
50static int sb_syn_handler(struct udevice *dev, void *packet,
51 unsigned int len)
52{
53 struct eth_sandbox_priv *priv = dev_get_priv(dev);
54 struct ethernet_hdr *eth = packet;
55 struct ip_tcp_hdr *tcp = packet + ETHER_HDR_SIZE;
56 struct ethernet_hdr *eth_send;
57 struct ip_tcp_hdr *tcp_send;
58
59 /* Don't allow the buffer to overrun */
60 if (priv->recv_packets >= PKTBUFSRX)
61 return 0;
62
63 eth_send = (void *)priv->recv_packet_buffer[priv->recv_packets];
64 memcpy(eth_send->et_dest, eth->et_src, ARP_HLEN);
65 memcpy(eth_send->et_src, priv->fake_host_hwaddr, ARP_HLEN);
66 eth_send->et_protlen = htons(PROT_IP);
67 tcp_send = (void *)eth_send + ETHER_HDR_SIZE;
68 tcp_send->tcp_src = tcp->tcp_dst;
69 tcp_send->tcp_dst = tcp->tcp_src;
70 tcp_send->tcp_seq = htonl(0);
71 tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1);
72 tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
73 tcp_send->tcp_flags = TCP_SYN | TCP_ACK;
74 tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
75 tcp_send->tcp_xsum = 0;
76 tcp_send->tcp_ugr = 0;
77 tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send,
78 tcp->ip_src,
79 tcp->ip_dst,
80 TCP_HDR_SIZE,
81 IP_TCP_HDR_SIZE);
82 net_set_ip_header((uchar *)tcp_send,
83 tcp->ip_src,
84 tcp->ip_dst,
85 IP_TCP_HDR_SIZE,
86 IPPROTO_TCP);
87
88 priv->recv_packet_length[priv->recv_packets] =
89 ETHER_HDR_SIZE + IP_TCP_HDR_SIZE;
90 ++priv->recv_packets;
91
92 return 0;
93}
94
95static int sb_ack_handler(struct udevice *dev, void *packet,
96 unsigned int len)
97{
98 struct eth_sandbox_priv *priv = dev_get_priv(dev);
99 struct ethernet_hdr *eth = packet;
100 struct ip_tcp_hdr *tcp = packet + ETHER_HDR_SIZE;
101 struct ethernet_hdr *eth_send;
102 struct ip_tcp_hdr *tcp_send;
103 void *data;
104 int pkt_len;
105 int payload_len = 0;
106 const char *payload1 = "HTTP/1.1 200 OK\r\n"
107 "Content-Length: 30\r\n\r\n\r\n"
108 "<html><body>Hi</body></html>\r\n";
109
110 /* Don't allow the buffer to overrun */
111 if (priv->recv_packets >= PKTBUFSRX)
112 return 0;
113
114 eth_send = (void *)priv->recv_packet_buffer[priv->recv_packets];
115 memcpy(eth_send->et_dest, eth->et_src, ARP_HLEN);
116 memcpy(eth_send->et_src, priv->fake_host_hwaddr, ARP_HLEN);
117 eth_send->et_protlen = htons(PROT_IP);
118 tcp_send = (void *)eth_send + ETHER_HDR_SIZE;
119 tcp_send->tcp_src = tcp->tcp_dst;
120 tcp_send->tcp_dst = tcp->tcp_src;
121 data = (void *)tcp_send + IP_TCP_HDR_SIZE;
122
123 if (ntohl(tcp->tcp_seq) == 1 && ntohl(tcp->tcp_ack) == 1) {
124 tcp_send->tcp_seq = htonl(ntohl(tcp->tcp_ack));
125 tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1);
126 payload_len = strlen(payload1);
127 memcpy(data, payload1, payload_len);
128 tcp_send->tcp_flags = TCP_ACK;
129 } else if (ntohl(tcp->tcp_seq) == 2) {
130 tcp_send->tcp_seq = htonl(ntohl(tcp->tcp_ack));
131 tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + 1);
132 payload_len = 0;
133 tcp_send->tcp_flags = TCP_ACK | TCP_FIN;
134 }
135
136 tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
137 tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
138 tcp_send->tcp_xsum = 0;
139 tcp_send->tcp_ugr = 0;
140 pkt_len = IP_TCP_HDR_SIZE + payload_len;
141 tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send,
142 tcp->ip_src,
143 tcp->ip_dst,
144 pkt_len - IP_HDR_SIZE,
145 pkt_len);
146 net_set_ip_header((uchar *)tcp_send,
147 tcp->ip_src,
148 tcp->ip_dst,
149 pkt_len,
150 IPPROTO_TCP);
151
152 if (ntohl(tcp->tcp_seq) == 1 || ntohl(tcp->tcp_seq) == 2) {
153 priv->recv_packet_length[priv->recv_packets] =
154 ETHER_HDR_SIZE + IP_TCP_HDR_SIZE + payload_len;
155 ++priv->recv_packets;
156 }
157
158 return 0;
159}
160
161static int sb_http_handler(struct udevice *dev, void *packet,
162 unsigned int len)
163{
164 struct ethernet_hdr *eth = packet;
165 struct ip_hdr *ip;
166 struct ip_tcp_hdr *tcp;
167
168 if (ntohs(eth->et_protlen) == PROT_ARP) {
169 return sb_arp_handler(dev, packet, len);
170 } else if (ntohs(eth->et_protlen) == PROT_IP) {
171 ip = packet + ETHER_HDR_SIZE;
172 if (ip->ip_p == IPPROTO_TCP) {
173 tcp = packet + ETHER_HDR_SIZE;
174 if (tcp->tcp_flags == TCP_SYN)
175 return sb_syn_handler(dev, packet, len);
176 else if (tcp->tcp_flags & TCP_ACK && !(tcp->tcp_flags & TCP_SYN))
177 return sb_ack_handler(dev, packet, len);
178 return 0;
179 }
180 return -EPROTONOSUPPORT;
181 }
182
183 return -EPROTONOSUPPORT;
184}
185
186static int net_test_wget(struct unit_test_state *uts)
187{
188 sandbox_eth_set_tx_handler(0, sb_http_handler);
189 sandbox_eth_set_priv(0, uts);
190
191 env_set("ethact", "eth@10002000");
192 env_set("ethrotate", "no");
193 env_set("loadaddr", "0x20000");
194 ut_assertok(run_command("wget ${loadaddr} 1.1.2.2:/index.html", 0));
195
196 sandbox_eth_set_tx_handler(0, NULL);
197
198 ut_assertok(console_record_reset_enable());
199 run_command("md5sum ${loadaddr} ${filesize}", 0);
200 ut_assert_nextline("md5 for 00020000 ... 0002001f ==> 234af48e94b0085060249ecb5942ab57");
201 ut_assertok(ut_check_console_end(uts));
202
203 return 0;
204}
205
206LIB_TEST(net_test_wget, 0);