From d8ae5cd585f2fc63817a9aa0e1d3d2f9f5698278 Mon Sep 17 00:00:00 2001
From: =?iso-8859-15?q?Beno=EEt=20Ganne?= <benoit.ganne@gmail.com>
Date: Sun, 30 Sep 2007 19:52:30 +0200
Subject: [PATCH 1/3] remove protocol-specific code from random.c

There is INET, INT6 and DCCP protocol specific code in drivers/char/random.c
This patch:
 - moves code to specific random.c files in each protocol subdir
 - move 2/3-md4-transform to lib/halfmd4.c
 - update other files and kbuild to reflect the changes
It is useful for mod-ipv4 and as a bonus, it allows to remove
inet6_hashtables.c, addrconf_core.c and exthdrs_core.o from built-in
when ipv6 is compiled as a module (thus, ipv6.ko does'nt need any built-in).
---
 drivers/char/random.c         |  266 +++--------------------------------------
 include/linux/cryptohash.h    |    1 +
 include/linux/random.h        |   44 +++++--
 include/net/inet_hashtables.h |   21 +++-
 include/net/inet_sock.h       |   20 ---
 include/net/ip.h              |    8 ++
 include/net/ipv6.h            |    7 +
 lib/halfmd4.c                 |   56 +++++++++
 net/dccp/Makefile             |    2 +-
 net/dccp/dccp.h               |    5 +
 net/dccp/random.c             |   33 +++++
 net/ipv4/Makefile             |    3 +-
 net/ipv4/inet_hashtables.c    |    2 +
 net/ipv4/random.c             |   70 +++++++++++
 net/ipv6/Makefile             |   13 +--
 net/ipv6/random.c             |   43 +++++++
 16 files changed, 302 insertions(+), 292 deletions(-)
 create mode 100644 net/dccp/random.c
 create mode 100644 net/ipv4/random.c
 create mode 100644 net/ipv6/random.c

diff --git a/drivers/char/random.c b/drivers/char/random.c
index 397c714..5fefa03 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1302,11 +1302,10 @@ ctl_table random_table[] = {
 };
 #endif 	/* CONFIG_SYSCTL */
 
-/********************************************************************
- *
- * Random funtions for networking
- *
- ********************************************************************/
+/*
+ * initially, the following functions were for INET use only,
+ * but it is more general now
+ */
 
 /*
  * TCP initial sequence number picking.  This uses the random number
@@ -1321,116 +1320,12 @@ ctl_table random_table[] = {
  * compensated for by changing the secret periodically.
  */
 
-/* F, G and H are basic MD4 functions: selection, majority, parity */
-#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-
-/*
- * The generic round function.  The application is so specific that
- * we don't bother protecting all the arguments with parens, as is generally
- * good macro practice, in favor of extra legibility.
- * Rotation is separate from addition to prevent recomputation
- */
-#define ROUND(f, a, b, c, d, x, s)	\
-	(a += f(b, c, d) + x, a = (a << s) | (a >> (32 - s)))
-#define K1 0
-#define K2 013240474631UL
-#define K3 015666365641UL
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-
-static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
-{
-	__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
-
-	/* Round 1 */
-	ROUND(F, a, b, c, d, in[ 0] + K1,  3);
-	ROUND(F, d, a, b, c, in[ 1] + K1,  7);
-	ROUND(F, c, d, a, b, in[ 2] + K1, 11);
-	ROUND(F, b, c, d, a, in[ 3] + K1, 19);
-	ROUND(F, a, b, c, d, in[ 4] + K1,  3);
-	ROUND(F, d, a, b, c, in[ 5] + K1,  7);
-	ROUND(F, c, d, a, b, in[ 6] + K1, 11);
-	ROUND(F, b, c, d, a, in[ 7] + K1, 19);
-	ROUND(F, a, b, c, d, in[ 8] + K1,  3);
-	ROUND(F, d, a, b, c, in[ 9] + K1,  7);
-	ROUND(F, c, d, a, b, in[10] + K1, 11);
-	ROUND(F, b, c, d, a, in[11] + K1, 19);
-
-	/* Round 2 */
-	ROUND(G, a, b, c, d, in[ 1] + K2,  3);
-	ROUND(G, d, a, b, c, in[ 3] + K2,  5);
-	ROUND(G, c, d, a, b, in[ 5] + K2,  9);
-	ROUND(G, b, c, d, a, in[ 7] + K2, 13);
-	ROUND(G, a, b, c, d, in[ 9] + K2,  3);
-	ROUND(G, d, a, b, c, in[11] + K2,  5);
-	ROUND(G, c, d, a, b, in[ 0] + K2,  9);
-	ROUND(G, b, c, d, a, in[ 2] + K2, 13);
-	ROUND(G, a, b, c, d, in[ 4] + K2,  3);
-	ROUND(G, d, a, b, c, in[ 6] + K2,  5);
-	ROUND(G, c, d, a, b, in[ 8] + K2,  9);
-	ROUND(G, b, c, d, a, in[10] + K2, 13);
-
-	/* Round 3 */
-	ROUND(H, a, b, c, d, in[ 3] + K3,  3);
-	ROUND(H, d, a, b, c, in[ 7] + K3,  9);
-	ROUND(H, c, d, a, b, in[11] + K3, 11);
-	ROUND(H, b, c, d, a, in[ 2] + K3, 15);
-	ROUND(H, a, b, c, d, in[ 6] + K3,  3);
-	ROUND(H, d, a, b, c, in[10] + K3,  9);
-	ROUND(H, c, d, a, b, in[ 1] + K3, 11);
-	ROUND(H, b, c, d, a, in[ 5] + K3, 15);
-	ROUND(H, a, b, c, d, in[ 9] + K3,  3);
-	ROUND(H, d, a, b, c, in[ 0] + K3,  9);
-	ROUND(H, c, d, a, b, in[ 4] + K3, 11);
-	ROUND(H, b, c, d, a, in[ 8] + K3, 15);
-
-	return buf[1] + b; /* "most hashed" word */
-	/* Alternative: return sum of all words? */
-}
-#endif
-
-#undef ROUND
-#undef F
-#undef G
-#undef H
-#undef K1
-#undef K2
-#undef K3
-
 /* This should not be decreased so low that ISNs wrap too fast. */
 #define REKEY_INTERVAL (300 * HZ)
-/*
- * Bit layout of the tcp sequence numbers (before adding current time):
- * bit 24-31: increased after every key exchange
- * bit 0-23: hash(source,dest)
- *
- * The implementation is similar to the algorithm described
- * in the Appendix of RFC 1185, except that
- * - it uses a 1 MHz clock instead of a 250 kHz clock
- * - it performs a rekey every 5 minutes, which is equivalent
- * 	to a (source,dest) tulple dependent forward jump of the
- * 	clock by 0..2^(HASH_BITS+1)
- *
- * Thus the average ISN wraparound time is 68 minutes instead of
- * 4.55 hours.
- *
- * SMP cleanup and lock avoidance with poor man's RCU.
- * 			Manfred Spraul <manfred@colorfullife.com>
- *
- */
-#define COUNT_BITS 8
-#define COUNT_MASK ((1 << COUNT_BITS) - 1)
-#define HASH_BITS 24
-#define HASH_MASK ((1 << HASH_BITS) - 1)
 
-static struct keydata {
-	__u32 count; /* already shifted to the final position */
-	__u32 secret[12];
-} ____cacheline_aligned ip_keydata[2];
+struct keydata ____cacheline_aligned rnd_keydata[2];
 
-static unsigned int ip_cnt;
+static unsigned int rnd_cnt;
 
 static void rekey_seq_generator(struct work_struct *work);
 
@@ -1450,23 +1345,24 @@ static DECLARE_DELAYED_WORK(rekey_work, rekey_seq_generator);
  */
 static void rekey_seq_generator(struct work_struct *work)
 {
-	struct keydata *keyptr = &ip_keydata[1 ^ (ip_cnt & 1)];
+	struct keydata *keyptr = &rnd_keydata[1 ^ (rnd_cnt & 1)];
 
 	get_random_bytes(keyptr->secret, sizeof(keyptr->secret));
-	keyptr->count = (ip_cnt & COUNT_MASK) << HASH_BITS;
+	keyptr->count = (rnd_cnt & COUNT_MASK) << HASH_BITS;
 	smp_wmb();
-	ip_cnt++;
+	rnd_cnt++;
 	schedule_delayed_work(&rekey_work, REKEY_INTERVAL);
 }
 
-static inline struct keydata *get_keyptr(void)
+inline struct keydata *get_keyptr(void)
 {
-	struct keydata *keyptr = &ip_keydata[ip_cnt & 1];
+	struct keydata *keyptr = &rnd_keydata[rnd_cnt & 1];
 
 	smp_rmb();
 
 	return keyptr;
 }
+EXPORT_SYMBOL(get_keyptr);
 
 static __init int seqgen_init(void)
 {
@@ -1475,36 +1371,10 @@ static __init int seqgen_init(void)
 }
 late_initcall(seqgen_init);
 
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-				   __be16 sport, __be16 dport)
-{
-	__u32 seq;
-	__u32 hash[12];
-	struct keydata *keyptr = get_keyptr();
-
-	/* The procedure is the same as for IPv4, but addresses are longer.
-	 * Thus we must use twothirdsMD4Transform.
-	 */
-
-	memcpy(hash, saddr, 16);
-	hash[4]=((__force u16)sport << 16) + (__force u16)dport;
-	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
-
-	seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
-	seq += keyptr->count;
-
-	seq += ktime_get_real().tv64;
-
-	return seq;
-}
-EXPORT_SYMBOL(secure_tcpv6_sequence_number);
-#endif
-
 /*  The code below is shamelessly stolen from secure_tcp_sequence_number().
  *  All blames to Andrey V. Savochkin <saw@msu.ru>.
  */
