From 923347bb83c67c3a572b04decb5875c3adb0d306 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 9 Dec 2013 18:25:16 +0800 Subject: tun: unbreak truncated packet signalling Commit 6680ec68eff47d36f67b4351bc9836fd6cba9532 (tuntap: hardware vlan tx support) breaks the truncated packet signal by never return a length greater than iov length in tun_put_user(). This patch fixes this by always return the length of packet plus possible vlan header. Caller can detect the truncated packet by comparing the return value and the size of iov length. Reported-by: Vlad Yasevich Cc: Vlad Yasevich Cc: Zhi Yong Wu Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/tun.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'drivers/net/tun.c') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e26cbea1ce68..dd1bd7aedc3c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1183,7 +1183,11 @@ static ssize_t tun_put_user(struct tun_struct *tun, const struct iovec *iv, int len) { struct tun_pi pi = { 0, skb->protocol }; - ssize_t total = 0; + struct { + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + } veth; + ssize_t total = 0, off = 0; int vlan_offset = 0; if (!(tun->flags & TUN_NO_PI)) { @@ -1248,14 +1252,11 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += tun->vnet_hdr_sz; } + off = total; if (!vlan_tx_tag_present(skb)) { len = min_t(int, skb->len, len); } else { int copy, ret; - struct { - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - } veth; veth.h_vlan_proto = skb->vlan_proto; veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); @@ -1264,22 +1265,22 @@ static ssize_t tun_put_user(struct tun_struct *tun, 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, total, copy); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, off, copy); len -= copy; - total += copy; + off += copy; if (ret || !len) goto done; copy = min_t(int, sizeof(veth), len); - ret = memcpy_toiovecend(iv, (void *)&veth, total, copy); + ret = memcpy_toiovecend(iv, (void *)&veth, off, copy); len -= copy; - total += copy; + off += copy; if (ret || !len) goto done; } - skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len); - total += len; + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, off, len); + total += skb->len + (vlan_offset ? sizeof(veth) : 0); done: tun->dev->stats.tx_packets++; -- cgit v1.2.3 From bbd37626e6be9500e74aa244a3be1a69b6645ea0 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 10 Dec 2013 22:10:21 -0500 Subject: net: Revert macvtap/tun truncation signalling changes. Jason Wang and Michael S. Tsirkin are still discussing how to properly fix this. Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 27 +++++++++++++-------------- drivers/net/tun.c | 23 +++++++++++------------ 2 files changed, 24 insertions(+), 26 deletions(-) (limited to 'drivers/net/tun.c') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 7544a0c686b4..957cc5c3653d 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -767,14 +767,10 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, const struct sk_buff *skb, const struct iovec *iv, int len) { - int ret, off; + int ret; int vnet_hdr_len = 0; int vlan_offset = 0; int copied; - struct { - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - } veth; if (q->flags & IFF_VNET_HDR) { struct virtio_net_hdr vnet_hdr; @@ -789,13 +785,16 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (memcpy_toiovecend(iv, (void *)&vnet_hdr, 0, sizeof(vnet_hdr))) return -EFAULT; } - off = copied = vnet_hdr_len; + 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 = skb->vlan_proto; veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); @@ -803,22 +802,22 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, 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, off, copy); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); len -= copy; - off += copy; + copied += copy; if (ret || !len) goto done; copy = min_t(int, sizeof(veth), len); - ret = memcpy_toiovecend(iv, (void *)&veth, off, copy); + ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); len -= copy; - off += copy; + copied += copy; if (ret || !len) goto done; } - ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, off, len); - copied += skb->len + (vlan_offset ? sizeof(veth) : 0); + ret = skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); + copied += len; done: return ret ? ret : copied; @@ -876,7 +875,7 @@ static ssize_t macvtap_aio_read(struct kiocb *iocb, const struct iovec *iv, } ret = macvtap_do_read(q, iocb, iv, len, file->f_flags & O_NONBLOCK); - ret = min_t(ssize_t, ret, len); + ret = min_t(ssize_t, ret, len); /* XXX copied from tun.c. Why? */ if (ret > 0) iocb->ki_pos = ret; out: diff --git a/drivers/net/tun.c b/drivers/net/tun.c index dd1bd7aedc3c..e26cbea1ce68 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1183,11 +1183,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, const struct iovec *iv, int len) { struct tun_pi pi = { 0, skb->protocol }; - struct { - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - } veth; - ssize_t total = 0, off = 0; + ssize_t total = 0; int vlan_offset = 0; if (!(tun->flags & TUN_NO_PI)) { @@ -1252,11 +1248,14 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += tun->vnet_hdr_sz; } - off = total; if (!vlan_tx_tag_present(skb)) { len = min_t(int, skb->len, len); } else { int copy, ret; + struct { + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + } veth; veth.h_vlan_proto = skb->vlan_proto; veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); @@ -1265,22 +1264,22 @@ static ssize_t tun_put_user(struct tun_struct *tun, 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, off, copy); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy); len -= copy; - off += copy; + total += copy; if (ret || !len) goto done; copy = min_t(int, sizeof(veth), len); - ret = memcpy_toiovecend(iv, (void *)&veth, off, copy); + ret = memcpy_toiovecend(iv, (void *)&veth, total, copy); len -= copy; - off += copy; + total += copy; if (ret || !len) goto done; } - skb_copy_datagram_const_iovec(skb, vlan_offset, iv, off, len); - total += skb->len + (vlan_offset ? sizeof(veth) : 0); + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len); + total += len; done: tun->dev->stats.tx_packets++; -- cgit v1.2.3 From e6fd07c899cd719bb5517bc7f32ce03a62220351 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Wed, 11 Dec 2013 13:08:33 +0800 Subject: tun: unbreak truncated packet signalling Commit 6680ec68eff47d36f67b4351bc9836fd6cba9532 (tuntap: hardware vlan tx support) breaks the truncated packet signal by nev return a length greater than iov length in tun_put_user(). This patch fixes by always return the length of packet plus possible vlan header. Caller can detect the truncated packet by comparing the return value and the size of io length. Cc: Zhi Yong Wu Cc: Michael S. Tsirkin Signed-off-by: Vlad Yasevich Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/tun.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/net/tun.c') diff --git a/drivers/net/tun.c b/drivers/net/tun.c index e26cbea1ce68..7c8343a4f918 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1184,7 +1184,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, { struct tun_pi pi = { 0, skb->protocol }; ssize_t total = 0; - int vlan_offset = 0; + int vlan_offset = 0, copied; if (!(tun->flags & TUN_NO_PI)) { if ((len -= sizeof(pi)) < 0) @@ -1248,6 +1248,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, total += tun->vnet_hdr_sz; } + copied = total; + total += skb->len; if (!vlan_tx_tag_present(skb)) { len = min_t(int, skb->len, len); } else { @@ -1262,24 +1264,24 @@ static ssize_t tun_put_user(struct tun_struct *tun, 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); - ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy); + ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); len -= copy; - total += copy; + copied += copy; if (ret || !len) goto done; copy = min_t(int, sizeof(veth), len); - ret = memcpy_toiovecend(iv, (void *)&veth, total, copy); + ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy); len -= copy; - total += copy; + copied += copy; if (ret || !len) goto done; } - skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len); - total += len; + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len); done: tun->dev->stats.tx_packets++; -- cgit v1.2.3