diff -Naur tomato/release/src/router/pptp-client/AUTHORS tomato121/release/src/router/pptp-client/AUTHORS
--- tomato/release/src/router/pptp-client/AUTHORS	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/AUTHORS	2008-04-22 21:44:06.000000000 +1000
@@ -1,4 +1,4 @@
-Primary author of this package:
+Primary author of this package (when it was called pptp-linux):
 
 C. Scott Ananian <cananian@alumni.princeton.edu>
 
@@ -7,10 +7,21 @@
 Christoph Lameter <christoph@lameter.com>
 Gordon Chaffee <chaffee@HOME.COM>
 mulix <mulix@actcom.co.il>
-James Cameron <james.cameron@compaq.com>
+James Cameron <james.cameron@hp.com>
 Rein Klazes <rklazes@xs4all.nl>
 Thomas Quinot <thomas@cuivre.fr.eu.org>
 Rhialto <rhialto@azenomei.knuffel.net>
 Scott Venier <scott@scooter.cx>
-Jeff Wiedemeier <Jeff.Wiedemeier@compaq.com>
+Jeff Wiedemeier <Jeff.Wiedemeier@hp.com>
 Yura Zotov <yz@altlinux.ru>
+Chris Wilson <chris@netservers.co.uk>
+Ed Marcotte <epm@cisco.com>
+Jan Pieter <jp@jp.dhs.org>
+Ed Meaney <epm@cisco.com>
+Yury Tarasievich <grog@grsu.by>
+Paul Howarth <paul@city-fan.org>
+Peter Surda <shurdeek@routehat.org>
+
+Package renamed from pptp-linux to pptp after version 1.5.0.
+
+$Id: AUTHORS,v 1.14 2004/07/21 09:05:06 quozl Exp $
diff -Naur tomato/release/src/router/pptp-client/ChangeLog tomato121/release/src/router/pptp-client/ChangeLog
--- tomato/release/src/router/pptp-client/ChangeLog	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/ChangeLog	2008-04-22 21:44:06.000000000 +1000
@@ -1,3 +1,656 @@
+Wed Jul 27 20:49:30 2005  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-1.7.0 released.
+
+Mon Jul 11 13:17:37 2005  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c (decaps_gre): silently discard packets that are not
+	for this call.  Reported by: Alan Jenkins.
+
+Thu Mar 31 17:41:17 2005  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (pptp_dispatch): handle signals first, since there's
+	a possibility of premature return from the function.
+	
+	* pptp_callmgr.c (callmgr_main): terminate faster when peer closes
+	control connection.
+
+Thu Mar 10 11:07:52 2005  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (pptp_handle_timer): when we close connection due to
+	loss of echo replies, say so in the log.
+	Reported by: Jean Wolter.
+
+	* pptp_ctrl.c: fix signal deadlock on kernel 2.6.x
+	Reported by: Jean Wolter.
+	
+	* util.c, util.h: adopt sigpipe implementation from pptpd.
+
+	* pptp_ctrl.c (pptp_conn_open): use sigpipe implementation instead
+	of trying I/O in signal handler (which causes deadlocks).
+
+	* pptp_ctrl.c (pptp_fd_set): include the sigpipe in the file
+	descriptor set.
+	
+	* pptp_ctrl.c (pptp_dispatch): detect queued signals via sigpipe.
+	
+	* pptp_ctrl.c (pptp_conn_destroy): close the sigpipe.
+
+Fri Feb 18 12:38:18 2005  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-1.6.0 released.
+
+Fri Feb 18 12:38:02 2005  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile (install): move options.pptp to this package from the
+	RPM spec file.
+
+Tue Dec 14 08:56:07 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (ctrlp_disp): fix typo.  From: Avi Kivity
+	<avi@argo.co.il>
+
+Tue Dec  7 09:43:00 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c: add error propagation to the ctrlp_disp callchain,
+	so that we don't double-free the connection on a stop control
+	connection reply.  From: Avi Kivity <avi@argo.co.il>
+
+Wed Nov 10 09:49:48 2004  James Cameron  <quozl@us.netrek.org>
+
+	* util.{c,h}: recent compilers spew a packetload of compilation
+	warnings.  From: Avi Kivity <avi@argo.co.il>
+
+Tue Nov  9 12:30:57 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.{8,c}, pptp_ctrl.c, pptp_options.h: add --idle-wait (time
+	to wait before sending an echo request on the control connection)
+	and --max-echo-wait (time to wait before giving up on lack of
+	reply to an echo request).  The latter is not yet implemented.
+
+Tue Nov  9 12:23:48 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_callmgr.c, pptp_ctrl.{c,h}: pptp_dispatch and its
+	subordinates insist on handling fatal errors by calling
+	pptp_conn_destroy. unfortunately, as the comments say,
+	callmgr_main uses the connection afterwards with the usual
+	results.  Added error propagation to the routines mentioned,
+	allowing callmgr_main to have the honor of closing the connection.
+	From: Avi Kivity <avi@argo.co.il>
+
+Wed Oct 27 21:03:28 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_callmgr.c (callmgr_main): pptp sometimes crashes in
+	pptp_fd_set and leaves a core dump.  Think this is due to a signal
+	being caught and longjmp'ed to callmgr_main's shutdown label after
+	we are out of that function, causing garbage local variables to be
+	used.  From: Avi Kivity <avi@argo.co.il>
+
+Wed Jul 21 16:52:01 CEST 2004 Rein Klazes <rklazes@xs4all.nl>
+	
+	* pptp_ctrl.c (ctrlp_rep): Do not log sending of echo requests,
+        preventing dead-locks observed with Linux 2.6 systems.
+        The syslog call is not reentrant and must not be used within a
+        signal handler. A better solution would probably be to get rid of
+        the SIGALRM timer altogether.
+
+Wed Jul 21 19:00:59 2004  Peter Surda  <shurdeek@routehat.org>
+	
+	* pptp_callmgr.c (callmgr_main): prevent kill of init.
+
+Sat Jun 26 14:37:10 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c (decaps_hdlc): portability fix, use IPPROTO_IP in
+	place of SOL_IP in getsockopt().  From: Thomas Quinot
+	<thomas@cuivre.fr.eu.org>
+
+Tue Jun 22 19:08:58 2004  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile, AUTHORS, rename package from pptp-linux to pptp.
+
+Tue Jun 22 18:08:27 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.5.0 released.
+
+Fri Jun 11 09:28:05 2004  Chris Wilson  <chris@netservers.co.uk>
+
+	* pptp.8, pptp_gre.c: make the statistics work properly when
+	buffering is disabled.  Fix the issue with log messages claiming
+	buffering when no buffering is being done.
+
+Thu Jun 10 16:58:53 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c (main): remove the sleep(3) on termination; it isn't
+	really required; and causes the GRE-to-PPP gateway process to hang
+	around after the connection has been terminated.
+
+	* pptp.c (open_callmgr): call manager was inheriting the GRE
+	socket, so close it before launching the callmgr, a regression
+	introduced 18th July 2002, in the patch to bind the GRE socket
+	earlier.
+
+Thu Jun 10 08:34:17 CEST 2004 Rein Klazes <rklazes@xs4all.nl>
+
+	* pptp_callmgr.c: fix a case when the call manager does not
+	shutdown properly, a regression introduced by the changes on
+	2003 Oct 22 and 23.
+
+Wed Jun  9 10:08:02 2004  Chris Wilson  <chris@netservers.co.uk>
+
+	* pptp.8, pptp.c, pptp_gre.c, pptp_gre.h: add --nobuffer option to
+	eliminate all buffering of packets, a "pptp quake patch".
+
+Wed Jun  9 09:37:06 2004  Paul Howarth  <paul@city-fan.org>
+
+	* inststr.c: fix non-setting of the command line.
+
+Tue Jun  8 21:25:27 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.5.0-rc1 released.
+
+Sat Jun  5 22:44:50 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (pptp_read_some): fix for CPU loop after pppd killed
+	with -9, if read() returns zero, it is because the control
+	connection has closed, so destroy the connection.
+
+Wed Mar 24 08:45:12 2004  Mark-Andre Hopf  <mhopf@innominate.com>
+
+	* pptp.c: fix compile for ARM architecture.
+
+Mon Mar  8 11:04:00 2004  Chris Wilson <chris@netservers.co.uk>
+
+	* pptp.8: added documentation for command-line options where
+	missing.  Updated to reflect the use of getopt.
+
+Tue Mar  2 09:53:53 2004  Peter McCurdy <pmccurdy@nit.ca>
+
+	* pptp.c (main, do_nothing): do not hang when a connection is
+	refused.  When the controlling process (pptp.c) paused while
+	waiting for the child to send SIGUSR1, if the child died then the
+	controlling process wouldn't ever wake up.  Now if the child dies,
+	SIGCHLD gets handled and the controlling process quits.
+
+Tue Feb 10 20:35:18 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c (decaps_hdlc): temporarily add code that captures
+	additional detail if EMSGSIZE is returned by read().
+
+Fri Jan  2 10:05:17 2004  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.4.0 released.
+
+Mon Dec  1 11:58:24 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c (main): remove arguments debugging printf.
+
+Wed Nov 26 12:22:00 2003  Chris Wilson   <chris@netservers.co.uk>
+
+	* pptp.c: fixed argument handling so that hostname can be supplied
+	anywhere on the command line, not just at the start.  pppd options
+	starting with "-" but before "--" are no longer supported.
+	
+	* pptp.c: added some spacing to improve readability, removed
+	pointless "Step X" comments.
+	
+	* pptp.c: fixed usage message: there should not be a "pppd" in the
+	command line.
+
+Mon Nov 10 15:39:41 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.4.0-rc1 released.
+
+Thu Oct 23 12:48:54 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_callmgr.c (callmgr_main): if connection fails, pptp enters
+	a CPU loop calling select() with no file descriptors set, and
+	being given EBADF.  Introduced by yesterday's modifications.
+	Correct code to detect this situation and break the main loop.
+
+Wed Oct 22 13:02:04 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c (pptp_call_open): add an assertion to prevent a call
+	open attempt while the control connection is not established.
+
+	* pptp_callmgr.c (callmgr_main): avoid accepting a UNIX socket
+	connection and therefore calling pptp_call_open() if the control
+	connection has not yet been established.
+
+	* pptp_ctrl.c (pptp_conn_established): add function for
+	pptp_callmgr.c to use to determine if the control connection has
+	been established.
+
+	TODO: if a connection reply is not received, what happens?
+
+	Reported by: John BouAntoun
+
+Mon Sep  8 10:33:41 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c: fix for compile on OpenBSD.  From: Waldemar Brodkorb
+
+Mon Aug 18 12:12:00 2003  Chris Wilson   <chris@netservers.co.uk>
+
+	* pptp.c pptp_gre.c util.h: add log level control, to increase
+	or reduce verbosity of log messages, for debugging and for people
+	who have lossy connections.
+
+Thu Aug  7 12:20:09 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c (decaps_gre): fix reporting of packet loss.
+	From: Chris Wilson
+
+Wed Jun 25 12:59:28 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_callmgr.c: Wait for the replies on our Call-Clear-Request's and
+        Stop-Control-Connection-Request's.
+        
+        * pptp_ctrl.c: small tweak in a message about non existant call:
+        report the received call ID's.
+        
+Sun Jun 22 19:08:14 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_ctrl.c: Log the buffering and sending of ALL control
+        messages (except Echo messages and Replies of course).
+        Change the way the sending of these messages is done. The 
+        original way was to first put them into a buffer ( in
+        pptp_send_ctrl_packet()) and at some later write the buffered
+        bytes to the socket ( in pptp_write_some()). Now
+        pptp_send_ctrl_packet first attempts to write the packet directly.
+        Only it the write() does not write all of the bytes, the remaining
+        ones are buffered. This should help to track bugs in this area (like
+        one sending two Start-Control-Request's).
+
+Thu Jun 19 09:09:53 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_ctrl.c: Improve logging of received control packets:
+        Move duplicated code to report on Result codes and General errors
+        to a separate function; Verbosely report error codes embedded in
+        start-control-connection replies; Translated some French comment;
+        Log when an unexpected Outgoing Call Reply is received; Log the
+        receipt of ALL control messages (except in case of echo
+        request/reply packets of which only the first 10 are logged);
+        Shorten the name of the function "pptp_dispatch_ctrl_packet" to
+        "ctrlp_disp", 25 characters is just too much in the log files.
+
+Thu Jun 19 10:11:26 2003  Jan Pieter  <jp@jp.dhs.org>
+
+	* Makefile (uninstall): include uninstall target, and a minor fix
+	to dist.
+	
+Wed Jun 18 12:19:09 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_gre.c: Instead of logging the (a)synchronous mode
+        of ppp, only issue a warning when it conflicts with the
+        mode of pptp.
+        Comparing two sequence numbers for(in)equality is safe even when
+        a wrap-around has occurred. This contrasts with comparing for 
+        smaller/bigger. Remove a few unneeded tests for wrap-around.
+
+Tue Jun 17 19:40:41 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * dirutil.c, ppp_fcs.c, pptp.c, pptp_gre.c, util.c, vector_test.c,
+        * pptp_ctrl.c, pptp_callmgr.c, vector.c : reformat code with 
+        standard 4 spaced indents, uniform function headings and some 
+        general tidying up. Patches have been separated in "diff -w"
+        invariant patches that should be safe and others that may be 
+        not so safe.
+
+Wed Jun 11 14:06:21 2003  Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_gre.c: When a timeout is specified in the select call
+        make it always non-zero. Making this call block makes it likely
+        that pppd will run before the select returns. This results in a
+        big reduction in transmitted ack-only packets (number down from 
+        40% to 0.8% of received packets on my system).
+
+Tue Jun 11 18:42:00 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.3.1 released.
+
+Tue Jun 10 13:53:00 2003  Chris Wilson  <chris@netservers.co.uk>
+
+	* pptp_callmgr.c: fixed a bug with call manager socket naming,
+	introduced since 1.2.0, which caused confusing problems when
+	trying to open more than one tunnel from the same machine.
+
+Tue Jun 10 18:43:34 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp-linux-1.3.0 released.
+
+Tue Jun  3 19:16:52 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.8, pptp.c: change SIGHUP to SIGUSR1 for dumping stats.
+
+Tue May 20 13:20:00 2003  Chris Wilson  <chris@netservers.co.uk>
+
+	* pptp.c: rewrote command-line usage information, to increase
+	clarity and usefulness, and to describe various command-line
+	options which have been added recently.
+
+Fri May 23 20:52:05 2003  Rein Klazes  <rklazes@xs4all.nl>
+
+	* pptp_ctrl.c: increase the verbosity of the log message at the
+	receipt of a Call Disconnect Notification.
+
+Mon May 12 16:56:14 2003  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile: don't install the manpage with execute permission,
+	swap LDFLAGS and LIBS so that one can say 'make LDFLAGS=-s' to
+	create a stripped versions of the executables, introduce the
+	optimization flag as a make variable, so that one can say 'make
+	DEBUG= OPTIMIZE=-O2 LDFLAGS=-s'.  From: Peter Breitenlohner
+
+Tue Apr 29 19:13:33 2003  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile (dist): remove CVS directory from distribution.
+	Reported by: Ola Lundqvist
+
+Tue Apr 15 10:28:00 2003  Chris Wilson   <chris@netservers.co.uk>
+
+	* pptp.c, pptp_gre.c, pptp_gre.h: Added GRE statistics counters
+	and RTT calculation, which can be dumped to the syslog by sending
+	a SIGHUP to the GRE-to-PPP gateway process.
+
+Mon Apr 14 11:57:00 2003  Chris Wilson   <chris@netservers.co.uk>
+
+	* pptp_gre.c: Fixed one case where an ACK could be immediately
+	followed by a data packet, they should be combined into a
+	single packet.
+
+Sat Mar 8 2003 15:19:12 2003 Rein Klazes <rklazes@xs4all.nl>
+
+        * pptp_gre.c, pqueue.c: Actually copy the packet into a new entry
+        in the packet queue, fixing "unknown protocol" error messages;
+        Change the program logic making it obvious that there is not a 
+        memory leak;
+        Restore the "buffering out-of-order packet" log messages, so we
+        have a chance to notice any more side effects.
+
+Mon Feb 17 09:18:30 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_callmgr.c, pptp.c, Makefile: compile call manager from
+	Makefile rather than include from pptp.c.  From: Jan Pieter
+	<jp@jp.dhs.org>
+
+Sat Feb 15 21:32:42 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_ctrl.c, pptp_msg.h: move code out of .h file and into .c
+	file.  From: Jan Pieter <jp@jp.dhs.org>
+
+Sat Feb 15 17:34:38 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c: add include fixes for Apple MacOS X as contributed by an
+	anonymous donor.
+
+Sat Feb 15 14:59:20 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c, pptp_callmgr.c, pptp_gre.c: add localbind option to
+	support multiple clients from separate alias IP addresses.  
+	From: Yury Tarasievich, with contributions by Ed Marcotte.
+
+Fri Feb 14 10:11:27 2003  James Cameron  <quozl@us.netrek.org>
+	
+	* pptp-linux-1.2.0 released.
+	
+Fri Feb 14 16:08:26 CET 2003 Rein Klazes <rklazes@xs4all.nl>
+	
+	* pptp_ctrl.c, pptp_msg.h: tweak the outgoing call reply messages
+	once more. Print the error text that comes with the result code. 
+
+	* pptp.c: close all unused file descriptors belonging to the pty.
+
+	* pptp_gre.c: Convert received acknowledgement numbers from network
+	to host order.
+
+Mon Jan 20 11:46    2003  Chris Wilson <chris@netservers.co.uk>
+
+	* pqueue.c, pqueue.h: changed "expires" field of pqueue entry to a
+	struct timeval for microsecond accuracy (in theory =)
+
+	* pptp_gre.c: use queue head expiry time as the upper bound on how
+	long we block waiting for data from the network or pppd
+
+	* pptp.c: allow setting of packet timeout with sub-second
+	accuracy, print error message to stderr and exit if timeout out of
+	range
+
+Mon Jan 13 10:28    2003  Chris Wilson <chris@netservers.co.uk>
+
+	* pqueue.c, pqueue.h: added freelist support for packet queue,
+	From: Kai Poitschke <kai@poitschke.de>.  Should help to
+	prevent memory fragmentation and perhaps improve performance a
+	little.
+	
+	* pqueue.c: wrap some log() statements with DEBUG_CMD, should
+	improve performance (thanks to Kai Poitschke)
+	
+	* pptpd.c: bugfix for --log-string option: make a copy of the
+	string with strdup, because optarg will be destroyed
+
+Wed Jan 15 14:16:27 2003  James Cameron  <quozl@us.netrek.org>
+
+	* AUTHORS, DEVELOPERS, NEWS, README, TODO, USING: add or move CVS
+	header to tail.
+	* DEVELOPERS: change IRC server name to new alias.
+	* AUTHORS: change a few addresses.
+	* INSTALL: rewrite.
+	* README, USING: review and adjust, minor changes.
+	* Makefile (install): add MANDIR and man page.
+
+Thu Jan  2 11:28:41 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c: fix response to dropped packets.  From: Rein Klazes.
+
+Thu Jan  2 09:11:33 2003  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.8: the IP address should be before the option.  From: Rein
+	Klazes
+
+Mon Dec 30 15:57:48 2002  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile (install): add install target.
+
+Mon Dec  9 08:52:56 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_callmgr.c, pptp.c: close stderr after becoming daemon,
+	otherwise ssh sessions, CGI scripts, or other programs that start
+	pptp don't exit properly; they are held up until the pptp
+	processes terminate and close stderr.
+
+Thu Nov 21 08:41:39 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c: log return value from the read of the GRE socket as
+	a signed number as well.
+
+Wed Nov 20 11:21:48 CET 2002 Rein Klazes <rklazes@xs4all.nl>
+
+	* pptp_gre.c: log return value from the read of the pty as a signed
+	number.
+
+	* pptp_ctrl.c: change the log message to clarify that error codes in a 
+	outgoing call reply come from the server, not the client.
+	
+Wed Nov 20 16:07:30 2002  James Cameron  <quozl@us.netrek.org>
+
+	* Makefile (dist): adjust distribution target to include new files
+	since prior use.
+
+Wed Nov 20 15:17:12 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp_gre.c: hid many packet reordering log calls in an ifdef,
+	added a hint as to cause of EIO on read of the pty.
+
+Fri Oct 11 15:44 BST  2002 Chris Wilson <chris@netservers.co.uk>
+
+	* pptp.c util.c util.h: added "--logstring" option to help identify
+	  connections in syslog output where multiple connections are made
+	  from the same host.
+
+Wed Oct 02 10:31 BST  2002 Chris Wilson <chris@netservers.co.uk>
+
+	* pptp_gre.c pqueue.c: changed some "log" statements to "warn" to
+	  reflect the severity of the condition, allowing much better filtering
+	* util.c: changed _warn to log at WARNING, and _fatal at CRIT level
+	* pptp_gre.c: disabled logging of individual accepted packets
+	* pptp_gre.c: removed a potential NULL pointer dereference crash
+	* pptp_gre.c: fixed the select-timeout check for packets in the queue
+	* pqueue.h: increased window size to 300 following testing
+	* pptp.c: added command-line parameter "--timeout" to set the
+	  lost packet timeout
+
+Fri Aug 30 09:55:05 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
+
+	pptp_gre.c: Try to send more ACK's piggy backed on data packets.
+	Previously if there were any outstanding ACK's to be sent, the 
+	program used a non-blocking select (timeout zero) to see if
+	any data packets are available. In most cases there will be none,
+	since the time passed since the last read is too short and an ACK
+	without data will be sent.
+	This change allows one outstanding ACK, for at most 0.5 second,
+	multiple outstanding ACK's are treated as before.
+	Tests show that this gives a big reduction in the number of
+	sent packets.
+
+Fri Aug 30 09:15:35 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
+
+	* pptp_gre.c: Sequence numbers of sent gre packets should start
+	with 1.
+
+Mon Aug 26 10:56:42 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
+
+	* pptp.c pptp_gre.c pptp_gre.h: added "--sync" option to work 
+	in combination with the pppd sync option. In synchronous mode
+	checksum calculations and (un-)escaping of control characters
+	become unnecessary. This results in big CPU usage reduction.
+	
+Mon Aug 26 08:53:45 CEST 2002 Rein Klazes <rklazes@xs4all.nl>
+
+	* pptp.c: fix bug in command line options parsing (misplaced break
+	in switch statement).
+	
+Wed Aug 21 10:57:01 2002  James Cameron  <quozl@us.netrek.org>
+
+	* pptp.c: add handler for SIGCHLD.
+	From: Peter Surda <shurdeek@panorama.sth.ac.at>
+
+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>
 
 	* Makefile (all): make config.h before making $(PPTP_BIN). 
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.ip-down tomato121/release/src/router/pptp-client/config/pptpd_client.ip-down
--- tomato/release/src/router/pptp-client/config/pptpd_client.ip-down	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.ip-down	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,18 @@
+#!/bin/sh
+REMOTESUB=$(/usr/sbin/nvram get pptpd_client_srvsub)
+REMOTENET=$(/usr/sbin/nvram get pptpd_client_srvsubmsk)
+case "$6" in
+ kelokepptpd)
+  /sbin/route del -net $REMOTESUB netmask $REMOTENET dev $1
+  /usr/sbin/iptables -D OUTPUT --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables -D INPUT --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables -D FORWARD --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables -D FORWARD --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables -D FORWARD --protocol tcp --tcp-flags SYN,RST SYN --jump TCPMSS --clamp-mss-to-pmtu
+  if [ "$(/usr/sbin/nvram get pptpd_client_nat)" = "1" ]; then
+      /usr/sbin/iptables --table nat -D POSTROUTING --out-interface $1 --jump MASQUERADE
+  fi
+  ;;
+ *)
+esac   
+exit 0 
\ No newline at end of file
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.ip-up tomato121/release/src/router/pptp-client/config/pptpd_client.ip-up
--- tomato/release/src/router/pptp-client/config/pptpd_client.ip-up	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.ip-up	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,18 @@
+#!/bin/sh
+REMOTESUB=$(/usr/sbin/nvram get pptpd_client_srvsub)
+REMOTENET=$(/usr/sbin/nvram get pptpd_client_srvsubmsk)
+case "$6" in
+ kelokepptpd)
+  /sbin/route add -net $REMOTESUB netmask $REMOTENET dev $1
+  /usr/sbin/iptables --insert OUTPUT --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables --insert INPUT --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables --insert FORWARD --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables --insert FORWARD --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables --insert FORWARD --protocol tcp --tcp-flags SYN,RST SYN --jump TCPMSS --clamp-mss-to-pmtu 
+  if [ "$(/usr/sbin/nvram get pptpd_client_nat)" = "1" ]; then
+      /usr/sbin/iptables --table nat --append POSTROUTING --out-interface $1 --jump MASQUERADE
+  fi
+  ;;
+ *)
+esac
+exit 0
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.nvramconfig tomato121/release/src/router/pptp-client/config/pptpd_client.nvramconfig
--- tomato/release/src/router/pptp-client/config/pptpd_client.nvramconfig	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.nvramconfig	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,10 @@
+ "pptpd_client_enable"   "PPTPD Client Enable"   "CHOICE" "2" "0" "1"  "FALSE" "0"
+ "pptpd_client_nat"   "PPTPD Client Nat"   "CHOICE" "2" "0" "1"  "FALSE" "0"
+ "pptpd_client_srvip"  "PPTPD Client SrvIP" "NULL" "FALSE" "0"
+ "pptpd_client_srvsub"  "PPTPD Client SrvSub" "MERGEIPADDRS" "FALSE" "0"
+ "pptpd_client_srvsubmsk"  "PPTPD Client SrvSubMsk" "MERGEIPADDRS" "FALSE" "0"
+ "pptpd_client_srvuser"  "PPTPD Client SrvUser" "NULL" "FALSE" "0"
+ "pptpd_client_srvpass"  "PPTPD Client SrvPass" "NULL" "FALSE" "0"
+ "pptpd_client_srvsec"  "PPTPD Client Srvsec" "NULL" "FALSE" "0"
+ "pptpd_client_srvmtu"  "PPTPD Client SrvMtu" "RANGE" "120" "1500" "FALSE" "0"
+ "pptpd_client_srvmru"  "PPTPD Client SrvMru" "RANGE" "120" "1500" "FALSE" "0"
\ No newline at end of file
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.options tomato121/release/src/router/pptp-client/config/pptpd_client.options
--- tomato/release/src/router/pptp-client/config/pptpd_client.options	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.options	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,13 @@
+defaultroute
+lock
+noauth
+nodetach
+refuse-eap
+lcp-echo-failure 3
+lcp-echo-interval 2
+persist
+usepeerdns
+idle 0
+ip-up-script /tmp/pptpd_client/ip-up
+ip-down-script /tmp/pptpd_client/ip-down
+ipparam kelokepptpd
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.sh tomato121/release/src/router/pptp-client/config/pptpd_client.sh
--- tomato/release/src/router/pptp-client/config/pptpd_client.sh	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.sh	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,26 @@
+#!/bin/sh
+USER=$(/usr/sbin/nvram get pptpd_client_srvuser)
+PASS=$(/usr/sbin/nvram get pptpd_client_srvpass)
+SEC=$(/usr/sbin/nvram get pptpd_client_srvsec)
+MTU=$(/usr/sbin/nvram get pptpd_client_srvmtu)
+MRU=$(/usr/sbin/nvram get pptpd_client_srvmru)
+sleep 30
+mkdir /tmp/pptpd_client
+mkdir /tmp/ppp
+cp /etc/config/pptpd_client.options /tmp/pptpd_client/options.vpn
+echo "$SEC"  >> /tmp/pptpd_client/options.vpn
+echo -n "mtu " >> /tmp/pptpd_client/options.vpn
+echo "$MTU"  >> /tmp/pptpd_client/options.vpn
+echo -n "mru " >> /tmp/pptpd_client/options.vpn
+echo "$MRU"  >> /tmp/pptpd_client/options.vpn
+echo -n "name "  >> /tmp/pptpd_client/options.vpn
+echo "$USER" >> /tmp/pptpd_client/options.vpn
+echo -n "password "  >> /tmp/pptpd_client/options.vpn
+echo "$PASS" >> /tmp/pptpd_client/options.vpn
+cp /etc/config/pptpd_client.vpn /tmp/pptpd_client/vpn
+chmod +x /tmp/pptpd_client/vpn
+cp /etc/config/pptpd_client.ip-up /tmp/pptpd_client/ip-up
+chmod +x /tmp/pptpd_client/ip-up
+cp /etc/config/pptpd_client.ip-down /tmp/pptpd_client/ip-down
+chmod +x /tmp/pptpd_client/ip-down
+pidof vpn || /tmp/pptpd_client/vpn start
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.startup tomato121/release/src/router/pptp-client/config/pptpd_client.startup
--- tomato/release/src/router/pptp-client/config/pptpd_client.startup	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.startup	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,24 @@
+#!/bin/sh
+if [ -z "$(nvram get pptpd_client_enable)" ]; then
+    nvram set pptpd_client_enable=0
+    nvram set pptpd_client_srvuser="DOMAIN\\\\Username"
+    nvram set pptpd_client_srvsec="mppe required"
+    nvram set pptpd_client_srvmtu="1450"
+    nvram set pptpd_client_srvmru="1450"
+    nvram set pptpd_client_nat="1"  
+    nvram need_commit=1
+fi
+
+if [ "$(nvram get pptpd_client_enable)" = "0" ]; then
+    if test -e "/tmp/pptpd_client/vpn"; then nohup /tmp/pptpd_client/vpn stop; fi
+fi
+
+if [ "$(nvram get pptpd_client_enable)" = "1" ]; then
+    if [ -z "$(nvram get pptpd_client_srvip)" ]
+    then
+     echo "No Ip or DNS name have been entered"
+    if test -e "/tmp/pptpd_client/vpn"; then nohup /tmp/pptpd_client/vpn stop; fi
+    else    
+    /etc/config/pptpd_client.sh &
+    fi
+fi
diff -Naur tomato/release/src/router/pptp-client/config/pptpd_client.vpn tomato121/release/src/router/pptp-client/config/pptpd_client.vpn
--- tomato/release/src/router/pptp-client/config/pptpd_client.vpn	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/pptpd_client.vpn	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,115 @@
+#!/bin/sh
+#######################################################################
+# VPN script Created by rcalvert                                      #
+# VPN Script and Related Scripts Modify by Cesar_G AKA Keloke         #
+# Module for DD-WRT created by Cesar_G AKA Keloke                     #
+#######################################################################
+
+RESP=0
+PPTPSERVER=$(nvram get pptpd_client_srvip)
+
+case $1 in
+ "start" )
+  echo "Launching VPN process"
+  $0 go &
+  echo "Process launched"
+;;
+
+ "go"  )
+  echo "Waiting......."
+  sleep 10
+  PIDFILE="/var/run/vpn.pid"
+  if [ -f "${PIDFILE}" ];
+  then
+   PID="`cat ${PIDFILE}`"
+   if egrep vpn "/proc/${PID}/cmdline" 2>&1 > /dev/null;
+   then
+    echo "Already active!"
+    exit 16
+   fi
+   echo "Removing PID file"
+   rm -f "${PIDFILE}"
+  fi
+  echo -n $$ > "${PIDFILE}"
+  echo "PID file created"
+  echo "Attempting initial connect"
+  pptp $PPTPSERVER file /tmp/pptpd_client/options.vpn
+  echo "Initial connection dropped"
+
+  while [ 1 ];
+  do
+   echo "Attempting connect... "
+   killall pptp 2>/dev/null
+   sleep 2
+   killall -9 pptp 2>/dev/null
+   sleep 1
+   pptp $PPTPSERVER file /tmp/pptpd_client/options.vpn
+   echo "Connection dropped... "
+   sleep 2
+  done;
+ ;;
+
+ "debug"  )
+  echo "Waiting......."
+  sleep 10
+  PIDFILE="/var/run/vpn.pid"
+  if [ -f "${PIDFILE}" ];
+  then
+   PID="`cat ${PIDFILE}`"
+   if egrep vpn "/proc/${PID}/cmdline" 2>&1 > /dev/null;
+   then
+    echo "Already active!"
+    exit 16
+   fi
+   echo "Removing PID file"
+   rm -f "${PIDFILE}"
+  fi
+  echo -n $$ > "${PIDFILE}"
+  echo "PID file created"
+  echo "Attempting initial connect"
+  pptp $PPTPSERVER file /tmp/pptpd_client/options.vpn debug nodetach
+  echo "Initial connection dropped"
+
+  while [ 1 ];
+  do
+   echo "Attempting connect... "
+   killall pptp 2>/dev/null
+   sleep 2
+   killall -9 pptp 2>/dev/null
+   sleep 1
+   pptp $PPTPSERVER file /tmp/pptpd_client/options.vpn debug nodetach
+   echo "Connection dropped... "
+   sleep 2
+  done;
+ ;;
+
+"stop"   )
+
+  VPNPID=`cat /var/run/vpn.pid`
+  echo "Killing VPN PID $VPNPID"
+  kill $VPNPID
+  sleep 2
+  kill -9 $VPNPID 2>/dev/null
+
+  PPTPPID=`pidof -s pptp`
+  echo "Killing PPTP PID $PPTPPID"
+  kill $PPTPPID
+  sleep 2
+  kill -9 $PPTPPID
+  sleep 2
+  rm /var/run/vpn.pid
+  echo "VPN Stopped"
+ ;; 
+* ) 
+  echo " "
+  echo "  PTPP VPN CLIENT" 
+  echo "  --------" 
+  echo " " 
+  echo "   start  -  Starts the Client" 
+  echo "   stop   -  Stops the Client" 
+  echo "   go     -  Run the Client interactively (for debugging)" 
+  echo "   debug  -  Run the Client interactively (in full debug mode)" 
+  echo " " 
+ ;; 
+esac
+return $RESP
diff -Naur tomato/release/src/router/pptp-client/config/vpn/ip-down tomato121/release/src/router/pptp-client/config/vpn/ip-down
--- tomato/release/src/router/pptp-client/config/vpn/ip-down	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/vpn/ip-down	2008-04-23 18:34:56.000000000 +1000
@@ -0,0 +1,18 @@
+#!/bin/sh
+REMOTESUB=$(/bin/nvram get pptp_client_srvsub)
+REMOTENET=$(/bin/nvram get pptp_client_srvsubmsk)
+case "$6" in
+ kelokepptpd)
+  /sbin/route del -net $REMOTESUB netmask $REMOTENET dev $1
+  /usr/sbin/iptables -D OUTPUT --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables -D INPUT --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables -D FORWARD --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables -D FORWARD --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables -D FORWARD --protocol tcp --tcp-flags SYN,RST SYN --jump TCPMSS --clamp-mss-to-pmtu
+  if [ "$(/bin/nvram get pptp_client_nat)" = "1" ]; then
+      /usr/sbin/iptables --table nat -D POSTROUTING --out-interface $1 --jump MASQUERADE
+  fi
+  ;;
+ *)
+esac   
+exit 0 
\ No newline at end of file
diff -Naur tomato/release/src/router/pptp-client/config/vpn/ip-up tomato121/release/src/router/pptp-client/config/vpn/ip-up
--- tomato/release/src/router/pptp-client/config/vpn/ip-up	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/vpn/ip-up	2008-04-23 18:35:18.000000000 +1000
@@ -0,0 +1,18 @@
+#!/bin/sh
+REMOTESUB=$(/bin/nvram get pptp_client_srvsub)
+REMOTENET=$(/bin/nvram get pptp_client_srvsubmsk)
+case "$6" in
+ kelokepptpd)
+  /sbin/route add -net $REMOTESUB netmask $REMOTENET dev $1
+  /usr/sbin/iptables --insert OUTPUT --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables --insert INPUT --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables --insert FORWARD --source 0.0.0.0/0.0.0.0 --destination $REMOTESUB/$REMOTENET --jump ACCEPT --out-interface $1
+  /usr/sbin/iptables --insert FORWARD --source $REMOTESUB/$REMOTENET --destination 0.0.0.0/0.0.0.0 --jump ACCEPT --in-interface $1
+  /usr/sbin/iptables --insert FORWARD --protocol tcp --tcp-flags SYN,RST SYN --jump TCPMSS --clamp-mss-to-pmtu 
+  if [ "$(/bin/nvram get pptp_client_nat)" = "1" ]; then
+      /usr/sbin/iptables --table nat --append POSTROUTING --out-interface $1 --jump MASQUERADE
+  fi
+  ;;
+ *)
+esac
+exit 0
diff -Naur tomato/release/src/router/pptp-client/config/vpn/options.vpn tomato121/release/src/router/pptp-client/config/vpn/options.vpn
--- tomato/release/src/router/pptp-client/config/vpn/options.vpn	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/vpn/options.vpn	2008-04-23 20:03:21.000000000 +1000
@@ -0,0 +1,15 @@
+lock
+noauth
+nodetach
+refuse-eap
+lcp-echo-failure 3
+lcp-echo-interval 2
+persist
+usepeerdns
+idle 0
+ip-up-script /etc/vpn/ip-up
+ip-down-script /etc/vpn/ip-down
+ipparam kelokepptpd
+
+mtu 1450
+mru 1450
diff -Naur tomato/release/src/router/pptp-client/config/vpn/vpn tomato121/release/src/router/pptp-client/config/vpn/vpn
--- tomato/release/src/router/pptp-client/config/vpn/vpn	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config/vpn/vpn	2008-04-23 18:35:47.000000000 +1000
@@ -0,0 +1,115 @@
+#!/bin/sh
+#######################################################################
+# VPN script Created by rcalvert                                      #
+# VPN Script and Related Scripts Modify by Cesar_G AKA Keloke         #
+# Module for DD-WRT created by Cesar_G AKA Keloke                     #
+#######################################################################
+
+RESP=0
+PPTPSERVER=$(nvram get pptp_client_srvip)
+
+case $1 in
+ "start" )
+  echo "Launching VPN process"
+  $0 go &
+  echo "Process launched"
+;;
+
+ "go"  )
+  echo "Waiting......."
+  sleep 10
+  PIDFILE="/var/run/vpn.pid"
+  if [ -f "${PIDFILE}" ];
+  then
+   PID="`cat ${PIDFILE}`"
+   if egrep vpn "/proc/${PID}/cmdline" 2>&1 > /dev/null;
+   then
+    echo "Already active!"
+    exit 16
+   fi
+   echo "Removing PID file"
+   rm -f "${PIDFILE}"
+  fi
+  echo -n $$ > "${PIDFILE}"
+  echo "PID file created"
+  echo "Attempting initial connect"
+  pptp $PPTPSERVER file /etc/vpn/options.vpn
+  echo "Initial connection dropped"
+
+  while [ 1 ];
+  do
+   echo "Attempting connect... "
+   killall pptp 2>/dev/null
+   sleep 2
+   killall -9 pptp 2>/dev/null
+   sleep 1
+   pptp $PPTPSERVER file /etc/vpn/options.vpn
+   echo "Connection dropped... "
+   sleep 2
+  done;
+ ;;
+
+ "debug"  )
+  echo "Waiting......."
+  sleep 10
+  PIDFILE="/var/run/vpn.pid"
+  if [ -f "${PIDFILE}" ];
+  then
+   PID="`cat ${PIDFILE}`"
+   if egrep vpn "/proc/${PID}/cmdline" 2>&1 > /dev/null;
+   then
+    echo "Already active!"
+    exit 16
+   fi
+   echo "Removing PID file"
+   rm -f "${PIDFILE}"
+  fi
+  echo -n $$ > "${PIDFILE}"
+  echo "PID file created"
+  echo "Attempting initial connect"
+  pptp $PPTPSERVER file /etc/vpn/options.vpn debug nodetach
+  echo "Initial connection dropped"
+
+  while [ 1 ];
+  do
+   echo "Attempting connect... "
+   killall pptp 2>/dev/null
+   sleep 2
+   killall -9 pptp 2>/dev/null
+   sleep 1
+   pptp $PPTPSERVER file /etc/vpn/options.vpn debug nodetach
+   echo "Connection dropped... "
+   sleep 2
+  done;
+ ;;
+
+"stop"   )
+
+  VPNPID=`cat /var/run/vpn.pid`
+  echo "Killing VPN PID $VPNPID"
+  kill $VPNPID
+  sleep 2
+  kill -9 $VPNPID 2>/dev/null
+
+  PPTPPID=`pidof -s pptp`
+  echo "Killing PPTP PID $PPTPPID"
+  kill $PPTPPID
+  sleep 2
+  kill -9 $PPTPPID
+  sleep 2
+  rm /var/run/vpn.pid
+  echo "VPN Stopped"
+ ;; 
+* ) 
+  echo " "
+  echo "  PTPP VPN CLIENT" 
+  echo "  --------" 
+  echo " " 
+  echo "   start  -  Starts the Client" 
+  echo "   stop   -  Stops the Client" 
+  echo "   go     -  Run the Client interactively (for debugging)" 
+  echo "   debug  -  Run the Client interactively (in full debug mode)" 
+  echo " " 
+ ;; 
+esac
+return $RESP
diff -Naur tomato/release/src/router/pptp-client/config.h tomato121/release/src/router/pptp-client/config.h
--- tomato/release/src/router/pptp-client/config.h	2007-06-26 15:53:22.000000000 +1000
+++ tomato121/release/src/router/pptp-client/config.h	1970-01-01 10:00:00.000000000 +1000
@@ -1,3 +0,0 @@
-/* text added by Makefile target config.h */
-#define PPTP_LINUX_VERSION "1.1.0"
-#define PPPD_BINARY "/usr/sbin/pppd"
diff -Naur tomato/release/src/router/pptp-client/debian/changelog tomato121/release/src/router/pptp-client/debian/changelog
--- tomato/release/src/router/pptp-client/debian/changelog	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/changelog	1970-01-01 10:00:00.000000000 +1000
@@ -1,71 +0,0 @@
-pptp-linux (1.1.0-1) frozen unstable; urgency=low
-
-  * New upstream release.
-
- -- James Cameron <james.cameron@compaq.com>  Fri, 20 Mar 2002 11:30:55 +1100
-
-pptp-linux (1.0.3-2) frozen unstable; urgency=low
-
-  * Update upstream distribution information. Closes: #97159.
-
- -- Thomas Quinot <thomas@debian.org>  Fri, 11 May 2001 16:57:11 +0200
-
-pptp-linux (1.0.3-1) frozen unstable; urgency=low
-
-  * New upstream release. Debian patches have been integrated.
-  * Get rid of yada.
-
- -- Thomas Quinot <thomas@debian.org>  Thu, 10 May 2001 14:29:30 +0200
-
-pptp-linux (1.0.2-5) frozen unstable; urgency=low
-
-  * Remove bashism in debian/rules.
-    Reported by Peter Palfrader <weasel@debian.org>.
-    Closes: #87653.
-  * Make sure yada is executable. Closes: #86888.
-
- -- Thomas Quinot <thomas@debian.org>  Tue, 13 Mar 2001 11:43:31 +0100
-
-pptp-linux (1.0.2-4) frozen unstable; urgency=low
-
-  * Updated YADA to 0.9.4. Closes: #84564.
-
- -- Thomas Quinot <thomas@debian.org>  Sun,  4 Feb 2001 18:42:10 +0100
-
-pptp-linux (1.0.2-3) frozen unstable; urgency=low
-
-  * New maintainer.
-  * Update Standards-Version.
-  * Use YADA.
-  * Fix order of local and remote call ID.
-    Fix bearer capability specification.
-    Closes:  #48536, #55532.
-  * Fix several gross bugs. Closes: #55583.
-  * Patch to allow bug-compatibility with Alcated ADSL 1000 modem.
-    
- -- Thomas Quinot <thomas@debian.org>  Mon, 10 Jul 2000 23:52:16 +0200
-
-pptp-linux (1.0.2-2) frozen unstable; urgency=low
-
-  * lintian: binary-without-manpage pptp,
-             binary-without-manpage pptp_callmgr
-    including links to undocumented.7.gz for now (Bug#20141)
-
- -- Roberto Lumbreras <rover@debian.org>  Tue, 24 Mar 1998 04:06:02 +0100
-
-pptp-linux (1.0.2-1) unstable; urgency=low
-
-  * new upstream version
-  * updated to Standards-Version 2.4.0.0
-
- -- Roberto Lumbreras <rover@debian.org>  Mon,  2 Mar 1998 04:34:22 +0100
-
-pptp-linux (1.0.1-1) unstable; urgency=low
-
-  * Initial Release.
-
- -- Christoph Lameter <clameter@debian.org>  Sun, 25 Jan 1998 22:42:45 -0800
-
-Local variables:
-mode: debian-changelog
-End:
diff -Naur tomato/release/src/router/pptp-client/debian/control tomato121/release/src/router/pptp-client/debian/control
--- tomato/release/src/router/pptp-client/debian/control	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/control	1970-01-01 10:00:00.000000000 +1000
@@ -1,15 +0,0 @@
-Source: pptp-linux
-Maintainer: Thomas Quinot <thomas@debian.org>
-Section: net
-Priority: optional
-Standards-Version: 3.1.1
-Build-Depends: debhelper
-
-Package: pptp-linux
-Architecture: any
-Depends: ${shlibs:Depends}, ppp
-Description: Point-to-Point Tunneling Protocol (PPTP) Client
- Client for the proprietary Microsoft Point-to-Point Tunneling
- Protocol, PPTP.  Allows connection to a PPTP based VPN as used
- by employers and some cable and ADSL service providers.
- Requires MPPE support in kernel, use package kernel-patch-mppe.
diff -Naur tomato/release/src/router/pptp-client/debian/copyright tomato121/release/src/router/pptp-client/debian/copyright
--- tomato/release/src/router/pptp-client/debian/copyright	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/copyright	1970-01-01 10:00:00.000000000 +1000
@@ -1,11 +0,0 @@
-This package was initially debianized by Christoph Lameter,
-<clameter@debian.org>, on Sun, 25 Jan 1998 22:42:45 -0800.
-It is now maintained by Thomas Quinot <thomas@debian.org>.
-
-The current release is available from
-  http://pptpclient.sourceforge.net
-
-Copyright: GPL
-
-On Debian GNU/Linux systems, the complete text of the GNU General
-Public License can be found in `/usr/share/doc/copyright/GPL'.
diff -Naur tomato/release/src/router/pptp-client/debian/pptp.8 tomato121/release/src/router/pptp-client/debian/pptp.8
--- tomato/release/src/router/pptp-client/debian/pptp.8	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/pptp.8	1970-01-01 10:00:00.000000000 +1000
@@ -1,36 +0,0 @@
-.TH PPTP 8
-.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
-.\" other parms are allowed: see man(7), man(1)
-.SH NAME
-pptp \- PPTP driver
-.br
-pptp_callmgr \- Call Manager
-.SH SYNOPSIS
-.B pptp
-.I "<pptp-server-IP> [ppp-options] ..."
-.SH "DESCRIPTION"
-This manual page documents briefly the
-.BR pptp
-command.
-This manual page was written for the Debian GNU/Linux distribution
-because the original program does not have a manual page.
-Instead, it has documentation in text format.
-.PP
-.B pptp
-is a program that allows one to establish the client side of
-a Virtual Private Network.
-.SH OPTIONS
-The first argument on the
-.B pptp
-command line must be the name or IP address of your PPTP server.
-The remaining arguments are passed as is to
-.B
-pppd
-.SH "SEE ALSO"
-.IR pppd (8)
-.PP
-Documentation in
-.IR /usr/share/doc/pptp-linux
-.SH AUTHOR
-This manual page was written by Thomas Quinot <thomas@debian.org>,
-for the Debian GNU/Linux system (but may be used by others).
diff -Naur tomato/release/src/router/pptp-client/debian/README.Debian tomato121/release/src/router/pptp-client/debian/README.Debian
--- tomato/release/src/router/pptp-client/debian/README.Debian	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/README.Debian	1970-01-01 10:00:00.000000000 +1000
@@ -1,9 +0,0 @@
-pptp-linux for DEBIAN
-----------------------
-
-The documentation is not sufficient right now. Please contact the
-list at pptp@debs.fuller.edu. Subscribe by:
-
-echo "subscribe"|mail pptp-request@debs.fuller.edu
-
-Christoph Lameter <clameter@debian.org>, Sun, 25 Jan 1998 22:42:45 -0800
diff -Naur tomato/release/src/router/pptp-client/debian/README.Reference tomato121/release/src/router/pptp-client/debian/README.Reference
--- tomato/release/src/router/pptp-client/debian/README.Reference	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/README.Reference	1970-01-01 10:00:00.000000000 +1000
@@ -1,19 +0,0 @@
-In this directory are the various standards documents implemented in
-the pptp-linux package.
-
-rfc791.txt		Internet Protocol (IP).
-rfc793.txt		Transmission Control Protocol (TCP).
-rfc1661.txt		The Point-to-Point Protocol (PPP).
-rfc1662.txt		PPP in HDLC-like Framing. (serial encoding).
-rfc1701.txt		Generic Routing Encapsulation (GRE).
-rfc1702.txt		Generic Routing Encapsulation over IPv4 networks.
-rfc1990.txt		The PPP Multilink Protocol (MP).
-ms-chap.txt		Microsoft PPP CHAP extensions.
-pptp-draft.txt		July 1997 draft of the PPTP standard.
-
-rfc1990 is currently unimplemented in pptp-linux.
-                                                        CSA, 12/12/97
-
-Note:
-The following RFCs are note included: 791, 793, 1661, 1662
-They can be found in package doc-rfc.
diff -Naur tomato/release/src/router/pptp-client/debian/rules tomato121/release/src/router/pptp-client/debian/rules
--- tomato/release/src/router/pptp-client/debian/rules	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/debian/rules	1970-01-01 10:00:00.000000000 +1000
@@ -1,81 +0,0 @@
-#!/usr/bin/make -f
-# Sample debian/rules that uses debhelper.
-# This file is public domain software, originally written by Joey Hess. 
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-# This is the debhelper compatibility version to use.
-export DH_COMPAT=3
-
-build: build-stamp
-build-stamp:
-	dh_testdir
-
-	$(MAKE)
-
-	touch build-stamp
-
-clean:
-	dh_testdir
-	dh_testroot
-	rm -f build-stamp
-
-	-$(MAKE) distclean
-
-	dh_clean
-
-install: build
-	dh_testdir
-	dh_testroot
-	dh_clean -k
-	dh_installdirs
-
-	# Add here commands to install the package into debian/<packagename>
-	mkdir -p `pwd`/debian/`dh_listpackages`/usr/sbin
-	install -o root -m 555 pptp `pwd`/debian/`dh_listpackages`/usr/sbin
-
-
-# Build architecture-independent files here.
-binary-indep: build install
-# We have nothing to do by default.
-
-# Build architecture-dependent files here.
-binary-arch: build install
-	dh_testdir
-	dh_testroot
-#	dh_installdebconf	
-	dh_installdocs debian/copyright \
-	README TODO USING AUTHORS debian/README.Debian \
-	Documentation/* debian/README.Reference \
-	Reference/rfc1701.txt \
-	Reference/rfc1702.txt \
-	Reference/rfc1990.txt \
-	Reference/pptp-draft.txt \
-	Reference/ms-chap.txt
-	dh_installexamples
-	dh_installmenu
-#	dh_installlogrotate
-#	dh_installemacsen
-#	dh_installpam
-#	dh_installmime
-#	dh_installinit
-#	dh_installcron
-	dh_installman debian/pptp.8
-	dh_installinfo
-#	dh_undocumented
-	dh_installchangelogs NEWS
-	dh_link
-	dh_strip
-	dh_compress
-	dh_fixperms
-#	dh_makeshlibs
-	dh_installdeb
-#	dh_perl
-	dh_shlibdeps
-	dh_gencontrol
-	dh_md5sums
-	dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff -Naur tomato/release/src/router/pptp-client/DEVELOPERS tomato121/release/src/router/pptp-client/DEVELOPERS
--- tomato/release/src/router/pptp-client/DEVELOPERS	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/DEVELOPERS	2008-04-22 21:44:06.000000000 +1000
@@ -1,5 +1,3 @@
-$Id: DEVELOPERS,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
-
 Developers Information
 
 
@@ -82,7 +80,8 @@
 Developers who use IRC on a regular basis are welcome to add the
 project's channel to their list of autojoin channels.
 
-	Server: irc.openprojects.net
+	Server: irc.freenode.net
 	Channel: #pptp
 
---
+
+$Id: DEVELOPERS,v 1.4 2003/01/15 05:29:20 quozl Exp $
diff -Naur tomato/release/src/router/pptp-client/dirutil.c tomato121/release/src/router/pptp-client/dirutil.c
--- tomato/release/src/router/pptp-client/dirutil.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/dirutil.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* dirutil.c ... directory utilities.
  *               C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: dirutil.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: dirutil.c,v 1.2 2003/06/17 17:25:47 reink Exp $
  */
 
 #include <sys/stat.h>
@@ -12,51 +12,57 @@
 #include "dirutil.h"
 
 /* Returned malloc'ed string representing basename */
-char *basenamex(char *pathname) {
-  char *dup = strdup(pathname);
-  char *ptr = strrchr(stripslash(dup), '/');
-  if (ptr==NULL) return dup;
-  ptr = strdup(ptr+1);
-  free(dup);
-  return ptr;
+char *basenamex(char *pathname)
+{
+    char *dup = strdup(pathname);
+    char *ptr = strrchr(stripslash(dup), '/');
+    if (ptr == NULL) return dup;
+    ptr = strdup(ptr+1);
+    free(dup);
+    return ptr;
 }
+
 /* Return malloc'ed string representing directory name (no trailing slash) */
-char *dirname(char *pathname) {
-  char *dup = strdup(pathname);
-  char *ptr = strrchr(stripslash(dup), '/');
-  if (ptr==NULL) { free(dup); return strdup("."); }
-  if (ptr==dup && dup[0]=='/') ptr++;
-  *ptr = '\0';
-  return dup;
+char *dirname(char *pathname)
+{
+    char *dup = strdup(pathname);
+    char *ptr = strrchr(stripslash(dup), '/');
+    if (ptr == NULL) { free(dup); return strdup("."); }
+    if (ptr == dup && dup[0] == '/') ptr++;
+    *ptr = '\0';
+    return dup;
 }
+
 /* In-place modify a string to remove trailing slashes.  Returns arg.
  * stripslash("/") returns "/";
  */
 char *stripslash(char *pathname) {
-  int len = strlen(pathname);
-  while (len > 1 && pathname[len-1]=='/')
-    pathname[--len]='\0';
-  return pathname;
+    int len = strlen(pathname);
+    while (len > 1 && pathname[len - 1] == '/')
+        pathname[--len] = '\0';
+    return pathname;
 }
+
 /* ensure dirname exists, creating it if necessary. */
-int make_valid_path(char *dir, mode_t mode) {
-  struct stat st;
-  char *tmp=NULL, *path = stripslash(strdup(dir));
-  int retval;
-  if (stat(path, &st) == 0) { /* file exists */
-    if (S_ISDIR(st.st_mode)) { retval=1; goto end; }
-    else { retval=0; goto end; } /* not a directory.  Oops. */
-  }
-  /* Directory doesn't exist.  Let's make it. */
-  /*   Make parent first. */
-  if (!make_valid_path(tmp = dirname(path), mode)) { retval=0; goto end; }
-  /*   Now make this 'un. */
-  if (mkdir(path, mode) < 0) { retval=0; goto end; }
-  /* Success. */
-  retval=1;
+int make_valid_path(char *dir, mode_t mode)
+{
+    struct stat st;
+    char *tmp = NULL, *path = stripslash(strdup(dir));
+    int retval;
+    if (stat(path, &st) == 0) { /* file exists */
+        if (S_ISDIR(st.st_mode)) { retval = 1; goto end; }
+        else { retval = 0; goto end; } /* not a directory.  Oops. */
+    }
+    /* Directory doesn't exist.  Let's make it. */
+    /*   Make parent first. */
+    if (!make_valid_path(tmp = dirname(path), mode)) { retval = 0; goto end; }
+    /*   Now make this 'un. */
+    if (mkdir(path, mode) < 0) { retval = 0; goto end; }
+    /* Success. */
+    retval = 1;
 
 end:
-  if (tmp!=NULL) free(tmp);
-  if (path!=NULL) free(path);
-  return retval;
+    if (tmp != NULL) free(tmp);
+    if (path != NULL) free(path);
+    return retval;
 }
diff -Naur tomato/release/src/router/pptp-client/dirutil.h tomato121/release/src/router/pptp-client/dirutil.h
--- tomato/release/src/router/pptp-client/dirutil.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/dirutil.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* dirutil.h ... directory utilities.
  *               C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: dirutil.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: dirutil.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
  */
 
 /* Returned malloc'ed string representing basename */
diff -Naur tomato/release/src/router/pptp-client/Documentation/PORTING tomato121/release/src/router/pptp-client/Documentation/PORTING
--- tomato/release/src/router/pptp-client/Documentation/PORTING	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/Documentation/PORTING	2008-04-22 21:44:06.000000000 +1000
@@ -1,5 +1,5 @@
-pptp-linux uses very few linux-specific features, and should be
-easily portable to most Unix systems.
+pptp uses very few linux-specific features, and should be easily
+portable to most Unix systems.
 
 Two things to watch:
   1)
diff -Naur tomato/release/src/router/pptp-client/INSTALL tomato121/release/src/router/pptp-client/INSTALL
--- tomato/release/src/router/pptp-client/INSTALL	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/INSTALL	2008-04-22 21:44:06.000000000 +1000
@@ -1,9 +1,45 @@
-First, install pppd (the Point-to-Point Protocol package) and make
-sure it is working.  You will need MS-CHAP support in pppd to use
-encrypted authentication for pptp. 
-
-Look at the Makefile; make sure its settings are correct.  In
-particular, if your pppd program in not installed in either /bin or
-/usr/bin, edit the path in PPPD_BINARY to point to your pppd program.
+Installation Instructions - Brief
 
-Type 'make'.  This should generate the 'pptp' executable.
+    1.  install pppd (with MPPE if you require it),
+    2.  if pppd is not in /usr/sbin, edit Makefile, variable PPPD,
+    3.  'make'
+    4.  'make install'
+
+
+Installation Instructions - Detailed
+
+    1.  install PPP, and make sure it is working.
+
+        On most distributions, use the package called ppp or pppd.
+
+        If your PPTP server requires MPPE, make sure the pppd program
+        has been built with MPPE and MS-CHAP support.  PPP from
+        version 2.4.2 onwards has this support.  PPP may require
+        kernel support for MPPE, which may require patching your
+        kernel.
+
+    2.  verify that the pppd program is in the /usr/sbin/ directory.
+
+        On some distributions, it is in /usr/bin, or somewhere else.
+        If it isn't in the default directory, edit the Makefile, and
+        change the PPPD variable to point at the pppd program.
+
+        You may even want to run a separate pppd program with MPPE
+        support.
+
+    3.  compile
+
+        Type 'make'.  This should generate the 'pptp' executable.
+
+    4.  install binaries
+
+	Type 'make install' to have the program and the manual page
+	installed.
+
+
+Further information
+
+    http://pptpclient.sourceforge.net/
+
+
+$Id: INSTALL,v 1.2 2003/01/15 05:29:20 quozl Exp $	
diff -Naur tomato/release/src/router/pptp-client/inststr.c tomato121/release/src/router/pptp-client/inststr.c
--- tomato/release/src/router/pptp-client/inststr.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/inststr.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,11 +1,16 @@
 /* inststr.c ... stolen from bdupdate.c, which stole it from perl 4.
  *               Theft by C. Scott Ananian <cananian@alumni.princeton.edu>
+ *               Modified similarly to perl 5.8.3's alignment-checking code
+8                by Paul Howarth <paul@city-fan.org>
  *
- * $Id: inststr.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: inststr.c,v 1.3 2004/06/08 23:40:14 quozl Exp $
  */
 
 #include <string.h>
 
+#define PTRSIZE sizeof(void *)
+typedef unsigned long UL;
+
 void
 inststr(int argc, char **argv, char **environ, char *src)
 {
@@ -18,22 +23,46 @@
         strcpy(argv[0], src);
     } else
     {
-        /* stolen from the source to perl 4.036 (assigning to $0) */
+        /* Stolen from the source to perl 4.036 (assigning to $0) */
+        /* Modified to allow for aligned array members, assuming  */
+        /* no system has something bizarre like the argv[]        */
+        /* interleaved with some other data. Also allow for argv  */
+        /* array having higher numbered elements lower in memory  */
+        /* than lower numbered elements.                          */
         char *ptr, *ptr2;
         int count;
+        UL mask = ~(UL)(PTRSIZE == 4 ? 3 : PTRSIZE == 8 ? 7 : PTRSIZE == 16 ? 15 : 0);
+        int aligned = (mask < ~(UL)0) && (((UL)(argv[0]) & mask) == (UL)(argv[0]));
         ptr = argv[0] + strlen(argv[0]);
-        for (count = 1; count < argc; count++) {
-               if (argv[count] == ptr + 1) {
-                   int fwd = strlen(++ptr);
-                   ptr += fwd; 
-               }
+        if (argv[argc - 1] >= argv[1]) {
+            /* argv pointers in ascending memory order */
+            for (count = 1; count < argc; count++) {
+                if (argv[count] == ptr + 1
+                    ||
+                    (aligned && argv[count] > ptr && argv[count] <= (char *)((UL)(ptr + PTRSIZE) & mask))
+                   ) {
+                    ptr = argv[count] + strlen(argv[count]);
+                }
+            }
+        } else
+        {
+            /* sometimes the argv pointers go down in memory rather than up */
+            for (count = argc - 1; count > 0; count--) {
+                if (argv[count] == ptr + 1
+                    ||
+                    (aligned && argv[count] > ptr && argv[count] <= (char *)((UL)(ptr + PTRSIZE) & mask))
+                   ) {
+                    ptr = argv[count] + strlen(argv[count]);
+                }
+            }
         }
-        if (environ[0] == ptr + 1) {
-            for (count = 0; environ[count]; count++)
-                if (environ[count] == ptr + 1) {
-                   int fwd = strlen(++ptr);
-                   ptr += fwd; 
-               }
+        for (count = 0; environ[count]; count++) {
+            if (environ[count] == ptr + 1
+                ||
+                (aligned && environ[count] > ptr && environ[count] <= (char *)((UL)(ptr + PTRSIZE) & mask))
+               ) {
+                   ptr = environ[count] + strlen(environ[count]);
+            }
         }
         count = 0;
         for (ptr2 = argv[0]; ptr2 <= ptr; ptr2++) {
diff -Naur tomato/release/src/router/pptp-client/inststr.h tomato121/release/src/router/pptp-client/inststr.h
--- tomato/release/src/router/pptp-client/inststr.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/inststr.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,6 +1,6 @@
 /* inststr.h ..... change argv[0].
  *
- * $Id: inststr.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: inststr.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
  */
 
 void inststr(int argc, char **argv, char **envp, char *src);
diff -Naur tomato/release/src/router/pptp-client/Makefile tomato121/release/src/router/pptp-client/Makefile
--- tomato/release/src/router/pptp-client/Makefile	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/Makefile	2008-04-22 21:44:06.000000000 +1000
@@ -1,30 +1,36 @@
-VERSION = 1.1.0
-
-CT_SPEC = 1
+# $Id: Makefile,v 1.38 2005/03/10 01:18:20 quozl Exp $
+VERSION=1.7.0
+RELEASE=
 
 #################################################################
 # CHANGE THIS LINE to point to the location of your pppd binary.
 PPPD = /usr/sbin/pppd
 #################################################################
 
-#CROSS =mipsel-linux-
-#CC = $(CROSS)gcc -s
+BINDIR=$(DESTDIR)/usr/sbin
+MANDIR=$(DESTDIR)/usr/share/man/man8
+PPPDIR=$(DESTDIR)/etc/ppp
+
+#CC	= gcc
 RM	= rm -f
+OPTIMIZE= $(COPTS) -ffunction-sections -fdata-sections -Wl,--gc-sections
+
+#OPTIMIZE= -O0
 DEBUG	= -g
 INCLUDE =
-CFLAGS  = -Wall -O1 $(DEBUG) $(INCLUDE)	-I$(SRCBASE)/include
-LIBS	=
-#LDFLAGS	= -lutil
+CFLAGS  = -Wall $(OPTIMIZE) $(DEBUG) $(INCLUDE)
+LIBS	= -lutil -ffunction-sections -fdata-sections -Wl,--gc-sections
+LDFLAGS	=
 
 PPTP_BIN = pptp
 
 PPTP_OBJS = pptp.o pptp_gre.o ppp_fcs.o \
             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_callmgr.o
 
 PPTP_DEPS = pptp_callmgr.h pptp_gre.h ppp_fcs.h util.h \
-	    pptp_quirks.h orckit_quirks.h config.h pptp_options.h
+	    pptp_quirks.h orckit_quirks.h config.h pqueue.h
 
 all: config.h $(PPTP_BIN)
 
@@ -33,56 +39,52 @@
 
 config.h: 
 	echo "/* text added by Makefile target config.h */" > config.h
-	echo "#define PPTP_LINUX_VERSION \"$(VERSION)\"" >> config.h
+	echo "#define PPTP_LINUX_VERSION \"$(VERSION)$(RELEASE)\"" >> config.h
 	echo "#define PPPD_BINARY \"$(PPPD)\"" >> config.h
 
 vector_test: vector_test.o vector.o
 	$(CC) -o vector_test vector_test.o vector.o
 
 clean:
-	$(RM) *.o pptp
+	$(RM) *.o config.h
 
 clobber: clean
 	$(RM) $(PPTP_BIN) vector_test
 
 distclean: clobber
-	$(RM) pptp-linux-*.tar.gz
-	$(RM) -r pptp-linux-*
 
 test: vector_test
 
-dist: clobber
-	$(RM) pptp-linux-$(VERSION).tar.gz
-	$(RM) -r pptp-linux-$(VERSION)
-	mkdir pptp-linux-$(VERSION)
-	mkdir pptp-linux-$(VERSION)/Documentation
-	mkdir pptp-linux-$(VERSION)/Reference
-	cp \
-AUTHORS COPYING INSTALL Makefile NEWS README TODO USING		\
-dirutil.c dirutil.h inststr.c inststr.h ppp_fcs.c ppp_fcs.h	\
-pptp.c pptp_callmgr.c pptp_callmgr.h pptp_ctrl.c pptp_ctrl.h	\
-pptp_gre.c pptp_gre.h pptp_msg.h pptp_options.h			\
-util.c util.h vector.c vector.h vector_test.c	\
-version.c version.h \
-  pptp-linux-$(VERSION)
-	cp \
-Documentation/DESIGN.CALLMGR	\
-Documentation/DESIGN.PPTP	\
-Documentation/PORTING	\
-  pptp-linux-$(VERSION)/Documentation
-	cp \
-Reference/README	\
-Reference/ms-chap.txt	\
-Reference/pptp-draft.txt	\
-Reference/rfc1661.txt	\
-Reference/rfc1662.txt	\
-Reference/rfc1701.txt	\
-Reference/rfc1702.txt	\
-Reference/rfc1990.txt	\
-Reference/rfc791.txt	\
-Reference/rfc793.txt	\
-  pptp-linux-$(VERSION)/Reference
-	tar czf pptp-linux-$(VERSION).tar.gz pptp-linux-$(VERSION)
-	$(RM) -r pptp-linux-$(VERSION)
+install:
+	mkdir -p $(BINDIR)
+	install -o root -m 555 pptp $(BINDIR)
+	mkdir -p $(MANDIR)
+	install -m 644 pptp.8 $(MANDIR)
+	mkdir -p $(PPPDIR)
+	install -m 644 options.pptp $(PPPDIR)
+
+uninstall:
+	$(RM) $(BINDIR)/pptp $(MANDIR)/pptp.8
 
-pptp_ctrl.o: $(SRCBASE)/include/cyutils.h
+dist: clobber
+	$(RM) pptp-$(VERSION)$(RELEASE).tar.gz
+	$(RM) -r pptp-$(VERSION)
+	mkdir pptp-$(VERSION)
+	cp --recursive ChangeLog Makefile *.c *.h options.pptp pptp.8 \
+		Documentation Reference AUTHORS COPYING INSTALL NEWS \
+		README DEVELOPERS TODO USING \
+		pptp-$(VERSION)/
+	$(RM) -r pptp-$(VERSION)/CVS pptp-$(VERSION)/*/CVS
+	tar czf pptp-$(VERSION)$(RELEASE).tar.gz pptp-$(VERSION)
+	$(RM) -r pptp-$(VERSION)
+	md5sum pptp-$(VERSION)$(RELEASE).tar.gz
+
+deb:
+	chmod +x debian/rules 
+	fakeroot dpkg-buildpackage -us -uc
+	mv ../pptp_$(VERSION)-0_i386.deb .
+
+WEB=~/public_html/external/mine/pptp/pptpconfig
+release:
+	cp pptp_$(VERSION)-0_i386.deb $(WEB)
+	cd $(WEB);make
diff -Naur tomato/release/src/router/pptp-client/NEWS tomato121/release/src/router/pptp-client/NEWS
--- tomato/release/src/router/pptp-client/NEWS	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/NEWS	2008-04-22 21:44:06.000000000 +1000
@@ -1,4 +1,75 @@
-Release 1.1.0:
+Release 1.7.0: (27th July 2005)
+
+- silently discard packets not for the call [Cameron/Jenkins]
+- adopt sigpipe for use with SIGALRM on control connection [Wolter/Cameron]
+- fixes known valgrind heap violations in 1.6.0 [Cameron/Thorne]
+- properly report control connection echo reply loss [Wolter]
+
+Release 1.6.0: (18th February 2005)
+
+- fix double-free on stop control connection reply [Kivity]
+- add --idle-wait option [Cameron]
+- fix segfault on fatal connection error [Kivity]
+- prevent a possible signal race [Kivity]
+- prevent kill of init [Shurdeek]
+- portability fix for non-Linux systems [Quinot]
+- rename package from pptp-linux to pptp [Cameron]
+
+Release 1.5.0: (22nd June 2004)
+
+- fix statistics when buffering disabled [Wilson]
+- do not inherit the GRE socket [Cameron]
+- fix a case of non-shutdown of call manager [Klazes]
+- add --nobuffer option to eliminate all buffering of packets [Wilson]
+- fix corruption of command line as shown by ps [Howarth]
+- fix CPU loop after pppd killed [Cameron]
+- fix compile for ARM architecture [Hopf]
+- add documentation for command-line options [Wilson]
+- do not hang when a connection is refused [McCurdy]
+- better describe a cause of EMSGSIZE [Cameron]
+
+Release 1.4.0: (2nd January 2004)
+
+- support options before hostname [Wilson]
+- defer OCRQ until after SCCRP [Cameron]
+- include uninstall target [Pieter]
+- only issue a warning if sync mode is different to pppd [Klazes]
+- reformat and tidy code [Klazes]
+- reduce transmitted ack-only packets from 40% to 0.8% [Klazes]
+
+Release 1.3.1: (11th June 2003)
+
+- fixed bug introduced since 1.2.0 that prevented simultaneous tunnels.
+
+Release 1.3.0: (10th June 2003)
+
+- rewrite command usage text.
+- increase call disconnect notification log message verbosity.
+- inherit more make command line options.
+- remove execute permissions on man page.
+- fixed inefficient acknowledgement immediately followed by data packet.
+- added statistics for link quality monitoring.
+- remove include of callmgr, do separate compile.
+- remove duplicate messages caused by code in header file.
+- compilation fixes for Apple MacOS X.
+- support multiple clients on alias IP addresses.
+
+Release 1.2.0: (14th February 2003)
+
+- subsecond packet timeout to improve performance on fast links.
+- rewrite INSTALL.
+- add man page to install target.
+- fix response to dropped packets.
+- fix man page, address must be before options.
+- adopt man page contributed by Thomas Quinot.
+- close stderr to prevent holding open ssh sessions.
+- minor hint added in case of EIO on read() of pty.
+- support synchronous HDLC ppp encoding. Synchronous mode results in an
+  important improvement of the CPU efficiency.
+- 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: (20th March 2002)
 
 - New release engineer.
 - allow activation as a psuedo-tty child process from pppd.
@@ -11,7 +82,7 @@
 - integrated call manager into pptp binary.
 - many bugfixes improving stability.
 
-Release 1.0.3:
+Release 1.0.3: (7th May 2001)
 
 - New maintaining team.
 - Various bug fixes from the Debian package and FreeBSD port.
@@ -37,3 +108,4 @@
 
 - This is the first public release of the pptp-linux package.
 
+$Id: NEWS,v 1.44 2005/07/27 10:51:44 quozl Exp $	
diff -Naur tomato/release/src/router/pptp-client/options.pptp tomato121/release/src/router/pptp-client/options.pptp
--- tomato/release/src/router/pptp-client/options.pptp	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/options.pptp	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,49 @@
+###############################################################################
+# $Id: options.pptp,v 1.1 2005/02/18 01:40:23 quozl Exp $
+#
+# Sample PPTP PPP options file /etc/ppp/options.pptp
+# Options used by PPP when a connection is made by a PPTP client.
+# This file can be referred to by an /etc/ppp/peers file for the tunnel.
+# Changes are effective on the next connection.  See "man pppd".
+#
+# You are expected to change this file to suit your system.  As
+# packaged, it requires PPP 2.4.2 or later from http://ppp.samba.org/
+# and the kernel MPPE module available from the CVS repository also on
+# http://ppp.samba.org/, which is packaged for DKMS as kernel_ppp_mppe.
+###############################################################################
+
+# Lock the port
+lock
+
+# Authentication
+# We don't need the tunnel server to authenticate itself
+noauth
+
+# We won't do EAP, CHAP, or MSCHAP, but we will accept MSCHAP-V2
+refuse-eap
+refuse-chap
+refuse-mschap
+
+# Compression
+# Turn off compression protocols we know won't be used
+nobsdcomp
+nodeflate
+
+# Encryption
+# (There have been multiple versions of PPP with encryption support,
+# choose with of the following sections you will use.  Note that MPPE
+# requires the use of MSCHAP-V2 during authentication)
+
+# http://ppp.samba.org/ the PPP project version of PPP by Paul Mackarras
+# ppp-2.4.2 or later with MPPE only, kernel module ppp_mppe.o
+# {{{
+# Require MPPE 128-bit encryption
+require-mppe-128
+# }}}
+
+# http://polbox.com/h/hs001/ fork from PPP project by Jan Dubiec
+# ppp-2.4.2 or later with MPPE and MPPC, kernel module ppp_mppe_mppc.o
+# {{{
+# Require MPPE 128-bit encryption
+#mppe required,stateless
+# }}}
diff -Naur tomato/release/src/router/pptp-client/orckit_quirks.c tomato121/release/src/router/pptp-client/orckit_quirks.c
--- tomato/release/src/router/pptp-client/orckit_quirks.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/orckit_quirks.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* orckit_quirks.c ...... fix quirks in orckit adsl modems
  *                        mulix <mulix@actcom.co.il>
  *
- * $Id: orckit_quirks.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: orckit_quirks.c,v 1.3 2002/03/01 01:23:36 quozl Exp $
  */
 
 #include <string.h>
diff -Naur tomato/release/src/router/pptp-client/orckit_quirks.h tomato121/release/src/router/pptp-client/orckit_quirks.h
--- tomato/release/src/router/pptp-client/orckit_quirks.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/orckit_quirks.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* orckit_quirks.h ...... fix quirks in orckit adsl modems
  *                        mulix <mulix@actcom.co.il>
  *
- * $Id: orckit_quirks.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: orckit_quirks.h,v 1.2 2001/11/23 03:42:51 quozl Exp $
  */
 
 #ifndef INC_ORCKIT_QUIRKS_H_
diff -Naur tomato/release/src/router/pptp-client/ppp_fcs.c tomato121/release/src/router/pptp-client/ppp_fcs.c
--- tomato/release/src/router/pptp-client/ppp_fcs.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/ppp_fcs.c	2008-04-22 21:44:06.000000000 +1000
@@ -15,7 +15,7 @@
  *
  *  [9]   LeVan, J., "A Fast CRC", Byte, November 1987.
  *
- * $Id: ppp_fcs.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: ppp_fcs.c,v 1.2 2003/06/17 17:25:47 reink Exp $
  */
 
 #include <sys/types.h>
@@ -78,13 +78,16 @@
  * Calculate a new fcs given the current fcs and the new data.
  */
 u16 pppfcs16(u16 fcs, void *_cp, int len)
-{   register unsigned char *cp = (unsigned char *)_cp;
-
+{
+    register unsigned char *cp = (unsigned char *)_cp;
+    /* don't worry about the efficiency of these asserts here.  gcc will
+     * recognise that the asserted expressions are constant and remove them.
+     * Whether they are usefull is another question. 
+     */
     ASSERT(sizeof (u16) == 2);
     ASSERT(((u16) -1) > 0);
     while (len--)
         fcs = (fcs >> 8) ^ fcstab[(fcs ^ *cp++) & 0xff];
-
     return (fcs);
 }
 
diff -Naur tomato/release/src/router/pptp-client/ppp_fcs.h tomato121/release/src/router/pptp-client/ppp_fcs.h
--- tomato/release/src/router/pptp-client/ppp_fcs.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/ppp_fcs.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* ppp_fcs.h ... header file for PPP-HDLC FCS 
  *               C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: ppp_fcs.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: ppp_fcs.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
  */ 
 
 #define PPPINITFCS16    0xffff  /* Initial FCS value */
diff -Naur tomato/release/src/router/pptp-client/pptp.8 tomato121/release/src/router/pptp-client/pptp.8
--- tomato/release/src/router/pptp-client/pptp.8	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp.8	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,185 @@
+.\" SH section heading
+.\" SS subsection heading
+.\" LP paragraph
+.\" IP indented paragraph
+.\" TP hanging label
+.TH PPTP 8
+.\" NAME should be all caps, SECTION should be 1-8, maybe w/ subsection
+.\" other parms are allowed: see man(7), man(1)
+.SH NAME
+pptp \- PPTP driver
+.SH SYNOPSIS
+.B pptp
+.I "<pptp-server-IP> <pptp-options> [ppp-options] ..."
+.SH "DESCRIPTION"
+.LP
+.B pptp
+establishes the client side of a Virtual Private Network (VPN) using
+the Point-to-Point Tunneling Protocol (PPTP).  Use this program to
+connect to an employer's PPTP based VPN, or to certain cable and ADSL
+service providers.
+.LP
+By default, \fBpptp\fR establishes the PPTP call to the PPTP server,
+and then starts an instance of \fBpppd\fR to manage the data transfer.
+However, \fBpptp\fR can also be run as a connection manager within
+\fBpppd\fR.
+.SH OPTIONS
+.LP
+The first non-option argument on the \fBpptp\fR command line must be the host
+name or IP address of the PPTP server.
+.LP
+All long options (starting with "--")
+are interpreted as pptp options, and a fatal error occurs if an 
+unrecognised option is used.
+.LP
+All command-line arguments which do not start
+with "-" are interpreted as ppp options, and passed as is to \fBpppd\fR unless
+\fB--nolaunchpppd\fR is given.
+.TP
+.B \--phone <number>
+Pass <number> to remote host as phone number
+.TP
+.B \--nolaunchpppd
+Do not launch
+.B pppd
+but use stdin as the network connection.  Use this flag when including
+.B pptp
+as a
+.B pppd
+connection process using the
+.B pty
+option.  See EXAMPLES.
+.TP
+.B \--quirks <quirk>
+Work around a buggy PPTP implementation, adopts special case handling for
+particular PPTP servers and ADSL modems.
+Currently recognised values are BEZEQ_ISRAEL only
+.TP
+.B \--debug
+Run in foreground (for debugging with gdb)
+.TP
+.B \--sync
+Enable Synchronous HDLC (pppd must use it too)
+.TP
+.B \--timeout <secs>
+Time to wait for reordered packets (0.01 to 10 secs)
+.TP
+.B \--nobuffer
+Completely disables buffering and reordering of packets.
+Any --timeout specified will be ignored.
+.TP
+.B \--idle-wait <secs>
+Time to wait before sending a control connection echo request.
+The RFC2637 default is 60 seconds.
+.TP
+.B \--max-echo-wait <secs>
+Time to wait for an echo reply before closing the control connection.
+The RFC2637 default is 60 seconds.
+.TP
+.B \--logstring <name>
+Use <name> instead of 'anon' in syslog messages
+.TP
+.B \--localbind <addr>
+Bind to specified IP address instead of wildcard
+.TP
+.B \--loglevel <level>
+Sets the debugging level (0=low, 1=default, 2=high)
+
+.SH "QUIRKS"
+
+.TP
+.B BEZEQ_ISRAEL
+modifies packets to interoperate with Orckit ADSL modems on the BEZEQ
+network in Israel.
+
+.SH "EXAMPLES"
+
+.B Connection to a Microsoft Windows VPN Server
+
+.BR
+pppd noauth nobsdcomp nodeflate mppe-40 mppe-128
+mppe-stateless name domain\\\\\\\\username remotename PPTP
+require-chapms-v2
+pty "pptp 10.0.0.5 --nolaunchpppd"
+.PP
+Note that the \fBchap-secrets\fR file used by \fBpppd\fR must include an entry for domain\\\\username
+
+.SH "STATISTICS"
+The pptp process collects statistics when sending and receiving
+GRE packets. They are intended to be useful for debugging poor PPTP
+performance and for general monitoring of link quality. The statistics
+are cumulative since the pptp process was started.
+.PP
+The statistics can be viewed by sending a SIGUSR1 signal to the
+"GRE-to-PPP Gateway" process, which will cause it to dump them
+to the system logs (at the LOG_NOTICE level). A better way to present
+the statistics to applications is being sought (e.g. SNMP?).
+.PP
+The following statistics are collected at the time of writing (April 2003):
+.TP
+.B rx accepted
+the number of GRE packets successfully passed to PPP
+.TP
+.B rx lost
+the number of packets never received, and presumed lost in the network
+.TP
+.B rx under win
+the number of packets which were duplicates or had old sequence numbers
+(this might be caused by a packet-reordering network if your reordering
+timeout is set too low)
+.TP
+.B rx over win
+the number of packets which were too far ahead in the sequence to be
+reordered (might be caused by loss of more than 300 packets in a row)
+.TP
+.B rx buffered
+the number of packets which were slightly ahead of sequence, and were
+either buffered for reordering, or if buffering is disabled, accepted
+immediately (resulting in the intermediate packets being discarded).
+.TP
+.B rx OS errors
+the number of times where the operating system reported an error when
+we tried to read a packet
+.TP
+.B rx truncated
+the number of times we received a packet which was shorter than the
+length implied by the GRE header
+.TP
+.B rx invalid
+the number of times we received a packet which had invalid or unsupported
+flags set in the header, wrong version, or wrong protocol.
+.TP
+.B rx acks
+the number of pure acknowledgements received (without data). Too many
+of these will waste bandwidth, and might be solved by tuning the remote host.
+.TP
+.B tx sent
+the number of GRE packets sent with data
+.TP
+.B tx failed
+the number of packets we tried to send, but the OS reported an error
+.TP
+.B tx short
+the number of times the OS would not let us write a complete packet
+.TP
+.B tx acks
+the number of times we sent a pure ack, without data
+.TP
+.B tx oversize
+the number of times we couldn't send a packet because it was over
+PACKET_MAX bytes long
+.TP
+.B round trip
+the estimated round-trip time in milliseconds
+
+.SH "SEE ALSO"
+.IR pppd (8)
+.PP
+Documentation in
+.IR /usr/share/doc/pptp
+.SH AUTHOR
+This manual page was written by James Cameron
+<james.cameron@hp.com> from text contributed by Thomas Quinot
+<thomas@debian.org>, for the Debian GNU/Linux system.
+The description of the available statistics was written by Chris Wilson
+<chris@netservers.co.uk>.
diff -Naur tomato/release/src/router/pptp-client/pptp.c tomato121/release/src/router/pptp-client/pptp.c
--- tomato/release/src/router/pptp-client/pptp.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp.c	2008-04-22 21:44:06.000000000 +1000
@@ -2,21 +2,23 @@
  *            the pppd from the command line.
  *            C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp.c,v 1.2 2002/08/20 07:11:40 honor Exp $
+ * $Id: pptp.c,v 1.42 2004/11/09 21:56:46 quozl Exp $
  */
 
 #include <sys/types.h>
 #include <sys/socket.h>
 #if defined(__FreeBSD__)
 #include <libutil.h>
-#elif defined(__NetBSD__)
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#include <util.h>
+#elif defined(__APPLE__)
 #include <util.h>
 #else
 #include <pty.h>
 #endif
-//#ifdef USER_PPP
+#ifdef USER_PPP
 #include <fcntl.h>
-//#endif
+#endif
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <sys/un.h>
@@ -24,12 +26,18 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
+#include <syslog.h>
 #include <unistd.h>
 #include <signal.h>
 #include <setjmp.h>
 #include <errno.h>
 #include <sys/wait.h>
+#include <sys/param.h>
+#if defined(__APPLE__)
+#include "getopt.h"
+#else
 #include <getopt.h>
+#endif
 #include <limits.h>
 #include "config.h"
 #include "pptp_callmgr.h"
@@ -38,416 +46,464 @@
 #include "inststr.h"
 #include "util.h"
 #include "pptp_quirks.h"
+#include "pqueue.h"
+#include "pptp_options.h"
 
 #ifndef PPPD_BINARY
 #define PPPD_BINARY "pppd"
 #endif
 
+int syncppp = 0;
+int log_level = 1;
+int disable_buffer = 0;
+
 struct in_addr get_ip_address(char *name);
-int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp);
+int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp, int pty_fd, int gre_fd);
 void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,char **argv,char **envp);
 int get_call_id(int sock, pid_t gre, pid_t pppd, 
 		 u_int16_t *call_id, u_int16_t *peer_call_id);
 void launch_pppd(char *ttydev, int argc, char **argv);
 
-
-/* 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. */
-/* Create pseudo tty master slave pair and set terminal attributes
-   according to TERMP and WINP.  Return handles for both ends in
-   AMASTER and ASLAVE, and return the name of the slave end in NAME.  */
-
-/* from uClibc 0.9.9 openpty.c */
-int
-my_openpty (int *amaster, int *aslave, char *name, struct termios *termp,
-         struct winsize *winp)
+/*** print usage and exit *****************************************************/
+void usage(char *progname)
 {
-#if 0
-#ifdef PATH_MAX
-  char _buf[PATH_MAX];
-#else
-  char _buf[512];
-#endif
-  char *buf = _buf;
-#else
-#ifdef PATH_MAX
-  char buf[PATH_MAX];
-#else
-  char buf[512];
-#endif
-#endif
-  int master, slave;
-
-  master = getpt ();
-  if (master == -1)
-    return -1;
-
-  if (grantpt (master))
-    goto fail;
-
-  if (unlockpt (master))
-    goto fail;
-
-#if 0
-  if (pts_name (master, &buf, sizeof (_buf)))
-#else
-  if (ptsname_r (master, buf, sizeof buf))
-#endif
-    goto fail;
-
-  slave = open (buf, O_RDWR | O_NOCTTY);
-  if (slave == -1)
-    {
-#if 0
-      if (buf != _buf)
-        free (buf);
-#endif
-      goto fail;
-    }
-
-  /* XXX Should we ignore errors here?  */
-  if(termp)
-    tcsetattr (slave, TCSAFLUSH, termp);
-  if (winp)
-    ioctl (slave, TIOCSWINSZ, winp);
-
-  *amaster = master;
-  *aslave = slave;
-  if (name != NULL)
-    strcpy (name, buf);
-
-#if 0
-  if (buf != _buf)
-    free (buf);
-#endif
-  return 0;
-
- fail:
-  close (master);
-  return -1;
-}
-
-void usage(char *progname) {
-  fprintf(stderr,
-	  "%s\n"
-	  "Usage:\n"
-	  " %s hostname [[--phone <phone number>] [--quirks ISP_NAME] -- ][ pppd options]\n"
-	  "\nOr using pppd option pty: \n"
-	  " pty \" %s hostname --nolaunchpppd [--phone <phone number>] [--quirks ISP_NAME]\"\n"
-	  "Currently recognized ISP_NAMEs for quirks are BEZEQ_ISRAEL\n",
-	  version, progname, progname);
-  log("%s called with wrong arguments, program not started.", progname);
-  
-  exit(1);
+    printf(
+            "%s\n"
+            "Usage:\n"
+            "  %s <hostname> [<pptp options>] [[--] <pppd options>]\n"
+            "\n"
+            "Or using pppd's pty option: \n"
+            "  pppd pty \"%s <hostname> --nolaunchpppd <pptp options>\"\n"
+            "\n"
+            "Available pptp options:\n"
+            "  --phone <number>	Pass <number> to remote host as phone number\n"
+            "  --nolaunchpppd	Do not launch pppd, for use as a pppd pty\n"
+            "  --quirks <quirk>	Work around a buggy PPTP implementation\n"
+            "			Currently recognised values are BEZEQ_ISRAEL only\n"
+            "  --debug		Run in foreground (for debugging with gdb)\n"
+            "  --sync		Enable Synchronous HDLC (pppd must use it too)\n"
+            "  --timeout <secs>	Time to wait for reordered packets (0.01 to 10 secs)\n"
+	    "  --nobuffer		Disable packet buffering and reordering completely\n"
+	    "  --idle-wait		Time to wait before sending echo request\n"
+            "  --max-echo-wait		Time to wait before giving up on lack of reply\n"
+            "  --logstring <name>	Use <name> instead of 'anon' in syslog messages\n"
+            "  --localbind <addr>	Bind to specified IP address instead of wildcard\n"
+            "  --loglevel <level>	Sets the debugging level (0=low, 1=default, 2=high)\n",
+
+            version, progname, progname);
+    log("%s called with wrong arguments, program not started.", progname);
+    exit(1);
 }
 
+struct in_addr localbind = { INADDR_NONE };
 static int signaled = 0;
 
-void do_nothing(int sig) { 
+/*** do nothing signal handler ************************************************/
+void do_nothing(int sig)
+{ 
     /* do nothing signal handler. Better than SIG_IGN. */
-    signaled = 1;
+    signaled = sig;
 }
 
 sigjmp_buf env;
-void sighandler(int sig) {
-  siglongjmp(env, 1);
+
+/*** signal handler ***********************************************************/
+void sighandler(int sig)
+{
+    siglongjmp(env, 1);
+}
+
+/*** report statistics signal handler (SIGUSR1) *******************************/
+void sigstats(int sig)
+{
+    syslog(LOG_NOTICE, "GRE statistics:\n");
+#define LOG(name,value) syslog(LOG_NOTICE, name "\n", stats .value)
+    LOG("rx accepted  = %d", rx_accepted);
+    LOG("rx lost      = %d", rx_lost);
+    LOG("rx under win = %d", rx_underwin);
+    LOG("rx over  win = %d", rx_overwin);
+    LOG("rx buffered  = %d", rx_buffered);
+    LOG("rx OS errors = %d", rx_errors);
+    LOG("rx truncated = %d", rx_truncated);
+    LOG("rx invalid   = %d", rx_invalid);
+    LOG("rx acks      = %d", rx_acks);
+    LOG("tx sent      = %d", tx_sent);
+    LOG("tx failed    = %d", tx_failed);
+    LOG("tx short     = %d", tx_short);
+    LOG("tx acks      = %d", tx_acks);
+    LOG("tx oversize  = %d", tx_oversize);
+    LOG("round trip   = %d usecs", rtt);
+#undef LOG
 }
 
+/*** main *********************************************************************/
 /* 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)
+{
+    struct in_addr inetaddr;
+    volatile int callmgr_sock = -1;
+    char ttydev[PATH_MAX];
+    int pty_fd, tty_fd, gre_fd, rc;
+    volatile pid_t parent_pid, child_pid;
+    u_int16_t call_id, peer_call_id;
+    char buf[128];
+    int pppdargc;
+    char **pppdargv;
+    char phonenrbuf[65]; /* maximum length of field plus one for the trailing
+                          * '\0' */
+    char * volatile phonenr = NULL;
+    volatile int launchpppd = 1, debug = 0;
+
+    while(1){ 
+        /* structure with all recognised options for pptp */
+        static struct option long_options[] = {
+            {"phone", 1, 0, 0},  
+            {"nolaunchpppd", 0, 0, 0},  
+            {"quirks", 1, 0, 0},
+            {"debug", 0, 0, 0},
+            {"sync", 0, 0, 0},
+            {"timeout", 1, 0, 0},
+            {"logstring", 1, 0, 0},
+            {"localbind", 1, 0, 0},
+            {"loglevel", 1, 0, 0},
+	    {"nobuffer", 0, 0, 0},
+	    {"idle-wait", 1, 0, 0},
+	    {"max-echo-wait", 1, 0, 0},
+            {0, 0, 0, 0}
+        };
+        int option_index = 0;
+        int c;
+        c = getopt_long (argc, argv, "", long_options, &option_index);
+        if (c == -1) break;  /* no more options */
+        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]);
+                } else if (option_index == 3) {/* --debug */
+                    debug = 1;
+                } else if (option_index == 4) {/* --sync specified */
+                    syncppp = 1;
+                } else if (option_index == 5) {/* --timeout */
+                    float new_packet_timeout = atof(optarg);
+                    if (new_packet_timeout < 0.0099 ||
+                            new_packet_timeout > 10) {
+                        printf( "Packet timeout %s (%f) out of range: "
+                                "should be between 0.01 and 10 seconds\n",
+                                optarg, new_packet_timeout);
+                        log("Packet timeout %s (%f) out of range: should be"
+                                "between 0.01 and 10 seconds", optarg,
+                                new_packet_timeout);
+                        exit(2);
+                    } else {
+                        packet_timeout_usecs = new_packet_timeout * 1000000;
+                    }
+                } else if (option_index == 6) {/* --logstring */
+                    log_string = strdup(optarg);
+                } else if (option_index == 7) {/* --localbind */ 
+                    if (inet_pton(AF_INET, optarg, (void *) &localbind) < 1) {
+                        printf( "Local bind address %s invalid\n", 
+				optarg);
+                        log("Local bind address %s invalid\n", optarg);
+                        exit(2);
+                    }
+                } else if (option_index == 8) { /* --loglevel */
+                    log_level = atoi(optarg);
+                    if (log_level < 0 || log_level > 2)
+                        usage(argv[0]);
+                } else if (option_index == 9) { /* --nobuffer */
+		    disable_buffer = 1;
+                } else if (option_index == 10) { /* --idle-wait */
+                    int x = atoi(optarg);
+                    if (x < 0) {
+                        printf( "--idle-wait must not be negative\n");
+                        log("--idle-wait must not be negative\n");
+                        exit(2);
+                    } else {
+                        idle_wait = x;
+                    }
+                } else if (option_index == 11) { /* --max-echo-wait */
+                    int x = atoi(optarg);
+                    if (x < 0) {
+                        printf( "--max-echo-wait must not be negative\n");
+                        log("--max-echo-wait must not be negative\n");
+                        exit(2);
+                    } else {
+                        max_echo_wait = x;
+                    }
+		    printf( "--max-echo-wait ignored, not yet implemented\n");
+                }
+                break;
+            case '?': /* unrecognised option */
+                /* fall through */
+            default:
+		usage(argv[0]);
+        }
+        if (c == -1) break;  /* no more options for pptp */
+    }
 
-int main(int argc, char **argv, char **envp) {
-  struct in_addr inetaddr;
-  volatile int callmgr_sock = -1;
-  char ttydev[PATH_MAX];
-  int pty_fd, tty_fd, rc;
-  volatile pid_t parent_pid, child_pid;
-  u_int16_t call_id, peer_call_id;
-  int pppdargc;
-  char **pppdargv;
-  char phonenrbuf[65]; /* maximum length of field plus one for the trailing
-                        * '\0' */
-  char * volatile phonenr = NULL;
-  volatile int launchpppd = 1;
-  if (argc < 2)
-    usage(argv[0]);
-
-  /* Step 1a: Get IP address for the hostname in argv[1] */
-  inetaddr = get_ip_address(argv[1]);
-
-  /* step 1b: Find the ppp options, extract phone number */
-  argc--;
-  argv++;
-  while(1){ 
-      /* structure with all recognised options for pptp */
-      static struct option long_options[] = {
-          {"phone", 1, 0, 0},  
-          {"nolaunchpppd", 0, 0, 0},  
-	  {"quirks", 1, 0, 0},
-          {0, 0, 0, 0}
-      };
-      int option_index = 0;
-      int c;
-      opterr=0; /* suppress "unrecognised option" message, here
-                 * we assume that it is a pppd option */
-      c = getopt_long (argc, argv, "", long_options, &option_index);
-      if( c==-1) break;  /* no more options */
-      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]);
-            }
-            /* other pptp options come here */
-            break;
-        case '?': /* unrecognised option, treat it as the first pppd option */
-            /* fall through */
-        default:
-            c = -1;
-            break;
-      }
-      if( c==-1) break;  /* no more options for pptp */
+    /* at least one argument is required */
+    if (argc <= optind)
+        usage(argv[0]);
+
+    /* Get IP address for the hostname in argv[1] */
+    inetaddr = get_ip_address(argv[optind]);
+    optind++;
+
+    /* Find the ppp options, extract phone number */
+    pppdargc = argc - optind;
+    pppdargv = argv + optind;
+    log("The synchronous pptp option is %sactivated\n", syncppp ? "" : "NOT ");
+
+    /* 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.");
     }
-  pppdargc = argc - optind;
-  pppdargv = argv + optind;
+
+    /* Find an open pty/tty pair. */
+    if(launchpppd){
+        rc = openpty (&pty_fd, &tty_fd, ttydev, NULL, NULL);
+        if (rc < 0) { 
+            close(callmgr_sock); 
+            fatal("Could not find free pty.");
+        }
+
+        /* fork and wait. */
+        signal(SIGUSR1, do_nothing); /* don't die */
+        signal(SIGCHLD, do_nothing); /* don't ignore SIGCHLD */
+        parent_pid = getpid();
+        switch (child_pid = fork()) {
+            case -1:
+                fatal("Could not fork pppd process");
+            case 0: /* I'm the child! */
+                close (tty_fd);
+                signal(SIGUSR1, SIG_DFL);
+                child_pid = getpid();
+                break;
+            default: /* parent */
+                close (pty_fd);
+                /*
+                 * There is still a very small race condition here.  If a signal
+                 * occurs after signaled is checked but before pause is called,
+                 * things will hang.
+                 */
+                if (!signaled) {
+                    pause(); /* wait for the signal */
+                }
+ 
+                if (signaled == SIGCHLD)
+                    fatal("Child process died");
  
-  /* Step 3: Find an open pty/tty pair. */
-  if(launchpppd){
-      rc = my_openpty (&pty_fd, &tty_fd, ttydev, NULL, NULL);
-      if (rc < 0) { 
-          close(callmgr_sock); 
-          fatal("Could not find free pty.");
-      }
-  
-      /* Step 4: fork and wait. */
-      signal(SIGUSR1, do_nothing); /* don't die */
-      parent_pid = getpid();
-      switch (child_pid = fork()) {
-      case -1:
-        fatal("Could not fork pppd process");
-
-      case 0: /* I'm the child! */
-        close (tty_fd);
-        signal(SIGUSR1, SIG_DFL);
+                launch_pppd(ttydev, pppdargc, pppdargv); /* launch pppd */
+                perror("Error");
+                fatal("Could not launch pppd");
+        }
+    } else { /* ! launchpppd */
+        pty_fd = tty_fd = STDIN_FILENO;
+        /* close unused file descriptor, that is redirected to the pty */
+        close(STDOUT_FILENO);
         child_pid = getpid();
-        break;
-      default: /* parent */
-        close (pty_fd);
+        parent_pid = 0; /* don't kill pppd */
+    }
+
+    do {
         /*
-         * There is still a very small race condition here.  If a signal
-         * occurs after signaled is checked but before pause is called,
-         * things will hang.
+         * Open connection to call manager (Launch call manager if necessary.)
          */
-        if (!signaled) {
-            pause(); /* wait for the signal */
+        callmgr_sock = open_callmgr(inetaddr, phonenr, argc, argv, envp,
+		pty_fd, gre_fd);
+        /* Exchange PIDs, get call ID */
+    } while (get_call_id(callmgr_sock, parent_pid, child_pid, 
+                &call_id, &peer_call_id) < 0);
+
+    /* Send signal to wake up pppd task */
+    if (launchpppd) {
+        kill(parent_pid, SIGUSR1);
+        sleep(2);
+        /* become a daemon */
+        if (!debug && daemon(0, 0) != 0) {
+            perror("daemon");
         }
-        launch_pppd(ttydev, pppdargc, pppdargv); /* launch pppd */
-        perror("Error");
-        fatal("Could not launch pppd");
-      }
-  } else { /* ! launchpppd */
-      pty_fd=tty_fd=0;
-      child_pid=getpid();
-      parent_pid=0; /* don't kill pppd */
-  }
+    } else {
+        /* re-open stderr as /dev/null to release it */
+        file2fd("/dev/null", "wb", STDERR_FILENO);
+    }
 
-  do {
-    /*
-     * Step 2: Open connection to call manager
-     *         (Launch call manager if necessary.)
-     */
-    callmgr_sock = open_callmgr(inetaddr, phonenr, argc, argv, envp);
+    snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", 
+            ttyname(tty_fd));
+    inststr(argc, argv, envp, buf);
+    if (sigsetjmp(env, 1)!= 0) goto shutdown;
+
+    signal(SIGINT,  sighandler);
+    signal(SIGTERM, sighandler);
+    signal(SIGKILL, sighandler);
+    signal(SIGCHLD, sighandler);
+    signal(SIGUSR1, sigstats);
 
-  /* Step 5: Exchange PIDs, get call ID */
-  } while (get_call_id(callmgr_sock, parent_pid, child_pid, 
-	               &call_id, &peer_call_id) < 0);
-
-  /* Step 5b: Send signal to wake up pppd task */
-  if(launchpppd){
-      kill(parent_pid, SIGUSR1);
-      sleep(2);
-  }
- 
-  {
-    char buf[128];
-    snprintf(buf, sizeof(buf), "pptp: GRE-to-PPP gateway on %s", ttyname(tty_fd));
-    inststr(argc,argv,envp, buf);
-  }
-
-  if (sigsetjmp(env, 1)!=0) goto shutdown;
-  signal(SIGINT,  sighandler);
-  signal(SIGTERM, sighandler);
-  signal(SIGKILL, sighandler);
- 
-  /* Step 6: Do GRE copy until close. */
-  pptp_gre_copy(call_id, peer_call_id, pty_fd, inetaddr);
+    /* Do GRE copy until close. */
+    pptp_gre_copy(call_id, peer_call_id, pty_fd, gre_fd);
 
 shutdown:
-  /* on close, kill all. */
-  if(launchpppd)
-      kill(parent_pid, SIGTERM);
-  close(pty_fd);
-  close(callmgr_sock);
-  sleep(3);     /* give ctrl manager a chance to exit */
-  exit(0);
+    /* on close, kill all. */
+    if(launchpppd)
+        kill(parent_pid, SIGTERM);
+    close(pty_fd);
+    close(callmgr_sock);
+    exit(0);
 }
 
-struct in_addr get_ip_address(char *name) {
-  struct in_addr retval;
-  struct hostent *host = gethostbyname(name);
-  if (host==NULL) {
-    if (h_errno == HOST_NOT_FOUND)
-      fatal("gethostbyname: HOST NOT FOUND");
-    else if (h_errno == NO_ADDRESS)
-      fatal("gethostbyname: NO IP ADDRESS");
-    else
-      fatal("gethostbyname: name server error");
-  }
-  
-  if (host->h_addrtype != AF_INET)
-    fatal("Host has non-internet address");
-  
-  memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr));
-  return retval;
+/*** get the ipaddress coming from the command line ***************************/
+struct in_addr get_ip_address(char *name)
+{
+    struct in_addr retval;
+    struct hostent *host = gethostbyname(name);
+    if (host == NULL) {
+        if (h_errno == HOST_NOT_FOUND)
+            fatal("gethostbyname '%s': HOST NOT FOUND", name);
+        else if (h_errno == NO_ADDRESS)
+            fatal("gethostbyname '%s': NO IP ADDRESS", name);
+        else
+            fatal("gethostbyname '%s': name server error", name);
+    }
+    if (host->h_addrtype != AF_INET)
+        fatal("Host '%s' has non-internet address", name);
+    memcpy(&retval.s_addr, host->h_addr, sizeof(retval.s_addr));
+    return retval;
 }
 
-int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char **argv, char **envp)
+/*** start the call manager ***************************************************/
+int open_callmgr(struct in_addr inetaddr, char *phonenr, int argc, char **argv,
+        char **envp, int pty_fd, int gre_fd)
 {
-  /* Try to open unix domain socket to call manager. */
-  struct sockaddr_un where;
-  const int NUM_TRIES = 3;
-  int i, fd;
-  pid_t pid;
-  int status;
-
-  /* Open socket */
-  if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-    fatal("Could not create unix domain socket: %s", strerror(errno));
-  }
-
-  /* Make address */
-  where.sun_family = AF_UNIX;
-  snprintf(where.sun_path, sizeof(where.sun_path), 
-	   PPTP_SOCKET_PREFIX "%s", inet_ntoa(inetaddr));
-
-  for (i=0; i<NUM_TRIES; i++) {
-    if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) {
-      /* couldn't connect.  We'll have to launch this guy. */
-
-      unlink (where.sun_path);	
-
-      /* fork and launch call manager process */
-      switch (pid=fork()) {
-      case -1: /* failure */
-	  fatal("fork() to launch call manager failed.");
-      case 0: /* child */
-	  {
-	      close (fd);
-	      launch_callmgr(inetaddr, phonenr, argc,argv,envp);
-	  }
-      default: /* parent */
-	  waitpid(pid, &status, 0);
-	  if (status!=0)
-	      fatal("Call manager exited with error %d", status);
-	  break;
-      }
-      sleep(1);
+    /* Try to open unix domain socket to call manager. */
+    struct sockaddr_un where;
+    const int NUM_TRIES = 3;
+    int i, fd;
+    pid_t pid;
+    int status;
+    /* Open socket */
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        fatal("Could not create unix domain socket: %s", strerror(errno));
+    }
+    /* Make address */
+    callmgr_name_unixsock(&where, inetaddr, localbind);
+    for (i = 0; i < NUM_TRIES; i++) {
+        if (connect(fd, (struct sockaddr *) &where, sizeof(where)) < 0) {
+            /* couldn't connect.  We'll have to launch this guy. */
+
+            unlink (where.sun_path);	
+
+            /* fork and launch call manager process */
+            switch (pid = fork()) {
+                case -1: /* failure */
+                    fatal("fork() to launch call manager failed.");
+                case 0: /* child */
+                {
+                    close (fd);
+                    /* close the pty and gre in the call manager */
+                    close(pty_fd);
+                    close(gre_fd);
+                    launch_callmgr(inetaddr, phonenr, argc, argv, envp);
+                }
+                default: /* parent */
+                    waitpid(pid, &status, 0);
+                    if (status!= 0)
+                        fatal("Call manager exited with error %d", status);
+                    break;
+            }
+            sleep(1);
+        }
+        else return fd;
     }
-    else return fd;
-  }
-  close(fd);
-  fatal("Could not launch call manager after %d tries.", i);
-  return -1;   /* make gcc happy */
+    close(fd);
+    fatal("Could not launch call manager after %d tries.", i);
+    return -1;   /* make gcc happy */
 }
 
+/*** call the call manager main ***********************************************/
 void launch_callmgr(struct in_addr inetaddr, char *phonenr, int argc,
         char**argv,char**envp) 
 {
-      int callmgr_main(int argc, char**argv, char**envp);
       char *my_argv[3] = { argv[0], inet_ntoa(inetaddr), phonenr };
       char buf[128];
       snprintf(buf, sizeof(buf), "pptp: call manager for %s", my_argv[1]);
-      inststr(argc,argv,envp,buf);
+      inststr(argc, argv, envp, buf);
       exit(callmgr_main(3, my_argv, envp));
-      /*
-      const char *callmgr = PPTP_CALLMGR_BINARY;
-      execlp(callmgr, callmgr, inet_ntoa(inetaddr), NULL);
-      fatal("execlp() of call manager [%s] failed: %s", 
-	  callmgr, strerror(errno));
-      */
 }
 
+/*** exchange data with the call manager  *************************************/
 /* XXX need better error checking XXX */
 int get_call_id(int sock, pid_t gre, pid_t pppd, 
 		 u_int16_t *call_id, u_int16_t *peer_call_id)
 {
-  u_int16_t m_call_id, m_peer_call_id;
-  /* write pid's to socket */
-  /* don't bother with network byte order, because pid's are meaningless
-   * outside the local host.
-   */
-  int rc;
-  rc = write(sock, &gre, sizeof(gre));
-  if (rc != sizeof(gre))
-      return -1;
-  rc = write(sock, &pppd, sizeof(pppd));
-  if (rc != sizeof(pppd))
-      return -1;
-  rc = read(sock,  &m_call_id, sizeof(m_call_id));
-  if (rc != sizeof(m_call_id))
-      return -1;
-  rc = read(sock,  &m_peer_call_id, sizeof(m_peer_call_id));
-  if (rc != sizeof(m_peer_call_id))
-      return -1;
-  /*
-   * XXX FIX ME ... DO ERROR CHECKING & TIME-OUTS XXX
-   * (Rhialto: I am assuming for now that timeouts are not relevant
-   * here, because the read and write calls would return -1 (fail) when
-   * the peer goes away during the process. We know it is (or was)
-   * running because the connect() call succeeded.)
-   */
-  *call_id = m_call_id;
-  *peer_call_id = m_peer_call_id;
-
-  return 0;
+    u_int16_t m_call_id, m_peer_call_id;
+    /* write pid's to socket */
+    /* don't bother with network byte order, because pid's are meaningless
+     * outside the local host.
+     */
+    int rc;
+    rc = write(sock, &gre, sizeof(gre));
+    if (rc != sizeof(gre))
+        return -1;
+    rc = write(sock, &pppd, sizeof(pppd));
+    if (rc != sizeof(pppd))
+        return -1;
+    rc = read(sock,  &m_call_id, sizeof(m_call_id));
+    if (rc != sizeof(m_call_id))
+        return -1;
+    rc = read(sock,  &m_peer_call_id, sizeof(m_peer_call_id));
+    if (rc != sizeof(m_peer_call_id))
+        return -1;
+    /*
+     * XXX FIXME ... DO ERROR CHECKING & TIME-OUTS XXX
+     * (Rhialto: I am assuming for now that timeouts are not relevant
+     * here, because the read and write calls would return -1 (fail) when
+     * the peer goes away during the process. We know it is (or was)
+     * running because the connect() call succeeded.)
+     * (James: on the other hand, if the route to the peer goes away, we
+     * wouldn't get told by read() or write() for quite some time.)
+     */
+    *call_id = m_call_id;
+    *peer_call_id = m_peer_call_id;
+    return 0;
 }
 
-void launch_pppd(char *ttydev, int argc, char **argv) {
-  char *new_argv[argc+4]; /* XXX if not using GCC, hard code a limit here. */
-  int i = 0, j;
-
-  new_argv[i++] = PPPD_BINARY;
+/*** execvp pppd **************************************************************/
+void launch_pppd(char *ttydev, int argc, char **argv)
+{
+    char *new_argv[argc + 4];/* XXX if not using GCC, hard code a limit here. */
+    int i = 0, j;
+    new_argv[i++] = PPPD_BINARY;
 #ifdef USER_PPP
-  new_argv[i++] = "-direct";
-  /* ppp expects to have stdin connected to ttydev */
-  if ((j = open(ttydev, O_RDWR)) == -1)
-    fatal("Cannot open %s: %s", ttydev, strerror(errno));
-  if (dup2(j, 0) == -1)
-    fatal("dup2 failed: %s", strerror(errno));
-  close(j);
+    new_argv[i++] = "-direct";
+    /* ppp expects to have stdin connected to ttydev */
+    if ((j = open(ttydev, O_RDWR)) == -1)
+        fatal("Cannot open %s: %s", ttydev, strerror(errno));
+    if (dup2(j, 0) == -1)
+        fatal("dup2 failed: %s", strerror(errno));
+    close(j);
 #else
-  new_argv[i++] = ttydev;
-  new_argv[i++] = "38400";
+    new_argv[i++] = ttydev;
+    new_argv[i++] = "38400";
 #endif
-  for (j=0; j<argc; j++)
-    new_argv[i++] = argv[j];
-  new_argv[i] = NULL;
-  execvp(new_argv[0], new_argv);
+    for (j = 0; j < argc; j++)
+        new_argv[i++] = argv[j];
+    new_argv[i] = NULL;
+    execvp(new_argv[0], new_argv);
 }
 
-/*************** COMPILE call manager into same binary *********/
-#define main       callmgr_main
-#define sighandler callmgr_sighandler
-#define do_nothing callmgr_do_nothing
-#define env        callmgr_env
-#include "pptp_callmgr.c"
diff -Naur tomato/release/src/router/pptp-client/pptp_callmgr.c tomato121/release/src/router/pptp-client/pptp_callmgr.c
--- tomato/release/src/router/pptp-client/pptp_callmgr.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_callmgr.c	2008-04-22 21:44:06.000000000 +1000
@@ -2,7 +2,7 @@
  *                    Handles TCP port 1723 protocol.
  *                    C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_callmgr.c,v 1.2 2002/08/23 01:23:28 honor Exp $
+ * $Id: pptp_callmgr.c,v 1.20 2005/03/31 07:42:39 quozl Exp $
  */
 #include <signal.h>
 #include <sys/time.h>
@@ -25,418 +25,364 @@
 #include "dirutil.h"
 #include "vector.h"
 #include "util.h"
-#include <fcntl.h>
+
+extern struct in_addr localbind; /* from pptp.c */
 
 int open_inetsock(struct in_addr inetaddr);
 int open_unixsock(struct in_addr inetaddr);
 void close_inetsock(int fd, struct in_addr inetaddr);
 void close_unixsock(int fd, struct in_addr inetaddr);
 
-sigjmp_buf env;
+sigjmp_buf callmgr_env;
 
-void sighandler(int sig) {
-    siglongjmp (env, 1);
+void callmgr_sighandler(int sig) {
+    /* TODO: according to signal(2), siglongjmp() is unsafe used here */
+    siglongjmp (callmgr_env, 1);
 }
 
-void do_nothing(int sig) {
+void callmgr_do_nothing(int sig) {
     /* do nothing signal handler */
 }
 
 struct local_callinfo {
-  int unix_sock;
-  pid_t pid[2];
+    int unix_sock;
+    pid_t pid[2];
 };
 
 struct local_conninfo {
-  VECTOR * call_list;
-  fd_set * call_set;
+    VECTOR * call_list;
+    fd_set * call_set;
 };
 
-/* 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) {
-  struct local_callinfo *lci;
-  struct local_conninfo *conninfo;
-  u_int16_t call_id[2];
-
-  switch(state) {
-  case CALL_OPEN_DONE:
-    /* okey dokey.  This means that the call_id and peer_call_id are now
-     * valid, so lets send them on to our friends who requested this call.
-     */
-    lci = pptp_call_closure_get(conn, call); assert(lci != NULL);
-    pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);
-    write(lci->unix_sock, &call_id, sizeof(call_id));
-    /* Our duty to the fatherland is now complete. */
-    break;
-  case CALL_OPEN_FAIL:
-  case CALL_CLOSE_RQST:
-  case CALL_CLOSE_DONE:
-    /* don't need to do anything here, except make sure tables are sync'ed */
-    log("Closing connection");
-    conninfo = pptp_conn_closure_get(conn);
-    lci = pptp_call_closure_get(conn, call); 
-    assert(lci != NULL && conninfo != NULL);
-    if (vector_contains(conninfo->call_list, lci->unix_sock)) {
-      vector_remove(conninfo->call_list, lci->unix_sock);
-      close(lci->unix_sock);
-      FD_CLR(lci->unix_sock, conninfo->call_set);
-      if(lci->pid[0]) kill(lci->pid[0], SIGTERM);
-      if(lci->pid[1]) kill(lci->pid[1], SIGTERM);
-    }
-    break;
-  default:
-    log("Unhandled call callback state [%d].", (int) state);
-    break;
-  }
+void call_callback(PPTP_CONN *conn, PPTP_CALL *call, enum call_state state)
+{
+    struct local_callinfo *lci;
+    struct local_conninfo *conninfo;
+    u_int16_t call_id[2];
+    switch(state) {
+        case CALL_OPEN_DONE:
+            /* okey dokey.  This means that the call_id and peer_call_id are
+             * now valid, so lets send them on to our friends who requested
+             * this call.  */
+            lci = pptp_call_closure_get(conn, call); assert(lci != NULL);
+            pptp_call_get_ids(conn, call, &call_id[0], &call_id[1]);
+            write(lci->unix_sock, &call_id, sizeof(call_id));
+            /* Our duty to the fatherland is now complete. */
+            break;
+        case CALL_OPEN_FAIL:
+        case CALL_CLOSE_RQST:
+        case CALL_CLOSE_DONE:
+            /* don't need to do anything here, except make sure tables
+             * are sync'ed */
+            log("Closing connection (call state)");
+            conninfo = pptp_conn_closure_get(conn);
+            lci = pptp_call_closure_get(conn, call); 
+            assert(lci != NULL && conninfo != NULL);
+            if (vector_contains(conninfo->call_list, lci->unix_sock)) {
+                vector_remove(conninfo->call_list, lci->unix_sock);
+                close(lci->unix_sock);
+                FD_CLR(lci->unix_sock, conninfo->call_set);
+                if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
+                if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
+            }
+            break;
+        default:
+            log("Unhandled call callback state [%d].", (int) state);
+            break;
+    }
 }
 
-/* Call Manager */
-
-/* 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,    */
-/* the volatile qualifiers should be removed as well.                  */ 
-int main(int argc, char **argv, char **envp) {
-  struct in_addr inetaddr;
-  int inet_sock, unix_sock;
-  fd_set call_set;
-  PPTP_CONN * conn;
-  VECTOR * call_list;
-  int max_fd=0;
-  volatile int first=1;
-  int retval;
-  int i;
-  char * volatile phonenr;
-
-  /* Step 0: Check arguments */
-  if (argc < 2) 
-    fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv[0]);
-  phonenr = argc==3 ? argv[2] : NULL;
-  if (inet_aton(argv[1], &inetaddr)==0)
-    fatal("Invalid IP address: %s", argv[1]);
-
-  /* Step 1: Open sockets. */
-  if ((inet_sock = open_inetsock(inetaddr)) < 0)
-    fatal("Could not open control connection to %s", argv[1]);
-  if ((unix_sock = open_unixsock(inetaddr)) < 0)
-    fatal("Could not open unix socket for %s", argv[1]);
-
-  /* Step 1b: FORK and return status to calling process. */
-  switch (fork()) {
-  case 0: /* child. stick around. */
-    break;
-  case -1: /* failure.  Fatal. */
-    fatal("Could not fork.");
-  default: /* Parent. Return status to caller. */
-    exit(0);
-  }
-
-  /* Step 1c: Clean up unix socket on TERM */
-  if (sigsetjmp(env, 1)!=0)
-    goto cleanup;
-
-  signal(SIGINT, sighandler);
-  signal(SIGTERM, sighandler);
-
-  signal(SIGPIPE, do_nothing);
-  signal(SIGUSR1, do_nothing); /* signal state change; wake up accept */
-
-  /* Step 2: Open control connection and register callback */
-  if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {
-    close(unix_sock); close(inet_sock); fatal("Could not open connection.");
-  }
-
-  FD_ZERO(&call_set);
-  max_fd = unix_sock;
-  call_list = vector_create();
-  { 
-    struct local_conninfo *conninfo = malloc(sizeof(*conninfo));
-    if (conninfo==NULL) {
-      close(unix_sock); close(inet_sock); fatal("No memory.");
-    }
-    conninfo->call_list = call_list;
-    conninfo->call_set  = &call_set;
-    pptp_conn_closure_put(conn, conninfo);
-  }
-
-  if (sigsetjmp(env, 1)!=0) goto shutdown;
-
-  /* Step 3: Get FD_SETs */
-  do {
-    int rc;
-    fd_set read_set = call_set, write_set;
-    FD_ZERO (&write_set);
-    FD_SET (unix_sock, &read_set);
-    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
-
-    for (; max_fd > 0 ; max_fd--) {
-      if (FD_ISSET (max_fd, &read_set) ||
-          FD_ISSET (max_fd, &write_set))
-        break;
-    }
-
-    /* Step 4: Wait on INET or UNIX event */
-
-    if ((rc = select(max_fd+1, &read_set, &write_set, NULL, NULL)) <0)
-      /* a signal or somesuch. */
-      continue;
-
-    /* Step 5a: Handle INET events */
-    pptp_dispatch(conn, &read_set, &write_set);
-
-    /* Step 5b: Handle new connection to UNIX socket */
-    if (FD_ISSET(unix_sock, &read_set)) {
-      /* New call! */
-      struct sockaddr_un from;
-      int len = sizeof(from);
-      PPTP_CALL * call;
-      struct local_callinfo *lci;
-      int s;
-
-      /* Accept the socket */
-      FD_CLR (unix_sock, &read_set);
-      if ((s = accept(unix_sock, (struct sockaddr *) &from, &len))<0) {
-	warn("Socket not accepted: %s", strerror(errno));
-	goto skip_accept;
-      }
-      /* Allocate memory for local call information structure. */
-      if ((lci = malloc(sizeof(*lci))) == NULL) {
-	warn("Out of memory."); close(s); goto skip_accept;
-      }
-      lci->unix_sock = s;
-
-      /* Give the initiator time to write the PIDs while we open the call */
-      call = pptp_call_open(conn, call_callback, phonenr);
-      /* Read and store the associated pids */
-      read(s, &lci->pid[0], sizeof(lci->pid[0]));
-      read(s, &lci->pid[1], sizeof(lci->pid[1]));
-      /* associate the local information with the call */
-      pptp_call_closure_put(conn, call, (void *) lci);
-      /* The rest is done on callback. */
-      
-      /* Keep alive; wait for close */
-      retval = vector_insert(call_list, s, call); assert(retval);
-      if (s > max_fd) max_fd = s;
-      FD_SET(s, &call_set);
-      first = 0;
-    }
-  skip_accept:
-    /* Step 5c: Handle socket close */
-    for (i=0; i<max_fd+1; i++)
-      if (FD_ISSET(i, &read_set)) {
-	/* close it */
-	PPTP_CALL * call;
-	retval = vector_search(call_list, i, &call);
-	if (retval) {
-	  struct local_callinfo *lci = pptp_call_closure_get(conn, call);
-          log("Closing connection");
-	  if(lci->pid[0]) kill(lci->pid[0], SIGTERM);
-	  if(lci->pid[1]) kill(lci->pid[1], SIGTERM);
-	  free(lci);
-	  /* soft shutdown.  Callback will do hard shutdown later */
-	  pptp_call_close(conn, call);
-	  vector_remove(call_list, i);
+/******************************************************************************
+ * NOTE ABOUT 'VOLATILE':
+ * several variables here get a volatile qualifier to silence warnings
+ * from older (before 3.0) gccs. if the longjmp stuff is removed,
+ * the volatile qualifiers should be removed as well.
+ *****************************************************************************/
+
+/*** Call Manager *************************************************************/
+int callmgr_main(int argc, char **argv, char **envp)
+{
+    struct in_addr inetaddr;
+    int inet_sock, unix_sock;
+    fd_set call_set;
+    PPTP_CONN * conn;
+    VECTOR * call_list;
+    int max_fd = 0;
+    volatile int first = 1;
+    int retval;
+    int i;
+    char * volatile phonenr;
+    /* Step 0: Check arguments */
+    if (argc < 2) 
+        fatal("Usage: %s ip.add.ress.here [--phone <phone number>]", argv[0]);
+    phonenr = argc == 3 ? argv[2] : NULL;
+    if (inet_aton(argv[1], &inetaddr) == 0)
+        fatal("Invalid IP address: %s", argv[1]);
+    /* Step 1: Open sockets. */
+    if ((inet_sock = open_inetsock(inetaddr)) < 0)
+        fatal("Could not open control connection to %s", argv[1]);
+    if ((unix_sock = open_unixsock(inetaddr)) < 0)
+        fatal("Could not open unix socket for %s", argv[1]);
+    /* Step 1b: FORK and return status to calling process. */
+    switch (fork()) {
+        case 0: /* child. stick around. */
+            break;
+        case -1: /* failure.  Fatal. */
+            fatal("Could not fork.");
+        default: /* Parent. Return status to caller. */
+            exit(0);
+    }
+    /* re-open stderr as /dev/null to release it */
+    file2fd("/dev/null", "wb", STDERR_FILENO);
+    /* Step 1c: Clean up unix socket on TERM */
+    if (sigsetjmp(callmgr_env, 1) != 0)
+        goto cleanup;
+    signal(SIGINT, callmgr_sighandler);
+    signal(SIGTERM, callmgr_sighandler);
+    signal(SIGPIPE, callmgr_do_nothing);
+    signal(SIGUSR1, callmgr_do_nothing); /* signal state change
+                                            wake up accept */
+    /* Step 2: Open control connection and register callback */
+    if ((conn = pptp_conn_open(inet_sock, 1, NULL/* callback */)) == NULL) {
+        close(unix_sock); close(inet_sock); fatal("Could not open connection.");
+    }
+    FD_ZERO(&call_set);
+    call_list = vector_create();
+    { 
+        struct local_conninfo *conninfo = malloc(sizeof(*conninfo));
+        if (conninfo == NULL) {
+            close(unix_sock); close(inet_sock); fatal("No memory.");
+        }
+        conninfo->call_list = call_list;
+        conninfo->call_set  = &call_set;
+        pptp_conn_closure_put(conn, conninfo);
+    }
+    if (sigsetjmp(callmgr_env, 1) != 0) goto shutdown;
+    /* Step 3: Get FD_SETs */
+    max_fd = unix_sock;
+    do {
+        int rc;
+        fd_set read_set = call_set, write_set;
+        FD_ZERO (&write_set);
+        if (pptp_conn_established(conn)) {
+	  FD_SET (unix_sock, &read_set);
+	  if (unix_sock > max_fd) max_fd = unix_sock;
 	}
-	FD_CLR(i, &call_set);
-	close(i);
-      }
-  } while (vector_size(call_list)>0 || first);
-
+        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
+        for (; max_fd > 0 ; max_fd--) {
+            if (FD_ISSET (max_fd, &read_set) ||
+                    FD_ISSET (max_fd, &write_set))
+                break;
+        }
+        /* Step 4: Wait on INET or UNIX event */
+        if ((rc = select(max_fd + 1, &read_set, &write_set, NULL, NULL)) <0) {
+	  if (errno == EBADF) break;
+	  /* a signal or somesuch. */
+	  continue;
+	}
+        /* Step 5a: Handle INET events */
+        rc = pptp_dispatch(conn, &read_set, &write_set);
+	if (rc < 0)
+	    break;
+        /* Step 5b: Handle new connection to UNIX socket */
+        if (FD_ISSET(unix_sock, &read_set)) {
+            /* New call! */
+            struct sockaddr_un from;
+            int len = sizeof(from);
+            PPTP_CALL * call;
+            struct local_callinfo *lci;
+            int s;
+            /* Accept the socket */
+            FD_CLR (unix_sock, &read_set);
+            if ((s = accept(unix_sock, (struct sockaddr *) &from, &len)) < 0) {
+                warn("Socket not accepted: %s", strerror(errno));
+                goto skip_accept;
+            }
+            /* Allocate memory for local call information structure. */
+            if ((lci = malloc(sizeof(*lci))) == NULL) {
+                warn("Out of memory."); close(s); goto skip_accept;
+            }
+            lci->unix_sock = s;
+            /* Give the initiator time to write the PIDs while we open
+             * the call */
+            call = pptp_call_open(conn, call_callback, phonenr);
+            /* Read and store the associated pids */
+            read(s, &lci->pid[0], sizeof(lci->pid[0]));
+            read(s, &lci->pid[1], sizeof(lci->pid[1]));
+            /* associate the local information with the call */
+            pptp_call_closure_put(conn, call, (void *) lci);
+            /* The rest is done on callback. */
+            /* Keep alive; wait for close */
+            retval = vector_insert(call_list, s, call); assert(retval);
+            if (s > max_fd) max_fd = s;
+            FD_SET(s, &call_set);
+            first = 0;
+        }
+skip_accept: /* Step 5c: Handle socket close */
+        for (i = 0; i < max_fd + 1; i++)
+            if (FD_ISSET(i, &read_set)) {
+                /* close it */
+                PPTP_CALL * call;
+                retval = vector_search(call_list, i, &call);
+                if (retval) {
+                    struct local_callinfo *lci =
+                        pptp_call_closure_get(conn, call);
+                    log("Closing connection (unhandled)");
+                    if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
+                    if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
+                    free(lci);
+                    /* soft shutdown.  Callback will do hard shutdown later */
+                    pptp_call_close(conn, call);
+                    vector_remove(call_list, i);
+                }
+                FD_CLR(i, &call_set);
+                close(i);
+            }
+    } while (vector_size(call_list) > 0 || first);
 shutdown:
-  {
-    fd_set read_set, write_set;
-
-    /* warn("Shutdown"); */
-    /* kill all open calls */
-    for (i=0; i<vector_size(call_list); i++) {
-      PPTP_CALL *call = vector_get_Nth(call_list, i);
-      struct local_callinfo *lci = pptp_call_closure_get(conn, call);
-      log("Closing connection");
-      pptp_call_close(conn, call);
-      if(lci->pid[0]) kill(lci->pid[0], SIGTERM);
-      if(lci->pid[1]) kill(lci->pid[1], SIGTERM);
-    }
-    /* attempt to dispatch these messages */
-    FD_ZERO(&read_set);
-    FD_ZERO(&write_set);
-    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
-    FD_ZERO(&read_set);
-    pptp_dispatch(conn, &read_set, &write_set);
-    if (i>0) sleep(2);
-    /* no more open calls.  Close the connection. */
-    pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);
-    FD_ZERO(&read_set);
-    FD_ZERO(&write_set);
-    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
-    FD_ZERO(&read_set);
-    pptp_dispatch(conn, &read_set, &write_set);
-    sleep(2);
-    /* with extreme prejudice */
-    pptp_conn_destroy(conn);
-    vector_destroy(call_list);
-  }
+    {
+        int rc;
+        fd_set read_set, write_set;
+        struct timeval tv;
+	signal(SIGINT, callmgr_do_nothing);
+	signal(SIGTERM, callmgr_do_nothing);
+        /* warn("Shutdown"); */
+        /* kill all open calls */
+        for (i = 0; i < vector_size(call_list); i++) {
+            PPTP_CALL *call = vector_get_Nth(call_list, i);
+            struct local_callinfo *lci = pptp_call_closure_get(conn, call);
+            log("Closing connection (shutdown)");
+            pptp_call_close(conn, call);
+            if(lci->pid[0] > 1) kill(lci->pid[0], SIGTERM);
+            if(lci->pid[1] > 1) kill(lci->pid[1], SIGTERM);
+        }
+        /* attempt to dispatch these messages */
+        FD_ZERO(&read_set);
+        FD_ZERO(&write_set);
+        pptp_fd_set(conn, &read_set, &write_set, &max_fd);
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	select(max_fd + 1, &read_set, &write_set, NULL, &tv);
+        rc = pptp_dispatch(conn, &read_set, &write_set);
+	if (rc > 0) {
+	  /* wait for a respond, a timeout because there might not be one */ 
+	  FD_ZERO(&read_set);
+	  FD_ZERO(&write_set);
+	  pptp_fd_set(conn, &read_set, &write_set, &max_fd);
+	  tv.tv_sec = 2;
+	  tv.tv_usec = 0;
+	  select(max_fd + 1, &read_set, &write_set, NULL, &tv);
+	  rc = pptp_dispatch(conn, &read_set, &write_set);
+	  if (rc > 0) {
+	    if (i > 0) sleep(2);
+	    /* no more open calls.  Close the connection. */
+	    pptp_conn_close(conn, PPTP_STOP_LOCAL_SHUTDOWN);
+	    /* wait for a respond, a timeout because there might not be one */ 
+	    FD_ZERO(&read_set);
+	    FD_ZERO(&write_set);
+	    pptp_fd_set(conn, &read_set, &write_set, &max_fd);
+	    tv.tv_sec = 2;
+	    tv.tv_usec = 0;
+	    select(max_fd + 1, &read_set, &write_set, NULL, &tv);
+	    pptp_dispatch(conn, &read_set, &write_set);
+	    if (rc > 0) sleep(2);
+	  }
+	}
+        /* with extreme prejudice */
+        pptp_conn_destroy(conn);
+        vector_destroy(call_list);
+    }
 cleanup:
-  close_inetsock(inet_sock, inetaddr);
-  close_unixsock(unix_sock, inetaddr);
-  return 0;
+    signal(SIGINT, callmgr_do_nothing);
+    signal(SIGTERM, callmgr_do_nothing);
+    close_inetsock(inet_sock, inetaddr);
+    close_unixsock(unix_sock, inetaddr);
+    return 0;
 }
 
-/**
- * Connect socket, but with a timeout.
- * A signal will interrupt this function.
- *
- * param: msec is the timeout in milliseconds
- * return: -1 on error, errno is set
- *         -2 on timeout
- *          0 on successful
- */
-int connect_timeout(int socket, struct sockaddr *addr, socklen_t len, int msec) 
-{ 
-  int oldflags; /* flags to be restored later */ 
-  int newflags; /* nonblocking sockopt for socket */ 
-  int ret;      /* Result of syscalls */ 
-  int value;    /* Value to be returned */ 
- 
-  /* Make sure the socket is nonblocking */ 
-  oldflags = fcntl(socket, F_GETFL, 0); 
-  if(oldflags == -1) 
-    return -1; 
-  newflags = oldflags | O_NONBLOCK; 
-  ret = fcntl(socket, F_SETFL, newflags); 
-  if(ret == -1) 
-    return -1; 
- 
-  /* Issue the connect request */ 
-  ret = connect(socket, addr, len); 
-  value = ret; 
- 
-  if(ret == 0) 
-  { 
-    /* Connect finished directly */ 
-  } 
-  else if(errno == EINPROGRESS || errno == EWOULDBLOCK) 
-  { 
-    fd_set wset; 
-    struct timeval tv; 
- 
-    FD_ZERO(&wset); 
-    FD_SET(socket, &wset); 
- 
-    tv.tv_sec = msec / 1000; 
-    tv.tv_usec = 1000*(msec % 1000); 
- 
-    ret = select(socket+1, NULL, &wset, NULL, &tv); 
- 
-    if(ret == 1 && FD_ISSET(socket, &wset)) 
-    { 
-      int optval; 
-      socklen_t optlen = sizeof(optval); 
- 
-      ret = getsockopt(socket, SOL_SOCKET, SO_ERROR, &optval, &optlen); 
-      if(ret == -1) 
-        return -1; 
- 
-      if(optval==0) 
-        value = 0; 
-      else 
-        value = -1; 
-    } 
-    else if(ret == 0) {
-	warn("connect timeout for %d seconds",msec / 1000);
-        value = -2; /* select timeout */ 
-    }
-    else {
-	warn("select error");
-      	value = -1; /* select error */ 
-    }
-  } 
-  else 
-    value = -1; 
- 
-  /* Restore the socket flags */ 
-  ret = fcntl(socket, F_SETFL, oldflags); 
-  if(ret == -1) 
-    perror("restoring socket flags: fcntl"); 
- 
-  return value; 
-} 
-
-int open_inetsock(struct in_addr inetaddr) {
-  struct sockaddr_in dest;
-  int s;
-
-  dest.sin_family = AF_INET;
-  dest.sin_port   = htons(PPTP_PORT);
-  dest.sin_addr   = inetaddr;
-
-  if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-    warn("socket: %s", strerror(errno));
+/*** open_inetsock ************************************************************/
+int open_inetsock(struct in_addr inetaddr)
+{
+    struct sockaddr_in dest, src;
+    int s;
+    dest.sin_family = AF_INET;
+    dest.sin_port   = htons(PPTP_PORT);
+    dest.sin_addr   = inetaddr;
+    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+        warn("socket: %s", strerror(errno));
+        return s;
+    }
+    if (localbind.s_addr != INADDR_NONE) {
+        bzero(&src, sizeof(src));
+        src.sin_family = AF_INET;
+        src.sin_addr   = localbind;
+        if (bind(s, (struct sockaddr *) &src, sizeof(src)) != 0) {
+            warn("bind: %s", strerror(errno));
+            close(s); return -1;
+        }
+    }
+    if (connect(s, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
+        warn("connect: %s", strerror(errno));
+        close(s); return -1;
+    }
     return s;
-  }
-  if (connect_timeout(s, (struct sockaddr *) &dest, sizeof(dest), 15000) < 0) {
-    warn("connect: %s", strerror(errno));
-    close(s); return -1;
-  }
-  return s;
 }
-int open_unixsock(struct in_addr inetaddr) {
-  struct sockaddr_un where;
-  struct stat st;
-  char *dir;
-  int s;
 
-  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
-    warn("socket: %s", strerror(errno));
+/*** open_unixsock ************************************************************/
+int open_unixsock(struct in_addr inetaddr)
+{
+    struct sockaddr_un where;
+    struct stat st;
+    char *dir;
+    int s;
+    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        warn("socket: %s", strerror(errno));
+        return s;
+    }
+    callmgr_name_unixsock( &where, inetaddr, localbind);
+    if (stat(where.sun_path, &st) >= 0) {
+        warn("Call manager for %s is already running.", inet_ntoa(inetaddr));
+        close(s); return -1;
+    }
+    /* Make sure path is valid. */
+    dir = dirname(where.sun_path);
+    if (!make_valid_path(dir, 0770))
+        fatal("Could not make path to %s: %s", where.sun_path, strerror(errno));
+    free(dir);
+    if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) {
+        warn("bind: %s", strerror(errno));
+        close(s); return -1;
+    }
+    chmod(where.sun_path, 0777);
+    listen(s, 127);
     return s;
-  }
-
-  where.sun_family = AF_UNIX;
-  snprintf(where.sun_path, sizeof(where.sun_path), 
-	   PPTP_SOCKET_PREFIX "%s", inet_ntoa(inetaddr));
-
-  if (stat(where.sun_path, &st) >= 0) {
-    warn("Call manager for %s is already running.", inet_ntoa(inetaddr));
-    close(s); return -1;
-  }
-
-  /* Make sure path is valid. */
-  dir = dirname(where.sun_path);
-  if (!make_valid_path(dir, 0770))
-    fatal("Could not make path to %s: %s", where.sun_path, strerror(errno));
-  free(dir);
-
-  if (bind(s, (struct sockaddr *) &where, sizeof(where)) < 0) {
-    warn("bind: %s", strerror(errno));
-    close(s); return -1;
-  }
-
-  chmod(where.sun_path, 0777);
-
-  listen(s, 127);
+}
 
-  return s;
+/*** close_inetsock ***********************************************************/
+void close_inetsock(int fd, struct in_addr inetaddr)
+{
+    close(fd);
 }
-void close_inetsock(int fd, struct in_addr inetaddr) {
-  close(fd);
+
+/*** close_unixsock ***********************************************************/
+void close_unixsock(int fd, struct in_addr inetaddr)
+{
+    struct sockaddr_un where;
+    close(fd);
+    callmgr_name_unixsock(&where, inetaddr, localbind);
+    unlink(where.sun_path);
 }
-void close_unixsock(int fd, struct in_addr inetaddr) {
-  struct sockaddr_un where;
-  close(fd);
-  snprintf(where.sun_path, sizeof(where.sun_path), 
-	   PPTP_SOCKET_PREFIX "%s", inet_ntoa(inetaddr));
-  unlink(where.sun_path);
+
+/*** make a unix socket address ***********************************************/
+void callmgr_name_unixsock(struct sockaddr_un *where, 
+			   struct in_addr inetaddr,
+			   struct in_addr localbind)
+{
+    char localaddr[16], remoteaddr[16];
+    where->sun_family = AF_UNIX;
+    strncpy(localaddr,  inet_ntoa(localbind), 16);
+    strncpy(remoteaddr, inet_ntoa(inetaddr),  16);
+    snprintf(where->sun_path, sizeof(where->sun_path),
+            PPTP_SOCKET_PREFIX "%s:%s", localaddr, remoteaddr);
 }
diff -Naur tomato/release/src/router/pptp-client/pptp_callmgr.h tomato121/release/src/router/pptp-client/pptp_callmgr.h
--- tomato/release/src/router/pptp-client/pptp_callmgr.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_callmgr.h	2008-04-22 21:44:06.000000000 +1000
@@ -2,8 +2,12 @@
  *                    Handles TCP port 1723 protocol.
  *                    C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_callmgr.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_callmgr.h,v 1.3 2003/02/17 00:22:17 quozl Exp $
  */
 
 #define PPTP_SOCKET_PREFIX "/var/run/pptp/"
-#define PPTP_CALLMGR_BINARY "./pptp_callmgr"
+
+int callmgr_main(int argc, char**argv, char**envp);
+void callmgr_name_unixsock(struct sockaddr_un *where,
+			   struct in_addr inetaddr,
+			   struct in_addr localbind);
diff -Naur tomato/release/src/router/pptp-client/pptp_ctrl.c tomato121/release/src/router/pptp-client/pptp_ctrl.c
--- tomato/release/src/router/pptp-client/pptp_ctrl.c	2006-10-17 14:27:29.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_ctrl.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* pptp_ctrl.c ... handle PPTP control connection.
  *                 C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_ctrl.c,v 1.2 2004/07/27 09:17:58 honor Exp $
+ * $Id: pptp_ctrl.c,v 1.31 2005/03/31 07:42:39 quozl Exp $
  */
 
 #include <errno.h>
@@ -43,890 +43,1036 @@
  *  (linux-threads v0.6, linux kernel 2.1.72), it does not.]
  */
 
-/* add by zg 2006.09.16
- * fix cdrouter3.3 item 28(cdrouter_pptp_30) bug
- */
-u_int8_t PPTP_CALL_CLEAR_RQST_FLAG=0;
+/* Globals */
+
+/* control the number of times echo packets will be logged */
+static int nlogecho = 10;
 
 static struct thread_specific {
-  struct sigaction old_sigaction; /* evil signals */
-  PPTP_CONN * conn;
+    struct sigaction old_sigaction; /* evil signals */
+    PPTP_CONN * conn;
 } global;
 
 #define INITIAL_BUFSIZE 512 /* initial i/o buffer size. */
 
 struct PPTP_CONN {
-  int inet_sock;
-  
-  /* Connection States */
-  enum { 
-    CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED 
-  } conn_state; /* on startup: CONN_IDLE */
-  /* Keep-alive states */
-  enum { 
-    KA_NONE, KA_OUTSTANDING 
-  } ka_state;  /* on startup: KA_NONE */
-  /* Keep-alive ID; monotonically increasing (watch wrap-around!) */
-  u_int32_t ka_id; /* on startup: 1 */
-
-  /* Other properties. */
-  u_int16_t version;
-  u_int16_t firmware_rev;
-  u_int8_t  hostname[64], vendor[64];
-  /* XXX these are only PNS properties, currently XXX */
-
-  /* Call assignment information. */
-  u_int16_t call_serial_number;
-
-  VECTOR *call;
-
-  void * closure;
-  pptp_conn_cb callback;
-
-  /******* IO buffers ******/
-  char * read_buffer, *write_buffer;
-  size_t read_alloc,   write_alloc;
-  size_t read_size,    write_size;
+    int inet_sock;
+    /* Connection States */
+    enum { 
+        CONN_IDLE, CONN_WAIT_CTL_REPLY, CONN_WAIT_STOP_REPLY, CONN_ESTABLISHED 
+    } conn_state; /* on startup: CONN_IDLE */
+    /* Keep-alive states */
+    enum { 
+        KA_NONE, KA_OUTSTANDING 
+    } ka_state;  /* on startup: KA_NONE */
+    /* Keep-alive ID; monotonically increasing (watch wrap-around!) */
+    u_int32_t ka_id; /* on startup: 1 */
+    /* Other properties. */
+    u_int16_t version;
+    u_int16_t firmware_rev;
+    u_int8_t  hostname[64], vendor[64];
+    /* XXX these are only PNS properties, currently XXX */
+    /* Call assignment information. */
+    u_int16_t call_serial_number;
+    VECTOR *call;
+    void * closure;
+    pptp_conn_cb callback;
+    /******* IO buffers ******/
+    char * read_buffer, *write_buffer;
+    size_t read_alloc,   write_alloc;
+    size_t read_size,    write_size;
 };
 
 struct PPTP_CALL {
-  /* Call properties */
-  enum {
-    PPTP_CALL_PAC, PPTP_CALL_PNS
-  } call_type;
-  union { 
-    enum pptp_pac_state {
-      PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS
-    } pac;
-    enum pptp_pns_state {
-      PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT 
-    } pns;
-  } state;
-  u_int16_t call_id, peer_call_id;
-  u_int16_t sernum;
-  u_int32_t speed;
-
-  /* For user data: */
-  pptp_call_cb callback;
-  void * closure;
+    /* Call properties */
+    enum {
+        PPTP_CALL_PAC, PPTP_CALL_PNS
+    } call_type;
+    union { 
+        enum pptp_pac_state {
+            PAC_IDLE, PAC_WAIT_REPLY, PAC_ESTABLISHED, PAC_WAIT_CS_ANS
+        } pac;
+        enum pptp_pns_state {
+            PNS_IDLE, PNS_WAIT_REPLY, PNS_ESTABLISHED, PNS_WAIT_DISCONNECT 
+        } pns;
+    } state;
+    u_int16_t call_id, peer_call_id;
+    u_int16_t sernum;
+    u_int32_t speed;
+    /* For user data: */
+    pptp_call_cb callback;
+    void * closure;
+};
+
+
+/* PPTP error codes: ----------------------------------------------*/
+
+/* (General Error Codes) */
+static const struct {
+    const char *name, *desc;
+} pptp_general_errors[] = {
+#define PPTP_GENERAL_ERROR_NONE                 0
+    { "(None)", "No general error" },
+#define PPTP_GENERAL_ERROR_NOT_CONNECTED        1
+    { "(Not-Connected)", "No control connection exists yet for this "
+        "PAC-PNS pair" },
+#define PPTP_GENERAL_ERROR_BAD_FORMAT           2
+    { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" },
+#define PPTP_GENERAL_ERROR_BAD_VALUE            3
+    { "(Bad-Value)", "One of the field values was out of range or "
+            "reserved field was non-zero" },
+#define PPTP_GENERAL_ERROR_NO_RESOURCE          4
+    { "(No-Resource)", "Insufficient resources to handle this command now" },
+#define PPTP_GENERAL_ERROR_BAD_CALLID           5
+    { "(Bad-Call ID)", "The Call ID is invalid in this context" },
+#define PPTP_GENERAL_ERROR_PAC_ERROR            6
+    { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" }
 };
 
+#define  MAX_GENERAL_ERROR ( sizeof(pptp_general_errors) / \
+        sizeof(pptp_general_errors[0]) - 1)
+
+/* Outgoing Call Reply Result Codes */
+static const char *pptp_out_call_reply_result[] = {
+/* 0 */	"Unknown Result Code",
+/* 1 */	"Connected",
+/* 2 */	"General Error",
+/* 3 */	"No Carrier Detected",
+/* 4 */	"Busy Signal",
+/* 5 */	"No Dial Tone",
+/* 6 */	"Time Out",
+/* 7 */	"Not Accepted, Call is administratively prohibited" };
+
+#define MAX_OUT_CALL_REPLY_RESULT 7
+
+/* Call Disconnect Notify  Result Codes */
+static const char *pptp_call_disc_ntfy[] = {
+/* 0 */	"Unknown Result Code",
+/* 1 */	"Lost Carrier",
+/* 2 */	"General Error",
+/* 3 */	"Administrative Shutdown",
+/* 4 */	"(your) Request" };
+
+#define MAX_CALL_DISC_NTFY 4
+
+/* Call Disconnect Notify  Result Codes */
+static const char *pptp_start_ctrl_conn_rply[] = {
+/* 0 */	"Unknown Result Code",
+/* 1 */	"Successful Channel Establishment",
+/* 2 */	"General Error",
+/* 3 */	"Command Channel Already Exists",
+/* 4 */	"Requester is not Authorized" };
+
+#define MAX_START_CTRL_CONN_REPLY 4
+
+/* timing options */
+int idle_wait = PPTP_TIMEOUT;
+int max_echo_wait = PPTP_TIMEOUT;
+
 /* Local prototypes */
 static void pptp_reset_timer(void);
-static void pptp_handle_timer(int sig);
+static void pptp_handle_timer();
 /* Write/read as much as we can without blocking. */
-void pptp_write_some(PPTP_CONN * conn);
-void pptp_read_some(PPTP_CONN * conn);
+int pptp_write_some(PPTP_CONN * conn);
+int pptp_read_some(PPTP_CONN * conn);
 /* Make valid packets from read_buffer */
 int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size);
 /* Add packet to write_buffer */
 int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
 /* Dispatch packets (general) */
-void pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
+int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size);
 /* Dispatch packets (control messages) */
-void pptp_dispatch_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size);
+int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size);
 /* Set link info, for pptp servers that need it.
    this is a noop, unless the user specified a quirk and
    there's a set_link hook defined in the quirks table
    for that quirk */
 void pptp_set_link(PPTP_CONN * conn, int peer_call_id);
-/*----------------------------------------------------------------------*/
-/* Constructors and Destructors.                                        */
 
-/* Open new pptp_connection.  Returns NULL on failure. */
-PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
+/*** log error information in control packets *********************************/
+static void ctrlp_error( int result, int error, int cause,
+        const char *result_text[], int max_result)
 {
-  struct sigaction sigact;
-  PPTP_CONN *conn;
-  /* Allocate structure */
-  if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
-  if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
-  /* Initialize */
-  conn->inet_sock = inet_sock;
-  conn->conn_state= CONN_IDLE;
-  conn->ka_state  = KA_NONE;
-  conn->ka_id     = 1;
-  conn->call_serial_number = 0;
-  conn->callback  = callback;
-  /* Create I/O buffers */
-  conn->read_size = conn->write_size = 0;
-  conn->read_alloc= conn->write_alloc= INITIAL_BUFSIZE;
-  conn->read_buffer = malloc(sizeof(*(conn->read_buffer))*conn->read_alloc);
-  conn->write_buffer= malloc(sizeof(*(conn->write_buffer))*conn->write_alloc);
-  if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
-    if (conn->read_buffer !=NULL) free(conn->read_buffer);
-    if (conn->write_buffer!=NULL) free(conn->write_buffer);
-    vector_destroy(conn->call); free(conn); return NULL;
-  }
- 
-  /* Make this socket non-blocking. */
-  fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
- 
-  /* Request connection from server, if this is a client */
-  if (isclient) {
-    struct pptp_start_ctrl_conn packet = {
-      PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
-      hton16(PPTP_VERSION), 0, 0, 
-      hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
-      hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), 
-      PPTP_HOSTNAME, PPTP_VENDOR
-    };
+    if( cause >= 0)
+        log("Result code is %d '%s'. Error code is %d, Cause code is %d",
+                result, result_text[result <= max_result ?  result : 0], error,
+                cause );
+    else
+        log("Reply result code is %d '%s'. Error code is %d",
+                result, result_text[result <= max_result ?  result : 0], error);
+    if ((error > 0) && (error <= MAX_GENERAL_ERROR)){
+        if( result != PPTP_RESULT_GENERAL_ERROR )
+            log("Result code is something else then \"general error\", "
+                    "so the following error is probably bogus.");
+        log("Error is '%s', Error message: '%s'",
+                pptp_general_errors[error].name,
+                pptp_general_errors[error].desc);
+    }
+}
 
-    char hostname[64];
-    bzero(hostname, sizeof(hostname));
-    gethostname(hostname, sizeof(hostname));
-    memcpy(packet.hostname, hostname, sizeof(hostname));
+static const char *ctrl_msg_types[] = {
+         "invalid control message type",
+/*         (Control Connection Management) */
+         "Start-Control-Connection-Request",            /* 1 */
+         "Start-Control-Connection-Reply",              /* 2 */
+         "Stop-Control-Connection-Request",             /* 3 */
+         "Stop-Control-Connection-Reply",               /* 4 */
+         "Echo-Request",                                /* 5 */
+         "Echo-Reply",                                  /* 6 */
+/*         (Call Management) */
+         "Outgoing-Call-Request",                       /* 7 */
+         "Outgoing-Call-Reply",                         /* 8 */
+         "Incoming-Call-Request",                       /* 9 */
+         "Incoming-Call-Reply",                        /* 10 */
+         "Incoming-Call-Connected",                    /* 11 */
+         "Call-Clear-Request",                         /* 12 */
+         "Call-Disconnect-Notify",                     /* 13 */
+/*         (Error Reporting) */
+         "WAN-Error-Notify",                           /* 14 */
+/*         (PPP Session Control) */
+         "Set-Link-Info"                              /* 15 */
+};
+#define MAX_CTRLMSG_TYPE 15
+         
+/*** report a sent packet ****************************************************/
+static void ctrlp_rep( void * buffer, int size, int isbuff)
+{
+    struct pptp_header *packet = buffer;
+    unsigned int type;
+    if(size < sizeof(struct pptp_header)) return;
+    type = ntoh16(packet->ctrl_type);
+    /* FIXME: do not report sending echo requests as long as they are
+     * sent in a signal handler. This may dead lock as the syslog call
+     * is not reentrant */
+    if( type ==  PPTP_ECHO_RQST ) return;
+    /* don't keep reporting sending of echo's */
+    if( (type == PPTP_ECHO_RQST || type == PPTP_ECHO_RPLY) && nlogecho <= 0 ) return;
+    log("%s control packet type is %d '%s'\n",isbuff ? "Buffered" : "Sent", 
+            type, ctrl_msg_types[type <= MAX_CTRLMSG_TYPE ? type : 0]);
 
-    /* fix this packet, if necessary */
-    int idx, rc;
-    if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].start_ctrl_conn) {
-	if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
-	    warn("calling the start_ctrl_conn hook failed (%d)", rc);
-    }
-
-    if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
-      conn->conn_state = CONN_WAIT_CTL_REPLY;
-    else return NULL; /* could not send initial start request. */
-  }
-
-  /* Set up interval/keep-alive timer */
-  /*   First, register handler for SIGALRM */
-  sigact.sa_handler = pptp_handle_timer;
-  sigemptyset(&sigact.sa_mask);
-  sigact.sa_flags = SA_RESTART;
-  global.conn = conn;
-  sigaction(SIGALRM, &sigact, &global.old_sigaction);
+}
+    
+    
 
-  /* Reset event timer */
-  pptp_reset_timer();
+/* Open new pptp_connection.  Returns NULL on failure. */
+PPTP_CONN * pptp_conn_open(int inet_sock, int isclient, pptp_conn_cb callback)
+{
+    PPTP_CONN *conn;
+    /* Allocate structure */
+    if ((conn = malloc(sizeof(*conn))) == NULL) return NULL;
+    if ((conn->call = vector_create()) == NULL) { free(conn); return NULL; }
+    /* Initialize */
+    conn->inet_sock = inet_sock;
+    conn->conn_state = CONN_IDLE;
+    conn->ka_state  = KA_NONE;
+    conn->ka_id     = 1;
+    conn->call_serial_number = 0;
+    conn->callback  = callback;
+    /* Create I/O buffers */
+    conn->read_size = conn->write_size = 0;
+    conn->read_alloc = conn->write_alloc = INITIAL_BUFSIZE;
+    conn->read_buffer =
+        malloc(sizeof(*(conn->read_buffer)) * conn->read_alloc);
+    conn->write_buffer =
+        malloc(sizeof(*(conn->write_buffer)) * conn->write_alloc);
+    if (conn->read_buffer == NULL || conn->write_buffer == NULL) {
+        if (conn->read_buffer  != NULL) free(conn->read_buffer);
+        if (conn->write_buffer != NULL) free(conn->write_buffer);
+        vector_destroy(conn->call); free(conn); return NULL;
+    }
+    /* Make this socket non-blocking. */
+    fcntl(conn->inet_sock, F_SETFL, O_NONBLOCK);
+    /* Request connection from server, if this is a client */
+    if (isclient) {
+        struct pptp_start_ctrl_conn packet = {
+            PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RQST),
+            hton16(PPTP_VERSION), 0, 0, 
+            hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
+            hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION), 
+            PPTP_HOSTNAME, PPTP_VENDOR
+        };
+        /* fix this packet, if necessary */
+        int idx, rc;
+        idx = get_quirk_index();
+        if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
+            if ((rc = pptp_fixups[idx].start_ctrl_conn(&packet)))
+                warn("calling the start_ctrl_conn hook failed (%d)", rc);
+        }
+        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet)))
+            conn->conn_state = CONN_WAIT_CTL_REPLY;
+        else
+            return NULL; /* could not send initial start request. */
+    }
+    /* Set up interval/keep-alive timer */
+    /*   First, register handler for SIGALRM */
+    sigpipe_create();
+    sigpipe_assign(SIGALRM);
+    global.conn = conn;
+    /* Reset event timer */
+    pptp_reset_timer();
+    /* all done. */
+    return conn;
+}
 
-  /* all done. */
-  return conn;
+int pptp_conn_established(PPTP_CONN *conn) {
+  return (conn->conn_state == CONN_ESTABLISHED);
 }
 
 /* This currently *only* works for client call requests.
  * We need to do something else to allocate calls for incoming requests.
  */
-PPTP_CALL * pptp_call_open(PPTP_CONN * conn,
-			   pptp_call_cb callback, char *phonenr)
+PPTP_CALL * pptp_call_open(PPTP_CONN * conn, pptp_call_cb callback,
+        char *phonenr)
 {
-  PPTP_CALL * call;
-  int i;
-  assert(conn && conn->call);
-
-  /* Assign call id */
-  if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS-1, &i))
-    /* no more calls available! */
-    return NULL;
-
-  /* allocate structure. */
-  if ((call = malloc(sizeof(*call)))==NULL) return NULL;
-  /* Initialize call structure */
-  call->call_type = PPTP_CALL_PNS;
-  call->state.pns = PNS_IDLE;
-  call->call_id   = (u_int16_t) i;
-  call->sernum    = conn->call_serial_number++;
-  call->callback  = callback;
-  call->closure   = NULL;
-  /* Send off the call request */
-  {
+    PPTP_CALL * call;
+    int i;
+    int idx, rc;
+    /* Send off the call request */
     struct pptp_out_call_rqst packet = {
-      PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
-      hton16(call->call_id), hton16(call->sernum),
-      hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
-      hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP),
-      hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0}
+        PPTP_HEADER_CTRL(PPTP_OUT_CALL_RQST),
+        0,0, /*call_id, sernum */
+        hton32(PPTP_BPS_MIN), hton32(PPTP_BPS_MAX),
+        hton32(PPTP_BEARER_CAP), hton32(PPTP_FRAME_CAP), 
+        hton16(PPTP_WINDOW), 0, 0, 0, {0}, {0}
     };
-
-    int idx, rc;
+    assert(conn && conn->call);
+    assert(conn->conn_state == CONN_ESTABLISHED);
+    /* Assign call id */
+    if (!vector_scan(conn->call, 0, PPTP_MAX_CHANNELS - 1, &i))
+        /* no more calls available! */
+        return NULL;
+    /* allocate structure. */
+    if ((call = malloc(sizeof(*call))) == NULL) return NULL;
+    /* Initialize call structure */
+    call->call_type = PPTP_CALL_PNS;
+    call->state.pns = PNS_IDLE;
+    call->call_id   = (u_int16_t) i;
+    call->sernum    = conn->call_serial_number++;
+    call->callback  = callback;
+    call->closure   = NULL;
+    packet.call_id = htons(call->call_id);
+    packet.call_sernum = htons(call->sernum);
     /* if we have a quirk, build a new packet to fit it */
-    if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].out_call_rqst_hook) {
-	if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
-	    warn("calling the out_call_rqst hook failed (%d)", rc);
+    idx = get_quirk_index();
+    if (idx != -1 && pptp_fixups[idx].out_call_rqst_hook) {
+        if ((rc = pptp_fixups[idx].out_call_rqst_hook(&packet)))
+            warn("calling the out_call_rqst hook failed (%d)", rc);
     }
-
-
     /* fill in the phone number if it was specified */
     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);
     }
-
     if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
-      pptp_reset_timer();
-      call->state.pns = PNS_WAIT_REPLY;
-      /* and add it to the call vector */
-      vector_insert(conn->call, i, call);
-      return call;
+        pptp_reset_timer();
+        call->state.pns = PNS_WAIT_REPLY;
+        /* and add it to the call vector */
+        vector_insert(conn->call, i, call);
+        return call;
     } else { /* oops, unsuccessful. Deallocate. */
-      free(call);
-      return NULL;
+        free(call);
+        return NULL;
     }
-  }
 }
 
-void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call) {
-  struct pptp_call_clear_rqst rqst = {
-    PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
-  };
-  assert(conn && conn->call); assert(call);
-  assert(vector_contains(conn->call, call->call_id));
-  assert(call->call_type == PPTP_CALL_PNS); /* haven't thought about PAC yet */
-  assert(call->state.pns != PNS_IDLE);
-  rqst.call_id = hton16(call->call_id);
-
-  /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
-   * requests to be made.
-   */
-
-  pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
-
-  /* add by zg 2006.09.16
-   * fix cdrouter3.3 item 28(cdrouter_pptp_30) bug
-   */
-  PPTP_CALL_CLEAR_RQST_FLAG=1;
-
-  pptp_reset_timer();
-  call->state.pns = PNS_WAIT_DISCONNECT;
-
-  /* call structure will be freed when we have confirmation of disconnect. */
-}
-/* hard close. */
-void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call) {
-  assert(conn && conn->call); assert(call);
-  assert(vector_contains(conn->call, call->call_id));
-  /* notify */
-  if (call->callback!=NULL) call->callback(conn, call, CALL_CLOSE_DONE);
-  /* deallocate */
-  vector_remove(conn->call, call->call_id);
-  free(call);
-}
-/* this is a soft close */
-void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason) {
-  struct pptp_stop_ctrl_conn rqst = {
-    PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), 
-    hton8(close_reason), 0, 0};
-  int i;
-  
-  assert(conn && conn->call);
+/*** pptp_call_close **********************************************************/
+void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call)
+{
+    struct pptp_call_clear_rqst rqst = {
+        PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_RQST), 0, 0
+    };
+    assert(conn && conn->call); assert(call);
+    assert(vector_contains(conn->call, call->call_id));
+    /* haven't thought about PAC yet */
+    assert(call->call_type == PPTP_CALL_PNS);
+    assert(call->state.pns != PNS_IDLE);
+    rqst.call_id = hton16(call->call_id);
+    /* don't check state against WAIT_DISCONNECT... allow multiple disconnect
+     * requests to be made.
+     */
+    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
+    pptp_reset_timer();
+    call->state.pns = PNS_WAIT_DISCONNECT;
+    /* call structure will be freed when we have confirmation of disconnect. */
+}
 
-  /* avoid repeated close attempts */
-  if (conn->conn_state==CONN_IDLE || conn->conn_state==CONN_WAIT_STOP_REPLY) 
-    return;
+/*** hard close ***************************************************************/
+void pptp_call_destroy(PPTP_CONN *conn, PPTP_CALL *call)
+{
+    assert(conn && conn->call); assert(call);
+    assert(vector_contains(conn->call, call->call_id));
+    /* notify */
+    if (call->callback != NULL) call->callback(conn, call, CALL_CLOSE_DONE);
+    /* deallocate */
+    vector_remove(conn->call, call->call_id);
+    free(call);
+}
 
-  /* close open calls, if any */
-  for (i=0; i<vector_size(conn->call); i++)
-    pptp_call_close(conn, vector_get_Nth(conn->call, i));
-    
-  /* now close connection */
-  log("Closing PPTP connection");
-  pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
-  pptp_reset_timer(); /* wait 60 seconds for reply */
-  conn->conn_state = CONN_WAIT_STOP_REPLY;
-  return;
-}
-/* this is a hard close */
-void pptp_conn_destroy(PPTP_CONN * conn) {
-  int i;
-  assert(conn != NULL); assert(conn->call != NULL);
-  /* destroy all open calls */
-  for (i=0; i<vector_size(conn->call); i++)
-    pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
-  /* notify */
-  if (conn->callback!=NULL) conn->callback(conn, CONN_CLOSE_DONE);
-  sigaction(SIGALRM, &global.old_sigaction, NULL);
-  close(conn->inet_sock);
-  /* deallocate */
-  vector_destroy(conn->call);
-  free(conn);
+/*** this is a soft close *****************************************************/
+void pptp_conn_close(PPTP_CONN * conn, u_int8_t close_reason)
+{
+    struct pptp_stop_ctrl_conn rqst = {
+        PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RQST), 
+        hton8(close_reason), 0, 0
+    };
+    int i;
+    assert(conn && conn->call);
+    /* avoid repeated close attempts */
+    if (conn->conn_state == CONN_IDLE || conn->conn_state == CONN_WAIT_STOP_REPLY) 
+        return;
+    /* close open calls, if any */
+    for (i = 0; i < vector_size(conn->call); i++)
+        pptp_call_close(conn, vector_get_Nth(conn->call, i));
+    /* now close connection */
+    log("Closing PPTP connection");
+    pptp_send_ctrl_packet(conn, &rqst, sizeof(rqst));
+    pptp_reset_timer(); /* wait 60 seconds for reply */
+    conn->conn_state = CONN_WAIT_STOP_REPLY;
+    return;
 }
 
-/************** Deal with messages, in a non-blocking manner *************/
+/*** this is a hard close *****************************************************/
+void pptp_conn_destroy(PPTP_CONN * conn)
+{
+    int i;
+    assert(conn != NULL); assert(conn->call != NULL);
+    /* destroy all open calls */
+    for (i = 0; i < vector_size(conn->call); i++)
+        pptp_call_destroy(conn, vector_get_Nth(conn->call, i));
+    /* notify */
+    if (conn->callback != NULL) conn->callback(conn, CONN_CLOSE_DONE);
+    sigpipe_close();
+    close(conn->inet_sock);
+    /* deallocate */
+    vector_destroy(conn->call);
+    free(conn);
+}
 
-/* Add file descriptors used by pptp to fd_set. */
+/*** Deal with messages, in a non-blocking manner 
+ * Add file descriptors used by pptp to fd_set.
+ */
 void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set,
-                 int *max_fd) {
-  assert(conn && conn->call);
-
-  /* Add fd to write_set if there are outstanding writes. */
-  if (conn->write_size > 0)
-    FD_SET(conn->inet_sock, write_set);
-
-  /* Always add fd to read_set. (always want something to read) */
-  FD_SET(conn->inet_sock, read_set);
-  if (*max_fd < conn->inet_sock)
-    *max_fd = conn->inet_sock;
-}
-/* handle any pptp file descriptors set in fd_set, and clear them */
-void pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set) {
-  assert(conn && conn->call);
-  /* Check write_set could be set. */
-  if (FD_ISSET(conn->inet_sock, write_set)) {
-    FD_CLR(conn->inet_sock, write_set);
+                 int * max_fd)
+{
+    assert(conn && conn->call);
+    /* Add fd to write_set if there are outstanding writes. */
     if (conn->write_size > 0)
-      pptp_write_some(conn); /* write as much as we can without blocking */
-  }
-  /* Check read_set */
-  if (FD_ISSET(conn->inet_sock, read_set)) {
-    void *buffer; size_t size;
-    FD_CLR(conn->inet_sock, read_set);
-    pptp_read_some(conn); /* read as much as we can without blocking */
-    /* make packets of the buffer, while we can. */
-    while (pptp_make_packet(conn, &buffer, &size)) {
-      pptp_dispatch_packet(conn, buffer, size);
-      free(buffer);
-    }
-  }
-  /* That's all, folks.  Simple, eh? */
-}
-/********************* Non-blocking I/O buffering *********************/
-void pptp_write_some(PPTP_CONN * conn) {
-  ssize_t retval;
-  assert(conn && conn->call);
-  retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
-  if (retval < 0) { /* error. */
-    if (errno == EAGAIN || errno == EINTR) { 
-      /* ignore */;
-    } else { /* a real error */
-      log("write error: %s", strerror(errno));
-      pptp_conn_destroy(conn); /* shut down fast. */
-    }
-    return;
-  }
-  assert(retval <= conn->write_size);
-  conn->write_size-=retval;
-  memmove(conn->write_buffer, conn->write_buffer+retval, 
-	  conn->write_size);
-}
-void pptp_read_some(PPTP_CONN * conn) {
-  ssize_t retval;
-  assert(conn && conn->call);
-  if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
-    char *new_buffer=realloc(conn->read_buffer, 
-			     sizeof(*(conn->read_buffer))*conn->read_alloc*2);
-    if (new_buffer == NULL) {
-      log("Out of memory"); return;
-    }
-    conn->read_alloc*=2;
-    conn->read_buffer = new_buffer;
-  }
-  retval = read(conn->inet_sock, 
-		conn->read_buffer + conn->read_size,
-		conn->read_alloc  - conn->read_size);
-  if (retval < 0) {
-    if (errno == EINTR || errno == EAGAIN)
-      /* ignore */ ;
-    else { /* a real error */
-      log("read error: %s", strerror(errno));
-      pptp_conn_destroy(conn); /* shut down fast. */
+        FD_SET(conn->inet_sock, write_set);
+    /* Always add fd to read_set. (always want something to read) */
+    FD_SET(conn->inet_sock, read_set);
+    if (*max_fd < conn->inet_sock) *max_fd = conn->inet_sock;
+    /* Add signal pipe file descriptor to set */
+    int sig_fd = sigpipe_fd();
+    FD_SET(sig_fd, read_set);
+    if (*max_fd < sig_fd) *max_fd = sig_fd;
+}
+
+/*** handle any pptp file descriptors set in fd_set, and clear them ***********/
+int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set)
+{
+    int r = 0;
+    assert(conn && conn->call);
+    /* Check for signals */
+    if (FD_ISSET(sigpipe_fd(), read_set)) {
+        if (sigpipe_read() == SIGALRM) pptp_handle_timer();
+	FD_CLR(sigpipe_fd(), read_set);
+    }
+    /* Check write_set could be set. */
+    if (FD_ISSET(conn->inet_sock, write_set)) {
+        FD_CLR(conn->inet_sock, write_set);
+        if (conn->write_size > 0)
+            r = pptp_write_some(conn);/* write as much as we can without blocking */
+    }
+    /* Check read_set */
+    if (r >= 0 && FD_ISSET(conn->inet_sock, read_set)) {
+        void *buffer; size_t size;
+        FD_CLR(conn->inet_sock, read_set);
+        r = pptp_read_some(conn); /* read as much as we can without blocking */
+	if (r < 0)
+	    return r;
+        /* make packets of the buffer, while we can. */
+        while (r >= 0 && pptp_make_packet(conn, &buffer, &size)) {
+            r = pptp_dispatch_packet(conn, buffer, size);
+            free(buffer);
+        }
+    }
+    /* That's all, folks.  Simple, eh? */
+    return r;
+}
+
+/*** Non-blocking write *******************************************************/
+int pptp_write_some(PPTP_CONN * conn) {
+    ssize_t retval;
+    assert(conn && conn->call);
+    retval = write(conn->inet_sock, conn->write_buffer, conn->write_size);
+    if (retval < 0) { /* error. */
+        if (errno == EAGAIN || errno == EINTR) { 
+            return 0;
+        } else { /* a real error */
+            log("write error: %s", strerror(errno));
+	    return -1;
+        }
+    }
+    assert(retval <= conn->write_size);
+    conn->write_size -= retval;
+    memmove(conn->write_buffer, conn->write_buffer + retval, conn->write_size);
+    ctrlp_rep(conn->write_buffer, retval, 0);
+    return 0;
+}
+
+/*** Non-blocking read ********************************************************/
+int pptp_read_some(PPTP_CONN * conn)
+{
+    ssize_t retval;
+    assert(conn && conn->call);
+    if (conn->read_size == conn->read_alloc) { /* need to alloc more memory */
+        char *new_buffer = realloc(conn->read_buffer, 
+                sizeof(*(conn->read_buffer)) * conn->read_alloc * 2);
+        if (new_buffer == NULL) {
+            log("Out of memory"); return -1;
+        }
+        conn->read_alloc *= 2;
+        conn->read_buffer = new_buffer;
+    }
+    retval = read(conn->inet_sock, conn->read_buffer + conn->read_size,
+            conn->read_alloc  - conn->read_size);
+    if (retval == 0) {
+        log("read returned zero, peer has closed");
+        return -1;
+    }
+    if (retval < 0) {
+        if (errno == EINTR || errno == EAGAIN)
+	    return 0;
+        else { /* a real error */
+            log("read error: %s", strerror(errno));
+            return -1;
+        }
+    }
+    conn->read_size += retval;
+    assert(conn->read_size <= conn->read_alloc);
+    return 0;
+}
+
+/*** Packet formation *********************************************************/
+int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size)
+{
+    struct pptp_header *header;
+    size_t bad_bytes = 0;
+    assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
+    /* Give up unless there are at least sizeof(pptp_header) bytes */
+    while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
+        /* Throw out bytes until we have a valid header. */
+        header = (struct pptp_header *) (conn->read_buffer + bad_bytes);
+        if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
+        if (ntoh16(header->reserved0) != 0)
+            log("reserved0 field is not zero! (0x%x) Cisco feature? \n",
+                    ntoh16(header->reserved0));
+        if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
+        if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
+        /* well.  I guess it's good. Let's see if we've got it all. */
+        if (ntoh16(header->length) > (conn->read_size-bad_bytes))
+            /* nope.  Let's wait until we've got it, then. */
+            goto flushbadbytes;
+        /* One last check: */
+        if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
+                (ntoh16(header->length) !=
+                         PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
+            goto throwitout;
+        /* well, I guess we've got it. */
+        *size = ntoh16(header->length);
+        *buf = malloc(*size);
+        if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ }
+        memcpy(*buf, conn->read_buffer + bad_bytes, *size);
+        /* Delete this packet from the read_buffer. */
+        conn->read_size -= (bad_bytes + *size);
+        memmove(conn->read_buffer, conn->read_buffer + bad_bytes + *size, 
+                conn->read_size);
+        if (bad_bytes > 0) 
+            log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
+        return 1;
+throwitout:
+        bad_bytes++;
     }
-    return;
-  }
-  conn->read_size += retval;
-  assert(conn->read_size <= conn->read_alloc);
-}
-/********************* Packet formation *******************************/
-int pptp_make_packet(PPTP_CONN * conn, void **buf, size_t *size) {
-  struct pptp_header *header;
-  size_t bad_bytes = 0;
-  assert(conn && conn->call); assert(buf != NULL); assert(size != NULL);
-
-  /* Give up unless there are at least sizeof(pptp_header) bytes */
-  while ((conn->read_size-bad_bytes) >= sizeof(struct pptp_header)) {
-    /* Throw out bytes until we have a valid header. */
-    header = (struct pptp_header *) (conn->read_buffer+bad_bytes);
-    if (ntoh32(header->magic) != PPTP_MAGIC) goto throwitout;
-    if (ntoh16(header->reserved0) != 0)
-	log("reserved0 field is not zero! (0x%x) Cisco feature? \n",
-		ntoh16(header->reserved0));
-    if (ntoh16(header->length) < sizeof(struct pptp_header)) goto throwitout;
-    if (ntoh16(header->length) > PPTP_CTRL_SIZE_MAX) goto throwitout;
-    /* well.  I guess it's good. Let's see if we've got it all. */
-    if (ntoh16(header->length) > (conn->read_size-bad_bytes))
-      /* nope.  Let's wait until we've got it, then. */
-      goto flushbadbytes;
-    /* One last check: */
-    if ((ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL) &&
-	(ntoh16(header->length) != PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))))
-      goto throwitout;
-
-    /* well, I guess we've got it. */
-    *size= ntoh16(header->length);
-    *buf = malloc(*size);
-    if (*buf == NULL) { log("Out of memory."); return 0; /* ack! */ }
-    memcpy(*buf, conn->read_buffer+bad_bytes, *size);
-    /* Delete this packet from the read_buffer. */
-    conn->read_size -= (bad_bytes + *size);
-    memmove(conn->read_buffer, conn->read_buffer+bad_bytes+*size, 
-	    conn->read_size);
+flushbadbytes:
+    /* no more packets.  Let's get rid of those bad bytes */
+    conn->read_size -= bad_bytes;
+    memmove(conn->read_buffer, conn->read_buffer + bad_bytes, conn->read_size);
     if (bad_bytes > 0) 
-      log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
+        log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
+    return 0;
+}
+
+/*** pptp_send_ctrl_packet ****************************************************/
+int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size)
+{
+    assert(conn && conn->call); assert(buffer);
+    if( conn->write_size > 0) pptp_write_some( conn);
+    if( conn->write_size == 0) {
+        ssize_t retval;
+        retval = write(conn->inet_sock, buffer, size);
+        if (retval < 0) { /* error. */
+            if (errno == EAGAIN || errno == EINTR) { 
+                /* ignore */;
+                retval = 0;
+            } else { /* a real error */
+                log("write error: %s", strerror(errno));
+                pptp_conn_destroy(conn); /* shut down fast. */
+                return 0;
+            }
+        }
+        ctrlp_rep( buffer, retval, 0);
+        size -= retval;
+        if( size <= 0) return 1;
+    }
+    /* Shove anything not written into the write buffer */
+    if (conn->write_size + size > conn->write_alloc) { /* need more memory */
+        char *new_buffer = realloc(conn->write_buffer, 
+                sizeof(*(conn->write_buffer)) * conn->write_alloc * 2);
+        if (new_buffer == NULL) {
+            log("Out of memory"); return 0;
+        }
+        conn->write_alloc *= 2;
+        conn->write_buffer = new_buffer;
+    }
+    memcpy(conn->write_buffer + conn->write_size, buffer, size);
+    conn->write_size += size;
+    ctrlp_rep( buffer,size,1);
     return 1;
+}
 
-  throwitout:
-    bad_bytes++;
-  }
-flushbadbytes:
-  /* no more packets.  Let's get rid of those bad bytes */
-  conn->read_size -= bad_bytes;
-  memmove(conn->read_buffer, conn->read_buffer+bad_bytes, conn->read_size);
-  if (bad_bytes > 0) 
-    log("%lu bad bytes thrown away.", (unsigned long) bad_bytes);
-  return 0;
-}
-int pptp_send_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size) {
-  assert(conn && conn->call); assert(buffer);
-  /* Shove this into the write buffer */
-  if (conn->write_size + size > conn->write_alloc) { /* need more memory */
-    char *new_buffer=realloc(conn->write_buffer, 
-			   sizeof(*(conn->write_buffer))*conn->write_alloc*2);
-    if (new_buffer == NULL) {
-      log("Out of memory"); return 0;
-    }
-    conn->write_alloc*=2;
-    conn->write_buffer = new_buffer;
-  }
-  memcpy(conn->write_buffer + conn->write_size, buffer, size);
-  conn->write_size+=size;
-  return 1;
-}
-/********************** Packet Dispatch ****************************/
-void pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size) {
-  struct pptp_header *header = (struct pptp_header *)buffer;
-  assert(conn && conn->call); assert(buffer);
-  assert(ntoh32(header->magic)==PPTP_MAGIC);
-  assert(ntoh16(header->length)==size);
-
-  switch (ntoh16(header->pptp_type)) {
-  case PPTP_MESSAGE_CONTROL:
-    pptp_dispatch_ctrl_packet(conn, buffer, size);
-    break;
-  case PPTP_MESSAGE_MANAGE:
-    /* MANAGEMENT messages aren't even part of the spec right now. */
-    log("PPTP management message received, but not understood.");
-    break;
-  default:
-    log("Unknown PPTP control message type received: %u", 
-	(unsigned int) ntoh16(header->pptp_type));
-    break;
-  }
-}
-
-void pptp_dispatch_ctrl_packet(PPTP_CONN * conn, void * buffer, size_t size) {
-  struct pptp_header *header = (struct pptp_header *)buffer;
-  u_int8_t close_reason = PPTP_STOP_NONE;
-
-  assert(conn && conn->call); assert(buffer);
-  assert(ntoh32(header->magic)==PPTP_MAGIC);
-  assert(ntoh16(header->length)==size);
-  assert(ntoh16(header->pptp_type)==PPTP_MESSAGE_CONTROL);
-
-  if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
-    log("Invalid packet received [type: %d; length: %d].",
-	(int) ntoh16(header->ctrl_type), (int) size);
-    return;
-  }
+/*** Packet Dispatch **********************************************************/
+int pptp_dispatch_packet(PPTP_CONN * conn, void * buffer, size_t size)
+{
+    int r = 0;
+    struct pptp_header *header = (struct pptp_header *)buffer;
+    assert(conn && conn->call); assert(buffer);
+    assert(ntoh32(header->magic) == PPTP_MAGIC);
+    assert(ntoh16(header->length) == size);
+    switch (ntoh16(header->pptp_type)) {
+        case PPTP_MESSAGE_CONTROL:
+            r = ctrlp_disp(conn, buffer, size);
+            break;
+        case PPTP_MESSAGE_MANAGE:
+            /* MANAGEMENT messages aren't even part of the spec right now. */
+            log("PPTP management message received, but not understood.");
+            break;
+        default:
+            log("Unknown PPTP control message type received: %u", 
+                    (unsigned int) ntoh16(header->pptp_type));
+            break;
+    }
+    return r;
+}
 
-  switch (ntoh16(header->ctrl_type)) {
-    /* ----------- STANDARD Start-Session MESSAGES ------------ */
-  case PPTP_START_CTRL_CONN_RQST:
-    {
-      struct pptp_start_ctrl_conn *packet = 
-	(struct pptp_start_ctrl_conn *) buffer;
-      struct pptp_start_ctrl_conn reply = {
-	PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
-	hton16(PPTP_VERSION), 0, 0,
-	hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
-	hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
-	PPTP_HOSTNAME, PPTP_VENDOR };
-
-      char hostname[64];
-      bzero(hostname, sizeof(hostname));
-      gethostname(hostname, sizeof(hostname));
-      memcpy(reply.hostname, hostname, sizeof(hostname));
-
-      /* fix this packet, if necessary */
-      int idx, rc;
-      if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].start_ctrl_conn) {
-	  if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
-	      warn("calling the start_ctrl_conn hook failed (%d)", rc);
-      }
-
-      if (conn->conn_state == CONN_IDLE) {
-	if (ntoh16(packet->version) < PPTP_VERSION) {
-	  /* Can't support this (earlier) PPTP_VERSION */
-	  reply.version = packet->version;
-	  reply.result_code = hton8(5); /* protocol version not supported */
-	  pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
-	  pptp_reset_timer(); /* give sender a chance for a retry */
-	} else { /* same or greater version */
-	  if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
-	    conn->conn_state=CONN_ESTABLISHED;
-	    log("server connection ESTABLISHED.");
-	    pptp_reset_timer();
-	  }
-	}
-      }
-      break;
-    }
-  case PPTP_START_CTRL_CONN_RPLY:
-    {
-      struct pptp_start_ctrl_conn *packet = 
-	(struct pptp_start_ctrl_conn *) buffer;
-      if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
-	/* XXX handle collision XXX [see rfc] */
-	if (ntoh16(packet->version) != PPTP_VERSION) {
-	  if (conn->callback!=NULL) conn->callback(conn, CONN_OPEN_FAIL);
-	  close_reason = PPTP_STOP_PROTOCOL;
-	  goto pptp_conn_close;
-	}
-        /* J'ai change le if () afin que la connection ne se ferme pas pour un "rien" :p
-         * adel@cybercable.fr -
-         */                                            
-	if (ntoh8(packet->result_code) !=1 && ntoh8(packet->result_code) !=0) { 
-	  if (conn->callback!=NULL) conn->callback(conn, CONN_OPEN_FAIL);
-	  close_reason = PPTP_STOP_PROTOCOL;
-	  goto pptp_conn_close;
-	}
-	conn->conn_state = CONN_ESTABLISHED;
-
-	/* log session properties */
-	conn->version      = ntoh16(packet->version);
-	conn->firmware_rev = ntoh16(packet->firmware_rev);
-	memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
-	memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
-
-	pptp_reset_timer(); /* 60 seconds until keep-alive */
-	log("Client connection established.");
-
-	if (conn->callback!=NULL) conn->callback(conn, CONN_OPEN_DONE);
-      } /* else goto pptp_conn_close; */
-      break;
-    }
-  /* ----------- STANDARD Stop-Session MESSAGES ------------ */
-  case PPTP_STOP_CTRL_CONN_RQST:
-    {
-#if 0 /* make gcc happy about "unused variable 'packet'" here */
-      struct pptp_stop_ctrl_conn *packet = /* XXX do something with this XXX */
-	(struct pptp_stop_ctrl_conn *) buffer; 
-#endif
-      /* conn_state should be CONN_ESTABLISHED, but it could be 
-       * something else */
-      struct pptp_stop_ctrl_conn reply = {
-	PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), 
-	hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0};
-
-      if (conn->conn_state==CONN_IDLE) break;
-      if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
-	if (conn->callback!=NULL) conn->callback(conn, CONN_CLOSE_RQST);
-	conn->conn_state=CONN_IDLE;
-	pptp_conn_destroy(conn);
-      }
-      break;
-    }
-  case PPTP_STOP_CTRL_CONN_RPLY:
-    {
-#if 0 /* make gcc happy about "unused variable 'packet'" here */
-      struct pptp_stop_ctrl_conn *packet = /* XXX do something with this XXX */
-	(struct pptp_stop_ctrl_conn *) buffer;
-#endif
-      /* conn_state should be CONN_WAIT_STOP_REPLY, but it 
-       * could be something else */
-
-      if (conn->conn_state == CONN_IDLE) break;
-      conn->conn_state=CONN_IDLE;
-      pptp_conn_destroy(conn);
-      break;
-    }
-  /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
-  case PPTP_ECHO_RPLY:
-    {
-      struct pptp_echo_rply *packet = 
-	(struct pptp_echo_rply *) buffer;
-      if ((conn->ka_state == KA_OUTSTANDING) && 
-	  (ntoh32(packet->identifier)==conn->ka_id)) {
-	conn->ka_id++;
-	conn->ka_state=KA_NONE;
-	pptp_reset_timer();
-      }
-      break;
-    }
-  case PPTP_ECHO_RQST:
-    {
-      struct pptp_echo_rqst *packet = 
-	(struct pptp_echo_rqst *) buffer;
-      struct pptp_echo_rply reply = {
-	PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), 
-	packet->identifier, /* skip hton32(ntoh32(id)) */
-	hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0};
-      pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
-      pptp_reset_timer();
-      break;
-    }
-  /* ----------- OUTGOING CALL MESSAGES ------------ */
-  case PPTP_OUT_CALL_RQST:
-    {
-      struct pptp_out_call_rqst *packet =
-	(struct pptp_out_call_rqst *)buffer;
-      struct pptp_out_call_rply reply = {
-	PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
-	0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
-	hton32(PPTP_CONNECT_SPEED), 
-	hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0 };
-      /* XXX PAC: eventually this should make an outgoing call. XXX */
-      reply.result_code = hton8(7); /* outgoing calls verboten */
-      pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
-      break;
-    }
-  case PPTP_OUT_CALL_RPLY:
-    {
-      struct pptp_out_call_rply *packet =
-	(struct pptp_out_call_rply *)buffer;
-      PPTP_CALL * call;
-      u_int16_t callid = ntoh16(packet->call_id_peer);
-      if (!vector_search(conn->call, (int) callid, &call)) {
-	log("PPTP_OUT_CALL_RPLY received for non-existant call.");
-	break;
-      }
-      if (call->call_type!=PPTP_CALL_PNS) {
-	log("Ack!  How did this call_type get here?"); /* XXX? */
-	break; 
-      }
-      if (call->state.pns == PNS_WAIT_REPLY) {
-	/* check for errors */
-	if (packet->result_code!=1) {
-	  /* An error.  Log it verbosely. */
-	  unsigned int legal_error_value =
-	       sizeof(pptp_general_errors)/sizeof(pptp_general_errors[0]);
-	  int err = packet->error_code;
-          log("Error '%d' opening call. [callid %d]",
-	      packet->result_code, (int) callid);
-          log("Error code is '%d', Cause code is '%d'", err,
-	      packet->cause_code);
-          if ((err > 0) && (err < legal_error_value)){
-            log("Error is '%s', Error message: '%s'",
-            pptp_general_errors[err].name,
-            pptp_general_errors[err].desc);
-	  }
-
-
-	  call->state.pns = PNS_IDLE;
-	  if (call->callback!=NULL) call->callback(conn, call, CALL_OPEN_FAIL);
-	  pptp_call_destroy(conn, call);
-	} else {
-	  /* connection established */
-	  call->state.pns = PNS_ESTABLISHED;
-	  call->peer_call_id = ntoh16(packet->call_id);
-	  call->speed        = ntoh32(packet->speed);
-	  pptp_reset_timer();
-	  /* call pptp_set_link. unless the user specified a quirk
-	     and this quirk has a set_link hook, this is a noop */
- 	  pptp_set_link(conn, call->peer_call_id);
-
-	  if (call->callback!=NULL) call->callback(conn, call, CALL_OPEN_DONE);
-	  log("Outgoing call established (call ID %u, peer's call ID %u).\n",
-		call->call_id, call->peer_call_id);
-	}
-      }
-      break;
-    }
-  /* ----------- INCOMING CALL MESSAGES ------------ */
-  /* XXX write me XXX */
-  /* ----------- CALL CONTROL MESSAGES ------------ */
-  case PPTP_CALL_CLEAR_RQST:
-    {
-      struct pptp_call_clear_rqst *packet =
-	(struct pptp_call_clear_rqst *)buffer;
-      struct pptp_call_clear_ntfy reply = {
-	PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
-	1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
-      };
-      if (vector_contains(conn->call, ntoh16(packet->call_id))) {
-	PPTP_CALL * call;
-	vector_search(conn->call, ntoh16(packet->call_id), &call);
-	if (call->callback!=NULL) call->callback(conn, call, CALL_CLOSE_RQST);
-	pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
-	pptp_call_destroy(conn, call);
-	log("Call closed (RQST) (call id %d)", (int) call->call_id);
-      }
-      break;
-    }
-  case PPTP_CALL_CLEAR_NTFY:
-    {
-      struct pptp_call_clear_ntfy *packet =
-	(struct pptp_call_clear_ntfy *)buffer;
-      if (vector_contains(conn->call, ntoh16(packet->call_id))) {
-	PPTP_CALL * call;
-	vector_search(conn->call, ntoh16(packet->call_id), &call);
-	pptp_call_destroy(conn, call);
-	log("Call closed (NTFY) (call id %d)", (int) call->call_id);
-      }
-
-      /* add by zg 2006.09.16
-       * fix cdrouter3.3 item 28(cdrouter_pptp_30) bug
-       */ 
-      if(PPTP_CALL_CLEAR_RQST_FLAG==0)
-      {
-            struct in_addr inetaddr;
-            volatile int callmgr_sock = -1;
-            int pty_fd;
-            volatile pid_t parent_pid, child_pid;
-            u_int16_t call_id, peer_call_id;
-            const char* optarg=BEZEQ_ISRAEL;
-
-            /* --quirks specified */
-            set_quirk_index(find_quirk(optarg));
-                     
-            /*  Find an open pty/tty pair. */
-            pty_fd=0;
-            child_pid=getpid();
-            parent_pid=0; /* don't kill pppd */
-
-            /*  Exchange PIDs, get call ID */
-            get_call_id(callmgr_sock, parent_pid, child_pid, 
-	               &call_id, &peer_call_id) ;
-
-            /*  Send signal to wake up pppd task */
-            kill(parent_pid, SIGUSR1);
-            sleep(2);
- 
-            /*  Do GRE copy until close. */
-            pptp_gre_copy(call_id, peer_call_id, pty_fd, inetaddr);
-      }
-      else
-      {
-            PPTP_CALL_CLEAR_RQST_FLAG=0;
-      }
-      /* end by zg 2006.09.16
-       * fix cdrouter3.3 item 28(cdrouter_pptp_30) bug
-       */
-
-      /* XXX we could log call stats here XXX */
-      break;
-    }
-  case PPTP_SET_LINK_INFO:
-    {
-      /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
-      /* this is really dealt with in the HDLC deencapsulation, anyway. */
-      struct pptp_set_link_info *packet =
-	(struct pptp_set_link_info *)buffer;
-      if (ntoh32(packet->send_accm)==0 && ntoh32(packet->recv_accm)==0)
-	break; /* this is what we expect. */
-      /* log it, otherwise. */
-      log("PPTP_SET_LINK_INFO recieved from peer_callid %u",
-	  (unsigned int) ntoh16(packet->call_id_peer));
-      log("  send_accm is %08lX, recv_accm is %08lX",
-	  (unsigned long) ntoh32(packet->send_accm),
-	  (unsigned long) ntoh32(packet->recv_accm));
-      break;
-    }
-  default:
-    log("Unrecognized Packet %d received.", 
-	(int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
-    /* goto pptp_conn_close; */
-    break;
-  }
-  return;
+/*** log echo request/replies *************************************************/
+static void logecho( int type)
+{
+    /* hack to stop flooding the log files (the most interesting part is right
+     * after the connection built-up) */
+    if( nlogecho > 0) {
+        log( "Echo Re%s received.", type == PPTP_ECHO_RQST ? "quest" :"ply");
+        if( --nlogecho == 0)
+            log("no more Echo Reply/Request packets will be reported.");
+    }
+}
 
+/*** pptp_dispatch_ctrl_packet ************************************************/
+int ctrlp_disp(PPTP_CONN * conn, void * buffer, size_t size)
+{
+    struct pptp_header *header = (struct pptp_header *)buffer;
+    u_int8_t close_reason = PPTP_STOP_NONE;
+    assert(conn && conn->call); assert(buffer);
+    assert(ntoh32(header->magic) == PPTP_MAGIC);
+    assert(ntoh16(header->length) == size);
+    assert(ntoh16(header->pptp_type) == PPTP_MESSAGE_CONTROL);
+    if (size < PPTP_CTRL_SIZE(ntoh16(header->ctrl_type))) {
+        log("Invalid packet received [type: %d; length: %d].",
+                (int) ntoh16(header->ctrl_type), (int) size);
+        return 0;
+    }
+    switch (ntoh16(header->ctrl_type)) {
+        /* ----------- STANDARD Start-Session MESSAGES ------------ */
+        case PPTP_START_CTRL_CONN_RQST:
+        {
+            struct pptp_start_ctrl_conn *packet = 
+                (struct pptp_start_ctrl_conn *) buffer;
+            struct pptp_start_ctrl_conn reply = {
+                PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
+                hton16(PPTP_VERSION), 0, 0,
+                hton32(PPTP_FRAME_CAP), hton32(PPTP_BEARER_CAP),
+                hton16(PPTP_MAX_CHANNELS), hton16(PPTP_FIRMWARE_VERSION),
+                PPTP_HOSTNAME, PPTP_VENDOR };
+            int idx, rc;
+            log("Received Start Control Connection Request");
+            /* fix this packet, if necessary */
+            idx = get_quirk_index();
+            if (idx != -1 && pptp_fixups[idx].start_ctrl_conn) {
+                if ((rc = pptp_fixups[idx].start_ctrl_conn(&reply)))
+                    warn("calling the start_ctrl_conn hook failed (%d)", rc);
+            }
+            if (conn->conn_state == CONN_IDLE) {
+                if (ntoh16(packet->version) < PPTP_VERSION) {
+                    /* Can't support this (earlier) PPTP_VERSION */
+                    reply.version = packet->version;
+                    /* protocol version not supported */
+                    reply.result_code = hton8(5);
+                    pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
+                    pptp_reset_timer(); /* give sender a chance for a retry */
+                } else { /* same or greater version */
+                    if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
+                        conn->conn_state = CONN_ESTABLISHED;
+                        log("server connection ESTABLISHED.");
+                        pptp_reset_timer();
+                    }
+                }
+            }
+            break;
+        }
+        case PPTP_START_CTRL_CONN_RPLY:
+        {
+            struct pptp_start_ctrl_conn *packet = 
+                (struct pptp_start_ctrl_conn *) buffer;
+            log("Received Start Control Connection Reply");
+            if (conn->conn_state == CONN_WAIT_CTL_REPLY) {
+                /* XXX handle collision XXX [see rfc] */
+                if (ntoh16(packet->version) != PPTP_VERSION) {
+                    if (conn->callback != NULL)
+                        conn->callback(conn, CONN_OPEN_FAIL);
+                    close_reason = PPTP_STOP_PROTOCOL;
+                    goto pptp_conn_close;
+                }
+                if (ntoh8(packet->result_code) != 1 &&
+                    /* J'ai change le if () afin que la connection ne se ferme
+                     * pas pour un "rien" :p adel@cybercable.fr -
+                     * 
+                     * Don't close the connection if the result code is zero
+                     * (feature found in certain ADSL modems)
+                     */
+                        ntoh8(packet->result_code) != 0) { 
+                    log("Negative reply received to our Start Control "
+                            "Connection Request");
+                    ctrlp_error(packet->result_code, packet->error_code,
+                            -1, pptp_start_ctrl_conn_rply,
+                            MAX_START_CTRL_CONN_REPLY);
+                    if (conn->callback != NULL)
+                        conn->callback(conn, CONN_OPEN_FAIL);
+                    close_reason = PPTP_STOP_PROTOCOL;
+                    goto pptp_conn_close;
+                }
+                conn->conn_state = CONN_ESTABLISHED;
+                /* log session properties */
+                conn->version      = ntoh16(packet->version);
+                conn->firmware_rev = ntoh16(packet->firmware_rev);
+                memcpy(conn->hostname, packet->hostname, sizeof(conn->hostname));
+                memcpy(conn->vendor, packet->vendor, sizeof(conn->vendor));
+                pptp_reset_timer(); /* 60 seconds until keep-alive */
+                log("Client connection established.");
+                if (conn->callback != NULL)
+                    conn->callback(conn, CONN_OPEN_DONE);
+            } /* else goto pptp_conn_close; */
+            break;
+        }
+            /* ----------- STANDARD Stop-Session MESSAGES ------------ */
+        case PPTP_STOP_CTRL_CONN_RQST:
+        {
+            /* conn_state should be CONN_ESTABLISHED, but it could be 
+             * something else */
+            struct pptp_stop_ctrl_conn reply = {
+                PPTP_HEADER_CTRL(PPTP_STOP_CTRL_CONN_RPLY), 
+                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
+            };
+            log("Received Stop Control Connection Request.");
+            if (conn->conn_state == CONN_IDLE) break;
+            if (pptp_send_ctrl_packet(conn, &reply, sizeof(reply))) {
+                if (conn->callback != NULL)
+                    conn->callback(conn, CONN_CLOSE_RQST);
+                conn->conn_state = CONN_IDLE;
+		return -1;
+            }
+            break;
+        }
+        case PPTP_STOP_CTRL_CONN_RPLY:
+        {
+            log("Received Stop Control Connection Reply.");
+            /* conn_state should be CONN_WAIT_STOP_REPLY, but it 
+             * could be something else */
+            if (conn->conn_state == CONN_IDLE) break;
+            conn->conn_state = CONN_IDLE;
+	    return -1;
+        }
+            /* ----------- STANDARD Echo/Keepalive MESSAGES ------------ */
+        case PPTP_ECHO_RPLY:
+        {
+            struct pptp_echo_rply *packet = 
+                (struct pptp_echo_rply *) buffer;
+            logecho( PPTP_ECHO_RPLY);
+            if ((conn->ka_state == KA_OUTSTANDING) && 
+                    (ntoh32(packet->identifier) == conn->ka_id)) {
+                conn->ka_id++;
+                conn->ka_state = KA_NONE;
+                pptp_reset_timer();
+            }
+            break;
+        }
+        case PPTP_ECHO_RQST:
+        {
+            struct pptp_echo_rqst *packet = 
+                (struct pptp_echo_rqst *) buffer;
+            struct pptp_echo_rply reply = {
+                PPTP_HEADER_CTRL(PPTP_ECHO_RPLY), 
+                packet->identifier, /* skip hton32(ntoh32(id)) */
+                hton8(1), hton8(PPTP_GENERAL_ERROR_NONE), 0
+            };
+            logecho( PPTP_ECHO_RQST);
+            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
+            pptp_reset_timer();
+            break;
+        }
+            /* ----------- OUTGOING CALL MESSAGES ------------ */
+        case PPTP_OUT_CALL_RQST:
+        {
+            struct pptp_out_call_rqst *packet =
+                (struct pptp_out_call_rqst *)buffer;
+            struct pptp_out_call_rply reply = {
+                PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
+                0 /* callid */, packet->call_id, 1, PPTP_GENERAL_ERROR_NONE, 0,
+                hton32(PPTP_CONNECT_SPEED), 
+                hton16(PPTP_WINDOW), hton16(PPTP_DELAY), 0 
+            };
+            log("Received Outgoing Call Request.");
+            /* XXX PAC: eventually this should make an outgoing call. XXX */
+            reply.result_code = hton8(7); /* outgoing calls verboten */
+            pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
+            break;
+        }
+        case PPTP_OUT_CALL_RPLY:
+        {
+            struct pptp_out_call_rply *packet =
+                (struct pptp_out_call_rply *)buffer;
+            PPTP_CALL * call;
+            u_int16_t callid = ntoh16(packet->call_id_peer);
+            log("Received Outgoing Call Reply.");
+            if (!vector_search(conn->call, (int) callid, &call)) {
+                log("PPTP_OUT_CALL_RPLY received for non-existant call: "
+                        "peer call ID (us)  %d call ID (them) %d.",
+                        callid, ntoh16(packet->call_id));
+                break;
+            }
+            if (call->call_type != PPTP_CALL_PNS) {
+                log("Ack!  How did this call_type get here?"); /* XXX? */
+                break; 
+            }
+            if (call->state.pns != PNS_WAIT_REPLY) {
+                warn("Unexpected(?) Outgoing Call Reply will be ignored.");
+                break;
+            }
+            /* check for errors */
+            if (packet->result_code != 1) {
+                /* An error.  Log it verbosely. */
+                log("Our outgoing call request [callid %d] has not been "
+                        "accepted.", (int) callid);
+                ctrlp_error(packet->result_code, packet->error_code,
+                        packet->cause_code, pptp_out_call_reply_result,
+                        MAX_OUT_CALL_REPLY_RESULT);
+                call->state.pns = PNS_IDLE;
+                if (call->callback != NULL)
+                    call->callback(conn, call, CALL_OPEN_FAIL);
+                pptp_call_destroy(conn, call);
+            } else {
+                /* connection established */
+                call->state.pns = PNS_ESTABLISHED;
+                call->peer_call_id = ntoh16(packet->call_id);
+                call->speed        = ntoh32(packet->speed);
+                pptp_reset_timer();
+                /* call pptp_set_link. unless the user specified a quirk
+                   and this quirk has a set_link hook, this is a noop */
+                pptp_set_link(conn, call->peer_call_id);
+                if (call->callback != NULL)
+                    call->callback(conn, call, CALL_OPEN_DONE);
+                log("Outgoing call established (call ID %u, peer's "
+                        "call ID %u).\n", call->call_id, call->peer_call_id);
+            }
+            break;
+        }
+            /* ----------- INCOMING CALL MESSAGES ------------ */
+            /* XXX write me XXX */
+            /* ----------- CALL CONTROL MESSAGES ------------ */
+        case PPTP_CALL_CLEAR_RQST:
+        {
+            struct pptp_call_clear_rqst *packet =
+                (struct pptp_call_clear_rqst *)buffer;
+            struct pptp_call_clear_ntfy reply = {
+                PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY), packet->call_id,
+                1, PPTP_GENERAL_ERROR_NONE, 0, 0, {0}
+            };
+            log("Received Call Clear Request.");
+            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
+                PPTP_CALL * call;
+                vector_search(conn->call, ntoh16(packet->call_id), &call);
+                if (call->callback != NULL)
+                    call->callback(conn, call, CALL_CLOSE_RQST);
+                pptp_send_ctrl_packet(conn, &reply, sizeof(reply));
+                pptp_call_destroy(conn, call);
+                log("Call closed (RQST) (call id %d)", (int) call->call_id);
+            }
+            break;
+        }
+        case PPTP_CALL_CLEAR_NTFY:
+        {
+            struct pptp_call_clear_ntfy *packet =
+                (struct pptp_call_clear_ntfy *)buffer;
+            log("Call disconnect notification received (call id %d)",
+                    ntoh16(packet->call_id));
+            if (vector_contains(conn->call, ntoh16(packet->call_id))) {
+                PPTP_CALL * call;
+                ctrlp_error(packet->result_code, packet->error_code,
+                        packet->cause_code, pptp_call_disc_ntfy,
+                        MAX_CALL_DISC_NTFY);
+                vector_search(conn->call, ntoh16(packet->call_id), &call);
+                pptp_call_destroy(conn, call);
+            }
+            /* XXX we could log call stats here XXX */
+            /* XXX not all servers send this XXX */
+            break;
+        }
+        case PPTP_SET_LINK_INFO:
+        {
+            /* I HAVE NO CLUE WHAT TO DO IF send_accm IS NOT 0! */
+            /* this is really dealt with in the HDLC deencapsulation, anyway. */
+            struct pptp_set_link_info *packet =
+                (struct pptp_set_link_info *)buffer;
+            /* log it. */
+            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",
+                    (unsigned long) ntoh32(packet->send_accm),
+                    (unsigned long) ntoh32(packet->recv_accm));
+            if (!(ntoh32(packet->send_accm) == 0 &&
+                    ntoh32(packet->recv_accm) == 0))
+                warn("Non-zero Async Control Character Maps are not supported!");
+            break;
+        }
+        default:
+            log("Unrecognized Packet %d received.", 
+                    (int) ntoh16(((struct pptp_header *)buffer)->ctrl_type));
+            /* goto pptp_conn_close; */
+            break;
+    }
+    return 0;
 pptp_conn_close:
-  warn("pptp_conn_close(%d)", (int) close_reason);
-  pptp_conn_close(conn, close_reason);
+    warn("pptp_conn_close(%d)", (int) close_reason);
+    pptp_conn_close(conn, close_reason);
+    return 0;
 }
 
-void
-pptp_set_link(PPTP_CONN* conn, int peer_call_id)
+/*** pptp_set_link **************************************************************/
+void pptp_set_link(PPTP_CONN* conn, int peer_call_id)
 {
     int idx, rc;
-
     /* if we need to send a set_link packet because of buggy
        hardware or pptp server, do it now */
     if ((idx = get_quirk_index()) != -1 && pptp_fixups[idx].set_link_hook) {
-	struct pptp_set_link_info packet;
-	if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
-	    warn("calling the set_link hook failed (%d)", rc);
-
-	if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
-	    pptp_reset_timer();
-	}
+        struct pptp_set_link_info packet;
+        if ((rc = pptp_fixups[idx].set_link_hook(&packet, peer_call_id)))
+            warn("calling the set_link hook failed (%d)", rc);
+        if (pptp_send_ctrl_packet(conn, &packet, sizeof(packet))) {
+            pptp_reset_timer();
+        }
     }
 }
 
-/********************* Get info from call structure *******************/
-
+/*** Get info from call structure *********************************************/
 /* NOTE: The peer_call_id is undefined until we get a server response. */
 void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
-		       u_int16_t * call_id, u_int16_t * peer_call_id) {
-  assert(conn!=NULL); assert(call != NULL);
-  *call_id = call->call_id;
-  *peer_call_id = call->peer_call_id;
-}
-void   pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl) {
-  assert(conn != NULL); assert(call != NULL);
-  call->closure = cl;
-}
-void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call) {
-  assert(conn != NULL); assert(call != NULL);
-  return call->closure;
-}
-void   pptp_conn_closure_put(PPTP_CONN * conn, void *cl) {
-  assert(conn != NULL);
-  conn->closure = cl;
-}
-void * pptp_conn_closure_get(PPTP_CONN * conn) {
-  assert(conn != NULL);
-  return conn->closure;
-}
-
-/*********************** Handle keep-alive timer ***************/
-static void pptp_reset_timer(void) {
-  const struct itimerval tv = { {  0, 0 },   /* stop on time-out */
-				{ PPTP_TIMEOUT, 0 } }; /* 60-second timer */
-  setitimer(ITIMER_REAL, &tv, NULL);
-}
-
-static void pptp_handle_timer(int sig) {
-  int i;
-  /* "Keep Alives and Timers, 1": check connection state */
-  if (global.conn->conn_state != CONN_ESTABLISHED) {
-    if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) 
-      /* hard close. */
-      pptp_conn_destroy(global.conn);
-    else /* soft close */
-      pptp_conn_close(global.conn, PPTP_STOP_NONE);
-  }
-  /* "Keep Alives and Timers, 2": check echo status */
-  if (global.conn->ka_state == KA_OUTSTANDING) /*no response to keep-alive*/
-    pptp_conn_close(global.conn, PPTP_STOP_NONE);
-  else { /* ka_state == NONE */ /* send keep-alive */
-    struct pptp_echo_rqst rqst = {
-      PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
-    pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst));
-    global.conn->ka_state = KA_OUTSTANDING;
-    /* XXX FIXME: wake up ctrl thread -- or will the SIGALRM do that
-     * automagically? XXX
-     */
-  }
-  /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
-  for (i=0; i<vector_size(global.conn->call); i++) {
-    PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
-    if (call->call_type == PPTP_CALL_PNS) {
-      if (call->state.pns==PNS_WAIT_REPLY) {
-	/* send close request */
-	pptp_call_close(global.conn, call);
-	assert(call->state.pns==PNS_WAIT_DISCONNECT);
-      } else if (call->state.pns==PNS_WAIT_DISCONNECT) {
-	/* hard-close the call */
-	pptp_call_destroy(global.conn, call);
-      }
-    } else if (call->call_type == PPTP_CALL_PAC) {
-      if (call->state.pac == PAC_WAIT_REPLY) {
-	/* XXX FIXME -- drop the PAC connection XXX */
-      } else if (call->state.pac == PAC_WAIT_CS_ANS) {
-	/* XXX FIXME -- drop the PAC connection XXX */
-      }
+		       u_int16_t * call_id, u_int16_t * peer_call_id)
+{
+    assert(conn != NULL); assert(call != NULL);
+    *call_id = call->call_id;
+    *peer_call_id = call->peer_call_id;
+}
+
+/*** pptp_call_closure_put ****************************************************/
+void   pptp_call_closure_put(PPTP_CONN * conn, PPTP_CALL * call, void *cl)
+{
+    assert(conn != NULL); assert(call != NULL);
+    call->closure = cl;
+}
+
+/*** pptp_call_closure_get ****************************************************/
+void * pptp_call_closure_get(PPTP_CONN * conn, PPTP_CALL * call)
+{
+    assert(conn != NULL); assert(call != NULL);
+    return call->closure;
+}
+
+/*** pptp_conn_closure_put ****************************************************/
+void   pptp_conn_closure_put(PPTP_CONN * conn, void *cl)
+{
+    assert(conn != NULL);
+    conn->closure = cl;
+}
+
+/*** pptp_conn_closure_get ****************************************************/
+void * pptp_conn_closure_get(PPTP_CONN * conn)
+{
+    assert(conn != NULL);
+    return conn->closure;
+}
+
+/*** Reset keep-alive timer ***************************************************/
+static void pptp_reset_timer(void)
+{
+    const struct itimerval tv = { {  0, 0 },   /* stop on time-out */
+        { idle_wait, 0 } };
+    if (idle_wait) setitimer(ITIMER_REAL, &tv, NULL);
+}
+
+
+/*** Handle keep-alive timer **************************************************/
+static void pptp_handle_timer()
+{
+    int i;
+    /* "Keep Alives and Timers, 1": check connection state */
+    if (global.conn->conn_state != CONN_ESTABLISHED) {
+        if (global.conn->conn_state == CONN_WAIT_STOP_REPLY) 
+            /* hard close. */
+            pptp_conn_destroy(global.conn);
+        else /* soft close */
+            pptp_conn_close(global.conn, PPTP_STOP_NONE);
+    }
+    /* "Keep Alives and Timers, 2": check echo status */
+    if (global.conn->ka_state == KA_OUTSTANDING) {
+        /* no response to keep-alive */
+        log ("closing control connection due to missing echo reply");
+	pptp_conn_close(global.conn, PPTP_STOP_NONE);
+    } else { /* ka_state == NONE */ /* send keep-alive */
+        struct pptp_echo_rqst rqst = {
+            PPTP_HEADER_CTRL(PPTP_ECHO_RQST), hton32(global.conn->ka_id) };
+        pptp_send_ctrl_packet(global.conn, &rqst, sizeof(rqst));
+        global.conn->ka_state = KA_OUTSTANDING;
+    }
+    /* check incoming/outgoing call states for !IDLE && !ESTABLISHED */
+    for (i = 0; i < vector_size(global.conn->call); i++) {
+        PPTP_CALL * call = vector_get_Nth(global.conn->call, i);
+        if (call->call_type == PPTP_CALL_PNS) {
+            if (call->state.pns == PNS_WAIT_REPLY) {
+                /* send close request */
+                pptp_call_close(global.conn, call);
+                assert(call->state.pns == PNS_WAIT_DISCONNECT);
+            } else if (call->state.pns == PNS_WAIT_DISCONNECT) {
+                /* hard-close the call */
+                pptp_call_destroy(global.conn, call);
+            }
+        } else if (call->call_type == PPTP_CALL_PAC) {
+            if (call->state.pac == PAC_WAIT_REPLY) {
+                /* XXX FIXME -- drop the PAC connection XXX */
+            } else if (call->state.pac == PAC_WAIT_CS_ANS) {
+                /* XXX FIXME -- drop the PAC connection XXX */
+            }
+        }
     }
-  }
-  pptp_reset_timer();
+    pptp_reset_timer();
 }
diff -Naur tomato/release/src/router/pptp-client/pptp_ctrl.h tomato121/release/src/router/pptp-client/pptp_ctrl.h
--- tomato/release/src/router/pptp-client/pptp_ctrl.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_ctrl.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* pptp_ctrl.h ... handle PPTP control connection.
  *                 C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_ctrl.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_ctrl.h,v 1.5 2004/11/09 01:42:32 quozl Exp $
  */
 
 #ifndef INC_PPTP_CTRL_H
@@ -27,6 +27,7 @@
 			   pptp_conn_cb callback);
 PPTP_CALL * pptp_call_open(PPTP_CONN * conn, 
 			   pptp_call_cb callback, char *phonenr);
+int pptp_conn_established(PPTP_CONN * conn);
 /* soft close.  Will callback on completion. */
 void pptp_call_close(PPTP_CONN * conn, PPTP_CALL * call);
 /* hard close. */
@@ -39,7 +40,7 @@
 /* Add file descriptors used by pptp to fd_set. */
 void pptp_fd_set(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set, int *max_fd);
 /* handle any pptp file descriptors set in fd_set, and clear them */
-void pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set);
+int pptp_dispatch(PPTP_CONN * conn, fd_set * read_set, fd_set * write_set);
 
 /* Get info about connection, call */
 void pptp_call_get_ids(PPTP_CONN * conn, PPTP_CALL * call,
diff -Naur tomato/release/src/router/pptp-client/pptp_gre.c tomato121/release/src/router/pptp-client/pptp_gre.c
--- tomato/release/src/router/pptp-client/pptp_gre.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_gre.c	2008-04-22 21:44:06.000000000 +1000
@@ -2,7 +2,7 @@
  *                Handle the IP Protocol 47 portion of PPTP.
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_gre.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_gre.c,v 1.39 2005/07/11 03:23:48 quozl Exp $
  */
 
 #include <sys/types.h>
@@ -17,94 +17,162 @@
 #include <fcntl.h>
 #include "ppp_fcs.h"
 #include "pptp_msg.h"
+#include "pptp_gre.h"
 #include "util.h"
+#include "pqueue.h"
 
 #define PACKET_MAX 8196
 /* test for a 32 bit counter overflow */
 #define WRAPPED( curseq, lastseq) \
-    ((((curseq) & 0xffffff00)==0) && (((lastseq) & 0xffffff00 )==0xffffff00))
+    ((((curseq) & 0xffffff00) == 0) && \
+     (((lastseq) & 0xffffff00 ) == 0xffffff00))
 
 static u_int32_t ack_sent, ack_recv;
 static u_int32_t seq_sent, seq_recv;
 static u_int16_t pptp_gre_call_id, pptp_gre_peer_call_id;
+gre_stats_t stats;
 
-/* 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
 #include <stdio.h>
-void print_packet(int fd, void *pack, unsigned int len) {
-  unsigned char *b = (unsigned char *)pack;
-  unsigned int i,j;
-  FILE *out = fdopen(fd, "w");
-
-  fprintf(out,"-- begin packet (%u) --\n", len);
-  for (i=0; i<len; i+=16) {
-    for (j=0; j<8; j++)
-      if (i+2*j+1<len)
-	fprintf(out, "%02x%02x ", 
-		(unsigned int) b[i+2*j], (unsigned int) b[i+2*j+1]);
-      else if (i+2*j<len)
-	fprintf(out, "%02x ", (unsigned int) b[i+2*j]);
-    fprintf(out, "\n");
-  }
-  fprintf(out, "-- end packet --\n");
-  fflush(out);
+void print_packet(int fd, void *pack, unsigned int len)
+{
+    unsigned char *b = (unsigned char *)pack;
+    unsigned int i,j;
+    FILE *out = fdopen(fd, "w");
+    fprintf(out,"-- begin packet (%u) --\n", len);
+    for (i = 0; i < len; i += 16) {
+        for (j = 0; j < 8; j++)
+            if (i + 2 * j + 1 < len)
+                fprintf(out, "%02x%02x ", 
+                        (unsigned int) b[i + 2 * j],
+                        (unsigned int) b[i + 2 * j + 1]);
+            else if (i + 2 * j < len)
+                fprintf(out, "%02x ", (unsigned int) b[i + 2 * j]);
+        fprintf(out, "\n");
+    }
+    fprintf(out, "-- end packet --\n");
+    fflush(out);
 }
 #endif
 
-void pptp_gre_copy(u_int16_t call_id, u_int16_t peer_call_id, 
-		   int pty_fd, 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;
-
-  /* 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;
-  }
-  /* 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 */
-
-  /* Dispatch loop */
-  for (;;) { /* until error happens on s or pty_fd */
-    struct timeval tv = {0, 0}; /* non-blocking select */
-    fd_set rfds;
-    int retval;
-
-    /* watch terminal and socket for input */
-    FD_ZERO(&rfds);
-    FD_SET(s, &rfds);
-    FD_SET(pty_fd,&rfds);
-
-    /* if there is a pending ACK, do non-blocking select,
-       otherwise, block until data is available */
-    retval = select(n, &rfds, NULL, NULL, (ack_sent != seq_recv) ? &tv : NULL);
-
-    if (retval == 0 && ack_sent != seq_recv) /* if outstanding ack */
-      encaps_gre(s, 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;
-  }
+/*** time_now_usecs ***********************************************************/
+uint64_t time_now_usecs()
+{
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return (tv.tv_sec * 1000000) + tv.tv_usec;
+}
+
+/*** Open IP protocol socket **************************************************/
+int pptp_gre_bind(struct in_addr inetaddr)
+{
+    struct sockaddr_in src_addr, loc_addr;
+    extern struct in_addr localbind;
+    int s = socket(AF_INET, SOCK_RAW, PPTP_PROTO);
+    if (s < 0) { warn("socket: %s", strerror(errno)); return -1; }
+    if (localbind.s_addr != INADDR_NONE) {
+        bzero(&loc_addr, sizeof(loc_addr));
+        loc_addr.sin_family = AF_INET;
+        loc_addr.sin_addr   = localbind;
+        if (bind(s, (struct sockaddr *) &loc_addr, sizeof(loc_addr)) != 0) {
+            warn("bind: %s", strerror(errno)); close(s); return -1;
+        }
+    }
+    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)); close(s); return -1;
+    }
+    return s;
+}
 
-  /* Close up when done. */
-  close(s); close(pty_fd);
+/*** pptp_gre_copy ************************************************************/
+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;
+    /* weird select semantics */
+    max_fd = gre_fd;
+    if (pty_fd > max_fd) max_fd = pty_fd;
+    /* Dispatch loop */
+    for (;;) { /* until error happens on gre_fd or pty_fd */
+        struct timeval tv = {0, 0};
+        struct timeval *tvp;
+        fd_set rfds;
+        int retval;
+        pqueue_t *head;
+        int block_usecs = -1; /* wait forever */
+        /* watch terminal and socket for input */
+        FD_ZERO(&rfds);
+        FD_SET(gre_fd, &rfds);
+        FD_SET(pty_fd, &rfds);
+        /*
+         * if there are multiple pending ACKs, then do a minimal timeout;
+         * else if there is a single pending ACK then timeout after 0,5 seconds;
+         * else block until data is available.
+         */
+        if (ack_sent != seq_recv) {
+            if (ack_sent + 1 == seq_recv)  /* u_int wrap-around safe */
+                block_usecs = 500000;
+            else
+                /* don't use zero, this will force a resceduling */
+                /* when calling select(), giving pppd a chance to */
+                /* run. */
+                block_usecs = 1;
+        }
+        /* otherwise block_usecs == -1, which means wait forever */
+        /*
+         * If there is a packet in the queue, then don't wait longer than
+         * the time remaining until it expires.
+         */
+        head = pqueue_head();
+        if (head != NULL) {
+            int expiry_time = pqueue_expiry_time(head);
+            if (block_usecs == -1 || expiry_time < block_usecs)
+                block_usecs = expiry_time;
+        }
+        if (block_usecs == -1) {
+            tvp = NULL;
+        } else {
+            tvp = &tv;
+            tv.tv_usec = block_usecs;
+            tv.tv_sec  = tv.tv_usec / 1000000;
+            tv.tv_usec %= 1000000;
+        }
+        retval = select(max_fd + 1, &rfds, NULL, NULL, tvp);
+        if (FD_ISSET(pty_fd, &rfds)) {
+            if (decaps_hdlc(pty_fd, encaps_gre,  gre_fd) < 0)
+                break;
+        } else if (retval == 0 && ack_sent != seq_recv) {
+            /* if outstanding ack */
+            /* send ack with no payload */
+            encaps_gre(gre_fd, NULL, 0);         
+        }
+        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(gre_fd);
+    close(pty_fd);
 }
 
 #define HDLC_FLAG         0x7E
@@ -113,202 +181,343 @@
 
 /* ONE blocking read per call; dispatches all packets possible */
 /* returns 0 on success, or <0 on read failure                 */
-int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl) {
-  unsigned char buffer[PACKET_MAX];
-  unsigned int start = 0;
-  int end;
-  int status;
-
-  static unsigned int len = 0, escape = 0;
-  static unsigned char copy[PACKET_MAX];
-  
-  /* start is start of packet.  end is end of buffer data */
-  /*  this is the only blocking read we will allow */
-
-  if ((end = read (fd, buffer, sizeof(buffer))) <= 0) {
-    log ("short read (%u): %s", end, strerror(errno));
-    return -1;
-  }
-  
-  while (start < end) {
-
-    /* Copy to 'copy' and un-escape as we go. */
-
-    while (buffer[start] != HDLC_FLAG) {
-      if ((escape == 0) && buffer[start] == HDLC_ESCAPE) {
-	escape = HDLC_TRANSPARENCY;
-      } else {
-        if (len < PACKET_MAX)
-	  copy [len++] = buffer[start] ^ escape;
-        escape = 0;
-      }
-      start++;
-
-      if (start >= end)
-        return 0; /* No more data, but the frame is not complete yet. */
-    }
-
-    /* found flag.  skip past it */
-    start++;
-
-    /* check for over-short packets and silently discard, as per RFC1662 */
-    if ((len < 4) || (escape != 0)) {
-      len = 0; escape = 0;
-      continue;
-    }
-    /* check, then remove the 16-bit FCS checksum field */
-    if (pppfcs16 (PPPINITFCS16, copy, len) != PPPGOODFCS16)
-      log("Bad Frame Check Sequence during PPP to GRE decapsulation");
-    len -= sizeof(u_int16_t);
-
-    /* so now we have a packet of length 'len' in 'copy' */
-    if ((status = cb (cl, copy, len)) < 0)
-      return status; /* error-check */
-
-    /* Great!  Let's do more! */
-    len = 0; escape = 0;
-  }
-
-  return 0;
-  /* No more data to process. */
+int decaps_hdlc(int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl)
+{
+    unsigned char buffer[PACKET_MAX];
+    unsigned int start = 0;
+    int end;
+    int status;
+    static unsigned int len = 0, escape = 0;
+    static unsigned char copy[PACKET_MAX];
+    static int checkedsync = 0;
+    /* start is start of packet.  end is end of buffer data */
+    /*  this is the only blocking read we will allow */
+    if ((end = read (fd, buffer, sizeof(buffer))) <= 0) {
+        int saved_errno = errno;
+        warn("short read (%d): %s", end, strerror(saved_errno));
+	switch (saved_errno) {
+	  case EMSGSIZE: {
+	    int optval, optlen = sizeof(optval);
+	    warn("transmitted GRE packet triggered an ICMP destination unreachable, fragmentation needed, or exceeds the MTU of the network interface");
+#define IP_MTU 14
+	    if(getsockopt(fd, IPPROTO_IP, IP_MTU, &optval, &optlen) < 0)
+	      warn("getsockopt: %s", strerror(errno));
+	    warn("getsockopt: IP_MTU: %d\n", optval);
+	    return 0;
+	  }
+	case EIO:
+    	    warn("pppd may have shutdown, see pppd log");
+	    break;
+	}
+        return -1;
+    }
+    /* warn if the sync options of ppp and pptp don't match */
+    if( !checkedsync) {
+        checkedsync = 1;
+        if( buffer[0] == HDLC_FLAG){
+            if( syncppp )
+                warn( "pptp --sync option is active, "
+                        "yet the ppp mode is asynchronous!\n");
+        }
+	else if( !syncppp )
+            warn( "The ppp mode is synchronous, "
+                    "yet no pptp --sync option is specified!\n");
+    }
+    /* in synchronous mode there are no hdlc control characters nor checksum
+     * bytes. Find end of packet with the length information in the PPP packet
+     */
+    if ( syncppp ){
+        while ( start + 8 < end) {
+            len = ntoh16(*(short int *)(buffer + start + 6)) + 4;
+            /* note: the buffer may contain an incomplete packet at the end
+             * this packet will be read again at the next read() */
+            if ( start + len <= end)
+                if ((status = cb (cl, buffer + start, len)) < 0)
+                    return status; /* error-check */
+            start += len;
+        }
+        return 0;
+    }
+    /* asynchronous mode */
+    while (start < end) {
+        /* Copy to 'copy' and un-escape as we go. */
+        while (buffer[start] != HDLC_FLAG) {
+            if ((escape == 0) && buffer[start] == HDLC_ESCAPE) {
+                escape = HDLC_TRANSPARENCY;
+            } else {
+                if (len < PACKET_MAX)
+                    copy [len++] = buffer[start] ^ escape;
+                escape = 0;
+            }
+            start++;
+            if (start >= end)
+                return 0; /* No more data, but the frame is not complete yet. */
+        }
+        /* found flag.  skip past it */
+        start++;
+        /* check for over-short packets and silently discard, as per RFC1662 */
+        if ((len < 4) || (escape != 0)) {
+            len = 0; escape = 0;
+            continue;
+        }
+        /* check, then remove the 16-bit FCS checksum field */
+        if (pppfcs16 (PPPINITFCS16, copy, len) != PPPGOODFCS16)
+            warn("Bad Frame Check Sequence during PPP to GRE decapsulation");
+        len -= sizeof(u_int16_t);
+        /* so now we have a packet of length 'len' in 'copy' */
+        if ((status = cb (cl, copy, len)) < 0)
+            return status; /* error-check */
+        /* Great!  Let's do more! */
+        len = 0; escape = 0;
+    }
+    return 0;
+    /* No more data to process. */
 }
 
-/* Make stripped packet into HDLC packet */
-int encaps_hdlc(int fd, void *pack, unsigned int len) {
-  unsigned char *source = (unsigned char *)pack;
-  unsigned char dest[2*PACKET_MAX+2]; /* largest expansion possible */
-  unsigned int pos=0, i;
-  u_int16_t fcs;
-
-  /* Compute the FCS */
-  fcs = pppfcs16(PPPINITFCS16, source, len) ^ 0xFFFF;
-
-  /* start character */
-  dest[pos++]=HDLC_FLAG;
-  /* escape the payload */
-  for (i=0; i<len+2; i++) {
-    /* wacked out assignment to add FCS to end of source buffer */
-    unsigned char c = (i<len)?source[i]:(i==len)?(fcs&0xFF):((fcs>>8)&0xFF);
-    if (pos>=sizeof(dest)) break; /* truncate on overflow */
-    if ( (c<0x20) || (c==HDLC_FLAG) || (c==HDLC_ESCAPE) ) {
-      dest[pos++]=HDLC_ESCAPE;
-      if (pos<sizeof(dest))
-	dest[pos++]=c^0x20;
-    } else
-      dest[pos++]=c;
-  }
-  /* tack on the end-flag */
-  if (pos<sizeof(dest))
-    dest[pos++]=HDLC_FLAG;
-  
-  /* now write this packet */
-  return write(fd, dest, pos);
+/*** Make stripped packet into HDLC packet ************************************/
+int encaps_hdlc(int fd, void *pack, unsigned int len)
+{
+    unsigned char *source = (unsigned char *)pack;
+    unsigned char dest[2 * PACKET_MAX + 2]; /* largest expansion possible */
+    unsigned int pos = 0, i;
+    u_int16_t fcs;
+    /* in synchronous mode there is little to do */
+    if ( syncppp )
+        return write(fd, source, len);
+    /* asynchronous mode */
+    /* Compute the FCS */
+    fcs = pppfcs16(PPPINITFCS16, source, len) ^ 0xFFFF;
+    /* start character */
+    dest[pos++] = HDLC_FLAG;
+    /* escape the payload */
+    for (i = 0; i < len + 2; i++) {
+        /* wacked out assignment to add FCS to end of source buffer */
+        unsigned char c =
+            (i < len)?source[i]:(i == len)?(fcs & 0xFF):((fcs >> 8) & 0xFF);
+        if (pos >= sizeof(dest)) break; /* truncate on overflow */
+        if ( (c < 0x20) || (c == HDLC_FLAG) || (c == HDLC_ESCAPE) ) {
+            dest[pos++] = HDLC_ESCAPE;
+            if (pos < sizeof(dest))
+                dest[pos++] = c ^ 0x20;
+        } else
+            dest[pos++] = c;
+    }
+    /* tack on the end-flag */
+    if (pos < sizeof(dest))
+        dest[pos++] = HDLC_FLAG;
+    /* now write this packet */
+    return write(fd, dest, pos);
 }
 
-int decaps_gre (int fd, int (*cb)(int cl, void *pack, unsigned int len), int cl) {
-  unsigned char buffer[PACKET_MAX+64/*ip header*/];
-  struct pptp_gre_header *header;
-  int status, ip_len=0;
-  static int first=1;
-
-  if ((status = read (fd, buffer, sizeof(buffer))) <= 0) {
-    log("short read (%u): %s", status, strerror(errno));
-    return -1;
-  }
-
-  /* strip off IP header, if present */
-  if ((buffer[0]&0xF0)==0x40) 
-    ip_len = (buffer[0]&0xF)*4;
-  header = (struct pptp_gre_header *)(buffer+ip_len);
-
-  /* verify packet (else discard) */
-  if (((ntoh8(header->ver)&0x7F)!=PPTP_GRE_VER) || /* version should be 1   */
-      (ntoh16(header->protocol)!=PPTP_GRE_PROTO)|| /* GRE protocol for PPTP */
-      PPTP_GRE_IS_C(ntoh8(header->flags)) ||    /* flag C should be clear   */
-      PPTP_GRE_IS_R(ntoh8(header->flags)) ||    /* flag R should be clear   */
-      (!PPTP_GRE_IS_K(ntoh8(header->flags))) || /* flag K should be set     */
-      ((ntoh8(header->flags)&0xF)!=0)) { /* routing and recursion ctrl = 0  */
-    /* if invalid, discard this packet */
-    log("Discarding GRE: %X %X %X %X %X %X", 
-	 ntoh8(header->ver)&0x7F, ntoh16(header->protocol), 
-	 PPTP_GRE_IS_C(ntoh8(header->flags)),
-	 PPTP_GRE_IS_R(ntoh8(header->flags)), 
-	 PPTP_GRE_IS_K(ntoh8(header->flags)),
-	 ntoh8(header->flags)&0xF);
-    return 0;
-  }
-  if (PPTP_GRE_IS_A(ntoh8(header->ver))) { /* acknowledgement present */
-    u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))?
-      header->ack:header->seq; /* ack in different place if S=0 */
-    if (ack > ack_recv) ack_recv = ack;
-    /* also handle sequence number wrap-around  */
-    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);
+/*** decaps_gre ***************************************************************/
+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) {
+        warn("short read (%d): %s", status, strerror(errno));
+        stats.rx_errors++;
+        return -1;
+    }
+    /* strip off IP header, if present */
+    if ((buffer[0] & 0xF0) == 0x40) 
+        ip_len = (buffer[0] & 0xF) * 4;
+    header = (struct pptp_gre_header *)(buffer + ip_len);
+    /* verify packet (else discard) */
+    if (    /* version should be 1 */
+            ((ntoh8(header->ver) & 0x7F) != PPTP_GRE_VER) ||
+            /* PPTP-GRE protocol for PPTP */
+            (ntoh16(header->protocol) != PPTP_GRE_PROTO)||
+            /* flag C should be clear   */
+            PPTP_GRE_IS_C(ntoh8(header->flags)) ||
+            /* flag R should be clear   */
+            PPTP_GRE_IS_R(ntoh8(header->flags)) ||
+            /* flag K should be set     */
+            (!PPTP_GRE_IS_K(ntoh8(header->flags))) ||
+            /* routing and recursion ctrl = 0  */
+            ((ntoh8(header->flags)&0xF) != 0)) {
+        /* if invalid, discard this packet */
+        warn("Discarding GRE: %X %X %X %X %X %X", 
+                ntoh8(header->ver)&0x7F, ntoh16(header->protocol), 
+                PPTP_GRE_IS_C(ntoh8(header->flags)),
+                PPTP_GRE_IS_R(ntoh8(header->flags)), 
+                PPTP_GRE_IS_K(ntoh8(header->flags)),
+                ntoh8(header->flags) & 0xF);
+        stats.rx_invalid++;
+        return 0;
+    }
+    /* silently discard packets not for this call */
+    if (ntoh16(header->call_id) != pptp_gre_call_id) return 0;
+    /* test if acknowledgement present */
+    if (PPTP_GRE_IS_A(ntoh8(header->ver))) { 
+        u_int32_t ack = (PPTP_GRE_IS_S(ntoh8(header->flags)))?
+            header->ack:header->seq; /* ack in different place if S = 0 */
+        ack = ntoh32( ack);
+        if (ack > ack_recv) ack_recv = ack;
+        /* also handle sequence number wrap-around  */
+        if (WRAPPED(ack,ack_recv)) ack_recv = ack;
+        if (ack_recv == stats.pt.seq) {
+            int rtt = time_now_usecs() - stats.pt.time;
+            stats.rtt = (stats.rtt + rtt) / 2;
+        }
+    }
+    /* test if payload present */
+    if (!PPTP_GRE_IS_S(ntoh8(header->flags)))
+        return 0; /* ack, but no payload */
+    headersize  = sizeof(*header);
+    payload_len = ntoh16(header->payload_len);
+    seq         = ntoh32(header->seq);
+    /* no ack present? */
+    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);
+    if (status - headersize < payload_len) {
+        warn("discarding truncated packet (expected %d, got %d bytes)",
+                payload_len, status - headersize);
+        stats.rx_truncated++;
+        return 0; 
+    }
+    /* check for expected sequence number */
+    if ( first || (seq == seq_recv + 1)) { /* wrap-around safe */
+	if ( log_level >= 2 )
+            log("accepting packet %d", seq);
+        stats.rx_accepted++;
+        first = 0;
+        seq_recv = seq;
+        return callback(cl, buffer + ip_len + headersize, payload_len);
+    /* out of order, check if the number is too low and discard the packet. 
+     * (handle sequence number wrap-around, and try to do it right) */
+    } else if ( seq < seq_recv + 1 || WRAPPED(seq_recv, seq) ) {
+	if ( log_level >= 1 )
+            log("discarding duplicate or old packet %d (expecting %d)",
+                seq, seq_recv + 1);
+        stats.rx_underwin++;
+    /* sequence number too high, is it reasonably close? */
+    } else if ( seq < seq_recv + MISSING_WINDOW ||
+                WRAPPED(seq, seq_recv + MISSING_WINDOW) ) {
+	stats.rx_buffered++;
+        if ( log_level >= 1 )
+            log("%s packet %d (expecting %d, lost or reordered)",
+                disable_buffer ? "accepting" : "buffering",
+                seq, seq_recv+1);
+        if ( disable_buffer ) {
+            seq_recv = seq;
+            stats.rx_lost += seq - seq_recv - 1;
+            return callback(cl, buffer + ip_len + headersize, payload_len);
+        } else {
+            pqueue_add(seq, buffer + ip_len + headersize, payload_len);
+	}
+    /* no, packet must be discarded */
     } else {
-      log("discarding out-of-order  seq is %d seqrecv is %d", seq, seq_recv); 
-      return 0; /* discard out-of-order packets */
+	if ( log_level >= 1 )
+            warn("discarding bogus packet %d (expecting %d)", 
+		 seq, seq_recv + 1);
+        stats.rx_overwin++;
     }
-  }
-  return 0; /* ack, but no payload */
-}
-int encaps_gre (int fd, void *pack, unsigned int len) {
-  union {
-    struct pptp_gre_header header;
-    unsigned char buffer[PACKET_MAX+sizeof(struct pptp_gre_header)];
-  } u;
-  static u_int32_t seq=0;
-  unsigned int header_len;
-
-  /* package this up in a GRE shell. */
-  u.header.flags	= hton8 (PPTP_GRE_FLAG_K);
-  u.header.ver  	= hton8 (PPTP_GRE_VER);
-  u.header.protocol	= hton16(PPTP_GRE_PROTO);
-  u.header.payload_len	= hton16(len);
-  u.header.call_id	= hton16(pptp_gre_peer_call_id);
-  
-  /* special case ACK with no payload */
-  if (pack==NULL) {
-    if (ack_sent != seq_recv) {
-      u.header.ver |= hton8(PPTP_GRE_FLAG_A);
-      u.header.payload_len = hton16(0);
-      u.header.seq = hton32(seq_recv); /* ack is in odd place because S=0 */
-      ack_sent = seq_recv;
-      return write(fd, &u.header, sizeof(u.header)-sizeof(u.header.seq));
-    } else return 0; /* we don't need to send ACK */
-  } /* explicit brace to avoid ambiguous `else' warning */
-  /* send packet with payload */
-  u.header.flags |= hton8(PPTP_GRE_FLAG_S);
-  u.header.seq    = hton32(seq);
-  if (ack_sent != seq_recv) { /* send ack with this message */
-    u.header.ver |= hton8(PPTP_GRE_FLAG_A);
-    u.header.ack  = hton32(seq_recv);
-    ack_sent = seq_recv;
-    header_len = sizeof(u.header);
-  } else { /* don't send ack */
-    header_len = sizeof(u.header) - sizeof(u.header.ack);
-  }
-  if (header_len+len>=sizeof(u.buffer)) return 0; /* drop this, it's too big */
-  /* copy payload into buffer */
-  memcpy(u.buffer+header_len, pack, len);
-  /* record and increment sequence numbers */
-  seq_sent = seq; seq++;
-  /* write this baby out to the net */
-  /* print_packet(2, u.buffer, header_len+len); */
-  return write(fd, u.buffer, header_len+len);
+    return 0;
 }
 
