IPv6 support for VServer
[linux-2.6.git] / net / ipv6 / inet6_hashtables.c
index 2ae84c9..dd991f6 100644 (file)
@@ -14,7 +14,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/random.h>
 
@@ -58,14 +57,14 @@ EXPORT_SYMBOL(__inet6_hash);
  */
 struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
                                           const struct in6_addr *saddr,
-                                          const u16 sport,
+                                          const __be16 sport,
                                           const struct in6_addr *daddr,
                                           const u16 hnum,
                                           const int dif)
 {
        struct sock *sk;
        const struct hlist_node *node;
-       const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+       const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
        /* Optimize here for direct hit, only listening connections can
         * have wildcards anyways.
         */
@@ -83,7 +82,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
        sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
                const struct inet_timewait_sock *tw = inet_twsk(sk);
 
-               if(*((__u32 *)&(tw->tw_dport))  == ports        &&
+               if(*((__portpair *)&(tw->tw_dport))     == ports        &&
                   sk->sk_family                == PF_INET6) {
                        const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
 
@@ -103,6 +102,26 @@ hit:
 }
 EXPORT_SYMBOL(__inet6_lookup_established);
 
+/*
+ *      Check if a given address matches for an inet socket
+ *
+ *      nxi:    the socket's nx_info if any
+ *      addr:   to be verified address
+ *      saddr:  socket addresses
+ */
+static inline int inet6_addr_match(
+       struct nx_info *nxi,
+       const struct in6_addr *addr,
+       const struct in6_addr *saddr)
+{
+       if ((addr->s6_addr32[0] || addr->s6_addr32[1] || addr->s6_addr32[2] || addr->s6_addr32[3]) &&
+                       memcmp(saddr,addr, sizeof(struct in6_addr)) == 0)
+               return 1;
+       if (!(saddr->s6_addr32[0] || saddr->s6_addr32[1] || saddr->s6_addr32[2] || saddr->s6_addr32[3]))
+               return addr6_in_nx_info(nxi, addr);
+       return 0;
+}
+
 struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
                                   const struct in6_addr *daddr,
                                   const unsigned short hnum, const int dif)
@@ -128,6 +147,10 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
                                        continue;
                                score++;
                        }
+                       if (!inet6_addr_match(sk->sk_nx_info, daddr, &(np->rcv_saddr))) {
+                               /* No, this address is not available for guest */
+                               continue;
+                       }
                        if (score == 3) {
                                result = sk;
                                break;
@@ -147,8 +170,8 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo,
 EXPORT_SYMBOL_GPL(inet6_lookup_listener);
 
 struct sock *inet6_lookup(struct inet_hashinfo *hashinfo,
-                         const struct in6_addr *saddr, const u16 sport,
-                         const struct in6_addr *daddr, const u16 dport,
+                         const struct in6_addr *saddr, const __be16 sport,
+                         const struct in6_addr *daddr, const __be16 dport,
                          const int dif)
 {
        struct sock *sk;
@@ -172,8 +195,8 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
        const struct in6_addr *daddr = &np->rcv_saddr;
        const struct in6_addr *saddr = &np->daddr;
        const int dif = sk->sk_bound_dev_if;
-       const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
-       const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr,
+       const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
+       const unsigned int hash = inet6_ehashfn(daddr, lport, saddr,
                                                inet->dport);
        struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
        struct sock *sk2;
@@ -189,7 +212,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
 
                tw = inet_twsk(sk2);
 
-               if(*((__u32 *)&(tw->tw_dport)) == ports          &&
+               if(*((__portpair *)&(tw->tw_dport)) == ports             &&
                   sk2->sk_family              == PF_INET6       &&
                   ipv6_addr_equal(&tw6->tw_v6_daddr, saddr)     &&
                   ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&