diff --git a/hw/net/allwinner-sun8i-emac.c b/hw/net/allwinner-sun8i-emac.c index 3fc5e34640..28637ff4c1 100644 --- a/hw/net/allwinner-sun8i-emac.c +++ b/hw/net/allwinner-sun8i-emac.c @@ -395,7 +395,7 @@ static void allwinner_sun8i_emac_flush_desc(FrameDescriptor *desc, cpu_physical_memory_write(phys_addr, desc, sizeof(*desc)); } -static int allwinner_sun8i_emac_can_receive(NetClientState *nc) +static bool allwinner_sun8i_emac_can_receive(NetClientState *nc) { AwSun8iEmacState *s = qemu_get_nic_opaque(nc); FrameDescriptor desc; @@ -611,10 +611,10 @@ static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset, value = s->mii_data; break; case REG_ADDR_HIGH: /* MAC Address High */ - value = *(((uint32_t *) (s->conf.macaddr.a)) + 1); + value = lduw_le_p(s->conf.macaddr.a + 4); break; case REG_ADDR_LOW: /* MAC Address Low */ - value = *(uint32_t *) (s->conf.macaddr.a); + value = ldl_le_p(s->conf.macaddr.a); break; case REG_TX_DMA_STA: /* Transmit DMA Status */ break; @@ -728,14 +728,10 @@ static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset, s->mii_data = value; break; case REG_ADDR_HIGH: /* MAC Address High */ - s->conf.macaddr.a[4] = (value & 0xff); - s->conf.macaddr.a[5] = (value & 0xff00) >> 8; + stw_le_p(s->conf.macaddr.a + 4, value); break; case REG_ADDR_LOW: /* MAC Address Low */ - s->conf.macaddr.a[0] = (value & 0xff); - s->conf.macaddr.a[1] = (value & 0xff00) >> 8; - s->conf.macaddr.a[2] = (value & 0xff0000) >> 16; - s->conf.macaddr.a[3] = (value & 0xff000000) >> 24; + stl_le_p(s->conf.macaddr.a, value); break; case REG_TX_DMA_STA: /* Transmit DMA Status */ case REG_TX_CUR_DESC: /* Transmit Current Descriptor */ diff --git a/hw/net/allwinner_emac.c b/hw/net/allwinner_emac.c index e9bbff8710..ddddf35c45 100644 --- a/hw/net/allwinner_emac.c +++ b/hw/net/allwinner_emac.c @@ -178,7 +178,7 @@ static uint32_t fifo8_pop_word(Fifo8 *fifo) return ret; } -static int aw_emac_can_receive(NetClientState *nc) +static bool aw_emac_can_receive(NetClientState *nc) { AwEmacState *s = qemu_get_nic_opaque(nc); diff --git a/hw/net/cadence_gem.c b/hw/net/cadence_gem.c index 6340c1eaf8..51ec5a072d 100644 --- a/hw/net/cadence_gem.c +++ b/hw/net/cadence_gem.c @@ -505,7 +505,7 @@ static void phy_update_link(CadenceGEMState *s) } } -static int gem_can_receive(NetClientState *nc) +static bool gem_can_receive(NetClientState *nc) { CadenceGEMState *s; int i; @@ -518,7 +518,7 @@ static int gem_can_receive(NetClientState *nc) s->can_rx_state = 1; DB_PRINT("can't receive - no enable\n"); } - return 0; + return false; } for (i = 0; i < s->num_priority_queues; i++) { @@ -532,14 +532,14 @@ static int gem_can_receive(NetClientState *nc) s->can_rx_state = 2; DB_PRINT("can't receive - all the buffer descriptors are busy\n"); } - return 0; + return false; } if (s->can_rx_state != 0) { s->can_rx_state = 0; DB_PRINT("can receive\n"); } - return 1; + return true; } /* diff --git a/hw/net/can/can_sja1000.c b/hw/net/can/can_sja1000.c index 39c78faf9b..ea915a023a 100644 --- a/hw/net/can/can_sja1000.c +++ b/hw/net/can/can_sja1000.c @@ -733,21 +733,21 @@ uint64_t can_sja_mem_read(CanSJA1000State *s, hwaddr addr, unsigned size) return temp; } -int can_sja_can_receive(CanBusClientState *client) +bool can_sja_can_receive(CanBusClientState *client) { CanSJA1000State *s = container_of(client, CanSJA1000State, bus_client); if (s->clock & 0x80) { /* PeliCAN Mode */ if (s->mode & 0x01) { /* reset mode. */ - return 0; + return false; } } else { /* BasicCAN mode */ if (s->control & 0x01) { - return 0; + return false; } } - return 1; /* always return 1, when operation mode */ + return true; /* always return true, when operation mode */ } ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames, diff --git a/hw/net/can/can_sja1000.h b/hw/net/can/can_sja1000.h index 220a622087..7ca9cd681e 100644 --- a/hw/net/can/can_sja1000.h +++ b/hw/net/can/can_sja1000.h @@ -137,7 +137,7 @@ void can_sja_disconnect(CanSJA1000State *s); int can_sja_init(CanSJA1000State *s, qemu_irq irq); -int can_sja_can_receive(CanBusClientState *client); +bool can_sja_can_receive(CanBusClientState *client); ssize_t can_sja_receive(CanBusClientState *client, const qemu_can_frame *frames, size_t frames_cnt); diff --git a/hw/net/dp8393x.c b/hw/net/dp8393x.c index 1563c11b9e..c54db0d62d 100644 --- a/hw/net/dp8393x.c +++ b/hw/net/dp8393x.c @@ -414,7 +414,7 @@ static void dp8393x_do_stop_timer(dp8393xState *s) dp8393x_update_wt_regs(s); } -static int dp8393x_can_receive(NetClientState *nc); +static bool dp8393x_can_receive(NetClientState *nc); static void dp8393x_do_receiver_enable(dp8393xState *s) { @@ -718,13 +718,11 @@ static void dp8393x_watchdog(void *opaque) dp8393x_update_irq(s); } -static int dp8393x_can_receive(NetClientState *nc) +static bool dp8393x_can_receive(NetClientState *nc) { dp8393xState *s = qemu_get_nic_opaque(nc); - if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN)) - return 0; - return 1; + return !!(s->regs[SONIC_CR] & SONIC_CR_RXEN); } static int dp8393x_receive_filter(dp8393xState *s, const uint8_t * buf, diff --git a/hw/net/e1000.c b/hw/net/e1000.c index 9233248c9a..2a69eee63f 100644 --- a/hw/net/e1000.c +++ b/hw/net/e1000.c @@ -845,7 +845,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t total_size) return total_size <= bufs * s->rxbuf_size; } -static int +static bool e1000_can_receive(NetClientState *nc) { E1000State *s = qemu_get_nic_opaque(nc); diff --git a/hw/net/e1000e.c b/hw/net/e1000e.c index a91dbdca3c..79ba158d41 100644 --- a/hw/net/e1000e.c +++ b/hw/net/e1000e.c @@ -199,7 +199,7 @@ static const MemoryRegionOps io_ops = { }, }; -static int +static bool e1000e_nc_can_receive(NetClientState *nc) { E1000EState *s = qemu_get_nic_opaque(nc); @@ -328,7 +328,7 @@ e1000e_init_net_peer(E1000EState *s, PCIDevice *pci_dev, uint8_t *macaddr) s->nic = qemu_new_nic(&net_e1000e_info, &s->conf, object_get_typename(OBJECT(s)), dev->id, s); - s->core.max_queue_num = s->conf.peers.queues - 1; + s->core.max_queue_num = s->conf.peers.queues ? s->conf.peers.queues - 1 : 0; trace_e1000e_mac_set_permanent(MAC_ARG(macaddr)); memcpy(s->core.permanent_mac, macaddr, sizeof(s->core.permanent_mac)); diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c index df957e0c1a..d5676871fa 100644 --- a/hw/net/e1000e_core.c +++ b/hw/net/e1000e_core.c @@ -967,7 +967,7 @@ e1000e_start_recv(E1000ECore *core) } } -int +bool e1000e_can_receive(E1000ECore *core) { int i; diff --git a/hw/net/e1000e_core.h b/hw/net/e1000e_core.h index 49abb136dd..aee32f7e48 100644 --- a/hw/net/e1000e_core.h +++ b/hw/net/e1000e_core.h @@ -143,7 +143,7 @@ e1000e_core_set_link_status(E1000ECore *core); void e1000e_core_pci_uninit(E1000ECore *core); -int +bool e1000e_can_receive(E1000ECore *core); ssize_t diff --git a/hw/net/ftgmac100.c b/hw/net/ftgmac100.c index 2f92b65d4e..041ed21017 100644 --- a/hw/net/ftgmac100.c +++ b/hw/net/ftgmac100.c @@ -562,18 +562,18 @@ static void ftgmac100_do_tx(FTGMAC100State *s, uint32_t tx_ring, ftgmac100_update_irq(s); } -static int ftgmac100_can_receive(NetClientState *nc) +static bool ftgmac100_can_receive(NetClientState *nc) { FTGMAC100State *s = FTGMAC100(qemu_get_nic_opaque(nc)); FTGMAC100Desc bd; if ((s->maccr & (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) != (FTGMAC100_MACCR_RXDMA_EN | FTGMAC100_MACCR_RXMAC_EN)) { - return 0; + return false; } if (ftgmac100_read_bd(&bd, s->rx_descriptor)) { - return 0; + return false; } return !(bd.des0 & FTGMAC100_RXDES0_RXPKT_RDY); } diff --git a/hw/net/i82596.c b/hw/net/i82596.c index fe9f2390a9..055c3a1470 100644 --- a/hw/net/i82596.c +++ b/hw/net/i82596.c @@ -43,6 +43,9 @@ #define SCB_STATUS_CNA 0x2000 /* CU left active state */ #define SCB_STATUS_RNR 0x1000 /* RU left active state */ +#define SCB_COMMAND_ACK_MASK \ + (SCB_STATUS_CX | SCB_STATUS_FR | SCB_STATUS_CNA | SCB_STATUS_RNR) + #define CU_IDLE 0 #define CU_SUSPENDED 1 #define CU_ACTIVE 2 @@ -348,14 +351,7 @@ static void examine_scb(I82596State *s) /* and clear the scb command word */ set_uint16(s->scb + 2, 0); - if (command & BIT(31)) /* ACK-CX */ - s->scb_status &= ~SCB_STATUS_CX; - if (command & BIT(30)) /*ACK-FR */ - s->scb_status &= ~SCB_STATUS_FR; - if (command & BIT(29)) /*ACK-CNA */ - s->scb_status &= ~SCB_STATUS_CNA; - if (command & BIT(28)) /*ACK-RNR */ - s->scb_status &= ~SCB_STATUS_RNR; + s->scb_status &= ~(command & SCB_COMMAND_ACK_MASK); switch (cuc) { case 0: /* no change */ @@ -474,23 +470,23 @@ void i82596_h_reset(void *opaque) i82596_s_reset(s); } -int i82596_can_receive(NetClientState *nc) +bool i82596_can_receive(NetClientState *nc) { I82596State *s = qemu_get_nic_opaque(nc); if (s->rx_status == RX_SUSPENDED) { - return 0; + return false; } if (!s->lnkst) { - return 0; + return false; } if (USE_TIMER && !timer_pending(s->flush_queue_timer)) { - return 1; + return true; } - return 1; + return true; } #define MIN_BUF_SIZE 60 @@ -501,7 +497,8 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz) uint32_t rfd_p; uint32_t rbd; uint16_t is_broadcast = 0; - size_t len = sz; + size_t len = sz; /* length of data for guest (including CRC) */ + size_t bufsz = sz; /* length of data in buf */ uint32_t crc; uint8_t *crc_ptr; uint8_t buf1[MIN_BUF_SIZE + VLAN_HLEN]; @@ -595,6 +592,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz) if (len < MIN_BUF_SIZE) { len = MIN_BUF_SIZE; } + bufsz = len; } /* Calculate the ethernet checksum (4 bytes) */ @@ -627,6 +625,7 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz) while (len) { uint16_t buffer_size, num; uint32_t rba; + size_t bufcount, crccount; /* printf("Receive: rbd is %08x\n", rbd); */ buffer_size = get_uint16(rbd + 12); @@ -639,14 +638,37 @@ ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t sz) } rba = get_uint32(rbd + 8); /* printf("rba is 0x%x\n", rba); */ - address_space_write(&address_space_memory, rba, - MEMTXATTRS_UNSPECIFIED, buf, num); - rba += num; - buf += num; - len -= num; - if (len == 0) { /* copy crc */ - address_space_write(&address_space_memory, rba - 4, - MEMTXATTRS_UNSPECIFIED, crc_ptr, 4); + /* + * Calculate how many bytes we want from buf[] and how many + * from the CRC. + */ + if ((len - num) >= 4) { + /* The whole guest buffer, we haven't hit the CRC yet */ + bufcount = num; + } else { + /* All that's left of buf[] */ + bufcount = len - 4; + } + crccount = num - bufcount; + + if (bufcount > 0) { + /* Still some of the actual data buffer to transfer */ + assert(bufsz >= bufcount); + bufsz -= bufcount; + address_space_write(&address_space_memory, rba, + MEMTXATTRS_UNSPECIFIED, buf, bufcount); + rba += bufcount; + buf += bufcount; + len -= bufcount; + } + + /* Write as much of the CRC as fits */ + if (crccount > 0) { + address_space_write(&address_space_memory, rba, + MEMTXATTRS_UNSPECIFIED, crc_ptr, crccount); + rba += crccount; + crc_ptr += crccount; + len -= crccount; } num |= 0x4000; /* set F BIT */ diff --git a/hw/net/i82596.h b/hw/net/i82596.h index 1238ac11f8..f0bbe810eb 100644 --- a/hw/net/i82596.h +++ b/hw/net/i82596.h @@ -48,7 +48,7 @@ void i82596_ioport_writel(void *opaque, uint32_t addr, uint32_t val); uint32_t i82596_ioport_readl(void *opaque, uint32_t addr); uint32_t i82596_bcr_readw(I82596State *s, uint32_t rap); ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t size_); -int i82596_can_receive(NetClientState *nc); +bool i82596_can_receive(NetClientState *nc); void i82596_set_link_status(NetClientState *nc); void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info); extern const VMStateDescription vmstate_i82596; diff --git a/hw/net/imx_fec.c b/hw/net/imx_fec.c index 5c145a8197..a35c33683e 100644 --- a/hw/net/imx_fec.c +++ b/hw/net/imx_fec.c @@ -1049,7 +1049,7 @@ static void imx_eth_write(void *opaque, hwaddr offset, uint64_t value, imx_eth_update(s); } -static int imx_eth_can_receive(NetClientState *nc) +static bool imx_eth_can_receive(NetClientState *nc) { IMXFECState *s = IMX_FEC(qemu_get_nic_opaque(nc)); diff --git a/hw/net/opencores_eth.c b/hw/net/opencores_eth.c index 6b338c2f29..2ba0dc8c2f 100644 --- a/hw/net/opencores_eth.c +++ b/hw/net/opencores_eth.c @@ -349,12 +349,11 @@ static void open_eth_reset(void *opaque) open_eth_set_link_status(qemu_get_queue(s->nic)); } -static int open_eth_can_receive(NetClientState *nc) +static bool open_eth_can_receive(NetClientState *nc) { OpenEthState *s = qemu_get_nic_opaque(nc); - return GET_REGBIT(s, MODER, RXEN) && - (s->regs[TX_BD_NUM] < 0x80); + return GET_REGBIT(s, MODER, RXEN) && (s->regs[TX_BD_NUM] < 0x80); } static ssize_t open_eth_receive(NetClientState *nc, diff --git a/hw/net/rtl8139.c b/hw/net/rtl8139.c index ae4739bc09..70aca7ec26 100644 --- a/hw/net/rtl8139.c +++ b/hw/net/rtl8139.c @@ -793,26 +793,28 @@ static bool rtl8139_cp_rx_valid(RTL8139State *s) return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0); } -static int rtl8139_can_receive(NetClientState *nc) +static bool rtl8139_can_receive(NetClientState *nc) { RTL8139State *s = qemu_get_nic_opaque(nc); int avail; /* Receive (drop) packets if card is disabled. */ - if (!s->clock_enabled) - return 1; - if (!rtl8139_receiver_enabled(s)) - return 1; + if (!s->clock_enabled) { + return true; + } + if (!rtl8139_receiver_enabled(s)) { + return true; + } if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) { /* ??? Flow control not implemented in c+ mode. This is a hack to work around slirp deficiencies anyway. */ - return 1; - } else { - avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, - s->RxBufferSize); - return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow)); + return true; } + + avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, + s->RxBufferSize); + return avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow); } static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt) diff --git a/hw/net/smc91c111.c b/hw/net/smc91c111.c index e9eb6f6c05..b3240b9335 100644 --- a/hw/net/smc91c111.c +++ b/hw/net/smc91c111.c @@ -130,16 +130,16 @@ static void smc91c111_update(smc91c111_state *s) qemu_set_irq(s->irq, level); } -static int smc91c111_can_receive(smc91c111_state *s) +static bool smc91c111_can_receive(smc91c111_state *s) { if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST)) { - return 1; + return true; } if (s->allocated == (1 << NUM_PACKETS) - 1 || s->rx_fifo_len == NUM_PACKETS) { - return 0; + return false; } - return 1; + return true; } static inline void smc91c111_flush_queued_packets(smc91c111_state *s) @@ -667,7 +667,7 @@ static void smc91c111_writefn(void *opaque, hwaddr addr, } } -static int smc91c111_can_receive_nc(NetClientState *nc) +static bool smc91c111_can_receive_nc(NetClientState *nc) { smc91c111_state *s = qemu_get_nic_opaque(nc); diff --git a/hw/net/spapr_llan.c b/hw/net/spapr_llan.c index 80f5a1dd37..a2377025a7 100644 --- a/hw/net/spapr_llan.c +++ b/hw/net/spapr_llan.c @@ -110,11 +110,11 @@ typedef struct SpaprVioVlan { RxBufPool *rx_pool[RX_MAX_POOLS]; /* Receive buffer descriptor pools */ } SpaprVioVlan; -static int spapr_vlan_can_receive(NetClientState *nc) +static bool spapr_vlan_can_receive(NetClientState *nc) { SpaprVioVlan *dev = qemu_get_nic_opaque(nc); - return (dev->isopen && dev->rx_bufs > 0); + return dev->isopen && dev->rx_bufs > 0; } /** diff --git a/hw/net/sungem.c b/hw/net/sungem.c index 89da51f7f6..b01197d952 100644 --- a/hw/net/sungem.c +++ b/hw/net/sungem.c @@ -433,7 +433,7 @@ static bool sungem_rx_full(SunGEMState *s, uint32_t kick, uint32_t done) return kick == ((done + 1) & s->rx_mask); } -static int sungem_can_receive(NetClientState *nc) +static bool sungem_can_receive(NetClientState *nc) { SunGEMState *s = qemu_get_nic_opaque(nc); uint32_t kick, done, rxdma_cfg, rxmac_cfg; @@ -445,11 +445,11 @@ static int sungem_can_receive(NetClientState *nc) /* If MAC disabled, can't receive */ if ((rxmac_cfg & MAC_RXCFG_ENAB) == 0) { trace_sungem_rx_mac_disabled(); - return 0; + return false; } if ((rxdma_cfg & RXDMA_CFG_ENABLE) == 0) { trace_sungem_rx_txdma_disabled(); - return 0; + return false; } /* Check RX availability */ diff --git a/hw/net/sunhme.c b/hw/net/sunhme.c index 8863601f6c..9c38583180 100644 --- a/hw/net/sunhme.c +++ b/hw/net/sunhme.c @@ -657,11 +657,11 @@ static void sunhme_transmit(SunHMEState *s) sunhme_update_irq(s); } -static int sunhme_can_receive(NetClientState *nc) +static bool sunhme_can_receive(NetClientState *nc) { SunHMEState *s = qemu_get_nic_opaque(nc); - return s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE; + return !!(s->macregs[HME_MACI_RXCFG >> 2] & HME_MAC_RXCFG_ENABLE); } static void sunhme_link_status_changed(NetClientState *nc) diff --git a/hw/net/tulip.c b/hw/net/tulip.c index cfac2719d3..1295f51d07 100644 --- a/hw/net/tulip.c +++ b/hw/net/tulip.c @@ -170,6 +170,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) } else { len = s->rx_frame_len; } + + if (s->rx_frame_len + len > sizeof(s->rx_frame)) { + return; + } pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len); s->rx_frame_len -= len; @@ -181,6 +185,10 @@ static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc) } else { len = s->rx_frame_len; } + + if (s->rx_frame_len + len > sizeof(s->rx_frame)) { + return; + } pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame + (s->rx_frame_size - s->rx_frame_len), len); s->rx_frame_len -= len; @@ -227,7 +235,8 @@ static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size) trace_tulip_receive(buf, size); - if (size < 14 || size > 2048 || s->rx_frame_len || tulip_rx_stopped(s)) { + if (size < 14 || size > sizeof(s->rx_frame) - 4 + || s->rx_frame_len || tulip_rx_stopped(s)) { return 0; } @@ -275,7 +284,6 @@ static ssize_t tulip_receive_nc(NetClientState *nc, return tulip_receive(qemu_get_nic_opaque(nc), buf, size); } - static NetClientInfo net_tulip_info = { .type = NET_CLIENT_DRIVER_NIC, .size = sizeof(NICState), @@ -558,7 +566,7 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc) if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) { /* Internal or external Loopback */ tulip_receive(s, s->tx_frame, s->tx_frame_len); - } else { + } else if (s->tx_frame_len <= sizeof(s->tx_frame)) { qemu_send_packet(qemu_get_queue(s->nic), s->tx_frame, s->tx_frame_len); } @@ -570,23 +578,31 @@ static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc) } } -static void tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) +static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc) { int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK; int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK; + if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) { + return -1; + } if (len1) { pci_dma_read(&s->dev, desc->buf_addr1, s->tx_frame + s->tx_frame_len, len1); s->tx_frame_len += len1; } + if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) { + return -1; + } if (len2) { pci_dma_read(&s->dev, desc->buf_addr2, s->tx_frame + s->tx_frame_len, len2); s->tx_frame_len += len2; } desc->status = (len1 + len2) ? 0 : 0x7fffffff; + + return 0; } static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n) @@ -651,13 +667,15 @@ static uint32_t tulip_ts(TULIPState *s) static void tulip_xmit_list_update(TULIPState *s) { +#define TULIP_DESC_MAX 128 + uint8_t i = 0; struct tulip_descriptor desc; if (tulip_ts(s) != CSR5_TS_SUSPENDED) { return; } - for (;;) { + for (i = 0; i < TULIP_DESC_MAX; i++) { tulip_desc_read(s, s->current_tx_desc, &desc); tulip_dump_tx_descriptor(s, &desc); @@ -675,10 +693,10 @@ static void tulip_xmit_list_update(TULIPState *s) s->tx_frame_len = 0; } - tulip_copy_tx_buffers(s, &desc); - - if (desc.control & TDES1_LS) { - tulip_tx(s, &desc); + if (!tulip_copy_tx_buffers(s, &desc)) { + if (desc.control & TDES1_LS) { + tulip_tx(s, &desc); + } } } tulip_desc_write(s, s->current_tx_desc, &desc); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index 3627bb1717..a46e3b37a7 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1234,26 +1234,26 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) qemu_flush_queued_packets(qemu_get_subqueue(n->nic, queue_index)); } -static int virtio_net_can_receive(NetClientState *nc) +static bool virtio_net_can_receive(NetClientState *nc) { VirtIONet *n = qemu_get_nic_opaque(nc); VirtIODevice *vdev = VIRTIO_DEVICE(n); VirtIONetQueue *q = virtio_net_get_subqueue(nc); if (!vdev->vm_running) { - return 0; + return false; } if (nc->queue_index >= n->curr_queues) { - return 0; + return false; } if (!virtio_queue_ready(q->rx_vq) || !(vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) { - return 0; + return false; } - return 1; + return true; } static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize) diff --git a/hw/net/xilinx_ethlite.c b/hw/net/xilinx_ethlite.c index cf07e698b3..71d16fef3d 100644 --- a/hw/net/xilinx_ethlite.c +++ b/hw/net/xilinx_ethlite.c @@ -175,7 +175,7 @@ static const MemoryRegionOps eth_ops = { } }; -static int eth_can_rx(NetClientState *nc) +static bool eth_can_rx(NetClientState *nc) { struct xlx_ethlite *s = qemu_get_nic_opaque(nc); unsigned int rxbase = s->rxbuf * (0x800 / 4); diff --git a/include/net/can_emu.h b/include/net/can_emu.h index d4fc51b57d..fce9770928 100644 --- a/include/net/can_emu.h +++ b/include/net/can_emu.h @@ -83,7 +83,7 @@ typedef struct CanBusClientState CanBusClientState; typedef struct CanBusState CanBusState; typedef struct CanBusClientInfo { - int (*can_receive)(CanBusClientState *); + bool (*can_receive)(CanBusClientState *); ssize_t (*receive)(CanBusClientState *, const struct qemu_can_frame *frames, size_t frames_cnt); } CanBusClientInfo; diff --git a/include/net/net.h b/include/net/net.h index 094e966af9..39085d9444 100644 --- a/include/net/net.h +++ b/include/net/net.h @@ -42,7 +42,7 @@ typedef struct NICConf { /* Net clients */ typedef void (NetPoll)(NetClientState *, bool enable); -typedef int (NetCanReceive)(NetClientState *); +typedef bool (NetCanReceive)(NetClientState *); typedef ssize_t (NetReceive)(NetClientState *, const uint8_t *, size_t); typedef ssize_t (NetReceiveIOV)(NetClientState *, const struct iovec *, int); typedef void (NetCleanup) (NetClientState *); diff --git a/net/can/can_socketcan.c b/net/can/can_socketcan.c index 29bfacd4f8..807f31fcde 100644 --- a/net/can/can_socketcan.c +++ b/net/can/can_socketcan.c @@ -110,9 +110,9 @@ static void can_host_socketcan_read(void *opaque) } } -static int can_host_socketcan_can_receive(CanBusClientState *client) +static bool can_host_socketcan_can_receive(CanBusClientState *client) { - return 1; + return true; } static ssize_t can_host_socketcan_receive(CanBusClientState *client, diff --git a/net/colo-compare.c b/net/colo-compare.c index 7ee17f2cf8..10c0239f9d 100644 --- a/net/colo-compare.c +++ b/net/colo-compare.c @@ -48,8 +48,8 @@ static NotifierList colo_compare_notifiers = #define COLO_COMPARE_FREE_PRIMARY 0x01 #define COLO_COMPARE_FREE_SECONDARY 0x02 -/* TODO: Should be configurable */ #define REGULAR_PACKET_CHECK_MS 3000 +#define DEFAULT_TIME_OUT_MS 3000 static QemuMutex event_mtx; static QemuCond event_complete_cond; @@ -92,6 +92,8 @@ typedef struct CompareState { SocketReadState sec_rs; SocketReadState notify_rs; bool vnet_hdr; + uint32_t compare_timeout; + uint32_t expired_scan_cycle; /* * Record the connection that through the NIC @@ -607,10 +609,9 @@ static int colo_old_packet_check_one_conn(Connection *conn, CompareState *s) { GList *result = NULL; - int64_t check_time = REGULAR_PACKET_CHECK_MS; result = g_queue_find_custom(&conn->primary_list, - &check_time, + &s->compare_timeout, (GCompareFunc)colo_old_packet_check_one); if (result) { @@ -822,7 +823,7 @@ static void check_old_packet_regular(void *opaque) /* if have old packet we will notify checkpoint */ colo_old_packet_check(s); timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - REGULAR_PACKET_CHECK_MS); + s->expired_scan_cycle); } /* Public API, Used for COLO frame to notify compare event */ @@ -852,7 +853,7 @@ static void colo_compare_timer_init(CompareState *s) SCALE_MS, check_old_packet_regular, s); timer_mod(s->packet_check_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + - REGULAR_PACKET_CHECK_MS); + s->expired_scan_cycle); } static void colo_compare_timer_del(CompareState *s) @@ -984,6 +985,72 @@ static void compare_set_notify_dev(Object *obj, const char *value, Error **errp) s->notify_dev = g_strdup(value); } +static void compare_get_timeout(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + uint32_t value = s->compare_timeout; + + visit_type_uint32(v, name, &value, errp); +} + +static void compare_set_timeout(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + Error *local_err = NULL; + uint32_t value; + + visit_type_uint32(v, name, &value, &local_err); + if (local_err) { + goto out; + } + if (!value) { + error_setg(&local_err, "Property '%s.%s' requires a positive value", + object_get_typename(obj), name); + goto out; + } + s->compare_timeout = value; + +out: + error_propagate(errp, local_err); +} + +static void compare_get_expired_scan_cycle(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + uint32_t value = s->expired_scan_cycle; + + visit_type_uint32(v, name, &value, errp); +} + +static void compare_set_expired_scan_cycle(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + CompareState *s = COLO_COMPARE(obj); + Error *local_err = NULL; + uint32_t value; + + visit_type_uint32(v, name, &value, &local_err); + if (local_err) { + goto out; + } + if (!value) { + error_setg(&local_err, "Property '%s.%s' requires a positive value", + object_get_typename(obj), name); + goto out; + } + s->expired_scan_cycle = value; + +out: + error_propagate(errp, local_err); +} + static void compare_pri_rs_finalize(SocketReadState *pri_rs) { CompareState *s = container_of(pri_rs, CompareState, pri_rs); @@ -1090,6 +1157,16 @@ static void colo_compare_complete(UserCreatable *uc, Error **errp) return; } + if (!s->compare_timeout) { + /* Set default value to 3000 MS */ + s->compare_timeout = DEFAULT_TIME_OUT_MS; + } + + if (!s->expired_scan_cycle) { + /* Set default value to 3000 MS */ + s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS; + } + if (find_and_check_chardev(&chr, s->pri_indev, errp) || !qemu_chr_fe_init(&s->chr_pri_in, chr, errp)) { return; @@ -1185,6 +1262,14 @@ static void colo_compare_init(Object *obj) compare_get_notify_dev, compare_set_notify_dev, NULL); + object_property_add(obj, "compare_timeout", "uint32", + compare_get_timeout, + compare_set_timeout, NULL, NULL, NULL); + + object_property_add(obj, "expired_scan_cycle", "uint32", + compare_get_expired_scan_cycle, + compare_set_expired_scan_cycle, NULL, NULL, NULL); + s->vnet_hdr = false; object_property_add_bool(obj, "vnet_hdr_support", compare_get_vnet_hdr, compare_set_vnet_hdr, NULL); diff --git a/net/filter-buffer.c b/net/filter-buffer.c index 88da78f821..12e0254287 100644 --- a/net/filter-buffer.c +++ b/net/filter-buffer.c @@ -74,7 +74,7 @@ static ssize_t filter_buffer_receive_iov(NetFilterState *nf, * the filter can still accept packets until its internal queue is full. * For example: * For some reason, receiver could not receive more packets - * (.can_receive() returns zero). Without a filter, at most one packet + * (.can_receive() returns false). Without a filter, at most one packet * will be queued in incoming queue and sender's poll will be disabled * unit its sent_cb() was called. With a filter, it will keep receiving * the packets without caring about the receiver. This is suboptimal. diff --git a/net/hub.c b/net/hub.c index 88cfb876f3..1375738bf1 100644 --- a/net/hub.c +++ b/net/hub.c @@ -90,7 +90,7 @@ static NetHub *net_hub_new(int id) return hub; } -static int net_hub_port_can_receive(NetClientState *nc) +static bool net_hub_port_can_receive(NetClientState *nc) { NetHubPort *port; NetHubPort *src_port = DO_UPCAST(NetHubPort, nc, nc); @@ -102,11 +102,11 @@ static int net_hub_port_can_receive(NetClientState *nc) } if (qemu_can_send_packet(&port->nc)) { - return 1; + return true; } } - return 0; + return false; } static ssize_t net_hub_port_receive(NetClientState *nc, diff --git a/qemu-options.hx b/qemu-options.hx index 962a5ebaa6..16debd03cb 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4615,7 +4615,7 @@ SRST stored. The file format is libpcap, so it can be analyzed with tools such as tcpdump or Wireshark. - ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id]`` + ``-object colo-compare,id=id,primary_in=chardevid,secondary_in=chardevid,outdev=chardevid,iothread=id[,vnet_hdr_support][,notify_dev=id][,compare_timeout=@var{ms}][,expired_scan_cycle=@var{ms}`` Colo-compare gets packet from primary\_inchardevid and secondary\_inchardevid, than compare primary packet with secondary packet. If the packets are same, we will output @@ -4624,8 +4624,12 @@ SRST outdevchardevid. In order to improve efficiency, we need to put the task of comparison in another thread. If it has the vnet\_hdr\_support flag, colo compare will send/recv packet with - vnet\_hdr\_len. If you want to use Xen COLO, will need the - notify\_dev to notify Xen colo-frame to do checkpoint. + vnet\_hdr\_len. Then compare\_timeout=@var{ms} determines the + maximum delay colo-compare wait for the packet. + The expired\_scan\_cycle=@var{ms} to set the period of scanning + expired primary node network packets. + If you want to use Xen COLO, will need the notify\_dev to + notify Xen colo-frame to do checkpoint. we must use it with the help of filter-mirror and filter-redirector. diff --git a/tests/qtest/Makefile.include b/tests/qtest/Makefile.include index 10a28de8a3..9e5a51d033 100644 --- a/tests/qtest/Makefile.include +++ b/tests/qtest/Makefile.include @@ -217,6 +217,7 @@ qos-test-obj-y += tests/qtest/es1370-test.o qos-test-obj-y += tests/qtest/ipoctal232-test.o qos-test-obj-y += tests/qtest/megasas-test.o qos-test-obj-y += tests/qtest/ne2000-test.o +qos-test-obj-y += tests/qtest/tulip-test.o qos-test-obj-y += tests/qtest/nvme-test.o qos-test-obj-y += tests/qtest/pca9552-test.o qos-test-obj-y += tests/qtest/pci-test.o diff --git a/tests/qtest/tulip-test.c b/tests/qtest/tulip-test.c new file mode 100644 index 0000000000..2fb6c4d5a7 --- /dev/null +++ b/tests/qtest/tulip-test.c @@ -0,0 +1,91 @@ +/* + * QTest testcase for DEC/Intel Tulip 21143 + * + * Copyright (c) 2020 Li Qiang + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "libqtest.h" +#include "qemu/module.h" +#include "libqos/qgraph.h" +#include "libqos/pci.h" +#include "qemu/bitops.h" +#include "hw/net/tulip.h" + +typedef struct QTulip_pci QTulip_pci; + +struct QTulip_pci { + QOSGraphObject obj; + QPCIDevice dev; +}; + +static void *tulip_pci_get_driver(void *obj, const char *interface) +{ + QTulip_pci *tulip_pci = obj; + + if (!g_strcmp0(interface, "pci-device")) { + return &tulip_pci->dev; + } + + fprintf(stderr, "%s not present in tulip_pci\n", interface); + g_assert_not_reached(); +} + +static void *tulip_pci_create(void *pci_bus, QGuestAllocator *alloc, void *addr) +{ + QTulip_pci *tulip_pci = g_new0(QTulip_pci, 1); + QPCIBus *bus = pci_bus; + + qpci_device_init(&tulip_pci->dev, bus, addr); + tulip_pci->obj.get_driver = tulip_pci_get_driver; + + return &tulip_pci->obj; +} + +static void tulip_large_tx(void *obj, void *data, QGuestAllocator *alloc) +{ + QTulip_pci *tulip_pci = obj; + QPCIDevice *dev = &tulip_pci->dev; + QPCIBar bar; + struct tulip_descriptor context; + char guest_data[4096]; + uint64_t context_pa; + uint64_t guest_pa; + + qpci_device_enable(dev); + bar = qpci_iomap(dev, 0, NULL); + context_pa = guest_alloc(alloc, sizeof(context)); + guest_pa = guest_alloc(alloc, 4096); + memset(guest_data, 'A', sizeof(guest_data)); + context.status = TDES0_OWN; + context.control = TDES1_BUF2_SIZE_MASK << TDES1_BUF2_SIZE_SHIFT | + TDES1_BUF1_SIZE_MASK << TDES1_BUF1_SIZE_SHIFT; + context.buf_addr2 = guest_pa; + context.buf_addr1 = guest_pa; + + qtest_memwrite(dev->bus->qts, context_pa, &context, sizeof(context)); + qtest_memwrite(dev->bus->qts, guest_pa, guest_data, sizeof(guest_data)); + qpci_io_writel(dev, bar, 0x20, context_pa); + qpci_io_writel(dev, bar, 0x30, CSR6_ST); + guest_free(alloc, context_pa); + guest_free(alloc, guest_pa); +} + +static void tulip_register_nodes(void) +{ + QOSGraphEdgeOptions opts = { + .extra_device_opts = "addr=04.0", + }; + add_qpci_address(&opts, &(QPCIAddress) { .devfn = QPCI_DEVFN(4, 0) }); + + qos_node_create_driver("tulip", tulip_pci_create); + qos_node_consumes("tulip", "pci-bus", &opts); + qos_node_produces("tulip", "pci-device"); + + qos_add_test("tulip_large_tx", "tulip", tulip_large_tx, NULL); +} + +libqos_init(tulip_register_nodes);