diff -urNp mpd3-cvs.orig/src/chap.c mpd3-cvs/src/chap.c
--- mpd3-cvs.orig/src/chap.c	Sun May  8 17:54:56 2005
+++ mpd3-cvs/src/chap.c	Tue Jul  4 15:23:39 2006
@@ -312,8 +312,10 @@ ChapInput(Mbuf bp)
 
 	/* Check packet */
 	if (a->self_to_peer != PROTO_CHAP
-	    || lnk->lcp.phase != PHASE_AUTHENTICATE)
+	    || lnk->lcp.phase != PHASE_AUTHENTICATE) {
 	  Log(LG_AUTH, (" Not expected, but that's OK"));
+          break;
+        }
 	if (ChapParsePkt(bp, len, peer_name, chap_value, &chap_value_size) < 0)
 	  break;
 
@@ -450,8 +452,11 @@ ChapInput(Mbuf bp)
 
 	/* Check response */
 	if (a->peer_to_self != PROTO_CHAP
-	    || lnk->lcp.phase != PHASE_AUTHENTICATE)
+	    || lnk->lcp.phase != PHASE_AUTHENTICATE) {
 	  Log(LG_AUTH, (" Not expected, but that's OK"));
+          break;
+        }
+
 	if (ChapParsePkt(bp, len,
 	    peer_name, chap_value, &chap_value_size) < 0) {
 	  whyFail = AUTH_FAIL_INVALID_PACKET;
diff -urNp mpd3-cvs.orig/src/iface.c mpd3-cvs/src/iface.c
--- mpd3-cvs.orig/src/iface.c	Fri Nov  5 08:31:58 2004
+++ mpd3-cvs/src/iface.c	Tue May 23 22:56:53 2006
@@ -20,6 +20,7 @@
 #include "netgraph.h"
 #include "radius.h"
 #include "util.h"
+#include "pptp.h"
 #include <sys/sockio.h>
 #include <net/if.h>
 #include <net/if_types.h>
@@ -29,9 +30,11 @@
 #ifdef __DragonFly__
 #include <netgraph/iface/ng_iface.h>
 #include <netgraph/bpf/ng_bpf.h>
+#include <netgraph/tee/ng_tee.h>
 #else
 #include <netgraph/ng_iface.h>
 #include <netgraph/ng_bpf.h>
+#include <netgraph/ng_tee.h>
 #endif
 
 /*
@@ -284,7 +287,12 @@ IfaceUp(struct in_addr self, struct in_a
 
     /* Reset bpf node statistics */
     memset(&iface->idleStats, 0, sizeof(iface->idleStats));
+    if (gEnableTee) {
+      snprintf(path, sizeof(path), "%s:%s.%s", iface->ifname,
+        NG_IFACE_HOOK_INET, NG_TEE_HOOK_RIGHT);
+    } else {
     snprintf(path, sizeof(path), "%s:%s", iface->ifname, NG_IFACE_HOOK_INET);
+    }
     if (NgSendMsg(bund->csock, path, NGM_BPF_COOKIE,
 	NGM_BPF_CLR_STATS, BPF_HOOK_IFACE, sizeof(BPF_HOOK_IFACE)) < 0)
       Log(LG_ERR, ("[%s] can't clear %s stats: %s",
@@ -315,9 +323,11 @@ IfaceUp(struct in_addr self, struct in_a
 #endif
 
   /* Turn on interface traffic flow */
-  if (Enabled(&iface->options, IFACE_CONF_TCPMSSFIX))
+  if (Enabled(&iface->options, IFACE_CONF_TCPMSSFIX)) {
     NgFuncConfigBPF(bund, BPF_MODE_MSSFIX);
-  else 
+    if (gNgTcpMssFix)
+	NgFuncConfigTCPMSS(bund, MAXMSS(iface->mtu));
+  } else 
     NgFuncConfigBPF(bund, BPF_MODE_ON);
 
   /* Send any cached packets */
@@ -685,11 +695,24 @@ IfaceIpIfaceUp(int ready)
       ns2buf[0] = '\0';
 
     snprintf(peerbuf, sizeof(peerbuf), "%s", inet_ntoa(iface->peer_addr));
+
+    if (lnk->phys->type == &gPptpPhysType) {
+	char		pptp_peer[100];
+
+	snprintf(pptp_peer, sizeof(pptp_peer), "%s", inet_ntoa(*(PptpGetPeerIp())));
+    	ExecCmd(LG_IFACE, "%s %s inet %s %s %s %s %s %s",
+	      iface->up_script, iface->ifname, inet_ntoa(iface->self_addr),
+	      peerbuf, 
+	      *bund->peer_authname ? bund->peer_authname : bund->conf.authname,
+	      ns1buf, ns2buf,
+	      pptp_peer);
+    } else {
     ExecCmd(LG_IFACE, "%s %s inet %s %s %s %s %s",
       iface->up_script, iface->ifname, inet_ntoa(iface->self_addr),
       peerbuf, 
       *bund->peer_authname ? bund->peer_authname : bund->conf.authname,
       ns1buf, ns2buf);
+    }
   }
 
   /* Done */
@@ -837,7 +860,12 @@ IfaceIdleTimeout(void *arg)
 
   /* Get updated bpf node traffic statistics */
   oldStats = iface->idleStats;
+  if (gEnableTee) {
+    snprintf(path, sizeof(path), "%s:%s.%s", iface->ifname,
+      NG_IFACE_HOOK_INET, NG_TEE_HOOK_RIGHT);
+  } else {
   snprintf(path, sizeof(path), "%s:%s", iface->ifname, NG_IFACE_HOOK_INET);
+  }
   if (NgSendMsg(bund->csock, path, NGM_BPF_COOKIE,
       NGM_BPF_GET_STATS, BPF_HOOK_IFACE, sizeof(BPF_HOOK_IFACE)) < 0) {
     Log(LG_ERR, ("[%s] can't get %s stats: %s",
diff -urNp mpd3-cvs.orig/src/link.h mpd3-cvs/src/link.h
--- mpd3-cvs.orig/src/link.h	Sun Jul 25 00:26:20 2004
+++ mpd3-cvs/src/link.h	Tue May 23 22:56:53 2006
@@ -99,6 +99,8 @@
 	u_int64_t 	runts;		/* Too short MP fragments */
 	u_int64_t 	dupFragments;	/* MP frames with duplicate seq # */
 	u_int64_t	dropFragments;	/* MP fragments we had to drop */
+	u_int64_t	sv_xmitOctets;	/* update-limit support */
+	u_int64_t	sv_recvOctets;	/* update-limit support */
   };
   typedef struct linkstat *LinkStats;
 
diff -urNp mpd3-cvs.orig/src/main.c mpd3-cvs/src/main.c
--- mpd3-cvs.orig/src/main.c	Sat Oct 11 10:26:13 2003
+++ mpd3-cvs/src/main.c	Tue May 23 22:56:53 2006
@@ -64,6 +64,10 @@
 				"Show version information"	},
     { 0, 'h',	"help",		"",
 				"Show usage information"	},
+    { 0, 't',	"tee",		"",
+                                "Insert ng_tee into netgraph"	},
+    { 0, 'm',	"mssfix",		"",
+                                "Use ng_tcpmss instead of internal one"	},
   };
 
   #define OPTLIST_SIZE		(sizeof(OptList) / sizeof(*OptList))
@@ -81,6 +85,8 @@
   Bund			*gBundles;
   int			gNumLinks;
   int			gNumBundles;
+  int			gEnableTee = FALSE;
+  int			gNgTcpMssFix;
 
   const char		*gConfigFile = CONF_FILE;
   const char		*gConfDirectory = PATH_CONF_DIR;
@@ -514,6 +520,12 @@ OptApply(Option opt, int ac, char *av[])
       exit(EX_NORMAL);
     case 'h':
       Usage(EX_NORMAL);
+    case 't':
+      gEnableTee = TRUE;
+      return(0);
+    case 'm':
+      gNgTcpMssFix = TRUE;
+      return(0);
     default:
       assert(0);
   }
diff -urNp mpd3-cvs.orig/src/ngfunc.c mpd3-cvs/src/ngfunc.c
--- mpd3-cvs.orig/src/ngfunc.c	Sun Jul 25 00:26:20 2004
+++ mpd3-cvs/src/ngfunc.c	Tue May 23 22:56:53 2006
@@ -29,6 +29,8 @@
 #include <netgraph/ppp/ng_ppp.h>
 #include <netgraph/vjc/ng_vjc.h>
 #include <netgraph/bpf/ng_bpf.h>
+#include <netgraph/tee/ng_tee.h>
+#include <netgraph/tcpmss/ng_tcpmss.h>
 #else
 #include <netgraph/ng_socket.h>
 #include <netgraph/ng_ksocket.h>
@@ -36,6 +38,8 @@
 #include <netgraph/ng_ppp.h>
 #include <netgraph/ng_vjc.h>
 #include <netgraph/ng_bpf.h>
+#include <netgraph/ng_tee.h>
+#include <netgraph/ng_tcpmss.h>
 #endif
 
 /*
@@ -123,18 +127,13 @@
 
   /* A BPF filter that matches TCP SYN packets */
   static const struct bpf_insn gTCPSYNProg[] = {
-
-	/* Load IP protocol number and IP header length */
 /*00*/	BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9),		/* A <- IP protocol */
-/*01*/	BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0),		/* X <- header len */
-
-/*02*/	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 1, 0),	/* -> 04 */
-/*03*/	BPF_STMT(BPF_RET+BPF_K, 0),			/* reject packet */
-
-	/* Protocol is TCP -> accept if TH_SYN bit set */
-/*04*/	BPF_STMT(BPF_LD+BPF_B+BPF_IND, 13),		/* A <- TCP flags */
-/*05*/	BPF_STMT(BPF_ALU+BPF_AND+BPF_K, TH_SYN),	/* A <- A & TH_SYN */
-/*06*/	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, 0, 1, 0),	/* compare to zero */
+/*01*/	BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 6),	/* reject if not TCP */
+/*02*/	BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 6),		/* A <- fragmentation offset */
+/*03*/	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 4, 0),	/* ensure we have TCP hdr */
+/*04*/	BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0),		/* X <- header len */
+/*05*/	BPF_STMT(BPF_LD+BPF_B+BPF_IND, 13),		/* A <- TCP flags */
+/*06*/	BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, TH_SYN, 0, 1),	/* jump if set */
 /*07*/	BPF_STMT(BPF_RET+BPF_K, (u_int)-1),		/* accept packet */
 /*08*/	BPF_STMT(BPF_RET+BPF_K, 0),			/* reject packet */
   };
