diff -uNr linux-3.9.4-vanilla/include/linux/murmur3.h linux-3.9.4-hiccups/include/linux/murmur3.h
--- linux-3.9.4-vanilla/include/linux/murmur3.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-3.9.4-hiccups/include/linux/murmur3.h	2014-05-07 13:43:09.968338198 -0700
@@ -0,0 +1,14 @@
+/*
+ * murmur3.h
+ * See linux/lib/murmur3.c for license
+ *
+ * This is a portable ANSI C implementation of MurmurHash3_x86_32 (Murmur3A)
+ */
+#ifndef _LINUX_MURMUR3_H
+#define _LINUX_MURMUR3_H
+
+#include <linux/types.h>
+
+extern u32 murmur3(u32 seed, const void *key, int len);
+
+#endif /* _LINUX_MURMUR3_H */
diff -uNr linux-3.9.4-vanilla/include/linux/socket.h linux-3.9.4-hiccups/include/linux/socket.h
--- linux-3.9.4-vanilla/include/linux/socket.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/linux/socket.h	2014-05-07 13:43:09.968338198 -0700
@@ -253,6 +253,7 @@
 #define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */
 #define MSG_EOF         MSG_FIN
 
+#define MSG_HICCUPS     0x10000000  /* RMC: Use AppSalt hiccups */
 #define MSG_FASTOPEN	0x20000000	/* Send data in TCP SYN */
 #define MSG_CMSG_CLOEXEC 0x40000000	/* Set close_on_exit for file
 					   descriptor received through
diff -uNr linux-3.9.4-vanilla/include/linux/tcp.h linux-3.9.4-hiccups/include/linux/tcp.h
--- linux-3.9.4-vanilla/include/linux/tcp.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/linux/tcp.h	2014-05-07 13:43:09.967338198 -0700
@@ -96,6 +96,8 @@
 	u8	num_sacks;	/* Number of SACK blocks		*/
 	u16	user_mss;	/* mss requested by user in ioctl	*/
 	u16	mss_clamp;	/* Maximal mss, negotiated at connection setup */
+    u16 hic_mpcapable;  /* RMC */
+    u16 hic_exp;
 };
 
 static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
@@ -103,6 +105,8 @@
 	rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
 	rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
 	rx_opt->cookie_plus = 0;
+    rx_opt->hic_mpcapable = 0;  /* RMC */
+    rx_opt->hic_exp = 0;
 }
 
 /* This is the max number of SACKS that we'll generate and process. It's safe
@@ -289,6 +293,27 @@
 
 	int			linger2;
 
+    /* RMC: hiccups vars */
+    u32 hic_appsalt;
+    struct {
+        u16     isn_upper;
+        u16     ipid;
+        u16     rcvwin;
+    } hic_as_hash;
+    struct {
+        u32     crc;
+        u32     murmur;
+    } hic_as_candidate[16];   /* set to HNUMPROBES */
+    u32 hic_coverage            : 8,
+        hic_want_coverage       : 8,
+        hic_syn_match           : 3,
+        hic_synack_match        : 3,
+        hic_status              : 3,
+        hic_in_conn             : 1,
+        hic_in_connreq          : 1,
+        hic_awaiting_appsalt    : 1,
+        hic_do_client_appsalt   : 1;
+
 /* Receiver side RTT estimation */
 	struct {
 		u32	rtt;
diff -uNr linux-3.9.4-vanilla/include/net/inet_sock.h linux-3.9.4-hiccups/include/net/inet_sock.h
--- linux-3.9.4-vanilla/include/net/inet_sock.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/net/inet_sock.h	2014-05-07 13:43:09.969338198 -0700
@@ -86,7 +86,9 @@
 				wscale_ok  : 1,
 				ecn_ok	   : 1,
 				acked	   : 1,
-				no_srccheck: 1;
+				no_srccheck: 1,
+                hic_mpcapable : 1,  /* RMC */
+                hic_exp    : 1;
 	kmemcheck_bitfield_end(flags);
 	struct ip_options_rcu	*opt;
 };
diff -uNr linux-3.9.4-vanilla/include/net/tcp.h linux-3.9.4-hiccups/include/net/tcp.h
--- linux-3.9.4-vanilla/include/net/tcp.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/net/tcp.h	2014-05-07 13:43:09.969338198 -0700
@@ -179,6 +179,8 @@
 #define TCPOPT_SACK             5       /* SACK Block */
 #define TCPOPT_TIMESTAMP	8	/* Better RTT estimations/PAWS */
 #define TCPOPT_MD5SIG		19	/* MD5 Signature (RFC2385) */
+#define TCPOPT_HICMP        30  /* RMC: fake MPCAPABLE option */
+#define TCPOPT_HICEXP       99  /* RMC: fake experimental option */
 #define TCPOPT_COOKIE		253	/* Cookie extension (experimental) */
 #define TCPOPT_EXP		254	/* Experimental */
 /* Magic number to be after the option value for sharing TCP
@@ -200,6 +202,8 @@
 #define TCPOLEN_COOKIE_PAIR    3	/* Cookie pair header extension */
 #define TCPOLEN_COOKIE_MIN     (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
 #define TCPOLEN_COOKIE_MAX     (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MAX)
+#define TCPOLEN_HICMP          12   /* RMC */
+#define TCPOLEN_HICEXP         4
 
 /* But this is what stacks really send out. */
 #define TCPOLEN_TSTAMP_ALIGNED		12
@@ -210,6 +214,8 @@
 #define TCPOLEN_SACK_PERBLOCK		8
 #define TCPOLEN_MD5SIG_ALIGNED		20
 #define TCPOLEN_MSS_ALIGNED		4
+#define TCPOLEN_HICMP_ALIGNED       12  /* RMC */
+#define TCPOLEN_HICEXP_ALIGNED      4
 
 /* Flags in tp->nonagle */
 #define TCP_NAGLE_OFF		1	/* Nagle's algo is disabled */
@@ -1141,6 +1147,9 @@
 	ireq->ecn_ok = 0;
 	ireq->rmt_port = tcp_hdr(skb)->source;
 	ireq->loc_port = tcp_hdr(skb)->dest;
+    /* RMC */
+    ireq->hic_mpcapable = rx_opt->hic_mpcapable;
+    ireq->hic_exp = rx_opt->hic_exp;
 }
 
 /* Compute time elapsed between SYNACK and the ACK completing 3WHS */
diff -uNr linux-3.9.4-vanilla/include/net/tcp_hiccups.h linux-3.9.4-hiccups/include/net/tcp_hiccups.h
--- linux-3.9.4-vanilla/include/net/tcp_hiccups.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-3.9.4-hiccups/include/net/tcp_hiccups.h	2014-05-07 13:43:09.968338198 -0700
@@ -0,0 +1,124 @@
+/**
+ * HICCUPS header file
+ */
+
+#include <net/tcp.h>
+
+#define HNUMPROBES 16   /* don't count HONEWAY */
+/* Note: if you add or remove probes, you'll also need to edit
+ * include/linux/tcp.h to resize the arrays
+ */
+
+/* probe types */
+#define HNONAT   0
+#define HFULL    1
+#define HNAT     2
+#define HNOOPT   3
+#define HONLYOPT 4
+#define HECNIP   5
+#define HECNTCP  6
+#define HLEN     7
+#define HMSS     8
+#define HWINSCL  9
+#define HTSTAMP  10
+#define HMPTCP   11
+#define HEXOPT   12
+#define HFLAGS   13
+#define HSAFE    14
+#define HNULL    15
+#define HONEWAY  248
+/* Note: if you change these, you'll also need to edit
+ * populate_hb() and get_cvr_name()
+ */
+
+/* result types */
+#define NOTYETCHECK 0
+#define BOTHMATCH   1
+#define SAMATCH     2
+#define SANULLMATCH 3
+#define SYNMATCH    4
+#define NONEMATCH   5
+
+enum logLevel {LOG_OFF, LOG_LOW, LOG_HIGH};
+extern int sysctl_tcp_hiccups_loglevel;
+extern int sysctl_tcp_hiccups_appsalt;
+extern int sysctl_tcp_hiccups_experiments;
+
+/**
+ * This struct lists the elements that are used
+ * in the calculation of a HICCUPS check
+ */
+struct hiccups_bits {
+        u8      ihl:4,
+                version:4;
+        u8	    ecn:2,
+		        dscp:6;
+        u16	    tot_len;
+        u16     frag_off;
+        u8      protocol;
+    	u8      coverage;
+        u32     saddr;
+        u32     daddr;
+        u16     sport;
+        u16     dport;
+        u16     res1:4,
+                doff:4,
+                fin:1,
+                syn:1,
+                rst:1,
+                psh:1,
+                ack:1,
+                urg:1,
+                ece:1,
+                cwr:1;
+        u16     window;
+        u16     urg_ptr;
+	    u16     salt;
+        /**
+         * "options" includes enough room for 40 bytes each of IP and TCP options.
+         * It must come last, because we won't always hash the whole thing.
+         */
+        u8      options[80];
+};
+
+/** The different types of hashes we do. */
+struct hiccups_hashes {
+    u32 murmur;
+    u32 crc;
+};
+
+/** Holds hash pieces after being calculated. */
+struct hash_pieces {
+    u32 isn;
+    u16 salt;
+    u16 isn_upper;
+    u16 ipid;
+    u16 rcvwin;
+};
+
+/* Functions for debugging */
+#define h_print(level,x...) do {if (sysctl_tcp_hiccups_loglevel >= level) {printk(x);} } while (0)
+#define h_call(level,x) do {if (sysctl_tcp_hiccups_loglevel >= level) {x;} } while(0)
+extern void print_iphdr_struct(struct iphdr *iph);
+extern void print_tcphdr_struct(struct tcphdr *th);
+extern void print_tcp_skb_cb_struct(struct tcp_skb_cb *tcb);
+extern void print_sk_buff_struct(struct sk_buff *skb);
+extern void print_inet_sock_struct(struct inet_sock *inet);
+extern void print_tcp_sock_struct(struct tcp_sock *tp);
+extern void print_sock_struct(struct sock *sk);
+extern void print_inet_request_sock_struct(struct inet_request_sock *ireq);
+extern void print_tcp_request_sock_struct(struct tcp_request_sock *treq);
+extern void print_request_sock_struct(struct request_sock *req);
+extern void print_hex(void const *s, size_t len, int brk, int tabs);
+
+/* The actual HICCUPS hooks */
+extern void tcp_hiccups_syn_out(struct sock *sk, struct sk_buff *skb);
+extern void tcp_hiccups_after_syn_out(struct sock *sk, struct sk_buff *buff);
+extern void tcp_hiccups_syn_in(struct sock *sk, struct sk_buff *skb);
+extern void tcp_hiccups_synack_out(struct sock *sk, struct sk_buff *skb);
+extern void tcp_hiccups_after_synack_out(struct sock *sk, struct sk_buff *skb, struct request_sock *req);
+extern void tcp_hiccups_synack_in(struct sock *sk, struct sk_buff *skb);
+extern u32  tcp_hiccups_outgoing_appsalt(struct sock *sk, struct msghdr *msg, size_t size);
+extern void tcp_hiccups_appsalt_post(struct sock *sk, struct sk_buff *skb);
+extern void tcp_hiccups_clear(struct sock *sk);
+
diff -uNr linux-3.9.4-vanilla/include/uapi/linux/sysctl.h linux-3.9.4-hiccups/include/uapi/linux/sysctl.h
--- linux-3.9.4-vanilla/include/uapi/linux/sysctl.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/uapi/linux/sysctl.h	2014-05-07 13:43:09.966338198 -0700
@@ -425,6 +425,8 @@
 	NET_TCP_ALLOWED_CONG_CONTROL=123,
 	NET_TCP_MAX_SSTHRESH=124,
 	NET_TCP_FRTO_RESPONSE=125,
