aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/tun.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index a72d141047cb..5dce262f538e 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -60,6 +60,7 @@
60#include <linux/if_arp.h> 60#include <linux/if_arp.h>
61#include <linux/if_ether.h> 61#include <linux/if_ether.h>
62#include <linux/if_tun.h> 62#include <linux/if_tun.h>
63#include <linux/if_vlan.h>
63#include <linux/crc32.h> 64#include <linux/crc32.h>
64#include <linux/nsproxy.h> 65#include <linux/nsproxy.h>
65#include <linux/virtio_net.h> 66#include <linux/virtio_net.h>
@@ -1265,6 +1266,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1265{ 1266{
1266 struct tun_pi pi = { 0, skb->protocol }; 1267 struct tun_pi pi = { 0, skb->protocol };
1267 ssize_t total = 0; 1268 ssize_t total = 0;
1269 int vlan_offset = 0;
1268 1270
1269 if (!(tun->flags & TUN_NO_PI)) { 1271 if (!(tun->flags & TUN_NO_PI)) {
1270 if ((len -= sizeof(pi)) < 0) 1272 if ((len -= sizeof(pi)) < 0)
@@ -1328,11 +1330,40 @@ static ssize_t tun_put_user(struct tun_struct *tun,
1328 total += tun->vnet_hdr_sz; 1330 total += tun->vnet_hdr_sz;
1329 } 1331 }
1330 1332
1331 len = min_t(int, skb->len, len); 1333 if (!vlan_tx_tag_present(skb)) {
1334 len = min_t(int, skb->len, len);
1335 } else {
1336 int copy, ret;
1337 struct {
1338 __be16 h_vlan_proto;
1339 __be16 h_vlan_TCI;
1340 } veth;
1341
1342 veth.h_vlan_proto = skb->vlan_proto;
1343 veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
1344
1345 vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
1346 len = min_t(int, skb->len + VLAN_HLEN, len);
1347
1348 copy = min_t(int, vlan_offset, len);
1349 ret = skb_copy_datagram_const_iovec(skb, 0, iv, total, copy);
1350 len -= copy;
1351 total += copy;
1352 if (ret || !len)
1353 goto done;
1354
1355 copy = min_t(int, sizeof(veth), len);
1356 ret = memcpy_toiovecend(iv, (void *)&veth, total, copy);
1357 len -= copy;
1358 total += copy;
1359 if (ret || !len)
1360 goto done;
1361 }
1332 1362
1333 skb_copy_datagram_const_iovec(skb, 0, iv, total, len); 1363 skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len);
1334 total += skb->len; 1364 total += len;
1335 1365
1366done:
1336 tun->dev->stats.tx_packets++; 1367 tun->dev->stats.tx_packets++;
1337 tun->dev->stats.tx_bytes += len; 1368 tun->dev->stats.tx_bytes += len;
1338 1369
@@ -1691,7 +1722,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
1691 tun_flow_init(tun); 1722 tun_flow_init(tun);
1692 1723
1693 dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | 1724 dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST |
1694 TUN_USER_FEATURES; 1725 TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX |
1726 NETIF_F_HW_VLAN_STAG_TX;
1695 dev->features = dev->hw_features; 1727 dev->features = dev->hw_features;
1696 dev->vlan_features = dev->features; 1728 dev->vlan_features = dev->features;
1697 1729