diff options
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 92 |
1 files changed, 70 insertions, 22 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ee1cc3f8599f..bd4b9df8f614 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/ipv6.h> | 34 | #include <linux/ipv6.h> |
35 | #include <linux/icmpv6.h> | 35 | #include <linux/icmpv6.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/module.h> | ||
37 | #include <linux/skbuff.h> | 38 | #include <linux/skbuff.h> |
38 | #include <asm/uaccess.h> | 39 | #include <asm/uaccess.h> |
39 | 40 | ||
@@ -50,8 +51,6 @@ | |||
50 | #include <linux/seq_file.h> | 51 | #include <linux/seq_file.h> |
51 | #include "udp_impl.h" | 52 | #include "udp_impl.h" |
52 | 53 | ||
53 | DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; | ||
54 | |||
55 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) | 54 | static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) |
56 | { | 55 | { |
57 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); | 56 | return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); |
@@ -121,6 +120,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
121 | struct inet_sock *inet = inet_sk(sk); | 120 | struct inet_sock *inet = inet_sk(sk); |
122 | struct sk_buff *skb; | 121 | struct sk_buff *skb; |
123 | unsigned int ulen, copied; | 122 | unsigned int ulen, copied; |
123 | int peeked; | ||
124 | int err; | 124 | int err; |
125 | int is_udplite = IS_UDPLITE(sk); | 125 | int is_udplite = IS_UDPLITE(sk); |
126 | 126 | ||
@@ -131,7 +131,8 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
131 | return ipv6_recv_error(sk, msg, len); | 131 | return ipv6_recv_error(sk, msg, len); |
132 | 132 | ||
133 | try_again: | 133 | try_again: |
134 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 134 | skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), |
135 | &peeked, &err); | ||
135 | if (!skb) | 136 | if (!skb) |
136 | goto out; | 137 | goto out; |
137 | 138 | ||
@@ -164,6 +165,9 @@ try_again: | |||
164 | if (err) | 165 | if (err) |
165 | goto out_free; | 166 | goto out_free; |
166 | 167 | ||
168 | if (!peeked) | ||
169 | UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); | ||
170 | |||
167 | sock_recv_timestamp(msg, sk, skb); | 171 | sock_recv_timestamp(msg, sk, skb); |
168 | 172 | ||
169 | /* Copy the address. */ | 173 | /* Copy the address. */ |
@@ -200,13 +204,17 @@ try_again: | |||
200 | err = ulen; | 204 | err = ulen; |
201 | 205 | ||
202 | out_free: | 206 | out_free: |
207 | lock_sock(sk); | ||
203 | skb_free_datagram(sk, skb); | 208 | skb_free_datagram(sk, skb); |
209 | release_sock(sk); | ||
204 | out: | 210 | out: |
205 | return err; | 211 | return err; |
206 | 212 | ||
207 | csum_copy_err: | 213 | csum_copy_err: |
208 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); | 214 | lock_sock(sk); |
209 | skb_kill_datagram(sk, skb, flags); | 215 | if (!skb_kill_datagram(sk, skb, flags)) |
216 | UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); | ||
217 | release_sock(sk); | ||
210 | 218 | ||
211 | if (flags & MSG_DONTWAIT) | 219 | if (flags & MSG_DONTWAIT) |
212 | return -EAGAIN; | 220 | return -EAGAIN; |
@@ -251,13 +259,14 @@ static __inline__ void udpv6_err(struct sk_buff *skb, | |||
251 | struct inet6_skb_parm *opt, int type, | 259 | struct inet6_skb_parm *opt, int type, |
252 | int code, int offset, __be32 info ) | 260 | int code, int offset, __be32 info ) |
253 | { | 261 | { |
254 | return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); | 262 | __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); |
255 | } | 263 | } |
256 | 264 | ||
257 | int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | 265 | int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) |
258 | { | 266 | { |
259 | struct udp_sock *up = udp_sk(sk); | 267 | struct udp_sock *up = udp_sk(sk); |
260 | int rc; | 268 | int rc; |
269 | int is_udplite = IS_UDPLITE(sk); | ||
261 | 270 | ||
262 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) | 271 | if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) |
263 | goto drop; | 272 | goto drop; |
@@ -265,7 +274,7 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
265 | /* | 274 | /* |
266 | * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). | 275 | * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). |
267 | */ | 276 | */ |
268 | if ((up->pcflag & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { | 277 | if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { |
269 | 278 | ||
270 | if (up->pcrlen == 0) { /* full coverage was set */ | 279 | if (up->pcrlen == 0) { /* full coverage was set */ |
271 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" | 280 | LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" |
@@ -289,13 +298,13 @@ int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) | |||
289 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { | 298 | if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { |
290 | /* Note that an ENOMEM error is charged twice */ | 299 | /* Note that an ENOMEM error is charged twice */ |
291 | if (rc == -ENOMEM) | 300 | if (rc == -ENOMEM) |
292 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, up->pcflag); | 301 | UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); |
293 | goto drop; | 302 | goto drop; |
294 | } | 303 | } |
295 | UDP6_INC_STATS_BH(UDP_MIB_INDATAGRAMS, up->pcflag); | 304 | |
296 | return 0; | 305 | return 0; |
297 | drop: | 306 | drop: |
298 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, up->pcflag); | 307 | UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); |
299 | kfree_skb(skb); | 308 | kfree_skb(skb); |
300 | return -1; | 309 | return -1; |
301 | } | 310 | } |
@@ -361,10 +370,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, | |||
361 | while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, | 370 | while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, |
362 | uh->source, saddr, dif))) { | 371 | uh->source, saddr, dif))) { |
363 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); | 372 | struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); |
364 | if (buff) | 373 | if (buff) { |
365 | udpv6_queue_rcv_skb(sk2, buff); | 374 | bh_lock_sock_nested(sk2); |
375 | if (!sock_owned_by_user(sk2)) | ||
376 | udpv6_queue_rcv_skb(sk2, buff); | ||
377 | else | ||
378 | sk_add_backlog(sk2, buff); | ||
379 | bh_unlock_sock(sk2); | ||
380 | } | ||
366 | } | 381 | } |
367 | udpv6_queue_rcv_skb(sk, skb); | 382 | bh_lock_sock_nested(sk); |
383 | if (!sock_owned_by_user(sk)) | ||
384 | udpv6_queue_rcv_skb(sk, skb); | ||
385 | else | ||
386 | sk_add_backlog(sk, skb); | ||
387 | bh_unlock_sock(sk); | ||
368 | out: | 388 | out: |
369 | read_unlock(&udp_hash_lock); | 389 | read_unlock(&udp_hash_lock); |
370 | return 0; | 390 | return 0; |
@@ -477,7 +497,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], | |||
477 | 497 | ||
478 | /* deliver */ | 498 | /* deliver */ |
479 | 499 | ||
480 | udpv6_queue_rcv_skb(sk, skb); | 500 | bh_lock_sock_nested(sk); |
501 | if (!sock_owned_by_user(sk)) | ||
502 | udpv6_queue_rcv_skb(sk, skb); | ||
503 | else | ||
504 | sk_add_backlog(sk, skb); | ||
505 | bh_unlock_sock(sk); | ||
481 | sock_put(sk); | 506 | sock_put(sk); |
482 | return 0; | 507 | return 0; |
483 | 508 | ||
@@ -523,6 +548,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
523 | struct inet_sock *inet = inet_sk(sk); | 548 | struct inet_sock *inet = inet_sk(sk); |
524 | struct flowi *fl = &inet->cork.fl; | 549 | struct flowi *fl = &inet->cork.fl; |
525 | int err = 0; | 550 | int err = 0; |
551 | int is_udplite = IS_UDPLITE(sk); | ||
526 | __wsum csum = 0; | 552 | __wsum csum = 0; |
527 | 553 | ||
528 | /* Grab the skbuff where UDP header space exists. */ | 554 | /* Grab the skbuff where UDP header space exists. */ |
@@ -538,7 +564,7 @@ static int udp_v6_push_pending_frames(struct sock *sk) | |||
538 | uh->len = htons(up->len); | 564 | uh->len = htons(up->len); |
539 | uh->check = 0; | 565 | uh->check = 0; |
540 | 566 | ||
541 | if (up->pcflag) | 567 | if (is_udplite) |
542 | csum = udplite_csum_outgoing(sk, skb); | 568 | csum = udplite_csum_outgoing(sk, skb); |
543 | else | 569 | else |
544 | csum = udp_csum_outgoing(sk, skb); | 570 | csum = udp_csum_outgoing(sk, skb); |
@@ -554,7 +580,7 @@ out: | |||
554 | up->len = 0; | 580 | up->len = 0; |
555 | up->pending = 0; | 581 | up->pending = 0; |
556 | if (!err) | 582 | if (!err) |
557 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, up->pcflag); | 583 | UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); |
558 | return err; | 584 | return err; |
559 | } | 585 | } |
560 | 586 | ||
@@ -578,7 +604,7 @@ int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
578 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; | 604 | int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; |
579 | int err; | 605 | int err; |
580 | int connected = 0; | 606 | int connected = 0; |
581 | int is_udplite = up->pcflag; | 607 | int is_udplite = IS_UDPLITE(sk); |
582 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); | 608 | int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); |
583 | 609 | ||
584 | /* destination address check */ | 610 | /* destination address check */ |
@@ -748,7 +774,7 @@ do_udp_sendmsg: | |||
748 | if (final_p) | 774 | if (final_p) |
749 | ipv6_addr_copy(&fl.fl6_dst, final_p); | 775 | ipv6_addr_copy(&fl.fl6_dst, final_p); |
750 | 776 | ||
751 | if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { | 777 | if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { |
752 | if (err == -EREMOTE) | 778 | if (err == -EREMOTE) |
753 | err = ip6_dst_blackhole(sk, &dst, &fl); | 779 | err = ip6_dst_blackhole(sk, &dst, &fl); |
754 | if (err < 0) | 780 | if (err < 0) |
@@ -988,6 +1014,10 @@ struct proto udpv6_prot = { | |||
988 | .hash = udp_lib_hash, | 1014 | .hash = udp_lib_hash, |
989 | .unhash = udp_lib_unhash, | 1015 | .unhash = udp_lib_unhash, |
990 | .get_port = udp_v6_get_port, | 1016 | .get_port = udp_v6_get_port, |
1017 | .memory_allocated = &udp_memory_allocated, | ||
1018 | .sysctl_mem = sysctl_udp_mem, | ||
1019 | .sysctl_wmem = &sysctl_udp_wmem_min, | ||
1020 | .sysctl_rmem = &sysctl_udp_rmem_min, | ||
991 | .obj_size = sizeof(struct udp6_sock), | 1021 | .obj_size = sizeof(struct udp6_sock), |
992 | #ifdef CONFIG_COMPAT | 1022 | #ifdef CONFIG_COMPAT |
993 | .compat_setsockopt = compat_udpv6_setsockopt, | 1023 | .compat_setsockopt = compat_udpv6_setsockopt, |
@@ -1007,9 +1037,27 @@ static struct inet_protosw udpv6_protosw = { | |||
1007 | }; | 1037 | }; |
1008 | 1038 | ||
1009 | 1039 | ||
1010 | void __init udpv6_init(void) | 1040 | int __init udpv6_init(void) |
1041 | { | ||
1042 | int ret; | ||
1043 | |||
1044 | ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); | ||
1045 | if (ret) | ||
1046 | goto out; | ||
1047 | |||
1048 | ret = inet6_register_protosw(&udpv6_protosw); | ||
1049 | if (ret) | ||
1050 | goto out_udpv6_protocol; | ||
1051 | out: | ||
1052 | return ret; | ||
1053 | |||
1054 | out_udpv6_protocol: | ||
1055 | inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | void udpv6_exit(void) | ||
1011 | { | 1060 | { |
1012 | if (inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP) < 0) | 1061 | inet6_unregister_protosw(&udpv6_protosw); |
1013 | printk(KERN_ERR "udpv6_init: Could not register protocol\n"); | 1062 | inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); |
1014 | inet6_register_protosw(&udpv6_protosw); | ||
1015 | } | 1063 | } |