Index: migrate.kernel/Makefile
diff -c migrate.kernel/Makefile:1.1.1.2 migrate.kernel/Makefile:1.4
*** migrate.kernel/Makefile:1.1.1.2	Mon Sep  4 13:47:54 2000
--- migrate.kernel/Makefile	Wed Nov 22 14:41:37 2000
***************
*** 1,7 ****
  VERSION = 2
  PATCHLEVEL = 2
  SUBLEVEL = 17
! EXTRAVERSION =
  
  ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
  
--- 1,7 ----
  VERSION = 2
  PATCHLEVEL = 2
  SUBLEVEL = 17
! EXTRAVERSION = migrate
  
  ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
  
***************
*** 107,120 ****
  # Include the make variables (CC, etc...)
  #
  
! CORE_FILES	=kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o
  FILESYSTEMS	=fs/filesystems.a
  NETWORKS	=net/network.a
  DRIVERS		=drivers/block/block.a \
  		 drivers/char/char.a \
  	         drivers/misc/misc.a
  LIBS		=$(TOPDIR)/lib/lib.a
! SUBDIRS		=kernel drivers mm fs net ipc lib
  
  ifdef CONFIG_NUBUS
  DRIVERS := $(DRIVERS) drivers/nubus/nubus.a
--- 107,120 ----
  # Include the make variables (CC, etc...)
  #
  
! CORE_FILES	=kernel/kernel.o mm/mm.o fs/fs.o ipc/ipc.o crypto/crypto.a
  FILESYSTEMS	=fs/filesystems.a
  NETWORKS	=net/network.a
  DRIVERS		=drivers/block/block.a \
  		 drivers/char/char.a \
  	         drivers/misc/misc.a
  LIBS		=$(TOPDIR)/lib/lib.a
! SUBDIRS		=kernel drivers mm fs net ipc lib crypto
  
  ifdef CONFIG_NUBUS
  DRIVERS := $(DRIVERS) drivers/nubus/nubus.a
Index: migrate.kernel/Documentation/Configure.help
diff -c migrate.kernel/Documentation/Configure.help:1.1.1.2 migrate.kernel/Documentation/Configure.help:1.5
*** migrate.kernel/Documentation/Configure.help:1.1.1.2	Mon Sep  4 13:39:15 2000
--- migrate.kernel/Documentation/Configure.help	Wed Nov 22 15:33:11 2000
***************
*** 1225,1230 ****
--- 1225,1277 ----
    
    If unsure, say Y.
  
+ TCP Migrate Options
+ CONFIG_MIGRATE
+   The TCP Migrate options allow TCP connections to be migrated across
+   IP addresses to support host mobility.  These options are described in
+   The Internet-Draft <draft-snoeren-tcp-migrate-00.txt>.
+ 
+   The current version of the draft and further documentation can be
+   found at:
+ 
+     http://nms.lcs.mit.edu/projects/migrate
+ 
+   If you say Y here, note that the options aren't enabled by default;
+   you can enable them by saying Y to "/proc filesystem support" and
+   "Sysctl support" below and executing the command
+ 
+     echo 1 >/proc/sys/net/ipv4/tcp_migrate 
+ 
+   at boot time after the proc filesystem has been mounted.
+ 
+   If you choose to build in a crypto library, you may also select a
+   system-wide default ECC curve by issuing
+ 
+     echo # >/proc/sys/net/ipv4/tcp_migrate_curve
+ 
+   Where # is the number of the curve.  The default is 0, the null
+   curve, providing no crypographic security.
+ 
+   If unsure, say N.
+ 
+ MIRACL Crypto Support
+ CONFIG_MIRACL
+   MIRACL is a C/C++ large number and crypto library from Shamus Software.
+   You must download and install this separately in linux/crypto/miracl.
+   MIRACL can be found at:
+ 
+     http://indigo.ie/~mscott/
+ 
+   The necessary patches for installation into the kernel are included
+   with the patches for TCP Migrate support.  Make sure to patch the
+   MIRACL distribution before attempting to build the kernel.
+ 
+   The TCP Migrate options require a crypto library to support Elliptic
+   Curve Diffie Hellman negotiation.  Without this, the migrate options
+   will be unsecured.
+ 
+   If unsure, say Y.
+ 
  Sun floppy controller support
  CONFIG_BLK_DEV_SUNFD
    This is support for floppy drives on Sun SPARC workstations. Say Y
Index: migrate.kernel/Documentation/networking/ip-sysctl.txt
diff -c migrate.kernel/Documentation/networking/ip-sysctl.txt:1.1.1.1 migrate.kernel/Documentation/networking/ip-sysctl.txt:1.2
*** migrate.kernel/Documentation/networking/ip-sysctl.txt:1.1.1.1	Tue Jan  4 13:12:10 2000
--- migrate.kernel/Documentation/networking/ip-sysctl.txt	Mon Jul 17 18:35:19 2000
***************
*** 103,108 ****
--- 103,115 ----
  	On retransmit try to send bigger packets to work around bugs in
  	certain TCP stacks.
  
+ tcp_migrate - BOOLEAN
+ 	Enable migrate option.
+ 
+ tcp_migrate_curve - INTEGER
+ 	Select ECC curve for ECDH migrate handshake.  See
+ 	http://nms.lcs.mit.edu/projects/migrate for more documentation.
+ 
  ip_local_port_range - 2 INTEGERS
  	Defines the local port range that is used by TCP and UDP to
  	choose the local port. The first number is the first, the 
Index: migrate.kernel/crypto/Makefile
diff -c /dev/null migrate.kernel/crypto/Makefile:1.2
*** /dev/null	Wed Aug 15 18:53:08 2001
--- migrate.kernel/crypto/Makefile	Mon Jul 31 15:36:47 2000
***************
*** 0 ****
--- 1,19 ----
+ #
+ # Makefile for linux crypto.
+ #
+ # Note! Dependencies are done automagically by 'make dep', which also
+ # removes any old dependencies. DON'T put your own dependencies here
+ # unless it's something special (ie not a .c file).
+ #
+ # Note 2! The CFLAGS definition is now in the main makefile...
+ 
+ SUB_DIRS := 
+ 
+ ifeq ($(CONFIG_MIRACL),y)
+ SUB_DIRS += miracl
+ endif
+ 
+ L_TARGET := crypto.a
+ L_OBJS   := sha.o $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
+ 
+ include $(TOPDIR)/Rules.make
Index: migrate.kernel/crypto/sha.c
diff -c /dev/null migrate.kernel/crypto/sha.c:1.1
*** /dev/null	Wed Aug 15 18:53:08 2001
--- migrate.kernel/crypto/sha.c	Mon Jul 17 18:35:19 2000
***************
*** 0 ****
--- 1,223 ----
+ /*
+  * Copyright (C) 2000 Massachusetts Institute of Technology 
+  *
+  * This software is being provided by the copyright holders under the
+  * following license. By obtaining, using and/or copying this software,
+  * you agree that you have read, understood, and will comply with the
+  * following terms and conditions:
+  *
+  * Permission to use, copy, modify, distribute, and sell this software
+  * and its documentation for any purpose and without fee or royalty is
+  * hereby granted, provided that the full text of this NOTICE appears on
+  * ALL copies of the software and documentation or portions thereof,
+  * including modifications, that you make.
+  *
+  * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+  * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+  * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+  * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+  * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+  * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+  * DOCUMENTATION.
+  *
+  * The name and trademarks of copyright holders may NOT be used in
+  * advertising or publicity pertaining to the software without specific,
+  * written prior permission. Title to copyright in this software and any
+  * associated documentation will at all times remain with copyright
+  * holders. See the file AUTHORS which should have accompanied this software
+  * for a list of all copyright holders.
+  *
+  * This file may be derived from previously copyrighted software. This
+  * copyright applies only to those changes made by the copyright
+  * holders listed in the AUTHORS file. The rest of this file is covered by
+  * the copyright notices, if any, listed below.
+  *
+  * Migrate TCP option handling 
+  *
+  * Version:   $Id: sha.c,v 1.1 2000/07/17 22:35:19 snoeren Exp $
+  *
+  */
+ /* Implementation of NIST's Secure Hash Algorithm (FIPS 180)
+  * Lightly bummed for execution efficiency.
+  *
+  * Jim Gillogly 3 May 1993
+  *
+  * 27 Aug 93: imported LITTLE_ENDIAN mods from Peter Gutmann's implementation
+  *  5 Jul 94: Modified for NSA fix
+  * 16 May 00: Ported for inclusion in Linux kernel - snoeren@lcs.mit.edu
+  *
+  * Output: 40-hex-digit digest of each file specified (160 bits)
+  *
+  * Synopsis of the function calls:
+  *
+  *   void sha1(__u8 *mem, __u32 length, __u32 *buffer)
+  *      Input is a memory block "length" bytes long.
+  *
+  * Limitation:
+  *      sha1 will deal with blocks no longer than 4 gigabytes
+  *
+  * Bugs:
+  *      The standard is defined for bit strings; I assume bytes.
+  *
+  * Copyright 1993, Dr. James J. Gillogly
+  * This code may be freely used in any application.
+  */
+ 
+ #include <linux/string.h>
+ 
+ #ifdef __LITTLE_ENDIAN    /* Imported from Peter Gutmann's implementation */
+ 
+ /* When run on a little-endian CPU we need to perform byte reversal on an
+    array of longwords.  It is possible to make the code endianness-
+    independant by fiddling around with data at the byte level, but this
+    makes for very slow code, so we rely on the user to sort out endianness
+    at compile time */
+ 
+ static void
+ byteReverse(__u32 *buffer, int byteCount)
+ {
+     __u32 value;
+     int count;
+ 
+     byteCount /= sizeof( __u32 );
+     for( count = 0; count < byteCount; count++ )
+ 	{
+ 	value = ( buffer[ count ] << 16 ) | ( buffer[ count ] >> 16 );
+ 	buffer[ count ] = ( ( value & 0xFF00FF00L ) >> 8 ) | ( ( value & 0x00FF00FFL ) << 8 );
+ 	}
+ }
+ #endif /* __LITTLE_ENDIAN */
+ 
+ 
+ 
+ union longbyte
+ {
+     __u32 W[80];        /* Process 16 32-bit words at a time */
+     __u8 B[320];                /* But read them as bytes for counting */
+ };
+ 
+ 
+ #define f0(x,y,z) (z ^ (x & (y ^ z)))           /* Magic functions */
+ #define f1(x,y,z) (x ^ y ^ z)
+ #define f2(x,y,z) ((x & y) | (z & (x | y)))
+ #define f3(x,y,z) (x ^ y ^ z)
+ 
+ #define K0 0x5a827999                           /* Magic constants */
+ #define K1 0x6ed9eba1
+ #define K2 0x8f1bbcdc
+ #define K3 0xca62c1d6
+ 
+ #define S(n, X) ((X << n) | (X >> (32 - n)))    /* Barrel roll */
+ 
+ #define r0(f, K) \
+     temp = S(5, A) + f(B, C, D) + E + *p0++ + K; \
+     E = D;  \
+     D = C;  \
+     C = S(30, B); \
+     B = A;  \
+     A = temp
+ 
+ #define r1(f, K) \
+     temp = *p1++ ^ *p2++ ^ *p3++ ^ *p4++; \
+     temp = S(5, A) + f(B, C, D) + E + (*p0++ = S(1,temp)) + K; \
+     E = D;  \
+     D = C;  \
+     C = S(30, B); \
+     B = A;  \
+     A = temp
+ 
+ void
+ sha1(__u8 *mem, __u32 length, __u32 *buf)
+ {
+     int i, nread, nbits;
+     union longbyte d;
+     __u32 hi_length, lo_length;
+     int padded;
+     __u8 *s;
+ 
+     register __u32 *p0, *p1, *p2, *p3, *p4;
+     __u32 A, B, C, D, E, temp;
+ 
+     __u32 h0, h1, h2, h3, h4;
+ 
+     h0 = 0x67452301;                            /* Accumulators */
+     h1 = 0xefcdab89;
+     h2 = 0x98badcfe;
+     h3 = 0x10325476;
+     h4 = 0xc3d2e1f0;
+ 
+     padded = 0;
+     s = mem;
+     for (hi_length = lo_length = 0; ;)  /* Process 16 longs at a time */
+     {
+         if (length < 64) nread = length;
+         else             nread = 64;
+         length -= nread;
+         memcpy(d.B, s, nread);
+         s += nread;
+ 
+ 	if (nread < 64)   /* Partial block? */
+ 	{
+ 		nbits = nread << 3;               /* Length: bits */
+ 		if ((lo_length += nbits) < nbits)
+ 			hi_length++;              /* 64-bit integer */
+ 
+ 		if (nread < 64 && ! padded)  /* Append a single bit */
+ 		{
+ 			d.B[nread++] = 0x80; /* Using up next byte */
+ 			padded = 1;       /* Single bit once */
+ 		}
+ 		for (i = nread; i < 64; i++) /* Pad with nulls */
+ 			d.B[i] = 0;
+ 		if (nread <= 56)   /* Room for length in this block */
+ 		{
+ 			d.W[14] = hi_length;
+ 			d.W[15] = lo_length;
+ #ifdef __LITTLE_ENDIAN
+ 	      byteReverse(d.W, 56 );
+ #endif /* __LITTLE_ENDIAN */
+ 		}
+ #ifdef __LITTLE_ENDIAN
+ 	   else byteReverse(d.W, 64 );
+ #endif /* __LITTLE_ENDIAN */
+ 	}
+ 	else    /* Full block -- get efficient */
+ 	{
+ 		if ((lo_length += 512) < 512)
+ 			hi_length++;    /* 64-bit integer */
+ #ifdef __LITTLE_ENDIAN
+ 	   byteReverse(d.W, 64 );
+ #endif /* __LITTLE_ENDIAN */
+ 	}
+ 
+ 	p0 = d.W;
+ 	A = h0; B = h1; C = h2; D = h3; E = h4;
+ 
+ 	r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);
+ 	r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);
+ 	r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0); r0(f0,K0);
+ 	r0(f0,K0);
+ 
+ 	p1 = &d.W[13]; p2 = &d.W[8]; p3 = &d.W[2]; p4 = &d.W[0];
+ 
+ 		   r1(f0,K0); r1(f0,K0); r1(f0,K0); r1(f0,K0);
+ 	r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);
+ 	r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);
+ 	r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);
+ 	r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1); r1(f1,K1);
+ 	r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);
+ 	r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);
+ 	r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);
+ 	r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2); r1(f2,K2);
+ 	r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);
+ 	r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);
+ 	r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);
+ 	r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3); r1(f3,K3);
+ 
+ 	h0 += A; h1 += B; h2 += C; h3 += D; h4 += E;
+ 
+ 	if (nread <= 56) break; /* If it's greater, length in next block */
+     }
+     buf[0] = h0; buf[1] = h1; buf[2] = h2; buf[3] = h3; buf[4] = h4;
+ }
Index: migrate.kernel/include/linux/net.h
diff -c migrate.kernel/include/linux/net.h:1.1.1.1 migrate.kernel/include/linux/net.h:1.2
*** migrate.kernel/include/linux/net.h:1.1.1.1	Thu Apr 15 19:28:55 1999
--- migrate.kernel/include/linux/net.h	Wed Nov 22 14:27:52 2000
***************
*** 42,49 ****
  #define SYS_GETSOCKOPT	15		/* sys_getsockopt(2)		*/
  #define SYS_SENDMSG	16		/* sys_sendmsg(2)		*/
  #define SYS_RECVMSG	17		/* sys_recvmsg(2)		*/
  
- 
  typedef enum {
    SS_FREE = 0,				/* not allocated		*/
    SS_UNCONNECTED,			/* unconnected to any socket	*/
--- 42,50 ----
  #define SYS_GETSOCKOPT	15		/* sys_getsockopt(2)		*/
  #define SYS_SENDMSG	16		/* sys_sendmsg(2)		*/
  #define SYS_RECVMSG	17		/* sys_recvmsg(2)		*/
+ #define SYS_GETSOCKSTATE 18             /* sys_getsockstate(2)          */
+ #define SYS_SETSOCKSTATE 19             /* sys_setsockstate(2)          */
  
  typedef enum {
    SS_FREE = 0,				/* not allocated		*/
    SS_UNCONNECTED,			/* unconnected to any socket	*/
***************
*** 106,111 ****
--- 107,116 ----
  			 unsigned long arg);	
    int   (*sendmsg)	(struct socket *sock, struct msghdr *m, int total_len, struct scm_cookie *scm);
    int   (*recvmsg)	(struct socket *sock, struct msghdr *m, int total_len, int flags, struct scm_cookie *scm);
+   int   (*setstate)     (struct socket *sock, struct sockstate *ustate,
+ 			 int usockstate_len);
+   int   (*getstate)     (struct socket *sock, struct sockstate *ustate,
+ 			 int *usockstate_len);
  };
  
  struct net_proto_family 
Index: migrate.kernel/include/linux/skbuff.h
diff -c migrate.kernel/include/linux/skbuff.h:1.1.1.1 migrate.kernel/include/linux/skbuff.h:1.3
*** migrate.kernel/include/linux/skbuff.h:1.1.1.1	Thu May 13 13:33:17 1999
--- migrate.kernel/include/linux/skbuff.h	Tue Aug  1 17:34:57 2000
***************
*** 75,81 ****
  
  	struct  dst_entry *dst;
  
! 	char		cb[48];	 
  
  	unsigned int 	len;			/* Length of actual data			*/
  	unsigned int	csum;			/* Checksum 					*/
--- 75,81 ----
  
  	struct  dst_entry *dst;
  
! 	char		cb[48];
  
  	unsigned int 	len;			/* Length of actual data			*/
  	unsigned int	csum;			/* Checksum 					*/
