diff -Nru2 --exclude CVS pptp-linux-1.1.0/AUTHORS src/AUTHORS
--- pptp-linux-1.1.0/AUTHORS	Fri Mar  8 00:23:37 2002
+++ src/AUTHORS	Thu Jul 18 03:36:51 2002
@@ -15,2 +15,3 @@
 Jeff Wiedemeier <Jeff.Wiedemeier@compaq.com>
 Yura Zotov <yz@altlinux.ru>
+Chris Wilson <chris@netservers.co.uk>
diff -Nru2 --exclude CVS pptp-linux-1.1.0/ChangeLog src/ChangeLog
--- pptp-linux-1.1.0/ChangeLog	Mon Mar 11 08:36:52 2002
+++ src/ChangeLog	Fri Aug 16 09:35:28 2002
@@ -1,2 +1,120 @@
+Thu Aug 15 09:30:00 2002  Chris Wilson  <chris@netservers.co.uk>
+
+	* pqueue.h: increased window size following James' tests
+	* pptp_gre.c: check for errors while dequeueing packets
+
+Wed Aug 14 20:02:39 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c, pptp_gre.c, pqueue.c: packet re-ordering bugfixes
+	following distributed testing:
+
+	- Moved daemon() call to run on GRE gateway process only, and not
+	if running as pppd pty
+	- Make select() timeout after 1 second if there is data in the
+	queue, to prevent the queue from having to wait forever
+	- Added log messages for accepting individual packets (noisy!)
+	and for timeouts on missing packets
+	- Fixed a bug with the packet queue (append to tail was broken)
+	- Removed unused code from pqueue.c
+	
+	From: chris@netservers.co.uk
+
+Wed Aug 14 11:14:05 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pqueue.c, pqueue.h, pptp_gre.c: major changes to support packet
+	re-ordering.
+
+	Queueing
+
+	Packets are added to the queue by decaps_gre if their sequence
+	number is higher than expected, but within the window. The default
+	window is defined as 30 packets.
+
+	Packets which are below the window (older than the most recent
+	packet read) or above the window (too far ahead) are discarded, to
+	protect against denial-of-service attacks.
+
+	Dequeueing
+
+	The new function dequeue_gre retrieves packets from the head of
+	the queue which are:
+
+	1. Next in sequence (unwrapped or wrapped)
+
+	2. Older than five seconds (assuming that the intermediate packets
+	have been lost by the network).
+
+	The function will continue to read packets from the head of the
+	queue until it finds one which doesn't match these criteria, and
+	then stop.
+
+	Limitations
+	
+	There are some limitations with this patch:
+
+	- The receive window is hardcoded at 30 packets. I couldn't see
+	where to get the negotiated and/or current window size from.
+
+	- The timeout is hardcoded at 5 seconds. A packet which was
+	received and queued within the window, but which should have been
+	preceded by other packets which never appeared, will be accepted
+	anyway after this time (increasing the sequence number to its
+	own).
+
+	- There may be memory leaks or other bugs in the reordering code.
+	
+	* pqueue.c, pqueue.h, Makefile (PPTP_OBJS, PPTP_DEPS): add two new
+	files to the pptp executable. pqueue.c implements the packet queue
+	used by the reordering code, and pqueue.h describes its public
+	interface. The queue is implemented as a linked list. This is
+	required for reordering.
+	
+	* pptp.c: Add a new command-line option, --debug.  Prevents pptp
+	from going into the background.
+
+	Change to call the daemon(3) function to change the current
+	directory and close the standard file descriptors. This prevents a
+	shell from hanging open if pptp is started remotely.
+
+	* Makefile (CFLAGS): reduce the optimisation level (gcc's -O flag)
+	to zero (none), to make debugging easier.
+
+	* pptp.c (get_ip_address): avoid reporting h_errno value.
+
+	From: chris@netservers.co.uk
+
+Thu Jul 18 12:26:25 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.h, pptp_gre.c, pptp.c: bind the GRE socket early, by
+	calling the a function pptp_gre_bind.  Also changed prototype of
+	pptp_gre_copy.  Fixes ICMP Unreachable bug:
+	<1026868263.2855.67.camel@jander> 16th July 2002.
+	From: chris@netservers.co.uk
+
+Thu May 30 18:28:02 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (pptp_call_open): do translation to network byte
+	order after limit checking of phone number.
+	From: staelin@hpl.hp.com
+	
+2002-05-13 08:14:40  Muli Ben-Yehuda  <mulix@actcom.co.il>
+
+	* TODO: remove 'remove setjmp/longjmp' TODO item. 
+	* pptp.c: change comment re volatile qualifiers. 
+	* pptp_callmgr.c: remove unused function 'conn_callback' and
+	change comment re volatile qualifiers. 
+
+Thu Apr  4 09:34:10 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c: correct spelling error.
+	From: Mary.Deck@COMPAQ.com
+
+2002-03-30 13:13:52  mulix  <mulix@actcom.co.il>
+
+	* USING: change URL for bezeq adsl howto.  
+	* pptp.c: (get_ip_address): if the user runs 'pptp --quirks ...'
+	instead of 'pptp hostname', we'll get here and then give a verbose
+	error message. 
+
 Mon Mar 11 10:21:00 2002  mulix  <mulix@actcom.co.il>
 
diff -Nru2 --exclude CVS pptp-linux-1.1.0/Makefile src/Makefile
--- pptp-linux-1.1.0/Makefile	Mon Mar 11 08:36:52 2002
+++ src/Makefile	Wed Aug 14 09:00:48 2002
@@ -10,5 +10,5 @@
 DEBUG	= -g
 INCLUDE =
-CFLAGS  = -Wall -O1 $(DEBUG) $(INCLUDE)
+CFLAGS  = -Wall -O0 $(DEBUG) $(INCLUDE)
 LIBS	=
 LDFLAGS	= -lutil
@@ -19,8 +19,8 @@
             pptp_ctrl.o dirutil.o vector.o \
             inststr.o util.o version.o \
-	    pptp_quirks.o orckit_quirks.o
+	    pptp_quirks.o orckit_quirks.o pqueue.o
 
 PPTP_DEPS = pptp_callmgr.h pptp_gre.h ppp_fcs.h util.h \
-	    pptp_quirks.h orckit_quirks.h config.h
+	    pptp_quirks.h orckit_quirks.h config.h pqueue.h
 
 all: config.h $(PPTP_BIN)
diff -Nru2 --exclude CVS pptp-linux-1.1.0/NEWS src/NEWS
--- pptp-linux-1.1.0/NEWS	Thu Mar  7 23:13:27 2002
+++ src/NEWS	Wed Aug 14 09:00:48 2002
@@ -1,2 +1,5 @@
+- handle out-of-order packets arriving on the GRE socket by buffering.
+- bind GRE socket early to prevent ICMP Unreachable response by client.
+
 Release 1.1.0:
 
diff -Nru2 --exclude CVS pptp-linux-1.1.0/TODO src/TODO
--- pptp-linux-1.1.0/TODO	Mon Mar 11 01:33:03 2002
+++ src/TODO	Mon May 13 06:37:46 2002
@@ -1,5 +1,7 @@
-10th March 2002
+1st May 2002
 
-- redesign to avoid use of setjmp/longjmp.
+- log failure of write() to raw socket, as Ryan Murray
+  <rmurray@debian.org> has encountered an EPERM situation that was not
+  being logged.
 
 12th February 2002
diff -Nru2 --exclude CVS pptp-linux-1.1.0/USING src/USING
--- pptp-linux-1.1.0/USING	Fri Mar  1 16:55:57 2002
+++ src/USING	Sun Mar 31 12:14:56 2002
@@ -1,3 +1,3 @@
-$Id: USING,v 1.3 2002/03/01 16:55:57 quozl Exp $	
+$Id: USING,v 1.4 2002/03/31 11:14:56 mulix Exp $	
 
 pptp is started as a psuedo-tty child process using pppd's pty option:
@@ -46,4 +46,4 @@
 
 More information on Bezeq's ADSL service can be found at
-http://www.pointer.co.il/~mulix/adsl-howto.txt and
+http://vipe.technion.il/~mulix/adsl-howto.txt and
 http://damyen.technion.ac.il/~dani/adsl-howto.txt.
diff -Nru2 --exclude CVS pptp-linux-1.1.0/debian/README.Reference src/debian/README.Reference
--- pptp-linux-1.1.0/debian/README.Reference	Sat Dec 23 08:32:15 2000
+++ src/debian/README.Reference	Thu Apr  4 16:31:37 2002
@@ -16,4 +16,4 @@
 
 Note:
-The following RFCs are note included: 791, 793, 1661, 1662
+The following RFCs are not included: 791, 793, 1661, 1662
 They can be found in package doc-rfc.
diff -Nru2 --exclude CVS pptp-linux-1.1.0/debian/changelog src/debian/changelog
--- pptp-linux-1.1.0/debian/changelog	Fri Mar 22 04:09:14 2002
+++ src/debian/changelog	Fri Mar 22 09:46:17 2002
@@ -1,7 +1,7 @@
-pptp-linux (1.1.0-1) frozen unstable; urgency=low
+pptp-linux (1.1.0-1) unstable; urgency=low
 
   * New upstream release.
 
- -- James Cameron <james.cameron@compaq.com>  Fri, 20 Mar 2002 11:30:55 +1100
+ -- Thomas Quinot <thomas@debian.org>  Fri, 20 Mar 2002 11:30:55 +1100
 
 pptp-linux (1.0.3-2) frozen unstable; urgency=low
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp.c src/pptp.c
--- pptp-linux-1.1.0/pptp.c	Mon Mar 11 01:51:41 2002
+++ src/pptp.c	Thu Aug 15 09:11:43 2002
@@ -3,5 +3,5 @@
  *            C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp.c,v 1.11 2002/03/11 01:51:41 quozl Exp $
+ * $Id: pptp.c,v 1.16 2002/08/14 10:04:20 quozl Exp $
  */
 
@@ -79,5 +79,5 @@
 /* TODO: redesign to avoid longjmp/setjmp.  Several variables here
    have a volatile qualifier to silence warnings from gcc < 3.0.
-   Remove the volatile qualifiers when longjmp/setjmp are removed. */
+   Remove the volatile qualifiers if longjmp/setjmp are removed. */
 
 int main(int argc, char **argv, char **envp) {
@@ -85,5 +85,5 @@
   volatile int callmgr_sock = -1;
   char ttydev[PATH_MAX];
-  int pty_fd, tty_fd, rc;
+  int pty_fd, tty_fd, gre_fd, rc;
   volatile pid_t parent_pid, child_pid;
   u_int16_t call_id, peer_call_id;
@@ -93,5 +93,6 @@
                         * '\0' */
   char * volatile phonenr = NULL;
-  volatile int launchpppd = 1;
+  volatile int launchpppd = 1, debug = 0;
+  
   if (argc < 2)
     usage(argv[0]);
@@ -109,4 +110,5 @@
           {"nolaunchpppd", 0, 0, 0},  
 	  {"quirks", 1, 0, 0},
+	  {"debug", 0, 0, 0},
           {0, 0, 0, 0}
       };
@@ -119,18 +121,21 @@
       switch (c) {
         case 0: 
-            if(option_index == 0) { /* --phone specified */
-                /* copy it to a buffer, as the argv's will be overwritten by 
-                 * inststr() */
-                strncpy(phonenrbuf,optarg,sizeof(phonenrbuf));
-                phonenrbuf[sizeof(phonenrbuf)-1]='\0';
-                phonenr=phonenrbuf;
-            }else if(option_index == 1) {/* --nolaunchpppd specified */
-                  launchpppd=0;
-            }else if(option_index == 2) {/* --quirks specified */
-                if (set_quirk_index(find_quirk(optarg)))
-                    usage(argv[0]);
-            }
+	  if (option_index == 0) { /* --phone specified */
+	    /* copy it to a buffer, as the argv's will be overwritten by 
+	     * inststr() */
+	    strncpy(phonenrbuf,optarg,sizeof(phonenrbuf));
+	    phonenrbuf[sizeof(phonenrbuf)-1]='\0';
+	    phonenr=phonenrbuf;
+	  } else if (option_index == 1) {/* --nolaunchpppd specified */
+	    launchpppd=0;
+	  } else if (option_index == 2) {/* --quirks specified */
+	    if (set_quirk_index(find_quirk(optarg)))
+	      usage(argv[0]);
+	  } else if (option_index == 3) {/* --debug */
+	    debug = 1;
+	  } else {
             /* other pptp options come here */
             break;
+	  }
         case '?': /* unrecognised option, treat it as the first pppd option */
             /* fall through */
@@ -143,5 +148,15 @@
   pppdargc = argc - optind;
   pppdargv = argv + optind;
- 
+
+  /* Step 2a: Now we have the peer address, bind the GRE socket early,
+     before starting pppd. This prevents the ICMP Unreachable bug
+     documented in <1026868263.2855.67.camel@jander> */
+
+  gre_fd = pptp_gre_bind(inetaddr);
+  if (gre_fd < 0) {
+      close(callmgr_sock);
+      fatal("Cannot bind GRE socket, aborting.");
+  }
+
   /* Step 3: Find an open pty/tty pair. */
   if(launchpppd){
@@ -196,12 +211,17 @@
 
   /* Step 5b: Send signal to wake up pppd task */
-  if(launchpppd){
-      kill(parent_pid, SIGUSR1);
-      sleep(2);
+  if (launchpppd){
+    kill(parent_pid, SIGUSR1);
+    sleep(2);
+    /* be a good daemon and close our stdin/out/err fds */
+    if (!debug && daemon(0, 0) != 0) {
+      perror("daemon");
+    }
   }
  
   {
     char buf[128];
-    snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", ttyname(tty_fd));
+    snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", 
+	     ttyname(tty_fd));
     inststr(argc,argv,envp, buf);
   }
@@ -213,5 +233,5 @@
  
   /* Step 6: Do GRE copy until close. */
-  pptp_gre_copy(call_id, peer_call_id, pty_fd, inetaddr);
+  pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd);
 
 shutdown:
@@ -230,13 +250,13 @@
   if (host==NULL) {
     if (h_errno == HOST_NOT_FOUND)
-      fatal("gethostbyname: HOST NOT FOUND");
+      fatal("gethostbyname '%s': HOST NOT FOUND", name);
     else if (h_errno == NO_ADDRESS)
-      fatal("gethostbyname: NO IP ADDRESS");
+      fatal("gethostbyname '%s': NO IP ADDRESS", name);
     else
-      fatal("gethostbyname: name server error");
+      fatal("gethostbyname '%s': name server error", name);
   }
   
   if (host->h_addrtype != AF_INET)
-    fatal("Host has non-internet address");
+    fatal("Host '%s' has non-internet address", name);
   
   memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr));
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_callmgr.c src/pptp_callmgr.c
--- pptp-linux-1.1.0/pptp_callmgr.c	Mon Mar 11 01:51:41 2002
+++ src/pptp_callmgr.c	Mon May 13 06:37:46 2002
@@ -3,5 +3,5 @@
  *                    C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_callmgr.c,v 1.5 2002/03/11 01:51:41 quozl Exp $
