16 #include <linux/module.h>
17 #include <linux/random.h>
18 #include <linux/sched.h>
19 #include <linux/slab.h>
20 #include <linux/wait.h>
34 const unsigned short snum)
54 if (hlist_empty(&tb->
owners)) {
55 __hlist_del(&tb->
node);
56 release_net(ib_net(tb));
62 const unsigned short snum)
68 inet_sk(sk)->inet_num = snum;
69 sk_add_bind_node(sk, &tb->
owners);
71 inet_csk(sk)->icsk_bind_hash =
tb;
77 static void __inet_put_port(
struct sock *
sk)
80 const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->inet_num,
87 spin_lock(&head->
lock);
88 tb = inet_csk(sk)->icsk_bind_hash;
89 __sk_del_bind_node(sk);
91 inet_csk(sk)->icsk_bind_hash =
NULL;
92 inet_sk(sk)->inet_num = 0;
94 spin_unlock(&head->
lock);
108 unsigned short port = inet_sk(child)->inet_num;
109 const int bhash = inet_bhashfn(sock_net(sk), port,
114 spin_lock(&head->
lock);
115 tb = inet_csk(sk)->icsk_bind_hash;
116 if (tb->
port != port) {
124 if (net_eq(ib_net(tb), sock_net(sk)) &&
130 sock_net(sk), head, port);
132 spin_unlock(&head->
lock);
138 spin_unlock(&head->
lock);
144 static inline int compute_score(
struct sock *sk,
struct net *
net,
151 if (net_eq(sock_net(sk), net) && inet->
inet_num == hnum &&
153 __be32 rcv_saddr = inet->inet_rcv_saddr;
154 score = sk->sk_family ==
PF_INET ? 1 : 0;
156 if (rcv_saddr != daddr)
160 if (sk->sk_bound_dev_if) {
161 if (sk->sk_bound_dev_if != dif)
179 const __be32 daddr,
const unsigned short hnum,
184 unsigned int hash = inet_lhashfn(net, hnum);
193 score = compute_score(sk, net, hnum, daddr, dif);
194 if (score > hiscore) {
209 else if (
unlikely(compute_score(result, net, hnum, daddr,
233 unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport);
241 saddr, daddr, ports, dif)) {
245 saddr, daddr, ports, dif))) {
257 if (get_nulls_value(node) != slot)
264 saddr, daddr, ports, dif)) {
270 saddr, daddr, ports, dif))) {
282 if (get_nulls_value(node) != slot)
298 __be32 daddr = inet->inet_rcv_saddr;
300 int dif = sk->sk_bound_dev_if;
303 struct net *net = sock_net(sk);
304 unsigned int hash = inet_ehashfn(net, daddr, lport,
305 saddr, inet->inet_dport);
307 spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
320 saddr, daddr, ports, dif)) {
321 if (twsk_unique(sk, sk2, twp))
332 saddr, daddr, ports, dif))
343 __sk_nulls_add_node_rcu(sk, &
head->chain);
351 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
368 static inline u32 inet_sk_port_offset(
const struct sock *sk)
370 const struct inet_sock *inet = inet_sk(sk);
386 sk->sk_hash = inet_sk_ehashfn(sk);
389 lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
392 __sk_nulls_add_node_rcu(sk, list);
394 WARN_ON(sk->sk_hash != tw->tw_hash);
398 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
403 static void __inet_hash(
struct sock *sk)
414 ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)];
416 spin_lock(&ilb->
lock);
417 __sk_nulls_add_node_rcu(sk, &ilb->
head);
418 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
419 spin_unlock(&ilb->
lock);
442 lock = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)].lock;
444 lock = inet_ehash_lockp(hashinfo, sk->sk_hash);
447 done =__sk_nulls_del_node_init_rcu(sk);
449 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
450 spin_unlock_bh(lock);
455 struct sock *sk,
u32 port_offset,
461 const unsigned short snum = inet_sk(sk)->inet_num;
465 struct net *net = sock_net(sk);
476 remaining = (high -
low) + 1;
479 for (i = 1; i <= remaining; i++) {
480 port = low + (i +
offset) % remaining;
481 if (inet_is_reserved_local_port(port))
483 head = &hinfo->
bhash[inet_bhashfn(net, port,
485 spin_lock(&head->
lock);
492 if (net_eq(ib_net(tb), net) &&
497 if (!check_established(death_row, sk,
507 spin_unlock(&head->
lock);
514 spin_unlock(&head->
lock);
525 if (sk_unhashed(sk)) {
526 inet_sk(sk)->inet_sport =
htons(port);
527 twrefcnt +=
hash(sk, tw);
531 spin_unlock(&head->
lock);
546 tb = inet_csk(sk)->icsk_bind_hash;
547 spin_lock_bh(&head->
lock);
548 if (sk_head(&tb->
owners) == sk && !sk->sk_bind_node.next) {
550 spin_unlock_bh(&head->
lock);
553 spin_unlock(&head->
lock);
555 ret = check_established(death_row, sk, snum,
NULL);