aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/inet6_hashtables.c93
1 files changed, 2 insertions, 91 deletions
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 06b01befc90e..ece6d0ee2da5 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -233,97 +233,8 @@ static inline u32 inet6_sk_port_offset(const struct sock *sk)
233int inet6_hash_connect(struct inet_timewait_death_row *death_row, 233int inet6_hash_connect(struct inet_timewait_death_row *death_row,
234 struct sock *sk) 234 struct sock *sk)
235{ 235{
236 struct inet_hashinfo *hinfo = death_row->hashinfo; 236 return __inet_hash_connect(death_row, sk,
237 const unsigned short snum = inet_sk(sk)->num; 237 __inet6_check_established, __inet6_hash);
238 struct inet_bind_hashbucket *head;
239 struct inet_bind_bucket *tb;
240 int ret;
241
242 if (snum == 0) {
243 int i, port, low, high, remaining;
244 static u32 hint;
245 const u32 offset = hint + inet6_sk_port_offset(sk);
246 struct hlist_node *node;
247 struct inet_timewait_sock *tw = NULL;
248
249 inet_get_local_port_range(&low, &high);
250 remaining = (high - low) + 1;
251
252 local_bh_disable();
253 for (i = 1; i <= remaining; i++) {
254 port = low + (i + offset) % remaining;
255 head = &hinfo->bhash[inet_bhashfn(port, hinfo->bhash_size)];
256 spin_lock(&head->lock);
257
258 /* Does not bother with rcv_saddr checks,
259 * because the established check is already
260 * unique enough.
261 */
262 inet_bind_bucket_for_each(tb, node, &head->chain) {
263 if (tb->port == port) {
264 BUG_TRAP(!hlist_empty(&tb->owners));
265 if (tb->fastreuse >= 0)
266 goto next_port;
267 if (!__inet6_check_established(death_row,
268 sk, port,
269 &tw))
270 goto ok;
271 goto next_port;
272 }
273 }
274
275 tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep,
276 head, port);
277 if (!tb) {
278 spin_unlock(&head->lock);
279 break;
280 }
281 tb->fastreuse = -1;
282 goto ok;
283
284 next_port:
285 spin_unlock(&head->lock);
286 }
287 local_bh_enable();
288
289 return -EADDRNOTAVAIL;
290
291ok:
292 hint += i;
293
294 /* Head lock still held and bh's disabled */
295 inet_bind_hash(sk, tb, port);
296 if (sk_unhashed(sk)) {
297 inet_sk(sk)->sport = htons(port);
298 __inet6_hash(hinfo, sk);
299 }
300 spin_unlock(&head->lock);
301
302 if (tw) {
303 inet_twsk_deschedule(tw, death_row);
304 inet_twsk_put(tw);
305 }
306
307 ret = 0;
308 goto out;
309 }
310
311 head = &hinfo->bhash[inet_bhashfn(snum, hinfo->bhash_size)];
312 tb = inet_csk(sk)->icsk_bind_hash;
313 spin_lock_bh(&head->lock);
314
315 if (sk_head(&tb->owners) == sk && sk->sk_bind_node.next == NULL) {
316 __inet6_hash(hinfo, sk);
317 spin_unlock_bh(&head->lock);
318 return 0;
319 } else {
320 spin_unlock(&head->lock);
321 /* No definite answer... Walk to established hash table */
322 ret = __inet6_check_established(death_row, sk, snum, NULL);
323out:
324 local_bh_enable();
325 return ret;
326 }
327} 238}
328 239
329EXPORT_SYMBOL_GPL(inet6_hash_connect); 240EXPORT_SYMBOL_GPL(inet6_hash_connect);