static int udp_v4_get_port(struct sock *sk, unsigned short snum) { struct hlist_node *node; struct sock *sk2; struct inet_sock *inet = inet_sk(sk); write_lock_bh(&udp_hash_lock); if (!snum) { int i, low, high, remaining; unsigned rover, best, best_size_so_far; inet_get_local_port_range(&low, &high); remaining = (high - low) + 1; best_size_so_far = UINT_MAX; best = rover = net_random() % remaining + low; if (!udp_lport_inuse(rover) && !inet_is_reserved_local_port(rover)) goto gotit; /* 1st pass: look for empty (or shortest) hash chain */ for (i = 0; i < UDP_HTABLE_SIZE; i++) { struct hlist_head *list; int size = 0; list = &udp_hash[rover & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(list) && !inet_is_reserved_local_port(rover)) goto gotit; sk_for_each(sk2, node, list) if (++size >= best_size_so_far) goto next; best_size_so_far = size; best = rover; next: /* fold back if end of range */ if (++rover > high) rover = low + ((rover - low) & (UDP_HTABLE_SIZE - 1)); } /* 2nd pass: find hole in shortest hash chain */ rover = best; for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) { if (!udp_lport_inuse(rover) && !inet_is_reserved_local_port(rover)) goto gotit; rover += UDP_HTABLE_SIZE; if (rover > high) rover = low + ((rover - low) & (UDP_HTABLE_SIZE - 1)); } /* All ports in use! */ goto fail; gotit: snum = rover; } else {
/* Obtain a reference to a local port for the given sock, * if snum is zero it means select any available local port. */ int inet_csk_get_port(struct sock *sk, unsigned short snum) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_bind_hashbucket *head; struct inet_bind_bucket *tb; int ret, attempts = 5; struct net *net = sock_net(sk); int smallest_size = -1, smallest_rover; //kuid_t uid = sock_i_uid(sk); //local_bh_disable(); if (!snum) { int remaining, rover, low, high; again: inet_get_local_port_range(net,&low, &high); remaining = (high - low) + 1; smallest_rover = rover = net_random() % remaining + low; smallest_size = -1; do { if (inet_is_reserved_local_port(net,rover)) goto next_nolock; head = &hashinfo->bhash[inet_bhashfn(net, rover, hashinfo->bhash_size)]; //spin_lock(&head->lock); inet_bind_bucket_for_each(tb, &head->chain) if (net_eq(ib_net(tb), net) && tb->port == rover) { if (((tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN) || (tb->fastreuseport > 0 && sk->sk_reuseport )) // && uid_eq(tb->fastuid, uid) && (tb->num_owners < smallest_size || smallest_size == -1)) { smallest_size = tb->num_owners; smallest_rover = rover; if ((atomic_read(&hashinfo->bsockets) > (high - low) + 1) && (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false))) { snum = smallest_rover; goto tb_found; } } if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) { snum = rover; goto tb_found; } goto next; } break; next: //spin_unlock(&head->lock); next_nolock: if (++rover > high) rover = low; } while (--remaining > 0); /* Exhausted local port range during search? It is not * possible for us to be holding one of the bind hash * locks if this test triggers, because if 'remaining' * drops to zero, we broke out of the do/while loop at * the top level, not from the 'break;' statement. */ ret = 1; if (remaining <= 0) { if (smallest_size != -1) { snum = smallest_rover; goto have_snum; } goto fail; } /* OK, here is the one we will use. HEAD is * non-NULL and we hold it's mutex. */ snum = rover; } else {