summaryrefslogtreecommitdiffstats
path: root/firmware/microblaze/lib
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/microblaze/lib')
-rw-r--r--firmware/microblaze/lib/Makefile.am12
-rw-r--r--firmware/microblaze/lib/arp_cache.c90
-rw-r--r--firmware/microblaze/lib/arp_cache.h33
-rw-r--r--firmware/microblaze/lib/banal.c49
-rw-r--r--firmware/microblaze/lib/banal.h93
-rw-r--r--firmware/microblaze/lib/eth_mac.h2
-rw-r--r--firmware/microblaze/lib/ethernet.h2
-rw-r--r--firmware/microblaze/lib/ethertype.h27
-rw-r--r--firmware/microblaze/lib/if_arp.h153
-rw-r--r--firmware/microblaze/lib/net_common.c435
-rw-r--r--firmware/microblaze/lib/net_common.h60
11 files changed, 952 insertions, 4 deletions
diff --git a/firmware/microblaze/lib/Makefile.am b/firmware/microblaze/lib/Makefile.am
index 0f5a5298c..02e9dda73 100644
--- a/firmware/microblaze/lib/Makefile.am
+++ b/firmware/microblaze/lib/Makefile.am
@@ -51,7 +51,10 @@ libu2fw_a_SOURCES = \
printf.c \
sd.c \
spi.c \
- u2_init.c
+ u2_init.c \
+ net_common.c \
+ arp_cache.c \
+ banal.c
noinst_HEADERS = \
ad9510.h \
@@ -84,7 +87,12 @@ noinst_HEADERS = \
stdio.h \
u2_init.h \
usrp2_bytesex.h \
- wb16550.h
+ wb16550.h \
+ net_common.h \
+ if_arp.h \
+ arp_cache.h \
+ banal.h \
+ ethertype.h
EXTRA_DIST = \
microblaze.ld
diff --git a/firmware/microblaze/lib/arp_cache.c b/firmware/microblaze/lib/arp_cache.c
new file mode 100644
index 000000000..9c586fa6b
--- /dev/null
+++ b/firmware/microblaze/lib/arp_cache.c
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "arp_cache.h"
+#include <stddef.h>
+
+typedef struct {
+ struct ip_addr ip;
+ eth_mac_addr_t mac;
+} arp_cache_t;
+
+#define NENTRIES 8 // power-of-2
+
+static size_t nentries;
+static size_t victim;
+static arp_cache_t cache[NENTRIES];
+
+void
+arp_cache_init(void)
+{
+ nentries = 0;
+ victim = 0;
+}
+
+// returns non-negative index if found, else -1
+static int
+arp_cache_lookup(const struct ip_addr *ip)
+{
+ int i;
+ for (i = 0; i < nentries; i++)
+ if (cache[i].ip.addr == ip->addr)
+ return i;
+
+ return -1;
+}
+
+static int
+arp_cache_alloc(void)
+{
+ if (nentries < NENTRIES)
+ return nentries++;
+
+ int i = victim;
+ victim = (victim + 1) % NENTRIES;
+ return i;
+}
+
+void
+arp_cache_update(const struct ip_addr *ip,
+ const eth_mac_addr_t *mac)
+{
+ int i = arp_cache_lookup(ip);
+ if (i < 0){
+ i = arp_cache_alloc();
+ cache[i].ip = *ip;
+ cache[i].mac = *mac;
+ }
+ else {
+ cache[i].mac = *mac;
+ }
+}
+
+bool
+arp_cache_lookup_mac(const struct ip_addr *ip,
+ eth_mac_addr_t *mac)
+{
+ int i = arp_cache_lookup(ip);
+ if (i < 0)
+ return false;
+
+ *mac = cache[i].mac;
+ return true;
+}
diff --git a/firmware/microblaze/lib/arp_cache.h b/firmware/microblaze/lib/arp_cache.h
new file mode 100644
index 000000000..8e84a1f94
--- /dev/null
+++ b/firmware/microblaze/lib/arp_cache.h
@@ -0,0 +1,33 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_ARP_CACHE_H
+#define INCLUDED_ARP_CACHE_H
+
+#include <lwip/ip_addr.h>
+#include <net/eth_mac_addr.h>
+#include <stdbool.h>
+
+void arp_cache_init(void);
+
+void arp_cache_update(const struct ip_addr *ip,
+ const eth_mac_addr_t *mac);
+
+bool arp_cache_lookup_mac(const struct ip_addr *ip,
+ eth_mac_addr_t *mac);
+
+#endif /* INCLUDED_ARP_CACHE_H */
diff --git a/firmware/microblaze/lib/banal.c b/firmware/microblaze/lib/banal.c
new file mode 100644
index 000000000..23f5f3b8a
--- /dev/null
+++ b/firmware/microblaze/lib/banal.c
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <banal.h>
+
+uint32_t
+get_uint32(const unsigned char *s)
+{
+ return (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3];
+}
+
+uint64_t
+get_uint64(const unsigned char *s)
+{
+ return (((uint64_t)get_uint32(s)) << 32) | get_uint32(s+4);
+}
+
+uint32_t
+divide_uint64(uint64_t dividend, uint32_t divisor)
+{
+ uint32_t result = 0;
+ uint64_t dividend_ = 0;
+ for(int i = 31; i >= 0; i--){
+ //approximate the divisor with the ith result bit set
+ uint64_t tmp = dividend_;
+ tmp += (uint64_t)divisor << i;
+ //set the ith result bit if the approximation is less
+ if (tmp <= dividend){
+ dividend_ = tmp;
+ result |= 1 << i;
+ }
+ }
+ return result;
+}
diff --git a/firmware/microblaze/lib/banal.h b/firmware/microblaze/lib/banal.h
new file mode 100644
index 000000000..6d9420602
--- /dev/null
+++ b/firmware/microblaze/lib/banal.h
@@ -0,0 +1,93 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_BANAL_H
+#define INCLUDED_BANAL_H
+
+#include <stdint.h>
+#include <lwip/ip_addr.h>
+
+/*
+ * 1's complement sum for IP and UDP headers
+ *
+ * init chksum to zero to start.
+ */
+static inline unsigned int
+CHKSUM(unsigned int x, unsigned int *chksum)
+{
+ *chksum += x;
+ *chksum = (*chksum & 0xffff) + (*chksum>>16);
+ *chksum = (*chksum & 0xffff) + (*chksum>>16);
+ return x;
+}
+
+unsigned int
+chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum);
+
+//-------------- unsigned get_int 8, 16, 32, 64 --------------//
+
+static inline uint8_t
+get_uint8(const unsigned char *s)
+{
+ return s[0];
+}
+
+static inline uint16_t
+get_uint16(const unsigned char *s)
+{
+ return (s[0] << 8) | s[1];
+}
+
+uint32_t
+get_uint32(const unsigned char *s);
+
+uint64_t
+get_uint64(const unsigned char *s);
+
+//--------------- signed get_int 8, 16, 32, 64 --------------//
+
+static inline int8_t
+get_int8(const unsigned char *s)
+{
+ return get_uint8(s);
+}
+
+static inline int16_t
+get_int16(const unsigned char *s)
+{
+ return get_uint16(s);
+}
+
+static inline int32_t
+get_int32(const unsigned char *s)
+{
+ return get_uint32(s);
+}
+
+static inline int64_t
+get_int64(const unsigned char *s)
+{
+ return get_uint64(s);
+}
+
+void
+print_ip(struct ip_addr ip);
+
+uint32_t
+divide_uint64(uint64_t dividend, uint32_t divisor);
+
+#endif /* INCLUDED_BANAL_H */
diff --git a/firmware/microblaze/lib/eth_mac.h b/firmware/microblaze/lib/eth_mac.h
index 65717f6f8..73feec955 100644
--- a/firmware/microblaze/lib/eth_mac.h
+++ b/firmware/microblaze/lib/eth_mac.h
@@ -19,7 +19,7 @@
#ifndef INCLUDED_ETH_MAC_H
#define INCLUDED_ETH_MAC_H
-#include "network.h"
+#include <net/eth_mac_addr.h>
void eth_mac_init(const eth_mac_addr_t *src);
diff --git a/firmware/microblaze/lib/ethernet.h b/firmware/microblaze/lib/ethernet.h
index 0e42d9b8d..70b7077c6 100644
--- a/firmware/microblaze/lib/ethernet.h
+++ b/firmware/microblaze/lib/ethernet.h
@@ -19,7 +19,7 @@
#ifndef INCLUDED_ETHERNET_H
#define INCLUDED_ETHERNET_H
-#include "network.h"
+#include <net/eth_mac_addr.h>
#include <stdbool.h>
typedef void (*ethernet_link_changed_callback_t)(int speed);
diff --git a/firmware/microblaze/lib/ethertype.h b/firmware/microblaze/lib/ethertype.h
new file mode 100644
index 000000000..11f4bafec
--- /dev/null
+++ b/firmware/microblaze/lib/ethertype.h
@@ -0,0 +1,27 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_ETHERTYPE_H
+#define INCLUDED_ETHERTYPE_H
+
+// all we care about
+
+#define ETHERTYPE_IPV4 0x0800
+#define ETHERTYPE_ARP 0x0806
+
+
+#endif /* INCLUDED_ETHERTYPE_H */
diff --git a/firmware/microblaze/lib/if_arp.h b/firmware/microblaze/lib/if_arp.h
new file mode 100644
index 000000000..63519c4be
--- /dev/null
+++ b/firmware/microblaze/lib/if_arp.h
@@ -0,0 +1,153 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the ARP (RFC 826) protocol.
+ *
+ * Version: @(#)if_arp.h 1.0.1 04/16/93
+ *
+ * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988
+ * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source.
+ * Ross Biro
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Florian La Roche,
+ * Jonathan Layes <layes@loran.com>
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _LINUX_IF_ARP_H
+#define _LINUX_IF_ARP_H
+
+/* ARP protocol HARDWARE identifiers. */
+#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */
+#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */
+#define ARPHRD_EETHER 2 /* Experimental Ethernet */
+#define ARPHRD_AX25 3 /* AX.25 Level 2 */
+#define ARPHRD_PRONET 4 /* PROnet token ring */
+#define ARPHRD_CHAOS 5 /* Chaosnet */
+#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */
+#define ARPHRD_ARCNET 7 /* ARCnet */
+#define ARPHRD_APPLETLK 8 /* APPLEtalk */
+#define ARPHRD_DLCI 15 /* Frame Relay DLCI */
+#define ARPHRD_ATM 19 /* ATM */
+#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */
+#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */
+#define ARPHRD_EUI64 27 /* EUI-64 */
+#define ARPHRD_INFINIBAND 32 /* InfiniBand */
+
+/* Dummy types for non ARP hardware */
+#define ARPHRD_SLIP 256
+#define ARPHRD_CSLIP 257
+#define ARPHRD_SLIP6 258
+#define ARPHRD_CSLIP6 259
+#define ARPHRD_RSRVD 260 /* Notional KISS type */
+#define ARPHRD_ADAPT 264
+#define ARPHRD_ROSE 270
+#define ARPHRD_X25 271 /* CCITT X.25 */
+#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */
+#define ARPHRD_CAN 280 /* Controller Area Network */
+#define ARPHRD_PPP 512
+#define ARPHRD_CISCO 513 /* Cisco HDLC */
+#define ARPHRD_HDLC ARPHRD_CISCO
+#define ARPHRD_LAPB 516 /* LAPB */
+#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */
+#define ARPHRD_RAWHDLC 518 /* Raw HDLC */
+
+#define ARPHRD_TUNNEL 768 /* IPIP tunnel */
+#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */
+#define ARPHRD_FRAD 770 /* Frame Relay Access Device */
+#define ARPHRD_SKIP 771 /* SKIP vif */
+#define ARPHRD_LOOPBACK 772 /* Loopback device */
+#define ARPHRD_LOCALTLK 773 /* Localtalk device */
+#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */
+#define ARPHRD_BIF 775 /* AP1000 BIF */
+#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */
+#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */
+#define ARPHRD_IPGRE 778 /* GRE over IP */
+#define ARPHRD_PIMREG 779 /* PIMSM register interface */
+#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */
+#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */
+#define ARPHRD_ECONET 782 /* Acorn Econet */
+#define ARPHRD_IRDA 783 /* Linux-IrDA */
+/* ARP works differently on different FC media .. so */
+#define ARPHRD_FCPP 784 /* Point to point fibrechannel */
+#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */
+#define ARPHRD_FCPL 786 /* Fibrechannel public loop */
+#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */
+ /* 787->799 reserved for fibrechannel media types */
+#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */
+#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */
+#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */
+#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */
+
+#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
+#define ARPHRD_NONE 0xFFFE /* zero header length */
+
+/* ARP protocol opcodes. */
+#define ARPOP_REQUEST 1 /* ARP request */
+#define ARPOP_REPLY 2 /* ARP reply */
+#define ARPOP_RREQUEST 3 /* RARP request */
+#define ARPOP_RREPLY 4 /* RARP reply */
+#define ARPOP_InREQUEST 8 /* InARP request */
+#define ARPOP_InREPLY 9 /* InARP reply */
+#define ARPOP_NAK 10 /* (ATM)ARP NAK */
+
+
+/* ARP Flag values. */
+#define ATF_COM 0x02 /* completed entry (ha valid) */
+#define ATF_PERM 0x04 /* permanent entry */
+#define ATF_PUBL 0x08 /* publish entry */
+#define ATF_USETRAILERS 0x10 /* has requested trailers */
+#define ATF_NETMASK 0x20 /* want to use a netmask (only
+ for proxy entries) */
+#define ATF_DONTPUB 0x40 /* don't answer this addresses */
+
+typedef unsigned short __be16;
+
+/*
+ * This structure defines an ethernet arp header.
+ */
+struct arphdr
+{
+ __be16 ar_hrd; /* format of hardware address */
+ __be16 ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ __be16 ar_op; /* ARP opcode (command) */
+
+#if 0
+ /*
+ * Ethernet looks like this : This bit is variable sized however...
+ */
+ unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+#endif
+
+};
+
+/*
+ * This structure defines an ethernet arp header.
+ */
+struct arp_eth_ipv4
+{
+ __be16 ar_hrd; /* format of hardware address */
+ __be16 ar_pro; /* format of protocol address */
+ unsigned char ar_hln; /* length of hardware address */
+ unsigned char ar_pln; /* length of protocol address */
+ __be16 ar_op; /* ARP opcode (command) */
+
+ unsigned char ar_sha[6]; /* sender hardware address */
+ unsigned char ar_sip[4]; /* sender IP address */
+ unsigned char ar_tha[6]; /* target hardware address */
+ unsigned char ar_tip[4]; /* target IP address */
+};
+
+
+#endif /* _LINUX_IF_ARP_H */
diff --git a/firmware/microblaze/lib/net_common.c b/firmware/microblaze/lib/net_common.c
new file mode 100644
index 000000000..693502d18
--- /dev/null
+++ b/firmware/microblaze/lib/net_common.c
@@ -0,0 +1,435 @@
+/* -*- c -*- */
+/*
+ * Copyright 2009,2010 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "net_common.h"
+#include "banal.h"
+#include <hal_io.h>
+#include <buffer_pool.h>
+#include <memory_map.h>
+#include <memcpy_wa.h>
+#include <ethernet.h>
+#include <net/padded_eth_hdr.h>
+#include <lwip/ip.h>
+#include <lwip/udp.h>
+#include <lwip/icmp.h>
+#include <stdlib.h>
+#include <nonstdio.h>
+#include "arp_cache.h"
+#include "if_arp.h"
+#include <ethertype.h>
+#include <string.h>
+
+
+int cpu_tx_buf_dest_port = PORT_ETH;
+
+// If this is non-zero, this dbsm could be writing to the ethernet
+dbsm_t *ac_could_be_sending_to_eth;
+
+static inline bool
+ip_addr_eq(const struct ip_addr a, const struct ip_addr b)
+{
+ return a.addr == b.addr;
+}
+
+// ------------------------------------------------------------------------
+
+get_eth_mac_addr_t _get_eth_mac_addr = NULL;
+
+void register_get_eth_mac_addr(get_eth_mac_addr_t get_eth_mac_addr){
+ _get_eth_mac_addr = get_eth_mac_addr;
+}
+
+get_ip_addr_t _get_ip_addr = NULL;
+
+void register_get_ip_addr(get_ip_addr_t get_ip_addr){
+ _get_ip_addr = get_ip_addr;
+}
+
+//-------------------------------------------------------------------------
+
+#define MAX_UDP_LISTENERS 6
+
+struct listener_entry {
+ unsigned short port;
+ udp_receiver_t rcvr;
+};
+
+static struct listener_entry listeners[MAX_UDP_LISTENERS];
+
+static struct listener_entry *
+find_listener_by_port(unsigned short port)
+{
+ for (int i = 0; i < MAX_UDP_LISTENERS; i++){
+ if (port == listeners[i].port)
+ return &listeners[i];
+ }
+ return 0;
+}
+
+static struct listener_entry *
+find_free_listener(void)
+{
+ for (int i = 0; i < MAX_UDP_LISTENERS; i++){
+ if (listeners[i].rcvr == 0)
+ return &listeners[i];
+ }
+ abort();
+}
+
+void
+register_udp_listener(int port, udp_receiver_t rcvr)
+{
+ struct listener_entry *lx = find_listener_by_port(port);
+ if (lx)
+ lx->rcvr = rcvr;
+ else {
+ lx = find_free_listener();
+ lx->port = port;
+ lx->rcvr = rcvr;
+ }
+}
+
+// ------------------------------------------------------------------------
+
+
+/*!
+ * low level routine to assembly an ethernet frame and send it.
+ *
+ * \param dst destination mac address
+ * \param ethertype ethertype field
+ * \param buf0 first part of data
+ * \param len0 length of first part of data
+ * \param buf1 second part of data
+ * \param len1 length of second part of data
+ * \param buf2 third part of data
+ * \param len2 length of third part of data
+ */
+static void
+send_pkt(eth_mac_addr_t dst, int ethertype,
+ const void *buf0, size_t len0,
+ const void *buf1, size_t len1,
+ const void *buf2, size_t len2)
+{
+ // Wait for buffer to become idle
+ // FIXME can this ever not be ready?
+
+ //hal_set_leds(LED_BUF_BUSY, LED_BUF_BUSY);
+ while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0)
+ ;
+ //hal_set_leds(0, LED_BUF_BUSY);
+
+ // Assemble the header
+ padded_eth_hdr_t ehdr;
+ ehdr.pad = 0;
+ ehdr.dst = dst;
+ ehdr.src = _get_eth_mac_addr();
+ ehdr.ethertype = ethertype;
+
+ uint32_t *p = buffer_ram(CPU_TX_BUF);
+
+ // Copy the pieces into the buffer
+ *p++ = 0x0; // slow path
+ memcpy_wa(p, &ehdr, sizeof(ehdr)); // 4 lines
+ p += sizeof(ehdr)/sizeof(uint32_t);
+
+
+ // FIXME modify memcpy_wa to do read/modify/write if reqd
+
+ if (len0 && ((len0 & 0x3) || (intptr_t) buf0 & 0x3))
+ printf("send_pkt: bad alignment of len0 and/or buf0\n");
+
+ if (len1 && ((len1 & 0x3) || (intptr_t) buf1 & 0x3))
+ printf("send_pkt: bad alignment of len1 and/or buf1\n");
+
+ if (len2 && ((len2 & 0x3) || (intptr_t) buf2 & 0x3))
+ printf("send_pkt: bad alignment of len2 and/or buf2\n");
+
+ if (len0){
+ memcpy_wa(p, buf0, len0);
+ p += len0/sizeof(uint32_t);
+ }
+ if (len1){
+ memcpy_wa(p, buf1, len1);
+ p += len1/sizeof(uint32_t);
+ }
+ if (len2){
+ memcpy_wa(p, buf2, len2);
+ p += len2/sizeof(uint32_t);
+ }
+
+ size_t total_len = (p - buffer_ram(CPU_TX_BUF)) * sizeof(uint32_t);
+ if (total_len < 60) // ensure that we don't try to send a short packet
+ total_len = 60;
+
+ // wait until nobody else is sending to the ethernet
+ if (ac_could_be_sending_to_eth){
+ //hal_set_leds(LED_ETH_BUSY, LED_ETH_BUSY);
+ dbsm_wait_for_opening(ac_could_be_sending_to_eth);
+ //hal_set_leds(0x0, LED_ETH_BUSY);
+ }
+
+ if (0){
+ printf("send_pkt to port %d, len = %d\n",
+ cpu_tx_buf_dest_port, (int) total_len);
+ print_buffer(buffer_ram(CPU_TX_BUF), total_len/4);
+ }
+
+ // fire it off
+ bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, total_len/4);
+
+ // wait for it to complete (not long, it's a small pkt)
+ while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0)
+ ;
+
+ bp_clear_buf(CPU_TX_BUF);
+}
+
+unsigned int
+chksum_buffer(unsigned short *buf, int nshorts, unsigned int initial_chksum)
+{
+ unsigned int chksum = initial_chksum;
+ for (int i = 0; i < nshorts; i++)
+ CHKSUM(buf[i], &chksum);
+
+ return chksum;
+}
+
+
+void
+send_ip_pkt(struct ip_addr dst, int protocol,
+ const void *buf0, size_t len0,
+ const void *buf1, size_t len1)
+{
+ struct ip_addr src = _get_ip_addr();
+ int ttl = 32;
+
+ struct ip_hdr ip;
+ IPH_VHLTOS_SET(&ip, 4, 5, 0);
+ IPH_LEN_SET(&ip, IP_HLEN + len0 + len1);
+ IPH_ID_SET(&ip, 0);
+ IPH_OFFSET_SET(&ip, IP_DF); /* don't fragment */
+ ip._ttl_proto = (ttl << 8) | (protocol & 0xff);
+ ip._chksum = 0;
+ ip.src = src;
+ ip.dest = dst;
+
+ ip._chksum = ~chksum_buffer((unsigned short *) &ip,
+ sizeof(ip)/sizeof(short), 0);
+
+ eth_mac_addr_t dst_mac;
+ bool found = arp_cache_lookup_mac(&ip.dest, &dst_mac);
+ if (!found){
+ printf("net_common: failed to hit cache looking for ");
+ print_ip(ip.dest);
+ newline();
+ return;
+ }
+
+ send_pkt(dst_mac, ETHERTYPE_IPV4,
+ &ip, sizeof(ip), buf0, len0, buf1, len1);
+}
+
+void
+send_udp_pkt(int src_port, struct socket_address dst,
+ const void *buf, size_t len)
+{
+ struct udp_hdr udp _AL4;
+ udp.src = src_port;
+ udp.dest = dst.port;
+ udp.len = UDP_HLEN + len;
+ udp.chksum = 0;
+
+ send_ip_pkt(dst.addr, IP_PROTO_UDP,
+ &udp, sizeof(udp), buf, len);
+}
+
+static void
+handle_udp_packet(struct ip_addr src_ip, struct ip_addr dst_ip,
+ struct udp_hdr *udp, size_t len)
+{
+ if (len != udp->len){
+ printf("UDP inconsistent lengths: %d %d\n", (int)len, udp->len);
+ return;
+ }
+
+ unsigned char *payload = ((unsigned char *) udp) + UDP_HLEN;
+ int payload_len = len - UDP_HLEN;
+
+ if (0){
+ printf("\nUDP: src = %d dst = %d len = %d\n",
+ udp->src, udp->dest, udp->len);
+
+ //print_bytes(0, payload, payload_len);
+ }
+
+ struct listener_entry *lx = find_listener_by_port(udp->dest);
+ if (lx){
+ struct socket_address src = make_socket_address(src_ip, udp->src);
+ struct socket_address dst = make_socket_address(dst_ip, udp->dest);
+ lx->rcvr(src, dst, payload, payload_len);
+ }
+}
+
+static void
+handle_icmp_packet(struct ip_addr src, struct ip_addr dst,
+ struct icmp_echo_hdr *icmp, size_t len)
+{
+ switch (icmp->type){
+ case ICMP_DUR: // Destinatino Unreachable
+ //stop_streaming(); //FIXME
+ if (icmp->code == ICMP_DUR_PORT){ // port unreachable
+ //struct udp_hdr *udp = (struct udp_hdr *)((char *)icmp + 28);
+ //printf("icmp port unr %d\n", udp->dest);
+ putchar('i');
+ }
+ else {
+ //printf("icmp dst unr (code: %d)", icmp->code);
+ putchar('i');
+ }
+ break;
+
+ case ICMP_ECHO:
+ default:
+ break;
+ }
+}
+
+static void __attribute__((unused))
+print_arp_ip(const unsigned char ip[4])
+{
+ printf("%d.%d.%d.%d", ip[0], ip[1], ip[2],ip[3]);
+}
+
+static void
+send_arp_reply(struct arp_eth_ipv4 *req, eth_mac_addr_t our_mac)
+{
+ struct arp_eth_ipv4 reply _AL4;
+ reply.ar_hrd = req->ar_hrd;
+ reply.ar_pro = req->ar_pro;
+ reply.ar_hln = req->ar_hln;
+ reply.ar_pln = req->ar_pln;
+ reply.ar_op = ARPOP_REPLY;
+ memcpy(reply.ar_sha, &our_mac, 6);
+ memcpy(reply.ar_sip, req->ar_tip, 4);
+ memcpy(reply.ar_tha, req->ar_sha, 6);
+ memcpy(reply.ar_tip, req->ar_sip, 4);
+
+ eth_mac_addr_t t;
+ memcpy(t.addr, reply.ar_tha, 6);
+ send_pkt(t, ETHERTYPE_ARP, &reply, sizeof(reply), 0, 0, 0, 0);
+}
+
+
+static void
+handle_arp_packet(struct arp_eth_ipv4 *p, size_t size)
+{
+ if (size < sizeof(struct arp_eth_ipv4)){
+ printf("\nhandle_arp: weird size = %d\n", (int)size);
+ return;
+ }
+
+ if (0){
+ printf("ar_hrd = %d\n", p->ar_hrd);
+ printf("ar_pro = %d\n", p->ar_pro);
+ printf("ar_hln = %d\n", p->ar_hln);
+ printf("ar_pln = %d\n", p->ar_pln);
+ printf("ar_op = %d\n", p->ar_op);
+ printf("ar_sha = "); print_mac_addr(p->ar_sha); newline();
+ printf("ar_sip = "); print_arp_ip(p->ar_sip); newline();
+ printf("ar_tha = "); print_mac_addr(p->ar_tha); newline();
+ printf("ar_tip = "); print_arp_ip(p->ar_tip); newline();
+ }
+
+ if (p->ar_hrd != ARPHRD_ETHER
+ || p->ar_pro != ETHERTYPE_IPV4
+ || p->ar_hln != 6
+ || p->ar_pln != 4)
+ return;
+
+ if (p->ar_op != ARPOP_REQUEST)
+ return;
+
+ struct ip_addr sip;
+ struct ip_addr tip;
+
+ sip.addr = get_int32(p->ar_sip);
+ tip.addr = get_int32(p->ar_tip);
+
+ if (ip_addr_eq(tip, _get_ip_addr())){ // They're looking for us...
+ send_arp_reply(p, _get_eth_mac_addr());
+ }
+}
+
+void
+handle_eth_packet(uint32_t *p, size_t nlines)
+{
+ //print_buffer(p, nlines);
+
+ int ethertype = p[3] & 0xffff;
+
+ if (ethertype == ETHERTYPE_ARP){
+ struct arp_eth_ipv4 *arp = (struct arp_eth_ipv4 *)(p + 4);
+ handle_arp_packet(arp, nlines*sizeof(uint32_t) - 14);
+ }
+ else if (ethertype == ETHERTYPE_IPV4){
+ struct ip_hdr *ip = (struct ip_hdr *)(p + 4);
+ if (IPH_V(ip) != 4 || IPH_HL(ip) != 5) // ignore pkts w/ bad version or options
+ return;
+
+ if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK)) // ignore fragmented packets
+ return;
+
+ // FIXME filter on dest ip addr (should be broadcast or for us)
+
+ arp_cache_update(&ip->src, (eth_mac_addr_t *)(((char *)p)+8));
+
+ int protocol = IPH_PROTO(ip);
+ int len = IPH_LEN(ip) - IP_HLEN;
+
+ switch (protocol){
+ case IP_PROTO_UDP:
+ handle_udp_packet(ip->src, ip->dest, (struct udp_hdr *)(((char *)ip) + IP_HLEN), len);
+ break;
+
+ case IP_PROTO_ICMP:
+ handle_icmp_packet(ip->src, ip->dest, (struct icmp_echo_hdr *)(((char *)ip) + IP_HLEN), len);
+ break;
+
+ default: // ignore
+ break;
+ }
+ }
+ else
+ return; // Not ARP or IPV4, ignore
+}
+
+// ------------------------------------------------------------------------
+
+void
+print_ip(struct ip_addr ip)
+{
+ unsigned int t = ntohl(ip.addr);
+ printf("%d.%d.%d.%d",
+ (t >> 24) & 0xff,
+ (t >> 16) & 0xff,
+ (t >> 8) & 0xff,
+ t & 0xff);
+}
diff --git a/firmware/microblaze/lib/net_common.h b/firmware/microblaze/lib/net_common.h
new file mode 100644
index 000000000..cfba43412
--- /dev/null
+++ b/firmware/microblaze/lib/net_common.h
@@ -0,0 +1,60 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2009,2010 Ettus Research LLC
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef INCLUDED_NET_COMMON_H
+#define INCLUDED_NET_COMMON_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <dbsm.h>
+#include <net/socket_address.h>
+#include <net/eth_mac_addr.h>
+
+#define CPU_TX_BUF 7 // cpu -> eth
+
+extern int cpu_tx_buf_dest_port;
+
+// If this is non-zero, this dbsm could be writing to the ethernet
+extern dbsm_t *ac_could_be_sending_to_eth;
+
+void stop_streaming(void);
+
+/*!
+ * Helpful typedefs for callback
+ */
+typedef void (*udp_receiver_t)(struct socket_address src, struct socket_address dst,
+ unsigned char *payload, int payload_len);
+
+typedef eth_mac_addr_t (*get_eth_mac_addr_t)(void);
+typedef struct ip_addr (*get_ip_addr_t)(void);
+
+/*!
+ * Functions to register callbacks
+ */
+void register_get_eth_mac_addr(get_eth_mac_addr_t get_eth_mac_addr);
+
+void register_get_ip_addr(get_ip_addr_t get_ip_addr);
+
+void register_udp_listener(int port, udp_receiver_t rcvr);
+
+void send_udp_pkt(int src_port, struct socket_address dst,
+ const void *buf, size_t len);
+
+void handle_eth_packet(uint32_t *p, size_t nlines);
+
+
+#endif /* INCLUDED_NET_COMMON_H */