@@ -258,17 +257,30 @@ NgFuncInit(Bund b, const char *reqIface)
     goto fail;
   }
 
-  /* Connect the other side of the bpf node to the iface node */
+  /* Connect the other side of the bpf node to the iface or tee node */
   snprintf(path, sizeof(path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_INET);
+  if (gEnableTee) {
+    snprintf(cn.path, sizeof(cn.path), "%s:%s",
+      b->iface.ifname, NG_IFACE_HOOK_INET);
+    snprintf(cn.peerhook, sizeof(cn.peerhook), "%s", NG_TEE_HOOK_RIGHT);
+  } else {
   snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ifname);
-  snprintf(cn.ourhook, sizeof(cn.ourhook), "%s", BPF_HOOK_IFACE);
   snprintf(cn.peerhook, sizeof(cn.peerhook), "%s", NG_IFACE_HOOK_INET);
+  }
+  snprintf(cn.ourhook, sizeof(cn.ourhook), "%s", BPF_HOOK_IFACE);
+
   if (NgSendMsg(b->csock, path,
       NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
+    if (gEnableTee) {
+      Log(LG_ERR, ("[%s] can't connect %s and %s: %s",
+        b->name, BPF_HOOK_IFACE, NG_TEE_HOOK_RIGHT, strerror(errno)));
+      goto fail;
+    } else {
     Log(LG_ERR, ("[%s] can't connect %s and %s: %s",
       b->name, BPF_HOOK_IFACE, NG_IFACE_HOOK_INET, strerror(errno)));
     goto fail;
   }
+  }
 
   /* Connect a hook from the bpf node to our socket node */
   snprintf(cn.path, sizeof(cn.path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_INET);
@@ -281,6 +293,22 @@ NgFuncInit(Bund b, const char *reqIface)
     goto fail;
   }
 
+  if (gNgTcpMssFix) {
+	  /* Add a tcpmss node to the bpf node on the "tcpmssfix" hook */
+	  snprintf(path, sizeof(path), "%s.%s", MPD_HOOK_PPP, NG_PPP_HOOK_INET);
+	  snprintf(mp.type, sizeof(mp.type), "%s", NG_TCPMSS_NODE_TYPE);
+	  snprintf(mp.ourhook, sizeof(mp.ourhook), "%s", BPF_HOOK_TCPMSS);
+	  snprintf(mp.peerhook, sizeof(mp.peerhook), "%s", BPF_HOOK_TCPMSS);
+	  if (NgSendMsg(b->csock, path,
+		NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
+			Log(LG_ERR, ("[%s] can't create %s node: %s",
+				b->name, NG_TCPMSS_NODE_TYPE, strerror(errno)));
+			goto fail;
+	  }
+	  /* Initial configuration of ng_tcpmss */
+	  NgFuncConfigTCPMSS(b, 0);
+  }
+
   /* Configure bpf(8) node */
   NgFuncConfigBPF(b, BPF_MODE_OFF);
 
@@ -399,6 +427,7 @@ NgFuncCreateIface(Bund b, const char *if
   struct nodeinfo	*const ni = (struct nodeinfo *)(void *)u.reply.data;
   struct ngm_rmhook	rm;
   struct ngm_mkpeer	mp;
+  struct ngm_connect	cn;
   int			rtn = 0;
 
   /* If ifname is not null, create interfaces until it gets created */
@@ -450,6 +479,38 @@ NgFuncCreateIface(Bund b, const char *if
   snprintf(buf, max, "%s", ni->name);
 
 done:
+
+  /* Disconnect temporary hook */
+  snprintf(rm.ourhook, sizeof(rm.ourhook), "%s", TEMPHOOK);
+  if (NgSendMsg(b->csock, ".",
+      NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
+    Log(LG_ERR, ("[%s] can't remove hook %s: %s",
+      b->name, TEMPHOOK, strerror(errno)));
+    rtn = -1;
+  }
+
+  /* Add netgraph tee node to created iface if configured */
+  if (gEnableTee && (rtn != -1)) {
+    /* Create tee node (as a temporary peer of the socket node) */
+    snprintf(mp.type, sizeof(mp.type), "%s", NG_TEE_NODE_TYPE);
+    snprintf(mp.ourhook, sizeof(mp.ourhook), "%s", TEMPHOOK);
+    snprintf(mp.peerhook, sizeof(mp.peerhook), "%s", NG_TEE_HOOK_RIGHT);
+    if (NgSendMsg(b->csock, ".",
+        NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
+      Log(LG_ERR, ("[%s] can't create %s node: %s",
+        b->name, NG_TEE_NODE_TYPE, strerror(errno)));
+      return(-1);
+    }
+    /* Connect tee and iface nodes */
+    snprintf(cn.path, sizeof(cn.path), "%s:", ni->name);
+    snprintf(cn.ourhook, sizeof(cn.ourhook), "%s", NG_TEE_HOOK_LEFT);
+    snprintf(cn.peerhook, sizeof(cn.peerhook), "%s", NG_IFACE_HOOK_INET);
+    if (NgSendMsg(b->csock, TEMPHOOK,
+        NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
+      Log(LG_ERR, ("[%s] can't connect %s and %s: %s",
+        b->name, NG_TEE_HOOK_LEFT, NG_IFACE_HOOK_INET, strerror(errno)));
+      rtn = -1;
+    }
   /* Disconnect temporary hook */
   snprintf(rm.ourhook, sizeof(rm.ourhook), "%s", TEMPHOOK);
   if (NgSendMsg(b->csock, ".",
@@ -458,6 +519,7 @@ done:
       b->name, TEMPHOOK, strerror(errno)));
     rtn = -1;
   }
+  }
 
   /* Done */
   return(rtn);
@@ -482,7 +544,12 @@ NgFuncConfigBPF(Bund b, int mode)
   char				path[NG_PATHLEN + 1];
 
   /* Get absolute path to bpf node */
+  if (gEnableTee) {
+    snprintf(path, sizeof(path), "%s:%s.%s", b->iface.ifname,
+      NG_IFACE_HOOK_INET, NG_TEE_HOOK_RIGHT);
+  } else {
   snprintf(path, sizeof(path), "%s:%s", b->iface.ifname, NG_IFACE_HOOK_INET);
+  }
 
   /* First, configure the hook on the interface node side of the BPF node */
   memset(&u, 0, sizeof(u));
@@ -532,7 +599,11 @@ NgFuncConfigBPF(Bund b, int mode)
       snprintf(hp->ifNotMatch, sizeof(hp->ifNotMatch), "%s", BPF_HOOK_IFACE);
       break;
     case BPF_MODE_MSSFIX:
+      if (gNgTcpMssFix) {
+	      snprintf(hp->ifMatch, sizeof(hp->ifMatch), "%s", BPF_HOOK_TCPMSS);
+      } else {
       snprintf(hp->ifMatch, sizeof(hp->ifMatch), "%s", BPF_HOOK_MPD);
+      }
       snprintf(hp->ifNotMatch, sizeof(hp->ifNotMatch), "%s", BPF_HOOK_IFACE);
       break;
     default:
@@ -567,13 +638,43 @@ NgFuncConfigBPF(Bund b, int mode)
       assert(0);
   }
 
-  /* Set new program on the BPF_HOOK_IFACE hook */
+  /* Set new program on the BPF_HOOK_MPD hook */
+  if (NgSendMsg(b->csock, path, NGM_BPF_COOKIE,
+      NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
+    Log(LG_ERR, ("[%s] can't set %s node program: %s",
+      b->name, NG_BPF_NODE_TYPE, strerror(errno)));
+    DoExit(EX_ERRDEAD);
+  }
+
+  if (gNgTcpMssFix) {
+	/* Configure the hook on the TCPMSS node side of the BPF node */
+	memset(&u, 0, sizeof(u));
+	snprintf(hp->thisHook, sizeof(hp->thisHook), "%s", BPF_HOOK_TCPMSS);
+	hp->bpf_prog_len = NOMATCH_PROG_LEN;
+	memcpy(&hp->bpf_prog,
+		&gNoMatchProg, NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
+	switch (mode) {
+		case BPF_MODE_OFF:
+		case BPF_MODE_DEMAND:
+		case BPF_MODE_ON:
+			memset(&hp->ifMatch, 0, sizeof(hp->ifMatch));
+			memset(&hp->ifNotMatch, 0, sizeof(hp->ifNotMatch));
+			break;
+		case BPF_MODE_MSSFIX:
+			snprintf(hp->ifMatch, sizeof(hp->ifMatch), "%s", BPF_HOOK_IFACE);
+			snprintf(hp->ifNotMatch, sizeof(hp->ifNotMatch), "%s", BPF_HOOK_IFACE);
+			break;
+		default:
+			assert(0);
+	}
+	/* Set new program on the BPF_HOOK_TCPMSS hook */
   if (NgSendMsg(b->csock, path, NGM_BPF_COOKIE,
       NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
     Log(LG_ERR, ("[%s] can't set %s node program: %s",
       b->name, NG_BPF_NODE_TYPE, strerror(errno)));
     DoExit(EX_ERRDEAD);
   }
+  }
 }
 
 /*
@@ -599,10 +700,23 @@ NgFuncShutdownInternal(Bund b, int iface
   Bund	bund_save;
   Link	lnk_save;
   int	k;
+  struct ngm_rmhook rm;
 
   if (iface) {
+    if (gEnableTee) {
+      /* Disconnect tee:right hook */
+      snprintf(path, sizeof(path), "%s:%s",
+        b->iface.ifname, NG_IFACE_HOOK_INET);
+      snprintf(rm.ourhook, sizeof(rm.ourhook), "%s", NG_TEE_HOOK_RIGHT);
+      if (NgSendMsg(b->csock, path,
+        NGM_GENERIC_COOKIE, NGM_RMHOOK, &rm, sizeof(rm)) < 0) {
+          Log(LG_ERR, ("[%s] can't remove hook %s: %s",
+            b->name, NG_TEE_HOOK_RIGHT, strerror(errno)));
+      }
+    } else {
     snprintf(path, sizeof(path), "%s:", b->iface.ifname);
     NgFuncShutdownNode(b, b->name, path);
+    }
   }
   lnk_save = lnk;
   bund_save = bund;
@@ -954,5 +1068,36 @@ NgFuncErr(const char *fmt, ...)
     buf, strerror(errno)));
 }
 
+/*
+ * NgFuncConfigTCPMSS()
+ *
+ * Configure the tcpmss node to reduce MSS to given value.
+ */
 
+void
+NgFuncConfigTCPMSS(Bund b, int maxMSS)
+{
+	char			path[NG_PATHLEN + 1];
+	struct ng_tcpmss_config	tcpmsscfg;
 
+	/* Get absolute path to  node */
+	if (gEnableTee)
+		snprintf(path, sizeof(path), "%s:%s.%s.%s", b->iface.ifname,
+			NG_IFACE_HOOK_INET, NG_TEE_HOOK_RIGHT, BPF_HOOK_TCPMSS);
+	else
+		snprintf(path, sizeof(path), "%s:%s.%s", b->iface.ifname,
+			NG_IFACE_HOOK_INET, BPF_HOOK_TCPMSS);
+
+	/* Send configuration message */
+	memset(&tcpmsscfg,0,sizeof(tcpmsscfg));
+	snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "%s", BPF_HOOK_TCPMSS);
+	snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "%s", BPF_HOOK_TCPMSS);
+	tcpmsscfg.maxMSS = maxMSS;
+
+	if (NgSendMsg(bund->csock, path, NGM_TCPMSS_COOKIE,
+		NGM_TCPMSS_CONFIG, &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
+		Log(LG_ERR, ("[%s] can't set %s node program: %s",
+			b->name, NG_TCPMSS_NODE_TYPE, strerror(errno)));
+		DoExit(EX_ERRDEAD);
+	}
+}
diff -urNp mpd3-cvs.orig/src/ngfunc.h mpd3-cvs/src/ngfunc.h
--- mpd3-cvs.orig/src/ngfunc.h	Sun Jul 25 00:26:20 2004
+++ mpd3-cvs/src/ngfunc.h	Tue May 23 22:56:53 2006
@@ -30,6 +30,7 @@
   #define BPF_HOOK_PPP		"ppp"
   #define BPF_HOOK_IFACE	"iface"
   #define BPF_HOOK_MPD		"mpd"
+  #define BPF_HOOK_TCPMSS	"tcpmssfix"
 
   #define BPF_MODE_OFF		0	/* no BPF node traffic gets through */
   #define BPF_MODE_ON		1	/* normal BPF node traffic flow */
@@ -53,6 +54,7 @@
 			const char *path2, const char *hook2);
   extern int	NgFuncDisconnect(const char *path, const char *hook);
   extern int	NgFuncShutdownNode(Bund b, const char *label, const char *path);
