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