static void virtio_net_receive(void *opaque, const uint8_t *buf, size_t size)

{

    VirtIONet *n = opaque;

    struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;

    size_t hdr_len, offset, i;



    if (!do_virtio_net_can_receive(n, size))

        return;



    if (!receive_filter(n, buf, size))

        return;



    /* hdr_len refers to the header we supply to the guest */

    hdr_len = n->mergeable_rx_bufs ?

        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);



    offset = i = 0;



    while (offset < size) {

        VirtQueueElement elem;

        int len, total;

        struct iovec sg[VIRTQUEUE_MAX_SIZE];



        len = total = 0;



        if ((i != 0 && !n->mergeable_rx_bufs) ||

            virtqueue_pop(n->rx_vq, &elem) == 0) {

            if (i == 0)

                return;

            fprintf(stderr, "virtio-net truncating packet\n");

            exit(1);

        }



        if (elem.in_num < 1) {

            fprintf(stderr, "virtio-net receive queue contains no in buffers\n");

            exit(1);

        }



        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {

            fprintf(stderr, "virtio-net header not in first element\n");

            exit(1);

        }



        memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);



        if (i == 0) {

            if (n->mergeable_rx_bufs)

                mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;



            offset += receive_header(n, sg, elem.in_num,

                                     buf + offset, size - offset, hdr_len);

            total += hdr_len;

        }



        /* copy in packet.  ugh */

        len = iov_fill(sg, elem.in_num,

                       buf + offset, size - offset);

        total += len;



        /* signal other side */

        virtqueue_fill(n->rx_vq, &elem, total, i++);



        offset += len;

    }



    if (mhdr)

        mhdr->num_buffers = i;



    virtqueue_flush(n->rx_vq, i);

    virtio_notify(&n->vdev, n->rx_vq);

}

static void virtio_net_receive(void *opaque, const uint8_t *buf, size_t size)

{

    VirtIONet *n = opaque;

    struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;

    size_t hdr_len, offset, i;



    if (!do_virtio_net_can_receive(n, size))

        return;



    if (!receive_filter(n, buf, size))

        return;



    

    hdr_len = n->mergeable_rx_bufs ?

        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);



    offset = i = 0;



    while (offset < size) {

        VirtQueueElement elem;

        int len, total;

        struct iovec sg[VIRTQUEUE_MAX_SIZE];



        len = total = 0;



        if ((i != 0 && !n->mergeable_rx_bufs) ||

            virtqueue_pop(n->rx_vq, &elem) == 0) {

            if (i == 0)

                return;

            fprintf(stderr, "virtio-net truncating packet\n");

            exit(1);

        }



        if (elem.in_num < 1) {

            fprintf(stderr, "virtio-net receive queue contains no in buffers\n");

            exit(1);

        }



        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {

            fprintf(stderr, "virtio-net header not in first element\n");

            exit(1);

        }



        memcpy(&sg, &elem.in_sg[0], sizeof(sg[0]) * elem.in_num);



        if (i == 0) {

            if (n->mergeable_rx_bufs)

                mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;



            offset += receive_header(n, sg, elem.in_num,

                                     buf + offset, size - offset, hdr_len);

            total += hdr_len;

        }



        

        len = iov_fill(sg, elem.in_num,

                       buf + offset, size - offset);

        total += len;



        

        virtqueue_fill(n->rx_vq, &elem, total, i++);



        offset += len;

    }



    if (mhdr)

        mhdr->num_buffers = i;



    virtqueue_flush(n->rx_vq, i);

    virtio_notify(&n->vdev, n->rx_vq);

}

static void FUNC_0(void *VAR_0, const uint8_t *VAR_1, size_t VAR_2)

