|
60 | 60 | #include <linux/if_arp.h> |
61 | 61 | #include <linux/if_ether.h> |
62 | 62 | #include <linux/if_tun.h> |
| 63 | +#include <linux/if_vlan.h> |
63 | 64 | #include <linux/crc32.h> |
64 | 65 | #include <linux/nsproxy.h> |
65 | 66 | #include <linux/virtio_net.h> |
@@ -1265,6 +1266,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, |
1265 | 1266 | { |
1266 | 1267 | struct tun_pi pi = { 0, skb->protocol }; |
1267 | 1268 | ssize_t total = 0; |
| 1269 | + int vlan_offset = 0; |
1268 | 1270 |
|
1269 | 1271 | if (!(tun->flags & TUN_NO_PI)) { |
1270 | 1272 | if ((len -= sizeof(pi)) < 0) |
@@ -1328,11 +1330,40 @@ static ssize_t tun_put_user(struct tun_struct *tun, |
1328 | 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); |
1334 | | - total += skb->len; |
| 1363 | + skb_copy_datagram_const_iovec(skb, vlan_offset, iv, total, len); |
| 1364 | + total += len; |
1335 | 1365 |
|
| 1366 | +done: |
1336 | 1367 | tun->dev->stats.tx_packets++; |
1337 | 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 | 1722 | tun_flow_init(tun); |
1692 | 1723 |
|
1693 | 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 | 1727 | dev->features = dev->hw_features; |
1696 | 1728 | dev->vlan_features = dev->features; |
1697 | 1729 |
|
|
0 commit comments