inet: switch IP ID generator to siphash
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / net / ipv6 / output_core.c
index 4fe7c90962ddae3356200376aa911bab6d75bb48..868ae23dbae195de0e81fcad2566af2420294d7e 100644 (file)
 #include <net/secure_seq.h>
 #include <linux/netfilter.h>
 
-static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
+static u32 __ipv6_select_ident(struct net *net,
                               const struct in6_addr *dst,
                               const struct in6_addr *src)
 {
+       const struct {
+               struct in6_addr dst;
+               struct in6_addr src;
+       } __aligned(SIPHASH_ALIGNMENT) combined = {
+               .dst = *dst,
+               .src = *src,
+       };
        u32 hash, id;
 
-       hash = __ipv6_addr_jhash(dst, hashrnd);
-       hash = __ipv6_addr_jhash(src, hash);
-       hash ^= net_hash_mix(net);
+       /* Note the following code is not safe, but this is okay. */
+       if (unlikely(siphash_key_is_zero(&net->ipv4.ip_id_key)))
+               get_random_bytes(&net->ipv4.ip_id_key,
+                                sizeof(net->ipv4.ip_id_key));
+
+       hash = siphash(&combined, sizeof(combined), &net->ipv4.ip_id_key);
 
        /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve,
         * set the hight order instead thus minimizing possible future
@@ -41,7 +51,6 @@ static u32 __ipv6_select_ident(struct net *net, u32 hashrnd,
  */
 __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
 {
-       static u32 ip6_proxy_idents_hashrnd __read_mostly;
        struct in6_addr buf[2];
        struct in6_addr *addrs;
        u32 id;
@@ -53,11 +62,7 @@ __be32 ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb)
        if (!addrs)
                return 0;
 
-       net_get_random_once(&ip6_proxy_idents_hashrnd,
-                           sizeof(ip6_proxy_idents_hashrnd));
-
-       id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd,
-                                &addrs[1], &addrs[0]);
+       id = __ipv6_select_ident(net, &addrs[1], &addrs[0]);
        return htonl(id);
 }
 EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident);
@@ -66,12 +71,9 @@ __be32 ipv6_select_ident(struct net *net,
                         const struct in6_addr *daddr,
                         const struct in6_addr *saddr)
 {
-       static u32 ip6_idents_hashrnd __read_mostly;
        u32 id;
 
-       net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd));
-
-       id = __ipv6_select_ident(net, ip6_idents_hashrnd, daddr, saddr);
+       id = __ipv6_select_ident(net, daddr, saddr);
        return htonl(id);
 }
 EXPORT_SYMBOL(ipv6_select_ident);