/** * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up * @udptable: hash list table, must be of UDP_HTABLE_SIZE * @port_rover: pointer to record of last unallocated port * @saddr_comp: AF-dependent comparison of bound local IP addresses */ int __udp_lib_get_port(struct sock *sk, unsigned short snum, struct hlist_head udptable[], int *port_rover, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { struct hlist_node *node; struct hlist_head *head; struct sock *sk2; int error = 1; write_lock_bh(&udp_hash_lock); if (snum == 0) { int best_size_so_far, best, result, i; if (*port_rover > sysctl_local_port_range[1] || *port_rover < sysctl_local_port_range[0]) *port_rover = sysctl_local_port_range[0]; best_size_so_far = 32767; best = result = *port_rover; for (i = 0; i < UDP_HTABLE_SIZE; i++, result++) { int size; head = &udptable[result & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(head)) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); goto gotit; } size = 0; sk_for_each(sk2, node, head) { if (++size >= best_size_so_far) goto next; } best_size_so_far = size; best = result; next: ; } result = best; for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++, result += UDP_HTABLE_SIZE) { if (result > sysctl_local_port_range[1]) result = sysctl_local_port_range[0] + ((result - sysctl_local_port_range[0]) & (UDP_HTABLE_SIZE - 1)); if (! __udp_lib_lport_inuse(result, udptable)) break; } if (i >= (1 << 16) / UDP_HTABLE_SIZE) goto fail; gotit: *port_rover = snum = result; } else {
/** * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up * @saddr_comp: AF-dependent comparison of bound local IP addresses */ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { struct hlist_head *udptable = sk->sk_prot->h.udp_hash; struct hlist_node *node; struct hlist_head *head; struct sock *sk2; int error = 1; struct net *net = sock_net(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; /* 1st pass: look for empty (or shortest) hash chain */ for (i = 0; i < UDP_HTABLE_SIZE; i++) { int size = 0; head = &udptable[udp_hashfn(net, rover)]; if (hlist_empty(head)) goto gotit; sk_for_each(sk2, node, head) { 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_lib_lport_inuse(net, rover, udptable)) 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 {
/** * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up * @udptable: hash list table, must be of UDP_HTABLE_SIZE * @saddr_comp: AF-dependent comparison of bound local IP addresses */ int __udp_lib_get_port(struct sock *sk, unsigned short snum, struct hlist_head udptable[], int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { struct hlist_node *node; struct hlist_head *head; struct sock *sk2; int error = 1; write_lock_bh(&udp_hash_lock); if (!snum) { int i; int low = sysctl_local_port_range[0]; int high = sysctl_local_port_range[1]; unsigned rover, best, best_size_so_far; best_size_so_far = UINT_MAX; best = rover = net_random() % (high - low) + low; /* 1st pass: look for empty (or shortest) hash chain */ for (i = 0; i < UDP_HTABLE_SIZE; i++) { int size = 0; head = &udptable[rover & (UDP_HTABLE_SIZE - 1)]; if (hlist_empty(head)) goto gotit; sk_for_each(sk2, node, head) { 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_lib_lport_inuse(rover, udptable)) 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 {