Merge branch 'net-queue'

* net-queue: (28 commits)
  virtio-net: Increase filter and control limits
  virtio-net: Add new RX filter controls
  virtio-net: MAC filter optimization
  virtio-net: Fix MAC filter overflow handling
  virtio-net: reorganize receive_filter()
  virtio-net: Use a byte to store RX mode flags
  virtio-net: Add version_id 7 placeholder for vnet header support
  virtio-net: implement rx packet queueing
  net: make use of async packet sending API in tap client
  net: add qemu_send_packet_async()
  net: split out packet queueing and flushing into separate functions
  net: return status from qemu_deliver_packet()
  net: add return value to packet receive handler
  net: pass VLANClientState* as first arg to receive handlers
  net: re-name vc->fd_read() to vc->receive()
  net: add fd_readv() handler to qemu_new_vlan_client() args
  net: only read from tapfd when we can send
  net: vlan clients with no fd_can_read() can always receive
  net: move the tap buffer into TAPState
  net: factor tap_read_packet() out of tap_send()
  ...

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2009-06-10 18:05:55 -05:00
commit f8e76fbf51
26 changed files with 859 additions and 478 deletions

View File

@ -407,9 +407,9 @@ static void do_transmit_packets(dp8393xState *s)
if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
/* Loopback */ /* Loopback */
s->regs[SONIC_TCR] |= SONIC_TCR_CRSL; s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
if (s->vc->fd_can_read(s)) { if (s->vc->can_receive(s->vc)) {
s->loopback_packet = 1; s->loopback_packet = 1;
s->vc->fd_read(s, s->tx_buffer, tx_len); s->vc->receive(s->vc, s->tx_buffer, tx_len);
} }
} else { } else {
/* Transmit packet */ /* Transmit packet */
@ -676,9 +676,9 @@ static CPUWriteMemoryFunc *dp8393x_write[3] = {
dp8393x_writel, dp8393x_writel,
}; };
static int nic_can_receive(void *opaque) static int nic_can_receive(VLANClientState *vc)
{ {
dp8393xState *s = opaque; dp8393xState *s = vc->opaque;
if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
return 0; return 0;
@ -725,10 +725,10 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
return -1; return -1;
} }
static void nic_receive(void *opaque, const uint8_t * buf, int size) static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size)
{ {
uint16_t data[10]; uint16_t data[10];
dp8393xState *s = opaque; dp8393xState *s = vc->opaque;
int packet_type; int packet_type;
uint32_t available, address; uint32_t available, address;
int width, rx_len = size; int width, rx_len = size;
@ -742,7 +742,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
packet_type = receive_filter(s, buf, size); packet_type = receive_filter(s, buf, size);
if (packet_type < 0) { if (packet_type < 0) {
DPRINTF("packet not for netcard\n"); DPRINTF("packet not for netcard\n");
return; return -1;
} }
/* XXX: Check byte ordering */ /* XXX: Check byte ordering */
@ -755,7 +755,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0); s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
if (data[0 * width] & 0x1) { if (data[0 * width] & 0x1) {
/* Still EOL ; stop reception */ /* Still EOL ; stop reception */
return; return -1;
} else { } else {
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA]; s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
} }
@ -833,6 +833,8 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
/* Done */ /* Done */
dp8393x_update_irq(s); dp8393x_update_irq(s);
return size;
} }
static void nic_reset(void *opaque) static void nic_reset(void *opaque)
@ -888,8 +890,8 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s); s->watchdog = qemu_new_timer(vm_clock, dp8393x_watchdog, s);
s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, nic_can_receive,
nic_receive, nic_can_receive, nic_cleanup, s); nic_receive, NULL, nic_cleanup, s);
qemu_format_nic_info_str(s->vc, nd->macaddr); qemu_format_nic_info_str(s->vc, nd->macaddr);
qemu_register_reset(nic_reset, 0, s); qemu_register_reset(nic_reset, 0, s);

View File

@ -598,17 +598,17 @@ e1000_set_link_status(VLANClientState *vc)
} }
static int static int
e1000_can_receive(void *opaque) e1000_can_receive(VLANClientState *vc)
{ {
E1000State *s = opaque; E1000State *s = vc->opaque;
return (s->mac_reg[RCTL] & E1000_RCTL_EN); return (s->mac_reg[RCTL] & E1000_RCTL_EN);
} }
static void static ssize_t
e1000_receive(void *opaque, const uint8_t *buf, int size) e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
E1000State *s = opaque; E1000State *s = vc->opaque;
struct e1000_rx_desc desc; struct e1000_rx_desc desc;
target_phys_addr_t base; target_phys_addr_t base;
unsigned int n, rdt; unsigned int n, rdt;
@ -617,16 +617,16 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
uint8_t vlan_status = 0, vlan_offset = 0; uint8_t vlan_status = 0, vlan_offset = 0;
if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
return; return -1;
if (size > s->rxbuf_size) { if (size > s->rxbuf_size) {
DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size, DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
s->rxbuf_size); (unsigned long)size, s->rxbuf_size);
return; return -1;
} }
if (!receive_filter(s, buf, size)) if (!receive_filter(s, buf, size))
return; return size;
if (vlan_enabled(s) && is_vlan_packet(s, buf)) { if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14))); vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
@ -641,7 +641,7 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
do { do {
if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
set_ics(s, 0, E1000_ICS_RXO); set_ics(s, 0, E1000_ICS_RXO);
return; return -1;
} }
base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
sizeof(desc) * s->mac_reg[RDH]; sizeof(desc) * s->mac_reg[RDH];
@ -665,7 +665,7 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n", DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
set_ics(s, 0, E1000_ICS_RXO); set_ics(s, 0, E1000_ICS_RXO);
return; return -1;
} }
} while (desc.buffer_addr == 0); } while (desc.buffer_addr == 0);
@ -683,6 +683,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size)
n |= E1000_ICS_RXDMT0; n |= E1000_ICS_RXDMT0;
set_ics(s, 0, n); set_ics(s, 0, n);
return size;
} }
static uint32_t static uint32_t
@ -1119,8 +1121,8 @@ static void pci_e1000_init(PCIDevice *pci_dev)
d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
d->vc = qdev_get_vlan_client(&d->dev.qdev, d->vc = qdev_get_vlan_client(&d->dev.qdev,
e1000_receive, e1000_can_receive, e1000_can_receive, e1000_receive,
e1000_cleanup, d); NULL, e1000_cleanup, d);
d->vc->link_status_changed = e1000_set_link_status; d->vc->link_status_changed = e1000_set_link_status;
qemu_format_nic_info_str(d->vc, macaddr); qemu_format_nic_info_str(d->vc, macaddr);

View File

