summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/inet6_hashtables.h12
-rw-r--r--include/net/inet_sock.h11
-rw-r--r--net/ipv4/af_inet.c16
-rw-r--r--net/ipv6/af_inet6.c5
4 files changed, 35 insertions, 9 deletions
diff --git a/include/net/inet6_hashtables.h b/include/net/inet6_hashtables.h
index c28e424f53d9..668056b4bb0b 100644
--- a/include/net/inet6_hashtables.h
+++ b/include/net/inet6_hashtables.h
@@ -19,6 +19,9 @@
#include <linux/in6.h>
#include <linux/ipv6.h>
#include <linux/types.h>
+#include <linux/jhash.h>
+
+#include <net/inet_sock.h>
#include <net/ipv6.h>
@@ -28,12 +31,11 @@ struct inet_hashinfo;
static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport,
const struct in6_addr *faddr, const __be16 fport)
{
- unsigned int hashent = (lport ^ (__force u16)fport);
+ u32 ports = (lport ^ (__force u16)fport);
- hashent ^= (__force u32)(laddr->s6_addr32[3] ^ faddr->s6_addr32[3]);
- hashent ^= hashent >> 16;
- hashent ^= hashent >> 8;
- return hashent;
+ return jhash_3words((__force u32)laddr->s6_addr32[3],
+ (__force u32)faddr->s6_addr32[3],
+ ports, inet_ehash_secret);
}
static inline int inet6_sk_ehashfn(const struct sock *sk)
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index ce6da97bc848..62daf214931f 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -19,6 +19,7 @@
#include <linux/string.h>
#include <linux/types.h>
+#include <linux/jhash.h>
#include <net/flow.h>
#include <net/sock.h>
@@ -167,13 +168,15 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
extern int inet_sk_rebuild_header(struct sock *sk);
+extern u32 inet_ehash_secret;
+extern void build_ehash_secret(void);
+
static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
const __be32 faddr, const __be16 fport)
{
- unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport);
- h ^= h >> 16;
- h ^= h >> 8;
- return h;
+ return jhash_2words((__force __u32) laddr ^ (__force __u32) faddr,
+ ((__u32) lport) << 16 | (__force __u32)fport,
+ inet_ehash_secret);
}
static inline int inet_sk_ehashfn(const struct sock *sk)
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f011390f19c9..b7b7278d801c 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -87,6 +87,7 @@
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/netfilter_ipv4.h>
+#include <linux/random.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -217,6 +218,16 @@ out:
return err;
}
+u32 inet_ehash_secret;
+EXPORT_SYMBOL(inet_ehash_secret);
+
+void build_ehash_secret(void)
+{
+ while (!inet_ehash_secret)
+ get_random_bytes(&inet_ehash_secret, 4);
+}
+EXPORT_SYMBOL(build_ehash_secret);
+
/*
* Create an inet socket.
*/
@@ -233,6 +244,11 @@ static int inet_create(struct socket *sock, int protocol)
int try_loading_module = 0;
int err;
+ if (sock->type != SOCK_RAW &&
+ sock->type != SOCK_DGRAM &&
+ !inet_ehash_secret)
+ build_ehash_secret();
+
sock->state = SS_UNCONNECTED;
/* Look for the requested type/protocol pair. */
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 82572b507547..df31cdd33cda 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -98,6 +98,11 @@ static int inet6_create(struct socket *sock, int protocol)
int try_loading_module = 0;
int err;
+ if (sock->type != SOCK_RAW &&
+ sock->type != SOCK_DGRAM &&
+ !inet_ehash_secret)
+ build_ehash_secret();
+
/* Look for the requested type/protocol pair. */
answer = NULL;
lookup_protocol: