diff options
-rw-r--r-- | include/linux/skbuff.h | 2 | ||||
-rw-r--r-- | net/core/datagram.c | 21 | ||||
-rw-r--r-- | net/ipv4/udp.c | 4 | ||||
-rw-r--r-- | net/ipv6/udp.c | 4 |
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 | ||
2048 | extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, | 2048 | extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, |
2049 | int *peeked, int *err); | 2049 | int *peeked, int *off, int *err); |
2050 | extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | 2050 | extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, |
2051 | int noblock, int *err); | 2051 | int noblock, int *err); |
2052 | extern unsigned int datagram_poll(struct file *file, struct socket *sock, | 2052 | extern 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 | */ |
160 | struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, | 162 | struct 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); | |||
215 | struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, | 220 | struct 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 | } |
223 | EXPORT_SYMBOL(skb_recv_datagram); | 228 | EXPORT_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 | ||
1184 | try_again: | 1184 | try_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 | ||
360 | try_again: | 360 | try_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 | ||