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