aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2012-02-21 02:30:58 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-21 14:58:57 -0500
commit3f518bf745cbd6007d8069100fb9cb09e960c872 (patch)
treedebbe9e9340d46080f1b82e4149a2427545c4aef
parent4934b0329f7150dcb5f90506860e2db32274c755 (diff)
datagram: Add offset argument to __skb_recv_datagram
This one is only considered for MSG_PEEK flag and the value pointed by it specifies where to start peeking bytes from. If the offset happens to point into the middle of the returned skb, the offset within this skb is put back to this very argument. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-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