Commit 2b11e678 authored by David S. Miller's avatar David S. Miller

Merge branch 'tun-net'

Herbert Xu says:

====================
tun: Fix csum_start and TUN_PKT_STRIP

The first patch fixes a serious problem that breaks checksum offload
in VMs while the second patch fixes a problem that probably affects
no one.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7071cf7f 2eb783c4
...@@ -1235,12 +1235,20 @@ static ssize_t tun_put_user(struct tun_struct *tun, ...@@ -1235,12 +1235,20 @@ static ssize_t tun_put_user(struct tun_struct *tun,
struct tun_pi pi = { 0, skb->protocol }; struct tun_pi pi = { 0, skb->protocol };
ssize_t total = 0; ssize_t total = 0;
int vlan_offset = 0, copied; int vlan_offset = 0, copied;
int vlan_hlen = 0;
int vnet_hdr_sz = 0;
if (vlan_tx_tag_present(skb))
vlan_hlen = VLAN_HLEN;
if (tun->flags & TUN_VNET_HDR)
vnet_hdr_sz = tun->vnet_hdr_sz;
if (!(tun->flags & TUN_NO_PI)) { if (!(tun->flags & TUN_NO_PI)) {
if ((len -= sizeof(pi)) < 0) if ((len -= sizeof(pi)) < 0)
return -EINVAL; return -EINVAL;
if (len < skb->len) { if (len < skb->len + vlan_hlen + vnet_hdr_sz) {
/* Packet will be striped */ /* Packet will be striped */
pi.flags |= TUN_PKT_STRIP; pi.flags |= TUN_PKT_STRIP;
} }
...@@ -1250,9 +1258,9 @@ static ssize_t tun_put_user(struct tun_struct *tun, ...@@ -1250,9 +1258,9 @@ static ssize_t tun_put_user(struct tun_struct *tun,
total += sizeof(pi); total += sizeof(pi);
} }
if (tun->flags & TUN_VNET_HDR) { if (vnet_hdr_sz) {
struct virtio_net_hdr gso = { 0 }; /* no info leak */ struct virtio_net_hdr gso = { 0 }; /* no info leak */
if ((len -= tun->vnet_hdr_sz) < 0) if ((len -= vnet_hdr_sz) < 0)
return -EINVAL; return -EINVAL;
if (skb_is_gso(skb)) { if (skb_is_gso(skb)) {
...@@ -1284,7 +1292,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, ...@@ -1284,7 +1292,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
if (skb->ip_summed == CHECKSUM_PARTIAL) { if (skb->ip_summed == CHECKSUM_PARTIAL) {
gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
gso.csum_start = skb_checksum_start_offset(skb); gso.csum_start = skb_checksum_start_offset(skb) +
vlan_hlen;
gso.csum_offset = skb->csum_offset; gso.csum_offset = skb->csum_offset;
} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
...@@ -1293,14 +1302,13 @@ static ssize_t tun_put_user(struct tun_struct *tun, ...@@ -1293,14 +1302,13 @@ static ssize_t tun_put_user(struct tun_struct *tun,
if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total,
sizeof(gso)))) sizeof(gso))))
return -EFAULT; return -EFAULT;
total += tun->vnet_hdr_sz; total += vnet_hdr_sz;
} }
copied = total; copied = total;
total += skb->len; len = min_t(int, skb->len + vlan_hlen, len);
if (!vlan_tx_tag_present(skb)) { total += skb->len + vlan_hlen;
len = min_t(int, skb->len, len); if (vlan_hlen) {
} else {
int copy, ret; int copy, ret;
struct { struct {
__be16 h_vlan_proto; __be16 h_vlan_proto;
...@@ -1311,8 +1319,6 @@ static ssize_t tun_put_user(struct tun_struct *tun, ...@@ -1311,8 +1319,6 @@ static ssize_t tun_put_user(struct tun_struct *tun,
veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
len = min_t(int, skb->len + VLAN_HLEN, len);
total += VLAN_HLEN;
copy = min_t(int, vlan_offset, len); copy = min_t(int, vlan_offset, len);
ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment