aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJason Wang <jasowang@redhat.com>2013-12-11 00:08:33 -0500
committerDavid S. Miller <davem@davemloft.net>2013-12-11 15:23:06 -0500
commite6fd07c899cd719bb5517bc7f32ce03a62220351 (patch)
treea696c4fea94bcb51b6a8006074e1bb233e53ce95 /drivers/net
parent1598f7cb4745c40467decc91ee44ec615773eb45 (diff)
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 <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>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/tun.c16
1 files changed, 9 insertions, 7 deletions
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,
1184{ 1184{
1185 struct tun_pi pi = { 0, skb->protocol }; 1185 struct tun_pi pi = { 0, skb->protocol };
1186 ssize_t total = 0; 1186 ssize_t total = 0;
1187 int vlan_offset = 0; 1187 int vlan_offset = 0, copied;
1188 1188
1189 if (!(tun->flags & TUN_NO_PI)) { 1189 if (!(tun->flags & TUN_NO_PI)) {
1190 if ((len -= sizeof(pi)) < 0) 1190 if ((len -= sizeof(pi)) < 0)
@@ -1248,6 +1248,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1248 total += tun->vnet_hdr_sz; 1248 total += tun->vnet_hdr_sz;
1249 } 1249 }
1250 1250
1251 copied = total;
1252 total += skb->len;
1251 if (!vlan_tx_tag_present(skb)) { 1253 if (!vlan_tx_tag_present(skb)) {
1252 len = min_t(int, skb->len, len); 1254 len = min_t(int, skb->len, len);
1253 } else { 1255 } else {
@@ -1262,24 +1264,24 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1262 1264
1263 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); 1265 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
1264 len = min_t(int, skb->len + VLAN_HLEN, len); 1266 len = min_t(int, skb->len + VLAN_HLEN, len);
1267 total += VLAN_HLEN;
1265 1268
1266 copy = min_t(int, vlan_offset, len); 1269 copy = min_t(int, vlan_offset, len);
1267 ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy); 1270 ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
1268 len -= copy; 1271 len -= copy;
1269 total += copy; 1272 copied += copy;
1270 if (ret || !len) 1273 if (ret || !len)
1271 goto done; 1274 goto done;
1272 1275
1273 copy = min_t(int, sizeof(veth), len); 1276 copy = min_t(int, sizeof(veth), len);
1274 ret = memcpy_toiovecend(iv, (void *)&veth, total, copy); 1277 ret = memcpy_toiovecend(iv, (void *)&veth, copied, copy);
1275 len -= copy; 1278 len -= copy;
1276 total += copy; 1279 copied += copy;
1277 if (ret || !len) 1280 if (ret || !len)
1278 goto done; 1281 goto done;
1279 } 1282 }
1280 1283
1281 skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len); 1284 skb_copy_datagram_const_iovec(skb, vlan_offset, iv, copied, len);
1282 total += len;
1283 1285
1284done: 1286done:
1285 tun->dev->stats.tx_packets++; 1287 tun->dev->stats.tx_packets++;