@ -1433,21 +1433,21 @@ static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
} }
} }
static int nic_can_receive(void *opaque) static int nic_can_receive(VLANClientState *vc)
{ {
EEPRO100State *s = opaque; EEPRO100State *s = vc->opaque;
logout("%p\n", s); logout("%p\n", s);
return get_ru_state(s) == ru_ready; return get_ru_state(s) == ru_ready;
//~ return !eepro100_buffer_full(s); //~ return !eepro100_buffer_full(s);
} }
static void nic_receive(void *opaque, const uint8_t * buf, int size) static ssize_t nic_receive(VLANClientState *vc, const uint8_t * buf, size_t size)
{ {
/* TODO: /* TODO:
* - Magic packets should set bit 30 in power management driver register. * - Magic packets should set bit 30 in power management driver register.
* - Interesting packets should set bit 29 in power management driver register. * - Interesting packets should set bit 29 in power management driver register.
*/ */
EEPRO100State *s = opaque; EEPRO100State *s = vc->opaque;
uint16_t rfd_status = 0xa000; uint16_t rfd_status = 0xa000;
static const uint8_t broadcast_macaddr[6] = static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -1458,18 +1458,18 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
if (s->configuration[8] & 0x80) { if (s->configuration[8] & 0x80) {
/* CSMA is disabled. */ /* CSMA is disabled. */
logout("%p received while CSMA is disabled\n", s); logout("%p received while CSMA is disabled\n", s);
return; return -1;
} else if (size < 64 && (s->configuration[7] & 1)) { } else if (size < 64 && (s->configuration[7] & 1)) {
/* Short frame and configuration byte 7/0 (discard short receive) set: /* Short frame and configuration byte 7/0 (discard short receive) set:
* Short frame is discarded */ * Short frame is discarded */
logout("%p received short frame (%d byte)\n", s, size); logout("%p received short frame (%d byte)\n", s, size);
s->statistics.rx_short_frame_errors++; s->statistics.rx_short_frame_errors++;
//~ return; //~ return -1;
} else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) { } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) {
/* Long frame and configuration byte 18/3 (long receive ok) not set: /* Long frame and configuration byte 18/3 (long receive ok) not set:
* Long frames are discarded. */ * Long frames are discarded. */
logout("%p received long frame (%d byte), ignored\n", s, size); logout("%p received long frame (%d byte), ignored\n", s, size);
return; return -1;
} else if (memcmp(buf, s->macaddr, 6) == 0) { // !!! } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!!
/* Frame matches individual address. */ /* Frame matches individual address. */
/* TODO: check configuration byte 15/4 (ignore U/L). */ /* TODO: check configuration byte 15/4 (ignore U/L). */
@ -1485,7 +1485,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
assert(!(s->configuration[21] & BIT(3))); assert(!(s->configuration[21] & BIT(3)));
int mcast_idx = compute_mcast_idx(buf); int mcast_idx = compute_mcast_idx(buf);
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
return; return size;
} }
rfd_status |= 0x0002; rfd_status |= 0x0002;
} else if (s->configuration[15] & 1) { } else if (s->configuration[15] & 1) {
@ -1495,7 +1495,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
} else { } else {
logout("%p received frame, ignored, len=%d,%s\n", s, size, logout("%p received frame, ignored, len=%d,%s\n", s, size,
nic_dump(buf, size)); nic_dump(buf, size));
return; return size;
} }
if (get_ru_state(s) != ru_ready) { if (get_ru_state(s) != ru_ready) {
@ -1503,7 +1503,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
logout("no ressources, state=%u\n", get_ru_state(s)); logout("no ressources, state=%u\n", get_ru_state(s));
s->statistics.rx_resource_errors++; s->statistics.rx_resource_errors++;
//~ assert(!"no ressources"); //~ assert(!"no ressources");
return; return -1;
} }
//~ !!! //~ !!!
//~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 <repeats 1518 times>}} //~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 <repeats 1518 times>}}
@ -1540,6 +1540,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size)
/* S bit is set. */ /* S bit is set. */
set_ru_state(s, ru_suspended); set_ru_state(s, ru_suspended);
} }
return size;
} }
static int nic_load(QEMUFile * f, void *opaque, int version_id) static int nic_load(QEMUFile * f, void *opaque, int version_id)
@ -1766,7 +1767,7 @@ static void nic_init(PCIDevice *pci_dev, uint32_t device)
nic_reset(s); nic_reset(s);
s->vc = qdev_get_vlan_client(&d->dev.qdev, s->vc = qdev_get_vlan_client(&d->dev.qdev,
nic_receive, nic_can_receive, nic_can_receive, nic_receive, NULL,
nic_cleanup, s); nic_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);

View File

@ -496,21 +496,21 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa)
return match; return match;
} }
static int eth_can_receive(void *opaque) static int eth_can_receive(VLANClientState *vc)
{ {
return 1; return 1;
} }
static void eth_receive(void *opaque, const uint8_t *buf, int size) static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct fs_eth *eth = opaque; struct fs_eth *eth = vc->opaque;
int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma0 = eth->regs[RW_REC_CTRL] & 1;
int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int use_ma1 = eth->regs[RW_REC_CTRL] & 2;
int r_bcast = eth->regs[RW_REC_CTRL] & 8; int r_bcast = eth->regs[RW_REC_CTRL] & 8;
if (size < 12) if (size < 12)
return; return -1;
D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n",
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
@ -521,10 +521,12 @@ static void eth_receive(void *opaque, const uint8_t *buf, int size)
&& (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6))
&& (!r_bcast || memcmp(buf, sa_bcast, 6)) && (!r_bcast || memcmp(buf, sa_bcast, 6))
&& !eth_match_groupaddr(eth, buf)) && !eth_match_groupaddr(eth, buf))
return; return size;
/* FIXME: Find another way to pass on the fake csum. */ /* FIXME: Find another way to pass on the fake csum. */
etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1);
return size;
} }
static int eth_tx_push(void *opaque, unsigned char *buf, int len) static int eth_tx_push(void *opaque, unsigned char *buf, int len)
@ -593,7 +595,7 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env,
cpu_register_physical_memory (base, 0x5c, eth->ethregs); cpu_register_physical_memory (base, 0x5c, eth->ethregs);
eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
eth_receive, eth_can_receive, eth_can_receive, eth_receive, NULL,
eth_cleanup, eth); eth_cleanup, eth);
eth->vc->opaque = eth; eth->vc->opaque = eth;
eth->vc->link_status_changed = eth_set_link; eth->vc->link_status_changed = eth_set_link;

View File

@ -347,15 +347,15 @@ static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value)
mcf_fec_update(s); mcf_fec_update(s);
} }
static int mcf_fec_can_receive(void *opaque) static int mcf_fec_can_receive(VLANClientState *vc)
{ {
mcf_fec_state *s = (mcf_fec_state *)opaque; mcf_fec_state *s = vc->opaque;
return s->rx_enabled; return s->rx_enabled;
} }
static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size) static ssize_t mcf_fec_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
mcf_fec_state *s = (mcf_fec_state *)opaque; mcf_fec_state *s = vc->opaque;
mcf_fec_bd bd; mcf_fec_bd bd;
uint32_t flags = 0; uint32_t flags = 0;
uint32_t addr; uint32_t addr;
@ -426,6 +426,7 @@ static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size)
s->rx_descriptor = addr; s->rx_descriptor = addr;
mcf_fec_enable_rx(s); mcf_fec_enable_rx(s);
mcf_fec_update(s); mcf_fec_update(s);
return size;
} }
static CPUReadMemoryFunc *mcf_fec_readfn[] = { static CPUReadMemoryFunc *mcf_fec_readfn[] = {
@ -462,7 +463,7 @@ void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
cpu_register_physical_memory(base, 0x400, s->mmio_index); cpu_register_physical_memory(base, 0x400, s->mmio_index);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
mcf_fec_receive, mcf_fec_can_receive, mcf_fec_can_receive, mcf_fec_receive, NULL,
mcf_fec_cleanup, s); mcf_fec_cleanup, s);
memcpy(s->macaddr, nd->macaddr, 6); memcpy(s->macaddr, nd->macaddr, 6);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);

View File

@ -66,24 +66,24 @@ static int mipsnet_buffer_full(MIPSnetState *s)
return 0; return 0;
} }
static int mipsnet_can_receive(void *opaque) static int mipsnet_can_receive(VLANClientState *vc)
{ {
MIPSnetState *s = opaque; MIPSnetState *s = vc->opaque;
if (s->busy) if (s->busy)
return 0; return 0;
return !mipsnet_buffer_full(s); return !mipsnet_buffer_full(s);
} }
static void mipsnet_receive(void *opaque, const uint8_t *buf, int size) static ssize_t mipsnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
MIPSnetState *s = opaque; MIPSnetState *s = vc->opaque;
#ifdef DEBUG_MIPSNET_RECEIVE #ifdef DEBUG_MIPSNET_RECEIVE
printf("mipsnet: receiving len=%d\n", size); printf("mipsnet: receiving len=%d\n", size);
#endif #endif
if (!mipsnet_can_receive(opaque)) if (!mipsnet_can_receive(vc))
return; return -1;
s->busy = 1; s->busy = 1;
@ -98,6 +98,8 @@ static void mipsnet_receive(void *opaque, const uint8_t *buf, int size)
/* Now we can signal we have received something. */ /* Now we can signal we have received something. */
s->intctl |= MIPSNET_INTCTL_RXDONE; s->intctl |= MIPSNET_INTCTL_RXDONE;
mipsnet_update_irq(s); mipsnet_update_irq(s);
return size;
} }
static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr) static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
@ -262,7 +264,7 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
s->irq = irq; s->irq = irq;
if (nd && nd->vlan) { if (nd && nd->vlan) {
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
mipsnet_receive, mipsnet_can_receive, mipsnet_can_receive, mipsnet_receive, NULL,
mipsnet_cleanup, s); mipsnet_cleanup, s);
} else { } else {
s->vc = NULL; s->vc = NULL;

View File

@ -557,14 +557,14 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc)
le32_to_cpus(&desc->next); le32_to_cpus(&desc->next);
} }
static int eth_can_receive(void *opaque) static int eth_can_receive(VLANClientState *vc)
{ {
return 1; return 1;
} }
static void eth_receive(void *opaque, const uint8_t *buf, int size) static ssize_t eth_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
mv88w8618_eth_state *s = opaque; mv88w8618_eth_state *s = vc->opaque;
uint32_t desc_addr; uint32_t desc_addr;
mv88w8618_rx_desc desc; mv88w8618_rx_desc desc;
int i; int i;
@ -586,11 +586,12 @@ static void eth_receive(void *opaque, const uint8_t *buf, int size)
if (s->icr & s->imr) if (s->icr & s->imr)
qemu_irq_raise(s->irq); qemu_irq_raise(s->irq);
eth_rx_desc_put(desc_addr, &desc); eth_rx_desc_put(desc_addr, &desc);
return; return size;
} }
desc_addr = desc.next; desc_addr = desc.next;
} while (desc_addr != s->rx_queue[i]); } while (desc_addr != s->rx_queue[i]);
} }
return size;
} }
static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc)
@ -753,7 +754,7 @@ static void mv88w8618_eth_init(SysBusDevice *dev)
sysbus_init_irq(dev, &s->irq); sysbus_init_irq(dev, &s->irq);
s->vc = qdev_get_vlan_client(&dev->qdev, s->vc = qdev_get_vlan_client(&dev->qdev,
eth_receive, eth_can_receive, eth_can_receive, eth_receive, NULL,
eth_cleanup, s); eth_cleanup, s);
s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn,
mv88w8618_eth_writefn, s); mv88w8618_eth_writefn, s);