+    NET_TCP_HICCUPS_LOGLEVEL=126,   /* RMC */
+    NET_TCP_HICCUPS_APPSALT=127,
 };
 
 enum {
diff -uNr linux-3.9.4-vanilla/include/uapi/linux/tcp.h linux-3.9.4-hiccups/include/uapi/linux/tcp.h
--- linux-3.9.4-vanilla/include/uapi/linux/tcp.h	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/include/uapi/linux/tcp.h	2014-05-07 13:43:09.967338198 -0700
@@ -112,6 +112,11 @@
 #define TCP_REPAIR_OPTIONS	22
 #define TCP_FASTOPEN		23	/* Enable FastOpen on listeners */
 #define TCP_TIMESTAMP		24
+/* RMC */
+#define TCP_HICCUPS_STATUS          25  /* Gives results of hiccups checks */
+#define TCP_HICCUPS_SYN_MATCH       26  /* Gives match bits for hiccups syn */
+#define TCP_HICCUPS_SYNACK_MATCH    27  /* Gives match bits for hiccups syn-ack */
+#define TCP_HICCUPS_COVERAGE        28  /* Field coverage selector for hiccups checks */
 
 struct tcp_repair_opt {
 	__u32	opt_code;
diff -uNr linux-3.9.4-vanilla/kernel/sysctl_binary.c linux-3.9.4-hiccups/kernel/sysctl_binary.c
--- linux-3.9.4-vanilla/kernel/sysctl_binary.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/kernel/sysctl_binary.c	2014-05-07 13:43:09.970338198 -0700
@@ -427,6 +427,10 @@
 	/* NET_IPV4_ICMP_PARAMPROB_RATE unused */
 	/* NET_IPV4_ICMP_ECHOREPLY_RATE unused */
 	/* NET_IPV4_ALWAYS_DEFRAG unused */
+
+    { CTL_INT,  NET_TCP_HICCUPS_LOGLEVEL,       "tcp_hiccups_loglevel" },
+    { CTL_INT,  NET_TCP_HICCUPS_APPSALT,       "tcp_hiccups_appsalt" },
+
 	{}
 };
 
diff -uNr linux-3.9.4-vanilla/lib/Makefile linux-3.9.4-hiccups/lib/Makefile
--- linux-3.9.4-vanilla/lib/Makefile	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/lib/Makefile	2014-05-07 13:43:09.970338198 -0700
@@ -66,6 +66,8 @@
 obj-$(CONFIG_CRC8)	+= crc8.o
 obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
 
+obj-y += murmur3.o
+
 obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
 obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
 obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
diff -uNr linux-3.9.4-vanilla/lib/murmur3.c linux-3.9.4-hiccups/lib/murmur3.c
--- linux-3.9.4-vanilla/lib/murmur3.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-3.9.4-hiccups/lib/murmur3.c	2014-05-07 13:43:09.970338198 -0700
@@ -0,0 +1,280 @@
+/*-----------------------------------------------------------------------------
+ * MurmurHash3 was written by Austin Appleby, and is placed in the public
+ * domain.
+ *
+ * This implementation was written by Shane Day, and is also public domain.
+ *
+ * This is a portable ANSI C implementation of MurmurHash3_x86_32 (Murmur3A)
+ * with support for progressive processing.
+ */
+
+/*-----------------------------------------------------------------------------
+ 
+If you want to understand the MurmurHash algorithm you would be much better
+off reading the original source. Just point your browser at:
+http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp
+
+
+What this version provides?
+
+1. Progressive data feeding. Useful when the entire payload to be hashed
+does not fit in memory or when the data is streamed through the application.
+Also useful when hashing a number of strings with a common prefix. A partial
+hash of a prefix string can be generated and reused for each suffix string.
+
+2. Portability. Plain old C so that it should compile on any old compiler.
+Both CPU endian and access-alignment neutral, but avoiding inefficient code
+when possible depending on CPU capabilities.
+
+3. Drop in. I personally like nice self contained public domain code, making it
+easy to pilfer without loads of refactoring to work properly in the existing
+application code & makefile structure and mucking around with licence files.
+Just copy PMurHash.h and PMurHash.c and you're ready to go.
+
+
+How does it work?
+
+We can only process entire 32 bit chunks of input, except for the very end
+that may be shorter. So along with the partial hash we need to give back to
+the caller a carry containing up to 3 bytes that we were unable to process.
+This carry also needs to record the number of bytes the carry holds. I use
+the low 2 bits as a count (0..3) and the carry bytes are shifted into the
+high byte in stream order.
+
+To handle endianess I simply use a macro that reads a uint32_t and define
+that macro to be a direct read on little endian machines, a read and swap
+on big endian machines, or a byte-by-byte read if the endianess is unknown.
+
+-----------------------------------------------------------------------------*/
+
+#include <linux/murmur3.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+/* RMC: I took out the type determination code since we know we're using 
+ * a new gcc.
+ */
+
+/*-----------------------------------------------------------------------------
+ * Endianess, misalignment capabilities and util macros
+ *
+ * The following 3 macros are defined in this section. The other macros defined
+ * are only needed to help derive these 3.
+ *
+ * READ_UINT32(x)   Read a little endian unsigned 32-bit int
+ * UNALIGNED_SAFE   Defined if READ_UINT32 works on non-word boundaries
+ * ROTL32(x,r)      Rotate x left by r bits
+ */
+
+/* Convention is to define __BYTE_ORDER == to one of these values */
+#if !defined(__BIG_ENDIAN)
+  #define __BIG_ENDIAN 4321
+#endif
+#if !defined(__LITTLE_ENDIAN)
+  #define __LITTLE_ENDIAN 1234
+#endif
+
+/* I386 */
+#ifdef CONFIG_X86
+  #define __BYTE_ORDER __LITTLE_ENDIAN
+  #define UNALIGNED_SAFE
+#endif
+
+/* gcc 'may' define __LITTLE_ENDIAN__ or __BIG_ENDIAN__ to 1 (Note the trailing __),
+ * or even _LITTLE_ENDIAN or _BIG_ENDIAN (Note the single _ prefix) */
+#if !defined(__BYTE_ORDER)
+  #if defined(__LITTLE_ENDIAN__) && __LITTLE_ENDIAN__==1 || defined(_LITTLE_ENDIAN) && _LITTLE_ENDIAN==1
+    #define __BYTE_ORDER __LITTLE_ENDIAN
+  #elif defined(__BIG_ENDIAN__) && __BIG_ENDIAN__==1 || defined(_BIG_ENDIAN) && _BIG_ENDIAN==1
+    #define __BYTE_ORDER __BIG_ENDIAN
+  #endif
+#endif
+
+/* gcc (usually) defines xEL/EB macros for ARM and MIPS endianess */
+#if !defined(__BYTE_ORDER)
+  #if defined(__ARMEL__) || defined(__MIPSEL__)
+    #define __BYTE_ORDER __LITTLE_ENDIAN
+  #endif
+  #if defined(__ARMEB__) || defined(__MIPSEB__)
+    #define __BYTE_ORDER __BIG_ENDIAN
+  #endif
+#endif
+
+/* Now find best way we can to READ_UINT32 */
+#if __BYTE_ORDER==__LITTLE_ENDIAN
+  /* CPU endian matches murmurhash algorithm, so read 32-bit word directly */
+  #define READ_UINT32(ptr)   (*((uint32_t*)(ptr)))
+#elif __BYTE_ORDER==__BIG_ENDIAN
+  /* TODO: Add additional cases below where a compiler provided bswap32 is available */
+  #if defined(__GNUC__) && (__GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>=3))
+    #define READ_UINT32(ptr)   (__builtin_bswap32(*((uint32_t*)(ptr))))
+  #else
+    /* Without a known fast bswap32 we're just as well off doing this */
+    #define READ_UINT32(ptr)   (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24)
+    #define UNALIGNED_SAFE
+  #endif
+#else
+  /* Unknown endianess so last resort is to read individual bytes */
+  #define READ_UINT32(ptr)   (ptr[0]|ptr[1]<<8|ptr[2]<<16|ptr[3]<<24)
+
+  /* Since we're not doing word-reads we can skip the messing about with realignment */
+  #define UNALIGNED_SAFE
+#endif
+
+/* Find best way to ROTL32 */
+/* gcc recognises this code and generates a rotate instruction for CPUs with one */
+#define ROTL32(x,r)  (((uint32_t)x << r) | ((uint32_t)x >> (32 - r)))
+
+
+/*-----------------------------------------------------------------------------
+ * Core murmurhash algorithm macros */
+
+#define C1  (0xcc9e2d51)
+#define C2  (0x1b873593)
+
+/* This is the main processing body of the algorithm. It operates
+ * on each full 32-bits of input. */
+#define DOBLOCK(h1, k1) do{ \
+        k1 *= C1; \
+        k1 = ROTL32(k1,15); \
+        k1 *= C2; \
+        \
+        h1 ^= k1; \
+        h1 = ROTL32(h1,13); \
+        h1 = h1*5+0xe6546b64; \
+    }while(0)
+
+
+/* Append unaligned bytes to carry, forcing hash churn if we have 4 bytes */
+/* cnt=bytes to process, h1=name of h1 var, c=carry, n=bytes in c, ptr/len=payload */
+#define DOBYTES(cnt, h1, c, n, ptr, len) do{ \
+    int _i = cnt; \
+    while(_i--) { \
+        c = c>>8 | *ptr++<<24; \
+        n++; len--; \
+        if(n==4) { \
+            DOBLOCK(h1, c); \
+            n = 0; \
+        } \
+    } }while(0)
+
+/*---------------------------------------------------------------------------*/
+
+/* Main hashing function. Initialise carry to 0 and h1 to 0 or an initial seed
+ * if wanted. Both ph1 and pcarry are required arguments. */
+static void PMurHash32_Process(uint32_t *ph1, uint32_t *pcarry, const void *key, int len)
+{
+  uint32_t h1 = *ph1;
+  uint32_t c = *pcarry;
+
+  const uint8_t *ptr = (uint8_t*)key;
+  const uint8_t *end;
+
+  /* Extract carry count from low 2 bits of c value */
+  int n = c & 3;
+
+#if defined(UNALIGNED_SAFE)
+  /* This CPU handles unaligned word access */
+
+  /* Consume any carry bytes */
+  int i = (4-n) & 3;
+  if(i && i <= len) {
+    DOBYTES(i, h1, c, n, ptr, len);
+  }
+
+  /* Process 32-bit chunks */
+  end = ptr + len/4*4;
+  for( ; ptr < end ; ptr+=4) {
+    uint32_t k1 = READ_UINT32(ptr);
+    DOBLOCK(h1, k1);
+  }
+
+#else /*UNALIGNED_SAFE*/
+  /* This CPU does not handle unaligned word access */
+
+  /* Consume enough so that the next data byte is word aligned */
+  int i = -(long)ptr & 3;
+  if(i && i <= len) {
+      DOBYTES(i, h1, c, n, ptr, len);
+  }
+
+  /* We're now aligned. Process in aligned blocks. Specialise for each possible carry count */
+  end = ptr + len/4*4;
+  switch(n) { /* how many bytes in c */
+  case 0: /* c=[----]  w=[3210]  b=[3210]=w            c'=[----] */
+    for( ; ptr < end ; ptr+=4) {
+      uint32_t k1 = READ_UINT32(ptr);
+      DOBLOCK(h1, k1);
+    }
+    break;
+  case 1: /* c=[0---]  w=[4321]  b=[3210]=c>>24|w<<8   c'=[4---] */
+    for( ; ptr < end ; ptr+=4) {
+      uint32_t k1 = c>>24;
+      c = READ_UINT32(ptr);
+      k1 |= c<<8;
+      DOBLOCK(h1, k1);
+    }
+    break;
+  case 2: /* c=[10--]  w=[5432]  b=[3210]=c>>16|w<<16  c'=[54--] */
+    for( ; ptr < end ; ptr+=4) {
+      uint32_t k1 = c>>16;
+      c = READ_UINT32(ptr);
+      k1 |= c<<16;
+      DOBLOCK(h1, k1);
+    }
+    break;
+  case 3: /* c=[210-]  w=[6543]  b=[3210]=c>>8|w<<24   c'=[654-] */
+    for( ; ptr < end ; ptr+=4) {
+      uint32_t k1 = c>>8;
+      c = READ_UINT32(ptr);
+      k1 |= c<<24;
+      DOBLOCK(h1, k1);
+    }
+  }
+#endif /*UNALIGNED_SAFE*/
+
+  /* Advance over whole 32-bit chunks, possibly leaving 1..3 bytes */
+  len -= len/4*4;
+
+  /* Append any remaining bytes into carry */
+  DOBYTES(len, h1, c, n, ptr, len);
+
+  /* Copy out new running hash and carry */
+  *ph1 = h1;
+  *pcarry = (c & ~0xff) | n;
+} 
+
+/*---------------------------------------------------------------------------*/
+
+/* Finalize a hash. To match the original Murmur3A the total_length must be provided */
+static uint32_t PMurHash32_Result(uint32_t h, uint32_t carry, uint32_t total_length)
+{
+  uint32_t k1;
+  int n = carry & 3;
+  if(n) {
+    k1 = carry >> (4-n)*8;
+    k1 *= C1; k1 = ROTL32(k1,15); k1 *= C2; h ^= k1;
+  }
+  h ^= total_length;
+
+  /* fmix */
+  h ^= h >> 16;
+  h *= 0x85ebca6b;
+  h ^= h >> 13;
+  h *= 0xc2b2ae35;
+  h ^= h >> 16;
+
+  return h;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* Murmur3A compatable all-at-once */
+u32 murmur3(u32 seed, const void *key, int len)
+{
+  uint32_t h1=seed, carry=0;
+  PMurHash32_Process(&h1, &carry, key, len);
+  return PMurHash32_Result(h1, carry, len);
+}
+EXPORT_SYMBOL(murmur3);
+
diff -uNr linux-3.9.4-vanilla/Makefile linux-3.9.4-hiccups/Makefile
--- linux-3.9.4-vanilla/Makefile	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/Makefile	2014-05-07 13:43:09.970338198 -0700
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 9
 SUBLEVEL = 4
-EXTRAVERSION =
+EXTRAVERSION = -hiccups
 NAME = Unicycling Gorilla
 
 # *DOCUMENTATION*
diff -uNr linux-3.9.4-vanilla/net/ipv4/ip_output.c linux-3.9.4-hiccups/net/ipv4/ip_output.c
--- linux-3.9.4-vanilla/net/ipv4/ip_output.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/ip_output.c	2014-05-07 13:43:09.971338198 -0700
@@ -80,6 +80,8 @@
 #include <linux/netlink.h>
 #include <linux/tcp.h>
 
+#include <net/tcp_hiccups.h>            /* RMC */
+
 int sysctl_ip_default_ttl __read_mostly = IPDEFTTL;
 EXPORT_SYMBOL(sysctl_ip_default_ttl);
 
@@ -158,6 +160,10 @@
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
 
+    /* RMC: Grab outgoing SYN-ACKs if we followed the right path in connreq */
+    if ((tcp_hdr(skb)->syn) && (tcp_hdr(skb)->ack) && (tcp_sk(sk)->hic_in_connreq))
+                tcp_hiccups_synack_out(sk, skb);
+
 	/* Send it out. */
 	return ip_local_out(skb);
 }
