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.c123
1 files changed, 52 insertions, 71 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 57e26fa66185..eacf4cfef146 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -108,9 +108,6 @@
108 * Snmp MIB for the UDP layer 108 * Snmp MIB for the UDP layer
109 */ 109 */
110 110
111DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly;
112EXPORT_SYMBOL(udp_stats_in6);
113
114struct hlist_head udp_hash[UDP_HTABLE_SIZE]; 111struct hlist_head udp_hash[UDP_HTABLE_SIZE];
115DEFINE_RWLOCK(udp_hash_lock); 112DEFINE_RWLOCK(udp_hash_lock);
116 113
@@ -125,14 +122,23 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
125atomic_t udp_memory_allocated; 122atomic_t udp_memory_allocated;
126EXPORT_SYMBOL(udp_memory_allocated); 123EXPORT_SYMBOL(udp_memory_allocated);
127 124
128static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, 125static int udp_lib_lport_inuse(struct net *net, __u16 num,
129 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))
130{ 130{
131 struct sock *sk; 131 struct sock *sk2;
132 struct hlist_node *node; 132 struct hlist_node *node;
133 133
134 sk_for_each(sk, node, &udptable[udp_hashfn(net, num)]) 134 sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)])
135 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))
136 return 1; 142 return 1;
137 return 0; 143 return 0;
138} 144}
@@ -149,83 +155,37 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum,
149 const struct sock *sk2 ) ) 155 const struct sock *sk2 ) )
150{ 156{
151 struct hlist_head *udptable = sk->sk_prot->h.udp_hash; 157 struct hlist_head *udptable = sk->sk_prot->h.udp_hash;
152 struct hlist_node *node;
153 struct hlist_head *head;
154 struct sock *sk2;
155 int error = 1; 158 int error = 1;
156 struct net *net = sock_net(sk); 159 struct net *net = sock_net(sk);
157 160
158 write_lock_bh(&udp_hash_lock); 161 write_lock_bh(&udp_hash_lock);
159 162
160 if (!snum) { 163 if (!snum) {
161 int i, low, high, remaining; 164 int low, high, remaining;
162 unsigned rover, best, best_size_so_far; 165 unsigned rand;
166 unsigned short first;
163 167
164 inet_get_local_port_range(&low, &high); 168 inet_get_local_port_range(&low, &high);
165 remaining = (high - low) + 1; 169 remaining = (high - low) + 1;
166 170
167 best_size_so_far = UINT_MAX; 171 rand = net_random();
168 best = rover = net_random() % remaining + low; 172 snum = first = rand % remaining + low;
169 173 rand |= 1;
170 /* 1st pass: look for empty (or shortest) hash chain */ 174 while (udp_lib_lport_inuse(net, snum, udptable, sk,
171 for (i = 0; i < UDP_HTABLE_SIZE; i++) { 175 saddr_comp)) {
172 int size = 0; 176 do {
173 177 snum = snum + rand;
174 head = &udptable[udp_hashfn(net, rover)]; 178 } while (snum < low || snum > high);
175 if (hlist_empty(head)) 179 if (snum == first)
176 goto gotit; 180 goto fail;
177
178 sk_for_each(sk2, node, head) {
179 if (++size >= best_size_so_far)
180 goto next;
181 }
182 best_size_so_far = size;
183 best = rover;
184 next:
185 /* fold back if end of range */
186 if (++rover > high)
187 rover = low + ((rover - low)
188 & (UDP_HTABLE_SIZE - 1));
189
190
191 }
192
193 /* 2nd pass: find hole in shortest hash chain */
194 rover = best;
195 for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
196 if (! __udp_lib_lport_inuse(net, rover, udptable))
197 goto gotit;
198 rover += UDP_HTABLE_SIZE;
199 if (rover > high)
200 rover = low + ((rover - low)
201 & (UDP_HTABLE_SIZE - 1));
202 } 181 }
203 182 } else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp))
204
205 /* All ports in use! */
206 goto fail; 183 goto fail;
207 184
208gotit:
209 snum = rover;
210 } else {
211 head = &udptable[udp_hashfn(net, snum)];
212
213 sk_for_each(sk2, node, head)
214 if (sk2->sk_hash == snum &&
215 sk2 != sk &&
216 net_eq(sock_net(sk2), net) &&
217 (!sk2->sk_reuse || !sk->sk_reuse) &&
218 (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
219 || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
220 (*saddr_comp)(sk, sk2) )
221 goto fail;
222 }
223
224 inet_sk(sk)->num = snum; 185 inet_sk(sk)->num = snum;
225 sk->sk_hash = snum; 186 sk->sk_hash = snum;
226 if (sk_unhashed(sk)) { 187 if (sk_unhashed(sk)) {
227 head = &udptable[udp_hashfn(net, snum)]; 188 sk_add_node(sk, &udptable[udp_hashfn(net, snum)]);
228 sk_add_node(sk, head);
229 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 189 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
230 } 190 }
231 error = 0; 191 error = 0;
@@ -302,6 +262,28 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
302 return result; 262 return result;
303} 263}
304 264
265static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb,
266 __be16 sport, __be16 dport,
267 struct hlist_head udptable[])
268{
269 struct sock *sk;
270 const struct iphdr *iph = ip_hdr(skb);
271
272 if (unlikely(sk = skb_steal_sock(skb)))
273 return sk;
274 else
275 return __udp4_lib_lookup(dev_net(skb->dst->dev), iph->saddr, sport,
276 iph->daddr, dport, inet_iif(skb),
277 udptable);
278}
279
280struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport,
281 __be32 daddr, __be16 dport, int dif)
282{
283 return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, udp_hash);
284}
285EXPORT_SYMBOL_GPL(udp4_lib_lookup);
286
305static inline struct sock *udp_v4_mcast_next(struct sock *sk, 287static inline struct sock *udp_v4_mcast_next(struct sock *sk,
306 __be16 loc_port, __be32 loc_addr, 288 __be16 loc_port, __be32 loc_addr,
307 __be16 rmt_port, __be32 rmt_addr, 289 __be16 rmt_port, __be32 rmt_addr,
@@ -1201,8 +1183,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1201 return __udp4_lib_mcast_deliver(net, skb, uh, 1183 return __udp4_lib_mcast_deliver(net, skb, uh,
1202 saddr, daddr, udptable); 1184 saddr, daddr, udptable);
1203 1185
1204 sk = __udp4_lib_lookup(net, saddr, uh->source, daddr, 1186 sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
1205 uh->dest, inet_iif(skb), udptable);
1206 1187
1207 if (sk != NULL) { 1188 if (sk != NULL) {
1208 int ret = udp_queue_rcv_skb(sk, skb); 1189 int ret = udp_queue_rcv_skb(sk, skb);