diff options
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 4028ddd14dd5..868ed74a76a8 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1889,6 +1889,22 @@ static void tcp_recv_timestamp(struct msghdr *msg, const struct sock *sk, | |||
1889 | } | 1889 | } |
1890 | } | 1890 | } |
1891 | 1891 | ||
1892 | static int tcp_inq_hint(struct sock *sk) | ||
1893 | { | ||
1894 | const struct tcp_sock *tp = tcp_sk(sk); | ||
1895 | u32 copied_seq = READ_ONCE(tp->copied_seq); | ||
1896 | u32 rcv_nxt = READ_ONCE(tp->rcv_nxt); | ||
1897 | int inq; | ||
1898 | |||
1899 | inq = rcv_nxt - copied_seq; | ||
1900 | if (unlikely(inq < 0 || copied_seq != READ_ONCE(tp->copied_seq))) { | ||
1901 | lock_sock(sk); | ||
1902 | inq = tp->rcv_nxt - tp->copied_seq; | ||
1903 | release_sock(sk); | ||
1904 | } | ||
1905 | return inq; | ||
1906 | } | ||
1907 | |||
1892 | /* | 1908 | /* |
1893 | * This routine copies from a sock struct into the user buffer. | 1909 | * This routine copies from a sock struct into the user buffer. |
1894 | * | 1910 | * |
@@ -1905,13 +1921,14 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, | |||
1905 | u32 peek_seq; | 1921 | u32 peek_seq; |
1906 | u32 *seq; | 1922 | u32 *seq; |
1907 | unsigned long used; | 1923 | unsigned long used; |
1908 | int err; | 1924 | int err, inq; |
1909 | int target; /* Read at least this many bytes */ | 1925 | int target; /* Read at least this many bytes */ |
1910 | long timeo; | 1926 | long timeo; |
1911 | struct sk_buff *skb, *last; | 1927 | struct sk_buff *skb, *last; |
1912 | u32 urg_hole = 0; | 1928 | u32 urg_hole = 0; |
1913 | struct scm_timestamping tss; | 1929 | struct scm_timestamping tss; |
1914 | bool has_tss = false; | 1930 | bool has_tss = false; |
1931 | bool has_cmsg; | ||
1915 | 1932 | ||
1916 | if (unlikely(flags & MSG_ERRQUEUE)) | 1933 | if (unlikely(flags & MSG_ERRQUEUE)) |
1917 | return inet_recv_error(sk, msg, len, addr_len); | 1934 | return inet_recv_error(sk, msg, len, addr_len); |
@@ -1926,6 +1943,7 @@ int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, | |||
1926 | if (sk->sk_state == TCP_LISTEN) | 1943 | if (sk->sk_state == TCP_LISTEN) |
1927 | goto out; | 1944 | goto out; |
1928 | 1945 | ||
1946 | has_cmsg = tp->recvmsg_inq; | ||
1929 | timeo = sock_rcvtimeo(sk, nonblock); | 1947 | timeo = sock_rcvtimeo(sk, nonblock); |
1930 | 1948 | ||
1931 | /* Urgent data needs to be handled specially. */ | 1949 | /* Urgent data needs to be handled specially. */ |
@@ -2112,6 +2130,7 @@ skip_copy: | |||
2112 | if (TCP_SKB_CB(skb)->has_rxtstamp) { | 2130 | if (TCP_SKB_CB(skb)->has_rxtstamp) { |
2113 | tcp_update_recv_tstamps(skb, &tss); | 2131 | tcp_update_recv_tstamps(skb, &tss); |
2114 | has_tss = true; | 2132 | has_tss = true; |
2133 | has_cmsg = true; | ||
2115 | } | 2134 | } |
2116 | if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) | 2135 | if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) |
2117 | goto found_fin_ok; | 2136 | goto found_fin_ok; |
@@ -2131,13 +2150,20 @@ skip_copy: | |||
2131 | * on connected socket. I was just happy when found this 8) --ANK | 2150 | * on connected socket. I was just happy when found this 8) --ANK |
2132 | */ | 2151 | */ |
2133 | 2152 | ||
2134 | if (has_tss) | ||
2135 | tcp_recv_timestamp(msg, sk, &tss); | ||
2136 | |||
2137 | /* Clean up data we have read: This will do ACK frames. */ | 2153 | /* Clean up data we have read: This will do ACK frames. */ |
2138 | tcp_cleanup_rbuf(sk, copied); | 2154 | tcp_cleanup_rbuf(sk, copied); |
2139 | 2155 | ||
2140 | release_sock(sk); | 2156 | release_sock(sk); |
2157 | |||
2158 | if (has_cmsg) { | ||
2159 | if (has_tss) | ||
2160 | tcp_recv_timestamp(msg, sk, &tss); | ||
2161 | if (tp->recvmsg_inq) { | ||
2162 | inq = tcp_inq_hint(sk); | ||
2163 | put_cmsg(msg, SOL_TCP, TCP_CM_INQ, sizeof(inq), &inq); | ||
2164 | } | ||
2165 | } | ||
2166 | |||
2141 | return copied; | 2167 | return copied; |
2142 | 2168 | ||
2143 | out: | 2169 | out: |
@@ -3006,6 +3032,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level, | |||
3006 | tp->notsent_lowat = val; | 3032 | tp->notsent_lowat = val; |
3007 | sk->sk_write_space(sk); | 3033 | sk->sk_write_space(sk); |
3008 | break; | 3034 | break; |
3035 | case TCP_INQ: | ||
3036 | if (val > 1 || val < 0) | ||
3037 | err = -EINVAL; | ||
3038 | else | ||
3039 | tp->recvmsg_inq = val; | ||
3040 | break; | ||
3009 | default: | 3041 | default: |
3010 | err = -ENOPROTOOPT; | 3042 | err = -ENOPROTOOPT; |
3011 | break; | 3043 | break; |
@@ -3431,6 +3463,9 @@ static int do_tcp_getsockopt(struct sock *sk, int level, | |||
3431 | case TCP_NOTSENT_LOWAT: | 3463 | case TCP_NOTSENT_LOWAT: |
3432 | val = tp->notsent_lowat; | 3464 | val = tp->notsent_lowat; |
3433 | break; | 3465 | break; |
3466 | case TCP_INQ: | ||
3467 | val = tp->recvmsg_inq; | ||
3468 | break; | ||
3434 | case TCP_SAVE_SYN: | 3469 | case TCP_SAVE_SYN: |
3435 | val = tp->save_syn; | 3470 | val = tp->save_syn; |
3436 | break; | 3471 | break; |