+/*** dequeue_gre **************************************************************/
+int dequeue_gre (callback_t callback, int cl)
+{
+    pqueue_t *head;
+    int status;
+    /* process packets in the queue that either are expected or have 
+     * timed out. */
+    head = pqueue_head();
+    while ( head != NULL &&
+            ( (head->seq == seq_recv + 1) || /* wrap-around safe */ 
+              (pqueue_expiry_time(head) <= 0) 
+            )
+          ) {
+        /* if it is timed out... */
+        if (head->seq != seq_recv + 1 ) {  /* wrap-around safe */          
+            stats.rx_lost += head->seq - seq_recv - 1;
+	    if (log_level >= 2)
+                log("timeout waiting for %d packets", head->seq - seq_recv - 1);
+        }
+	if (log_level >= 2)
+            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;
+}
 
+/*** encaps_gre ***************************************************************/
+int encaps_gre (int fd, void *pack, unsigned int len)
+{
+    union {
+        struct pptp_gre_header header;
+        unsigned char buffer[PACKET_MAX + sizeof(struct pptp_gre_header)];
+    } u;
+    static u_int32_t seq = 1; /* first sequence number sent must be 1 */
+    unsigned int header_len;
+    int rc;
+    /* package this up in a GRE shell. */
+    u.header.flags       = hton8 (PPTP_GRE_FLAG_K);
+    u.header.ver         = hton8 (PPTP_GRE_VER);
+    u.header.protocol    = hton16(PPTP_GRE_PROTO);
+    u.header.payload_len = hton16(len);
+    u.header.call_id     = hton16(pptp_gre_peer_call_id);
+    /* special case ACK with no payload */
+    if (pack == NULL) {
+        if (ack_sent != seq_recv) {
+            u.header.ver |= hton8(PPTP_GRE_FLAG_A);
+            u.header.payload_len = hton16(0);
+            /* ack is in odd place because S == 0 */
+            u.header.seq = hton32(seq_recv);
+            ack_sent = seq_recv;
+            rc = write(fd, &u.header, sizeof(u.header) - sizeof(u.header.seq));
+            if (rc < 0) {
+                stats.tx_failed++;
+            } else if (rc < sizeof(u.header) - sizeof(u.header.seq)) {
+                stats.tx_short++;
+            } else {
+                stats.tx_acks++;
+            }
+            return rc;
+        } else return 0; /* we don't need to send ACK */
+    } /* explicit brace to avoid ambiguous `else' warning */
+    /* send packet with payload */
+    u.header.flags |= hton8(PPTP_GRE_FLAG_S);
+    u.header.seq    = hton32(seq);
+    if (ack_sent != seq_recv) { /* send ack with this message */
+        u.header.ver |= hton8(PPTP_GRE_FLAG_A);
+        u.header.ack  = hton32(seq_recv);
+        ack_sent = seq_recv;
+        header_len = sizeof(u.header);
+    } else { /* don't send ack */
+        header_len = sizeof(u.header) - sizeof(u.header.ack);
+    }
+    if (header_len + len >= sizeof(u.buffer)) {
+        stats.tx_oversize++;
+        return 0; /* drop this, it's too big */
+    }
+    /* copy payload into buffer */
+    memcpy(u.buffer + header_len, pack, len);
+    /* record and increment sequence numbers */
+    seq_sent = seq; seq++;
+    /* write this baby out to the net */
+    /* print_packet(2, u.buffer, header_len + len); */
+    rc = write(fd, u.buffer, header_len + len);
+    if (rc < 0) {
+        stats.tx_failed++;
+    } else if (rc < header_len + len) {
+        stats.tx_short++;
+    } else {
+        stats.tx_sent++;
+        stats.pt.seq  = seq_sent;
+        stats.pt.time = time_now_usecs();
+    }
+    return rc;
+}
diff -Naur tomato/release/src/router/pptp-client/pptp_gre.h tomato121/release/src/router/pptp-client/pptp_gre.h
--- tomato/release/src/router/pptp-client/pptp_gre.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_gre.h	2008-04-22 21:44:06.000000000 +1000
@@ -2,10 +2,50 @@
  *               Handle the IP Protocol 47 portion of PPTP.
  *               C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_gre.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_gre.h,v 1.5 2004/06/09 00:13:32 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);