@@ -400,6 +406,11 @@
 	skb->priority = sk->sk_priority;
 	skb->mark = sk->sk_mark;
 
+    /* RMC: lots of stuff goes out through here, but at least the skb will be built by now */
+    /* Important: note that this skb is a clone! */
+    if ((tcp_hdr(skb)->syn) && (! tcp_hdr(skb)->ack) && (tcp_sk(sk)->hic_in_conn))
+        tcp_hiccups_syn_out(sk, skb);
+
 	res = ip_local_out(skb);
 	rcu_read_unlock();
 	return res;
diff -uNr linux-3.9.4-vanilla/net/ipv4/Makefile linux-3.9.4-hiccups/net/ipv4/Makefile
--- linux-3.9.4-vanilla/net/ipv4/Makefile	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/Makefile	2014-05-07 13:43:09.972338198 -0700
@@ -11,7 +11,7 @@
 	     datagram.o raw.o udp.o udplite.o \
 	     arp.o icmp.o devinet.o af_inet.o  igmp.o \
 	     fib_frontend.o fib_semantics.o fib_trie.o \
-	     inet_fragment.o ping.o
+	     inet_fragment.o ping.o tcp_hiccups.o
 
 obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o
 obj-$(CONFIG_PROC_FS) += proc.o
diff -uNr linux-3.9.4-vanilla/net/ipv4/sysctl_net_ipv4.c linux-3.9.4-hiccups/net/ipv4/sysctl_net_ipv4.c
--- linux-3.9.4-vanilla/net/ipv4/sysctl_net_ipv4.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/sysctl_net_ipv4.c	2014-05-07 13:43:09.972338198 -0700
@@ -25,6 +25,7 @@
 #include <net/inet_frag.h>
 #include <net/ping.h>
 #include <net/tcp_memcontrol.h>
+#include <net/tcp_hiccups.h>        /* RMC */
 
 static int zero;
 static int one = 1;
@@ -785,6 +786,27 @@
 		.proc_handler	= proc_dointvec_minmax,
 		.extra1		= &one
 	},
+    {
+        .procname   = "tcp_hiccups_loglevel",
+        .data       = &sysctl_tcp_hiccups_loglevel,
+        .maxlen     = sizeof(int),
+        .mode       = 0644,
+        .proc_handler   = proc_dointvec
+    },      /* RMC */
+    {
+        .procname   = "tcp_hiccups_appsalt",
+        .data       = &sysctl_tcp_hiccups_appsalt,
+        .maxlen     = sizeof(int),
+        .mode       = 0644,
+        .proc_handler   = proc_dointvec
+    },      /* RMC */
+    {
+        .procname   = "tcp_hiccups_experiments",
+        .data       = &sysctl_tcp_hiccups_experiments,
+        .maxlen     = sizeof(int),
+        .mode       = 0644,
+        .proc_handler   = proc_dointvec
+    },      /* RMC */
 	{ }
 };
 
diff -uNr linux-3.9.4-vanilla/net/ipv4/tcp.c linux-3.9.4-hiccups/net/ipv4/tcp.c
--- linux-3.9.4-vanilla/net/ipv4/tcp.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/tcp.c	2014-05-07 13:43:09.971338198 -0700
@@ -280,6 +280,8 @@
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
+#include <net/tcp_hiccups.h>            /* RMC */
+
 int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT;
 
 struct percpu_counter tcp_orphan_count;
@@ -1022,6 +1024,20 @@
 	return err;
 }
 
+/**
+ * RMC: If the user just does a sendto() without a connect and only uses
+ * the MSG_HICCUPS flag (i.e. no TFO), this makes sure there's a valid
+ * connection first.
+ */
+static int tcp_sendmsg_hiccups(struct sock *sk, struct msghdr *msg)
+{
+    int flags;
+
+    flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0;
+    return __inet_stream_connect(sk->sk_socket, msg->msg_name,
+                    msg->msg_namelen, flags);
+}
+
 int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 		size_t size)
 {
@@ -1036,6 +1052,14 @@
 	lock_sock(sk);
 
 	flags = msg->msg_flags;
+    /**
+     * RMC: Calculate AppSalt before the connection is started.
+     * We'll catch the SYN on its way out and XOR the hiccups_isn with it.
+     */
+    if (flags & MSG_HICCUPS) {
+        tp->hic_do_client_appsalt = 1;
+        tp->hic_appsalt = tcp_hiccups_outgoing_appsalt(sk, msg, size);
+    }
 	if (flags & MSG_FASTOPEN) {
 		err = tcp_sendmsg_fastopen(sk, msg, &copied_syn);
 		if (err == -EINPROGRESS && copied_syn > 0)
@@ -1044,6 +1068,13 @@
 			goto out_err;
 		offset = copied_syn;
 	}
+    else if (flags & MSG_HICCUPS) {
+        /* RMC: if we don't want to do TFO but we still want to do hiccups,
+         * do a plain connect before we send the msg */
+        err = tcp_sendmsg_hiccups(sk, msg);
+        if (err)
+            goto out_err;
+    }
 
 	timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
@@ -2291,6 +2322,7 @@
 	tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
 	tp->snd_cwnd_cnt = 0;
 	tp->window_clamp = 0;
+    tcp_hiccups_clear(sk);      /* RMC */
 	tcp_set_ca_state(sk, TCP_CA_Open);
 	tcp_clear_retrans(tp);
 	inet_csk_delack_init(sk);
@@ -2719,6 +2751,11 @@
 		else
 			tp->tsoffset = val - tcp_time_stamp;
 		break;
+    case TCP_HICCUPS_COVERAGE:
+        /* RMC: allows the user to set a field coverage selector for the hiccups probe */
+        if ((val >= 0) && (val < HNUMPROBES))
+            tp->hic_want_coverage = val;
+        break;
 	default:
 		err = -ENOPROTOOPT;
 		break;
@@ -2970,6 +3007,22 @@
 	case TCP_TIMESTAMP:
 		val = tcp_time_stamp + tp->tsoffset;
 		break;
+    case TCP_HICCUPS_STATUS:
+        /* RMC: returns results of last check */
+        val = tp->hic_status;
+        break;
+    case TCP_HICCUPS_SYN_MATCH:
+        /* RMC: returns match bits of last check */
+        val = tp->hic_syn_match;
+        break;
+    case TCP_HICCUPS_SYNACK_MATCH:
+        /* RMC: returns match bits of last check */
+        val = tp->hic_synack_match;
+        break;
+    case TCP_HICCUPS_COVERAGE:
+        /* RMC: returns the detected field coverage selector for the last hiccups check */
+        val = tp->hic_coverage;
+        break;
 	default:
 		return -ENOPROTOOPT;
 	}
