diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2009-06-10 18:05:55 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2009-06-10 18:08:35 -0500 |
commit | f8e76fbf5190575c0f927fe3c5b0ec6934c6c3fc (patch) | |
tree | c67bf81b0bfa6b897f4fb7a236962a85819e15f7 | |
parent | b319820d4099ec6b98c9c260e06d519fc41d544c (diff) | |
parent | 4ffb17f5c3244e405198ae285ffbb20a62e0d4b3 (diff) |
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>
-rw-r--r-- | hw/dp8393x.c | 22 | ||||
-rw-r--r-- | hw/e1000.c | 30 | ||||
-rw-r--r-- | hw/eepro100.c | 23 | ||||
-rw-r--r-- | hw/etraxfs_eth.c | 14 | ||||
-rw-r--r-- | hw/mcf_fec.c | 11 | ||||
-rw-r--r-- | hw/mipsnet.c | 16 | ||||
-rw-r--r-- | hw/musicpal.c | 11 | ||||
-rw-r--r-- | hw/ne2000.c | 25 | ||||
-rw-r--r-- | hw/pci-hotplug.c | 7 | ||||
-rw-r--r-- | hw/pcnet.c | 17 | ||||
-rw-r--r-- | hw/qdev.c | 9 | ||||
-rw-r--r-- | hw/rtl8139.c | 39 | ||||
-rw-r--r-- | hw/smc91c111.c | 18 | ||||
-rw-r--r-- | hw/stellaris_enet.c | 20 | ||||
-rw-r--r-- | hw/usb-net.c | 18 | ||||
-rw-r--r-- | hw/virtio-net.c | 154 | ||||
-rw-r--r-- | hw/virtio-net.h | 14 | ||||
-rw-r--r-- | hw/xen_nic.c | 26 | ||||
-rw-r--r-- | net.c | 708 | ||||
-rw-r--r-- | net.h | 31 | ||||
-rw-r--r-- | savevm.c | 2 | ||||
-rw-r--r-- | slirp/libslirp.h | 2 | ||||
-rw-r--r-- | slirp/slirp.c | 2 | ||||
-rw-r--r-- | sysemu.h | 3 | ||||
-rw-r--r-- | tap-win32.c | 8 | ||||
-rw-r--r-- | vl.c | 57 |
26 files changed, 834 insertions, 453 deletions
diff --git a/hw/dp8393x.c b/hw/dp8393x.c index 5aa12119cb..cff84aa0a1 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -407,9 +407,9 @@ static void do_transmit_packets(dp8393xState *s) if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) { /* Loopback */ 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->vc->fd_read(s, s->tx_buffer, tx_len); + s->vc->receive(s->vc, s->tx_buffer, tx_len); } } else { /* Transmit packet */ @@ -676,9 +676,9 @@ static CPUWriteMemoryFunc *dp8393x_write[3] = { 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)) return 0; @@ -725,10 +725,10 @@ static int receive_filter(dp8393xState *s, const uint8_t * buf, int size) 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]; - dp8393xState *s = opaque; + dp8393xState *s = vc->opaque; int packet_type; uint32_t available, address; 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); if (packet_type < 0) { DPRINTF("packet not for netcard\n"); - return; + return -1; } /* 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); if (data[0 * width] & 0x1) { /* Still EOL ; stop reception */ - return; + return -1; } else { 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 */ dp8393x_update_irq(s); + + return size; } 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->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ - s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - nic_receive, nic_can_receive, nic_cleanup, s); + s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, nic_can_receive, + nic_receive, NULL, nic_cleanup, s); qemu_format_nic_info_str(s->vc, nd->macaddr); qemu_register_reset(nic_reset, 0, s); diff --git a/hw/e1000.c b/hw/e1000.c index 03fad4cc94..eed02a69f7 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -598,17 +598,17 @@ e1000_set_link_status(VLANClientState *vc) } 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); } -static void -e1000_receive(void *opaque, const uint8_t *buf, int size) +static ssize_t +e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - E1000State *s = opaque; + E1000State *s = vc->opaque; struct e1000_rx_desc desc; target_phys_addr_t base; 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; if (!(s->mac_reg[RCTL] & E1000_RCTL_EN)) - return; + return -1; if (size > s->rxbuf_size) { - DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size, - s->rxbuf_size); - return; + DBGOUT(RX, "packet too large for buffers (%lu > %d)\n", + (unsigned long)size, s->rxbuf_size); + return -1; } if (!receive_filter(s, buf, size)) - return; + return size; if (vlan_enabled(s) && is_vlan_packet(s, buf)) { 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 { if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { set_ics(s, 0, E1000_ICS_RXO); - return; + return -1; } base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + 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", rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]); set_ics(s, 0, E1000_ICS_RXO); - return; + return -1; } } while (desc.buffer_addr == 0); @@ -683,6 +683,8 @@ e1000_receive(void *opaque, const uint8_t *buf, int size) n |= E1000_ICS_RXDMT0; set_ics(s, 0, n); + + return size; } static uint32_t @@ -1119,8 +1121,8 @@ static void pci_e1000_init(PCIDevice *pci_dev) d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum; d->vc = qdev_get_vlan_client(&d->dev.qdev, - e1000_receive, e1000_can_receive, - e1000_cleanup, d); + e1000_can_receive, e1000_receive, + NULL, e1000_cleanup, d); d->vc->link_status_changed = e1000_set_link_status; qemu_format_nic_info_str(d->vc, macaddr); diff --git a/hw/eepro100.c b/hw/eepro100.c index fcb091c9f4..a6355dc754 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -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); return get_ru_state(s) == ru_ready; //~ 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: * - Magic packets should set bit 30 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; static const uint8_t broadcast_macaddr[6] = { 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) { /* CSMA is disabled. */ logout("%p received while CSMA is disabled\n", s); - return; + return -1; } else if (size < 64 && (s->configuration[7] & 1)) { /* Short frame and configuration byte 7/0 (discard short receive) set: * Short frame is discarded */ logout("%p received short frame (%d byte)\n", s, size); s->statistics.rx_short_frame_errors++; - //~ return; + //~ return -1; } 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 frames are discarded. */ logout("%p received long frame (%d byte), ignored\n", s, size); - return; + return -1; } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!! /* Frame matches individual address. */ /* 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))); int mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) { - return; + return size; } rfd_status |= 0x0002; } else if (s->configuration[15] & 1) { @@ -1495,7 +1495,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size) } else { logout("%p received frame, ignored, len=%d,%s\n", s, size, nic_dump(buf, size)); - return; + return size; } 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)); s->statistics.rx_resource_errors++; //~ 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>}} @@ -1540,6 +1540,7 @@ static void nic_receive(void *opaque, const uint8_t * buf, int size) /* S bit is set. */ set_ru_state(s, ru_suspended); } + return size; } 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); s->vc = qdev_get_vlan_client(&d->dev.qdev, - nic_receive, nic_can_receive, + nic_can_receive, nic_receive, NULL, nic_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 68b8de38eb..c7df44ee45 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -496,21 +496,21 @@ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) return match; } -static int eth_can_receive(void *opaque) +static int eth_can_receive(VLANClientState *vc) { 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 }; - struct fs_eth *eth = opaque; + struct fs_eth *eth = vc->opaque; int use_ma0 = eth->regs[RW_REC_CTRL] & 1; int use_ma1 = eth->regs[RW_REC_CTRL] & 2; int r_bcast = eth->regs[RW_REC_CTRL] & 8; if (size < 12) - return; + return -1; 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], @@ -521,10 +521,12 @@ static void eth_receive(void *opaque, const uint8_t *buf, int size) && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) && (!r_bcast || memcmp(buf, sa_bcast, 6)) && !eth_match_groupaddr(eth, buf)) - return; + return size; /* FIXME: Find another way to pass on the fake csum. */ 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) @@ -593,7 +595,7 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, cpu_register_physical_memory (base, 0x5c, eth->ethregs); 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->vc->opaque = eth; eth->vc->link_status_changed = eth_set_link; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 6c0acc5789..179ec19e07 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -347,15 +347,15 @@ static void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value) 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; } -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; uint32_t flags = 0; uint32_t addr; @@ -426,6 +426,7 @@ static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size) s->rx_descriptor = addr; mcf_fec_enable_rx(s); mcf_fec_update(s); + return size; } 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); 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); memcpy(s->macaddr, nd->macaddr, 6); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/mipsnet.c b/hw/mipsnet.c index e842984219..803522949b 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -66,24 +66,24 @@ static int mipsnet_buffer_full(MIPSnetState *s) 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) return 0; 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 printf("mipsnet: receiving len=%d\n", size); #endif - if (!mipsnet_can_receive(opaque)) - return; + if (!mipsnet_can_receive(vc)) + return -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. */ s->intctl |= MIPSNET_INTCTL_RXDONE; mipsnet_update_irq(s); + + return size; } 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; if (nd && nd->vlan) { 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); } else { s->vc = NULL; diff --git a/hw/musicpal.c b/hw/musicpal.c index 9389af9589..8c70a2bec8 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -557,14 +557,14 @@ static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) le32_to_cpus(&desc->next); } -static int eth_can_receive(void *opaque) +static int eth_can_receive(VLANClientState *vc) { 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; mv88w8618_rx_desc desc; int i; @@ -586,11 +586,12 @@ static void eth_receive(void *opaque, const uint8_t *buf, int size) if (s->icr & s->imr) qemu_irq_raise(s->irq); eth_rx_desc_put(desc_addr, &desc); - return; + return size; } desc_addr = desc.next; } while (desc_addr != s->rx_queue[i]); } + return size; } 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); s->vc = qdev_get_vlan_client(&dev->qdev, - eth_receive, eth_can_receive, + eth_can_receive, eth_receive, NULL, eth_cleanup, s); s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, mv88w8618_eth_writefn, s); diff --git a/hw/ne2000.c b/hw/ne2000.c index 2af0d109b9..f5ae9d7394 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -213,9 +213,9 @@ static int ne2000_buffer_full(NE2000State *s) 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) return 1; @@ -224,9 +224,10 @@ static int ne2000_can_receive(void *opaque) #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; unsigned int total_len, next, avail, len, index, mcast_idx; uint8_t buf1[60]; @@ -238,7 +239,7 @@ static void ne2000_receive(void *opaque, const uint8_t *buf, int size) #endif if (s->cmd & E8390_STOP || ne2000_buffer_full(s)) - return; + return -1; /* XXX: check this */ 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)) { /* broadcast address */ if (!(s->rxcr & 0x04)) - return; + return size; } else if (buf[0] & 0x01) { /* multicast */ if (!(s->rxcr & 0x08)) - return; + return size; mcast_idx = compute_mcast_idx(buf); if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) - return; + return size; } else if (s->mem[0] == buf[0] && s->mem[2] == buf[1] && 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]) { /* match */ } 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 */ s->isr |= ENISR_RX; ne2000_update_irq(s); + + return size_; } 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); 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); 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); ne2000_reset(s); s->vc = qdev_get_vlan_client(&d->dev.qdev, - ne2000_receive, ne2000_can_receive, + ne2000_can_receive, ne2000_receive, NULL, ne2000_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c index 4d18ea2fca..abe5bae4ac 100644 --- a/hw/pci-hotplug.c +++ b/hw/pci-hotplug.c @@ -33,11 +33,12 @@ #include "virtio-blk.h" #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; - ret = net_client_init("nic", opts); + ret = net_client_init(mon, "nic", opts); if (ret < 0) return NULL; 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) - 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) dev = qemu_pci_hot_add_storage(mon, pci_bus, opts); else diff --git a/hw/pcnet.c b/hw/pcnet.c index c44ba7edf4..b5793ff246 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -1062,9 +1062,9 @@ static int pcnet_tdte_poll(PCNetState *s) 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)) return 0; @@ -1076,16 +1076,17 @@ static int pcnet_can_receive(void *opaque) #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; uint8_t buf1[60]; int remaining; int crc_err = 0; + int size = size_; if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) - return; + return -1; #ifdef PCNET_DEBUG 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_update_irq(s); + + return size_; } static void pcnet_transmit(PCNetState *s) @@ -1302,7 +1305,7 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) == 1) add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); 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; } else if (s->vc) @@ -1952,7 +1955,7 @@ static void pcnet_common_init(DeviceState *dev, PCNetState *s, qdev_get_macaddr(dev, s->macaddr); s->vc = qdev_get_vlan_client(dev, - pcnet_receive, pcnet_can_receive, + pcnet_can_receive, pcnet_receive, NULL, cleanup, s); pcnet_h_reset(s); register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s); @@ -258,15 +258,16 @@ void qdev_connect_gpio_out(DeviceState * dev, int n, qemu_irq pin) } VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque) { NICInfo *nd = dev->nd; assert(nd); - return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - fd_read, fd_can_read, cleanup, opaque); + return qemu_new_vlan_client(nd->vlan, nd->model, nd->name, can_receive, + receive, receive_iov, cleanup, opaque); } diff --git a/hw/rtl8139.c b/hw/rtl8139.c index ea27dcfea0..de5a68fc99 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -790,9 +790,9 @@ static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high) #endif } -static int rtl8139_can_receive(void *opaque) +static int rtl8139_can_receive(VLANClientState *vc) { - RTL8139State *s = opaque; + RTL8139State *s = vc->opaque; int avail; /* 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; @@ -828,7 +829,7 @@ static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int d if (!s->clock_enabled) { DEBUG_PRINT(("RTL8139: stopped ==========================\n")); - return; + return -1; } /* 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)) { DEBUG_PRINT(("RTL8139: receiver disabled ================\n")); - return; + return -1; } /* 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 */ ++s->tally_counters.RxERR; - return; + return size; } 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 */ ++s->tally_counters.RxERR; - return; + return size; } 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 */ ++s->tally_counters.RxERR; - return; + return size; } 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 */ ++s->tally_counters.RxERR; - return; + return size; } 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 */ ++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; rtl8139_update_irq(s); - return; + return size_; } 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; rtl8139_update_irq(s); - return; + return size_; } 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->RxMissed; rtl8139_update_irq(s); - return; + return size_; } 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); } + + 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) @@ -1758,7 +1761,7 @@ static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size if (TxLoopBack == (s->TxConfig & TxLoopBack)) { 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 { @@ -3479,7 +3482,7 @@ static void pci_rtl8139_init(PCIDevice *dev) qemu_register_reset(rtl8139_reset, 0, s); rtl8139_reset(s); s->vc = qdev_get_vlan_client(&dev->qdev, - rtl8139_receive, rtl8139_can_receive, + rtl8139_can_receive, rtl8139_receive, NULL, rtl8139_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 38cbd016e9..93a1fae0dc 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -591,9 +591,9 @@ static uint32_t smc91c111_readl(void *opaque, target_phys_addr_t offset) 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)) return 1; @@ -602,9 +602,9 @@ static int smc91c111_can_receive(void *opaque) 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 packetsize; uint32_t crc; @@ -612,7 +612,7 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) uint8_t *p; if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) - return; + return -1; /* Short packets are padded with zeros. Receiving a packet < 64 bytes long is considered an error condition. */ if (size < 64) @@ -625,10 +625,10 @@ static void smc91c111_receive(void *opaque, const uint8_t *buf, int size) packetsize += 4; /* TODO: Flag overrun and receive errors. */ if (packetsize > 2048) - return; + return -1; packetnum = smc91c111_allocate_packet(s); if (packetnum == 0x80) - return; + return -1; s->rx_fifo[s->rx_fifo_len++] = packetnum; 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? */ s->int_level |= INT_RCV; smc91c111_update(s); + + return size; } static CPUReadMemoryFunc *smc91c111_readfn[] = { @@ -711,7 +713,7 @@ static void smc91c111_init1(SysBusDevice *dev) smc91c111_reset(s); s->vc = qdev_get_vlan_client(&dev->qdev, - smc91c111_receive, smc91c111_can_receive, + smc91c111_can_receive, smc91c111_receive, NULL, smc91c111_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); /* ??? Save/restore. */ diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 36fabd3260..f5b83e445c 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -78,18 +78,18 @@ static void stellaris_enet_update(stellaris_enet_state *s) } /* 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; uint8_t *p; uint32_t crc; if ((s->rctl & SE_RCTL_RXEN) == 0) - return; + return -1; if (s->np >= 31) { DPRINTF("Packet dropped\n"); - return; + return -1; } 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; 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) return 1; @@ -128,9 +130,9 @@ static int stellaris_enet_can_receive(void *opaque) 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; switch (offset) { @@ -405,8 +407,8 @@ static void stellaris_enet_init(SysBusDevice *dev) qdev_get_macaddr(&dev->qdev, s->macaddr); s->vc = qdev_get_vlan_client(&dev->qdev, - stellaris_enet_receive, stellaris_enet_can_receive, + stellaris_enet_receive, NULL, stellaris_enet_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/usb-net.c b/hw/usb-net.c index 9e6442506f..0e80ca6923 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1369,17 +1369,17 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) 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; if (s->rndis) { msg = (struct rndis_packet_msg_type *) s->in_buf; if (!s->rndis_state == RNDIS_DATA_INITIALIZED) - return; + return -1; if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) - return; + return -1; memset(msg, 0, sizeof(struct rndis_packet_msg_type)); 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); } else { if (size > sizeof(s->in_buf)) - return; + return -1; memcpy(s->in_buf, buf, size); s->in_len = size; } 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) return 1; @@ -1458,8 +1459,9 @@ USBDevice *usb_net_init(NICInfo *nd) pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Network Interface"); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - usbnet_receive, usbnet_can_receive, + usbnet_receive, + NULL, usbnet_cleanup, s); qemu_format_nic_info_str(s->vc, s->mac); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 60aa6dab1b..d584287a51 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -16,9 +16,9 @@ #include "qemu-timer.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 */ typedef struct VirtIONet @@ -33,10 +33,17 @@ typedef struct VirtIONet QEMUTimer *tx_timer; int tx_timer_active; int mergeable_rx_bufs; - int promisc; - int allmulti; + uint8_t promisc; + uint8_t allmulti; + uint8_t alluni; + uint8_t nomulti; + uint8_t nouni; + uint8_t nobcast; struct { int in_use; + int first_multi; + uint8_t multi_overflow; + uint8_t uni_overflow; uint8_t *macs; } mac_table; uint32_t *vlans; @@ -95,9 +102,16 @@ static void virtio_net_reset(VirtIODevice *vdev) /* Reset back to compatibility mode */ n->promisc = 1; n->allmulti = 0; + n->alluni = 0; + n->nomulti = 0; + n->nouni = 0; + n->nobcast = 0; /* Flush any MAC and VLAN filter table state */ 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->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_CTRL_VQ) | (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; } @@ -151,6 +166,14 @@ static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd, n->promisc = on; else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI) 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 return VIRTIO_NET_ERR; @@ -168,6 +191,9 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd, return VIRTIO_NET_ERR; 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); 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); n->mac_table.in_use += mac_data.entries; } else { - n->promisc = 1; - return VIRTIO_NET_OK; + n->mac_table.uni_overflow = 1; } + n->mac_table.first_multi = n->mac_table.in_use; + mac_data.entries = ldl_le_p(elem->out_sg[2].iov_base); 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), mac_data.entries * ETH_ALEN); n->mac_table.in_use += mac_data.entries; - } else - n->allmulti = 1; + } else { + n->mac_table.multi_overflow = 1; + } } 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) { + VirtIONet *n = to_virtio_net(vdev); + + qemu_flush_queued_packets(n->vc); } 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; } -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); } @@ -344,34 +375,50 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size) return 0; } - if ((ptr[0] & 1) && n->allmulti) - return 1; - - if (!memcmp(ptr, bcast, sizeof(bcast))) - return 1; - - if (!memcmp(ptr, n->mac, ETH_ALEN)) - return 1; + 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; + } - for (i = 0; i < n->mac_table.in_use; i++) { - if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) + 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; + } + } + } 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; + } + + for (i = 0; i < n->mac_table.first_multi; i++) { + if (!memcmp(ptr, &n->mac_table.macs[i * ETH_ALEN], ETH_ALEN)) { + return 1; + } + } } 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; size_t hdr_len, offset, i; if (!do_virtio_net_can_receive(n, size)) - return; + return 0; if (!receive_filter(n, buf, size)) - return; + return size; /* hdr_len refers to the header we supply to the guest */ 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) || virtqueue_pop(n->rx_vq, &elem) == 0) { if (i == 0) - return; + return -1; fprintf(stderr, "virtio-net truncating packet\n"); 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); virtio_notify(&n->vdev, n->rx_vq); + + return size; } /* 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->mergeable_rx_bufs); qemu_put_be16(f, n->status); - qemu_put_be32(f, n->promisc); - qemu_put_be32(f, n->allmulti); + qemu_put_byte(f, n->promisc); + qemu_put_byte(f, n->allmulti); 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, (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) { VirtIONet *n = opaque; + int i; if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION) return -EINVAL; @@ -542,8 +599,13 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->status = qemu_get_be16(f); if (version_id >= 4) { - n->promisc = qemu_get_be32(f); - n->allmulti = qemu_get_be32(f); + if (version_id < 8) { + n->promisc = 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) { @@ -554,7 +616,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) n->mac_table.in_use * ETH_ALEN); } else if (n->mac_table.in_use) { 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; } } @@ -562,6 +624,32 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) if (version_id >= 6) 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) { qemu_mod_timer(n->tx_timer, 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->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->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); n->status = VIRTIO_NET_S_LINK_UP; n->vc = qdev_get_vlan_client(dev, - virtio_net_receive, virtio_net_can_receive, + virtio_net_receive, NULL, virtio_net_cleanup, n); n->vc->link_status_changed = virtio_net_set_link_status; diff --git a/hw/virtio-net.h b/hw/virtio-net.h index 390fe10224..2085181673 100644 --- a/hw/virtio-net.h +++ b/hw/virtio-net.h @@ -43,6 +43,7 @@ #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_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 */ @@ -103,14 +104,19 @@ typedef uint8_t virtio_net_ctrl_ack; #define VIRTIO_NET_ERR 1 /* - * Control the RX mode, ie. promisucous and allmulti. PROMISC and - * ALLMULTI commands require an "out" sg entry containing a 1 byte - * state value, zero = disable, non-zero = enable. These commands - * are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Control the RX mode, ie. promisucous, allmulti, etc... + * All commands require an "out" sg entry containing a 1 byte + * state value, zero = disable, non-zero = enable. Commands + * 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_PROMISC 0 #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. diff --git a/hw/xen_nic.c b/hw/xen_nic.c index 4206132aea..9a3c870c2d 100644 --- a/hw/xen_nic.c +++ b/hw/xen_nic.c @@ -223,9 +223,9 @@ static void net_rx_response(struct XenNetDev *netdev, #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; if (netdev->xendev.be_state != XenbusStateConnected) @@ -243,15 +243,15 @@ static int net_rx_ok(void *opaque) 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; RING_IDX rc, rp; void *page; if (netdev->xendev.be_state != XenbusStateConnected) - return; + return -1; rc = netdev->rx_ring.req_cons; 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)) { xen_be_printf(&netdev->xendev, 2, "no buffer, drop packet\n"); - return; + return -1; } if (size > XC_PAGE_SIZE - NET_IP_ALIGN) { - xen_be_printf(&netdev->xendev, 0, "packet too big (%d > %ld)", - size, XC_PAGE_SIZE - NET_IP_ALIGN); - return; + xen_be_printf(&netdev->xendev, 0, "packet too big (%lu > %ld)", + (unsigned long)size, XC_PAGE_SIZE - NET_IP_ALIGN); + return -1; } 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", rxreq.gref); net_rx_response(netdev, &rxreq, NETIF_RSP_ERROR, 0, 0, 0); - return; + return -1; } memcpy(page + NET_IP_ALIGN, buf, size); xc_gnttab_munmap(netdev->xendev.gnttabdev, page, 1); 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); netdev->vs = qemu_new_vlan_client(vlan, "xen", NULL, - net_rx_packet, net_rx_ok, NULL, - netdev); + net_rx_ok, net_rx_packet, NULL, + NULL, netdev); snprintf(netdev->vs->info_str, sizeof(netdev->vs->info_str), "nic: xenbus vif macaddr=%s", netdev->mac); @@ -332,8 +332,9 @@ static char *assign_name(VLANClientState *vc1, const char *model) VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *model, const char *name, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque) { @@ -344,8 +345,9 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, vc->name = strdup(name); else vc->name = assign_name(vc, model); - vc->fd_read = fd_read; - vc->fd_can_read = fd_can_read; + vc->can_receive = can_receive; + vc->receive = receive; + vc->receive_iov = receive_iov; vc->cleanup = cleanup; vc->opaque = opaque; vc->vlan = vlan; @@ -389,61 +391,126 @@ VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque) return NULL; } -int qemu_can_send_packet(VLANClientState *vc1) +int qemu_can_send_packet(VLANClientState *sender) { - VLANState *vlan = vc1->vlan; + VLANState *vlan = sender->vlan; VLANClientState *vc; - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1) { - if (vc->fd_can_read && vc->fd_can_read(vc->opaque)) - return 1; + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { + if (vc == sender) { + continue; + } + + /* no can_receive() handler, they can always receive */ + if (!vc->can_receive || vc->can_receive(vc)) { + return 1; } } return 0; } -static void +static int qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) { VLANClientState *vc; + int ret = -1; + + sender->vlan->delivering = 1; for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != sender && !vc->link_down) { - vc->fd_read(vc->opaque, buf, size); + ssize_t len; + + if (vc == sender) { + continue; } + + if (vc->link_down) { + ret = size; + continue; + } + + len = vc->receive(vc, buf, size); + + ret = (ret >= 0) ? ret : len; } + + sender->vlan->delivering = 0; + + return ret; } -void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) +void qemu_flush_queued_packets(VLANClientState *vc) { - VLANState *vlan = vc->vlan; VLANPacket *packet; - if (vc->link_down) - return; + while ((packet = vc->vlan->send_queue) != NULL) { + int ret; + + vc->vlan->send_queue = packet->next; + + ret = qemu_deliver_packet(packet->sender, packet->data, packet->size); + if (ret == 0 && packet->sent_cb != NULL) { + packet->next = vc->vlan->send_queue; + vc->vlan->send_queue = packet; + break; + } + + if (packet->sent_cb) + packet->sent_cb(packet->sender); + + qemu_free(packet); + } +} + +static void qemu_enqueue_packet(VLANClientState *sender, + const uint8_t *buf, int size, + NetPacketSent *sent_cb) +{ + VLANPacket *packet; + + packet = qemu_malloc(sizeof(VLANPacket) + size); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->size = size; + packet->sent_cb = sent_cb; + memcpy(packet->data, buf, size); + sender->vlan->send_queue = packet; +} + +ssize_t qemu_send_packet_async(VLANClientState *sender, + const uint8_t *buf, int size, + NetPacketSent *sent_cb) +{ + int ret; + + if (sender->link_down) { + return size; + } #ifdef DEBUG_NET - printf("vlan %d send:\n", vlan->id); + printf("vlan %d send:\n", sender->vlan->id); hex_dump(stdout, buf, size); #endif - if (vlan->delivering) { - packet = qemu_malloc(sizeof(VLANPacket) + size); - packet->next = vlan->send_queue; - packet->sender = vc; - packet->size = size; - memcpy(packet->data, buf, size); - vlan->send_queue = packet; - } else { - vlan->delivering = 1; - qemu_deliver_packet(vc, buf, size); - while ((packet = vlan->send_queue) != NULL) { - qemu_deliver_packet(packet->sender, packet->data, packet->size); - vlan->send_queue = packet->next; - qemu_free(packet); - } - vlan->delivering = 0; + + if (sender->vlan->delivering) { + qemu_enqueue_packet(sender, buf, size, NULL); + return size; + } + + ret = qemu_deliver_packet(sender, buf, size); + if (ret == 0 && sent_cb != NULL) { + qemu_enqueue_packet(sender, buf, size, sent_cb); + return 0; } + + qemu_flush_queued_packets(sender); + + return ret; +} + +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) +{ + qemu_send_packet_async(vc, buf, size, NULL); } static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, @@ -461,9 +528,7 @@ static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, offset += len; } - vc->fd_read(vc->opaque, buffer, offset); - - return offset; + return vc->receive(vc, buffer, offset); } static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) @@ -476,44 +541,133 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) return offset; } -ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, - int iovcnt) +static int qemu_deliver_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) { - VLANState *vlan = vc1->vlan; VLANClientState *vc; - ssize_t max_len = 0; + int ret = -1; - if (vc1->link_down) - return calc_iov_length(iov, iovcnt); + sender->vlan->delivering = 1; - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { - ssize_t len = 0; + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len; + + if (vc == sender) { + continue; + } - if (vc == vc1) + if (vc->link_down) { + ret = calc_iov_length(iov, iovcnt); continue; + } - if (vc->link_down) - len = calc_iov_length(iov, iovcnt); - if (vc->fd_readv) - len = vc->fd_readv(vc->opaque, iov, iovcnt); - else if (vc->fd_read) + if (vc->receive_iov) { + len = vc->receive_iov(vc, iov, iovcnt); + } else { len = vc_sendv_compat(vc, iov, iovcnt); + } - max_len = MAX(max_len, len); + ret = (ret >= 0) ? ret : len; } - return max_len; + sender->vlan->delivering = 0; + + return ret; +} + +static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt, + NetPacketSent *sent_cb) +{ + VLANPacket *packet; + size_t max_len = 0; + int i; + + max_len = calc_iov_length(iov, iovcnt); + + packet = qemu_malloc(sizeof(VLANPacket) + max_len); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->sent_cb = sent_cb; + packet->size = 0; + + for (i = 0; i < iovcnt; i++) { + size_t len = iov[i].iov_len; + + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } + + sender->vlan->send_queue = packet; + + return packet->size; +} + +ssize_t qemu_sendv_packet_async(VLANClientState *sender, + const struct iovec *iov, int iovcnt, + NetPacketSent *sent_cb) +{ + int ret; + + if (sender->link_down) { + return calc_iov_length(iov, iovcnt); + } + + if (sender->vlan->delivering) { + return qemu_enqueue_packet_iov(sender, iov, iovcnt, NULL); + } + + ret = qemu_deliver_packet_iov(sender, iov, iovcnt); + if (ret == 0 && sent_cb != NULL) { + qemu_enqueue_packet_iov(sender, iov, iovcnt, sent_cb); + return 0; + } + + qemu_flush_queued_packets(sender); + + return ret; +} + +ssize_t +qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt) +{ + return qemu_sendv_packet_async(vc, iov, iovcnt, NULL); +} + +static void config_error(Monitor *mon, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (mon) { + monitor_vprintf(mon, fmt, ap); + } else { + fprintf(stderr, "qemu: "); + vfprintf(stderr, fmt, ap); + exit(1); + } + va_end(ap); } #if defined(CONFIG_SLIRP) /* slirp network adapter */ +struct slirp_config_str { + struct slirp_config_str *next; + const char *str; +}; + static int slirp_inited; -static int slirp_restrict; -static char *slirp_ip; +static struct slirp_config_str *slirp_redirs; +#ifndef _WIN32 +static const char *slirp_smb_export; +#endif static VLANClientState *slirp_vc; +static void slirp_smb(const char *exported_dir); +static void slirp_redirection(Monitor *mon, const char *redir_str); + int slirp_can_output(void) { return !slirp_vc || qemu_can_send_packet(slirp_vc); @@ -535,13 +689,14 @@ int slirp_is_inited(void) return slirp_inited; } -static void slirp_receive(void *opaque, const uint8_t *buf, int size) +static ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { #ifdef DEBUG_SLIRP printf("slirp input:\n"); hex_dump(stdout, buf, size); #endif slirp_input(buf, size); + return size; } static int slirp_in_use; @@ -551,7 +706,8 @@ static void net_slirp_cleanup(VLANClientState *vc) slirp_in_use = 0; } -static int net_slirp_init(VLANState *vlan, const char *model, const char *name) +static int net_slirp_init(VLANState *vlan, const char *model, const char *name, + int restricted, const char *ip) { if (slirp_in_use) { /* slirp only supports a single instance so far */ @@ -559,10 +715,24 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) } if (!slirp_inited) { slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); + slirp_init(restricted, ip); + + while (slirp_redirs) { + struct slirp_config_str *config = slirp_redirs; + + slirp_redirection(NULL, config->str); + slirp_redirs = config->next; + qemu_free(config); + } +#ifndef _WIN32 + if (slirp_smb_export) { + slirp_smb(slirp_smb_export); + } +#endif } - slirp_vc = qemu_new_vlan_client(vlan, model, name, - slirp_receive, NULL, net_slirp_cleanup, NULL); + + slirp_vc = qemu_new_vlan_client(vlan, model, name, NULL, slirp_receive, + NULL, net_slirp_cleanup, NULL); slirp_vc->info_str[0] = '\0'; slirp_in_use = 1; return 0; @@ -643,32 +813,18 @@ static void net_slirp_redir_rm(Monitor *mon, const char *port_str) monitor_printf(mon, "invalid format\n"); } -void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2) +static void slirp_redirection(Monitor *mon, const char *redir_str) { - int is_udp; - char buf[256], *r; - const char *p, *errmsg; struct in_addr guest_addr; int host_port, guest_port; - - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); - } - - if (!strcmp(redir_str, "remove")) { - net_slirp_redir_rm(mon, redir_opt2); - return; - } - - if (!strcmp(redir_str, "list")) { - net_slirp_redir_list(mon); - return; - } + const char *p; + char buf[256], *r; + int is_udp; p = redir_str; - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } if (!strcmp(buf, "tcp") || buf[0] == '\0') { is_udp = 0; } else if (!strcmp(buf, "udp")) { @@ -677,39 +833,65 @@ void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2 goto fail_syntax; } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } host_port = strtol(buf, &r, 0); - if (r == buf) + if (r == buf) { goto fail_syntax; + } - if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) + if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) { goto fail_syntax; + } if (buf[0] == '\0') { pstrcpy(buf, sizeof(buf), "10.0.2.15"); } - if (!inet_aton(buf, &guest_addr)) + if (!inet_aton(buf, &guest_addr)) { goto fail_syntax; + } guest_port = strtol(p, &r, 0); - if (r == p) + if (r == p) { goto fail_syntax; + } if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { - errmsg = "could not set up redirection\n"; - goto fail; + config_error(mon, "could not set up redirection '%s'\n", redir_str); } return; fail_syntax: - errmsg = "invalid redirection format\n"; - fail: - if (mon) { - monitor_printf(mon, "%s", errmsg); - } else { - fprintf(stderr, "qemu: %s", errmsg); - exit(1); + config_error(mon, "invalid redirection format '%s'\n", redir_str); +} + +void net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2) +{ + struct slirp_config_str *config; + + if (!slirp_inited) { + if (mon) { + monitor_printf(mon, "user mode network stack not in use\n"); + } else { + config = qemu_malloc(sizeof(*config)); + config->str = redir_str; + config->next = slirp_redirs; + slirp_redirs = config; + } + return; + } + + if (!strcmp(redir_str, "remove")) { + net_slirp_redir_rm(mon, redir_opt2); + return; + } + + if (!strcmp(redir_str, "list")) { + net_slirp_redir_list(mon); + return; } + + slirp_redirection(mon, redir_str); } #ifndef _WIN32 @@ -747,18 +929,12 @@ static void smb_exit(void) erase_dir(smb_dir); } -/* automatic user mode samba server configuration */ -void net_slirp_smb(const char *exported_dir) +static void slirp_smb(const char *exported_dir) { char smb_conf[1024]; char smb_cmdline[1024]; FILE *f; - if (!slirp_inited) { - slirp_inited = 1; - slirp_init(slirp_restrict, slirp_ip); - } - /* XXX: better tmp dir construction */ snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid()); if (mkdir(smb_dir, 0700) < 0) { @@ -802,7 +978,21 @@ void net_slirp_smb(const char *exported_dir) slirp_add_exec(0, smb_cmdline, 4, 139); } +/* automatic user mode samba server configuration */ +void net_slirp_smb(const char *exported_dir) +{ + if (slirp_smb_export) { + fprintf(stderr, "-smb given twice\n"); + exit(1); + } + slirp_smb_export = exported_dir; + if (slirp_inited) { + slirp_smb(exported_dir); + } +} + #endif /* !defined(_WIN32) */ + void do_info_slirp(Monitor *mon) { slirp_stats(); @@ -834,14 +1024,15 @@ typedef struct TAPState { int fd; char down_script[1024]; char down_script_arg[128]; + uint8_t buf[4096]; } TAPState; static int launch_script(const char *setup_script, const char *ifname, int fd); -static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, +static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov, int iovcnt) { - TAPState *s = opaque; + TAPState *s = vc->opaque; ssize_t len; do { @@ -851,37 +1042,68 @@ static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, return len; } -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; - int ret; - for(;;) { - ret = write(s->fd, buf, size); - if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { - } else { - break; - } - } + TAPState *s = vc->opaque; + ssize_t len; + + do { + len = write(s->fd, buf, size); + } while (len == -1 && (errno == EINTR || errno == EAGAIN)); + + return len; } -static void tap_send(void *opaque) +static int tap_can_send(void *opaque) { TAPState *s = opaque; - uint8_t buf[4096]; - int size; + + return qemu_can_send_packet(s->vc); +} #ifdef __sun__ +static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) +{ struct strbuf sbuf; int f = 0; - sbuf.maxlen = sizeof(buf); + + sbuf.maxlen = maxlen; sbuf.buf = (char *)buf; - size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1; + + return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1; +} #else - size = read(s->fd, buf, sizeof(buf)); +static ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen) +{ + return read(tapfd, buf, maxlen); +} #endif - if (size > 0) { - qemu_send_packet(s->vc, buf, size); - } + +static void tap_send(void *opaque); + +static void tap_send_completed(VLANClientState *vc) +{ + TAPState *s = vc->opaque; + + qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); +} + +static void tap_send(void *opaque) +{ + TAPState *s = opaque; + int size; + + do { + size = tap_read_packet(s->fd, s->buf, sizeof(s->buf)); + if (size <= 0) { + break; + } + + size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed); + if (size == 0) { + qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); + } + } while (size > 0); } static void tap_cleanup(VLANClientState *vc) @@ -907,10 +1129,9 @@ static TAPState *net_tap_fd_init(VLANState *vlan, s = qemu_mallocz(sizeof(TAPState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, - NULL, tap_cleanup, s); - s->vc->fd_readv = tap_receive_iov; - qemu_set_fd_handler(s->fd, tap_send, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive, + tap_receive_iov, tap_cleanup, s); + qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); return s; } @@ -1107,38 +1328,46 @@ static int tap_open(char *ifname, int ifname_size) static int launch_script(const char *setup_script, const char *ifname, int fd) { + sigset_t oldmask, mask; int pid, status; char *args[3]; char **parg; - /* try to launch network script */ - pid = fork(); - if (pid >= 0) { - if (pid == 0) { - int open_max = sysconf (_SC_OPEN_MAX), i; - for (i = 0; i < open_max; i++) - if (i != STDIN_FILENO && - i != STDOUT_FILENO && - i != STDERR_FILENO && - i != fd) - close(i); - - parg = args; - *parg++ = (char *)setup_script; - *parg++ = (char *)ifname; - *parg++ = NULL; - execv(setup_script, args); - _exit(1); - } - while (waitpid(pid, &status, 0) != pid); - if (!WIFEXITED(status) || - WEXITSTATUS(status) != 0) { - fprintf(stderr, "%s: could not launch network script\n", - setup_script); - return -1; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(SIG_BLOCK, &mask, &oldmask); + + /* try to launch network script */ + pid = fork(); + if (pid == 0) { + int open_max = sysconf(_SC_OPEN_MAX), i; + + for (i = 0; i < open_max; i++) { + if (i != STDIN_FILENO && + i != STDOUT_FILENO && + i != STDERR_FILENO && + i != fd) { + close(i); } } - return 0; + parg = args; + *parg++ = (char *)setup_script; + *parg++ = (char *)ifname; + *parg++ = NULL; + execv(setup_script, args); + _exit(1); + } else if (pid > 0) { + while (waitpid(pid, &status, 0) != pid) { + /* loop */ + } + sigprocmask(SIG_SETMASK, &oldmask, NULL); + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + return 0; + } + } + fprintf(stderr, "%s: could not launch network script\n", setup_script); + return -1; } static int net_tap_init(VLANState *vlan, const char *model, @@ -1194,17 +1423,16 @@ static void vde_to_qemu(void *opaque) } } -static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) +static ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - VDEState *s = opaque; - int ret; - for(;;) { - ret = vde_send(s->vde, (const char *)buf, size, 0); - if (ret < 0 && errno == EINTR) { - } else { - break; - } - } + VDEState *s = vc->opaque; + ssize ret; + + do { + ret = vde_send(s->vde, (const char *)buf, size, 0); + } while (ret < 0 && errno == EINTR); + + return ret; } static void vde_cleanup(VLANClientState *vc) @@ -1235,7 +1463,7 @@ static int net_vde_init(VLANState *vlan, const char *model, free(s); return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_receive, NULL, vde_cleanup, s); qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", @@ -1263,21 +1491,22 @@ typedef struct NetSocketListenState { } NetSocketListenState; /* XXX: we consider we can send the whole packet without blocking */ -static void net_socket_receive(void *opaque, const uint8_t *buf, int size) +static ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - NetSocketState *s = opaque; + NetSocketState *s = vc->opaque; uint32_t len; len = htonl(size); send_all(s->fd, (const uint8_t *)&len, sizeof(len)); - send_all(s->fd, buf, size); + return send_all(s->fd, buf, size); } -static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size) +static ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size) { - NetSocketState *s = opaque; - sendto(s->fd, buf, size, 0, - (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); + NetSocketState *s = vc->opaque; + + return sendto(s->fd, buf, size, 0, + (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); } static void net_socket_send(void *opaque) @@ -1473,7 +1702,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive_dgram, NULL, net_socket_cleanup, s); qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); @@ -1501,7 +1730,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, NetSocketState *s; s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, + s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive, NULL, net_socket_cleanup, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); @@ -1714,16 +1943,16 @@ struct pcap_sf_pkthdr { uint32_t len; }; -static void dump_receive(void *opaque, const uint8_t *buf, int size) +static ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size) { - DumpState *s = opaque; + DumpState *s = vc->opaque; struct pcap_sf_pkthdr hdr; int64_t ts; int caplen; /* Early return in case of previous error. */ if (s->fd < 0) { - return; + return size; } ts = muldiv64(qemu_get_clock(vm_clock), 1000000, ticks_per_sec); @@ -1739,6 +1968,8 @@ static void dump_receive(void *opaque, const uint8_t *buf, int size) close(s->fd); s->fd = -1; } + + return size; } static void net_dump_cleanup(VLANClientState *vc) @@ -1749,7 +1980,7 @@ static void net_dump_cleanup(VLANClientState *vc) qemu_free(s); } -static int net_dump_init(VLANState *vlan, const char *device, +static int net_dump_init(Monitor *mon, VLANState *vlan, const char *device, const char *name, const char *filename, int len) { struct pcap_file_hdr hdr; @@ -1759,7 +1990,7 @@ static int net_dump_init(VLANState *vlan, const char *device, s->fd = open(filename, O_CREAT | O_WRONLY, 0644); if (s->fd < 0) { - fprintf(stderr, "-net dump: can't open %s\n", filename); + config_error(mon, "-net dump: can't open %s\n", filename); return -1; } @@ -1774,13 +2005,13 @@ static int net_dump_init(VLANState *vlan, const char *device, hdr.linktype = 1; if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { - perror("-net dump write error"); + config_error(mon, "-net dump write error: %s\n", strerror(errno)); close(s->fd); qemu_free(s); return -1; } - s->pcap_vc = qemu_new_vlan_client(vlan, device, name, dump_receive, NULL, + s->pcap_vc = qemu_new_vlan_client(vlan, device, name, NULL, dump_receive, NULL, net_dump_cleanup, s); snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), "dump to %s (len=%d)", filename, len); @@ -1849,7 +2080,7 @@ void qemu_check_nic_model_list(NICInfo *nd, const char * const *models, exit(exit_status); } -int net_client_init(const char *device, const char *p) +int net_client_init(Monitor *mon, const char *device, const char *p) { static const char * const fd_params[] = { "vlan", "name", "fd", NULL @@ -1866,7 +2097,7 @@ int net_client_init(const char *device, const char *p) vlan = qemu_find_vlan(vlan_id); if (get_param_value(buf, sizeof(buf), "name", p)) { - name = strdup(buf); + name = qemu_strdup(buf); } if (!strcmp(device, "nic")) { static const char * const nic_params[] = { @@ -1876,12 +2107,13 @@ int net_client_init(const char *device, const char *p) uint8_t *macaddr; int idx = nic_get_free_idx(); - if (check_params(nic_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(buf, sizeof(buf), nic_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (idx == -1 || nb_nics >= MAX_NICS) { - fprintf(stderr, "Too Many NICs\n"); + config_error(mon, "Too Many NICs\n"); ret = -1; goto out; } @@ -1896,7 +2128,7 @@ int net_client_init(const char *device, const char *p) if (get_param_value(buf, sizeof(buf), "macaddr", p)) { if (parse_macaddr(macaddr, buf) < 0) { - fprintf(stderr, "invalid syntax for ethernet address\n"); + config_error(mon, "invalid syntax for ethernet address\n"); ret = -1; goto out; } @@ -1914,8 +2146,9 @@ int net_client_init(const char *device, const char *p) } else if (!strcmp(device, "none")) { if (*p != '\0') { - fprintf(stderr, "qemu: 'none' takes no parameters\n"); - return -1; + config_error(mon, "'none' takes no parameters\n"); + ret = -1; + goto out; } /* does nothing. It is needed to signal that no network cards are wanted */ @@ -1926,21 +2159,26 @@ int net_client_init(const char *device, const char *p) static const char * const slirp_params[] = { "vlan", "name", "hostname", "restrict", "ip", NULL }; - if (check_params(slirp_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + int restricted = 0; + char *ip = NULL; + + if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (get_param_value(buf, sizeof(buf), "hostname", p)) { pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); } if (get_param_value(buf, sizeof(buf), "restrict", p)) { - slirp_restrict = (buf[0] == 'y') ? 1 : 0; + restricted = (buf[0] == 'y') ? 1 : 0; } if (get_param_value(buf, sizeof(buf), "ip", p)) { - slirp_ip = strdup(buf); + ip = qemu_strdup(buf); } vlan->nb_host_devs++; - ret = net_slirp_init(vlan, device, name); + ret = net_slirp_init(vlan, device, name, restricted, ip); + qemu_free(ip); } else if (!strcmp(device, "channel")) { long port; char name[20], *devname; @@ -1949,7 +2187,7 @@ int net_client_init(const char *device, const char *p) port = strtol(p, &devname, 10); devname++; if (port < 1 || port > 65535) { - fprintf(stderr, "vmchannel wrong port number\n"); + config_error(mon, "vmchannel wrong port number\n"); ret = -1; goto out; } @@ -1957,8 +2195,8 @@ int net_client_init(const char *device, const char *p) snprintf(name, 20, "vmchannel%ld", port); vmc->hd = qemu_chr_open(name, devname, NULL); if (!vmc->hd) { - fprintf(stderr, "qemu: could not open vmchannel device" - "'%s'\n", devname); + config_error(mon, "could not open vmchannel device '%s'\n", + devname); ret = -1; goto out; } @@ -1976,12 +2214,13 @@ int net_client_init(const char *device, const char *p) }; char ifname[64]; - if (check_params(tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(buf, sizeof(buf), tap_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { - fprintf(stderr, "tap: no interface name\n"); + config_error(mon, "tap: no interface name\n"); ret = -1; goto out; } @@ -1991,14 +2230,15 @@ int net_client_init(const char *device, const char *p) #elif defined (_AIX) #else if (!strcmp(device, "tap")) { - char ifname[64]; + char ifname[64], chkbuf[64]; char setup_script[1024], down_script[1024]; int fd; vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - if (check_params(fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } fd = strtol(buf, NULL, 0); fcntl(fd, F_SETFL, O_NONBLOCK); @@ -2008,9 +2248,10 @@ int net_client_init(const char *device, const char *p) static const char * const tap_params[] = { "vlan", "name", "ifname", "script", "downscript", NULL }; - if (check_params(tap_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) { ifname[0] = '\0'; @@ -2026,11 +2267,13 @@ int net_client_init(const char *device, const char *p) } else #endif if (!strcmp(device, "socket")) { + char chkbuf[64]; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; - if (check_params(fd_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } fd = strtol(buf, NULL, 0); ret = -1; @@ -2040,31 +2283,34 @@ int net_client_init(const char *device, const char *p) static const char * const listen_params[] = { "vlan", "name", "listen", NULL }; - if (check_params(listen_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_listen_init(vlan, device, name, buf); } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { static const char * const connect_params[] = { "vlan", "name", "connect", NULL }; - if (check_params(connect_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_connect_init(vlan, device, name, buf); } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) { static const char * const mcast_params[] = { "vlan", "name", "mcast", NULL }; - if (check_params(mcast_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p); + ret = -1; + goto out; } ret = net_socket_mcast_init(vlan, device, name, buf); } else { - fprintf(stderr, "Unknown socket options: %s\n", p); + config_error(mon, "Unknown socket options: %s\n", p); ret = -1; goto out; } @@ -2078,9 +2324,10 @@ int net_client_init(const char *device, const char *p) char vde_sock[1024], vde_group[512]; int vde_port, vde_mode; - if (check_params(vde_params, p) < 0) { - fprintf(stderr, "qemu: invalid parameter in '%s'\n", p); - return -1; + if (check_params(buf, sizeof(buf), vde_params, p) < 0) { + config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p); + ret = -1; + goto out; } vlan->nb_host_devs++; if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) { @@ -2111,18 +2358,17 @@ int net_client_init(const char *device, const char *p) if (!get_param_value(buf, sizeof(buf), "file", p)) { snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id); } - ret = net_dump_init(vlan, device, name, buf, len); + ret = net_dump_init(mon, vlan, device, name, buf, len); } else { - fprintf(stderr, "Unknown network device: %s\n", device); + config_error(mon, "Unknown network device: %s\n", device); ret = -1; goto out; } if (ret < 0) { - fprintf(stderr, "Could not initialize device '%s'\n", device); + config_error(mon, "Could not initialize device '%s'\n", device); } out: - if (name) - free(name); + qemu_free(name); return ret; } @@ -2160,7 +2406,7 @@ void net_host_device_add(Monitor *mon, const char *device, const char *opts) monitor_printf(mon, "invalid host network device %s\n", device); return; } - if (net_client_init(device, opts ? opts : "") < 0) { + if (net_client_init(mon, device, opts ? opts : "") < 0) { monitor_printf(mon, "adding host network device %s failed\n", device); } } @@ -2206,7 +2452,7 @@ int net_client_parse(const char *str) if (*p == ',') p++; - return net_client_init(device, p); + return net_client_init(NULL, device, p); } void do_info_network(Monitor *mon) @@ -5,19 +5,20 @@ /* VLANs support */ -typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); - 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 (LinkStatusChanged)(VLANClientState *); struct VLANClientState { - IOReadHandler *fd_read; - IOReadvHandler *fd_readv; + NetReceive *receive; + NetReceiveIOV *receive_iov; /* Packets may still be sent if this returns zero. It's used to rate-limit the slirp code. */ - IOCanRWHandler *fd_can_read; + NetCanReceive *can_receive; NetCleanup *cleanup; LinkStatusChanged *link_status_changed; int link_down; @@ -31,10 +32,13 @@ struct VLANClientState { typedef struct VLANPacket VLANPacket; +typedef void (NetPacketSent) (VLANClientState *); + struct VLANPacket { struct VLANPacket *next; VLANClientState *sender; int size; + NetPacketSent *sent_cb; uint8_t data[0]; }; @@ -51,8 +55,9 @@ VLANState *qemu_find_vlan(int id); VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *model, const char *name, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque); 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); ssize_t qemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, 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); +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_check_nic_model(NICInfo *nd, const char *model); 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); /* 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); int net_client_parse(const char *str); 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); VLANClientState *qdev_get_vlan_client(DeviceState *dev, - IOReadHandler *fd_read, - IOCanRWHandler *fd_can_read, + NetCanReceive *can_receive, + NetReceive *receive, + NetReceiveIOV *receive_iov, NetCleanup *cleanup, void *opaque); @@ -131,7 +131,7 @@ static void qemu_announce_self_once(void *opaque) len = announce_self_create(buf, nd_table[i].macaddr); vlan = nd_table[i].vlan; for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - vc->fd_read(vc->opaque, buf, len); + vc->receive(vc, buf, len); } } if (count--) { diff --git a/slirp/libslirp.h b/slirp/libslirp.h index b2313b43c6..d0df24b2af 100644 --- a/slirp/libslirp.h +++ b/slirp/libslirp.h @@ -5,7 +5,7 @@ extern "C" { #endif -void slirp_init(int restricted, char *special_ip); +void slirp_init(int restricted, const char *special_ip); void slirp_select_fill(int *pnfds, fd_set *readfds, fd_set *writefds, fd_set *xfds); diff --git a/slirp/slirp.c b/slirp/slirp.c index 9cab73124e..30d4ee2d26 100644 --- a/slirp/slirp.c +++ b/slirp/slirp.c @@ -171,7 +171,7 @@ static void slirp_cleanup(void) static void slirp_state_save(QEMUFile *f, void *opaque); 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); @@ -270,7 +270,8 @@ void usb_info(Monitor *mon); int get_param_value(char *buf, int buf_size, 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); diff --git a/tap-win32.c b/tap-win32.c index 3ff957fe69..ba93355a74 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -650,11 +650,11 @@ static void tap_cleanup(VLANClientState *vc) 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) @@ -684,7 +684,7 @@ int tap_win32_init(VLANState *vlan, const char *model, 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); snprintf(s->vc->info_str, sizeof(s->vc->info_str), @@ -1836,45 +1836,34 @@ int get_param_value(char *buf, int buf_size, 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; - char *name_buf; - 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); + int i; p = str; while (*p != '\0') { - p = get_opt_name(name_buf, name_buf_size, p, '='); + p = get_opt_name(buf, buf_size, p, '='); if (*p != '=') { - ret = -1; - break; + return -1; } p++; - for(i = 0; params[i] != NULL; i++) - if (!strcmp(params[i], name_buf)) + for (i = 0; params[i] != NULL; i++) { + if (!strcmp(params[i], buf)) { break; + } + } if (params[i] == NULL) { - ret = -1; - break; + return -1; } p = get_opt_value(NULL, 0, p); - if (*p != ',') + if (*p != ',') { break; + } p++; } - - qemu_free(name_buf); - return ret; + return 0; } /***********************************************************/ @@ -2227,8 +2216,9 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) "cache", "format", "serial", "werror", NULL }; - if (check_params(params, str) < 0) { - fprintf(stderr, "qemu: unknown parameter in '%s'\n", str); + if (check_params(buf, sizeof(buf), params, str) < 0) { + fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", + buf, str); return -1; } @@ -2709,7 +2699,7 @@ static int usb_device_add(const char *devname, int is_hotplug) } else if (strstart(devname, "net:", &p)) { int nic = nb_nics; - if (net_client_init("nic", p) < 0) + if (net_client_init(NULL, "nic", p) < 0) return -1; nd_table[nic].model = "usb"; dev = usb_net_init(&nd_table[nic]); @@ -4783,7 +4773,12 @@ static void termsig_handler(int signal) 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; @@ -4792,6 +4787,10 @@ static void termsig_setup(void) sigaction(SIGINT, &act, NULL); sigaction(SIGHUP, &act, NULL); sigaction(SIGTERM, &act, NULL); + + act.sa_handler = sigchld_handler; + act.sa_flags = SA_NOCLDSTOP; + sigaction(SIGCHLD, &act, NULL); } #endif @@ -5920,7 +5919,7 @@ int main(int argc, char **argv, char **envp) #ifndef _WIN32 /* must be after terminal init, SDL library changes signal handlers */ - termsig_setup(); + sighandler_setup(); #endif /* Maintain compatibility with multiple stdio monitors */ |