+
+extern int syncppp;
+extern int disable_buffer;
+
+typedef struct pack_track {
+  uint32_t seq;       // seq no of this tracked packet
+  uint64_t time;      // time when this tracked packet was sent (in usecs)
+} pack_track_t;
+
+typedef struct gre_stats {
+  /* statistics for GRE receive */
+
+  uint32_t rx_accepted;  // data packet was passed to pppd
+  uint32_t rx_lost;      // data packet did not arrive before timeout
+  uint32_t rx_underwin;  // data packet was under window (arrived too late
+                         // or duplicate packet)
+  uint32_t rx_overwin;   // data packet was over window
+                         // (too many packets lost?)
+  uint32_t rx_buffered;  // data packet arrived earlier than expected,
+                         // packet(s) before it were lost or reordered
+  uint32_t rx_errors;    // OS error on receive
+  uint32_t rx_truncated; // truncated packet
+  uint32_t rx_invalid;   // wrong protocol or invalid flags 
+  uint32_t rx_acks;      // acknowledgement only
+
+  /* statistics for GRE transmit */
+
+  uint32_t tx_sent;      // data packet write() to GRE socket succeeded
+  uint32_t tx_failed;    // data packet write() to GRE socket returned error
+  uint32_t tx_short;     // data packet write() to GRE socket underflowed
+  uint32_t tx_acks;      // sent packet with just ACK
+  uint32_t tx_oversize;  // data packet dropped because it was too large
+
+  /* statistics for packet tracking, for RTT calculation */
+
+  pack_track_t pt;       // last data packet seq/time
+  int rtt;               // estimated round-trip time in us
+
+} gre_stats_t;
+
+extern gre_stats_t stats;
diff -Naur tomato/release/src/router/pptp-client/pptp_msg.h tomato121/release/src/router/pptp-client/pptp_msg.h
--- tomato/release/src/router/pptp-client/pptp_msg.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_msg.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /*  pptp.h:  packet structures and magic constants for the PPTP protocol 
  *           C. Scott Ananian <cananian@alumni.princeton.edu>            
  *
- * $Id: pptp_msg.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_msg.h,v 1.3 2003/02/15 10:37:21 quozl Exp $
  */
 
 #ifndef INC_PPTP_H
