## Automatically generated incremental diff
## From:   linux-2.0.37-pre11
## To:     linux-2.0.37-pre12
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.0.37-pre11/arch/i386/kernel/sys_i386.c linux-2.0.37-pre12/arch/i386/kernel/sys_i386.c
--- linux-2.0.37-pre11/arch/i386/kernel/sys_i386.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/arch/i386/kernel/sys_i386.c	1996-04-11 23:49:30.000000000 -0700
@@ -48,23 +48,19 @@
 	int error;
 	unsigned long flags;
 	struct file * file = NULL;
-	unsigned long b[6];
 
 	error = verify_area(VERIFY_READ, buffer, 6*sizeof(long));
 	if (error)
 		return error;
-	memcpy_fromfs(&b[0], buffer, 6*sizeof(long));
-	flags = b[3];
+	flags = get_user(buffer+3);
 	if (!(flags & MAP_ANONYMOUS)) {
-		unsigned long fd = b[4];
+		unsigned long fd = get_user(buffer+4);
 		if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
 			return -EBADF;
 	}
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	down(&current->mm->mmap_sem);
-	error = do_mmap(file, b[0], b[1], b[2], flags, b[5]);
-	up(&current->mm->mmap_sem);
-	return error;
+	return do_mmap(file, get_user(buffer), get_user(buffer+1),
+		       get_user(buffer+2), flags, get_user(buffer+5));
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
diff -urN linux-2.0.37-pre11/CREDITS linux-2.0.37-pre12/CREDITS
--- linux-2.0.37-pre11/CREDITS	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/CREDITS	2003-08-15 15:04:50.000000000 -0700
@@ -557,6 +557,14 @@
 S: Atlanta, Georgia 30332
 S: USA
 
+N: John Hardin
+E: jhardin@wolfenet.com
+W: http://www.wolfenet.com/~jhardin/
+D: IPSec and PPTP masquerade
+S: 17014 Broadway ave.
+S: Snohomish, WA 98296-8031
+S: USA
+
 N: Angelo Haritsis
 E: ah@doc.ic.ac.uk
 D: kernel patches (serial, watchdog)
diff -urN linux-2.0.37-pre11/drivers/block/floppy.c linux-2.0.37-pre12/drivers/block/floppy.c
--- linux-2.0.37-pre11/drivers/block/floppy.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/drivers/block/floppy.c	2003-08-15 15:04:50.000000000 -0700
@@ -601,7 +601,7 @@
 		drive = current_drive;
 	del_timer(&fd_timeout);
 	if (drive < 0 || drive > N_DRIVE) {
-		fd_timeout.expires = jiffies + 20*HZ;
+		fd_timeout.expires = jiffies + 20UL*HZ;
 		drive=0;
 	} else
 		fd_timeout.expires = jiffies + UDP->timeout;
@@ -969,7 +969,7 @@
 }
 
 /* waits for a delay (spinup or select) to pass */
