| 122 |
uint16_t rcnt; |
uint16_t rcnt; |
| 123 |
uint32_t rsar; |
uint32_t rsar; |
| 124 |
uint8_t rsr; |
uint8_t rsr; |
| 125 |
|
uint8_t rxcr; |
| 126 |
uint8_t isr; |
uint8_t isr; |
| 127 |
uint8_t dcfg; |
uint8_t dcfg; |
| 128 |
uint8_t imr; |
uint8_t imr; |
| 131 |
uint8_t mult[8]; /* multicast mask array */ |
uint8_t mult[8]; /* multicast mask array */ |
| 132 |
int irq; |
int irq; |
| 133 |
PCIDevice *pci_dev; |
PCIDevice *pci_dev; |
| 134 |
NetDriverState *nd; |
VLANClientState *vc; |
| 135 |
|
uint8_t macaddr[6]; |
| 136 |
uint8_t mem[NE2000_MEM_SIZE]; |
uint8_t mem[NE2000_MEM_SIZE]; |
| 137 |
} NE2000State; |
} NE2000State; |
| 138 |
|
|
| 141 |
int i; |
int i; |
| 142 |
|
|
| 143 |
s->isr = ENISR_RESET; |
s->isr = ENISR_RESET; |
| 144 |
memcpy(s->mem, s->nd->macaddr, 6); |
memcpy(s->mem, s->macaddr, 6); |
| 145 |
s->mem[14] = 0x57; |
s->mem[14] = 0x57; |
| 146 |
s->mem[15] = 0x57; |
s->mem[15] = 0x57; |
| 147 |
|
|
| 169 |
} |
} |
| 170 |
} |
} |
| 171 |
|
|
| 172 |
|
#define POLYNOMIAL 0x04c11db6 |
| 173 |
|
|
| 174 |
|
/* From FreeBSD */ |
| 175 |
|
/* XXX: optimize */ |
| 176 |
|
static int compute_mcast_idx(const uint8_t *ep) |
| 177 |
|
{ |
| 178 |
|
uint32_t crc; |
| 179 |
|
int carry, i, j; |
| 180 |
|
uint8_t b; |
| 181 |
|
|
| 182 |
|
crc = 0xffffffff; |
| 183 |
|
for (i = 0; i < 6; i++) { |
| 184 |
|
b = *ep++; |
| 185 |
|
for (j = 0; j < 8; j++) { |
| 186 |
|
carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); |
| 187 |
|
crc <<= 1; |
| 188 |
|
b >>= 1; |
| 189 |
|
if (carry) |
| 190 |
|
crc = ((crc ^ POLYNOMIAL) | carry); |
| 191 |
|
} |
| 192 |
|
} |
| 193 |
|
return (crc >> 26); |
| 194 |
|
} |
| 195 |
|
|
| 196 |
/* return the max buffer size if the NE2000 can receive more data */ |
/* return the max buffer size if the NE2000 can receive more data */ |
| 197 |
static int ne2000_can_receive(void *opaque) |
static int ne2000_can_receive(void *opaque) |
| 198 |
{ |
{ |
| 218 |
{ |
{ |
| 219 |
NE2000State *s = opaque; |
NE2000State *s = opaque; |
| 220 |
uint8_t *p; |
uint8_t *p; |
| 221 |
int total_len, next, avail, len, index; |
int total_len, next, avail, len, index, mcast_idx; |
| 222 |
uint8_t buf1[60]; |
uint8_t buf1[60]; |
| 223 |
|
static const uint8_t broadcast_macaddr[6] = |
| 224 |
|
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
| 225 |
|
|
| 226 |
#if defined(DEBUG_NE2000) |
#if defined(DEBUG_NE2000) |
| 227 |
printf("NE2000: received len=%d\n", size); |
printf("NE2000: received len=%d\n", size); |
| 228 |
#endif |
#endif |
| 229 |
|
|
| 230 |
|
if (!ne2000_can_receive(s)) |
| 231 |
|
return; |
| 232 |
|
|
| 233 |
|
/* XXX: check this */ |
| 234 |
|
if (s->rxcr & 0x10) { |
| 235 |
|
/* promiscuous: receive all */ |
| 236 |
|
} else { |
| 237 |
|
if (!memcmp(buf, broadcast_macaddr, 6)) { |
| 238 |
|
/* broadcast address */ |
| 239 |
|
if (!(s->rxcr & 0x04)) |
| 240 |
|
return; |
| 241 |
|
} else if (buf[0] & 0x01) { |
| 242 |
|
/* multicast */ |
| 243 |
|
if (!(s->rxcr & 0x08)) |
| 244 |
|
return; |
| 245 |
|
mcast_idx = compute_mcast_idx(buf); |
| 246 |
|
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) |
| 247 |
|
return; |
| 248 |
|
} else if (s->mem[0] == buf[0] && |
| 249 |
|
s->mem[2] == buf[1] && |
| 250 |
|
s->mem[4] == buf[2] && |
| 251 |
|
s->mem[6] == buf[3] && |
| 252 |
|
s->mem[8] == buf[4] && |
| 253 |
|
s->mem[10] == buf[5]) { |
| 254 |
|
/* match */ |
| 255 |
|
} else { |
| 256 |
|
return; |
| 257 |
|
} |
| 258 |
|
} |
| 259 |
|
|
| 260 |
|
|
| 261 |
/* if too small buffer, then expand it */ |
/* if too small buffer, then expand it */ |
| 262 |
if (size < MIN_BUF_SIZE) { |
if (size < MIN_BUF_SIZE) { |
| 263 |
memcpy(buf1, buf, size); |
memcpy(buf1, buf, size); |
| 332 |
index -= NE2000_PMEM_SIZE; |
index -= NE2000_PMEM_SIZE; |
| 333 |
/* fail safe: check range on the transmitted length */ |
/* fail safe: check range on the transmitted length */ |
| 334 |
if (index + s->tcnt <= NE2000_PMEM_END) { |
if (index + s->tcnt <= NE2000_PMEM_END) { |
| 335 |
qemu_send_packet(s->nd, s->mem + index, s->tcnt); |
qemu_send_packet(s->vc, s->mem + index, s->tcnt); |
| 336 |
} |
} |
| 337 |
/* signal end of transfert */ |
/* signal end of transfert */ |
| 338 |
s->tsr = ENTSR_PTX; |
s->tsr = ENTSR_PTX; |
| 379 |
case EN0_RCNTHI: |
case EN0_RCNTHI: |
| 380 |
s->rcnt = (s->rcnt & 0x00ff) | (val << 8); |
s->rcnt = (s->rcnt & 0x00ff) | (val << 8); |
| 381 |
break; |
break; |
| 382 |
|
case EN0_RXCR: |
| 383 |
|
s->rxcr = val; |
| 384 |
|
break; |
| 385 |
case EN0_DCFG: |
case EN0_DCFG: |
| 386 |
s->dcfg = val; |
s->dcfg = val; |
| 387 |
break; |
break; |
| 670 |
return 0; |
return 0; |
| 671 |
} |
} |
| 672 |
|
|
| 673 |
void isa_ne2000_init(int base, int irq, NetDriverState *nd) |
void isa_ne2000_init(int base, int irq, NICInfo *nd) |
| 674 |
{ |
{ |
| 675 |
NE2000State *s; |
NE2000State *s; |
| 676 |
|
|
| 677 |
s = qemu_mallocz(sizeof(NE2000State)); |
s = qemu_mallocz(sizeof(NE2000State)); |
| 678 |
if (!s) |
if (!s) |
| 679 |
return; |
return; |
| 689 |
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
| 690 |
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
| 691 |
s->irq = irq; |
s->irq = irq; |
| 692 |
s->nd = nd; |
memcpy(s->macaddr, nd->macaddr, 6); |
| 693 |
|
|
| 694 |
ne2000_reset(s); |
ne2000_reset(s); |
| 695 |
|
|
| 696 |
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); |
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); |
| 697 |
|
|
| 698 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 699 |
|
"ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
| 700 |
|
s->macaddr[0], |
| 701 |
|
s->macaddr[1], |
| 702 |
|
s->macaddr[2], |
| 703 |
|
s->macaddr[3], |
| 704 |
|
s->macaddr[4], |
| 705 |
|
s->macaddr[5]); |
| 706 |
|
|
| 707 |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
|
|
|
| 708 |
} |
} |
| 709 |
|
|
| 710 |
/***********************************************************/ |
/***********************************************************/ |
| 735 |
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
| 736 |
} |
} |
| 737 |
|
|
| 738 |
void pci_ne2000_init(PCIBus *bus, NetDriverState *nd) |
void pci_ne2000_init(PCIBus *bus, NICInfo *nd) |
| 739 |
{ |
{ |
| 740 |
PCINE2000State *d; |
PCINE2000State *d; |
| 741 |
NE2000State *s; |
NE2000State *s; |
| 760 |
s = &d->ne2000; |
s = &d->ne2000; |
| 761 |
s->irq = 16; // PCI interrupt |
s->irq = 16; // PCI interrupt |
| 762 |
s->pci_dev = (PCIDevice *)d; |
s->pci_dev = (PCIDevice *)d; |
| 763 |
s->nd = nd; |
memcpy(s->macaddr, nd->macaddr, 6); |
| 764 |
ne2000_reset(s); |
ne2000_reset(s); |
| 765 |
qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); |
s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s); |
| 766 |
|
|
| 767 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 768 |
|
"ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x", |
| 769 |
|
s->macaddr[0], |
| 770 |
|
s->macaddr[1], |
| 771 |
|
s->macaddr[2], |
| 772 |
|
s->macaddr[3], |
| 773 |
|
s->macaddr[4], |
| 774 |
|
s->macaddr[5]); |
| 775 |
|
|
| 776 |
/* XXX: instance number ? */ |
/* XXX: instance number ? */ |
| 777 |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
register_savevm("ne2000", 0, 1, ne2000_save, ne2000_load, s); |
| 778 |
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, |
register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load, |