@@ -71,30 +71,7 @@
 #define PPTP_BEARER_DIGITAL 	2
 #define PPTP_BEARER_ANY		3
 
-/* PPTP error codes: ----------------------------------------------*/
-
-/* (General Error Codes) */
-static const struct {
-  const char *name, *desc;
-} pptp_general_errors[] = {
-
-#define PPTP_GENERAL_ERROR_NONE			0
-  { "(None)", "No general error" },
-#define PPTP_GENERAL_ERROR_NOT_CONNECTED	1
-  { "(Not-Connected)", "No control connection exists yet for this "
-                       "PAC-PNS pair" },
-#define PPTP_GENERAL_ERROR_BAD_FORMAT		2
-  { "(Bad-Format)", "Length is wrong or Magic Cookie value is incorrect" },
-#define PPTP_GENERAL_ERROR_BAD_VALUE		3
-  { "(Bad-Value)", "One of the field values was out of range or "
-                    "reserved field was non-zero" },
-#define PPTP_GENERAL_ERROR_NO_RESOURCE		4
-  { "(No-Resource)", "Insufficient resources to handle this command now" },
-#define PPTP_GENERAL_ERROR_BAD_CALLID		5
-  { "(Bad-Call ID)", "The Call ID is invalid in this context" },
-#define PPTP_GENERAL_ERROR_PAC_ERROR		6
-  { "(PAC-Error)", "A generic vendor-specific error occured in the PAC" }
-};
+#define PPTP_RESULT_GENERAL_ERROR 2
 
 /* (Reasons to close a connection) */
 #define PPTP_STOP_NONE		  1 /* no good reason                        */
