Revision 22cc84db hw/virtio-net.c

b/hw/virtio-net.c
504 504
 * cache.
505 505
 */
506 506
static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
507
                                        const uint8_t *buf, size_t size)
507
                                        uint8_t *buf, size_t size)
508 508
{
509 509
    if ((hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && /* missing csum */
510 510
        (size > 27 && size < 1500) && /* normal sized MTU */
511 511
        (buf[12] == 0x08 && buf[13] == 0x00) && /* ethertype == IPv4 */
512 512
        (buf[23] == 17) && /* ip.protocol == UDP */
513 513
        (buf[34] == 0 && buf[35] == 67)) { /* udp.srcport == bootps */
514
        /* FIXME this cast is evil */
515
        net_checksum_calculate((uint8_t *)buf, size);
514
        net_checksum_calculate(buf, size);
516 515
        hdr->flags &= ~VIRTIO_NET_HDR_F_NEEDS_CSUM;
517 516
    }
518 517
}
519 518

  
520
static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
521
                          const void *buf, size_t size, size_t hdr_len)
519
static int receive_header(VirtIONet *n, const struct iovec *iov, int iov_cnt,
520
                          const void *buf, size_t size)
522 521
{
523
    struct virtio_net_hdr *hdr = (struct virtio_net_hdr *)iov[0].iov_base;
524 522
    int offset = 0;
525 523

  
526
    hdr->flags = 0;
527
    hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
528

  
529 524
    if (n->has_vnet_hdr) {
530
        memcpy(hdr, buf, sizeof(*hdr));
531
        offset = sizeof(*hdr);
532
        work_around_broken_dhclient(hdr, buf + offset, size - offset);
525
        /* FIXME this cast is evil */
526
        void *wbuf = (void *)buf;
527
        work_around_broken_dhclient(wbuf, wbuf + offset, size - offset);
528
        offset = sizeof(struct virtio_net_hdr);
529
        iov_from_buf(iov, iov_cnt, 0, buf, offset);
530
    } else {
531
        struct virtio_net_hdr hdr = {
532
            .flags = 0,
533
            .gso_type = VIRTIO_NET_HDR_GSO_NONE
534
        };
535
        iov_from_buf(iov, iov_cnt, 0, &hdr, sizeof hdr);
533 536
    }
534 537

  
535
    /* We only ever receive a struct virtio_net_hdr from the tapfd,
536
     * but we may be passing along a larger header to the guest.
537
     */
538
    iov[0].iov_base += hdr_len;
539
    iov[0].iov_len  -= hdr_len;
540

  
541 538
    return offset;
542 539
}
543 540

  
......
598 595
{
599 596
    VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
600 597
    struct virtio_net_hdr_mrg_rxbuf *mhdr = NULL;
601
    size_t offset, i;
598
    const struct iovec *sg = elem.in_sg;
599
    size_t offset, i, guest_offset;
602 600

  
603 601
    if (!virtio_net_can_receive(&n->nic->nc))
604 602
        return -1;
......
615 613
    while (offset < size) {
616 614
        VirtQueueElement elem;
617 615
        int len, total;
618
        struct iovec sg[VIRTQUEUE_MAX_SIZE];
616
        const struct iovec *sg = elem.in_sg;
619 617

  
620 618
        total = 0;
621 619

  
......
640 638
            exit(1);
641 639
        }
642 640

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

  
645 641
        if (i == 0) {
646 642
            if (n->mergeable_rx_bufs)
647 643
                mhdr = (struct virtio_net_hdr_mrg_rxbuf *)sg[0].iov_base;
648 644

  
649 645
            offset += receive_header(n, sg, elem.in_num,
650
                                     buf + offset, size - offset,
651
                                     n->guest_hdr_len);
646
                                     buf + offset, size - offset);
652 647
            total += n->guest_hdr_len;
648
            guest_offset = n->guest_hdr_len;
649
        } else {
650
            guest_offset = 0;
653 651
        }
654 652

  
655 653
        /* copy in packet.  ugh */
656
        len = iov_from_buf(sg, elem.in_num, 0,
654
        len = iov_from_buf(sg, elem.in_num, guest_offset,
657 655
                           buf + offset, size - offset);
658 656
        total += len;
659 657
        offset += len;

Also available in: Unified diff