xref: /openbmc/u-boot/drivers/net/sandbox.c (revision 0223462b373b975d970fa86e5e1a7eadd1d41820)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
23ea143abSJoe Hershberger /*
33ea143abSJoe Hershberger  * Copyright (c) 2015 National Instruments
43ea143abSJoe Hershberger  *
53ea143abSJoe Hershberger  * (C) Copyright 2015
63ea143abSJoe Hershberger  * Joe Hershberger <joe.hershberger@ni.com>
73ea143abSJoe Hershberger  */
83ea143abSJoe Hershberger 
93ea143abSJoe Hershberger #include <common.h>
103ea143abSJoe Hershberger #include <dm.h>
113ea143abSJoe Hershberger #include <malloc.h>
123ea143abSJoe Hershberger #include <net.h>
13c7eb733dSJoe Hershberger #include <asm/eth.h>
146f2707c6SJoe Hershberger #include <asm/test.h>
153ea143abSJoe Hershberger 
163ea143abSJoe Hershberger DECLARE_GLOBAL_DATA_PTR;
173ea143abSJoe Hershberger 
186f2707c6SJoe Hershberger static bool skip_timeout;
192eede1f3SJoe Hershberger 
202eede1f3SJoe Hershberger /*
212eede1f3SJoe Hershberger  * sandbox_eth_disable_response()
222eede1f3SJoe Hershberger  *
232eede1f3SJoe Hershberger  * index - The alias index (also DM seq number)
242eede1f3SJoe Hershberger  * disable - If non-zero, ignore sent packets and don't send mock response
252eede1f3SJoe Hershberger  */
sandbox_eth_disable_response(int index,bool disable)262eede1f3SJoe Hershberger void sandbox_eth_disable_response(int index, bool disable)
272eede1f3SJoe Hershberger {
28e4ab9a65SJoe Hershberger 	struct udevice *dev;
29e4ab9a65SJoe Hershberger 	struct eth_sandbox_priv *priv;
30e4ab9a65SJoe Hershberger 	int ret;
31e4ab9a65SJoe Hershberger 
32e4ab9a65SJoe Hershberger 	ret = uclass_get_device(UCLASS_ETH, index, &dev);
33e4ab9a65SJoe Hershberger 	if (ret)
34e4ab9a65SJoe Hershberger 		return;
35e4ab9a65SJoe Hershberger 
36e4ab9a65SJoe Hershberger 	priv = dev_get_priv(dev);
37e4ab9a65SJoe Hershberger 	priv->disabled = disable;
382eede1f3SJoe Hershberger }
392eede1f3SJoe Hershberger 
406f2707c6SJoe Hershberger /*
416f2707c6SJoe Hershberger  * sandbox_eth_skip_timeout()
426f2707c6SJoe Hershberger  *
436f2707c6SJoe Hershberger  * When the first packet read is attempted, fast-forward time
446f2707c6SJoe Hershberger  */
sandbox_eth_skip_timeout(void)456f2707c6SJoe Hershberger void sandbox_eth_skip_timeout(void)
466f2707c6SJoe Hershberger {
476f2707c6SJoe Hershberger 	skip_timeout = true;
486f2707c6SJoe Hershberger }
496f2707c6SJoe Hershberger 
50e95bb161SJoe Hershberger /*
51e95bb161SJoe Hershberger  * sandbox_eth_arp_req_to_reply()
52e95bb161SJoe Hershberger  *
53e95bb161SJoe Hershberger  * Check for an arp request to be sent. If so, inject a reply
54e95bb161SJoe Hershberger  *
55e95bb161SJoe Hershberger  * returns 0 if injected, -EAGAIN if not
56e95bb161SJoe Hershberger  */
sandbox_eth_arp_req_to_reply(struct udevice * dev,void * packet,unsigned int len)57e95bb161SJoe Hershberger int sandbox_eth_arp_req_to_reply(struct udevice *dev, void *packet,
58e95bb161SJoe Hershberger 				 unsigned int len)
59e95bb161SJoe Hershberger {
60e95bb161SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
61e95bb161SJoe Hershberger 	struct ethernet_hdr *eth = packet;
62e95bb161SJoe Hershberger 	struct arp_hdr *arp;
63e95bb161SJoe Hershberger 	struct ethernet_hdr *eth_recv;
64e95bb161SJoe Hershberger 	struct arp_hdr *arp_recv;
65e95bb161SJoe Hershberger 
66e95bb161SJoe Hershberger 	if (ntohs(eth->et_protlen) != PROT_ARP)
67e95bb161SJoe Hershberger 		return -EAGAIN;
68e95bb161SJoe Hershberger 
69e95bb161SJoe Hershberger 	arp = packet + ETHER_HDR_SIZE;
70e95bb161SJoe Hershberger 
71e95bb161SJoe Hershberger 	if (ntohs(arp->ar_op) != ARPOP_REQUEST)
72e95bb161SJoe Hershberger 		return -EAGAIN;
73e95bb161SJoe Hershberger 
74c67a4207SJoe Hershberger 	/* Don't allow the buffer to overrun */
75c67a4207SJoe Hershberger 	if (priv->recv_packets >= PKTBUFSRX)
76c67a4207SJoe Hershberger 		return 0;
77c67a4207SJoe Hershberger 
78e95bb161SJoe Hershberger 	/* store this as the assumed IP of the fake host */
79e95bb161SJoe Hershberger 	priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
80e95bb161SJoe Hershberger 
81e95bb161SJoe Hershberger 	/* Formulate a fake response */
82c67a4207SJoe Hershberger 	eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
83e95bb161SJoe Hershberger 	memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
84e95bb161SJoe Hershberger 	memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
85e95bb161SJoe Hershberger 	eth_recv->et_protlen = htons(PROT_ARP);
86e95bb161SJoe Hershberger 
87e95bb161SJoe Hershberger 	arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
88e95bb161SJoe Hershberger 	arp_recv->ar_hrd = htons(ARP_ETHER);
89e95bb161SJoe Hershberger 	arp_recv->ar_pro = htons(PROT_IP);
90e95bb161SJoe Hershberger 	arp_recv->ar_hln = ARP_HLEN;
91e95bb161SJoe Hershberger 	arp_recv->ar_pln = ARP_PLEN;
92e95bb161SJoe Hershberger 	arp_recv->ar_op = htons(ARPOP_REPLY);
93e95bb161SJoe Hershberger 	memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
94e95bb161SJoe Hershberger 	net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
95e95bb161SJoe Hershberger 	memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
96e95bb161SJoe Hershberger 	net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
97e95bb161SJoe Hershberger 
98c67a4207SJoe Hershberger 	priv->recv_packet_length[priv->recv_packets] =
99c67a4207SJoe Hershberger 		ETHER_HDR_SIZE + ARP_HDR_SIZE;
100c67a4207SJoe Hershberger 	++priv->recv_packets;
101e95bb161SJoe Hershberger 
102e95bb161SJoe Hershberger 	return 0;
103e95bb161SJoe Hershberger }
104e95bb161SJoe Hershberger 
105e95bb161SJoe Hershberger /*
106e95bb161SJoe Hershberger  * sandbox_eth_ping_req_to_reply()
107e95bb161SJoe Hershberger  *
108e95bb161SJoe Hershberger  * Check for a ping request to be sent. If so, inject a reply
109e95bb161SJoe Hershberger  *
110e95bb161SJoe Hershberger  * returns 0 if injected, -EAGAIN if not
111e95bb161SJoe Hershberger  */
sandbox_eth_ping_req_to_reply(struct udevice * dev,void * packet,unsigned int len)112e95bb161SJoe Hershberger int sandbox_eth_ping_req_to_reply(struct udevice *dev, void *packet,
113e95bb161SJoe Hershberger 				  unsigned int len)
114e95bb161SJoe Hershberger {
115e95bb161SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
116e95bb161SJoe Hershberger 	struct ethernet_hdr *eth = packet;
117e95bb161SJoe Hershberger 	struct ip_udp_hdr *ip;
118e95bb161SJoe Hershberger 	struct icmp_hdr *icmp;
119e95bb161SJoe Hershberger 	struct ethernet_hdr *eth_recv;
120e95bb161SJoe Hershberger 	struct ip_udp_hdr *ipr;
121e95bb161SJoe Hershberger 	struct icmp_hdr *icmpr;
122e95bb161SJoe Hershberger 
123e95bb161SJoe Hershberger 	if (ntohs(eth->et_protlen) != PROT_IP)
124e95bb161SJoe Hershberger 		return -EAGAIN;
125e95bb161SJoe Hershberger 
126e95bb161SJoe Hershberger 	ip = packet + ETHER_HDR_SIZE;
127e95bb161SJoe Hershberger 
128e95bb161SJoe Hershberger 	if (ip->ip_p != IPPROTO_ICMP)
129e95bb161SJoe Hershberger 		return -EAGAIN;
130e95bb161SJoe Hershberger 
131e95bb161SJoe Hershberger 	icmp = (struct icmp_hdr *)&ip->udp_src;
132e95bb161SJoe Hershberger 
133e95bb161SJoe Hershberger 	if (icmp->type != ICMP_ECHO_REQUEST)
134e95bb161SJoe Hershberger 		return -EAGAIN;
135e95bb161SJoe Hershberger 
136c67a4207SJoe Hershberger 	/* Don't allow the buffer to overrun */
137c67a4207SJoe Hershberger 	if (priv->recv_packets >= PKTBUFSRX)
138c67a4207SJoe Hershberger 		return 0;
139c67a4207SJoe Hershberger 
140e95bb161SJoe Hershberger 	/* reply to the ping */
141c67a4207SJoe Hershberger 	eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
142e95bb161SJoe Hershberger 	memcpy(eth_recv, packet, len);
143e95bb161SJoe Hershberger 	ipr = (void *)eth_recv + ETHER_HDR_SIZE;
144e95bb161SJoe Hershberger 	icmpr = (struct icmp_hdr *)&ipr->udp_src;
145e95bb161SJoe Hershberger 	memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
146e95bb161SJoe Hershberger 	memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
147e95bb161SJoe Hershberger 	ipr->ip_sum = 0;
148e95bb161SJoe Hershberger 	ipr->ip_off = 0;
149e95bb161SJoe Hershberger 	net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
150e95bb161SJoe Hershberger 	net_write_ip((void *)&ipr->ip_src, priv->fake_host_ipaddr);
151e95bb161SJoe Hershberger 	ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
152e95bb161SJoe Hershberger 
153e95bb161SJoe Hershberger 	icmpr->type = ICMP_ECHO_REPLY;
154e95bb161SJoe Hershberger 	icmpr->checksum = 0;
155e95bb161SJoe Hershberger 	icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
156e95bb161SJoe Hershberger 
157c67a4207SJoe Hershberger 	priv->recv_packet_length[priv->recv_packets] = len;
158c67a4207SJoe Hershberger 	++priv->recv_packets;
159e95bb161SJoe Hershberger 
160e95bb161SJoe Hershberger 	return 0;
161e95bb161SJoe Hershberger }
162e95bb161SJoe Hershberger 
163c7eb733dSJoe Hershberger /*
16445988daeSJoe Hershberger  * sandbox_eth_recv_arp_req()
16545988daeSJoe Hershberger  *
16645988daeSJoe Hershberger  * Inject an ARP request for this target
16745988daeSJoe Hershberger  *
16845988daeSJoe Hershberger  * returns 0 if injected, -EOVERFLOW if not
16945988daeSJoe Hershberger  */
sandbox_eth_recv_arp_req(struct udevice * dev)17045988daeSJoe Hershberger int sandbox_eth_recv_arp_req(struct udevice *dev)
17145988daeSJoe Hershberger {
17245988daeSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
17345988daeSJoe Hershberger 	struct ethernet_hdr *eth_recv;
17445988daeSJoe Hershberger 	struct arp_hdr *arp_recv;
17545988daeSJoe Hershberger 
17645988daeSJoe Hershberger 	/* Don't allow the buffer to overrun */
17745988daeSJoe Hershberger 	if (priv->recv_packets >= PKTBUFSRX)
17845988daeSJoe Hershberger 		return -EOVERFLOW;
17945988daeSJoe Hershberger 
18045988daeSJoe Hershberger 	/* Formulate a fake request */
18145988daeSJoe Hershberger 	eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
18245988daeSJoe Hershberger 	memcpy(eth_recv->et_dest, net_bcast_ethaddr, ARP_HLEN);
18345988daeSJoe Hershberger 	memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
18445988daeSJoe Hershberger 	eth_recv->et_protlen = htons(PROT_ARP);
18545988daeSJoe Hershberger 
18645988daeSJoe Hershberger 	arp_recv = (void *)eth_recv + ETHER_HDR_SIZE;
18745988daeSJoe Hershberger 	arp_recv->ar_hrd = htons(ARP_ETHER);
18845988daeSJoe Hershberger 	arp_recv->ar_pro = htons(PROT_IP);
18945988daeSJoe Hershberger 	arp_recv->ar_hln = ARP_HLEN;
19045988daeSJoe Hershberger 	arp_recv->ar_pln = ARP_PLEN;
19145988daeSJoe Hershberger 	arp_recv->ar_op = htons(ARPOP_REQUEST);
19245988daeSJoe Hershberger 	memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, ARP_HLEN);
19345988daeSJoe Hershberger 	net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
19445988daeSJoe Hershberger 	memcpy(&arp_recv->ar_tha, net_null_ethaddr, ARP_HLEN);
19545988daeSJoe Hershberger 	net_write_ip(&arp_recv->ar_tpa, net_ip);
19645988daeSJoe Hershberger 
19745988daeSJoe Hershberger 	priv->recv_packet_length[priv->recv_packets] =
19845988daeSJoe Hershberger 		ETHER_HDR_SIZE + ARP_HDR_SIZE;
19945988daeSJoe Hershberger 	++priv->recv_packets;
20045988daeSJoe Hershberger 
20145988daeSJoe Hershberger 	return 0;
20245988daeSJoe Hershberger }
20345988daeSJoe Hershberger 
20445988daeSJoe Hershberger /*
205*72ff0042SJoe Hershberger  * sandbox_eth_recv_ping_req()
206*72ff0042SJoe Hershberger  *
207*72ff0042SJoe Hershberger  * Inject a ping request for this target
208*72ff0042SJoe Hershberger  *
209*72ff0042SJoe Hershberger  * returns 0 if injected, -EOVERFLOW if not
210*72ff0042SJoe Hershberger  */
sandbox_eth_recv_ping_req(struct udevice * dev)211*72ff0042SJoe Hershberger int sandbox_eth_recv_ping_req(struct udevice *dev)
212*72ff0042SJoe Hershberger {
213*72ff0042SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
214*72ff0042SJoe Hershberger 	struct ethernet_hdr *eth_recv;
215*72ff0042SJoe Hershberger 	struct ip_udp_hdr *ipr;
216*72ff0042SJoe Hershberger 	struct icmp_hdr *icmpr;
217*72ff0042SJoe Hershberger 
218*72ff0042SJoe Hershberger 	/* Don't allow the buffer to overrun */
219*72ff0042SJoe Hershberger 	if (priv->recv_packets >= PKTBUFSRX)
220*72ff0042SJoe Hershberger 		return -EOVERFLOW;
221*72ff0042SJoe Hershberger 
222*72ff0042SJoe Hershberger 	/* Formulate a fake ping */
223*72ff0042SJoe Hershberger 	eth_recv = (void *)priv->recv_packet_buffer[priv->recv_packets];
224*72ff0042SJoe Hershberger 
225*72ff0042SJoe Hershberger 	memcpy(eth_recv->et_dest, net_ethaddr, ARP_HLEN);
226*72ff0042SJoe Hershberger 	memcpy(eth_recv->et_src, priv->fake_host_hwaddr, ARP_HLEN);
227*72ff0042SJoe Hershberger 	eth_recv->et_protlen = htons(PROT_IP);
228*72ff0042SJoe Hershberger 
229*72ff0042SJoe Hershberger 	ipr = (void *)eth_recv + ETHER_HDR_SIZE;
230*72ff0042SJoe Hershberger 	ipr->ip_hl_v = 0x45;
231*72ff0042SJoe Hershberger 	ipr->ip_len = htons(IP_ICMP_HDR_SIZE);
232*72ff0042SJoe Hershberger 	ipr->ip_off = htons(IP_FLAGS_DFRAG);
233*72ff0042SJoe Hershberger 	ipr->ip_p = IPPROTO_ICMP;
234*72ff0042SJoe Hershberger 	ipr->ip_sum = 0;
235*72ff0042SJoe Hershberger 	net_write_ip(&ipr->ip_src, priv->fake_host_ipaddr);
236*72ff0042SJoe Hershberger 	net_write_ip(&ipr->ip_dst, net_ip);
237*72ff0042SJoe Hershberger 	ipr->ip_sum = compute_ip_checksum(ipr, IP_HDR_SIZE);
238*72ff0042SJoe Hershberger 
239*72ff0042SJoe Hershberger 	icmpr = (struct icmp_hdr *)&ipr->udp_src;
240*72ff0042SJoe Hershberger 
241*72ff0042SJoe Hershberger 	icmpr->type = ICMP_ECHO_REQUEST;
242*72ff0042SJoe Hershberger 	icmpr->code = 0;
243*72ff0042SJoe Hershberger 	icmpr->checksum = 0;
244*72ff0042SJoe Hershberger 	icmpr->un.echo.id = 0;
245*72ff0042SJoe Hershberger 	icmpr->un.echo.sequence = htons(1);
246*72ff0042SJoe Hershberger 	icmpr->checksum = compute_ip_checksum(icmpr, ICMP_HDR_SIZE);
247*72ff0042SJoe Hershberger 
248*72ff0042SJoe Hershberger 	priv->recv_packet_length[priv->recv_packets] =
249*72ff0042SJoe Hershberger 		ETHER_HDR_SIZE + IP_ICMP_HDR_SIZE;
250*72ff0042SJoe Hershberger 	++priv->recv_packets;
251*72ff0042SJoe Hershberger 
252*72ff0042SJoe Hershberger 	return 0;
253*72ff0042SJoe Hershberger }
254*72ff0042SJoe Hershberger 
255*72ff0042SJoe Hershberger /*
256c7eb733dSJoe Hershberger  * sb_default_handler()
257c7eb733dSJoe Hershberger  *
258c7eb733dSJoe Hershberger  * perform typical responses to simple ping
259c7eb733dSJoe Hershberger  *
260c7eb733dSJoe Hershberger  * dev - device pointer
261c7eb733dSJoe Hershberger  * pkt - "sent" packet buffer
262c7eb733dSJoe Hershberger  * len - length of packet
263c7eb733dSJoe Hershberger  */
sb_default_handler(struct udevice * dev,void * packet,unsigned int len)264c7eb733dSJoe Hershberger static int sb_default_handler(struct udevice *dev, void *packet,
265c7eb733dSJoe Hershberger 			      unsigned int len)
266c7eb733dSJoe Hershberger {
267c7eb733dSJoe Hershberger 	if (!sandbox_eth_arp_req_to_reply(dev, packet, len))
268c7eb733dSJoe Hershberger 		return 0;
269c7eb733dSJoe Hershberger 	if (!sandbox_eth_ping_req_to_reply(dev, packet, len))
270c7eb733dSJoe Hershberger 		return 0;
271c7eb733dSJoe Hershberger 
272c7eb733dSJoe Hershberger 	return 0;
273c7eb733dSJoe Hershberger }
274c7eb733dSJoe Hershberger 
275c7eb733dSJoe Hershberger /*
276c7eb733dSJoe Hershberger  * sandbox_eth_set_tx_handler()
277c7eb733dSJoe Hershberger  *
278c7eb733dSJoe Hershberger  * Set a custom response to a packet being sent through the sandbox eth test
279c7eb733dSJoe Hershberger  *	driver
280c7eb733dSJoe Hershberger  *
281c7eb733dSJoe Hershberger  * index - interface to set the handler for
282c7eb733dSJoe Hershberger  * handler - The func ptr to call on send. If NULL, set to default handler
283c7eb733dSJoe Hershberger  */
sandbox_eth_set_tx_handler(int index,sandbox_eth_tx_hand_f * handler)284c7eb733dSJoe Hershberger void sandbox_eth_set_tx_handler(int index, sandbox_eth_tx_hand_f *handler)
285c7eb733dSJoe Hershberger {
286c7eb733dSJoe Hershberger 	struct udevice *dev;
287c7eb733dSJoe Hershberger 	struct eth_sandbox_priv *priv;
288c7eb733dSJoe Hershberger 	int ret;
289c7eb733dSJoe Hershberger 
290c7eb733dSJoe Hershberger 	ret = uclass_get_device(UCLASS_ETH, index, &dev);
291c7eb733dSJoe Hershberger 	if (ret)
292c7eb733dSJoe Hershberger 		return;
293c7eb733dSJoe Hershberger 
294c7eb733dSJoe Hershberger 	priv = dev_get_priv(dev);
295c7eb733dSJoe Hershberger 	if (handler)
296c7eb733dSJoe Hershberger 		priv->tx_handler = handler;
297c7eb733dSJoe Hershberger 	else
298c7eb733dSJoe Hershberger 		priv->tx_handler = sb_default_handler;
299c7eb733dSJoe Hershberger }
300c7eb733dSJoe Hershberger 
3019cbe5972SJoe Hershberger /*
3029cbe5972SJoe Hershberger  * Set priv ptr
3039cbe5972SJoe Hershberger  *
3049cbe5972SJoe Hershberger  * priv - priv void ptr to store in the device
3059cbe5972SJoe Hershberger  */
sandbox_eth_set_priv(int index,void * priv)3069cbe5972SJoe Hershberger void sandbox_eth_set_priv(int index, void *priv)
3079cbe5972SJoe Hershberger {
3089cbe5972SJoe Hershberger 	struct udevice *dev;
3099cbe5972SJoe Hershberger 	struct eth_sandbox_priv *dev_priv;
3109cbe5972SJoe Hershberger 	int ret;
3119cbe5972SJoe Hershberger 
3129cbe5972SJoe Hershberger 	ret = uclass_get_device(UCLASS_ETH, index, &dev);
3139cbe5972SJoe Hershberger 	if (ret)
3149cbe5972SJoe Hershberger 		return;
3159cbe5972SJoe Hershberger 
3169cbe5972SJoe Hershberger 	dev_priv = dev_get_priv(dev);
3179cbe5972SJoe Hershberger 
3189cbe5972SJoe Hershberger 	dev_priv->priv = priv;
3199cbe5972SJoe Hershberger }
3209cbe5972SJoe Hershberger 
sb_eth_start(struct udevice * dev)3213ea143abSJoe Hershberger static int sb_eth_start(struct udevice *dev)
3223ea143abSJoe Hershberger {
323d87a457bSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
324d87a457bSJoe Hershberger 
3253ea143abSJoe Hershberger 	debug("eth_sandbox: Start\n");
3263ea143abSJoe Hershberger 
327c67a4207SJoe Hershberger 	priv->recv_packets = 0;
328c67a4207SJoe Hershberger 	for (int i = 0; i < PKTBUFSRX; i++) {
329c67a4207SJoe Hershberger 		priv->recv_packet_buffer[i] = net_rx_packets[i];
330c67a4207SJoe Hershberger 		priv->recv_packet_length[i] = 0;
331c67a4207SJoe Hershberger 	}
332b32dd183SJoe Hershberger 
3333ea143abSJoe Hershberger 	return 0;
3343ea143abSJoe Hershberger }
3353ea143abSJoe Hershberger 
sb_eth_send(struct udevice * dev,void * packet,int length)3363ea143abSJoe Hershberger static int sb_eth_send(struct udevice *dev, void *packet, int length)
3373ea143abSJoe Hershberger {
338d87a457bSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
339d87a457bSJoe Hershberger 
3403ea143abSJoe Hershberger 	debug("eth_sandbox: Send packet %d\n", length);
3413ea143abSJoe Hershberger 
342e4ab9a65SJoe Hershberger 	if (priv->disabled)
3432eede1f3SJoe Hershberger 		return 0;
3442eede1f3SJoe Hershberger 
345c7eb733dSJoe Hershberger 	return priv->tx_handler(dev, packet, length);
3463ea143abSJoe Hershberger }
3473ea143abSJoe Hershberger 
sb_eth_recv(struct udevice * dev,int flags,uchar ** packetp)348a1ca92eaSSimon Glass static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
3493ea143abSJoe Hershberger {
350d87a457bSJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
351d87a457bSJoe Hershberger 
3526f2707c6SJoe Hershberger 	if (skip_timeout) {
353c5a75339SJoe Hershberger 		sandbox_timer_add_offset(11000UL);
3546f2707c6SJoe Hershberger 		skip_timeout = false;
3556f2707c6SJoe Hershberger 	}
3566f2707c6SJoe Hershberger 
357c67a4207SJoe Hershberger 	if (priv->recv_packets) {
358c67a4207SJoe Hershberger 		int lcl_recv_packet_length = priv->recv_packet_length[0];
359d87a457bSJoe Hershberger 
360c67a4207SJoe Hershberger 		debug("eth_sandbox: received packet[%d], %d waiting\n",
361c67a4207SJoe Hershberger 		      lcl_recv_packet_length, priv->recv_packets - 1);
362c67a4207SJoe Hershberger 		*packetp = priv->recv_packet_buffer[0];
363d87a457bSJoe Hershberger 		return lcl_recv_packet_length;
364d87a457bSJoe Hershberger 	}
3653ea143abSJoe Hershberger 	return 0;
3663ea143abSJoe Hershberger }
3673ea143abSJoe Hershberger 
sb_eth_free_pkt(struct udevice * dev,uchar * packet,int length)368c67a4207SJoe Hershberger static int sb_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
369c67a4207SJoe Hershberger {
370c67a4207SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
371c67a4207SJoe Hershberger 	int i;
372c67a4207SJoe Hershberger 
373c67a4207SJoe Hershberger 	if (!priv->recv_packets)
374c67a4207SJoe Hershberger 		return 0;
375c67a4207SJoe Hershberger 
376c67a4207SJoe Hershberger 	--priv->recv_packets;
377c67a4207SJoe Hershberger 	for (i = 0; i < priv->recv_packets; i++) {
378c67a4207SJoe Hershberger 		priv->recv_packet_length[i] = priv->recv_packet_length[i + 1];
379c67a4207SJoe Hershberger 		memcpy(priv->recv_packet_buffer[i],
380c67a4207SJoe Hershberger 		       priv->recv_packet_buffer[i + 1],
381c67a4207SJoe Hershberger 		       priv->recv_packet_length[i + 1]);
382c67a4207SJoe Hershberger 	}
383c67a4207SJoe Hershberger 	priv->recv_packet_length[priv->recv_packets] = 0;
384c67a4207SJoe Hershberger 
385c67a4207SJoe Hershberger 	return 0;
386c67a4207SJoe Hershberger }
387c67a4207SJoe Hershberger 
sb_eth_stop(struct udevice * dev)3883ea143abSJoe Hershberger static void sb_eth_stop(struct udevice *dev)
3893ea143abSJoe Hershberger {
3903ea143abSJoe Hershberger 	debug("eth_sandbox: Stop\n");
3913ea143abSJoe Hershberger }
3923ea143abSJoe Hershberger 
sb_eth_write_hwaddr(struct udevice * dev)3933ea143abSJoe Hershberger static int sb_eth_write_hwaddr(struct udevice *dev)
3943ea143abSJoe Hershberger {
3953ea143abSJoe Hershberger 	struct eth_pdata *pdata = dev_get_platdata(dev);
3963ea143abSJoe Hershberger 
3973ea143abSJoe Hershberger 	debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name,
3983ea143abSJoe Hershberger 	      pdata->enetaddr);
3993ea143abSJoe Hershberger 	return 0;
4003ea143abSJoe Hershberger }
4013ea143abSJoe Hershberger 
4023ea143abSJoe Hershberger static const struct eth_ops sb_eth_ops = {
4033ea143abSJoe Hershberger 	.start			= sb_eth_start,
4043ea143abSJoe Hershberger 	.send			= sb_eth_send,
4053ea143abSJoe Hershberger 	.recv			= sb_eth_recv,
406c67a4207SJoe Hershberger 	.free_pkt		= sb_eth_free_pkt,
4073ea143abSJoe Hershberger 	.stop			= sb_eth_stop,
4083ea143abSJoe Hershberger 	.write_hwaddr		= sb_eth_write_hwaddr,
4093ea143abSJoe Hershberger };
4103ea143abSJoe Hershberger 
sb_eth_remove(struct udevice * dev)4113ea143abSJoe Hershberger static int sb_eth_remove(struct udevice *dev)
4123ea143abSJoe Hershberger {
4133ea143abSJoe Hershberger 	return 0;
4143ea143abSJoe Hershberger }
4153ea143abSJoe Hershberger 
sb_eth_ofdata_to_platdata(struct udevice * dev)4163ea143abSJoe Hershberger static int sb_eth_ofdata_to_platdata(struct udevice *dev)
4173ea143abSJoe Hershberger {
4183ea143abSJoe Hershberger 	struct eth_pdata *pdata = dev_get_platdata(dev);
419b32dd183SJoe Hershberger 	struct eth_sandbox_priv *priv = dev_get_priv(dev);
420b32dd183SJoe Hershberger 	const u8 *mac;
4213ea143abSJoe Hershberger 
422b32dd183SJoe Hershberger 	pdata->iobase = dev_read_addr(dev);
423b32dd183SJoe Hershberger 
424b32dd183SJoe Hershberger 	mac = dev_read_u8_array_ptr(dev, "fake-host-hwaddr", ARP_HLEN);
425b32dd183SJoe Hershberger 	if (!mac) {
426b32dd183SJoe Hershberger 		printf("'fake-host-hwaddr' is missing from the DT\n");
427b32dd183SJoe Hershberger 		return -EINVAL;
428b32dd183SJoe Hershberger 	}
429b32dd183SJoe Hershberger 	memcpy(priv->fake_host_hwaddr, mac, ARP_HLEN);
430e4ab9a65SJoe Hershberger 	priv->disabled = false;
431c7eb733dSJoe Hershberger 	priv->tx_handler = sb_default_handler;
432b32dd183SJoe Hershberger 
4333ea143abSJoe Hershberger 	return 0;
4343ea143abSJoe Hershberger }
4353ea143abSJoe Hershberger 
4363ea143abSJoe Hershberger static const struct udevice_id sb_eth_ids[] = {
4373ea143abSJoe Hershberger 	{ .compatible = "sandbox,eth" },
4383ea143abSJoe Hershberger 	{ }
4393ea143abSJoe Hershberger };
4403ea143abSJoe Hershberger 
4413ea143abSJoe Hershberger U_BOOT_DRIVER(eth_sandbox) = {
4423ea143abSJoe Hershberger 	.name	= "eth_sandbox",
4433ea143abSJoe Hershberger 	.id	= UCLASS_ETH,
4443ea143abSJoe Hershberger 	.of_match = sb_eth_ids,
4453ea143abSJoe Hershberger 	.ofdata_to_platdata = sb_eth_ofdata_to_platdata,
4463ea143abSJoe Hershberger 	.remove	= sb_eth_remove,
4473ea143abSJoe Hershberger 	.ops	= &sb_eth_ops,
448d87a457bSJoe Hershberger 	.priv_auto_alloc_size = sizeof(struct eth_sandbox_priv),
4493ea143abSJoe Hershberger 	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
4503ea143abSJoe Hershberger };
451