-static int wait_for_completion(int delay, timeout_fn function)
+static int wait_for_completion(unsigned long delay, timeout_fn function)
 {
 	if (FDCS->reset){
 		reset_fdc(); /* do the reset during sleep to win time
@@ -1318,7 +1318,7 @@
 	 * Pause 5 msec to avoid trouble. (Needs to be 2 jiffies)
 	 */
 	FDCS->dtr = raw_cmd->rate & 3;
-	return(wait_for_completion(jiffies+2*HZ/100,
+	return(wait_for_completion(jiffies+2UL*HZ/100,
 				   (timeout_fn) floppy_ready));
 } /* fdc_dtr */
 
@@ -2903,7 +2903,7 @@
  * Misc Ioctl's and support
  * ========================
  */
-static int fd_copyout(void *param, const void *address, int size)
+static int fd_copyout(void *param, const void *address, unsigned long size)
 {
 	int ret;
 
@@ -2912,7 +2912,7 @@
 	return 0;
 }
 
-static int fd_copyin(void *param, void *address, int size)
+static int fd_copyin(void *param, void *address, unsigned long size)
 {
 	int ret;
 
diff -urN linux-2.0.37-pre11/drivers/net/eql.c linux-2.0.37-pre12/drivers/net/eql.c
--- linux-2.0.37-pre11/drivers/net/eql.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/drivers/net/eql.c	2003-08-15 15:04:50.000000000 -0700
@@ -389,8 +389,8 @@
 
 	eql_schedule_slaves (eql->queue);
   
-	slave_dev = eql_best_slave_dev (eql->queue);
 	slave = eql_best_slave (eql->queue); 
+	slave_dev = slave ? slave->dev : 0;
 
 	if ( slave_dev != 0 )
 	{
diff -urN linux-2.0.37-pre11/fs/locks.c linux-2.0.37-pre12/fs/locks.c
--- linux-2.0.37-pre11/fs/locks.c	1998-11-15 10:33:13.000000000 -0800
+++ linux-2.0.37-pre12/fs/locks.c	2003-08-15 15:04:50.000000000 -0700
@@ -107,6 +107,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
+#include <linux/file.h>
 #include <linux/fcntl.h>
 
 #include <asm/segment.h>
@@ -255,17 +256,25 @@
 {
 	struct file_lock file_lock;
 	struct file *filp;
-
-	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
+	int err = -EINVAL;
+	
+	filp = fget(fd);
+	if(filp==NULL)
+		return -EBADF;
+	
 
 	if (!flock_make_lock(filp, &file_lock, cmd))
-		return (-EINVAL);
-	
-	if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
-		return (-EBADF);
+		goto out;
 
-	return (flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1));
+	if ((file_lock.fl_type != F_UNLCK) && !(filp->f_mode & 3))
+	{
+		err = -EBADF;
+		goto out;
+	}
+	err=flock_lock_file(filp, &file_lock, (cmd & (LOCK_UN | LOCK_NB)) ? 0 : 1);
+out:
+	fput(filp, filp->f_inode);
+	return err;	
 }
 
 /* Report the first existing lock that would conflict with l.
@@ -278,19 +287,27 @@
 	struct file *filp;
 	struct file_lock *fl,file_lock;
 
-	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
 	error = verify_area(VERIFY_WRITE, l, sizeof(*l));
 	if (error)
 		return (error);
 
+	filp = fget(fd);
+	if(filp==NULL)
+		return -EBADF;
+
 	memcpy_fromfs(&flock, l, sizeof(flock));
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
-		return (-EINVAL);
+	{
+		error = -EINVAL;
+		goto out;
+	}
 
 	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
-		return (-EINVAL);
-
+	{
+		error = -EINVAL;
+		goto out;
+	}
+	
 	flock.l_type = F_UNLCK;
 	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
 		if (!(fl->fl_flags & FL_POSIX))
@@ -307,7 +324,9 @@
 	}
 
 	memcpy_tofs(l, &flock, sizeof(flock));
-	return (0);
+out:
+	fput(filp, filp->f_inode);
+	return error;
 }
 
 /* Apply the lock described by l to an open file descriptor.
@@ -326,19 +345,20 @@
 	/* Get arguments and validate them ...
 	 */
 
-	if ((fd >= NR_OPEN) || !(filp = current->files->fd[fd]))
-		return (-EBADF);
-	
 	error = verify_area(VERIFY_READ, l, sizeof(*l));
 	if (error)
 		return (error);
-	
-	if (!(inode = filp->f_inode))
-		return (-EINVAL);
-	
+		
+	filp = fget(fd);
+	if(filp==NULL)
+		return -EBADF;
+
+	inode = filp->f_inode;
+		
 	/*
 	 * This might block, so we do it before checking the inode.
 	 */
+
 	memcpy_fromfs(&flock, l, sizeof(flock));
 
 	/* Don't allow mandatory locks on files that may be memory mapped
@@ -350,22 +370,34 @@
 		struct vm_area_struct *vma = inode->i_mmap;
 		do {
 			if (vma->vm_flags & VM_MAYSHARE)
-				return (-EAGAIN);
+			{
+				error = -EAGAIN;
+				goto out;
+			}
 			vma = vma->vm_next_share;
 		} while (vma != inode->i_mmap);
 	}
 
 	if (!posix_make_lock(filp, &file_lock, &flock))
-		return (-EINVAL);
+	{
+		error = -EINVAL;
+		goto out;
+	}
 	
 	switch (flock.l_type) {
 	case F_RDLCK:
 		if (!(filp->f_mode & 1))
-			return (-EBADF);
+		{
+			error = -EBADF;
+			goto out;
+		}
 		break;
 	case F_WRLCK:
 		if (!(filp->f_mode & 2))
-			return (-EBADF);
+		{
+			error = -EBADF;
+			goto out;
+		}
 		break;
 	case F_UNLCK:
 		break;
@@ -384,13 +416,19 @@
 }
 #endif
 		if (!(filp->f_mode & 3))
-			return (-EBADF);
+		{
+			error = -EBADF;
+			goto out;
+		}
 		break;
 	default:
 		return (-EINVAL);
 	}
 	
-	return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW));
+	error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);
+out:
+	fput(filp, filp->f_inode);
+	return error;
 }
 
 /* This function is called when the file is closed.
diff -urN linux-2.0.37-pre11/fs/open.c linux-2.0.37-pre12/fs/open.c
--- linux-2.0.37-pre11/fs/open.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/fs/open.c	2003-08-15 15:04:50.000000000 -0700
@@ -68,11 +68,10 @@
 	int error;
 	struct iattr newattrs;
 
-
         /* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
         if ((off_t) length < 0)
         	return -EINVAL;
-
+                                 
 	down(&inode->i_sem);
 	newattrs.ia_size = length;
 	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
diff -urN linux-2.0.37-pre11/fs/select.c linux-2.0.37-pre12/fs/select.c
--- linux-2.0.37-pre11/fs/select.c	1998-11-15 10:33:14.000000000 -0800
+++ linux-2.0.37-pre12/fs/select.c	2003-08-15 15:04:50.000000000 -0700
@@ -347,10 +347,8 @@
 		(fd_set *) &res_out,
 		(fd_set *) &res_ex,
 		(fd_set *) &locked);
-	timeout = current->timeout - jiffies - 1;
+	timeout = current->timeout?current->timeout - jiffies - 1:0;
 	current->timeout = 0;
-	if ((long) timeout < 0)
-		timeout = 0;
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
 		put_user(timeout/HZ, &tvp->tv_sec);
 		timeout %= HZ;
diff -urN linux-2.0.37-pre11/include/linux/in.h linux-2.0.37-pre12/include/linux/in.h
--- linux-2.0.37-pre11/include/linux/in.h	1997-12-02 14:18:11.000000000 -0800
+++ linux-2.0.37-pre12/include/linux/in.h	2003-08-15 15:04:50.000000000 -0700
@@ -31,6 +31,9 @@
   IPPROTO_PUP = 12,		/* PUP protocol				*/
   IPPROTO_UDP = 17,		/* User Datagram Protocol		*/
   IPPROTO_IDP = 22,		/* XNS IDP protocol			*/
+  IPPROTO_GRE = 47,		/* GRE Encapsulation used by PPTP et al	*/
+  IPPROTO_ESP = 50,		/* ESP protocol for IPSec		*/
+  IPPROTO_AH = 51,		/* AH protocol for IPSec		*/
 
   IPPROTO_RAW = 255,		/* Raw IP packets			*/
   IPPROTO_MAX
diff -urN linux-2.0.37-pre11/include/net/ip_masq.h linux-2.0.37-pre12/include/net/ip_masq.h
--- linux-2.0.37-pre11/include/net/ip_masq.h	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/include/net/ip_masq.h	2003-08-15 15:04:50.000000000 -0700
@@ -85,12 +85,11 @@
 	unsigned  flags;        	/* status flags */
 	struct ip_masq	*control;	/* Corresponding control connection */
 #ifdef CONFIG_IP_MASQUERADE_IPSEC
-        struct ip_masq  *d_link;	/* hashed link ptr */
+	struct ip_masq  *d_link;	/* hashed link ptr */
 	__u32		ospi, ispi;	/* outbound and inbound SPI keys for IPSEC */
-                                        /* also the cookie for ISAKMP masq (maybe) */
+					/* also the icookie for ISAKMP masquerade  */
 	short		ocnt;		/* counter of inits sent - limit blocking  */
-        short           blocking;       /* if we're blocking another host */
-
+	short		blocking;	/* if we're blocking another host          */
 #endif /* CONFIG_IP_MASQUERADE_IPSEC */
 };
 
diff -urN linux-2.0.37-pre11/mm/mmap.c linux-2.0.37-pre12/mm/mmap.c
--- linux-2.0.37-pre11/mm/mmap.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/mm/mmap.c	1998-11-15 10:33:20.000000000 -0800
@@ -69,21 +69,20 @@
 	unsigned long newbrk, oldbrk;
 	struct mm_struct *mm = current->mm;
 
-	down(&mm->mmap_sem);
-
 	if (brk < mm->end_code)
-		goto out;
+		return mm->brk;
 	newbrk = PAGE_ALIGN(brk);
 	oldbrk = PAGE_ALIGN(mm->brk);
 	if (oldbrk == newbrk)
-		goto set_brk;
+		return mm->brk = brk;
 
 	/*
 	 * Always allow shrinking brk
 	 */
 	if (brk <= mm->brk) {
+		mm->brk = brk;
 		do_munmap(newbrk, oldbrk-newbrk);
-		goto set_brk;
+		return brk;
 	}
 	/*
 	 * Check against rlimit and stack..
@@ -92,19 +91,19 @@
 	if (rlim >= RLIM_INFINITY)
 		rlim = ~0;
 	if (brk - mm->end_code > rlim)
-		goto out;
+		return mm->brk;
 
 	/*
 	 * Check against existing mmap mappings.
 	 */
 	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
-		goto out;
+		return mm->brk;
 
 	/*
 	 * Check if we have enough memory..
 	 */
 	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
-		goto out;
+		return mm->brk;
 
 	/*
 	 * Ok, looks good - let it rip.
@@ -112,12 +111,8 @@
 	if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
 		PROT_READ|PROT_WRITE|PROT_EXEC,
 		   MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
-		goto out;
-set_brk:
-	mm->brk = brk;
-out:
-	up(&mm->mmap_sem);
-	return mm->brk;
+		return mm->brk;
+	return mm->brk = brk;
 }
 
 /*
@@ -789,12 +784,7 @@
 
 asmlinkage int sys_munmap(unsigned long addr, size_t len)
 {
-	int ret;
-
-	down(&current->mm->mmap_sem);
-	ret = do_munmap(addr, len);
-	up(&current->mm->mmap_sem);
-	return ret;
+	return do_munmap(addr, len);
 }
 
 /*
@@ -806,7 +796,7 @@
 int do_munmap(unsigned long addr, size_t len)
 {
 	struct vm_area_struct *mpnt, *prev, *next, **npp, *free;
-	
+
 	if ((addr & ~PAGE_MASK) || addr > MAX_USER_ADDR || len > MAX_USER_ADDR-addr)
 		return -EINVAL;
 
@@ -864,6 +854,7 @@
 	} while (free);
 
 	/* we could zap the page tables here too.. */
+
 	return 0;
 }
 
@@ -989,9 +980,10 @@
 {
 	struct vm_area_struct *prev, *mpnt, *next;
 
+	down(&mm->mmap_sem);
 	mpnt = find_vma(mm, start_addr);
 	if (!mpnt)
-		return;
+		goto no_vma;
 
 	avl_neighbours(mpnt, mm->mmap_avl, &prev, &next);
 	/* we have  prev->vm_next == mpnt && mpnt->vm_next = next */
@@ -1051,4 +1043,6 @@
 		kfree_s(mpnt, sizeof(*mpnt));
 		mpnt = prev;
 	}
+no_vma:
+	up(&mm->mmap_sem);
 }
diff -urN linux-2.0.37-pre11/net/ipv4/Config.in linux-2.0.37-pre12/net/ipv4/Config.in
--- linux-2.0.37-pre11/net/ipv4/Config.in	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/net/ipv4/Config.in	2003-08-15 15:04:50.000000000 -0700
@@ -16,21 +16,23 @@
         comment 'Protocol-specific masquerading support will be built as modules.'
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then	
           bool 'IP: ipautofw masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW
-          bool 'IP: MS PPTP client masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP
+          bool 'IP: MS PPTP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP
           if [ "$CONFIG_IP_MASQUERADE_PPTP" = "y" ]; then	
+            bool 'IP: MS PPTP Call ID masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_PPTP_MULTICLIENT
             bool 'IP: MS PPTP masq debugging' DEBUG_IP_MASQUERADE_PPTP
             if [ "$DEBUG_IP_MASQUERADE_PPTP" = "y" ]; then	
               bool 'IP: MS PPTP masq verbose debugging' DEBUG_IP_MASQUERADE_PPTP_VERBOSE
             fi
-         fi
-         bool 'IP: IPSEC ESP & ISAKMP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPSEC
-         if [ "$CONFIG_IP_MASQUERADE_IPSEC" = "y" ]; then	
-           int 'IP: IPSEC masq table lifetime (minutes)' CONFIG_IP_MASQUERADE_IPSEC_EXPIRE 30
-           bool 'IP: IPSEC masq debugging' DEBUG_IP_MASQUERADE_IPSEC
-           if [ "$DEBUG_IP_MASQUERADE_IPSEC" = "y" ]; then	
-             bool 'IP: IPSEC masq verbose debugging' DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
-           fi
-         fi
+          fi
+          bool 'IP: IPSEC ESP & ISAKMP masq support (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPSEC
+          if [ "$CONFIG_IP_MASQUERADE_IPSEC" = "y" ]; then	
+            int 'IP: IPSEC masq table lifetime (minutes)' CONFIG_IP_MASQUERADE_IPSEC_EXPIRE 30
+            bool 'IP: Disable inbound ESP destination guessing' CONFIG_IP_MASQUERADE_IPSEC_NOGUESS
+            bool 'IP: IPSEC masq debugging' DEBUG_IP_MASQUERADE_IPSEC
+            if [ "$DEBUG_IP_MASQUERADE_IPSEC" = "y" ]; then	
+              bool 'IP: IPSEC masq verbose debugging' DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+            fi
+          fi
         fi
         bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
       fi
diff -urN linux-2.0.37-pre11/net/ipv4/ip_masq.c linux-2.0.37-pre12/net/ipv4/ip_masq.c
--- linux-2.0.37-pre11/net/ipv4/ip_masq.c	2003-08-15 15:04:50.000000000 -0700
+++ linux-2.0.37-pre12/net/ipv4/ip_masq.c	2003-08-15 15:04:50.000000000 -0700
@@ -46,8 +46,6 @@
 
 #define IP_MASQ_TAB_SIZE 256    /* must be power of 2 */
 
-#define IPPROTO_GRE	47	/* GRE Encapsulation used by PPTP */
-
 #ifdef CONFIG_IP_MASQUERADE_PPTP
 /*
  * This is clumsier than it otherwise might be (i.e. the
@@ -60,6 +58,9 @@
  * be somewhat more generic.
  *
  * Maybe for 2.0.38 - we'll see.
+ *
+ * John Hardin <jhardin@wolfenet.com> gets all blame...
+ * See also http://www.wolfenet.com/~jhardin/ip_masq_vpn.html
  */
 
 static const char *strGREProt = "GRE";
@@ -125,9 +126,6 @@
 #endif /* CONFIG_IP_MASQUERADE_PPTP */
 
 
-#define IPPROTO_ESP	50	/* ESP protocol for IPSEC */
-#define IPPROTO_AH 	51	/* AH protocol for IPSEC */
-
 #ifdef CONFIG_IP_MASQUERADE_IPSEC
 /*
  * The above comments about PPTP apply here, too. This should all be a module.
@@ -1262,8 +1260,6 @@
 /*
  *      Masquerade of GRE connections
  *      to support a PPTP VPN client or server.
- *      John Hardin <jhardin@wolfenet.com> gets all blame...
- *      See also http://www.wolfenet.com/~jhardin/ip_masq_pptp.html
  */
 
 /*
@@ -1679,8 +1675,10 @@
         pptph = (struct PptpPacketHeader *)&(((char *)iph)[sizeof(struct iphdr) + sizeof(struct tcphdr)]);
 #ifdef DEBUG_IP_MASQUERADE_PPTP_VERBOSE
         printk(KERN_DEBUG "ip_masq_pptp(): ");
-        printk("LEN=%d TY=%d MC=%lX\n", ntohs(pptph->packetLength),
+        printk("LEN=%d TY=%d MC=%lX", ntohs(pptph->packetLength),
                 ntohs(pptph->packetType), ntohl(pptph->magicCookie));
+	printk(" from %s", in_ntoa(iph->saddr));
+	printk(" to %s\n", in_ntoa(iph->daddr));
 #endif /* DEBUG_IP_MASQUERADE_PPTP_VERBOSE */
 
         if (ntohs(pptph->packetType) == PPTP_CONTROL_PACKET &&
@@ -1735,7 +1733,7 @@
                                 }
                         break;
                         case PPTP_OUT_CALL_REPLY:
-                                if (iph->saddr == ms->daddr)    /* inbound only */
+                                if (iph->saddr == ms->daddr)    /* inbound (masqueraded client) */
                                 {
 #ifdef DEBUG_IP_MASQUERADE_PPTP
                                         printk(KERN_DEBUG "ip_masq_pptp(): ");
@@ -1799,7 +1797,7 @@
                                 }
                         break;
                         case PPTP_IN_CALL_REPLY:
-                                if (iph->saddr == ms->daddr)    /* inbound only */
+                                if (iph->saddr == ms->daddr)    /* inbound (masqueraded client) */
                                 {
 #ifdef DEBUG_IP_MASQUERADE_PPTP
                                         printk(KERN_DEBUG "ip_masq_pptp(): ");
@@ -1948,6 +1946,11 @@
  * This will DoS the server for the duration of the connection
  * attempt, so keep the masq entry's lifetime short until a
  * response comes in.
+ * If multiple masqueraded hosts are in contention for the same
+ * remote host, enforce round-robin access. This may lead to
+ * misassociation of response traffic if the response is delayed
+ * a great deal, but the masqueraded hosts will clean that up
+ * if it happens.
  */
 
 int ip_fw_masq_esp(struct sk_buff **skb_p, struct device *dev)
@@ -2132,10 +2135,23 @@
         struct sk_buff 	*skb   = *skb_p;
  	struct iphdr	*iph   = skb->h.iph;
         struct ip_masq	*ms;
-        unsigned long    flags;
+        unsigned long   flags;
         __u32 i_spi;
         __u16 fake_sport;
-
+#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS
+	#define ESP_GUESS_SZ 5			/* minimum 3, please */
+	#define ESP_CAND_MIN_TM 5*60*HZ		/* max 10*60*HZ? */
+	unsigned	hash;
+	int		i, ii,
+			ncand = 0, nguess = 0;
+	__u16		isakmp;
+	__u32		cand_ip,
+			guess_ip[ESP_GUESS_SZ];
+	unsigned long	cand_tm,
+			guess_tm[ESP_GUESS_SZ];
+	struct sk_buff 	*skb_cl;
+	struct iphdr	*iph_cl;
+#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */
 
         i_spi = *((__u32 *)&(((char *)iph)[iph->ihl*4]));
         fake_sport = (__u16) ntohl(i_spi) & 0xffff;
@@ -2150,14 +2166,15 @@
                 /* illegal SPI - discard */
                 printk(KERN_INFO "ip_fw_demasq_esp(): ");
                 printk("zero SPI from %s discarded\n", in_ntoa(iph->saddr));
-                return 0;
+                return -1;
         }
 
         if (i_spi == IPSEC_INIT_SQUELCHED) {
                 /* Ack! This shouldn't happen! */
+		/* IPSEC_INIT_SQUELCHED is chosen to be a reserved value as of 4/99 */
                 printk(KERN_NOTICE "ip_fw_demasq_esp(): ");
                 printk("SPI from %s is IPSEC_INIT_SQUELCHED - modify ip_masq.c!\n", in_ntoa(iph->saddr));
-                return 0;
+                return -1;
         }
 
  	/*
@@ -2203,6 +2220,133 @@
                 return 1;
  	}
 
+#ifndef CONFIG_IP_MASQUERADE_IPSEC_NOGUESS
+	/* Guess who this packet is likely intended for:
+	 * Scan the UDP masq table for local hosts that have communicated via
+	 * ISAKMP with the host who sent this packet.
+	 * Using an insertion sort with duplicate IP suppression, build a list
+	 * of the ESP_GUESS_SZ most recent ISAKMP sessions (determined by
+	 * sorting in decreasing order of timeout timer).
+	 * Clone the original packet and send it to those hosts, but DON'T make
+	 * a masq table entry, as we're only guessing. It is assumed that the correct
+	 * host will respond to the traffic and that will create a masq table entry.
+	 * To limit the list a bit, don't consider any ISAKMP masq entries with
+	 * less than ESP_CAND_MIN_TM time to live. This should be some value less
+	 * than the IPSEC table timeout or *all* entries will be ignored...
+	 */
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+	printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+        printk("guessing from %s SPI %lX\n", in_ntoa(iph->saddr), ntohl(i_spi));
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+
+	/* zero out the guess table */
+	for (i = 0;i < ESP_GUESS_SZ; i++) {
+		guess_ip[i] = 0;
+		guess_tm[i] = 0;
+	}
+
+	/* scan ISAKMP sessions with the source host */
+	isakmp = htons(UDP_PORT_ISAKMP);
+        hash = ip_masq_hash_key(IPPROTO_UDP, iph->saddr, isakmp);
+	for(ms = ip_masq_d_tab[hash]; ms ; ms = ms->d_link) {
+		if (ms->protocol == IPPROTO_UDP &&
+		    ms->daddr == iph->saddr &&
+		    ms->sport == isakmp &&
+		    ms->dport == isakmp &&
+		    ms->mport == isakmp &&
+		    ms->ospi != 0) {
+			/* a candidate... */
+			ncand++;
+			cand_ip = ms->saddr;
+			cand_tm = ms->timer.expires - jiffies;
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+			printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+			printk("cand %d: IP %s TM %ld\n", ncand, in_ntoa(cand_ip), cand_tm);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+			if (cand_tm > ESP_CAND_MIN_TM) {
+				/* traffic is recent enough, add to list (maybe) */
+				for (i = 0; i < ESP_GUESS_SZ; i++) {
+					if (cand_tm > guess_tm[i]) {
+						/* newer */
+						if (guess_ip[i] != 0 && cand_ip != guess_ip[i]) {
+							/* newer and IP different - insert */
+							if (i < (ESP_GUESS_SZ - 1)) {
+								/* move entries down the list,
+								 * find first entry after this slot
+								 * where the IP is 0 (unused) or
+								 * IP == candidate (older traffic, same host)
+								 * rather than simply going to the end of the list,
+								 * for efficiency (don't shift zeros) and
+								 * duplicate IP suppression (don't keep older entries
+								 * having the same IP)
+								 */
+								for (ii = i + 1; ii < (ESP_GUESS_SZ - 1); ii++) {
+									if (guess_ip[ii] == 0 || guess_ip[ii] == cand_ip)
+										break;
+								}
+								for (ii-- ; ii >= i; ii--) {
+									guess_ip[ii+1] = guess_ip[ii];
+									guess_tm[ii+1] = guess_tm[ii];
+								}
+							}
+						}
+						guess_ip[i] = cand_ip;
+						guess_tm[i] = cand_tm;
+						break;
+					}
+					if (cand_ip == guess_ip[i]) {
+						/* fresher entry already there */
+						break;
+					}
+				}
+			}
+		}
+	}
+	
+	if (guess_ip[0]) {
+		/* had guesses - send */
+		if (guess_ip[1]) {
+			/* multiple guesses, send a copy to all */
+			for (i = 0; guess_ip[i] != 0; i++) {
+				nguess++;
+#ifdef DEBUG_IP_MASQUERADE_IPSEC_VERBOSE
+				printk(KERN_DEBUG "ip_fw_demasq_esp(): ");
+				printk("guess %d: IP %s TM %ld\n", nguess, in_ntoa(guess_ip[i]), guess_tm[i]);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC_VERBOSE */
+				/* duplicate and send the skb */
+				if ((skb_cl = skb_copy(skb, GFP_ATOMIC)) == NULL) {
+					printk(KERN_INFO "ip_fw_demasq_esp(): ");
+					printk("guessing: cannot copy skb\n");
+				} else {
+					iph_cl = skb_cl->h.iph;
+					iph_cl->daddr = guess_ip[i];
+					ip_send_check(iph_cl);
+					ip_forward(skb_cl, dev, IPFWD_MASQUERADED, iph_cl->daddr);
+					kfree_skb(skb_cl, FREE_WRITE);
+				}
+			}
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+                        printk(KERN_INFO "ip_fw_demasq_esp(): ");
+                        printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi));
+                        printk(" %d hosts (%d cand)\n", nguess, ncand);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+			return -1;	/* discard original packet */
+		} else {
+			/* only one guess, send original packet to that host */
+			iph->daddr = guess_ip[0];
+			ip_send_check(iph);
+
+#ifdef DEBUG_IP_MASQUERADE_IPSEC
+                        printk(KERN_INFO "ip_fw_demasq_esp(): ");
+                        printk("guessing from %s SPI %lX sent to", in_ntoa(iph->saddr), ntohl(i_spi));
+                        printk(" %s (%d cand)\n", in_ntoa(guess_ip[0]), ncand);
+#endif /* DEBUG_IP_MASQUERADE_IPSEC */
+			return 1;
+		}
+	}
+#endif /* CONFIG_IP_MASQUERADE_IPSEC_NOGUESS */
+
  	/* sorry, all this trouble for a no-hit :) */
         printk(KERN_INFO "ip_fw_demasq_esp(): ");
 	printk("Inbound from %s SPI %lX has no masq table entry.\n", in_ntoa(iph->saddr), ntohl(i_spi));