{

    VirtIONet *n = VAR_0;

    struct virtio_net_hdr_mrg_rxbuf *VAR_3 = NULL;

    size_t hdr_len, offset, i;



    if (!do_virtio_net_can_receive(n, VAR_2))

        return;



    if (!receive_filter(n, VAR_1, VAR_2))

        return;



    

    hdr_len = n->mergeable_rx_bufs ?

        sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr);



    offset = i = 0;



    while (offset < VAR_2) {

        VirtQueueElement elem;

        int VAR_4, VAR_5;

        struct iovec VAR_6[VIRTQUEUE_MAX_SIZE];



        VAR_4 = VAR_5 = 0;



        if ((i != 0 && !n->mergeable_rx_bufs) ||

            virtqueue_pop(n->rx_vq, &elem) == 0) {

            if (i == 0)

                return;

            fprintf(stderr, "virtio-net truncating packet\n");

            exit(1);

        }



        if (elem.in_num < 1) {

            fprintf(stderr, "virtio-net receive queue contains no in buffers\n");

            exit(1);

        }



        if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) {

            fprintf(stderr, "virtio-net header not in first element\n");

            exit(1);

        }



        memcpy(&VAR_6, &elem.in_sg[0], sizeof(VAR_6[0]) * elem.in_num);



        if (i == 0) {

            if (n->mergeable_rx_bufs)

                VAR_3 = (struct virtio_net_hdr_mrg_rxbuf *)VAR_6[0].iov_base;



            offset += receive_header(n, VAR_6, elem.in_num,

                                     VAR_1 + offset, VAR_2 - offset, hdr_len);

            VAR_5 += hdr_len;

        }



        

        VAR_4 = iov_fill(VAR_6, elem.in_num,

                       VAR_1 + offset, VAR_2 - offset);

        VAR_5 += VAR_4;



        

        virtqueue_fill(n->rx_vq, &elem, VAR_5, i++);



        offset += VAR_4;

    }



    if (VAR_3)

        VAR_3->num_buffers = i;



    virtqueue_flush(n->rx_vq, i);

    virtio_notify(&n->vdev, n->rx_vq);

}

static void FUNC_0(void *VAR_0, const uint8_t *VAR_1, size_t VAR_2)
{ VirtIONet *n = VAR_0; struct virtio_net_hdr_mrg_rxbuf *VAR_3 = NULL; size_t hdr_len, offset, i; if (!do_virtio_net_can_receive(n, VAR_2))
return; if (!receive_filter(n, VAR_1, VAR_2))
return; hdr_len = n->mergeable_rx_bufs ?
sizeof(struct virtio_net_hdr_mrg_rxbuf) : sizeof(struct virtio_net_hdr); offset = i = 0; while (offset < VAR_2) { VirtQueueElement elem; int VAR_4, VAR_5; struct iovec VAR_6[VIRTQUEUE_MAX_SIZE]; VAR_4 = VAR_5 = 0; if ((i != 0 && !n->mergeable_rx_bufs) ||
virtqueue_pop(n->rx_vq, &elem) == 0) { if (i == 0)
return; fprintf(stderr, "virtio-net truncating packet\n"); exit(1); } if (elem.in_num < 1) { fprintf(stderr, "virtio-net receive queue contains no in buffers\n"); exit(1); } if (!n->mergeable_rx_bufs && elem.in_sg[0].iov_len != hdr_len) { fprintf(stderr, "virtio-net header not in first element\n"); exit(1); } memcpy(&VAR_6, &elem.in_sg[0], sizeof(VAR_6[0]) * elem.in_num); if (i == 0) { if (n->mergeable_rx_bufs)
VAR_3 = (struct virtio_net_hdr_mrg_rxbuf *)VAR_6[0].iov_base; offset += receive_header(n, VAR_6, elem.in_num,
VAR_1 + offset, VAR_2 - offset, hdr_len); VAR_5 += hdr_len; } VAR_4 = iov_fill(VAR_6, elem.in_num,
VAR_1 + offset, VAR_2 - offset); VAR_5 += VAR_4; virtqueue_fill(n->rx_vq, &elem, VAR_5, i++); offset += VAR_4; } if (VAR_3)
VAR_3->num_buffers = i; virtqueue_flush(n->rx_vq, i); virtio_notify(&n->vdev, n->rx_vq); }