diff options
Diffstat (limited to 'net.c')
-rw-r--r-- | net.c | 155 |
1 files changed, 98 insertions, 57 deletions
@@ -415,6 +415,8 @@ 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) { ssize_t len; @@ -432,13 +434,38 @@ qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) ret = (ret >= 0) ? ret : len; } + sender->vlan->delivering = 0; + return ret; } +static void qemu_flush_queued_packets(VLANClientState *vc) +{ + VLANPacket *packet; + + while ((packet = vc->vlan->send_queue) != NULL) { + vc->vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); + qemu_free(packet); + } +} + +static void +qemu_enqueue_packet(VLANClientState *sender, const uint8_t *buf, int size) +{ + VLANPacket *packet; + + packet = qemu_malloc(sizeof(VLANPacket) + size); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->size = size; + memcpy(packet->data, buf, size); + sender->vlan->send_queue = packet; +} + void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) { VLANState *vlan = vc->vlan; - VLANPacket *packet; if (vc->link_down) return; @@ -448,22 +475,12 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) 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) { - vlan->send_queue = packet->next; - qemu_deliver_packet(packet->sender, packet->data, packet->size); - qemu_free(packet); - } - vlan->delivering = 0; + qemu_enqueue_packet(vc, buf, size); + return; } + + qemu_deliver_packet(vc, buf, size); + qemu_flush_queued_packets(vc); } static ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov, @@ -496,60 +513,84 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) return offset; } -ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, - int iovcnt) +static int qemu_deliver_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) { - VLANState *vlan = sender->vlan; VLANClientState *vc; + int ret = -1; + + sender->vlan->delivering = 1; + + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len; + + if (vc == sender) { + continue; + } + + if (vc->link_down) { + ret = calc_iov_length(iov, iovcnt); + continue; + } + + if (vc->receive_iov) { + len = vc->receive_iov(vc, iov, iovcnt); + } else { + len = vc_sendv_compat(vc, iov, iovcnt); + } + + ret = (ret >= 0) ? ret : len; + } + + sender->vlan->delivering = 0; + + return ret; +} + +static ssize_t qemu_enqueue_packet_iov(VLANClientState *sender, + const struct iovec *iov, int iovcnt) +{ VLANPacket *packet; - ssize_t max_len = 0; + size_t max_len = 0; int i; - if (sender->link_down) - return calc_iov_length(iov, iovcnt); + max_len = calc_iov_length(iov, iovcnt); - if (vlan->delivering) { - max_len = calc_iov_length(iov, iovcnt); + packet = qemu_malloc(sizeof(VLANPacket) + max_len); + packet->next = sender->vlan->send_queue; + packet->sender = sender; + packet->size = 0; - packet = qemu_malloc(sizeof(VLANPacket) + max_len); - packet->next = vlan->send_queue; - packet->sender = sender; - packet->size = 0; - for (i = 0; i < iovcnt; i++) { - size_t len = iov[i].iov_len; + 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; - } - vlan->send_queue = packet; - } else { - vlan->delivering = 1; + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { - ssize_t len = 0; + sender->vlan->send_queue = packet; - if (vc == sender) { - continue; - } - if (vc->link_down) { - len = calc_iov_length(iov, iovcnt); - } else if (vc->receive_iov) { - len = vc->receive_iov(vc, iov, iovcnt); - } else if (vc->receive) { - len = vc_sendv_compat(vc, iov, iovcnt); - } - max_len = MAX(max_len, len); - } + return packet->size; +} - while ((packet = vlan->send_queue) != NULL) { - vlan->send_queue = packet->next; - qemu_deliver_packet(packet->sender, packet->data, packet->size); - qemu_free(packet); - } - vlan->delivering = 0; +ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, + int iovcnt) +{ + int ret; + + if (sender->link_down) { + return calc_iov_length(iov, iovcnt); + } + + if (sender->vlan->delivering) { + return qemu_enqueue_packet_iov(sender, iov, iovcnt); } - return max_len; + ret = qemu_deliver_packet_iov(sender, iov, iovcnt); + + qemu_flush_queued_packets(sender); + + return ret; } static void config_error(Monitor *mon, const char *fmt, ...) |