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