diff options
Diffstat (limited to 'hw/eepro100.c')
-rw-r--r-- | hw/eepro100.c | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/hw/eepro100.c b/hw/eepro100.c index 8cbc3aa7a2..41d792ad24 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); @@ -1282,7 +1290,7 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val) static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr) { - uint8_t val; + uint8_t val = 0; if (addr <= sizeof(s->mem) - sizeof(val)) { memcpy(&val, &s->mem[addr], sizeof(val)); } @@ -1325,7 +1333,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr) static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr) { - uint16_t val; + uint16_t val = 0; if (addr <= sizeof(s->mem) - sizeof(val)) { memcpy(&val, &s->mem[addr], sizeof(val)); } @@ -1348,7 +1356,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr) static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr) { - uint32_t val; + uint32_t val = 0; if (addr <= sizeof(s->mem) - sizeof(val)) { memcpy(&val, &s->mem[addr], sizeof(val)); } @@ -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))); |