1a346ca79SJoe Hershberger /* 2a346ca79SJoe Hershberger * Copyright (c) 2015 National Instruments 3a346ca79SJoe Hershberger * 4a346ca79SJoe Hershberger * (C) Copyright 2015 5a346ca79SJoe Hershberger * Joe Hershberger <joe.hershberger@ni.com> 6a346ca79SJoe Hershberger * 7a346ca79SJoe Hershberger * SPDX-License-Identifier: GPL-2.0 8a346ca79SJoe Hershberger */ 9a346ca79SJoe Hershberger 10a346ca79SJoe Hershberger #include <asm/eth-raw-os.h> 11a346ca79SJoe Hershberger #include <common.h> 12a346ca79SJoe Hershberger #include <dm.h> 13a346ca79SJoe Hershberger #include <malloc.h> 14a346ca79SJoe Hershberger #include <net.h> 15a346ca79SJoe Hershberger 16a346ca79SJoe Hershberger DECLARE_GLOBAL_DATA_PTR; 17a346ca79SJoe Hershberger 1822f68524SJoe Hershberger static int reply_arp; 19049a95a7SJoe Hershberger static struct in_addr arp_ip; 20a346ca79SJoe Hershberger 21a346ca79SJoe Hershberger static int sb_eth_raw_start(struct udevice *dev) 22a346ca79SJoe Hershberger { 23a346ca79SJoe Hershberger struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); 24a346ca79SJoe Hershberger struct eth_pdata *pdata = dev_get_platdata(dev); 25a346ca79SJoe Hershberger const char *interface; 26a346ca79SJoe Hershberger 27a346ca79SJoe Hershberger debug("eth_sandbox_raw: Start\n"); 28a346ca79SJoe Hershberger 29a346ca79SJoe Hershberger interface = fdt_getprop(gd->fdt_blob, dev->of_offset, 30a346ca79SJoe Hershberger "host-raw-interface", NULL); 31a346ca79SJoe Hershberger if (interface == NULL) 32a346ca79SJoe Hershberger return -EINVAL; 33a346ca79SJoe Hershberger 3422f68524SJoe Hershberger if (strcmp(interface, "lo") == 0) { 3522f68524SJoe Hershberger priv->local = 1; 3622f68524SJoe Hershberger setenv("ipaddr", "127.0.0.1"); 3722f68524SJoe Hershberger setenv("serverip", "127.0.0.1"); 3822f68524SJoe Hershberger } 39a346ca79SJoe Hershberger return sandbox_eth_raw_os_start(interface, pdata->enetaddr, priv); 40a346ca79SJoe Hershberger } 41a346ca79SJoe Hershberger 42a346ca79SJoe Hershberger static int sb_eth_raw_send(struct udevice *dev, void *packet, int length) 43a346ca79SJoe Hershberger { 44a346ca79SJoe Hershberger struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); 45a346ca79SJoe Hershberger 46a346ca79SJoe Hershberger debug("eth_sandbox_raw: Send packet %d\n", length); 47a346ca79SJoe Hershberger 4822f68524SJoe Hershberger if (priv->local) { 4922f68524SJoe Hershberger struct ethernet_hdr *eth = packet; 5022f68524SJoe Hershberger 5122f68524SJoe Hershberger if (ntohs(eth->et_protlen) == PROT_ARP) { 5222f68524SJoe Hershberger struct arp_hdr *arp = packet + ETHER_HDR_SIZE; 5322f68524SJoe Hershberger 5422f68524SJoe Hershberger /** 5522f68524SJoe Hershberger * localhost works on a higher-level API in Linux than 5622f68524SJoe Hershberger * ARP packets, so fake it 5722f68524SJoe Hershberger */ 58049a95a7SJoe Hershberger arp_ip = net_read_ip(&arp->ar_tpa); 5922f68524SJoe Hershberger reply_arp = 1; 6022f68524SJoe Hershberger return 0; 6122f68524SJoe Hershberger } 6222f68524SJoe Hershberger packet += ETHER_HDR_SIZE; 6322f68524SJoe Hershberger length -= ETHER_HDR_SIZE; 6422f68524SJoe Hershberger } 65a346ca79SJoe Hershberger return sandbox_eth_raw_os_send(packet, length, priv); 66a346ca79SJoe Hershberger } 67a346ca79SJoe Hershberger 68*a1ca92eaSSimon Glass static int sb_eth_raw_recv(struct udevice *dev, int flags, uchar **packetp) 69a346ca79SJoe Hershberger { 7022f68524SJoe Hershberger struct eth_pdata *pdata = dev_get_platdata(dev); 71a346ca79SJoe Hershberger struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); 7222f68524SJoe Hershberger int retval = 0; 73a346ca79SJoe Hershberger int length; 74a346ca79SJoe Hershberger 7522f68524SJoe Hershberger if (reply_arp) { 7622f68524SJoe Hershberger struct arp_hdr *arp = (void *)net_rx_packets[0] + 7722f68524SJoe Hershberger ETHER_HDR_SIZE; 7822f68524SJoe Hershberger 7922f68524SJoe Hershberger /* 8022f68524SJoe Hershberger * Fake an ARP response. The u-boot network stack is sending an 8122f68524SJoe Hershberger * ARP request (to find the MAC address to address the actual 8222f68524SJoe Hershberger * packet to) and requires an ARP response to continue. Since 8322f68524SJoe Hershberger * this is the localhost interface, there is no Etherent level 8422f68524SJoe Hershberger * traffic at all, so there is no way to send an ARP request or 8522f68524SJoe Hershberger * to get a response. For this reason we fake the response to 8622f68524SJoe Hershberger * make the u-boot network stack happy. 8722f68524SJoe Hershberger */ 8822f68524SJoe Hershberger arp->ar_hrd = htons(ARP_ETHER); 8922f68524SJoe Hershberger arp->ar_pro = htons(PROT_IP); 9022f68524SJoe Hershberger arp->ar_hln = ARP_HLEN; 9122f68524SJoe Hershberger arp->ar_pln = ARP_PLEN; 9222f68524SJoe Hershberger arp->ar_op = htons(ARPOP_REPLY); 9322f68524SJoe Hershberger /* Any non-zero MAC address will work */ 9422f68524SJoe Hershberger memset(&arp->ar_sha, 0x01, ARP_HLEN); 9522f68524SJoe Hershberger /* Use whatever IP we were looking for (always 127.0.0.1?) */ 96049a95a7SJoe Hershberger net_write_ip(&arp->ar_spa, arp_ip); 9722f68524SJoe Hershberger memcpy(&arp->ar_tha, pdata->enetaddr, ARP_HLEN); 98049a95a7SJoe Hershberger net_write_ip(&arp->ar_tpa, net_ip); 9922f68524SJoe Hershberger length = ARP_HDR_SIZE; 10022f68524SJoe Hershberger } else { 10122f68524SJoe Hershberger /* If local, the Ethernet header won't be included; skip it */ 10222f68524SJoe Hershberger uchar *pktptr = priv->local ? 10322f68524SJoe Hershberger net_rx_packets[0] + ETHER_HDR_SIZE : net_rx_packets[0]; 10422f68524SJoe Hershberger 10522f68524SJoe Hershberger retval = sandbox_eth_raw_os_recv(pktptr, &length, priv); 10622f68524SJoe Hershberger } 107a346ca79SJoe Hershberger 108a346ca79SJoe Hershberger if (!retval && length) { 10922f68524SJoe Hershberger if (priv->local) { 11022f68524SJoe Hershberger struct ethernet_hdr *eth = (void *)net_rx_packets[0]; 11122f68524SJoe Hershberger 11222f68524SJoe Hershberger /* Fill in enough of the missing Ethernet header */ 11322f68524SJoe Hershberger memcpy(eth->et_dest, pdata->enetaddr, ARP_HLEN); 11422f68524SJoe Hershberger memset(eth->et_src, 0x01, ARP_HLEN); 11522f68524SJoe Hershberger eth->et_protlen = htons(reply_arp ? PROT_ARP : PROT_IP); 11622f68524SJoe Hershberger reply_arp = 0; 11722f68524SJoe Hershberger length += ETHER_HDR_SIZE; 11822f68524SJoe Hershberger } 11922f68524SJoe Hershberger 120a346ca79SJoe Hershberger debug("eth_sandbox_raw: received packet %d\n", 121a346ca79SJoe Hershberger length); 122a346ca79SJoe Hershberger *packetp = net_rx_packets[0]; 123a346ca79SJoe Hershberger return length; 124a346ca79SJoe Hershberger } 125a346ca79SJoe Hershberger return retval; 126a346ca79SJoe Hershberger } 127a346ca79SJoe Hershberger 128a346ca79SJoe Hershberger static void sb_eth_raw_stop(struct udevice *dev) 129a346ca79SJoe Hershberger { 130a346ca79SJoe Hershberger struct eth_sandbox_raw_priv *priv = dev_get_priv(dev); 131a346ca79SJoe Hershberger 132a346ca79SJoe Hershberger debug("eth_sandbox_raw: Stop\n"); 133a346ca79SJoe Hershberger 134a346ca79SJoe Hershberger sandbox_eth_raw_os_stop(priv); 135a346ca79SJoe Hershberger } 136a346ca79SJoe Hershberger 137a346ca79SJoe Hershberger static const struct eth_ops sb_eth_raw_ops = { 138a346ca79SJoe Hershberger .start = sb_eth_raw_start, 139a346ca79SJoe Hershberger .send = sb_eth_raw_send, 140a346ca79SJoe Hershberger .recv = sb_eth_raw_recv, 141a346ca79SJoe Hershberger .stop = sb_eth_raw_stop, 142a346ca79SJoe Hershberger }; 143a346ca79SJoe Hershberger 144a346ca79SJoe Hershberger static int sb_eth_raw_ofdata_to_platdata(struct udevice *dev) 145a346ca79SJoe Hershberger { 146a346ca79SJoe Hershberger struct eth_pdata *pdata = dev_get_platdata(dev); 147a346ca79SJoe Hershberger 148a346ca79SJoe Hershberger pdata->iobase = dev_get_addr(dev); 149a346ca79SJoe Hershberger return 0; 150a346ca79SJoe Hershberger } 151a346ca79SJoe Hershberger 152a346ca79SJoe Hershberger static const struct udevice_id sb_eth_raw_ids[] = { 153a346ca79SJoe Hershberger { .compatible = "sandbox,eth-raw" }, 154a346ca79SJoe Hershberger { } 155a346ca79SJoe Hershberger }; 156a346ca79SJoe Hershberger 157a346ca79SJoe Hershberger U_BOOT_DRIVER(eth_sandbox_raw) = { 158a346ca79SJoe Hershberger .name = "eth_sandbox_raw", 159a346ca79SJoe Hershberger .id = UCLASS_ETH, 160a346ca79SJoe Hershberger .of_match = sb_eth_raw_ids, 161a346ca79SJoe Hershberger .ofdata_to_platdata = sb_eth_raw_ofdata_to_platdata, 162a346ca79SJoe Hershberger .ops = &sb_eth_raw_ops, 163a346ca79SJoe Hershberger .priv_auto_alloc_size = sizeof(struct eth_sandbox_raw_priv), 164a346ca79SJoe Hershberger .platdata_auto_alloc_size = sizeof(struct eth_pdata), 165a346ca79SJoe Hershberger }; 166