From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from [140.186.70.92] (port=33658 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PpNlL-0006Lb-6v for qemu-devel@nongnu.org; Tue, 15 Feb 2011 11:28:31 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1PpNlJ-00077C-TE for qemu-devel@nongnu.org; Tue, 15 Feb 2011 11:28:26 -0500 Received: from mx1.redhat.com ([209.132.183.28]:11804) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1PpNlJ-000774-I6 for qemu-devel@nongnu.org; Tue, 15 Feb 2011 11:28:25 -0500 Date: Tue, 15 Feb 2011 18:27:55 +0200 From: "Michael S. Tsirkin" Message-ID: <577246d76cde25110fa46428340b504da779aa73.1297787220.git.mst@redhat.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Subject: [Qemu-devel] [PATCHv2 3/3] e1000: verify we have buffers, upfront List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, Anthony Liguori Cc: kwolf@redhat.com, Jes.Sorensen@redhat.com, Alex Williamson , agraf@suse.de, stefanha@linux.vnet.ibm.com The spec says: Any descriptor with a non-zero status byte has been processed by the hardware, and is ready to be handled by the software. Thus, once we change a descriptor status to non-zero we should never move the head backwards and try to reuse this descriptor from hardware. This actually happened with a multibuffer packet that arrives when we don't have enough buffers. Fix by checking that we have enough buffers upfront so we never need to discard the packet midway through. Signed-off-by: Michael S. Tsirkin --- hw/e1000.c | 28 ++++++++++++++++++++++------ 1 files changed, 22 insertions(+), 6 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 2943a1a..0a4574c 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -631,6 +631,24 @@ e1000_can_receive(VLANClientState *nc) return (s->mac_reg[RCTL] & E1000_RCTL_EN); } +static bool e1000_has_rxbufs(E1000State *s, size_t total_size) +{ + int bufs; + /* Fast-path short packets */ + if (total_size <= s->rxbuf_size) { + return s->mac_reg[RDH] != s->mac_reg[RDT] || !s->check_rxov; + } + if (s->mac_reg[RDH] < s->mac_reg[RDT]) { + bufs = s->mac_reg[RDT] - s->mac_reg[RDH]; + } else if (s->mac_reg[RDH] > s->mac_reg[RDT] || !s->check_rxov) { + bufs = s->mac_reg[RDLEN] / sizeof(struct e1000_rx_desc) + + s->mac_reg[RDT] - s->mac_reg[RDH]; + } else { + return false; + } + return total_size <= bufs * s->rxbuf_size; +} + static ssize_t e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) { @@ -671,17 +689,15 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) rdh_start = s->mac_reg[RDH]; desc_offset = 0; total_size = size + fcs_len(s); + if (!e1000_has_rxbufs(s, total_size)) { + set_ics(s, 0, E1000_ICS_RXO); + return -1; + } do { desc_size = total_size - desc_offset; if (desc_size > s->rxbuf_size) { desc_size = s->rxbuf_size; } - if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) { - /* Discard all data written so far */ - s->mac_reg[RDH] = rdh_start; - set_ics(s, 0, E1000_ICS_RXO); - return -1; - } base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] + sizeof(desc) * s->mac_reg[RDH]; cpu_physical_memory_read(base, (void *)&desc, sizeof(desc)); -- 1.7.3.2.91.g446ac