diff -uNr linux-3.9.4-vanilla/net/ipv4/tcp_hiccups.c linux-3.9.4-hiccups/net/ipv4/tcp_hiccups.c
--- linux-3.9.4-vanilla/net/ipv4/tcp_hiccups.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-3.9.4-hiccups/net/ipv4/tcp_hiccups.c	2014-05-07 13:43:09.972338198 -0700
@@ -0,0 +1,1222 @@
+/**
+ * tcp_hiccups.c
+ * 
+ * This file contains functions used for HICCUPS (packet manipulation detection).
+ */
+
+#include <linux/inet.h>
+#include <linux/crc32.h>
+#include <linux/murmur3.h>
+#include <linux/random.h>
+#include <net/tcp.h>
+#include <net/tcp_hiccups.h>
+
+/****************************************************
+ * Section 1: Debugging functions
+ *
+ * These functions are mostly to pretty print the contents of the
+ * various structs used by the kernel TCP code
+ *
+ ****************************************************/
+
+/* Assumes that str points to a buffer of size 9 */
+static void byte_to_binary(__u8 byte, char *str)
+{
+	char *p;
+	__u8 z;
+	
+	p = str;
+	for (z = 128; z > 0; z >>= 1)
+		*p++ = (((byte & z) == z) ? '1' : '0');
+	*p = '\0';
+}
+
+static void ip_numtostr(unsigned int num, char *str)
+{
+	sprintf(str, "%u.%u.%u.%u", (num&0xFF000000)>>24, (num&0xFF0000)>>16, (num&0xFF00)>>8, num&0xFF);
+}
+
+/**
+ * Prints an IP header struct
+ * Note: an iphdr can be extracted from a sk_buff struct via ip_hdr(skb)
+ */
+void print_iphdr_struct(struct iphdr *iph)
+{
+	char ip_str[INET_ADDRSTRLEN];
+	char tos_str[9];
+
+	ip_numtostr(ntohl(iph->saddr), ip_str);
+	byte_to_binary(iph->tos, tos_str);
+
+	printk("\t--------------- IP header (struct iphdr) -----------------\n");
+    printk("\t| version=%u   ihl=%u   tos=0b %s   tot_len=%hu\n",
+	iph->version, iph->ihl, tos_str, ntohs(iph->tot_len));
+    printk("\t| id=%hu (0x%hx)   flags=", ntohs(iph->id), ntohs(iph->id));
+	
+	if (ntohs(iph->frag_off) & IP_CE) printk(" rsvd ");
+	if (ntohs(iph->frag_off) & IP_DF) printk(" DF ");
+	if (ntohs(iph->frag_off) & IP_MF) printk(" MF ");
+	
+	printk("   frag_off=%hu\n", (ntohs(iph->frag_off) & IP_OFFSET));
+	printk("\t| ttl=%hhu   protocol=%hhu   check=0x%x\n",
+    iph->ttl, iph->protocol, ntohs(iph->check));
+    printk("\t| saddr=%s ", ip_str);
+	ip_numtostr(ntohl(iph->daddr), ip_str);
+	printk("   daddr=%s\n", ip_str);
+}
+EXPORT_SYMBOL(print_iphdr_struct);
+
+/**
+ * Prints a TCP header struct
+ * Note: a tcphdr can be extracted from a sk_buff struct via tcp_hdr(skb)
+ */
+void print_tcphdr_struct(struct tcphdr *th)
+{
+	printk("\t-------------- TCP header (struct tcphdr) ----------------\n");
+	printk("\t| source=%hu     dest=%hu\n", ntohs(th->source), ntohs(th->dest));
+	printk("\t| seq=%u (0x%x)     ack_seq=%u (0x%x)\n", 
+    ntohl(th->seq), ntohl(th->seq), ntohl(th->ack_seq), ntohl(th->ack_seq));
+	printk("\t| doff=%u   res1=%u     flags=", th->doff, th->res1);
+	if (th->cwr) printk(" cwr ");
+	if (th->ece) printk(" ece ");
+	if (th->urg) printk(" urg ");
+	if (th->ack) printk(" ack ");
+	if (th->psh) printk(" psh ");
+	if (th->rst) printk(" rst ");
+	if (th->syn) printk(" syn ");
+	if (th->fin) printk(" fin ");
+	printk("\n");
+	printk("\t| window=%hu   check=0x%x   urg_ptr=%hu\n",
+	ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr));
+}
+EXPORT_SYMBOL(print_tcphdr_struct);
+
+/**
+ * Prints useful fields from a TCP SKB control block
+ */
+void print_tcp_skb_cb_struct(struct tcp_skb_cb *tcb)
+{
+	printk("\t------- TCP SKB control block (struct tcp_skb_cb) --------\n");
+	printk("\t| seq=%u, end_seq=%u, when=%u, ack_seq=%u\n",
+    tcb->seq, tcb->end_seq, tcb->when, tcb->ack_seq);
+}
+EXPORT_SYMBOL(print_tcp_skb_cb_struct);
+
+/**
+ * Prints a socket buffer struct
+ * 
+ * An skb is essentially a packet.  It holds everything from the packet's data
+ * to its data link, network, and transport headers to private socket variables
+ * in a space called the control block.  Be weary that skb's are usually cloned
+ * before they are given to tcp_transmit_skb() which builds the headers and
+ * sends them down the stack.  An skb and its clone share the same data area
+ * (which includes protocol headers but not stuff in the head and tail rooms).
+ *
+ * For more, see:
+ * - http://vger.kernel.org/~davem/skb.html
+ * - http://vger.kernel.org/~davem/skb_data.html
+ */
+void print_sk_buff_struct(struct sk_buff *skb)
+{
+	unsigned char *iphdr, *tcphdr, *datahdr;
+    int iphdr_len, tcphdr_len, data_len;
+
+    iphdr = skb_network_header(skb);
+    iphdr_len = skb_network_header_len(skb);
+    tcphdr = skb_transport_header(skb);
+    tcphdr_len = tcp_hdrlen(skb);
+    datahdr = tcphdr + tcphdr_len;
+    data_len = ((int) (skb_tail_pointer(skb) - tcphdr)) - tcphdr_len;
+
+	print_iphdr_struct(ip_hdr(skb));
+	printk("\t| IP header bytes:\t");
+    print_hex(iphdr, iphdr_len, 10, 4);
+
+	print_tcphdr_struct(tcp_hdr(skb));
+	printk("\t| TCP header bytes:\t");
+    print_hex(tcphdr, tcphdr_len, 10, 4);
+
+    /* the ipv4 part of the cb (inet_skb_parm) isn't really interesting to us */
+    print_tcp_skb_cb_struct(TCP_SKB_CB(skb));
+	
+	printk("\t------------ Other pointers from the sk_buff -------------\n");
+    printk("\t| skb            = 0x%lx\n", (unsigned long) skb);
+    printk("\t| skb->head      = 0x%lx\n", (unsigned long) skb->head);
+    printk("\t| skb->datalink  = 0x%lx\n", (unsigned long) skb_mac_header(skb));
+    printk("\t| skb->network   = 0x%lx\n", (unsigned long) skb_network_header(skb));
+    printk("\t| skb->transport = 0x%lx\n", (unsigned long) skb_transport_header(skb));
+    printk("\t| skb->data      = 0x%lx\n", (unsigned long) skb->data);
+    printk("\t| skb->tail      = 0x%lx\n", (unsigned long) skb_tail_pointer(skb));
+    printk("\t| skb->end       = 0x%lx\n", (unsigned long) skb->end);
+}
+EXPORT_SYMBOL(print_sk_buff_struct);
+
+/**
+ * Prints an IPv4 sock struct
+ */
+void print_inet_sock_struct(struct inet_sock *inet)
+{
+	printk("\t------------- INET Socket (struct inet_sock) -------------\n");
+	printk("\t| inet_id=%u (0x%x)\n", inet->inet_id, inet->inet_id);
+}
+EXPORT_SYMBOL(print_inet_sock_struct);
+
+/**
+ * Prints a TCP sock struct
+ * Note: a tcp_sock can be extracted from a sock struct via tcp_sk(sk)
+ */
+void print_tcp_sock_struct(struct tcp_sock *tp)
+{
+	printk("\t------------- TCP Socket (struct tcp_sock) ---------------\n");
+
+	printk("\t| tcp_header_len=%hu   xmit_size_goal_segs=%hu   pred_flags=%u\n",
+	tp->tcp_header_len, tp->xmit_size_goal_segs, tp->pred_flags);
+    printk("\t| rcv_nxt=%u   copied_seq=%u   rcv_wup=%u   snd_nxt=%u\n",
+	tp->rcv_nxt, tp->copied_seq, tp->rcv_wup, tp->snd_nxt);
+    printk("\t| snd_una=%u   snd_sml=%u   rcv_tstamp=%u   lsndtime=%u\n",
+	tp->snd_una, tp->snd_sml, tp->rcv_tstamp, tp->lsndtime);
+
+	printk("\t| snd_wl1=%u   snd_wnd=%u   max_window=%u   mss_cache=%u\n",
+	tp->snd_wl1, tp->snd_wnd, tp->max_window, tp->mss_cache);
+	printk("\t| window_clamp=%u   rcv_ssthresh=%u   frto_highmark=%u   advmss=%hu\n",
+	tp->window_clamp, tp->rcv_ssthresh, tp->frto_highmark, tp->advmss);
+	
+	printk("\t| packets_out=%u   retrans_out=%u   urg_data=%hu\n",
+	tp->packets_out, tp->retrans_out, tp->urg_data);
+	printk("\t| ecn_flags=%hhu   reordering=%hhu   snd_up=%u   keepalive_probes=%hhu\n",
+	tp->ecn_flags, tp->reordering, tp->snd_up, tp->keepalive_probes);
+
+	printk("\t| rcv_wnd=%u   write_seq=%u   pushed_seq=%u   lost_out=%u\n",
+	tp->rcv_wnd, tp->write_seq, tp->pushed_seq, tp->lost_out);
+	printk("\t| sacked_out=%u   fackets_out=%u   tso_deferred=%u\n",
+	tp->sacked_out, tp->fackets_out, tp->tso_deferred);
+
+    /* bytes_acked was removed in v3.9 along with Approp. Byte Counting */
+
+    printk("\t| retransmit_high=%u   lost_retrans_low=%u   high_seq=%u   urg_seq=%u\n",
+	tp->retransmit_high, tp->lost_retrans_low, tp->high_seq, tp->urg_seq);
+
+	printk("\t| --> hic_status = %d\n", tp->hic_status);
+    /* TODO: add others */
+}
+EXPORT_SYMBOL(print_tcp_sock_struct);
+
+/**
+ * Prints an entire sock struct
+ */
+void print_sock_struct(struct sock *sk)
+{
+	print_inet_sock_struct(inet_sk(sk));
+	print_tcp_sock_struct(tcp_sk(sk));
+}
+EXPORT_SYMBOL(print_sock_struct);
+
+/**
+ * Prints useful fields from an IPv4 request socket
+ */
+void print_inet_request_sock_struct(struct inet_request_sock *ireq)
+{
+	/* Nothing useful found yet */
+}
+EXPORT_SYMBOL(print_inet_request_sock_struct);
+
+/**
+ * Prints useful fields from a TCP request socket (a mini socket)
+ */
+void print_tcp_request_sock_struct(struct tcp_request_sock *treq)
+{
+	printk("\t------ TCP Request Socket (struct tcp_request_sock) ------\n");
+	printk("\t| rcv_isn=%u   snt_isn=%u   rcv_nxt=%u\n",
+    treq->rcv_isn, treq->snt_isn, treq->rcv_nxt);
+}
+EXPORT_SYMBOL(print_tcp_request_sock_struct);
+
+/**
+ * Prints a request sock (used by the kernel to represent a connection request)
+ */
+void print_request_sock_struct(struct request_sock *req)
+{
+    print_inet_request_sock_struct(inet_rsk(req));
+    print_tcp_request_sock_struct(tcp_rsk(req));
+}
+EXPORT_SYMBOL(print_request_sock_struct);
+
+/**
+ * Returns the name of each coverage type
+ */
+static char *get_cvr_name(int cvr)
+{
+    char *cvr_name[] = { "HNONAT", "HFULL", "HNAT", "HNOOPT", "HONLYOPT",
+        "HECNIP", "HECNTCP", "HLEN", "HMSS", "HWINSCL", "HTSTAMP", "HMPTCP", 
+        "HEXOPT", "HFLAGS", "HSAFE", "HNULL"};
+
+    if ((cvr >= 0) && (cvr < HNUMPROBES))
+        return cvr_name[cvr];
+    if (cvr == HONEWAY)
+        return "HONEWAY";
+    return "?UNK?";
+}
+
+/**
+ * Prints the specified data range out to hex chars
+ */
+void print_hex(void const *start, size_t len, int brk, int tabs)
+{
+    unsigned char const *s = (unsigned char *) start;
+    size_t i;
+    int j;
+
+    for (i = 0; i < len; i++) {
+        if ( (i > 0) && (i % brk == 0) ) {
+            printk("\n");
+            for (j=0;j<tabs;j++) printk("\t");
+        }
+        printk("%02X ", s[i]);
+    }
+    printk("\n");
+}
+EXPORT_SYMBOL(print_hex);
+
+
+/***********************************************************
+ * Section 2: HICCUPS helper functions
+ *
+ * These functions handle various HICCUPS tasks
+ *
+ ***********************************************************/
+
+/**
+ * Populates an hb with a specific TCP option.
+ * @return Length of hb to end of options
+ */
+static int populate_hb_tcpopt(struct sk_buff *skb, struct hiccups_bits *hb, u8 kind)
+{
+    unsigned char *dest, *byte;
+    int full_len, opt_len, copied, pos;
+
+    copied = pos = 0;
+    dest = (unsigned char *) &(hb->options);
+    byte = skb_transport_header(skb) + 20;
+    full_len = tcp_optlen(skb);
+    
+    /* scan the TCP options and copy any with the specified kind byte */
+    while (pos < full_len) {
+        if (*byte == 0) break;
+        opt_len = *(byte + 1);
+        if (*byte != kind) {
+            if (*byte == 1) opt_len = 1;
+            pos += opt_len;
+            byte += opt_len;
+            continue;
+        }
+        memcpy(dest, byte, opt_len);
+        pos += opt_len;
+        copied += opt_len;
+        byte += opt_len;
+        dest += opt_len;
+    }
+        
+    return (sizeof (*hb) - sizeof (hb->options)) + copied;
+}
+
+/**
+ * Copies IP and TCP options to an hb.
+ * @return Length of hb to end of options
+ */
+static int populate_hb_options(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+    unsigned char *dest, *ip_options_start, *tcp_options_start;
+    int ip_options_len, tcp_options_len;    /* in octets */
+
+    /* locate the IP and TCP options */
+    dest = (unsigned char *) &(hb->options);
+    ip_options_start  = skb_network_header(skb) + 20;
+    ip_options_len    = skb_transport_header(skb) - ip_options_start;
+    tcp_options_start = skb_transport_header(skb) + 20;
+    tcp_options_len   = tcp_optlen(skb);
+
+    /* load IP and TCP options into hiccups_bits struct */
+    memcpy(dest, ip_options_start, ip_options_len);
+    memcpy(dest + ip_options_len, tcp_options_start, tcp_options_len);
+
+    /* calculate hiccups_bits length to end of options */
+    return (sizeof (*hb) - sizeof (hb->options)) + ip_options_len + tcp_options_len;
+}
+
+/**
+ * Populate IP addresses and TCP ports into an hb.
+ */
+static void populate_hb_addrport(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+    /* all fields in hb are in network order */
+    hb->saddr = iph->saddr;
+    hb->daddr = iph->daddr;
+    hb->sport = th->source;
+    hb->dport = th->dest;
+}
+
+/**
+ * Populate length-related fields into an hb.
+ */
+static void populate_hb_len(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+	hb->ihl = iph->ihl;
+	hb->doff = th->doff;
+
+    /* On outgoing packets, the iph->tot_len won't be set so we have to use skb->len 
+     * instead.  It doesn't get set until the first line of ip_local_out().
+	 */
+	if (! iph->tot_len)
+		hb->tot_len = htons(skb->len);
+	else
+		hb->tot_len = iph->tot_len;
+}
+
+/**
+ * Populate "safe" fields into an hb.
+ * These fields should be less likely to encounter changes.
+ */
+static void populate_hb_safe(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+	hb->version = iph->version;
+    hb->frag_off |= ntohs(IP_CE) & iph->frag_off; /* reserved bit */
+	hb->protocol = iph->protocol;
+    hb->res1 |= 0xE & th->res1; /* everything except nonce-sum */
+	hb->urg_ptr = th->urg_ptr;
+}
+
+/**
+ * Populate IP header ECN bits into an hb.
+ */
+static void populate_hb_ecnip(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+
+    /* only keep the OR of the 2 ECN bits */	
+	hb->ecn = iph->tos & 3;
+	hb->ecn = ((hb->ecn & 2)>1) | (hb->ecn & 1);
+}
+
+/**
+ * Populate TCP header ECN bits into an hb.
+ */
+static void populate_hb_ecntcp(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct tcphdr *th = tcp_hdr(skb);
+
+    hb->res1 |= 0x1 & th->res1; /* nonce-sum bit */
+	hb->ece = th->ece;
+	hb->cwr = th->cwr;
+}
+
+/**
+ * Populates flags into an hb.
+ */
+static void populate_hb_flags(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+	struct iphdr *iph = ip_hdr(skb);
+	struct tcphdr *th = tcp_hdr(skb);
+
+    hb->frag_off |= ntohs(IP_DF) & iph->frag_off;
+	hb->fin = th->fin;
+	hb->syn = th->syn;
+	hb->rst = th->rst;
+	hb->psh = th->psh;
+	hb->ack = th->ack;
+	hb->urg = th->urg;
+}
+
+/**
+ * Populates all of the fixed-length (non-options) header fields into an hb.
+ */
+static void populate_hb_nonat_fixed(struct sk_buff *skb, struct hiccups_bits *hb)
+{
+    populate_hb_safe(skb, hb);
+    populate_hb_len(skb, hb);
+    populate_hb_ecnip(skb, hb);
+    populate_hb_ecntcp(skb, hb);
+    populate_hb_flags(skb, hb);
+}
+
+/**
+ * Populates an hb for convenient hashing.
+ * @return Length of hb to end of options
+ */
+static int populate_hb(struct sk_buff *skb, struct hiccups_bits *hb, u8 cvr)
+{
+    int len = sizeof (*hb) - sizeof (hb->options);   /* length of hb without any options */
+
+    /* different things get populated depending on specified field coverage */
+    switch (cvr) {
+    case HFULL:
+        populate_hb_addrport(skb, hb);
+        populate_hb_nonat_fixed(skb, hb);
+        len = populate_hb_options(skb, hb);
+        break;
+    case HNAT:
+        populate_hb_addrport(skb, hb);
+        break;
+    case HNOOPT:
+        populate_hb_nonat_fixed(skb, hb);
+        break;
+    case HONLYOPT:
+        len = populate_hb_options(skb, hb);
+        break;
+    case HECNIP:
+        populate_hb_ecnip(skb, hb);
+        break;
+    case HECNTCP:
+        populate_hb_ecntcp(skb, hb);
+        break;
+    case HLEN:
+        populate_hb_len(skb, hb);
+        break;
+    case HMSS:
+        len = populate_hb_tcpopt(skb, hb, 2);
+        break;
+    case HWINSCL:
+        len = populate_hb_tcpopt(skb, hb, 3);
+        break;
+    case HTSTAMP:
+        len = populate_hb_tcpopt(skb, hb, 8);
+        break;
+    case HMPTCP:
+        len = populate_hb_tcpopt(skb, hb, 30);
+        break;
+    case HEXOPT:
+        len = populate_hb_tcpopt(skb, hb, 99);
+        break;
+    case HFLAGS:
+        populate_hb_flags(skb, hb);
+        len = populate_hb_tcpopt(skb, hb, 4);
+        break;
+    case HSAFE:
+        populate_hb_safe(skb, hb);
+        break;
+    case HNULL:
+    case HONEWAY:
+        break;
+    case HNONAT:
+    default:
+        populate_hb_nonat_fixed(skb, hb);
+        len = populate_hb_options(skb, hb);
+        break;
+    }
+
+    hb->coverage = cvr;
+    /* hb->salt = ntohs(iph->id); */  /* doesn't really matter if we do this now */
+
+    /* return the length of the fixed fields plus the options (if) we copied */
+    return len;
+}
+
+/**
+ * Hashes selected fields from a packet's headers.
+ */
+static void __hiccups_hash(struct sk_buff *skb, u8 cvr, struct hiccups_hashes *hash, int log_level)
+{
+    struct hiccups_bits hb;
+    int hb_len;
+
+    memset(&hb, 0, sizeof (hb));
+    hb_len = populate_hb(skb, &hb, cvr);
+
+    hash->crc = crc32(0, &hb, hb_len);
+    hash->murmur = murmur3(0, &hb, hb_len);
+
+    h_print(log_level,"hiccups_bits [ cvr = %d / hb_len = %d ]\n", cvr, hb_len);
+	h_call(log_level, print_hex(&hb, hb_len, 4, 0));
+    h_print(log_level, "\n");
+    h_print(log_level,"hashing result: crc32 = 0x%x / murmur3 = 0x%x\n", hash->crc, hash->murmur);
+}
+
+static void hiccups_hash(struct sk_buff *skb, u8 cvr, struct hiccups_hashes *hash)
+{
+    __hiccups_hash(skb, cvr, hash, LOG_LOW);
+}
+
+/**
+ * Determines the appropriate value for each integrity transmission field.
+ */
+static void fill_hash_pieces(struct hiccups_hashes *hash, u8 cvr, struct hash_pieces *hp)
+{
+    u16 shifted_cvr = cvr << 12;
+
+    hp->isn_upper = shifted_cvr | (hash->crc & 0x00000FFF);
+    hp->ipid      = shifted_cvr | (hash->murmur & 0x00000FFF);
+    hp->rcvwin    = shifted_cvr | ((hash->murmur & 0xFFF00000) >> 20);
+}
+
+/**
+ * Adds randomness to the ISN to prevent easy spoofing.
+ */
+static void protect_isn(struct hash_pieces *hp)
+{
+	get_random_bytes(&(hp->salt), sizeof (hp->salt));
+    hp->isn = ((hp->salt ^ hp->isn_upper) << 16) | hp->salt;
+}
+
+static int uniq_add(int *arr, int len, int val)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        if (val == arr[i])
+            return len;
+    }
+    arr[len] = val;
+    return len + 1;
+}
+
+/**
+ * Set the order of the coverage checks, trying the ones given to us first
+ */
+static int set_smart_cvr_order(struct hash_pieces *hp, int *cvr)
+{
+    int i, ret, cvr_len = 0;
+
+    /* add the 3 cvrs in the hash pieces first */
+    cvr_len = uniq_add(cvr, cvr_len, hp->isn_upper >> 12);
+    cvr_len = uniq_add(cvr, cvr_len, hp->ipid >> 12);
+    cvr_len = uniq_add(cvr, cvr_len, hp->rcvwin >> 12);
+    ret = cvr_len;
+
+    /* then snatch the rest of them */
+    for (i = 0; i < HNUMPROBES; i++)
+        cvr_len = uniq_add(cvr, cvr_len, i);
+    return ret;
+}
+
+/**
+ * Returns 1 if a majority of the bits are 1
+ */
+static int majority_exists(u8 a)
+{
+    if ((a == 0x3) || (a == 0x5) || (a == 0x6) || (a == 0x7))
+        return 1;
+    else
+        return 0;
+}
+
+/**
+ * Compares two sets of hashes, returning a binary code of how many matched
+ */
+static u8 compare_hashes(struct hash_pieces *h1, struct hash_pieces *h2)
+{
+    u8 match = 0;
+    if ((h1->isn_upper & 0x0FFF) == (h2->isn_upper & 0x0FFF))
+        match |= 0x4;
+    if ((h1->ipid & 0x0FFF) == (h2->ipid & 0x0FFF))
+        match |= 0x2;
+    if ((h1->rcvwin & 0x0FFF) == (h2->rcvwin & 0x0FFF))
+        match |= 0x1;
+    return match;
+}
+
+/**
+ * Checks all possibile coverage values to see if we can find a match
+ */
+static u8 find_hic_coverage(struct sock *sk, struct sk_buff *skb, struct hash_pieces *hp_rcvd)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+    struct hiccups_hashes hash;
+    struct hash_pieces hp_calc;
+    int i, end_rcv_cvrs, cvr[HNUMPROBES];
+    u8 want_cvr, s_want_cvr = 0;
+    u8 match, s_match = 0;
+    u8 isn_cvr          = hp_rcvd->isn_upper >> 12;
+    u8 ipid_cvr         = hp_rcvd->ipid >> 12;
+    u8 rcvwin_cvr       = hp_rcvd->rcvwin >> 12;
+
+    end_rcv_cvrs = set_smart_cvr_order(hp_rcvd, cvr);
+
+    for (i = 0; i < HNUMPROBES; i++) {
+        __hiccups_hash(skb, cvr[i], &hash, LOG_HIGH);
+
+        /* we have to save all the candidates if we have to do delayed checks */
+        if (sysctl_tcp_hiccups_appsalt) {
+            tp->hic_as_candidate[cvr[i]].crc = hash.crc;
+            tp->hic_as_candidate[cvr[i]].murmur = hash.murmur;
+        }
+        if (i >= end_rcv_cvrs) continue;
+        /* if still going, we're checking a cvr we received */
+
+        fill_hash_pieces(&hash, cvr[i], &hp_calc);
+        match = compare_hashes(hp_rcvd, &hp_calc);
+        want_cvr = 0;
+        if (match & 0x04) want_cvr = isn_cvr;
+        if (match & 0x01) want_cvr = rcvwin_cvr;
+        if (match & 0x02) want_cvr = ipid_cvr;
+
+        /* only say we found the cvr used for the SYN hashes if at least 2 of 3 match */
+        if (majority_exists(match)) {
+            tp->hic_syn_match = match;
+            tp->hic_want_coverage = want_cvr;
+            return cvr[i];
+        }
+        if (match > 0) {
+            s_match = match;
+            s_want_cvr = want_cvr;
+        }
+    }
+    /* if no single hash matched for any of the checks, do majority 
+     * rules to try to infer what coverage they wanted */
+    if (s_match == 0) {
+        if (isn_cvr == ipid_cvr) s_want_cvr = isn_cvr;
+        else if (isn_cvr == rcvwin_cvr) s_want_cvr = isn_cvr;
+        else if (ipid_cvr == rcvwin_cvr) s_want_cvr = ipid_cvr;
+        else s_want_cvr = HONEWAY; /* if no majority, send back HONEWAY */
+    }
+    tp->hic_syn_match = s_match;
+    tp->hic_want_coverage = s_want_cvr;
+    return HONEWAY; /* there wasn't a match */
+}
+
+/**
+ * Determines most reasonable set of syn_match bits.
+ * Takes as input the match bits and hashes from the SYN-ACK.
+ */
+static u8 get_syn_match(u8 sa_match, struct hash_pieces *hp)
+{
+    u8 isn_syn_match = 0xDD;
+    u8 ipid_syn_match = 0xEE;
+    u8 rcvwin_syn_match = 0xFF;
+
+    /* In searching for a majority, we only consider syn_match candidates from
+     * integrity transmission fields marked in the SYN-ACK's match bits
+     * -AND- have a 1 in the highest bit of the syn_match.
+     */
+    if ((sa_match & 0x4) && (hp->isn_upper & 0x8000))   /* isn was marked */
+        isn_syn_match = (hp->isn_upper >> 12) & 0x7;
+    if ((sa_match & 0x2) && (hp->ipid & 0x8000))        /* ipid */
+        ipid_syn_match = (hp->ipid >> 12) & 0x7;
+    if ((sa_match & 0x1) && (hp->rcvwin & 0x8000))      /* rcvwin */
+        rcvwin_syn_match = (hp->rcvwin >> 12) & 0x7;
+
+    /* now see if there's a majority amongst the valid candidates */
+    if (isn_syn_match == ipid_syn_match) return isn_syn_match;
+    if (isn_syn_match == rcvwin_syn_match) return isn_syn_match;
+    if (ipid_syn_match == rcvwin_syn_match) return ipid_syn_match;
+    /* else */
+    return 0;
+}
+
+/**
+ * Encodes a 32-bit integrity value with the AppSalt
+ */
+static void hiccups_encode_appsalt(struct hiccups_hashes *hash, u32 as, int print)
+{
+    u32 crc = hash->crc;
+    u32 murmur = hash->murmur;
+
+    if (print) h_print(LOG_LOW, "A *** Encoding APPSALT 0x%x:\n", as);
+    if (print) h_print(LOG_LOW, "A *** | In:  crc = 0x%x  /  murmur = 0x%x\n", hash->crc, hash->murmur);
+    hash->crc = crc32(as, &crc, sizeof (crc));
+    hash->murmur = crc32(as, &murmur, sizeof (murmur));
+    if (print) h_print(LOG_LOW, "A *** | Out: crc = 0x%x  /  murmur = 0x%x\n", hash->crc, hash->murmur);
+}
+
+/**
+ * Now that we know the AppSalt, go back and encode each candidate to check
+ */
+static u8 find_as_coverage(struct sock *sk, u32 as_hash)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+    struct hiccups_hashes hash;
+    struct hash_pieces hp_rcvd, hp_calc;
+    u8 match, cvr = 0;
+
+    /* restore these from saved values */
+    hp_rcvd.isn_upper = tp->hic_as_hash.isn_upper;
+    hp_rcvd.ipid = tp->hic_as_hash.ipid;
+    hp_rcvd.rcvwin = tp->hic_as_hash.rcvwin;
+
+    /* encode each saved hash and check against the saved values */
+    for (;cvr < HNUMPROBES; cvr++) {
+        hash.crc = tp->hic_as_candidate[cvr].crc;
+        hash.murmur = tp->hic_as_candidate[cvr].murmur;
+        hiccups_encode_appsalt(&hash, as_hash, 0);
+
+        fill_hash_pieces(&hash, cvr, &hp_calc);
+        match = compare_hashes(&hp_rcvd, &hp_calc);
+        if (majority_exists(match))
+            return cvr;
+    }
+    return HONEWAY; /* there wasn't a match */
+}
+
+/**
+ * Calculates the AppSalt, a 32-bit representation of the application data
+ */
+static u32 hiccups_calc_appsalt(const unsigned char *ad, size_t len)
+{
+    size_t ad_len = min_t(size_t, len, 40);     /* use at most first 40 bytes */
+
+    h_print(LOG_HIGH, "\tApp Data range:\t");
+    h_call(LOG_HIGH, print_hex(ad, ad_len, 10, 3));
+
+    return crc32(0, ad, ad_len);
+}
+
+static void print_as_candidates(struct sock *sk, u32 as, int v)
+{
+    struct tcp_sock *tp = tcp_sk(sk);
+    struct hiccups_hashes h;
+    int cvr = 0;
+
+    for (; cvr < HNUMPROBES; cvr++) {
+        h.crc = tp->hic_as_candidate[cvr].crc;
+        h.murmur = tp->hic_as_candidate[cvr].murmur;
+        if (as) hiccups_encode_appsalt(&h, as, 0);
+        h_print(v, " B *** %8s = crc:0x%08x / murmur:0x%08x\n", get_cvr_name(cvr), h.crc, h.murmur);
+    }
+}
+
+static void clear_as_candidates(struct sock *sk)
+{
+    struct tcp_sock *tp = tcp_sk(sk);
+    int i;
+
+    for (i = 0; i < HNUMPROBES; i++) {
+        tp->hic_as_candidate[i].crc = 0;
+        tp->hic_as_candidate[i].murmur = 0;
+    }
+}
+
+/***********************************************************
+ * Section 3: HICCUPS hooks functions
+ *
+ * These functions provide the necessary hooks
+ * to compute and check hash values
+ *
+ ***********************************************************/
+
+/**
+ * Calculates the HICCUPS hash to load into the sequence number
+ * and the IPID salt value for an outgoing SYN packet
+ *
+ * Hooked: ip_queue_xmit() in ip_output.c after headers are built but right before
+ * sending the SYN skb to ip_local_out()
+ */
+void tcp_hiccups_syn_out(struct sock *sk, struct sk_buff *skb)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct tcp_sock *tp    = tcp_sk(sk);
+	struct iphdr *iph      = ip_hdr(skb);
+	struct tcphdr *th      = tcp_hdr(skb);
+    struct hiccups_hashes hash;
+    struct hash_pieces hp;
+    u8 cvr = tp->hic_want_coverage;
+
+	h_print(LOG_LOW, "\n A >>> Sending out SYN >>> ======================================\n");
+    h_call(LOG_HIGH, print_sk_buff_struct(skb));
+    h_call(LOG_HIGH, print_sock_struct(sk));
+    h_print(LOG_HIGH, "(the print outs above are from before any changes are made)\n");
+    h_print(LOG_LOW, " A *** Calculating hash using cvr=%d (%s)\n", cvr, get_cvr_name(cvr));
+
+    iph->tot_len = 0;   /* needed because sometimes the field is dirty */
+    hiccups_hash(skb, cvr, &hash);
+
+    /* if the user used sendmsg() with the MSG_HICCUPS flag, encode the hash with the appsalt */
+    if (tp->hic_do_client_appsalt) {
+        hiccups_encode_appsalt(&hash, tp->hic_appsalt, 1);
+        tp->hic_do_client_appsalt = 0;
+    }
+
+    fill_hash_pieces(&hash, cvr, &hp);
+    protect_isn(&hp);
+	h_print(LOG_LOW, " A *** isn = 0x%x, salt = 0x%hx\n", hp.isn, hp.salt);
+    h_print(LOG_LOW, " A *** isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n",
+        hp.isn_upper, hp.ipid, hp.rcvwin);
+    
+	/* Now modify the skb and sk structs... */
+
+	/* with the new ipid: */
+	iph->id = htons(hp.ipid);		/* affects outgoing packet */
+	hp.ipid++;
+	inet->inet_id = hp.ipid;		/* affects rest of connection */
+
+    /* with the new rcvwin: */
+    th->window = htons(hp.rcvwin); /* affects outgoing packet */
+
+	/* and the new isn: */
+	th->seq     = htonl(hp.isn);	/* affects outgoing packet */
+	tp->snd_nxt = hp.isn;          /* affects rest of connection ... */
+	tp->snd_una = hp.isn;          /*              |                 */
+	tp->snd_sml = hp.isn;          /*              V                 */
+	tp->snd_up  = hp.isn;
+	hp.isn++;
+	tp->write_seq = hp.isn;
+}
+EXPORT_SYMBOL(tcp_hiccups_syn_out);
+
+/**
+ * Since we were working with a clone of the SYN skb in tcp_hiccups_syn_out(),
+ * the original is still sitting back up the stack with all of the old sequence
+ * numbers in its control block.  This is bad if the SYN needs to be
+ * retransmitted or if any more sequence numbers are copied from the SYN skb
+ * instead of the socket's data structure.  This function takes care of that by
+ * adjusting the control block in the pre-cloning SYN skb to match the new
+ * values (which can be grabbed out of the sock struct).
+ *
+ * We don't fix any header fields because the pre-cloning skb is headerless.
+ * Headers are only built in tcp_transmit_skb() on the clone.
+ *
+ * Hooked: tcp_connect() in tcp_output.c immediately after call that sends SYN
+ */
+void tcp_hiccups_after_syn_out(struct sock *sk, struct sk_buff *skb)
+{
+	struct tcp_sock *tp    = tcp_sk(sk);
+	struct tcp_skb_cb *tcb = TCP_SKB_CB(skb);
+
+	tcb->seq      = tp->snd_nxt;
+	tcb->end_seq  = tp->write_seq;
+
+	h_print(LOG_HIGH, "After cleanup:\n");
+	h_call(LOG_HIGH, print_tcp_skb_cb_struct(tcb));
+
+}
+EXPORT_SYMBOL(tcp_hiccups_after_syn_out);
+
+/** 
+ * This function calculates the HICCUPS hash over values in the received SYN
+ * and determines if it matches the hash from the connection initiator.
+ *
+ * Hooked: tcp_v4_conn_request() in tcp_ipv4.c before SYN is processed
+ */
+void tcp_hiccups_syn_in(struct sock *sk, struct sk_buff *skb)
+{
+    struct tcp_sock *tp = tcp_sk(sk);
+	struct iphdr *iph   = ip_hdr(skb);
+	struct tcphdr *th   = tcp_hdr(skb);
+    struct hash_pieces hp_rcvd;
+    u8 cvr;
+
+    /* break apart the SYN we just received */
+    hp_rcvd.isn       = ntohl(th->seq);
+    hp_rcvd.salt      = hp_rcvd.isn & 0x0000FFFF;
+    hp_rcvd.isn_upper = (hp_rcvd.isn >> 16) ^ hp_rcvd.salt;
+    hp_rcvd.ipid      = ntohs(iph->id);
+    hp_rcvd.rcvwin    = ntohs(th->window);
+
+    /* print information about the packet */
+	h_print(LOG_LOW, "\n B >>> Received incoming SYN >>> =================================\n");
+    h_print(LOG_LOW, " B *** isn = 0x%x, salt = 0x%hx\n", hp_rcvd.isn, hp_rcvd.salt);
+    h_print(LOG_LOW, " B *** isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n", 
+        hp_rcvd.isn_upper, hp_rcvd.ipid, hp_rcvd.rcvwin);
+	h_call(LOG_HIGH, print_sk_buff_struct(skb));
+
+    cvr = find_hic_coverage(sk, skb, &hp_rcvd);
+    tp->hic_coverage = cvr;
+	
+	h_print(LOG_LOW, "\n B *** Checked hashes, result: -+- cvr=%d -+-  , want_cvr=%d, syn_match=%d\n",
+        cvr, tp->hic_want_coverage, tp->hic_syn_match);
+
+    if (sysctl_tcp_hiccups_appsalt) {
+        if (cvr < HNUMPROBES) {
+    		h_print(LOG_LOW, " B *** No AppSalt, but plain hashes matched.\n");
+            h_print(LOG_LOW, " B *** Setting status 2, coverage %s (%d).\n", get_cvr_name(cvr), cvr);
+            clear_as_candidates(sk);
+            tp->hic_awaiting_appsalt = 0;
+	    	tp->hic_status = 2;
+        }
+        else {
+            h_print(LOG_LOW, " B *** Saved pre-encoded hashes for delayed AppSalt checks...\n");
+            print_as_candidates(sk, 0, LOG_HIGH);
+            tp->hic_awaiting_appsalt = 1;
+            /* save these so we can decode them once we get the AppSalt */
+            tp->hic_as_hash.isn_upper = hp_rcvd.isn_upper;
+            tp->hic_as_hash.ipid = hp_rcvd.ipid;
+            tp->hic_as_hash.rcvwin = hp_rcvd.rcvwin;
+            /* leave status 0 to indicate we still haven't actually checked any hashes */
+        }
+    }
+    else {
+        if (cvr < HNUMPROBES) {
+    		h_print(LOG_LOW, " B *** Hashes matched.  Setting status 1, coverage %s (%d).\n",
+            get_cvr_name(cvr), cvr);
+	    	tp->hic_status = 1;
+    	}
+        else {
+    		h_print(LOG_LOW, " B *** Failed match.  Setting status 3.\n");
+	    	tp->hic_status = 3;
+    	}
+    }
+}
+EXPORT_SYMBOL(tcp_hiccups_syn_in);
+
+/**
+ * Calculates the HICCUPS hash to load into the sequence number
+ * and the IPID salt value for an outgoing SYNACK packet
+ *
+ * Hooked: ip_build_and_send_pkt() in ip_output.c after headers are built
+ */
+void tcp_hiccups_synack_out(struct sock *sk, struct sk_buff *skb)
+{
+	struct inet_sock *inet = inet_sk(sk);
+	struct tcp_sock *tp    = tcp_sk(sk);
+	struct iphdr *iph      = ip_hdr(skb);
+	struct tcphdr *th      = tcp_hdr(skb);
+    struct hiccups_hashes hash;
+    struct hash_pieces hp;
+    u8 cvr = tp->hic_want_coverage; /* cvr is what was requested on incoming SYN */
+
+	h_print(LOG_LOW, "\n B <<< Sending out SYN-ACK <<< ===================================\n");
+	h_call(LOG_HIGH, print_sk_buff_struct(skb));
+	/* "sk" is mostly empty here since request_socks are used instead to handle conn reqs */
+	h_call(LOG_HIGH, print_sock_struct(sk));
+    h_print(LOG_HIGH, "(the print outs above are from before any changes are made)\n");
+    h_print(LOG_LOW, " B *** Calculating new hash with want_cvr = %d (%s)\n", cvr, get_cvr_name(cvr));
+
+    iph->tot_len = 0;   /* needed because sometimes the field is dirty */
+	hiccups_hash(skb, cvr, &hash);
+    fill_hash_pieces(&hash, tp->hic_syn_match | 0x8, &hp);
+    protect_isn(&hp);
+	h_print(LOG_LOW, " A *** isn = 0x%x, salt = 0x%hx\n", hp.isn, hp.salt);
+    h_print(LOG_LOW, " A *** isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n",
+        hp.isn_upper, hp.ipid, hp.rcvwin);
+
+	/* now modify the skb and sk structs... */
+
+	/* with the new salt: */
+	iph->id = htons(hp.ipid);		/* affects outgoing packet */
+	hp.ipid++;
+	inet->inet_id = hp.ipid;		/* affects rest of connection */
+
+    /* with the new receive window: */
+    th->window  = htons(hp.rcvwin);    /* affects outgoing packet */
+
+	/* and the new isn: */
+	th->seq     = htonl(hp.isn);	/* affects outgoing packet */
+	tp->snd_nxt = hp.isn;		    /* not used by linux, but we use it in the "after" hook */
+	
+}
+EXPORT_SYMBOL(tcp_hiccups_synack_out);
+
+/**
+ * Adjusts some of the struct fields with the newly calculated seq. number (which is left for us in snd_nxt)
+ * Have to save some of our back-writes until after we come back out of layer 3
+ *
+ * Hooked: tcp_v4_conn_request() in tcp_ipv4.c immediately after non-TFO build-and-send for SYN-ACK
+ */
+void tcp_hiccups_after_synack_out(struct sock *sk, struct sk_buff *skb, struct request_sock *req)
+{
+	struct tcp_sock *tp           = tcp_sk(sk);
+	struct tcp_request_sock *treq = tcp_rsk(req);
+	struct tcp_skb_cb *tcb        = TCP_SKB_CB(skb);
+	u32 isn = tp->snd_nxt;
+
+	h_print(LOG_HIGH, "Before the AFTER hook:\n");
+	h_call(LOG_HIGH, print_tcp_skb_cb_struct(tcb));
+	h_call(LOG_HIGH, print_tcp_request_sock_struct(treq));
+
+	treq->snt_isn = isn;
+	tcb->seq      = isn;
+	tcb->end_seq  = isn + 1;
+
+	tp->snd_nxt = 0;		/* put snd_nxt back to how it was before we borrowed it */
+
+	h_print(LOG_HIGH, "After cleanup:\n");
+	h_call(LOG_HIGH, print_tcp_skb_cb_struct(tcb));
+	h_call(LOG_HIGH, print_tcp_request_sock_struct(treq));
+}
+EXPORT_SYMBOL(tcp_hiccups_after_synack_out);
+
+
+/** 
+ * This function calculates the HICCUPS hash over values in the received SYN-ACK
+ * and determines if it matches the hash from the receiver.
+ *
+ * Hooked: tcp_rcv_synsent_state_process() in tcp_input.c at the beginning of SYN-ACK processing
+ */
+void tcp_hiccups_synack_in(struct sock *sk, struct sk_buff *skb)
+{
+    struct tcp_sock *tp = tcp_sk(sk);
+	struct iphdr *iph   = ip_hdr(skb);
+	struct tcphdr *th   = tcp_hdr(skb);
+    struct hiccups_hashes hash;
+    struct hash_pieces hp_rcvd, hp_calc;
+    u8 syn_match, match, cvr;
+
+    /* break apart the SYN/ACK we just received */
+    hp_rcvd.isn       = ntohl(th->seq);
+    hp_rcvd.salt      = hp_rcvd.isn & 0x0000FFFF;
+    hp_rcvd.isn_upper = (hp_rcvd.isn >> 16) ^ hp_rcvd.salt;
+    hp_rcvd.ipid      = ntohs(iph->id);
+    hp_rcvd.rcvwin    = ntohs(th->window);
+
+    /* print information about the packet */
+	h_print(LOG_LOW, "\n A <<< Received incoming SYN-ACK <<< =============================\n");
+    h_print(LOG_LOW, " A *** isn = 0x%x, salt = 0x%hx\n", hp_rcvd.isn, hp_rcvd.salt);
+    h_print(LOG_LOW, " A *** isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n", 
+        hp_rcvd.isn_upper, hp_rcvd.ipid, hp_rcvd.rcvwin);
+	h_call(LOG_HIGH, print_sk_buff_struct(skb));
+
+    /* If the forward path was unmodified, then cvr will be the 
+     * same as was requested.  If the SYN was modified but the 
+     * hiccups transmission fields were left intact, then cvr
+     * will also be the same as requested.
+     */
+    cvr = tp->hic_want_coverage;
+    h_print(LOG_HIGH, "Testing coverage type %s (%d):\n", get_cvr_name(cvr), cvr);
+	__hiccups_hash(skb, tp->hic_want_coverage, &hash, LOG_HIGH);
+    fill_hash_pieces(&hash, tp->hic_want_coverage, &hp_calc);
+    match = compare_hashes(&hp_rcvd, &hp_calc);
+    h_print(LOG_HIGH, "From the calculated hash: (compared with received values above)\n");
+    h_print(LOG_HIGH, "isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n",
+        hp_calc.isn_upper, hp_calc.ipid, hp_calc.rcvwin);
+    if (majority_exists(match)) {       /* syn-ack integrity matched, check syn status */
+        syn_match = get_syn_match(match, &hp_rcvd);
+        h_print(LOG_HIGH, "Majority found.  Extracted SYN_Match value: %d\n", syn_match);
+        if (majority_exists(syn_match)) {
+		    h_print(LOG_LOW, " A *** Both paths matched.  Setting status %d.\n", BOTHMATCH);
+    		tp->hic_status = BOTHMATCH;
+        }
+        else {
+    		h_print(LOG_LOW, " A *** SYN-ACK matched but SYN did not.  Setting status %d.\n", SAMATCH);
+            tp->hic_status = SAMATCH;
+        }
+        tp->hic_coverage = cvr;
+        tp->hic_syn_match = syn_match;
+        tp->hic_synack_match = match;
+        return;
+    }
+    h_print(LOG_HIGH, "Didn't match at least 2 of the 3 (ISN, IPID, RWIN).  Checking HONEWAY...\n");
+
+    /* Or, if the SYN was completely trashed (meaning our hashes
+     * themselves were modified), then cvr will be HONEWAY.
+     */
+    h_print(LOG_HIGH, "Testing coverage type HONEWAY (%d):\n", HONEWAY);
+    __hiccups_hash(skb, HONEWAY, &hash, LOG_HIGH);
+    fill_hash_pieces(&hash, HONEWAY, &hp_calc);
+    match = compare_hashes(&hp_rcvd, &hp_calc);
+    h_print(LOG_HIGH, "From the calculated hash: (compared with received values above)\n");
+    h_print(LOG_HIGH, "isn_upper = 0x%hx, ipid = 0x%hx, rcvwin = 0x%hx\n",
+        hp_calc.isn_upper, hp_calc.ipid, hp_calc.rcvwin);
+    if (majority_exists(match)) {
+        /* syn-ack integrity matched, but syn was trashed */
+        syn_match = get_syn_match(match, &hp_rcvd);        
+        h_print(LOG_HIGH, "Majority found.  Extracted SYN_Match value: %d\n", syn_match);
+   		h_print(LOG_LOW, " A *** SYN-ACK passed but SYN trashed.  Setting status %d.\n", SANULLMATCH);
+        tp->hic_status = SANULLMATCH;
+        tp->hic_coverage = HONEWAY;
+        tp->hic_syn_match = syn_match;
+        tp->hic_synack_match = match;
+        return;
+    }
+    h_print(LOG_HIGH, "Didn't match at least 2 of the 3 (ISN, IPID, RWIN).  SYN-ACK integrity failed.\n");
+
+    /* Else, SYN-ACK integrity failed */
+    syn_match = get_syn_match(0x7, &hp_rcvd);
+    h_print(LOG_HIGH, "Did SYN match?  Extracted SYN_Match value: %d\n", syn_match);
+    if (majority_exists(syn_match)) {
+   		h_print(LOG_LOW, " A *** SYN-ACK failed but SYN passed.  Setting status %d.\n", SYNMATCH);
+        tp->hic_status = SYNMATCH;
+    }
+    else {
+		h_print(LOG_LOW, " A *** Both paths failed to match.  Setting status %d.\n", NONEMATCH);
+		tp->hic_status = NONEMATCH;
+	}
+    tp->hic_syn_match = syn_match;
+    tp->hic_synack_match = 0;
+}
+EXPORT_SYMBOL(tcp_hiccups_synack_in);
+
+/**
+ * Returns the AppSalt, a 32-bit hash of the application data, to be used for encoding
+ *
+ * Hooked: tcp_sendmsg() in tcp.c before it tries to start a connection
+ */
+u32 tcp_hiccups_outgoing_appsalt(struct sock *sk, struct msghdr *msg, size_t size)
+{
+    unsigned char *as = (unsigned char *) msg->msg_iov->iov_base;
+
+    h_print(LOG_LOW, "\n A *** Adding AppSalt to SYN using MSG_HICCUPS socket API =======\n");
+    h_print(LOG_HIGH, "msg->msg_iov = 0x%lx , #iovblks = %ld , size = %ld\n",
+    (unsigned long) msg->msg_iov, (long) msg->msg_iovlen, (long) size);
+    h_print(LOG_HIGH, "iov->iov_base = 0x%lx , iov->iov_len = %ld\n",
+    (unsigned long) msg->msg_iov->iov_base, (long) msg->msg_iov->iov_len);
+
+    return hiccups_calc_appsalt(as, size);
+}
+EXPORT_SYMBOL(tcp_hiccups_outgoing_appsalt);
+
+/**
+ * Checks to see if the AppSalt hashes matched.
+ * Should run for all incoming data packets.
+ *
+ * Hooked: tcp_data_queue() in tcp_input.c just before sk is notified data ready
+ *         ... and others!
+ */
+void tcp_hiccups_appsalt_post(struct sock *sk, struct sk_buff *skb)
+{
+    unsigned char *tcphdr, *data;
+    int tcphdr_len, data_len;
+    u32 as_hash;
+    u8 cvr;
+    struct tcp_sock *tp = tcp_sk(sk);
+
+    if (!sysctl_tcp_hiccups_appsalt) return;
+
+    if (tp->hic_awaiting_appsalt && skb->len) {
+        tcphdr      = skb_transport_header(skb);
+        tcphdr_len  = tcp_hdrlen(skb);
+        data        = tcphdr + tcphdr_len;
+        data_len    = ((int) (skb_tail_pointer(skb) - tcphdr)) - tcphdr_len;
+
+      	h_print(LOG_LOW, "\n B >>> Received some new application data >>> ====================\n");
+        h_call(LOG_HIGH, print_sk_buff_struct(skb));
+
+        as_hash = hiccups_calc_appsalt(data, data_len);
+        h_print(LOG_LOW, " B *** Recalculated AppSalt = 0x%x\n", as_hash);
+        h_print(LOG_LOW, " B *** Expected hash pieces: isn_upper=0x%x, ipid=0x%x, rcvwin=0x%x\n", 
+            tp->hic_as_hash.isn_upper, tp->hic_as_hash.ipid, tp->hic_as_hash.rcvwin);
+        h_print(LOG_LOW, " B *** Encoding each hash candidate with AppSalt:\n");
+        print_as_candidates(sk, as_hash, LOG_LOW);
+        cvr = find_as_coverage(sk, as_hash);
+
+        if (cvr != HONEWAY) {
+       		h_print(LOG_LOW, " B *** AppSalt hashes matched.  Setting status 1, coverage %s (%d).\n", get_cvr_name(cvr), cvr);
+        	tp->hic_status = 1;
+            tp->hic_coverage = cvr;
+        }
+        else {
+        	h_print(LOG_LOW, " B *** Failed match.  Setting status 3.\n");
+    	    tp->hic_status = 3;
+        }
+
+        clear_as_candidates(sk);
+        tp->hic_awaiting_appsalt = 0;
+    }
+}
+EXPORT_SYMBOL(tcp_hiccups_appsalt_post);
+
+void tcp_hiccups_clear(struct sock *sk)
+{
+    struct tcp_sock *tp = tcp_sk(sk);
+
+    tp->hic_appsalt             = 0;
+    tp->hic_as_hash.isn_upper   = 0;
+    tp->hic_as_hash.ipid        = 0;
+    tp->hic_as_hash.rcvwin      = 0;
+    tp->hic_coverage            = 0;
+    tp->hic_want_coverage       = 0;
+    tp->hic_syn_match           = 0;
+    tp->hic_synack_match        = 0;
+    tp->hic_status              = 0;
+    tp->hic_in_conn             = 0;
+    tp->hic_in_connreq          = 0;
+    tp->hic_awaiting_appsalt    = 0;
+    tp->hic_do_client_appsalt   = 0;
+    clear_as_candidates(sk);
+}
+EXPORT_SYMBOL(tcp_hiccups_clear);
+
diff -uNr linux-3.9.4-vanilla/net/ipv4/tcp_input.c linux-3.9.4-hiccups/net/ipv4/tcp_input.c
--- linux-3.9.4-vanilla/net/ipv4/tcp_input.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/tcp_input.c	2014-05-07 13:43:09.971338198 -0700
@@ -74,6 +74,7 @@
 #include <linux/ipsec.h>
 #include <asm/unaligned.h>
 #include <net/netdma.h>