-__u32 secure_ip_id(__be32 daddr)
+__u32 secure_rnd_id(__be32 seed)
 {
 	struct keydata *keyptr;
 	__u32 hash[4];
@@ -1516,118 +1386,14 @@ __u32 secure_ip_id(__be32 daddr)
 	 *  The dest ip address is placed in the starting vector,
 	 *  which is then hashed with random data.
 	 */
-	hash[0] = (__force __u32)daddr;
+	hash[0] = (__force __u32)seed;
 	hash[1] = keyptr->secret[9];
 	hash[2] = keyptr->secret[10];
 	hash[3] = keyptr->secret[11];
 
 	return half_md4_transform(hash, keyptr->secret);
 }
-
-#ifdef CONFIG_INET
-
-__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
-				 __be16 sport, __be16 dport)
-{
-	__u32 seq;
-	__u32 hash[4];
-	struct keydata *keyptr = get_keyptr();
-
-	/*
-	 *  Pick a unique starting offset for each TCP connection endpoints
-	 *  (saddr, daddr, sport, dport).
-	 *  Note that the words are placed into the starting vector, which is
-	 *  then mixed with a partial MD4 over random data.
-	 */
-	hash[0]=(__force u32)saddr;
-	hash[1]=(__force u32)daddr;
-	hash[2]=((__force u16)sport << 16) + (__force u16)dport;
-	hash[3]=keyptr->secret[11];
-
-	seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
-	seq += keyptr->count;
-	/*
-	 *	As close as possible to RFC 793, which
-	 *	suggests using a 250 kHz clock.
-	 *	Further reading shows this assumes 2 Mb/s networks.
-	 *	For 10 Gb/s Ethernet, a 1 GHz clock is appropriate.
-	 *	That's funny, Linux has one built in!  Use it!
-	 *	(Networks are faster now - should this be increased?)
-	 */
-	seq += ktime_get_real().tv64;
-#if 0
-	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
-	       saddr, daddr, sport, dport, seq);
-#endif
-	return seq;
-}
-
-/* Generate secure starting point for ephemeral IPV4 transport port search */
-u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
-{
-	struct keydata *keyptr = get_keyptr();
-	u32 hash[4];
-
-	/*
-	 *  Pick a unique starting offset for each ephemeral port search
-	 *  (saddr, daddr, dport) and 48bits of random data.
-	 */
-	hash[0] = (__force u32)saddr;
-	hash[1] = (__force u32)daddr;
-	hash[2] = (__force u32)dport ^ keyptr->secret[10];
-	hash[3] = keyptr->secret[11];
-
-	return half_md4_transform(hash, keyptr->secret);
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport)
-{
-	struct keydata *keyptr = get_keyptr();
-	u32 hash[12];
-
-	memcpy(hash, saddr, 16);
-	hash[4] = (__force u32)dport;
-	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
-
-	return twothirdsMD4Transform((const __u32 *)daddr, hash);
-}
-#endif
-
-#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
-/* Similar to secure_tcp_sequence_number but generate a 48 bit value
- * bit's 32-47 increase every key exchange
- *       0-31  hash(source, dest)
- */
-u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
-				__be16 sport, __be16 dport)
-{
-	u64 seq;
-	__u32 hash[4];
-	struct keydata *keyptr = get_keyptr();
-
-	hash[0] = (__force u32)saddr;
-	hash[1] = (__force u32)daddr;
-	hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
-	hash[3] = keyptr->secret[11];
-
-	seq = half_md4_transform(hash, keyptr->secret);
-	seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
-
-	seq += ktime_get_real().tv64;
-	seq &= (1ull << 48) - 1;
-#if 0
-	printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
-	       saddr, daddr, sport, dport, seq);
-#endif
-	return seq;
-}
-
-EXPORT_SYMBOL(secure_dccp_sequence_number);
-#endif
-
-#endif /* CONFIG_INET */
-
+EXPORT_SYMBOL(secure_rnd_id);
 
 /*
  * Get a random word for internal kernel use only. Similar to urandom but
@@ -1643,7 +1409,7 @@ unsigned int get_random_int(void)
 	 * drain on it), and uses halfMD4Transform within the second. We
 	 * also mix it with jiffies and the PID:
 	 */
