diff options
Diffstat (limited to 'drivers/net/tun.c')
-rw-r--r-- | drivers/net/tun.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 95749006d687..4f4a842a1c9c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c | |||
@@ -1952,8 +1952,11 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile, | |||
1952 | 1952 | ||
1953 | tun_debug(KERN_INFO, tun, "tun_do_read\n"); | 1953 | tun_debug(KERN_INFO, tun, "tun_do_read\n"); |
1954 | 1954 | ||
1955 | if (!iov_iter_count(to)) | 1955 | if (!iov_iter_count(to)) { |
1956 | if (skb) | ||
1957 | kfree_skb(skb); | ||
1956 | return 0; | 1958 | return 0; |
1959 | } | ||
1957 | 1960 | ||
1958 | if (!skb) { | 1961 | if (!skb) { |
1959 | /* Read frames from ring */ | 1962 | /* Read frames from ring */ |
@@ -2069,22 +2072,24 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, | |||
2069 | { | 2072 | { |
2070 | struct tun_file *tfile = container_of(sock, struct tun_file, socket); | 2073 | struct tun_file *tfile = container_of(sock, struct tun_file, socket); |
2071 | struct tun_struct *tun = tun_get(tfile); | 2074 | struct tun_struct *tun = tun_get(tfile); |
2075 | struct sk_buff *skb = m->msg_control; | ||
2072 | int ret; | 2076 | int ret; |
2073 | 2077 | ||
2074 | if (!tun) | 2078 | if (!tun) { |
2075 | return -EBADFD; | 2079 | ret = -EBADFD; |
2080 | goto out_free_skb; | ||
2081 | } | ||
2076 | 2082 | ||
2077 | if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { | 2083 | if (flags & ~(MSG_DONTWAIT|MSG_TRUNC|MSG_ERRQUEUE)) { |
2078 | ret = -EINVAL; | 2084 | ret = -EINVAL; |
2079 | goto out; | 2085 | goto out_put_tun; |
2080 | } | 2086 | } |
2081 | if (flags & MSG_ERRQUEUE) { | 2087 | if (flags & MSG_ERRQUEUE) { |
2082 | ret = sock_recv_errqueue(sock->sk, m, total_len, | 2088 | ret = sock_recv_errqueue(sock->sk, m, total_len, |
2083 | SOL_PACKET, TUN_TX_TIMESTAMP); | 2089 | SOL_PACKET, TUN_TX_TIMESTAMP); |
2084 | goto out; | 2090 | goto out; |
2085 | } | 2091 | } |
2086 | ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, | 2092 | ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT, skb); |
2087 | m->msg_control); | ||
2088 | if (ret > (ssize_t)total_len) { | 2093 | if (ret > (ssize_t)total_len) { |
2089 | m->msg_flags |= MSG_TRUNC; | 2094 | m->msg_flags |= MSG_TRUNC; |
2090 | ret = flags & MSG_TRUNC ? ret : total_len; | 2095 | ret = flags & MSG_TRUNC ? ret : total_len; |
@@ -2092,6 +2097,13 @@ static int tun_recvmsg(struct socket *sock, struct msghdr *m, size_t total_len, | |||
2092 | out: | 2097 | out: |
2093 | tun_put(tun); | 2098 | tun_put(tun); |
2094 | return ret; | 2099 | return ret; |
2100 | |||
2101 | out_put_tun: | ||
2102 | tun_put(tun); | ||
2103 | out_free_skb: | ||
2104 | if (skb) | ||
2105 | kfree_skb(skb); | ||
2106 | return ret; | ||
2095 | } | 2107 | } |
2096 | 2108 | ||
2097 | static int tun_peek_len(struct socket *sock) | 2109 | static int tun_peek_len(struct socket *sock) |