+#include <net/tcp_hiccups.h>    /* RMC */
 
 int sysctl_tcp_timestamps __read_mostly = 1;
 int sysctl_tcp_window_scaling __read_mostly = 1;
@@ -100,6 +101,10 @@
 int sysctl_tcp_moderate_rcvbuf __read_mostly = 1;
 int sysctl_tcp_early_retrans __read_mostly = 2;
 
+int sysctl_tcp_hiccups_loglevel __read_mostly = 0;      /* RMC */
+int sysctl_tcp_hiccups_appsalt __read_mostly = 1;       /* RMC */
+int sysctl_tcp_hiccups_experiments __read_mostly = 0;   /* RMC */
+
 #define FLAG_DATA		0x01 /* Incoming frame contained data.		*/
 #define FLAG_WIN_UPDATE		0x02 /* Incoming ACK was a window update.	*/
 #define FLAG_DATA_ACKED		0x04 /* This ACK acknowledged new data.		*/
@@ -3779,6 +3784,16 @@
 					}
 				}
 				break;
+            case TCPOPT_HICMP:
+                if (opsize == TCPOLEN_HICMP && th->syn && 
+                    !estab && sysctl_tcp_hiccups_experiments)
+                    opt_rx->hic_mpcapable = 1;
+                break;
+            case TCPOPT_HICEXP:
+                if (opsize == TCPOLEN_HICEXP && th->syn && 
+                    !estab && sysctl_tcp_hiccups_experiments)
+                    opt_rx->hic_exp = 1;
+                break;
 			case TCPOPT_WINDOW:
 				if (opsize == TCPOLEN_WINDOW && th->syn &&
 				    !estab && sysctl_tcp_window_scaling) {
@@ -4617,6 +4632,8 @@
 			__set_current_state(TASK_RUNNING);
 
 			local_bh_enable();
+            /* RMC */
+            /* printk("Line 4625: iov pointer --> %x", (unsigned int) tp->ucopy.iov); */
 			if (!skb_copy_datagram_iovec(skb, 0, tp->ucopy.iov, chunk)) {
 				tp->ucopy.len -= chunk;
 				tp->copied_seq += chunk;
@@ -4632,6 +4649,8 @@
 			    tcp_try_rmem_schedule(sk, skb, skb->truesize))
 				goto drop;
 
+            /* RMC */
+            /* if (skb->len) printk("4643: skb->len = %u, skb->data_len = %u\n", skb->len, skb->data_len); */
 			eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen);
 		}
 		tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
