1 // 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 <command.h>
10 #include <dm.h>
11 #include <env.h>
12 #include <fdtdec.h>
13 #include <log.h>
14 #include <malloc.h>
15 #include <net.h>
16 #include <net/tcp.h>
17 #include <net/wget.h>
18 #include <asm/eth.h>
19 #include <dm/test.h>
20 #include <dm/device-internal.h>
21 #include <dm/uclass-internal.h>
22 #include <test/cmd.h>
23 #include <test/test.h>
24 #include <test/ut.h>
25
26 #define SHIFT_TO_TCPHDRLEN_FIELD(x) ((x) << 4)
27 #define LEN_B_TO_DW(x) ((x) >> 2)
28 #define GET_TCP_HDR_LEN_IN_BYTES(x) ((x) >> 2)
29
sb_arp_handler(struct udevice * dev,void * packet,unsigned int len)30 static 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
sb_syn_handler(struct udevice * dev,void * packet,unsigned int len)50 static 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 priv->irs = ntohl(tcp->tcp_seq);
67 priv->iss = ~priv->irs; /* just to differ from irs */
68 eth_send->et_protlen = htons(PROT_IP);
69 tcp_send = (void *)eth_send + ETHER_HDR_SIZE;
70 tcp_send->tcp_src = tcp->tcp_dst;
71 tcp_send->tcp_dst = tcp->tcp_src;
72 tcp_send->tcp_seq = htonl(priv->iss);
73 tcp_send->tcp_ack = htonl(priv->irs + 1);
74 tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
75 tcp_send->tcp_flags = TCP_SYN | TCP_ACK;
76 tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
77 tcp_send->tcp_xsum = 0;
78 tcp_send->tcp_ugr = 0;
79 tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send,
80 tcp->ip_src,
81 tcp->ip_dst,
82 TCP_HDR_SIZE,
83 IP_TCP_HDR_SIZE);
84 net_set_ip_header((uchar *)tcp_send,
85 tcp->ip_src,
86 tcp->ip_dst,
87 IP_TCP_HDR_SIZE,
88 IPPROTO_TCP);
89
90 priv->recv_packet_length[priv->recv_packets] =
91 ETHER_HDR_SIZE + IP_TCP_HDR_SIZE;
92 ++priv->recv_packets;
93
94 return 0;
95 }
96
sb_ack_handler(struct udevice * dev,void * packet,unsigned int len)97 static int sb_ack_handler(struct udevice *dev, void *packet,
98 unsigned int len)
99 {
100 struct eth_sandbox_priv *priv = dev_get_priv(dev);
101 struct ethernet_hdr *eth = packet;
102 struct ip_tcp_hdr *tcp = packet + ETHER_HDR_SIZE;
103 struct ethernet_hdr *eth_send;
104 struct ip_tcp_hdr *tcp_send;
105 void *data;
106 int pkt_len;
107 int payload_len = 0;
108 u32 tcp_seq, tcp_ack;
109 int tcp_data_len;
110 const char *payload1 =
111 /* response status line */
112 "HTTP/1.1 200 OK\r\n"
113 /* response header fields */
114 "Date: Mon, 23 Dec 2024 05:18:23 GMT\r\n"
115 "Server: Apache/2.4.62 (Debian)\r\n"
116 "Last-Modified: Mon, 23 Dec 2024 05:04:50 GMT\r\n"
117 "ETag: \"1d-629e8efb09e7b\"\r\n"
118 "Accept-Ranges: bytes\r\n"
119 "Content-Length: 29\r\n"
120 "Connection: close\r\n"
121 "Content-Type: text/html\r\n"
122 /* response header fields end marker */
123 "\r\n"
124 /* file data (for HTTP GET requests) */
125 "<html><body>Hi</body></html>\n";
126
127 /* Don't allow the buffer to overrun */
128 if (priv->recv_packets >= PKTBUFSRX)
129 return 0;
130
131 eth_send = (void *)priv->recv_packet_buffer[priv->recv_packets];
132 memcpy(eth_send->et_dest, eth->et_src, ARP_HLEN);
133 memcpy(eth_send->et_src, priv->fake_host_hwaddr, ARP_HLEN);
134 eth_send->et_protlen = htons(PROT_IP);
135 tcp_send = (void *)eth_send + ETHER_HDR_SIZE;
136 tcp_send->tcp_src = tcp->tcp_dst;
137 tcp_send->tcp_dst = tcp->tcp_src;
138 data = (void *)tcp_send + IP_TCP_HDR_SIZE;
139
140 tcp_seq = ntohl(tcp->tcp_seq) - priv->irs;
141 tcp_ack = ntohl(tcp->tcp_ack) - priv->iss;
142 tcp_data_len = len - ETHER_HDR_SIZE - IP_HDR_SIZE - GET_TCP_HDR_LEN_IN_BYTES(tcp->tcp_hlen);
143
144 if (tcp->tcp_flags & TCP_FIN)
145 tcp_data_len++;
146
147 tcp_send->tcp_seq = htonl(ntohl(tcp->tcp_ack));
148 tcp_send->tcp_ack = htonl(ntohl(tcp->tcp_seq) + tcp_data_len);
149
150 if (tcp_seq == 1 && tcp_ack == 1) {
151 if (tcp_data_len == 0) {
152 /* no data, wait for GET/HEAD request */
153 return -1;
154 }
155
156 /* reply to GET/HEAD request */
157 payload_len = strlen(payload1);
158 memcpy(data, payload1, payload_len);
159 tcp_send->tcp_flags = TCP_ACK;
160 } else if (tcp_ack == 1 + strlen(payload1)) {
161 payload_len = 0;
162 tcp_send->tcp_flags = TCP_ACK | TCP_FIN;
163 } else if (tcp_ack == 2 + strlen(payload1)) {
164 payload_len = 0;
165 tcp_send->tcp_flags = TCP_ACK;
166 }
167
168 tcp_send->tcp_hlen = SHIFT_TO_TCPHDRLEN_FIELD(LEN_B_TO_DW(TCP_HDR_SIZE));
169 tcp_send->tcp_win = htons(PKTBUFSRX * TCP_MSS >> TCP_SCALE);
170 tcp_send->tcp_xsum = 0;
171 tcp_send->tcp_ugr = 0;
172 pkt_len = IP_TCP_HDR_SIZE + payload_len;
173 tcp_send->tcp_xsum = tcp_set_pseudo_header((uchar *)tcp_send,
174 tcp->ip_src,
175 tcp->ip_dst,
176 pkt_len - IP_HDR_SIZE,
177 pkt_len);
178 net_set_ip_header((uchar *)tcp_send,
179 tcp->ip_src,
180 tcp->ip_dst,
181 pkt_len,
182 IPPROTO_TCP);
183
184 priv->recv_packet_length[priv->recv_packets] =
185 ETHER_HDR_SIZE + IP_TCP_HDR_SIZE + payload_len;
186 ++priv->recv_packets;
187
188 return 0;
189 }
190
sb_http_handler(struct udevice * dev,void * packet,unsigned int len)191 static int sb_http_handler(struct udevice *dev, void *packet,
192 unsigned int len)
193 {
194 struct ethernet_hdr *eth = packet;
195 struct ip_hdr *ip;
196 struct ip_tcp_hdr *tcp;
197
198 if (ntohs(eth->et_protlen) == PROT_ARP) {
199 return sb_arp_handler(dev, packet, len);
200 } else if (ntohs(eth->et_protlen) == PROT_IP) {
201 ip = packet + ETHER_HDR_SIZE;
202 if (ip->ip_p == IPPROTO_TCP) {
203 tcp = packet + ETHER_HDR_SIZE;
204 if (tcp->tcp_flags == TCP_SYN)
205 return sb_syn_handler(dev, packet, len);
206 else if (tcp->tcp_flags & TCP_ACK && !(tcp->tcp_flags & TCP_SYN))
207 return sb_ack_handler(dev, packet, len);
208 return 0;
209 }
210 return -EPROTONOSUPPORT;
211 }
212
213 return -EPROTONOSUPPORT;
214 }
215
net_test_wget(struct unit_test_state * uts)216 static int net_test_wget(struct unit_test_state *uts)
217 {
218 char *prev_ethact = env_get("ethact");
219 char *prev_ethrotate = env_get("ethrotate");
220
221 sandbox_eth_set_tx_handler(0, sb_http_handler);
222 sandbox_eth_set_priv(0, uts);
223
224 env_set("ethact", "eth@10002000");
225 env_set("ethrotate", "no");
226 env_set("wgetaddr", "0x20000");
227 ut_assertok(run_command("wget ${wgetaddr} 1.1.2.2:/index.html", 0));
228 ut_assert_nextline_empty();
229 ut_assert_nextline("Packets received 5, Transfer Successful");
230 ut_assert_nextline("Bytes transferred = 29 (1d hex)");
231
232 sandbox_eth_set_tx_handler(0, NULL);
233
234 run_command("md5sum ${wgetaddr} ${filesize}", 0);
235 ut_assert_nextline("md5 for 00020000 ... 0002001c ==> 847d5e7320a27462e90bc1ed75eb8cd8");
236 ut_assert_console_end();
237
238 env_set("ethact", prev_ethact);
239 env_set("ethrotate", prev_ethrotate);
240
241 return 0;
242 }
243 CMD_TEST(net_test_wget, UTF_CONSOLE);
244
net_test_wget_uri_validate(struct unit_test_state * uts)245 static int net_test_wget_uri_validate(struct unit_test_state *uts)
246 {
247 ut_asserteq(true, wget_validate_uri("http://foo.com/bar.html"));
248 ut_asserteq(true, wget_validate_uri("http://1.1.2.3/bar.html"));
249 ut_asserteq(false, wget_validate_uri("http://foo/ba r.html"));
250 ut_asserteq(false, wget_validate_uri("http://"));
251
252 if (CONFIG_IS_ENABLED(WGET_HTTPS)) {
253 ut_asserteq(true,
254 wget_validate_uri("https://foo.com/bar.html"));
255 ut_asserteq(true,
256 wget_validate_uri("https://1.1.2.3/bar.html"));
257 ut_asserteq(false, wget_validate_uri("https://foo/ba r.html"));
258 ut_asserteq(false, wget_validate_uri("https://"));
259 }
260
261 return 0;
262 }
263 CMD_TEST(net_test_wget_uri_validate, UTF_CONSOLE);
264