summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Weil <weil@mail.berlios.de>2010-09-29 21:59:55 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2010-10-12 16:09:45 -0500
commite74f86377a6184326be13f1c7a6c7f9c218b1798 (patch)
tree5d88c7cb55315972423df83dc863b8356395646c
parent286409ad631f3c5df737d0693785ef67dcfd8ba7 (diff)
downloadqemu-e74f86377a6184326be13f1c7a6c7f9c218b1798.tar.gz
eepro100: Add support for multiple individual addresses (multiple IA)
I reviewed the latest sources of Linux, FreeBSD and NetBSD. They all reset the multiple IA bit (multi_ia in BSD) to zero, but I did not find code which sets this bit to one (like it is done by some routers). Running Windows guests also did not set this bit. Intel's Open Source Software Developer Manual does not give much information on the semantics related to this bit, so I had to guess how it works. The guess was good enough to make the router emulation work. Related changes in this patch: * Update naming and documentation of the internal hash register. It is not limited to multicast, but also used for multiple IA. * Dump complete configuration register when debug traces are enabled. * Debug output when multiple IA bit is set during CmdConfigure. * Debug output when frames are received because multiple IA bit is set, or when they are ignored although it is set. Cc: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Stefan Weil <weil@mail.berlios.de> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> (cherry picked from commit 010ec6293409f10b88631c36145944b9c3277ce1)
-rw-r--r--hw/eepro100.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 2b75c8f495..5f6dcb6e6e 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -219,7 +219,8 @@ typedef enum {
typedef struct {
PCIDevice dev;
- uint8_t mult[8]; /* multicast mask array */
+ /* Hash register (multicast mask array, multiple individual addresses). */
+ uint8_t mult[8];
int mmio_index;
NICState *nic;
NICConf conf;
@@ -599,7 +600,7 @@ static void nic_reset(void *opaque)
{
EEPRO100State *s = opaque;
TRACE(OTHER, logout("%p\n", s));
- /* TODO: Clearing of multicast table for selective reset, too? */
+ /* TODO: Clearing of hash register for selective reset, too? */
memset(&s->mult[0], 0, sizeof(s->mult));
nic_selective_reset(s);
}
@@ -851,7 +852,14 @@ static void action_command(EEPRO100State *s)
case CmdConfigure:
cpu_physical_memory_read(s->cb_address + 8, &s->configuration[0],
sizeof(s->configuration));
- TRACE(OTHER, logout("configuration: %s\n", nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[0], 16)));
+ TRACE(OTHER, logout("configuration: %s\n",
+ nic_dump(&s->configuration[16],
+ ARRAY_SIZE(s->configuration) - 16)));
+ if (s->configuration[20] & BIT(6)) {
+ TRACE(OTHER, logout("Multiple IA bit\n"));
+ }
break;
case CmdMulticastList:
set_multicast_list(s);
@@ -1647,12 +1655,6 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- /* TODO: check multiple IA bit. */
- if (s->configuration[20] & BIT(6)) {
- missing("Multiple IA bit");
- return -1;
- }
-
if (s->configuration[8] & 0x80) {
/* CSMA is disabled. */
logout("%p received while CSMA is disabled\n", s);
@@ -1702,6 +1704,16 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
/* Promiscuous: receive all. */
TRACE(RXTX, logout("%p received frame in promiscuous mode, len=%zu\n", s, size));
rfd_status |= 0x0004;
+ } else if (s->configuration[20] & BIT(6)) {
+ /* Multiple IA bit set. */
+ unsigned mcast_idx = compute_mcast_idx(buf);
+ assert(mcast_idx < 64);
+ if (s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))) {
+ TRACE(RXTX, logout("%p accepted, multiple IA bit set\n", s));
+ } else {
+ TRACE(RXTX, logout("%p frame ignored, multiple IA bit set\n", s));
+ return -1;
+ }
} else {
TRACE(RXTX, logout("%p received frame, ignored, len=%zu,%s\n", s, size,
nic_dump(buf, size)));