diff -NurpP linux-2.6.31.5-vs2.3.0.36.21-1/net/ipv6/udp.c linux-2.6.31.5-vs2.3.0.36.21.5/net/ipv6/udp.c --- linux-2.6.31.5-vs2.3.0.36.21-1/net/ipv6/udp.c 2009-09-10 16:11:43.000000000 +0200 +++ linux-2.6.31.5-vs2.3.0.36.21.5/net/ipv6/udp.c 2009-11-05 05:04:49.000000000 +0100 @@ -61,41 +61,50 @@ int ipv6_rcv_saddr_equal(const struct so 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 (sk2_ipv6only && !sk2_rcv_saddr6) - addr_type2 = IPV6_ADDR_ANY; - - /* if both are mapped or any, treat as IPv4 */ - if ((addr_type == IPV6_ADDR_MAPPED || (addr_type == IPV6_ADDR_ANY && !sk_ipv6only)) && - (addr_type2 == IPV6_ADDR_MAPPED || (addr_type2 == IPV6_ADDR_ANY && !sk2_ipv6only))) { - if (!sk_rcv_saddr && !sk2_rcv_saddr) { - if (nx_v4_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info)) - return 1; - else if (addr_type != IPV6_ADDR_ANY && sk2_rcv_saddr6) - return 0; - /* remaining cases are at least one ANY */ - } else if (!sk_rcv_saddr) - return v4_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr, -1); - else if (!sk2_rcv_saddr) - return v4_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr, -1); + /* if both are mapped, treat as IPv4 */ + if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { + if (!sk2_ipv6only && + (!sk_rcv_saddr || !sk2_rcv_saddr || + sk_rcv_saddr == sk2_rcv_saddr)) + goto vs_v4; else - return (sk_rcv_saddr == sk2_rcv_saddr); + return 0; } - if (!sk2_rcv_saddr6) - addr_type2 = IPV6_ADDR_ANY; + if (addr_type2 == IPV6_ADDR_ANY && + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + goto vs; - /* both are IPv6 */ - if (addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY) - return nx_v6_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); + if (addr_type == IPV6_ADDR_ANY && + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + goto vs; - if (addr_type == IPV6_ADDR_ANY) - return v6_addr_in_nx_info(sk->sk_nx_info, - sk2_rcv_saddr6 ? sk2_rcv_saddr6 : &in6addr_any, -1); + if (sk2_rcv_saddr6 && + ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + goto vs; - if (addr_type2 == IPV6_ADDR_ANY) - return v6_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6, -1); + return 0; - return ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6); +vs_v4: + if (!sk_rcv_saddr && !sk2_rcv_saddr) + return nx_v4_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); + if (!sk2_rcv_saddr) + return v4_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr, -1); + if (!sk_rcv_saddr) + return v4_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr, -1); + return 1; +vs: + if (addr_type2 == IPV6_ADDR_ANY && addr_type == IPV6_ADDR_ANY) + return nx_v6_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); + else if (addr_type2 == IPV6_ADDR_ANY) + return v6_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6, -1); + else if (addr_type == IPV6_ADDR_ANY) { + if (addr_type2 == IPV6_ADDR_MAPPED) + return nx_v4_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info); + else + return v6_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6, -1); + } + return 1; } int udp_v6_get_port(struct sock *sk, unsigned short snum)