diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 71 |
1 files changed, 42 insertions, 29 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0b5ab04d3c5a..6728772a943a 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -69,6 +69,7 @@ | |||
69 | #include <net/transp_v6.h> | 69 | #include <net/transp_v6.h> |
70 | #include <net/ipv6.h> | 70 | #include <net/ipv6.h> |
71 | #include <net/inet_common.h> | 71 | #include <net/inet_common.h> |
72 | #include <net/timewait_sock.h> | ||
72 | #include <net/xfrm.h> | 73 | #include <net/xfrm.h> |
73 | 74 | ||
74 | #include <linux/inet.h> | 75 | #include <linux/inet.h> |
@@ -118,6 +119,39 @@ static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) | |||
118 | skb->h.th->source); | 119 | skb->h.th->source); |
119 | } | 120 | } |
120 | 121 | ||
122 | int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) | ||
123 | { | ||
124 | const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw); | ||
125 | struct tcp_sock *tp = tcp_sk(sk); | ||
126 | |||
127 | /* With PAWS, it is safe from the viewpoint | ||
128 | of data integrity. Even without PAWS it is safe provided sequence | ||
129 | spaces do not overlap i.e. at data rates <= 80Mbit/sec. | ||
130 | |||
131 | Actually, the idea is close to VJ's one, only timestamp cache is | ||
132 | held not per host, but per port pair and TW bucket is used as state | ||
133 | holder. | ||
134 | |||
135 | If TW bucket has been already destroyed we fall back to VJ's scheme | ||
136 | and use initial timestamp retrieved from peer table. | ||
137 | */ | ||
138 | if (tcptw->tw_ts_recent_stamp && | ||
139 | (twp == NULL || (sysctl_tcp_tw_reuse && | ||
140 | xtime.tv_sec - tcptw->tw_ts_recent_stamp > 1))) { | ||
141 | tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; | ||
142 | if (tp->write_seq == 0) | ||
143 | tp->write_seq = 1; | ||
144 | tp->rx_opt.ts_recent = tcptw->tw_ts_recent; | ||
145 | tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; | ||
146 | sock_hold(sktw); | ||
147 | return 1; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | EXPORT_SYMBOL_GPL(tcp_twsk_unique); | ||
154 | |||
121 | /* called with local bh disabled */ | 155 | /* called with local bh disabled */ |
122 | static int __tcp_v4_check_established(struct sock *sk, __u16 lport, | 156 | static int __tcp_v4_check_established(struct sock *sk, __u16 lport, |
123 | struct inet_timewait_sock **twp) | 157 | struct inet_timewait_sock **twp) |
@@ -142,35 +176,9 @@ static int __tcp_v4_check_established(struct sock *sk, __u16 lport, | |||
142 | tw = inet_twsk(sk2); | 176 | tw = inet_twsk(sk2); |
143 | 177 | ||
144 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) { | 178 | if (INET_TW_MATCH(sk2, hash, acookie, saddr, daddr, ports, dif)) { |
145 | const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2); | 179 | if (twsk_unique(sk, sk2, twp)) |
146 | struct tcp_sock *tp = tcp_sk(sk); | ||
147 | |||
148 | /* With PAWS, it is safe from the viewpoint | ||
149 | of data integrity. Even without PAWS it | ||
150 | is safe provided sequence spaces do not | ||
151 | overlap i.e. at data rates <= 80Mbit/sec. | ||
152 | |||
153 | Actually, the idea is close to VJ's one, | ||
154 | only timestamp cache is held not per host, | ||
155 | but per port pair and TW bucket is used | ||
156 | as state holder. | ||
157 | |||
158 | If TW bucket has been already destroyed we | ||
159 | fall back to VJ's scheme and use initial | ||
160 | timestamp retrieved from peer table. | ||
161 | */ | ||
162 | if (tcptw->tw_ts_recent_stamp && | ||
163 | (!twp || (sysctl_tcp_tw_reuse && | ||
164 | xtime.tv_sec - | ||
165 | tcptw->tw_ts_recent_stamp > 1))) { | ||
166 | tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; | ||
167 | if (tp->write_seq == 0) | ||
168 | tp->write_seq = 1; | ||
169 | tp->rx_opt.ts_recent = tcptw->tw_ts_recent; | ||
170 | tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; | ||
171 | sock_hold(sk2); | ||
172 | goto unique; | 180 | goto unique; |
173 | } else | 181 | else |
174 | goto not_unique; | 182 | goto not_unique; |
175 | } | 183 | } |
176 | } | 184 | } |
@@ -869,6 +877,11 @@ struct request_sock_ops tcp_request_sock_ops = { | |||
869 | .send_reset = tcp_v4_send_reset, | 877 | .send_reset = tcp_v4_send_reset, |
870 | }; | 878 | }; |
871 | 879 | ||
880 | static struct timewait_sock_ops tcp_timewait_sock_ops = { | ||
881 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), | ||
882 | .twsk_unique = tcp_twsk_unique, | ||
883 | }; | ||
884 | |||
872 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | 885 | int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
873 | { | 886 | { |
874 | struct inet_request_sock *ireq; | 887 | struct inet_request_sock *ireq; |
@@ -1979,7 +1992,7 @@ struct proto tcp_prot = { | |||
1979 | .sysctl_rmem = sysctl_tcp_rmem, | 1992 | .sysctl_rmem = sysctl_tcp_rmem, |
1980 | .max_header = MAX_TCP_HEADER, | 1993 | .max_header = MAX_TCP_HEADER, |
1981 | .obj_size = sizeof(struct tcp_sock), | 1994 | .obj_size = sizeof(struct tcp_sock), |
1982 | .twsk_obj_size = sizeof(struct tcp_timewait_sock), | 1995 | .twsk_prot = &tcp_timewait_sock_ops, |
1983 | .rsk_prot = &tcp_request_sock_ops, | 1996 | .rsk_prot = &tcp_request_sock_ops, |
1984 | }; | 1997 | }; |
1985 | 1998 | ||