diff -Naur tomato/release/src/router/pptp-client/pptp_options.h tomato121/release/src/router/pptp-client/pptp_options.h
--- tomato/release/src/router/pptp-client/pptp_options.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_options.h	2008-04-22 21:44:06.000000000 +1000
@@ -2,18 +2,18 @@
  *                       #define STANDARD to emulate NT 4.0 exactly.
  *                       C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: pptp_options.h,v 1.3 2004/07/27 06:20:15 honor Exp $
+ * $Id: pptp_options.h,v 1.3 2004/11/09 01:42:32 quozl Exp $
  */
 
-#include <cyutils.h>
-
 #ifndef INC_PPTP_OPTIONS_H
 #define INC_PPTP_OPTIONS_H
 
 #undef  PPTP_FIRMWARE_STRING
 #undef  PPTP_FIRMWARE_VERSION
 #define PPTP_BUF_MAX 65536
-#define PPTP_TIMEOUT 15 /* seconds */
+#define PPTP_TIMEOUT 60 /* seconds */
+extern int idle_wait;
+extern int max_echo_wait;
 #define PPTP_CONNECT_SPEED 10000000
 #define PPTP_WINDOW 3
 #define PPTP_DELAY  0
@@ -24,8 +24,8 @@
 #define PPTP_MAX_CHANNELS 65535
 #define PPTP_FIRMWARE_STRING "0.01"
 #define PPTP_FIRMWARE_VERSION 0x001
