aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r--net/ipv4/udp.c77
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,
214gotit: 221gotit:
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
330static inline struct sock *udp_v4_mcast_next( 355static 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);