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

cvs diff -r1.67 -r1.68 pkgsrc/emulators/gxemul/Makefile (expand / switch to unified diff)

--- 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
3DISTNAME= gxemul-0.6.2 3DISTNAME= gxemul-0.6.2
 4PKGREVISION= 1
4CATEGORIES= emulators 5CATEGORIES= emulators
5MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=gxemul/} 6MASTER_SITES= ${MASTER_SITE_SOURCEFORGE:=gxemul/}
6 7
7MAINTAINER= pkgsrc-users@NetBSD.org 8MAINTAINER= pkgsrc-users@NetBSD.org
8HOMEPAGE= http://gavare.se/gxemul/ 9HOMEPAGE= http://gavare.se/gxemul/
9COMMENT= Framework for full-system computer architecture emulation 10COMMENT= Framework for full-system computer architecture emulation
10LICENSE= modified-bsd 11LICENSE= modified-bsd
11 12
12USE_TOOLS+= pax 13USE_TOOLS+= pax
13 14
14USE_LANGUAGES= c c++ 15USE_LANGUAGES= c c++
15HAS_CONFIGURE= yes 16HAS_CONFIGURE= yes
16BUILD_TARGET= build 17BUILD_TARGET= build

cvs diff -r1.60 -r1.61 pkgsrc/emulators/gxemul/distinfo (expand / switch to unified diff)

--- 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
3SHA1 (gxemul-0.6.2.tar.gz) = aabaeba783e70be952ab0056bf84d0f2b70c2155 3SHA1 (gxemul-0.6.2.tar.gz) = aabaeba783e70be952ab0056bf84d0f2b70c2155
4RMD160 (gxemul-0.6.2.tar.gz) = ccac73d82446f89792b1fc803bee623813f3aab2 4RMD160 (gxemul-0.6.2.tar.gz) = ccac73d82446f89792b1fc803bee623813f3aab2
5SHA512 (gxemul-0.6.2.tar.gz) = 4f389c509f9ecf39603ceed50e899e2bee285d3fefac9b3214076115ee71b5a7a68d1d92690b6debc8de5cf5f0303da83b3cc921a5c0b5eb4c7ad89baa730b59 5SHA512 (gxemul-0.6.2.tar.gz) = 4f389c509f9ecf39603ceed50e899e2bee285d3fefac9b3214076115ee71b5a7a68d1d92690b6debc8de5cf5f0303da83b3cc921a5c0b5eb4c7ad89baa730b59
6Size (gxemul-0.6.2.tar.gz) = 5897883 bytes 6Size (gxemul-0.6.2.tar.gz) = 5897883 bytes
 7SHA1 (patch-doc_networking.html) = dd7a1519a678196fd5a835317a32ba483630ece8
 8SHA1 (patch-src_devices_dev_dec21143.cc) = 52f36741038c76a2dbafc7da6737e816aed5c9f9
 9SHA1 (patch-src_devices_dev_ether.cc) = 00221e09530743e81faedcc75ee951fa853d0e2c
 10SHA1 (patch-src_devices_dev_le.cc) = a728e8008a7a9f33aaf95811a33ebac2cb86e80e
 11SHA1 (patch-src_devices_dev_rtl8139c.cc) = ee6dbba7c7c9c62c50493c476297ee5ac89d2b83
 12SHA1 (patch-src_devices_dev_sgi_mec.cc) = 24b1259350faf60265df7958f0f680302f475e8e
 13SHA1 (patch-src_devices_dev_sn.cc) = e939521be1630f51e7ddc67abe90980de38e8837
 14SHA1 (patch-src_include_net.h) = 4d31fcefe384fcc9d68255825240c89b45acc92e
 15SHA1 (patch-src_net_Makefile.skel) = 4738229a928b9cb5a2531dfc357297f91e9fdc09
 16SHA1 (patch-src_net_net.cc) = 57397c9a8197ee25e7faa8c0733273014e3e0670
 17SHA1 (patch-src_net_net_ether.cc) = ef7464dbb0812a9cb8d5be806db07cc19853fc1e
 18SHA1 (patch-src_net_net_ip.cc) = f5615f3b347e9bdcd256fa4b5b1594473fd2e5e4
 19SHA1 (patch-src_net_net_tap.cc) = f913b3efb51bc4a8080420988d5fc845e8a38f73
 20SHA1 (patch-src_old_main_emul.cc) = 0b1106745e7c5d320e93f9f7775d8ced6109c089
 21SHA1 (patch-src_old_main_emul_parse.cc) = 23048bc3a0a83fd189b3bbd4656ef0e1a2c23b99

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-doc_networking.html
$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>

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_dec21143.cc
$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);

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_ether.cc
$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);

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_le.cc
$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);
 }
 

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_rtl8139c.cc
$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;
 }

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_sgi_mec.cc
$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);
 }
 
 

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_devices_dev_sn.cc
$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;
 }

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_include_net.h
$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;
 };

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_net_Makefile.skel
$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)
 

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_net_net.cc
$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);

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_net_net_ether.cc
$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;
+}

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_net_net_ip.cc
$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);
 		}
 

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_net_net_tap.cc
$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;
+}

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_old_main_emul.cc
$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);

File Added: pkgsrc/emulators/gxemul/patches/Attic/patch-src_old_main_emul_parse.cc
$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);