View File

@ -213,9 +213,9 @@ static int ne2000_buffer_full(NE2000State *s)
return 0; return 0;
} }
static int ne2000_can_receive(void *opaque) static int ne2000_can_receive(VLANClientState *vc)
{ {
NE2000State *s = opaque; NE2000State *s = vc->opaque;
if (s->cmd & E8390_STOP) if (s->cmd & E8390_STOP)
return 1; return 1;
@ -224,9 +224,10 @@ static int ne2000_can_receive(void *opaque)
#define MIN_BUF_SIZE 60 #define MIN_BUF_SIZE 60
static void ne2000_receive(void *opaque, const uint8_t *buf, int size) static ssize_t ne2000_receive(VLANClientState *vc, const uint8_t *buf, size_t size_)
{ {
NE2000State *s = opaque; NE2000State *s = vc->opaque;
int size = size_;
uint8_t *p; uint8_t *p;
unsigned int total_len, next, avail, len, index, mcast_idx; unsigned int total_len, next, avail, len, index, mcast_idx;
uint8_t buf1[60]; uint8_t buf1[60];
@ -238,7 +239,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
#endif #endif
if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
return; return -1;
/* XXX: check this */ /* XXX: check this */
if (s->rxcr & 0x10) { if (s->rxcr & 0x10) {
@ -247,14 +248,14 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
if (!memcmp(buf, broadcast_macaddr, 6)) { if (!memcmp(buf, broadcast_macaddr, 6)) {
/* broadcast address */ /* broadcast address */
if (!(s->rxcr & 0x04)) if (!(s->rxcr & 0x04))
return; return size;
} else if (buf[0] & 0x01) { } else if (buf[0] & 0x01) {
/* multicast */ /* multicast */
if (!(s->rxcr & 0x08)) if (!(s->rxcr & 0x08))
return; return size;
mcast_idx = compute_mcast_idx(buf); mcast_idx = compute_mcast_idx(buf);
if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
return; return size;
} else if (s->mem[0] == buf[0] && } else if (s->mem[0] == buf[0] &&
s->mem[2] == buf[1] && s->mem[2] == buf[1] &&
s->mem[4] == buf[2] && s->mem[4] == buf[2] &&
@ -263,7 +264,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
s->mem[10] == buf[5]) { s->mem[10] == buf[5]) {
/* match */ /* match */
} else { } else {
return; return size;
} }
} }
@ -316,6 +317,8 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
/* now we can signal we have received something */ /* now we can signal we have received something */
s->isr |= ENISR_RX; s->isr |= ENISR_RX;
ne2000_update_irq(s); ne2000_update_irq(s);
return size_;
} }
static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val) static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
@ -757,7 +760,7 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
ne2000_reset(s); ne2000_reset(s);
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
ne2000_receive, ne2000_can_receive, ne2000_can_receive, ne2000_receive, NULL,
isa_ne2000_cleanup, s); isa_ne2000_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);
@ -821,7 +824,7 @@ static void pci_ne2000_init(PCIDevice *pci_dev)
qdev_get_macaddr(&d->dev.qdev, s->macaddr); qdev_get_macaddr(&d->dev.qdev, s->macaddr);
ne2000_reset(s); ne2000_reset(s);
s->vc = qdev_get_vlan_client(&d->dev.qdev, s->vc = qdev_get_vlan_client(&d->dev.qdev,
ne2000_receive, ne2000_can_receive, ne2000_can_receive, ne2000_receive, NULL,
ne2000_cleanup, s); ne2000_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);

View File

@ -33,11 +33,12 @@
#include "virtio-blk.h" #include "virtio-blk.h"
#if defined(TARGET_I386) || defined(TARGET_X86_64) #if defined(TARGET_I386) || defined(TARGET_X86_64)
static PCIDevice *qemu_pci_hot_add_nic(PCIBus *pci_bus, const char *opts) static PCIDevice *qemu_pci_hot_add_nic(Monitor *mon, PCIBus *pci_bus,
const char *opts)
{ {
int ret; int ret;
ret = net_client_init("nic", opts); ret = net_client_init(mon, "nic", opts);
if (ret < 0) if (ret < 0)
return NULL; return NULL;
return pci_nic_init(pci_bus, &nd_table[ret], -1, "rtl8139"); return pci_nic_init(pci_bus, &nd_table[ret], -1, "rtl8139");
@ -149,7 +150,7 @@ void pci_device_hot_add(Monitor *mon, const char *pci_addr, const char *type,
} }
if (strcmp(type, "nic") == 0) if (strcmp(type, "nic") == 0)
dev = qemu_pci_hot_add_nic(pci_bus, opts); dev = qemu_pci_hot_add_nic(mon, pci_bus, opts);
else if (strcmp(type, "storage") == 0) else if (strcmp(type, "storage") == 0)
dev = qemu_pci_hot_add_storage(mon, pci_bus, opts); dev = qemu_pci_hot_add_storage(mon, pci_bus, opts);
else else

View File

@ -1062,9 +1062,9 @@ static int pcnet_tdte_poll(PCNetState *s)
return !!(CSR_CXST(s) & 0x8000); return !!(CSR_CXST(s) & 0x8000);
} }
static int pcnet_can_receive(void *opaque) static int pcnet_can_receive(VLANClientState *vc)
{ {
PCNetState *s = opaque; PCNetState *s = vc->opaque;
if (CSR_STOP(s) || CSR_SPND(s)) if (CSR_STOP(s) || CSR_SPND(s))
return 0; return 0;
@ -1076,16 +1076,17 @@ static int pcnet_can_receive(void *opaque)
#define MIN_BUF_SIZE 60 #define MIN_BUF_SIZE 60
static void pcnet_receive(void *opaque, const uint8_t *buf, int size) static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size_)
{ {
PCNetState *s = opaque; PCNetState *s = vc->opaque;
int is_padr = 0, is_bcast = 0, is_ladr = 0; int is_padr = 0, is_bcast = 0, is_ladr = 0;
uint8_t buf1[60]; uint8_t buf1[60];
int remaining; int remaining;
int crc_err = 0; int crc_err = 0;
int size = size_;
if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
return; return -1;
#ifdef PCNET_DEBUG #ifdef PCNET_DEBUG
printf("pcnet_receive size=%d\n", size); printf("pcnet_receive size=%d\n", size);
@ -1252,6 +1253,8 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
pcnet_poll(s); pcnet_poll(s);
pcnet_update_irq(s); pcnet_update_irq(s);
return size_;
} }
static void pcnet_transmit(PCNetState *s) static void pcnet_transmit(PCNetState *s)
@ -1302,7 +1305,7 @@ static void pcnet_transmit(PCNetState *s)
if (BCR_SWSTYLE(s) == 1) if (BCR_SWSTYLE(s) == 1)
add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS);
s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC;
pcnet_receive(s, s->buffer, s->xmit_pos); pcnet_receive(s->vc, s->buffer, s->xmit_pos);
s->looptest = 0; s->looptest = 0;
} else } else
if (s->vc) if (s->vc)
@ -1952,7 +1955,7 @@ static void pcnet_common_init(DeviceState *dev, PCNetState *s,
qdev_get_macaddr(dev, s->macaddr); qdev_get_macaddr(dev, s->macaddr);
s->vc = qdev_get_vlan_client(dev, s->vc = qdev_get_vlan_client(dev,
pcnet_receive, pcnet_can_receive, pcnet_can_receive, pcnet_receive, NULL,
cleanup, s); cleanup, s);
pcnet_h_reset(s); pcnet_h_reset(s);
register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s); register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s);

