Переглянути джерело

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>
Jason Wang 11 роки тому
батько
коміт
e6fd07c899
1 змінених файлів з 9 додано та 7 видалено
  1. 9 7
      drivers/net/tun.c

+ 9 - 7
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 };
 	struct tun_pi pi = { 0, skb->protocol };
 	ssize_t total = 0;
 	ssize_t total = 0;
-	int vlan_offset = 0;
+	int vlan_offset = 0, copied;
 
 
 	if (!(tun->flags & TUN_NO_PI)) {
 	if (!(tun->flags & TUN_NO_PI)) {
 		if ((len -= sizeof(pi)) < 0)
 		if ((len -= sizeof(pi)) < 0)
@@ -1248,6 +1248,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 		total += tun->vnet_hdr_sz;
 		total += tun->vnet_hdr_sz;
 	}
 	}
 
 
+	copied = total;
+	total += skb->len;
 	if (!vlan_tx_tag_present(skb)) {
 	if (!vlan_tx_tag_present(skb)) {
 		len = min_t(int, skb->len, len);
 		len = min_t(int, skb->len, len);
 	} else {
 	} else {
@@ -1262,24 +1264,24 @@ static ssize_t tun_put_user(struct tun_struct *tun,
 
 
 		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);
 		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, total, copy);
+		ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy);
 		len -= copy;
 		len -= copy;
-		total += copy;
+		copied += copy;
 		if (ret || !len)
 		if (ret || !len)
 			goto done;
 			goto done;
 
 
 		copy = min_t(int, sizeof(veth), len);
 		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;
 		len -= copy;
-		total += copy;
+		copied += copy;
 		if (ret || !len)
 		if (ret || !len)
 			goto done;
 			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:
 done:
 	tun->dev->stats.tx_packets++;
 	tun->dev->stats.tx_packets++;