Common subdirectories: pptpd-1.1.1/html and pptpd-1.1.1-reorder/html
diff -u pptpd-1.1.1/pptpctrl.c pptpd-1.1.1-reorder/pptpctrl.c
--- pptpd-1.1.1/pptpctrl.c	Wed Dec 29 11:06:41 1999
+++ pptpd-1.1.1-reorder/pptpctrl.c	Thu Sep 28 11:19:56 2000
@@ -500,6 +500,12 @@
 				break;
 			case STOP_CTRL_CONN_RPLY:
 				goto skip;
+			case 0:
+				syslog(LOG_WARNING, "CTRL: Client already disconnected control stream");
+				goto skip;
+			case -1:
+				syslog(LOG_WARNING, "CTRL: Error reading control stream during disconnect, aborting");
+				goto skip;
 			default:
 				syslog(LOG_WARNING, "CTRL: Unexpected control message %d in disconnect sequence", pkt);
 			}
Only in pptpd-1.1.1-reorder: pptpd-1.1.1-reorder-v2.diff
diff -u pptpd-1.1.1/pptpgre.c pptpd-1.1.1-reorder/pptpgre.c
--- pptpd-1.1.1/pptpgre.c	Thu Dec 23 20:03:44 1999
+++ pptpd-1.1.1-reorder/pptpgre.c	Mon Oct  2 12:29:18 2000
@@ -73,6 +73,7 @@
 
   memset (gre, 0, sizeof (*gre));
   reset_pty_to_gre (gre);
+  gre->seq_recv=-1;
 
   /* Open IP protocol socket */
   gre->gre_fd = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
