diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /net/ipv6/udp.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 300 |
1 files changed, 233 insertions, 67 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index cf538ed5ef6a..90824852f598 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/skbuff.h> | 36 | #include <linux/skbuff.h> |
37 | #include <linux/slab.h> | ||
37 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
38 | 39 | ||
39 | #include <net/ndisc.h> | 40 | #include <net/ndisc.h> |
@@ -53,7 +54,7 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
53 | { | 54 | { |
54 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; | 55 | const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; |
55 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); | 56 | const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); |
56 | __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; | 57 | __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr; |
57 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); | 58 | __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); |
58 | int sk_ipv6only = ipv6_only_sock(sk); | 59 | int sk_ipv6only = ipv6_only_sock(sk); |
59 | int sk2_ipv6only = inet_v6_ipv6only(sk2); | 60 | int sk2_ipv6only = inet_v6_ipv6only(sk2); |
@@ -63,8 +64,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
63 | /* if both are mapped, treat as IPv4 */ | 64 | /* if both are mapped, treat as IPv4 */ |
64 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) | 65 | if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) |
65 | return (!sk2_ipv6only && | 66 | return (!sk2_ipv6only && |
66 | (!sk_rcv_saddr || !sk2_rcv_saddr || | 67 | (!sk1_rcv_saddr || !sk2_rcv_saddr || |
67 | sk_rcv_saddr == sk2_rcv_saddr)); | 68 | sk1_rcv_saddr == sk2_rcv_saddr)); |
68 | 69 | ||
69 | if (addr_type2 == IPV6_ADDR_ANY && | 70 | if (addr_type2 == IPV6_ADDR_ANY && |
70 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) | 71 | !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) |
@@ -81,9 +82,33 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) | |||
81 | return 0; | 82 | return 0; |
82 | } | 83 | } |
83 | 84 | ||
85 | static unsigned int udp6_portaddr_hash(struct net *net, | ||
86 | const struct in6_addr *addr6, | ||
87 | unsigned int port) | ||
88 | { | ||
89 | unsigned int hash, mix = net_hash_mix(net); | ||
90 | |||
91 | if (ipv6_addr_any(addr6)) | ||
92 | hash = jhash_1word(0, mix); | ||
93 | else if (ipv6_addr_v4mapped(addr6)) | ||
94 | hash = jhash_1word(addr6->s6_addr32[3], mix); | ||
95 | else | ||
96 | hash = jhash2(addr6->s6_addr32, 4, mix); | ||
97 | |||
98 | return hash ^ port; | ||
99 | } | ||
100 | |||
101 | |||
84 | int udp_v6_get_port(struct sock *sk, unsigned short snum) | 102 | int udp_v6_get_port(struct sock *sk, unsigned short snum) |
85 | { | 103 | { |
86 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); | 104 | unsigned int hash2_nulladdr = |
105 | udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); | ||
106 | unsigned int hash2_partial = | ||
107 | udp6_portaddr_hash(sock_net(sk), &inet6_sk(sk)->rcv_saddr, 0); | ||
108 | |||
109 | /* precompute partial secondary hash */ | ||
110 | udp_sk(sk)->udp_portaddr_hash = hash2_partial; | ||
111 | return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); | ||
87 | } | 112 | } |
88 | 113 | ||
89 | static inline int compute_score(struct sock *sk, struct net *net, | 114 | static inline int compute_score(struct sock *sk, struct net *net, |
@@ -94,14 +119,14 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
94 | { | 119 | { |
95 | int score = -1; | 120 | int score = -1; |
96 | 121 | ||
97 | if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && | 122 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && |
98 | sk->sk_family == PF_INET6) { | 123 | sk->sk_family == PF_INET6) { |
99 | struct ipv6_pinfo *np = inet6_sk(sk); | 124 | struct ipv6_pinfo *np = inet6_sk(sk); |
100 | struct inet_sock *inet = inet_sk(sk); | 125 | struct inet_sock *inet = inet_sk(sk); |
101 | 126 | ||
102 | score = 0; | 127 | score = 0; |
103 | if (inet->dport) { | 128 | if (inet->inet_dport) { |
104 | if (inet->dport != sport) | 129 | if (inet->inet_dport != sport) |
105 | return -1; | 130 | return -1; |
106 | score++; | 131 | score++; |
107 | } | 132 | } |
@@ -124,6 +149,86 @@ static inline int compute_score(struct sock *sk, struct net *net, | |||
124 | return score; | 149 | return score; |
125 | } | 150 | } |
126 | 151 | ||
152 | #define SCORE2_MAX (1 + 1 + 1) | ||
153 | static inline int compute_score2(struct sock *sk, struct net *net, | ||
154 | const struct in6_addr *saddr, __be16 sport, | ||
155 | const struct in6_addr *daddr, unsigned short hnum, | ||
156 | int dif) | ||
157 | { | ||
158 | int score = -1; | ||
159 | |||
160 | if (net_eq(sock_net(sk), net) && udp_sk(sk)->udp_port_hash == hnum && | ||
161 | sk->sk_family == PF_INET6) { | ||
162 | struct ipv6_pinfo *np = inet6_sk(sk); | ||
163 | struct inet_sock *inet = inet_sk(sk); | ||
164 | |||
165 | if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) | ||
166 | return -1; | ||
167 | score = 0; | ||
168 | if (inet->inet_dport) { | ||
169 | if (inet->inet_dport != sport) | ||
170 | return -1; | ||
171 | score++; | ||
172 | } | ||
173 | if (!ipv6_addr_any(&np->daddr)) { | ||
174 | if (!ipv6_addr_equal(&np->daddr, saddr)) | ||
175 | return -1; | ||
176 | score++; | ||
177 | } | ||
178 | if (sk->sk_bound_dev_if) { | ||
179 | if (sk->sk_bound_dev_if != dif) | ||
180 | return -1; | ||
181 | score++; | ||
182 | } | ||
183 | } | ||
184 | return score; | ||
185 | } | ||
186 | |||
187 | |||
188 | /* called with read_rcu_lock() */ | ||
189 | static struct sock *udp6_lib_lookup2(struct net *net, | ||
190 | const struct in6_addr *saddr, __be16 sport, | ||
191 | const struct in6_addr *daddr, unsigned int hnum, int dif, | ||
192 | struct udp_hslot *hslot2, unsigned int slot2) | ||
193 | { | ||
194 | struct sock *sk, *result; | ||
195 | struct hlist_nulls_node *node; | ||
196 | int score, badness; | ||
197 | |||
198 | begin: | ||
199 | result = NULL; | ||
200 | badness = -1; | ||
201 | udp_portaddr_for_each_entry_rcu(sk, node, &hslot2->head) { | ||
202 | score = compute_score2(sk, net, saddr, sport, | ||
203 | daddr, hnum, dif); | ||
204 | if (score > badness) { | ||
205 | result = sk; | ||
206 | badness = score; | ||
207 | if (score == SCORE2_MAX) | ||
208 | goto exact_match; | ||
209 | } | ||
210 | } | ||
211 | /* | ||
212 | * if the nulls value we got at the end of this lookup is | ||
213 | * not the expected one, we must restart lookup. | ||
214 | * We probably met an item that was moved to another chain. | ||
215 | */ | ||
216 | if (get_nulls_value(node) != slot2) | ||
217 | goto begin; | ||
218 | |||
219 | if (result) { | ||
220 | exact_match: | ||
221 | if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) | ||
222 | result = NULL; | ||
223 | else if (unlikely(compute_score2(result, net, saddr, sport, | ||
224 | daddr, hnum, dif) < badness)) { | ||
225 | sock_put(result); | ||
226 | goto begin; | ||
227 | } | ||
228 | } | ||
229 | return result; | ||
230 | } | ||
231 | |||
127 | static struct sock *__udp6_lib_lookup(struct net *net, | 232 | static struct sock *__udp6_lib_lookup(struct net *net, |
128 | struct in6_addr *saddr, __be16 sport, | 233 | struct in6_addr *saddr, __be16 sport, |
129 | struct in6_addr *daddr, __be16 dport, | 234 | struct in6_addr *daddr, __be16 dport, |
@@ -132,11 +237,35 @@ static struct sock *__udp6_lib_lookup(struct net *net, | |||
132 | struct sock *sk, *result; | 237 | struct sock *sk, *result; |
133 | struct hlist_nulls_node *node; | 238 | struct hlist_nulls_node *node; |
134 | unsigned short hnum = ntohs(dport); | 239 | unsigned short hnum = ntohs(dport); |
135 | unsigned int hash = udp_hashfn(net, hnum); | 240 | unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); |
136 | struct udp_hslot *hslot = &udptable->hash[hash]; | 241 | struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; |
137 | int score, badness; | 242 | int score, badness; |
138 | 243 | ||
139 | rcu_read_lock(); | 244 | rcu_read_lock(); |
245 | if (hslot->count > 10) { | ||
246 | hash2 = udp6_portaddr_hash(net, daddr, hnum); | ||
247 | slot2 = hash2 & udptable->mask; | ||
248 | hslot2 = &udptable->hash2[slot2]; | ||
249 | if (hslot->count < hslot2->count) | ||
250 | goto begin; | ||
251 | |||
252 | result = udp6_lib_lookup2(net, saddr, sport, | ||
253 | daddr, hnum, dif, | ||
254 | hslot2, slot2); | ||
255 | if (!result) { | ||
256 | hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); | ||
257 | slot2 = hash2 & udptable->mask; | ||
258 | hslot2 = &udptable->hash2[slot2]; | ||
259 | if (hslot->count < hslot2->count) | ||
260 | goto begin; | ||
261 | |||
262 | result = udp6_lib_lookup2(net, saddr, sport, | ||
263 | &in6addr_any, hnum, dif, | ||
264 | hslot2, slot2); | ||
265 | } | ||
266 | rcu_read_unlock(); | ||
267 | return result; | ||
268 | } | ||
140 | begin: | 269 | begin: |
141 | result = NULL; | 270 | result = NULL; |
142 | badness = -1; | 271 | badness = -1; |
@@ -152,7 +281,7 @@ begin: | |||
152 | * not the expected one, we must restart lookup. | 281 | * not the expected one, we must restart lookup. |
153 | * We probably met an item that was moved to another chain. | 282 | * We probably met an item that was moved to another chain. |
154 | */ | 283 | */ |
155 | if (get_nulls_value(node) != hash) | 284 | if (get_nulls_value(node) != slot) |
156 | goto begin; | 285 | goto begin; |
157 | 286 | ||
158 | if (result) { | 287 | if (result) { |
@@ -194,7 +323,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
194 | struct ipv6_pinfo *np = inet6_sk(sk); | 323 | struct ipv6_pinfo *np = inet6_sk(sk); |
195 | struct inet_sock *inet = inet_sk(sk); | 324 | struct inet_sock *inet = inet_sk(sk); |
196 | struct sk_buff *skb; | 325 | struct sk_buff *skb; |
197 | unsigned int ulen, copied; | 326 | unsigned int ulen; |
198 | int peeked; | 327 | int peeked; |
199 | int err; | 328 | int err; |
200 | int is_udplite = IS_UDPLITE(sk); | 329 | int is_udplite = IS_UDPLITE(sk); |
@@ -213,10 +342,9 @@ try_again: | |||
213 | goto out; | 342 | goto out; |
214 | 343 | ||
215 | ulen = skb->len - sizeof(struct udphdr); | 344 | ulen = skb->len - sizeof(struct udphdr); |
216 | copied = len; | 345 | if (len > ulen) |
217 | if (copied > ulen) | 346 | len = ulen; |
218 | copied = ulen; | 347 | else if (len < ulen) |
219 | else if (copied < ulen) | ||
220 | msg->msg_flags |= MSG_TRUNC; | 348 | msg->msg_flags |= MSG_TRUNC; |
221 | 349 | ||
222 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); | 350 | is_udp4 = (skb->protocol == htons(ETH_P_IP)); |
@@ -227,14 +355,14 @@ try_again: | |||
227 | * coverage checksum (UDP-Lite), do it before the copy. | 355 | * coverage checksum (UDP-Lite), do it before the copy. |
228 | */ | 356 | */ |
229 | 357 | ||
230 | if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { | 358 | if (len < ulen || UDP_SKB_CB(skb)->partial_cov) { |
231 | if (udp_lib_checksum_complete(skb)) | 359 | if (udp_lib_checksum_complete(skb)) |
232 | goto csum_copy_err; | 360 | goto csum_copy_err; |
233 | } | 361 | } |
234 | 362 | ||
235 | if (skb_csum_unnecessary(skb)) | 363 | if (skb_csum_unnecessary(skb)) |
236 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), | 364 | err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), |
237 | msg->msg_iov, copied ); | 365 | msg->msg_iov,len); |
238 | else { | 366 | else { |
239 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); | 367 | err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); |
240 | if (err == -EINVAL) | 368 | if (err == -EINVAL) |
@@ -252,7 +380,7 @@ try_again: | |||
252 | UDP_MIB_INDATAGRAMS, is_udplite); | 380 | UDP_MIB_INDATAGRAMS, is_udplite); |
253 | } | 381 | } |
254 | 382 | ||
255 | sock_recv_timestamp(msg, sk, skb); | 383 | sock_recv_ts_and_drops(msg, sk, skb); |
256 | 384 | ||
257 | /* Copy the address. */ | 385 | /* Copy the address. */ |
258 | if (msg->msg_name) { | 386 | if (msg->msg_name) { |
@@ -265,8 +393,8 @@ try_again: | |||
265 | sin6->sin6_scope_id = 0; | 393 | sin6->sin6_scope_id = 0; |
266 | 394 | ||
267 | if (is_udp4) | 395 | if (is_udp4) |
268 | ipv6_addr_set(&sin6->sin6_addr, 0, 0, | 396 | ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, |
269 | htonl(0xffff), ip_hdr(skb)->saddr); | 397 | &sin6->sin6_addr); |
270 | else { | 398 | else { |
271 | ipv6_addr_copy(&sin6->sin6_addr, | 399 | ipv6_addr_copy(&sin6->sin6_addr, |
272 | &ipv6_hdr(skb)->saddr); | 400 | &ipv6_hdr(skb)->saddr); |
@@ -283,7 +411,7 @@ try_again: | |||
283 | datagram_recv_ctl(sk, msg, skb); | 411 | datagram_recv_ctl(sk, msg, skb); |
284 | } | 412 | } |
285 | 413 | ||
286 | err = copied; | 414 | err = len; |
287 | if (flags & MSG_TRUNC) | 415 | if (flags & MSG_TRUNC) |
288 | err = ulen; | 416 | err = ulen; |
289 | 417 | ||
@@ -383,18 +511,18 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
383 | goto drop; | 511 | goto drop; |
384 | } | 512 | } |
385 | 513 | ||
386 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 514 | if ((rc = sock_queue_rcv_skb(sk, skb)) < 0) { |
387 | /* Note that an ENOMEM error is charged twice */ | 515 | /* Note that an ENOMEM error is charged twice */ |
388 | if (rc == -ENOMEM) { | 516 | if (rc == -ENOMEM) |
389 | UDP6_INC_STATS_BH(sock_net(sk), | 517 | UDP6_INC_STATS_BH(sock_net(sk), |
390 | UDP_MIB_RCVBUFERRORS, is_udplite); | 518 | UDP_MIB_RCVBUFERRORS, is_udplite); |
391 | atomic_inc(&sk->sk_drops); | 519 | goto drop_no_sk_drops_inc; |
392 | } | ||
393 | goto drop; | ||
394 | } | 520 | } |
395 | 521 | ||
396 | return 0; | 522 | return 0; |
397 | drop: | 523 | drop: |
524 | atomic_inc(&sk->sk_drops); | ||
525 | drop_no_sk_drops_inc: | ||
398 | UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); | 526 | UDP6_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS, is_udplite); |
399 | kfree_skb(skb); | 527 | kfree_skb(skb); |
400 | return -1; | 528 | return -1; |
@@ -415,10 +543,11 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
415 | if (!net_eq(sock_net(s), net)) | 543 | if (!net_eq(sock_net(s), net)) |
416 | continue; | 544 | continue; |
417 | 545 | ||
418 | if (s->sk_hash == num && s->sk_family == PF_INET6) { | 546 | if (udp_sk(s)->udp_port_hash == num && |
547 | s->sk_family == PF_INET6) { | ||
419 | struct ipv6_pinfo *np = inet6_sk(s); | 548 | struct ipv6_pinfo *np = inet6_sk(s); |
420 | if (inet->dport) { | 549 | if (inet->inet_dport) { |
421 | if (inet->dport != rmt_port) | 550 | if (inet->inet_dport != rmt_port) |
422 | continue; | 551 | continue; |
423 | } | 552 | } |
424 | if (!ipv6_addr_any(&np->daddr) && | 553 | if (!ipv6_addr_any(&np->daddr) && |
@@ -440,6 +569,37 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, | |||
440 | return NULL; | 569 | return NULL; |
441 | } | 570 | } |
442 | 571 | ||
572 | static void flush_stack(struct sock **stack, unsigned int count, | ||
573 | struct sk_buff *skb, unsigned int final) | ||
574 | { | ||
575 | unsigned int i; | ||
576 | struct sock *sk; | ||
577 | struct sk_buff *skb1; | ||
578 | |||
579 | for (i = 0; i < count; i++) { | ||
580 | skb1 = (i == final) ? skb : skb_clone(skb, GFP_ATOMIC); | ||
581 | |||
582 | sk = stack[i]; | ||
583 | if (skb1) { | ||
584 | bh_lock_sock(sk); | ||
585 | if (!sock_owned_by_user(sk)) | ||
586 | udpv6_queue_rcv_skb(sk, skb1); | ||
587 | else if (sk_add_backlog(sk, skb1)) { | ||
588 | kfree_skb(skb1); | ||
589 | bh_unlock_sock(sk); | ||
590 | goto drop; | ||
591 | } | ||
592 | bh_unlock_sock(sk); | ||
593 | continue; | ||
594 | } | ||
595 | drop: | ||
596 | atomic_inc(&sk->sk_drops); | ||
597 | UDP6_INC_STATS_BH(sock_net(sk), | ||
598 | UDP_MIB_RCVBUFERRORS, IS_UDPLITE(sk)); | ||
599 | UDP6_INC_STATS_BH(sock_net(sk), | ||
600 | UDP_MIB_INERRORS, IS_UDPLITE(sk)); | ||
601 | } | ||
602 | } | ||
443 | /* | 603 | /* |
444 | * Note: called only from the BH handler context, | 604 | * Note: called only from the BH handler context, |
445 | * so we don't need to lock the hashes. | 605 | * so we don't need to lock the hashes. |
@@ -448,41 +608,43 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, | |||
448 | struct in6_addr *saddr, struct in6_addr *daddr, | 608 | struct in6_addr *saddr, struct in6_addr *daddr, |
449 | struct udp_table *udptable) | 609 | struct udp_table *udptable) |
450 | { | 610 | { |
451 | struct sock *sk, *sk2; | 611 | struct sock *sk, *stack[256 / sizeof(struct sock *)]; |
452 | const struct udphdr *uh = udp_hdr(skb); | 612 | const struct udphdr *uh = udp_hdr(skb); |
453 | struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; | 613 | struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); |
454 | int dif; | 614 | int dif; |
615 | unsigned int i, count = 0; | ||
455 | 616 | ||
456 | spin_lock(&hslot->lock); | 617 | spin_lock(&hslot->lock); |
457 | sk = sk_nulls_head(&hslot->head); | 618 | sk = sk_nulls_head(&hslot->head); |
458 | dif = inet6_iif(skb); | 619 | dif = inet6_iif(skb); |
459 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); | 620 | sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); |
460 | if (!sk) { | 621 | while (sk) { |
461 | kfree_skb(skb); | 622 | stack[count++] = sk; |
462 | goto out; | 623 | sk = udp_v6_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, |
463 | } | 624 | uh->source, saddr, dif); |
464 | 625 | if (unlikely(count == ARRAY_SIZE(stack))) { | |
465 | sk2 = sk; | 626 | if (!sk) |
466 | while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr, | 627 | break; |
467 | uh->source, saddr, dif))) { | 628 | flush_stack(stack, count, skb, ~0); |
468 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); | 629 | count = 0; |
469 | if (buff) { | ||
470 | bh_lock_sock(sk2); | ||
471 | if (!sock_owned_by_user(sk2)) | ||
472 | udpv6_queue_rcv_skb(sk2, buff); | ||
473 | else | ||
474 | sk_add_backlog(sk2, buff); | ||
475 | bh_unlock_sock(sk2); | ||
476 | } | 630 | } |
477 | } | 631 | } |
478 | bh_lock_sock(sk); | 632 | /* |
479 | if (!sock_owned_by_user(sk)) | 633 | * before releasing the lock, we must take reference on sockets |
480 | udpv6_queue_rcv_skb(sk, skb); | 634 | */ |
481 | else | 635 | for (i = 0; i < count; i++) |
482 | sk_add_backlog(sk, skb); | 636 | sock_hold(stack[i]); |
483 | bh_unlock_sock(sk); | 637 | |
484 | out: | ||
485 | spin_unlock(&hslot->lock); | 638 | spin_unlock(&hslot->lock); |
639 | |||
640 | if (count) { | ||
641 | flush_stack(stack, count, skb, count - 1); | ||
642 | |||
643 | for (i = 0; i < count; i++) | ||
644 | sock_put(stack[i]); | ||
645 | } else { | ||
646 | kfree_skb(skb); | ||
647 | } | ||
486 | return 0; | 648 | return 0; |
487 | } | 649 | } |
488 | 650 | ||
@@ -523,12 +685,11 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, | |||
523 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | 685 | int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, |
524 | int proto) | 686 | int proto) |
525 | { | 687 | { |
688 | struct net *net = dev_net(skb->dev); | ||
526 | struct sock *sk; | 689 | struct sock *sk; |
527 | struct udphdr *uh; | 690 | struct udphdr *uh; |
528 | struct net_device *dev = skb->dev; | ||
529 | struct in6_addr *saddr, *daddr; | 691 | struct in6_addr *saddr, *daddr; |
530 | u32 ulen = 0; | 692 | u32 ulen = 0; |
531 | struct net *net = dev_net(skb->dev); | ||
532 | 693 | ||
533 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) | 694 | if (!pskb_may_pull(skb, sizeof(struct udphdr))) |
534 | goto short_packet; | 695 | goto short_packet; |
@@ -587,7 +748,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
587 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, | 748 | UDP6_INC_STATS_BH(net, UDP_MIB_NOPORTS, |
588 | proto == IPPROTO_UDPLITE); | 749 | proto == IPPROTO_UDPLITE); |
589 | 750 | ||
590 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); | 751 | icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); |
591 | 752 | ||
592 | kfree_skb(skb); | 753 | kfree_skb(skb); |
593 | return 0; | 754 | return 0; |
@@ -598,8 +759,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, | |||
598 | bh_lock_sock(sk); | 759 | bh_lock_sock(sk); |
599 | if (!sock_owned_by_user(sk)) | 760 | if (!sock_owned_by_user(sk)) |
600 | udpv6_queue_rcv_skb(sk, skb); | 761 | udpv6_queue_rcv_skb(sk, skb); |
601 | else | 762 | else if (sk_add_backlog(sk, skb)) { |
602 | sk_add_backlog(sk, skb); | 763 | atomic_inc(&sk->sk_drops); |
764 | bh_unlock_sock(sk); | ||
765 | sock_put(sk); | ||
766 | goto discard; | ||
767 | } | ||
603 | bh_unlock_sock(sk); | 768 | bh_unlock_sock(sk); |
604 | sock_put(sk); | 769 | sock_put(sk); |
605 | return 0; | 770 | return 0; |
@@ -792,7 +957,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
792 | if (ipv6_addr_v4mapped(daddr)) { | 957 | if (ipv6_addr_v4mapped(daddr)) { |
793 | struct sockaddr_in sin; | 958 | struct sockaddr_in sin; |
794 | sin.sin_family = AF_INET; | 959 | sin.sin_family = AF_INET; |
795 | sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; | 960 | sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport; |
796 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; | 961 | sin.sin_addr.s_addr = daddr->s6_addr32[3]; |
797 | msg->msg_name = &sin; | 962 | msg->msg_name = &sin; |
798 | msg->msg_namelen = sizeof(sin); | 963 | msg->msg_namelen = sizeof(sin); |
@@ -865,7 +1030,7 @@ do_udp_sendmsg: | |||
865 | if (sk->sk_state != TCP_ESTABLISHED) | 1030 | if (sk->sk_state != TCP_ESTABLISHED) |
866 | return -EDESTADDRREQ; | 1031 | return -EDESTADDRREQ; |
867 | 1032 | ||
868 | fl.fl_ip_dport = inet->dport; | 1033 | fl.fl_ip_dport = inet->inet_dport; |
869 | daddr = &np->daddr; | 1034 | daddr = &np->daddr; |
870 | fl.fl6_flowlabel = np->flow_label; | 1035 | fl.fl6_flowlabel = np->flow_label; |
871 | connected = 1; | 1036 | connected = 1; |
@@ -877,6 +1042,8 @@ do_udp_sendmsg: | |||
877 | if (!fl.oif) | 1042 | if (!fl.oif) |
878 | fl.oif = np->sticky_pktinfo.ipi6_ifindex; | 1043 | fl.oif = np->sticky_pktinfo.ipi6_ifindex; |
879 | 1044 | ||
1045 | fl.mark = sk->sk_mark; | ||
1046 | |||
880 | if (msg->msg_controllen) { | 1047 | if (msg->msg_controllen) { |
881 | opt = &opt_space; | 1048 | opt = &opt_space; |
882 | memset(opt, 0, sizeof(struct ipv6_txoptions)); | 1049 | memset(opt, 0, sizeof(struct ipv6_txoptions)); |
@@ -909,7 +1076,7 @@ do_udp_sendmsg: | |||
909 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ | 1076 | fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ |
910 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) | 1077 | if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) |
911 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); | 1078 | ipv6_addr_copy(&fl.fl6_src, &np->saddr); |
912 | fl.fl_ip_sport = inet->sport; | 1079 | fl.fl_ip_sport = inet->inet_sport; |
913 | 1080 | ||
914 | /* merge ip6_build_xmit from ip6_output */ | 1081 | /* merge ip6_build_xmit from ip6_output */ |
915 | if (opt && opt->srcrt) { | 1082 | if (opt && opt->srcrt) { |
@@ -1190,10 +1357,10 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket | |||
1190 | 1357 | ||
1191 | dest = &np->daddr; | 1358 | dest = &np->daddr; |
1192 | src = &np->rcv_saddr; | 1359 | src = &np->rcv_saddr; |
1193 | destp = ntohs(inet->dport); | 1360 | destp = ntohs(inet->inet_dport); |
1194 | srcp = ntohs(inet->sport); | 1361 | srcp = ntohs(inet->inet_sport); |
1195 | seq_printf(seq, | 1362 | seq_printf(seq, |
1196 | "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " | 1363 | "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " |
1197 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", | 1364 | "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", |
1198 | bucket, | 1365 | bucket, |
1199 | src->s6_addr32[0], src->s6_addr32[1], | 1366 | src->s6_addr32[0], src->s6_addr32[1], |
@@ -1236,7 +1403,7 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { | |||
1236 | }, | 1403 | }, |
1237 | }; | 1404 | }; |
1238 | 1405 | ||
1239 | int udp6_proc_init(struct net *net) | 1406 | int __net_init udp6_proc_init(struct net *net) |
1240 | { | 1407 | { |
1241 | return udp_proc_register(net, &udp6_seq_afinfo); | 1408 | return udp_proc_register(net, &udp6_seq_afinfo); |
1242 | } | 1409 | } |
@@ -1282,7 +1449,6 @@ static struct inet_protosw udpv6_protosw = { | |||
1282 | .protocol = IPPROTO_UDP, | 1449 | .protocol = IPPROTO_UDP, |
1283 | .prot = &udpv6_prot, | 1450 | .prot = &udpv6_prot, |
1284 | .ops = &inet6_dgram_ops, | 1451 | .ops = &inet6_dgram_ops, |
1285 | .capability =-1, | ||
1286 | .no_check = UDP_CSUM_DEFAULT, | 1452 | .no_check = UDP_CSUM_DEFAULT, |
1287 | .flags = INET_PROTOSW_PERMANENT, | 1453 | .flags = INET_PROTOSW_PERMANENT, |
1288 | }; | 1454 | }; |