-//#define PPTP_HOSTNAME {'l','o','c','a','l',0}
-//#define PPTP_VENDOR   {'c','a','n','a','n','i','a','n',0}
+#define PPTP_HOSTNAME {'l','o','c','a','l',0}
+#define PPTP_VENDOR   {'c','a','n','a','n','i','a','n',0}
 #define PPTP_FRAME_CAP  PPTP_FRAME_ANY
 #define PPTP_BEARER_CAP PPTP_BEARER_ANY
 #else
diff -Naur tomato/release/src/router/pptp-client/pptp_quirks.c tomato121/release/src/router/pptp-client/pptp_quirks.c
--- tomato/release/src/router/pptp-client/pptp_quirks.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_quirks.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* pptp_quirks.c ...... various options to fix quirks found in buggy adsl modems
  *                      mulix <mulix@actcom.co.il>
  *
- * $Id: pptp_quirks.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_quirks.c,v 1.2 2001/11/23 03:42:51 quozl Exp $
  */
 
 #include <string.h>
diff -Naur tomato/release/src/router/pptp-client/pptp_quirks.h tomato121/release/src/router/pptp-client/pptp_quirks.h
--- tomato/release/src/router/pptp-client/pptp_quirks.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pptp_quirks.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* pptp_quirks.h ...... various options to fix quirks found in buggy adsl modems
  *                      mulix <mulix@actcom.co.il>
  *
