diff options
Diffstat (limited to 'net/ipv6/inet6_hashtables.c')
-rw-r--r-- | net/ipv6/inet6_hashtables.c | 122 |
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 | ||
26 | static 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 | |||
47 | static 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 | |||
26 | int __inet6_hash(struct sock *sk, struct inet_timewait_sock *tw) | 59 | int __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 | |||
106 | begintw: | ||
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; | ||
128 | out: | 138 | out: |
139 | sk = NULL; | ||
140 | found: | ||
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 | ||
280 | unique: | ||
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: | |||
312 | static inline u32 inet6_sk_port_offset(const struct sock *sk) | 312 | static 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 | ||