| From foo@baz Mon Jan 13 09:44:41 PST 2014 |
| From: Jason Wang <jasowang@redhat.com> |
| Date: Wed, 11 Dec 2013 13:08:33 +0800 |
| Subject: tun: unbreak truncated packet signalling |
| |
| From: Jason Wang <jasowang@redhat.com> |
| |
| [ Upstream commit e6fd07c899cd719bb5517bc7f32ce03a62220351 ] |
| |
| 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 <wuzhy@linux.vnet.ibm.com> |
| Cc: Michael S. Tsirkin <mst@redhat.com> |
| Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> |
| Signed-off-by: Jason Wang <jasowang@redhat.com> |
| Acked-by: Michael S. Tsirkin <mst@redhat.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/net/tun.c | 16 +++++++++------- |
| 1 file changed, 9 insertions(+), 7 deletions(-) |
| |
| --- a/drivers/net/tun.c |
| +++ b/drivers/net/tun.c |
| @@ -1184,7 +1184,7 @@ static ssize_t tun_put_user(struct tun_s |
| { |
| 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_s |
| 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_s |
| |
| 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++; |