diff -uNr rp-l2tp-0.4.orig/Makefile.in rp-l2tp-0.4/Makefile.in
--- rp-l2tp-0.4.orig/Makefile.in	Thu Jul  1 16:17:11 2004
+++ rp-l2tp-0.4/Makefile.in	Tue Dec  5 12:45:46 2006
@@ -27,7 +27,7 @@
 sbindir=@sbindir@
 
 OBJS=auth.o debug.o dgram.o main.o md5.o network.o options.o peer.o session.o tunnel.o utils.o
-EXTRA_LIBS=@LIBEVENT@/*.o -ldl
+EXTRA_LIBS=@LIBEVENT@/*.o
 
 SRCS=$(OBJS:.o=.c)
 CFLAGS=-g -I.. -I@LIBEVENT@ -Wall -Wstrict-prototypes -ansi -pedantic -D_GNU_SOURCE -DVERSION=\"$(VERSION)\" -DPREFIX=\"$(prefix)\"
@@ -43,7 +43,7 @@
 
 l2tpd: libl2tp.a libevent/libevent.a
 	$(MAKE) -C handlers
-	@CC@ -o l2tpd -rdynamic $(OBJS) $(EXTRA_LIBS)
+	@CC@ -o l2tpd -Wl,-E $(OBJS) $(EXTRA_LIBS)
 
 libevent/libevent.a:
 	test -d libevent || ln -s ../libevent .
diff -uNr rp-l2tp-0.4.orig/README rp-l2tp-0.4/README
--- rp-l2tp-0.4.orig/README	Mon Sep 30 19:46:45 2002
+++ rp-l2tp-0.4/README	Wed Dec  6 09:20:10 2006
@@ -1,6 +1,6 @@
 # LIC: GPL
 
-This is a user-space implementation of L2TP (RFC 2661) for Linux.
+This is a user-space implementation of L2TP (RFC 2661).
 
 Copying
 -------
@@ -18,7 +18,7 @@
 which is dynamically linked into l2tpd at run-time using the
 "load-handler" configuration directive.
 
-Although the handlers included with this package (sync-pppd and cmd)
+Although the handlers included with this package (async-pppd and cmd)
 are licensed under the GPL, as a special exception, you may write your
 own handlers which link to code in this package and not release them
 under the GPL.  There may be other reasons why your handlers must
@@ -29,7 +29,7 @@
 Installation
 ------------
 
-./configure && make
-make install
+./configure && gmake
+gmake install
 
 Now read l2tpd(8) and l2tp.conf(5)
diff -uNr rp-l2tp-0.4.orig/README.BSD rp-l2tp-0.4/README.BSD
--- rp-l2tp-0.4.orig/README.BSD	Thu Jan  1 01:00:00 1970
+++ rp-l2tp-0.4/README.BSD	Wed Dec  6 09:45:07 2006
@@ -0,0 +1,97 @@
+OpenBSD notes
+-------------
+
+If you get an error logged about no PPP device, then you need to run
+
+    # ifconfig ppp0 create
+
+Beware that OpenBSD has an /etc/ppp/options containing the 'auth' option
+which requires the peer to authenticate. If you are running as a LAC
+(client) you may need to set lac-pppd-opts "noauth ..." in l2tpd.conf to
+override this.
+
+(You can use the 'debug' option to help pin down problems like this. You'll
+need to change syslog.conf to log messages at level daemon.debug)
+
+Using OpenBSD as an L2TP/IPSEC client
+-------------------------------------
+
+To set up an L2TP over IPSEC transport mode connection, with:
+- local IP address Z.Z.Z.Z
+- remote host X.X.X.X
+- using preshared key XXXKEY
+- PPP username is XXXUSER
+- PPP CHAP password is XXXPASS
+
+==> /etc/ipsec.conf <==
+ike esp transport proto udp from Z.Z.Z.Z to X.X.X.X port 1701 \
+	main auth hmac-md5 enc 3des group modp1024 \
+	quick auth hmac-md5 enc 3des group none \
+	psk "XXXKEY"
+
+==> /etc/ppp/chap-secrets <==
+#	$OpenBSD: chap-secrets,v 1.3 2002/06/09 06:15:15 todd Exp $
+
+# Secrets for authentication using CHAP
+# client	server	secret			IP addresses
+XXXUSER		*	XXXPASS
+
+==> /etc/rc.conf.local <==
+isakmpd_flags="-K -4"
+ipsec="YES"
+
+==> /etc/l2tp/l2tp.conf <==
+global
+load-handler "async-pppd.so"
+load-handler "cmd.so"
+
+listen-addr Z.Z.Z.Z
+listen-port 1701
+
+section async-pppd
+lac-pppd-opts "noauth user XXXUSER name XXXUSER noipdefault ipcp-accept-local ipcp-accept-remote lcp-echo-interval 30 lcp-echo-failure 6 debug"
+
+section peer
+peer X.X.X.X
+port 1701
+lac-handler async-pppd
+
+section cmd
+
+-----------------------------
+
+To start IPSEC:
+# isakmpd -K -4
+# ipsecctl -f /etc/ipsec.conf
+
+(At this point, "ipsecctl -s all" should show the IPSEC flows agreed)
+
+To start L2TP:
+# l2tpd
+# l2tp-control "start-session X.X.X.X"
+
+(At this point, "l2tp-control dump-sessions" should show the L2TP tunnel up)
+
+About this port
+---------------
+
+This code has been ported to OpenBSD by changing the sync-pppd module to
+async-pppd. This is a grossly inefficient hack, as the OpenBSD ppp stack
+converts packets to asynchronous format, escaping control characters and
+adding a CRC, which rp-l2tp then strips back off again (and vice versa).
+However, OpenBSD currently has no packet-oriented line discipline like
+Linux's N_HDLC, and its pppd doesn't have a "sync" option to use it.
+
+Possible ways to improve this might be:
+
+(1) Modify OpenBSD's kernel and pppd to add the HDLC line discipline, making
+it closer to Linux.
+
+(2) Implement a new l2tp interface in the kernel, and merge pppd and rp-l2tp
+to control it. This would keep all data packets flowing in the kernel.
+
+(3) Add l2tp support to BSD's userland ppp. This is probably the most
+pragmatic approach; it could also scale better, as you wouldn't necessarily
+need a separate pppd process for each session, and it already has RADIUS
+support.
+
diff -uNr rp-l2tp-0.4.orig/debug.c rp-l2tp-0.4/debug.c
--- rp-l2tp-0.4.orig/debug.c	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/debug.c	Tue Dec  5 12:45:46 2006
@@ -84,7 +84,7 @@
 	AVPCASE(SEQUENCING_REQUIRED);
     }
     /* Unknown */
-    sprintf(buf, "Unknown_AVP#%d", (int) type);
+    snprintf(buf, sizeof(buf), "Unknown_AVP#%d", (int) type);
     return buf;
 }
 
@@ -116,7 +116,7 @@
 	MSGCASE(SLI);
 	MSGCASE(ZLB);
     }
-    sprintf(buf, "Unknown_Message#%d", (int) type);
+    snprintf(buf, sizeof(buf), "Unknown_Message#%d", (int) type);
     return buf;
 }
 
@@ -131,7 +131,7 @@
 l2tp_debug_tunnel_to_str(l2tp_tunnel *tunnel)
 {
     static char buf[64];
-    sprintf(buf, "%d/%d", (int) tunnel->my_id, (int) tunnel->assigned_id);
+    snprintf(buf, sizeof(buf), "%d/%d", (int) tunnel->my_id, (int) tunnel->assigned_id);
     return buf;
 }
 