View File

@ -258,15 +258,16 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin)
} }
VLANClientState *qdev_get_vlan_client(DeviceState *dev, VLANClientState *qdev_get_vlan_client(DeviceState *dev,
IOReadHandler *fd_read, NetCanReceive *can_receive,
IOCanRWHandler *fd_can_read, NetReceive *receive,
NetReceiveIOV *receive_iov,
NetCleanup *cleanup, NetCleanup *cleanup,
void *opaque) void *opaque)
{ {
NICInfo *nd = dev->nd; NICInfo *nd = dev->nd;
assert(nd); assert(nd);
return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive,
fd_read, fd_can_read, cleanup, opaque); receive, receive_iov, cleanup, opaque);
} }

View File

@ -790,9 +790,9 @@ static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
#endif #endif
} }
static int rtl8139_can_receive(void *opaque) static int rtl8139_can_receive(VLANClientState *vc)
{ {
RTL8139State *s = opaque; RTL8139State *s = vc->opaque;
int avail; int avail;
/* Receive (drop) packets if card is disabled. */ /* Receive (drop) packets if card is disabled. */
@ -812,9 +812,10 @@ static int rtl8139_can_receive(void *opaque)
} }
} }
static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt) static ssize_t rtl8139_do_receive(VLANClientState *vc, const uint8_t *buf, size_t size_, int do_interrupt)
{ {
RTL8139State *s = opaque; RTL8139State *s = vc->opaque;
int size = size_;
uint32_t packet_header = 0; uint32_t packet_header = 0;
@ -828,7 +829,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
if (!s->clock_enabled) if (!s->clock_enabled)
{ {
DEBUG_PRINT(("RTL8139: stopped ==========================\n")); DEBUG_PRINT(("RTL8139: stopped ==========================\n"));
return; return -1;
} }
/* first check if receiver is enabled */ /* first check if receiver is enabled */
@ -836,7 +837,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
if (!rtl8139_receiver_enabled(s)) if (!rtl8139_receiver_enabled(s))
{ {
DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); DEBUG_PRINT(("RTL8139: receiver disabled ================\n"));
return; return -1;
} }
/* XXX: check this */ /* XXX: check this */
@ -854,7 +855,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
/* update tally counter */ /* update tally counter */
++s->tally_counters.RxERR; ++s->tally_counters.RxERR;
return; return size;
} }
packet_header |= RxBroadcast; packet_header |= RxBroadcast;
@ -873,7 +874,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
/* update tally counter */ /* update tally counter */
++s->tally_counters.RxERR; ++s->tally_counters.RxERR;
return; return size;
} }
int mcast_idx = compute_mcast_idx(buf); int mcast_idx = compute_mcast_idx(buf);
@ -885,7 +886,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
/* update tally counter */ /* update tally counter */
++s->tally_counters.RxERR; ++s->tally_counters.RxERR;
return; return size;
} }
packet_header |= RxMulticast; packet_header |= RxMulticast;
@ -909,7 +910,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
/* update tally counter */ /* update tally counter */
++s->tally_counters.RxERR; ++s->tally_counters.RxERR;
return; return size;
} }
packet_header |= RxPhysical; packet_header |= RxPhysical;
@ -926,7 +927,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
/* update tally counter */ /* update tally counter */
++s->tally_counters.RxERR; ++s->tally_counters.RxERR;
return; return size;
} }
} }
@ -993,7 +994,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
++s->tally_counters.MissPkt; ++s->tally_counters.MissPkt;
rtl8139_update_irq(s); rtl8139_update_irq(s);
return; return size_;
} }
uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK; uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
@ -1013,7 +1014,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
++s->tally_counters.MissPkt; ++s->tally_counters.MissPkt;
rtl8139_update_irq(s); rtl8139_update_irq(s);
return; return size_;
} }
target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI); target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
@ -1118,7 +1119,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
s->IntrStatus |= RxOverflow; s->IntrStatus |= RxOverflow;
++s->RxMissed; ++s->RxMissed;
rtl8139_update_irq(s); rtl8139_update_irq(s);
return; return size_;
} }
packet_header |= RxStatusOK; packet_header |= RxStatusOK;
@ -1156,11 +1157,13 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d
{ {
rtl8139_update_irq(s); rtl8139_update_irq(s);
} }
return size_;
} }
static void rtl8139_receive(void *opaque, const uint8_t *buf, int size) static ssize_t rtl8139_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
rtl8139_do_receive(opaque, buf, size, 1); return rtl8139_do_receive(vc, buf, size, 1);
} }
static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize) static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
@ -1758,7 +1761,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size
if (TxLoopBack == (s->TxConfig & TxLoopBack)) if (TxLoopBack == (s->TxConfig & TxLoopBack))
{ {
DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n")); DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
rtl8139_do_receive(s, buf, size, do_interrupt); rtl8139_do_receive(s->vc, buf, size, do_interrupt);
} }
else else
{ {
@ -3479,7 +3482,7 @@ static void pci_rtl8139_init(PCIDevice *dev)
qemu_register_reset(rtl8139_reset, 0, s); qemu_register_reset(rtl8139_reset, 0, s);
rtl8139_reset(s); rtl8139_reset(s);
s->vc = qdev_get_vlan_client(&dev->qdev, s->vc = qdev_get_vlan_client(&dev->qdev,
rtl8139_receive, rtl8139_can_receive, rtl8139_can_receive, rtl8139_receive, NULL,
rtl8139_cleanup, s); rtl8139_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);

View File

@ -591,9 +591,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset)
return val; return val;
} }
static int smc91c111_can_receive(void *opaque) static int smc91c111_can_receive(VLANClientState *vc)
{ {
smc91c111_state *s = (smc91c111_state *)opaque; smc91c111_state *s = vc->opaque;
if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
return 1; return 1;
@ -602,9 +602,9 @@ static int smc91c111_can_receive(void *opaque)
return 1; return 1;
} }
static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) static ssize_t smc91c111_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
smc91c111_state *s = (smc91c111_state *)opaque; smc91c111_state *s = vc->opaque;
int status; int status;
int packetsize; int packetsize;
uint32_t crc; uint32_t crc;
@ -612,7 +612,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
uint8_t *p; uint8_t *p;
if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
return; return -1;
/* Short packets are padded with zeros. Receiving a packet /* Short packets are padded with zeros. Receiving a packet
< 64 bytes long is considered an error condition. */ < 64 bytes long is considered an error condition. */
if (size < 64) if (size < 64)
@ -625,10 +625,10 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
packetsize += 4; packetsize += 4;
/* TODO: Flag overrun and receive errors. */ /* TODO: Flag overrun and receive errors. */
if (packetsize > 2048) if (packetsize > 2048)
return; return -1;
packetnum = smc91c111_allocate_packet(s); packetnum = smc91c111_allocate_packet(s);
if (packetnum == 0x80) if (packetnum == 0x80)
return; return -1;
s->rx_fifo[s->rx_fifo_len++] = packetnum; s->rx_fifo[s->rx_fifo_len++] = packetnum;
p = &s->data[packetnum][0]; p = &s->data[packetnum][0];
@ -676,6 +676,8 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
/* TODO: Raise early RX interrupt? */ /* TODO: Raise early RX interrupt? */
s->int_level |= INT_RCV; s->int_level |= INT_RCV;
smc91c111_update(s); smc91c111_update(s);
return size;
} }
static CPUReadMemoryFunc *smc91c111_readfn[] = { static CPUReadMemoryFunc *smc91c111_readfn[] = {
@ -711,7 +713,7 @@ static void smc91c111_init1(SysBusDevice *dev)
smc91c111_reset(s); smc91c111_reset(s);
s->vc = qdev_get_vlan_client(&dev->qdev, s->vc = qdev_get_vlan_client(&dev->qdev,
smc91c111_receive, smc91c111_can_receive, smc91c111_can_receive, smc91c111_receive, NULL,
smc91c111_cleanup, s); smc91c111_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);
/* ??? Save/restore. */ /* ??? Save/restore. */

View File

@ -78,18 +78,18 @@ static void stellaris_enet_update(stellaris_enet_state *s)
} }
/* TODO: Implement MAC address filtering. */ /* TODO: Implement MAC address filtering. */
static void stellaris_enet_receive(void *opaque, const uint8_t *buf, int size) static ssize_t stellaris_enet_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
stellaris_enet_state *s = (stellaris_enet_state *)opaque; stellaris_enet_state *s = vc->opaque;
int n; int n;
uint8_t *p; uint8_t *p;
uint32_t crc; uint32_t crc;
if ((s->rctl & SE_RCTL_RXEN) == 0) if ((s->rctl & SE_RCTL_RXEN) == 0)
return; return -1;
if (s->np >= 31) { if (s->np >= 31) {
DPRINTF("Packet dropped\n"); DPRINTF("Packet dropped\n");
return; return -1;
} }
DPRINTF("Received packet len=%d\n", size); DPRINTF("Received packet len=%d\n", size);
@ -116,11 +116,13 @@ static void stellaris_enet_receive(void *opaque, const uint8_t *buf, int size)
s->ris |= SE_INT_RX; s->ris |= SE_INT_RX;
stellaris_enet_update(s); stellaris_enet_update(s);
return size;
} }
static int stellaris_enet_can_receive(void *opaque) static int stellaris_enet_can_receive(VLANClientState *vc)
{ {
stellaris_enet_state *s = (stellaris_enet_state *)opaque; stellaris_enet_state *s = vc->opaque;
if ((s->rctl & SE_RCTL_RXEN) == 0) if ((s->rctl & SE_RCTL_RXEN) == 0)
return 1; return 1;
@ -128,9 +130,9 @@ static int stellaris_enet_can_receive(void *opaque)
return (s->np < 31); return (s->np < 31);
} }
static uint32_t stellaris_enet_read(void *opaque, target_phys_addr_t offset) static uint32_t stellaris_enet_read(VLANClientState *vc, target_phys_addr_t offset)
{ {
stellaris_enet_state *s = (stellaris_enet_state *)opaque; stellaris_enet_state *s = vc->opaque;
uint32_t val; uint32_t val;
switch (offset) { switch (offset) {
@ -405,8 +407,8 @@ static void stellaris_enet_init(SysBusDevice *dev)
qdev_get_macaddr(&dev->qdev, s->macaddr); qdev_get_macaddr(&dev->qdev, s->macaddr);
s->vc = qdev_get_vlan_client(&dev->qdev, s->vc = qdev_get_vlan_client(&dev->qdev,
stellaris_enet_receive,
stellaris_enet_can_receive, stellaris_enet_can_receive,
stellaris_enet_receive, NULL,
stellaris_enet_cleanup, s); stellaris_enet_cleanup, s);
qemu_format_nic_info_str(s->vc, s->macaddr); qemu_format_nic_info_str(s->vc, s->macaddr);

View File

@ -1369,17 +1369,17 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p)
return ret; return ret;
} }
static void usbnet_receive(void *opaque, const uint8_t *buf, int size) static ssize_t usbnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
USBNetState *s = opaque; USBNetState *s = vc->opaque;
struct rndis_packet_msg_type *msg; struct rndis_packet_msg_type *msg;
if (s->rndis) { if (s->rndis) {
msg = (struct rndis_packet_msg_type *) s->in_buf; msg = (struct rndis_packet_msg_type *) s->in_buf;
if (!s->rndis_state == RNDIS_DATA_INITIALIZED) if (!s->rndis_state == RNDIS_DATA_INITIALIZED)
return; return -1;
if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
return; return -1;
memset(msg, 0, sizeof(struct rndis_packet_msg_type)); memset(msg, 0, sizeof(struct rndis_packet_msg_type));
msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG);
@ -1398,16 +1398,17 @@ static void usbnet_receive(void *opaque, const uint8_t *buf, int size)
s->in_len = size + sizeof(struct rndis_packet_msg_type); s->in_len = size + sizeof(struct rndis_packet_msg_type);
} else { } else {
if (size > sizeof(s->in_buf)) if (size > sizeof(s->in_buf))
return; return -1;
memcpy(s->in_buf, buf, size); memcpy(s->in_buf, buf, size);
s->in_len = size; s->in_len = size;
} }
s->in_ptr = 0; s->in_ptr = 0;
return size;
} }
static int usbnet_can_receive(void *opaque) static int usbnet_can_receive(VLANClientState *vc)
{ {
USBNetState *s = opaque; USBNetState *s = vc->opaque;
if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED) if (s->rndis && !s->rndis_state == RNDIS_DATA_INITIALIZED)
return 1; return 1;
@ -1458,8 +1459,9 @@ USBDevice *usb_net_init(NICInfo *nd)
pstrcpy(s->dev.devname, sizeof(s->dev.devname), pstrcpy(s->dev.devname, sizeof(s->dev.devname),
"QEMU USB Network Interface"); "QEMU USB Network Interface");
s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
usbnet_receive,
usbnet_can_receive, usbnet_can_receive,
usbnet_receive,
NULL,
usbnet_cleanup, s); usbnet_cleanup, s);
qemu_format_nic_info_str(s->vc, s->mac); qemu_format_nic_info_str(s->vc, s->mac);