-	return secure_ip_id((__force __be32)(current->pid + jiffies));
+	return secure_rnd_id((__force __be32)(current->pid + jiffies));
 }
 
 /*
diff --git a/include/linux/cryptohash.h b/include/linux/cryptohash.h
index c118b2a..0df3dba 100644
--- a/include/linux/cryptohash.h
+++ b/include/linux/cryptohash.h
@@ -8,5 +8,6 @@ void sha_init(__u32 *buf);
 void sha_transform(__u32 *digest, const char *data, __u32 *W);
 
 __u32 half_md4_transform(__u32 buf[4], __u32 const in[8]);
+__u32 twothirds_md4_transform(__u32 buf[4], __u32 const in[8]);
 
 #endif
diff --git a/include/linux/random.h b/include/linux/random.h
index 36f125c..4b0c483 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -42,6 +42,39 @@ struct rand_pool_info {
 
 #ifdef __KERNEL__
 
+/*
+ * Bit layout of the tcp sequence numbers (before adding current time):
+ * bit 24-31: increased after every key exchange
+ * bit 0-23: hash(source,dest)
+ *
+ * The implementation is similar to the algorithm described
+ * in the Appendix of RFC 1185, except that
+ * - it uses a 1 MHz clock instead of a 250 kHz clock
+ * - it performs a rekey every 5 minutes, which is equivalent
+ * 	to a (source,dest) tulple dependent forward jump of the
+ * 	clock by 0..2^(HASH_BITS+1)
+ *
+ * Thus the average ISN wraparound time is 68 minutes instead of
+ * 4.55 hours.
+ *
+ * SMP cleanup and lock avoidance with poor man's RCU.
+ * 			Manfred Spraul <manfred@colorfullife.com>
+ *
+ */
+#define COUNT_BITS 8
+#define COUNT_MASK ((1 << COUNT_BITS) - 1)
+#define HASH_BITS 24
+#define HASH_MASK ((1 << HASH_BITS) - 1)
+
+struct keydata {
+	__u32 count; /* already shifted to the final position */
+	__u32 secret[12];
+};
+extern struct keydata rnd_keydata[2];
+
+extern __u32 secure_rnd_id(__be32 seed);
+extern struct keydata *get_keyptr(void);
+
 extern void rand_initialize_irq(int irq);
 
 extern void add_input_randomness(unsigned int type, unsigned int code,
@@ -51,17 +84,6 @@ extern void add_interrupt_randomness(int irq);
 extern void get_random_bytes(void *buf, int nbytes);
 void generate_random_uuid(unsigned char uuid_out[16]);
 
-extern __u32 secure_ip_id(__be32 daddr);
-extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
-extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
-				      __be16 dport);
-extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
-					__be16 sport, __be16 dport);
-extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
-					  __be16 sport, __be16 dport);
-extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
-				       __be16 sport, __be16 dport);
-
 #ifndef MODULE
 extern const struct file_operations random_fops, urandom_fops;
 #endif
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index d27ee8c..fce886a 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -14,7 +14,6 @@
 #ifndef _INET_HASHTABLES_H
 #define _INET_HASHTABLES_H
 
