13ea143abSJoe Hershberger /* 23ea143abSJoe Hershberger * Copyright (c) 2015 National Instruments 33ea143abSJoe Hershberger * 43ea143abSJoe Hershberger * (C) Copyright 2015 53ea143abSJoe Hershberger * Joe Hershberger <joe.hershberger@ni.com> 63ea143abSJoe Hershberger * 73ea143abSJoe Hershberger * SPDX-License-Identifier: GPL-2.0 83ea143abSJoe Hershberger */ 93ea143abSJoe Hershberger 103ea143abSJoe Hershberger #include <common.h> 113ea143abSJoe Hershberger #include <dm.h> 123ea143abSJoe Hershberger #include <malloc.h> 133ea143abSJoe Hershberger #include <net.h> 143ea143abSJoe Hershberger 153ea143abSJoe Hershberger DECLARE_GLOBAL_DATA_PTR; 163ea143abSJoe Hershberger 17*d87a457bSJoe Hershberger /** 18*d87a457bSJoe Hershberger * struct eth_sandbox_priv - memory for sandbox mock driver 19*d87a457bSJoe Hershberger * 20*d87a457bSJoe Hershberger * fake_host_hwaddr: MAC address of mocked machine 21*d87a457bSJoe Hershberger * fake_host_ipaddr: IP address of mocked machine 22*d87a457bSJoe Hershberger * recv_packet_buffer: buffer of the packet returned as received 23*d87a457bSJoe Hershberger * recv_packet_length: length of the packet returned as received 24*d87a457bSJoe Hershberger */ 25*d87a457bSJoe Hershberger struct eth_sandbox_priv { 26*d87a457bSJoe Hershberger uchar fake_host_hwaddr[ARP_HLEN]; 27*d87a457bSJoe Hershberger IPaddr_t fake_host_ipaddr; 28*d87a457bSJoe Hershberger uchar *recv_packet_buffer; 29*d87a457bSJoe Hershberger int recv_packet_length; 30*d87a457bSJoe Hershberger }; 31*d87a457bSJoe Hershberger 323ea143abSJoe Hershberger static int sb_eth_start(struct udevice *dev) 333ea143abSJoe Hershberger { 34*d87a457bSJoe Hershberger struct eth_sandbox_priv *priv = dev_get_priv(dev); 35*d87a457bSJoe Hershberger 363ea143abSJoe Hershberger debug("eth_sandbox: Start\n"); 373ea143abSJoe Hershberger 38*d87a457bSJoe Hershberger fdtdec_get_byte_array(gd->fdt_blob, dev->of_offset, "fake-host-hwaddr", 39*d87a457bSJoe Hershberger priv->fake_host_hwaddr, ARP_HLEN); 40*d87a457bSJoe Hershberger priv->recv_packet_buffer = net_rx_packets[0]; 413ea143abSJoe Hershberger return 0; 423ea143abSJoe Hershberger } 433ea143abSJoe Hershberger 443ea143abSJoe Hershberger static int sb_eth_send(struct udevice *dev, void *packet, int length) 453ea143abSJoe Hershberger { 46*d87a457bSJoe Hershberger struct eth_sandbox_priv *priv = dev_get_priv(dev); 47*d87a457bSJoe Hershberger struct ethernet_hdr *eth = packet; 48*d87a457bSJoe Hershberger 493ea143abSJoe Hershberger debug("eth_sandbox: Send packet %d\n", length); 503ea143abSJoe Hershberger 51*d87a457bSJoe Hershberger if (ntohs(eth->et_protlen) == PROT_ARP) { 52*d87a457bSJoe Hershberger struct arp_hdr *arp = packet + ETHER_HDR_SIZE; 53*d87a457bSJoe Hershberger 54*d87a457bSJoe Hershberger if (ntohs(arp->ar_op) == ARPOP_REQUEST) { 55*d87a457bSJoe Hershberger struct ethernet_hdr *eth_recv; 56*d87a457bSJoe Hershberger struct arp_hdr *arp_recv; 57*d87a457bSJoe Hershberger 58*d87a457bSJoe Hershberger /* store this as the assumed IP of the fake host */ 59*d87a457bSJoe Hershberger priv->fake_host_ipaddr = NetReadIP(&arp->ar_tpa); 60*d87a457bSJoe Hershberger /* Formulate a fake response */ 61*d87a457bSJoe Hershberger eth_recv = (void *)priv->recv_packet_buffer; 62*d87a457bSJoe Hershberger memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN); 63*d87a457bSJoe Hershberger memcpy(eth_recv->et_src, priv->fake_host_hwaddr, 64*d87a457bSJoe Hershberger ARP_HLEN); 65*d87a457bSJoe Hershberger eth_recv->et_protlen = htons(PROT_ARP); 66*d87a457bSJoe Hershberger 67*d87a457bSJoe Hershberger arp_recv = (void *)priv->recv_packet_buffer + 68*d87a457bSJoe Hershberger ETHER_HDR_SIZE; 69*d87a457bSJoe Hershberger arp_recv->ar_hrd = htons(ARP_ETHER); 70*d87a457bSJoe Hershberger arp_recv->ar_pro = htons(PROT_IP); 71*d87a457bSJoe Hershberger arp_recv->ar_hln = ARP_HLEN; 72*d87a457bSJoe Hershberger arp_recv->ar_pln = ARP_PLEN; 73*d87a457bSJoe Hershberger arp_recv->ar_op = htons(ARPOP_REPLY); 74*d87a457bSJoe Hershberger memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr, 75*d87a457bSJoe Hershberger ARP_HLEN); 76*d87a457bSJoe Hershberger NetWriteIP(&arp_recv->ar_spa, priv->fake_host_ipaddr); 77*d87a457bSJoe Hershberger memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN); 78*d87a457bSJoe Hershberger NetCopyIP(&arp_recv->ar_tpa, &arp->ar_spa); 79*d87a457bSJoe Hershberger 80*d87a457bSJoe Hershberger priv->recv_packet_length = ETHER_HDR_SIZE + 81*d87a457bSJoe Hershberger ARP_HDR_SIZE; 82*d87a457bSJoe Hershberger } 83*d87a457bSJoe Hershberger } else if (ntohs(eth->et_protlen) == PROT_IP) { 84*d87a457bSJoe Hershberger struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE; 85*d87a457bSJoe Hershberger 86*d87a457bSJoe Hershberger if (ip->ip_p == IPPROTO_ICMP) { 87*d87a457bSJoe Hershberger struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src; 88*d87a457bSJoe Hershberger 89*d87a457bSJoe Hershberger if (icmp->type == ICMP_ECHO_REQUEST) { 90*d87a457bSJoe Hershberger struct ethernet_hdr *eth_recv; 91*d87a457bSJoe Hershberger struct ip_udp_hdr *ipr; 92*d87a457bSJoe Hershberger struct icmp_hdr *icmpr; 93*d87a457bSJoe Hershberger 94*d87a457bSJoe Hershberger /* reply to the ping */ 95*d87a457bSJoe Hershberger memcpy(priv->recv_packet_buffer, packet, 96*d87a457bSJoe Hershberger length); 97*d87a457bSJoe Hershberger eth_recv = (void *)priv->recv_packet_buffer; 98*d87a457bSJoe Hershberger ipr = (void *)priv->recv_packet_buffer + 99*d87a457bSJoe Hershberger ETHER_HDR_SIZE; 100*d87a457bSJoe Hershberger icmpr = (struct icmp_hdr *)&ipr->udp_src; 101*d87a457bSJoe Hershberger memcpy(eth_recv->et_dest, eth->et_src, 102*d87a457bSJoe Hershberger ARP_HLEN); 103*d87a457bSJoe Hershberger memcpy(eth_recv->et_src, priv->fake_host_hwaddr, 104*d87a457bSJoe Hershberger ARP_HLEN); 105*d87a457bSJoe Hershberger ipr->ip_sum = 0; 106*d87a457bSJoe Hershberger ipr->ip_off = 0; 107*d87a457bSJoe Hershberger NetCopyIP((void *)&ipr->ip_dst, &ip->ip_src); 108*d87a457bSJoe Hershberger NetWriteIP((void *)&ipr->ip_src, 109*d87a457bSJoe Hershberger priv->fake_host_ipaddr); 110*d87a457bSJoe Hershberger ipr->ip_sum = compute_ip_checksum(ipr, 111*d87a457bSJoe Hershberger IP_HDR_SIZE); 112*d87a457bSJoe Hershberger 113*d87a457bSJoe Hershberger icmpr->type = ICMP_ECHO_REPLY; 114*d87a457bSJoe Hershberger icmpr->checksum = 0; 115*d87a457bSJoe Hershberger icmpr->checksum = compute_ip_checksum(icmpr, 116*d87a457bSJoe Hershberger ICMP_HDR_SIZE); 117*d87a457bSJoe Hershberger 118*d87a457bSJoe Hershberger priv->recv_packet_length = length; 119*d87a457bSJoe Hershberger } 120*d87a457bSJoe Hershberger } 121*d87a457bSJoe Hershberger } 122*d87a457bSJoe Hershberger 1233ea143abSJoe Hershberger return 0; 1243ea143abSJoe Hershberger } 1253ea143abSJoe Hershberger 1263ea143abSJoe Hershberger static int sb_eth_recv(struct udevice *dev, uchar **packetp) 1273ea143abSJoe Hershberger { 128*d87a457bSJoe Hershberger struct eth_sandbox_priv *priv = dev_get_priv(dev); 129*d87a457bSJoe Hershberger 130*d87a457bSJoe Hershberger if (priv->recv_packet_length) { 131*d87a457bSJoe Hershberger int lcl_recv_packet_length = priv->recv_packet_length; 132*d87a457bSJoe Hershberger 133*d87a457bSJoe Hershberger debug("eth_sandbox: received packet %d\n", 134*d87a457bSJoe Hershberger priv->recv_packet_length); 135*d87a457bSJoe Hershberger priv->recv_packet_length = 0; 136*d87a457bSJoe Hershberger *packetp = priv->recv_packet_buffer; 137*d87a457bSJoe Hershberger return lcl_recv_packet_length; 138*d87a457bSJoe Hershberger } 1393ea143abSJoe Hershberger return 0; 1403ea143abSJoe Hershberger } 1413ea143abSJoe Hershberger 1423ea143abSJoe Hershberger static void sb_eth_stop(struct udevice *dev) 1433ea143abSJoe Hershberger { 1443ea143abSJoe Hershberger debug("eth_sandbox: Stop\n"); 1453ea143abSJoe Hershberger } 1463ea143abSJoe Hershberger 1473ea143abSJoe Hershberger static int sb_eth_write_hwaddr(struct udevice *dev) 1483ea143abSJoe Hershberger { 1493ea143abSJoe Hershberger struct eth_pdata *pdata = dev_get_platdata(dev); 1503ea143abSJoe Hershberger 1513ea143abSJoe Hershberger debug("eth_sandbox %s: Write HW ADDR - %pM\n", dev->name, 1523ea143abSJoe Hershberger pdata->enetaddr); 1533ea143abSJoe Hershberger return 0; 1543ea143abSJoe Hershberger } 1553ea143abSJoe Hershberger 1563ea143abSJoe Hershberger static const struct eth_ops sb_eth_ops = { 1573ea143abSJoe Hershberger .start = sb_eth_start, 1583ea143abSJoe Hershberger .send = sb_eth_send, 1593ea143abSJoe Hershberger .recv = sb_eth_recv, 1603ea143abSJoe Hershberger .stop = sb_eth_stop, 1613ea143abSJoe Hershberger .write_hwaddr = sb_eth_write_hwaddr, 1623ea143abSJoe Hershberger }; 1633ea143abSJoe Hershberger 1643ea143abSJoe Hershberger static int sb_eth_remove(struct udevice *dev) 1653ea143abSJoe Hershberger { 1663ea143abSJoe Hershberger return 0; 1673ea143abSJoe Hershberger } 1683ea143abSJoe Hershberger 1693ea143abSJoe Hershberger static int sb_eth_ofdata_to_platdata(struct udevice *dev) 1703ea143abSJoe Hershberger { 1713ea143abSJoe Hershberger struct eth_pdata *pdata = dev_get_platdata(dev); 1723ea143abSJoe Hershberger 1733ea143abSJoe Hershberger pdata->iobase = dev_get_addr(dev); 1743ea143abSJoe Hershberger return 0; 1753ea143abSJoe Hershberger } 1763ea143abSJoe Hershberger 1773ea143abSJoe Hershberger static const struct udevice_id sb_eth_ids[] = { 1783ea143abSJoe Hershberger { .compatible = "sandbox,eth" }, 1793ea143abSJoe Hershberger { } 1803ea143abSJoe Hershberger }; 1813ea143abSJoe Hershberger 1823ea143abSJoe Hershberger U_BOOT_DRIVER(eth_sandbox) = { 1833ea143abSJoe Hershberger .name = "eth_sandbox", 1843ea143abSJoe Hershberger .id = UCLASS_ETH, 1853ea143abSJoe Hershberger .of_match = sb_eth_ids, 1863ea143abSJoe Hershberger .ofdata_to_platdata = sb_eth_ofdata_to_platdata, 1873ea143abSJoe Hershberger .remove = sb_eth_remove, 1883ea143abSJoe Hershberger .ops = &sb_eth_ops, 189*d87a457bSJoe Hershberger .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv), 1903ea143abSJoe Hershberger .platdata_auto_alloc_size = sizeof(struct eth_pdata), 1913ea143abSJoe Hershberger }; 192