View File

@ -16,9 +16,9 @@
#include "qemu-timer.h" #include "qemu-timer.h"
#include "virtio-net.h" #include "virtio-net.h"
#define VIRTIO_NET_VM_VERSION 6 #define VIRTIO_NET_VM_VERSION 10
#define MAC_TABLE_ENTRIES 32 #define MAC_TABLE_ENTRIES 64
#define MAX_VLAN (1 << 12) /* Per 802.1Q definition */ #define MAX_VLAN (1 << 12) /* Per 802.1Q definition */
typedef struct VirtIONet typedef struct VirtIONet
@ -33,10 +33,17 @@ typedef struct VirtIONet
QEMUTimer *tx_timer; QEMUTimer *tx_timer;
int tx_timer_active; int tx_timer_active;
int mergeable_rx_bufs; int mergeable_rx_bufs;
int promisc; uint8_t promisc;
int allmulti; uint8_t allmulti;
uint8_t alluni;
uint8_t nomulti;
uint8_t nouni;
uint8_t nobcast;
struct { struct {
int in_use; int in_use;
int first_multi;
uint8_t multi_overflow;
uint8_t uni_overflow;
uint8_t *macs; uint8_t *macs;
} mac_table; } mac_table;
uint32_t *vlans; uint32_t *vlans;
@ -95,9 +102,16 @@ static void virtio_net_reset(VirtIODevice *vdev)
/* Reset back to compatibility mode */ /* Reset back to compatibility mode */
n->promisc = 1; n->promisc = 1;
n->allmulti = 0; n->allmulti = 0;
n->alluni = 0;
n->nomulti = 0;
n->nouni = 0;
n->nobcast = 0;
/* Flush any MAC and VLAN filter table state */ /* Flush any MAC and VLAN filter table state */
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
n->mac_table.first_multi = 0;
n->mac_table.multi_overflow = 0;
n->mac_table.uni_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
memset(n->vlans, 0, MAX_VLAN >> 3); memset(n->vlans, 0, MAX_VLAN >> 3);
} }
@ -108,7 +122,8 @@ static uint32_t virtio_net_get_features(VirtIODevice *vdev)
(1 << VIRTIO_NET_F_STATUS) | (1 << VIRTIO_NET_F_STATUS) |
(1 << VIRTIO_NET_F_CTRL_VQ) | (1 << VIRTIO_NET_F_CTRL_VQ) |
(1 << VIRTIO_NET_F_CTRL_RX) | (1 << VIRTIO_NET_F_CTRL_RX) |
(1 << VIRTIO_NET_F_CTRL_VLAN); (1 << VIRTIO_NET_F_CTRL_VLAN) |
(1 << VIRTIO_NET_F_CTRL_RX_EXTRA);
return features; return features;
} }
@ -151,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
n->promisc = on; n->promisc = on;
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI)
n->allmulti = on; n->allmulti = on;
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI)
n->alluni = on;
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI)
n->nomulti = on;
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI)
n->nouni = on;
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST)
n->nobcast = on;
else else
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
@ -168,6 +191,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
return VIRTIO_NET_ERR; return VIRTIO_NET_ERR;
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
n->mac_table.first_multi = 0;
n->mac_table.uni_overflow = 0;
n->mac_table.multi_overflow = 0;
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN); memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base); mac_data.entries = ldl_le_p(elem->out_sg[1].iov_base);
@ -181,10 +207,11 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
mac_data.entries * ETH_ALEN); mac_data.entries * ETH_ALEN);
n->mac_table.in_use += mac_data.entries; n->mac_table.in_use += mac_data.entries;
} else { } else {
n->promisc = 1; n->mac_table.uni_overflow = 1;
return VIRTIO_NET_OK;
} }
n->mac_table.first_multi = n->mac_table.in_use;
mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base);
if (sizeof(mac_data.entries) + if (sizeof(mac_data.entries) +
@ -197,8 +224,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
elem->out_sg[2].iov_base + sizeof(mac_data), elem->out_sg[2].iov_base + sizeof(mac_data),
mac_data.entries * ETH_ALEN); mac_data.entries * ETH_ALEN);
n->mac_table.in_use += mac_data.entries; n->mac_table.in_use += mac_data.entries;
} else } else {
n->allmulti = 1; n->mac_table.multi_overflow = 1;
}
} }
return VIRTIO_NET_OK; return VIRTIO_NET_OK;
@ -269,6 +297,9 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
{ {
VirtIONet *n = to_virtio_net(vdev);
qemu_flush_queued_packets(n->vc);
} }
static int do_virtio_net_can_receive(VirtIONet *n, int bufsize) static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
@ -288,9 +319,9 @@ static int do_virtio_net_can_receive(VirtIONet *n, int bufsize)
return 1; return 1;
} }
static int virtio_net_can_receive(void *opaque) static int virtio_net_can_receive(VLANClientState *vc)
{ {
VirtIONet *n = opaque; VirtIONet *n = vc->opaque;
return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE); return do_virtio_net_can_receive(n, VIRTIO_NET_MAX_BUFSIZE);
} }
@ -344,34 +375,50 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
return 0; return 0;
} }
if ((ptr[0] & 1) && n->allmulti) if (ptr[0] & 1) { // multicast
if (!memcmp(ptr, bcast, sizeof(bcast))) {
return !n->nobcast;
} else if (n->nomulti) {
return 0;
} else if (n->allmulti || n->mac_table.multi_overflow) {
return 1; return 1;
}
if (!memcmp(ptr, bcast, sizeof(bcast))) for (i = n->mac_table.first_multi; i < n->mac_table.in_use; i++) {
if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
return 1; return 1;
}
}
} else { // unicast
if (n->nouni) {
return 0;
} else if (n->alluni || n->mac_table.uni_overflow) {
return 1;
} else if (!memcmp(ptr, n->mac, ETH_ALEN)) {
return 1;
}
if (!memcmp(ptr, n->mac, ETH_ALEN)) for (i = 0; i < n->mac_table.first_multi; i++) {
return 1; if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) {
for (i = 0; i < n->mac_table.in_use; i++) {
if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN))
return 1; return 1;
} }
}
}
return 0; return 0;
} }
static void virtio_net_receive(void *opaque, const uint8_t *buf, int size) static ssize_t virtio_net_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
VirtIONet *n = opaque; VirtIONet *n = vc->opaque;
struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL; struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
size_t hdr_len, offset, i; size_t hdr_len, offset, i;
if (!do_virtio_net_can_receive(n, size)) if (!do_virtio_net_can_receive(n, size))
return; return 0;
if (!receive_filter(n, buf, size)) if (!receive_filter(n, buf, size))
return; return size;
/* hdr_len refers to the header we supply to the guest */ /* hdr_len refers to the header we supply to the guest */
hdr_len = n->mergeable_rx_bufs ? hdr_len = n->mergeable_rx_bufs ?
@ -389,7 +436,7 @@ static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
if ((i != 0 && !n->mergeable_rx_bufs) || if ((i != 0 && !n->mergeable_rx_bufs) ||
virtqueue_pop(n->rx_vq, &elem) == 0) { virtqueue_pop(n->rx_vq, &elem) == 0) {
if (i == 0) if (i == 0)
return; return -1;
fprintf(stderr, "virtio-net truncating packet\n"); fprintf(stderr, "virtio-net truncating packet\n");
exit(1); exit(1);
} }
@ -431,6 +478,8 @@ static void virtio_net_receive(void *opaque, const uint8_t *buf, int size)
virtqueue_flush(n->rx_vq, i); virtqueue_flush(n->rx_vq, i);
virtio_notify(&n->vdev, n->rx_vq); virtio_notify(&n->vdev, n->rx_vq);
return size;
} }
/* TX */ /* TX */
@ -518,16 +567,24 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
qemu_put_be32(f, n->tx_timer_active); qemu_put_be32(f, n->tx_timer_active);
qemu_put_be32(f, n->mergeable_rx_bufs); qemu_put_be32(f, n->mergeable_rx_bufs);
qemu_put_be16(f, n->status); qemu_put_be16(f, n->status);
qemu_put_be32(f, n->promisc); qemu_put_byte(f, n->promisc);
qemu_put_be32(f, n->allmulti); qemu_put_byte(f, n->allmulti);
qemu_put_be32(f, n->mac_table.in_use); qemu_put_be32(f, n->mac_table.in_use);
qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN); qemu_put_buffer(f, n->mac_table.macs, n->mac_table.in_use * ETH_ALEN);
qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); qemu_put_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
qemu_put_be32(f, 0); /* vnet-hdr placeholder */
qemu_put_byte(f, n->mac_table.multi_overflow);
qemu_put_byte(f, n->mac_table.uni_overflow);
qemu_put_byte(f, n->alluni);
qemu_put_byte(f, n->nomulti);
qemu_put_byte(f, n->nouni);
qemu_put_byte(f, n->nobcast);
} }
static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
{ {
VirtIONet *n = opaque; VirtIONet *n = opaque;
int i;
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
return -EINVAL; return -EINVAL;
@ -542,8 +599,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
n->status = qemu_get_be16(f); n->status = qemu_get_be16(f);
if (version_id >= 4) { if (version_id >= 4) {
if (version_id < 8) {
n->promisc = qemu_get_be32(f); n->promisc = qemu_get_be32(f);
n->allmulti = qemu_get_be32(f); n->allmulti = qemu_get_be32(f);
} else {
n->promisc = qemu_get_byte(f);
n->allmulti = qemu_get_byte(f);
}
} }
if (version_id >= 5) { if (version_id >= 5) {
@ -554,7 +616,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
n->mac_table.in_use * ETH_ALEN); n->mac_table.in_use * ETH_ALEN);
} else if (n->mac_table.in_use) { } else if (n->mac_table.in_use) {
qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR); qemu_fseek(f, n->mac_table.in_use * ETH_ALEN, SEEK_CUR);
n->promisc = 1; n->mac_table.multi_overflow = n->mac_table.uni_overflow = 1;
n->mac_table.in_use = 0; n->mac_table.in_use = 0;
} }
} }
@ -562,6 +624,32 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
if (version_id >= 6) if (version_id >= 6)
qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3); qemu_get_buffer(f, (uint8_t *)n->vlans, MAX_VLAN >> 3);
if (version_id >= 7 && qemu_get_be32(f)) {
fprintf(stderr,
"virtio-net: saved image requires vnet header support\n");
exit(1);
}
if (version_id >= 9) {
n->mac_table.multi_overflow = qemu_get_byte(f);
n->mac_table.uni_overflow = qemu_get_byte(f);
}
if (version_id >= 10) {
n->alluni = qemu_get_byte(f);
n->nomulti = qemu_get_byte(f);
n->nouni = qemu_get_byte(f);
n->nobcast = qemu_get_byte(f);
}
/* Find the first multicast entry in the saved MAC filter */
for (i = 0; i < n->mac_table.in_use; i++) {
if (n->mac_table.macs[i * ETH_ALEN] & 1) {
break;
}
}
n->mac_table.first_multi = i;
if (n->tx_timer_active) { if (n->tx_timer_active) {
qemu_mod_timer(n->tx_timer, qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL); qemu_get_clock(vm_clock) + TX_TIMER_INTERVAL);
@ -602,12 +690,12 @@ VirtIODevice *virtio_net_init(DeviceState *dev)
n->vdev.reset = virtio_net_reset; n->vdev.reset = virtio_net_reset;
n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx); n->rx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_rx);
n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx); n->tx_vq = virtio_add_queue(&n->vdev, 256, virtio_net_handle_tx);
n->ctrl_vq = virtio_add_queue(&n->vdev, 16, virtio_net_handle_ctrl); n->ctrl_vq = virtio_add_queue(&n->vdev, 64, virtio_net_handle_ctrl);
qdev_get_macaddr(dev, n->mac); qdev_get_macaddr(dev, n->mac);
n->status = VIRTIO_NET_S_LINK_UP; n->status = VIRTIO_NET_S_LINK_UP;
n->vc = qdev_get_vlan_client(dev, n->vc = qdev_get_vlan_client(dev,
virtio_net_receive,
virtio_net_can_receive, virtio_net_can_receive,
virtio_net_receive, NULL,
virtio_net_cleanup, n); virtio_net_cleanup, n);
n->vc->link_status_changed = virtio_net_set_link_status; n->vc->link_status_changed = virtio_net_set_link_status;