@@ -2240,38 +2384,14 @@
 
         if (iph->protocol==IPPROTO_ICMP) 
             return (ip_fw_masq_icmp(skb_ptr,dev));
-        if (iph->protocol==IPPROTO_GRE) 
 #ifdef CONFIG_IP_MASQUERADE_PPTP
+        if (iph->protocol==IPPROTO_GRE) 
             return (ip_fw_masq_gre(skb_ptr,dev));
-#else
-        {
-                /* received the traffic but can't handle it - let user know. */
-                printk(KERN_INFO "MASQ: %s %s ", "GRE", in_ntoa(iph->saddr));
-                printk("-> %s: ", in_ntoa(iph->daddr));
-                printk("%s Masq not enabled - reconfigure kernel\n", "PPTP");
-                return -1;
-        }
 #endif /* CONFIG_IP_MASQUERADE_PPTP */
-        if (iph->protocol==IPPROTO_ESP) 
 #ifdef CONFIG_IP_MASQUERADE_IPSEC
+        if (iph->protocol==IPPROTO_ESP) 
             return (ip_fw_masq_esp(skb_ptr,dev));
-#else
-        {
-                /* received the traffic but can't handle it - let user know. */
-                printk(KERN_INFO "MASQ: %s %s ", "ESP", in_ntoa(iph->saddr));
-                printk("-> %s: ", in_ntoa(iph->daddr));
-                printk("%s Masq not enabled - reconfigure kernel\n", "IPSEC/ISAKMP");
-                return -1;
-        }
 #endif /* CONFIG_IP_MASQUERADE_IPSEC */