Index: migrate.kernel/include/linux/socket.h
diff -c migrate.kernel/include/linux/socket.h:1.1.1.1 migrate.kernel/include/linux/socket.h:1.2
*** migrate.kernel/include/linux/socket.h:1.1.1.1	Tue Jan  4 13:12:25 2000
--- migrate.kernel/include/linux/socket.h	Wed Nov 22 14:27:52 2000
***************
*** 19,24 ****
--- 19,28 ----
  	char		sa_data[14];	/* 14 bytes of protocol address	*/
  };
  
+ struct sockstate {
+         char            ss_data[512];   /* > Size of tcp_opt */
+ };
+ 
  struct linger {
  	int		l_onoff;	/* Linger active		*/
  	int		l_linger;	/* How long to linger for	*/
Index: migrate.kernel/include/linux/sysctl.h
diff -c migrate.kernel/include/linux/sysctl.h:1.1.1.1 migrate.kernel/include/linux/sysctl.h:1.2
*** migrate.kernel/include/linux/sysctl.h:1.1.1.1	Wed Jun  7 17:26:44 2000
--- migrate.kernel/include/linux/sysctl.h	Mon Jul 17 18:35:19 2000
***************
*** 228,234 ****
  	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
  	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
  	NET_IPV4_ALWAYS_DEFRAG=67,
! 	NET_IPV4_IP_MASQ_UDP_DLOOSE=68
  };
  
  enum {
--- 228,236 ----
  	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
  	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
  	NET_IPV4_ALWAYS_DEFRAG=67,
! 	NET_IPV4_IP_MASQ_UDP_DLOOSE=68,
! 	NET_IPV4_TCP_MIGRATE=69,
! 	NET_IPV4_TCP_MIGRATE_CURVE=70
  };
  
  enum {
Index: migrate.kernel/include/linux/tcp.h
diff -c migrate.kernel/include/linux/tcp.h:1.1.1.1 migrate.kernel/include/linux/tcp.h:1.5
*** migrate.kernel/include/linux/tcp.h:1.1.1.1	Tue May 11 13:35:44 1999
--- migrate.kernel/include/linux/tcp.h	Wed Nov 22 14:27:52 2000
***************
*** 66,71 ****
--- 66,73 ----
    TCP_LAST_ACK,
    TCP_LISTEN,
    TCP_CLOSING,	 /* now a valid state */
+   TCP_MIGRATE_WAIT,
+   TCP_PRELOAD,
  
    TCP_MAX_STATES /* Leave at the end! */
  };
***************
*** 84,90 ****
    TCPF_CLOSE_WAIT = (1 << 8),
    TCPF_LAST_ACK  = (1 << 9),
    TCPF_LISTEN    = (1 << 10),
!   TCPF_CLOSING   = (1 << 11) 
  };
  
  #endif	/* _LINUX_TCP_H */
--- 86,96 ----
    TCPF_CLOSE_WAIT = (1 << 8),
    TCPF_LAST_ACK  = (1 << 9),
    TCPF_LISTEN    = (1 << 10),
!   TCPF_CLOSING   = (1 << 11),
!   TCPF_MIGRATE_WAIT = (1 << 12)
  };
+ 
+ #define SIOCMIGRATE	(SIOCPROTOPRIVATE + 0)	/* IP protocol privates */
+ #define SIOCGMIGRATE	(SIOCPROTOPRIVATE + 1)	/* IP protocol privates */
  
  #endif	/* _LINUX_TCP_H */
Index: migrate.kernel/include/net/snmp.h
diff -c migrate.kernel/include/net/snmp.h:1.1.1.2 migrate.kernel/include/net/snmp.h:1.3
*** migrate.kernel/include/net/snmp.h:1.1.1.2	Mon Sep  4 13:39:28 2000
--- migrate.kernel/include/net/snmp.h	Wed Nov 22 14:41:37 2000
***************
*** 179,184 ****
--- 179,189 ----
  	unsigned long	OutOfWindowIcmps; 
  	unsigned long	LockDroppedIcmps; 
  	unsigned long	SockMallocOOM; 
+         unsigned long   MigratesSent;
+         unsigned long   MigratesRecv;
+         unsigned long   MigratesFailed;
+         unsigned long   MigrateWaits;
+         unsigned long   MigrateTimeouts;
  };
   	
  #endif
Index: migrate.kernel/include/net/sock.h
diff -c migrate.kernel/include/net/sock.h:1.1.1.2 migrate.kernel/include/net/sock.h:1.5
*** migrate.kernel/include/net/sock.h:1.1.1.2	Mon Sep  4 13:39:28 2000
--- migrate.kernel/include/net/sock.h	Wed Nov 22 14:41:37 2000
***************
*** 278,284 ****
   */
  	char	tstamp_ok,	/* TIMESTAMP seen on SYN packet		*/
  		wscale_ok,	/* Wscale seen on SYN packet		*/
! 		sack_ok;	/* SACK seen on SYN packet		*/
  	char	saw_tstamp;	/* Saw TIMESTAMP on last packet		*/
          __u8	snd_wscale;	/* Window scaling received from sender	*/
          __u8	rcv_wscale;	/* Window scaling to send to receiver	*/
--- 278,286 ----
   */
  	char	tstamp_ok,	/* TIMESTAMP seen on SYN packet		*/
  		wscale_ok,	/* Wscale seen on SYN packet		*/
! 		sack_ok,	/* SACK seen on SYN packet		*/
! 	        migrate_ok,     /* Migrate seen on SYN packet           */
! 	        migrate;
  	char	saw_tstamp;	/* Saw TIMESTAMP on last packet		*/
          __u8	snd_wscale;	/* Window scaling received from sender	*/
          __u8	rcv_wscale;	/* Window scaling to send to receiver	*/
***************
*** 290,295 ****
--- 292,311 ----
  	int	num_sacks;	/* Number of SACK blocks		*/
  	struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/
  
+         __u8    curveName;      /* ECC Curve */
+         __u8    reqNo;          /* Migrate request counter */
+         __u8    snt_reqNo;
+         __u8    rcv_reqNo;
+         __u64   token;          /* Migrate token */
+         __u64   rcv_token;
+         __u64   request;        /* Migrate request hash */
+         __u8    key[25];        /* Curve */      
+         __u8    snt_ecdh[25];
+         __u8    rcv_ecdh[17];       
+         __u8    mig_state;      /* Store state at time of request */
+         __u32   snt_isn;
+         __u32   rcv_isn;
+ 
   	struct timer_list	probe_timer;		/* Probes	*/
  	__u32	window_clamp;	/* XXX Document this... -DaveM		*/
  	__u32	probes_out;	/* unanswered 0 window probes		*/
***************
*** 591,596 ****
--- 607,621 ----
  	unsigned long		retransmits;
  	char			name[32];
  	int			inuse, highestinuse;
+ 
+         /* New Session Layer functions */
+ 
+ 	int			(*setsockstate)(struct sock *sk,
+ 						struct sockstate *state,
+ 						int state_len);
+ 	int			(*getsockstate)(struct sock *sk,
+ 						struct sockstate *state,
+ 						int *state_len);
  };
  
  #define TIME_WRITE	1	/* Not yet used */
***************
*** 601,606 ****
--- 626,632 ----
  #define TIME_DESTROY	6
  #define TIME_DONE	7	/* Used to absorb those last few packets */
  #define TIME_PROBE0	8
+ #define TIME_MIGRATE    9
  
  /* About 10 seconds */
  #define SOCK_DESTROY_TIME (10*HZ)
Index: migrate.kernel/include/net/tcp.h
diff -c migrate.kernel/include/net/tcp.h:1.1.1.1 migrate.kernel/include/net/tcp.h:1.4
*** migrate.kernel/include/net/tcp.h:1.1.1.1	Wed May  3 20:16:52 2000
--- migrate.kernel/include/net/tcp.h	Wed Nov 22 14:27:52 2000
***************
*** 38,43 ****
--- 38,63 ----
  #define TCP_LHTABLE_SIZE	32	/* Yes, really, this is all you need. */
  extern struct sock *tcp_listening_hash[TCP_LHTABLE_SIZE];
  
+ /* We keep a hash table of all connections that have negotiated a migrate
+  * connection ID for quick lookup
+  */
+ struct mhe {
+         struct sock *           sk;
+         struct mhe *            next;
+         struct mhe **           pprev;
+         struct proc_dir_entry * proc_entry;
+ };
+ 
+ /* This is for established TCP connections that negotiated migrate options */
+ #define TCP_MHTABLE_SIZE        32
+ extern struct mhe *tcp_migrate_hash[TCP_MHTABLE_SIZE];
+ 
+ #ifdef CONFIG_MIRACL
+ #define CURVE_MAX 1
+ #else
+ #define CURVE_MAX 0
+ #endif
+ 
  /* There are a few simple rules, which allow for local port reuse by
   * an application.  In essence:
   *
***************
*** 208,223 ****
  
  /*
   * 40 is maximal IP options size
!  * 20 is the maximum TCP options size we can currently construct on a SYN.
   * 40 is the maximum possible TCP options size.
   */
  
! #define MAX_SYN_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + 20 + MAX_HEADER + 15)
  #define MAX_FIN_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
  #define BASE_ACK_SIZE	(NETHDR_SIZE + MAX_HEADER + 15)
  #define MAX_ACK_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
  #define MAX_RESET_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
! #define MAX_TCPHEADER_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + 20 + MAX_HEADER + 15)
  
  /* 
   * Never offer a window over 32767 without using window scaling. Some
--- 228,243 ----
  
  /*
   * 40 is maximal IP options size
!  * 40 is the maximum TCP options size we can currently construct on a SYN.
   * 40 is the maximum possible TCP options size.
   */
  
! #define MAX_SYN_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + 40 + MAX_HEADER + 15)
  #define MAX_FIN_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
  #define BASE_ACK_SIZE	(NETHDR_SIZE + MAX_HEADER + 15)
  #define MAX_ACK_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
  #define MAX_RESET_SIZE	(NETHDR_SIZE + sizeof(struct tcphdr) + MAX_HEADER + 15)
! #define MAX_TCPHEADER_SIZE (NETHDR_SIZE + sizeof(struct tcphdr) + 40 + MAX_HEADER + 15)
  
  /* 
   * Never offer a window over 32767 without using window scaling. Some
***************
*** 287,292 ****
--- 307,314 ----
  #define TCPOPT_SACK_PERM        4       /* SACK Permitted */
  #define TCPOPT_SACK             5       /* SACK Block */
  #define TCPOPT_TIMESTAMP	8	/* Better RTT estimations/PAWS */
+ #define TCPOPT_MIGRATE_PERM     14      /* Migrate ECDH */
+ #define TCPOPT_MIGRATE          15      /* Migrate request */
  
  /*
   *     TCP option lengths
***************
*** 296,301 ****
--- 318,327 ----
  #define TCPOLEN_WINDOW         3
  #define TCPOLEN_SACK_PERM      2
  #define TCPOLEN_TIMESTAMP      10
+ #define TCPOLEN_MIGRATE_PERM   20
+ #define TCPOLEN_MIGRATE_SHORT  3
+ #define TCPOLEN_MIGRATE        19
+ 
  
  /* But this is what stacks really send out. */
  #define TCPOLEN_TSTAMP_ALIGNED		12
***************
*** 304,310 ****
--- 330,341 ----
  #define TCPOLEN_SACK_BASE		2
  #define TCPOLEN_SACK_BASE_ALIGNED	4
  #define TCPOLEN_SACK_PERBLOCK		8
+ #define TCPOLEN_MIGRATEPERM_ALIGNED    20
+ #define TCPOLEN_MIGRATE_ALIGNED        20
+ #define TCPOLEN_MIGRATE_SHORT_ALIGNED   4
  
+ #define MIGRATE_PRELOAD  0x80
+ 
  struct open_request;
  
  struct or_calltable {
***************
*** 341,351 ****
  		rcv_wscale : 4, 
  		tstamp_ok : 1,
  		sack_ok : 1,
! 		wscale_ok : 1;
  	/* The following two fields can be easily recomputed I think -AK */
  	__u32			window_clamp;	/* window clamp at creation time */
  	__u32			rcv_wnd;	/* rcv_wnd offered first time */
  	__u32			ts_recent;
  	unsigned long		expires;
  	struct or_calltable	*class;
  	struct sock		*sk;
--- 372,391 ----
  		rcv_wscale : 4, 
  		tstamp_ok : 1,
  		sack_ok : 1,
! 		wscale_ok : 1,
!                 migrate_ok : 1,
!                 migrate : 1;
  	/* The following two fields can be easily recomputed I think -AK */
  	__u32			window_clamp;	/* window clamp at creation time */
  	__u32			rcv_wnd;	/* rcv_wnd offered first time */
  	__u32			ts_recent;
+         __u32                   ts_tsecr;
+         __u8                    reqNo;
+         __u8                    snt_reqNo;
+         __u8                    curveName;
+         __u8                    key[25];
+         __u8                    snt_ecdh[25];
+         __u8                    rcv_ecdh[17];
  	unsigned long		expires;
  	struct or_calltable	*class;
  	struct sock		*sk;
***************
*** 420,425 ****
--- 460,474 ----
  	void			(*addr2sockaddr)	(struct sock *sk,
  							 struct sockaddr *);
  
+ 	int			(*migrate_request)	(struct sock *sk,
+ 							 struct sk_buff *skb);
+ 
+    	int			(*migrate)		(struct sock *sk,
+ 							 struct sockaddr *addr,
+ 							 int len,
+ 							 struct sk_buff *buff,
+ 							 int mtu);
+ 
  	int sockaddr_len;
  };
  
***************
*** 508,513 ****
--- 557,564 ----
  
  extern void			tcp_parse_options(struct sock *sk, struct tcphdr *th,
  						  struct tcp_opt *tp, int no_fancy);
+ extern int                      tcp_setsockstate(struct sock *sk, struct sockstate *state, int state_len);
+ extern int                      tcp_getsockstate(struct sock *sk, struct sockstate *state, int *state_len);
  
  /*
   *	TCP v4 functions exported for the inet6 API
***************
*** 558,563 ****
--- 609,628 ----
  extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, 
  				     __u16 *mss);
  
+ /* From migrate.c */
+ extern void migrate_init(void);
+ extern void migrate_genkey(__u8 curveName, __u8 *key, __u8 *pub);
+ extern void migrate_perm_process_active(struct sock *sk, struct tcp_opt *req);
+ extern void migrate_perm_process_passive(struct open_request *req,
+ 					 struct tcp_opt *tp);
+ extern void tcp_v4_migrate_hash(struct sock *sk);
+ extern void tcp_v4_migrate_unhash(struct sock *sk);
+ extern struct sock *tcp_v4_lookup_migrate(struct tcp_opt *tp, u32 daddr,
+ 					  u16 hnum, int dif);
+ extern int tcp_v4_migrate_request(struct sock *sk, struct sk_buff *skb);
+ extern int tcp_v4_migrate(struct sock *sk, struct sockaddr *uaddr,
+ 			  int addr_len, struct sk_buff *buff, int mtu);
+ 
  /* tcp_output.c */
  
  extern void tcp_read_wakeup(struct sock *);
***************
*** 904,915 ****
  			tcp_statistics.TcpCurrEstab++;
  		break;
  
  	case TCP_CLOSE:
  	    {
  		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
  		/* Should be about 2 rtt's */
  		net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
! 		sk->prot->unhash(sk);
  		/* fall through */
  	    }
  	default:
--- 969,994 ----
  			tcp_statistics.TcpCurrEstab++;
  		break;
  
+ #ifdef CONFIG_MIGRATE
+ 	case TCP_MIGRATE_WAIT:
+ 	    {
+ 		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ 
+ 		if ((tp->mig_state = oldstate)==TCP_ESTABLISHED)
+ 		  tcp_statistics.TcpCurrEstab--;
+ 		/* We use 2MSL timeout */
+ 		tcp_clear_xmit_timers(sk);
+ 		net_reset_timer(sk, TIME_MIGRATE, TCP_TIMEWAIT_LEN);
+ 		break;
+ 	    }
+ #endif
+ 
  	case TCP_CLOSE:
  	    {
  		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
  		/* Should be about 2 rtt's */
  		net_reset_timer(sk, TIME_DONE, min(tp->srtt * 2, TCP_DONE_TIME));
! 	        sk->prot->unhash(sk);
  		/* fall through */
  	    }
  	default:
***************
*** 949,955 ****
   * can generate.
   */
  extern __inline__ void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
