diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/udp.c | 43 |
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); | |||
122 | atomic_t udp_memory_allocated; | 122 | atomic_t udp_memory_allocated; |
123 | EXPORT_SYMBOL(udp_memory_allocated); | 123 | EXPORT_SYMBOL(udp_memory_allocated); |
124 | 124 | ||
125 | static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, | 125 | static 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; |