+  extern void	NgFuncConfigTCPMSS(Bund b, int maxMSS);
 
 #endif
 
diff -urNp mpd3-cvs.orig/src/ppp.h mpd3-cvs/src/ppp.h
--- mpd3-cvs.orig/src/ppp.h	Sun Jul 25 00:26:20 2004
+++ mpd3-cvs/src/ppp.h	Tue May 23 22:56:53 2006
@@ -88,6 +88,8 @@
 
   extern int		gNumLinks;		/* Total number of links */
   extern int		gNumBundles;		/* Total number of bundles */
+  extern int		gEnableTee;		/* Insert ng_tee into netgraph */
+  extern int		gNgTcpMssFix;		/* Use ng_tcpmss node */
 
   extern Bund		bund;			/* Current bundle */
   extern Link		lnk;			/* Current link */
diff -urNp mpd3-cvs.orig/src/pptp.c mpd3-cvs/src/pptp.c
--- mpd3-cvs.orig/src/pptp.c	Mon Oct 18 16:49:30 2004
+++ mpd3-cvs/src/pptp.c	Tue May 23 22:56:53 2006
@@ -248,6 +248,16 @@ PptpOpen(PhysInfo p)
 
 	(*pptp->cinfo.answer)(pptp->cinfo.cookie,
 	  PPTP_OCR_RESL_OK, 0, 0, 64000 /*XXX*/ );
