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.c135
1 files changed, 17 insertions, 118 deletions
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index a66a7d8e2811..d325a9958909 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -54,7 +54,8 @@ EXPORT_SYMBOL(__inet6_hash);
54 * 54 *
55 * The sockhash lock must be held as a reader here. 55 * The sockhash lock must be held as a reader here.
56 */ 56 */
57struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo, 57struct sock *__inet6_lookup_established(struct net *net,
58 struct inet_hashinfo *hashinfo,
58 const struct in6_addr *saddr, 59 const struct in6_addr *saddr,
59 const __be16 sport, 60 const __be16 sport,
60 const struct in6_addr *daddr, 61 const struct in6_addr *daddr,
@@ -75,22 +76,13 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
75 read_lock(lock); 76 read_lock(lock);
76 sk_for_each(sk, node, &head->chain) { 77 sk_for_each(sk, node, &head->chain) {
77 /* For IPV6 do the cheaper port and family tests first. */ 78 /* For IPV6 do the cheaper port and family tests first. */
78 if (INET6_MATCH(sk, hash, saddr, daddr, ports, dif)) 79 if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif))
79 goto hit; /* You sunk my battleship! */ 80 goto hit; /* You sunk my battleship! */
80 } 81 }
81 /* Must check for a TIME_WAIT'er before going to listener hash. */ 82 /* Must check for a TIME_WAIT'er before going to listener hash. */
82 sk_for_each(sk, node, &head->twchain) { 83 sk_for_each(sk, node, &head->twchain) {
83 const struct inet_timewait_sock *tw = inet_twsk(sk); 84 if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif))
84 85 goto hit;
85 if(*((__portpair *)&(tw->tw_dport)) == ports &&
86 sk->sk_family == PF_INET6) {
87 const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
88
89 if (ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) &&
90 ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
91 (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif))
92 goto hit;
93 }
94 } 86 }
95 read_unlock(lock); 87 read_unlock(lock);
96 return NULL; 88 return NULL;
@@ -102,9 +94,9 @@ hit:
102} 94}
103EXPORT_SYMBOL(__inet6_lookup_established); 95EXPORT_SYMBOL(__inet6_lookup_established);
104 96
105struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, 97struct sock *inet6_lookup_listener(struct net *net,
106 const struct in6_addr *daddr, 98 struct inet_hashinfo *hashinfo, const struct in6_addr *daddr,
107 const unsigned short hnum, const int dif) 99 const unsigned short hnum, const int dif)
108{ 100{
109 struct sock *sk; 101 struct sock *sk;
110 const struct hlist_node *node; 102 const struct hlist_node *node;
@@ -113,7 +105,8 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
113 105
114 read_lock(&hashinfo->lhash_lock); 106 read_lock(&hashinfo->lhash_lock);
115 sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { 107 sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) {
116 if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { 108 if (sk->sk_net == net && inet_sk(sk)->num == hnum &&
109 sk->sk_family == PF_INET6) {
117 const struct ipv6_pinfo *np = inet6_sk(sk); 110 const struct ipv6_pinfo *np = inet6_sk(sk);
118 111
119 score = 1; 112 score = 1;
@@ -145,7 +138,7 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
145 138
146EXPORT_SYMBOL_GPL(inet6_lookup_listener); 139EXPORT_SYMBOL_GPL(inet6_lookup_listener);
147 140
148struct sock *inet6_lookup(struct inet_hashinfo *hashinfo, 141struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo,
149 const struct in6_addr *saddr, const __be16 sport, 142 const struct in6_addr *saddr, const __be16 sport,
150 const struct in6_addr *daddr, const __be16 dport, 143 const struct in6_addr *daddr, const __be16 dport,
151 const int dif) 144 const int dif)
@@ -153,7 +146,7 @@ struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
153 struct sock *sk; 146 struct sock *sk;
154 147
155 local_bh_disable(); 148 local_bh_disable();
156 sk = __inet6_lookup(hashinfo, saddr, sport, daddr, ntohs(dport), dif); 149 sk = __inet6_lookup(net, hashinfo, saddr, sport, daddr, ntohs(dport), dif);
157 local_bh_enable(); 150 local_bh_enable();
158 151
159 return sk; 152 return sk;
@@ -179,21 +172,16 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
179 struct sock *sk2; 172 struct sock *sk2;
180 const struct hlist_node *node; 173 const struct hlist_node *node;
181 struct inet_timewait_sock *tw; 174 struct inet_timewait_sock *tw;
175 struct net *net = sk->sk_net;
182 176
183 prefetch(head->chain.first); 177 prefetch(head->chain.first);
184 write_lock(lock); 178 write_lock(lock);
185 179
186 /* Check TIME-WAIT sockets first. */ 180 /* Check TIME-WAIT sockets first. */
187 sk_for_each(sk2, node, &head->twchain) { 181 sk_for_each(sk2, node, &head->twchain) {
188 const struct inet6_timewait_sock *tw6 = inet6_twsk(sk2);
189
190 tw = inet_twsk(sk2); 182 tw = inet_twsk(sk2);
191 183
192 if(*((__portpair *)&(tw->tw_dport)) == ports && 184 if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) {
193 sk2->sk_family == PF_INET6 &&
194 ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) &&
195 ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
196 (!sk2->sk_bound_dev_if || sk2->sk_bound_dev_if == dif)) {
197 if (twsk_unique(sk, sk2, twp)) 185 if (twsk_unique(sk, sk2, twp))
198 goto unique; 186 goto unique;
199 else 187 else
@@ -204,7 +192,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
204 192
205 /* And established part... */ 193 /* And established part... */
206 sk_for_each(sk2, node, &head->chain) { 194 sk_for_each(sk2, node, &head->chain) {
207 if (INET6_MATCH(sk2, hash, saddr, daddr, ports, dif)) 195 if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif))
208 goto not_unique; 196 goto not_unique;
209 } 197 }
210 198
@@ -248,97 +236,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
248int inet6_hash_connect(struct inet_timewait_death_row *death_row, 236int inet6_hash_connect(struct inet_timewait_death_row *death_row,
249 struct sock *sk) 237 struct sock *sk)
250{ 238{
251 struct inet_hashinfo *hinfo = death_row->hashinfo; 239 return __inet_hash_connect(death_row, sk,
252 const unsigned short snum = inet_sk(sk)->num; 240 __inet6_check_established, __inet6_hash);
253 struct inet_bind_hashbucket *head;
254 struct inet_bind_bucket *tb;
255 int ret;
256
257 if (snum == 0) {
258 int i, port, low, high, remaining;
259 static u32 hint;
260 const u32 offset = hint + inet6_sk_port_offset(sk);
261 struct hlist_node *node;
262 struct inet_timewait_sock *tw = NULL;
263
264 inet_get_local_port_range(&low, &high);
265 remaining = (high - low) + 1;
266
267 local_bh_disable();
268 for (i = 1; i <= remaining; i++) {
269 port = low + (i + offset) % remaining;
270 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
271 spin_lock(&head->lock);
272
273 /* Does not bother with rcv_saddr checks,
274 * because the established check is already
275 * unique enough.
276 */
277 inet_bind_bucket_for_each(tb, node, &head->chain) {
278 if (tb->port == port) {
279 BUG_TRAP(!hlist_empty(&tb->owners));
280 if (tb->fastreuse >= 0)
281 goto next_port;
282 if (!__inet6_check_established(death_row,
283 sk, port,
284 &tw))
285 goto ok;
286 goto next_port;
287 }
288 }
289
290 tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
291 head, port);
292 if (!tb) {
293 spin_unlock(&head->lock);
294 break;
295 }
296 tb->fastreuse = -1;
297 goto ok;
298
299 next_port:
300 spin_unlock(&head->lock);
301 }
302 local_bh_enable();
303
304 return -EADDRNOTAVAIL;
305
306ok:
307 hint += i;
308
309 /* Head lock still held and bh's disabled */
310 inet_bind_hash(sk, tb, port);
311 if (sk_unhashed(sk)) {
312 inet_sk(sk)->sport = htons(port);
313 __inet6_hash(hinfo, sk);
314 }
315 spin_unlock(&head->lock);
316
317 if (tw) {
318 inet_twsk_deschedule(tw, death_row);
319 inet_twsk_put(tw);
320 }
321
322 ret = 0;
323 goto out;
324 }
325
326 head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
327 tb = inet_csk(sk)->icsk_bind_hash;
328 spin_lock_bh(&head->lock);
329
330 if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
331 __inet6_hash(hinfo, sk);
332 spin_unlock_bh(&head->lock);
333 return 0;
334 } else {
335 spin_unlock(&head->lock);
336 /* No definite answer... Walk to established hash table */
337 ret = __inet6_check_established(death_row, sk, snum, NULL);
338out:
339 local_bh_enable();
340 return ret;
341 }
342} 241}
343 242
344EXPORT_SYMBOL_GPL(inet6_hash_connect); 243EXPORT_SYMBOL_GPL(inet6_hash_connect);