- * $Id: pptp_quirks.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: pptp_quirks.h,v 1.1 2001/11/20 06:30:10 quozl Exp $
  */
 
 #ifndef INC_PPTP_QUIRKS_H
diff -Naur tomato/release/src/router/pptp-client/pqueue.c tomato121/release/src/router/pptp-client/pqueue.c
--- tomato/release/src/router/pptp-client/pqueue.c	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pqueue.c	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,234 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "util.h" // for log()
+#include "pqueue.h"
+
+#ifdef DEBUG_PQUEUE
+#define DEBUG_ON 1
+#else
+#define DEBUG_ON 0
+#endif
+
+#define DEBUG_CMD(_a) if (DEBUG_ON) { _a }
+
+
+#define MIN_CAPACITY 128 /* min allocated buffer for a packet */
+
+static int pqueue_alloc (int seq, unsigned char *packet, int packlen, pqueue_t **new);
+
+int packet_timeout_usecs = DEFAULT_PACKET_TIMEOUT * 1000000;
+
+
+static pqueue_t *pq_head = NULL, *pq_tail = NULL;
+
+/* contains a list of free queue elements.*/
+static pqueue_t *pq_freelist_head = NULL;
+
+
+
+static int pqueue_alloc(int seq, unsigned char *packet, int packlen, pqueue_t **new) {
+
+  pqueue_t *newent;
+
+  DEBUG_CMD(log("seq=%d, packlen=%d", seq, packlen););
+
+  /* search the freelist for one that has sufficient space  */
+  if (pq_freelist_head) {
+
+    for (newent = pq_freelist_head; newent; newent = newent->next) {
+
+      if (newent->capacity >= packlen) {
+
+ 	/* unlink from freelist */
+	if (pq_freelist_head == newent) 
+	  pq_freelist_head = newent->next;
+
+	if (newent->prev) 
+	  newent->prev->next = newent->next;
+
+	if (newent->next) 
+	  newent->next->prev = newent->prev;
+
+	if (pq_freelist_head) 
+	  pq_freelist_head->prev = NULL;
+
+	break;
+      }	/* end if capacity >= packlen */
+    } /* end for */
+	
+    /* nothing found? Take first and reallocate it */
+    if (NULL == newent) {
+
+      newent = pq_freelist_head;
+      pq_freelist_head = pq_freelist_head->next;
+
+      if (pq_freelist_head) 
+	pq_freelist_head->prev = NULL;
+
+      DEBUG_CMD(log("realloc capacity %d to %d",newent->capacity, packlen););
+
+      newent->packet = (unsigned char *)realloc(newent->packet, packlen);
+
+      if (!newent->packet) {
+	warn("error reallocating packet: %s", strerror(errno));
+	return -1;
+      }
+      newent->capacity = packlen;
+    }
+    
+    DEBUG_CMD(log("Recycle entry from freelist. Capacity: %d", newent->capacity););
+
+  } else {
+
+    /* allocate a new one */
+    newent = (pqueue_t *)malloc( sizeof(pqueue_t) );
+    if (!newent) {
+      warn("error allocating newent: %s", strerror(errno));
+      return -1;
+    }
+    newent->capacity = 0;
+
+    DEBUG_CMD(log("Alloc new queue entry"););
+  }
+
+  if ( ! newent->capacity  ) {
+    /* a new queue entry was allocated. Allocate the packet buffer */
+    int size = packlen < MIN_CAPACITY ? MIN_CAPACITY : packlen;
+    /* Allocate at least MIN_CAPACITY */
+    DEBUG_CMD(log("allocating for packet size %d", size););
+    newent->packet = (unsigned char *)malloc(size);
+    if (!newent->packet) {
+      warn("error allocating packet: %s", strerror(errno));
+      return -1;
+    }
+    newent->capacity = size;
+  } /* endif ! capacity */
+  assert( newent->capacity >= packlen );
+  /* store the contents into the buffer */
+  memcpy(newent->packet, packet, packlen);
+
+  newent->next = newent->prev = NULL;
+  newent->seq     = seq;
+  newent->packlen = packlen;
+
+  gettimeofday(&newent->expires, NULL);
+  newent->expires.tv_usec += packet_timeout_usecs;
+  newent->expires.tv_sec  += (newent->expires.tv_usec / 1000000);
+  newent->expires.tv_usec %= 1000000;
+
+  *new = newent;
+  return 0;
+}
+
+
+
+int pqueue_add (int seq, unsigned char *packet, int packlen) {
+  pqueue_t *newent, *point;
+
+  /* get a new entry */
+  if ( 0 != pqueue_alloc(seq, packet, packlen, &newent) ) {
+    return -1;
+  }
+
+  for (point = pq_head; point != NULL; point = point->next) {
+    if (point->seq == seq) {
+      // queue already contains this packet
+      warn("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
+	DEBUG_CMD(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
+	DEBUG_CMD(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) {
+    DEBUG_CMD(log("adding %d to empty queue", seq););
+    pq_head = newent;
+  } else {
+    DEBUG_CMD(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) {
+
+  DEBUG_CMD(log("Move seq %d to freelist", point->seq););
+
+  /* unlink from pq */
+  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;
+
+  /* add point to the freelist */
+  point->next = pq_freelist_head;
+  point->prev = NULL;
+
+  if (point->next)
+    point->next->prev = point;
+  pq_freelist_head = point;
+
+  DEBUG_CMD(
+    int pq_count = 0;
+    int pq_freelist_count = 0;
+    pqueue_t *point;
+    for ( point = pq_head; point ; point = point->next) {
+      ++pq_count;
+    }
+
+    for ( point = pq_freelist_head; point ; point = point->next) {
+      ++pq_freelist_count;
+    }
+    log("queue length is %d, freelist length is %d", pq_count, pq_freelist_count);
+    );
+
+  return 0;
+}
+
+
+
+pqueue_t *pqueue_head () {
+  return pq_head;
+}
+
+
+
+int pqueue_expiry_time (pqueue_t *entry) {
+  struct timeval tv;
+  int expiry_time;
+
+  gettimeofday(&tv, NULL);
+  expiry_time  = (entry->expires.tv_sec  - tv.tv_sec) * 1000000;
+  expiry_time += (entry->expires.tv_usec - tv.tv_usec);
+  return expiry_time;
+}
diff -Naur tomato/release/src/router/pptp-client/pqueue.h tomato121/release/src/router/pptp-client/pqueue.h
--- tomato/release/src/router/pptp-client/pqueue.h	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/pqueue.h	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,30 @@
+#ifndef PQUEUE_H
+#define PQUEUE_H
+
+#include <time.h>
+#include <sys/time.h>
+
+/* wait this many seconds for missing packets before forgetting about them */
+#define DEFAULT_PACKET_TIMEOUT 0.3
+extern int packet_timeout_usecs;
+
+/* assume packet is bad/spoofed if it's more than this many seqs ahead */
+#define MISSING_WINDOW 300
+
+/* Packet queue structure: linked list of packets received out-of-order */
+typedef struct pqueue {
+  struct pqueue *next;
+  struct pqueue *prev;
+  int seq;
+  struct timeval expires;
+  unsigned char *packet;
+  int packlen;
+  int capacity;
+} pqueue_t;
+
+int       pqueue_add  (int seq, unsigned char *packet, int packlen);
+int       pqueue_del  (pqueue_t *point);
+pqueue_t *pqueue_head ();
+int       pqueue_expiry_time (pqueue_t *entry);
+
+#endif /* PQUEUE_H */
diff -Naur tomato/release/src/router/pptp-client/README tomato121/release/src/router/pptp-client/README
--- tomato/release/src/router/pptp-client/README	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/README	2008-04-22 21:44:06.000000000 +1000
@@ -1,31 +1,35 @@
-pptp-linux
+pptp
 
-pptp-linux is an implementation of the PPTP protocol for Linux and
+pptp is an implementation of the PPTP protocol for Linux and
 other Unix systems.
 
 The code is released under the terms of the GPL; see the file COPYING
 for details.
 
-You can find notes on installing and using this package in the file
-USING; design notes are in the Documentation directory; and the
-standards documents used to implement pptp-linux can be found in the
+You can find notes on installing in the file INSTALL, usage notes in
+the file USING, design notes in the Documentation directory, and the
+standards documents used to implement pptp can be found in the
 Reference directory.
 
 New versions and additional documentation can be found on the PPTP
 Client project page, at http://pptpclient.sourceforge.net/
 
-Discussion of this code now occurs on the mailing list for the PPTP
-Client project on SourceForge.  To subscribe, visit the project's
-mailing lists page, or
+Discussion of this code occurs on the mailing list for the PPTP Client
+project on SourceForge.  To subscribe, visit the project's mailing
+lists page, or
 
 http://lists.sourceforge.net/lists/listinfo/pptpclient-devel
 
 Discussion of this code used to occur on the mailing list
 pptp@debs.fuller.edu, subscribe by sending "subscribe" in the body on
 an email to pptp-request@debs.fuller.edu, or look at
-http://debs.fuller.edu.  Christoph Lameter is the list organizer.
+http://debs.fuller.edu.  Christoph Lameter was the list organizer.
 
 Re-organization and patches are of course greatly welcomed.
+See the file TODO.
 
-C. Scott Ananian <cananian@alumni.princeton.edu>
-James Cameron <james.cameron@compaq.com>
+James Cameron <james.cameron@hp.com> (maintainer, release engineer)
+C. Scott Ananian <cananian@alumni.princeton.edu> (original author)
+
+
+$Id: README,v 1.4 2004/06/22 09:52:26 quozl Exp $	
diff -Naur tomato/release/src/router/pptp-client/Reference/README tomato121/release/src/router/pptp-client/Reference/README
--- tomato/release/src/router/pptp-client/Reference/README	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/Reference/README	2008-04-22 21:44:06.000000000 +1000
@@ -1,5 +1,5 @@
 In this directory are the various standards documents implemented in
-the pptp-linux package.
+the pptp package.
 
 rfc791.txt		Internet Protocol (IP).
 rfc793.txt		Transmission Control Protocol (TCP).
@@ -11,5 +11,5 @@
 ms-chap.txt		Microsoft PPP CHAP extensions.
 pptp-draft.txt		July 1997 draft of the PPTP standard.
 
-rfc1990 is currently unimplemented in pptp-linux.
+rfc1990 is currently unimplemented in pptp
                                                         CSA, 12/12/97
diff -Naur tomato/release/src/router/pptp-client/Reference/README.Reference tomato121/release/src/router/pptp-client/Reference/README.Reference
--- tomato/release/src/router/pptp-client/Reference/README.Reference	1970-01-01 10:00:00.000000000 +1000
+++ tomato121/release/src/router/pptp-client/Reference/README.Reference	2008-04-22 21:44:06.000000000 +1000
@@ -0,0 +1,15 @@
+In this directory are the various standards documents implemented in
+the pptp package.
+
+rfc791.txt		Internet Protocol (IP).
+rfc793.txt		Transmission Control Protocol (TCP).
+rfc1661.txt		The Point-to-Point Protocol (PPP).
+rfc1662.txt		PPP in HDLC-like Framing. (serial encoding).
+rfc1701.txt		Generic Routing Encapsulation (GRE).
+rfc1702.txt		Generic Routing Encapsulation over IPv4 networks.
+rfc1990.txt		The PPP Multilink Protocol (MP).
+ms-chap.txt		Microsoft PPP CHAP extensions.
+pptp-draft.txt		July 1997 draft of the PPTP standard.
+
+rfc1990 is currently unimplemented in pptp
+                                                        CSA, 12/12/97
diff -Naur tomato/release/src/router/pptp-client/TODO tomato121/release/src/router/pptp-client/TODO
--- tomato/release/src/router/pptp-client/TODO	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/TODO	2008-04-22 21:44:06.000000000 +1000
@@ -1,11 +1,130 @@
-10th March 2002
+8th April 2005
 
-- redesign to avoid use of setjmp/longjmp.
+On Thu, Apr 07, 2005 at 07:36:41AM -0700, Roark Hennessy wrote:
+> I find in order to get the tunnel working I have to do a
+> route add -host <target_vpn_addr> gateway <my-netgear-wireless-router> dev
++ethN
+> Can this be done automatically in the config somewhere?
+
+Not everybody needs this in order to get the tunnel working, it depends
+on the configuration of the server, and it is problematic calculating
+the correct route to add.  However, the GUI PPTP client (pptpconfig)
+does this automatically, and when done unnecessarily it seems harmless.
+
+I'll take a patch that implements the same thing in C within pptp, so
+that people who don't use the GUI get it done for them.
+
+Here's what the pptpconfig.php program does;
+
+- the IP address of the PPTP server is obtained from the name, using
+  gethostbyname(),
+
+- the command "ip route get $ip | head -1" is executed, where $ip is the
+  IP address determined above, and the result of the command is stored;
+  it is a route specification of the path to the server before the
+  tunnel is started,
+
+- in routing_start(), an "ip route add" command is done using the route
+  specification obtained above,
+
+- when the tunnel is shutdown, an "ip route del" command is done using
+  the same route specification.
+
+I would prefer that the patch implements this by embedding the
+equivalent syscalls within the pptp program, rather than use system() or
+popen() to execute the /usr/sbin/ip program.
+
+I would also prefer that there be a command line option for disabling
+the feature.
+
+
+--
+
+
+10th March 2005
+
+- call manager is not being reused as it was designed to be; if a
+tunnel is started within a minute of a tunnel being stopped, it does
+not succeed; symptom is LCP ConfReq's without any traffic from the
+server.
+
+--
+
+- finish --max-echo-wait
+
+11th August 2004
+
+- add two configurable timeouts for echo generation and echo reply timeout,
+  requested by Tobias Brox.
+
+- ship .spec with tarball.
+
+5th June 2004
+
+- command line as shown by ps is corrupted.  Reported by Andre Ruiz
+  <andre@ruiz.net>
+
+5th June 2004
+
+- on Fedora Core 2, after the tunnel is stopped by the GUI, the pptp
+process spins with a select() on FD's 0 and 1 (the control connection
+and the UNIX domain socket respectively) and read()'s on FD 0 which
+return 0.  Eventually the process stops because of control connection
+ping failure.  Before that happens, any attempt to start another
+connection appears to hang; probably because the process already has a
+raw socket open to receive GRE packets from the server.
+
+pptp should handle a read() returning zero on the control connection
+as a termination.
+
+# lsof
+COMMAND  PID USER   FD   TYPE     DEVICE    SIZE   NODE NAME
+pptp    4082 root    0u  IPv4      12307            TCP lenny.lan:ms-sql-s->quozl.lan:1723 (CLOSE_WAIT)
+pptp    4082 root    1u  unix 0x04698380          12308 /var/run/pptp/255.255.255.255
+pptp    4082 root    2w   CHR        1,3          67097 /dev/null
+pptp    4082 root    3u  unix 0x04698500          12304 socket
+pptp    4082 root    4u   CHR      136,5              7 /dev/pts/5
+pptp    4082 root    5u   CHR      136,5              7 /dev/pts/5
+pptp    4082 root    6u   CHR      136,5              7 /dev/pts/5
+pptp    4082 root    7r  FIFO        0,7          12241 pipe
+pptp    4082 root    8w  FIFO        0,7          12241 pipe
+pptp    4082 root    9u   raw                     12305 0800000A:002F->0500000A:0000 st=01
+pptp    4082 root   10u  unix 0x04698b00          12310 /var/run/pptp/255.255.255.255
+
+# strace
+read(0, "", 512)                        = 0
+select(2, [0 1], [], NULL, NULL)        = 1 (in [0])
+read(0, "", 512)                        = 0
+select(2, [0 1], [], NULL, NULL)        = 1 (in [0])
+
+
+13th February 2004
+
+- timeout connect earlier, with option to extend timeout.
+
+11th June 2003
+
+- support --version  [JJ]
+
+20th May 2003
+
+- GRE stats to a pipe or shared memory, for GUI to use
+
+15th February 2003
+
+- pptp.8 update man page for new options
+- pptp.c long_options array should use NULL for second last arg, not 0
+- pptp.c use getopt_long more simply, e.g. set flags in option array
+
+1st May 2002
+
+- 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
 
 - clean up -T errors in pptp-command,
-- implement GRE reordering from PoPToP to make client more resilient.
 
 23rd December 2000
 
@@ -18,14 +137,5 @@
    GRE encapsulation.  pptp.c must then be modified to use an
    already-existing gre-copy process in the same way it uses an
    already-existing call manager.
-  Support server operation.
-   Obviously, this is more process trickery.  Upon receiving a call
-   request, the call manager must automagically launch new gre/pppd
-   processes to handle it.  Also, some portions of the server control
-   protocol in pptp_ctrl.c have not been completely implemented.
-  More flexible configuration system.
-   pptp needs to read in config options from /etc/pptp or somesuch.
-   This is very necessary for server operation, since presumably we
-   will want to limit the hosts we give PPTP access to.  Maybe not,
-   though.  We could allow everyone and then allow pppd to do the
-   access control.
+
+$Id: TODO,v 1.23 2005/04/07 23:35:11 quozl Exp $	
diff -Naur tomato/release/src/router/pptp-client/USING tomato121/release/src/router/pptp-client/USING
--- tomato/release/src/router/pptp-client/USING	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/USING	2008-04-22 21:44:06.000000000 +1000
@@ -1,4 +1,4 @@
-$Id: USING,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $	
+Usage Notes
 
 pptp is started as a psuedo-tty child process using pppd's pty option:
 
@@ -25,13 +25,16 @@
 manager, a GRE/PPP en/decapsulator, and pppd.  To shut down the pptp
 connection, kill the pppd process.
 
-NOTE THAT PPTP MUST BE RUN AS ROOT.
+NOTE THAT PPTP MUST BE RUN AS ROOT.  This is so that it can generate
+GRE packets using a raw socket.
 
 Most trouble with pptp will probably be due to incorrect pppd
 configuration.  Be sure you thoroughly understand MS-CHAP support in
 pppd.  Use the 'debug' option to pppd to log connection information;
 this will help you trouble-shoot the pppd side of pptp.
 
+See the project web site for diagnosis assistance.
+
 QUIRKS HANDLING:
 
 Some ADSL providers and some ADSL hardware are buggy or not conforming
@@ -45,5 +48,51 @@
 Bezeq, you probably want the '--quirks BEZEQ_ISRAEL' switch.
 
 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.
+
+TESTING MULTIPLE TUNNELS:
+
+For testing of PPTP servers, the client can be used to establish
+multiple tunnels from multiple IP addresses.  The addresses must be
+routable; this is something you'd do on a local area network.
+
+1. use an address pool on a concentrator.
+
+2. write an ip-up script (e.g. /etc/ppp/ip-up.local or /etc/ppp/ip-up.d)
+
+	#!/bin/sh
+	export PATH=/sbin:/usr/sbin:/bin:/usr/bin
+	REALDEVICE=$1
+	PEERADDR=$6
+	ifconfig ${REALDEVICE} dstaddr ${PEERADDR}
+
+The script performs an "ifconfig pppx dstaddr xx.xx.xx.xx" where
+xx.xx.xx.xx is the private address of the concentrator so that the
+routing works without having to do iptables or ipchains.  The address
+used is given on the pptp command line.
+
+3. create distinct source interfaces with:
+
+        ifconfig eth0:n xx.xx.xx.xx netmask yy.yy.yy.yy 
+
+Where "n" is the alias interface number, "xx.xx.xx.xx" is the new
+address, and "yy.yy.yy.yy" is the network mask.
+
+4. connect with
+
+	pptp concentrator --bind xx.xx.xx.xx name \
+        xx remotename yy ipparam yy.yy.yy.yy 
+                                       ^ (private address of concentrator).
+
+Where "xx.xx.xx.xx" is the address of the source interface, "xx" is
+the local name of the tunnel, "yy" is the remote name of the tunnel,
+and "yy.yy.yy.yy" is the private address of the concentrator.  This is
+passed to the ip-up script as the sixth argument.
+
+See also the following test scripts;
+
+test-multiple-tunnels-1.sh  creates multiple source interfaces
+test-multiple-tunnels-2.sh  creates multiple tunnels
+
+$Id: USING,v 1.6 2003/02/15 04:32:50 quozl Exp $	
diff -Naur tomato/release/src/router/pptp-client/util.c tomato121/release/src/router/pptp-client/util.c
--- tomato/release/src/router/pptp-client/util.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/util.c	2008-10-12 14:45:41.000000000 +1100
@@ -1,7 +1,7 @@
 /* util.c ....... error message utilities.
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: util.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: util.c,v 1.10 2005/03/10 01:18:20 quozl Exp $
  */
 
 #include <stdio.h>
@@ -15,39 +15,144 @@
 #define PROGRAM_NAME "pptp"
 #endif
 
+/* implementation of log_string, defined as extern in util.h */
+char *log_string = "pptp-client";
+
 static void open_log(void) __attribute__ ((constructor));
 static void close_log(void) __attribute__ ((destructor));
 
-static void open_log(void) {
-  openlog(PROGRAM_NAME, LOG_PID, LOG_DAEMON);
-}
-static void close_log(void) {
-  closelog();
-}
-
 #define MAKE_STRING(label) 				\
 va_list ap;						\
 char buf[256], string[256];				\
 va_start(ap, format);					\
 vsnprintf(buf, sizeof(buf), format, ap);		\
-snprintf(string, sizeof(string), "%s[%s:%s:%d]: %s",	\
-	 label, func, file, line, buf);			\
+snprintf(string, sizeof(string), "%s %s[%s:%s:%d]: %s",	\
+	 log_string, label, func, file, line, buf);	\
 va_end(ap)
 
-void _log(char *func, char *file, int line, char *format, ...) {
-  MAKE_STRING("log");
-  syslog(LOG_NOTICE, "%s", string);
-}
-
-void _warn(char *func, char *file, int line, char *format, ...) {
-  MAKE_STRING("warn");
-  fprintf(stderr, "%s\n", string);
-  syslog(LOG_NOTICE, "%s", string);
-}
-
-void _fatal(char *func, char *file, int line, char *format, ...) {
-  MAKE_STRING("fatal");
-  fprintf(stderr, "%s\n", string);
-  syslog(LOG_NOTICE, "%s", string);
-  exit(1);
+/*** open log *****************************************************************/
+static void open_log(void) {
+    openlog(PROGRAM_NAME, LOG_PID, LOG_DAEMON);
+}
+
+/*** close log ****************************************************************/
+static void close_log(void)
+{
+    closelog();
+}
+
+/*** print a message to syslog ************************************************/
+void _log(const char *func, const char *file, int line, const char *format, ...)
+{
+    MAKE_STRING("log");
+    syslog(LOG_NOTICE, "%s", string);
+}
+
+/*** print a warning to syslog ************************************************/
+void _warn(const char *func, const char *file, int line, const char *format, ...)
+{
+    MAKE_STRING("warn");
+//    fprintf(stderr, "%s\n", string);
+    syslog(LOG_WARNING, "%s", string);
+}
+
+/*** print a fatal warning to syslog and exit *********************************/
+void _fatal(const char *func, const char *file, int line, const char *format, ...)
+{
+    MAKE_STRING("fatal");
+//    fprintf(stderr, "%s\n", string);
+    syslog(LOG_CRIT, "%s", string);
+    exit(1);
+}
+
+/*** connect a file to a file descriptor **************************************/
+int file2fd(const char *path, const char *mode, int fd)
+{
+    int ok = 0;
+    FILE *file = NULL;
+    file = fopen(path, mode);
+    if (file != NULL && dup2(fileno(file), fd) != -1)
+        ok = 1;
+    if (file) fclose(file);
+    return ok;
 }
+
+/* signal to pipe delivery implementation */
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+
+/* pipe private to process */
+static int sigpipe[2];
+
+/* create a signal pipe, returns 0 for success, -1 with errno for failure */
+int sigpipe_create()
+{
+  int rc;
+  
+  rc = pipe(sigpipe);
+  if (rc < 0) return rc;
+  
+  fcntl(sigpipe[0], F_SETFD, FD_CLOEXEC);
+  fcntl(sigpipe[1], F_SETFD, FD_CLOEXEC);
+  
+#ifdef O_NONBLOCK
+#define FLAG_TO_SET O_NONBLOCK
+#else
+#ifdef SYSV
+#define FLAG_TO_SET O_NDELAY
+#else /* BSD */
+#define FLAG_TO_SET FNDELAY
+#endif
+#endif
+  
+  rc = fcntl(sigpipe[1], F_GETFL);
+  if (rc != -1)
+    rc = fcntl(sigpipe[1], F_SETFL, rc | FLAG_TO_SET);
+  if (rc < 0) return rc;
+  return 0;
+#undef FLAG_TO_SET
+}
+
+/* generic handler for signals, writes signal number to pipe */
+void sigpipe_handler(int signum)
+{
+  write(sigpipe[1], &signum, sizeof(signum));
+  signal(signum, sigpipe_handler);
+}
+
+/* assign a signal number to the pipe */
+void sigpipe_assign(int signum)
+{
+  sigset_t sigset;
+  struct sigaction sa;
+
+  sigemptyset(&sigset);
+  sigaddset(&sigset, signum);
+  
+  memset(&sa, 0, sizeof(sa));
+  sa.sa_handler = sigpipe_handler;
+  sigaction(signum, &sa, NULL);
+}
+
+/* return the signal pipe read file descriptor for select(2) */
+int sigpipe_fd()
+{
+  return sigpipe[0];
+}
+
+/* read and return the pending signal from the pipe */
+int sigpipe_read()
+{
+  int signum;
+  read(sigpipe[0], &signum, sizeof(signum));
+  return signum;
+}
+
+void sigpipe_close()
+{
+  close(sigpipe[0]);
+  close(sigpipe[1]);
+}
+
diff -Naur tomato/release/src/router/pptp-client/util.h tomato121/release/src/router/pptp-client/util.h
--- tomato/release/src/router/pptp-client/util.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/util.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,17 +1,26 @@
 /* util.h ....... error message utilities.
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: util.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: util.h,v 1.6 2005/03/10 01:18:20 quozl Exp $
  */
 
 #ifndef INC_UTIL_H
 #define INC_UTIL_H
 
-void _log(char *func, char *file, int line, char *format, ...)
+/* log_string is an identifier for this pptp process, passed from
+   command line using --log-string=X, and included with every log message.
+   Useful for people with multiple pptp sessions open at a time */
+extern char * log_string;
+
+/* log_level sets the logging verbosity. Values range from 0 (errors only)
+   to 1 (errors and warnings) to 2 (high verbosity, for debugging) */
+extern int    log_level;
+
+void _log(const char *func, const char *file, int line, const char *format, ...)
      __attribute__ ((format (printf, 4, 5)));
-void _warn(char *func, char *file, int line, char *format, ...)
+void _warn(const char *func, const char *file, int line, const char *format, ...)
      __attribute__ ((format (printf, 4, 5)));
-void _fatal(char *func, char *file, int line, char *format, ...)
+void _fatal(const char *func, const char *file, int line, const char *format, ...)
      __attribute__ ((format (printf, 4, 5))) __attribute__ ((noreturn));
 
 #define log(format, args...) \
@@ -21,4 +30,25 @@
 #define fatal(format, args...) \
 	_fatal(__FUNCTION__,__FILE__,__LINE__, format , ## args)
 
+int file2fd(const char *path, const char *mode, int fd);
+
+/* signal to pipe delivery implementation */
+
+/* create a signal pipe, returns 0 for success, -1 with errno for failure */
+int sigpipe_create();
+
+/* generic handler for signals, writes signal number to pipe */
+void sigpipe_handler(int signum);
+
+/* assign a signal number to the pipe */
+void sigpipe_assign(int signum);
+
+/* return the signal pipe read file descriptor for select(2) */
+int sigpipe_fd();
+
+/* read and return the pending signal from the pipe */
+int sigpipe_read();
+
+void sigpipe_close();
+
 #endif /* INC_UTIL_H */
diff -Naur tomato/release/src/router/pptp-client/vector.c tomato121/release/src/router/pptp-client/vector.c
--- tomato/release/src/router/pptp-client/vector.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/vector.c	2008-04-22 21:44:06.000000000 +1000
@@ -2,7 +2,7 @@
  *                efficiently.
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: vector.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: vector.c,v 1.3 2003/06/17 10:12:55 reink Exp $
  */
 
 #include <stdlib.h>
@@ -10,9 +10,7 @@
 #include <assert.h>
 #include "pptp_ctrl.h"
 #include "vector.h"
-
 /* #define VECTOR_DEBUG */
-
 #ifndef TRUE
 #define TRUE 1
 #endif
@@ -21,127 +19,141 @@
 #endif
 
 struct vector_item {
-  int key;
-  PPTP_CALL *call;
+    int key;
+    PPTP_CALL *call;
 };
+
 struct vector_struct {
-  struct vector_item *item;
-  int size;
-  int alloc;
-  
+    struct vector_item *item;
+    int size;
+    int alloc;
 #ifdef VECTOR_DEBUG
-  int key_max;
+    int key_max;
 #endif
 };
 
 static struct vector_item *binary_search(VECTOR *v, int key);
 
-VECTOR *vector_create() {
-  const int INITIAL_SIZE = 4;
-
-  VECTOR *v = malloc(sizeof(*v));
-  if (v==NULL) return v;
-
-  v->size = 0;
-  v->alloc= INITIAL_SIZE;
-  v->item = malloc(sizeof(*(v->item))*(v->alloc));
-
+/*** vector_create ************************************************************/
+VECTOR *vector_create()
+{
+    const int INITIAL_SIZE = 4;
+
+    VECTOR *v = malloc(sizeof(*v));
+    if (v == NULL) return v;
+
+    v->size = 0;
+    v->alloc = INITIAL_SIZE;
+    v->item = malloc(sizeof(*(v->item)) * (v->alloc));
 #ifdef VECTOR_DEBUG
-  v->key_max=-1;
+    v->key_max = -1;
 #endif
-
-  if (v->item == NULL) { free(v); return NULL; }
-  else return v;
+    if (v->item == NULL) { free(v); return NULL; }
+    else return v;
 }
 
-void vector_destroy(VECTOR *v) {
-  free(v->item);
+/*** vector_destroy ***********************************************************/
+void vector_destroy(VECTOR *v)
+{
+    free(v->item);
 #ifdef VECTOR_DEBUG
-  v->item = NULL;
+    v->item = NULL;
 #endif
-  free(v);
+    free(v);
 }
 
-int vector_size(VECTOR *v) {
-  assert(v != NULL);
-  return v->size;
+/*** vector_size **************************************************************/
+int vector_size(VECTOR *v)
+{
+    assert(v != NULL);
+    return v->size;
 }
 
-/* nice thing about file descriptors is that we are assured by POSIX 
+/*** vector_insert*************************************************************
+ * nice thing about file descriptors is that we are assured by POSIX 
  * that they are monotonically increasing.
  */
-int vector_insert(VECTOR *v, int key, PPTP_CALL * call) {
-  int i;
-  assert(v!=NULL && call != NULL);
-  assert(!vector_contains(v, key));
+int vector_insert(VECTOR *v, int key, PPTP_CALL * call)
+{
+    int i;
+    assert(v != NULL && call != NULL);
+    assert(!vector_contains(v, key));
 #ifdef VECTOR_DEBUG
-  assert(v->key_max < key);
+    assert(v->key_max < key);
 #endif
-
-  if (!(v->size < v->alloc)) {
-    void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc);
-    if (tmp!=NULL) {
-      v->alloc *=2;
-      v->item = tmp;
-    } else return FALSE; /* failed to alloc memory. */
-  }
-  assert(v->size < v->alloc);
-  
-  /* for safety, we make this work in the general case;
-   * but this is optimized for adding call to the end of the vector.
-   */
-  for(i=v->size-1; i>=0; i--)
-    if (v->item[i].key < key)
-      break;
-  /* insert after item i */
-  memmove(&v->item[i+2], &v->item[i+1], (v->size-i-1)*sizeof(*(v->item)));
-  v->item[i+1].key  = key;
-  v->item[i+1].call = call;
-  v->size++;
-
+    if (!(v->size < v->alloc)) {
+        void *tmp = realloc(v->item, sizeof(*(v->item)) * 2 * v->alloc);
+        if (tmp != NULL) {
+            v->alloc *= 2;
+            v->item = tmp;
+        } else return FALSE; /* failed to alloc memory. */
+    }
+    assert(v->size < v->alloc);
+    /* for safety, we make this work in the general case;
+     * but this is optimized for adding call to the end of the vector.
+     */
+    for(i = v->size - 1; i >= 0; i--)
+        if (v->item[i].key < key)
+            break;
+    /* insert after item i */
+    memmove(&v->item[i + 2], &v->item[i + 1],
+            (v->size - i - 1) * sizeof(*(v->item)));
+    v->item[i + 1].key  = key;
+    v->item[i + 1].call = call;
+    v->size++;
 #ifdef VECTOR_DEBUG
-  if (v->key_max < key) /* ie, always. */
-    v->key_max = key;
+    if (v->key_max < key) /* ie, always. */
+        v->key_max = key;
 #endif
-  
-  return TRUE;
+    return TRUE;
 }
 
-int  vector_remove(VECTOR *v, int key) {
-  struct vector_item *tmp;
-  assert(v);
-
-  if ((tmp=binary_search(v,key)) == NULL) return FALSE;
-  assert(tmp>=v->item && tmp < v->item+v->size);
-  memmove(tmp, tmp+1, (v->size-(v->item-tmp)-1)*sizeof(*(v->item)));
-  v->size--;
-  return TRUE;
-}
-int  vector_search(VECTOR *v, int key, PPTP_CALL **call) {
-  struct vector_item *tmp = binary_search(v, key);
-  if (tmp==NULL) return FALSE;
-  *call = tmp->call;
-  return TRUE;
-}
-int  vector_contains(VECTOR *v, int key) {
-  assert(v!=NULL);
-  return (binary_search(v, key)!=NULL);
+/*** vector_remove ************************************************************/
+int  vector_remove(VECTOR *v, int key)
+{
+    struct vector_item *tmp;
+    assert(v != NULL);
+    if ((tmp =binary_search(v,key)) == NULL) return FALSE;
+    assert(tmp >= v->item && tmp < v->item + v->size);
+    memmove(tmp, tmp + 1, (v->size - (v->item - tmp) - 1) * sizeof(*(v->item)));
+    v->size--;
+    return TRUE;
 }
 
-static struct vector_item *binary_search(VECTOR *v, int key) {
-  int l,r,x;
-  assert(v!=NULL);
-  l = 0;  r = v->size - 1;
+/*** vector_search ************************************************************/
+int  vector_search(VECTOR *v, int key, PPTP_CALL **call)
+{
+    struct vector_item *tmp;
+    assert(v != NULL);
+    tmp = binary_search(v, key);
+    if (tmp ==NULL) return FALSE;
+    *call = tmp->call;
+    return TRUE;
+}
 
-  while (r >= l) {
-    x = (l+r)/2;
-    if (key <  v->item[x].key) r = x - 1; else l = x + 1;
-    if (key == v->item[x].key) return &(v->item[x]);
-  }
-  return NULL;
+/*** vector_contains **********************************************************/
+int  vector_contains(VECTOR *v, int key)
+{
+    assert(v != NULL);
+    return (binary_search(v, key) != NULL);
+}
+
+/*** vector_item **************************************************************/
+static struct vector_item *binary_search(VECTOR *v, int key)
+{
+    int l,r,x;
+    l = 0;
+    r = v->size - 1;
+    while (r >= l) {
+        x = (l + r)/2;
+        if (key <  v->item[x].key) r = x - 1; else l = x + 1;
+        if (key == v->item[x].key) return &(v->item[x]);
+    }
+    return NULL;
 }
 
-/* Hmm.  Let's be fancy and use a binary search for the first
+/*** vector_scan ***************************************************************
+ * Hmm.  Let's be fancy and use a binary search for the first
  * unused key, taking advantage of the list is stored sorted; ie
  * we can look at pointers and keys at two different locations, 
  * and if (ptr1 - ptr2) = (key1 - key2) then all the slots
@@ -149,46 +161,49 @@
  * never be greater than key1-key2 (no duplicate keys!)... we
  * check for this.
  */
-int vector_scan(VECTOR *v, int lo, int hi, int *key) {
-  int l,r,x;
-  assert(v!=NULL);  assert(key!=NULL);
-
-  if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; }
-
-  /* our array bounds */
-  l = 0;  r = v->size - 1;
-
-  while (r > l) {
-    /* check for a free spot right after l */
-    if (v->item[l].key + 1 < v->item[l+1].key) { /* found it! */
-      *key = v->item[l].key + 1;
-      return TRUE;
+int vector_scan(VECTOR *v, int lo, int hi, int *key)
+{
+    int l,r,x;
+    assert(v != NULL);
+    assert(key != NULL);
+    if ((v->size<1) || (lo < v->item[0].key)) { *key = lo; return TRUE; }
+    /* our array bounds */
+    l = 0;  r = v->size - 1;
+    while (r > l) {
+        /* check for a free spot right after l */
+        if (v->item[l].key + 1 < v->item[l + 1].key) { /* found it! */
+            *key = v->item[l].key + 1;
+            return TRUE;
+        }
+        /* no dice. Let's see if the free spot is before or after the midpoint */
+        x = (l + r)/2;
+        /* Okay, we have right (r), left (l) and the probe (x). */
+        assert(x - l <= v->item[x].key - v->item[l].key);
+        assert(r - x <= v->item[r].key - v->item[x].key);
+        if (x - l < v->item[x].key - v->item[l].key)
+            /* room between l and x */
+            r = x;
+        else /* no room between l and x */
+            if (r - x < v->item[r].key - v->item[x].key)
+                /* room between x and r */
+                l = x;
+            else /* no room between x and r, either */
+                break; /* game over, man. */
     }
-    /* no dice.  Let's see if the free spot is before or after the midpoint */
-    x = (l+r)/2;
-    /* Okay, we have right (r), left (l) and the probe (x). */
-    assert(x-l <= v->item[x].key-v->item[l].key);
-    assert(r-x <= v->item[r].key-v->item[x].key);
-    if (x-l < v->item[x].key - v->item[l].key) /* room between l and x */
-      r = x;
-    else /* no room between l and x */
-      if (r-x < v->item[r].key - v->item[x].key) /* room between x and r */
-	l = x;
-      else /* no room between x and r, either */
-	break; /* game over, man. */
-  }
-  /* no room found in already allocated space.  Check to see if
-   * there's free space above allocated entries. */
-  if (v->item[v->size-1].key < hi) {
-    *key = v->item[v->size-1].key+1;
-    return TRUE;
-  }
-  /* outta luck */
-  return FALSE;
+    /* no room found in already allocated space.  Check to see if
+     * there's free space above allocated entries. */
+    if (v->item[v->size - 1].key < hi) {
+        *key = v->item[v->size - 1].key + 1;
+        return TRUE;
+    }
+    /* outta luck */
+    return FALSE;
 }
 
-PPTP_CALL * vector_get_Nth(VECTOR *v, int n) {
-  assert(v != NULL);
-  assert(0 <= n && n < vector_size(v));
-  return v->item[n].call;
+/*** vector_get_Nth ***********************************************************/
+PPTP_CALL * vector_get_Nth(VECTOR *v, int n)
+{
+    assert(v != NULL);
+    assert(0 <= n && n < vector_size(v));
+    return v->item[n].call;
 }
diff -Naur tomato/release/src/router/pptp-client/vector.h tomato121/release/src/router/pptp-client/vector.h
--- tomato/release/src/router/pptp-client/vector.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/vector.h	2008-04-22 21:44:06.000000000 +1000
@@ -2,7 +2,7 @@
  *                efficiently.
  *                C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: vector.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: vector.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
  */
 
 #ifndef INC_VECTOR_H
diff -Naur tomato/release/src/router/pptp-client/vector_test.c tomato121/release/src/router/pptp-client/vector_test.c
--- tomato/release/src/router/pptp-client/vector_test.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/vector_test.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* vector_test.c .... Test the vector package.
  *                    C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: vector_test.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: vector_test.c,v 1.2 2003/06/17 17:25:47 reink Exp $
  */
 
 #include <stdlib.h>
@@ -11,84 +11,84 @@
 #define MAX 25
 
 void main(void) {
-  int i, j, retval;
+    int i, j, retval;
 
-  VECTOR *v = vector_create();
-  assert(v != NULL);
-  assert(vector_size(v)==0);
-  for (i=0; i<=MAX; i++) {
-    assert(!vector_contains(v, i));
-    assert(!vector_remove(v, i));
-    assert(!vector_search(v, i, (PPTP_CALL **)&j));
-    retval = vector_scan(v, i, MAX*2, &j);
-    assert(retval);
-    assert(j==i);
-  }
+    VECTOR *v = vector_create();
+    assert(v != NULL);
+    assert(vector_size(v)==0);
+    for (i=0; i<=MAX; i++) {
+        assert(!vector_contains(v, i));
+        assert(!vector_remove(v, i));
+        assert(!vector_search(v, i, (PPTP_CALL **)&j));
+        retval = vector_scan(v, i, MAX*2, &j);
+        assert(retval);
+        assert(j==i);
+    }
+
+    for (i=1; i<=MAX; i++) {
+        retval = vector_insert(v, i, (PPTP_CALL *)i);
+        assert(retval);
+        assert(vector_size(v)==i);
+    }
+    for (i=1; i<MAX; i++) {
+        retval = vector_search(v, i, (PPTP_CALL **)&j);
+        assert(retval);
+        assert(j==i);
+        retval = vector_contains(v, i);
+        assert(retval);
+    }
+    assert(vector_size(v)==MAX);
+    retval = vector_contains(v, MAX+1);
+    assert(!retval);
+    retval = vector_search(v, MAX+1, (PPTP_CALL **)&j);
+    assert(!retval);
 
-  for (i=1; i<=MAX; i++) {
-    retval = vector_insert(v, i, (PPTP_CALL *)i);
-    assert(retval);
-    assert(vector_size(v)==i);
-  }
-  for (i=1; i<MAX; i++) {
-    retval = vector_search(v, i, (PPTP_CALL **)&j);
-    assert(retval);
-    assert(j==i);
-    retval = vector_contains(v, i);
-    assert(retval);
-  }
-  assert(vector_size(v)==MAX);
-  retval = vector_contains(v, MAX+1);
-  assert(!retval);
-  retval = vector_search(v, MAX+1, (PPTP_CALL **)&j);
-  assert(!retval);
-
-  retval = vector_scan(v, 0, MAX, &j);
-  assert(retval);
-  assert(j==0);
-  retval = vector_scan(v, 1, MAX, &j);
-  assert(!retval);
-  retval = vector_scan(v, 1, MAX+1, &j);
-  assert(retval);
-  assert(j==MAX+1);
-  retval = vector_scan(v, 1, MAX+MAX, &j);
-  assert(retval);
-  assert(j==MAX+1);
-
-  for (i=0; i<(MAX*10); i++) {
-    int k = (random() % MAX) + 1;
-    assert(vector_contains(v, k));
-    assert(!vector_scan(v, 1, k, &j));
-    assert(!vector_scan(v, k, MAX, &j));
-    retval = vector_remove(v, k);
+    retval = vector_scan(v, 0, MAX, &j);
     assert(retval);
-    assert(vector_size(v)==MAX-1);
-    assert(!vector_contains(v, k));
-    assert(!vector_search(v, k, (PPTP_CALL **) &j));
+    assert(j==0);
     retval = vector_scan(v, 1, MAX, &j);
+    assert(!retval);
+    retval = vector_scan(v, 1, MAX+1, &j);
     assert(retval);
-    assert(j==k);
-    retval = vector_insert(v, k, (PPTP_CALL *) k);
-    assert(retval);
-    assert(vector_size(v)==MAX);
-    assert(vector_contains(v, k));
-    assert(!vector_scan(v, 1, MAX, &j));
-    retval = vector_search(v, k, (PPTP_CALL **) &j);
+    assert(j==MAX+1);
+    retval = vector_scan(v, 1, MAX+MAX, &j);
     assert(retval);
-    assert(j==k);
-  }
+    assert(j==MAX+1);
 
-  for (i=1; i<=MAX; i++) {
-    assert(vector_size(v)==MAX-(i-1));
-    vector_remove(v, i);
-    assert(vector_size(v)==MAX-i);
-    assert(!vector_contains(v, i));
-    retval = vector_search(v, i, (PPTP_CALL **) &j);
-    assert(!retval);
-    retval = vector_scan(v, 1, MAX, &j);
-    assert(retval);
-    assert(j==1);
-  }
-  assert(vector_size(v)==0);
-  vector_destroy(v);
+    for (i=0; i<(MAX*10); i++) {
+        int k = (random() % MAX) + 1;
+        assert(vector_contains(v, k));
+        assert(!vector_scan(v, 1, k, &j));
+        assert(!vector_scan(v, k, MAX, &j));
+        retval = vector_remove(v, k);
+        assert(retval);
+        assert(vector_size(v)==MAX-1);
+        assert(!vector_contains(v, k));
+        assert(!vector_search(v, k, (PPTP_CALL **) &j));
+        retval = vector_scan(v, 1, MAX, &j);
+        assert(retval);
+        assert(j==k);
+        retval = vector_insert(v, k, (PPTP_CALL *) k);
+        assert(retval);
+        assert(vector_size(v)==MAX);
+        assert(vector_contains(v, k));
+        assert(!vector_scan(v, 1, MAX, &j));
+        retval = vector_search(v, k, (PPTP_CALL **) &j);
+        assert(retval);
+        assert(j==k);
+    }
+
+    for (i=1; i<=MAX; i++) {
+        assert(vector_size(v)==MAX-(i-1));
+        vector_remove(v, i);
+        assert(vector_size(v)==MAX-i);
+        assert(!vector_contains(v, i));
+        retval = vector_search(v, i, (PPTP_CALL **) &j);
+        assert(!retval);
+        retval = vector_scan(v, 1, MAX, &j);
+        assert(retval);
+        assert(j==1);
+    }
+    assert(vector_size(v)==0);
+    vector_destroy(v);
 }
diff -Naur tomato/release/src/router/pptp-client/version.c tomato121/release/src/router/pptp-client/version.c
--- tomato/release/src/router/pptp-client/version.c	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/version.c	2008-04-22 21:44:06.000000000 +1000
@@ -1,8 +1,8 @@
 /* version.c ..... keep track of package version number. 
  *                 C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: version.c,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: version.c,v 1.3 2004/06/22 09:52:26 quozl Exp $
  */
 
 #include "config.h"
-const char * version = "pptp-linux version " PPTP_LINUX_VERSION;
+const char * version = "pptp version " PPTP_LINUX_VERSION;
diff -Naur tomato/release/src/router/pptp-client/version.h tomato121/release/src/router/pptp-client/version.h
--- tomato/release/src/router/pptp-client/version.h	2006-08-03 17:07:34.000000000 +1000
+++ tomato121/release/src/router/pptp-client/version.h	2008-04-22 21:44:06.000000000 +1000
@@ -1,7 +1,7 @@
 /* version.h ..... keep track of package version number. 
  *                 C. Scott Ananian <cananian@alumni.princeton.edu>
  *
- * $Id: version.h,v 1.1.1.1 2002/07/25 06:52:39 honor Exp $
+ * $Id: version.h,v 1.1.1.1 2000/12/23 08:19:51 scott Exp $
  */
 
 #ifndef INC_VERSION_H
