diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2014-11-03 04:30:14 +0800 |
---|---|---|
committer | Willy Tarreau <w@1wt.eu> | 2017-06-08 00:47:09 +0200 |
commit | bda0832822183c326b2ee65cd7f8442532adbe36 (patch) | |
tree | 1127724a5aac6f0fd5af26582204216d7806e4a3 /drivers | |
parent | bfac3620dc5335d65dfc4c9e308f0558c1763f29 (diff) |
tun: Fix TUN_PKT_STRIP setting
commit 2eb783c43e7cf807a45899c10ed556b6dc116625 upstream.
We set the flag TUN_PKT_STRIP if the user buffer provided is too
small to contain the entire packet plus meta-data. However, this
has been broken ever since we added GSO meta-data. VLAN acceleration
also has the same problem.
This patch fixes this by taking both into account when setting the
TUN_PKT_STRIP flag.
The fact that this has been broken for six years without anyone
realising means that nobody actually uses this flag.
Fixes: f43798c27684 ("tun: Allow GSO using virtio_net_hdr")
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
[wt: no tuntap VLAN offloading in 3.10]
Signed-off-by: Willy Tarreau <w@1wt.eu>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/tun.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 582497103fe8..ea6ada39db15 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1272,12 +1272,16 @@ static ssize_t tun_put_user(struct tun_struct *tun, { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; + int vnet_hdr_sz = 0; + + if (tun->flags & TUN_VNET_HDR) + vnet_hdr_sz = tun->vnet_hdr_sz; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) < 0) return -EINVAL; - if (len < skb->len) { + if (len < skb->len + vnet_hdr_sz) { /* Packet will be striped */ pi.flags |= TUN_PKT_STRIP; } @@ -1287,9 +1291,9 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += sizeof(pi); } - if (tun->flags & TUN_VNET_HDR) { + if (vnet_hdr_sz) { struct virtio_net_hdr gso = { 0 }; /* no info leak */ - if ((len -= tun->vnet_hdr_sz) < 0) + if ((len -= vnet_hdr_sz) < 0) return -EINVAL; if (skb_is_gso(skb)) { @@ -1332,7 +1336,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, sizeof(gso)))) return -EFAULT; - total += tun->vnet_hdr_sz; + total += vnet_hdr_sz; } len = min_t(int, skb->len, len); |