gxemul: Update to 0.6.3 really

This commit is contained in:
ryoon 2021-02-22 14:03:35 +00:00
parent 269f7c8073
commit f557af58e9
18 changed files with 12 additions and 2614 deletions

View file

@ -1,4 +1,4 @@
@comment $NetBSD: PLIST,v 1.28 2019/08/23 13:13:49 ryoon Exp $
@comment $NetBSD: PLIST,v 1.29 2021/02/22 14:03:35 ryoon Exp $
bin/gxemul
man/man1/gxemul.1
share/doc/gxemul/20040504-ultrix45-boot1.png
@ -112,6 +112,8 @@ share/doc/gxemul/20190612-netbsd-sgimips-2.png
share/doc/gxemul/20190612-netbsd-sgimips-2_small.png
share/doc/gxemul/20190616-netbsd-playstation2-userland-small.png
share/doc/gxemul/20190616-netbsd-playstation2-userland.png
share/doc/gxemul/20190715-sgi-o2-linux-small.png
share/doc/gxemul/20190715-sgi-o2-linux.png
share/doc/gxemul/Doxyfile
share/doc/gxemul/HISTORY
share/doc/gxemul/LICENSE
@ -197,6 +199,10 @@ share/doc/gxemul/machines/machine_testmips-thumb.png
share/doc/gxemul/misc.html
share/doc/gxemul/model.png
share/doc/gxemul/networking.html
share/doc/gxemul/openbsd-luna88k-20210130-small.png
share/doc/gxemul/openbsd-luna88k-20210130.png
share/doc/gxemul/openbsd-luna88k-20210209-small.png
share/doc/gxemul/openbsd-luna88k-20210209.png
share/doc/gxemul/openbsd-pmax-20040710.png
share/doc/gxemul/openbsd-pmax-20040710_small.png
share/doc/gxemul/sgi-o2-real.jpg

View file

@ -1,22 +1,6 @@
$NetBSD: distinfo,v 1.62 2021/01/16 16:49:36 skrll Exp $
$NetBSD: distinfo,v 1.63 2021/02/22 14:03:35 ryoon Exp $
SHA1 (gxemul-0.6.2.tar.gz) = aabaeba783e70be952ab0056bf84d0f2b70c2155
RMD160 (gxemul-0.6.2.tar.gz) = ccac73d82446f89792b1fc803bee623813f3aab2
SHA512 (gxemul-0.6.2.tar.gz) = 4f389c509f9ecf39603ceed50e899e2bee285d3fefac9b3214076115ee71b5a7a68d1d92690b6debc8de5cf5f0303da83b3cc921a5c0b5eb4c7ad89baa730b59
Size (gxemul-0.6.2.tar.gz) = 5897883 bytes
SHA1 (patch-doc_networking.html) = dd7a1519a678196fd5a835317a32ba483630ece8
SHA1 (patch-src_cpus_cpu__mips__instr__loadstore.cc) = 378c514ddf3b93279b2c479f21b77447d83d5afd
SHA1 (patch-src_devices_dev_dec21143.cc) = 52f36741038c76a2dbafc7da6737e816aed5c9f9
SHA1 (patch-src_devices_dev_ether.cc) = 00221e09530743e81faedcc75ee951fa853d0e2c
SHA1 (patch-src_devices_dev_le.cc) = a728e8008a7a9f33aaf95811a33ebac2cb86e80e
SHA1 (patch-src_devices_dev_rtl8139c.cc) = ee6dbba7c7c9c62c50493c476297ee5ac89d2b83
SHA1 (patch-src_devices_dev_sgi_mec.cc) = 24b1259350faf60265df7958f0f680302f475e8e
SHA1 (patch-src_devices_dev_sn.cc) = e939521be1630f51e7ddc67abe90980de38e8837
SHA1 (patch-src_include_net.h) = 4d31fcefe384fcc9d68255825240c89b45acc92e
SHA1 (patch-src_net_Makefile.skel) = 4738229a928b9cb5a2531dfc357297f91e9fdc09
SHA1 (patch-src_net_net.cc) = 57397c9a8197ee25e7faa8c0733273014e3e0670
SHA1 (patch-src_net_net_ether.cc) = ef7464dbb0812a9cb8d5be806db07cc19853fc1e
SHA1 (patch-src_net_net_ip.cc) = f5615f3b347e9bdcd256fa4b5b1594473fd2e5e4
SHA1 (patch-src_net_net_tap.cc) = f913b3efb51bc4a8080420988d5fc845e8a38f73
SHA1 (patch-src_old_main_emul.cc) = 0b1106745e7c5d320e93f9f7775d8ced6109c089
SHA1 (patch-src_old_main_emul_parse.cc) = 23048bc3a0a83fd189b3bbd4656ef0e1a2c23b99
SHA1 (gxemul-0.6.3.tar.gz) = 433b26f34205924c4a0febd37ed9df3769da0111
RMD160 (gxemul-0.6.3.tar.gz) = c155accc030fc63002be3a72aae1e6b33d027878
SHA512 (gxemul-0.6.3.tar.gz) = 30bdb926ab180a44b277b734d5ff4d31b8f0a8b580c6976226f6ed1952cb50d16e18591591d6aeee243c5b3e9d27b71d24a3cba3906bcb332399f46a1ebd8ac5
Size (gxemul-0.6.3.tar.gz) = 6024573 bytes

