diff options
| author | Arnaldo Carvalho de Melo <acme@mandriva.com> | 2005-08-12 08:26:18 -0400 |
|---|---|---|
| committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:57:29 -0400 |
| commit | 5324a040ccc708998e61ea93e669b81312f0ae11 (patch) | |
| tree | 08e40652e7c9394277a0b5e08148c43a97d46670 /net/ipv6/tcp_ipv6.c | |
| parent | 505cbfc577f3fa778005e2800b869eca25727d5f (diff) | |
[INET6_HASHTABLES]: Move inet6_lookup functions to net/ipv6/inet6_hashtables.c
Doing this we allow tcp_diag to support IPV6 even if tcp_diag is compiled
statically and IPV6 is compiled as a module, removing the previous restriction
while not building any IPV6 code if it is not selected.
Now to work on the tcpdiag_register infrastructure and then to rename the whole
thing to inetdiag, reflecting its by then completely generic nature.
Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/tcp_ipv6.c')
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 154 |
1 files changed, 1 insertions, 153 deletions
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2bc7fafe76..fb291b81cf 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | 47 | ||
| 48 | #include <net/tcp.h> | 48 | #include <net/tcp.h> |
| 49 | #include <net/ndisc.h> | 49 | #include <net/ndisc.h> |
| 50 | #include <net/inet6_hashtables.h> | ||
| 50 | #include <net/ipv6.h> | 51 | #include <net/ipv6.h> |
| 51 | #include <net/transp_v6.h> | 52 | #include <net/transp_v6.h> |
| 52 | #include <net/addrconf.h> | 53 | #include <net/addrconf.h> |
| @@ -75,30 +76,6 @@ static int tcp_v6_xmit(struct sk_buff *skb, int ipfragok); | |||
| 75 | static struct tcp_func ipv6_mapped; | 76 | static struct tcp_func ipv6_mapped; |
| 76 | static struct tcp_func ipv6_specific; | 77 | static struct tcp_func ipv6_specific; |
| 77 | 78 | ||
| 78 | /* I have no idea if this is a good hash for v6 or not. -DaveM */ | ||
| 79 | static inline int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, | ||
| 80 | const struct in6_addr *faddr, const u16 fport, | ||
| 81 | const int ehash_size) | ||
| 82 | { | ||
| 83 | int hashent = (lport ^ fport); | ||
| 84 | |||
| 85 | hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); | ||
| 86 | hashent ^= hashent>>16; | ||
| 87 | hashent ^= hashent>>8; | ||
| 88 | return (hashent & (ehash_size - 1)); | ||
| 89 | } | ||
| 90 | |||
| 91 | static inline int inet6_sk_ehashfn(const struct sock *sk, const int ehash_size) | ||
| 92 | { | ||
| 93 | const struct inet_sock *inet = inet_sk(sk); | ||
| 94 | const struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 95 | const struct in6_addr *laddr = &np->rcv_saddr; | ||
| 96 | const struct in6_addr *faddr = &np->daddr; | ||
| 97 | const __u16 lport = inet->num; | ||
| 98 | const __u16 fport = inet->dport; | ||
| 99 | return inet6_ehashfn(laddr, lport, faddr, fport, ehash_size); | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline int tcp_v6_bind_conflict(const struct sock *sk, | 79 | static inline int tcp_v6_bind_conflict(const struct sock *sk, |
| 103 | const struct inet_bind_bucket *tb) | 80 | const struct inet_bind_bucket *tb) |
| 104 | { | 81 | { |
| @@ -259,135 +236,6 @@ static void tcp_v6_hash(struct sock *sk) | |||
| 259 | } | 236 | } |
| 260 | } | 237 | } |
| 261 | 238 | ||
| 262 | static struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, | ||
| 263 | const struct in6_addr *daddr, | ||
| 264 | const unsigned short hnum, | ||
| 265 | const int dif) | ||
| 266 | { | ||
| 267 | struct sock *sk; | ||
| 268 | struct hlist_node *node; | ||
| 269 | struct sock *result = NULL; | ||
| 270 | int score, hiscore; | ||
| 271 | |||
| 272 | hiscore=0; | ||
| 273 | read_lock(&hashinfo->lhash_lock); | ||
| 274 | sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { | ||
| 275 | if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { | ||
| 276 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
| 277 | |||
| 278 | score = 1; | ||
| 279 | if (!ipv6_addr_any(&np->rcv_saddr)) { | ||
| 280 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | ||
| 281 | continue; | ||
| 282 | score++; | ||
| 283 | } | ||
| 284 | if (sk->sk_bound_dev_if) { | ||
| 285 | if (sk->sk_bound_dev_if != dif) | ||
| 286 | continue; | ||
| 287 | score++; | ||
| 288 | } | ||
| 289 | if (score == 3) { | ||
| 290 | result = sk; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | if (score > hiscore) { | ||
| 294 | hiscore = score; | ||
| 295 | result = sk; | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | if (result) | ||
| 300 | sock_hold(result); | ||
| 301 | read_unlock(&hashinfo->lhash_lock); | ||
| 302 | return result; | ||
| 303 | } | ||
| 304 | |||
| 305 | /* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so | ||
| 306 | * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM | ||
| 307 | * | ||
| 308 | * The sockhash lock must be held as a reader here. | ||
| 309 | */ | ||
| 310 | |||
| 311 | static inline struct sock * | ||
| 312 | __inet6_lookup_established(struct inet_hashinfo *hashinfo, | ||
| 313 | const struct in6_addr *saddr, | ||
| 314 | const u16 sport, | ||
| 315 | const struct in6_addr *daddr, | ||
| 316 | const u16 hnum, | ||
| 317 | const int dif) | ||
| 318 | { | ||
| 319 | struct sock *sk; | ||
| 320 | const struct hlist_node *node; | ||
| 321 | const __u32 ports = INET_COMBINED_PORTS(sport, hnum); | ||
| 322 | /* Optimize here for direct hit, only listening connections can | ||
| 323 | * have wildcards anyways. | ||
| 324 | */ | ||
| 325 | const int hash = inet6_ehashfn(daddr, hnum, saddr, sport, | ||
| 326 | hashinfo->ehash_size); | ||
| 327 | struct inet_ehash_bucket *head = &hashinfo->ehash[hash]; | ||
| 328 | |||
| 329 | read_lock(&head->lock); | ||
| 330 | sk_for_each(sk, node, &head->chain) { | ||
| 331 | /* For IPV6 do the cheaper port and family tests first. */ | ||
| 332 | if (INET6_MATCH(sk, saddr, daddr, ports, dif)) | ||
| 333 | goto hit; /* You sunk my battleship! */ | ||
| 334 | } | ||
| 335 | /* Must check for a TIME_WAIT'er before going to listener hash. */ | ||
| 336 | sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) { | ||
| 337 | const struct inet_timewait_sock *tw = inet_twsk(sk); | ||
| 338 | |||
| 339 | if(*((__u32 *)&(tw->tw_dport)) == ports && | ||
| 340 | sk->sk_family == PF_INET6) { | ||
| 341 | const struct tcp6_timewait_sock *tcp6tw = tcp6_twsk(sk); | ||
| 342 | |||
| 343 | if (ipv6_addr_equal(&tcp6tw->tw_v6_daddr, saddr) && | ||
| 344 | ipv6_addr_equal(&tcp6tw->tw_v6_rcv_saddr, daddr) && | ||
| 345 | (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) | ||
| 346 | goto hit; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | read_unlock(&head->lock); | ||
| 350 | return NULL; | ||
| 351 | |||
| 352 | hit: | ||
| 353 | sock_hold(sk); | ||
| 354 | read_unlock(&head->lock); | ||
| 355 | return sk; | ||
| 356 | } | ||
| 357 | |||
| 358 | |||
| 359 | static inline struct sock *__inet6_lookup(struct inet_hashinfo *hashinfo, | ||
| 360 | const struct in6_addr *saddr, | ||
| 361 | const u16 sport, | ||
| 362 | const struct in6_addr *daddr, | ||
| 363 | const u16 hnum, | ||
| 364 | const int dif) | ||
| 365 | { | ||
| 366 | struct sock *sk = __inet6_lookup_established(hashinfo, saddr, sport, | ||
| 367 | daddr, hnum, dif); | ||
| 368 | if (sk) | ||
| 369 | return sk; | ||
| 370 | |||
| 371 | return inet6_lookup_listener(hashinfo, daddr, hnum, dif); | ||
| 372 | } | ||
| 373 | |||
| 374 | inline struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, | ||
| 375 | const struct in6_addr *saddr, const u16 sport, | ||
| 376 | const struct in6_addr *daddr, const u16 dport, | ||
| 377 | const int dif) | ||
| 378 | { | ||
| 379 | struct sock *sk; | ||
| 380 | |||
| 381 | local_bh_disable(); | ||
| 382 | sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); | ||
| 383 | local_bh_enable(); | ||
| 384 | |||
| 385 | return sk; | ||
| 386 | } | ||
| 387 | |||
| 388 | EXPORT_SYMBOL_GPL(inet6_lookup); | ||
| 389 | |||
| 390 | |||
| 391 | /* | 239 | /* |
| 392 | * Open request hash tables. | 240 | * Open request hash tables. |
| 393 | */ | 241 | */ |
