/* * QEMU VMWARE VMXNET* paravirtual NICs - RX packets abstractions * * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) * * Developed by Daynix Computing LTD (http://www.daynix.com) * * Authors: * Dmitry Fleytman * Tamir Shomer * Yan Vugenfirer * * This work is licensed under the terms of the GNU GPL, version 2 or later. * See the COPYING file in the top-level directory. * */ #include "vmxnet_rx_pkt.h" #include "net/eth.h" #include "qemu-common.h" #include "qemu/iov.h" #include "net/checksum.h" #include "net/tap.h" /* * RX packet may contain up to 2 fragments - rebuilt eth header * in case of VLAN tag stripping * and payload received from QEMU - in any case */ #define VMXNET_MAX_RX_PACKET_FRAGMENTS (2) struct VmxnetRxPkt { struct virtio_net_hdr virt_hdr; uint8_t ehdr_buf[ETH_MAX_L2_HDR_LEN]; struct iovec vec[VMXNET_MAX_RX_PACKET_FRAGMENTS]; uint16_t vec_len; uint32_t tot_len; uint16_t tci; bool vlan_stripped; bool has_virt_hdr; eth_pkt_types_e packet_type; /* Analysis results */ bool isip4; bool isip6; bool isudp; bool istcp; }; void vmxnet_rx_pkt_init(struct VmxnetRxPkt **pkt, bool has_virt_hdr) { struct VmxnetRxPkt *p = g_malloc0(sizeof *p); p->has_virt_hdr = has_virt_hdr; *pkt = p; } void vmxnet_rx_pkt_uninit(struct VmxnetRxPkt *pkt) { g_free(pkt); } struct virtio_net_hdr *vmxnet_rx_pkt_get_vhdr(struct VmxnetRxPkt *pkt) { assert(pkt); return &pkt->virt_hdr; } void vmxnet_rx_pkt_attach_data(struct VmxnetRxPkt *pkt, const void *data, size_t len, bool strip_vlan) { uint16_t tci = 0; uint16_t ploff; assert(pkt); pkt->vlan_stripped = false; if (strip_vlan) { pkt->vlan_stripped = eth_strip_vlan(data, pkt->ehdr_buf, &ploff, &tci); } if (pkt->vlan_stripped) { pkt->vec[0].iov_base = pkt->ehdr_buf; pkt->vec[0].iov_len = ploff - sizeof(struct vlan_header); pkt->vec[1].iov_base = (uint8_t *) data + ploff; pkt->vec[1].iov_len = len - ploff; pkt->vec_len = 2; pkt->tot_len = len - ploff + sizeof(struct eth_header); } else { pkt->vec[0].iov_base = (void *)data; pkt->vec[0].iov_len = len; pkt->vec_len = 1; pkt->tot_len = len; } pkt->tci = tci; } void vmxnet_rx_pkt_dump(struct VmxnetRxPkt *pkt) { #ifdef VMXNET_RX_PKT_DEBUG VmxnetRxPkt *pkt = (VmxnetRxPkt *)pkt; assert(pkt); printf("RX PKT: tot_len: %d, vlan_stripped: %d, vlan_tag: %d\n", pkt->tot_len, pkt->vlan_stripped, pkt->tci); #endif } void vmxnet_rx_pkt_set_packet_type(struct VmxnetRxPkt *pkt, eth_pkt_types_e packet_type) { assert(pkt); pkt->packet_type = packet_type; } eth_pkt_types_e vmxnet_rx_pkt_get_packet_type(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->packet_type; } size_t vmxnet_rx_pkt_get_total_len(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->tot_len; } void vmxnet_rx_pkt_set_protocols(struct VmxnetRxPkt *pkt, const void *data, size_t len) { assert(pkt); eth_get_protocols(data, len, &pkt->isip4, &pkt->isip6, &pkt->isudp, &pkt->istcp); } void vmxnet_rx_pkt_get_protocols(struct VmxnetRxPkt *pkt, bool *isip4, bool *isip6, bool *isudp, bool *istcp) { assert(pkt); *isip4 = pkt->isip4; *isip6 = pkt->isip6; *isudp = pkt->isudp; *istcp = pkt->istcp; } struct iovec *vmxnet_rx_pkt_get_iovec(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->vec; } void vmxnet_rx_pkt_set_vhdr(struct VmxnetRxPkt *pkt, struct virtio_net_hdr *vhdr) { assert(pkt); memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); } bool vmxnet_rx_pkt_is_vlan_stripped(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->vlan_stripped; } bool vmxnet_rx_pkt_has_virt_hdr(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->has_virt_hdr; } uint16_t vmxnet_rx_pkt_get_vlan_tag(struct VmxnetRxPkt *pkt) { assert(pkt); return pkt->tci; }