datagram: Add offset argument to __skb_recv_datagram
[~shefty/rdma-dev.git] / net / core / datagram.c
index 6f54d0a17f8e6baa7098bcc5ac0fede07307b399..d3cf12f62c8f213fc2c2a33797c1749f1d18be88 100644 (file)
@@ -132,6 +132,8 @@ out_noerr:
  *     __skb_recv_datagram - Receive a datagram skbuff
  *     @sk: socket
  *     @flags: MSG_ flags
+ *     @off: an offset in bytes to peek skb from. Returns an offset
+ *           within an skb where data actually starts
  *     @peeked: returns non-zero if this packet has been seen before
  *     @err: error code returned
  *
@@ -158,7 +160,7 @@ out_noerr:
  *     the standard around please.
  */
 struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
-                                   int *peeked, int *err)
+                                   int *peeked, int *off, int *err)
 {
        struct sk_buff *skb;
        long timeo;
@@ -183,19 +185,22 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
                struct sk_buff_head *queue = &sk->sk_receive_queue;
 
                spin_lock_irqsave(&queue->lock, cpu_flags);
-               skb = skb_peek(queue);
-               if (skb) {
+               skb_queue_walk(queue, skb) {
                        *peeked = skb->peeked;
                        if (flags & MSG_PEEK) {
+                               if (*off >= skb->len) {
+                                       *off -= skb->len;
+                                       continue;
+                               }
                                skb->peeked = 1;
                                atomic_inc(&skb->users);
                        } else
                                __skb_unlink(skb, queue);
-               }
-               spin_unlock_irqrestore(&queue->lock, cpu_flags);
 
-               if (skb)
+                       spin_unlock_irqrestore(&queue->lock, cpu_flags);
                        return skb;
+               }
+               spin_unlock_irqrestore(&queue->lock, cpu_flags);
 
                /* User doesn't want to wait */
                error = -EAGAIN;
@@ -215,10 +220,10 @@ EXPORT_SYMBOL(__skb_recv_datagram);
 struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
                                  int noblock, int *err)
 {
-       int peeked;
+       int peeked, off = 0;
 
        return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
-                                  &peeked, err);
+                                  &peeked, &off, err);
 }
 EXPORT_SYMBOL(skb_recv_datagram);