diff options
author | James Morris <jmorris@namei.org> | 2009-03-28 14:57:13 +1100 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2009-03-28 14:57:13 +1100 |
commit | bb798169d1bb860b07192cf9c75937fadc8610b4 (patch) | |
tree | fa67f14406a1e79897e6f29e59fed7c02ec31c30 /net/ipv6/udp.c | |
parent | a106cbfd1f3703402fc2d95d97e7a054102250f0 (diff) | |
parent | 5d80f8e5a9dc9c9a94d4aeaa567e219a808b8a4a (diff) | |
download | kernel-crypto-bb798169d1bb860b07192cf9c75937fadc8610b4.tar.gz kernel-crypto-bb798169d1bb860b07192cf9c75937fadc8610b4.tar.xz kernel-crypto-bb798169d1bb860b07192cf9c75937fadc8610b4.zip |
Merge branch 'master' of ssh://master.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into next
Diffstat (limited to 'net/ipv6/udp.c')
-rw-r--r-- | net/ipv6/udp.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 84b1a296eec..6842dd2edd5 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -49,6 +49,34 @@ #include <linux/seq_file.h> #include "udp_impl.h" +int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) +{ + const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; + const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); + int sk_ipv6only = ipv6_only_sock(sk); + int sk2_ipv6only = inet_v6_ipv6only(sk2); + int addr_type = ipv6_addr_type(sk_rcv_saddr6); + int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; + + /* if both are mapped, treat as IPv4 */ + if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) + return ipv4_rcv_saddr_equal(sk, sk2); + + if (addr_type2 == IPV6_ADDR_ANY && + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; + + if (addr_type == IPV6_ADDR_ANY && + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; + + if (sk2_rcv_saddr6 && + ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + + return 0; +} + int udp_v6_get_port(struct sock *sk, unsigned short snum) { return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); |