View File

@ -43,6 +43,7 @@
#define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ #define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */
#define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ #define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */
#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ #define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ #define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack;
#define VIRTIO_NET_ERR 1 #define VIRTIO_NET_ERR 1
/* /*
* Control the RX mode, ie. promisucous and allmulti. PROMISC and * Control the RX mode, ie. promisucous, allmulti, etc...
* ALLMULTI commands require an "out" sg entry containing a 1 byte * All commands require an "out" sg entry containing a 1 byte
* state value, zero = disable, non-zero = enable. These commands * state value, zero = disable, non-zero = enable. Commands
* are supported with the VIRTIO_NET_F_CTRL_RX feature. * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
* Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
*/ */
#define VIRTIO_NET_CTRL_RX_MODE 0 #define VIRTIO_NET_CTRL_RX_MODE 0
#define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0 #define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0
#define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1 #define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1
#define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2
#define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3
#define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4
#define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5
/* /*
* Control the MAC filter table. * Control the MAC filter table.

View File

@ -223,9 +223,9 @@ static void net_rx_response(struct XenNetDev *netdev,
#define NET_IP_ALIGN 2 #define NET_IP_ALIGN 2
static int net_rx_ok(void *opaque) static int net_rx_ok(VLANClientState *vc)
{ {
struct XenNetDev *netdev = opaque; struct XenNetDev *netdev = vc->opaque;
RING_IDX rc, rp; RING_IDX rc, rp;
if (netdev->xendev.be_state != XenbusStateConnected) if (netdev->xendev.be_state != XenbusStateConnected)
@ -243,15 +243,15 @@ static int net_rx_ok(void *opaque)
return 1; return 1;
} }
static void net_rx_packet(void *opaque, const uint8_t *buf, int size) static ssize_t net_rx_packet(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
struct XenNetDev *netdev = opaque; struct XenNetDev *netdev = vc->opaque;
netif_rx_request_t rxreq; netif_rx_request_t rxreq;
RING_IDX rc, rp; RING_IDX rc, rp;
void *page; void *page;
if (netdev->xendev.be_state != XenbusStateConnected) if (netdev->xendev.be_state != XenbusStateConnected)
return; return -1;
rc = netdev->rx_ring.req_cons; rc = netdev->rx_ring.req_cons;
rp = netdev->rx_ring.sring->req_prod; rp = netdev->rx_ring.sring->req_prod;
@ -259,12 +259,12 @@ static void net_rx_packet(void *opaque, const uint8_t *buf, int size)
if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) { if (rc == rp || RING_REQUEST_CONS_OVERFLOW(&netdev->rx_ring, rc)) {
xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n"); xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n");
return; return -1;
} }
if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { if (size > XC_PAGE_SIZE - NET_IP_ALIGN) {
xen_be_printf(&netdev->xendev, 0, "packet too big (%d > %ld)", xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)",
size, XC_PAGE_SIZE - NET_IP_ALIGN); (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN);
return; return -1;
} }
memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq)); memcpy(&rxreq, RING_GET_REQUEST(&netdev->rx_ring, rc), sizeof(rxreq));
@ -277,11 +277,13 @@ static void net_rx_packet(void *opaque, const uint8_t *buf, int size)
xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n", xen_be_printf(&netdev->xendev, 0, "error: rx gref dereference failed (%d)\n",
rxreq.gref); rxreq.gref);
net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0); net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0);
return; return -1;
} }
memcpy(page + NET_IP_ALIGN, buf, size); memcpy(page + NET_IP_ALIGN, buf, size);
xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1);
net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0); net_rx_response(netdev, &rxreq, NETIF_RSP_OKAY, NET_IP_ALIGN, size, 0);
return size;
} }
/* ------------------------------------------------------------- */ /* ------------------------------------------------------------- */
@ -301,8 +303,8 @@ static int net_init(struct XenDevice *xendev)
vlan = qemu_find_vlan(netdev->xendev.dev); vlan = qemu_find_vlan(netdev->xendev.dev);
netdev->vs = qemu_new_vlan_client(vlan, "xen", NULL, netdev->vs = qemu_new_vlan_client(vlan, "xen", NULL,
net_rx_packet, net_rx_ok, NULL, net_rx_ok, net_rx_packet, NULL,
netdev); NULL, netdev);
snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str), snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str),
"nic: xenbus vif macaddr=%s", netdev->mac); "nic: xenbus vif macaddr=%s", netdev->mac);