@@ -4655,6 +4674,13 @@
 
 		tcp_fast_path_check(sk);
 
+        /* RMC: If we're waiting to finish our appsalt checks and we get
+         * a packet with data in it... */
+        if (tp->hic_awaiting_appsalt && skb->len) {
+            /* printk("4662: skb->len = %u, skb->data_len = %u\n", skb->len, skb->data_len); */
+            tcp_hiccups_appsalt_post(sk, skb);
+        }
+
 		if (eaten > 0)
 			kfree_skb_partial(skb, fragstolen);
 		if (!sock_flag(sk, SOCK_DEAD))
@@ -5166,6 +5192,12 @@
 			if (skb_copy_bits(skb, ptr, &tmp, 1))
 				BUG();
 			tp->urg_data = TCP_URG_VALID | tmp;
+
+            if (tp->hic_awaiting_appsalt) {
+                printk("RMC: calling from tcp_urg - line 5185\n");
+                tcp_hiccups_appsalt_post(sk, skb);      /* RMC */
+            }
+
 			if (!sock_flag(sk, SOCK_DEAD))
 				sk->sk_data_ready(sk, 0);
 		}
@@ -5252,10 +5284,20 @@
 		if ((tp->ucopy.len == 0) ||
 		    (tcp_flag_word(tcp_hdr(skb)) & TCP_FLAG_PSH) ||
 		    (atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1))) {
+
+            if (tp->hic_awaiting_appsalt) {
+                printk("RMC: in dma function -- line 5277\n");
+                tcp_hiccups_appsalt_post(sk, skb);      /* RMC */
+            }
+
 			tp->ucopy.wakeup = 1;
 			sk->sk_data_ready(sk, 0);
 		}
 	} else if (chunk > 0) {
+        if (tp->hic_awaiting_appsalt) {
+            printk("RMC: in dma function -- line 5286\n");
+            tcp_hiccups_appsalt_post(sk, skb);      /* RMC */
+        }
 		tp->ucopy.wakeup = 1;
 		sk->sk_data_ready(sk, 0);
 	}