View file

@ -1,120 +0,0 @@
$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>

View file

@ -1,44 +0,0 @@
$NetBSD: patch-src_cpus_cpu__mips__instr__loadstore.cc,v 1.1 2021/01/16 16:49:36 skrll Exp $
--- src/cpus/cpu_mips_instr_loadstore.cc.orig 2021-01-16 16:33:52.314709654 +0000
+++ src/cpus/cpu_mips_instr_loadstore.cc
@@ -58,6 +58,30 @@ void LS_GENERIC_N(struct cpu *cpu, struc
/* Check alignment: */
if (addr & (LS_SIZE - 1)) {
#if 1
+ uint64_t vaddr_vpn2=0, vaddr_asid=0;
+
+ int exc_model = cpu->cd.mips.cpu_type.exc_model;
+ struct mips_coproc *cp0 = cpu->cd.mips.coproc[0];
+
+ if (exc_model == EXC3K) {
+ vaddr_asid = (cp0->reg[COP0_ENTRYHI] &
+ R2K3K_ENTRYHI_ASID_MASK) >>
+ R2K3K_ENTRYHI_ASID_SHIFT;
+ vaddr_vpn2 = (addr & R2K3K_ENTRYHI_VPN_MASK) >>
+ R2K3K_ENTRYHI_VPN_SHIFT;
+ } else {
+ vaddr_asid = cp0->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
+
+ if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
+ vaddr_vpn2 = (addr &
+ ENTRYHI_VPN2_MASK_R10K) >>
+ ENTRYHI_VPN2_SHIFT;
+ } else {
+ vaddr_vpn2 = (addr & ENTRYHI_VPN2_MASK) >>
+ ENTRYHI_VPN2_SHIFT;
+ }
+ }
+
/* Cause an address alignment exception: */
mips_cpu_exception(cpu,
#ifdef LS_LOAD
@@ -65,7 +89,7 @@ void LS_GENERIC_N(struct cpu *cpu, struc
#else
EXCEPTION_ADES,
#endif
- 0, addr, 0, 0, 0, 0);
+ 0, addr, 0, vaddr_vpn2, vaddr_asid, 0);
#else
fatal("{ mips dyntrans alignment exception, size = %i,"
" addr = %016"PRIx64", pc = %016"PRIx64" }\n", LS_SIZE,

View file

@ -1,890 +0,0 @@
$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);

View file

@ -1,74 +0,0 @@
$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);

View file

@ -1,232 +0,0 @@
$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);
}

View file

@ -1,51 +0,0 @@
$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;
}

View file

@ -1,69 +0,0 @@
$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);
}

View file

@ -1,40 +0,0 @@
$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;
}

View file

@ -1,107 +0,0 @@
$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;
};

View file

@ -1,15 +0,0 @@
$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)

View file

@ -1,318 +0,0 @@
$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);

View file

@ -1,150 +0,0 @@
$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;
+}

View file

@ -1,238 +0,0 @@
$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);
}

View file

@ -1,192 +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;
+}

View file

@ -1,14 +0,0 @@
$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);

View file

@ -1,38 +0,0 @@
$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);