aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <dada1@cosmosbay.com>2008-10-09 17:51:27 -0400
committerDavid S. Miller <davem@davemloft.net>2008-10-09 17:51:27 -0400
commitf24d43c07e208372aa3d3bff419afbf43ba87698 (patch)
tree7c7c79e4b5e1759288e8d6d7604e72cc591fdd60 /net
parent626e264dd1989bdc98a5eaf2e059af4dba07ac4f (diff)
udp: complete port availability checking
While looking at UDP port randomization, I noticed it was litle bit pessimistic, not looking at type of sockets (IPV6/IPV4) and not looking at bound addresses if any. We should perform same tests than when binding to a specific port. This permits a cleanup of udp_lib_get_port() Signed-off-by: Eric Dumazet <dada1@cosmosbay.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/udp.c43
1 files changed, 19 insertions, 24 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 67d8430b4a2a..eacf4cfef146 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -122,14 +122,23 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
122atomic_t udp_memory_allocated; 122atomic_t udp_memory_allocated;
123EXPORT_SYMBOL(udp_memory_allocated); 123EXPORT_SYMBOL(udp_memory_allocated);
124 124
125static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, 125static int udp_lib_lport_inuse(struct net *net, __u16 num,
126 const struct hlist_head udptable[]) 126 const struct hlist_head udptable[],
127 struct sock *sk,
128 int (*saddr_comp)(const struct sock *sk1,
129 const struct sock *sk2))
127{ 130{
128 struct sock *sk; 131 struct sock *sk2;
129 struct hlist_node *node; 132 struct hlist_node *node;
130 133
131 sk_for_each(sk, node, &udptable[udp_hashfn(net, num)]) 134 sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)])
132 if (net_eq(sock_net(sk), net) && sk->sk_hash == num) 135 if (net_eq(sock_net(sk2), net) &&
136 sk2 != sk &&
137 sk2->sk_hash == num &&
138 (!sk2->sk_reuse || !sk->sk_reuse) &&
139 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
140 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
141 (*saddr_comp)(sk, sk2))
133 return 1; 142 return 1;
134 return 0; 143 return 0;
135} 144}
@@ -146,9 +155,6 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
146 const struct sock *sk2 ) ) 155 const struct sock *sk2 ) )
147{ 156{
148 struct hlist_head *udptable = sk->sk_prot->h.udp_hash; 157 struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
149 struct hlist_node *node;
150 struct hlist_head *head;
151 struct sock *sk2;
152 int error = 1; 158 int error = 1;
153 struct net *net = sock_net(sk); 159 struct net *net = sock_net(sk);
154 160
@@ -165,32 +171,21 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
165 rand = net_random(); 171 rand = net_random();
166 snum = first = rand % remaining + low; 172 snum = first = rand % remaining + low;
167 rand |= 1; 173 rand |= 1;
168 while (__udp_lib_lport_inuse(net, snum, udptable)) { 174 while (udp_lib_lport_inuse(net, snum, udptable, sk,
175 saddr_comp)) {
169 do { 176 do {
170 snum = snum + rand; 177 snum = snum + rand;
171 } while (snum < low || snum > high); 178 } while (snum < low || snum > high);
172 if (snum == first) 179 if (snum == first)
173 goto fail; 180 goto fail;
174 } 181 }
175 } else { 182 } else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp))
176 head = &udptable[udp_hashfn(net, snum)]; 183 goto fail;
177
178 sk_for_each(sk2, node, head)
179 if (sk2->sk_hash == snum &&
180 sk2 != sk &&
181 net_eq(sock_net(sk2), net) &&
182 (!sk2->sk_reuse || !sk->sk_reuse) &&
183 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
184 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
185 (*saddr_comp)(sk, sk2) )
186 goto fail;
187 }
188 184
189 inet_sk(sk)->num = snum; 185 inet_sk(sk)->num = snum;
190 sk->sk_hash = snum; 186 sk->sk_hash = snum;
191 if (sk_unhashed(sk)) { 187 if (sk_unhashed(sk)) {
192 head = &udptable[udp_hashfn(net, snum)]; 188 sk_add_node(sk, &udptable[udp_hashfn(net, snum)]);
193 sk_add_node(sk, head);
194 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 189 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
195 } 190 }
196 error = 0; 191 error = 0;