@@ -5528,6 +5570,10 @@
 				__skb_queue_tail(&sk->sk_async_wait_queue, skb);
 			else
 #endif
+            if (tp->hic_awaiting_appsalt) {
+                printk("RMC: in tcp_rcv_established (fast path?) -- line 5562\n");
+                tcp_hiccups_appsalt_post(sk, skb);      /* RMC */
+            }
 			if (eaten)
 				kfree_skb_partial(skb, fragstolen);
 			sk->sk_data_ready(sk, 0);
@@ -5561,6 +5607,8 @@
 	/* step 7: process the segment text */
 	tcp_data_queue(sk, skb);
 
+/* RMC: I had some after checks here at one time, but skb is released in tcp_data_queue(). */
+
 	tcp_data_snd_check(sk);
 	tcp_ack_snd_check(sk);
 	return 0;
@@ -5721,6 +5769,9 @@
 		 *    state to ESTABLISHED..."
 		 */
 
+        /* RMC: Best place I can find to tap in for incoming SYN-ACK */
+        tcp_hiccups_synack_in(sk, skb);
+
 		TCP_ECN_rcv_synack(tp, th);
 
 		tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
@@ -6056,6 +6107,11 @@
 
 				tcp_initialize_rcv_mss(sk);
 				tcp_fast_path_on(tp);
