diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 56 |
1 files changed, 12 insertions, 44 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 85f8e8e10b1b..67d8430b4a2a 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -155,55 +155,23 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
155 | write_lock_bh(&udp_hash_lock); | 155 | write_lock_bh(&udp_hash_lock); |
156 | 156 | ||
157 | if (!snum) { | 157 | if (!snum) { |
158 | int i, low, high, remaining; | 158 | int low, high, remaining; |
159 | unsigned rover, best, best_size_so_far; | 159 | unsigned rand; |
160 | unsigned short first; | ||
160 | 161 | ||
161 | inet_get_local_port_range(&low, &high); | 162 | inet_get_local_port_range(&low, &high); |
162 | remaining = (high - low) + 1; | 163 | remaining = (high - low) + 1; |
163 | 164 | ||
164 | best_size_so_far = UINT_MAX; | 165 | rand = net_random(); |
165 | best = rover = net_random() % remaining + low; | 166 | snum = first = rand % remaining + low; |
166 | 167 | rand |= 1; | |
167 | /* 1st pass: look for empty (or shortest) hash chain */ | 168 | while (__udp_lib_lport_inuse(net, snum, udptable)) { |
168 | for (i = 0; i < UDP_HTABLE_SIZE; i++) { | 169 | do { |
169 | int size = 0; | 170 | snum = snum + rand; |
170 | 171 | } while (snum < low || snum > high); | |
171 | head = &udptable[udp_hashfn(net, rover)]; | 172 | if (snum == first) |
172 | if (hlist_empty(head)) | 173 | goto fail; |
173 | goto gotit; | ||
174 | |||
175 | sk_for_each(sk2, node, head) { | ||
176 | if (++size >= best_size_so_far) | ||
177 | goto next; | ||
178 | } | ||
179 | best_size_so_far = size; | ||
180 | best = rover; | ||
181 | next: | ||
182 | /* fold back if end of range */ | ||
183 | if (++rover > high) | ||
184 | rover = low + ((rover - low) | ||
185 | & (UDP_HTABLE_SIZE - 1)); | ||
186 | |||
187 | |||
188 | } | ||
189 | |||
190 | /* 2nd pass: find hole in shortest hash chain */ | ||
191 | rover = best; | ||
192 | for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) { | ||
193 | if (! __udp_lib_lport_inuse(net, rover, udptable)) | ||
194 | goto gotit; | ||
195 | rover += UDP_HTABLE_SIZE; | ||
196 | if (rover > high) | ||
197 | rover = low + ((rover - low) | ||
198 | & (UDP_HTABLE_SIZE - 1)); | ||
199 | } | 174 | } |
200 | |||
201 | |||
202 | /* All ports in use! */ | ||
203 | goto fail; | ||
204 | |||
205 | gotit: | ||
206 | snum = rover; | ||
207 | } else { | 175 | } else { |
208 | head = &udptable[udp_hashfn(net, snum)]; | 176 | head = &udptable[udp_hashfn(net, snum)]; |
209 | 177 | ||