+
+	if (pptp->state == PPTP_STATE_DOWN) {
+		/* XXX Control connection was closed in state OPENING */
+		Log(LG_ERR,
+			("[%s] Control connection was closed while answering",
+			 lnk->name));
+		PptpKillNode(pptp);
+		break;
+	}
+	
 	pptp->state = PPTP_STATE_UP;
 	PhysUp();
 	return;
diff -urNp mpd3-cvs.orig/src/pptp_ctrl.c mpd3-cvs/src/pptp_ctrl.c
--- mpd3-cvs.orig/src/pptp_ctrl.c	Sun Jul 25 00:25:28 2004
+++ mpd3-cvs/src/pptp_ctrl.c	Thu May 25 08:10:11 2006
@@ -838,7 +838,7 @@ abort:
     c->csock, DEV_PRIO, PptpCtrlReadCtrl, c);
 
   /* Start echo keep-alive timer */
-  PptpCtrlResetIdleTimer(c);
+  /* XXX boco PptpCtrlResetIdleTimer(c); */
 
   /* If we originated the call, we start the conversation */
   if (c->orig) {
@@ -931,7 +931,7 @@ abort:
     Log(LG_PPTP2, ("pptp%d: recv %s", c->id, gPptpMsgInfo[hdr->type].name));
     PptpCtrlDump(LG_PPTP2, hdr->type, msg);
     c->flen = 0;
-    PptpCtrlResetIdleTimer(c);
+    /* XXX boco PptpCtrlResetIdleTimer(c); */
     PptpCtrlMsg(c, hdr->type, msg);
   }
 }
