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 <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); 207