]> git.sur5r.net Git - u-boot/blobdiff - drivers/net/sandbox.c
rockchip: mkimage: remove (left-over) assignment w/o effect [coverity]
[u-boot] / drivers / net / sandbox.c
index 522990d8df68874d42c0b03d9cfa50b35f8b7056..79d0ae68bfd5281ff2d0c985053de8e9d71925d5 100644 (file)
 #include <dm.h>
 #include <malloc.h>
 #include <net.h>
+#include <asm/test.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/**
+ * struct eth_sandbox_priv - memory for sandbox mock driver
+ *
+ * fake_host_hwaddr: MAC address of mocked machine
+ * fake_host_ipaddr: IP address of mocked machine
+ * recv_packet_buffer: buffer of the packet returned as received
+ * recv_packet_length: length of the packet returned as received
+ */
+struct eth_sandbox_priv {
+       uchar fake_host_hwaddr[ARP_HLEN];
+       struct in_addr fake_host_ipaddr;
+       uchar *recv_packet_buffer;
+       int recv_packet_length;
+};
+
+static bool disabled[8] = {false};
+static bool skip_timeout;
+
+/*
+ * sandbox_eth_disable_response()
+ *
+ * index - The alias index (also DM seq number)
+ * disable - If non-zero, ignore sent packets and don't send mock response
+ */
+void sandbox_eth_disable_response(int index, bool disable)
+{
+       disabled[index] = disable;
+}
+
+/*
+ * sandbox_eth_skip_timeout()
+ *
+ * When the first packet read is attempted, fast-forward time
+ */
+void sandbox_eth_skip_timeout(void)
+{
+       skip_timeout = true;
+}
+
 static int sb_eth_start(struct udevice *dev)
 {
+       struct eth_sandbox_priv *priv = dev_get_priv(dev);
+
        debug("eth_sandbox: Start\n");
 
+       fdtdec_get_byte_array(gd->fdt_blob, dev_of_offset(dev),
+                             "fake-host-hwaddr", priv->fake_host_hwaddr,
+                             ARP_HLEN);
+       priv->recv_packet_buffer = net_rx_packets[0];
        return 0;
 }
 
 static int sb_eth_send(struct udevice *dev, void *packet, int length)
 {
+       struct eth_sandbox_priv *priv = dev_get_priv(dev);
+       struct ethernet_hdr *eth = packet;
+
        debug("eth_sandbox: Send packet %d\n", length);
 
+       if (dev->seq >= 0 && dev->seq < ARRAY_SIZE(disabled) &&
+           disabled[dev->seq])
+               return 0;
+
+       if (ntohs(eth->et_protlen) == PROT_ARP) {
+               struct arp_hdr *arp = packet + ETHER_HDR_SIZE;
+
+               if (ntohs(arp->ar_op) == ARPOP_REQUEST) {
+                       struct ethernet_hdr *eth_recv;
+                       struct arp_hdr *arp_recv;
+
+                       /* store this as the assumed IP of the fake host */
+                       priv->fake_host_ipaddr = net_read_ip(&arp->ar_tpa);
+                       /* Formulate a fake response */
+                       eth_recv = (void *)priv->recv_packet_buffer;
+                       memcpy(eth_recv->et_dest, eth->et_src, ARP_HLEN);
+                       memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
+                              ARP_HLEN);
+                       eth_recv->et_protlen = htons(PROT_ARP);
+
+                       arp_recv = (void *)priv->recv_packet_buffer +
+                               ETHER_HDR_SIZE;
+                       arp_recv->ar_hrd = htons(ARP_ETHER);
+                       arp_recv->ar_pro = htons(PROT_IP);
+                       arp_recv->ar_hln = ARP_HLEN;
+                       arp_recv->ar_pln = ARP_PLEN;
+                       arp_recv->ar_op = htons(ARPOP_REPLY);
+                       memcpy(&arp_recv->ar_sha, priv->fake_host_hwaddr,
+                              ARP_HLEN);
+                       net_write_ip(&arp_recv->ar_spa, priv->fake_host_ipaddr);
+                       memcpy(&arp_recv->ar_tha, &arp->ar_sha, ARP_HLEN);
+                       net_copy_ip(&arp_recv->ar_tpa, &arp->ar_spa);
+
+                       priv->recv_packet_length = ETHER_HDR_SIZE +
+                               ARP_HDR_SIZE;
+               }
+       } else if (ntohs(eth->et_protlen) == PROT_IP) {
+               struct ip_udp_hdr *ip = packet + ETHER_HDR_SIZE;
+
+               if (ip->ip_p == IPPROTO_ICMP) {
+                       struct icmp_hdr *icmp = (struct icmp_hdr *)&ip->udp_src;
+
+                       if (icmp->type == ICMP_ECHO_REQUEST) {
+                               struct ethernet_hdr *eth_recv;
+                               struct ip_udp_hdr *ipr;
+                               struct icmp_hdr *icmpr;
+
+                               /* reply to the ping */
+                               memcpy(priv->recv_packet_buffer, packet,
+                                      length);
+                               eth_recv = (void *)priv->recv_packet_buffer;
+                               ipr = (void *)priv->recv_packet_buffer +
+                                       ETHER_HDR_SIZE;
+                               icmpr = (struct icmp_hdr *)&ipr->udp_src;
+                               memcpy(eth_recv->et_dest, eth->et_src,
+                                      ARP_HLEN);
+                               memcpy(eth_recv->et_src, priv->fake_host_hwaddr,
+                                      ARP_HLEN);
+                               ipr->ip_sum = 0;
+                               ipr->ip_off = 0;
+                               net_copy_ip((void *)&ipr->ip_dst, &ip->ip_src);
+                               net_write_ip((void *)&ipr->ip_src,
+                                            priv->fake_host_ipaddr);
+                               ipr->ip_sum = compute_ip_checksum(ipr,
+                                       IP_HDR_SIZE);
+
+                               icmpr->type = ICMP_ECHO_REPLY;
+                               icmpr->checksum = 0;
+                               icmpr->checksum = compute_ip_checksum(icmpr,
+                                       ICMP_HDR_SIZE);
+
+                               priv->recv_packet_length = length;
+                       }
+               }
+       }
+
        return 0;
 }
 
-static int sb_eth_recv(struct udevice *dev, uchar **packetp)
+static int sb_eth_recv(struct udevice *dev, int flags, uchar **packetp)
 {
+       struct eth_sandbox_priv *priv = dev_get_priv(dev);
+
+       if (skip_timeout) {
+               sandbox_timer_add_offset(11000UL);
+               skip_timeout = false;
+       }
+
+       if (priv->recv_packet_length) {
+               int lcl_recv_packet_length = priv->recv_packet_length;
+
+               debug("eth_sandbox: received packet %d\n",
+                     priv->recv_packet_length);
+               priv->recv_packet_length = 0;
+               *packetp = priv->recv_packet_buffer;
+               return lcl_recv_packet_length;
+       }
        return 0;
 }
 
@@ -80,5 +221,6 @@ U_BOOT_DRIVER(eth_sandbox) = {
        .ofdata_to_platdata = sb_eth_ofdata_to_platdata,
        .remove = sb_eth_remove,
        .ops    = &sb_eth_ops,
+       .priv_auto_alloc_size = sizeof(struct eth_sandbox_priv),
        .platdata_auto_alloc_size = sizeof(struct eth_pdata),
 };