! 					     int offer_wscale, int wscale, __u32 tstamp, __u32 ts_recent)
  {
  	/* We always get an MSS option.
  	 * The option bytes which will be seen in normal data
--- 1028,1036 ----
   * can generate.
   */
  extern __inline__ void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
! 					     int offer_wscale, int wscale, __u32 tstamp, __u32 ts_recent,
! 					     int migrate_perm, __u8 curve, __u8*key,
! 					     int migrate, __u8 reqNo, __u64 token, __u64 request)
  {
  	/* We always get an MSS option.
  	 * The option bytes which will be seen in normal data
***************
*** 972,984 ****
  		else
  			*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
  						  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
! 		*ptr++ = htonl(tstamp);		/* TSVAL */
! 		*ptr++ = htonl(ts_recent);	/* TSECR */
  	} else if(sack)
  		*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
  					  (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
  	if (offer_wscale)
  		*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
  }
  
  /* Determine a window scaling and initial window to offer.
--- 1053,1089 ----
  		else
  			*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
  						  (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
! 		if(migrate_perm && curve) {
! 		  memcpy(ptr, key, 8);
! 		  ptr += 2;
! 		} else {
! 		  *ptr++ = htonl(tstamp);	/* TSVAL */
! 		  *ptr++ = htonl(ts_recent);	/* TSECR */
! 		}
  	} else if(sack)
  		*ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
  					  (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
  	if (offer_wscale)
  		*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
+ 	if (migrate_perm) {
+ 	  if (curve) {
+ 	    *ptr++ = htonl((TCPOPT_MIGRATE_PERM << 24 ) |
+ 			   (TCPOLEN_MIGRATE_PERM << 16) | (curve << 8) |
+ 			   key[8]);
+ 	    memcpy(ptr, &key[9], 16);
+ 	    ptr += 4;
+ 	  } else 
+ 	    *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_MIGRATE_PERM << 16 ) |
+ 			   (TCPOLEN_MIGRATE_SHORT << 8) | curve);
+ 	}
+ 	if (migrate) {
+ 	        *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_MIGRATE << 16) |
+ 			       (TCPOLEN_MIGRATE << 8) | reqNo);
+ 		*(__u64*)ptr = __cpu_to_be64(token);
+ 		ptr += 2;
+ 		*(__u64*)ptr = __cpu_to_be64(request);
+ 		ptr += 2;
+ 	}
  }
  
  /* Determine a window scaling and initial window to offer.
Index: migrate.kernel/net/socket.c
diff -c migrate.kernel/net/socket.c:1.1.1.1 migrate.kernel/net/socket.c:1.2
*** migrate.kernel/net/socket.c:1.1.1.1	Wed May  3 20:16:54 2000
--- migrate.kernel/net/socket.c	Wed Nov 22 14:27:52 2000
***************
*** 42,47 ****
--- 42,48 ----
   *		Andi Kleen	:	Some small cleanups, optimizations,
   *					and fixed a copy_from_user() bug.
   *		Tigran Aivazian	:	sys_send(args) calls sys_sendto(args, NULL, 0)
+  *              Alex C. Snoeren :       getsockstate/setsockstate.
   *
   *
   *		This program is free software; you can redistribute it and/or
***************
*** 144,149 ****
--- 145,153 ----
  					   :unix_mkname()).  
  					 */
  
+ #define MAX_SOCK_STATE 512             /* XXX: I don't know how much
+ 					  426 for v4 TCP */
+ 
  int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
  {
  	if(ulen<0||ulen>MAX_SOCK_ADDR)
***************
*** 178,183 ****
--- 182,210 ----
  	return __put_user(klen, ulen);
  }
  
+ int move_state_to_user(void *kstate, int klen, void *ustate, int *ulen)
+ {
+ 	int err;
+ 	int len;
+ 
+ 	if((err=get_user(len, ulen)))
+ 		return err;
+ 	if(len>klen)
+ 		len=klen;
+ 	if(len<0 || len> MAX_SOCK_STATE)
+ 		return -EINVAL;
+ 	if(len)
+ 	{
+ 		if(copy_to_user(ustate,kstate,len))
+ 			return -EFAULT;
+ 	}
+ 	/*
+ 	 *	"fromlen shall refer to the value before truncation.."
+ 	 *			1003.1g
+ 	 */
+ 	return __put_user(klen, ulen);
+ }
+ 
  /*
   *	Obtains the first available file descriptor and sets it up for use. 
   */
***************
*** 1085,1092 ****
--- 1112,1163 ----
  	return err;
  }
  
+ /*
+  *      Set the socket state information.
+  */
  
+ asmlinkage int
+ sys_setsockstate(int fd, struct sockstate *usockstate, int usockstate_len)
+ {
+ 	struct socket *sock;
+ 	int err;
+ 
+ 	lock_kernel();
+ 	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+ 	{
+ 		err = sock->ops->setstate(sock, usockstate, usockstate_len);
+ 		sockfd_put(sock);
+ 	}
+ 	unlock_kernel();
+ 	return err;
+ }
+ 
  /*
+  *      Get the socket state information.
+  */
+ 
+ asmlinkage int
+ sys_getsockstate(int fd, struct sockstate *usockstate, int *usockstate_len)
+ {
+ 	struct socket *sock;
+ 	char state[MAX_SOCK_STATE];
+ 	int len, err;
+ 
+ 	lock_kernel();
+ 	if ((sock = sockfd_lookup(fd, &err))!=NULL)
+ 	{
+ 		err = sock->ops->getstate(sock, (struct sockstate *)state,
+ 					  &len);
+ 		if (!err)
+ 			err=move_state_to_user(state, len, usockstate,
+ 					       usockstate_len);
+ 		sockfd_put(sock);
+ 	}
+ 	unlock_kernel();
+ 	return err;
+ }
+ 
+ /*
   *	Shutdown a socket.
   */
  
***************
*** 1302,1310 ****
  
  /* Argument list sizes for sys_socketcall */
  #define AL(x) ((x) * sizeof(unsigned long))
! static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
  				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
! 				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
  #undef AL
  
  /*
--- 1373,1382 ----
  
  /* Argument list sizes for sys_socketcall */
  #define AL(x) ((x) * sizeof(unsigned long))
! static unsigned char nargs[20]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
  				AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
! 				AL(6),AL(2),AL(5),AL(5),AL(3),AL(3),
!                                 AL(3),AL(3)};
  #undef AL
  
  /*
***************
*** 1321,1327 ****
  	unsigned long a0,a1;
  	int err;
  
! 	if(call<1||call>SYS_RECVMSG)
  		return -EINVAL;
  
  	/* copy_from_user should be SMP safe. */
--- 1393,1399 ----
  	unsigned long a0,a1;
  	int err;
  
! 	if(call<1||call>SYS_SETSOCKSTATE)
  		return -EINVAL;
  
  	/* copy_from_user should be SMP safe. */
***************
*** 1385,1390 ****
--- 1457,1470 ----
  			break;
  		case SYS_RECVMSG:
  			err = sys_recvmsg(a0, (struct msghdr *) a1, a[2]);
+ 			break;
+ 		case SYS_SETSOCKSTATE:
+ 			err = sys_setsockstate(a0, (struct sockstate *)a1,
+ 					       a[2]);
+ 			break;
+ 		case SYS_GETSOCKSTATE:
+ 			err = sys_getsockstate(a0, (struct sockstate *)a1,
+ 					       (int *)a[2]);
  			break;
  		default:
  			err = -EINVAL;
Index: migrate.kernel/net/ipv4/Config.in
diff -c migrate.kernel/net/ipv4/Config.in:1.1.1.1 migrate.kernel/net/ipv4/Config.in:1.3
*** migrate.kernel/net/ipv4/Config.in:1.1.1.1	Wed Jun  7 17:26:44 2000
--- migrate.kernel/net/ipv4/Config.in	Sun Jul 30 12:01:35 2000
***************
*** 74,79 ****
--- 74,85 ----
    fi
  fi
  bool 'IP: TCP syncookie support (not enabled per default)' CONFIG_SYN_COOKIES
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then 
+   bool 'IP: TCP migrate support (not enabled per default)' CONFIG_MIGRATE
+     if [ "$CONFIG_MIGRATE" = "y" ]; then
+       bool '      MIRACL Crypto support (required for ECC)' CONFIG_MIRACL
+     fi
+ fi
  comment '(it is safe to leave these untouched)'
  #bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
  tristate 'IP: Reverse ARP' CONFIG_INET_RARP
Index: migrate.kernel/net/ipv4/Makefile
diff -c migrate.kernel/net/ipv4/Makefile:1.1.1.1 migrate.kernel/net/ipv4/Makefile:1.4
*** migrate.kernel/net/ipv4/Makefile:1.1.1.1	Mon Jan  4 18:31:35 1999
--- migrate.kernel/net/ipv4/Makefile	Tue Aug  1 17:27:17 2000
***************
*** 105,110 ****
--- 105,115 ----
  IPV4_OBJS += ipconfig.o
  endif
  
+ ifeq ($(CONFIG_MIGRATE),y)
+ IPV4_OBJS += migrate.o
+ CFLAGS_migrate.o = -I$(TOPDIR)/crypto/miracl -I$(TOPDIR)/include/miracl
+ endif
+ 
  ifdef CONFIG_INET
  O_OBJS := $(IPV4_OBJS)
  OX_OBJS := $(IPV4X_OBJS)
Index: migrate.kernel/net/ipv4/af_inet.c
diff -c migrate.kernel/net/ipv4/af_inet.c:1.1.1.2 migrate.kernel/net/ipv4/af_inet.c:1.2
*** migrate.kernel/net/ipv4/af_inet.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/af_inet.c	Wed Nov 22 14:27:52 2000
***************
*** 253,258 ****
--- 253,287 ----
  	return sk->prot->getsockopt(sk,level,optname,optval,optlen);
  }
  
+ 
+ /*
+  *	Set socket state on an inet socket.
+  */
+  
+ int
+ inet_setsockstate(struct socket *sock, struct sockstate *ustate,
+ 		  int ustate_len)
+ {
+ 	struct sock *sk=sock->sk;
+ 	if (sk->prot->setsockstate==NULL)
+ 		return(-EOPNOTSUPP);
+ 	return sk->prot->setsockstate(sk,ustate,ustate_len);
+ }
+ 
+ /*
+  *	Get socket state on an AF_INET socket.
+  */
+ 
+ int
+ inet_getsockstate(struct socket *sock, struct sockstate *ustate,
+ 		  int *ustate_len)
+ {
+ 	struct sock *sk=sock->sk;
+ 	if (sk->prot->getsockstate==NULL)
+ 		return(-EOPNOTSUPP);
+ 	return sk->prot->getsockstate(sk,ustate,ustate_len);
+ }
+ 
  /*
   *	Automatically bind an unbound socket.
   */
***************
*** 966,972 ****
  	inet_getsockopt,
  	sock_no_fcntl,
  	inet_sendmsg,
