aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/inet6_hashtables.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/inet6_hashtables.c')
-rw-r--r--net/ipv6/inet6_hashtables.c122
1 files changed, 61 insertions, 61 deletions
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 066640e0ba8e..262e13c02ec2 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -23,6 +23,39 @@
23#include <net/secure_seq.h> 23#include <net/secure_seq.h>
24#include <net/ip.h> 24#include <net/ip.h>
25 25
26static unsigned int inet6_ehashfn(struct net *net,
27 const struct in6_addr *laddr,
28 const u16 lport,
29 const struct in6_addr *faddr,
30 const __be16 fport)
31{
32 static u32 inet6_ehash_secret __read_mostly;
33 static u32 ipv6_hash_secret __read_mostly;
34
35 u32 lhash, fhash;
36
37 net_get_random_once(&inet6_ehash_secret, sizeof(inet6_ehash_secret));
38 net_get_random_once(&ipv6_hash_secret, sizeof(ipv6_hash_secret));
39
40 lhash = (__force u32)laddr->s6_addr32[3];
41 fhash = __ipv6_addr_jhash(faddr, ipv6_hash_secret);
42
43 return __inet6_ehashfn(lhash, lport, fhash, fport,
44 inet6_ehash_secret + net_hash_mix(net));
45}
46
47static int inet6_sk_ehashfn(const struct sock *sk)
48{
49 const struct inet_sock *inet = inet_sk(sk);
50 const struct in6_addr *laddr = &sk->sk_v6_rcv_saddr;
51 const struct in6_addr *faddr = &sk->sk_v6_daddr;
52 const __u16 lport = inet->inet_num;
53 const __be16 fport = inet->inet_dport;
54 struct net *net = sock_net(sk);
55
56 return inet6_ehashfn(net, laddr, lport, faddr, fport);
57}
58
26int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) 59int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw)
27{ 60{
28 struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; 61 struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
@@ -89,43 +122,22 @@ begin:
89 sk_nulls_for_each_rcu(sk, node, &head->chain) { 122 sk_nulls_for_each_rcu(sk, node, &head->chain) {
90 if (sk->sk_hash != hash) 123 if (sk->sk_hash != hash)
91 continue; 124 continue;
92 if (likely(INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { 125 if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif))
93 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
94 goto begintw;
95 if (unlikely(!INET6_MATCH(sk, net, saddr, daddr,
96 ports, dif))) {
97 sock_put(sk);
98 goto begin;
99 }
100 goto out;
101 }
102 }
103 if (get_nulls_value(node) != slot)
104 goto begin;
105
106begintw:
107 /* Must check for a TIME_WAIT'er before going to listener hash. */
108 sk_nulls_for_each_rcu(sk, node, &head->twchain) {
109 if (sk->sk_hash != hash)
110 continue; 126 continue;
111 if (likely(INET6_TW_MATCH(sk, net, saddr, daddr, 127 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt)))
112 ports, dif))) {
113 if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) {
114 sk = NULL;
115 goto out;
116 }
117 if (unlikely(!INET6_TW_MATCH(sk, net, saddr, daddr,
118 ports, dif))) {
119 inet_twsk_put(inet_twsk(sk));
120 goto begintw;
121 }
122 goto out; 128 goto out;
129
130 if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) {
131 sock_gen_put(sk);
132 goto begin;
123 } 133 }
134 goto found;
124 } 135 }
125 if (get_nulls_value(node) != slot) 136 if (get_nulls_value(node) != slot)
126 goto begintw; 137 goto begin;
127 sk = NULL;
128out: 138out:
139 sk = NULL;
140found:
129 rcu_read_unlock(); 141 rcu_read_unlock();
130 return sk; 142 return sk;
131} 143}
@@ -140,11 +152,10 @@ static inline int compute_score(struct sock *sk, struct net *net,
140 152
141 if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && 153 if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum &&
142 sk->sk_family == PF_INET6) { 154 sk->sk_family == PF_INET6) {
143 const struct ipv6_pinfo *np = inet6_sk(sk);
144 155
145 score = 1; 156 score = 1;
146 if (!ipv6_addr_any(&np->rcv_saddr)) { 157 if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) {
147 if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) 158 if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr))
148 return -1; 159 return -1;
149 score++; 160 score++;
150 } 161 }
@@ -236,9 +247,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
236{ 247{
237 struct inet_hashinfo *hinfo = death_row->hashinfo; 248 struct inet_hashinfo *hinfo = death_row->hashinfo;
238 struct inet_sock *inet = inet_sk(sk); 249 struct inet_sock *inet = inet_sk(sk);
239 const struct ipv6_pinfo *np = inet6_sk(sk); 250 const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr;
240 const struct in6_addr *daddr = &np->rcv_saddr; 251 const struct in6_addr *saddr = &sk->sk_v6_daddr;
241 const struct in6_addr *saddr = &np->daddr;
242 const int dif = sk->sk_bound_dev_if; 252 const int dif = sk->sk_bound_dev_if;
243 const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); 253 const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport);
244 struct net *net = sock_net(sk); 254 struct net *net = sock_net(sk);
@@ -248,38 +258,28 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
248 spinlock_t *lock = inet_ehash_lockp(hinfo, hash); 258 spinlock_t *lock = inet_ehash_lockp(hinfo, hash);
249 struct sock *sk2; 259 struct sock *sk2;
250 const struct hlist_nulls_node *node; 260 const struct hlist_nulls_node *node;
251 struct inet_timewait_sock *tw; 261 struct inet_timewait_sock *tw = NULL;
252 int twrefcnt = 0; 262 int twrefcnt = 0;
253 263
254 spin_lock(lock); 264 spin_lock(lock);
255 265
256 /* Check TIME-WAIT sockets first. */
257 sk_nulls_for_each(sk2, node, &head->twchain) {
258 if (sk2->sk_hash != hash)
259 continue;
260
261 if (likely(INET6_TW_MATCH(sk2, net, saddr, daddr,
262 ports, dif))) {
263 tw = inet_twsk(sk2);
264 if (twsk_unique(sk, sk2, twp))
265 goto unique;
266 else
267 goto not_unique;
268 }
269 }
270 tw = NULL;
271
272 /* And established part... */
273 sk_nulls_for_each(sk2, node, &head->chain) { 266 sk_nulls_for_each(sk2, node, &head->chain) {
274 if (sk2->sk_hash != hash) 267 if (sk2->sk_hash != hash)
275 continue; 268 continue;
276 if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) 269
270 if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) {
271 if (sk2->sk_state == TCP_TIME_WAIT) {
272 tw = inet_twsk(sk2);
273 if (twsk_unique(sk, sk2, twp))
274 break;
275 }
277 goto not_unique; 276 goto not_unique;
277 }
278 } 278 }
279 279
280unique:
281 /* Must record num and sport now. Otherwise we will see 280 /* Must record num and sport now. Otherwise we will see
282 * in hash table socket with a funny identity. */ 281 * in hash table socket with a funny identity.
282 */
283 inet->inet_num = lport; 283 inet->inet_num = lport;
284 inet->inet_sport = htons(lport); 284 inet->inet_sport = htons(lport);
285 sk->sk_hash = hash; 285 sk->sk_hash = hash;
@@ -312,9 +312,9 @@ not_unique:
312static inline u32 inet6_sk_port_offset(const struct sock *sk) 312static inline u32 inet6_sk_port_offset(const struct sock *sk)
313{ 313{
314 const struct inet_sock *inet = inet_sk(sk); 314 const struct inet_sock *inet = inet_sk(sk);
315 const struct ipv6_pinfo *np = inet6_sk(sk); 315
316 return secure_ipv6_port_ephemeral(np->rcv_saddr.s6_addr32, 316 return secure_ipv6_port_ephemeral(sk->sk_v6_rcv_saddr.s6_addr32,
317 np->daddr.s6_addr32, 317 sk->sk_v6_daddr.s6_addr32,
318 inet->inet_dport); 318 inet->inet_dport);
319} 319}
320 320