diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/Makefile | 1 | ||||
-rw-r--r-- | net/ipv4/inet_hashtables.c | 2 | ||||
-rw-r--r-- | net/ipv4/inet_timewait_sock.c | 83 | ||||
-rw-r--r-- | net/ipv4/tcp_diag.c | 8 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 83 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 78 |
6 files changed, 101 insertions, 154 deletions
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 2d8d30e83eb0..6650d18e400f 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
@@ -5,6 +5,7 @@ | |||
5 | obj-y := route.o inetpeer.o protocol.o \ | 5 | obj-y := route.o inetpeer.o protocol.o \ |
6 | ip_input.o ip_fragment.o ip_forward.o ip_options.o \ | 6 | ip_input.o ip_fragment.o ip_forward.o ip_options.o \ |
7 | ip_output.o ip_sockglue.o inet_hashtables.o \ | 7 | ip_output.o ip_sockglue.o inet_hashtables.o \ |
8 | inet_timewait_sock.o \ | ||
8 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ | 9 | tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ |
9 | tcp_minisocks.o tcp_cong.o \ | 10 | tcp_minisocks.o tcp_cong.o \ |
10 | datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ | 11 | datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \ |
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 88fcba05b7d6..d94e962958a4 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c | |||
@@ -162,3 +162,5 @@ struct sock *__inet_lookup_listener(const struct hlist_head *head, const u32 dad | |||
162 | } | 162 | } |
163 | return result; | 163 | return result; |
164 | } | 164 | } |
165 | |||
166 | EXPORT_SYMBOL_GPL(__inet_lookup_listener); | ||
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c new file mode 100644 index 000000000000..d38d160faeb7 --- /dev/null +++ b/net/ipv4/inet_timewait_sock.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * INET An implementation of the TCP/IP protocol suite for the LINUX | ||
3 | * operating system. INET is implemented using the BSD Socket | ||
4 | * interface as the means of communication with the user level. | ||
5 | * | ||
6 | * Generic TIME_WAIT sockets functions | ||
7 | * | ||
8 | * From code orinally in TCP | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | |||
13 | #include <net/inet_hashtables.h> | ||
14 | #include <net/inet_timewait_sock.h> | ||
15 | |||
16 | /* Must be called with locally disabled BHs. */ | ||
17 | void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo) | ||
18 | { | ||
19 | struct inet_bind_hashbucket *bhead; | ||
20 | struct inet_bind_bucket *tb; | ||
21 | /* Unlink from established hashes. */ | ||
22 | struct inet_ehash_bucket *ehead = &hashinfo->ehash[tw->tw_hashent]; | ||
23 | |||
24 | write_lock(&ehead->lock); | ||
25 | if (hlist_unhashed(&tw->tw_node)) { | ||
26 | write_unlock(&ehead->lock); | ||
27 | return; | ||
28 | } | ||
29 | __hlist_del(&tw->tw_node); | ||
30 | sk_node_init(&tw->tw_node); | ||
31 | write_unlock(&ehead->lock); | ||
32 | |||
33 | /* Disassociate with bind bucket. */ | ||
34 | bhead = &hashinfo->bhash[inet_bhashfn(tw->tw_num, hashinfo->bhash_size)]; | ||
35 | spin_lock(&bhead->lock); | ||
36 | tb = tw->tw_tb; | ||
37 | __hlist_del(&tw->tw_bind_node); | ||
38 | tw->tw_tb = NULL; | ||
39 | inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); | ||
40 | spin_unlock(&bhead->lock); | ||
41 | #ifdef SOCK_REFCNT_DEBUG | ||
42 | if (atomic_read(&tw->tw_refcnt) != 1) { | ||
43 | printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n", | ||
44 | tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt)); | ||
45 | } | ||
46 | #endif | ||
47 | inet_twsk_put(tw); | ||
48 | } | ||
49 | |||
50 | /* | ||
51 | * Enter the time wait state. This is called with locally disabled BH. | ||
52 | * Essentially we whip up a timewait bucket, copy the relevant info into it | ||
53 | * from the SK, and mess with hash chains and list linkage. | ||
54 | */ | ||
55 | void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, | ||
56 | struct inet_hashinfo *hashinfo) | ||
57 | { | ||
58 | const struct inet_sock *inet = inet_sk(sk); | ||
59 | struct inet_ehash_bucket *ehead = &hashinfo->ehash[sk->sk_hashent]; | ||
60 | struct inet_bind_hashbucket *bhead; | ||
61 | /* Step 1: Put TW into bind hash. Original socket stays there too. | ||
62 | Note, that any socket with inet->num != 0 MUST be bound in | ||
63 | binding cache, even if it is closed. | ||
64 | */ | ||
65 | bhead = &hashinfo->bhash[inet_bhashfn(inet->num, hashinfo->bhash_size)]; | ||
66 | spin_lock(&bhead->lock); | ||
67 | tw->tw_tb = inet->bind_hash; | ||
68 | BUG_TRAP(inet->bind_hash); | ||
69 | inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); | ||
70 | spin_unlock(&bhead->lock); | ||
71 | |||
72 | write_lock(&ehead->lock); | ||
73 | |||
74 | /* Step 2: Remove SK from established hash. */ | ||
75 | if (__sk_del_node_init(sk)) | ||
76 | sock_prot_dec_use(sk->sk_prot); | ||
77 | |||
78 | /* Step 3: Hash TW into TIMEWAIT half of established hash table. */ | ||
79 | inet_twsk_add_node(tw, &(ehead + hashinfo->ehash_size)->chain); | ||
80 | atomic_inc(&tw->tw_refcnt); | ||
81 | |||
82 | write_unlock(&ehead->lock); | ||
83 | } | ||
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 6f2d6f2276b9..60c6a797cc50 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c | |||
@@ -174,8 +174,6 @@ nlmsg_failure: | |||
174 | return -1; | 174 | return -1; |
175 | } | 175 | } |
176 | 176 | ||
177 | extern struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, | ||
178 | int dif); | ||
179 | #ifdef CONFIG_IP_TCPDIAG_IPV6 | 177 | #ifdef CONFIG_IP_TCPDIAG_IPV6 |
180 | extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, | 178 | extern struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport, |
181 | struct in6_addr *daddr, u16 dport, | 179 | struct in6_addr *daddr, u16 dport, |
@@ -197,9 +195,9 @@ static int tcpdiag_get_exact(struct sk_buff *in_skb, const struct nlmsghdr *nlh) | |||
197 | struct sk_buff *rep; | 195 | struct sk_buff *rep; |
198 | 196 | ||
199 | if (req->tcpdiag_family == AF_INET) { | 197 | if (req->tcpdiag_family == AF_INET) { |
200 | sk = tcp_v4_lookup(req->id.tcpdiag_dst[0], req->id.tcpdiag_dport, | 198 | sk = inet_lookup(&tcp_hashinfo, req->id.tcpdiag_dst[0], |
201 | req->id.tcpdiag_src[0], req->id.tcpdiag_sport, | 199 | req->id.tcpdiag_dport, req->id.tcpdiag_src[0], |
202 | req->id.tcpdiag_if); | 200 | req->id.tcpdiag_sport, req->id.tcpdiag_if); |
203 | } | 201 | } |
204 | #ifdef CONFIG_IP_TCPDIAG_IPV6 | 202 | #ifdef CONFIG_IP_TCPDIAG_IPV6 |
205 | else if (req->tcpdiag_family == AF_INET6) { | 203 | else if (req->tcpdiag_family == AF_INET6) { |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ce423e48ebe0..e7e91e60ac74 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -238,71 +238,6 @@ void tcp_unhash(struct sock *sk) | |||
238 | inet_unhash(&tcp_hashinfo, sk); | 238 | inet_unhash(&tcp_hashinfo, sk); |
239 | } | 239 | } |
240 | 240 | ||
241 | /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so | ||
242 | * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM | ||
243 | * | ||
244 | * Local BH must be disabled here. | ||
245 | */ | ||
246 | |||
247 | static inline struct sock *__tcp_v4_lookup_established(const u32 saddr, | ||
248 | const u16 sport, | ||
249 | const u32 daddr, | ||
250 | const u16 hnum, | ||
251 | const int dif) | ||
252 | { | ||
253 | struct inet_ehash_bucket *head; | ||
254 | INET_ADDR_COOKIE(acookie, saddr, daddr) | ||
255 | const __u32 ports = INET_COMBINED_PORTS(sport, hnum); | ||
256 | struct sock *sk; | ||
257 | const struct hlist_node *node; | ||
258 | /* Optimize here for direct hit, only listening connections can | ||
259 | * have wildcards anyways. | ||
260 | */ | ||
261 | const int hash = inet_ehashfn(daddr, hnum, saddr, sport, tcp_hashinfo.ehash_size); | ||
262 | head = &tcp_hashinfo.ehash[hash]; | ||
263 | read_lock(&head->lock); | ||
264 | sk_for_each(sk, node, &head->chain) { | ||
265 | if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif)) | ||
266 | goto hit; /* You sunk my battleship! */ | ||
267 | } | ||
268 | |||
269 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | ||
270 | sk_for_each(sk, node, &(head + tcp_hashinfo.ehash_size)->chain) { | ||
271 | if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) | ||
272 | goto hit; | ||
273 | } | ||
274 | sk = NULL; | ||
275 | out: | ||
276 | read_unlock(&head->lock); | ||
277 | return sk; | ||
278 | hit: | ||
279 | sock_hold(sk); | ||
280 | goto out; | ||
281 | } | ||
282 | |||
283 | static inline struct sock *__tcp_v4_lookup(u32 saddr, u16 sport, | ||
284 | u32 daddr, u16 hnum, int dif) | ||
285 | { | ||
286 | struct sock *sk = __tcp_v4_lookup_established(saddr, sport, | ||
287 | daddr, hnum, dif); | ||
288 | |||
289 | return sk ? : inet_lookup_listener(&tcp_hashinfo, daddr, hnum, dif); | ||
290 | } | ||
291 | |||
292 | inline struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr, | ||
293 | u16 dport, int dif) | ||
294 | { | ||
295 | struct sock *sk; | ||
296 | |||
297 | local_bh_disable(); | ||
298 | sk = __tcp_v4_lookup(saddr, sport, daddr, ntohs(dport), dif); | ||
299 | local_bh_enable(); | ||
300 | |||
301 | return sk; | ||
302 | } | ||
303 | |||
304 | EXPORT_SYMBOL_GPL(tcp_v4_lookup); | ||
305 | |||
306 | static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) | 241 | static inline __u32 tcp_v4_init_sequence(struct sock *sk, struct sk_buff *skb) |
307 | { | 242 | { |
308 | return secure_tcp_sequence_number(skb->nh.iph->daddr, | 243 | return secure_tcp_sequence_number(skb->nh.iph->daddr, |
@@ -751,8 +686,8 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) | |||
751 | return; | 686 | return; |
752 | } | 687 | } |
753 | 688 | ||
754 | sk = tcp_v4_lookup(iph->daddr, th->dest, iph->saddr, | 689 | sk = inet_lookup(&tcp_hashinfo, iph->daddr, th->dest, iph->saddr, |
755 | th->source, tcp_v4_iif(skb)); | 690 | th->source, tcp_v4_iif(skb)); |
756 | if (!sk) { | 691 | if (!sk) { |
757 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); | 692 | ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); |
758 | return; | 693 | return; |
@@ -1359,11 +1294,9 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
1359 | if (req) | 1294 | if (req) |
1360 | return tcp_check_req(sk, skb, req, prev); | 1295 | return tcp_check_req(sk, skb, req, prev); |
1361 | 1296 | ||
1362 | nsk = __tcp_v4_lookup_established(skb->nh.iph->saddr, | 1297 | nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr, |
1363 | th->source, | 1298 | th->source, skb->nh.iph->daddr, |
1364 | skb->nh.iph->daddr, | 1299 | ntohs(th->dest), tcp_v4_iif(skb)); |
1365 | ntohs(th->dest), | ||
1366 | tcp_v4_iif(skb)); | ||
1367 | 1300 | ||
1368 | if (nsk) { | 1301 | if (nsk) { |
1369 | if (nsk->sk_state != TCP_TIME_WAIT) { | 1302 | if (nsk->sk_state != TCP_TIME_WAIT) { |
@@ -1505,9 +1438,9 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
1505 | TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; | 1438 | TCP_SKB_CB(skb)->flags = skb->nh.iph->tos; |
1506 | TCP_SKB_CB(skb)->sacked = 0; | 1439 | TCP_SKB_CB(skb)->sacked = 0; |
1507 | 1440 | ||
1508 | sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, | 1441 | sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, |
1509 | skb->nh.iph->daddr, ntohs(th->dest), | 1442 | skb->nh.iph->daddr, ntohs(th->dest), |
1510 | tcp_v4_iif(skb)); | 1443 | tcp_v4_iif(skb)); |
1511 | 1444 | ||
1512 | if (!sk) | 1445 | if (!sk) |
1513 | goto no_tcp_socket; | 1446 | goto no_tcp_socket; |
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 5b5a49335fbb..4112f7a6d108 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c | |||
@@ -56,42 +56,6 @@ static __inline__ int tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) | |||
56 | 56 | ||
57 | int tcp_tw_count; | 57 | int tcp_tw_count; |
58 | 58 | ||
59 | |||
60 | /* Must be called with locally disabled BHs. */ | ||
61 | static void tcp_timewait_kill(struct inet_timewait_sock *tw) | ||
62 | { | ||
63 | struct inet_bind_hashbucket *bhead; | ||
64 | struct inet_bind_bucket *tb; | ||
65 | /* Unlink from established hashes. */ | ||
66 | struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[tw->tw_hashent]; | ||
67 | |||
68 | write_lock(&ehead->lock); | ||
69 | if (hlist_unhashed(&tw->tw_node)) { | ||
70 | write_unlock(&ehead->lock); | ||
71 | return; | ||
72 | } | ||
73 | __hlist_del(&tw->tw_node); | ||
74 | sk_node_init(&tw->tw_node); | ||
75 | write_unlock(&ehead->lock); | ||
76 | |||
77 | /* Disassociate with bind bucket. */ | ||
78 | bhead = &tcp_hashinfo.bhash[inet_bhashfn(tw->tw_num, tcp_hashinfo.bhash_size)]; | ||
79 | spin_lock(&bhead->lock); | ||
80 | tb = tw->tw_tb; | ||
81 | __hlist_del(&tw->tw_bind_node); | ||
82 | tw->tw_tb = NULL; | ||
83 | inet_bind_bucket_destroy(tcp_hashinfo.bind_bucket_cachep, tb); | ||
84 | spin_unlock(&bhead->lock); | ||
85 | |||
86 | #ifdef SOCK_REFCNT_DEBUG | ||
87 | if (atomic_read(&tw->tw_refcnt) != 1) { | ||
88 | printk(KERN_DEBUG "%s timewait_sock %p refcnt=%d\n", | ||
89 | tw->tw_prot->name, tw, atomic_read(&tw->tw_refcnt)); | ||
90 | } | ||
91 | #endif | ||
92 | inet_twsk_put(tw); | ||
93 | } | ||
94 | |||
95 | /* | 59 | /* |
96 | * * Main purpose of TIME-WAIT state is to close connection gracefully, | 60 | * * Main purpose of TIME-WAIT state is to close connection gracefully, |
97 | * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN | 61 | * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN |
@@ -290,40 +254,6 @@ kill: | |||
290 | return TCP_TW_SUCCESS; | 254 | return TCP_TW_SUCCESS; |
291 | } | 255 | } |
292 | 256 | ||
293 | /* Enter the time wait state. This is called with locally disabled BH. | ||
294 | * Essentially we whip up a timewait bucket, copy the | ||
295 | * relevant info into it from the SK, and mess with hash chains | ||
296 | * and list linkage. | ||
297 | */ | ||
298 | static void __tcp_tw_hashdance(struct sock *sk, struct inet_timewait_sock *tw) | ||
299 | { | ||
300 | const struct inet_sock *inet = inet_sk(sk); | ||
301 | struct inet_ehash_bucket *ehead = &tcp_hashinfo.ehash[sk->sk_hashent]; | ||
302 | struct inet_bind_hashbucket *bhead; | ||
303 | /* Step 1: Put TW into bind hash. Original socket stays there too. | ||
304 | Note, that any socket with inet->num != 0 MUST be bound in | ||
305 | binding cache, even if it is closed. | ||
306 | */ | ||
307 | bhead = &tcp_hashinfo.bhash[inet_bhashfn(inet->num, tcp_hashinfo.bhash_size)]; | ||
308 | spin_lock(&bhead->lock); | ||
309 | tw->tw_tb = inet->bind_hash; | ||
310 | BUG_TRAP(inet->bind_hash); | ||
311 | inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); | ||
312 | spin_unlock(&bhead->lock); | ||
313 | |||
314 | write_lock(&ehead->lock); | ||
315 | |||
316 | /* Step 2: Remove SK from established hash. */ | ||
317 | if (__sk_del_node_init(sk)) | ||
318 | sock_prot_dec_use(sk->sk_prot); | ||
319 | |||
320 | /* Step 3: Hash TW into TIMEWAIT half of established hash table. */ | ||
321 | inet_twsk_add_node(tw, &(ehead + tcp_hashinfo.ehash_size)->chain); | ||
322 | atomic_inc(&tw->tw_refcnt); | ||
323 | |||
324 | write_unlock(&ehead->lock); | ||
325 | } | ||
326 | |||
327 | /* | 257 | /* |
328 | * Move a socket to time-wait or dead fin-wait-2 state. | 258 | * Move a socket to time-wait or dead fin-wait-2 state. |
329 | */ | 259 | */ |
@@ -381,7 +311,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo) | |||
381 | tw->tw_ipv6only = 0; | 311 | tw->tw_ipv6only = 0; |
382 | #endif | 312 | #endif |
383 | /* Linkage updates. */ | 313 | /* Linkage updates. */ |
384 | __tcp_tw_hashdance(sk, tw); | 314 | __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); |
385 | 315 | ||
386 | /* Get the TIME_WAIT timeout firing. */ | 316 | /* Get the TIME_WAIT timeout firing. */ |
387 | if (timeo < rto) | 317 | if (timeo < rto) |
@@ -448,7 +378,7 @@ rescan: | |||
448 | inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) { | 378 | inet_twsk_for_each_inmate(tw, node, &tcp_tw_death_row[slot]) { |
449 | __inet_twsk_del_dead_node(tw); | 379 | __inet_twsk_del_dead_node(tw); |
450 | spin_unlock(&tw_death_lock); | 380 | spin_unlock(&tw_death_lock); |
451 | tcp_timewait_kill(tw); | 381 | __inet_twsk_kill(tw, &tcp_hashinfo); |
452 | inet_twsk_put(tw); | 382 | inet_twsk_put(tw); |
453 | killed++; | 383 | killed++; |
454 | spin_lock(&tw_death_lock); | 384 | spin_lock(&tw_death_lock); |
@@ -544,7 +474,7 @@ void tcp_tw_deschedule(struct inet_timewait_sock *tw) | |||
544 | del_timer(&tcp_tw_timer); | 474 | del_timer(&tcp_tw_timer); |
545 | } | 475 | } |
546 | spin_unlock(&tw_death_lock); | 476 | spin_unlock(&tw_death_lock); |
547 | tcp_timewait_kill(tw); | 477 | __inet_twsk_kill(tw, &tcp_hashinfo); |
548 | } | 478 | } |
549 | 479 | ||
550 | /* Short-time timewait calendar */ | 480 | /* Short-time timewait calendar */ |
@@ -653,7 +583,7 @@ void tcp_twcal_tick(unsigned long dummy) | |||
653 | inet_twsk_for_each_inmate_safe(tw, node, safe, | 583 | inet_twsk_for_each_inmate_safe(tw, node, safe, |
654 | &tcp_twcal_row[slot]) { | 584 | &tcp_twcal_row[slot]) { |
655 | __inet_twsk_del_dead_node(tw); | 585 | __inet_twsk_del_dead_node(tw); |
656 | tcp_timewait_kill(tw); | 586 | __inet_twsk_kill(tw, &tcp_hashinfo); |
657 | inet_twsk_put(tw); | 587 | inet_twsk_put(tw); |
658 | killed++; | 588 | killed++; |
659 | } | 589 | } |