! 	inet_recvmsg
  };
  
  struct proto_ops inet_dgram_ops = {
--- 995,1003 ----
  	inet_getsockopt,
  	sock_no_fcntl,
  	inet_sendmsg,
! 	inet_recvmsg,
! 	inet_setsockstate,
! 	inet_getsockstate
  };
  
  struct proto_ops inet_dgram_ops = {
***************
*** 987,993 ****
  	inet_getsockopt,
  	sock_no_fcntl,
  	inet_sendmsg,
! 	inet_recvmsg
  };
  
  struct net_proto_family inet_family_ops = {
--- 1018,1026 ----
  	inet_getsockopt,
  	sock_no_fcntl,
  	inet_sendmsg,
! 	inet_recvmsg,
! 	inet_setsockstate,
! 	inet_getsockstate
  };
  
  struct net_proto_family inet_family_ops = {
Index: migrate.kernel/net/ipv4/migrate.c
diff -c /dev/null migrate.kernel/net/ipv4/migrate.c:1.6
*** /dev/null	Wed Aug 15 18:53:08 2001
--- migrate.kernel/net/ipv4/migrate.c	Wed Nov 22 15:31:29 2000
***************
*** 0 ****
--- 1,1006 ----
+ /*
+  * Copyright (C) 2000 Massachusetts Institute of Technology 
+  *
+  * This software is being provided by the copyright holders under the
+  * following license. By obtaining, using and/or copying this software,
+  * you agree that you have read, understood, and will comply with the
+  * following terms and conditions:
+  *
+  * Permission to use, copy, modify, distribute, and sell this software
+  * and its documentation for any purpose and without fee or royalty is
+  * hereby granted, provided that the full text of this NOTICE appears on
+  * ALL copies of the software and documentation or portions thereof,
+  * including modifications, that you make.
+  *
+  * THIS SOFTWARE IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO
+  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE,
+  * BUT NOT LIMITATION, COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS OR
+  * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR
+  * THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE ANY
+  * THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS. COPYRIGHT
+  * HOLDERS WILL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE OR
+  * DOCUMENTATION.
+  *
+  * The name and trademarks of copyright holders may NOT be used in
+  * advertising or publicity pertaining to the software without specific,
+  * written prior permission. Title to copyright in this software and any
+  * associated documentation will at all times remain with copyright
+  * holders. See the file AUTHORS which should have accompanied this software
+  * for a list of all copyright holders.
+  *
+  * This file may be derived from previously copyrighted software. This
+  * copyright applies only to those changes made by the copyright
+  * holders listed in the AUTHORS file. The rest of this file is covered by
+  * the copyright notices, if any, listed below.
+  *
+  * Migrate TCP option handling 
+  *
+  * Version:   $Id: migrate.c,v 1.6 2000/11/22 20:31:29 snoeren Exp $
+  *
+  */
+ 
+ #include <net/tcp.h>
+ 
+ #include <linux/inet.h>
+ #include <linux/proc_fs.h>
+ #include <linux/random.h>
+ 
+ extern int sysctl_tcp_migrate;
+ int sysctl_tcp_migrate_curve = 0;
+ 
+ /* From tcp_ipv4.c */
+ extern struct or_calltable or_ipv4;
+ extern void __tcp_v4_rehash(struct sock *sk);
+ extern int tcp_v4_unique_address(struct sock *sk);
+ extern void tcp_v4_send_reset(struct sk_buff *skb);
+ extern void tcp_v4_send_synack(struct sock *sk, struct open_request *req);
+ extern inline struct ip_options *tcp_v4_save_options(struct sock *sk,
+ 						     struct sk_buff *skb);
+ 
+ /* From sha.c */
+ void sha1(__u8 *mem, __u32 length, __u32 *buf);
+ 
+ struct mhe *tcp_migrate_hash[TCP_MHTABLE_SIZE];
+ 
+ #define CURVE_MAX_BITS 200
+ 
+ #ifdef CONFIG_MIRACL
+ 
+ #include <linux/malloc.h>
+ #include <p1363/p1363.h>
+ 
+ static octet       migrate_seed;
+ static ec2_domain* migrate_curves[CURVE_MAX];
+ 
+ struct domain_type {
+   int bits, A, aa, bb, cc;
+   char *b;
+   char *r;
+   char *gx;
+   char *gy;
+ };
+ 
+ static struct domain_type migrate_std_curves[CURVE_MAX] = {
+   { 191, 1, 9, 0, 0,
+     "52",
+     "1569275433846670190958947355795555763355389433009269561601",
+     "87193012393278900974214960573615980372488130485014071117",
+     "497005083962043850835303298710410275953660542564983531810"}
+ };
+ 
+ /* From p1363.c:- converts from big to octet format */
+ static void
+ convert_big_octet(_MIPD_ big w,octet *s)
+ { 
+     int i;
+     for (i=0;i<s->len;i++) s->val[i]=0;
+     s->len=(short)big_to_bytes(_MIPP_ 0,w,s->val);
+ }
+ 
+ inline void
+ shift_left(octet *o)
+ {
+   int i;
+ 
+   for(i=0; o->val[i]==0; i++)
+     ;
+   if(i) {
+     o->len -= i;
+     memmove(o->val,&o->val[i],o->len);
+   }
+ }
+ 
+ static void
+ init_miracl_curves(void)
+ {
+   int         dom,bits,bytes,err;
+   ec2_domain *domain;
+   miracl     *mr_mip;
+   big         q,r,gx,gy,b,k;
+ 
+   for(dom = 0; dom < CURVE_MAX; dom++) {
+     migrate_curves[dom] = domain = kmalloc(sizeof(ec2_domain), GFP_KERNEL);
+     bits = migrate_std_curves[dom].bits;
+     domain->words = 3 + (bits/MIRACL);
+     bytes = 2 + bits/8;
+     if(!(mr_mip=mirsys(domain->words,0)))
+       panic("MIRACL out of memory");
+ 
+     mr_mip->ERCON=TRUE;
+     mr_mip->fin=FALSE;
+ 
+     q=mirvar(_MIPP_ 0);
+     r=mirvar(_MIPP_ 0);
+     gx=mirvar(_MIPP_ 0);
+     gy=mirvar(_MIPP_ 0);
+     b=mirvar(_MIPP_ 0);
+     k=mirvar(_MIPP_ 0);
+ 
+     if(mr_mip->ERNUM)
+       panic("MIRACL out of memory");
+ 
+     cinstr(_MIPP_ b, migrate_std_curves[dom].b);
+     cinstr(_MIPP_ r, migrate_std_curves[dom].r);
+     cinstr(_MIPP_ gx, migrate_std_curves[dom].gx);
+     cinstr(_MIPP_ gy, migrate_std_curves[dom].gy);
+ 
+     domain->M = migrate_std_curves[dom].bits;
+     domain->A = migrate_std_curves[dom].A;
+ 
+     OCTET_INIT(&domain->B,bytes);
+     OCTET_INIT(&domain->R,bytes);
+     OCTET_INIT(&domain->Gx,bytes);
+     OCTET_INIT(&domain->Gy,bytes);
+     OCTET_INIT(&domain->K,bytes);
+     OCTET_INIT(&domain->IK,bytes);
+ 
+     domain->H = (1 + logb2(_MIPP_ r))/2;
+     domain->a = migrate_std_curves[dom].aa;
+     domain->b = migrate_std_curves[dom].bb;
+     domain->c = migrate_std_curves[dom].cc;
+ 
+     expint(_MIPP_ 2,bits,q);    /* q=2^m */
+ 
+     nroot(_MIPP_  q,2,k);
+     incr(_MIPP_ k,1,k);
+     multiply(_MIPP_ k,k,k);
+     divide(_MIPP_ k,r,k);        /* gets co-factor k */
+    
+     convert_big_octet(_MIPP_ b, &domain->B);
+     convert_big_octet(_MIPP_ r, &domain->R);
+     convert_big_octet(_MIPP_ gx, &domain->Gx);
+     convert_big_octet(_MIPP_ gy, &domain->Gy);
+     convert_big_octet(_MIPP_ k, &domain->K);
+     xgcd(_MIPP_ k, r, k, k, k);
+     convert_big_octet(_MIPP_ k, &domain->IK);
+     domain->PC.store = 0;
+ 
+     mirkill(_MIPP_ k);
+     mirkill(_MIPP_ b);
+     mirkill(_MIPP_ gx);
+     mirkill(_MIPP_ gy);
+     mirkill(_MIPP_ r);
+     mirkill(_MIPP_ q);
+     err=mr_mip->ERNUM;
+     mirexit(_MIPPO_ );
+ 
+     if(err)
+       panic ("MIRACL error");
+ 
+     if(EC2_DOMAIN_VALIDATE(NULL, domain)!=0)
+       panic ("ECC domain %d parameters invalid", dom);
+   }
+ }
+ #endif /* CONFIG_MIRACL */
+ 
+ 
+ void
+ migrate_genkey(__u8 curveName, __u8 *key, __u8 *pub)
+ {
+ #ifdef CONFIG_MIRACL
+   if(curveName && (curveName <= CURVE_MAX)) {
+ 
+     __u8 lsb;
+     octet s, x;
+ 
+     OCTET_INIT(&s, 27);
+     OCTET_INIT(&x, 27);
+ 
+     lsb = EC2_KEY_PAIR_GENERATE(NULL, migrate_curves[curveName-1],
+ 				  &migrate_seed, &s, &x, NULL);
+     if(!x.len && EC2_PUBLIC_KEY_VALIDATE(NULL, migrate_curves[curveName-1],
+ 					 TRUE, &x, NULL, lsb))
+       printk("Migrate ECDH keys failed validation!\n");
+ 
+     OCTET_PAD(&s, 25);
+     OCTET_PAD(&x, 25);
+     memcpy(pub, x.val, x.len);
+     memcpy(key, s.val, s.len);
+ 
+     if(lsb) pub[0] |= 0x80;
+ 
+     OCTET_KILL(&s);
+     OCTET_KILL(&x);
+   } else
+ #endif /* CONFIG_MIRACL */
+   {
+     memset(key, 0, 25);
+     memset(pub, 0, 25);
+   }
+ }
+ 
+ /* Takes sequence numbers in network byte order and generates a token */
+ static __u64
+ gentoken(__u32 ni, __u32 nj, __u8 *key)
+ {
+   __u8 buf[33];
+   __u32 hash[5];  
+   __u64 token;
+ 
+   memcpy(&buf[0], &ni, sizeof(ni));
+   memcpy(&buf[4], &nj, sizeof(nj));
+   memcpy(&buf[8], key, 25);
+   sha1((__u8*)&buf, 33, (__u32*)&hash);
+   token = hash[0];
+   token = (token << 32) | hash[1];
+   return token;
+ }
+ 
+ static __u64
+ genrequest(__u32 ni, __u32 nj, __u8 *key, __u32 s, __u8 reqNo)
+ {
+   __u8 buf[38];
+   __u32 hash[5];
+   __u64 request;
+ 
+   memcpy(&buf[0], &ni, sizeof(ni));
+   memcpy(&buf[4], &nj, sizeof(nj));
+   memcpy(&buf[8], key, 25);
+   memcpy(&buf[33], &s, sizeof(s));
+   memcpy(&buf[37], &reqNo, sizeof(reqNo));
+ 
+   sha1((__u8*)&buf, 38, (__u32*)&hash);
+   request = hash[0];
+   request = (request << 32) | hash[1];
+   return request;
+ }
+ 
+ static void
+ diffie_hellman(int curveName, __u8 *pub, __u8 *key, __u8* shared)
+ {
+ #ifdef CONFIG_MIRACL
+     int tmp;
+     octet pkey, s, z;
+ 
+     OCTET_INIT(&pkey, 27);
+     OCTET_INIT(&s, 27);
+     OCTET_INIT(&z, 27);
+ 
+     memcpy(pkey.val, pub, 25);
+     pkey.len = 25;
+     if(pkey.val[0] & 0x80)
+       tmp = 1;
+     else
+       tmp = 0;
+     pkey.val[0] &= 0x7f;
+ 
+     memcpy(s.val, key, 25);
+     s.len = 25;
+ 
+     shift_left(&s);
+     shift_left(&pkey);
+ 
+     EC2SVDP_DH(NULL,migrate_curves[curveName-1],&s,&pkey,NULL,tmp,&z);
+ 
+     OCTET_PAD(&z, 25);
+     memcpy(shared, z.val, 25);
+ 
+     OCTET_KILL(&s);
+     OCTET_KILL(&pkey);
+     OCTET_KILL(&z);
+ #else
+     memset(shared, 0, 25);
+ #endif
+ }
+ 
+ void
+ migrate_perm_process_active(struct sock *sk, struct tcp_opt *tp)
+ {
+   if (tp->curveName) {
+ 
+     int tmp;
+     __u8 pkey[25];
+ 
+     tmp = htonl(tp->rcv_tsval);
+     memcpy(pkey, &tmp, 4);
+     tmp = htonl(tp->rcv_tsecr);
+     memcpy(&pkey[4], &tmp, 4);
+     memcpy(&pkey[8], tp->rcv_ecdh, 17);
+ 
+     diffie_hellman(tp->curveName, pkey, tp->key, tp->key);
+   } else
+     memset(tp->key, 0, 25);
+ 
+   tp->token = gentoken(htonl(tp->snt_isn), htonl(tp->rcv_isn),
+ 		       tp->key);
+   tcp_v4_migrate_hash(sk);
+ }
+ 
+ void
+ migrate_perm_process_passive(struct open_request *req, struct tcp_opt *tp)
+ {
+   if (req->curveName) {
+ 
+     int tmp;
+     __u8 pkey[25];
+ 
+     tmp = htonl(req->ts_recent);
+     memcpy(pkey, &tmp, 4);
+     tmp = htonl(req->ts_tsecr);
+     memcpy(&pkey[4], &tmp, 4);
+     memcpy(&pkey[8], req->rcv_ecdh, 17);
+ 
+     diffie_hellman(tp->curveName, pkey, req->key, tp->key);
+   } else
+     memset(tp->key, 0, 25);
+ 
+   tp->token = gentoken(htonl(req->rcv_isn), htonl(req->snt_isn),
+ 		       tp->key);
+ }
+ 
+ #ifdef CONFIG_PROC_FS
+ 
+ struct proc_dir_entry *proc_net_migrate;
+ 
+ static int
+ migrate_write_proc(struct file *file, const char *buffer,
+ 		   unsigned long count, void *data)
+ {
+         struct sockaddr_in addr;
+         struct proc_dir_entry *de;
+ 	struct mhe *mhe;
+ 	struct tcp_opt *tp;
+ #define TMPBUFLEN 20
+ 	char buf[TMPBUFLEN], *p;
+ 	int left, len, tmp;
+ 	unsigned long val;
+ 
+ 	de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip;
+ 	if (!de || !de->data)
+ 		return -ENOTDIR;
+ 
+ 	mhe = (struct mhe*) de->data;
+ 	if (!mhe || !mhe->sk)
+ 		return -ENOTDIR;
+ 
+ 	/* Parse user input */
+ 	if(!count)
+ 	  return 0;
+ 	left = count - 1;
+ 	
+ 	/* Chew up whitespace */
+ #define isspace(c)	((c) == ' ')
+ 	while (left) {
+ 	  char c;
+ 	  if(get_user(c,(char *) buffer))
+ 	    return -EFAULT;
+ 	  if (!isspace(c))
+ 	    break;
+ 	    left--;
+ 	    ((char *) buffer)++;
+ 	}
+ 	if (!left)
+ 	  goto bad;
+ 	len = left;
+ 
+ 	/* Don't buffer overflow */
+ 	if (len > TMPBUFLEN - 1)
+ 	  len = TMPBUFLEN - 1;
+ 	if(copy_from_user(buf, buffer, len))
+ 	  return -EFAULT;
+ 	buf[len] = 0;
+ 	p = buf;
+ 	val = simple_strtoul(p, &p, 0);
+ 	len = p - buf;
+ 
+ 	/* Punt if we couldn't parse the number */
+ 	if ((len < left) && *p && !isspace(*p))
+ 	  goto bad;
+ 
+ 	/* Migrate the connection */
+ 	tp = &(mhe->sk->tp_pinfo.af_tcp);
+ 	addr.sin_family = AF_INET;
+ 	addr.sin_addr.s_addr = htonl(val);
+ 	tmp=tp->af_specific->migrate(mhe->sk, (struct sockaddr *)&addr,
+ 				     sizeof(struct sockaddr), NULL, 0);
+ 			
+ 	if (tmp)
+ 	  return(tmp);
+ 
+ 	return len;
+ 
+ bad:
+ 	return -EINVAL;
+ }
+ 
+ struct proc_dir_entry proc_conn = {
+ 	0, 0, NULL,
+ 	S_IFREG | S_IWUSR | S_IRUGO, 1, 0, 0,
+ 	0, &proc_net_inode_operations,
+ 	NULL, NULL,
+ 	NULL, NULL, NULL,
+ 	NULL, NULL, migrate_write_proc
+ };
+ 
+ int
+ migrate_proc_register(struct proc_dir_entry *ent)
+ {
+ 	if (!proc_net_migrate) return -1;
+ 	return proc_register(proc_net_migrate, ent);
+ }
+ 
+ void
+ migrate_proc_unregister(struct proc_dir_entry *ent)
+ {
+         if (!proc_net_migrate) return;
+ 	proc_unregister(proc_net_migrate, ent->low_ino);
+ }
+ 
+ #endif
+ 
+ 
+ static __inline__ int
+ tcp_mhashfn(unsigned short num)
+ {
+   return num & (TCP_MHTABLE_SIZE - 1);
+ }
+ 
+ /* We have a seperate hash for migrate connection ids */
+ 
+ static __inline__ int
+ tcp_sk_migrate_hashfn(struct sock *sk)
+ {
+         __u16 lport = sk->num;
+ 
+ 	return tcp_mhashfn(lport);
+ }
+ 
+ void
+ tcp_v4_migrate_hash(struct sock *sk)
+ {
+ 	struct mhe **mhp;
+ 	struct mhe *mhe;
+ 
+ 	if(sysctl_tcp_migrate && (sk->state != TCP_LISTEN) &&
+ 	   sk->tp_pinfo.af_tcp.migrate_ok) {
+ 
+ 	  if((mhe = kmalloc(sizeof(struct mhe), GFP_ATOMIC))) {
+ 	    mhe->sk = sk;
+ 
+ #ifdef CONFIG_PROC_FS
+ 	    if((mhe->proc_entry = kmalloc(sizeof(struct proc_dir_entry),
+ 					  GFP_ATOMIC))) {
+ 	      memcpy(mhe->proc_entry, &proc_conn, sizeof(proc_conn));
+ 	      if((mhe->proc_entry->name = kmalloc(45, GFP_ATOMIC))) {
+ 		sprintf((char *)mhe->proc_entry->name,
+ 			"%d.%d.%d.%d:%hd->%s:%hd",
+ 			(sk->rcv_saddr & 0xff),
+ 			((sk->rcv_saddr >> 8) & 0xff),
+ 			((sk->rcv_saddr >> 16) & 0xff),
+ 			((sk->rcv_saddr >> 24) & 0xff), ntohs(sk->sport),
+ 			in_ntoa(sk->daddr), ntohs(sk->dport));
+ 		mhe->proc_entry->namelen = strlen(mhe->proc_entry->name);
+ 		mhe->proc_entry->uid=(sk->socket?sk->socket->inode->i_uid:0); 
+ 		mhe->proc_entry->data = mhe;
+ 	      }
+ 	      migrate_proc_register(mhe->proc_entry);
+ 	    } else
+ 	      mhe->proc_entry = NULL;
+ #endif
+ 
+ 	    mhp = &tcp_migrate_hash[tcp_sk_migrate_hashfn(sk)];
+ 	  
+ 	    if((mhe->next = *mhp) != NULL)
+ 	      (*mhp)->pprev = &mhe->next;
+ 	    *mhp = mhe;
+ 	    mhe->pprev = mhp;
+ 	  } else {
+ 	    printk("Unable to create migrate hash entry\n");
+ 	  }
+ 	}
+ }
+ 
+ void
+ tcp_v4_migrate_unhash(struct sock *sk)
+ {
+ 	struct mhe *mhe;
+ 
+         if (sk->tp_pinfo.af_tcp.migrate_ok) {	  
+ 	  for(mhe=tcp_migrate_hash[tcp_mhashfn(sk->num)]; mhe; mhe=mhe->next) {
+ 	    if(sk==mhe->sk) {
+ 	      if(mhe->pprev) {
+ 		if(mhe->next)
+ 		  mhe->next->pprev = mhe->pprev;
+ 		*mhe->pprev = mhe->next;
+ 		mhe->pprev = NULL;
+ 	      }
+ 	      mhe->sk = NULL;
+ #ifdef CONFIG_PROC_FS
+ 	      if(mhe->proc_entry) {
+ 		migrate_proc_unregister(mhe->proc_entry);
+ 		if(mhe->proc_entry->name) {
+ 		  kfree(mhe->proc_entry->name);
+ 		  mhe->proc_entry = NULL;
+ 		}
+ 		kfree(mhe->proc_entry);
+ 		mhe->proc_entry = NULL;
+ 	      }
+ #endif
+ 	      kfree(mhe);
+ 	      break;
+ 	    }
+ 	  }
+ 	}
+ }
+ 
+ /* Search for open connections with appropriate migrate cookie */
+ 
+ struct sock *
+ tcp_v4_lookup_migrate(struct tcp_opt *tp, u32 daddr, u16 hnum, int dif)
+ {
+ 	struct sock *sk;
+ 	struct mhe *mhe;
+ 
+ 	for(mhe = tcp_migrate_hash[tcp_mhashfn(hnum)]; mhe;
+ 	    mhe = mhe->next) {
+ 	  sk = mhe->sk;
+ 	  if(sk->num == hnum) {
+ 	    if(sk->rcv_saddr)
+ 	      if (sk->rcv_saddr != daddr)
+ 		continue;
+ 	    if (sk->bound_dev_if)
+ 	      if (sk->bound_dev_if != dif)
+ 		continue;
+ 	      if (sk->tp_pinfo.af_tcp.token != tp->rcv_token)
+ 		continue;
+ 	      return sk;
+ 	  }
+ 	}
+         return NULL;
+ }
+ 
+ 
+ static __inline int
+ greaterthan(__u8 seq1, __u8 seq2)
+ {
+   /* Standard TCP sequence number algorithm--arithemetic mod 2**7 */
+   return (__u8)(seq2 - seq1)%MIGRATE_PRELOAD > 0x40;
+ }
+ 
+ /* Essentially identical to connect_request, except we keep all the state
+    from the previous connection */
+ int
+ tcp_v4_migrate_request(struct sock *sk, struct sk_buff *skb)
+ {
+ 	struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ 	struct tcp_opt ptp;
+ 	struct open_request *req;
+ 	struct tcphdr *th = skb->h.th;
+ 	__u32 saddr = skb->nh.iph->saddr;
+ 	__u32 daddr = skb->nh.iph->daddr;
+ 	struct sock *newsk;
+ 	struct sk_buff *tskb;
+ 
+ 	net_statistics.MigratesRecv++;
+ 
+ 	if(!sk) {
+ 	  printk("Tried to migrate a NULL socket!\n");
+ 	  goto dead;
+ 	}
+ 
+ 
+ 	/* Check for a valid request */
+ 	if(!greaterthan(tp->rcv_reqNo&~MIGRATE_PRELOAD, tp->reqNo) ||
+ 	   tp->request != genrequest(htonl(tp->snt_isn), htonl(tp->rcv_isn),
+ 				     (__u8*)&tp->key,
+ 				     htonl(TCP_SKB_CB(skb)->seq),
+ 				     tp->rcv_reqNo&~MIGRATE_PRELOAD)) {
+ 	  printk("Recieved an invalid migrate request %d %d\n",
+ 		 tp->rcv_reqNo&~MIGRATE_PRELOAD, tp->reqNo);
+ 	  tcp_v4_send_reset(skb);
+ 	  return 0;
+ 	}
+ 
+ 	/* Check for preload */
+ 	if(tp->rcv_reqNo & MIGRATE_PRELOAD) {
+ 	  tp->rcv_reqNo &= ~MIGRATE_PRELOAD;
+ 	  printk("Received a pre-loaded migrate request\n");
+ 	  /* First, purge the out_of_order queue. */
+ 	  tskb = __skb_dequeue_tail(&tp->out_of_order_queue);
+ 	  if(tskb != NULL) {
+ 	    do {	net_statistics.OfoPruned += tskb->len; 
+ 	    kfree_skb(tskb);
+ 	    tskb = __skb_dequeue_tail(&tp->out_of_order_queue);
+ 	    } while(tskb != NULL);
+ 	    if(tp->sack_ok)
+ 	      tp->num_sacks = 0;
+ 	  }
+ 	}
+ 
+ 	tp->reqNo = tp->rcv_reqNo;
+ 
+ 	/* We no longer send a reset, we just ignore and move on */
+ 	if(sk->daddr==saddr && sk->dport==th->source) {
+ 	  printk("Trying to migrate to the same place, ignore\n");
+ 	  return 0;
+ 	}
+ 
+ 	/* If the socket is dead, don't accept the connection.	*/
+ 	if (sk->dead) 
+ 		goto dead; 
+ 
+ 	/* Reserve a temporary sk for uniqueness checks */
+ 	newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0);
+ 	if(newsk == NULL)
+ 	  return -ENOBUFS;
+ 
+ 	/* Check for uniqueness */
+ 	newsk->bound_dev_if = sk->bound_dev_if;
+         newsk->dport = th->source;
+ 	newsk->num = sk->num;
+ 	newsk->saddr = sk->saddr;
+ 	newsk->daddr = saddr;
+ 	newsk->rcv_saddr = sk->rcv_saddr;
+ 	
+ 	if (!tcp_v4_unique_address(newsk)) {
+ 	  printk("Migrate request failed uniqueness check\n");
+ 	  sk_free(newsk);
+ 	  goto dead;
+ 	}
+ 
+ 	sk_free(newsk);
+ 
+ 	req = tcp_openreq_alloc();
+ 
+ 	if (req == NULL) {
+ 		goto dead;
+ 	}
+ 
+ 	req->rcv_wnd = 0;		/* So that tcp_send_synack() knows! */
+ 	ptp.mss_clamp = 65535;
+ 	tcp_parse_options(NULL, th, &ptp, 0);
+ 	if (ptp.mss_clamp == 65535)
+ 		tp->mss_clamp = 576 - sizeof(struct iphdr) -
+ 		  sizeof(struct iphdr);
+ 	else
+ 	  tp->mss_clamp = ptp.mss_clamp;
+ 
+ 	if (sk->tp_pinfo.af_tcp.user_mss &&
+ 	    sk->tp_pinfo.af_tcp.user_mss < tp->mss_clamp)
+ 		tp->mss_clamp = sk->tp_pinfo.af_tcp.user_mss;
+ 	req->mss = tp->mss_clamp;
+ 
+ 	if (tp->saw_tstamp)
+ 		req->ts_recent = tp->rcv_tsval;
+ 	req->tstamp_ok = tp->tstamp_ok;
+ 	req->sack_ok = tp->sack_ok;
+ 	req->snd_wscale = tp->snd_wscale;
+ 	req->wscale_ok = tp->wscale_ok;
+ 	req->migrate_ok = tp->migrate_ok;
+ 	req->curveName = tp->curveName;
+ 	memcpy(&req->key, &tp->key, 25);
+ 	req->reqNo = tp->reqNo;
+ 	req->snt_reqNo = tp->snt_reqNo;
+ 	req->rmt_port = th->source;
+ #ifdef CONFIG_IP_TRANSPARENT_PROXY
+ 	req->lcl_port = th->dest ; /* LVE */
+ #endif
+ 	req->af.v4_req.loc_addr = daddr;
+ 	req->af.v4_req.rmt_addr = saddr;
+ 
+ 	/* Flag that we're migrating a connection */
+ 	tp->migrate = req->migrate = 1;
+ 
+ 	/* We use the same sequence space for the syn */
+ 	req->snt_isn = tp->snd_una - 1;
+ 
+ 	req->af.v4_req.opt = tcp_v4_save_options(sk, skb);
+ 
+ 	req->class = &or_ipv4;
+ 	req->retrans = 0;
+ 	req->sk = NULL;
+ 
+ 	/* Punt cached route */
+ 	dst_release(sk->dst_cache);
+ 	sk->dst_cache = NULL;
+ 	tp->rto = TCP_TIMEOUT_INIT;
+ 	tp->srtt = 0;
+ 
+ 	/* Need to put stuff in the hashes now, since we don't really have
+          * a listening socket that spawned us.
+          */
+ 
+ 	lock_sock(sk);
+ 	tcp_v4_migrate_unhash(sk);
+ 	sk->daddr = req->af.v4_req.rmt_addr;
+ 	sk->dport = req->rmt_port;
+ 
+ 	if(sk->state==TCP_MIGRATE_WAIT)
+ 	  net_delete_timer(sk);
+ 	else
+ 	  tp->mig_state = sk->state;
+ 	tcp_set_state(sk, TCP_SYN_RECV);
+ 
+ 	__tcp_v4_rehash(sk);
+ 	tcp_v4_migrate_hash(sk);
+ 	release_sock(sk);
+ 
+ 	tcp_v4_send_synack(sk, req);
+ 
+ 	req->expires = jiffies + TCP_TIMEOUT_INIT;
+ 	tcp_inc_slow_timer(TCP_SLT_SYNACK);
+ 	tcp_synq_queue(&sk->tp_pinfo.af_tcp, req);
+ 
+ 	return 0;
+ 
+ dead:
+ 	SOCK_DEBUG(sk, "Reset on %p: Migrate on dead socket.\n",sk);
+ 	net_statistics.MigratesFailed++;
+ 	return -ENOTCONN; /* send reset */
+ }
+ 
+ 
+ /* This initiates a migrate request. */
+ 
+ int
+ tcp_v4_migrate(struct sock *sk, struct sockaddr *uaddr, int addr_len,
+ 	       struct sk_buff *buff, int mtu)
+ {
+         struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
+ 	struct rtable *rt = NULL;
+ 	struct sock *newsk = NULL;
+ 	u32 saddr, daddr, nexthop;
+ 	int tmp;
+ 
+ 	if (!sk || !tp || !usin) {
+ 	  printk("Tried to migrate a NULL socket or NULL tp or NULL usin\n");
+ 	  return(-EINVAL);
+ 	}
+ 
+ 	if (addr_len < sizeof(struct sockaddr_in))
+ 	  return(-EINVAL);
+ 
+ 	if (!tp->migrate_ok)
+ 	  return(-ENOPROTOOPT);
+ 
+ 	/* Check to see if this is a pre-loaded connection */
+ 	if (sk->state == TCP_PRELOAD) {
+ 
+ 	  /* We'll fix this up when we get a response from the other end.
+ 	   * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT.
+ 	   */
+ 	  tp->tcp_header_len = sizeof(struct tcphdr) +
+ 	    (tp->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0);
+ 	  
+ 	  lock_sock(sk);
+ 	  tcp_init_xmit_timers(sk);
+ 	  tp->migrate = 2; /* Flag we're preloaded */
+ 	  goto migrequest;
+ 	}
+ 
+ 	/* Can only migrate open connections */
+ 	if ((sk->state != TCP_ESTABLISHED) && (sk->state != TCP_FIN_WAIT1))
+ 	  return(-EISCONN);
+ 
+ 	/* Don't allow a self-migration */
+ 	if (sk->saddr==usin->sin_addr.s_addr && sk->num==usin->sin_port)
+ 	  return -EINVAL;
+ 
+ 	if (usin->sin_family != AF_INET) {
+ 	  static int complained;
+ 	  if (usin->sin_family)
+ 	    return(-EAFNOSUPPORT);
+ 	  if (!complained++)
+ 	    printk(KERN_DEBUG "%s forgot to set AF_INET in "
+ 		   __FUNCTION__ "\n", current->comm);
+ 	}
+ 
+ 	saddr = usin->sin_addr.s_addr;
+       	nexthop = daddr = sk->daddr;
+ 	if (sk->opt && sk->opt->srr) {
+ 	  if (daddr == 0)
+ 	    return -EINVAL;
+ 	  nexthop = sk->opt->faddr;
+ 	}
+ 	
+ 	/* Find route from new address */
+ 	tmp = ip_route_connect(&rt, nexthop, saddr,
+ 			       RT_TOS(sk->ip_tos)|RTO_CONN|sk->localroute,
+ 			       sk->bound_dev_if);
+ 	if (tmp < 0)
+ 	  return tmp;
+ 
+ 	if (!rt || rt->rt_flags&(RTCF_MULTICAST|RTCF_BROADCAST)) {
+ 	  ip_rt_put(rt);
+ 	  return -ENETUNREACH;
+ 	}
+ 
+ 	/* Reserve a temporary sk for uniqueness checks */
+ 	newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0);
+ 	if(newsk == NULL) {
+ 	  ip_rt_put(rt);
+ 	  return -ENOBUFS;
+ 	}
+ 
+ 	/* Check for uniqueness */
+ 	newsk->bound_dev_if = sk->bound_dev_if;
+         newsk->dport = sk->dport;
+ 	newsk->num = usin->sin_port;
+ 	newsk->saddr = saddr;
+ 	newsk->daddr = rt->rt_dst;
+ 	if (sk->opt && sk->opt->srr)
+ 	  newsk->daddr = daddr;
+ 	newsk->rcv_saddr = rt->rt_src;
+ 	
+ 	if (!tcp_v4_unique_address(newsk)) {
+ 	  printk("Failed uniqueness check\n");
+ 	  ip_rt_put(rt);
+ 	  sk_free(newsk);
+ 	  return -EADDRNOTAVAIL;
+ 	}
+ 
+ 	sk_free(newsk);
+ 	
+ 	/* Allocate buffer space */
+ 	if (buff==NULL)
+ 	  buff = sock_wmalloc(sk, (MAX_HEADER + sk->prot->max_header),
+ 			      0, GFP_KERNEL);	
+ 	if (buff == NULL) {
+ 	  if(rt)
+ 	    ip_rt_put(rt);
+ 	  return -ENOBUFS;
+ 	}
+ 
+ 	/* Diddle with addresses */
+ 	lock_sock(sk);
+ 	tcp_v4_migrate_unhash(sk);
+ 	
+ 	sk->saddr = saddr;
+ 	sk->daddr = rt->rt_dst;
+ 	if (sk->opt && sk->opt->srr)
+ 	  sk->daddr = daddr;
+ 	sk->rcv_saddr = sk->saddr;
+ 	dst_release(xchg(&sk->dst_cache, rt));
+ 	tp->rto = TCP_TIMEOUT_INIT; /* We can't use timestamp values */
+ 	tp->srtt = 0;
+ 	mtu = sk->dst_cache->pmtu;
+ 
+ 	tp->ext_header_len = 0;
+ 	if (sk->opt)
+ 	  tp->ext_header_len = sk->opt->optlen;
+ 	
+ 	if (!ip_dont_fragment(sk, &rt->u.dst) &&
+ 	    rt->u.dst.pmtu > 576 && rt->rt_dst != rt->rt_gateway) {
+ 	  /* Clamp mss at maximum of 536 and user_mss.
+ 	     Probably, user ordered to override tiny segment size
+ 	     in gatewayed case.
+ 	  */
+ 	  tp->mss_clamp = max(tp->user_mss, 536);
+ 	}
+ 
+ 	tp->mig_state = sk->state;
+ 	tp->migrate = 1;	
+ 
+ 	/* tp->window_clamp = sk->dst_cache->window; */
+ 
+  migrequest:
+ 
+ 	/* If user gave his TCP_MAXSEG, record it to clamp */
+ 	if (tp->user_mss)
+ 		tp->mss_clamp = tp->user_mss;
+ 	tcp_sync_mss(sk, mtu);
+ 
+ 	/* Now unpleasant action: if initial pmtu is too low
+ 	   set lower clamp. I am not sure that it is good.
+ 	   To be more exact, I do not think that clamping at value, which
+ 	   is apparently transient and may improve in future is good idea.
+ 	   It would be better to wait until peer will returns its MSS
+ 	   (probably 65535 too) and now advertise something sort of 65535
+ 	   or at least first hop device mtu. Is it clear, what I mean?
+ 	   We should tell peer what maximal mss we expect to RECEIVE,
+ 	   it has nothing to do with pmtu.
+ 	   I am afraid someone will be confused by such huge value.
+ 	                                                   --ANK (980731)
+ 	 */
+ 	if (tp->mss_cache + tp->tcp_header_len - sizeof(struct tcphdr) <
+ 	    tp->mss_clamp )
+ 		tp->mss_clamp = tp->mss_cache + tp->tcp_header_len -
+ 		  sizeof(struct tcphdr);
+ 
+ 	/* Deal with rollover */
+ 	if(++tp->snt_reqNo==MIGRATE_PRELOAD)
+ 	  tp->snt_reqNo=0;
+ 
+ 	/* Create a migrate request */	
+ 	tp->request = genrequest(htonl(tp->snt_isn), htonl(tp->rcv_isn),
+ 				 (__u8*)&tp->key, htonl(tp->snd_una-1),
+ 				 tp->snt_reqNo);
+ 
+ 	/* Reserve space for headers. */
+ 	skb_reserve(buff, MAX_HEADER + sk->prot->max_header);
+ 
+ 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
+ 	TCP_SKB_CB(buff)->sacked = 0;
+ 	TCP_SKB_CB(buff)->urg_ptr = 0;
+ 	buff->csum = 0;
+ 
+ 	/*
+ 	tcp_select_initial_window(sock_rspace(sk)/2,tp->mss_clamp,
+ 				  &tp->rcv_wnd,
+ 				  &tp->window_clamp,
+ 				  tp->wscale_ok,
+ 				  &tp->rcv_wscale);
+ 	*/
+ 
+ 	/* Back up in sequence space -- we now send the last acknowleged
+            sequence number, so any retransmissions are after the SYN sequence
+            number in order to be compatible with some firewalls */
+ 
+ 	TCP_SKB_CB(buff)->seq = tp->snd_una - 1;
+ 	TCP_SKB_CB(buff)->end_seq = tp->snd_una;
+ 
+ 	/* Socket identity change complete, no longer
+ 	 * in TCP_ESTABLISH, so update our entry in the
+ 	 * hash tables.
+ 	 */
+ 	tcp_set_state(sk,TCP_SYN_SENT);
+ 	__tcp_v4_rehash(sk);
+ 	tcp_v4_migrate_hash(sk);
+ 
+ 	/* Send it off. */
+ 	__skb_queue_tail(&sk->write_queue, buff);
+ 	TCP_SKB_CB(buff)->when = tcp_time_stamp;
+ 	tp->packets_out++;
+ 	tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL));
+ 	net_statistics.MigratesSent++;
+ 
+ 	/* Timer for repeating the SYN until an answer. */
+ 	tcp_reset_xmit_timer(sk, TIME_RETRANS, tp->rto);
+ 
+ 	/* Now, it is safe to release the socket. */
+ 	release_sock(sk);
+ 
+ 	return 0;
+ }
+ 
+ void
+ migrate_init(void)
+ {
+   char seed[100];
+ 
+   printk(KERN_INFO
+ 	 "TCP Migrate support by Alex C. Snoeren <snoeren@lcs.mit.edu>\n");
+ 
+   memset(tcp_migrate_hash, 0, TCP_MHTABLE_SIZE*sizeof(struct mhe *));
+ 
+ #ifdef CONFIG_MIRACL
+   get_random_bytes(&seed, 100);
+   RANDOM_START(100, seed, &migrate_seed);
+   printk(KERN_INFO
+ 	 "MIRACL Crypto Library by Shamus Software, Ltd.\n");
+   init_miracl_curves();
+ #endif
+ 
+ #ifdef CONFIG_PROC_FS        
+   if (!proc_net_migrate) {
+     struct proc_dir_entry *ent;
+     ent = create_proc_entry("net/migrate", S_IFDIR, 0);
+     if (ent)
+       proc_net_migrate = ent;
+     else
+       printk("Could not create \"/proc/net/migrate\" entry\n");
+   }
+ #endif	
+ }
+ 
Index: migrate.kernel/net/ipv4/proc.c
diff -c migrate.kernel/net/ipv4/proc.c:1.1.1.2 migrate.kernel/net/ipv4/proc.c:1.3
*** migrate.kernel/net/ipv4/proc.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/proc.c	Wed Nov 22 14:41:37 2000
***************
*** 359,366 ****
  	len = sprintf(buffer,
  		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
  		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
! 		      " OutOfWindowIcmps LockDroppedIcmps SockMallocOOM\n" 	
! 		      "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
  		      net_statistics.SyncookiesSent,
  		      net_statistics.SyncookiesRecv,
  		      net_statistics.SyncookiesFailed,
--- 359,369 ----
  	len = sprintf(buffer,
  		      "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
  		      " EmbryonicRsts PruneCalled RcvPruned OfoPruned"
! 		      " OutOfWindowIcmps LockDroppedIcmps SockMallocOOM"
! 		      " MigratesSent MigratesRecv MigratesFailed"
! 		      " MigrateWaits MigrateTimeouts\n"
! 		      "TcpExt: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu"
! 		      " %lu %lu %lu %lu %lu\n",
  		      net_statistics.SyncookiesSent,
  		      net_statistics.SyncookiesRecv,
  		      net_statistics.SyncookiesFailed,
***************
*** 370,376 ****
  		      net_statistics.OfoPruned,
  		      net_statistics.OutOfWindowIcmps,
  		      net_statistics.LockDroppedIcmps,
! 		      net_statistics.SockMallocOOM);
  
  	if (offset >= len)
  	{
--- 373,384 ----
  		      net_statistics.OfoPruned,
  		      net_statistics.OutOfWindowIcmps,
  		      net_statistics.LockDroppedIcmps,
! 		      net_statistics.SockMallocOOM,
! 		      net_statistics.MigratesSent,
! 		      net_statistics.MigratesRecv,
! 		      net_statistics.MigratesFailed,
! 		      net_statistics.MigrateWaits,
! 		      net_statistics.MigrateTimeouts);
  
  	if (offset >= len)
  	{
Index: migrate.kernel/net/ipv4/raw.c
diff -c migrate.kernel/net/ipv4/raw.c:1.1.1.1 migrate.kernel/net/ipv4/raw.c:1.2
*** migrate.kernel/net/ipv4/raw.c:1.1.1.1	Mon Aug  9 15:04:41 1999
--- migrate.kernel/net/ipv4/raw.c	Wed Nov 22 14:27:52 2000
***************
*** 569,573 ****
  	0,				/* retransmits */
  	"RAW",				/* name */
  	0,				/* inuse */
! 	0				/* highestinuse */
  };
--- 569,575 ----
  	0,				/* retransmits */
  	"RAW",				/* name */
  	0,				/* inuse */
! 	0,				/* highestinuse */
! 	NULL,                           /* setsockstate */
! 	NULL                            /* getsockstate */
  };