-
 #include <linux/interrupt.h>
 #include <linux/ipv6.h>
 #include <linux/list.h>
@@ -33,6 +32,26 @@
 #include <asm/atomic.h>
 #include <asm/byteorder.h>
 
+extern u32 inet_ehash_secret;
+static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
+					const __be32 faddr, const __be16 fport)
+{
+	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)
+{
+	const struct inet_sock *inet = inet_sk(sk);
+	const __be32 laddr = inet->rcv_saddr;
+	const __u16 lport = inet->num;
+	const __be32 faddr = inet->daddr;
+	const __be16 fport = inet->dport;
+
+	return inet_ehashfn(laddr, lport, faddr, fport);
+}
+
 /* This is for all connections with a full identity, no wildcards.
  * One chain is dedicated to TIME_WAIT sockets.
  * I'll experiment with dynamic table growth later.
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index 62daf21..8c993c8 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -168,26 +168,6 @@ 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)
-{
-	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)
-{
-	const struct inet_sock *inet = inet_sk(sk);
-	const __be32 laddr = inet->rcv_saddr;
-	const __u16 lport = inet->num;
-	const __be32 faddr = inet->daddr;
-	const __be16 fport = inet->dport;
-
-	return inet_ehashfn(laddr, lport, faddr, fport);
-}
-
 #endif	/* _INET_SOCK_H */