+
+                /* RMC */
+                if (tp->hic_awaiting_appsalt)
+                    h_print(LOG_HIGH, " B *** In slow path SYN_RECV: just received acceptable ack and changed to established.\n");
+
 			} else {
 				return 1;
 			}
diff -uNr linux-3.9.4-vanilla/net/ipv4/tcp_ipv4.c linux-3.9.4-hiccups/net/ipv4/tcp_ipv4.c
--- linux-3.9.4-vanilla/net/ipv4/tcp_ipv4.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/tcp_ipv4.c	2014-05-07 13:43:09.972338198 -0700
@@ -85,6 +85,8 @@
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
 
+#include <net/tcp_hiccups.h>        /* RMC */
+
 int sysctl_tcp_tw_reuse __read_mostly;
 int sysctl_tcp_low_latency __read_mostly;
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
@@ -234,13 +236,16 @@
 	sk->sk_gso_type = SKB_GSO_TCPV4;
 	sk_setup_caps(sk, &rt->dst);
 
-	if (!tp->write_seq && likely(!tp->repair))
-		tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
+	if (!tp->write_seq && likely(!tp->repair)) {
+        /* tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr,
 							   inet->inet_daddr,
 							   inet->inet_sport,
-							   usin->sin_port);
+							   usin->sin_port); */
+        tp->write_seq = 1111;   /* RMC */
+    }
 
-	inet->inet_id = tp->write_seq ^ jiffies;
+	/* inet->inet_id = tp->write_seq ^ jiffies; */
+    inet->inet_id = 3333;   /* RMC */
 
 	err = tcp_connect(sk);
 
@@ -860,6 +865,20 @@
 		err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr,
 					    ireq->rmt_addr,
 					    ireq->opt);
+
+        /* RMC: We used to hook in just here but the Fast Open (TFO) additions
+         * that came in 3.7 and later stopped using tcp_v4_send_synack().  Now,
+         * tcp_v4_conn_request() just calls ip_build_and_send_pkt() directly
+         * when not using TFO.  When using TFO, it goes through
+         * tcp_v4_conn_req_fastopen() which does the buildandsend after it
+         * successfully creates a new full sock (because there may be data in
+         * the SYN it needs to handle and it can't do that with just the small
+         * request sock).  Basically, this whole function is dead code now.
+         *
+         * The purpose of this hook was to fix values in the request sock since
+         * it's not passed down to us via the buildandsend. */
+        tcp_hiccups_after_synack_out(sk, skb, req);
+
 		err = net_xmit_eval(err);
 		if (!tcp_rsk(req)->snt_synack && !err)
 			tcp_rsk(req)->snt_synack = tcp_time_stamp;
@@ -1512,16 +1531,24 @@
 	if (!req)
 		goto drop;
 
+    /* RMC: Seems like the best place to do the HICCUPS check on the
+     * incoming SYN.  So far in tcp_v4_conn_request(), we haven't done
+     * any real processing of the skb or setup of the request_sock yet.
+     */
+    tcp_hiccups_syn_in(sk, skb);
+
 #ifdef CONFIG_TCP_MD5SIG
 	tcp_rsk(req)->af_specific = &tcp_request_sock_ipv4_ops;
 #endif
 
-	tcp_clear_options(&tmp_opt);
+	tcp_clear_options(&tmp_opt);    /* RMC: init our notes to 0 */
 	tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
 	tmp_opt.user_mss  = tp->rx_opt.user_mss;
 	tcp_parse_options(skb, &tmp_opt, &hash_location, 0,
 	    want_cookie ? NULL : &foc);
 
+    /* RMC: now tmp_opt has our notes in it */
+
 	if (tmp_opt.cookie_plus > 0 &&
 	    tmp_opt.saw_tstamp &&
 	    !tp->rx_opt.cookie_out_never &&
@@ -1560,7 +1587,7 @@
 		tcp_clear_options(&tmp_opt);
 
 	tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
-	tcp_openreq_init(req, &tmp_opt, skb);
+	tcp_openreq_init(req, &tmp_opt, skb);   /* RMC: notes saved from tmp_opt to req */
 
 	ireq = inet_rsk(req);
 	ireq->loc_addr = daddr;
@@ -1613,8 +1640,11 @@
 			goto drop_and_release;
 		}
 
-		isn = tcp_v4_init_sequence(skb);
+		/* isn = tcp_v4_init_sequence(skb); */
+        isn = 9999;     /* RMC: to make tracking easier */
+        tp->hic_in_connreq = 1;
 	}
+    /* RMC: we leave this alone so we don't disturb syncookies or timewait buckets */
 	tcp_rsk(req)->snt_isn = isn;
 
 	if (dst == NULL) {
@@ -1649,6 +1679,14 @@
 		int err;
 		err = ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr,
 		     ireq->rmt_addr, ireq->opt);
+
+        /* RMC: Fix values in the request sock since it's not passed
+         * down to us via ip_build_and_send_pkt(). */
+        if (tp->hic_in_connreq) {
+            tcp_hiccups_after_synack_out(sk, skb_synack, req);
+            tp->hic_in_connreq = 0;
+        }
+
 		err = net_xmit_eval(err);
 		if (err || want_cookie)
 			goto drop_and_free;
@@ -1663,6 +1701,9 @@
 	} else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req,
 	    (struct request_values *)&tmp_ext))
 		goto drop_and_free;
+    /* TODO RMC: need another hook inside the conn_req_fo above
+     * that also handles fixing of the client socket
+     */
 
 	return 0;
 
@@ -2031,6 +2072,24 @@
 		{
 			if (!tcp_prequeue(sk, skb))
 				ret = tcp_v4_do_rcv(sk, skb);
+        /**
+         * RMC: So most things go into the v4_do_rcv, which then splits into
+         * fast path and slow path.
+         *
+         * Fast path follows: tcp_v4_do_rcv() -> tcp_rcv_established() ->
+         * tcp_copy_to_iovec() -> skb_copy_datagram_iovec()
+         *
+         * Slow path follows: tcp_v4_do_rcv() -> [ tcp_rcv_established() |
+         * tcp_rcv_state_process() ] -> tcp_data_queue() -> skb_copy_datagram_iovec()
+         *
+         * So it would seem that skb_copy_datagram_iovec() would be a good chokepoint,
+         * but the socket pointer isn't one of its parameters and it seems to get
+         * called a lot (especially if there are fragments).
+         *
+         * So our strategy to calc AppSalt on the receive data will be to hook
+         * in before each of the sk_data_ready calls and look for app data.  This
+         * call is used to wake up the socket when data is available for the user.
+         */
 		}
 	} else if (unlikely(sk_add_backlog(sk, skb,
 					   sk->sk_rcvbuf + sk->sk_sndbuf))) {
diff -uNr linux-3.9.4-vanilla/net/ipv4/tcp_output.c linux-3.9.4-hiccups/net/ipv4/tcp_output.c
--- linux-3.9.4-vanilla/net/ipv4/tcp_output.c	2013-05-24 11:45:59.000000000 -0700
+++ linux-3.9.4-hiccups/net/ipv4/tcp_output.c	2014-05-07 13:43:09.974338198 -0700
@@ -37,6 +37,7 @@
 #define pr_fmt(fmt) "TCP: " fmt
 
 #include <net/tcp.h>
+#include <net/tcp_hiccups.h>        /* RMC */
 
 #include <linux/compiler.h>
 #include <linux/gfp.h>
@@ -386,6 +387,8 @@
 #define OPTION_WSCALE		(1 << 3)
 #define OPTION_COOKIE_EXTENSION	(1 << 4)
 #define OPTION_FAST_OPEN_COOKIE	(1 << 8)
+#define OPTION_HICMP            (1 << 12)
+#define OPTION_HICEXP           (1 << 13)
 
 struct tcp_out_options {
 	u16 options;		/* bit field of OPTION_* */
@@ -547,6 +550,20 @@
 			       opts->ws);
 	}
 
+    /* RMC: write our fake options if they were requested in the SYN */
+    if (OPTION_HICMP & options) {
+        *ptr++ = htonl((TCPOPT_HICMP << 24) |
+                    (TCPOLEN_HICMP << 16) |
+                    0x0081);
+        *ptr++ = htonl(0xdeadbeef);
+        *ptr++ = htonl(0xdeadbeef);
+    }
+    if (OPTION_HICEXP & options) {
+		*ptr++ = htonl((TCPOPT_HICEXP << 24) |
+			       (TCPOLEN_HICEXP << 16) |
+			       0xbeef);
+    }
+
 	if (unlikely(opts->num_sack_blocks)) {
 		struct tcp_sack_block *sp = tp->rx_opt.dsack ?
 			tp->duplicate_sack : tp->selective_acks;
@@ -732,6 +749,16 @@
 	opts->mss = mss;
 	remaining -= TCPOLEN_MSS_ALIGNED;
 
+    /* RMC: our new fake option responses */
+	if (ireq->hic_mpcapable) {
+        opts->options |= OPTION_HICMP;
+        remaining -= TCPOLEN_HICMP_ALIGNED;
+    }
+	if (ireq->hic_exp) {
+        opts->options |= OPTION_HICEXP;
+        remaining -= TCPOLEN_HICEXP_ALIGNED;
+    }
+    /* </RMC> */
 	if (likely(ireq->wscale_ok)) {
 		opts->ws = ireq->rcv_wscale;
 		opts->options |= OPTION_WSCALE;
@@ -2747,6 +2774,7 @@
 	else
 #endif
 	TCP_SKB_CB(skb)->when = tcp_time_stamp;
+    /* RMC: copy our options from ireq to opts->options bit field */
 	tcp_header_size = tcp_synack_options(sk, req, mss,
 					     skb, &opts, &md5, xvp, foc)
 			+ sizeof(*th);
@@ -2807,6 +2835,7 @@
 
 	/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
 	th->window = htons(min(req->rcv_wnd, 65535U));
+    /* RMC: copy our options from opts->options to the tcp header */
 	tcp_options_write((__be32 *)(th + 1), tp, &opts);
 	th->doff = (tcp_header_size >> 2);
 	TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, tcp_skb_pcount(skb));
@@ -3020,12 +3049,21 @@
 	tcp_connect_queue_skb(sk, buff);
 	TCP_ECN_send_syn(sk, buff);
 
+    /* RMC: Need to know we came by here so when we're down in the weeds
+     * during this next statement, we know it isn't some kind of retransmit
+     */
+    tp->hic_in_conn = 1;
+
 	/* Send off SYN; include data in Fast Open. */
 	err = tp->fastopen_req ? tcp_send_syn_data(sk, buff) :
 	      tcp_transmit_skb(sk, buff, 1, sk->sk_allocation);
 	if (err == -ECONNREFUSED)
 		return err;
 
+    /* RMC: Take care of some final cleanup on the TCP skb's control block */
+    tp->hic_in_conn = 0;
+    tcp_hiccups_after_syn_out(sk, buff);
+
 	/* We change tp->snd_nxt after the tcp_transmit_skb() call
 	 * in order to make this packet get counted in tcpOutSegs.
 	 */