Index: migrate.kernel/net/ipv4/sysctl_net_ipv4.c
diff -c migrate.kernel/net/ipv4/sysctl_net_ipv4.c:1.1.1.1 migrate.kernel/net/ipv4/sysctl_net_ipv4.c:1.2
*** migrate.kernel/net/ipv4/sysctl_net_ipv4.c:1.1.1.1	Wed Jun  7 17:26:44 2000
--- migrate.kernel/net/ipv4/sysctl_net_ipv4.c	Mon Jul 17 18:35:20 2000
***************
*** 51,56 ****
--- 51,58 ----
  extern int sysctl_tcp_timestamps;
  extern int sysctl_tcp_window_scaling;
  extern int sysctl_tcp_sack;
+ extern int sysctl_tcp_migrate;
+ extern int sysctl_tcp_migrate_curve;
  extern int sysctl_tcp_retrans_collapse;
  extern int sysctl_tcp_keepalive_time;
  extern int sysctl_tcp_keepalive_probes;
***************
*** 121,126 ****
--- 123,134 ----
           &proc_dointvec},
          {NET_IPV4_TCP_SACK, "tcp_sack",
           &sysctl_tcp_sack, sizeof(int), 0644, NULL,
+          &proc_dointvec},
+         {NET_IPV4_TCP_MIGRATE, "tcp_migrate",
+          &sysctl_tcp_migrate, sizeof(int), 0644, NULL,
+          &proc_dointvec},
+         {NET_IPV4_TCP_MIGRATE_CURVE, "tcp_migrate_curve",
+          &sysctl_tcp_migrate_curve, sizeof(int), 0644, NULL,
           &proc_dointvec},
          {NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse",
           &sysctl_tcp_retrans_collapse, sizeof(int), 0644, NULL,
Index: migrate.kernel/net/ipv4/tcp.c
diff -c migrate.kernel/net/ipv4/tcp.c:1.1.1.2 migrate.kernel/net/ipv4/tcp.c:1.5
*** migrate.kernel/net/ipv4/tcp.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/tcp.c	Wed Nov 22 14:41:37 2000
***************
*** 202,207 ****
--- 202,208 ----
   *		Eric Schenk	:	Fix fast close down bug with
   *					shutdown() followed by close().
   *		Andi Kleen :	Make poll agree with SIGIO
+  *              Alex C. Snoeren :       Support for MIGRATE_WAIT state
   *					
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
***************
*** 241,246 ****
--- 242,250 ----
   *				buffer that we have to finish sending
   *
   *	TCP_CLOSE		socket is finished
+  *
+  *      TCP_MIGRATE_WAIT        received a RST while in ESTABLISHED on a 
+  *                              connection with migrate permitted option
   */
  
  /*
***************
*** 621,627 ****
  
  int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
! 	int answ;
  
  	switch(cmd) {
  	case TIOCINQ:
--- 625,631 ----
  
  int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
  {
! 	int answ=0;
  
  	switch(cmd) {
  	case TIOCINQ:
***************
*** 645,650 ****
--- 649,682 ----
  			return(-EINVAL);
  		answ = sock_wspace(sk);
  		break;
+ #ifdef CONFIG_MIGRATE
+ 	case SIOCMIGRATE:
+ 	        {
+ 	                struct sockaddr uaddr;
+ 			struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ 			int tmp;
+ 
+ 			answ = 0;
+ 			tmp = copy_from_user(&uaddr, (caddr_t) arg,
+ 					     sizeof(struct sockaddr));
+ 
+ 			if (tmp)
+ 			  return(-EFAULT);
+ 
+ 			tmp=tp->af_specific->migrate(sk, &uaddr,
+ 						     sizeof(struct sockaddr),
+ 						     NULL,
+ 						     0);
+ 			
+ 			if (tmp)
+ 			  return(tmp);
+ 			
+ 			break;
+ 		}
+ 	case SIOCGMIGRATE:
+ 	        /* XXX: Return ISS, reqNo and key[] */
+ 	        break;
+ #endif
  	default:
  		return(-ENOIOCTLCMD);
  	};