diff --git a/include/net/ip.h b/include/net/ip.h
index abf2820..93e7766 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -393,4 +393,12 @@ extern int ip_misc_proc_init(void);
 
 extern struct ctl_table ipv4_table[];
 
+/*
+ * Functions provided by random.c
+ */
+
+extern __u32 secure_ip_id(__be32 daddr);
+extern __u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport);
+extern u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport);
+
 #endif	/* _IP_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 78a0d06..5a80189 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -620,5 +620,12 @@ extern void ipv6_sysctl_register(void);
 extern void ipv6_sysctl_unregister(void);
 #endif
 
+/*
+ * Functions provided by random.c
+ */
+
+extern __u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr, __be16 sport, __be16 dport);
+extern u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport);
+
 #endif /* __KERNEL__ */
 #endif /* _NET_IPV6_H */
diff --git a/lib/halfmd4.c b/lib/halfmd4.c
index e11db26..2bbf331 100644
--- a/lib/halfmd4.c
+++ b/lib/halfmd4.c
@@ -64,3 +64,59 @@ __u32 half_md4_transform(__u32 buf[4], __u32 const in[8])
 	return buf[1]; /* "most hashed" word */
 }
 EXPORT_SYMBOL(half_md4_transform);
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+/* 
+ * move away from drivers/char/random.c
+ */
+__u32 twothirds_md4_transform (__u32 buf[4], __u32 const in[12])
+{
+	__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
+
+	/* Round 1 */
+	ROUND(F, a, b, c, d, in[ 0] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 1] + K1,  7);
+	ROUND(F, c, d, a, b, in[ 2] + K1, 11);
+	ROUND(F, b, c, d, a, in[ 3] + K1, 19);
+	ROUND(F, a, b, c, d, in[ 4] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 5] + K1,  7);
+	ROUND(F, c, d, a, b, in[ 6] + K1, 11);
+	ROUND(F, b, c, d, a, in[ 7] + K1, 19);
+	ROUND(F, a, b, c, d, in[ 8] + K1,  3);
+	ROUND(F, d, a, b, c, in[ 9] + K1,  7);
+	ROUND(F, c, d, a, b, in[10] + K1, 11);
+	ROUND(F, b, c, d, a, in[11] + K1, 19);
+
+	/* Round 2 */
+	ROUND(G, a, b, c, d, in[ 1] + K2,  3);
+	ROUND(G, d, a, b, c, in[ 3] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 5] + K2,  9);
+	ROUND(G, b, c, d, a, in[ 7] + K2, 13);
+	ROUND(G, a, b, c, d, in[ 9] + K2,  3);
+	ROUND(G, d, a, b, c, in[11] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 0] + K2,  9);
+	ROUND(G, b, c, d, a, in[ 2] + K2, 13);
+	ROUND(G, a, b, c, d, in[ 4] + K2,  3);
+	ROUND(G, d, a, b, c, in[ 6] + K2,  5);
+	ROUND(G, c, d, a, b, in[ 8] + K2,  9);
+	ROUND(G, b, c, d, a, in[10] + K2, 13);
+
+	/* Round 3 */
+	ROUND(H, a, b, c, d, in[ 3] + K3,  3);
+	ROUND(H, d, a, b, c, in[ 7] + K3,  9);
+	ROUND(H, c, d, a, b, in[11] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 2] + K3, 15);
+	ROUND(H, a, b, c, d, in[ 6] + K3,  3);
+	ROUND(H, d, a, b, c, in[10] + K3,  9);
+	ROUND(H, c, d, a, b, in[ 1] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 5] + K3, 15);
+	ROUND(H, a, b, c, d, in[ 9] + K3,  3);
+	ROUND(H, d, a, b, c, in[ 0] + K3,  9);
+	ROUND(H, c, d, a, b, in[ 4] + K3, 11);
+	ROUND(H, b, c, d, a, in[ 8] + K3, 15);
+
+	return buf[1] + b; /* "most hashed" word */
+	/* Alternative: return sum of all words? */
+}
+EXPORT_SYMBOL(twothirds_md4_transform);
+#endif
diff --git a/net/dccp/Makefile b/net/dccp/Makefile
index f4f8793..6649c30 100644
--- a/net/dccp/Makefile
+++ b/net/dccp/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o
 
 dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
 
