summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2018-06-06 18:23:01 +0300
committerDavid S. Miller <davem@davemloft.net>2018-06-07 23:15:38 +0300
commitfd3a88625844907151737fc3b4201676effa6d27 (patch)
tree73ec5aec120ca37add89d275b0adbd593164ac55 /drivers
parent7eced5ab5a7366ee7ca5360b3eca9d220c2b2887 (diff)
downloadlinux-fd3a88625844907151737fc3b4201676effa6d27.tar.xz
net: in virtio_net_hdr only add VLAN_HLEN to csum_start if payload holds vlan
Tun, tap, virtio, packet and uml vector all use struct virtio_net_hdr to communicate packet metadata to userspace. For skbuffs with vlan, the first two return the packet as it may have existed on the wire, inserting the VLAN tag in the user buffer. Then virtio_net_hdr.csum_start needs to be adjusted by VLAN_HLEN bytes. Commit f09e2249c4f5 ("macvtap: restore vlan header on user read") added this feature to macvtap. Commit 3ce9b20f1971 ("macvtap: Fix csum_start when VLAN tags are present") then fixed up csum_start. Virtio, packet and uml do not insert the vlan header in the user buffer. When introducing virtio_net_hdr_from_skb to deduplicate filling in the virtio_net_hdr, the variant from macvtap which adds VLAN_HLEN was applied uniformly, breaking csum offset for packets with vlan on virtio and packet. Make insertion of VLAN_HLEN optional. Convert the callers to pass it when needed. Fixes: e858fae2b0b8f4 ("virtio_net: use common code for virtio_net_hdr and skb GSO conversion") Fixes: 1276f24eeef2 ("packet: use common code for virtio_net_hdr and skb GSO conversion") Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/tap.c5
-rw-r--r--drivers/net/tun.c3
-rw-r--r--drivers/net/virtio_net.c3
3 files changed, 8 insertions, 3 deletions
diff --git a/drivers/net/tap.c b/drivers/net/tap.c
index 9b6cb780affe..f0f7cd977667 100644
--- a/drivers/net/tap.c
+++ b/drivers/net/tap.c
@@ -774,13 +774,16 @@ static ssize_t tap_put_user(struct tap_queue *q,
int total;
if (q->flags & IFF_VNET_HDR) {
+ int vlan_hlen = skb_vlan_tag_present(skb) ? VLAN_HLEN : 0;
struct virtio_net_hdr vnet_hdr;
+
vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz);
if (iov_iter_count(iter) < vnet_hdr_len)
return -EINVAL;
if (virtio_net_hdr_from_skb(skb, &vnet_hdr,
- tap_is_little_endian(q), true))
+ tap_is_little_endian(q), true,
+ vlan_hlen))
BUG();
if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 85e14adf5207..a192a017cc68 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -2089,7 +2089,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
return -EINVAL;
if (virtio_net_hdr_from_skb(skb, &gso,
- tun_is_little_endian(tun), true)) {
+ tun_is_little_endian(tun), true,
+ vlan_hlen)) {
struct skb_shared_info *sinfo = skb_shinfo(skb);
pr_err("unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 2aaa18ec7d46..1619ee3070b6 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -1411,7 +1411,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
hdr = skb_vnet_hdr(skb);
if (virtio_net_hdr_from_skb(skb, &hdr->hdr,
- virtio_is_little_endian(vi->vdev), false))
+ virtio_is_little_endian(vi->vdev), false,
+ 0))
BUG();
if (vi->mergeable_rx_bufs)