***************
*** 775,781 ****
  
  	/* Wait for a connection to finish. */
  	flags = msg->msg_flags;
! 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))
  		if((err = wait_for_tcp_connect(sk, flags)) != 0)
  			goto out;
  
--- 807,814 ----
  
  	/* Wait for a connection to finish. */
  	flags = msg->msg_flags;
! 	if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT |
! 				 TCPF_MIGRATE_WAIT))
  		if((err = wait_for_tcp_connect(sk, flags)) != 0)
  			goto out;
  
***************
*** 1028,1034 ****
  	/* If we're closed, don't send an ack, or we'll get a RST
  	 * from the closed destination.
  	 */
! 	if (sk->state != TCP_CLOSE)
  		tcp_send_ack(sk);
  }
  
--- 1061,1067 ----
  	/* If we're closed, don't send an ack, or we'll get a RST
  	 * from the closed destination.
  	 */
! 	if ((sk->state != TCP_CLOSE) && (sk->state != TCP_MIGRATE_WAIT))
  		tcp_send_ack(sk);
  }
  
***************
*** 1420,1425 ****
--- 1453,1459 ----
    /* TCP_LAST_ACK	*/ TCP_LAST_ACK,
    /* TCP_LISTEN		*/ TCP_CLOSE,
    /* TCP_CLOSING	*/ TCP_CLOSING,
+   /* TCP_MIGRATE_WAIT   */ TCP_CLOSE,
  };
  
  static int tcp_close_state(struct sock *sk, int dead)
***************
*** 1459,1465 ****
  
  	/* If we've already sent a FIN, or it's a closed state, skip this. */
  	if ((1 << sk->state) &
! 	    (TCPF_ESTABLISHED|TCPF_SYN_SENT|TCPF_SYN_RECV|TCPF_CLOSE_WAIT)) {
  		lock_sock(sk);
  
  		/* Clear out any half completed packets.  FIN if needed. */
--- 1493,1500 ----
  
  	/* If we've already sent a FIN, or it's a closed state, skip this. */
  	if ((1 << sk->state) &
! 	    (TCPF_ESTABLISHED | TCPF_SYN_SENT | TCPF_SYN_RECV |
! 	     TCPF_CLOSE_WAIT | TCPF_MIGRATE_WAIT)) {
  		lock_sock(sk);
  
  		/* Clear out any half completed packets.  FIN if needed. */
***************
*** 1496,1507 ****
  		
  		iter = req;
  		req = req->dl_next;
! 		
  		if (iter->sk) {
  			tcp_close(iter->sk, 0);
  			sk->ack_backlog--;
  		} else {
! 			tcp_dec_slow_timer(TCP_SLT_SYNACK);
  			sk->tp_pinfo.af_tcp.syn_backlog--;
  		}
  		(*iter->class->destructor)(iter);
--- 1531,1542 ----
  		
  		iter = req;
  		req = req->dl_next;
! 
  		if (iter->sk) {
  			tcp_close(iter->sk, 0);
  			sk->ack_backlog--;
  		} else {
! 		        tcp_dec_slow_timer(TCP_SLT_SYNACK);
  			sk->tp_pinfo.af_tcp.syn_backlog--;
  		}
  		(*iter->class->destructor)(iter);
***************
*** 1796,1801 ****
--- 1831,1966 ----
  	if(copy_to_user(optval, &val,len))
  		return -EFAULT;
    	return 0;
+ }
+ 
+ 
+ int
+ tcp_setsockstate(struct sock *sk, struct sockstate *state, int state_len)
+ {
+         struct tcp_opt *utp = (struct tcp_opt *)state;
+         struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
+ 
+ 	/* These are required */
+ 
+ 	tp->write_seq = utp->write_seq;
+ 	tp->user_mss = utp->user_mss;
+ 
+ 	tp->rcv_nxt = utp->rcv_nxt;
+ 	tp->snd_nxt = utp->snd_nxt;
+ 	tp->snd_una = utp->snd_una;
+ 	tp->copied_seq = utp->copied_seq;
+ 	tp->window_clamp = utp->window_clamp;
+ 
+ 	/* The rest could be ignored... */
+ 
+ 	tp->rcv_tstamp = utp->rcv_tstamp;
+ 	tp->lrcvtime = utp->lrcvtime;
+ 
+ 	tp->ato = utp->ato;
+ 	tp->snd_wl1 = utp->snd_wl1;
+ 	tp->snd_wl2 = utp->snd_wl2;
+ 	tp->snd_wnd = utp->snd_wnd;
+ 	tp->pmtu_cookie = tp->pmtu_cookie;
+ 
+ 	tp->user_mss = utp->user_mss;
+ 
+ 	/* No timers */
+ 
+ 	/* Don't mess with out_of_order_queue, nor send, retrans heads */
+ 
+ 	tp->rcv_wup = utp->rcv_wup;
+ 	tp->write_seq = utp->write_seq;
+ 
+ 	tp->sack_ok = utp->sack_ok;
+ 	tp->migrate_ok = utp->migrate_ok;
+ 	tp->migrate = utp->migrate;
+ 
+ 	tp->saw_tstamp = utp->saw_tstamp;
+ 	tp->snd_wscale = utp->snd_wscale;
+ 	tp->rcv_wscale = utp->rcv_wscale;
+ 	tp->rexmt_done = utp->rexmt_done;
+ 	tp->rcv_tsval = utp->rcv_tsval;
+ 	tp->rcv_tsecr = utp->rcv_tsecr;
+ 	tp->ts_recent = utp->ts_recent;
+ 	tp->ts_recent_stamp = utp->ts_recent_stamp;
+ 
+ 	/* Punt SACK info */
+ 
+ 	tp->curveName = utp->curveName;
+ 	tp->reqNo = utp->reqNo;
+ 	tp->snt_reqNo = utp->snt_reqNo;
+ 	printk("Stuffing a socket with Migrate request %d\n", tp->snt_reqNo);
+ 	tp->rcv_reqNo = utp->rcv_reqNo;
+ 	tp->token = utp->token;
+ 	tp->rcv_token = utp->rcv_token;
+ 	tp->request = utp->request;
+ 	memcpy(tp->key, utp->key, 25);
+ 	memcpy(tp->snt_ecdh, utp->snt_ecdh, 25);
+ 	memcpy(tp->rcv_ecdh, utp->rcv_ecdh, 17);
+ 	tp->mig_state = utp->mig_state;
+ 	tp->snt_isn = utp->snt_isn;
+ 	tp->rcv_isn = utp->rcv_isn;
+ 
+ 	/* Leave probes untouched */
+ 
+ 	tp->probes_out = utp->probes_out;
+ 	tp->syn_seq = utp->syn_seq;
+ 	tp->fin_seq = utp->fin_seq;
+ 	tp->urg_seq = utp->urg_seq;
+ 	tp->urg_data = utp->urg_data;
+ 
+ 	tp->last_seg_size = utp->last_seg_size;
+ 	tp->rcv_mss = utp->rcv_mss;
+ 
+        	/* Punt partial writers */
+ 
+ 	/* SYN stuff not copied */
+ 
+ 	/* Questionable stuff */
+ 
+ 	tp->mss_cache = utp->mss_cache; /* XXX */
+ 
+ 	tp->ext_header_len = utp->ext_header_len; /* XXX */
+ 
+ 	sk->err = 0;
+ 	sk->state = TCP_PRELOAD;
+    
+ 	return 0;
+ 
+ 	/* These are explicitly reset during migration */
+ 
+ 	tp->tcp_header_len = utp->tcp_header_len;
+ 	tp->mss_clamp = utp->mss_clamp;
+ 	tp->rcv_wnd = utp->rcv_wnd;
+ 	tp->rto = utp->rto;
+ 	tp->srtt = utp->srtt;
+ 	tp->mdev = utp->mdev;
+ 
+ 	tp->packets_out = utp->packets_out;
+ 	tp->fackets_out = utp->fackets_out;
+ 	tp->retrans_out = utp->retrans_out;
+ 	tp->high_seq = utp->high_seq;
+ 	tp->snd_ssthresh = utp->snd_ssthresh;
+ 	tp->snd_cwnd_cnt = utp->snd_cwnd_cnt;
+ 	tp->dup_acks = utp->dup_acks;
+ 	tp->delayed_acks = utp->delayed_acks;
+ 	tp->pending = utp->pending;
+ 	tp->retransmits = utp->retransmits;
+ 	tp->last_ack_sent = utp->last_ack_sent;
+ 	tp->backoff = utp->backoff;
+ 	tp->snd_cwnd = utp->snd_cwnd;
+ }
+ 
+ 
+ int
+ tcp_getsockstate(struct sock *sk, struct sockstate *state, int *state_len)
+ {
+ 	memcpy(state, &sk->tp_pinfo.af_tcp, sizeof(struct tcp_opt));
+ 	/* Store the socket state in mig_state */
+ 	((struct tcp_opt *) state)->mig_state = sk->state;
+ 	*state_len = sizeof(struct tcp_opt);
+ 
+         return 0;
  }
  
  void tcp_set_keepalive(struct sock *sk, int val)
Index: migrate.kernel/net/ipv4/tcp_input.c
diff -c migrate.kernel/net/ipv4/tcp_input.c:1.1.1.2 migrate.kernel/net/ipv4/tcp_input.c:1.6
*** migrate.kernel/net/ipv4/tcp_input.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/tcp_input.c	Wed Nov 22 14:41:37 2000
***************
*** 54,61 ****
   *					connections with MSS<min(MTU,ann. MSS)
   *					work without delayed acks. 
   *		Andi Kleen:		Process packets with PSH set in the
!  *					fast path.
!  *		Vincent Zweije		Fix TIME-WAIT FIN ACK bug.
   */
  
  #include <linux/config.h>
--- 54,62 ----
   *					connections with MSS<min(MTU,ann. MSS)
   *					work without delayed acks. 
   *		Andi Kleen:		Process packets with PSH set in the
!  * 				        fast path.
!  *              Vincent Zweije          Fix TIME-WAIT FIN ACK bug.
!  *              Alex C. Snoeren:        Implemented Migrate options.
   */
  
  #include <linux/config.h>
***************
*** 78,83 ****
--- 79,85 ----
  int sysctl_tcp_timestamps = 1;
  int sysctl_tcp_window_scaling = 1;
  int sysctl_tcp_sack = 1;
+ int sysctl_tcp_migrate = 0;
  
  int sysctl_tcp_syncookies = SYNC_INIT; 
  int sysctl_tcp_stdurg;
***************
*** 269,275 ****
  }
  
  /* When we get a reset we do this. */
! static void tcp_reset(struct sock *sk)
  {
  	unsigned char orig_state = sk->state;
  
--- 271,280 ----
  }
  
  /* When we get a reset we do this. */
! #ifndef CONFIG_MIGRATE
! static
! #endif
! void tcp_reset(struct sock *sk)
  {
  	unsigned char orig_state = sk->state;
  
***************
*** 296,302 ****
  		sk->dport = 0;
  		sk->daddr = 0;
  		sk->num = 0;
! 		tcp_clear_xmit_timer(sk, TIME_RETRANS);
  	}
  	sk->shutdown = SHUTDOWN_MASK;
  	if (!sk->dead) 
--- 301,307 ----
  		sk->dport = 0;
  		sk->daddr = 0;
  		sk->num = 0;
!                 tcp_clear_xmit_timer(sk, TIME_RETRANS);
  	}
  	sk->shutdown = SHUTDOWN_MASK;
  	if (!sk->dead) 
***************
*** 420,426 ****
  						}
  					}
  					break;
- 
  				case TCPOPT_SACK:
  					if((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) &&
  					   sysctl_tcp_sack && (sk != NULL) && !th->syn) {
--- 425,430 ----
***************
*** 434,439 ****
--- 438,479 ----
  							tcp_sacktag_write_queue(sk, sackp, num_sacks);
  						}
  					}
+ #ifdef CONFIG_MIGRATE
+ 					break;
+ 				case TCPOPT_MIGRATE_PERM:
+ 				  if(th->syn && sysctl_tcp_migrate &&
+ 				     opsize >= TCPOLEN_MIGRATE_SHORT &&
+ 				     !no_fancy) {
+ 				    if(tp->migrate_ok && *ptr && 
+ 				       (tp->curveName !=*ptr)) {
+ 				      tp->migrate_ok = 0;
+ 				      printk("Migrate curve clash\n");
+ 				    } else {
+ 				      tp->migrate_ok = 1;
+ 				      if((tp->curveName=*ptr) > CURVE_MAX) {
+ 					tp->curveName = 0;
+ 					printk("Unknown migrate curve\n");
+ 				      }
+ 				      memcpy(&tp->rcv_ecdh, ptr+1, opsize-3);
+ 				    }
+ 				  }
+ 				  break;
+ 
+ 				case TCPOPT_MIGRATE:
+ 				  if(opsize==TCPOLEN_MIGRATE && th->syn) {
+ 				    if (sysctl_tcp_migrate && !no_fancy) {
+ 				      tp->migrate = 1;
+ 				      tp->rcv_reqNo = *ptr;
+ 				      tp->rcv_token =
+ 					__be64_to_cpu(*(__u64*)(ptr+1));
+ 				      tp->request =
+ 					__be64_to_cpu(*(__u64*)(ptr+9));
+ 				      printk("tok: %x%x\n",
+                                           (__u32)tp->rcv_token,
+                                           (__u32)(tp->rcv_token >> 32));
+ 				    }
+ 				  }
+ #endif
  	  			};
  	  			ptr+=opsize-2;
  	  			length-=opsize;
***************
*** 619,624 ****
--- 659,680 ----
  	__u32 now = tcp_time_stamp;
  	int acked = 0;
  
