diff options
-rw-r--r-- | include/net/inet_connection_sock.h | 2 | ||||
-rw-r--r-- | include/net/tcp.h | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 35 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 31 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 8 |
5 files changed, 44 insertions, 34 deletions
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index e4f494b42e06..6c93a56cc958 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h | |||
@@ -43,7 +43,7 @@ struct inet_connection_sock_af_ops { | |||
43 | struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb, | 43 | struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb, |
44 | struct request_sock *req, | 44 | struct request_sock *req, |
45 | struct dst_entry *dst); | 45 | struct dst_entry *dst); |
46 | int (*remember_stamp)(struct sock *sk); | 46 | struct inet_peer *(*get_peer)(struct sock *sk, bool *release_it); |
47 | u16 net_header_len; | 47 | u16 net_header_len; |
48 | u16 sockaddr_len; | 48 | u16 sockaddr_len; |
49 | int (*setsockopt)(struct sock *sk, int level, int optname, | 49 | int (*setsockopt)(struct sock *sk, int level, int optname, |
diff --git a/include/net/tcp.h b/include/net/tcp.h index e36c874c7fb1..3e239641d4ee 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -312,7 +312,7 @@ extern void tcp_shutdown (struct sock *sk, int how); | |||
312 | 312 | ||
313 | extern int tcp_v4_rcv(struct sk_buff *skb); | 313 | extern int tcp_v4_rcv(struct sk_buff *skb); |
314 | 314 | ||
315 | extern int tcp_v4_remember_stamp(struct sock *sk); | 315 | extern struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it); |
316 | extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); | 316 | extern int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); |
317 | extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | 317 | extern int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, |
318 | size_t size); | 318 | size_t size); |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 00285fcf6788..0ddf819cfb5d 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -1763,44 +1763,25 @@ do_time_wait: | |||
1763 | goto discard_it; | 1763 | goto discard_it; |
1764 | } | 1764 | } |
1765 | 1765 | ||
1766 | /* VJ's idea. Save last timestamp seen from this destination | 1766 | struct inet_peer *tcp_v4_get_peer(struct sock *sk, bool *release_it) |
1767 | * and hold it at least for normal timewait interval to use for duplicate | ||
1768 | * segment detection in subsequent connections, before they enter synchronized | ||
1769 | * state. | ||
1770 | */ | ||
1771 | |||
1772 | int tcp_v4_remember_stamp(struct sock *sk) | ||
1773 | { | 1767 | { |
1768 | struct rtable *rt = (struct rtable *) __sk_dst_get(sk); | ||
1774 | struct inet_sock *inet = inet_sk(sk); | 1769 | struct inet_sock *inet = inet_sk(sk); |
1775 | struct tcp_sock *tp = tcp_sk(sk); | 1770 | struct inet_peer *peer; |
1776 | struct rtable *rt = (struct rtable *)__sk_dst_get(sk); | ||
1777 | struct inet_peer *peer = NULL; | ||
1778 | int release_it = 0; | ||
1779 | 1771 | ||
1780 | if (!rt || rt->rt_dst != inet->inet_daddr) { | 1772 | if (!rt || rt->rt_dst != inet->inet_daddr) { |
1781 | peer = inet_getpeer_v4(inet->inet_daddr, 1); | 1773 | peer = inet_getpeer_v4(inet->inet_daddr, 1); |
1782 | release_it = 1; | 1774 | *release_it = true; |
1783 | } else { | 1775 | } else { |
1784 | if (!rt->peer) | 1776 | if (!rt->peer) |
1785 | rt_bind_peer(rt, 1); | 1777 | rt_bind_peer(rt, 1); |
1786 | peer = rt->peer; | 1778 | peer = rt->peer; |
1779 | *release_it = false; | ||
1787 | } | 1780 | } |
1788 | 1781 | ||
1789 | if (peer) { | 1782 | return peer; |
1790 | if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 || | ||
1791 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
1792 | peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { | ||
1793 | peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; | ||
1794 | peer->tcp_ts = tp->rx_opt.ts_recent; | ||
1795 | } | ||
1796 | if (release_it) | ||
1797 | inet_putpeer(peer); | ||
1798 | return 1; | ||
1799 | } | ||
1800 | |||
1801 | return 0; | ||
1802 | } | 1783 | } |
1803 | EXPORT_SYMBOL(tcp_v4_remember_stamp); | 1784 | EXPORT_SYMBOL(tcp_v4_get_peer); |
1804 | 1785 | ||
1805 | int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) | 1786 | int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) |
1806 | { | 1787 | { |
@@ -1828,7 +1809,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = { | |||
1828 | .rebuild_header = inet_sk_rebuild_header, | 1809 | .rebuild_header = inet_sk_rebuild_header, |
1829 | .conn_request = tcp_v4_conn_request, | 1810 | .conn_request = tcp_v4_conn_request, |
1830 | .syn_recv_sock = tcp_v4_syn_recv_sock, | 1811 | .syn_recv_sock = tcp_v4_syn_recv_sock, |
1831 | .remember_stamp = tcp_v4_remember_stamp, | 1812 | .get_peer = tcp_v4_get_peer, |
1832 | .net_header_len = sizeof(struct iphdr), | 1813 | .net_header_len = sizeof(struct iphdr), |
1833 | .setsockopt = ip_setsockopt, | 1814 | .setsockopt = ip_setsockopt, |
1834 | .getsockopt = ip_getsockopt, | 1815 | .getsockopt = ip_getsockopt, |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 43cf901d7659..059082c873cf 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -49,6 +49,35 @@ struct inet_timewait_death_row tcp_death_row = { | |||
49 | }; | 49 | }; |
50 | EXPORT_SYMBOL_GPL(tcp_death_row); | 50 | EXPORT_SYMBOL_GPL(tcp_death_row); |
51 | 51 | ||
52 | /* VJ's idea. Save last timestamp seen from this destination | ||
53 | * and hold it at least for normal timewait interval to use for duplicate | ||
54 | * segment detection in subsequent connections, before they enter synchronized | ||
55 | * state. | ||
56 | */ | ||
57 | |||
58 | static int tcp_remember_stamp(struct sock *sk) | ||
59 | { | ||
60 | const struct inet_connection_sock *icsk = inet_csk(sk); | ||
61 | struct tcp_sock *tp = tcp_sk(sk); | ||
62 | struct inet_peer *peer; | ||
63 | bool release_it; | ||
64 | |||
65 | peer = icsk->icsk_af_ops->get_peer(sk, &release_it); | ||
66 | if (peer) { | ||
67 | if ((s32)(peer->tcp_ts - tp->rx_opt.ts_recent) <= 0 || | ||
68 | ((u32)get_seconds() - peer->tcp_ts_stamp > TCP_PAWS_MSL && | ||
69 | peer->tcp_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { | ||
70 | peer->tcp_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; | ||
71 | peer->tcp_ts = tp->rx_opt.ts_recent; | ||
72 | } | ||
73 | if (release_it) | ||
74 | inet_putpeer(peer); | ||
75 | return 1; | ||
76 | } | ||
77 | |||
78 | return 0; | ||
79 | } | ||
80 | |||
52 | static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) | 81 | static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) |
53 | { | 82 | { |
54 | if (seq == s_win) | 83 | if (seq == s_win) |
@@ -274,7 +303,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
274 | int recycle_ok = 0; | 303 | int recycle_ok = 0; |
275 | 304 | ||
276 | if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) | 305 | if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) |
277 | recycle_ok = icsk->icsk_af_ops->remember_stamp(sk); | 306 | recycle_ok = tcp_remember_stamp(sk); |
278 | 307 | ||
279 | if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) | 308 | if (tcp_death_row.tw_count < tcp_death_row.sysctl_max_tw_buckets) |
280 | tw = inet_twsk_alloc(sk, state); | 309 | tw = inet_twsk_alloc(sk, state); |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7e41e2cbb85e..e394d0029d8d 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -1818,10 +1818,10 @@ do_time_wait: | |||
1818 | goto discard_it; | 1818 | goto discard_it; |
1819 | } | 1819 | } |
1820 | 1820 | ||
1821 | static int tcp_v6_remember_stamp(struct sock *sk) | 1821 | struct inet_peer *tcp_v6_get_peer(struct sock *sk, bool *release_it) |
1822 | { | 1822 | { |
1823 | /* Alas, not yet... */ | 1823 | /* Alas, not yet... */ |
1824 | return 0; | 1824 | return NULL; |
1825 | } | 1825 | } |
1826 | 1826 | ||
1827 | static const struct inet_connection_sock_af_ops ipv6_specific = { | 1827 | static const struct inet_connection_sock_af_ops ipv6_specific = { |
@@ -1830,7 +1830,7 @@ static const struct inet_connection_sock_af_ops ipv6_specific = { | |||
1830 | .rebuild_header = inet6_sk_rebuild_header, | 1830 | .rebuild_header = inet6_sk_rebuild_header, |
1831 | .conn_request = tcp_v6_conn_request, | 1831 | .conn_request = tcp_v6_conn_request, |
1832 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1832 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1833 | .remember_stamp = tcp_v6_remember_stamp, | 1833 | .get_peer = tcp_v6_get_peer, |
1834 | .net_header_len = sizeof(struct ipv6hdr), | 1834 | .net_header_len = sizeof(struct ipv6hdr), |
1835 | .setsockopt = ipv6_setsockopt, | 1835 | .setsockopt = ipv6_setsockopt, |
1836 | .getsockopt = ipv6_getsockopt, | 1836 | .getsockopt = ipv6_getsockopt, |
@@ -1862,7 +1862,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = { | |||
1862 | .rebuild_header = inet_sk_rebuild_header, | 1862 | .rebuild_header = inet_sk_rebuild_header, |
1863 | .conn_request = tcp_v6_conn_request, | 1863 | .conn_request = tcp_v6_conn_request, |
1864 | .syn_recv_sock = tcp_v6_syn_recv_sock, | 1864 | .syn_recv_sock = tcp_v6_syn_recv_sock, |
1865 | .remember_stamp = tcp_v4_remember_stamp, | 1865 | .get_peer = tcp_v4_get_peer, |
1866 | .net_header_len = sizeof(struct iphdr), | 1866 | .net_header_len = sizeof(struct iphdr), |
1867 | .setsockopt = ipv6_setsockopt, | 1867 | .setsockopt = ipv6_setsockopt, |
1868 | .getsockopt = ipv6_getsockopt, | 1868 | .getsockopt = ipv6_getsockopt, |