diff options
-rw-r--r-- | include/linux/ipv6.h | 3 | ||||
-rw-r--r-- | include/net/inet_timewait_sock.h | 3 | ||||
-rw-r--r-- | include/net/sock.h | 4 | ||||
-rw-r--r-- | include/net/tcp.h | 3 | ||||
-rw-r--r-- | include/net/timewait_sock.h | 31 | ||||
-rw-r--r-- | net/core/sock.c | 21 | ||||
-rw-r--r-- | net/dccp/ipv4.c | 9 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 6 | ||||
-rw-r--r-- | net/ipv4/inet_timewait_sock.c | 5 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 71 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 25 |
11 files changed, 118 insertions, 63 deletions
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 7d3908594fac..a0d04891fe12 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h | |||
@@ -360,7 +360,8 @@ struct tcp6_timewait_sock { | |||
360 | 360 | ||
361 | static inline u16 inet6_tw_offset(const struct proto *prot) | 361 | static inline u16 inet6_tw_offset(const struct proto *prot) |
362 | { | 362 | { |
363 | return prot->twsk_obj_size - sizeof(struct inet6_timewait_sock); | 363 | return prot->twsk_prot->twsk_obj_size - |
364 | sizeof(struct inet6_timewait_sock); | ||
364 | } | 365 | } |
365 | 366 | ||
366 | static inline struct inet6_timewait_sock *inet6_twsk(const struct sock *sk) | 367 | static inline struct inet6_timewait_sock *inet6_twsk(const struct sock *sk) |
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index ca240f856c46..e396a65473d7 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | #include <net/sock.h> | 27 | #include <net/sock.h> |
28 | #include <net/tcp_states.h> | 28 | #include <net/tcp_states.h> |
29 | #include <net/timewait_sock.h> | ||
29 | 30 | ||
30 | #include <asm/atomic.h> | 31 | #include <asm/atomic.h> |
31 | 32 | ||
@@ -200,7 +201,7 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw) | |||
200 | printk(KERN_DEBUG "%s timewait_sock %p released\n", | 201 | printk(KERN_DEBUG "%s timewait_sock %p released\n", |
201 | tw->tw_prot->name, tw); | 202 | tw->tw_prot->name, tw); |
202 | #endif | 203 | #endif |
203 | kmem_cache_free(tw->tw_prot->twsk_slab, tw); | 204 | kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); |
204 | module_put(owner); | 205 | module_put(owner); |
205 | } | 206 | } |
206 | } | 207 | } |
diff --git a/include/net/sock.h b/include/net/sock.h index 0fbae85c6d55..91d28957dc10 100644 --- a/include/net/sock.h +++ b/include/net/sock.h | |||
@@ -493,6 +493,7 @@ extern void sk_stream_kill_queues(struct sock *sk); | |||
493 | extern int sk_wait_data(struct sock *sk, long *timeo); | 493 | extern int sk_wait_data(struct sock *sk, long *timeo); |
494 | 494 | ||
495 | struct request_sock_ops; | 495 | struct request_sock_ops; |
496 | struct timewait_sock_ops; | ||
496 | 497 | ||
497 | /* Networking protocol blocks we attach to sockets. | 498 | /* Networking protocol blocks we attach to sockets. |
498 | * socket layer -> transport layer interface | 499 | * socket layer -> transport layer interface |
@@ -557,11 +558,10 @@ struct proto { | |||
557 | kmem_cache_t *slab; | 558 | kmem_cache_t *slab; |
558 | unsigned int obj_size; | 559 | unsigned int obj_size; |
559 | 560 | ||
560 | kmem_cache_t *twsk_slab; | ||
561 | unsigned int twsk_obj_size; | ||
562 | atomic_t *orphan_count; | 561 | atomic_t *orphan_count; |
563 | 562 | ||
564 | struct request_sock_ops *rsk_prot; | 563 | struct request_sock_ops *rsk_prot; |
564 | struct timewait_sock_ops *twsk_prot; | ||
565 | 565 | ||
566 | struct module *owner; | 566 | struct module *owner; |
567 | 567 | ||
diff --git a/include/net/tcp.h b/include/net/tcp.h index 83b117a25c2a..176221cd0cce 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -287,6 +287,9 @@ extern int tcp_rcv_established(struct sock *sk, | |||
287 | 287 | ||
288 | extern void tcp_rcv_space_adjust(struct sock *sk); | 288 | extern void tcp_rcv_space_adjust(struct sock *sk); |
289 | 289 | ||
290 | extern int tcp_twsk_unique(struct sock *sk, | ||
291 | struct sock *sktw, void *twp); | ||
292 | |||
290 | static inline void tcp_dec_quickack_mode(struct sock *sk, | 293 | static inline void tcp_dec_quickack_mode(struct sock *sk, |
291 | const unsigned int pkts) | 294 | const unsigned int pkts) |
292 | { | 295 | { |
diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h new file mode 100644 index 000000000000..2544281e1d5e --- /dev/null +++ b/include/net/timewait_sock.h | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * NET Generic infrastructure for Network protocols. | ||
3 | * | ||
4 | * Authors: Arnaldo Carvalho de Melo <acme@conectiva.com.br> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | #ifndef _TIMEWAIT_SOCK_H | ||
12 | #define _TIMEWAIT_SOCK_H | ||
13 | |||
14 | #include <linux/slab.h> | ||
15 | #include <net/sock.h> | ||
16 | |||
17 | struct timewait_sock_ops { | ||
18 | kmem_cache_t *twsk_slab; | ||
19 | unsigned int twsk_obj_size; | ||
20 | int (*twsk_unique)(struct sock *sk, | ||
21 | struct sock *sktw, void *twp); | ||
22 | }; | ||
23 | |||
24 | static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) | ||
25 | { | ||
26 | if (sk->sk_prot->twsk_prot->twsk_unique != NULL) | ||
27 | return sk->sk_prot->twsk_prot->twsk_unique(sk, sktw, twp); | ||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | #endif /* _TIMEWAIT_SOCK_H */ | ||
diff --git a/net/core/sock.c b/net/core/sock.c index 13cc3be4f056..6465b0e4c8cb 100644 --- a/net/core/sock.c +++ b/net/core/sock.c | |||
@@ -1488,7 +1488,7 @@ int proto_register(struct proto *prot, int alloc_slab) | |||
1488 | } | 1488 | } |
1489 | } | 1489 | } |
1490 | 1490 | ||
1491 | if (prot->twsk_obj_size) { | 1491 | if (prot->twsk_prot != NULL) { |
1492 | static const char mask[] = "tw_sock_%s"; | 1492 | static const char mask[] = "tw_sock_%s"; |
1493 | 1493 | ||
1494 | timewait_sock_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); | 1494 | timewait_sock_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL); |
@@ -1497,11 +1497,12 @@ int proto_register(struct proto *prot, int alloc_slab) | |||
1497 | goto out_free_request_sock_slab; | 1497 | goto out_free_request_sock_slab; |
1498 | 1498 | ||
1499 | sprintf(timewait_sock_slab_name, mask, prot->name); | 1499 | sprintf(timewait_sock_slab_name, mask, prot->name); |
1500 | prot->twsk_slab = kmem_cache_create(timewait_sock_slab_name, | 1500 | prot->twsk_prot->twsk_slab = |
1501 | prot->twsk_obj_size, | 1501 | kmem_cache_create(timewait_sock_slab_name, |
1502 | 0, SLAB_HWCACHE_ALIGN, | 1502 | prot->twsk_prot->twsk_obj_size, |
1503 | NULL, NULL); | 1503 | 0, SLAB_HWCACHE_ALIGN, |
1504 | if (prot->twsk_slab == NULL) | 1504 | NULL, NULL); |
1505 | if (prot->twsk_prot->twsk_slab == NULL) | ||
1505 | goto out_free_timewait_sock_slab_name; | 1506 | goto out_free_timewait_sock_slab_name; |
1506 | } | 1507 | } |
1507 | } | 1508 | } |
@@ -1548,12 +1549,12 @@ void proto_unregister(struct proto *prot) | |||
1548 | prot->rsk_prot->slab = NULL; | 1549 | prot->rsk_prot->slab = NULL; |
1549 | } | 1550 | } |
1550 | 1551 | ||
1551 | if (prot->twsk_slab != NULL) { | 1552 | if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { |
1552 | const char *name = kmem_cache_name(prot->twsk_slab); | 1553 | const char *name = kmem_cache_name(prot->twsk_prot->twsk_slab); |
1553 | 1554 | ||
1554 | kmem_cache_destroy(prot->twsk_slab); | 1555 | kmem_cache_destroy(prot->twsk_prot->twsk_slab); |
1555 | kfree(name); | 1556 | kfree(name); |
1556 | prot->twsk_slab = NULL; | 1557 | prot->twsk_prot->twsk_slab = NULL; |
1557 | } | 1558 | } |
1558 | } | 1559 | } |
1559 | 1560 | ||
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index bc28d71905e2..e11cda0cb6b3 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <net/icmp.h> | 20 | #include <net/icmp.h> |
21 | #include <net/inet_hashtables.h> | 21 | #include <net/inet_hashtables.h> |
22 | #include <net/sock.h> | 22 | #include <net/sock.h> |
23 | #include <net/timewait_sock.h> | ||
23 | #include <net/tcp_states.h> | 24 | #include <net/tcp_states.h> |
24 | #include <net/xfrm.h> | 25 | #include <net/xfrm.h> |
25 | 26 | ||
@@ -1309,6 +1310,10 @@ static struct request_sock_ops dccp_request_sock_ops = { | |||
1309 | .send_reset = dccp_v4_ctl_send_reset, | 1310 | .send_reset = dccp_v4_ctl_send_reset, |
1310 | }; | 1311 | }; |
1311 | 1312 | ||
1313 | static struct timewait_sock_ops dccp_timewait_sock_ops = { | ||
1314 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | ||
1315 | }; | ||
1316 | |||
1312 | struct proto dccp_prot = { | 1317 | struct proto dccp_prot = { |
1313 | .name = "DCCP", | 1318 | .name = "DCCP", |
1314 | .owner = THIS_MODULE, | 1319 | .owner = THIS_MODULE, |
@@ -1332,5 +1337,7 @@ struct proto dccp_prot = { | |||
1332 | .max_header = MAX_DCCP_HEADER, | 1337 | .max_header = MAX_DCCP_HEADER, |
1333 | .obj_size = sizeof(struct dccp_sock), | 1338 | .obj_size = sizeof(struct dccp_sock), |
1334 | .rsk_prot = &dccp_request_sock_ops, | 1339 | .rsk_prot = &dccp_request_sock_ops, |
1335 | .twsk_obj_size = sizeof(struct inet_timewait_sock), | 1340 | .twsk_prot = &dccp_timewait_sock_ops, |
1336 | }; | 1341 | }; |
1342 | |||
1343 | EXPORT_SYMBOL_GPL(dccp_prot); | ||
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index a7d2aee5b3af..4d078f5b911b 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -652,6 +652,10 @@ static struct request_sock_ops dccp6_request_sock_ops = { | |||
652 | .send_reset = dccp_v6_ctl_send_reset, | 652 | .send_reset = dccp_v6_ctl_send_reset, |
653 | }; | 653 | }; |
654 | 654 | ||
655 | static struct timewait_sock_ops dccp6_timewait_sock_ops = { | ||
656 | .twsk_obj_size = sizeof(struct dccp6_timewait_sock), | ||
657 | }; | ||
658 | |||
655 | static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 659 | static void dccp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) |
656 | { | 660 | { |
657 | struct ipv6_pinfo *np = inet6_sk(sk); | 661 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -1359,7 +1363,7 @@ static struct proto dccp_v6_prot = { | |||
1359 | .max_header = MAX_DCCP_HEADER, | 1363 | .max_header = MAX_DCCP_HEADER, |
1360 | .obj_size = sizeof(struct dccp6_sock), | 1364 | .obj_size = sizeof(struct dccp6_sock), |
1361 | .rsk_prot = &dccp6_request_sock_ops, | 1365 | .rsk_prot = &dccp6_request_sock_ops, |
1362 | .twsk_obj_size = sizeof(struct dccp6_timewait_sock), | 1366 | .twsk_prot = &dccp6_timewait_sock_ops, |
1363 | }; | 1367 | }; |
1364 | 1368 | ||
1365 | static struct inet6_protocol dccp_v6_protocol = { | 1369 | static struct inet6_protocol dccp_v6_protocol = { |
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index a010e9a68811..417f126c749e 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c | |||
@@ -90,8 +90,9 @@ EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); | |||
90 | 90 | ||
91 | struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state) | 91 | struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int state) |
92 | { | 92 | { |
93 | struct inet_timewait_sock *tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_slab, | 93 | struct inet_timewait_sock *tw = |
94 | SLAB_ATOMIC); | 94 | kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, |
95 | SLAB_ATOMIC); | ||
95 | if (tw != NULL) { | 96 | if (tw != NULL) { |
96 | const struct inet_sock *inet = inet_sk(sk); | 97 | const struct inet_sock *inet = inet_sk(sk); |
97 | 98 | ||
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 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e5c8a669e84e..514b57bb80b7 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -60,6 +60,7 @@ | |||
60 | #include <net/addrconf.h> | 60 | #include <net/addrconf.h> |
61 | #include <net/snmp.h> | 61 | #include <net/snmp.h> |
62 | #include <net/dsfield.h> | 62 | #include <net/dsfield.h> |
63 | #include <net/timewait_sock.h> | ||
63 | 64 | ||
64 | #include <asm/uaccess.h> | 65 | #include <asm/uaccess.h> |
65 | 66 | ||
@@ -147,22 +148,9 @@ static int __tcp_v6_check_established(struct sock *sk, const __u16 lport, | |||
147 | ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && | 148 | ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) && |
148 | ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && | 149 | ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) && |
149 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) { | 150 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) { |
150 | const struct tcp_timewait_sock *tcptw = tcp_twsk(sk2); | 151 | if (twsk_unique(sk, sk2, twp)) |
151 | struct tcp_sock *tp = tcp_sk(sk); | ||
152 | |||
153 | if (tcptw->tw_ts_recent_stamp && | ||
154 | (!twp || | ||
155 | (sysctl_tcp_tw_reuse && | ||
156 | xtime.tv_sec - tcptw->tw_ts_recent_stamp > 1))) { | ||
157 | /* See comment in tcp_ipv4.c */ | ||
158 | tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; | ||
159 | if (!tp->write_seq) | ||
160 | tp->write_seq = 1; | ||
161 | tp->rx_opt.ts_recent = tcptw->tw_ts_recent; | ||
162 | tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; | ||
163 | sock_hold(sk2); | ||
164 | goto unique; | 152 | goto unique; |
165 | } else | 153 | else |
166 | goto not_unique; | 154 | goto not_unique; |
167 | } | 155 | } |
168 | } | 156 | } |
@@ -711,6 +699,11 @@ static struct request_sock_ops tcp6_request_sock_ops = { | |||
711 | .send_reset = tcp_v6_send_reset | 699 | .send_reset = tcp_v6_send_reset |
712 | }; | 700 | }; |
713 | 701 | ||
702 | static struct timewait_sock_ops tcp6_timewait_sock_ops = { | ||
703 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | ||
704 | .twsk_unique = tcp_twsk_unique, | ||
705 | }; | ||
706 | |||
714 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) | 707 | static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) |
715 | { | 708 | { |
716 | struct ipv6_pinfo *np = inet6_sk(sk); | 709 | struct ipv6_pinfo *np = inet6_sk(sk); |
@@ -1752,7 +1745,7 @@ struct proto tcpv6_prot = { | |||
1752 | .sysctl_rmem = sysctl_tcp_rmem, | 1745 | .sysctl_rmem = sysctl_tcp_rmem, |
1753 | .max_header = MAX_TCP_HEADER, | 1746 | .max_header = MAX_TCP_HEADER, |
1754 | .obj_size = sizeof(struct tcp6_sock), | 1747 | .obj_size = sizeof(struct tcp6_sock), |
1755 | .twsk_obj_size = sizeof(struct tcp6_timewait_sock), | 1748 | .twsk_prot = &tcp6_timewait_sock_ops, |
1756 | .rsk_prot = &tcp6_request_sock_ops, | 1749 | .rsk_prot = &tcp6_request_sock_ops, |
1757 | }; | 1750 | }; |
1758 | 1751 | ||