Skip to content

Commit

Permalink
macvtap: restore vlan header on user read
Browse files Browse the repository at this point in the history
Ethernet vlan header is not on the packet and kept in the skb->vlan_tci
when it comes from lower dev. This patch inserts vlan header in user
buffer during skb copy on user read.

Signed-off-by: Basil Gor <[email protected]>
Acked-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
basilgor authored and davem330 committed May 11, 2012
1 parent c53cff5 commit f09e224
Showing 1 changed file with 38 additions and 5 deletions.
43 changes: 38 additions & 5 deletions drivers/net/macvtap.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <linux/etherdevice.h>
#include <linux/if_macvlan.h>
#include <linux/if_vlan.h>
#include <linux/interrupt.h>
#include <linux/nsproxy.h>
#include <linux/compat.h>
Expand Down Expand Up @@ -759,6 +760,8 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
struct macvlan_dev *vlan;
int ret;
int vnet_hdr_len = 0;
int vlan_offset = 0;
int copied;

if (q->flags & IFF_VNET_HDR) {
struct virtio_net_hdr vnet_hdr;
Expand All @@ -773,18 +776,48 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr)))
return -EFAULT;
}
copied = vnet_hdr_len;

if (!vlan_tx_tag_present(skb))
len = min_t(int, skb->len, len);
else {
int copy;
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
} veth;
veth.h_vlan_proto = htons(ETH_P_8021Q);
veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));

vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
len = min_t(int, skb->len + VLAN_HLEN, len);

copy = min_t(int, vlan_offset, len);
ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
len -= copy;
copied += copy;
if (ret || !len)
goto done;

copy = min_t(int, sizeof(veth), len);
ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy);
len -= copy;
copied += copy;
if (ret || !len)
goto done;
}

len = min_t(int, skb->len, len);

ret = skb_copy_datagram_const_iovec(skb, 0, iv, vnet_hdr_len, len);
ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
copied += len;

done:
rcu_read_lock_bh();
vlan = rcu_dereference_bh(q->vlan);
if (vlan)
macvlan_count_rx(vlan, len, ret == 0, 0);
macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0);
rcu_read_unlock_bh();

return ret ? ret : (len + vnet_hdr_len);
return ret ? ret : copied;
}

static ssize_t macvtap_do_read(struct macvtap_queue *q, struct kiocb *iocb,
Expand Down

0 comments on commit f09e224

Please sign in to comment.