+ #ifdef CONFIG_MIGRATE
+ 	/*
+          * An ACK during migrate establishment is an explicit ack for
+          * the SYN in addition to any other data packets it may ack
+          */
+ 	if (tp->migrate) {
+ 	  skb=skb_peek_tail(&sk->write_queue);
+ 	  if(skb && (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN)) {
+ 	    tp->packets_out--;
+ 	    /* Don't use the RTT value here
+ 	       *seq_rtt = now - TCP_SKB_CB(skb)->when; */
+ 	    __skb_unlink(skb, skb->list);
+ 	    kfree_skb(skb);
+ 	  }
+ 	}
+ #endif
  	/* If we are retransmitting, and this ACK clears up to
  	 * the retransmit head, or further, then clear our state.
  	 */
***************
*** 658,663 ****
--- 714,723 ----
  		}		
  		tp->packets_out--;
  		*seq = scb->seq;
+ #ifdef CONFIG_MIGRATE
+ 		/* Don't use RTT from migrated packets */
+ 		if(!tp->migrate)
+ #endif
  		*seq_rtt = now - scb->when;
  		__skb_unlink(skb, skb->list);
  		kfree_skb(skb);
***************
*** 916,921 ****
--- 976,982 ----
  
  uninteresting_ack:
  	SOCK_DEBUG(sk, "Ack ignored %u %u\n", ack, tp->snd_nxt);
+ 	printk("Ack ignored %u %u\n", ack, tp->snd_nxt);
  	return 0;
  }
  
***************
*** 1830,1836 ****
  	 */
  	if (tcp_fast_parse_options(sk, th, tp)) {
  		if (tp->saw_tstamp) {
! 			if (tcp_paws_discard(tp, th, len)) {
  				tcp_statistics.TcpInErrs++;
  				if (!th->rst) {
  					tcp_send_ack(sk);
--- 1891,1897 ----
  	 */
  	if (tcp_fast_parse_options(sk, th, tp)) {
  		if (tp->saw_tstamp) {
! 		        if (tcp_paws_discard(tp, th, len)) {
  				tcp_statistics.TcpInErrs++;
  				if (!th->rst) {
  					tcp_send_ack(sk);
***************
*** 1897,1902 ****
--- 1958,1975 ----
  	 *	Standard slow path.
  	 */
  
+ #ifdef CONFIG_MIGRATE
+ 	/* We no longer do a sequence space check */
+ 
+ 	if(tp->migrate && th->syn) {
+ 	  if (sysctl_tcp_migrate) {
+ 	    if(tp->af_specific->migrate_request(sk, skb) < 0)
+ 	      return 1;
+ 	    goto discard;
+ 	  }
+ 	}
+ #endif
+ 
  	if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
  		/* RFC793, page 37: "In all states except SYN-SENT, all reset
  		 * (RST) segments are validated by checking their SEQ-fields."
***************
*** 1905,1911 ****
  		 * is set, if so drop the segment and return)".
  		 */
  		if (th->rst)
! 			goto discard;
  		if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
  			SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
  				   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
--- 1978,1984 ----
  		 * is set, if so drop the segment and return)".
  		 */
  		if (th->rst)
! 			goto discard;		
  		if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) {
  			SOCK_DEBUG(sk, "seq:%d end:%d wup:%d wnd:%d\n",
  				   TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq,
***************
*** 1923,1928 ****
--- 1996,2008 ----
  	}
  	
  	if(th->rst) {
+ #ifdef CONFIG_MIGRATE
+ 	        if(tp->migrate_ok) {
+ 		  net_statistics.MigrateWaits++;
+ 		  tcp_set_state(sk, TCP_MIGRATE_WAIT);
+ 		  goto discard;
+ 		}
+ #endif
  		tcp_reset(sk);
  		goto discard;
  	}
***************
*** 2025,2032 ****
  		sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
  		if (sk == NULL)
  			return NULL;
! 		
! 		tcp_dec_slow_timer(TCP_SLT_SYNACK);
  		req->expires = 0UL;
  		req->sk = sk;
  	}
--- 2105,2112 ----
  		sk = tp->af_specific->syn_recv_sock(sk, skb, req, NULL);
  		if (sk == NULL)
  			return NULL;
! 
! 		tcp_dec_slow_timer(TCP_SLT_SYNACK);		
  		req->expires = 0UL;
  		req->sk = sk;
  	}
***************
*** 2069,2074 ****
--- 2149,2173 ----
  		 */
  		return 1;
  
+ #ifdef CONFIG_MIGRATE
+ 	case TCP_MIGRATE_WAIT:
+ 	        if(th->syn) {
+ 		  struct tcp_opt ptp;
+ 		  
+ 		  ptp.migrate = ptp.migrate_ok = 0;
+ 		  tcp_parse_options(NULL, th, &ptp, 0);
+ 		  if(ptp.migrate) {
+ 		    if(tp->af_specific->migrate_request(sk, skb) < 0)
+ 		      return 1;
+ 
+ 		    /* As below, there may be data in the frame.  We also chose
+ 		     * to drop it.
+ 		     */
+ 		    goto discard;
+ 		  }
+ 		}
+ 		return 1;
+ #endif
  	case TCP_LISTEN:
  		/* These use the socket TOS.. 
  		 * might want to be the received TOS 
***************
*** 2128,2134 ****
--- 2227,2239 ----
  			 *  test reduces to:
  			 */
  			if (sk->zapped ||
+ #ifdef CONFIG_MIGRATE
+ 			    (!tp->migrate &&
+ #endif
  			    TCP_SKB_CB(skb)->ack_seq != tp->snd_nxt)
+ #ifdef CONFIG_MIGRATE
+ 			    )
+ #endif
  				return 1;
  
  			/* Now ACK is acceptable.
***************
*** 2180,2189 ****
--- 2285,2318 ----
  			 *                                     --ANK (990514)
  			 */
  
+ #ifdef CONFIG_MIGRATE
+ 			/* If this was a PRELOAD, we'll just believe what
+ 			 * we hear in terms of sequence numbers.
+ 			 */
+ 
+ 			if (tp->migrate==2) {
+ 			  tp->snd_nxt = tp->snd_una = tp->write_seq =
+ 			    TCP_SKB_CB(skb)->ack_seq;
+ 			  printk("Ack phew %u %u\n", tp->snd_nxt, tp->snd_una);
+ 			}
+ #endif
+ 
  			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
  			tcp_ack(sk,th, TCP_SKB_CB(skb)->seq,
  				TCP_SKB_CB(skb)->ack_seq, len);
  
+ #ifdef CONFIG_MIGRATE
+ 			if (tp->migrate) {
+ 			  tcp_set_state(sk, tp->mig_state);
+ 			  tp->mig_state = TCP_SYN_SENT;
+ 			  if (tp->migrate==1) {
+ 			    tp->migrate = 0;
+ 			    goto migfin;
+ 			  }
+ 			} else
+ #endif
+ 			  tcp_set_state(sk, TCP_ESTABLISHED);
+ 
  			/* Ok.. it's good. Set up sequence numbers and
  			 * move to established.
  			 */
***************
*** 2198,2204 ****
  			tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
  			tp->fin_seq = TCP_SKB_CB(skb)->seq;
  
! 			tcp_set_state(sk, TCP_ESTABLISHED);
  			tcp_parse_options(sk, th, tp, 0);
  
          		if (tp->wscale_ok == 0) {
--- 2327,2338 ----
  			tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
  			tp->fin_seq = TCP_SKB_CB(skb)->seq;
  
! #ifdef CONFIG_MIGRATE
! 			if(tp->migrate) {
! 			  tp->migrate = 0;
! 			  goto migfin;
! 			}
! #endif  
  			tcp_parse_options(sk, th, tp, 0);
  
          		if (tp->wscale_ok == 0) {
***************
*** 2216,2221 ****
--- 2350,2363 ----
  				tp->ts_recent_stamp = tcp_time_stamp;
  			}
  
+ #ifdef CONFIG_MIGRATE
+ 			if(!tp->rcv_isn)
+ 			  tp->rcv_isn = TCP_SKB_CB(skb)->seq;
+ 			if(sysctl_tcp_migrate && tp->migrate_ok) {
+ 			  migrate_perm_process_active(sk, tp);
+ 			}
+ migfin:
+ #endif
  			/* Can't be earlier, doff would be wrong. */
  			tcp_send_ack(sk);
  
***************
*** 2276,2281 ****
--- 2418,2433 ----
  		 * negotiate the option. tcp_fast_parse_options() must
  		 * guarantee this.
  		 */
+ #ifdef CONFIG_MIGRATE
+ 	        /* On first packet of migrated connection, need to ignore
+ 		 * the timestamp option, and simply update our records.
+                  */
+ 	        if(tp->migrate && sk->state==TCP_SYN_RECV) {		  
+ 		  tp->ts_recent = tp->rcv_tsval;
+ 		  tp->ts_recent_stamp = tcp_time_stamp;
+ 		  tp->saw_tstamp = 0;
+ 		}
+ #endif
  		if (tp->saw_tstamp) {
  			if (tcp_paws_discard(tp, th, len)) {
  				tcp_statistics.TcpInErrs++;
***************
*** 2314,2319 ****
--- 2466,2478 ----
  
  	/* step 2: check RST bit */
  	if(th->rst) {
+ #ifdef CONFIG_MIGRATE
+ 	        if(tp->migrate_ok && sk->state==TCP_FIN_WAIT1) {
+ 		  net_statistics.MigrateWaits++;
+ 		  tcp_set_state(sk, TCP_MIGRATE_WAIT);
+ 		  goto discard;
+ 		}
+ #endif
  		tcp_reset(sk);
  		goto discard;
  	}
***************
*** 2349,2355 ****
  		switch(sk->state) {
  		case TCP_SYN_RECV:
  			if (acceptable) {
! 				tcp_set_state(sk, TCP_ESTABLISHED);
  				sk->dport = th->source;
  				tp->copied_seq = tp->rcv_nxt;
  
--- 2508,2520 ----
  		switch(sk->state) {
  		case TCP_SYN_RECV:
  			if (acceptable) {
! #ifdef CONFIG_MIGRATE
! 			        if(tp->migrate) {
! 				  tcp_set_state(sk, tp->mig_state);
! 				} else
! #endif 
! 			          tcp_set_state(sk, TCP_ESTABLISHED);
! 
  				sk->dport = th->source;
  				tp->copied_seq = tp->rcv_nxt;
  
***************
*** 2358,2367 ****
--- 2523,2545 ----
  
  				tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
  				tp->snd_wnd = htons(th->window) << tp->snd_wscale;
+ #ifdef CONFIG_MIGRATE
+ 				/* We don't update windows on migration */
+ 
+ 				if(tp->migrate) {
+ 				  tp->migrate = 0;
+ 				  /* Force a timeout, since we're not going to
+ 				     get any more ACKs */
+ 				  printk("Forcing a timeout\n");
+ 				  tcp_retransmit_timer((unsigned long) sk);
+ 				  break;
+ 				}
+ #endif
  				tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
  				tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
  
  			} else {
+ 			        printk("Ugly ack in SYN_REcV\n");
  				SOCK_DEBUG(sk, "bad ack\n");
  				return 1;
  			}
Index: migrate.kernel/net/ipv4/tcp_ipv4.c
diff -c migrate.kernel/net/ipv4/tcp_ipv4.c:1.1.1.2 migrate.kernel/net/ipv4/tcp_ipv4.c:1.6
*** migrate.kernel/net/ipv4/tcp_ipv4.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/tcp_ipv4.c	Wed Aug 15 18:37:29 2001
***************
*** 45,50 ****
--- 45,51 ----
   *	Vitaly E. Lavrov	:	Transparent proxy revived after year coma.
   *	Andi Kleen		:	Fix new listen.
   *	Andi Kleen		:	Fix accept error reporting.
+  *      Alex C. Snoeren         :       Migrate option handling.
   */
  
  #include <linux/config.h>
***************
*** 66,71 ****
--- 67,74 ----
  extern int sysctl_tcp_timestamps;
  extern int sysctl_tcp_window_scaling;
  extern int sysctl_tcp_sack;
+ extern int sysctl_tcp_migrate;
+ extern int sysctl_tcp_migrate_curve;
  extern int sysctl_tcp_syncookies;
  extern int sysctl_ip_dynaddr;
  extern __u32 sysctl_wmem_max;
***************
*** 78,84 ****
  struct inode tcp_inode;
  struct socket *tcp_socket=&tcp_inode.u.socket_i;
  
! static void tcp_v4_send_reset(struct sk_buff *skb);
  
  void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
  		       struct sk_buff *skb);
--- 81,87 ----
  struct inode tcp_inode;
  struct socket *tcp_socket=&tcp_inode.u.socket_i;
  
! void tcp_v4_send_reset(struct sk_buff *skb);
  
  void tcp_v4_send_check(struct sock *sk, struct tcphdr *th, int len, 
  		       struct sk_buff *skb);
***************
*** 348,353 ****
--- 351,359 ----
  	if (sk->state != TCP_CLOSE) {
  		SOCKHASH_LOCK();
  		__tcp_v4_hash(sk);
+ #ifdef CONFIG_MIGRATE
+ 		tcp_v4_migrate_hash(sk);
+ #endif
  		SOCKHASH_UNLOCK();
  	}
  }
***************
*** 364,369 ****
--- 370,378 ----
  		if (sk->prev != NULL)
  			__tcp_put_port(sk);
  	}
+ #ifdef CONFIG_MIGRATE
+ 	tcp_v4_migrate_unhash(sk);
+ #endif
  	SOCKHASH_UNLOCK();
  }
  
***************
*** 419,424 ****
--- 428,436 ----
  	__u32 ports = TCP_COMBINED_PORTS(sport, hnum);
  	struct sock *sk;
  	int hash;
+ #ifdef CONFIG_MIGRATE
+         struct tcp_opt tp;
+ #endif
  
  	/* Check TCP register quick cache first. */
  	sk = TCP_RHASH(sport);
***************
*** 440,445 ****
--- 452,475 ----
  	for(sk = tcp_ehash[hash+(tcp_ehash_size/2)]; sk; sk = sk->next)
  		if(TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif))
  			goto hit;
+ 
+ #ifdef CONFIG_MIGRATE
+ 	/* Check for a migrate connection before opening it up to listeners */
+ 	if(sysctl_tcp_migrate && th) {
+ 	  tp.migrate = tp.migrate_ok = 0;
+ 	  tcp_parse_options(NULL, th, &tp, 0);
+ 	  if (tp.migrate) {
+ 	    printk("Looking for migrate...");
+ 	    sk = tcp_v4_lookup_migrate(&tp, daddr, hnum, dif);
+ 	    if(sk)
+ 	      printk("Found it!\n");
+ 	    else
+ 	      printk("Hmmm..\n");
+ 	    return sk;
+ 	  }
+ 	}
+ #endif
+ 
  	sk = tcp_v4_lookup_listener(daddr, hnum, dif);
  hit:
  	return sk;
***************
*** 547,553 ****
   * The good_socknum and verify_bind scheme we use makes this
   * work.
   */
! static int tcp_v4_unique_address(struct sock *sk)
  {
  	struct tcp_bind_bucket *tb;
  	unsigned short snum = sk->num;
--- 577,583 ----
   * The good_socknum and verify_bind scheme we use makes this
   * work.
   */
! int tcp_v4_unique_address(struct sock *sk)
  {
  	struct tcp_bind_bucket *tb;
  	unsigned short snum = sk->num;
***************
*** 583,589 ****
  	u32 daddr, nexthop;
  	int tmp;
  
! 	if (sk->state != TCP_CLOSE) 
  		return(-EISCONN);
  
  	/* Don't allow a double connect. */
--- 613,619 ----
  	u32 daddr, nexthop;
  	int tmp;
  
! 	if ((sk->state != TCP_CLOSE) && (sk->state != TCP_PRELOAD))
  		return(-EISCONN);
  
  	/* Don't allow a double connect. */
***************
*** 648,656 ****
  		return -EADDRNOTAVAIL;
  	}
  
- 	tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
- 						   sk->sport, usin->sin_port);
- 
  	tp->ext_header_len = 0;
  	if (sk->opt)
  		tp->ext_header_len = sk->opt->optlen;
--- 678,683 ----
***************
*** 667,672 ****
--- 694,709 ----
  		tp->mss_clamp = max(tp->user_mss, 536);
  	}
  
+ 	/* Check to see if we've preloaded the state */
+ 
+ 	if (sk->state == TCP_PRELOAD)
+ 	  return tcp_v4_migrate(sk, (struct sockaddr *)&sk->saddr,
+ 				sizeof(struct sockaddr_in), buff,
+ 				rt->u.dst.pmtu);
+ 
+ 	tp->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr,
+ 						   sk->sport, usin->sin_port);
+ 
  	tcp_connect(sk, buff, rt->u.dst.pmtu);
  	return 0;
  }
***************
*** 978,984 ****
   *	Exception: precedence violation. We do not implement it in any case.
   */
  
! static void tcp_v4_send_reset(struct sk_buff *skb)
  {
  	struct tcphdr *th = skb->h.th;
  	struct tcphdr rth;
--- 1015,1021 ----
   *	Exception: precedence violation. We do not implement it in any case.
   */
  
! void tcp_v4_send_reset(struct sk_buff *skb)
  {
  	struct tcphdr *th = skb->h.th;
  	struct tcphdr rth;
***************
*** 1138,1144 ****
   *	This still operates on a open_request only, not on a big
   *	socket.
   */ 
! static void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
  {
  	struct rtable *rt;
  	struct ip_options *opt;
--- 1175,1181 ----
   *	This still operates on a open_request only, not on a big
   *	socket.
   */ 
! void tcp_v4_send_synack(struct sock *sk, struct open_request *req)
  {
  	struct rtable *rt;
  	struct ip_options *opt;
***************
*** 1206,1212 ****
  /* 
   * Save and compile IPv4 options into the open_request if needed. 
   */
! static inline struct ip_options * 
  tcp_v4_save_options(struct sock *sk, struct sk_buff *skb)
  {
  	struct ip_options *opt = &(IPCB(skb)->opt);
--- 1243,1249 ----
  /* 
   * Save and compile IPv4 options into the open_request if needed. 
   */
! inline struct ip_options * 
  tcp_v4_save_options(struct sock *sk, struct sk_buff *skb)
  {
  	struct ip_options *opt = &(IPCB(skb)->opt);
***************
*** 1289,1297 ****
--- 1326,1349 ----
  
  	req->rcv_isn = TCP_SKB_CB(skb)->seq;
   	tp.tstamp_ok = tp.sack_ok = tp.wscale_ok = tp.snd_wscale = 0;
+ #ifdef CONFIG_MIGRATE
+ 	tp.migrate = tp.migrate_ok = tp.curveName = 0;
+ 	tp.reqNo = tp.rcv_reqNo = tp.snt_reqNo = 0;
+ #endif
  
  	tp.mss_clamp = 65535;
  	tcp_parse_options(NULL, th, &tp, want_cookie);
+ #ifdef CONFIG_MIGRATE
+ 	/* Never accept migrate requests - they were meant for someone else */
+ 	if (tp.migrate) {
+ 	  if (req->af.v4_req.opt)
+ 	    kfree(req->af.v4_req.opt);
+ 	  tcp_v4_or_free(req); 
+ 	  tcp_openreq_free(req);
+ 	  printk("Migrate received by socket in LISTEN state\n");
+ 	  goto dead;
+ 	}
+ #endif
  	if (tp.mss_clamp == 65535)
  		tp.mss_clamp = 576 - sizeof(struct iphdr) - sizeof(struct iphdr);
  
***************
*** 1305,1310 ****
--- 1357,1373 ----
  	req->sack_ok = tp.sack_ok;
  	req->snd_wscale = tp.snd_wscale;
  	req->wscale_ok = tp.wscale_ok;
+ #ifdef CONFIG_MIGRATE
+ 	req->migrate = 0;
+ 	req->ts_tsecr = tp.rcv_tsecr;
+ 	req->reqNo = req->snt_reqNo = 0;
+ 	if((req->migrate_ok = tp.migrate_ok)) {
+ 	  req->curveName = tp.curveName;
+ 	  memcpy(&req->rcv_ecdh, &tp.rcv_ecdh, 17);
+ 	  migrate_genkey(req->curveName, (__u8*)&req->key,
+ 			 (__u8*)&req->snt_ecdh);
+ 	}
+ #endif
  	req->rmt_port = th->source;
  #ifdef CONFIG_IP_TRANSPARENT_PROXY
  	req->lcl_port = th->dest ; /* LVE */
***************
*** 1479,1484 ****
--- 1542,1558 ----
  		newtp->window_clamp = req->window_clamp;
  		newtp->rcv_wnd = req->rcv_wnd;
  		newtp->wscale_ok = req->wscale_ok;
+ 		newtp->tcp_header_len = sizeof(struct tcphdr);
+ #ifdef CONFIG_MIGRATE
+ 		newtp->snt_isn = req->rcv_isn;
+ 		newtp->rcv_isn = req->snt_isn;
+ 		newtp->migrate_ok = req->migrate_ok;
+ 		newtp->curveName = req->curveName;
+ 		newtp->reqNo = req->reqNo;
+ 		newtp->snt_reqNo = req->snt_reqNo;
+ 		if(req->migrate_ok && !req->migrate)
+ 		  migrate_perm_process_passive(req, newtp);
+ #endif
  		if (newtp->wscale_ok) {
  			newtp->snd_wscale = req->snd_wscale;
  			newtp->rcv_wscale = req->rcv_wscale;
***************
*** 1489,1498 ****
  		if (newtp->tstamp_ok) {
  			newtp->ts_recent = req->ts_recent;
  			newtp->ts_recent_stamp = tcp_time_stamp;
! 			newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED;
! 		} else {
! 			newtp->tcp_header_len = sizeof(struct tcphdr);
! 		}
  	}
  	return newsk;
  }
--- 1563,1570 ----
  		if (newtp->tstamp_ok) {
  			newtp->ts_recent = req->ts_recent;
  			newtp->ts_recent_stamp = tcp_time_stamp;
! 			newtp->tcp_header_len += TCPOLEN_TSTAMP_ALIGNED;
! 		} 
  	}
  	return newsk;
  }
***************
*** 1568,1573 ****
--- 1640,1648 ----
  	__tcp_v4_hash(newsk);
  	__tcp_inherit_port(sk, newsk);
  	__add_to_prot_sklist(newsk);
+ #ifdef CONFIG_MIGRATE
+ 	tcp_v4_migrate_hash(newsk);
+ #endif
  
  	sk->data_ready(sk, 0); /* Deliver SIGIO */ 
  
***************
*** 1804,1810 ****
  	}
  }
  
! static void __tcp_v4_rehash(struct sock *sk)
  {
  	struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
  
--- 1879,1885 ----
  	}
  }
  
! void __tcp_v4_rehash(struct sock *sk)
  {
  	struct sock **skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))];
  
***************
*** 1934,1939 ****
--- 2009,2016 ----
  	ip_setsockopt,
  	ip_getsockopt,
  	v4_addr2sockaddr,
+ 	tcp_v4_migrate_request,
+ 	tcp_v4_migrate,
  	sizeof(struct sockaddr_in)
  };
  
