aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/skbuff.h2
-rw-r--r--net/core/datagram.c21
-rw-r--r--net/ipv4/udp.c4
-rw-r--r--net/ipv6/udp.c4
4 files changed, 18 insertions, 13 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2b7317ff297f..f3cf43de3c2a 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2046,7 +2046,7 @@ static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag)
2046 for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) 2046 for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next)
2047 2047
2048extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, 2048extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
2049 int *peeked, int *err); 2049 int *peeked, int *off, int *err);
2050extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, 2050extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
2051 int noblock, int *err); 2051 int noblock, int *err);
2052extern unsigned int datagram_poll(struct file *file, struct socket *sock, 2052extern unsigned int datagram_poll(struct file *file, struct socket *sock,
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 6f54d0a17f8e..d3cf12f62c8f 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -132,6 +132,8 @@ out_noerr:
132 * __skb_recv_datagram - Receive a datagram skbuff 132 * __skb_recv_datagram - Receive a datagram skbuff
133 * @sk: socket 133 * @sk: socket
134 * @flags: MSG_ flags 134 * @flags: MSG_ flags
135 * @off: an offset in bytes to peek skb from. Returns an offset
136 * within an skb where data actually starts
135 * @peeked: returns non-zero if this packet has been seen before 137 * @peeked: returns non-zero if this packet has been seen before
136 * @err: error code returned 138 * @err: error code returned
137 * 139 *
@@ -158,7 +160,7 @@ out_noerr:
158 * the standard around please. 160 * the standard around please.
159 */ 161 */
160struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, 162struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
161 int *peeked, int *err) 163 int *peeked, int *off, int *err)
162{ 164{
163 struct sk_buff *skb; 165 struct sk_buff *skb;
164 long timeo; 166 long timeo;
@@ -183,19 +185,22 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
183 struct sk_buff_head *queue = &sk->sk_receive_queue; 185 struct sk_buff_head *queue = &sk->sk_receive_queue;
184 186
185 spin_lock_irqsave(&queue->lock, cpu_flags); 187 spin_lock_irqsave(&queue->lock, cpu_flags);
186 skb = skb_peek(queue); 188 skb_queue_walk(queue, skb) {
187 if (skb) {
188 *peeked = skb->peeked; 189 *peeked = skb->peeked;
189 if (flags & MSG_PEEK) { 190 if (flags & MSG_PEEK) {
191 if (*off >= skb->len) {
192 *off -= skb->len;
193 continue;
194 }
190 skb->peeked = 1; 195 skb->peeked = 1;
191 atomic_inc(&skb->users); 196 atomic_inc(&skb->users);
192 } else 197 } else
193 __skb_unlink(skb, queue); 198 __skb_unlink(skb, queue);
194 }
195 spin_unlock_irqrestore(&queue->lock, cpu_flags);
196 199
197 if (skb) 200 spin_unlock_irqrestore(&queue->lock, cpu_flags);
198 return skb; 201 return skb;
202 }
203 spin_unlock_irqrestore(&queue->lock, cpu_flags);
199 204
200 /* User doesn't want to wait */ 205 /* User doesn't want to wait */
201 error = -EAGAIN; 206 error = -EAGAIN;
@@ -215,10 +220,10 @@ EXPORT_SYMBOL(__skb_recv_datagram);
215struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, 220struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
216 int noblock, int *err) 221 int noblock, int *err)
217{ 222{
218 int peeked; 223 int peeked, off = 0;
219 224
220 return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), 225 return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
221 &peeked, err); 226 &peeked, &off, err);
222} 227}
223EXPORT_SYMBOL(skb_recv_datagram); 228EXPORT_SYMBOL(skb_recv_datagram);
224 229
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index cd99f1a0f59f..7c41ab84e72e 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1167,7 +1167,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1167 struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; 1167 struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;
1168 struct sk_buff *skb; 1168 struct sk_buff *skb;
1169 unsigned int ulen, copied; 1169 unsigned int ulen, copied;
1170 int peeked; 1170 int peeked, off = 0;
1171 int err; 1171 int err;
1172 int is_udplite = IS_UDPLITE(sk); 1172 int is_udplite = IS_UDPLITE(sk);
1173 bool slow; 1173 bool slow;
@@ -1183,7 +1183,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
1183 1183
1184try_again: 1184try_again:
1185 skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), 1185 skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
1186 &peeked, &err); 1186 &peeked, &off, &err);
1187 if (!skb) 1187 if (!skb)
1188 goto out; 1188 goto out;
1189 1189
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8aebf8f90436..37b0699e95e5 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -342,7 +342,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
342 struct inet_sock *inet = inet_sk(sk); 342 struct inet_sock *inet = inet_sk(sk);
343 struct sk_buff *skb; 343 struct sk_buff *skb;
344 unsigned int ulen, copied; 344 unsigned int ulen, copied;
345 int peeked; 345 int peeked, off = 0;
346 int err; 346 int err;
347 int is_udplite = IS_UDPLITE(sk); 347 int is_udplite = IS_UDPLITE(sk);
348 int is_udp4; 348 int is_udp4;
@@ -359,7 +359,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,
359 359
360try_again: 360try_again:
361 skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), 361 skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
362 &peeked, &err); 362 &peeked, &off, &err);
363 if (!skb) 363 if (!skb)
364 goto out; 364 goto out;
365 365