diff options
-rw-r--r-- | arch/alpha/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/arm/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/avr32/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/cris/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/frv/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/h8300/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/ia64/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/m32r/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/m68k/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/mips/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/mn10300/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/parisc/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/powerpc/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/socket.h | 1 | ||||
-rw-r--r-- | arch/xtensa/include/asm/socket.h | 1 | ||||
-rw-r--r-- | include/asm-generic/socket.h | 1 | ||||
-rw-r--r-- | include/linux/net.h | 1 | ||||
-rw-r--r-- | include/linux/skbuff.h | 20 | ||||
-rw-r--r-- | include/net/sock.h | 25 | ||||
-rw-r--r-- | net/core/datagram.c | 26 | ||||
-rw-r--r-- | net/core/sock.c | 13 | ||||
-rw-r--r-- | net/ipv4/udp.c | 4 | ||||
-rw-r--r-- | net/ipv6/udp.c | 4 | ||||
-rw-r--r-- | net/unix/af_unix.c | 50 |
25 files changed, 138 insertions, 22 deletions
diff --git a/arch/alpha/include/asm/socket.h b/arch/alpha/include/asm/socket.h index 082355f159e6..16449d330dae 100644 --- a/arch/alpha/include/asm/socket.h +++ b/arch/alpha/include/asm/socket.h @@ -71,6 +71,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/arm/include/asm/socket.h b/arch/arm/include/asm/socket.h index dec6f9afb3cf..d958c74e5260 100644 --- a/arch/arm/include/asm/socket.h +++ b/arch/arm/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/avr32/include/asm/socket.h b/arch/avr32/include/asm/socket.h index 247b88c760be..30078f98b3ab 100644 --- a/arch/avr32/include/asm/socket.h +++ b/arch/avr32/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* __ASM_AVR32_SOCKET_H */ diff --git a/arch/cris/include/asm/socket.h b/arch/cris/include/asm/socket.h index e269264df7c4..048aba64600c 100644 --- a/arch/cris/include/asm/socket.h +++ b/arch/cris/include/asm/socket.h @@ -66,6 +66,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/frv/include/asm/socket.h b/arch/frv/include/asm/socket.h index ce80fdadcce5..7a361810f3cc 100644 --- a/arch/frv/include/asm/socket.h +++ b/arch/frv/include/asm/socket.h @@ -64,6 +64,7 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/h8300/include/asm/socket.h b/arch/h8300/include/asm/socket.h index cf1daab6f27e..e7bbfcee5b99 100644 --- a/arch/h8300/include/asm/socket.h +++ b/arch/h8300/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/ia64/include/asm/socket.h b/arch/ia64/include/asm/socket.h index 4b03664e3fb5..ced62de9d5a9 100644 --- a/arch/ia64/include/asm/socket.h +++ b/arch/ia64/include/asm/socket.h @@ -73,5 +73,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_IA64_SOCKET_H */ diff --git a/arch/m32r/include/asm/socket.h b/arch/m32r/include/asm/socket.h index e8b8c5bb053c..696cb4c7ca4e 100644 --- a/arch/m32r/include/asm/socket.h +++ b/arch/m32r/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_M32R_SOCKET_H */ diff --git a/arch/m68k/include/asm/socket.h b/arch/m68k/include/asm/socket.h index d4708ce466e0..e8b41a6775f9 100644 --- a/arch/m68k/include/asm/socket.h +++ b/arch/m68k/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/mips/include/asm/socket.h b/arch/mips/include/asm/socket.h index ad5c0a7a02a7..52104872e9e3 100644 --- a/arch/mips/include/asm/socket.h +++ b/arch/mips/include/asm/socket.h @@ -84,6 +84,7 @@ To add: #define SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #ifdef __KERNEL__ diff --git a/arch/mn10300/include/asm/socket.h b/arch/mn10300/include/asm/socket.h index 876356d78522..013fcc51698f 100644 --- a/arch/mn10300/include/asm/socket.h +++ b/arch/mn10300/include/asm/socket.h @@ -64,5 +64,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h index d28c51b61067..f717c9bec16f 100644 --- a/arch/parisc/include/asm/socket.h +++ b/arch/parisc/include/asm/socket.h @@ -63,6 +63,7 @@ #define SO_WIFI_STATUS 0x4022 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x4023 /* O_NONBLOCK clashes with the bits used for socket types. Therefore we * have to define SOCK_NONBLOCK to a different value here. diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h index 2fc2af8fbf59..fe1c0b478fd7 100644 --- a/arch/powerpc/include/asm/socket.h +++ b/arch/powerpc/include/asm/socket.h @@ -71,5 +71,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_POWERPC_SOCKET_H */ diff --git a/arch/s390/include/asm/socket.h b/arch/s390/include/asm/socket.h index 67b5c1b14b51..581702fa1b0c 100644 --- a/arch/s390/include/asm/socket.h +++ b/arch/s390/include/asm/socket.h @@ -72,5 +72,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _ASM_SOCKET_H */ diff --git a/arch/sparc/include/asm/socket.h b/arch/sparc/include/asm/socket.h index 8af1b64168b3..68e2e2746f6f 100644 --- a/arch/sparc/include/asm/socket.h +++ b/arch/sparc/include/asm/socket.h @@ -60,6 +60,7 @@ #define SO_WIFI_STATUS 0x0025 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 0x0026 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/arch/xtensa/include/asm/socket.h b/arch/xtensa/include/asm/socket.h index bb06968be227..74818b161362 100644 --- a/arch/xtensa/include/asm/socket.h +++ b/arch/xtensa/include/asm/socket.h @@ -75,5 +75,6 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* _XTENSA_SOCKET_H */ diff --git a/include/asm-generic/socket.h b/include/asm-generic/socket.h index 49c1704173e7..d9aaac0c36d4 100644 --- a/include/asm-generic/socket.h +++ b/include/asm-generic/socket.h @@ -67,4 +67,5 @@ #define SO_WIFI_STATUS 41 #define SCM_WIFI_STATUS SO_WIFI_STATUS +#define SO_PEEK_OFF 42 #endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/include/linux/net.h b/include/linux/net.h index b29923006b11..be60c7f5e145 100644 --- a/include/linux/net.h +++ b/include/linux/net.h @@ -206,6 +206,7 @@ struct proto_ops { int offset, size_t size, int flags); ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, struct pipe_inode_info *pipe, size_t len, unsigned int flags); + void (*set_peek_off)(struct sock *sk, int val); }; #define DECLARE_SOCKADDR(type, dst, src) \ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2b7317ff297f..c11a44ea1bf4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -877,6 +877,24 @@ static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) } /** + * skb_peek_next - peek skb following the given one from a queue + * @skb: skb to start from + * @list_: list to peek at + * + * Returns %NULL when the end of the list is met or a pointer to the + * next element. The reference count is not incremented and the + * reference is therefore volatile. Use with caution. + */ +static inline struct sk_buff *skb_peek_next(struct sk_buff *skb, + const struct sk_buff_head *list_) +{ + struct sk_buff *next = skb->next; + if (next == (struct sk_buff *)list_) + next = NULL; + return next; +} + +/** * skb_peek_tail - peek at the tail of an &sk_buff_head * @list_: list to peek at * @@ -2046,7 +2064,7 @@ static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag) for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, - int *peeked, int *err); + int *peeked, int *off, int *err); extern struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock, diff --git a/include/net/sock.h b/include/net/sock.h index 91c1c8baf020..9c0553b9e451 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -357,6 +357,7 @@ struct sock { struct page *sk_sndmsg_page; struct sk_buff *sk_send_head; __u32 sk_sndmsg_off; + __s32 sk_peek_off; int sk_write_pending; #ifdef CONFIG_SECURITY void *sk_security; @@ -373,6 +374,30 @@ struct sock { void (*sk_destruct)(struct sock *sk); }; +static inline int sk_peek_offset(struct sock *sk, int flags) +{ + if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0)) + return sk->sk_peek_off; + else + return 0; +} + +static inline void sk_peek_offset_bwd(struct sock *sk, int val) +{ + if (sk->sk_peek_off >= 0) { + if (sk->sk_peek_off >= val) + sk->sk_peek_off -= val; + else + sk->sk_peek_off = 0; + } +} + +static inline void sk_peek_offset_fwd(struct sock *sk, int val) +{ + if (sk->sk_peek_off >= 0) + sk->sk_peek_off += val; +} + /* * Hashed lists helper routines */ diff --git a/net/core/datagram.c b/net/core/datagram.c index 68bbf9f65cb0..d3cf12f62c8f 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -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; @@ -180,21 +182,25 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, * However, this function was correct in any case. 8) */ unsigned long cpu_flags; + struct sk_buff_head *queue = &sk->sk_receive_queue; - spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) { + spin_lock_irqsave(&queue->lock, cpu_flags); + 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, &sk->sk_receive_queue); - } - spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); + __skb_unlink(skb, queue); - 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; @@ -214,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); diff --git a/net/core/sock.c b/net/core/sock.c index 02f8dfe320b7..19942d4bb6e6 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -793,6 +793,12 @@ set_rcvbuf: sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool); break; + case SO_PEEK_OFF: + if (sock->ops->set_peek_off) + sock->ops->set_peek_off(sk, val); + else + ret = -EOPNOTSUPP; + break; default: ret = -ENOPROTOOPT; break; @@ -1018,6 +1024,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = !!sock_flag(sk, SOCK_WIFI_STATUS); break; + case SO_PEEK_OFF: + if (!sock->ops->set_peek_off) + return -EOPNOTSUPP; + + v.val = sk->sk_peek_off; + break; default: return -ENOPROTOOPT; } @@ -2092,6 +2104,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; + sk->sk_peek_off = -1; sk->sk_peer_pid = NULL; sk->sk_peer_cred = NULL; 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, struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; unsigned int ulen, copied; - int peeked; + int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); bool slow; @@ -1183,7 +1183,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, try_again: skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); + &peeked, &off, &err); if (!skb) goto out; 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, struct inet_sock *inet = inet_sk(sk); struct sk_buff *skb; unsigned int ulen, copied; - int peeked; + int peeked, off = 0; int err; int is_udplite = IS_UDPLITE(sk); int is_udp4; @@ -359,7 +359,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, try_again: skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); + &peeked, &off, &err); if (!skb) goto out; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 85d3bb7490aa..0be4d24f6ae8 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *, static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, struct msghdr *, size_t, int); +static void unix_set_peek_off(struct sock *sk, int val) +{ + struct unix_sock *u = unix_sk(sk); + + mutex_lock(&u->readlock); + sk->sk_peek_off = val; + mutex_unlock(&u->readlock); +} + + static const struct proto_ops unix_stream_ops = { .family = PF_UNIX, .owner = THIS_MODULE, @@ -549,6 +559,7 @@ static const struct proto_ops unix_stream_ops = { .recvmsg = unix_stream_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_dgram_ops = { @@ -570,6 +581,7 @@ static const struct proto_ops unix_dgram_ops = { .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static const struct proto_ops unix_seqpacket_ops = { @@ -591,6 +603,7 @@ static const struct proto_ops unix_seqpacket_ops = { .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, }; static struct proto unix_proto = { @@ -1756,6 +1769,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, int noblock = flags & MSG_DONTWAIT; struct sk_buff *skb; int err; + int peeked, skip; err = -EOPNOTSUPP; if (flags&MSG_OOB) @@ -1769,7 +1783,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skb = skb_recv_datagram(sk, flags, noblock, &err); + skip = sk_peek_offset(sk, flags); + + skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err); if (!skb) { unix_state_lock(sk); /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ @@ -1786,12 +1802,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, if (msg->msg_name) unix_copy_addr(msg, skb->sk); - if (size > skb->len) - size = skb->len; - else if (size < skb->len) + if (size > skb->len - skip) + size = skb->len - skip; + else if (size < skb->len - skip) msg->msg_flags |= MSG_TRUNC; - err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size); + err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size); if (err) goto out_free; @@ -1808,6 +1824,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, if (!(flags & MSG_PEEK)) { if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); + + sk_peek_offset_bwd(sk, skb->len); } else { /* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8) @@ -1821,6 +1839,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, clearly however! */ + + sk_peek_offset_fwd(sk, size); + if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); } @@ -1884,6 +1905,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, int target; int err = 0; long timeo; + int skip; err = -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) @@ -1913,12 +1935,15 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } + skip = sk_peek_offset(sk, flags); + do { int chunk; struct sk_buff *skb; unix_state_lock(sk); skb = skb_peek(&sk->sk_receive_queue); +again: if (skb == NULL) { unix_sk(sk)->recursion_level = 0; if (copied >= target) @@ -1953,6 +1978,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, unix_state_unlock(sk); break; } + + if (skip >= skb->len) { + skip -= skb->len; + skb = skb_peek_next(skb, &sk->sk_receive_queue); + goto again; + } + unix_state_unlock(sk); if (check_creds) { @@ -1972,8 +2004,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, sunaddr = NULL; } - chunk = min_t(unsigned int, skb->len, size); - if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { + chunk = min_t(unsigned int, skb->len - skip, size); + if (memcpy_toiovec(msg->msg_iov, skb->data + skip, chunk)) { if (copied == 0) copied = -EFAULT; break; @@ -1985,6 +2017,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (!(flags & MSG_PEEK)) { skb_pull(skb, chunk); + sk_peek_offset_bwd(sk, chunk); + if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); @@ -2002,6 +2036,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (UNIXCB(skb).fp) siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); + sk_peek_offset_fwd(sk, chunk); + break; } } while (size); |