X-Git-Url: https://git.karo-electronics.de/?a=blobdiff_plain;f=net%2Fipv6%2Fudp.c;h=53739de829db07eb8ad1c3b9ab2b25d4e2b162c5;hb=f8303dd3db57bd7ab2062985ad7a9e898a8ac423;hp=8b3e6d61bf55d37203c867ac25cb59c5f70100a3;hpb=09f7709f4929666006931f1d4efc498a6d419bbc;p=mv-sheeva.git diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8b3e6d61bf5..53739de829d 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -51,15 +51,13 @@ #include #include "udp_impl.h" -DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6) __read_mostly; -EXPORT_SYMBOL(udp_stats_in6); - static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) { return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } -static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, +static struct sock *__udp6_lib_lookup(struct net *net, + struct in6_addr *saddr, __be16 sport, struct in6_addr *daddr, __be16 dport, int dif, struct hlist_head udptable[]) { @@ -72,7 +70,8 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_hash == hnum && sk->sk_family == PF_INET6) { + if (sk->sk_net == net && sk->sk_hash == hnum && + sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); int score = 0; if (inet->dport) { @@ -207,13 +206,17 @@ try_again: err = ulen; out_free: + lock_sock(sk); skb_free_datagram(sk, skb); + release_sock(sk); out: return err; csum_copy_err: + lock_sock(sk); if (!skb_kill_datagram(sk, skb, flags)) UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); if (flags & MSG_DONTWAIT) return -EAGAIN; @@ -232,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; - sk = __udp6_lib_lookup(daddr, uh->dest, + sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, saddr, uh->source, inet6_iif(skb), udptable); if (sk == NULL) return; @@ -258,7 +261,7 @@ static __inline__ void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info ) { - return __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); + __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); } int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) @@ -369,10 +372,21 @@ static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, uh->source, saddr, dif))) { struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) - udpv6_queue_rcv_skb(sk2, buff); + if (buff) { + bh_lock_sock_nested(sk2); + if (!sock_owned_by_user(sk2)) + udpv6_queue_rcv_skb(sk2, buff); + else + sk_add_backlog(sk2, buff); + bh_unlock_sock(sk2); + } } - udpv6_queue_rcv_skb(sk, skb); + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); out: read_unlock(&udp_hash_lock); return 0; @@ -466,7 +480,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = __udp6_lib_lookup(saddr, uh->source, + sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { @@ -485,7 +499,12 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], /* deliver */ - udpv6_queue_rcv_skb(sk, skb); + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); sock_put(sk); return 0; @@ -997,6 +1016,10 @@ struct proto udpv6_prot = { .hash = udp_lib_hash, .unhash = udp_lib_unhash, .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, .obj_size = sizeof(struct udp6_sock), #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udpv6_setsockopt,