722
net.c

File diff suppressed because it is too large Load Diff

31
net.h
View File

@ -5,19 +5,20 @@
/* VLANs support */ /* VLANs support */
typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int);
typedef struct VLANClientState VLANClientState; typedef struct VLANClientState VLANClientState;
typedef int (NetCanReceive)(VLANClientState *);
typedef ssize_t (NetReceive)(VLANClientState *, const uint8_t *, size_t);
typedef ssize_t (NetReceiveIOV)(VLANClientState *, const struct iovec *, int);
typedef void (NetCleanup) (VLANClientState *); typedef void (NetCleanup) (VLANClientState *);
typedef void (LinkStatusChanged)(VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *);
struct VLANClientState { struct VLANClientState {
IOReadHandler *fd_read; NetReceive *receive;
IOReadvHandler *fd_readv; NetReceiveIOV *receive_iov;
/* Packets may still be sent if this returns zero. It's used to /* Packets may still be sent if this returns zero. It's used to
rate-limit the slirp code. */ rate-limit the slirp code. */
IOCanRWHandler *fd_can_read; NetCanReceive *can_receive;
NetCleanup *cleanup; NetCleanup *cleanup;
LinkStatusChanged *link_status_changed; LinkStatusChanged *link_status_changed;
int link_down; int link_down;
@ -31,10 +32,13 @@ struct VLANClientState {
typedef struct VLANPacket VLANPacket; typedef struct VLANPacket VLANPacket;
typedef void (NetPacketSent) (VLANClientState *);
struct VLANPacket { struct VLANPacket {
struct VLANPacket *next; struct VLANPacket *next;
VLANClientState *sender; VLANClientState *sender;
int size; int size;
NetPacketSent *sent_cb;
uint8_t data[0]; uint8_t data[0];
}; };
@ -51,8 +55,9 @@ VLANState *qemu_find_vlan(int id);
VLANClientState *qemu_new_vlan_client(VLANState *vlan, VLANClientState *qemu_new_vlan_client(VLANState *vlan,
const char *model, const char *model,
const char *name, const char *name,
IOReadHandler *fd_read, NetCanReceive *can_receive,
IOCanRWHandler *fd_can_read, NetReceive *receive,
NetReceiveIOV *receive_iov,
NetCleanup *cleanup, NetCleanup *cleanup,
void *opaque); void *opaque);
void qemu_del_vlan_client(VLANClientState *vc); void qemu_del_vlan_client(VLANClientState *vc);
@ -60,7 +65,12 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque);
int qemu_can_send_packet(VLANClientState *vc); int qemu_can_send_packet(VLANClientState *vc);
ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov,
int iovcnt); int iovcnt);
ssize_t qemu_sendv_packet_async(VLANClientState *vc, const struct iovec *iov,
int iovcnt, NetPacketSent *sent_cb);
void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size); void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
ssize_t qemu_send_packet_async(VLANClientState *vc, const uint8_t *buf,
int size, NetPacketSent *sent_cb);
void qemu_flush_queued_packets(VLANClientState *vc);
void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]); void qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6]);
void qemu_check_nic_model(NICInfo *nd, const char *model); void qemu_check_nic_model(NICInfo *nd, const char *model);
void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, void qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
@ -108,7 +118,7 @@ uint16_t net_checksum_tcpudp(uint16_t length, uint16_t proto,
void net_checksum_calculate(uint8_t *data, int length); void net_checksum_calculate(uint8_t *data, int length);
/* from net.c */ /* from net.c */
int net_client_init(const char *device, const char *p); int net_client_init(Monitor *mon, const char *device, const char *p);
void net_client_uninit(NICInfo *nd); void net_client_uninit(NICInfo *nd);
int net_client_parse(const char *str); int net_client_parse(const char *str);
void net_slirp_smb(const char *exported_dir); void net_slirp_smb(const char *exported_dir);
@ -129,8 +139,9 @@ void net_host_device_remove(Monitor *mon, int vlan_id, const char *device);
void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr); void qdev_get_macaddr(DeviceState *dev, uint8_t *macaddr);
VLANClientState *qdev_get_vlan_client(DeviceState *dev, VLANClientState *qdev_get_vlan_client(DeviceState *dev,
IOReadHandler *fd_read, NetCanReceive *can_receive,
IOCanRWHandler *fd_can_read, NetReceive *receive,
NetReceiveIOV *receive_iov,
NetCleanup *cleanup, NetCleanup *cleanup,
void *opaque); void *opaque);

