Wed Oct 7 00:43:05 2020 UTC ()
- Add tap(4) networking support to gxemul. See the networking documentation
for it's theory of operation in gxemul and how to configure it.
- Add address filtering to the LANCE and Tulip emulation.
These changes have already been upstreamed in the main gxemul repository.
Bump package version to gxemul-0.6.2nb1.
(thorpej)
diff -r1.67 -r1.68 pkgsrc/emulators/gxemul/Makefile
diff -r1.60 -r1.61 pkgsrc/emulators/gxemul/distinfo
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-doc_networking.html
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_dec21143.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_ether.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_le.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_rtl8139c.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_sgi_mec.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_devices_dev_sn.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_include_net.h
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_net_Makefile.skel
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_net_net.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_net_net_ether.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_net_net_ip.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_net_net_tap.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_old_main_emul.cc
diff -r0 -r1.1 pkgsrc/emulators/gxemul/patches/patch-src_old_main_emul_parse.cc
--- pkgsrc/emulators/gxemul/Makefile 2019/08/23 13:13:49 1.67
+++ pkgsrc/emulators/gxemul/Makefile 2020/10/07 00:43:04 1.68
| @@ -1,16 +1,17 @@ | | | @@ -1,16 +1,17 @@ |
1 | # $NetBSD: Makefile,v 1.67 2019/08/23 13:13:49 ryoon Exp $ | | 1 | # $NetBSD: Makefile,v 1.68 2020/10/07 00:43:04 thorpej Exp $ |
2 | | | 2 | |
3 | DISTNAME= gxemul-0.6.2 | | 3 | DISTNAME= gxemul-0.6.2 |
| | | 4 | PKGREVISION= 1 |
4 | CATEGORIES= emulators | | 5 | CATEGORIES= emulators |
5 | MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=gxemul/} | | 6 | MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=gxemul/} |
6 | | | 7 | |
7 | MAINTAINER= pkgsrc-users@NetBSD.org | | 8 | MAINTAINER= pkgsrc-users@NetBSD.org |
8 | HOMEPAGE= http://gavare.se/gxemul/ | | 9 | HOMEPAGE= http://gavare.se/gxemul/ |
9 | COMMENT= Framework for full-system computer architecture emulation | | 10 | COMMENT= Framework for full-system computer architecture emulation |
10 | LICENSE= modified-bsd | | 11 | LICENSE= modified-bsd |
11 | | | 12 | |
12 | USE_TOOLS+= pax | | 13 | USE_TOOLS+= pax |
13 | | | 14 | |
14 | USE_LANGUAGES= c c++ | | 15 | USE_LANGUAGES= c c++ |
15 | HAS_CONFIGURE= yes | | 16 | HAS_CONFIGURE= yes |
16 | BUILD_TARGET= build | | 17 | BUILD_TARGET= build |
--- pkgsrc/emulators/gxemul/distinfo 2019/08/23 13:13:49 1.60
+++ pkgsrc/emulators/gxemul/distinfo 2020/10/07 00:43:04 1.61
| @@ -1,6 +1,21 @@ | | | @@ -1,6 +1,21 @@ |
1 | $NetBSD: distinfo,v 1.60 2019/08/23 13:13:49 ryoon Exp $ | | 1 | $NetBSD: distinfo,v 1.61 2020/10/07 00:43:04 thorpej Exp $ |
2 | | | 2 | |
3 | SHA1 (gxemul-0.6.2.tar.gz) = aabaeba783e70be952ab0056bf84d0f2b70c2155 | | 3 | SHA1 (gxemul-0.6.2.tar.gz) = aabaeba783e70be952ab0056bf84d0f2b70c2155 |
4 | RMD160 (gxemul-0.6.2.tar.gz) = ccac73d82446f89792b1fc803bee623813f3aab2 | | 4 | RMD160 (gxemul-0.6.2.tar.gz) = ccac73d82446f89792b1fc803bee623813f3aab2 |
5 | SHA512 (gxemul-0.6.2.tar.gz) = 4f389c509f9ecf39603ceed50e899e2bee285d3fefac9b3214076115ee71b5a7a68d1d92690b6debc8de5cf5f0303da83b3cc921a5c0b5eb4c7ad89baa730b59 | | 5 | SHA512 (gxemul-0.6.2.tar.gz) = 4f389c509f9ecf39603ceed50e899e2bee285d3fefac9b3214076115ee71b5a7a68d1d92690b6debc8de5cf5f0303da83b3cc921a5c0b5eb4c7ad89baa730b59 |
6 | Size (gxemul-0.6.2.tar.gz) = 5897883 bytes | | 6 | Size (gxemul-0.6.2.tar.gz) = 5897883 bytes |
| | | 7 | SHA1 (patch-doc_networking.html) = dd7a1519a678196fd5a835317a32ba483630ece8 |
| | | 8 | SHA1 (patch-src_devices_dev_dec21143.cc) = 52f36741038c76a2dbafc7da6737e816aed5c9f9 |
| | | 9 | SHA1 (patch-src_devices_dev_ether.cc) = 00221e09530743e81faedcc75ee951fa853d0e2c |
| | | 10 | SHA1 (patch-src_devices_dev_le.cc) = a728e8008a7a9f33aaf95811a33ebac2cb86e80e |
| | | 11 | SHA1 (patch-src_devices_dev_rtl8139c.cc) = ee6dbba7c7c9c62c50493c476297ee5ac89d2b83 |
| | | 12 | SHA1 (patch-src_devices_dev_sgi_mec.cc) = 24b1259350faf60265df7958f0f680302f475e8e |
| | | 13 | SHA1 (patch-src_devices_dev_sn.cc) = e939521be1630f51e7ddc67abe90980de38e8837 |
| | | 14 | SHA1 (patch-src_include_net.h) = 4d31fcefe384fcc9d68255825240c89b45acc92e |
| | | 15 | SHA1 (patch-src_net_Makefile.skel) = 4738229a928b9cb5a2531dfc357297f91e9fdc09 |
| | | 16 | SHA1 (patch-src_net_net.cc) = 57397c9a8197ee25e7faa8c0733273014e3e0670 |
| | | 17 | SHA1 (patch-src_net_net_ether.cc) = ef7464dbb0812a9cb8d5be806db07cc19853fc1e |
| | | 18 | SHA1 (patch-src_net_net_ip.cc) = f5615f3b347e9bdcd256fa4b5b1594473fd2e5e4 |
| | | 19 | SHA1 (patch-src_net_net_tap.cc) = f913b3efb51bc4a8080420988d5fc845e8a38f73 |
| | | 20 | SHA1 (patch-src_old_main_emul.cc) = 0b1106745e7c5d320e93f9f7775d8ced6109c089 |
| | | 21 | SHA1 (patch-src_old_main_emul_parse.cc) = 23048bc3a0a83fd189b3bbd4656ef0e1a2c23b99 |
$NetBSD: patch-doc_networking.html,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Document tap(4)-based networking.
--- doc/networking.html.orig 2020-10-05 22:53:41.969487340 +0000
+++ doc/networking.html 2020-10-05 22:54:17.309695478 +0000
@@ -46,6 +46,7 @@ SUCH DAMAGE.
<p><br>
<ul>
<li><a href="#intro">Introduction</a>
+ <li><a href="#tap">Virtual Ethernet switch using a tap device</a>
<li><a href="#multihost">Network across multiple hosts</a>
<li><a href="#direct_example_1">Direct-access example 1: udp_snoop</a>
</ul>
@@ -60,9 +61,11 @@ SUCH DAMAGE.
<a name="intro"></a>
<h3>Introduction:</h3>
-<p>GXemul's current networking layer supports two modes:
+<p>GXemul's current networking layer supports three modes:
<p><ol>
+ <li>A vitual Ethernet switch built on top of a <i>tap</i> device.
+ <p>
<li>A NAT-like layer, which allows guest OSes to access the outside
internet world (IPv4 only, so far). When only one machine is being
emulated, the following default values apply to the guest OS:<pre>
@@ -78,7 +81,7 @@ SUCH DAMAGE.
ethernet packages from/to the emulator.
</ol>
-<p><i>NOTE:</i> Both these modes have problems. The NAT-like layer is very
+<p><i>NOTE:</i> The latter two modes have problems. The NAT-like layer is very
"hackish" and was only meant as a proof-of-concept, to see if networking
like this would work with e.g. NetBSD as a guest OS. (If you are
interested in the technical details, and the reasons why NAT networking is
@@ -120,6 +123,83 @@ href="machine_decstation.html#netbsdpmax
+<p><br>
+<a name="tap"></a>
+<h3>Virtual Ethernet switch using a <i>tap</i> device:</h3>
+
+<p>The simplest way to emulate a real Ethernet network is using a <i>tap</i>
+device. In this mode, the emulator disables the simulated NAT and
+direct-access machinery and internally treats all emulated NICs as if
+they are on a single Ethernet switch. In this mode, packets destined for
+the guest's specific MAC address as well as Ethernet multicast and broadcast
+packets are send to the individual guest instances. Individual NIC
+emulations may also apply their own multicast filtering; multcast filtering
+is implemented for the DEC 21143 and Lance NICs.
+
+<p>The <i>tap</i> interface on the host can be thought of as an upstream
+link on the virtual Ethernet switch. In addition to providing a "port"
+for the host, the <i>tap</i> interface can be bridged to a physical Ethernet
+port on the host, allowing the guests to access the host's connected LAN.
+
+<p>Networking services such as DHCP and DNS must be provided either by
+the host or by the host's connected LAN.
+
+<p>Support for the <i>tap</i> device was developed on NetBSD, but should
+also work on FreeBSD, OpenBSD, and Linux hosts.
+
+<p>Here is a simple example:
+
+<p><pre>
+<font color="#2020cf">! Configuration file for
+! virtual Ethernet switch networking
+! using a tap device.</font>
+
+<b>net(</b>
+ <b>tapdev(</b><font color="#ff003f">"/dev/tap0"</font><b>)</b>
+<b>)</b>
+<b>machine(</b>
+ <b>name(<font color="#ff003f">"guest machine"</font>)</b>
+
+ <b>type(<font color="#ff003f">"dec"</font>)</b>
+ <b>subtype(<font color="#ff003f">"5000/200"</font>)</b>
+
+ <font color="#2020cf">! Add a disk, etc.</font>
+<b>)</b>
+</pre>
+
+<p>Before starting the emulator, you will need to create the <i>tap</i>
+interface on the host. Here is an example for NetBSD:
+
+<p><pre>
+<b>#ifconfig tap0 create up</b>
+</pre>
+
+<p>If you wish to simply network the host and the guests together, then
+simply assign an IP address to the <i>tap</i> interface on the host:
+
+<p><pre>
+<b># ifconfig tap0 10.0.0.254</b>
+</pre>
+
+<p>You can now run a DHCP server on the host for the guests, or you can
+configure the guests manually.
+
+<p>If instead you would like to bridge to the host's connected LAN,
+Here is an example for NetBSD:
+
+<p><pre>
+<b># ifconfig bridge0 create up</b>
+<b># brconfig add tap0 add wm0</b>
+</pre>
+
+<p>Although it <i>is</i> possible to have more than one machine per
+configuration file, I strongly recommend against it. Please use one
+configuration file for one emulated machine. Each configuration file
+must have a unique <i>tap</i> instance, and machines in separate
+configuration files must use bridged <i>tap</i> devices if they wish
+to communicate with each other as if on the same LAN.
+
+
<p><br>
<a name="multihost"></a>
$NetBSD: patch-src_devices_dev_dec21143.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
- Add support for tap(4)-based networking.
- Process the setup packet, and implement all of the Tulip receive
filtering modes.
- Add ugly hack to deal with PCI vs. CPU views of main memory differences
between systems.
--- src/devices/dev_dec21143.cc.orig 2020-10-05 22:54:55.903897678 +0000
+++ src/devices/dev_dec21143.cc 2020-10-05 22:55:15.711704852 +0000
@@ -45,8 +45,6 @@
* o) Handle _writes_ to MII registers.
* o) Make it work with modern Linux kernels (as a guest OS).
* o) Endianness for descriptors? If necessary.
- * o) Actually handle the "Setup" packet.
- * o) MAC filtering on incoming packets.
* o) Don't hardcode as many values.
*/
@@ -76,16 +74,15 @@
#define ROM_WIDTH 6
struct dec21143_data {
+ /* NIC common data */
+ struct nic_data nic;
+
struct interrupt irq;
int irq_was_asserted;
/* PCI: */
int pci_little_endian;
- /* Ethernet address, and a network which we are connected to: */
- uint8_t mac[6];
- struct net *net;
-
/* SROM emulation: */
uint8_t srom[1 << (ROM_WIDTH + 1)];
int srom_curbit;
@@ -105,19 +102,66 @@ struct dec21143_data {
uint32_t reg[N_REGS];
/* Internal TX state: */
- uint64_t cur_tx_addr;
+ uint32_t cur_tx_addr;
unsigned char *cur_tx_buf;
int cur_tx_buf_len;
int tx_idling;
int tx_idling_threshold;
/* Internal RX state: */
- uint64_t cur_rx_addr;
+ uint32_t cur_rx_addr;
unsigned char *cur_rx_buf;
int cur_rx_buf_len;
int cur_rx_offset;
+
+ /*
+ * Receive filter information. We keep our own copy of
+ * the promiscuous flag because to implement some of the
+ * filtering modes, we need to tell the network layer that
+ * we want all packets.
+ */
+ int (*drop_packet)(struct net *, struct dec21143_data *);
+ int allmulti;
+ int promiscuous;
+ int filter_needs_promiscuous;
+ uint8_t perfect_filter[6 * TULIP_MAXADDRS];
+
+ /* Only 16 bits are used per filter word. */
+#define MCHASH_NWORDS (TULIP_MCHASHSIZE / 16)
+ uint32_t hash_filter[MCHASH_NWORDS];
+ int hash_filter_saturated;
+
+ /*
+ * XXX XXX XXX
+ * XXX UGLY HACK. Need a proper way to deal with
+ * XXX different PCI vs. CPU views of RAM.
+ * XXX XXX XXX
+ */
+ uint32_t xxx_dma_to_phys_mask;
};
+/* XXX This is an UGLY hack. */
+static uint64_t dma_to_phys(const struct dec21143_data *d, uint32_t dma_addr)
+{
+ return dma_addr & d->xxx_dma_to_phys_mask;
+}
+
+
+static inline uint32_t load_le32(const uint8_t *buf)
+{
+ return buf[0] | ((uint32_t)buf[1] << 8) |
+ ((uint32_t)buf[2] << 16) | ((uint32_t)buf[3] << 24);
+}
+
+
+static inline void store_le32(uint8_t *buf, uint32_t val)
+{
+ buf[0] = (uint8_t)val;
+ buf[1] = (uint8_t)(val >> 8);
+ buf[2] = (uint8_t)(val >> 16);
+ buf[3] = (uint8_t)(val >> 24);
+}
+
/* Internal states during MII data stream decode: */
#define MII_STATE_RESET 0
@@ -130,6 +174,171 @@ struct dec21143_data {
/*
+ * The 21143 has multiple address matching modes:
+ *
+ * - Perfect Filtering: The chip interprets the descriptor buffer
+ * as a table of 16 MAC addresses that it should match. The
+ * station address and broadcast must be included in the list.
+ *
+ * - Hash Perfect Filtering: The chip interprets the descriptor buffer
+ * as a 512-bit hash table plus one perfect filter match. Multicast
+ * addresses only are matched against the hash table.
+ *
+ * - Inverse Filtering: Like Perfect Filtering, but the table is
+ * addresses NOT to match.
+ *
+ * - Hash-only Filtering: Like Hash Perfect, except without the Perfect.
+ * All addresses are matched against the hash table.
+ *
+ * The mode seleted by the TDCTL descriptor field is reflected in 3
+ * read-only bits in the OPMODE register.
+ *
+ * We implement all 4 (NetBSD, at least, is known to use Perfect and
+ * Hash Perfect on the 21143; it also uses Hash-only on the 21140).
+ */
+
+#define TDCTL_Tx_FT_MASK (TDCTL_Tx_FT1|TDCTL_Tx_FT0)
+
+#define dec21143_mchash(addr) \
+ (net_ether_crc32_le((addr), 6) & (TULIP_MCHASHSIZE - 1))
+
+static int dec21143_drop_packet_perfect(struct net *net,
+ struct dec21143_data *d)
+{
+ int i;
+
+ for (i = 0; i < TULIP_MAXADDRS; i++) {
+ if (net_ether_eq(d->cur_rx_buf, &d->perfect_filter[6 * i])) {
+ /* Match! */
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int dec21143_drop_packet_hashperfect(struct net *net,
+ struct dec21143_data *d)
+{
+
+ /*
+ * In this mode, we have the network layer match our station
+ * address, and we reflect the true promiscuous status there
+ * as well. This means that if it's not a multicast address,
+ * then it's already been sufficiently matched.
+ */
+ if (! net_ether_multicast(d->cur_rx_buf))
+ return 0;
+
+ /*
+ * Note that the broadcast address is also checked against
+ * the hash table in this mode!
+ */
+
+ const uint32_t hash = dec21143_mchash(d->cur_rx_buf);
+ if (d->hash_filter[hash >> 4] & (1U << (hash & 0xf))) {
+ /* Match! */
+ return 0;
+ }
+
+ return 1;
+}
+
+static int dec21143_drop_packet_inverse(struct net *net,
+ struct dec21143_data *d)
+{
+ return !dec21143_drop_packet_perfect(net, d);
+}
+
+static int dec21143_drop_packet_hashonly(struct net *net,
+ struct dec21143_data *d)
+{
+ const uint32_t hash = dec21143_mchash(d->cur_rx_buf);
+ if (d->hash_filter[hash >> 4] & (1U << (hash & 0xf))) {
+ /* Match! */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/*
+ * dec21143_rx_drop_packet():
+ *
+ * Implement the logic to determine if we should drop a packet
+ * before paassing it to the guest. Returns 1 if the packet
+ * was dropped.
+ */
+static int dec21143_rx_drop_packet(struct net *net, struct dec21143_data *d)
+{
+ /* Only implement filtering if using a tap device. */
+ if (net->tapdev == NULL)
+ return 0;
+
+ /*
+ * We might have told the network layer that we're promiscuous
+ * due to the chosen filtering mode, so check the truth here.
+ */
+ if (d->promiscuous)
+ return 0;
+
+ /*
+ * If the guest wants all multicast (either all the bits are
+ * set or the OPMODE_PM bit is set), then check to see if we
+ * can short-circuit the checks.
+ */
+ if (d->allmulti && net_ether_multicast(d->cur_rx_buf))
+ return 0;
+
+ /*
+ * Note that if we haven't gotten a setup packet yet, then
+ * d->drop_packet will be NULL. If this happens, we always
+ * drop. This is akin to the real hardware defaulting to
+ * Perfect filtering mode but not having any valid addresses
+ * in the list to match against.
+ */
+ if (d->drop_packet == NULL || d->drop_packet(net, d)) {
+ /* Not for us; drop the packet. */
+ free(d->cur_rx_buf);
+ d->cur_rx_buf = NULL;
+ d->cur_rx_buf_len = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * dec21143_update_rx_mode():
+ *
+ * Update promiscuous / allmulti indicators based on OPMODE
+ * and filter state.
+ */
+static void dec21143_update_rx_mode(struct dec21143_data *d)
+{
+ int opmode_pr = (d->reg[CSR_OPMODE / 8] & OPMODE_PR) != 0;
+ int opmode_pm = (d->reg[CSR_OPMODE / 8] & OPMODE_PM) != 0;
+
+ debug("[ dec21143 rx mode: opmode_pr = %d ]\n",
+ opmode_pr);
+ debug("[ dec21143 rx mode: filter_needs_promiscuous = %d ]\n",
+ d->filter_needs_promiscuous);
+ debug("[ dec21143 rx mode: opmode_pm = %d ]\n",
+ opmode_pm);
+ debug("[ dec21143 rx mode: filter_saturated = %d ]\n",
+ d->hash_filter_saturated);
+
+ d->promiscuous = opmode_pr;
+ d->nic.promiscuous_mode =
+ d->promiscuous || d->filter_needs_promiscuous;
+
+ d->allmulti = opmode_pm || d->hash_filter_saturated;
+}
+
+
+/*
* dec21143_rx():
*
* Receive a packet. (If there is no current packet, then check for newly
@@ -138,20 +347,23 @@ struct dec21143_data {
*/
int dec21143_rx(struct cpu *cpu, struct dec21143_data *d)
{
- uint64_t addr = d->cur_rx_addr, bufaddr;
+ uint32_t addr = d->cur_rx_addr, bufaddr;
unsigned char descr[16];
uint32_t rdes0, rdes1, rdes2, rdes3;
int bufsize, buf1_size, buf2_size, i, writeback_len = 4, to_xfer;
/* No current packet? Then check for new ones. */
- if (d->cur_rx_buf == NULL) {
+ while (d->cur_rx_buf == NULL) {
/* Nothing available? Then abort. */
- if (!net_ethernet_rx_avail(d->net, d))
+ if (!net_ethernet_rx_avail(d->nic.net, &d->nic))
return 0;
/* Get the next packet into our buffer: */
- net_ethernet_rx(d->net, d, &d->cur_rx_buf,
- &d->cur_rx_buf_len);
+ net_ethernet_rx(d->nic.net, &d->nic,
+ &d->cur_rx_buf, &d->cur_rx_buf_len);
+
+ if (dec21143_rx_drop_packet(d->nic.net, d))
+ continue;
/* Append a 4 byte CRC: */
d->cur_rx_buf_len += 4;
@@ -165,15 +377,14 @@ int dec21143_rx(struct cpu *cpu, struct
}
/* fatal("{ dec21143_rx: base = 0x%08x }\n", (int)addr); */
- addr &= 0x7fffffff;
- if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t),
- MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, addr),
+ descr, sizeof(uint32_t), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_rx: memory_rw failed! ]\n");
return 0;
}
- rdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24);
+ rdes0 = load_le32(&descr[0]);
/* Only use descriptors owned by the 21143: */
if (!(rdes0 & TDSTAT_OWN)) {
@@ -181,16 +392,17 @@ int dec21143_rx(struct cpu *cpu, struct
return 0;
}
- if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr +
- sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL |
- NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem,
+ dma_to_phys(d, addr + sizeof(uint32_t)),
+ descr + sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ,
+ PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_rx: memory_rw failed! ]\n");
return 0;
}
- rdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24);
- rdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24);
- rdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24);
+ rdes1 = load_le32(&descr[4]);
+ rdes2 = load_le32(&descr[8]);
+ rdes3 = load_le32(&descr[12]);
buf1_size = rdes1 & TDCTL_SIZE1;
buf2_size = (rdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;
@@ -210,7 +422,6 @@ int dec21143_rx(struct cpu *cpu, struct
debug("{ RX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n",
(long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize, (int)bufaddr);
- bufaddr &= 0x7fffffff;
/* Turn off all status bits, and give up ownership: */
rdes0 = 0x00000000;
@@ -221,7 +432,7 @@ int dec21143_rx(struct cpu *cpu, struct
/* DMA bytes from the packet into emulated physical memory: */
for (i=0; i<to_xfer; i++) {
- cpu->memory_rw(cpu, cpu->mem, bufaddr + i,
+ cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, bufaddr + i),
d->cur_rx_buf + d->cur_rx_offset + i, 1, MEM_WRITE,
PHYSICAL | NO_EXCEPTIONS);
/* fatal(" %02x", d->cur_rx_buf[d->cur_rx_offset + i]); */
@@ -253,19 +464,16 @@ int dec21143_rx(struct cpu *cpu, struct
}
/* Descriptor writeback: */
- descr[ 0] = rdes0; descr[ 1] = rdes0 >> 8;
- descr[ 2] = rdes0 >> 16; descr[ 3] = rdes0 >> 24;
+ store_le32(&descr[0], rdes0);
if (writeback_len > 1) {
- descr[ 4] = rdes1; descr[ 5] = rdes1 >> 8;
- descr[ 6] = rdes1 >> 16; descr[ 7] = rdes1 >> 24;
- descr[ 8] = rdes2; descr[ 9] = rdes2 >> 8;
- descr[10] = rdes2 >> 16; descr[11] = rdes2 >> 24;
- descr[12] = rdes3; descr[13] = rdes3 >> 8;
- descr[14] = rdes3 >> 16; descr[15] = rdes3 >> 24;
+ store_le32(&descr[4], rdes1);
+ store_le32(&descr[8], rdes2);
+ store_le32(&descr[12], rdes3);
}
- if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t)
- * writeback_len, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, addr), descr,
+ sizeof(uint32_t) * writeback_len, MEM_WRITE,
+ PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_rx: memory_rw failed! ]\n");
return 0;
}
@@ -275,6 +483,178 @@ int dec21143_rx(struct cpu *cpu, struct
/*
+ * dec21143_setup_copy_enaddr():
+ *
+ * Copy an Ethernet address out of the setup packet.
+ */
+static void dec21143_setup_copy_enaddr(uint8_t *enaddr,
+ const uint32_t *setup_packet)
+{
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ enaddr[i*2 ] = (uint8_t)setup_packet[i];
+ enaddr[i*2 + 1] = (uint8_t)(setup_packet[i] >> 8);
+ }
+}
+
+
+/*
+ * dec21143_setup_perfect():
+ *
+ * Setup perfect filtering mode.
+ */
+static void dec21143_setup_perfect(struct dec21143_data *d,
+ const uint32_t *setup_packet)
+{
+ int i;
+
+ for (i = 0; i < TULIP_MAXADDRS; i++) {
+ dec21143_setup_copy_enaddr(&d->perfect_filter[i * 6],
+ &setup_packet[i * 3]);
+ debug("dec21143 PERFECT[%d] %02x:%02x:%02x:%02x:%02x:%02x\n",
+ i,
+ d->perfect_filter[i*6 + 0],
+ d->perfect_filter[i*6 + 1],
+ d->perfect_filter[i*6 + 2],
+ d->perfect_filter[i*6 + 3],
+ d->perfect_filter[i*6 + 4],
+ d->perfect_filter[i*6 + 5]);
+ }
+
+ d->drop_packet = dec21143_drop_packet_perfect;
+}
+
+
+/*
+ * dec21143_setup_hashperfect():
+ *
+ * Setup hash-perfect filtering mode.
+ */
+static void dec21143_setup_hashperfect(struct dec21143_data *d,
+ const uint32_t *setup_packet)
+{
+ int i;
+
+ debug("dec21143 HASHPERFECT:");
+ for (i = 0; i < MCHASH_NWORDS; i++) {
+ if ((i % 8) == 0)
+ debug("\n\t");
+ debug(" %04x", setup_packet[i]);
+ d->hash_filter[i] = setup_packet[i];
+ d->hash_filter_saturated |= (d->hash_filter[i] == 0xffff);
+ }
+ debug("\n");
+
+ dec21143_setup_copy_enaddr(d->nic.mac_address, &setup_packet[39]);
+ debug("dec21143 HASHPERFECT %02x:%02x:%02x:%02x:%02x:%02x\n",
+ d->nic.mac_address[0],
+ d->nic.mac_address[1],
+ d->nic.mac_address[2],
+ d->nic.mac_address[3],
+ d->nic.mac_address[4],
+ d->nic.mac_address[5]);
+
+ d->filter_needs_promiscuous = 0;
+ d->drop_packet = dec21143_drop_packet_hashperfect;
+}
+
+
+/*
+ * dec21143_setup_inverse():
+ *
+ * Setup inverse filtering mode.
+ */
+static void dec21143_setup_inverse(struct dec21143_data *d,
+ const uint32_t *setup_packet)
+{
+ dec21143_setup_perfect(d, setup_packet);
+ debug("dec21143 INVERSE ^^^^\n");
+ d->drop_packet = dec21143_drop_packet_inverse;
+}
+
+
+/*
+ * dec21143_setup_hashonly():
+ *
+ * Setup hash-only filtering mode.
+ */
+static void dec21143_setup_hashonly(struct dec21143_data *d,
+ const uint32_t *setup_packet)
+{
+ int i;
+
+ debug("dec21143 HASHONLY:");
+ for (i = 0; i < MCHASH_NWORDS; i++) {
+ if ((i % 8) == 0)
+ fatal("\n\t");
+ debug(" %04x", setup_packet[i]);
+ d->hash_filter[i] = setup_packet[i];
+ d->hash_filter_saturated |= (d->hash_filter[i] == 0xffff);
+ }
+ debug("\n");
+
+ d->drop_packet = dec21143_drop_packet_hashonly;
+}
+
+
+/*
+ * dec21143_process_setup_packet():
+ *
+ * Process the address filter setup packet.
+ */
+static void dec21143_process_setup_packet(struct cpu *cpu,
+ struct dec21143_data *d, uint32_t tdctl, uint32_t bufaddr)
+{
+ uint32_t setup_packet[TULIP_SETUP_PACKET_LEN / sizeof(uint32_t)];
+ uint8_t *cp = (uint8_t *)setup_packet;
+ uint32_t tmp;
+ int i;
+
+ if (!cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, bufaddr), cp,
+ TULIP_SETUP_PACKET_LEN, MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
+ fatal("[ dec21143_process_setup_packet: memory_rw failed! ]\n");
+ return;
+ }
+
+ /* Ensure host order of each word. */
+ for (i = 0; i < TULIP_SETUP_PACKET_LEN; i += sizeof(uint32_t)) {
+ tmp = load_le32(&cp[i]);
+ setup_packet[i / sizeof(uint32_t)] = tmp;
+ }
+
+ /* Defaults. */
+ d->hash_filter_saturated = 0;
+ d->filter_needs_promiscuous = 1;
+
+ d->reg[CSR_OPMODE / 8] &= ~(OPMODE_HP | OPMODE_HO | OPMODE_IF);
+
+ switch (tdctl & TDCTL_Tx_FT_MASK) {
+ case TDCTL_Tx_FT_PERFECT:
+ dec21143_setup_perfect(d, setup_packet);
+ break;
+
+ case TDCTL_Tx_FT_HASH:
+ dec21143_setup_hashperfect(d, setup_packet);
+ d->reg[CSR_OPMODE / 8] |= OPMODE_HP;
+ break;
+
+ case TDCTL_Tx_FT_INVERSE:
+ dec21143_setup_inverse(d, setup_packet);
+ d->reg[CSR_OPMODE / 8] |= OPMODE_IF;
+ break;
+
+ case TDCTL_Tx_FT_HASHONLY:
+ dec21143_setup_hashonly(d, setup_packet);
+ d->reg[CSR_OPMODE / 8] |= OPMODE_HO;
+ break;
+ }
+
+ dec21143_update_rx_mode(d);
+}
+
+
+/*
* dec21143_tx():
*
* Transmit a packet, if the guest OS has marked a descriptor as containing
@@ -282,20 +662,18 @@ int dec21143_rx(struct cpu *cpu, struct
*/
int dec21143_tx(struct cpu *cpu, struct dec21143_data *d)
{
- uint64_t addr = d->cur_tx_addr, bufaddr;
+ uint32_t addr = d->cur_tx_addr, bufaddr;
unsigned char descr[16];
uint32_t tdes0, tdes1, tdes2, tdes3;
int bufsize, buf1_size, buf2_size, i;
- addr &= 0x7fffffff;
-
- if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t),
- MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, addr), descr,
+ sizeof(uint32_t), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_tx: memory_rw failed! ]\n");
return 0;
}
- tdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24);
+ tdes0 = load_le32(&descr[0]);
/* fatal("{ dec21143_tx: base=0x%08x, tdes0=0x%08x }\n",
(int)addr, (int)tdes0); */
@@ -310,16 +688,17 @@ int dec21143_tx(struct cpu *cpu, struct
return 0;
}
- if (!cpu->memory_rw(cpu, cpu->mem, addr + sizeof(uint32_t), descr +
- sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ, PHYSICAL |
- NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem,
+ dma_to_phys(d, addr + sizeof(uint32_t)),
+ descr + sizeof(uint32_t), sizeof(uint32_t) * 3, MEM_READ,
+ PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_tx: memory_rw failed! ]\n");
return 0;
}
- tdes1 = descr[4] + (descr[5]<<8) + (descr[6]<<16) + (descr[7]<<24);
- tdes2 = descr[8] + (descr[9]<<8) + (descr[10]<<16) + (descr[11]<<24);
- tdes3 = descr[12] + (descr[13]<<8) + (descr[14]<<16) + (descr[15]<<24);
+ tdes1 = load_le32(&descr[4]);
+ tdes2 = load_le32(&descr[8]);
+ tdes3 = load_le32(&descr[12]);
buf1_size = tdes1 & TDCTL_SIZE1;
buf2_size = (tdes1 & TDCTL_SIZE2) >> TDCTL_SIZE2_SHIFT;
@@ -338,10 +717,9 @@ int dec21143_tx(struct cpu *cpu, struct
}
/*
- fatal("{ TX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n",
- (long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr);
+ fatal("{ TX (%x): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n",
+ addr, tdes0, tdes1, tdes2, tdes3, bufsize, bufaddr);
*/
- bufaddr &= 0x7fffffff;
/* Assume no error: */
tdes0 &= ~ (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC
@@ -350,13 +728,13 @@ int dec21143_tx(struct cpu *cpu, struct
if (tdes1 & TDCTL_Tx_SET) {
/*
* Setup Packet.
- *
- * TODO. For now, just ignore it, and pretend it worked.
*/
/* fatal("{ TX: setup packet }\n"); */
- if (bufsize != 192)
+ if (bufsize != TULIP_SETUP_PACKET_LEN)
fatal("[ dec21143: setup packet len = %i, should be"
- " 192! ]\n", (int)bufsize);
+ " %d! ]\n", (int)bufsize, TULIP_SETUP_PACKET_LEN);
+ else
+ dec21143_process_setup_packet(cpu, d, tdes1, bufaddr);
if (tdes1 & TDCTL_Tx_IC)
d->reg[CSR_STATUS/8] |= STATUS_TI;
/* New descriptor values, according to the docs: */
@@ -388,7 +766,8 @@ int dec21143_tx(struct cpu *cpu, struct
/* "DMA" data from emulated physical memory into the buf: */
for (i=0; i<bufsize; i++) {
- cpu->memory_rw(cpu, cpu->mem, bufaddr + i,
+ cpu->memory_rw(cpu, cpu->mem,
+ dma_to_phys(d, bufaddr + i),
d->cur_tx_buf + d->cur_tx_buf_len + i, 1, MEM_READ,
PHYSICAL | NO_EXCEPTIONS);
/* fatal(" %02x", d->cur_tx_buf[
@@ -400,9 +779,9 @@ int dec21143_tx(struct cpu *cpu, struct
/* Last segment? Then actually transmit it: */
if (tdes1 & TDCTL_Tx_LS) {
/* fatal("{ TX: data frame complete. }\n"); */
- if (d->net != NULL) {
- net_ethernet_tx(d->net, d, d->cur_tx_buf,
- d->cur_tx_buf_len);
+ if (d->nic.net != NULL) {
+ net_ethernet_tx(d->nic.net, &d->nic,
+ d->cur_tx_buf, d->cur_tx_buf_len);
} else {
static int warn = 0;
if (!warn)
@@ -430,17 +809,13 @@ int dec21143_tx(struct cpu *cpu, struct
tdes0 |= TDSTAT_ES;
/* Descriptor writeback: */
- descr[ 0] = tdes0; descr[ 1] = tdes0 >> 8;
- descr[ 2] = tdes0 >> 16; descr[ 3] = tdes0 >> 24;
- descr[ 4] = tdes1; descr[ 5] = tdes1 >> 8;
- descr[ 6] = tdes1 >> 16; descr[ 7] = tdes1 >> 24;
- descr[ 8] = tdes2; descr[ 9] = tdes2 >> 8;
- descr[10] = tdes2 >> 16; descr[11] = tdes2 >> 24;
- descr[12] = tdes3; descr[13] = tdes3 >> 8;
- descr[14] = tdes3 >> 16; descr[15] = tdes3 >> 24;
+ store_le32(&descr[0], tdes0);
+ store_le32(&descr[4], tdes1);
+ store_le32(&descr[8], tdes2);
+ store_le32(&descr[12], tdes3);
- if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t)
- * 4, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
+ if (!cpu->memory_rw(cpu, cpu->mem, dma_to_phys(d, addr), descr,
+ sizeof(uint32_t) * 4, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) {
fatal("[ dec21143_tx: memory_rw failed! ]\n");
return 0;
}
@@ -750,7 +1125,6 @@ static void srom_access(struct cpu *cpu,
*/
static void dec21143_reset(struct cpu *cpu, struct dec21143_data *d)
{
- int leaf;
if (d->cur_rx_buf != NULL)
free(d->cur_rx_buf);
@@ -759,7 +1133,6 @@ static void dec21143_reset(struct cpu *c
d->cur_rx_buf = d->cur_tx_buf = NULL;
memset(d->reg, 0, sizeof(uint32_t) * N_REGS);
- memset(d->srom, 0, sizeof(d->srom));
memset(d->mii_phy_reg, 0, sizeof(d->mii_phy_reg));
/* Register values at reset, according to the manual: */
@@ -772,35 +1145,8 @@ static void dec21143_reset(struct cpu *c
d->tx_idling_threshold = 10;
d->cur_rx_addr = d->cur_tx_addr = 0;
- /* Version (= 1) and Chip count (= 1): */
- d->srom[TULIP_ROM_SROM_FORMAT_VERION] = 1;
- d->srom[TULIP_ROM_CHIP_COUNT] = 1;
-
/* Set the MAC address: */
- memcpy(d->srom + TULIP_ROM_IEEE_NETWORK_ADDRESS, d->mac, 6);
-
- leaf = 30;
- d->srom[TULIP_ROM_CHIPn_DEVICE_NUMBER(0)] = 0;
- d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)] = leaf & 255;
- d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)+1] = leaf >> 8;
-
- d->srom[leaf+TULIP_ROM_IL_SELECT_CONN_TYPE] = 0; /* Not used? */
- d->srom[leaf+TULIP_ROM_IL_MEDIA_COUNT] = 2;
- leaf += TULIP_ROM_IL_MEDIAn_BLOCK_BASE;
-
- d->srom[leaf] = 7; /* descriptor length */
- d->srom[leaf+1] = TULIP_ROM_MB_21142_SIA;
- d->srom[leaf+2] = TULIP_ROM_MB_MEDIA_100TX;
- /* here comes 4 bytes of GPIO control/data settings */
- leaf += d->srom[leaf];
-
- d->srom[leaf] = 15; /* descriptor length */
- d->srom[leaf+1] = TULIP_ROM_MB_21142_MII;
- d->srom[leaf+2] = 0; /* PHY nr */
- d->srom[leaf+3] = 0; /* len of select sequence */
- d->srom[leaf+4] = 0; /* len of reset sequence */
- /* 5,6, 7,8, 9,10, 11,12, 13,14 = unused by GXemul */
- leaf += d->srom[leaf];
+ memcpy(d->nic.mac_address, d->srom + TULIP_ROM_IEEE_NETWORK_ADDRESS, 6);
/* MII PHY initial state: */
d->mii_state = MII_STATE_RESET;
@@ -814,12 +1160,13 @@ static void dec21143_reset(struct cpu *c
DEVICE_ACCESS(dec21143)
{
struct dec21143_data *d = (struct dec21143_data *) extra;
- uint64_t idata = 0, odata = 0;
+ uint32_t idata = 0, odata = 0;
uint32_t oldreg = 0;
int regnr = relative_addr >> 3;
if (writeflag == MEM_WRITE)
- idata = memory_readmax64(cpu, data, len | d->pci_little_endian);
+ idata = (uint32_t)memory_readmax64(cpu, data,
+ len | d->pci_little_endian);
if ((relative_addr & 7) == 0 && regnr < N_REGS) {
if (writeflag == MEM_READ) {
@@ -916,8 +1263,15 @@ DEVICE_ACCESS(dec21143)
/* Turned off RX? Then go to stopped state: */
d->reg[CSR_STATUS/8] &= ~STATUS_RS;
}
+ /* Maintain r/o filter mode bits: */
+ d->reg[CSR_OPMODE/8] &=
+ ~(OPMODE_HP | OPMODE_HO | OPMODE_IF);
+ d->reg[CSR_OPMODE/8] |= oldreg &
+ (OPMODE_HP | OPMODE_HO | OPMODE_IF);
idata &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS
- | OPMODE_PS | OPMODE_SF | OPMODE_TTM | OPMODE_FD);
+ | OPMODE_PS | OPMODE_SF | OPMODE_TTM | OPMODE_FD
+ | OPMODE_IF | OPMODE_HO | OPMODE_HP | OPMODE_PR
+ | OPMODE_PM);
if (idata & OPMODE_PNIC_IT) {
idata &= ~OPMODE_PNIC_IT;
d->tx_idling = d->tx_idling_threshold;
@@ -926,6 +1280,7 @@ DEVICE_ACCESS(dec21143)
fatal("[ dec21143: UNIMPLEMENTED OPMODE bits"
": 0x%08x ]\n", (int)idata);
}
+ dec21143_update_rx_mode(d);
dev_dec21143_tick(cpu, extra);
}
break;
@@ -976,6 +1331,7 @@ DEVINIT(dec21143)
{
struct dec21143_data *d;
char name2[100];
+ int leaf;
CHECK_ALLOCATION(d = (struct dec21143_data *) malloc(sizeof(struct dec21143_data)));
memset(d, 0, sizeof(struct dec21143_data));
@@ -983,15 +1339,80 @@ DEVINIT(dec21143)
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
d->pci_little_endian = devinit->pci_little_endian;
- net_generate_unique_mac(devinit->machine, d->mac);
- net_add_nic(devinit->machine->emul->net, d, d->mac);
- d->net = devinit->machine->emul->net;
+ /* XXX XXX XXX */
+ switch (devinit->machine->machine_type) {
+ /*
+ * Footbridge systems -- this is actually configurable by
+ * system software, but this is the window setting that
+ * NetBSD uses.
+ */
+ case MACHINE_CATS:
+ case MACHINE_NETWINDER:
+ d->xxx_dma_to_phys_mask = ~0x20000000;
+ break;
+
+ /*
+ * V3 Semi PCI bus controller -- this is actually configurable
+ * by system sofware, but this is the value previously hard-coded
+ * for all platforms that did not work on Footbridge systems.
+ */
+ case MACHINE_ALGOR:
+ /* FALLTHROUGH */
+
+ /* Other known users of dc21143 that came along for the ride. */
+ case MACHINE_COBALT:
+ case MACHINE_PMPPC:
+ case MACHINE_PREP:
+ case MACHINE_MACPPC:
+ case MACHINE_MVMEPPC:
+ d->xxx_dma_to_phys_mask = 0x7fffffff;
+ break;
+
+ default:
+ fatal("[ dec21143: default DMA mask for unhandled machine %d\n",
+ devinit->machine->machine_type);
+ d->xxx_dma_to_phys_mask = 0xffffffff;
+ }
+
+ memset(d->srom, 0, sizeof(d->srom));
+
+ /* Version (= 1) and Chip count (= 1): */
+ d->srom[TULIP_ROM_SROM_FORMAT_VERION] = 1;
+ d->srom[TULIP_ROM_CHIP_COUNT] = 1;
+
+ leaf = 30;
+ d->srom[TULIP_ROM_CHIPn_DEVICE_NUMBER(0)] = 0;
+ d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)] = leaf & 255;
+ d->srom[TULIP_ROM_CHIPn_INFO_LEAF_OFFSET(0)+1] = leaf >> 8;
+
+ d->srom[leaf+TULIP_ROM_IL_SELECT_CONN_TYPE] = 0; /* Not used? */
+ d->srom[leaf+TULIP_ROM_IL_MEDIA_COUNT] = 2;
+ leaf += TULIP_ROM_IL_MEDIAn_BLOCK_BASE;
+
+ d->srom[leaf] = 7; /* descriptor length */
+ d->srom[leaf+1] = TULIP_ROM_MB_21142_SIA;
+ d->srom[leaf+2] = TULIP_ROM_MB_MEDIA_100TX;
+ /* here comes 4 bytes of GPIO control/data settings */
+ leaf += d->srom[leaf];
+
+ d->srom[leaf] = 15; /* descriptor length */
+ d->srom[leaf+1] = TULIP_ROM_MB_21142_MII;
+ d->srom[leaf+2] = 0; /* PHY nr */
+ d->srom[leaf+3] = 0; /* len of select sequence */
+ d->srom[leaf+4] = 0; /* len of reset sequence */
+ /* 5,6, 7,8, 9,10, 11,12, 13,14 = unused by GXemul */
+ leaf += d->srom[leaf];
+
+ net_generate_unique_mac(devinit->machine, d->nic.mac_address);
+ memcpy(d->srom + TULIP_ROM_IEEE_NETWORK_ADDRESS, d->nic.mac_address, 6);
+ net_add_nic(devinit->machine->emul->net, &d->nic);
dec21143_reset(devinit->machine->cpus[0], d);
snprintf(name2, sizeof(name2), "%s [%02x:%02x:%02x:%02x:%02x:%02x]",
- devinit->name, d->mac[0], d->mac[1], d->mac[2], d->mac[3],
- d->mac[4], d->mac[5]);
+ devinit->name, d->nic.mac_address[0], d->nic.mac_address[1],
+ d->nic.mac_address[2], d->nic.mac_address[3],
+ d->nic.mac_address[4], d->nic.mac_address[5]);
memory_device_register(devinit->machine->memory, name2,
devinit->addr, 0x100, dev_dec21143_access, d, DM_DEFAULT, NULL);
$NetBSD: patch-src_devices_dev_ether.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/devices/dev_ether.cc.orig 2020-10-05 22:56:01.167967575 +0000
+++ src/devices/dev_ether.cc 2020-10-05 22:56:17.330782903 +0000
@@ -49,6 +49,8 @@
#define DEV_ETHER_TICK_SHIFT 14
struct ether_data {
+ struct nic_data nic;
+
unsigned char buf[DEV_ETHER_BUFFER_SIZE];
unsigned char mac[6];
@@ -66,7 +68,7 @@ DEVICE_TICK(ether)
d->status &= ~DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
if (cpu->machine->emul->net != NULL)
- r = net_ethernet_rx_avail(cpu->machine->emul->net, d);
+ r = net_ethernet_rx_avail(cpu->machine->emul->net, &d->nic);
if (r)
d->status |= DEV_ETHER_STATUS_MORE_PACKETS_AVAILABLE;
@@ -147,7 +149,7 @@ DEVICE_ACCESS(ether)
else {
d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
if (net_ethernet_rx(cpu->machine->emul->net,
- d, &incoming_ptr, &incoming_len)) {
+ &d->nic, &incoming_ptr, &incoming_len)) {
d->status |=
DEV_ETHER_STATUS_PACKET_RECEIVED;
if (incoming_len>DEV_ETHER_BUFFER_SIZE)
@@ -167,7 +169,7 @@ DEVICE_ACCESS(ether)
fatal("[ ether: SEND but no net? ]\n");
else
net_ethernet_tx(cpu->machine->emul->net,
- d, d->buf, d->packet_len);
+ &d->nic, d->buf, d->packet_len);
d->status &= ~DEV_ETHER_STATUS_PACKET_RECEIVED;
dev_ether_tick(cpu, d);
break;
@@ -183,7 +185,7 @@ DEVICE_ACCESS(ether)
fatal("[ ether: read of MAC is not allowed! ]\n");
} else {
// Write out the MAC address to the address given.
- cpu->memory_rw(cpu, cpu->mem, idata, d->mac,
+ cpu->memory_rw(cpu, cpu->mem, idata, d->nic.mac_address,
6, MEM_WRITE, CACHE_NONE);
}
break;
@@ -221,9 +223,11 @@ DEVINIT(ether)
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
- net_generate_unique_mac(devinit->machine, d->mac);
+ net_generate_unique_mac(devinit->machine, d->nic.mac_address);
snprintf(tmp, sizeof(tmp), "%02x:%02x:%02x:%02x:%02x:%02x",
- d->mac[0], d->mac[1], d->mac[2], d->mac[3], d->mac[4], d->mac[5]);
+ d->nic.mac_address[0], d->nic.mac_address[1],
+ d->nic.mac_address[2], d->nic.mac_address[3],
+ d->nic.mac_address[4], d->nic.mac_address[5]);
snprintf(n1, nlen, "%s [%s]", devinit->name, tmp);
snprintf(n2, nlen, "%s [%s, control]", devinit->name, tmp);
@@ -237,7 +241,7 @@ DEVINIT(ether)
DEV_ETHER_LENGTH-DEV_ETHER_BUFFER_SIZE, dev_ether_access, (void *)d,
DM_DEFAULT, NULL);
- net_add_nic(devinit->machine->emul->net, d, d->mac);
+ net_add_nic(devinit->machine->emul->net, &d->nic);
machine_add_tickfunction(devinit->machine,
dev_ether_tick, d, DEV_ETHER_TICK_SHIFT);
$NetBSD: patch-src_devices_dev_le.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
- Add support for tap(4)-based networking.
- Process the setup packet, and implement address filtering.
--- src/devices/dev_le.cc.orig 2020-10-05 22:56:40.808218933 +0000
+++ src/devices/dev_le.cc 2020-10-05 22:56:55.751440817 +0000
@@ -72,9 +72,10 @@
extern int quiet_mode;
-#define LE_MODE_LOOP 4
-#define LE_MODE_DTX 2
-#define LE_MODE_DRX 1
+#define LE_MODE_PROM 0x8000
+#define LE_MODE_LOOP 0x0004
+#define LE_MODE_DTX 0x0002
+#define LE_MODE_DRX 0x0001
#define N_REGISTERS 4
@@ -83,6 +84,8 @@ extern int quiet_mode;
struct le_data {
+ struct nic_data nic;
+
struct interrupt irq;
int irq_asserted;
@@ -101,13 +104,14 @@ struct le_data {
uint32_t init_block_addr;
uint16_t mode;
- uint64_t padr; /* MAC address */
- uint64_t ladrf;
+ uint16_t ladrf[4];
uint32_t rdra; /* receive descriptor ring address */
int rlen; /* nr of rx descriptors */
uint32_t tdra; /* transmit descriptor ring address */
int tlen; /* nr ot tx descriptors */
+ int allmulti;/* receive all multicast packets */
+
/* Current rx and tx descriptor indices: */
int rxp;
int txp;
@@ -157,6 +161,9 @@ static void le_write_16bit(struct le_dat
*/
static void le_chip_init(struct le_data *d)
{
+ uint16_t tmp;
+ uint8_t macaddr[6];
+
d->init_block_addr = (d->reg[1] & 0xffff) + ((d->reg[2] & 0xff) << 16);
if (d->init_block_addr & 1)
fatal("[ le: WARNING! initialization block address "
@@ -165,13 +172,36 @@ static void le_chip_init(struct le_data
debug("[ le: d->init_block_addr = 0x%06x ]\n", d->init_block_addr);
d->mode = le_read_16bit(d, d->init_block_addr + 0);
- d->padr = le_read_16bit(d, d->init_block_addr + 2);
- d->padr += (le_read_16bit(d, d->init_block_addr + 4) << 16);
- d->padr += (le_read_16bit(d, d->init_block_addr + 6) << 32);
- d->ladrf = le_read_16bit(d, d->init_block_addr + 8);
- d->ladrf += (le_read_16bit(d, d->init_block_addr + 10) << 16);
- d->ladrf += (le_read_16bit(d, d->init_block_addr + 12) << 32);
- d->ladrf += (le_read_16bit(d, d->init_block_addr + 14) << 48);
+
+ /*
+ * The MAC address is packed into the PADR field as 3 little-endian
+ * 16-bit words.
+ */
+ tmp = le_read_16bit(d, d->init_block_addr + 2);
+ macaddr[0] = (uint8_t)(tmp);
+ macaddr[1] = (uint8_t)(tmp >> 8);
+ tmp = le_read_16bit(d, d->init_block_addr + 4);
+ macaddr[2] = (uint8_t)(tmp);
+ macaddr[3] = (uint8_t)(tmp >> 8);
+ tmp = le_read_16bit(d, d->init_block_addr + 6);
+ macaddr[4] = (uint8_t)(tmp);
+ macaddr[5] = (uint8_t)(tmp >> 8);
+ memcpy(d->nic.mac_address, macaddr, sizeof(d->nic.mac_address));
+
+ /*
+ * The muticast address filter is packed into the LADRF field
+ * as 4 little-endian 16-bit words.
+ */
+ d->ladrf[0] = le_read_16bit(d, d->init_block_addr + 8);
+ d->ladrf[1] = le_read_16bit(d, d->init_block_addr + 10);
+ d->ladrf[2] = le_read_16bit(d, d->init_block_addr + 12);
+ d->ladrf[3] = le_read_16bit(d, d->init_block_addr + 14);
+ if (d->ladrf[0] == 0xffff && d->ladrf[1] == 0xffff &&
+ d->ladrf[2] == 0xffff && d->ladrf[3] == 0xffff)
+ d->allmulti = 1;
+ else
+ d->allmulti = 0;
+
d->rdra = le_read_16bit(d, d->init_block_addr + 16);
d->rdra += ((le_read_16bit(d, d->init_block_addr + 18) & 0xff) << 16);
d->rlen = 1 << ((le_read_16bit(d, d->init_block_addr + 18) >> 13) & 7);
@@ -179,13 +209,16 @@ static void le_chip_init(struct le_data
d->tdra += ((le_read_16bit(d, d->init_block_addr + 22) & 0xff) << 16);
d->tlen = 1 << ((le_read_16bit(d, d->init_block_addr + 22) >> 13) & 7);
- debug("[ le: DEBUG: mode %04x ]\n", d->mode);
- debug("[ le: DEBUG: padr %016llx ]\n", (long long)d->padr);
- debug("[ le: DEBUG: ladrf %016llx ]\n", (long long)d->ladrf);
- debug("[ le: DEBUG: rdra %06llx ]\n", d->rdra);
- debug("[ le: DEBUG: rlen %3i ]\n", d->rlen);
- debug("[ le: DEBUG: tdra %06llx ]\n", d->tdra);
- debug("[ le: DEBUG: tlen %3i ]\n", d->tlen);
+ debug("[ le: DEBUG: mode %04x ]\n", d->mode);
+ debug("[ le: DEBUG: padr %02x:%02x:%02x:%02x:%02x:%02x ]\n",
+ macaddr[0], macaddr[1], macaddr[2],
+ macaddr[3], macaddr[4], macaddr[5]);
+ debug("[ le: DEBUG: ladrf %04x:%04x:%04x:%04x ]\n",
+ d->ladrf[0], d->ladrf[1], d->ladrf[2], d->ladrf[3]);
+ debug("[ le: DEBUG: rdra %06llx ]\n", d->rdra);
+ debug("[ le: DEBUG: rlen %3i ]\n", d->rlen);
+ debug("[ le: DEBUG: tdra %06llx ]\n", d->tdra);
+ debug("[ le: DEBUG: tlen %3i ]\n", d->tlen);
/* Set TXON and RXON, unless they are disabled by 'mode': */
if (d->mode & LE_MODE_DTX)
@@ -198,6 +231,9 @@ static void le_chip_init(struct le_data
else
d->reg[0] |= LE_RXON;
+ /* Initialize promiscuous mode. */
+ d->nic.promiscuous_mode = (d->mode & LE_MODE_PROM) ? 1 : 0;
+
/* Go to the start of the descriptor rings: */
d->rxp = d->txp = 0;
@@ -308,7 +344,8 @@ static void le_tx(struct net *net, struc
* the packet.
*/
if (enp) {
- net_ethernet_tx(net, d, d->tx_packet, d->tx_packet_len);
+ net_ethernet_tx(net, &d->nic, d->tx_packet,
+ d->tx_packet_len);
free(d->tx_packet);
d->tx_packet = NULL;
@@ -446,6 +483,62 @@ static void le_rx(struct net *net, struc
/*
+ * le_rx_drop_packet():
+ *
+ * Implement the logic to determine if we should drop a packet
+ * before passing it to the guest. Returns 1 if the packet was
+ * dropped.
+ */
+static int
+le_rx_drop_packet(struct net *net, struct le_data *d)
+{
+ /* Only implement filtering if using a tap device. */
+ if (net->tapdev == NULL)
+ return 0;
+
+ /*
+ * The network layer has already checked for our MAC address
+ * or promiscuous mode. We just need to check the multicast
+ * filter or broadcast.
+ */
+
+ /* If the packet is not multicast, we know it should be received. */
+ if (! net_ether_multicast(d->rx_packet))
+ return 0;
+
+ /*
+ * Optimization -- if the guest has set all of the filter
+ * bits, then we can skip additional checks.
+ */
+ if (d->allmulti)
+ return 0;
+
+ /* Check for broadcast. */
+ if (net_ether_broadcast(d->rx_packet))
+ return 0;
+
+ /*
+ * Check the multicast address filter. We pass the address
+ * through the little-endian Ethernet CRC generator. The
+ * high-order 6 bits are the index into the 64-bit filter.
+ * The upper 2 bits select the 16-bit filter word, and the
+ * remaining 4 select the bit in the word.
+ */
+ uint32_t crc = net_ether_crc32_le(d->rx_packet, 6);
+ crc >>= 26;
+ if (d->ladrf[crc >> 4] & (1 << (crc & 0xf)))
+ return 0;
+
+ /* Not for us; drop the packet. */
+ free(d->rx_packet);
+ d->rx_packet = NULL;
+ d->rx_packet_len = 0;
+
+ return 1;
+}
+
+
+/*
* le_register_fix():
*/
static void le_register_fix(struct net *net, struct le_data *d)
@@ -481,9 +574,12 @@ static void le_register_fix(struct net *
break;
if (d->rx_packet == NULL &&
- net_ethernet_rx_avail(net, d))
- net_ethernet_rx(net, d,
+ net_ethernet_rx_avail(net, &d->nic)) {
+ net_ethernet_rx(net, &d->nic,
&d->rx_packet, &d->rx_packet_len);
+ if (le_rx_drop_packet(net, d))
+ continue;
+ }
} while (d->rx_packet != NULL);
}
@@ -813,6 +909,7 @@ void dev_le_init(struct machine *machine
machine_add_tickfunction(machine, dev_le_tick, d, LE_TICK_SHIFT);
- net_add_nic(machine->emul->net, d, &d->rom[0]);
+ memcpy(d->nic.mac_address, &d->rom[0], sizeof(d->nic.mac_address));
+ net_add_nic(machine->emul->net, &d->nic);
}
$NetBSD: patch-src_devices_dev_rtl8139c.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Updates for tap(4)-related changes to Ethernet support.
--- src/devices/dev_rtl8139c.cc.orig 2020-10-05 22:57:40.189047655 +0000
+++ src/devices/dev_rtl8139c.cc 2020-10-05 22:57:53.936646578 +0000
@@ -50,8 +50,9 @@
#define EEPROM_SIZE 0x100
struct rtl8139c_data {
+ struct nic_data nic;
+
struct interrupt irq;
- unsigned char macaddr[6];
/* Registers: */
uint8_t rl_command;
@@ -205,25 +206,26 @@ DEVINIT(rtl8139c)
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
- net_generate_unique_mac(devinit->machine, d->macaddr);
+ net_generate_unique_mac(devinit->machine, d->nic.mac_address);
/* TODO: eeprom address width = 6 on 8129? */
d->eeprom_address_width = 8;
d->eeprom_reg[0] = 0x8139;
- d->eeprom_reg[7] = d->macaddr[0] + (d->macaddr[1] << 8);
- d->eeprom_reg[8] = d->macaddr[2] + (d->macaddr[3] << 8);
- d->eeprom_reg[9] = d->macaddr[4] + (d->macaddr[5] << 8);
+ d->eeprom_reg[7] = d->nic.mac_address[0] + (d->nic.mac_address[1] << 8);
+ d->eeprom_reg[8] = d->nic.mac_address[2] + (d->nic.mac_address[3] << 8);
+ d->eeprom_reg[9] = d->nic.mac_address[4] + (d->nic.mac_address[5] << 8);
CHECK_ALLOCATION(name2 = (char *) malloc(nlen));
snprintf(name2, nlen, "%s [%02x:%02x:%02x:%02x:%02x:%02x]",
- devinit->name, d->macaddr[0], d->macaddr[1], d->macaddr[2],
- d->macaddr[3], d->macaddr[4], d->macaddr[5]);
+ devinit->name, d->nic.mac_address[0], d->nic.mac_address[1],
+ d->nic.mac_address[2], d->nic.mac_address[3],
+ d->nic.mac_address[4], d->nic.mac_address[5]);
memory_device_register(devinit->machine->memory, name2,
devinit->addr, DEV_RTL8139C_LENGTH, dev_rtl8139c_access, (void *)d,
DM_DEFAULT, NULL);
- net_add_nic(devinit->machine->emul->net, d, d->macaddr);
+ net_add_nic(devinit->machine->emul->net, &d->nic);
return 1;
}
$NetBSD: patch-src_devices_dev_sgi_mec.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Updates for tap(4)-related changes to Ethernet support.
--- src/devices/dev_sgi_mec.cc.orig 2020-10-05 22:58:11.248005164 +0000
+++ src/devices/dev_sgi_mec.cc 2020-10-05 22:58:31.644418157 +0000
@@ -81,13 +81,13 @@
#define N_RX_ADDRESSES 16
struct sgi_mec_data {
+ struct nic_data nic;
+
uint64_t reg[DEV_SGI_MEC_LENGTH / sizeof(uint64_t)];
struct interrupt irq;
int prev_asserted;
- unsigned char macaddr[6];
-
unsigned char cur_tx_packet[MAX_TX_PACKET_LEN];
int cur_tx_packet_len;
@@ -157,8 +157,8 @@ static int mec_try_rx(struct cpu *cpu, s
}
if (d->cur_rx_packet == NULL &&
- net_ethernet_rx_avail(cpu->machine->emul->net, d))
- net_ethernet_rx(cpu->machine->emul->net, d,
+ net_ethernet_rx_avail(cpu->machine->emul->net, &d->nic))
+ net_ethernet_rx(cpu->machine->emul->net, &d->nic,
&d->cur_rx_packet, &d->cur_rx_packet_len);
if (d->cur_rx_packet == NULL)
@@ -343,7 +343,7 @@ static int mec_try_tx(struct cpu *cpu, s
if (j < len)
fatal("[ mec_try_tx: not enough data? ]\n");
- net_ethernet_tx(cpu->machine->emul->net, d,
+ net_ethernet_tx(cpu->machine->emul->net, &d->nic,
d->cur_tx_packet, d->cur_tx_packet_len);
/* see openbsd's if_mec.c for details */
@@ -675,13 +675,14 @@ void dev_sgi_mec_init(struct machine *ma
memset(d, 0, sizeof(struct sgi_mec_data));
INTERRUPT_CONNECT(irq_path, d->irq);
- memcpy(d->macaddr, macaddr, 6);
+ memcpy(d->nic.mac_address, macaddr, 6);
mec_reset(d);
CHECK_ALLOCATION(name2 = (char *) malloc(nlen));
snprintf(name2, nlen, "mec [%02x:%02x:%02x:%02x:%02x:%02x]",
- d->macaddr[0], d->macaddr[1], d->macaddr[2],
- d->macaddr[3], d->macaddr[4], d->macaddr[5]);
+ d->nic.mac_address[0], d->nic.mac_address[1],
+ d->nic.mac_address[2], d->nic.mac_address[3],
+ d->nic.mac_address[4], d->nic.mac_address[5]);
memory_device_register(mem, name2, baseaddr,
DEV_SGI_MEC_LENGTH, dev_sgi_mec_access, (void *)d,
@@ -690,7 +691,7 @@ void dev_sgi_mec_init(struct machine *ma
machine_add_tickfunction(machine, dev_sgi_mec_tick, d,
MEC_TICK_SHIFT);
- net_add_nic(machine->emul->net, d, macaddr);
+ net_add_nic(machine->emul->net, &d->nic);
}
$NetBSD: patch-src_devices_dev_sn.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Updates for tap(4)-related changes to Ethernet support.
--- src/devices/dev_sn.cc.orig 2020-10-05 22:58:49.162038719 +0000
+++ src/devices/dev_sn.cc 2020-10-05 22:59:04.524312162 +0000
@@ -48,8 +48,8 @@
#define DEV_SN_LENGTH 0x1000
struct sn_data {
+ struct nic_data nic;
struct interrupt irq;
- unsigned char macaddr[6];
uint32_t reg[SONIC_NREGS];
};
@@ -104,18 +104,19 @@ DEVINIT(sn)
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq);
- net_generate_unique_mac(devinit->machine, d->macaddr);
+ net_generate_unique_mac(devinit->machine, d->nic.mac_address);
CHECK_ALLOCATION(name2 = (char *) malloc(nlen));
snprintf(name2, nlen, "%s [%02x:%02x:%02x:%02x:%02x:%02x]",
- devinit->name, d->macaddr[0], d->macaddr[1], d->macaddr[2],
- d->macaddr[3], d->macaddr[4], d->macaddr[5]);
+ devinit->name, d->nic.mac_address[0], d->nic.mac_address[1],
+ d->nic.mac_address[2], d->nic.mac_address[3],
+ d->nic.mac_address[4], d->nic.mac_address[5]);
memory_device_register(devinit->machine->memory, name2,
devinit->addr, DEV_SN_LENGTH,
dev_sn_access, (void *)d, DM_DEFAULT, NULL);
- net_add_nic(devinit->machine->emul->net, d, d->macaddr);
+ net_add_nic(devinit->machine->emul->net, &d->nic);
return 1;
}
$NetBSD: patch-src_include_net.h,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/include/net.h.orig 2020-10-05 22:59:17.124851904 +0000
+++ src/include/net.h 2020-10-05 22:59:31.468423021 +0000
@@ -112,6 +112,15 @@ struct tcp_connection {
/*****************************************************************************/
+/* Common data for emulated Ethernet NICs. */
+
+struct nic_data {
+ struct net *net; /* net we belong to */
+ uint8_t mac_address[6]; /* our MAC address */
+ int promiscuous_mode;/* receive all packets */
+};
+
+/*****************************************************************************/
#define MAX_TCP_CONNECTIONS 100
#define MAX_UDP_CONNECTIONS 100
@@ -120,13 +129,17 @@ struct net {
/* The emul struct which this net belong to: */
struct emul *emul;
+ /* The network's tap device, if we're using tap: */
+ const char *tapdev;
+ int tap_fd;
+
/* The network's addresses: */
struct in_addr netmask_ipv4;
int netmask_ipv4_len;
/* NICs connected to this network: */
int n_nics;
- void **nic_extra; /* one void * per NIC */
+ struct nic_data **nic_data; /* one per NIC */
/* The "special machine": */
unsigned char gateway_ipv4_addr[4];
@@ -151,6 +164,18 @@ struct net {
struct remote_net *remote_nets;
};
+/* net_tap.c: */
+void net_tap_rx_avail(struct net *net);
+void net_tap_tx(struct net *net, struct nic_data *nic, unsigned char *packet,
+ int len);
+int net_tap_init(struct net *net, const char *tapdev);
+
+/* net_ether.cc */
+int net_ether_eq(const uint8_t *a1, const uint8_t *a2);
+int net_ether_broadcast(const uint8_t *a);
+int net_ether_multicast(const uint8_t *a);
+uint32_t net_ether_crc32_le(const uint8_t *buf, size_t len);
+
/* net_misc.c: */
void net_debugaddr(void *addr, int type);
void net_generate_unique_mac(struct machine *, unsigned char *macbuf);
@@ -162,25 +187,27 @@ void net_ip_checksum(unsigned char *ip_h
void net_ip_tcp_checksum(unsigned char *tcp_header, int chksumoffset,
int tcp_len, unsigned char *srcaddr, unsigned char *dstaddr,
int udpflag);
-void net_ip_tcp_connectionreply(struct net *net, void *extra,
+void net_ip_tcp_connectionreply(struct net *net, struct nic_data *nic,
int con_id, int connecting, unsigned char *data, int datalen, int rst);
-void net_ip_broadcast(struct net *net, void *extra,
+void net_ip_broadcast(struct net *net, struct nic_data *nic,
unsigned char *packet, int len);
-void net_ip(struct net *net, void *extra, unsigned char *packet, int len);
-void net_udp_rx_avail(struct net *net, void *extra);
-void net_tcp_rx_avail(struct net *net, void *extra);
+void net_ip(struct net *net, struct nic_data *nic, unsigned char *packet,
+ int len);
+void net_udp_rx_avail(struct net *net, struct nic_data *nic);
+void net_tcp_rx_avail(struct net *net, struct nic_data *nic);
/* net.c: */
struct ethernet_packet_link *net_allocate_ethernet_packet_link(
- struct net *net, void *extra, size_t len);
-int net_ethernet_rx_avail(struct net *net, void *extra);
-int net_ethernet_rx(struct net *net, void *extra,
+ struct net *net, struct nic_data *nic, size_t len);
+int net_ethernet_rx_avail(struct net *net, struct nic_data *nic);
+int net_ethernet_rx(struct net *net, struct nic_data *nic,
unsigned char **packetp, int *lenp);
-void net_ethernet_tx(struct net *net, void *extra,
+void net_ethernet_tx(struct net *net, struct nic_data *nic,
unsigned char *packet, int len);
void net_dumpinfo(struct net *net);
-void net_add_nic(struct net *net, void *extra, unsigned char *macaddr);
+void net_add_nic(struct net *net, struct nic_data *nic);
struct net *net_init(struct emul *emul, int init_flags,
+ const char *tapdev,
const char *ipv4addr, int netipv4len, char **remote, int n_remote,
int local_port, const char *settings_prefix);
@@ -195,7 +222,7 @@ struct ethernet_packet_link {
struct ethernet_packet_link *prev;
struct ethernet_packet_link *next;
- void *extra;
+ struct nic_data *nic;
unsigned char *data;
int len;
};
$NetBSD: patch-src_net_Makefile.skel,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/net/Makefile.skel.orig 2020-10-05 22:59:56.683092920 +0000
+++ src/net/Makefile.skel 2020-10-05 23:00:09.053165122 +0000
@@ -4,7 +4,7 @@
CXXFLAGS=$(CWARNINGS) $(COPTIM) $(XINCLUDE) $(DINCLUDE)
-OBJS=net.o net_ip.o net_misc.o
+OBJS=net.o net_ip.o net_misc.o net_tap.o net_ether.o
all: $(OBJS)
$NetBSD: patch-src_net_net.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/net/net.cc.orig 2020-10-05 23:00:24.839832619 +0000
+++ src/net/net.cc 2020-10-05 23:00:41.597469289 +0000
@@ -30,10 +30,10 @@
* (Read the README file in this directory for more details.)
*
*
- * NOTE: The 'extra' argument used in many functions in this file is a pointer
- * to something unique for each NIC (i.e. the NIC itself :-), so that if
- * multiple NICs are emulated concurrently, they will not get packets that
- * are meant for some other controller.
+ * NOTE: The 'nic' argument used in many functions in this file is a pointer
+ * to the nic_data for each NIC, so that if multiple NICs are emulated
+ * concurrently, they will not get packets that are meant for some other
+ * controller.
*/
#include <stdio.h>
@@ -62,7 +62,7 @@
*
* This routine allocates an ethernet_packet_link struct, and adds it at
* the end of the packet chain. A data buffer is allocated, and the data,
- * extra, and len fields of the link are set.
+ * nic, and len fields of the link are set.
*
* Note: The data buffer is not zeroed.
*
@@ -70,7 +70,7 @@
* failure.
*/
struct ethernet_packet_link *net_allocate_ethernet_packet_link(
- struct net *net, void *extra, size_t len)
+ struct net *net, struct nic_data *nic, size_t len)
{
struct ethernet_packet_link *lp;
@@ -78,7 +78,7 @@ struct ethernet_packet_link *net_allocat
malloc(sizeof(struct ethernet_packet_link)));
lp->len = len;
- lp->extra = extra;
+ lp->nic = nic;
CHECK_ALLOCATION(lp->data = (unsigned char *) malloc(len));
lp->next = NULL;
@@ -116,7 +116,7 @@ struct ethernet_packet_link *net_allocat
* An ARP request with the same from and to IP addresses should be ignored.
* (This would be a host testing to see if there is an IP collision.)
*/
-static void net_arp(struct net *net, void *extra,
+static void net_arp(struct net *net, struct nic_data *nic,
unsigned char *packet, int len, int reverse)
{
int q;
@@ -161,7 +161,7 @@ static void net_arp(struct net *net, voi
break;
lp = net_allocate_ethernet_packet_link(
- net, extra, 60 + 14);
+ net, nic, 60 + 14);
/* Copy the old packet first: */
memset(lp->data, 0, 60 + 14);
@@ -186,7 +186,7 @@ static void net_arp(struct net *net, voi
break;
case 3: /* Reverse Request */
lp = net_allocate_ethernet_packet_link(
- net, extra, 60 + 14);
+ net, nic, 60 + 14);
/* Copy the old packet first: */
memset(lp->data, 0, 60 + 14);
@@ -242,7 +242,7 @@ static void net_arp(struct net *net, voi
/*
* net_ethernet_rx_avail():
*
- * Return 1 if there is a packet available for this 'extra' pointer, otherwise
+ * Return 1 if there is a packet available for this nic, otherwise
* return 0.
*
* Appart from actually checking for incoming packets from the outside world,
@@ -250,12 +250,21 @@ static void net_arp(struct net *net, voi
* a return value telling us whether there is a packet or not, we don't
* actually get the packet.
*/
-int net_ethernet_rx_avail(struct net *net, void *extra)
+int net_ethernet_rx_avail(struct net *net, struct nic_data *nic)
{
if (net == NULL)
return 0;
/*
+ * If we're using a tap device, check in with that and
+ * that's it.
+ */
+ if (net->tapdev) {
+ net_tap_rx_avail(net);
+ return net_ethernet_rx(net, nic, NULL, NULL);
+ }
+
+ /*
* If the network is distributed across multiple emulator processes,
* then receive incoming packets from those processes.
*/
@@ -282,7 +291,7 @@ int net_ethernet_rx_avail(struct net *ne
for (i=0; i<net->n_nics; i++) {
struct ethernet_packet_link *lp;
lp = net_allocate_ethernet_packet_link(
- net, net->nic_extra[i], res);
+ net, net->nic_data[i], res);
memcpy(lp->data, buf, res);
}
}
@@ -290,10 +299,10 @@ int net_ethernet_rx_avail(struct net *ne
}
/* IP protocol specific: */
- net_udp_rx_avail(net, extra);
- net_tcp_rx_avail(net, extra);
+ net_udp_rx_avail(net, nic);
+ net_tcp_rx_avail(net, nic);
- return net_ethernet_rx(net, extra, NULL, NULL);
+ return net_ethernet_rx(net, nic, NULL, NULL);
}
@@ -309,11 +318,11 @@ int net_ethernet_rx_avail(struct net *ne
* available, 0 is returned.
*
* If packetp is NULL, then the search is aborted as soon as a packet with
- * the correct 'extra' field is found, and a 1 is returned, but as packetp
+ * the correct 'nic' field is found, and a 1 is returned, but as packetp
* is NULL we can't return the actual packet. (This is the internal form
* if net_ethernet_rx_avail().)
*/
-int net_ethernet_rx(struct net *net, void *extra,
+int net_ethernet_rx(struct net *net, struct nic_data *nic,
unsigned char **packetp, int *lenp)
{
struct ethernet_packet_link *lp, *prev;
@@ -321,12 +330,12 @@ int net_ethernet_rx(struct net *net, voi
if (net == NULL)
return 0;
- /* Find the first packet which has the right 'extra' field. */
+ /* Find the first packet which has the right 'nic' field. */
lp = net->first_ethernet_packet;
prev = NULL;
while (lp != NULL) {
- if (lp->extra == extra) {
+ if (lp->nic == nic) {
/* We found a packet for this controller! */
if (packetp == NULL || lenp == NULL)
return 1;
@@ -368,7 +377,7 @@ int net_ethernet_rx(struct net *net, voi
* If the packet can be handled here, it will not necessarily be transmitted
* to the outside world.
*/
-void net_ethernet_tx(struct net *net, void *extra,
+void net_ethernet_tx(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
int i, eth_type, for_the_gateway;
@@ -376,8 +385,6 @@ void net_ethernet_tx(struct net *net, vo
if (net == NULL)
return;
- for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6);
-
/* Drop too small packets: */
if (len < 20) {
fatal("[ net_ethernet_tx: Warning: dropping tiny packet "
@@ -386,15 +393,26 @@ void net_ethernet_tx(struct net *net, vo
}
/*
+ * If we're using a tap device, we send the packet that way
+ * and that's it.
+ */
+ if (net->tapdev) {
+ net_tap_tx(net, nic, packet, len);
+ return;
+ }
+
+ for_the_gateway = !memcmp(packet, net->gateway_ethernet_addr, 6);
+
+ /*
* Copy this packet to all other NICs on this network (except if
* it is aimed specifically at the gateway's ethernet address):
*/
- if (!for_the_gateway && extra != NULL && net->n_nics > 0) {
+ if (!for_the_gateway && nic != NULL && net->n_nics > 0) {
for (i=0; i<net->n_nics; i++)
- if (extra != net->nic_extra[i]) {
+ if (nic != net->nic_data[i]) {
struct ethernet_packet_link *lp;
lp = net_allocate_ethernet_packet_link(net,
- net->nic_extra[i], len);
+ net->nic_data[i], len);
/* Copy the entire packet: */
memcpy(lp->data, packet, len);
@@ -438,7 +456,7 @@ void net_ethernet_tx(struct net *net, vo
if (eth_type == ETHERTYPE_IP) {
/* Routed via the gateway? */
if (for_the_gateway) {
- net_ip(net, extra, packet, len);
+ net_ip(net, nic, packet, len);
return;
}
@@ -446,7 +464,7 @@ void net_ethernet_tx(struct net *net, vo
if (packet[0] == 0xff && packet[1] == 0xff &&
packet[2] == 0xff && packet[3] == 0xff &&
packet[4] == 0xff && packet[5] == 0xff) {
- net_ip_broadcast(net, extra, packet, len);
+ net_ip_broadcast(net, nic, packet, len);
return;
}
@@ -465,13 +483,13 @@ void net_ethernet_tx(struct net *net, vo
if (len != 42 && len != 60)
fatal("[ net_ethernet_tx: WARNING! unusual "
"ARP len (%i) ]\n", len);
- net_arp(net, extra, packet + 14, len - 14, 0);
+ net_arp(net, nic, packet + 14, len - 14, 0);
return;
}
/* RARP: */
if (eth_type == ETHERTYPE_REVARP) {
- net_arp(net, extra, packet + 14, len - 14, 1);
+ net_arp(net, nic, packet + 14, len - 14, 1);
return;
}
@@ -595,21 +613,28 @@ static void parse_resolvconf(struct net
* Add a NIC to a network. (All NICs on a network will see each other's
* packets.)
*/
-void net_add_nic(struct net *net, void *extra, unsigned char *macaddr)
+void net_add_nic(struct net *net, struct nic_data *nic)
{
if (net == NULL)
return;
- if (extra == NULL) {
- fprintf(stderr, "net_add_nic(): extra = NULL\n");
+ if (nic == NULL) {
+ fprintf(stderr, "net_add_nic(): nic = NULL\n");
exit(1);
}
- net->n_nics ++;
- CHECK_ALLOCATION(net->nic_extra = (void **)
- realloc(net->nic_extra, sizeof(void *) * net->n_nics));
+ /*
+ * Set up some of the basics for this NIC. We assume the
+ * device has set up all of the other fields.
+ */
+ nic->net = net;
+ nic->promiscuous_mode = 0;
+
+ net->n_nics++;
+ CHECK_ALLOCATION(net->nic_data = (struct nic_data **)
+ realloc(net->nic_data, sizeof(struct nic_data *) * net->n_nics));
- net->nic_extra[net->n_nics - 1] = extra;
+ net->nic_data[net->n_nics - 1] = nic;
}
@@ -661,6 +686,12 @@ void net_dumpinfo(struct net *net)
debug_indentation(iadd);
+ if (net->tapdev) {
+ debug("tap device: %s\n", net->tapdev);
+ debug_indentation(-iadd);
+ return;
+ }
+
debug("simulated network: ");
net_debugaddr(&net->netmask_ipv4, NET_ADDR_IPV4);
debug("/%i", net->netmask_ipv4_len);
@@ -718,6 +749,7 @@ void net_dumpinfo(struct net *net)
* On failure, exit() is called.
*/
struct net *net_init(struct emul *emul, int init_flags,
+ const char *tapdev,
const char *ipv4addr, int netipv4len,
char **remote, int n_remote, int local_port,
const char *settings_prefix)
@@ -734,6 +766,19 @@ struct net *net_init(struct emul *emul,
/* Sane defaults: */
net->timestamp = 0;
net->first_ethernet_packet = net->last_ethernet_packet = NULL;
+ net->tapdev = NULL;
+ net->tap_fd = -1;
+
+ /*
+ * If we're using a tap device, attempt to initialize it and
+ * none of the other stuff.
+ */
+ if (tapdev) {
+ if (! net_tap_init(net, tapdev))
+ exit(1);
+ net_dumpinfo(net);
+ return net;
+ }
#ifdef HAVE_INET_PTON
res = inet_pton(AF_INET, ipv4addr, &net->netmask_ipv4);
$NetBSD: patch-src_net_net_ether.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add some generic Ethernet routines used for address filtering.
--- /dev/null 2020-10-05 22:44:11.028207457 +0000
+++ src/net/net_ether.cc 2020-10-05 23:01:48.744053911 +0000
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 Jason R. Thorpe. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Common Ethernet support routines.
+ */
+
+#include <sys/types.h>
+#include <string.h>
+
+#include "misc.h"
+#include "net.h"
+
+
+/*
+ * net_ether_eq():
+ *
+ * Compare two Ethernet addresses for equality.
+ */
+int net_ether_eq(const uint8_t *a1, const uint8_t *a2)
+{
+
+ return a1[5] == a2[5] &&
+ a1[4] == a2[4] &&
+ a1[3] == a2[3] &&
+ a1[2] == a2[2] &&
+ a1[1] == a2[1] &&
+ a1[0] == a2[0];
+}
+
+
+/*
+ * net_ether_broadcast():
+ *
+ * Returns 1 if the specified destination address is the Ethernet
+ * broadcast address.
+ */
+int net_ether_broadcast(const uint8_t *a)
+{
+ static const uint8_t ether_broadcast[6] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ return net_ether_eq(a, ether_broadcast);
+}
+
+
+/*
+ * net_ether_multicast():
+ *
+ * Returns 1 if the specfied destination address is an Ethernet
+ * multicast address.
+ *
+ * Note that this also matches Ethernet broadcast, which is just
+ * a special case of multicast.
+ */
+int net_ether_multicast(const uint8_t *a)
+{
+ return (*a & 0x01);
+}
+
+
+/*
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)if_ethersubr.c 8.2 (Berkeley) 4/4/96
+ */
+
+
+/*
+ * net_ether_crc32_le():
+ *
+ * Fast table-driven little-endian Ethernet CRC generator.
+ */
+uint32_t net_ether_crc32_le(const uint8_t *buf, size_t len)
+{
+ static const uint32_t crctab[] = {
+ 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+ 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+ 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+ 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+ };
+ uint32_t crc;
+ size_t i;
+
+ crc = 0xffffffffU; /* initial value */
+
+ for (i = 0; i < len; i++) {
+ crc ^= buf[i];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ crc = (crc >> 4) ^ crctab[crc & 0xf];
+ }
+
+ return crc;
+}
$NetBSD: patch-src_net_net_ip.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/net/net_ip.cc.orig 2020-10-05 23:02:21.375165006 +0000
+++ src/net/net_ip.cc 2020-10-05 23:02:33.181030722 +0000
@@ -155,7 +155,7 @@ void net_ip_tcp_checksum(unsigned char *
* 1c1d1e1f202122232425262728292a2b
* 2c2d2e2f3031323334353637
*/
-static void net_ip_icmp(struct net *net, void *extra,
+static void net_ip_icmp(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
int type;
@@ -166,7 +166,7 @@ static void net_ip_icmp(struct net *net,
switch (type) {
case 8: /* ECHO request */
debug("[ ICMP echo ]\n");
- lp = net_allocate_ethernet_packet_link(net, extra, len);
+ lp = net_allocate_ethernet_packet_link(net, nic, len);
/* Copy the old packet first: */
memcpy(lp->data + 12, packet + 12, len - 12);
@@ -225,7 +225,7 @@ static void tcp_closeconnection(struct n
* This creates an ethernet packet for the guest OS with an ACK to the
* initial SYN packet.
*/
-void net_ip_tcp_connectionreply(struct net *net, void *extra,
+void net_ip_tcp_connectionreply(struct net *net, struct nic_data *nic,
int con_id, int connecting, unsigned char *data, int datalen, int rst)
{
struct ethernet_packet_link *lp;
@@ -238,7 +238,7 @@ void net_ip_tcp_connectionreply(struct n
net->tcp_connections[con_id].tcp_id ++;
tcp_length = 20 + option_len + datalen;
ip_len = 20 + tcp_length;
- lp = net_allocate_ethernet_packet_link(net, extra, 14 + ip_len);
+ lp = net_allocate_ethernet_packet_link(net, nic, 14 + ip_len);
/* Ethernet header: */
memcpy(lp->data + 0, net->tcp_connections[con_id].ethernet_address, 6);
@@ -376,7 +376,7 @@ void net_ip_tcp_connectionreply(struct n
* http://www.networksorcery.com/enp/protocol/tcp.htm
* http://www.tcpipguide.com/free/t_TCPIPTransmissionControlProtocolTCP.htm
*/
-static void net_ip_tcp(struct net *net, void *extra,
+static void net_ip_tcp(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
int con_id, free_con_id, i, res;
@@ -585,7 +585,7 @@ static void net_ip_tcp(struct net *net,
if (rst) {
debug("[ 'rst': disconnecting TCP connection %i ]\n", con_id);
- net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
+ net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 1);
tcp_closeconnection(net, con_id);
return;
}
@@ -596,7 +596,7 @@ static void net_ip_tcp(struct net *net,
"connection %i ]\n", con_id);
/* Send an RST? (TODO, this is wrong...) */
- net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 1);
+ net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 1);
/* ... and forget about this connection: */
tcp_closeconnection(net, con_id);
@@ -610,7 +610,7 @@ static void net_ip_tcp(struct net *net,
/* Send an ACK: */
net->tcp_connections[con_id].state = TCP_OUTSIDE_CONNECTED;
- net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
+ net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0);
net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
return;
}
@@ -620,7 +620,7 @@ static void net_ip_tcp(struct net *net,
con_id);
/* Send ACK: */
- net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
+ net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0);
net->tcp_connections[con_id].state = TCP_OUTSIDE_DISCONNECTED2;
/* Return and send FIN: */
@@ -725,7 +725,7 @@ debug(" all acked\n");
ret:
/* Send an ACK (or FIN) to the guest OS: */
- net_ip_tcp_connectionreply(net, extra, con_id, 0, NULL, 0, 0);
+ net_ip_tcp_connectionreply(net, nic, con_id, 0, NULL, 0, 0);
}
@@ -746,7 +746,7 @@ ret:
* srcport=fffc dstport=0035 length=0028 chksum=76b6
* 43e20100000100000000000003667470066e6574627364036f726700001c0001
*/
-static void net_ip_udp(struct net *net, void *extra,
+static void net_ip_udp(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
int con_id, free_con_id, i, srcport, dstport, udp_len;
@@ -882,7 +882,8 @@ static void net_ip_udp(struct net *net,
*
* Handle an IP packet, coming from the emulated NIC.
*/
-void net_ip(struct net *net, void *extra, unsigned char *packet, int len)
+void net_ip(struct net *net, struct nic_data *nic, unsigned char *packet,
+ int len)
{
#if 1
int i;
@@ -913,13 +914,13 @@ void net_ip(struct net *net, void *extra
/* IPv4: */
switch (packet[23]) {
case 1: /* ICMP */
- net_ip_icmp(net, extra, packet, len);
+ net_ip_icmp(net, nic, packet, len);
break;
case 6: /* TCP */
- net_ip_tcp(net, extra, packet, len);
+ net_ip_tcp(net, nic, packet, len);
break;
case 17:/* UDP */
- net_ip_udp(net, extra, packet, len);
+ net_ip_udp(net, nic, packet, len);
break;
default:
fatal("[ net: IP: UNIMPLEMENTED protocol %i ]\n",
@@ -939,7 +940,7 @@ void net_ip(struct net *net, void *extra
* Read http://tools.ietf.org/html/rfc2131 for details on DHCP.
* (And http://users.telenet.be/mydotcom/library/network/dhcp.htm.)
*/
-static void net_ip_broadcast_dhcp(struct net *net, void *extra,
+static void net_ip_broadcast_dhcp(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
/*
@@ -1008,7 +1009,7 @@ static void net_ip_broadcast_dhcp(struct
fatal(" ]\n");
reply_len = 307;
- lp = net_allocate_ethernet_packet_link(net, extra, reply_len);
+ lp = net_allocate_ethernet_packet_link(net, nic, reply_len);
/* From old packet, copy everything before options field: */
memcpy(lp->data, packet, 278);
@@ -1130,7 +1131,7 @@ packet = lp->data;
* Handle an IP broadcast packet, coming from the emulated NIC.
* (This is usually a DHCP request, or similar.)
*/
-void net_ip_broadcast(struct net *net, void *extra,
+void net_ip_broadcast(struct net *net, struct nic_data *nic,
unsigned char *packet, int len)
{
unsigned char *p = (unsigned char *) &net->netmask_ipv4;
@@ -1193,7 +1194,7 @@ void net_ip_broadcast(struct net *net, v
packet[23] == 0x11 && /* UDP */
packet[34] == 0 && packet[35] == 68 && /* DHCP client */
packet[36] == 0 && packet[37] == 67) { /* DHCP server */
- net_ip_broadcast_dhcp(net, extra, packet, len);
+ net_ip_broadcast_dhcp(net, nic, packet, len);
return;
}
@@ -1222,7 +1223,7 @@ void net_ip_broadcast(struct net *net, v
*
* Receive any available UDP packets (from the outside world).
*/
-void net_udp_rx_avail(struct net *net, void *extra)
+void net_udp_rx_avail(struct net *net, struct nic_data *nic)
{
int received_packets_this_tick = 0;
int max_packets_this_tick = 200;
@@ -1326,7 +1327,7 @@ void net_udp_rx_avail(struct net *net, v
ip_len = 20 + this_packets_data_length;
- lp = net_allocate_ethernet_packet_link(net, extra,
+ lp = net_allocate_ethernet_packet_link(net, nic,
14 + 20 + this_packets_data_length);
/* Ethernet header: */
@@ -1381,7 +1382,7 @@ void net_udp_rx_avail(struct net *net, v
*
* Receive any available TCP packets (from the outside world).
*/
-void net_tcp_rx_avail(struct net *net, void *extra)
+void net_tcp_rx_avail(struct net *net, struct nic_data *nic)
{
int received_packets_this_tick = 0;
int max_packets_this_tick = 200;
@@ -1445,7 +1446,7 @@ void net_tcp_rx_avail(struct net *net, v
net->tcp_connections[con_id].state =
TCP_OUTSIDE_CONNECTED;
debug("CHANGING TO TCP_OUTSIDE_CONNECTED\n");
- net_ip_tcp_connectionreply(net, extra, con_id, 1,
+ net_ip_tcp_connectionreply(net, nic, con_id, 1,
NULL, 0, 0);
}
@@ -1477,7 +1478,7 @@ void net_tcp_rx_avail(struct net *net, v
net->tcp_connections[con_id].
incoming_buf_seqnr;
- net_ip_tcp_connectionreply(net, extra, con_id,
+ net_ip_tcp_connectionreply(net, nic, con_id,
0, net->tcp_connections[con_id].
incoming_buf,
net->tcp_connections[con_id].
@@ -1519,21 +1520,21 @@ void net_tcp_rx_avail(struct net *net, v
memcpy(net->tcp_connections[con_id].incoming_buf,
buf, res);
- net_ip_tcp_connectionreply(net, extra, con_id, 0,
+ net_ip_tcp_connectionreply(net, nic, con_id, 0,
buf, res, 0);
} else if (res == 0) {
net->tcp_connections[con_id].state =
TCP_OUTSIDE_DISCONNECTED;
debug("CHANGING TO TCP_OUTSIDE_DISCONNECTED, read"
" res=0\n");
- net_ip_tcp_connectionreply(net, extra, con_id, 0,
+ net_ip_tcp_connectionreply(net, nic, con_id, 0,
NULL, 0, 0);
} else {
net->tcp_connections[con_id].state =
TCP_OUTSIDE_DISCONNECTED;
fatal("CHANGING TO TCP_OUTSIDE_DISCONNECTED, "
"read res<=0, errno = %i\n", errno);
- net_ip_tcp_connectionreply(net, extra, con_id, 0,
+ net_ip_tcp_connectionreply(net, nic, con_id, 0,
NULL, 0, 0);
}
$NetBSD: patch-src_net_net_tap.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- /dev/null 2020-10-05 22:44:11.028207457 +0000
+++ src/net/net_tap.cc 2020-10-05 23:03:15.768748362 +0000
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2020 Jason R. Thorpe. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Support for Ethernet tap interfaces.
+ *
+ * A single tap instance is used for the entire simulated network.
+ * We treat this as sort of virtual Ethernet switch, with the tap
+ * being the upstream port. This is very simple, conceptually, and
+ * fits in nicely with the rest of the network simulation model in
+ * GXemul.
+ *
+ * Use of the tap interface is completely optional, but if it is used
+ * the all of the virtual IP network support is bypassed completely.
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "misc.h"
+#include "net.h"
+
+/*
+ * net_tap_rx_for_nic():
+ *
+ * Receive a packet from the virtual Ethernet switch for this NIC.
+ */
+static void net_tap_rx_for_nic(struct net *net, struct nic_data *nic,
+ unsigned char *buf, ssize_t size)
+{
+ struct ethernet_packet_link *lp;
+
+ /*
+ * We should deliver to the interface if:
+ *
+ * ==> The interface is in promiscuous mode.
+ * -- or --
+ * ==> The packet is broadcast or multicast (the emulated device
+ * can further apply a multicast filter if it wishes).
+ * -- or --
+ * ==> The destination MAC address matches the NIC MAC address.
+ *
+ * Note that normally a switch would not know if an interface
+ * is in promiscuous mode, but this is a bit of extra magic
+ * we implement because we can for the sake of convenience.
+ * Also, some emulated interfaces may want to see all packets
+ * so as to implement their own filtering logic.
+ *
+ * Also note that testing for multicast also catches the broadcast
+ * case.
+ */
+
+ if (nic->promiscuous_mode ||
+ net_ether_multicast(buf) || net_ether_eq(nic->mac_address, buf)) {
+ lp = net_allocate_ethernet_packet_link(net, nic, (int)size);
+ memcpy(lp->data, buf, size);
+ }
+}
+
+/*
+ * net_tap_rx_avail():
+ *
+ * We poll the net-shared tap device and link up any available packets to
+ * their destination interfaces, acting like a virtual Ethernet switch.
+ */
+void net_tap_rx_avail(struct net *net)
+{
+ int received_packets_this_tick = 0;
+ int max_packets_this_tick = 200;
+
+ for (;;) {
+ unsigned char buf[1518];
+ ssize_t bytes_read;
+ int i;
+
+ if (received_packets_this_tick > max_packets_this_tick)
+ break;
+
+ /* Read one packet from the tap device. */
+ bytes_read = read(net->tap_fd, buf, sizeof(buf));
+
+ if (bytes_read < 0) {
+ /* No more packets available on the tap. */
+ break;
+ }
+
+ /*
+ * Drop runt packets now; allow other layers to assume
+ * valid Ethernet frames. This really should be 64, but
+ * 20 is used in the transmit path.
+ */
+ if (bytes_read < 20)
+ continue;
+
+ for (i = 0; i < net->n_nics; i++) {
+ net_tap_rx_for_nic(net, net->nic_data[i],
+ buf, bytes_read);
+ }
+ }
+}
+
+/*
+ * net_tap_tx():
+ *
+ * Transmit an ethernet packet, as seen from the emulated ethernet controller,
+ * to the net-shared tap device. Even if the packet is destined only for
+ * a NIC on the local virtual Ethernet switch, we always send it to the
+ * tap device so that the host system can monitor traffic by running tcpdump
+ * on its view of the tap.
+ */
+void net_tap_tx(struct net *net, struct nic_data *nic,
+ unsigned char *packet, int len)
+{
+ int i;
+
+ for (i = 0; i < net->n_nics; i++) {
+ if (nic == net->nic_data[i])
+ continue;
+ net_tap_rx_for_nic(net, net->nic_data[i], packet, len);
+ }
+
+ /*
+ * Don't bother checking for errors here. The tap driver in the
+ * kernel will either take the entire packet or none of it, and
+ * there isn't any useful error recovery for us anyway.
+ */
+ write(net->tap_fd, packet, len);
+}
+
+/*
+ * net_tap_init():
+ *
+ * Initialize the tap interface. Returns 1 if successful, 0 otherwise.
+ */
+int net_tap_init(struct net *net, const char *tapdev)
+{
+ int fd;
+ int one = 1;
+
+ fd = open(tapdev, O_RDWR);
+ if (fd < 0) {
+ fatal("[ net: unable to open tap device '%s': %s ]\n",
+ tapdev, strerror(errno));
+ return 0;
+ }
+
+ if (ioctl(fd, FIONBIO, &one) < 0) {
+ fatal("[ net: unable to set non-blocking mode on "
+ "tap device '%s': %s ]\n", tapdev, strerror(errno));
+ close(fd);
+ return 0;
+ }
+
+ net->tapdev = strdup(tapdev);
+ net->tap_fd = fd;
+
+ return 1;
+}
$NetBSD: patch-src_old_main_emul.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/old_main/emul.cc.orig 2020-10-05 23:04:14.559513959 +0000
+++ src/old_main/emul.cc 2020-10-05 23:04:26.418738637 +0000
@@ -748,6 +748,7 @@ void emul_simple_init(struct emul *emul)
/* Create a simple network: */
emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
+ NULL,
NET_DEFAULT_IPV4_MASK,
NET_DEFAULT_IPV4_LEN,
NULL, 0, 0, NULL);
$NetBSD: patch-src_old_main_emul_parse.cc,v 1.1 2020/10/07 00:43:05 thorpej Exp $
Add support for tap(4)-based networking.
--- src/old_main/emul_parse.cc.orig 2020-10-05 23:04:38.529354586 +0000
+++ src/old_main/emul_parse.cc 2020-10-05 23:04:50.653298084 +0000
@@ -197,6 +197,7 @@ static void read_one_word(FILE *f, char
#define PARSESTATE_NET 2
#define PARSESTATE_MACHINE 3
+static char cur_net_tapdev[50];
static char cur_net_ipv4net[50];
static char cur_net_ipv4len[50];
static char cur_net_local_port[10];
@@ -315,6 +316,7 @@ static void parse__emul(struct emul *e,
line, EXPECT_LEFT_PARENTHESIS);
/* Default net: */
+ strlcpy(cur_net_tapdev, "", sizeof(cur_net_tapdev));
strlcpy(cur_net_ipv4net, NET_DEFAULT_IPV4_MASK,
sizeof(cur_net_ipv4net));
snprintf(cur_net_ipv4len, sizeof(cur_net_ipv4len), "%i",
@@ -391,6 +393,7 @@ static void parse__net(struct emul *e, F
sizeof(cur_net_local_port));
e->net = net_init(e, NET_INIT_FLAG_GATEWAY,
+ cur_net_tapdev[0] ? cur_net_tapdev : NULL,
cur_net_ipv4net, atoi(cur_net_ipv4len),
cur_net_remote, cur_net_n_remote,
atoi(cur_net_local_port), NULL);
@@ -410,6 +413,7 @@ static void parse__net(struct emul *e, F
return;
}
+ WORD("tapdev", cur_net_tapdev);
WORD("ipv4net", cur_net_ipv4net);
WORD("ipv4len", cur_net_ipv4len);
WORD("local_port", cur_net_local_port);