@@ -146,7 +146,7 @@
 l2tp_debug_session_to_str(l2tp_session *session)
 {
     static char buf[128];
-    sprintf(buf, "(%d/%d, %d/%d)",
+    snprintf(buf, sizeof(buf), "(%d/%d, %d/%d)",
 	    (int) session->tunnel->my_id,
 	    (int) session->tunnel->assigned_id,
 	    (int) session->my_id, (int) session->assigned_id);
diff -uNr rp-l2tp-0.4.orig/dgram.c rp-l2tp-0.4/dgram.c
--- rp-l2tp-0.4.orig/dgram.c	Sat Jan 11 05:29:03 2003
+++ rp-l2tp-0.4/dgram.c	Wed Dec  6 09:11:48 2006
@@ -307,8 +307,9 @@
 l2tp_dgram_take_from_wire(struct sockaddr_in *from)
 {
     /* EXTRA_HEADER_ROOM bytes for other headers like PPPoE, etc. */
+    /* And an extra 2 bytes at end for async-pppd to add CRC */
 
-    unsigned char inbuf[MAX_PACKET_LEN+EXTRA_HEADER_ROOM];
+    unsigned char inbuf[MAX_PACKET_LEN+EXTRA_HEADER_ROOM+2];
     unsigned char *buf;
     socklen_t len = sizeof(struct sockaddr_in);
     int cursor;
diff -uNr rp-l2tp-0.4.orig/handlers/Makefile.in rp-l2tp-0.4/handlers/Makefile.in
--- rp-l2tp-0.4.orig/handlers/Makefile.in	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/handlers/Makefile.in	Tue Dec  5 12:45:46 2006
@@ -10,9 +10,9 @@
 install_dir=@INSTALL@ -d
 sbindir=@sbindir@
 
-HANDLERS=sync-pppd.so cmd.so
+HANDLERS=async-pppd.so cmd.so
 
-OBJS=pty.o sync-pppd.o dstring.o
+OBJS=pty.o async-pppd.o dstring.o
 SRCS=$(OBJS:.o=.c)
 CFLAGS=-g -O2 -I.. -I../libevent -I../../libevent -Wall
 
@@ -27,8 +27,8 @@
 %.o: %.c
 	gcc $(CFLAGS) -fPIC -c -o $@ $<
 
-sync-pppd.so: pty.o sync-pppd.o
-	gcc -shared -o $@ $^
+async-pppd.so: pty.o async-pppd.o
+	gcc -shared -o $@ $^ -lutil
 
 cmd.so: cmd.o dstring.o
 	gcc -shared -o $@ $^
diff -uNr rp-l2tp-0.4.orig/handlers/async-pppd.c rp-l2tp-0.4/handlers/async-pppd.c
--- rp-l2tp-0.4.orig/handlers/async-pppd.c	Thu Jan  1 01:00:00 1970
+++ rp-l2tp-0.4/handlers/async-pppd.c	Wed Dec  6 10:34:05 2006
@@ -0,0 +1,621 @@
+/***********************************************************************
+*
+* async-pppd.c
+*
+* An LNS handler which starts pppd attached to a PTY in
+* asynchronous mode (since openbsd doesn't support N_HDLC line discipline,
+* and its pppd doesn't support the 'sync' option)
+*
+* Copyright (C) 2002 by Roaring Penguin Software Inc.
+*
+* This software may be distributed under the terms of the GNU General
+* Public License, Version 2, or (at your option) any later version.
+*
+* LIC: GPL
+*
+***********************************************************************/
+
+static char const RCSID[] =
+"$Id: async-pppd.c,v 1.4 2003/12/22 14:57:33 dskoll Exp $";
+
+#include "l2tp.h"
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+
+#define HANDLER_NAME "async-pppd"
+
+#define DEFAULT_PPPD_PATH "/usr/sbin/pppd"
+
+#define MAX_FDS 256
+
+extern int pty_get(int *mfp, int *sfp);
+static int establish_session(l2tp_session *ses);
+static void close_session(l2tp_session *ses, char const *reason, int may_reestablish);
+static void handle_frame(l2tp_session *ses, unsigned char *buf, size_t len);
+
+/* Options for invoking pppd */
+#define MAX_OPTS 64
+static char *pppd_lns_options[MAX_OPTS+1];
+static char *pppd_lac_options[MAX_OPTS+1];
+static int num_pppd_lns_options = 0;
+static int num_pppd_lac_options = 0;
+static int use_unit_option = 0;
+static char *pppd_path = NULL;
+
+#define PUSH_LNS_OPT(x) pppd_lns_options[num_pppd_lns_options++] = (x)
+#define PUSH_LAC_OPT(x) pppd_lac_options[num_pppd_lac_options++] = (x)
+
+/* Our call ops */
+static l2tp_call_ops my_ops = {
+    establish_session,
+    close_session,
+    handle_frame
+};
+
+/* The slave process */
+struct slave {
+    EventSelector *es;		/* Event selector */
+    l2tp_session *ses;		/* L2TP session we're hooked to */
+    pid_t pid;			/* PID of child PPPD process */
+    int fd;			/* File descriptor for event-handler loop */
+    EventHandler *event;	/* Event handler */
+};
+
+static int handle_lac_opts(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
+static int handle_lns_opts(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
+
+/* Options */
+static l2tp_opt_descriptor my_opts[] = {
+    /*  name               type                 addr */
+    { "lac-pppd-opts",     OPT_TYPE_CALLFUNC,   (void *) handle_lac_opts},
+    { "lns-pppd-opts",     OPT_TYPE_CALLFUNC,   (void *) handle_lns_opts},
+    { "set-ppp-if-name",   OPT_TYPE_BOOL,       &use_unit_option},
+    { "pppd-path",         OPT_TYPE_STRING,     &pppd_path},
+    { NULL,                OPT_TYPE_BOOL,       NULL }
+};
+
+static int
+process_option(EventSelector *es, char const *name, char const *value)
+{
+    if (!strcmp(name, "*begin*")) return 0;
+    if (!strcmp(name, "*end*")) return 0;
+    return l2tp_option_set(es, name, value, my_opts);
+}
+
+static option_handler my_option_handler = {
+    NULL, HANDLER_NAME, process_option
+};
+
+static int
+handle_lac_opts(EventSelector *es,
+		l2tp_opt_descriptor *desc, char const *value)
+{
+    char word[512];
+    while (value && *value) {
+	value = l2tp_chomp_word(value, word);
+	if (!word[0]) break;
+	if (num_pppd_lac_options < MAX_OPTS) {
+	    char *x = strdup(word);
+	    if (x) PUSH_LAC_OPT(x);
+	    pppd_lac_options[num_pppd_lac_options] = NULL;
+	} else {
+	    break;
+	}
+    }
+    return 0;
+}
+
+static int
+handle_lns_opts(EventSelector *es,
+		l2tp_opt_descriptor *desc, char const *value)
+{
+    char word[512];
+    while (value && *value) {
+	value = l2tp_chomp_word(value, word);
+	if (!word[0]) break;
+	if (num_pppd_lns_options < MAX_OPTS) {
+	    char *x = strdup(word);
+	    if (x) PUSH_LNS_OPT(x);
+	    pppd_lns_options[num_pppd_lns_options] = NULL;
+	} else {
+	    break;
+	}
+    }
+    return 0;
+}
+
+/**********************************************************************
+* CRC16 implementation from RFC1662
+***********************************************************************/
+
+/*
+ * FCS lookup table as calculated by the table generator.
+ */
+static u_int16_t fcstab[256] = {
+      0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+      0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+      0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+      0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+      0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+      0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+      0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+      0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+      0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+      0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+      0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+      0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+      0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+      0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+      0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+      0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+      0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+      0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+      0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+      0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+      0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+      0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+      0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+      0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+      0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+      0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+      0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+      0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+      0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+      0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+      0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+      0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+#define PPPINITFCS16    0xffff  /* Initial FCS value */
+#define PPPGOODFCS16    0xf0b8  /* Good final FCS value */
+
+/*
+ * Calculate a new fcs given the current fcs and the new data.
+ */
+u_int16_t pppfcs16(
+    register u_int16_t fcs,
+    register unsigned char *cp,
+    register int len)
+{
+    while (len--)
+        fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
+
+    return (fcs);
+}
+
+#if 0
+static void dump_pkt(const char *msg, const unsigned char *p, int l)
+{
+    fprintf(stderr, "%s", msg);
+    while (l--) {
+	fprintf(stderr," %02X", *p++);
+    }
+    fprintf(stderr, "\n");
+}
+#else
+#define dump_pkt(x,y,z) ((void)0)
+#endif
+#if 1
+#define dump_n(x,y,z) fprintf(stderr,"%s(%d): %d\n", x, (int)(y), (int)(z))
+#else
+#define dump_n(x,y,z) ((void)0)
+#endif
+
+/**********************************************************************
+* %FUNCTION: handle_frame
+* %ARGUMENTS:
+*  ses -- l2tp session
+*  buf -- received PPP frame
+*  len -- length of frame
+* %RETURNS:
+*  Nothing
+* %DESCRIPTION:
+*  Shoots the frame to PPP's pty
+*  This is broken; probably should write to a circular buffer and use
+*  EVENT_FLAG_WRITEABLE to drain the buffer to the pty
+***********************************************************************/
+static void
+handle_frame(l2tp_session *ses,
+	     unsigned char *buf,
+	     size_t len)
+{
+    struct slave *sl = ses->private;
+    int n;
+    unsigned char obuf[8192];
+    int olen = 0;
+    u_int16_t trialfcs;
+
+    if (!sl) return;
+
+    dump_pkt("Write orig packet:", buf, len);
+
+    /* Add framing bytes */
+    //obuf[olen++] = 0x7E;
+    obuf[olen++] = 0xFF;
+    obuf[olen++] = 0x03;
+
+    /* Calculate CRC (RFC1662) */
+    trialfcs = pppfcs16( PPPINITFCS16, obuf+olen-2, 2 );
+    trialfcs = pppfcs16( trialfcs, buf, len );
+    trialfcs ^= 0xffff;			/* complement */
+    /* The CRC needs to be escaped too. 2 bytes reserved for this in
+       l2tp_dgram_take_from_wire */
+    buf[len++] = (trialfcs & 0x00ff);	/* least significant byte first */
+    buf[len++] = ((trialfcs >> 8) & 0x00ff);
+  
+    /* Escape the Control field */
+    obuf[olen-1] = 0x7D;
+    obuf[olen++] = 0x23;
+    
+    /* Copy data and escape */
+    for (n=0; n<len; n++) {
+	int ch = buf[n];
+	/* We must assume ACCM=0xffffffff. Even though this may be negotiated
+           down later, it doesn't hurt to keep escaping them */
+	if (ch == 0x7e || ch == 0x7d || ch < 0x20) {
+	    obuf[olen++] = 0x7D;
+	    ch ^= 0x20;
+        }
+        obuf[olen++] = ch;
+	if (olen >= sizeof(obuf) - 3) return;
+    }
+
+    /* Add flag */
+    obuf[olen++] = 0x7E;
+
+    dump_pkt("Write line packet:", obuf, olen);
+    n = 0;
+    while (1) {
+        fd_set wfds;
+	int nw = write(sl->fd, obuf+n, olen-n);
+	dump_n("write", olen-n, nw);
+	if (nw < 0) return;
+        n += nw;
+        if (n >= olen) return;
+        
+        /* Simulate a blocking write */
+        FD_ZERO(&wfds);
+        FD_SET(sl->fd, &wfds);
+        if (select(sl->fd+1, NULL, &wfds, NULL, NULL) <= 0) return;
+    }
+}
+
+/**********************************************************************
+* %FUNCTION: close_session
+* %ARGUMENTS:
+*  ses -- L2TP session
+*  reason -- reason why session is closing
+* %RETURNS:
+*  Nothing
+* %DESCRIPTION:
+*  Kills pppd.
+***********************************************************************/
+static void
+close_session(l2tp_session *ses, char const *reason, int may_reestablish)
+{
+    l2tp_tunnel *tunnel = ses->tunnel;
+    struct slave *sl = ses->private;
+    if (!sl) return;
+
+    /* Detach slave */
+    ses->private = NULL;
+    sl->ses = NULL;
+
+    kill(SIGTERM, sl->pid);
+    close(sl->fd);
+    sl->fd = -1;
+    Event_DelHandler(sl->es, sl->event);
+    sl->event = NULL;
+
+    /* Re-establish session if desired */
+    if (may_reestablish && tunnel->peer->persist && tunnel->peer->fail < tunnel->peer->maxfail) {
+        struct timeval t;
+
+        t.tv_sec = tunnel->peer->holdoff;
+        t.tv_usec = 0;
+        Event_AddTimerHandler(tunnel->es, t, l2tp_tunnel_reestablish, tunnel->peer);
+    }
+}
+
+/**********************************************************************
+* %FUNCTION: slave_exited
+* %ARGUMENTS:
+*  pid -- PID of exiting slave
+*  status -- exit status of slave
+*  data -- the slave structure
+* %RETURNS:
+*  Nothing
+* %DESCRIPTION:
+*  Handles an exiting slave
+***********************************************************************/
+static void
+slave_exited(pid_t pid, int status, void *data)
+{
+    l2tp_session *ses;
+    struct slave *sl = (struct slave *) data;
+    if (!sl) return;
+
+    ses = sl->ses;
+
+    if (sl->fd >= 0) close(sl->fd);
+    if (sl->event) Event_DelHandler(sl->es, sl->event);
+
+    if (ses) {
+	ses->private = NULL;
+	l2tp_session_send_CDN(ses, RESULT_GENERAL_REQUEST, 0,
+			      "pppd process exited");
+    }
+    free(sl);
+}
+
+static unsigned char ibuf_pad[EXTRA_HEADER_ROOM + 8192];
+static unsigned char *const ibuf = ibuf_pad + EXTRA_HEADER_ROOM;
+static unsigned char *ibufend = ibuf_pad + EXTRA_HEADER_ROOM;
+
+/**********************************************************************
+* %FUNCTION: readable
+* %ARGUMENTS:
+*  es -- event selector
+*  fd -- file descriptor
+*  flags -- we ignore
+*  data -- the L2TP session
+* %RETURNS:
+*  Nothing
+* %DESCRIPTION:
+*  Handles readability on PTY; shoots PPP frame over tunnel
+***********************************************************************/
+static void
+readable(EventSelector *es, int fd, unsigned int flags, void *data)
+{
+    int n;
+    unsigned char *ip, *iq, *fs, *dst;
+    l2tp_session *ses = (l2tp_session *) data;
+
+    /* Read whatever is available */
+    while (1) {
+	fd_set rfds;
+	struct timeval tv;
+
+	n = read(fd, ibufend, ibuf_pad+sizeof(ibuf_pad)-ibufend);
+	dump_n("read", ibuf_pad+sizeof(ibuf_pad)-ibufend, n);
+	if (n < 0) return;
+	ibufend += n;
+
+	/* Nasty hack: OpenBSD seems only to return 1024 (TTYHOG?) bytes at a time */
+	if (n < 1024) break;
+	FD_ZERO(&rfds);
+	FD_SET(fd, &rfds);
+	tv.tv_sec = 0;
+	tv.tv_usec = 1000;
+	n = select(fd+1, &rfds, NULL, NULL, &tv);
+	dump_n("select", fd, n);
+	if (n < 0) return;
+	if (n == 0) break;
+    }
+
+    /* Check if any whole packet(s) to process */
+    ip = ibuf;
+    while (ip < ibufend) {
+        iq = memchr(ip, 0x7E, ibufend-ip);
+        if (!iq) break;
+	n = iq - ip;
+	dump_pkt("Read line packet:", ip, n+1);
+	if (n <= 5 || !ses) {
+	    ip = iq+1;
+	    continue;
+	}
+
+	/* De-escape */
+	fs = ip;
+	dst = ip;
+	while (ip < iq) {
+	    if (ip[0] == 0x7D && ip < iq - 1)
+		*dst++ = ip[1] ^ 0x20, ip += 2, n--;
+	    else
+		*dst++ = *ip++;
+	}
+
+	/* Chop off CRC (should we check it?) */
+	n -= 2;
+	/* Chop off header */
+	if (fs[0] == 0xFF && fs[1] == 0x03)
+		fs += 2, n -= 2;
+
+	dump_pkt("Read processed packet:", fs, n);
+	if (n > 4)
+	    l2tp_dgram_send_ppp_frame(ses, fs, n);
+
+	/* Note: l2tp_dgram_send_ppp_frame writes in front of buffer */
+	/* but not after it */
+        ip = iq+1;
+    }
+
+    /* any leftovers? */
+    if (ip < ibufend) {
+        memmove(ibuf, ip, ibufend-ip);
+	ibufend = ibuf + (ibufend-ip);
+    } else
+	ibufend = ibuf;
+}
+
+/**********************************************************************
+* %FUNCTION: establish_session
+* %ARGUMENTS:
+*  ses -- the L2TP session
+* %RETURNS:
+*  0 if session could be established, -1 otherwise.
+* %DESCRIPTION:
+*  Forks a pppd process and connects fd to pty
+***********************************************************************/
+static int
+establish_session(l2tp_session *ses)
+{
+    int m_pty, s_pty;
+    pid_t pid;
+    EventSelector *es = ses->tunnel->es;
+    struct slave *sl = malloc(sizeof(struct slave));
+    int i;
+    char unit[32];
+
+    ses->private = NULL;
+    if (!sl) return -1;
+    sl->ses = ses;
+    sl->es = es;
+
+    /* Get pty */
+    if (pty_get(&m_pty, &s_pty) < 0) {
+	free(sl);
+	return -1;
+    }
+
+    /* Fork */
+    pid = fork();
+    if (pid == (pid_t) -1) {
+	free(sl);
+	return -1;
+    }
+
+    if (pid) {
+	int flags;
+
+	/* In the parent */
+	sl->pid = pid;
+
+	/* Set up handler for when pppd exits */
+	Event_HandleChildExit(es, pid, slave_exited, sl);
+
+	/* Close the slave tty */
+	close(s_pty);
+
+	sl->fd = m_pty;
+
+	/* Set slave FD non-blocking */
+	flags = fcntl(sl->fd, F_GETFL);
+	if (flags >= 0) fcntl(sl->fd, F_SETFL, (long) flags | O_NONBLOCK);
+
+	/* Handle readability on slave end */
+	sl->event = Event_AddHandler(es, m_pty, EVENT_FLAG_READABLE,
+			 readable, ses);
+
+	ses->private = sl;
+	return 0;
+    }
+
+    /* In the child.  Exec pppd */
+    /* Close all file descriptors except s_pty */
+    for (i=0; i<MAX_FDS; i++) {
+	if (i != s_pty) close(i);
+    }
+
+    /* Dup s_pty onto stdin and stdout */
+    dup2(s_pty, 0);
+    dup2(s_pty, 1);
+    if (s_pty > 1) close(s_pty);
+
+    /* Create unit */
+    sprintf(unit, "%d", (int) getpid());
+
+    if (ses->we_are_lac) {
+        char **lac_opt;
+
+	/* Push a unit option */
+	if (use_unit_option && num_pppd_lac_options <= MAX_OPTS-2) {
+	    PUSH_LAC_OPT("unit");
+	    PUSH_LAC_OPT(unit);
+	}
+        /* push peer specific options */
+        lac_opt = ses->tunnel->peer->lac_options;
+        while (*lac_opt) {
+            if (num_pppd_lac_options <= MAX_OPTS-1) {
+		PUSH_LAC_OPT(*lac_opt);
+		++lac_opt;
+	    } else {
+		break;
+	    }
+        }
+	if (pppd_path) {
+	    execv(pppd_path, pppd_lac_options);
+	} else {
+	    execv(DEFAULT_PPPD_PATH, pppd_lac_options);
+	}
+    } else {
+        char **lns_opt;
+
+	/* Push a unit option */
+	if (use_unit_option && num_pppd_lns_options <= MAX_OPTS-2) {
+	    PUSH_LNS_OPT("unit");
+	    PUSH_LNS_OPT(unit);
+	}
+        /* push peer specific options */
+        lns_opt = ses->tunnel->peer->lns_options;
+        while (*lns_opt) {
+            if (num_pppd_lns_options <= MAX_OPTS-1) {
+		PUSH_LNS_OPT(*lns_opt);
+		++lns_opt;
+	    } else {
+		break;
+	    }
+        }
+	if (pppd_path) {
+	    execv(pppd_path, pppd_lns_options);
+	} else {
+	    execv(DEFAULT_PPPD_PATH, pppd_lns_options);
+	}
+    }
+
+    /* Doh.. execl failed */
+    _exit(1);
+}
+
+static l2tp_lns_handler my_lns_handler = {
+    NULL,
+    HANDLER_NAME,
+    &my_ops
+};
+
+static l2tp_lac_handler my_lac_handler = {
+    NULL,
+    HANDLER_NAME,
+    &my_ops
+};
+
+void
+handler_init(EventSelector *es)
+{
+    l2tp_session_register_lns_handler(&my_lns_handler);
+    l2tp_session_register_lac_handler(&my_lac_handler);
+    l2tp_option_register_section(&my_option_handler);
+
+    PUSH_LNS_OPT("pppd");
+    PUSH_LNS_OPT("nodetach");
+    PUSH_LNS_OPT("noaccomp");
+    PUSH_LNS_OPT("nobsdcomp");
+    PUSH_LNS_OPT("nodeflate");
+    PUSH_LNS_OPT("nopcomp");
+    PUSH_LNS_OPT("novj");
+    PUSH_LNS_OPT("novjccomp");
+#if 0
+    PUSH_LNS_OPT("logfile");
+    PUSH_LNS_OPT("/dev/null");
+    PUSH_LNS_OPT("nolog");
+#endif
+    pppd_lns_options[num_pppd_lns_options] = NULL;
+
+    PUSH_LAC_OPT("pppd");
+    PUSH_LAC_OPT("nodetach");
+    PUSH_LAC_OPT("noaccomp");
+    PUSH_LAC_OPT("nobsdcomp");
+    PUSH_LAC_OPT("nodeflate");
+    PUSH_LAC_OPT("nopcomp");
+    PUSH_LAC_OPT("novj");
+    PUSH_LAC_OPT("novjccomp");
+#if 0
+    PUSH_LAC_OPT("logfile");
+    PUSH_LAC_OPT("/dev/null");
+    PUSH_LAC_OPT("nolog");
+#endif
+    pppd_lac_options[num_pppd_lac_options] = NULL;
+}
+
diff -uNr rp-l2tp-0.4.orig/handlers/cmd-control.c rp-l2tp-0.4/handlers/cmd-control.c
--- rp-l2tp-0.4.orig/handlers/cmd-control.c	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/handlers/cmd-control.c	Tue Dec  5 12:45:46 2006
@@ -38,7 +38,7 @@
 *  Sends a command to the server
 ***********************************************************************/
 static int
-send_cmd(char const *cmd)
+send_cmd(char const *cmd, char const *sockpath)
 {
     struct sockaddr_un addr;
     int fd;
@@ -52,7 +52,7 @@
 
     memset(&addr, 0, sizeof(addr));
     addr.sun_family = AF_LOCAL;
-    strncpy(addr.sun_path, "/var/run/l2tpctrl", sizeof(addr.sun_path) - 1);
+    strncpy(addr.sun_path, sockpath, sizeof(addr.sun_path) - 1);
 
     fd = socket(AF_LOCAL, SOCK_STREAM, 0);
     if (fd < 0) {
@@ -78,13 +78,20 @@
     int fd;
     int n;
     char buf[4096];
+    char *sockpath = "/var/run/l2tpctrl";
 
+    if (argc > 2 && !strcmp(argv[1],"-s") && argv[2] && argv[2][0]) {
+	sockpath = argv[2];
+	argv += 2;
+	argc -= 2;
+    }
+
     if (argc != 2) {
-	fprintf(stderr, "Usage: %s command\n", argv[0]);
+	fprintf(stderr, "Usage: %s [-s socket] command\n", argv[0]);
 	return 1;
     }
 
-    fd = send_cmd(argv[1]);
+    fd = send_cmd(argv[1], sockpath);
     if (fd < 0) {
 	return 1;
     }
diff -uNr rp-l2tp-0.4.orig/handlers/pty.c rp-l2tp-0.4/handlers/pty.c
--- rp-l2tp-0.4.orig/handlers/pty.c	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/handlers/pty.c	Wed Dec  6 10:44:39 2006
@@ -1,3 +1,4 @@
+#include <errno.h>
 /***********************************************************************
 *
 * pty.c
@@ -19,11 +20,10 @@
 #include "../l2tp.h"
 #include <sys/ioctl.h>
 #include <termios.h>
+#include <util.h>
+#include <string.h>
 #include <fcntl.h>
 #include <stdio.h>
-#ifndef N_HDLC
-#include <linux/termios.h>
-#endif
 
 /**********************************************************************
 * %FUNCTION: pty_get
@@ -33,64 +33,45 @@
 * %RETURNS:
 *  0 on success, -1 on failure
 * %DESCRIPTION:
-*  Opens a PTY and sets line discipline to N_HDLC for ppp.
-*  Taken almost verbatim from Linux pppd code.
+*  Opens a PTY and sets raw mode (OpenBSD does not have a HDLC line discipline)
 ***********************************************************************/
 int
 pty_get(int *mfp, int *sfp)
 {
-    char pty_name[24];
     struct termios tios;
-    int mfd, sfd;
-    int disc = N_HDLC;
 
-    mfd = -1;
-    sfd = -1;
+    memset(&tios, 0, sizeof(tios));
+    tios.c_cflag = CS8 | CREAD | CLOCAL;
+    tios.c_iflag  = IGNPAR;
+    tios.c_oflag  = 0;
+    tios.c_lflag  = 0;
+    tios.c_ispeed = tios.c_ospeed = B115200;
+    if (openpty(mfp, sfp, NULL, &tios, NULL) < 0)
+	return -1;
 
-    mfd = open("/dev/ptmx", O_RDWR);
-    if (mfd >= 0) {
-	int ptn;
-	if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
-	    snprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
-	    ptn = 0;
-	    if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0) {
-		/* warn("Couldn't unlock pty slave %s: %m", pty_name); */
-	    }
-	    if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0) {
-		/* warn("Couldn't open pty slave %s: %m", pty_name); */
-	    }
-	}
-    }
+    return 0;
+}
 
-    if (sfd < 0 || mfd < 0) {
-	if (sfd >= 0) close(sfd);
-	if (mfd >= 0) close(mfd);
+#if 0
+int
+pty_get(int *mfp, int *sfp)
+{
+    struct termios tios;
+
+    if (openpty(mfp, sfp, NULL, NULL, NULL) < 0)
 	return -1;
-    }
 
-    *mfp = mfd;
-    *sfp = sfd;
-    if (tcgetattr(sfd, &tios) == 0) {
+    if (tcgetattr(*sfp, &tios) == 0) {
 	tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
 	tios.c_cflag |= CS8 | CREAD | CLOCAL;
 	tios.c_iflag  = IGNPAR;
 	tios.c_oflag  = 0;
 	tios.c_lflag  = 0;
-	tcsetattr(sfd, TCSAFLUSH, &tios);
+	/* read returns immediately with whatever is available only */
+	tios.c_cc[VMIN] = 0;
+	tios.c_cc[VTIME] = 0;
+	tcsetattr(*sfp, TCSAFLUSH, &tios);
     }
-    if (ioctl(sfd, TIOCSETD, &disc) < 0) {
-	l2tp_set_errmsg("Unable to set line discipline to N_HDLC");
-	close(mfd);
-	close(sfd);
-	return -1;
-    }
-    disc = N_HDLC;
-    if (ioctl(mfd, TIOCSETD, &disc) < 0) {
-	l2tp_set_errmsg("Unable to set line discipline to N_HDLC");
-	close(mfd);
-	close(sfd);
-	return -1;
-    }
     return 0;
 }
-
+#endif
diff -uNr rp-l2tp-0.4.orig/handlers/sync-pppd.c rp-l2tp-0.4/handlers/sync-pppd.c
--- rp-l2tp-0.4.orig/handlers/sync-pppd.c	Thu Jul  1 15:58:56 2004
+++ rp-l2tp-0.4/handlers/sync-pppd.c	Tue Dec  5 12:45:46 2006
@@ -1,443 +0,0 @@
-/***********************************************************************
-*
-* sync-pppd.c
-*
-* An LNS handler which starts pppd attached to a PTY in
-* synchronous mode.
-*
-* Copyright (C) 2002 by Roaring Penguin Software Inc.
-*
-* This software may be distributed under the terms of the GNU General
-* Public License, Version 2, or (at your option) any later version.
-*
-* LIC: GPL
-*
-***********************************************************************/
-
-static char const RCSID[] =
-"$Id: sync-pppd.c,v 1.4 2003/12/22 14:57:33 dskoll Exp $";
-
-#include "l2tp.h"
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <fcntl.h>
-
-#define HANDLER_NAME "sync-pppd"
-
-#define DEFAULT_PPPD_PATH "/usr/sbin/pppd"
-
-#define MAX_FDS 256
-
-extern int pty_get(int *mfp, int *sfp);
-static int establish_session(l2tp_session *ses);
-static void close_session(l2tp_session *ses, char const *reason, int may_reestablish);
-static void handle_frame(l2tp_session *ses, unsigned char *buf, size_t len);
-
-/* Options for invoking pppd */
-#define MAX_OPTS 64
-static char *pppd_lns_options[MAX_OPTS+1];
-static char *pppd_lac_options[MAX_OPTS+1];
-static int num_pppd_lns_options = 0;
-static int num_pppd_lac_options = 0;
-static int use_unit_option = 0;
-static char *pppd_path = NULL;
-
-#define PUSH_LNS_OPT(x) pppd_lns_options[num_pppd_lns_options++] = (x)
-#define PUSH_LAC_OPT(x) pppd_lac_options[num_pppd_lac_options++] = (x)
-
-/* Our call ops */
-static l2tp_call_ops my_ops = {
-    establish_session,
-    close_session,
-    handle_frame
-};
-
-/* The slave process */
-struct slave {
-    EventSelector *es;		/* Event selector */
-    l2tp_session *ses;		/* L2TP session we're hooked to */
-    pid_t pid;			/* PID of child PPPD process */
-    int fd;			/* File descriptor for event-handler loop */
-    EventHandler *event;	/* Event handler */
-};
-
-static int handle_lac_opts(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
-static int handle_lns_opts(EventSelector *es, l2tp_opt_descriptor *desc, char const *value);
-
-/* Options */
-static l2tp_opt_descriptor my_opts[] = {
-    /*  name               type                 addr */
-    { "lac-pppd-opts",     OPT_TYPE_CALLFUNC,   (void *) handle_lac_opts},
-    { "lns-pppd-opts",     OPT_TYPE_CALLFUNC,   (void *) handle_lns_opts},
-    { "set-ppp-if-name",   OPT_TYPE_BOOL,       &use_unit_option},
-    { "pppd-path",         OPT_TYPE_STRING,     &pppd_path},
-    { NULL,                OPT_TYPE_BOOL,       NULL }
-};
-
-static int
-process_option(EventSelector *es, char const *name, char const *value)
-{
-    if (!strcmp(name, "*begin*")) return 0;
-    if (!strcmp(name, "*end*")) return 0;
-    return l2tp_option_set(es, name, value, my_opts);
-}
-
-static option_handler my_option_handler = {
-    NULL, HANDLER_NAME, process_option
-};
-
-static int
-handle_lac_opts(EventSelector *es,
-		l2tp_opt_descriptor *desc, char const *value)
-{
-    char word[512];
-    while (value && *value) {
-	value = l2tp_chomp_word(value, word);
-	if (!word[0]) break;
-	if (num_pppd_lac_options < MAX_OPTS) {
-	    char *x = strdup(word);
-	    if (x) PUSH_LAC_OPT(x);
-	    pppd_lac_options[num_pppd_lac_options] = NULL;
-	} else {
-	    break;
-	}
-    }
-    return 0;
-}
-
-static int
-handle_lns_opts(EventSelector *es,
-		l2tp_opt_descriptor *desc, char const *value)
-{
-    char word[512];
-    while (value && *value) {
-	value = l2tp_chomp_word(value, word);
-	if (!word[0]) break;
-	if (num_pppd_lns_options < MAX_OPTS) {
-	    char *x = strdup(word);
-	    if (x) PUSH_LNS_OPT(x);
-	    pppd_lns_options[num_pppd_lns_options] = NULL;
-	} else {
-	    break;
-	}
-    }
-    return 0;
-}
-
-/**********************************************************************
-* %FUNCTION: handle_frame
-* %ARGUMENTS:
-*  ses -- l2tp session
-*  buf -- received PPP frame
-*  len -- length of frame
-* %RETURNS:
-*  Nothing
-* %DESCRIPTION:
-*  Shoots the frame to PPP's pty
-***********************************************************************/
-static void
-handle_frame(l2tp_session *ses,
-	     unsigned char *buf,
-	     size_t len)
-{
-    struct slave *sl = ses->private;
-    int n;
-
-    if (!sl) return;
-
-    /* Add framing bytes */
-    *--buf = 0x03;
-    *--buf = 0xFF;
-    len += 2;
-
-    /* TODO: Add error checking */
-    n = write(sl->fd, buf, len);
-}
-
-/**********************************************************************
-* %FUNCTION: close_session
-* %ARGUMENTS:
-*  ses -- L2TP session
-*  reason -- reason why session is closing
-* %RETURNS:
-*  Nothing
-* %DESCRIPTION:
-*  Kills pppd.
-***********************************************************************/
-static void
-close_session(l2tp_session *ses, char const *reason, int may_reestablish)
-{
-    l2tp_tunnel *tunnel = ses->tunnel;
-    struct slave *sl = ses->private;
-    if (!sl) return;
-
-    /* Detach slave */
-    ses->private = NULL;
-    sl->ses = NULL;
-
-    kill(SIGTERM, sl->pid);
-    close(sl->fd);
-    sl->fd = -1;
-    Event_DelHandler(sl->es, sl->event);
-    sl->event = NULL;
-
-    /* Re-establish session if desired */
-    if (may_reestablish && tunnel->peer->persist && tunnel->peer->fail < tunnel->peer->maxfail) {
-        struct timeval t;
-
-        t.tv_sec = tunnel->peer->holdoff;
-        t.tv_usec = 0;
-        Event_AddTimerHandler(tunnel->es, t, l2tp_tunnel_reestablish, tunnel->peer);
-    }
-}
-
-/**********************************************************************
-* %FUNCTION: slave_exited
-* %ARGUMENTS:
-*  pid -- PID of exiting slave
-*  status -- exit status of slave
-*  data -- the slave structure
-* %RETURNS:
-*  Nothing
-* %DESCRIPTION:
-*  Handles an exiting slave
-***********************************************************************/
-static void
-slave_exited(pid_t pid, int status, void *data)
-{
-    l2tp_session *ses;
-    struct slave *sl = (struct slave *) data;
-    if (!sl) return;
-
-    ses = sl->ses;
-
-    if (sl->fd >= 0) close(sl->fd);
-    if (sl->event) Event_DelHandler(sl->es, sl->event);
-
-    if (ses) {
-	ses->private = NULL;
-	l2tp_session_send_CDN(ses, RESULT_GENERAL_REQUEST, 0,
-			      "pppd process exited");
-    }
-    free(sl);
-}
-
-/**********************************************************************
-* %FUNCTION: readable
-* %ARGUMENTS:
-*  es -- event selector
-*  fd -- file descriptor
-*  flags -- we ignore
-*  data -- the L2TP session
-* %RETURNS:
-*  Nothing
-* %DESCRIPTION:
-*  Handles readability on PTY; shoots PPP frame over tunnel
-***********************************************************************/
-static void
-readable(EventSelector *es, int fd, unsigned int flags, void *data)
-{
-    unsigned char buf[4096+EXTRA_HEADER_ROOM];
-    int n;
-    l2tp_session *ses = (l2tp_session *) data;
-    int iters = 5;
-
-    /* It seems to be better to read in a loop than to go
-       back to select loop.  However, don't loop forever, or
-       we could have a DoS potential */
-    while(iters--) {
-	/* EXTRA_HEADER_ROOM bytes extra space for l2tp header */
-	n = read(fd, buf+EXTRA_HEADER_ROOM, sizeof(buf)-EXTRA_HEADER_ROOM);
-
-	/* TODO: Check this.... */
-	if (n <= 2) return;
-
-	if (!ses) continue;
-
-	/* Chop off framing bytes */
-	l2tp_dgram_send_ppp_frame(ses, buf+EXTRA_HEADER_ROOM+2, n-2);
-    }
-}
-
-/**********************************************************************
-* %FUNCTION: establish_session
-* %ARGUMENTS:
-*  ses -- the L2TP session
-* %RETURNS:
-*  0 if session could be established, -1 otherwise.
-* %DESCRIPTION:
-*  Forks a pppd process and connects fd to pty
-***********************************************************************/
-static int
-establish_session(l2tp_session *ses)
-{
-    int m_pty, s_pty;
-    pid_t pid;
-    EventSelector *es = ses->tunnel->es;
-    struct slave *sl = malloc(sizeof(struct slave));
-    int i;
-    char unit[32];
-
-    ses->private = NULL;
-    if (!sl) return -1;
-    sl->ses = ses;
-    sl->es = es;
-
-    /* Get pty */
-    if (pty_get(&m_pty, &s_pty) < 0) {
-	free(sl);
-	return -1;
-    }
-
-    /* Fork */
-    pid = fork();
-    if (pid == (pid_t) -1) {
-	free(sl);
-	return -1;
-    }
-
-    if (pid) {
-	int flags;
-
-	/* In the parent */
-	sl->pid = pid;
-
-	/* Set up handler for when pppd exits */
-	Event_HandleChildExit(es, pid, slave_exited, sl);
-
-	/* Close the slave tty */
-	close(s_pty);
-
-	sl->fd = m_pty;
-
-	/* Set slave FD non-blocking */
-	flags = fcntl(sl->fd, F_GETFL);
-	if (flags >= 0) fcntl(sl->fd, F_SETFL, (long) flags | O_NONBLOCK);
-
-	/* Handle readability on slave end */
-	sl->event = Event_AddHandler(es, m_pty, EVENT_FLAG_READABLE,
-			 readable, ses);
-
-	ses->private = sl;
-	return 0;
-    }
-
-    /* In the child.  Exec pppd */
-    /* Close all file descriptors except s_pty */
-    for (i=0; i<MAX_FDS; i++) {
-	if (i != s_pty) close(i);
-    }
-
-    /* Dup s_pty onto stdin and stdout */
-    dup2(s_pty, 0);
-    dup2(s_pty, 1);
-    if (s_pty > 1) close(s_pty);
-
-    /* Create unit */
-    sprintf(unit, "%d", (int) getpid());
-
-    if (ses->we_are_lac) {
-        char **lac_opt;
-
-	/* Push a unit option */
-	if (use_unit_option && num_pppd_lac_options <= MAX_OPTS-2) {
-	    PUSH_LAC_OPT("unit");
-	    PUSH_LAC_OPT(unit);
-	}
-        /* push peer specific options */
-        lac_opt = ses->tunnel->peer->lac_options;
-        while (*lac_opt) {
-            if (num_pppd_lac_options <= MAX_OPTS-1) {
-		PUSH_LAC_OPT(*lac_opt);
-		++lac_opt;
-	    } else {
-		break;
-	    }
-        }
-	if (pppd_path) {
-	    execv(pppd_path, pppd_lac_options);
-	} else {
-	    execv(DEFAULT_PPPD_PATH, pppd_lac_options);
-	}
-    } else {
-        char **lns_opt;
-
-	/* Push a unit option */
-	if (use_unit_option && num_pppd_lns_options <= MAX_OPTS-2) {
-	    PUSH_LNS_OPT("unit");
-	    PUSH_LNS_OPT(unit);
-	}
-        /* push peer specific options */
-        lns_opt = ses->tunnel->peer->lns_options;
-        while (*lns_opt) {
-            if (num_pppd_lns_options <= MAX_OPTS-1) {
-		PUSH_LNS_OPT(*lns_opt);
-		++lns_opt;
-	    } else {
-		break;
-	    }
-        }
-	if (pppd_path) {
-	    execv(pppd_path, pppd_lns_options);
-	} else {
-	    execv(DEFAULT_PPPD_PATH, pppd_lns_options);
-	}
-    }
-
-    /* Doh.. execl failed */
-    _exit(1);
-}
-
-static l2tp_lns_handler my_lns_handler = {
-    NULL,
-    HANDLER_NAME,
-    &my_ops
-};
-
-static l2tp_lac_handler my_lac_handler = {
-    NULL,
-    HANDLER_NAME,
-    &my_ops
-};
-
-void
-handler_init(EventSelector *es)
-{
-    l2tp_session_register_lns_handler(&my_lns_handler);
-    l2tp_session_register_lac_handler(&my_lac_handler);
-    l2tp_option_register_section(&my_option_handler);
-
-    PUSH_LNS_OPT("pppd");
-    PUSH_LNS_OPT("sync");
-    PUSH_LNS_OPT("nodetach");
-    PUSH_LNS_OPT("noaccomp");
-    PUSH_LNS_OPT("nobsdcomp");
-    PUSH_LNS_OPT("nodeflate");
-    PUSH_LNS_OPT("nopcomp");
-    PUSH_LNS_OPT("novj");
-    PUSH_LNS_OPT("novjccomp");
-#if 0
-    PUSH_LNS_OPT("logfile");
-    PUSH_LNS_OPT("/dev/null");
-    PUSH_LNS_OPT("nolog");
-#endif
-    pppd_lns_options[num_pppd_lns_options] = NULL;
-
-    PUSH_LAC_OPT("pppd");
-    PUSH_LAC_OPT("sync");
-    PUSH_LAC_OPT("nodetach");
-    PUSH_LAC_OPT("noaccomp");
-    PUSH_LAC_OPT("nobsdcomp");
-    PUSH_LAC_OPT("nodeflate");
-    PUSH_LAC_OPT("nopcomp");
-    PUSH_LAC_OPT("novj");
-    PUSH_LAC_OPT("novjccomp");
-#if 0
-    PUSH_LAC_OPT("logfile");
-    PUSH_LAC_OPT("/dev/null");
-    PUSH_LAC_OPT("nolog");
-#endif
-    pppd_lac_options[num_pppd_lac_options] = NULL;
-}
-
diff -uNr rp-l2tp-0.4.orig/l2tp.conf rp-l2tp-0.4/l2tp.conf
--- rp-l2tp-0.4.orig/l2tp.conf	Mon Sep 30 19:46:53 2002
+++ rp-l2tp-0.4/l2tp.conf	Wed Dec  6 11:02:36 2006
@@ -4,33 +4,33 @@
 global
 
 # Load handlers
-load-handler "sync-pppd.so"
+load-handler "async-pppd.so"
 load-handler "cmd.so"
 
 # Bind address
 listen-port 1701
 
-# Configure the sync-pppd handler.  You MUST have a "section sync-pppd" line
+# Configure the async-pppd handler.  You MUST have a "section async-pppd" line
 # even if you don't set any options.
-section sync-pppd
+section async-pppd
 lns-pppd-opts "require-pap 10.0.0.1:10.0.0.2 lcp-echo-interval 30 lcp-echo-failure 6"
-lac-pppd-opts "user example name example noipdefault ipcp-accept-local ipcp-accept-remote lcp-echo-interval 30 lcp-echo-failure 6"
+lac-pppd-opts "noauth user example name example noipdefault ipcp-accept-local ipcp-accept-remote lcp-echo-interval 30 lcp-echo-failure 6"
 
 # Peer section
 section peer
 peer 192.168.2.3
 secret s3cr3t
 port 1701
-lac-handler sync-pppd
-lns-handler sync-pppd
+lac-handler async-pppd
+lns-handler async-pppd
 hide-avps yes
 
 section peer
 peer 192.168.2.9
 # No secret - no authentication
 port 1701
-lac-handler sync-pppd
-lns-handler sync-pppd
+lac-handler async-pppd
+lns-handler async-pppd
 hide-avps no
 
 # Configure the cmd handler.  You MUST have a "section cmd" line
diff -uNr rp-l2tp-0.4.orig/l2tp.h rp-l2tp-0.4/l2tp.h
--- rp-l2tp-0.4.orig/l2tp.h	Thu Jul  1 15:58:55 2004
+++ rp-l2tp-0.4/l2tp.h	Tue Dec  5 12:45:46 2006
@@ -14,6 +14,7 @@
 #define L2TP_H
 
 #include <stdint.h>
+#include <sys/types.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 
diff -uNr rp-l2tp-0.4.orig/main.c rp-l2tp-0.4/main.c
--- rp-l2tp-0.4.orig/main.c	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/main.c	Tue Dec  5 12:45:46 2006
@@ -32,6 +32,7 @@
     fprintf(stderr, "Usage: %s [options]\n", argv[0]);
     fprintf(stderr, "Options:\n");
     fprintf(stderr, "-d level               -- Set debugging to 'level'\n");
+    fprintf(stderr, "-c file                -- Set config file\n");
     fprintf(stderr, "-f                     -- Do not fork\n");
     fprintf(stderr, "-h                     -- Print usage\n");
     fprintf(stderr, "\nThis program is licensed under the terms of\nthe GNU General Public License, Version 2.\n");
@@ -46,8 +47,9 @@
     int opt;
     int do_fork = 1;
     int debugmask = 0;
+    char *config_file = "/etc/l2tp/l2tp.conf";
 
-    while((opt = getopt(argc, argv, "d:fh")) != -1) {
+    while((opt = getopt(argc, argv, "d:c:fh")) != -1) {
 	switch(opt) {
 	case 'h':
 	    usage(argc, argv, EXIT_SUCCESS);
@@ -58,6 +60,9 @@
 	case 'd':
 	    sscanf(optarg, "%d", &debugmask);
 	    break;
+        case 'c':
+            config_file = optarg;
+            break;
 	default:
 	    usage(argc, argv, EXIT_FAILURE);
 	}
@@ -68,7 +73,7 @@
     l2tp_peer_init();
     l2tp_debug_set_bitmask(debugmask);
 
-    if (l2tp_parse_config_file(es, "/etc/l2tp/l2tp.conf") < 0) {
+    if (l2tp_parse_config_file(es, config_file) < 0) {
 	l2tp_die();
     }
 
diff -uNr rp-l2tp-0.4.orig/make-release.sh rp-l2tp-0.4/make-release.sh
--- rp-l2tp-0.4.orig/make-release.sh	Thu Jul  1 15:58:55 2004
+++ rp-l2tp-0.4/make-release.sh	Wed Dec  6 11:02:01 2006
@@ -15,7 +15,7 @@
 
 test -d libevent || ln -s ../libevent . || exit 1
 
-MANIFEST="README Makefile.in install-sh auth.c configure configure.in debug.c dgram.c l2tp.conf l2tp.h main.c make-release.sh md5.c md5.h network.c options.c peer.c session.c tunnel.c utils.c handlers/Makefile.in handlers/cmd-control.c handlers/cmd.c handlers/dstring.c handlers/dstring.h handlers/pty.c handlers/sync-pppd.c man/l2tpd.8 man/l2tp.conf.5 libevent/Makefile.in libevent/event.c libevent/event.h libevent/event_sig.c libevent/event_tcp.c libevent/event_tcp.h libevent/eventpriv.h libevent/hash.c libevent/hash.h libevent/Doc/flow.fig libevent/Doc/libevent.tex libevent/Doc/style.tex libevent/Doc/libevent.pdf"
+MANIFEST="README README.BSD Makefile.in install-sh auth.c configure configure.in debug.c dgram.c l2tp.conf l2tp.h main.c make-release.sh md5.c md5.h network.c options.c peer.c session.c tunnel.c utils.c handlers/Makefile.in handlers/cmd-control.c handlers/cmd.c handlers/dstring.c handlers/dstring.h handlers/pty.c handlers/async-pppd.c man/l2tpd.8 man/l2tp.conf.5 libevent/Makefile.in libevent/event.c libevent/event.h libevent/event_sig.c libevent/event_tcp.c libevent/event_tcp.h libevent/eventpriv.h libevent/hash.c libevent/hash.h libevent/Doc/flow.fig libevent/Doc/libevent.tex libevent/Doc/style.tex libevent/Doc/libevent.pdf"
 
 DIR=rp-l2tp-$VERSION
 PWD=`pwd`
diff -uNr rp-l2tp-0.4.orig/man/l2tpd.8 rp-l2tp-0.4/man/l2tpd.8
--- rp-l2tp-0.4.orig/man/l2tpd.8	Mon Sep 30 20:45:00 2002
+++ rp-l2tp-0.4/man/l2tpd.8	Tue Dec  5 12:45:46 2006
@@ -20,6 +20,10 @@
 65535 for maximum debugging information.
 
 .TP
+.B \-c \fIfile\fR
+Specify a different configuration file.
+
+.TP
 .B \-f
 Do not fork.  Normally, \fBl2tpd\fR forks and puts itself in the
 background.  This option causes it to stay running in the foreground.
diff -uNr rp-l2tp-0.4.orig/peer.c rp-l2tp-0.4/peer.c
--- rp-l2tp-0.4.orig/peer.c	Thu Jul  1 15:58:55 2004
+++ rp-l2tp-0.4/peer.c	Tue Dec  5 12:45:46 2006
@@ -17,6 +17,7 @@
 "$Id: peer.c,v 1.5 2003/12/22 14:57:33 dskoll Exp $";
 
 #include "l2tp.h"
+#include <sys/socket.h>
 #include <stddef.h>
 #include <string.h>
 
@@ -365,8 +366,8 @@
 	unsigned long mask = candidate->mask_bits ?
 	    htonl(0xFFFFFFFFUL << (32 - candidate->mask_bits)) : 0;
 
-	strcpy(addr1_str, inet_ntoa(addr->sin_addr));
-	strcpy(addr2_str, inet_ntoa(candidate->addr.sin_addr));
+	strlcpy(addr1_str, inet_ntoa(addr->sin_addr), sizeof(addr1_str));
+	strlcpy(addr2_str, inet_ntoa(candidate->addr.sin_addr), sizeof(addr2_str));
 	DBG(l2tp_db(DBG_TUNNEL, "l2tp_peer_find(%s) examining peer %s/%d\n",
 	       addr1_str, addr2_str,
 	       candidate->mask_bits));
@@ -386,9 +387,9 @@
 	}
     }
 
-    strcpy(addr1_str, inet_ntoa(addr->sin_addr));
+    strlcpy(addr1_str, inet_ntoa(addr->sin_addr), sizeof(addr1_str));
     if (peer != NULL)
-	strcpy(addr2_str, inet_ntoa(peer->addr.sin_addr));
+	strlcpy(addr2_str, inet_ntoa(peer->addr.sin_addr), sizeof(addr2_str));
     DBG(l2tp_db(DBG_TUNNEL, "l2tp_peer_find(%s) found %s/%d\n",
 	   addr1_str,
 	   peer == NULL ? "NULL" : addr2_str,