+ * $Id: pptp_callmgr.c,v 1.6 2002/05/13 05:37:46 mulix Exp $
  */
 #include <signal.h>
@@ -52,18 +52,4 @@
 };
 
-/* Connection callback */
-void conn_callback(PPTP_CONN *conn, enum conn_state state) {
-
-  switch(state) {
-  case CONN_OPEN_FAIL:
-  case CONN_CLOSE_DONE:
-    /* get outta here */
-    siglongjmp(env, 1);
-    break;
-  default:
-    log("Unhandled connection callback state [%d].", (int) state);
-    break;
-  }
-}
 /* Call callback */
 void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state) {
@@ -108,5 +94,5 @@
 /* NOTE ABOUT 'VOLATILE':                                              */
 /* several variables here get a volatile qualifier to silence warnings */
-/* from older (before 3.0) gccs. once the longjmp stuff is removed,    */
+/* from older (before 3.0) gccs. if the longjmp stuff is removed,      */
 /* the volatile qualifiers should be removed as well.                  */ 
 int main(int argc, char **argv, char **envp) {
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_ctrl.c src/pptp_ctrl.c
--- pptp-linux-1.1.0/pptp_ctrl.c	Mon Mar 11 01:51:16 2002
+++ src/pptp_ctrl.c	Thu May 30 09:31:35 2002
@@ -2,5 +2,5 @@
  *                 C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_ctrl.c,v 1.10 2002/03/11 01:51:16 quozl Exp $
+ * $Id: pptp_ctrl.c,v 1.12 2002/05/30 08:31:35 quozl Exp $
  */
 
@@ -239,7 +239,8 @@
     if (phonenr) {
         strncpy(packet.phone_num, phonenr, sizeof(packet.phone_num));
-        packet.phone_len = hton16 (strlen(phonenr));
+        packet.phone_len = strlen(phonenr);
         if( packet.phone_len > sizeof(packet.phone_num))
             packet.phone_len = sizeof(packet.phone_num);
+	packet.phone_len = hton16 (packet.phone_len);
     }
 
@@ -754,5 +755,5 @@
 	break; /* this is what we expect. */
       /* log it, otherwise. */
-      log("PPTP_SET_LINK_INFO recieved from peer_callid %u",
+      log("PPTP_SET_LINK_INFO received from peer_callid %u",
 	  (unsigned int) ntoh16(packet->call_id_peer));
       log("  send_accm is %08lX, recv_accm is %08lX",
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_gre.c src/pptp_gre.c
--- pptp-linux-1.1.0/pptp_gre.c	Fri Mar  1 01:23:36 2002
+++ src/pptp_gre.c	Fri Aug 16 09:35:28 2002
@@ -3,5 +3,5 @@
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_gre.c,v 1.9 2002/03/01 01:23:36 quozl Exp $
+ * $Id: pptp_gre.c,v 1.13 2002/08/15 23:37:32 quozl Exp $
  */
 
@@ -19,4 +19,5 @@
 #include "pptp_msg.h"
 #include "util.h"
+#include "pqueue.h"
 
 #define PACKET_MAX 8196
@@ -29,10 +30,13 @@
 static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id;
 
-/* decaps gets all the packets possible with ONE blocking read */
+typedef int (*callback_t)(int cl, void *pack, unsigned int len);
+
+/* decaps_hdlc gets all the packets possible with ONE blocking read */
 /* returns <0 if read() call fails */
-int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl);
+int decaps_hdlc(int fd, callback_t callback, int cl);
 int encaps_hdlc(int fd, void *pack, unsigned int len);
-int decaps_gre (int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl);
+int decaps_gre (int fd, callback_t callback, int cl);
 int encaps_gre (int fd, void *pack, unsigned int len);
+int dequeue_gre(callback_t callback, int cl);
 
 #if 1
@@ -58,30 +62,41 @@
 #endif
 
-void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, 
-		   int pty_fd, struct in_addr inetaddr) {
+/* Open IP protocol socket */
+int pptp_gre_bind(struct in_addr inetaddr) {
   struct sockaddr_in src_addr;
-  int s, n;
 
-  pptp_gre_call_id = call_id;
-  pptp_gre_peer_call_id = peer_call_id;
+  int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
+  if (s<0) { warn("socket: %s", strerror(errno)); return -1; }
 
-  /* Open IP protocol socket */
-  s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
-  if (s<0) { warn("socket: %s", strerror(errno)); return; }
   src_addr.sin_family = AF_INET;
   src_addr.sin_addr   = inetaddr;
   src_addr.sin_port   = 0;
+
   if (connect(s, (struct sockaddr *) &src_addr, sizeof(src_addr))<0) {
-    warn("connect: %s", strerror(errno)); return;
+    warn("connect: %s", strerror(errno)); return -1;
   }
+
+  return s;
+}
+
+void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, 
+		   int pty_fd, int gre_fd) {
+  int max_fd;
+
+  pptp_gre_call_id = call_id;
+  pptp_gre_peer_call_id = peer_call_id;
+
   /* Pseudo-terminal already open. */
   
   ack_sent = ack_recv = seq_sent = seq_recv = 0;
 
-  n = (s>pty_fd)?(s+1):(pty_fd+1); /* weird select semantics */
+  /* weird select semantics */
+  max_fd = gre_fd;
+  if (pty_fd > max_fd) max_fd = pty_fd;
 
   /* Dispatch loop */
-  for (;;) { /* until error happens on s or pty_fd */
+  for (;;) { /* until error happens on gre_fd or pty_fd */
     struct timeval tv = {0, 0}; /* non-blocking select */
+    struct timeval *tvp;
     fd_set rfds;
     int retval;
@@ -89,21 +104,39 @@
     /* watch terminal and socket for input */
     FD_ZERO(&rfds);
-    FD_SET(s, &rfds);
-    FD_SET(pty_fd,&rfds);
+    FD_SET(gre_fd, &rfds);
+    FD_SET(pty_fd, &rfds);
 
-    /* if there is a pending ACK, do non-blocking select,
+    /* if there is a pending ACK, then do non-blocking select.
+       if there is data in the queue, then timeout after 1 second.
        otherwise, block until data is available */
-    retval = select(n, &rfds, NULL, NULL, (ack_sent != seq_recv) ? &tv : NULL);
+    tvp = NULL;
+    if (ack_sent != seq_recv) {
+      tv.tv_sec = 0;
+      tvp = &tv;
+    } else if (pqueue_head != NULL) {
+      tv.tv_sec = 1;
+      tvp = &tv;
+    }
+
+    retval = select(max_fd+1, &rfds, NULL, NULL, tvp);
 
     if (retval == 0 && ack_sent != seq_recv) /* if outstanding ack */
-      encaps_gre(s, NULL, 0); /* send ack with no payload */
+      encaps_gre(gre_fd, NULL, 0); /* send ack with no payload */
 
-    if ((FD_ISSET(pty_fd, &rfds) && (decaps_hdlc(pty_fd, encaps_gre, s) < 0))
-     || (FD_ISSET(s,  &rfds) && (decaps_gre(s, encaps_hdlc, pty_fd) < 0)))
-        break;
+    if (FD_ISSET(pty_fd, &rfds)) {
+	if (decaps_hdlc(pty_fd, encaps_gre,  gre_fd) < 0)
+	    break;
+    }
+    if (FD_ISSET(gre_fd, &rfds)) {
+	if (decaps_gre (gre_fd, encaps_hdlc, pty_fd) < 0)
+	    break;
+    }
+    if (dequeue_gre (encaps_hdlc, pty_fd) < 0)
+      break;
   }
 
   /* Close up when done. */
-  close(s); close(pty_fd);
+  close(gre_fd);
+  close(pty_fd);
 }
 
@@ -206,9 +239,12 @@
 }
 
-int decaps_gre (int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl) {
+int decaps_gre (int fd, callback_t callback, int cl) {
   unsigned char buffer[PACKET_MAX+64/*ip header*/];
   struct pptp_gre_header *header;
   int status, ip_len=0;
   static int first=1;
+  unsigned int headersize;
+  unsigned int payload_len;
+  u_int32_t seq;
 
   if ((status = read (fd, buffer, sizeof(buffer))) <= 0) {
@@ -245,25 +281,71 @@
     if (WRAPPED(ack,ack_recv)) ack_recv=ack;
   }
-  if (PPTP_GRE_IS_S(ntoh8(header->flags))) { /* payload present */
-    unsigned int headersize = sizeof(*header);
-    unsigned int payload_len= ntoh16(header->payload_len);
-    u_int32_t seq       = ntoh32(header->seq);
-    if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize-=sizeof(header->ack);
-    /* check for incomplete packet (length smaller than expected) */
-    if (status-headersize<payload_len) return 0; 
-    /* check for out-of-order sequence number */
-    /* (handle sequence number wrap-around, and try to do it right) */
-    if ( first || (seq > seq_recv) || 
-	WRAPPED( seq, seq_recv)){
-      seq_recv = seq;
-      first=0;
-      return cb(cl, buffer+ip_len+headersize, payload_len);
-    } else {
-      log("discarding out-of-order  seq is %d seqrecv is %d", seq, seq_recv); 
-      return 0; /* discard out-of-order packets */
-    }
+
+  if (!PPTP_GRE_IS_S(ntoh8(header->flags))) /* no payload present */
+    return 0; /* ack, but no payload */
+
+  headersize  = sizeof(*header);
+  payload_len = ntoh16(header->payload_len);
+  seq         = ntoh32(header->seq);
+
+  if (!PPTP_GRE_IS_A(ntoh8(header->ver))) headersize-=sizeof(header->ack);
+
+  /* check for incomplete packet (length smaller than expected) */
+  if (status-headersize < payload_len) {
+    log("discarding truncated packet (expected %d, got %d bytes)",
+	payload_len, status-headersize);
+    return 0; 
   }
-  return 0; /* ack, but no payload */
+
+  /* check for out-of-order sequence number */
+  /* (handle sequence number wrap-around, and try to do it right) */
+  if ( first || (seq == seq_recv+1) || 
+       WRAPPED(seq, seq_recv)){
+    log("accepting packet %d", seq);
+    first=0;
+    seq_recv = seq;
+    return callback(cl, buffer+ip_len+headersize, payload_len);
+
+  } else if ( seq < seq_recv+1 || WRAPPED(seq_recv,seq) ) {
+    log("discarding duplicate or old packet %d (expecting %d)",
+	 seq, seq_recv+1);
+
+  } else if ( seq < seq_recv+MISSING_WINDOW ||
+	      WRAPPED(seq, seq_recv+MISSING_WINDOW) ) {
+    log("buffering out-of-order packet %d (expecting %d)", seq, seq_recv+1); 
+    pqueue_add(seq, buffer+ip_len+headersize, payload_len);
+
+  } else {
+    log("discarding bogus packet %d (expecting %d)", seq, seq_recv+1);
+  }
+
+  return 0;
 }
+
+int dequeue_gre (callback_t callback, int cl) {
+  pqueue_t *head;
+  int status;
+  time_t now = time(NULL);
+
+  head = pqueue_head();
+  if (head == NULL) return 0;
+
+  while ( (head->seq == seq_recv+1)      || 
+	  (WRAPPED(head->seq, seq_recv)) ||
+	  (head->expires < now) ) {
+    if (head->expires < now)
+      log("timeout waiting for %d packets", head->seq - seq_recv - 1);
+    log("accepting %d from queue", head->seq);
+    seq_recv = head->seq;
+    status = callback(cl, head->packet, head->packlen);
+    pqueue_del(head);
+    if (status != 0)
+      return status;
+    head = pqueue_head();
+  }
+
+  return 0;
+}
+
 int encaps_gre (int fd, void *pack, unsigned int len) {
   union {
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pptp_gre.h src/pptp_gre.h
--- pptp-linux-1.1.0/pptp_gre.h	Sat Dec 23 08:19:51 2000
+++ src/pptp_gre.h	Thu Jul 18 03:34:30 2002
@@ -3,9 +3,8 @@
  *               C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_gre.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
+ * $Id: pptp_gre.h,v 1.2 2002/07/18 02:34:30 quozl Exp $
  */
 
-/*void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id,
-		   char *pty, char *inetaddr);*/
+int pptp_gre_bind(struct in_addr inetaddr);
 void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id,
-		   int pty_fd, struct in_addr inetaddr);
+		   int pty_fd, int gre_fd);
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pqueue.c src/pqueue.c
--- pptp-linux-1.1.0/pqueue.c	Thu Jan  1 01:00:00 1970
+++ src/pqueue.c	Thu Aug 15 09:11:43 2002
@@ -0,0 +1,86 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h" // for log()
+#include "pqueue.h"
+
+static pqueue_t *pq_head = NULL, *pq_tail = NULL;
+
+int pqueue_add (int seq, unsigned char *packet, int packlen) {
+  pqueue_t *newent, *point;
+
+  newent = (pqueue_t *)calloc(1, sizeof(pqueue_t));
+  if (!newent) {
+    log("error allocating newent: %s", strerror(errno));
+    return -1;
+  }
+
+  newent->packet = (unsigned char *)malloc(packlen);
+  if (!newent->packet) {
+    log("error allocating packet: %s", strerror(errno));
+    return -1;
+  }
+
+  memcpy(newent->packet, packet, packlen);
+  newent->seq     = seq;
+  newent->packlen = packlen;
+  newent->expires = time(NULL) + MISSING_TIMEOUT;
+  
+  for (point = pq_head; point != NULL; point = point->next) {
+    if (point->seq == seq) {
+      // queue already contains this packet
+      log("discarding duplicate packet %d", seq);
+      return -1;
+    }
+    if (point->seq > seq) {
+      // gone too far: point->seq > seq and point->prev->seq < seq
+      if (point->prev) {
+	// insert between point->prev and point
+	log("adding %d between %d and %d", 
+	    seq, point->prev->seq, point->seq);
+	point->prev->next = newent;
+      } else {
+	// insert at head of queue, before point
+	log("adding %d before %d", seq, point->seq);
+	pq_head = newent;
+      }
+      newent->prev = point->prev; // will be NULL, at head of queue
+      newent->next = point;
+      point->prev = newent;
+      return 0;
+    }
+  }
+
+  /* We didn't find anywhere to insert the packet,
+   * so there are no packets in the queue with higher sequences than this one,
+   * so all the packets in the queue have lower sequences,
+   * so this packet belongs at the end of the queue (which might be empty)
+   */
+  
+  if (pq_head == NULL) {
+    log("adding %d to empty queue", seq);
+    pq_head = newent;
+  } else {
+    log("adding %d as tail, after %d", seq, pq_tail->seq);
+    pq_tail->next = newent;
+  }
+  newent->prev = pq_tail;
+  pq_tail = newent;
+
+  return 0;
+}
+
+int pqueue_del (pqueue_t *point) {
+  if (pq_head == point) pq_head = point->next;
+  if (pq_tail == point) pq_tail = point->prev;
+  if (point->prev) point->prev->next = point->next;
+  if (point->next) point->next->prev = point->prev;
+  free(point->packet);
+  free(point);
+  return 0;
+}
+
+pqueue_t *pqueue_head () {
+  return pq_head;
+}
diff -Nru2 --exclude CVS pptp-linux-1.1.0/pqueue.h src/pqueue.h
--- pptp-linux-1.1.0/pqueue.h	Thu Jan  1 01:00:00 1970
+++ src/pqueue.h	Fri Aug 16 09:35:28 2002
@@ -0,0 +1,26 @@
+#ifndef PQUEUE_H
+#define PQUEUE_H
+
+#include <time.h>
+
+/* wait this many seconds for missing packets before forgetting about them */
+#define MISSING_TIMEOUT 5
+
+/* assume packet is bad/spoofed if it's more than this many seqs ahead */
+#define MISSING_WINDOW 50
+
+/* Packet queue structure: linked list of packets received out-of-order */
+typedef struct pqueue {
+  struct pqueue *next;
+  struct pqueue *prev;
+  int seq;
+  time_t expires;
+  unsigned char *packet;
+  int packlen;
+} pqueue_t;
+
+int       pqueue_add  (int seq, unsigned char *packet, int packlen);
+int       pqueue_del  (pqueue_t *point);
+pqueue_t *pqueue_head ();
+
+#endif /* PQUEUE_H */