-dccp_ipv4-y := ipv4.o
+dccp_ipv4-y := ipv4.o random.o
 
 # build dccp_ipv6 as module whenever either IPv6 or DCCP is a module
 obj-$(subst y,$(CONFIG_IP_DCCP),$(CONFIG_IPV6)) += dccp_ipv6.o
diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h
index d8ad27b..a055197 100644
--- a/net/dccp/dccp.h
+++ b/net/dccp/dccp.h
@@ -456,4 +456,9 @@ static inline void dccp_sysctl_exit(void)
 }
 #endif
 
+/*
+ * Functions provided by random.c
+ */
+extern u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport);
+
 #endif /* _DCCP_H */
diff --git a/net/dccp/random.c b/net/dccp/random.c
new file mode 100644
index 0000000..f0fe811
--- /dev/null
+++ b/net/dccp/random.c
@@ -0,0 +1,33 @@
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/hrtimer.h>
+#include <net/ip.h>
+
+/* Similar to secure_tcp_sequence_number but generate a 48 bit value
+ * bit's 32-47 increase every key exchange
+ *       0-31  hash(source, dest)
+ */
+u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
+				__be16 sport, __be16 dport)
+{
+	u64 seq;
+	__u32 hash[4];
+	struct keydata *keyptr = get_keyptr();
+
+	hash[0] = (__force u32)saddr;
+	hash[1] = (__force u32)daddr;
+	hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+	hash[3] = keyptr->secret[11];
+
+	seq = half_md4_transform(hash, keyptr->secret);
+	seq |= ((u64)keyptr->count) << (32 - HASH_BITS);
+
+	seq += ktime_get_real().tv64;
+	seq &= (1ull << 48) - 1;
+#if 0
+	printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
+	       saddr, daddr, sport, dport, seq);
+#endif
+	return seq;
+}
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 4ff6c15..c02aee0 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -10,7 +10,8 @@ obj-y     := route.o inetpeer.o protocol.o \
 	     tcp_minisocks.o tcp_cong.o \
 	     datagram.o raw.o udp.o udplite.o \
 	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
-	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+	     sysctl_net_ipv4.o fib_frontend.o fib_semantics.o \
+	     random.o
 
 obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
 obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fb66262..1d07db6 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -41,6 +41,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
 	}
 	return tb;
 }
