Merge git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[firefly-linux-kernel-4.4.55.git] / net / ipv6 / ip6_tunnel.c
index 6af3fcfdcbbdaff85f669c28617775cba4e7a6b7..9a1d5fe6aef8f229e22c8b2e8f3cef1663be09ce 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/netfilter_ipv6.h>
 #include <linux/slab.h>
+#include <linux/hash.h>
 
 #include <asm/uaccess.h>
 #include <linux/atomic.h>
@@ -70,11 +71,15 @@ MODULE_ALIAS_NETDEV("ip6tnl0");
 #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
 #define IPV6_TCLASS_SHIFT 20
 
-#define HASH_SIZE  32
+#define HASH_SIZE_SHIFT  5
+#define HASH_SIZE (1 << HASH_SIZE_SHIFT)
 
-#define HASH(addr) ((__force u32)((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
-                    (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
-                   (HASH_SIZE - 1))
+static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
+{
+       u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
+
+       return hash_32(hash, HASH_SIZE_SHIFT);
+}
 
 static int ip6_tnl_dev_init(struct net_device *dev);
 static void ip6_tnl_dev_setup(struct net_device *dev);
@@ -166,12 +171,11 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
 static struct ip6_tnl *
 ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
 {
-       unsigned int h0 = HASH(remote);
-       unsigned int h1 = HASH(local);
+       unsigned int hash = HASH(remote, local);
        struct ip6_tnl *t;
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
 
-       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[h0 ^ h1]) {
+       for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
                if (ipv6_addr_equal(local, &t->parms.laddr) &&
                    ipv6_addr_equal(remote, &t->parms.raddr) &&
                    (t->dev->flags & IFF_UP))
@@ -205,7 +209,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
 
        if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
                prio = 1;
-               h = HASH(remote) ^ HASH(local);
+               h = HASH(remotelocal);
        }
        return &ip6n->tnls[prio][h];
 }
@@ -550,6 +554,9 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                rel_type = ICMP_DEST_UNREACH;
                rel_code = ICMP_FRAG_NEEDED;
                break;
+       case NDISC_REDIRECT:
+               rel_type = ICMP_REDIRECT;
+               rel_code = ICMP_REDIR_HOST;
        default:
                return 0;
        }
@@ -606,8 +613,10 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                if (rel_info > dst_mtu(skb_dst(skb2)))
                        goto out;
 
-               skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info);
+               skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), NULL, skb2, rel_info);
        }
+       if (rel_type == ICMP_REDIRECT)
+               skb_dst(skb2)->ops->redirect(skb_dst(skb2), NULL, skb2);
 
        icmp_send(skb2, rel_type, rel_code, htonl(rel_info));
 
@@ -947,7 +956,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb,
        if (mtu < IPV6_MIN_MTU)
                mtu = IPV6_MIN_MTU;
        if (skb_dst(skb))
-               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), mtu);
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
        if (skb->len > mtu) {
                *pmtu = mtu;
                err = -EMSGSIZE;