diff options
Diffstat (limited to 'include/net/inet_hashtables.h')
-rw-r--r-- | include/net/inet_hashtables.h | 77 |
1 files changed, 72 insertions, 5 deletions
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index c38c637e0734..b5c0d64ea741 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <net/tcp_states.h> | 30 | #include <net/tcp_states.h> |
31 | 31 | ||
32 | #include <asm/atomic.h> | 32 | #include <asm/atomic.h> |
33 | #include <asm/byteorder.h> | ||
33 | 34 | ||
34 | /* This is for all connections with a full identity, no wildcards. | 35 | /* This is for all connections with a full identity, no wildcards. |
35 | * New scheme, half the table is for TIME_WAIT, the other half is | 36 | * New scheme, half the table is for TIME_WAIT, the other half is |
@@ -285,13 +286,13 @@ extern struct sock *__inet_lookup_listener(const struct hlist_head *head, | |||
285 | const int dif); | 286 | const int dif); |
286 | 287 | ||
287 | /* Optimize the common listener case. */ | 288 | /* Optimize the common listener case. */ |
288 | static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo, | 289 | static inline struct sock * |
289 | const u32 daddr, | 290 | inet_lookup_listener(struct inet_hashinfo *hashinfo, |
290 | const unsigned short hnum, | 291 | const u32 daddr, |
291 | const int dif) | 292 | const unsigned short hnum, const int dif) |
292 | { | 293 | { |
293 | struct sock *sk = NULL; | 294 | struct sock *sk = NULL; |
294 | struct hlist_head *head; | 295 | const struct hlist_head *head; |
295 | 296 | ||
296 | read_lock(&hashinfo->lhash_lock); | 297 | read_lock(&hashinfo->lhash_lock); |
297 | head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; | 298 | head = &hashinfo->listening_hash[inet_lhashfn(hnum)]; |
@@ -351,4 +352,70 @@ sherry_cache: | |||
351 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ | 352 | ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ |
352 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) | 353 | (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) |
353 | #endif /* 64-bit arch */ | 354 | #endif /* 64-bit arch */ |
355 | |||
356 | /* | ||
357 | * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need | ||
358 | * not check it for lookups anymore, thanks Alexey. -DaveM | ||
359 | * | ||
360 | * Local BH must be disabled here. | ||
361 | */ | ||
362 | static inline struct sock * | ||
363 | __inet_lookup_established(struct inet_hashinfo *hashinfo, | ||
364 | const u32 saddr, const u16 sport, | ||
365 | const u32 daddr, const u16 hnum, | ||
366 | const int dif) | ||
367 | { | ||
368 | INET_ADDR_COOKIE(acookie, saddr, daddr) | ||
369 | const __u32 ports = INET_COMBINED_PORTS(sport, hnum); | ||
370 | struct sock *sk; | ||
371 | const struct hlist_node *node; | ||
372 | /* Optimize here for direct hit, only listening connections can | ||
373 | * have wildcards anyways. | ||
374 | */ | ||
375 | const int hash = inet_ehashfn(daddr, hnum, saddr, sport, hashinfo->ehash_size); | ||
376 | struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; | ||
377 | |||
378 | read_lock(&head->lock); | ||
379 | sk_for_each(sk, node, &head->chain) { | ||
380 | if (INET_MATCH(sk, acookie, saddr, daddr, ports, dif)) | ||
381 | goto hit; /* You sunk my battleship! */ | ||
382 | } | ||
383 | |||
384 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | ||
385 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | ||
386 | if (INET_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) | ||
387 | goto hit; | ||
388 | } | ||
389 | sk = NULL; | ||
390 | out: | ||
391 | read_unlock(&head->lock); | ||
392 | return sk; | ||
393 | hit: | ||
394 | sock_hold(sk); | ||
395 | goto out; | ||
396 | } | ||
397 | |||
398 | static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo, | ||
399 | const u32 saddr, const u16 sport, | ||
400 | const u32 daddr, const u16 hnum, | ||
401 | const int dif) | ||
402 | { | ||
403 | struct sock *sk = __inet_lookup_established(hashinfo, saddr, sport, daddr, | ||
404 | hnum, dif); | ||
405 | return sk ? : inet_lookup_listener(hashinfo, daddr, hnum, dif); | ||
406 | } | ||
407 | |||
408 | static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo, | ||
409 | const u32 saddr, const u16 sport, | ||
410 | const u32 daddr, const u16 dport, | ||
411 | const int dif) | ||
412 | { | ||
413 | struct sock *sk; | ||
414 | |||
415 | local_bh_disable(); | ||
416 | sk = __inet_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); | ||
417 | local_bh_enable(); | ||
418 | |||
419 | return sk; | ||
420 | } | ||
354 | #endif /* _INET_HASHTABLES_H */ | 421 | #endif /* _INET_HASHTABLES_H */ |