@@ -1100,6 +1100,7 @@ PptpCtrlGetCtrl(int orig, struct in_addr
   int				k;
 
   /* See if we're already have a control block matching this address and port */
+/* XXX boco
   for (k = 0; k < gNumPptpCtrl; k++) {
     PptpCtrl	const c = gPptpCtrl[k];
 
@@ -1115,6 +1116,7 @@ PptpCtrlGetCtrl(int orig, struct in_addr
       }
     }
   }
+XXX boco */
 
   /* Find/create a free one */
   for (k = 0; k < gNumPptpCtrl && gPptpCtrl[k] != NULL; k++);
@@ -1296,7 +1298,7 @@ PptpCtrlKillCtrl(PptpCtrl c)
   }
   EventUnRegister(&c->connEvent);
   EventUnRegister(&c->ctrlEvent);
-  TimerStop(&c->idleTimer);
+  /* XXX boco TimerStop(&c->idleTimer); */
   for (prep = c->reps; prep; prep = next) {
     next = prep->next;
     TimerStop(&prep->timer);
@@ -1375,6 +1377,9 @@ pnsClear:
       return;
     case PPTP_CHAN_ST_WAIT_CTRL:
       PptpCtrlKillChan(ch, "link layer shutdown");
+      return;
+    case PPTP_CHAN_ST_FREE:
+      Log(LG_PPTP, ("pptp%d-%d: PptpCtrlCloseChan() is called recursively, ignoring", c->id, ch->id));
       return;
     default:
       assert(0);
diff -urNp mpd3-cvs.orig/src/radius.c mpd3-cvs/src/radius.c
--- mpd3-cvs.orig/src/radius.c	Mon Oct 18 16:49:30 2004
+++ mpd3-cvs/src/radius.c	Tue May 23 22:56:53 2006
@@ -31,7 +31,6 @@
   static int rad_demangle2(struct rad_handle *, const void *, size_t, u_char *);
   static int rad_demangle_mppe_key2(struct rad_handle *, const void *, size_t, u_char *, size_t *);
 
-
 /* Set menu options */
 
   enum {
@@ -40,7 +39,9 @@
     SET_TIMEOUT,
     SET_RETRIES,
     SET_CONFIG,
-    SET_UPDATE
+    SET_UPDATE,
+    SET_UPDATE_LIMIT_IN,
+    SET_UPDATE_LIMIT_OUT
   };
 
 /*
@@ -60,6 +61,10 @@
 	RadiusSetCommand, NULL, (void *) SET_CONFIG },
     { "acct-update <seconds>",		"set update interval",
 	RadiusSetCommand, NULL, (void *) SET_UPDATE },
+    { "update-limit-in <bytes>",	"set update limit (inbound traffic)",
+	    RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_IN },
+    { "update-limit-out <bytes>",	"set update limit (outbound traffic)",
+	    RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_OUT },
     { NULL },
   };
   
@@ -161,6 +166,22 @@ RadiusSetCommand(int ac, char *av[], voi
 	     conf->acct_update = val;
 	break;
 
+      case SET_UPDATE_LIMIT_IN:
+	val = atoi(*av);
+	if (val <= 0)
+		Log(LG_ERR, ("Update limit (in) must be positive."));
+	else
+		conf->update_limit_in = val;
+	break;
+	
+      case SET_UPDATE_LIMIT_OUT:
+	val = atoi(*av);
+	if (val <= 0)
+		Log(LG_ERR, ("Update limit (out) must be positive."));
+	else
+		conf->update_limit_out = val;
+	break;
+
       case SET_RETRIES:
 	val = atoi(*av);
 	if (val <= 0)
@@ -757,7 +778,7 @@ RadiusPAPAuthenticate(const char *name, 
   if (RadiusStart(RAD_ACCESS_REQUEST) == RAD_NACK) 
     return RAD_NACK;
   
-  if (RadiusPutAuth(name, password, 0, NULL, NULL, 0, RADIUS_PAP) == RAD_NACK) 
+  if (RadiusPutAuth(name, password, 0, NULL, 0, 0, RADIUS_PAP) == RAD_NACK) 
     return RAD_NACK;
   
   if (RadiusSendRequest() == RAD_NACK) 
@@ -1189,6 +1210,7 @@ RadiusAccount(short acct_type) 
   char  function[]	= "RadiusAccount";
   struct radius		*rad = &bund->radius;
   int			authentic;
+  int			send_update = 0;	/*  Should we send acct-update? */
 
   /* if Radius-Auth wasn't used, then copy in authname */
   if (!strlen(rad->authname))
@@ -1313,10 +1335,43 @@ RadiusAccount(short acct_type) 
     }
   }
 
