diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 782e38bfc1ee..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 | ||
1284 | done: | 1286 | done: |
1285 | tun->dev->stats.tx_packets++; | 1287 | tun->dev->stats.tx_packets++; |
@@ -1356,6 +1358,8 @@ static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv, | |||
1356 | ret = tun_do_read(tun, tfile, iocb, iv, len, | 1358 | ret = tun_do_read(tun, tfile, iocb, iv, len, |
1357 | file->f_flags & O_NONBLOCK); | 1359 | file->f_flags & O_NONBLOCK); |
1358 | ret = min_t(ssize_t, ret, len); | 1360 | ret = min_t(ssize_t, ret, len); |
1361 | if (ret > 0) | ||
1362 | iocb->ki_pos = ret; | ||
1359 | out: | 1363 | out: |
1360 | tun_put(tun); | 1364 | tun_put(tun); |
1361 | return ret; | 1365 | return ret; |