diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-08 20:39:29 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-08 20:39:29 -0500 |
commit | ba00410b8131b23edfb0e09f8b6dd26c8eb621fb (patch) | |
tree | c08504e4d2fa51ac91cef544f336d0169806c49f /drivers/net/tun.c | |
parent | 8ce74dd6057832618957fc2cbd38fa959c3a0a6c (diff) | |
parent | aa583096d9767892983332e7c1a984bd17e3cd39 (diff) |
Merge branch 'iov_iter' into for-next
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 53 |
1 files changed, 33 insertions, 20 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index a3420e091689..4d332dc93b70 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -65,6 +65,7 @@ | |||
65 | #include <linux/nsproxy.h> | 65 | #include <linux/nsproxy.h> |
66 | #include <linux/virtio_net.h> | 66 | #include <linux/virtio_net.h> |
67 | #include <linux/rcupdate.h> | 67 | #include <linux/rcupdate.h> |
68 | #include <net/ipv6.h> | ||
68 | #include <net/net_namespace.h> | 69 | #include <net/net_namespace.h> |
69 | #include <net/netns/generic.h> | 70 | #include <net/netns/generic.h> |
70 | #include <net/rtnetlink.h> | 71 | #include <net/rtnetlink.h> |
@@ -174,7 +175,7 @@ struct tun_struct { | |||
174 | struct net_device *dev; | 175 | struct net_device *dev; |
175 | netdev_features_t set_features; | 176 | netdev_features_t set_features; |
176 | #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ | 177 | #define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \ |
177 | NETIF_F_TSO6|NETIF_F_UFO) | 178 | NETIF_F_TSO6) |
178 | 179 | ||
179 | int vnet_hdr_sz; | 180 | int vnet_hdr_sz; |
180 | int sndbuf; | 181 | int sndbuf; |
@@ -1139,6 +1140,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1139 | break; | 1140 | break; |
1140 | } | 1141 | } |
1141 | 1142 | ||
1143 | skb_reset_network_header(skb); | ||
1144 | |||
1142 | if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { | 1145 | if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) { |
1143 | pr_debug("GSO!\n"); | 1146 | pr_debug("GSO!\n"); |
1144 | switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { | 1147 | switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { |
@@ -1149,8 +1152,20 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1149 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; | 1152 | skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; |
1150 | break; | 1153 | break; |
1151 | case VIRTIO_NET_HDR_GSO_UDP: | 1154 | case VIRTIO_NET_HDR_GSO_UDP: |
1155 | { | ||
1156 | static bool warned; | ||
1157 | |||
1158 | if (!warned) { | ||
1159 | warned = true; | ||
1160 | netdev_warn(tun->dev, | ||
1161 | "%s: using disabled UFO feature; please fix this program\n", | ||
1162 | current->comm); | ||
1163 | } | ||
1152 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; | 1164 | skb_shinfo(skb)->gso_type = SKB_GSO_UDP; |
1165 | if (skb->protocol == htons(ETH_P_IPV6)) | ||
1166 | ipv6_proxy_select_ident(skb); | ||
1153 | break; | 1167 | break; |
1168 | } | ||
1154 | default: | 1169 | default: |
1155 | tun->dev->stats.rx_frame_errors++; | 1170 | tun->dev->stats.rx_frame_errors++; |
1156 | kfree_skb(skb); | 1171 | kfree_skb(skb); |
@@ -1179,7 +1194,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, | |||
1179 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; | 1194 | skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; |
1180 | } | 1195 | } |
1181 | 1196 | ||
1182 | skb_reset_network_header(skb); | ||
1183 | skb_probe_transport_header(skb, 0); | 1197 | skb_probe_transport_header(skb, 0); |
1184 | 1198 | ||
1185 | rxhash = skb_get_hash(skb); | 1199 | rxhash = skb_get_hash(skb); |
@@ -1221,12 +1235,20 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1221 | struct tun_pi pi = { 0, skb->protocol }; | 1235 | struct tun_pi pi = { 0, skb->protocol }; |
1222 | ssize_t total = 0; | 1236 | ssize_t total = 0; |
1223 | int vlan_offset = 0, copied; | 1237 | int vlan_offset = 0, copied; |
1238 | int vlan_hlen = 0; | ||
1239 | int vnet_hdr_sz = 0; | ||
1240 | |||
1241 | if (vlan_tx_tag_present(skb)) | ||
1242 | vlan_hlen = VLAN_HLEN; | ||
1243 | |||
1244 | if (tun->flags & TUN_VNET_HDR) | ||
1245 | vnet_hdr_sz = tun->vnet_hdr_sz; | ||
1224 | 1246 | ||
1225 | if (!(tun->flags & TUN_NO_PI)) { | 1247 | if (!(tun->flags & TUN_NO_PI)) { |
1226 | if ((len -= sizeof(pi)) < 0) | 1248 | if ((len -= sizeof(pi)) < 0) |
1227 | return -EINVAL; | 1249 | return -EINVAL; |
1228 | 1250 | ||
1229 | if (len < skb->len) { | 1251 | if (len < skb->len + vlan_hlen + vnet_hdr_sz) { |
1230 | /* Packet will be striped */ | 1252 | /* Packet will be striped */ |
1231 | pi.flags |= TUN_PKT_STRIP; | 1253 | pi.flags |= TUN_PKT_STRIP; |
1232 | } | 1254 | } |
@@ -1236,9 +1258,9 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1236 | total += sizeof(pi); | 1258 | total += sizeof(pi); |
1237 | } | 1259 | } |
1238 | 1260 | ||
1239 | if (tun->flags & TUN_VNET_HDR) { | 1261 | if (vnet_hdr_sz) { |
1240 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ | 1262 | struct virtio_net_hdr gso = { 0 }; /* no info leak */ |
1241 | if ((len -= tun->vnet_hdr_sz) < 0) | 1263 | if ((len -= vnet_hdr_sz) < 0) |
1242 | return -EINVAL; | 1264 | return -EINVAL; |
1243 | 1265 | ||
1244 | if (skb_is_gso(skb)) { | 1266 | if (skb_is_gso(skb)) { |
@@ -1251,8 +1273,6 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1251 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; | 1273 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4; |
1252 | else if (sinfo->gso_type & SKB_GSO_TCPV6) | 1274 | else if (sinfo->gso_type & SKB_GSO_TCPV6) |
1253 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; | 1275 | gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6; |
1254 | else if (sinfo->gso_type & SKB_GSO_UDP) | ||
1255 | gso.gso_type = VIRTIO_NET_HDR_GSO_UDP; | ||
1256 | else { | 1276 | else { |
1257 | pr_err("unexpected GSO type: " | 1277 | pr_err("unexpected GSO type: " |
1258 | "0x%x, gso_size %d, hdr_len %d\n", | 1278 | "0x%x, gso_size %d, hdr_len %d\n", |
@@ -1272,7 +1292,8 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1272 | 1292 | ||
1273 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1293 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1274 | gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; | 1294 | gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; |
1275 | gso.csum_start = skb_checksum_start_offset(skb); | 1295 | gso.csum_start = skb_checksum_start_offset(skb) + |
1296 | vlan_hlen; | ||
1276 | gso.csum_offset = skb->csum_offset; | 1297 | gso.csum_offset = skb->csum_offset; |
1277 | } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { | 1298 | } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { |
1278 | gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; | 1299 | gso.flags = VIRTIO_NET_HDR_F_DATA_VALID; |
@@ -1281,14 +1302,13 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1281 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, | 1302 | if (unlikely(memcpy_toiovecend(iv, (void *)&gso, total, |
1282 | sizeof(gso)))) | 1303 | sizeof(gso)))) |
1283 | return -EFAULT; | 1304 | return -EFAULT; |
1284 | total += tun->vnet_hdr_sz; | 1305 | total += vnet_hdr_sz; |
1285 | } | 1306 | } |
1286 | 1307 | ||
1287 | copied = total; | 1308 | copied = total; |
1288 | total += skb->len; | 1309 | len = min_t(int, skb->len + vlan_hlen, len); |
1289 | if (!vlan_tx_tag_present(skb)) { | 1310 | total += skb->len + vlan_hlen; |
1290 | len = min_t(int, skb->len, len); | 1311 | if (vlan_hlen) { |
1291 | } else { | ||
1292 | int copy, ret; | 1312 | int copy, ret; |
1293 | struct { | 1313 | struct { |
1294 | __be16 h_vlan_proto; | 1314 | __be16 h_vlan_proto; |
@@ -1299,8 +1319,6 @@ static ssize_t tun_put_user(struct tun_struct *tun, | |||
1299 | veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); | 1319 | veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb)); |
1300 | 1320 | ||
1301 | vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); | 1321 | vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto); |
1302 | len = min_t(int, skb->len + VLAN_HLEN, len); | ||
1303 | total += VLAN_HLEN; | ||
1304 | 1322 | ||
1305 | copy = min_t(int, vlan_offset, len); | 1323 | copy = min_t(int, vlan_offset, len); |
1306 | ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); | 1324 | ret = skb_copy_datagram_const_iovec(skb, 0, iv, copied, copy); |
@@ -1762,11 +1780,6 @@ static int set_offload(struct tun_struct *tun, unsigned long arg) | |||
1762 | features |= NETIF_F_TSO6; | 1780 | features |= NETIF_F_TSO6; |
1763 | arg &= ~(TUN_F_TSO4|TUN_F_TSO6); | 1781 | arg &= ~(TUN_F_TSO4|TUN_F_TSO6); |
1764 | } | 1782 | } |
1765 | |||
1766 | if (arg & TUN_F_UFO) { | ||
1767 | features |= NETIF_F_UFO; | ||
1768 | arg &= ~TUN_F_UFO; | ||
1769 | } | ||
1770 | } | 1783 | } |
1771 | 1784 | ||
1772 | /* This gives the user a way to test for new features in future by | 1785 | /* This gives the user a way to test for new features in future by |