@@ -438,6 +439,8 @@
 read_gre (struct gre_state *gre)
 {
   int status, offset=0;
+  unsigned int i,j;
+  int recv_time,timeout;
   unsigned char buffer[GRE_PACKET_SIZE + 64 /* ip header */];
   struct gre_rcv_packet *recv_packet;
   unsigned char *data;
@@ -449,10 +452,6 @@
   memset (buffer, 0x66, sizeof(buffer));
   status = read (gre->gre_fd, buffer, sizeof(buffer));
 
-  recv_packet = &gre->window[(gre->gre_current_packet
-                              + gre->gre_num_packets) %
-                            (PCKT_RECV_WINDOW_SIZE + 1)];
-
   if (status < 0) {
     if (errno == EAGAIN || errno == EINTR) {
       /*syslog (LOG_INFO, "GRE read() wants retry");*/
@@ -480,11 +479,9 @@
     return 0;
   }
 
-  memset (recv_packet, 0x11, sizeof(*recv_packet));
-  /* FIXME: Too much copying.  Should just buffer the IP header. */
-  memcpy (recv_packet, &buffer[offset], status);
-
+  recv_packet = (struct gre_rcv_packet *) (buffer+offset);
   header = recv_packet->header;
+  recv_time = time(NULL);
 
   /* Validate the packet. */
   if ((ntoh8 (header.ver) & ~PPTP_GRE_FLAG_A) != PPTP_GRE_VER
@@ -532,7 +529,8 @@
   if (has_payload) {
     u_int32_t seq;
 
-    if (gre->gre_num_packets >= PCKT_RECV_WINDOW_SIZE) {
+    /* Keep 8 packets of buffer room for packet reordering */
+    if (gre->gre_num_packets >= (PCKT_RECV_WINDOW_SIZE-PCKT_REORDER_SIZE)) {
       syslog (LOG_ERR, "GRE: window overflowed.  Dropping packet...");
       return 1;
     }
@@ -546,15 +544,10 @@
       data = recv_packet->body.one.data;
     }
 
-    if (pptpctrl_debug && seq != gre->seq_recv + 1) {
-      syslog (LOG_INFO, "Unexpected sequence number; got %u after %u",
-              seq, gre->seq_recv);
-    }
-
     /* Check sequence number; discard if out of order */
     if (!seq_less_than (gre->seq_recv, seq)) {
       syslog (LOG_WARNING,
-              "Discarding out-of-order packet %x, already have %x",
+              "Discarding out-of-order packet %u, already have %u",
               seq, gre->seq_recv);
       return 0;
     }
@@ -568,8 +561,117 @@
       return 0;
     }
 
-    gre->seq_recv = seq;
-    gre->gre_num_packets++;
+    i=seq - gre->seq_recv - 1;
+
+    /* Timeout if there are no buffered packets waiting to go to pppd,
+     *  the current packet is not the next packet in the sequence,
+     *  and it has been 3 seconds size we last passed on a packet. */
+    timeout=FALSE;
+    if((gre->gre_num_packets == 0) && (i>0) && (recv_time > (gre->gre_last_recv_time+PCKT_REORDER_WAIT_TIME))) {
+      /* Check for packets in the buffer */
+      for(j=0 ; (j<PCKT_REORDER_SIZE) && (gre->window[(gre->gre_current_packet+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.payload_len == 0) ; j++);
+      /* If there is a buffered packet, trigger a timeout */
+      if(j!=PCKT_REORDER_SIZE)
+	timeout=TRUE;
+    }
+
+    /* If this packet is beyond the reorder buffer,
+     * stop waiting for the missing packet */
+    if ((i >= PCKT_REORDER_SIZE) || timeout) {
+      if(gre->gre_num_packets > 0) {
+	/* There are still packets in the queue, so we can't skip packets yet */
+	if(pptpctrl_debug) {
+	  syslog (LOG_INFO, "Dropping out-of-order packet; got %u after %u",
+		  seq, gre->seq_recv);
+	}
+	return 0;
+      }
+        /* Stop waiting for the oldest packet */
+        for(j=0 ; (j<i) && (j<PCKT_REORDER_SIZE) && (gre->window[(gre->gre_current_packet+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.payload_len == 0) ; j++);
+
+        /* Missing more than PCKT_REORDER_SIZE consecutive packets - just ignore them and process this new packet */
+	if(pptpctrl_debug) {
+	  if(timeout) {
+	    syslog (LOG_INFO, "Packet reorder timeout waiting for %u",gre->seq_recv+1);
+	  } else if(j==PCKT_REORDER_SIZE) {
+	    syslog (LOG_INFO, "Missing %d consecutive packets; got %u after %u",
+		    PCKT_REORDER_SIZE,seq, gre->seq_recv);
+	  } else {
+	    syslog (LOG_INFO, "Exceeded packet reorder buffer size; got %u after %u; skipping %d packets",
+		    seq, gre->seq_recv,j);
+	  }
+	}
+        if(j==PCKT_REORDER_SIZE) {
+            memcpy(&gre->window[gre->gre_current_packet],buffer+offset,status);
+#if 0
+	    if(pptpctrl_debug) {
+	      syslog(LOG_INFO,"Filling packet buffer slot %d with packet %u",gre->gre_current_packet,seq);
+	    }
+#endif
+            gre->seq_recv = seq;
+            gre->gre_num_packets++;
+	    gre->gre_last_recv_time=recv_time;
+            return 1;
+        }
+
+        /* Else skip forward to the oldest previously received packet */
+        gre->gre_current_packet=(gre->gre_current_packet+j) % (PCKT_RECV_WINDOW_SIZE+1);
+        gre->seq_recv += j;
+
+        i-=j;
+     }
+     /* Buffer the latest packet if it isn't too far ahead, else just drop it */
+     if(i < PCKT_REORDER_SIZE) {
+        if(pptpctrl_debug && (i>0)) {
+	      syslog (LOG_INFO, "Buffering out-of-order packet; got %u after %u",
+        	      seq, gre->seq_recv);
+        }
+        memcpy(&gre->window[(gre->gre_current_packet+gre->gre_num_packets+i) % (PCKT_RECV_WINDOW_SIZE+1)],buffer+offset,status);
+#if 0
+	    if(pptpctrl_debug) {
+	      syslog(LOG_INFO,"Filling packet buffer slot %d with packet %u (curr=%d,n=%d,i=%d)",(gre->gre_current_packet+gre->gre_num_packets+i) % (PCKT_RECV_WINDOW_SIZE+1),seq,gre->gre_current_packet,gre->gre_num_packets,i);
+	    }
+#endif
+     } else if(pptpctrl_debug) {
+          syslog (LOG_INFO, "Dropping out-of-order packet %u",seq);
+     }
+
+     /* Skip lost packets if we get PCKT_REORDER_SIZE consecutive following packets */
+
+     if((gre->gre_num_packets==0) && (gre->window[gre->gre_current_packet].header.payload_len == 0)) {
+       for(i=0,j=1;(i < (PCKT_REORDER_RESUME_SIZE)) && (j<PCKT_REORDER_SIZE);j++) {
+	 if(gre->window[(gre->gre_current_packet+j) % (PCKT_RECV_WINDOW_SIZE+1)].header.payload_len != 0) {
+	   i++;
+	 } else {
+	   i=0;
+	 }
+       }
+       if(i >= (PCKT_REORDER_RESUME_SIZE)) {
+	 /* Advance counters over the lost packet(s) */
+	 for(j=1 ; (j<PCKT_REORDER_SIZE) && (gre->window[(gre->gre_current_packet+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.payload_len == 0) ; j++);
+	 if((pptpctrl_debug) && (gre->seq_recv+j > 0)) {
+	   syslog (LOG_INFO, "Gave up waiting for %d lost packets beginning with %u",j,gre->seq_recv+1);
+	 }
+	 
+	 gre->gre_current_packet=(gre->gre_current_packet+j) % (PCKT_RECV_WINDOW_SIZE+1);
+	 gre->seq_recv += j;
+       }
+     }
+
+     /* Add all consecutive available packets to the queue */
+     for(j=0 ; (j<PCKT_REORDER_SIZE) && (gre->window[(gre->gre_current_packet+gre->gre_num_packets+j)%(PCKT_RECV_WINDOW_SIZE+1)].header.payload_len != 0) ; j++);
+     /*
+     if(pptpctrl_debug && (j>1)) {
+       syslog(LOG_INFO,"Adding %d packets to the queue",j);
+     }
+     */
+     gre->seq_recv += j;
+     gre->gre_num_packets += j;
+     if(j>0) {
+       gre->gre_last_recv_time = recv_time;
+       return 1;
+     }
+     return 0;
 
 #if 0
     /* Dump start of packet. */
@@ -578,7 +680,6 @@
             status, data[0], data[1], data[2], data[3], data[4],
             data[5], data[6]);
 #endif
-    return 1;
   }
 
   if (!has_payload && !has_ack)
@@ -656,8 +757,8 @@
   gre->gre_current_packet = ((gre->gre_current_packet + 1)
                              % (PCKT_RECV_WINDOW_SIZE + 1));
 
-  /* Fill packet with garbage */
-  memset (packet, 0x33, sizeof (*packet));
+  /* Zero out the packet so the payload_len parameter is zero which indicates this slot is empty */
+  memset (packet, 0x00, sizeof (*packet));
 }
 
 /* Send some stuff to the PTY.  Return 1 if we wrote something, 0 if
diff -u pptpd-1.1.1/pptpgre.h pptpd-1.1.1-reorder/pptpgre.h
--- pptpd-1.1.1/pptpgre.h	Thu Dec 23 16:43:33 1999
+++ pptpd-1.1.1-reorder/pptpgre.h	Fri Sep 29 13:02:55 2000
@@ -14,6 +14,26 @@
 #define GRE_PACKET_SIZE 2048
 #define HDLC_PACKET_SIZE (2*GRE_PACKET_SIZE + 6)
 
+/* Variables to control the packet reordering scheme:
+ *  PCKT_REORDER_SIZE
+ *     this is the number of packets ahead of the current packet that
+ *     will get buffered while waiting for a packet.  If a new packet
+ *     comes in more than this far ahead, we stop waiting for the missing packet
+ *
+ *  PCKT_REORDER_RESUME_SIZE
+ *     if this many consecutive packets are available in the buffer
+ *     while we are waiting for a lost packet, then we will stop waiting
+ *     for the missing packet
+ *
+ *  PCKT_REORDER_WAIT_TIME
+ *     if a new packet comes in and this many seconds have expired since
+ *     we last passed on a packet to pppd, then we will stop waiting
+ *     for the missing packet
+ */
+#define PCKT_REORDER_SIZE 12
+#define PCKT_REORDER_RESUME_SIZE 3
+#define PCKT_REORDER_WAIT_TIME 2
+
 enum gre_header_type { GRE_HEAD_ONE, GRE_HEAD_BOTH };
 
 struct gre_xmit_packet {
@@ -72,6 +92,7 @@
   struct gre_rcv_packet window[PCKT_RECV_WINDOW_SIZE+1];
   int gre_current_packet;
   int gre_num_packets;
+  int gre_last_recv_time;
 
   /* PTY output state */
   int pty_fd;
