summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2009-06-10 18:05:55 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2009-06-10 18:08:35 -0500
commit99467f1c885933e3aeac70dea16278b83172f563 (patch)
treec67bf81b0bfa6b897f4fb7a236962a85819e15f7
parentcf9b3cc0aaa862130ff9680c0030cd304e70994d (diff)
parent6f6a1c5e306a6405c488d7d9b138d41e14333dc6 (diff)
downloadqemu-99467f1c885933e3aeac70dea16278b83172f563.tar.gz
qemu-99467f1c885933e3aeac70dea16278b83172f563.tar.bz2
qemu-99467f1c885933e3aeac70dea16278b83172f563.zip
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.c22
-rw-r--r--hw/e1000.c30
-rw-r--r--hw/eepro100.c23
-rw-r--r--hw/etraxfs_eth.c14
-rw-r--r--hw/mcf_fec.c11
-rw-r--r--hw/mipsnet.c16
-rw-r--r--hw/musicpal.c11
-rw-r--r--hw/ne2000.c25
-rw-r--r--hw/pci-hotplug.c7
-rw-r--r--hw/pcnet.c17
-rw-r--r--hw/qdev.c9
-rw-r--r--hw/rtl8139.c39
-rw-r--r--hw/smc91c111.c18
-rw-r--r--hw/stellaris_enet.c20
-rw-r--r--hw/usb-net.c18
-rw-r--r--hw/virtio-net.c154
-rw-r--r--hw/virtio-net.h14
-rw-r--r--hw/xen_nic.c26
-rw-r--r--net.c708
-rw-r--r--net.h31
-rw-r--r--savevm.c2
-rw-r--r--slirp/libslirp.h2
-rw-r--r--slirp/slirp.c2
-rw-r--r--sysemu.h3
-rw-r--r--tap-win32.c8
-rw-r--r--vl.c57
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);
diff --git a/hw/qdev.c b/hw/qdev.c
index 636dc78e59..d23298ca08 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -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);
diff --git a/net.c b/net.c
index 2d24a7ce5f..4cf27be99c 100644
--- a/net.c
+++ b/net.c
@@ -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)
diff --git a/net.h b/net.h
index feee021f78..89e7706be4 100644
--- a/net.h
+++ b/net.h
@@ -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);
diff --git a/savevm.c b/savevm.c
index 248aea3edf..cae711762d 100644
--- a/savevm.c
+++ b/savevm.c
@@ -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);
diff --git a/sysemu.h b/sysemu.h
index 658aeec0b0..e5e5ba0603 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -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),
diff --git a/vl.c b/vl.c
index 69a9f918ca..bdd78cf8ea 100644
--- a/vl.c
+++ b/vl.c
@@ -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 */