diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 3d9481de031..0be4d24f6ae 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -559,6 +559,7 @@ static const struct proto_ops unix_stream_ops = { | |||
559 | .recvmsg = unix_stream_recvmsg, | 559 | .recvmsg = unix_stream_recvmsg, |
560 | .mmap = sock_no_mmap, | 560 | .mmap = sock_no_mmap, |
561 | .sendpage = sock_no_sendpage, | 561 | .sendpage = sock_no_sendpage, |
562 | .set_peek_off = unix_set_peek_off, | ||
562 | }; | 563 | }; |
563 | 564 | ||
564 | static const struct proto_ops unix_dgram_ops = { | 565 | static const struct proto_ops unix_dgram_ops = { |
@@ -1904,6 +1905,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1904 | int target; | 1905 | int target; |
1905 | int err = 0; | 1906 | int err = 0; |
1906 | long timeo; | 1907 | long timeo; |
1908 | int skip; | ||
1907 | 1909 | ||
1908 | err = -EINVAL; | 1910 | err = -EINVAL; |
1909 | if (sk->sk_state != TCP_ESTABLISHED) | 1911 | if (sk->sk_state != TCP_ESTABLISHED) |
@@ -1933,12 +1935,15 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1933 | goto out; | 1935 | goto out; |
1934 | } | 1936 | } |
1935 | 1937 | ||
1938 | skip = sk_peek_offset(sk, flags); | ||
1939 | |||
1936 | do { | 1940 | do { |
1937 | int chunk; | 1941 | int chunk; |
1938 | struct sk_buff *skb; | 1942 | struct sk_buff *skb; |
1939 | 1943 | ||
1940 | unix_state_lock(sk); | 1944 | unix_state_lock(sk); |
1941 | skb = skb_peek(&sk->sk_receive_queue); | 1945 | skb = skb_peek(&sk->sk_receive_queue); |
1946 | again: | ||
1942 | if (skb == NULL) { | 1947 | if (skb == NULL) { |
1943 | unix_sk(sk)->recursion_level = 0; | 1948 | unix_sk(sk)->recursion_level = 0; |
1944 | if (copied >= target) | 1949 | if (copied >= target) |
@@ -1973,6 +1978,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1973 | unix_state_unlock(sk); | 1978 | unix_state_unlock(sk); |
1974 | break; | 1979 | break; |
1975 | } | 1980 | } |
1981 | |||
1982 | if (skip >= skb->len) { | ||
1983 | skip -= skb->len; | ||
1984 | skb = skb_peek_next(skb, &sk->sk_receive_queue); | ||
1985 | goto again; | ||
1986 | } | ||
1987 | |||
1976 | unix_state_unlock(sk); | 1988 | unix_state_unlock(sk); |
1977 | 1989 | ||
1978 | if (check_creds) { | 1990 | if (check_creds) { |
@@ -1992,8 +2004,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1992 | sunaddr = NULL; | 2004 | sunaddr = NULL; |
1993 | } | 2005 | } |
1994 | 2006 | ||
1995 | chunk = min_t(unsigned int, skb->len, size); | 2007 | chunk = min_t(unsigned int, skb->len - skip, size); |
1996 | if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { | 2008 | if (memcpy_toiovec(msg->msg_iov, skb->data + skip, chunk)) { |
1997 | if (copied == 0) | 2009 | if (copied == 0) |
1998 | copied = -EFAULT; | 2010 | copied = -EFAULT; |
1999 | break; | 2011 | break; |
@@ -2005,6 +2017,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
2005 | if (!(flags & MSG_PEEK)) { | 2017 | if (!(flags & MSG_PEEK)) { |
2006 | skb_pull(skb, chunk); | 2018 | skb_pull(skb, chunk); |
2007 | 2019 | ||
2020 | sk_peek_offset_bwd(sk, chunk); | ||
2021 | |||
2008 | if (UNIXCB(skb).fp) | 2022 | if (UNIXCB(skb).fp) |
2009 | unix_detach_fds(siocb->scm, skb); | 2023 | unix_detach_fds(siocb->scm, skb); |
2010 | 2024 | ||
@@ -2022,6 +2036,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
2022 | if (UNIXCB(skb).fp) | 2036 | if (UNIXCB(skb).fp) |
2023 | siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); | 2037 | siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); |
2024 | 2038 | ||
2039 | sk_peek_offset_fwd(sk, chunk); | ||
2040 | |||
2025 | break; | 2041 | break; |
2026 | } | 2042 | } |
2027 | } while (size); | 2043 | } while (size); |