Skip to content

Commit

Permalink
nvnet: Add unicast and multicast filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
mborgerson committed Oct 18, 2023
1 parent ccb1211 commit d6e5342
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
62 changes: 62 additions & 0 deletions hw/xbox/nvnet.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,16 @@
#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"

#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__)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions hw/xbox/trace-events
Original file line number Diff line number Diff line change
Expand Up @@ -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"

0 comments on commit d6e5342

Please sign in to comment.