diff options
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r-- | net/ipv4/udp.c | 77 |
1 files changed, 51 insertions, 26 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 144970704c2c..113e0c4c8a92 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c | |||
@@ -203,6 +203,13 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
203 | result = sysctl_local_port_range[0] | 203 | result = sysctl_local_port_range[0] |
204 | + ((result - sysctl_local_port_range[0]) & | 204 | + ((result - sysctl_local_port_range[0]) & |
205 | (UDP_HTABLE_SIZE - 1)); | 205 | (UDP_HTABLE_SIZE - 1)); |
206 | hash = hash_port_and_addr(result, 0); | ||
207 | if (__udp_lib_port_inuse(hash, result, | ||
208 | 0, udptable)) | ||
209 | continue; | ||
210 | if (!inet_sk(sk)->rcv_saddr) | ||
211 | break; | ||
212 | |||
206 | hash = hash_port_and_addr(result, | 213 | hash = hash_port_and_addr(result, |
207 | inet_sk(sk)->rcv_saddr); | 214 | inet_sk(sk)->rcv_saddr); |
208 | if (! __udp_lib_port_inuse(hash, result, | 215 | if (! __udp_lib_port_inuse(hash, result, |
@@ -214,18 +221,36 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, | |||
214 | gotit: | 221 | gotit: |
215 | *port_rover = snum = result; | 222 | *port_rover = snum = result; |
216 | } else { | 223 | } else { |
217 | hash = hash_port_and_addr(snum, inet_sk(sk)->rcv_saddr); | 224 | hash = hash_port_and_addr(snum, 0); |
218 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | 225 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; |
219 | 226 | ||
220 | sk_for_each(sk2, node, head) | 227 | sk_for_each(sk2, node, head) |
221 | if (sk2->sk_hash == hash && | 228 | if (sk2->sk_hash == hash && |
222 | sk2 != sk && | 229 | sk2 != sk && |
223 | inet_sk(sk2)->num == snum && | 230 | inet_sk(sk2)->num == snum && |
224 | (!sk2->sk_reuse || !sk->sk_reuse) && | 231 | (!sk2->sk_reuse || !sk->sk_reuse) && |
225 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if | 232 | (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || |
226 | || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && | 233 | sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && |
227 | (*saddr_comp)(sk, sk2) ) | 234 | (*saddr_comp)(sk, sk2)) |
228 | goto fail; | 235 | goto fail; |
236 | |||
237 | if (inet_sk(sk)->rcv_saddr) { | ||
238 | hash = hash_port_and_addr(snum, | ||
239 | inet_sk(sk)->rcv_saddr); | ||
240 | head = &udptable[hash & (UDP_HTABLE_SIZE - 1)]; | ||
241 | |||
242 | sk_for_each(sk2, node, head) | ||
243 | if (sk2->sk_hash == hash && | ||
244 | sk2 != sk && | ||
245 | inet_sk(sk2)->num == snum && | ||
246 | (!sk2->sk_reuse || !sk->sk_reuse) && | ||
247 | (!sk2->sk_bound_dev_if || | ||
248 | !sk->sk_bound_dev_if || | ||
249 | sk2->sk_bound_dev_if == | ||
250 | sk->sk_bound_dev_if) && | ||
251 | (*saddr_comp)(sk, sk2)) | ||
252 | goto fail; | ||
253 | } | ||
229 | } | 254 | } |
230 | inet_sk(sk)->num = snum; | 255 | inet_sk(sk)->num = snum; |
231 | sk->sk_hash = hash; | 256 | sk->sk_hash = hash; |
@@ -270,10 +295,10 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, | |||
270 | struct sock *sk, *result = NULL; | 295 | struct sock *sk, *result = NULL; |
271 | struct hlist_node *node; | 296 | struct hlist_node *node; |
272 | unsigned int hash, hashwild; | 297 | unsigned int hash, hashwild; |
273 | int score, best = -1; | 298 | int score, best = -1, hport = ntohs(dport); |
274 | 299 | ||
275 | hash = hash_port_and_addr(ntohs(dport), daddr); | 300 | hash = hash_port_and_addr(hport, daddr); |
276 | hashwild = hash_port_and_addr(ntohs(dport), 0); | 301 | hashwild = hash_port_and_addr(hport, 0); |
277 | 302 | ||
278 | read_lock(&udp_hash_lock); | 303 | read_lock(&udp_hash_lock); |
279 | 304 | ||
@@ -283,7 +308,7 @@ lookup: | |||
283 | struct inet_sock *inet = inet_sk(sk); | 308 | struct inet_sock *inet = inet_sk(sk); |
284 | 309 | ||
285 | if (sk->sk_hash != hash || ipv6_only_sock(sk) || | 310 | if (sk->sk_hash != hash || ipv6_only_sock(sk) || |
286 | inet->num != dport) | 311 | inet->num != hport) |
287 | continue; | 312 | continue; |
288 | 313 | ||
289 | score = (sk->sk_family == PF_INET ? 1 : 0); | 314 | score = (sk->sk_family == PF_INET ? 1 : 0); |
@@ -327,11 +352,10 @@ found: | |||
327 | return result; | 352 | return result; |
328 | } | 353 | } |
329 | 354 | ||
330 | static inline struct sock *udp_v4_mcast_next( | 355 | static inline struct sock *udp_v4_mcast_next(struct sock *sk, unsigned int hnum, |
331 | struct sock *sk, | 356 | int hport, __be32 loc_addr, |
332 | unsigned int hnum, __be16 loc_port, __be32 loc_addr, | 357 | __be16 rmt_port, __be32 rmt_addr, |
333 | __be16 rmt_port, __be32 rmt_addr, | 358 | int dif) |
334 | int dif) | ||
335 | { | 359 | { |
336 | struct hlist_node *node; | 360 | struct hlist_node *node; |
337 | struct sock *s = sk; | 361 | struct sock *s = sk; |
@@ -340,7 +364,7 @@ static inline struct sock *udp_v4_mcast_next( | |||
340 | struct inet_sock *inet = inet_sk(s); | 364 | struct inet_sock *inet = inet_sk(s); |
341 | 365 | ||
342 | if (s->sk_hash != hnum || | 366 | if (s->sk_hash != hnum || |
343 | inet->num != loc_port || | 367 | inet->num != hport || |
344 | (inet->daddr && inet->daddr != rmt_addr) || | 368 | (inet->daddr && inet->daddr != rmt_addr) || |
345 | (inet->dport != rmt_port && inet->dport) || | 369 | (inet->dport != rmt_port && inet->dport) || |
346 | (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || | 370 | (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || |
@@ -1173,8 +1197,9 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb, | |||
1173 | { | 1197 | { |
1174 | struct sock *sk, *skw, *sknext; | 1198 | struct sock *sk, *skw, *sknext; |
1175 | int dif; | 1199 | int dif; |
1176 | unsigned int hash = hash_port_and_addr(ntohs(uh->dest), daddr); | 1200 | int hport = ntohs(uh->dest); |
1177 | unsigned int hashwild = hash_port_and_addr(ntohs(uh->dest), 0); | 1201 | unsigned int hash = hash_port_and_addr(hport, daddr); |
1202 | unsigned int hashwild = hash_port_and_addr(hport, 0); | ||
1178 | 1203 | ||
1179 | dif = skb->dev->ifindex; | 1204 | dif = skb->dev->ifindex; |
1180 | 1205 | ||
@@ -1183,20 +1208,20 @@ static int __udp4_lib_mcast_deliver(struct sk_buff *skb, | |||
1183 | sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]); | 1208 | sk = sk_head(&udptable[hash & (UDP_HTABLE_SIZE - 1)]); |
1184 | skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]); | 1209 | skw = sk_head(&udptable[hashwild & (UDP_HTABLE_SIZE - 1)]); |
1185 | 1210 | ||
1186 | sk = udp_v4_mcast_next(sk, hash, uh->dest, daddr, uh->source, saddr, dif); | 1211 | sk = udp_v4_mcast_next(sk, hash, hport, daddr, uh->source, saddr, dif); |
1187 | if (!sk) { | 1212 | if (!sk) { |
1188 | hash = hashwild; | 1213 | hash = hashwild; |
1189 | sk = udp_v4_mcast_next(skw, hash, uh->dest, daddr, uh->source, | 1214 | sk = udp_v4_mcast_next(skw, hash, hport, daddr, uh->source, |
1190 | saddr, dif); | 1215 | saddr, dif); |
1191 | } | 1216 | } |
1192 | if (sk) { | 1217 | if (sk) { |
1193 | do { | 1218 | do { |
1194 | struct sk_buff *skb1 = skb; | 1219 | struct sk_buff *skb1 = skb; |
1195 | sknext = udp_v4_mcast_next(sk_next(sk), hash, uh->dest, | 1220 | sknext = udp_v4_mcast_next(sk_next(sk), hash, hport, |
1196 | daddr, uh->source, saddr, dif); | 1221 | daddr, uh->source, saddr, dif); |
1197 | if (!sknext && hash != hashwild) { | 1222 | if (!sknext && hash != hashwild) { |
1198 | hash = hashwild; | 1223 | hash = hashwild; |
1199 | sknext = udp_v4_mcast_next(skw, hash, uh->dest, | 1224 | sknext = udp_v4_mcast_next(skw, hash, hport, |
1200 | daddr, uh->source, saddr, dif); | 1225 | daddr, uh->source, saddr, dif); |
1201 | } | 1226 | } |
1202 | if (sknext) | 1227 | if (sknext) |
@@ -1295,7 +1320,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], | |||
1295 | return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); | 1320 | return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); |
1296 | 1321 | ||
1297 | sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, | 1322 | sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, |
1298 | skb->dev->ifindex, udptable ); | 1323 | skb->dev->ifindex, udptable); |
1299 | 1324 | ||
1300 | if (sk != NULL) { | 1325 | if (sk != NULL) { |
1301 | int ret = udp_queue_rcv_skb(sk, skb); | 1326 | int ret = udp_queue_rcv_skb(sk, skb); |