Avoid buffer overflow when sending slirp packets.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1744 c046a42c-6fe2-441c-8c8c-71466251a162
diff --git a/hw/lance.c b/hw/lance.c
index 2fef6b1..c0cb0f9 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -283,6 +283,11 @@
#define MIN_BUF_SIZE 60
+static void lance_can_receive(void *opaque)
+{
+ return 1;
+}
+
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
@@ -440,7 +445,7 @@
lance_reset(s);
- s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, s);
+ s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
diff --git a/hw/ne2000.c b/hw/ne2000.c
index efc3ea8..674d83e 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -200,14 +200,10 @@
return (crc >> 26);
}
-/* return the max buffer size if the NE2000 can receive more data */
-static int ne2000_can_receive(void *opaque)
+static int ne2000_buffer_full(NE2000State *s)
{
- NE2000State *s = opaque;
int avail, index, boundary;
-
- if (s->cmd & E8390_STOP)
- return 0;
+
index = s->curpag << 8;
boundary = s->boundary << 8;
if (index < boundary)
@@ -215,8 +211,17 @@
else
avail = (s->stop - s->start) - (index - boundary);
if (avail < (MAX_ETH_FRAME_SIZE + 4))
- return 0;
- return MAX_ETH_FRAME_SIZE;
+ return 1;
+ return 0;
+}
+
+static int ne2000_can_receive(void *opaque)
+{
+ NE2000State *s = opaque;
+
+ if (s->cmd & E8390_STOP)
+ return 1;
+ return !ne2000_buffer_full(s);
}
#define MIN_BUF_SIZE 60
@@ -234,7 +239,7 @@
printf("NE2000: received len=%d\n", size);
#endif
- if (!ne2000_can_receive(s))
+ if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
return;
/* XXX: check this */
@@ -722,7 +727,8 @@
ne2000_reset(s);
- s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s);
+ s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
+ ne2000_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"ne2000 macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
@@ -791,7 +797,8 @@
s->pci_dev = (PCIDevice *)d;
memcpy(s->macaddr, nd->macaddr, 6);
ne2000_reset(s);
- s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive, s);
+ s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
+ ne2000_can_receive, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"ne2000 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 375debd..214e92e 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -593,6 +593,17 @@
return val;
}
+static int smc91c111_can_receive(void *opaque)
+{
+ smc91c111_state *s = (smc91c111_state *)opaque;
+
+ if ((s->rcr & RCR_RXEN) == 0 || (s->rcr & RCR_SOFT_RST))
+ return 1;
+ if (s->allocated == (1 << NUM_PACKETS) - 1)
+ return 0;
+ return 1;
+}
+
static void smc91c111_receive(void *opaque, const uint8_t *buf, int size)
{
smc91c111_state *s = (smc91c111_state *)opaque;
@@ -697,6 +708,7 @@
smc91c111_reset(s);
- s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive, s);
+ s->vc = qemu_new_vlan_client(nd->vlan, smc91c111_receive,
+ smc91c111_can_receive, s);
/* ??? Save/restore. */
}
diff --git a/vl.c b/vl.c
index d875f2a..6d319bc 100644
--- a/vl.c
+++ b/vl.c
@@ -1842,13 +1842,16 @@
}
VLANClientState *qemu_new_vlan_client(VLANState *vlan,
- IOReadHandler *fd_read, void *opaque)
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ void *opaque)
{
VLANClientState *vc, **pvc;
vc = qemu_mallocz(sizeof(VLANClientState));
if (!vc)
return NULL;
vc->fd_read = fd_read;
+ vc->fd_can_read = fd_can_read;
vc->opaque = opaque;
vc->vlan = vlan;
@@ -1860,6 +1863,20 @@
return vc;
}
+int qemu_can_send_packet(VLANClientState *vc1)
+{
+ VLANState *vlan = vc1->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 0;
+ }
+ }
+ return 1;
+}
+
void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
{
VLANState *vlan = vc1->vlan;
@@ -1885,7 +1902,7 @@
int slirp_can_output(void)
{
- return 1;
+ return qemu_can_send_packet(slirp_vc);
}
void slirp_output(const uint8_t *pkt, int pkt_len)
@@ -1913,7 +1930,7 @@
slirp_init();
}
slirp_vc = qemu_new_vlan_client(vlan,
- slirp_receive, NULL);
+ slirp_receive, NULL, NULL);
snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
return 0;
}
@@ -2098,7 +2115,7 @@
if (!s)
return NULL;
s->fd = fd;
- s->vc = qemu_new_vlan_client(vlan, tap_receive, s);
+ s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
qemu_set_fd_handler(s->fd, tap_send, NULL, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd);
return s;
@@ -2412,7 +2429,7 @@
return NULL;
s->fd = fd;
- s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, s);
+ s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s);
qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
/* mcast: save bound address as dst */
@@ -2440,7 +2457,7 @@
return NULL;
s->fd = fd;
s->vc = qemu_new_vlan_client(vlan,
- net_socket_receive, s);
+ net_socket_receive, NULL, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"socket: fd=%d", fd);
if (is_connected) {
diff --git a/vl.h b/vl.h
index 004498f..5986d50 100644
--- a/vl.h
+++ b/vl.h
@@ -279,6 +279,9 @@
struct VLANClientState {
IOReadHandler *fd_read;
+ /* Packets may still be sent if this returns zero. It's used to
+ rate-limit the slirp code. */
+ IOCanRWHandler *fd_can_read;
void *opaque;
struct VLANClientState *next;
struct VLANState *vlan;
@@ -293,8 +296,12 @@
VLANState *qemu_find_vlan(int id);
VLANClientState *qemu_new_vlan_client(VLANState *vlan,
- IOReadHandler *fd_read, void *opaque);
+ IOReadHandler *fd_read,
+ IOCanRWHandler *fd_can_read,
+ void *opaque);
+int qemu_can_send_packet(VLANClientState *vc);
void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size);
+void qemu_handler_true(void *opaque);
void do_info_network(void);