+EXPORT_SYMBOL(inet_bind_bucket_create);
 
 /*
  * Caller must hold hashbucket lock for this tb with local BH disabled
@@ -60,6 +61,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
 	sk_add_bind_node(sk, &tb->owners);
 	inet_csk(sk)->icsk_bind_hash = tb;
 }
+EXPORT_SYMBOL(inet_bind_hash);
 
 /*
  * Get rid of any references to a local port held by the given sock.
diff --git a/net/ipv4/random.c b/net/ipv4/random.c
new file mode 100644
index 0000000..1161817
--- /dev/null
+++ b/net/ipv4/random.c
@@ -0,0 +1,70 @@
+#include <linux/types.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/hrtimer.h>
+#include <net/ip.h>
+
+/********************************************************************
+ *
+ * Random funtions for networking
+ *
+ ********************************************************************/
+
+__u32 secure_ip_id(__be32 daddr)
+{
+        return secure_rnd_id(daddr);
+}
+
+__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
+				 __be16 sport, __be16 dport)
+{
+	__u32 seq;
+	__u32 hash[4];
+	struct keydata *keyptr = get_keyptr();
+
+	/*
+	 *  Pick a unique starting offset for each TCP connection endpoints
+	 *  (saddr, daddr, sport, dport).
+	 *  Note that the words are placed into the starting vector, which is
+	 *  then mixed with a partial MD4 over random data.
+	 */
+	hash[0]=(__force u32)saddr;
+	hash[1]=(__force u32)daddr;
+	hash[2]=((__force u16)sport << 16) + (__force u16)dport;
+	hash[3]=keyptr->secret[11];
+
+	seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
+	seq += keyptr->count;
+	/*
+	 *	As close as possible to RFC 793, which
+	 *	suggests using a 250 kHz clock.
+	 *	Further reading shows this assumes 2 Mb/s networks.
+	 *	For 10 Gb/s Ethernet, a 1 GHz clock is appropriate.
+	 *	That's funny, Linux has one built in!  Use it!
+	 *	(Networks are faster now - should this be increased?)
+	 */
+	seq += ktime_get_real().tv64;
+#if 0
+	printk("init_seq(%lx, %lx, %d, %d) = %d\n",
+	       saddr, daddr, sport, dport, seq);
+#endif
+	return seq;
+}
+
+/* Generate secure starting point for ephemeral IPV4 transport port search */
+u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
+{
+	struct keydata *keyptr = get_keyptr();
+	u32 hash[4];
+
+	/*
+	 *  Pick a unique starting offset for each ephemeral port search
+	 *  (saddr, daddr, dport) and 48bits of random data.
+	 */
+	hash[0] = (__force u32)saddr;
+	hash[1] = (__force u32)daddr;
+	hash[2] = (__force u32)dport ^ keyptr->secret[10];
+	hash[3] = keyptr->secret[11];
+
+	return half_md4_transform(hash, keyptr->secret);
+}
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index bb33309..c070977 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -5,10 +5,11 @@
 obj-$(CONFIG_IPV6) += ipv6.o
 
 ipv6-objs :=	af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
-		route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \
-		raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
-		exthdrs.o sysctl_net_ipv6.o datagram.o \
-		ip6_flowlabel.o inet6_connection_sock.o
+		route.o ip6_fib.o ipv6_sockglue.o inet6_hashtables.o \
+		ndisc.o udp.o udplite.o raw.o protocol.o icmp.o mcast.o \
+		reassembly.o tcp_ipv6.o exthdrs.o sysctl_net_ipv6.o \
+		datagram.o ip6_flowlabel.o inet6_connection_sock.o \
+		random.o addrconf_core.o exthdrs_core.o
 
 ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \
 	xfrm6_output.o
@@ -32,7 +33,3 @@ obj-$(CONFIG_NETFILTER)	+= netfilter/
 
 obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
-
-obj-y += addrconf_core.o exthdrs_core.o
-
-obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o
diff --git a/net/ipv6/random.c b/net/ipv6/random.c
new file mode 100644
index 0000000..1c86802
--- /dev/null
+++ b/net/ipv6/random.c
@@ -0,0 +1,43 @@
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/cryptohash.h>
+#include <linux/hrtimer.h>
+#include <net/ipv6.h>
+
+__u32 secure_tcpv6_sequence_number(__be32 *saddr, __be32 *daddr,
+				   __be16 sport, __be16 dport)
+{
+	__u32 seq;
+	__u32 hash[12];
+	struct keydata *keyptr = get_keyptr();
+
+	/* The procedure is the same as for IPv4, but addresses are longer.
+	 * Thus we must use twothirdsMD4Transform.
+	 */
+
+	memcpy(hash, saddr, 16);
+	hash[4]=((__force u16)sport << 16) + (__force u16)dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+
+	seq = twothirds_md4_transform((__u32 *)daddr, hash) & HASH_MASK;
+	seq += keyptr->count;
+
+	seq += ktime_get_real().tv64;
+
+	return seq;
+}
+EXPORT_SYMBOL(secure_tcpv6_sequence_number);
+
+u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport)
+{
+	struct keydata *keyptr = get_keyptr();
+	u32 hash[12];
+
+	memcpy(hash, saddr, 16);
+	hash[4] = (__force u32)dport;
+	memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+
+	return twothirds_md4_transform((__u32 *)daddr, hash);
+}
+
-- 
1.5.2.5