View File

@ -131,7 +131,7 @@ static void qemu_announce_self_once(void *opaque)
len = announce_self_create(buf, nd_table[i].macaddr); len = announce_self_create(buf, nd_table[i].macaddr);
vlan = nd_table[i].vlan; vlan = nd_table[i].vlan;
for(vc = vlan->first_client; vc != NULL; vc = vc->next) { for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
vc->fd_read(vc->opaque, buf, len); vc->receive(vc, buf, len);
} }
} }
if (count--) { if (count--) {

View File

@ -5,7 +5,7 @@
extern "C" { extern "C" {
#endif #endif
void slirp_init(int restricted, char *special_ip); void slirp_init(int restricted, const char *special_ip);
void slirp_select_fill(int *pnfds, void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds); fd_set *readfds, fd_set *writefds, fd_set *xfds);

View File

@ -171,7 +171,7 @@ static void slirp_cleanup(void)
static void slirp_state_save(QEMUFile *f, void *opaque); static void slirp_state_save(QEMUFile *f, void *opaque);
static int slirp_state_load(QEMUFile *f, void *opaque, int version_id); static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
void slirp_init(int restricted, char *special_ip) void slirp_init(int restricted, const char *special_ip)
{ {
// debug_init("/tmp/slirp.log", DEBUG_DEFAULT); // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);

View File

@ -270,7 +270,8 @@ void usb_info(Monitor *mon);
int get_param_value(char *buf, int buf_size, int get_param_value(char *buf, int buf_size,
const char *tag, const char *str); const char *tag, const char *str);
int check_params(const char * const *params, const char *str); int check_params(char *buf, int buf_size,
const char * const *params, const char *str);
void register_devices(void); void register_devices(void);

View File

@ -650,11 +650,11 @@ static void tap_cleanup(VLANClientState *vc)
qemu_free(s); qemu_free(s);
} }
static void tap_receive(void *opaque, const uint8_t *buf, int size) static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{ {
TAPState *s = opaque; TAPState *s = vc->opaque;
tap_win32_write(s->handle, buf, size); return tap_win32_write(s->handle, buf, size);
} }
static void tap_win32_send(void *opaque) static void tap_win32_send(void *opaque)
@ -684,7 +684,7 @@ int tap_win32_init(VLANState *vlan, const char *model,
return -1; return -1;
} }
s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
NULL, tap_cleanup, s); NULL, tap_cleanup, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str), snprintf(s->vc->info_str, sizeof(s->vc->info_str),

57
vl.c
View File

@ -1836,45 +1836,34 @@ int get_param_value(char *buf, int buf_size,
return 0; return 0;
} }
int check_params(const char * const *params, const char *str) int check_params(char *buf, int buf_size,
const char * const *params, const char *str)
{ {
int name_buf_size = 1;
const char *p; const char *p;
char *name_buf; int i;
int i, len;
int ret = 0;
for (i = 0; params[i] != NULL; i++) {
len = strlen(params[i]) + 1;
if (len > name_buf_size) {
name_buf_size = len;
}
}
name_buf = qemu_malloc(name_buf_size);
p = str; p = str;
while (*p != '\0') { while (*p != '\0') {
p = get_opt_name(name_buf, name_buf_size, p, '='); p = get_opt_name(buf, buf_size, p, '=');
if (*p != '=') { if (*p != '=') {
ret = -1; return -1;
break;
} }
p++; p++;
for(i = 0; params[i] != NULL; i++) for (i = 0; params[i] != NULL; i++) {
if (!strcmp(params[i], name_buf)) if (!strcmp(params[i], buf)) {
break; break;
}
}
if (params[i] == NULL) { if (params[i] == NULL) {
ret = -1; return -1;
break;
} }
p = get_opt_value(NULL, 0, p); p = get_opt_value(NULL, 0, p);
if (*p != ',') if (*p != ',') {
break; break;
}
p++; p++;
} }
return 0;
qemu_free(name_buf);
return ret;
} }
/***********************************************************/ /***********************************************************/
@ -2227,8 +2216,9 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
"cache", "format", "serial", "werror", "cache", "format", "serial", "werror",
NULL }; NULL };
if (check_params(params, str) < 0) { if (check_params(buf, sizeof(buf), params, str) < 0) {
fprintf(stderr, "qemu: unknown parameter in '%s'\n", str); fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
buf, str);
return -1; return -1;
} }
@ -2709,7 +2699,7 @@ static int usb_device_add(const char *devname, int is_hotplug)
} else if (strstart(devname, "net:", &p)) { } else if (strstart(devname, "net:", &p)) {
int nic = nb_nics; int nic = nb_nics;
if (net_client_init("nic", p) < 0) if (net_client_init(NULL, "nic", p) < 0)
return -1; return -1;
nd_table[nic].model = "usb"; nd_table[nic].model = "usb";
dev = usb_net_init(&nd_table[nic]); dev = usb_net_init(&nd_table[nic]);
@ -4783,7 +4773,12 @@ static void termsig_handler(int signal)
qemu_system_shutdown_request(); qemu_system_shutdown_request();
} }
static void termsig_setup(void) static void sigchld_handler(int signal)
{
waitpid(-1, NULL, WNOHANG);
}
static void sighandler_setup(void)
{ {
struct sigaction act; struct sigaction act;
@ -4792,6 +4787,10 @@ static void termsig_setup(void)
sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, NULL);
sigaction(SIGHUP, &act, NULL); sigaction(SIGHUP, &act, NULL);
sigaction(SIGTERM, &act, NULL); sigaction(SIGTERM, &act, NULL);
act.sa_handler = sigchld_handler;
act.sa_flags = SA_NOCLDSTOP;
sigaction(SIGCHLD, &act, NULL);
} }
#endif #endif
@ -5920,7 +5919,7 @@ int main(int argc, char **argv, char **envp)
#ifndef _WIN32 #ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */ /* must be after terminal init, SDL library changes signal handlers */
termsig_setup(); sighandler_setup();
#endif #endif
/* Maintain compatibility with multiple stdio monitors */ /* Maintain compatibility with multiple stdio monitors */