+  Log(LG_ALWAYS, ("[%s] ACCT: User-Name=%s NAS-IP-Address=%s NAS-Port=%d "
+    "Acct-Status-Type=%d Acct-Session-Id=%s Acct-Input-Octets=%u "
+    "Acct-Output-Octets=%u Acct-Input-Gigawords=%u Acct-Output-Gigawords=%u",
+    lnk->name, lnk->peer_authname, inet_ntoa(rad->conf.radius_me),
+    GetLinkID(), acct_type, lnk->radius.session_id,
+    (unsigned int) (lnk->stats.recvOctets % MAX_U_INT32),
+    (unsigned int) (lnk->stats.xmitOctets % MAX_U_INT32),
+    (unsigned int) (lnk->stats.recvOctets / MAX_U_INT32),
+    (unsigned int) (lnk->stats.xmitOctets / MAX_U_INT32)));
+
+  if (!(rad->conf.update_limit_in || rad->conf.update_limit_out))
+    send_update++;
+  else {
+    if (rad->conf.update_limit_in &&
+       lnk->stats.recvOctets - lnk->stats.sv_recvOctets > rad->conf.update_limit_in)
+         send_update++;
+    if (rad->conf.update_limit_out &&
+       lnk->stats.xmitOctets - lnk->stats.sv_xmitOctets > rad->conf.update_limit_out)
+         send_update++;
+  }
+  
+  if (acct_type == RAD_UPDATE && !send_update) {
+      Log(LG_RADIUS, ("[%s] RADIUS: %s: shouldn't send Interim-Update",
+       lnk->name, function));
+      RadiusClose();
+      return RAD_NACK;
+  }
+
   Log(LG_RADIUS, ("[%s] RADIUS: %s: Sending accounting data (Type: %d)",
     lnk->name, function, acct_type));
   if (RadiusSendRequest() == RAD_NACK) 
     return RAD_NACK;
