diff options
-rw-r--r-- | include/net/inet6_hashtables.h | 12 | ||||
-rw-r--r-- | include/net/inet_sock.h | 11 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 16 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 5 |
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 @@ | |||
19 | #include <linux/in6.h> | 19 | #include <linux/in6.h> |
20 | #include <linux/ipv6.h> | 20 | #include <linux/ipv6.h> |
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/jhash.h> | ||
23 | |||
24 | #include <net/inet_sock.h> | ||
22 | 25 | ||
23 | #include <net/ipv6.h> | 26 | #include <net/ipv6.h> |
24 | 27 | ||
@@ -28,12 +31,11 @@ struct inet_hashinfo; | |||
28 | static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, | 31 | static inline unsigned int inet6_ehashfn(const struct in6_addr *laddr, const u16 lport, |
29 | const struct in6_addr *faddr, const __be16 fport) | 32 | const struct in6_addr *faddr, const __be16 fport) |
30 | { | 33 | { |
31 | unsigned int hashent = (lport ^ (__force u16)fport); | 34 | u32 ports = (lport ^ (__force u16)fport); |
32 | 35 | ||
33 | hashent ^= (__force u32)(laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); | 36 | return jhash_3words((__force u32)laddr->s6_addr32[3], |
34 | hashent ^= hashent >> 16; | 37 | (__force u32)faddr->s6_addr32[3], |
35 | hashent ^= hashent >> 8; | 38 | ports, inet_ehash_secret); |
36 | return hashent; | ||
37 | } | 39 | } |
38 | 40 | ||
39 | static inline int inet6_sk_ehashfn(const struct sock *sk) | 41 | 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 @@ | |||
19 | 19 | ||
20 | #include <linux/string.h> | 20 | #include <linux/string.h> |
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/jhash.h> | ||
22 | 23 | ||
23 | #include <net/flow.h> | 24 | #include <net/flow.h> |
24 | #include <net/sock.h> | 25 | #include <net/sock.h> |
@@ -167,13 +168,15 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to, | |||
167 | 168 | ||
168 | extern int inet_sk_rebuild_header(struct sock *sk); | 169 | extern int inet_sk_rebuild_header(struct sock *sk); |
169 | 170 | ||
171 | extern u32 inet_ehash_secret; | ||
172 | extern void build_ehash_secret(void); | ||
173 | |||
170 | static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport, | 174 | static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport, |
171 | const __be32 faddr, const __be16 fport) | 175 | const __be32 faddr, const __be16 fport) |
172 | { | 176 | { |
173 | unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport); | 177 | return jhash_2words((__force __u32) laddr ^ (__force __u32) faddr, |
174 | h ^= h >> 16; | 178 | ((__u32) lport) << 16 | (__force __u32)fport, |
175 | h ^= h >> 8; | 179 | inet_ehash_secret); |
176 | return h; | ||
177 | } | 180 | } |
178 | 181 | ||
179 | static inline int inet_sk_ehashfn(const struct sock *sk) | 182 | 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 @@ | |||
87 | #include <linux/init.h> | 87 | #include <linux/init.h> |
88 | #include <linux/poll.h> | 88 | #include <linux/poll.h> |
89 | #include <linux/netfilter_ipv4.h> | 89 | #include <linux/netfilter_ipv4.h> |
90 | #include <linux/random.h> | ||
90 | 91 | ||
91 | #include <asm/uaccess.h> | 92 | #include <asm/uaccess.h> |
92 | #include <asm/system.h> | 93 | #include <asm/system.h> |
@@ -217,6 +218,16 @@ out: | |||
217 | return err; | 218 | return err; |
218 | } | 219 | } |
219 | 220 | ||
221 | u32 inet_ehash_secret; | ||
222 | EXPORT_SYMBOL(inet_ehash_secret); | ||
223 | |||
224 | void build_ehash_secret(void) | ||
225 | { | ||
226 | while (!inet_ehash_secret) | ||
227 | get_random_bytes(&inet_ehash_secret, 4); | ||
228 | } | ||
229 | EXPORT_SYMBOL(build_ehash_secret); | ||
230 | |||
220 | /* | 231 | /* |
221 | * Create an inet socket. | 232 | * Create an inet socket. |
222 | */ | 233 | */ |
@@ -233,6 +244,11 @@ static int inet_create(struct socket *sock, int protocol) | |||
233 | int try_loading_module = 0; | 244 | int try_loading_module = 0; |
234 | int err; | 245 | int err; |
235 | 246 | ||
247 | if (sock->type != SOCK_RAW && | ||
248 | sock->type != SOCK_DGRAM && | ||
249 | !inet_ehash_secret) | ||
250 | build_ehash_secret(); | ||
251 | |||
236 | sock->state = SS_UNCONNECTED; | 252 | sock->state = SS_UNCONNECTED; |
237 | 253 | ||
238 | /* Look for the requested type/protocol pair. */ | 254 | /* 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) | |||
98 | int try_loading_module = 0; | 98 | int try_loading_module = 0; |
99 | int err; | 99 | int err; |
100 | 100 | ||
101 | if (sock->type != SOCK_RAW && | ||
102 | sock->type != SOCK_DGRAM && | ||
103 | !inet_ehash_secret) | ||
104 | build_ehash_secret(); | ||
105 | |||
101 | /* Look for the requested type/protocol pair. */ | 106 | /* Look for the requested type/protocol pair. */ |
102 | answer = NULL; | 107 | answer = NULL; |
103 | lookup_protocol: | 108 | lookup_protocol: |