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.c137
1 files changed, 60 insertions, 77 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 57e26fa66185..cf02701ced48 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -8,7 +8,7 @@
8 * Authors: Ross Biro 8 * Authors: Ross Biro
9 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 9 * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
10 * Arnt Gulbrandsen, <agulbra@nvg.unit.no> 10 * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
11 * Alan Cox, <Alan.Cox@linux.org> 11 * Alan Cox, <alan@lxorguk.ukuu.org.uk>
12 * Hirokazu Takahashi, <taka@valinux.co.jp> 12 * Hirokazu Takahashi, <taka@valinux.co.jp>
13 * 13 *
14 * Fixes: 14 * Fixes:
@@ -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,7 +262,29 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
302 return result; 262 return result;
303} 263}
304 264
305static inline struct sock *udp_v4_mcast_next(struct sock *sk, 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
287static inline struct sock *udp_v4_mcast_next(struct net *net, 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,
308 int dif) 290 int dif)
@@ -314,7 +296,8 @@ static inline struct sock *udp_v4_mcast_next(struct sock *sk,
314 sk_for_each_from(s, node) { 296 sk_for_each_from(s, node) {
315 struct inet_sock *inet = inet_sk(s); 297 struct inet_sock *inet = inet_sk(s);
316 298
317 if (s->sk_hash != hnum || 299 if (!net_eq(sock_net(s), net) ||
300 s->sk_hash != hnum ||
318 (inet->daddr && inet->daddr != rmt_addr) || 301 (inet->daddr && inet->daddr != rmt_addr) ||
319 (inet->dport != rmt_port && inet->dport) || 302 (inet->dport != rmt_port && inet->dport) ||
320 (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || 303 (inet->rcv_saddr && inet->rcv_saddr != loc_addr) ||
@@ -1097,15 +1080,16 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
1097 read_lock(&udp_hash_lock); 1080 read_lock(&udp_hash_lock);
1098 sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); 1081 sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]);
1099 dif = skb->dev->ifindex; 1082 dif = skb->dev->ifindex;
1100 sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); 1083 sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif);
1101 if (sk) { 1084 if (sk) {
1102 struct sock *sknext = NULL; 1085 struct sock *sknext = NULL;
1103 1086
1104 do { 1087 do {
1105 struct sk_buff *skb1 = skb; 1088 struct sk_buff *skb1 = skb;
1106 1089
1107 sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, 1090 sknext = udp_v4_mcast_next(net, sk_next(sk), uh->dest,
1108 uh->source, saddr, dif); 1091 daddr, uh->source, saddr,
1092 dif);
1109 if (sknext) 1093 if (sknext)
1110 skb1 = skb_clone(skb, GFP_ATOMIC); 1094 skb1 = skb_clone(skb, GFP_ATOMIC);
1111 1095
@@ -1201,8 +1185,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
1201 return __udp4_lib_mcast_deliver(net, skb, uh, 1185 return __udp4_lib_mcast_deliver(net, skb, uh,
1202 saddr, daddr, udptable); 1186 saddr, daddr, udptable);
1203 1187
1204 sk = __udp4_lib_lookup(net, saddr, uh->source, daddr, 1188 sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
1205 uh->dest, inet_iif(skb), udptable);
1206 1189
1207 if (sk != NULL) { 1190 if (sk != NULL) {
1208 int ret = udp_queue_rcv_skb(sk, skb); 1191 int ret = udp_queue_rcv_skb(sk, skb);