+  
+  /* save old statistics (update-limit feature) */
+
+  lnk->stats.sv_recvOctets = lnk->stats.recvOctets;
+  lnk->stats.sv_xmitOctets = lnk->stats.xmitOctets;
 
   return RAD_ACK;
 
@@ -1417,6 +1472,8 @@ RadStat(int ac, char *av[], void *arg) 
   printf("\tConfig-file  : %s\n", conf->file);
   printf("\tMe (NAS-IP)  : %s\n", inet_ntoa(conf->radius_me));
   printf("\tAcct-Interval: %d\n", conf->acct_update);
+  printf("\tUpdate-Limit-In : %d\n", conf->update_limit_in);
+  printf("\tUpdate-Limit-Out: %d\n", conf->update_limit_out);
   
   if (conf->server != NULL) {
 
diff -urNp mpd3-cvs.orig/src/radius.h mpd3-cvs/src/radius.h
--- mpd3-cvs.orig/src/radius.h	Sat Dec  6 23:50:48 2003
+++ mpd3-cvs/src/radius.h	Tue May 23 22:56:53 2006
@@ -101,6 +101,10 @@ extern const	struct cmdtab RadiusSetCmds
     int		radius_timeout;
     int		radius_retries;
     int 	acct_update;		/* Accounting Update Interval */
+    int		update_limit_in;	/* Send Update only when counters
+					   grow more than "update_limit_xx"
+					   since last update */
+    int		update_limit_out;
     struct	in_addr radius_me;
     char	file[PATH_MAX];
     struct radiusserver_conf *server;
