From d6e5342f8993b338236bfea1e119c42ee2379b97 Mon Sep 17 00:00:00 2001 From: Matt Borgerson Date: Tue, 17 Oct 2023 23:34:39 -0700 Subject: [PATCH] nvnet: Add unicast and multicast filtering --- hw/xbox/nvnet.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ hw/xbox/trace-events | 7 +++++ 2 files changed, 69 insertions(+) diff --git a/hw/xbox/nvnet.c b/hw/xbox/nvnet.c index 121369a8be..2440b2cd93 100644 --- a/hw/xbox/nvnet.c +++ b/hw/xbox/nvnet.c @@ -25,6 +25,7 @@ #include "hw/pci/pci.h" #include "hw/qdev-properties.h" #include "net/net.h" +#include "qemu/bswap.h" #include "qemu/iov.h" #include "migration/vmstate.h" #include "nvnet_regs.h" @@ -32,6 +33,8 @@ #define IOPORT_SIZE 0x8 #define MMIO_SIZE 0x400 +static const uint8_t bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + // #define DEBUG #ifdef DEBUG # define NVNET_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) @@ -432,6 +435,58 @@ static bool nvnet_is_packet_oversized(size_t size) return size > RX_ALLOC_BUFSIZE; } +static bool receive_filter(NvNetState *s, const uint8_t *buf, int size) +{ + if (size < 6) { + return false; + } + + uint32_t rctl = nvnet_get_reg(s, NvRegPacketFilterFlags, 4); + int isbcast = !memcmp(buf, bcast, sizeof bcast); + + /* Broadcast */ + if (isbcast) { + /* FIXME: bcast filtering */ + trace_nvnet_rx_filter_bcast_match(); + return true; + } + + if (!(rctl & NVREG_PFF_MYADDR)) { + /* FIXME: Confirm PFF_MYADDR filters mcast */ + return true; + } + + /* Multicast */ + uint32_t addr[2]; + addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrA, 4)); + addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMulticastAddrB, 4)); + if (memcmp(addr, bcast, sizeof bcast)) { + uint32_t dest_addr[2]; + memcpy(dest_addr, buf, 6); + dest_addr[0] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskA, 4)); + dest_addr[1] &= cpu_to_le32(nvnet_get_reg(s, NvRegMulticastMaskB, 4)); + + if (!memcmp(dest_addr, addr, 6)) { + trace_nvnet_rx_filter_mcast_match(MAC_ARG(dest_addr)); + return true; + } else { + trace_nvnet_rx_filter_mcast_mismatch(MAC_ARG(dest_addr)); + } + } + + /* Unicast */ + addr[0] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrA, 4)); + addr[1] = cpu_to_le32(nvnet_get_reg(s, NvRegMacAddrB, 4)); + if (!memcmp(buf, addr, 6)) { + trace_nvnet_rx_filter_ucast_match(MAC_ARG(buf)); + return true; + } else { + trace_nvnet_rx_filter_ucast_mismatch(MAC_ARG(buf)); + } + + return false; +} + static ssize_t nvnet_receive_iov(NetClientState *nc, const struct iovec *iov, int iovcnt) { @@ -443,10 +498,17 @@ static ssize_t nvnet_receive_iov(NetClientState *nc, if (nvnet_is_packet_oversized(size)) { /* Drop */ NVNET_DPRINTF("%s packet too large!\n", __func__); + trace_nvnet_rx_oversized(size); return size; } iov_to_buf(iov, iovcnt, 0, s->rx_dma_buf, size); + + if (!receive_filter(s, s->rx_dma_buf, size)) { + trace_nvnet_rx_filter_dropped(); + return size; + } + #ifdef DEBUG nvnet_hex_dump(s, s->rx_dma_buf, size); #endif diff --git a/hw/xbox/trace-events b/hw/xbox/trace-events index 91e39b3ce2..fbda278fe7 100644 --- a/hw/xbox/trace-events +++ b/hw/xbox/trace-events @@ -7,3 +7,10 @@ nvnet_reg_read(uint32_t addr, const char *name, unsigned int size, uint64_t val) nvnet_reg_write(uint32_t addr, const char *name, unsigned int size, uint64_t val) "addr 0x%"PRIx32" %s size %d val 0x%"PRIx64 nvnet_io_read(uint32_t addr, unsigned int size, uint64_t val) "addr 0x%"PRIx32" size %d val 0x%"PRIx64 nvnet_io_write(uint32_t addr, unsigned int size, uint64_t val) "addr 0x%"PRIx32" size %d val 0x%"PRIx64 +nvnet_rx_filter_bcast_match(void) "broadcast match" +nvnet_rx_filter_mcast_match(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "multicast match: %02x:%02x:%02x:%02x:%02x:%02x" +nvnet_rx_filter_mcast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "multicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x" +nvnet_rx_filter_ucast_match(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast match: %02x:%02x:%02x:%02x:%02x:%02x" +nvnet_rx_filter_ucast_mismatch(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5) "unicast mismatch: %02x:%02x:%02x:%02x:%02x:%02x" +nvnet_rx_oversized(size_t size) "Received packet dropped because it was oversized (%zu bytes)" +nvnet_rx_filter_dropped(void) "Received packet dropped by RX filter"