***************
*** 1973,1978 ****
--- 2050,2060 ----
  	/* Init SYN queue. */
  	tcp_synq_init(tp);
  
+ #ifdef CONFIG_MIGRATE
+ 	/* Migrate option initialization */
+ 	tp->curveName = sysctl_tcp_migrate_curve;
+ #endif
+ 
  	sk->tp_pinfo.af_tcp.af_specific = &ipv4_specific;
  
  	return 0;
***************
*** 2032,2038 ****
  	0,				/* retransmits */
  	"TCP",				/* name */
  	0,				/* inuse */
! 	0				/* highestinuse */
  };
  
  
--- 2114,2122 ----
  	0,				/* retransmits */
  	"TCP",				/* name */
  	0,				/* inuse */
! 	0,				/* highestinuse */
! 	tcp_setsockstate,               /* setsockstate */
! 	tcp_getsockstate,               /* getsockstate */
  };
  
  
***************
*** 2055,2058 ****
--- 2139,2145 ----
  	tcp_socket->sk->allocation=GFP_ATOMIC;
  	tcp_socket->sk->num = 256;		/* Don't receive any data */
  	tcp_socket->sk->ip_ttl = MAXTTL;
+ #ifdef CONFIG_MIGRATE
+ 	migrate_init();
+ #endif
  }
Index: migrate.kernel/net/ipv4/tcp_output.c
diff -c migrate.kernel/net/ipv4/tcp_output.c:1.1.1.2 migrate.kernel/net/ipv4/tcp_output.c:1.5
*** migrate.kernel/net/ipv4/tcp_output.c:1.1.1.2	Mon Sep  4 13:39:29 2000
--- migrate.kernel/net/ipv4/tcp_output.c	Wed Nov 22 14:41:37 2000
***************
*** 31,36 ****
--- 31,37 ----
   *					during syn/ack processing.
   *		David S. Miller :	Output engine completely rewritten.
   *		Andrea Arcangeli:	SYNACK carry ts_recent in tsecr.
+  *              Alex C. Snoeren :       Migrate option support.
   *
   */
  
***************
*** 39,44 ****
--- 40,47 ----
  extern int sysctl_tcp_timestamps;
  extern int sysctl_tcp_window_scaling;
  extern int sysctl_tcp_sack;
+ extern int sysctl_tcp_migrate;
+ extern int sysctl_tcp_migrate_curve;
  
  /* People can turn this off for buggy TCP's found in printers etc. */
  int sysctl_tcp_retrans_collapse = 1;
***************
*** 111,120 ****
--- 114,132 ----
  #define SYSCTL_FLAG_TSTAMPS	0x1
  #define SYSCTL_FLAG_WSCALE	0x2
  #define SYSCTL_FLAG_SACK	0x4
+ #define SYSCTL_FLAG_MIGRATE_OK  0x8
+ #define SYSCTL_FLAG_MIGRATE     0x10
  
  		sysctl_flags = 0;
  		if(tcb->flags & TCPCB_FLAG_SYN) {
  			tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
+ #ifdef CONFIG_MIGRATE
+ 		  if(tp->migrate) {
+ 		        tcp_header_size += TCPOLEN_MIGRATE_ALIGNED;
+ 		        sysctl_flags |= SYSCTL_FLAG_MIGRATE;
+ 		  }
+ 		  else {
+ #endif
  			if(sysctl_tcp_timestamps) {
  				tcp_header_size += TCPOLEN_TSTAMP_ALIGNED;
  				sysctl_flags |= SYSCTL_FLAG_TSTAMPS;
***************
*** 128,133 ****
--- 140,155 ----
  				if(!(sysctl_flags & SYSCTL_FLAG_TSTAMPS))
  					tcp_header_size += TCPOLEN_SACKPERM_ALIGNED;
  			}
+ #ifdef CONFIG_MIGRATE
+ 			if(sysctl_tcp_migrate) {
+ 				sysctl_flags |= SYSCTL_FLAG_MIGRATE_OK;
+ 				if(tp->curveName) {
+ 				  tcp_header_size += TCPOLEN_MIGRATEPERM_ALIGNED;
+ 				} else
+ 				  tcp_header_size += TCPOLEN_MIGRATE_SHORT_ALIGNED;
+ 			}
+ 		  }
+ #endif
  		} else if(tp->sack_ok && tp->num_sacks) {
  			/* A SACK is 2 pad bytes, a 2 byte header, plus
  			 * 2 32-bit sequence numbers for each SACK block.
***************
*** 162,168 ****
  					      (sysctl_flags & SYSCTL_FLAG_WSCALE),
  					      tp->rcv_wscale,
  					      TCP_SKB_CB(skb)->when,
! 		      			      tp->ts_recent);
  		} else {
  			tcp_build_and_update_options((__u32 *)(th + 1),
  						     tp, TCP_SKB_CB(skb)->when);
--- 184,199 ----
  					      (sysctl_flags & SYSCTL_FLAG_WSCALE),
  					      tp->rcv_wscale,
  					      TCP_SKB_CB(skb)->when,
! 		      			      tp->ts_recent,
! 					      (sysctl_flags & SYSCTL_FLAG_MIGRATE_OK),
! 					      tp->curveName,
! 					      (__u8 *)&tp->snt_ecdh,
! 					      (sysctl_flags & SYSCTL_FLAG_MIGRATE),
! 					      (tp->migrate==2 ?
! 					       tp->snt_reqNo|MIGRATE_PRELOAD:
! 					       tp->snt_reqNo),
! 					      tp->token,
! 					      tp->request);
  		} else {
  			tcp_build_and_update_options((__u32 *)(th + 1),
  						     tp, TCP_SKB_CB(skb)->when);
***************
*** 177,182 ****
--- 208,215 ----
  #undef SYSCTL_FLAG_TSTAMPS
  #undef SYSCTL_FLAG_WSCALE
  #undef SYSCTL_FLAG_SACK
+ #undef SYSCTL_FLAG_MIGRATE_OK
+ #undef SYSCTL_FLAG_MIGRATE
  }
  
  /* This is the main buffer sending routine. We queue the buffer
***************
*** 621,627 ****
  	   (skb->len < (cur_mss >> 1)) &&
  	   (skb->next != tp->send_head) &&
  	   (skb->next != (struct sk_buff *)&sk->write_queue) &&
! 	   (skb->next != tp->retrans_head) &&
  	   (sysctl_tcp_retrans_collapse != 0))
  		tcp_retrans_try_collapse(sk, skb, cur_mss);
  
--- 654,660 ----
  	   (skb->len < (cur_mss >> 1)) &&
  	   (skb->next != tp->send_head) &&
  	   (skb->next != (struct sk_buff *)&sk->write_queue) &&
!            (skb->next != tp->retrans_head) &&
  	   (sysctl_tcp_retrans_collapse != 0))
  		tcp_retrans_try_collapse(sk, skb, cur_mss);
  
***************
*** 874,879 ****
--- 907,915 ----
  	struct tcphdr *th;
  	int tcp_header_size;
  	struct sk_buff *skb;
+ #ifdef CONFIG_MIGRATE
+        struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp);
+ #endif
  
  	skb = sock_wmalloc(sk, MAX_HEADER + sk->prot->max_header, 1, GFP_ATOMIC);
  	if (skb == NULL)
***************
*** 898,903 ****
--- 934,944 ----
  	tcp_header_size = (sizeof(struct tcphdr) + TCPOLEN_MSS +
  			   (req->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0) +
  			   (req->wscale_ok ? TCPOLEN_WSCALE_ALIGNED : 0) +
+ #ifdef CONFIG_MIGRATE
+ 			   (req->migrate_ok ? (req->curveName ?
+ 					       TCPOLEN_MIGRATEPERM_ALIGNED :
+ 					       TCPOLEN_MIGRATE_SHORT_ALIGNED) : 0) +
+ #endif
  			   /* SACK_PERM is in the place of NOP NOP of TS */
  			   ((req->sack_ok && !req->tstamp_ok) ? TCPOLEN_SACKPERM_ALIGNED : 0));
  	skb->h.th = th = (struct tcphdr *) skb_push(skb, tcp_header_size);
***************
*** 910,915 ****
--- 951,962 ----
  	TCP_SKB_CB(skb)->seq = req->snt_isn;
  	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
  	th->seq = htonl(TCP_SKB_CB(skb)->seq);
+ #ifdef CONFIG_MIGRATE
+ 	/* Migrate connections ACK in previous sequence space */
+ 	if(req->migrate)
+ 	  th->ack_seq = htonl(tp->rcv_nxt);
+ 	else
+ #endif
  	th->ack_seq = htonl(req->rcv_isn + 1);
  	if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
  		__u8 rcv_wscale; 
***************
*** 930,936 ****
  	tcp_syn_build_options((__u32 *)(th + 1), req->mss, req->tstamp_ok,
  			      req->sack_ok, req->wscale_ok, req->rcv_wscale,
  			      TCP_SKB_CB(skb)->when,
! 			      req->ts_recent);
  
  	skb->csum = 0;
  	th->doff = (tcp_header_size >> 2);
--- 977,985 ----
  	tcp_syn_build_options((__u32 *)(th + 1), req->mss, req->tstamp_ok,
  			      req->sack_ok, req->wscale_ok, req->rcv_wscale,
  			      TCP_SKB_CB(skb)->when,
! 			      req->ts_recent, req->migrate_ok, req->curveName,
! 			      (__u8*)&req->snt_ecdh,req->migrate,req->migrate,
! 			      req->snt_reqNo, 0);
  
  	skb->csum = 0;
  	th->doff = (tcp_header_size >> 2);
***************
*** 951,956 ****
--- 1000,1015 ----
  	tp->snd_wl2 = tp->write_seq;
  	tp->snd_una = tp->write_seq;
  	tp->rcv_nxt = 0;
+ #ifdef CONFIG_MIGRATE
+ 	tp->snt_isn = tp->write_seq;
+ 	tp->rcv_isn = 0;
+ 	if((tp->curveName = sysctl_tcp_migrate_curve)) {
+ 	  if(tp->curveName <= CURVE_MAX) {
+ 	    migrate_genkey(tp->curveName,(__u8*)&tp->key,(__u8*)&tp->snt_ecdh);
+ 	  } else
+ 	    tp->curveName = 0;
+ 	}
+ #endif
  
  	sk->err = 0;
  	
Index: migrate.kernel/net/ipv4/timer.c
diff -c migrate.kernel/net/ipv4/timer.c:1.1.1.1 migrate.kernel/net/ipv4/timer.c:1.2
*** migrate.kernel/net/ipv4/timer.c:1.1.1.1	Mon Feb 22 12:05:55 1999
--- migrate.kernel/net/ipv4/timer.c	Mon Jul 17 18:35:20 2000
***************
*** 50,55 ****
--- 50,59 ----
  #include <net/sock.h>
  #include <net/arp.h>
  
+ #ifdef CONFIG_MIGRATE
+ extern void tcp_reset(struct sock *);
+ #endif
+ 
  void net_delete_timer (struct sock *t)
  {
  	if(t->timer.prev)
***************
*** 118,127 ****
--- 122,141 ----
  			net_reset_timer (sk, TIME_DONE, TCP_DONE_TIME);
  			break;
  
+ #ifdef CONFIG_MIGRATE
+ 	        case TIME_MIGRATE:
+ 			net_statistics.MigrateTimeouts++;
+ 			tcp_reset(sk);
+ 			break;
+ #endif
+ 
  		default:
  			/* I want to see these... */
  			printk ("net_timer: timer expired - reason %d is unknown\n", why);
  			break;
  	}
  }
+ 
+ 
+ 
  
Index: migrate.kernel/net/ipv4/udp.c
diff -c migrate.kernel/net/ipv4/udp.c:1.1.1.1 migrate.kernel/net/ipv4/udp.c:1.2
*** migrate.kernel/net/ipv4/udp.c:1.1.1.1	Wed Jun  7 17:26:44 2000
--- migrate.kernel/net/ipv4/udp.c	Wed Nov 22 14:27:52 2000
***************
*** 1188,1192 ****
  	0,				/* retransmits */
   	"UDP",				/* name */
  	0,				/* inuse */
! 	0				/* highestinuse */
  };
--- 1188,1194 ----
  	0,				/* retransmits */
   	"UDP",				/* name */
  	0,				/* inuse */
! 	0,				/* highestinuse */
! 	NULL,                           /* setsockstate */
! 	NULL                            /* getsockstate */
  };