-        if (iph->protocol==IPPROTO_AH) 
-        {
-                /* received the traffic but can't handle it - let user know. */
-                printk(KERN_INFO "MASQ: %s %s ", "AH", in_ntoa(iph->saddr));
-                printk("-> %s: ", in_ntoa(iph->daddr));
-                printk("protocol cannot be masqueraded.\n");
-                return -1;
-        }
 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
 		return -1;
 
@@ -2421,6 +2541,13 @@
  	
  	if (masq_proto_num(iph->protocol)==0)
  	{
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+		if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) {
+			/* ISAKMP timeout should be same as ESP timeout to allow for rekeying */
+			timeout = MASQUERADE_EXPIRE_IPSEC;
+		} else
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
+
                 timeout = ip_masq_expire->udp_timeout;
  		recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,size);
  	}
@@ -2935,15 +3062,15 @@
 		portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
 		if ((ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
 		     ntohs(portptr[1]) > PORT_MASQ_END)
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+                    && ((iph->protocol != IPPROTO_UDP) || (ntohs(portptr[0]) != UDP_PORT_ISAKMP) || (ntohs(portptr[1]) != UDP_PORT_ISAKMP))
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
 #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW 
 		    && !ip_autofw_check_range(iph->saddr, portptr[1], 
 					      iph->protocol, 0)
 		    && !ip_autofw_check_direct(portptr[1], iph->protocol)
 		    && !ip_autofw_check_port(portptr[1], iph->protocol)
 #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */
-#ifdef CONFIG_IP_MASQUERADE_IPSEC
-                    && ((iph->protocol != IPPROTO_UDP) || (ntohs(portptr[0]) != UDP_PORT_ISAKMP) || (ntohs(portptr[1]) != UDP_PORT_ISAKMP))
-#endif /* CONFIG_IP_MASQUERADE_IPSEC */
 			)
 			return 0;
 
@@ -3088,6 +3215,14 @@
                 if (masq_proto_num(iph->protocol)==0)
 		{
                         recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len);
+
+#ifdef CONFIG_IP_MASQUERADE_IPSEC
+			if (iph->protocol == IPPROTO_UDP && ntohs(portptr[0]) == UDP_PORT_ISAKMP && ntohs(portptr[1]) == UDP_PORT_ISAKMP) {
+				/* ISAKMP timeout should be same as ESP timeout to allow for rekeying */
+				timeout = MASQUERADE_EXPIRE_IPSEC;
+			} else
+#endif /* CONFIG_IP_MASQUERADE_IPSEC */
+
 			timeout = ip_masq_expire->udp_timeout;
 		}
                 else
