| /* |
| * 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 <dmitry@daynix.com> |
| * Tamir Shomer <tamirs@daynix.com> |
| * Yan Vugenfirer <yan@daynix.com> |
| * |
| * 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 "qemu/osdep.h" |
| #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; |
| } |