changeset 1586:e0d88dc6a92f

Added PPP network support.
author nickg
date Wed, 14 Apr 2004 15:08:56 +0000
parents eead27d1aa2f
children 856938ebdda4
files packages/ChangeLog packages/NEWS packages/ecos.db packages/net/ppp/current/ChangeLog packages/net/ppp/current/cdl/ppp.cdl packages/net/ppp/current/doc/ppp.sgml packages/net/ppp/current/include/cbcp.h packages/net/ppp/current/include/ccp.h packages/net/ppp/current/include/chap.h packages/net/ppp/current/include/chap_ms.h packages/net/ppp/current/include/fsm.h packages/net/ppp/current/include/ipcp.h packages/net/ppp/current/include/lcp.h packages/net/ppp/current/include/magic.h packages/net/ppp/current/include/names.h packages/net/ppp/current/include/net/bpf.h packages/net/ppp/current/include/net/if_ppp.h packages/net/ppp/current/include/net/if_pppvar.h packages/net/ppp/current/include/net/ppp_comp.h packages/net/ppp/current/include/net/ppp_defs.h packages/net/ppp/current/include/net/zlib.h packages/net/ppp/current/include/ppp.h packages/net/ppp/current/include/ppp_io.h packages/net/ppp/current/include/pppd.h packages/net/ppp/current/include/slcompress.h packages/net/ppp/current/include/syslog.h packages/net/ppp/current/include/upap.h packages/net/ppp/current/src/auth.c packages/net/ppp/current/src/bsd_comp.c packages/net/ppp/current/src/cbcp.c packages/net/ppp/current/src/ccp.c packages/net/ppp/current/src/chap.c packages/net/ppp/current/src/chap_ms.c packages/net/ppp/current/src/chat.c packages/net/ppp/current/src/fsm.c packages/net/ppp/current/src/if_ppp.c packages/net/ppp/current/src/ipcp.c packages/net/ppp/current/src/lcp.c packages/net/ppp/current/src/magic.c packages/net/ppp/current/src/ppp_deflate.c packages/net/ppp/current/src/ppp_io.c packages/net/ppp/current/src/pppd.c packages/net/ppp/current/src/slcompress.c packages/net/ppp/current/src/sys-ecos.c packages/net/ppp/current/src/upap.c packages/net/ppp/current/src/zlib.c packages/net/ppp/current/tests/chat.c packages/net/ppp/current/tests/isp.c packages/net/ppp/current/tests/nc_test_framework.h packages/net/ppp/current/tests/nc_test_slave.c packages/net/ppp/current/tests/ppp_auth.c packages/net/ppp/current/tests/ppp_test_support.inl packages/net/ppp/current/tests/ppp_up.c packages/net/ppp/current/tests/ppp_updown.c packages/net/ppp/current/tests/tcp_echo.c packages/net/ppp/current/tests/test_server.sh
diffstat 56 files changed, 34173 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/packages/ChangeLog
+++ b/packages/ChangeLog
@@ -1,3 +1,7 @@
+2004-04-14  Nick Garnett  <nickg@calivar.com>
+
+	* ecos.db: Added PPP package.
+
 2004-03-12  Jonathan Larmour  <jifl@eCosCentric.com>
 
 	* pkgconf/rules.mak: When linking, $LDFLAGS must be after target.ld
--- a/packages/NEWS
+++ b/packages/NEWS
@@ -1,3 +1,4 @@
+* Added PPP network support. Contributed by Nick Garnett of eCosCentric.
 * Added support for network under vmWare using the LANCE chipset. Contributed
   by Iztok Zupet. 
 * Added support for FAT12/16 filesystems. Contributed by
--- a/packages/ecos.db
+++ b/packages/ecos.db
@@ -1321,6 +1321,13 @@ This package provides a SNTP client whic
 information and set the system clock."
 }  
 
+package CYGPKG_PPP {
+	alias 		{ "PPP support" ppp }
+	directory	net/ppp
+	script		ppp.cdl
+        description     "PPP support."
+}
+
 package CYGPKG_NET_IPSEC_LIBIPSEC {
         alias           { "libipsec support" libipsec }
         directory       net/ipsec/libipsec
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/ChangeLog
@@ -0,0 +1,344 @@
+2004-03-31  John Dallaway  <jld@ecoscentric.com>
+
+	* cdl/ppp.cdl: Correct capitalisation in display strings.
+
+2004-03-24  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Add CYGPKG_PPP_DEBUG_WARN_ONLY option to control
+	which syslog() messages actually get printed.
+
+	* include/ppp.h: Widen kdebugflag option to 5 bits.
+
+	* src/ppp_io.c: Converted some db_printf() calls to diag_printf().
+
+	* src/sys-ecos.c: Delay return of cyg_ppp_wait_up() until IP
+	addresses have been set. Add ifdef for CYGPKG_PPP_DEBUG_WARN_ONLY
+	to syslog().
+
+	* doc/ppp.sgml: Added documentation of CYGPKG_PPP_DEBUG_WARN_ONLY
+	option. Improved documentation of kdebugflag runtime option.
+
+2004-01-09  John Dallaway  <jld@ecoscentric.com>
+
+	* cdl/ppp.cdl: Fix typographical error.
+
+2004-01-08  Nick Garnett  <nickg@ecoscentric.com>
+
+	* tests/test_server.sh: Added a dbecho of the PPPD command line.
+
+2003-12-23  Nick Garnett  <nickg@ecoscentric.com>
+
+	* doc/ppp.sgml: Added A&M Adder boards to list of those that
+	support hardware flow control.
+
+2003-12-22  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/pppd.c (vfmtmsg): Disabled PowerPC-specific ifndef, we don't
+	have the differences in va_list that this is coping with.
+
+2003-11-12  John Dallaway  <jld@ecoscentric.com>
+
+	* doc/ppp.sgml: Addition comments concerning serial flow control from
+	Nick Garnett.
+
+2003-10-10  John Dallaway  <jld@ecoscentric.com>
+
+	* doc/ppp.sgml: Fix documentation build error.
+
+2003-09-25  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/magic.c (magic_init): Added pseudo-pid to seed
+	initialization to add some variety.
+
+	* include/pppd.h: 
+	* include/names.h: 
+	* src/pppd.c: Added flowctl global variable to control flow
+	control of serial line. Removed crtscts variable.
+
+	* cdl/ppp.cdl: Fixed enable of CHAP support, it was zero.
+
+	* src/ppp_io.h:
+	* src/ppp_io.c:
+	* src/sys-ecos.c (set_up_tty): Added switch to set flow control of
+	serial line depending on flowctl variable. Added ifdefs around use
+	of line status callbacks -- not all drivers support them.
+	
+	* include/ppp.h: Added flowctl field to cyg_ppp_options_t
+	structure plus a set of defines for its possible values.
+
+	* doc/ppp.sgml: Added documentation of flowctl field.
+
+	* tests/test_server.sh:
+	* tests/nc_test_slave.c:
+	* tests/tcp_echo.c:
+	Added ability to use software flow control in these tests and an
+	option on test_server commandline to select it for the host.
+	
+2003-07-18  Nick Garnett  <nickg@ecoscentric.com>
+
+	* tests/test_server.sh: Changed to /bin/bash on first line, just
+	in case. Added "nodetach" option to pppd. It seems that some
+	versions of pppd fork into the background by default, and some,
+	like the one I tested all this with initially, do not. This option
+	should make them all behave the same.
+
+2003-07-15  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/magic.c (magic): Removed use of getpid(), since this is the
+	only dependency here on the POSIX library.
+
+2003-07-14  Nick Garnett  <nickg@ecoscentric.com>
+
+	* doc/ppp.sgml: Updated configuration section to mention
+	requirement for net and serial packages. Various other fixes.
+
+	* cdl/ppp.cdl: Added requirements for CYGPKG_IO_SERIAL and
+	CYGPKG_IO_SERIAL_DEVICES. Various other tidies.
+
+	* src/sys-ecos.c: Added dummy versions of various PAP and CHAP
+	functions to satisfy references in auth.c when PAP and CHAP have
+	been configured out.
+
+	* tests/test_server.sh: Added some comments and tidied a little.
+	
+2003-07-11  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Added CYGPKG_PPP_TESTS_ALL to control which tests
+	get made. Changed default value of CYGPKG_PPP_TESTS_AUTOMATE to
+	build automated tests by default.
+
+	* tests/ppp_updown.c: Changed ping timeout to seven seconds. The
+	larger packets can take a long time to exchange at the lower baud
+	rates.
+	
+	* doc/ppp.sgml: Updated to reflect latest changes.
+
+2003-07-08  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Added CYGPKG_PPP_TESTS_AUTOMATE and
+	CYGDAT_PPP_TEST_BAUD_RATES options.
+	
+	* src/sys-ecos.c: Close sockfd correctly.
+
+	* src/chat.c: Some small fixes to make system re-entrant. Fixed
+	success flag to comply with documentation.
+	
+	* tests/ppp_test_support.inl: File added to contain the common
+	parts for all PPP tests. This mostly involves the sending of
+	commands to the test_server.sh script.
+
+	* tests/test_server.sh: Modified to respond to baud rate change
+	commands and to loop until a finish command is added. Added
+	various extra tests for authentication and chat testing.
+
+
+	* tests/ppp_auth.c: Test added to test PAP and CHAP
+	authentication.
+
+	* doc/ppp.sgml: Updated to reflect latest test changes.
+	
+	* tests/ppp_up.c: 
+	* tests/ppp_updown.c: 
+	* tests/chat.c: 
+	* tests/nc_test_slave.c: 
+	* tests/tcp_echo.c:
+	Tests converted to use ppp_test_support.inl and to run multiple
+	tests in some instances.
+
+2003-07-03  Nick Garnett  <nickg@ecoscentric.com>
+
+	* src/ppp_io.c (pppasyncstart): Removed a couple of spurious
+	breaks. These were causing the TX thread to loop unnecessarily,
+	and also seemed to cause some occasional packet corruptions.
+
+	* tests/ppp_up.c: Fixed loop to be more responsive to the PPP link
+	going down.
+	
+2003-07-01  Nick Garnett  <nickg@ecoscentric.com>
+
+	* doc/ppp.sgml: Added further documentation on testing.
+
+	* tests/test_server.sh: Various fixes.
+
+2003-06-26  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Added CYGPKG_PPP_TEST_DEVICE to specify device used
+	by test programs.
+	Added requirement for CYGPKG_IO_SERIAL_FLOW_CONTROL. 
+	
+	* doc/ppp.sgml: Added descriptions of test programs. Various
+	tidies and fixes.
+
+	* src/chat.c: Added some local debug support.
+	
+	* tests/ppp_up.c:
+	* tests/ppp_updown.c:
+	* tests/chat.c:
+	* tests/nc_test_slave.c:
+	* tests/tcp_echo.c:
+	Added chat script (or modified existing one) to announce the name
+	of the test over the serial line. This is to interface to the
+	test_server.sh script. Use CYGPKG_PPP_TEST_DEVICE. ppp_updown now
+	interrogates the ppp0 interface for the remote end's IP
+	address. chat now switches to 115200 baud.
+
+	* tests/isp.c: Use CYGPKG_PPP_TEST_DEVICE.
+
+	* tests/test_server.sh: Shell script to act as a remote end for
+	PPP testing. Each test announces itself over the link and this
+	script executes the correct set of commands to run the test.
+	
+2003-06-20  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Removed CYGNUM_PPP_THREAD_COUNT. Updated
+	descriptions of other options.
+
+	* src/chat.c:
+	* src/sys-ecos.c:
+	* include/ppp.h: Some minor tidying, and API semantic changes
+	mostly prompted by trying to document the API and discovering some
+	inconsistencies.
+
+	* tests/ppp_up.c: Modified in line with API semantic changes.
+	
+	* doc/ppp.sgml:
+	* doc/makefile:
+	* doc/ppp_sa.sgml:
+	Added documentation. The actual documentation is in ppp.sgml. The
+	makefile and ppp_sa.sgml allow a stand-alone copy of the
+	documentation to be generated.
+
+2003-06-17  Nick Garnett  <nickg@ecoscentric.com>
+
+	* include/ppp.h: Removed some unused options from
+	cyg_ppp_options_t.
+
+	* include/syslog.h: Tidied and commented.
+
+	* src/auth.c:
+	* src/ipcp.c:
+	* src/lcp.c:
+	* src/ppp_io.c:
+	* src/pppd.c:
+	* src/sys-ecos.c:
+	Removed some defunct BSD code, tidied up a little.
+
+	* src/chat.c: Some tidying.
+	
+	* cdl/ppp.cdl:
+	* tests/nc_test_slave.c:
+	* tests/nc_test_framework.h:
+	Added nc_test_slave test.
+
+	* tests/ppp_up.c: Changed wait to print out TCP/IP tables every
+	minute.
+
+	* tests/tcp_echo.c: Tidied up a little.
+	
+2003-06-13  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl: Added dialup number, control over compression, and
+	some extra tests.
+
+	* include/pppd.h: Changed inspeed to be a cyg_serial_baud_rate_t
+	enum.
+
+	* include/ppp.h: Added default_route, modem, baud and script
+	options to cyg_ppp_options_t.
+
+	* include/names.h: Header added to redefine all external names in
+	the PPP package so that they do not pollute to application's
+	namespace.
+	
+	* src/chat.c:
+	* include/syslog.h:
+	* include/ppp_io.h: Tidied and commented.
+
+
+	* src/if_ppp.c: Added include of pkgconf/ppp.h.
+
+	* src/ppp_io.c: Expunged some unnecessary BSD code, various tides.
+	
+	* src/pppd.c: Added handling of CHAT scripting during bring-up,
+	carrier detect and proper shutdown.
+	Expunged some unnecessary BSD code, various tides.
+	
+	* src/sys-ecos.c: Improved startup and shutdown synchronization,
+	added carrier detect handling.
+	Expunged some unnecessary BSD code, various tides.
+
+	* tests/isp.c:
+	* tests/ppp_up.c:
+	* tests/ppp_updown.c:
+	Generally tidied and cleaned up a bit. Added ping functionality to
+	some tests to check routing.
+	
+	* tests/tcp_echo.c:
+	New test, an adaptation of the standard tcp_echo net test that
+	brings the PPP link up before starting the test.
+	
+	* include/zlib.h:
+	* src/bsd_comp.c:
+	* src/ppp_deflate.c:
+	* src/zlib.c:
+	Added these files to implement PPP compression. However at present
+	there seem to be problems with this code, so compression is
+	disabled by default. In any case, these algorithms need enormous
+	amounts of working memory, so may not be useful in an embedded
+	system.
+	
+2003-06-10  Nick Garnett  <nickg@ecoscentric.com>
+
+	* cdl/ppp.cdl:
+	* include/cbcp.h:
+	* include/ccp.h:
+	* include/chap.h:
+	* include/chap_ms.h:
+	* include/fsm.h:
+	* include/ipcp.h:
+	* include/lcp.h:
+	* include/magic.h:
+	* include/ppp.h:
+	* include/ppp_io.h:
+	* include/pppd.h:
+	* include/slcompress.h:
+	* include/syslog.h:
+	* include/upap.h:
+	* include/net/bpf.h:
+	* include/net/if_ppp.h:
+	* include/net/if_pppvar.h:
+	* include/net/ppp_comp.h:
+	* include/net/ppp_defs.h:
+	* src/auth.c:
+	* src/cbcp.c:
+	* src/ccp.c:
+	* src/chap.c:
+	* src/chap_ms.c:
+	* src/chat.c:
+	* src/fsm.c:
+	* src/if_ppp.c:
+	* src/ipcp.c:
+	* src/lcp.c:
+	* src/magic.c:
+	* src/ppp_io.c:
+	* src/pppd.c:
+	* src/slcompress.c:
+	* src/sys-ecos.c:
+	* src/upap.c:
+	* tests/chat.c:
+	* tests/isp.c:
+	* tests/ppp_up.c:
+	* tests/ppp_updown.c:
+	Initial checkin of PPP code -- mainly as a safety/backup
+	measure. There is still a good deal of tidying up to be done
+	here. At present there is a lot of ifdeffed out BSD code present,
+	which is there as a reminder of what should be done in the eCos
+	code. The tests are incomplete, and there is no documentation.
+
+# Copyright (C) 2003 eCosCentric Ltd.
+# All Rights Reserved.
+#
+# Permission is granted to use, copy, modify and redistribute this
+# file.
+		
+	
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/cdl/ppp.cdl
@@ -0,0 +1,315 @@
+# ====================================================================
+#
+#      ppp.cdl
+#
+#      PPP configuration data
+#
+# ====================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+## -------------------------------------------
+## This file is part of eCos, the Embedded Configurable Operating System.
+## Copyright (C) 2003, 2004 eCosCentric Limited
+##
+## eCos is free software; you can redistribute it and/or modify it under
+## the terms of the GNU General Public License as published by the Free
+## Software Foundation; either version 2 or (at your option) any later version.
+##
+## eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or
+## FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+## for more details.
+##
+## You should have received a copy of the GNU General Public License along
+## with eCos; if not, write to the Free Software Foundation, Inc.,
+## 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+##
+## As a special exception, if other files instantiate templates or use macros
+## or inline functions from this file, or you compile this file and link it
+## with other works to produce a work based on this file, this file does not
+## by itself cause the resulting work to be covered by the GNU General Public
+## License. However the source code for this file must still be made available
+## in accordance with section (3) of the GNU General Public License.
+##
+## This exception does not invalidate any other reasons why a work based on
+## this file might be covered by the GNU General Public License.
+##
+## -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+# ====================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):      nickg
+# Original data:  nickg
+# Contributors:   
+# Date:           2002-10-15
+#
+#####DESCRIPTIONEND####
+#
+# ====================================================================
+
+cdl_package CYGPKG_PPP {
+    display       "PPP daemon"
+    parent        CYGPKG_NET
+    doc           ref/net-ppp.html
+    include_dir   cyg/ppp
+    requires      CYGPKG_IO
+    requires      CYGPKG_IO_SERIAL
+
+    requires      CYGPKG_IO_SERIAL_DEVICES
+    requires      CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING
+    requires      CYGPKG_NET
+    requires      CYGPKG_IO_SERIAL_FLOW_CONTROL
+    
+    description "PPP support for eCos. This package contains the PPP
+                 daemon functionality, BSD kernel device drivers for
+                 the network stack, plus other parts of the PPP
+                 infrastructure."
+
+    compile pppd.c sys-ecos.c ppp_io.c
+    compile auth.c ccp.c fsm.c magic.c
+    compile cbcp.c ipcp.c lcp.c 
+
+    compile if_ppp.c slcompress.c
+
+    cdl_option CYGNUM_PPP_PPPD_THREAD_PRIORITY {
+        display "PPP thread priority"
+        flavor data
+        default_value { CYGNUM_KERNEL_SCHED_PRIORITIES/2 }
+        legal_values 0 to CYGNUM_KERNEL_SCHED_PRIORITIES
+        description "The PPP system contains two threads, One is used for receiving
+                     data from the link and processing control packets.
+                     The other is used to transmit data asynchronously to the link
+                     when it cannot be completed synchronously. The receive thread
+                     runs at the priority given here, and the transmit thread
+                     runs at the next lower priority.
+                     The exact priority needed here depends on the importance of the
+                     PPP subsystem relative to the rest of the system. The default
+                     is to put it in the middle of the priority range to provide
+                     reasonable response without impacting genuine high
+                     priority threads."
+    }
+
+    cdl_component CYGPKG_PPP_DEBUG_WARN_ONLY {
+        display   "PPP protocol debug error only"
+        default_value 1
+        description "The runtime debug option enables logging of high
+                     level debug messages. Too many of these can interfere
+                     with the PPP device and may result in missed messages.
+                     This is because these messages are emitted via the diag_printf()
+                     mechanism, which disables interrupts while it prints.
+                     By default, therefore, we only report errors and warnings, and not
+                     all events. Setting this option to zero will enable the logging of
+                     all events."
+    }
+    
+    cdl_component CYGPKG_PPP_AUTH {
+        display "PPP authentication defaults"
+        flavor none
+        no_define
+        
+        cdl_option CYGPKG_PPP_AUTH_DEFAULT_USER {
+            display "Default user name"
+            flavor data
+            default_value {"\"eCos\""}
+            description "This option gives the default value
+                         for the user name used to intialize
+                         the user field in the PPP options."
+        }
+
+        cdl_option CYGPKG_PPP_AUTH_DEFAULT_PASSWD {
+            display "Default password"
+            flavor data
+            default_value {"\"secret\""}
+            description "This option gives the default value
+                         for the password used to intialize
+                         the passwd field in the PPP options."
+        }
+        
+    }
+
+    cdl_option CYGPKG_PPP_DEFAULT_DIALUP_NUMBER {
+        display "Default dialup number"
+        flavor data
+        default_value { "\"5551234\""}
+        description "This option provides a default dialup number for use in
+                     chat scripts. This value is not used anywhere
+                     in the PPP package, but is provided to complete the information
+                     needed, alongside the user name and password, for accessing a
+                     typical dialup server."
+    }
+    
+    cdl_component CYGPKG_PPP_PAP {
+        display "PAP support"
+        default_value 1
+        description "This component enables the inclusion of PAP authentication
+                     support."
+        compile upap.c
+
+    }
+
+    cdl_component CYGPKG_PPP_CHAP {
+        display "CHAP support"
+        default_value 1
+        description "This component enables the inclusion of CHAP authentication
+                     support."
+
+        compile chap.c chap_ms.c
+
+    }
+
+    cdl_component CYGPKG_PPP_COMPRESSION {
+        display "PPP compression options"
+        default_value 0
+        description "This component provides control over
+                     PPP compression features. WARNING: at
+                     present there are problems with this, and
+                     the compression code needs to allocate large
+                     amounts of memory. Hence this is all currently
+                     disabled."
+        
+        cdl_option PPP_BSDCOMP {
+            display "Enable BSD compression"
+            default_value 0
+            compile bsd_comp.c 
+            description "This option enables inclusion of BSD
+                         compression into the PPP protocol."
+        }
+
+        cdl_option PPP_DEFLATE {
+            display "Enable ZLIB compression"
+            default_value 0
+            compile ppp_deflate.c zlib.c
+            description "This option enables inclusion of ZLIB
+                         compression into the PPP protocol."
+        }
+        
+    }
+
+    cdl_component CYGPKG_PPP_CHAT {
+        display "Chat script support"
+        default_value 1
+        description "This component enables the inclusion of a
+                     simple scripting system to bring up PPP connections.
+                     It implements a subset of the CHAT scripting language."
+
+        compile chat.c
+        
+        cdl_option CYGNUM_PPP_CHAT_ABORTS_MAX {
+            display "Maximum number of ABORT strings"
+            flavor data
+            default_value 10
+            legal_values 5 to 500
+            description "This option defines the maximum number of ABORT
+                         strings that the CHAT system will store."
+        }
+
+        cdl_option CYGNUM_PPP_CHAT_ABORTS_SIZE {
+            display "Maximum size of each ABORT string"
+            flavor data
+            default_value 20
+            legal_values 10 to 100
+            description "This option defines the maximum size of each ABORT
+                         strings that the CHAT system will store."
+        }
+
+        cdl_option CYGNUM_PPP_CHAT_STRING_LENGTH {
+            display "Maximum size of CHAT strings"
+            flavor data
+            default_value 256
+            legal_values 32 to 32768
+            description "This option defines the maximum size of any
+                         expect or reply strings that the CHAT system
+                         will be given."
+        }
+        
+    }
+
+
+    cdl_component CYGPKG_PPP_OPTIONS {
+        display "PPP build options"
+        flavor  none
+	no_define
+
+        cdl_option CYGPKG_PPP_CFLAGS_ADD {
+            display "Additional compiler flags"
+            flavor  data
+            no_define
+            default_value { "-D__ECOS" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the PPP package.
+	        These flags are used in addition
+                to the set of global flags."
+        }
+
+        cdl_option CYGPKG_PPP_CFLAGS_REMOVE {
+            display "Suppressed compiler flags"
+            flavor  data
+            no_define
+            default_value { "" }
+            description   "
+                This option modifies the set of compiler flags for
+                building the PPP package. These flags are removed from
+                the set of global flags if present."
+        }
+    }
+
+    cdl_option CYGPKG_PPP_TESTS {
+        display "PPP tests"
+        flavor  data
+        no_define
+        calculated { "tests/ppp_up "         .
+                     "tests/ppp_updown "     .
+                     "tests/chat "           .
+                     "tests/ppp_auth "       .
+                     ((CYGPKG_PPP_TESTS_ALL) ?
+                      "tests/isp "           .
+                      "tests/tcp_echo "      .
+                      "tests/nc_test_slave "
+                     :
+                      "" )
+                   }
+            description   "
+             This option specifies the set of tests
+             for the PPP package."
+        }
+
+    cdl_option CYGPKG_PPP_TESTS_ALL {
+        display "Include all PPP tests"
+        default_value 0
+        description "This option enables the inclusion of extra PPP tests
+                     that are not normally suitable for automated testing."
+    }
+    
+    cdl_option CYGPKG_PPP_TEST_DEVICE {
+        display "PPP test device"
+        flavor data
+        default_value { "\"/dev/ser0\"" }
+        description "This is the name of the device used by the PPP tests
+                     to make the PPP connection."
+    }
+
+    cdl_component CYGPKG_PPP_TESTS_AUTOMATE {
+        display "PPP test automation"
+        default_value 1
+        description "This component controls the automation of PPP tests using the
+                     test_server.sh script to control the remote end. Without this
+                     option, PPP tests are configured to run stand-alone. With this
+                     option they emit control strings to change the line baud rate
+                     and announce the test being performed."
+
+        cdl_option CYGDAT_PPP_TEST_BAUD_RATES {
+            display "PPP test automation baud rates"
+            flavor data
+            default_value { "CYGNUM_SERIAL_BAUD_19200," .
+                            "CYGNUM_SERIAL_BAUD_38400," .
+                            "CYGNUM_SERIAL_BAUD_57600," .
+                            "CYGNUM_SERIAL_BAUD_115200"
+                          }
+            description "This option gives the set of baud rates for which some
+                         tests will execute."
+        }
+    }
+}
+
+# EOF ppp.cdl
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/doc/ppp.sgml
@@ -0,0 +1,1848 @@
+<!-- {{{ Banner                         -->
+
+<!-- =============================================================== -->
+<!--                                                                 -->
+<!--     ppp.sgml                                                    -->
+<!--                                                                 -->
+<!--     eCos PPP code                                               -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- ####COPYRIGHTBEGIN####                                          -->
+<!--                                                                 -->
+<!-- =============================================================== -->
+<!-- Copyright (C) 2003, 2004 eCosCentric Ltd.                             -->
+<!-- This material may be distributed only subject to the terms      -->
+<!-- and conditions set forth in the Open Publication License, v1.0  -->
+<!-- or later (the latest version is presently available at          -->
+<!-- http://www.opencontent.org/openpub/)                            -->
+<!-- =============================================================== -->
+<!--                                                                 -->      
+<!-- ####COPYRIGHTEND####                                            -->
+<!-- =============================================================== -->
+<!-- #####DESCRIPTIONBEGIN####                                       -->
+<!--                                                                 -->
+<!-- ####DESCRIPTIONEND####                                          -->
+<!-- =============================================================== -->
+
+<!-- }}} -->
+
+
+<part id="ppp">
+<title><productname>eCos</productname> PPP User Guide</title>
+
+<partintro>
+<para>
+This package provides support for PPP (Point-to-Point Protocol) in the
+<productname>eCos</productname> FreeBSD TCP/IP networking stack.
+</para>
+</partintro>
+
+<!-- {{{ Features                         -->
+
+<chapter id="ppp-features">
+<title>Features</title>
+<para>
+The <productname>eCos</productname> PPP implementation provides the
+following features:
+</para>
+<itemizedlist>
+
+<listitem>
+<para>
+PPP line protocol including VJ compression.
+</para>
+</listitem>
+
+<listitem>
+<para>
+LCP, IPCP and CCP control protocols.
+</para>
+</listitem>
+
+<listitem>
+<para>
+PAP and CHAP authentication.
+</para>
+</listitem>
+
+<listitem>
+<para>
+CHAT subset connection scripting.
+</para>
+</listitem>
+
+<listitem>
+<para>
+Modem control line support.
+</para>
+</listitem>
+
+</itemizedlist>
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Using                            -->
+
+<chapter id="ppp-using">
+<title>Using PPP</title>
+<para>
+Before going into detail, let's look at a simple example of how the
+<productname>eCos</productname> PPP package is used. Consider the
+following example:
+</para>
+
+<programlisting width=72>
+static void ppp_up(void)
+{
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+
+    // Bring up the TCP/IP network
+    init_all_network_interfaces();
+
+    // Initialize the options
+    cyg_ppp_options_init( &amp;options );
+
+    // Start up PPP
+    ppp_handle = cyg_ppp_up( "/dev/ser0", &amp;options );
+
+    // Wait for it to get running
+    if( cyg_ppp_wait_up( ppp_handle ) == 0 )
+    {
+        // Make use of PPP
+        use_ppp();
+
+        // Bring PPP link down
+        cyg_ppp_down( ppp_handle );
+
+        // Wait for connection to go down.
+        cyg_ppp_wait_down( ppp_handle );
+    }
+}
+</programlisting>
+
+<para>
+This is a simple example of how to bring up a simple PPP connection to
+another computer over a directly connected serial line. The other end
+is assumed to already be running PPP on the line and waiting for a
+connection.
+</para>
+
+<para>
+The first thing this code does is to call
+<function>init_all_network_interfaces()</function> to bring up the
+TCP/IP stack and initialize any other network interfaces. It then
+calls <function>cyg_ppp_options_init()</function> to initialize the
+PPP options structure to the defaults. As it happens, the default
+options are exactly what we want for this example, so we don't need to
+make any further changes. We go straight on to bring the PPP interface
+up by calling <function>cyg_ppp_up()</function>. The arguments to this
+function give the name of the serial device to use, in this case
+<literal>"/dev/ser0"</literal>, and a pointer to the options.
+</para>
+
+<para>
+When <function>cyg_ppp_up()</function> returns, it passes back a
+handle to the PPP connection which is to be used in other calls.  The
+PPP link will not necessarily have been fully initialized at this
+time. There is a certain amount of negotiation that goes on between
+the ends of a PPP link before it is ready to pass packets. An
+application can wait until the link is ready by calling
+<function>cyg_ppp_wait_up()</function>, which returns
+zero if the link is up and running, or
+<literal>-1</literal> if it has gone down or failed to come up.
+</para>
+
+<para>
+After a successful return from <function>cyg_ppp_wait_up()</function>,
+the application may make use of the PPP connection. This is
+represented here by the call to <function>use_ppp()</function> but
+it may, of course, be accessed by any thread. While the connection is
+up the application may use the standard socket calls to make or accept
+network connections and transfer data in the normal way.
+</para>
+
+<para>
+Once the application has finished with the PPP link, it can bring it
+down by calling <function>cyg_ppp_down()</function>. As with bringing
+the connection up, this call is asynchronous, it simply informs the
+PPP subsystem to start bringing the link down. The application can
+wait for the link to go down fully by calling
+<function>cyg_ppp_wait_down()</function>.
+</para>
+
+<para>
+That example showed how to use PPP to connect to a local peer. PPP is
+more often used to connect via a modem to a remote server, such as an
+ISP. The following example shows how this works:
+</para>
+
+<programlisting width=72>
+
+static char *isp_script[] =
+{
+    "ABORT"             ,       "BUSY"                                  ,
+    "ABORT"             ,       "NO CARRIER"                            ,
+    "ABORT"             ,       "ERROR"                                 ,
+    ""                  ,       "ATZ"                                   ,
+    "OK"                ,       "AT S7=45 S0=0 L1 V1 X4 &amp;C1 E1 Q0"      ,
+    "OK"                ,       "ATD" CYGPKG_PPP_DEFAULT_DIALUP_NUMBER  ,
+    "ogin:--ogin:"      ,       CYGPKG_PPP_AUTH_DEFAULT_USER            ,
+    "assword:"          ,       CYGPKG_PPP_AUTH_DEFAULT_PASSWD          ,
+    "otocol:"           ,       "ppp"                                   ,
+    "HELLO"             ,       "\\c"                                   ,
+    0
+};
+
+static void ppp_up(void)
+{
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+
+    // Bring up the TCP/IP network
+    init_all_network_interfaces();
+
+    // Initialize the options
+    cyg_ppp_options_init( &amp;options );
+
+    options.script = isp_script;
+    options.modem  = 1;
+
+    // Start up PPP
+    ppp_handle = cyg_ppp_up( "/dev/ser0", &amp;options );
+
+    // Wait for it to get running
+    if( cyg_ppp_wait_up( ppp_handle ) == 0 )
+    {
+        // Make use of PPP
+        use_ppp();
+
+        // Bring PPP link down
+        cyg_ppp_down( ppp_handle );
+
+        // Wait for connection to go down.
+        cyg_ppp_wait_down( ppp_handle );
+    }
+}
+</programlisting>
+
+<para>
+The majority of this code is exactly the same as the previous
+example. The main difference is in the setting of a couple of options
+before calling <function>cyg_ppp_up()</function>. The
+<structfield>script</structfield> option is set to point to a CHAT
+script to manage the setup of the connection. The
+<structfield>modem</structfield> option is set to cause the PPP system
+to make use of the modem control lines.
+</para>
+
+<para>
+During the PPP bring-up a call will be made to
+<function>cyg_ppp_chat()</function> to run the CHAT script (see <xref
+linkend="ppp-chat">). In the example this script sets up various modem
+options and then dials a number supplied as part of the PPP package
+configuration (see <xref linkend="ppp-config">). When the connection
+has been established, the script log on to the server, using a name
+and password also supplied by the configuration, and then starts PPP
+on the remote end. If this script succeeds the PPP connection will be
+brought up and will then function as expected.
+</para>
+
+<para>
+The <structfield>modem</structfield> option causes the PPP system to
+make use of the modem control lines. In particular it waits for
+<literal>Carrier Detect</literal> to be asserted, and will bring the
+link down if it is lost. See <xref linkend="ppp-options-init">
+for more details.
+</para>
+
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Interface                        -->
+
+<chapter id="ppp-interface">
+<title>PPP Interface</title>
+
+<!-- {{{ cyg_ppp_options_init             -->
+
+<refentry id="ppp-options-init">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_options_init()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_options_init</refname>
+      <refpurpose>Initialize PPP link options</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>cyg_int32 <function>cyg_ppp_options_init</function></funcdef>
+          <paramdef>cyg_ppp_options_t <parameter>*options</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-options-init-description">Description</title>
+<para>
+This function initializes the PPP options, pointed to by the
+<parameter>options</parameter> parameter, to the default state. Once
+the defaults have been initialized, application code may adjust them
+by assigning new values to the the fields of the
+<structname>cyg_ppp_options_t</structname> structure.
+</para>
+
+<para>
+This function returns zero if the options were initialized
+successfully. It returns -1 if the <parameter>options</parameter>
+argument is NULL, or the options could not be initialized.
+</para>
+
+<para>
+The option fields, their functions and default values are as follows:
+</para>
+
+<variablelist>
+
+<varlistentry>
+  <term>debug</term>
+  <listitem>
+    <para> If set to 1 this enables the reporting of debug messages
+    from the PPP system. These will be generated using
+    <function>diag_printf()</function> and will appear on the standard
+    debug channel. Note that <function>diag_printf()</function>
+    disables interrupts during output: this may cause the PPP link
+    device to overrun and miss characters. It is quite possible for
+    this option to cause errors and even make the PPP link fail
+    completely. Consequently, this option should be used with care.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>kdebugflag</term>
+  <listitem>
+    <para> This five bit field enables low level debugging messages from
+    the PPP device layer in the TCP/IP stack. As with the
+    <structfield>debug</structfield> option, this may result in missed
+    characters and cause errors. The bits of the field have the
+    following meanings:
+    </para>
+    <informaltable frame="all">
+      <tgroup cols="3" colsep="1" rowsep="1" align="left">
+        <thead>
+          <row>
+            <entry>Bit</entry>
+            <entry>BSD Name</entry>
+            <entry>Description</entry>
+          </row>
+        </thead>
+        <tbody>
+          <row>
+            <entry>0x01</entry>
+            <entry>SC_DEBUG</entry>
+            <entry>Enable debug messages</entry>
+          </row>
+          <row>
+            <entry>0x02</entry>
+            <entry>SC_LOG_INPKT</entry>
+            <entry>Log contents of good packets received</entry>
+          </row>
+          <row>
+            <entry>0x04</entry>
+            <entry>SC_LOG_OUTPKT</entry>
+            <entry>Log contents of packets sent</entry>
+          </row>
+          <row>
+            <entry>0x08</entry>
+            <entry>SC_LOG_RAWIN</entry>
+            <entry>Log all characters received</entry>
+          </row>
+          <row>
+            <entry>0x10</entry>
+            <entry>SC_LOG_FLUSH</entry>
+            <entry>Log all characters flushed</entry>
+          </row>
+        </tbody>
+      </tgroup>
+    </informaltable>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>default_route</term>
+  <listitem>
+    <para> If set to 1 this option causes the PPP subsystem to install
+    a default route in the TCP/IP stack's routing tables using the
+    peer as the gateway. This entry will be removed when the PPP link
+    is broken. If there is already an existing working network
+    connection, such as an ethernet device, then there may already be
+    a default route established. If this is the case, then this option
+    will have no effect.
+    </para>
+    <para>
+    Default value: 1
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>modem</term>
+  <listitem>
+    <para> If this option is set to 1, then the modem lines will be
+    used during the connection. Specifically, the PPP subsystem will
+    wait until the <literal>carrier detect</literal> signal is
+    asserted before bringing up the PPP link, and will take the PPP
+    link down if this signal is de-asserted.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>flowctl</term>
+  <listitem>
+    <para> This option is used to specify the mechanism used to
+    control data flow across the serial line. It can take one of the
+    following values:
+    </para>
+    <variablelist>
+      <varlistentry>
+        <term><literal>CYG_PPP_FLOWCTL_DEFAULT</literal></term>
+        <listitem>
+          <para>
+          The flow control mechanism is not changed and is left at
+          whatever value was set before bringing PPP up. This allows
+          a non-standard flow control mechanism to be used, or for it to
+          be chosen and set by some other means.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><literal>CYG_PPP_FLOWCTL_NONE</literal></term>
+        <listitem>
+          <para>
+          Flow control is turned off. It is not recommended that this
+          option be used unless the baud rate is set low or the two
+          communicating machines are particularly fast.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><literal>CYG_PPP_FLOWCTL_HARDWARE</literal></term>
+        <listitem>
+          <para>
+          Use hardware flow control via the RTS/CTS lines. This is the
+          most effective flow control mechanism and should always be
+          used if available. Availability of this mechanism depends on
+          whether the serial device hardware has the ability to control
+          these lines, whether they have been connected to the socket
+          pins and whether the device driver has the necessary support.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><literal>CYG_PPP_FLOWCTL_SOFTWARE</literal></term>
+        <listitem>
+          <para>
+          Use software flow control by embedding XON/XOFF characters in
+          the data stream. This is somewhat less effective that hardware
+          flow control since it is subject to the propagation time of
+          the serial cable and the latency of the communicating
+          devices. Since it does not rely on any hardware support, this
+          flow control mechanism is always available.
+          </para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+    <para>
+    Default value: CYG_PPP_FLOWCTL_HARDWARE
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>refuse_pap</term>
+  <listitem>
+    <para> If this option is set to 1, then the PPP subsystem will not
+    agree to authenticate itself to the peer with PAP. When dialling
+    in to a remote server it is normal to authenticate the
+    client. There are three ways this can be done, using a
+    straightforward login mechanism via the CHAT script, with the
+    Password Authentication Protocol (PAP), or with the Challenge
+    Handshake Authentication Protocol (CHAP). For PAP to work the
+    <structfield>user</structfield> and
+    <structfield>passwd</structfield> options must be set to the
+    expected values. If they are not, then this option should be set
+    to force CHAP authentication.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>refuse_chap</term>
+  <listitem>
+    <para> If this option is set to 1, then the PPP subsystem will not
+    agree to authenticate itself to the peer with CHAP. CHAP
+    authentication will only work if the
+    <structfield>passwd</structfield> option has been set to the
+    required CHAP secret for the destination server. Otherwise this
+    option should be disabled.
+    </para>
+    <para>
+    If both <structfield>refuse_pap</structfield> and
+    <structfield>refuse_chap</structfield> are set, then either no
+    authentication will be carried out, or it is the responsibility of
+    the <command>chat</command> script to do it. If the peer does not
+    require any authentication, then the setting of these options is
+    irrelevant.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>baud</term>
+  <listitem>
+    <para> This option is set to the baud rate at which the serial
+    connection should be run. The default value is the rate at which
+    modems conventionally operate. This field is an instance of the
+    <type>cyg_serial_baud_rate_t</type> enum defined in the
+    <literal>serialio.h</literal> header and may only take one of the
+    baud rate constants defined in there.
+    </para>
+    <para>
+    Default value: <literal>CYGNUM_SERIAL_BAUD_115200</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>idle_time_limit</term>
+  <listitem>
+    <para> This is the number of seconds that the PPP connection may
+    be idle before it is shut down automatically.
+    </para>
+    <para>
+    Default value: 60
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>maxconnect</term>
+  <listitem>
+    <para> This causes the connection to terminate when it has been up
+    for this number of seconds. The default value of zero means that
+    the connection will stay up indefinitely, until either end
+    explicitly brings it down, or the link is lost.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>our_address</term>
+  <listitem>
+    <para> This is the IP address, in network byte order, to be
+    attached to the local end of the PPP connection. The default value
+    of <literal>INADDR_ANY</literal> causes the local address to be
+    obtained from the peer.
+    </para>
+    <para>
+    Default value: <literal>INADDR_ANY</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>his_address</term>
+  <listitem>
+    <para> This is the IP address, in network byte order, to be
+    attached to the remote end of the PPP connection. The default
+    value of <literal>INADDR_ANY</literal> causes the remote address
+    to be obtained from the peer.
+    </para>
+    <para>
+    Default value: <literal>INADDR_ANY</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>script</term>
+  <listitem>
+    <para> This is a pointer to a CHAT script suitable for passing to
+    <function>cyg_ppp_chat()</function>. See <xref linkend="ppp-chat">
+    for details of the format and contents of this script.
+    </para>
+    <para>
+    Default value: <literal>NULL</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>user</term>
+  <listitem>
+    <para> This array contains the user name to be used for PAP
+    authentication. This field is not used for CHAP authentication. By
+    default the value of this option is set from the
+    <literal>CYGPKG_PPP_AUTH_DEFAULT_USER</literal> configuration
+    option.
+    </para>
+    <para>
+    Default value: <literal>CYGPKG_PPP_AUTH_DEFAULT_USER</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>passwd</term>
+  <listitem>
+    <para> This array contains the password to be used for PAP
+    authentication, or the secret to be used during CHAP
+    authentication. By default the value of this option is set from
+    the <literal>CYGPKG_PPP_AUTH_DEFAULT_PASSWD</literal>
+    configuration option.
+    </para>
+    <para>
+    Default value: <literal>CYGPKG_PPP_AUTH_DEFAULT_PASSWD</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+</variablelist>
+
+    </refsect1>
+
+</refentry>
+
+<!-- }}} -->
+<!-- {{{ cyg_ppp_up                       -->
+
+<refentry id="ppp-up">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_up()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_up</refname>
+      <refpurpose>Bring PPP connection up</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>cyg_ppp_handle_t <function>cyg_ppp_up</function></funcdef>
+          <paramdef>char <parameter>*devnam</parameter></paramdef>
+          <paramdef>const cyg_ppp_options_t <parameter>*options</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-up-description">Description</title>
+<para>
+This function starts up a PPP connection. The
+<parameter>devnam</parameter> argument is the name of the device to be
+used for the connection, typically <literal>"/dev/ser0"</literal> or
+<literal>"/dev/ser1"</literal>. The <structfield>options</structfield>
+argument should point to an initialized
+<structname>cyg_ppp_options_t</structname> object.
+</para>
+
+<para>
+The return value will either be zero, indicating a failure, or a
+<type>cyg_ppp_handle_t</type> object that may be used as an argument
+to other PPP functions.
+</para>
+
+<note>
+<para>
+Although the PPP API is designed to permit several simultaneous
+connections to co-exist, at present only one PPP connection is
+actually implemented. Any attempt to create a second connection while
+there is already one open will fail.
+</para>
+</note>
+
+</refsect1>
+
+</refentry>
+
+<!-- }}} -->
+<!-- {{{ cyg_ppp_down                     -->
+
+<refentry id="ppp-down">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_down()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_down</refname>
+      <refpurpose>Bring PPP connection down</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>cyg_int32 <function>cyg_ppp_down</function></funcdef>
+          <paramdef>cyg_ppp_handle_t <parameter>handle</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-down-description">Description</title>
+<para>
+This function brings the PPP connection down. The
+<parameter>handle</parameter> argument is the result of a successful
+call to <function>cyg_ppp_up()</function>. This function only signals
+to the PPP subsystem that the link should be brought down. The link
+will be terminated asynchronously. If the application needs to wait
+for the link to terminate, then it should call
+<function>cyg_ppp_wait_down()</function> after calling
+<function>cyg_ppp_down()</function>.
+</para>
+
+<para>
+The function returns zero if it was able to start the termination of
+the PPP connection successfully. It will return -1 if the connection
+is not running, or if it could not otherwise start the termination.
+</para>
+
+    </refsect1>
+
+</refentry>
+
+<!-- }}} -->  
+<!-- {{{ cyg_ppp_wait_up                  -->
+
+<refentry id="ppp-wait-up">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_wait_up()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_wait_up</refname>
+      <refpurpose>Wait for PPP connection to come up</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>cyg_int32 <function>cyg_ppp_wait_up</function></funcdef>
+          <paramdef>cyg_ppp_handle_t <parameter>handle</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-wait-up-description">Description</title>
+<para>
+This function waits until the PPP connection is running and then
+returns. This is needed because the actual bring up of the connection
+happens mostly after the call to <function>cyg_ppp_up()</function>
+returns, and may take some time to complete, especially if dialling a
+remote server.
+</para>
+
+<para>
+The result of this call will be zero when the connection is running,
+or -1 if the connection failed to start for some reason. If the
+connection is already running when this call is made it will return
+immediately with a zero result. If the connection is not in the
+process of coming up, or has failed, or has terminated, then a result
+of -1 will be returned immediately. Thus this function may also be
+used to test that the connection is still running at any point.
+</para>
+
+    </refsect1>
+
+</refentry>
+
+<!-- }}} -->  
+<!-- {{{ cyg_ppp_wait_down                -->
+
+<refentry id="ppp-wait-down">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_wait_down()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_wait_down</refname>
+      <refpurpose>Wait for PPP connection to terminate</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>void <function>cyg_ppp_wait_down</function></funcdef>
+          <paramdef>cyg_ppp_handle_t <parameter>handle</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-wait-down-description">Description</title>
+<para>
+This function waits for the PPP connection to terminate. The link may
+be terminated with a call to <function>cyg_ppp_down()</function>, by
+the remote end, or by the telephone line being dropped or lost. 
+</para>
+
+<para>
+This function has no return value. If the PPP connection is not
+running, or has terminated, it will return. Applications should use
+<function>cyg_ppp_wait_up()</function> to test the link state.
+</para>
+
+    </refsect1>
+
+</refentry>
+
+<!-- }}} -->  
+<!-- {{{ cyg_ppp_chat                     -->
+
+<refentry id="ppp-chat-fn">
+
+    <refmeta>
+    <refentrytitle>cyg_ppp_chat()</refentrytitle>
+    </refmeta>
+
+    <refnamediv>
+      <refname>cyg_ppp_chat</refname>
+      <refpurpose>Execute chat script</refpurpose>
+    </refnamediv>
+
+    <refsynopsisdiv>
+      <funcsynopsis>
+        <funcsynopsisinfo>
+#include &lt;cyg/ppp/ppp.h&gt;
+        </funcsynopsisinfo>
+        <funcprototype>
+          <funcdef>cyg_int32 <function>cyg_ppp_chat</function></funcdef>
+          <paramdef>const char <parameter>*devname</parameter></paramdef>
+          <paramdef>const char <parameter>*script[]</parameter></paramdef>
+        </funcprototype>
+      </funcsynopsis>
+    </refsynopsisdiv>
+
+    <refsect1><title id="ppp-chat-description">Description</title>
+<para>
+This function implements a subset of the automated conversational
+scripting as defined by the <command>chat</command> program. The first
+argument is the name of the serial device to be used, typically
+<literal>"/dev/ser0"</literal> or <literal>"/dev/ser1"</literal>. The
+<parameter>script</parameter> argument is a pointer to a zero
+terminated array of strings that comprise the chat script. See <xref
+linkend="ppp-using"> for an example script, and <xref
+linkend="ppp-chat"> for full detail of the script used.
+</para>
+
+<para>
+Under normal use this function is called from the PPP subsystem if the
+<structname>cyg_ppp_options_t</structname>
+<structfield>script</structfield> field is set to a
+non-<literal>NULL</literal> value. This function should only be used
+directly if the application needs to undertake special processing
+between running the chat script, and bringing up the PPP connections.
+</para>
+
+    </refsect1>
+
+</refentry>
+
+<!-- }}} -->  
+
+
+<!--IOCTLs???? -->
+
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Install and Config               -->
+
+<chapter id="ppp-config">
+<title>Installing and Configuring PPP</title>
+
+<sect1 id="ppp-config-include">
+<title>Including PPP in a Configuration</title>
+
+<para>
+PPP is contained entirely within a single
+<productname>eCos</productname> package. So to include PPP in a
+configuration all you need to do is add that package.
+</para>
+
+<para>
+In the GUI configuration tool use the
+<command>Build->Packages</command> menu item, find the "PPP Support"
+package in the left-hand pane and use the <command>Add</command> button
+to add it to the list of packages in use in the right-hand pane.
+</para>
+
+<para>
+In the command-line tool <command>ecosconfig</command>, you can use the
+following command during the configuration phase to add the PPP package:
+</para>
+
+<programlisting width=72>
+
+$ ecosconfig add ppp
+
+</programlisting>
+
+<para>
+In addition to the PPP package you will also need to have the
+<literal>"Network"</literal> package and the <literal>"Serial Device
+Drivers"</literal> package in the configuration. The dependencies and
+requirements of the networking package are such that it is strongly
+recommended that you start with the <literal>net</literal> template.
+</para>
+
+<para>
+See the <productname>eCos</productname> User Guide for full details on
+how to configure and build <productname>eCos</productname>.
+</para>
+
+</sect1>
+
+
+<sect1 id="ppp-config-config">
+<title>Configuring PPP</title>
+<para>
+The PPP package contains a number of configuration options that may be
+changed to affect its behaviour.
+
+<variablelist>
+
+<varlistentry>
+  <term>CYGNUM_PPP_PPPD_THREAD_PRIORITY</term>
+  <listitem>
+    <para>
+    The PPP system contains two threads, One is used for receiving
+    data from the link and processing control packets.  The other is
+    used to transmit data asynchronously to the link when it cannot be
+    completed synchronously. The receive thread runs at the priority
+    given here, and the transmit thread runs at the next lower
+    priority.  The exact priority needed here depends on the
+    importance of the PPP subsystem relative to the rest of the
+    system. The default is to put it in the middle of the priority
+    range to provide reasonable response without impacting genuine
+    high priority threads.
+    </para>
+    <para>
+    Default value: <literal>CYGNUM_KERNEL_SCHED_PRIORITIES/2</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_DEBUG_WARN_ONLY</term>
+  <listitem>
+    <para>
+    The runtime <varname>debug</varname> option enables logging of
+    high level debug messages. Too many of these can interfere with
+    the PPP device and may result in missed messages.  This is because
+    these messages are emitted via the diag_printf() mechanism, which
+    disables interrupts while it prints.  By default, therefore, we
+    only report errors and warnings, and not all events. Setting this
+    option to zero will enable the logging of all events.
+    </para>
+    <para>
+    Default value: <literal>1</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_AUTH_DEFAULT_USER</term>
+  <listitem>
+    <para>
+    This option gives the default value for the user name used to
+    initialize the <structfield>user</structfield> field in the PPP
+    options.
+    </para>
+    <para>
+    Default value: <literal>"eCos"</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_AUTH_DEFAULT_PASSWD</term>
+  <listitem>
+    <para>
+    This option gives the default value for the password used to
+    initialize the <structfield>passwd</structfield> field in the PPP
+    options.
+    </para>
+    <para>
+    Default value: <literal>"secret"</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_DEFAULT_DIALUP_NUMBER</term>
+  <listitem>
+    <para>
+    This option provides a default dialup number for use in
+    <command>chat</command> scripts. This value is not used anywhere
+    in the PPP package, but is provided to complete the information
+    needed, alongside the user name and password, for accessing a
+    typical dialup server.
+    </para>
+    <para>
+    Default value: <literal>"5551234"</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_PAP</term>
+  <listitem>
+    <para>
+    This component enables the inclusion of PAP authentication
+    support.
+    </para>
+    <para>
+    Default value: 1
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_CHAP</term>
+  <listitem>
+    <para>
+    This component enables the inclusion of CHAT authentication
+    support.
+    </para>
+    <para>
+    Default value: 1
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_COMPRESSION</term>
+  <listitem>
+    <para>
+    This component provides control over PPP compression
+    features. WARNING: at present there are problems with this option,
+    and and in any case the compression code needs to allocate large
+    amounts of memory. Hence this option is currently disabled and
+    should remain so.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>PPP_BSDCOMP</term>
+  <listitem>
+    <para>
+    This option enables inclusion of BSD compression into the PPP
+    protocol.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>PPP_DEFLATE</term>
+  <listitem>
+    <para>
+    This option enables inclusion of ZLIB compression into the PPP
+    protocol.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_CHAT</term>
+  <listitem>
+    <para>
+    This component enables the inclusion of a simple scripting system
+    to bring up PPP connections.  It implements a subset of the
+    <command>chat</command> scripting language.
+    </para>
+    <para>
+    Default value: 1
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGNUM_PPP_CHAT_ABORTS_MAX</term>
+  <listitem>
+    <para>
+    This option defines the maximum number of <literal>ABORT</literal>
+    strings that the CHAT system will store.
+    </para>
+    <para>
+    Default value: 10
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGNUM_PPP_CHAT_ABORTS_SIZE</term>
+  <listitem>
+    <para>
+    This option defines the maximum size of each
+    <literal>ABORT</literal> strings that the <command>chat</command>
+    system will store.
+    </para>
+    <para>
+    Default value: 20
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGNUM_PPP_CHAT_STRING_LENGTH</term>
+  <listitem>
+    <para>
+    This option defines the maximum size of any expect or reply
+    strings that the <command>chat</command> system will be given.
+    </para>
+    <para>
+    Default value: 256
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_TEST_DEVICE</term>
+  <listitem>
+    <para>
+    This option defines the serial device to be used for PPP test
+    programs.
+    </para>
+    <para>
+    Default value: <literal>"/dev/ser0"</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGPKG_PPP_TESTS_AUTOMATE</term>
+  <listitem>
+    <para>
+    This option enables automated testing features in certain test
+    programs. These programs will interact with a test server at the
+    remote end of the serial link to run a variety of tests in
+    different conditions. Without this option most tests default to
+    running a single test instance and are suitable for being run by
+    hand for debugging purposes.
+    </para>
+    <para>
+    Default value: 0
+    </para>
+  </listitem>
+</varlistentry>
+
+<varlistentry>
+  <term>CYGDAT_PPP_TEST_BAUD_RATES</term>
+  <listitem>
+    <para>
+    This option supplies a list of baud rates at which certain tests
+    will run if the <literal>CYGPKG_PPP_TESTS_AUTOMATE</literal>
+    option is set.
+    </para>
+    <para>
+    Default value: <literal>"CYGNUM_SERIAL_BAUD_19200,CYGNUM_SERIAL_BAUD_38400,CYGNUM_SERIAL_BAUD_57600,CYGNUM_SERIAL_BAUD_115200"</literal>
+    </para>
+  </listitem>
+</varlistentry>
+
+</variablelist>
+
+
+</para>
+
+</sect1>
+
+
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Chat                             -->
+
+<chapter id="ppp-chat">
+<title>CHAT Scripts</title>
+<para>
+The automated conversational scripting supported by the
+<productname>eCos</productname> PPP package is a subset of the
+scripting language provided by the <command>chat</command> command
+found on most UNIX and Linux systems.
+</para>
+
+<para>
+Unlike the <command>chat</command> command, the
+<productname>eCos</productname> <function>cyg_ppp_chat()</function>
+function takes as a parameter a zero-terminated array of pointers to
+strings. In most programs this will be defined by means of an
+initializer for a static array, although there is nothing to stop the
+application constructing it at runtime. A simple script would be
+defined like this:
+</para>
+
+<programlisting width=72>
+
+static char *chat_script[] =
+{
+    "ABORT"        ,  "BUSY"        ,
+    "ABORT"        ,  "NO CARRIER"  ,
+    ""             ,  "ATD5551234"  ,
+    "ogin:--ogin:" ,  "ppp"         ,
+    "ssword:"      ,  "hithere"     ,
+    0
+};
+
+</programlisting>
+
+<para>
+The following sections have been abstracted from the public domain
+documentation for the <command>chat</command> command. 
+</para>
+
+
+<sect1 id="ppp-chat-script">
+<title>Chat Script</title>
+<para>
+       A script consists of one or more "expect-send" pairs of
+       strings, separated by spaces, with an optional "subexpect-
+       subsend" string pair, separated by a dash as in the following
+       example:
+</para>
+
+<programlisting width=72>
+
+    "ogin:--ogin:"     ,  "ppp"       ,
+    "ssword:"          ,   "hello2u2" ,
+    0
+
+</programlisting>
+
+<para>
+       This script fragment indicates that the
+       <function>cyg_ppp_chat()</function> function should expect the
+       string "ogin:". If it fails to receive a login prompt within
+       the time interval allotted, it is to send a carriage return
+       to the remote and then expect the string "ogin:" again.  If
+       the first "ogin:" is received then the carriage return is not
+       generated.
+</para>
+<para>
+       Once it received the login prompt the
+       <function>cyg_ppp_chat()</function> function will send the
+       string "ppp" and then expect the prompt "ssword:".  When it
+       receives the prompt for the password, it will send the password
+       "hello2u2".
+</para>
+<para>
+       A carriage return is normally sent following the reply string.
+       It is not expected in the "expect" string unless it is
+       specifically requested by using the "\r" character sequence.
+</para>
+<para>
+       The expect sequence should contain only what is needed to
+       identify the string. It should not contain variable
+       information. It is generally not acceptable to look for time
+       strings, network identification strings, or other variable
+       pieces of data as an expect string.
+</para>
+<para>
+       To help correct for characters which may be corrupted during
+       the initial sequence, look for the string "ogin:" rather than
+       "login:". It is possible that the leading "l" character may be
+       received in error and you may never find the string even though
+       it was sent by the system. For this reason, scripts look for
+       "ogin:" rather than "login:" and "ssword:" rather than
+       "password:".
+</para>
+<para>
+       A very simple script might look like this:
+</para>
+<programlisting width=72>
+
+    "ogin:"    , "ppp"       ,
+    "ssword:"  , " hello2u2" ,
+    0
+
+</programlisting>
+
+<para>
+       In other words, expect "....ogin:", send "ppp", expect "...ssword:",
+       send "hello2u2".
+</para>
+<para>
+       In actual practice, simple scripts are rare. At the very least,
+       you should include sub-expect sequences should the original
+       string not be received. For example, consider the following
+       script:
+</para>
+<programlisting width=72>
+
+    "ogin:--ogin:"  , "ppp"     ,
+    "ssword:"       , "hello2u2",
+    0
+
+</programlisting>
+<para>
+       This would be a better script than the simple one used earlier.
+       This would look for the same "login:" prompt, however, if one
+       was not received, a single return sequence is sent and then it
+       will look for "login:" again. Should line noise obscure the
+       first login prompt then sending the empty line will usually
+       generate a login prompt again.
+</para>
+
+</sect1>
+
+<sect1 id="ppp-chat-abort">
+<title>ABORT Strings</title>
+
+<para>
+       Many modems will report the status of the call as a
+       string. These strings may be CONNECTED or NO CARRIER or
+       BUSY. It is often desirable to terminate the script should the
+       modem fail to connect to the remote. The difficulty is that a
+       script would not know exactly which modem string it may
+       receive. On one attempt, it may receive BUSY while the next
+       time it may receive NO CARRIER.
+</para>
+<para>
+       These "abort" strings may be specified in the script using
+       the ABORT sequence. It is written in the script as in  the
+       following example:
+</para>
+<programlisting width=72>
+
+    "ABORT"    , "BUSY"    ,
+    "ABORT"    , "NO CARRIER"  ,
+    ""         , "ATZ"         ,
+    "OK"       , "ATDT5551212" ,
+    "CONNECT"  , ...
+
+</programlisting>
+
+<para>
+       This sequence will expect nothing; and then send the string
+       ATZ.  The expected response to this is the string OK. When it
+       receives OK, it sends the string ATDT5551212 to dial the
+       telephone.  The expected string is CONNECT. If the string
+       CONNECT is received the remainder of the script is
+       executed. However, should the modem find a busy telephone, it
+       will send the string BUSY. This will cause the string to match
+       the abort character sequence. The script will then fail because
+       it found a match to the abort string. If it received the string
+       NO CARRIER, it will abort for the same reason. Either string
+       may be received. Either string will terminate the chat script.
+</para>
+
+</sect1>
+
+<sect1 id="ppp-chat-timeout">
+<title>TIMEOUT</title>
+<para>
+       The initial timeout value  is  45  seconds.
+       To  change  the  timeout value for the next expect string,
+       the following example may be used:
+</para>
+<programlisting width=72>
+
+    ""              , "ATZ"         ,
+    "OK"            , "ATDT5551212" ,
+    "CONNECT"       , "\\c"         ,
+    "TIMEOUT"       , "10"          ,
+    "ogin:--ogin:"  , "ppp"         ,
+    "TIMEOUT"       , "5"           ,
+    "assword:"      , "hello2u2"    ,
+    0
+
+</programlisting>
+<para>
+       This will change the timeout to 10 seconds when it expects the
+       login: prompt. The timeout is then changed to 5 seconds when
+       it looks for the password prompt.
+</para>
+<para>
+       The  timeout,  once changed, remains in effect until it is
+       changed again.
+</para>
+
+</sect1>
+
+<sect1 id="ppp-chat-eot">
+<title>Sending EOT</title>
+<para>
+       The special reply string of EOT indicates  that  the  chat
+       program  should  send an EOT character to the remote. This
+       is normally the End-of-file character sequence.  A  return
+       character is not sent following the EOT.  The EOT sequence
+       may be embedded into the send string  using  the  sequence
+       "\x04" (i.e. a Control-D character).
+</para>
+</sect1>
+
+<sect1 id="ppp-chat-escape">
+<title>Escape Sequences</title>
+<para>
+Most standard <command>chat</command> escape sequences can be replaced
+with standard C string escapes such as '\r', '\n', '\t'
+etc. Additional escape sequences may be embedded in the expect or
+reply strings by introducing them with <emphasis>two</emphasis>
+backslashes.
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term>\\c</term>
+<listitem>
+<para>
+Suppresses the newline at the end of the reply string.  This is the
+only method to send a string without a trailing return character. It
+must be at the end of the send string.  For example, the sequence
+"hello\\c" will simply send the characters h, e, l, l, o.  (not valid
+in expect strings.)
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Drivers                          -->
+
+<chapter id="ppp-drivers">
+<title>PPP Enabled Device Drivers</title>
+<para>
+For PPP to function fully over a serial device, its driver must
+implement certain features. At present not all
+<productname>eCos</productname> serial drivers implement these
+features. A driver indicates that it supports a certain feature by
+including an <literal>"implements"</literal> line in its CDL for the
+following interfaces:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><literal>CYGINT_IO_SERIAL_FLOW_CONTROL_HW</literal></term>
+<listitem>
+<para>
+This interface indicates that the driver implements hardware flow
+control using the RTS and CTS lines. When data is being transferred
+over high speed data lines, it is essential that flow control be used
+to prevent buffer overrun.
+</para>
+<para>
+The PPP subsystem functions best with hardware flow control. If this
+is not available, then it can be configured to use software flow
+control. Since software flow control is implemented by the device
+independent part of the serial device infrastructure, it is available
+for all serial devices. However, this will have an effect on the
+performance and reliability of the PPP link.
+</para>
+</listitem>
+</varlistentry>
+
+
+<varlistentry>
+<term><literal>CYGINT_IO_SERIAL_LINE_STATUS_HW</literal></term>
+<listitem>
+<para>
+This interface indicates that the driver implements a callback
+interface for indicating the status of various RS232 control lines. Of
+particular interest here is the ability to detect changes in the
+Carrier Detect (CD) line. Not all drivers that implement this
+interface can indicate CD status.
+</para>
+<para>
+This functionality is only needed if it is important that the link be
+dropped immediately a telephone connection fails. Without it, a
+connection will only be dropped after it times out. This may be
+acceptable in many situations.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+At the time of writing, the serial device drivers for the following
+platforms implement some or all of the required functionality:
+</para>
+
+<itemizedlist>
+
+<listitem>
+<para>
+All drivers that use the generic 16x5x driver implement all functions:
+</para>
+<itemizedlist>
+<listitem><para>ARM CerfPDA</para></listitem>
+<listitem><para>ARM IQ80321</para></listitem>
+<listitem><para>ARM PID</para></listitem>
+<listitem><para>ARM IOP310</para></listitem>
+<listitem><para>i386 PC</para></listitem>
+<listitem><para>MIPS Atlas</para></listitem>
+<listitem><para>MIPS Ref4955</para></listitem>
+<listitem><para>SH3 SE77x9</para></listitem>
+</itemizedlist>
+</listitem>
+
+<listitem>
+<para>
+The following drivers implement flow control but either do not support
+line status callbacks, or do not report CD changes:
+</para>
+<itemizedlist>
+<listitem><para>SH4 SCIF</para></listitem>
+<listitem><para>A&amp;M AdderI</para></listitem>
+<listitem><para>A&amp;M AdderII</para></listitem>
+</itemizedlist>
+</listitem>
+
+<listitem>
+<para>
+All other drivers can support software flow control only.
+</para>
+</listitem>
+
+</itemizedlist>
+
+
+</chapter>
+
+<!-- }}} -->
+<!-- {{{ Tests                            -->
+
+<chapter id="ppp-tests">
+<title>Testing</title>
+
+
+<sect1>
+<title>Test Programs</title>
+
+<para>
+There are a number of test programs supplied with the PPP
+subsystem. By default all of these tests use the device configured by
+<literal>CYGPKG_PPP_TEST_DEVICE</literal> as the PPP link device.
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><literal>ppp_up</literal></term>
+<listitem>
+<para>
+This test just brings up the PPP link on
+<literal>CYGPKG_PPP_TEST_DEVICE</literal> and waits until the remote end brings
+it back down. No modem lines are used and the program expects a PPP
+connection to be waiting on the other end of the line. Typically the
+remote end will test the link using <command>ping</command> or access
+the HTTP system monitor if it is present.
+</para>
+<para>
+If <literal>CYGPKG_PPP_TESTS_AUTOMATE</literal> is set, then this test
+attempts to bring PPP up at each of the baud rates specified in
+<literal>CYGDAT_PPP_TEST_BAUD_RATES</literal>. If it is not set then
+it will just bring the connection up at 115200 baud.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>ppp_updown</literal></term>
+<listitem>
+<para>
+This test brings the PPP link up on
+<literal>CYGPKG_PPP_TEST_DEVICE</literal> and attempts to
+<command>ping</command> the remote end of the link. Once the pings
+have finished, the link is then brought down.
+</para>
+<para>
+If <literal>CYGPKG_PPP_TESTS_AUTOMATE</literal> is set, then this test
+attempts to bring PPP up at each of the baud rates specified in
+<literal>CYGDAT_PPP_TEST_BAUD_RATES</literal>. If it is not set then
+it will just bring the connection up at 115200 baud.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>chat</literal></term>
+<listitem>
+<para>
+This test does not bring the PPP link up but simply executes a chat
+script. It expects a server at the remote end of the link to supply
+the correct responses.
+</para>
+<para>
+This program expects the <command>test_server.sh</command> script to
+be running on the remote end and attempts several different tests,
+expecting a variety of different responses for each.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>ppp_auth</literal></term>
+<listitem>
+<para>
+This test attempts to bring up the PPP link under a variety of
+different authentication conditions. This includes checking that both
+PAP and CHAP authentication work, and that the connection is rejected
+when the incorrect authentication protcol or secrets are used. 
+</para>
+<para>
+This test expects the <command>test_server.sh</command> script to be
+running on the remote end. For this test to work the <filename>/etc/ppp/pap-secrets</filename> file on the remote
+end should contain the following two lines:
+</para>
+<programlisting width=72>
+eCos       *         secret       *
+eCosPAP    *         secretPAP    *
+</programlisting>
+<para>
+The <filename>/etc/ppp/chap-secrets</filename> file should contain:
+</para>
+<programlisting width=72>
+eCos       *         secret       *
+eCosCHAP   *         secretCHAP   *
+</programlisting>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>isp</literal></term>
+<listitem>
+<para>
+This test expects the serial test device to be connected to a Hayes
+compatible modem. The test dials the telephone number given in
+<literal>CYGPKG_PPP_DEFAULT_DIALUP_NUMBER</literal> and attempts to
+log on to an ISP using the user name and password supplied in
+<literal>CYGPKG_PPP_AUTH_DEFAULT_USER</literal> and
+<literal>CYGPKG_PPP_AUTH_DEFAULT_PASSWD</literal>. Once the PPP
+connection has been made, the program then attempts to ping a number
+of well known addresses.
+</para>
+<para>
+Since this test is designed to interact with an ISP, it does not run
+within the automated testing system.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>tcp_echo</literal></term>
+<listitem>
+<para>
+This is a version of the standard network <command>tcp_echo</command>
+test that brings up the PPP connection before waiting for the
+<command>tcp_sink</command> and <command>tcp_source</command> programs
+to connect. It is expected that at least one of these programs will
+connect via the PPP link. However, if another network interface is
+present, such as an ethernet device, then one may connect via that
+interface.
+</para>
+<para>
+While this test is supported by the <command>test_server.sh</command>
+script, it runs for such a long time that it should not normally be
+used during automated testing.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>nc_test_slave</literal></term>
+<listitem>
+<para>
+This is a version of the standard network
+<command>nc_test_slave</command> test that brings up the PPP
+connection before waiting for the <command>nc_test_master</command>
+program to connect. It is expected that the master will connect via
+the PPP link.
+</para>
+<para>
+While this test is supported by the <command>test_server.sh</command>
+script, it runs for such a long time that it should not normally be
+used during automated testing.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="ppp-test-script">
+<title>Test Script</title>
+
+<para>
+The PPP package additionally contains a shell script
+(<command>test_server.sh</command>) that may be used to operate the
+remote end of a PPP test link.
+</para>
+
+<para>
+The script may be invoked with the following arguments:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><literal>--dev=&lt;devname&gt;</literal></term>
+<listitem>
+<para>
+This mandatory option gives the name of the device to be used for the
+PPP link. Typically <literal>"/dev/ttyS0"</literal> or
+<literal>"/dev/ttyS1"</literal>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--myip=&lt;ipaddress&gt;</literal></term>
+<listitem>
+<para>
+This mandatory option gives the IP address to be attached to this end
+of the PPP link.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--hisip=&lt;ipaddress&gt;</literal></term>
+<listitem>
+<para>
+This mandatory option gives the IP address to be attached to the
+remote (test target) end of the PPP link.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--baud=&lt;baud_rate&gt;</literal></term>
+<listitem>
+<para>
+This option gives the baud rate at which the PPP link is to be run. If
+absent then the link will run at the value set for
+<literal>--redboot-baud</literal>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--redboot</literal></term>
+<listitem>
+<para>
+If this option is present then the script will look for a
+<literal>"RedBoot&gt;"</literal> prompt between test runs. This is
+necessary if the serial device being used for testing is also used by
+RedBoot.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--redboot-baud=&lt;baud_rate&gt;</literal></term>
+<listitem>
+<para>
+This option gives the baud rate at which the search for the RedBoot
+prompt will be made. If absent then the link will run at 38400 baud.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><literal>--debug</literal></term>
+<listitem>
+<para>
+If this option is present, then the script will print out some
+additional debug messages while it runs.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>
+This script operates as follows: If the <literal>--redboot</literal>
+option is set it sets the device baud rate to the RedBoot baud rate
+and waits until a <literal>"RedBoot&gt;"</literal> prompt is encountered.
+It then sets the baud rate to the value given by the
+<literal>--baud</literal> option and reads lines from the device until
+a recognizable test announce string is read. It then executes an
+appropriate set of commands to satisfy the test. This usually means
+bringing up the PPP link by running <command>pppd</command> and maybe
+executing various commands. It then either terminates the link itself,
+or waits for the target to terminate it. It then goes back to looking
+for another test announce string. If a string of the form
+<literal>"BAUD:XXX"</literal> is received then the baud rate is
+changed depending on the <literal>XXX</literal> value. If a
+<literal>"FINISH"</literal> string is received it returns to waiting
+for a <literal>"RedBoot>"</literal> prompt. The script repeats this
+process until it is terminated with a signal.
+</para>
+
+</sect1>
+
+</chapter>
+
+<!-- }}} -->
+
+
+</part>
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/cbcp.h
@@ -0,0 +1,75 @@
+//==========================================================================
+//
+//      include/cbcp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+#ifndef CBCP_H
+#define CBCP_H
+
+typedef struct cbcp_state {
+    int    us_unit;	/* Interface unit number */
+    u_char us_id;		/* Current id */
+    u_char us_allowed;
+    int    us_type;
+    char   *us_number;    /* Telefone Number */
+} cbcp_state;
+
+extern cbcp_state cbcp[];
+
+extern struct protent cbcp_protent;
+
+#define CBCP_MINLEN 4
+
+#define CBCP_REQ    1
+#define CBCP_RESP   2
+#define CBCP_ACK    3
+
+#define CB_CONF_NO     1
+#define CB_CONF_USER   2
+#define CB_CONF_ADMIN  3
+#define CB_CONF_LIST   4
+#endif
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/ccp.h
@@ -0,0 +1,99 @@
+//==========================================================================
+//
+//      include/ccp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ccp.h - Definitions for PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/ccp.h,v 1.8 1999/08/28 01:19:00 peter Exp $
+ */
+
+typedef struct ccp_options {
+    u_int bsd_compress: 1;	/* do BSD Compress? */
+    u_int deflate: 1;		/* do Deflate? (RFC code) */
+    u_int baddeflate: 1;	/* do Deflate? (Magnalink!) */
+    u_int predictor_1: 1;	/* do Predictor-1? */
+    u_int predictor_2: 1;	/* do Predictor-2? */
+    u_int deflate_correct: 1;	/* use correct code for deflate? */
+    u_int deflate_draft: 1;	/* use draft RFC code for deflate? */
+    u_short bsd_bits;		/* # bits/code for BSD Compress */
+    u_short deflate_size;	/* lg(window size) for Deflate */
+    u_short baddeflate_size;	/* lg(window size) for Deflate */
+    short method;		/* code for chosen compression method */
+} ccp_options;
+
+extern fsm ccp_fsm[];
+extern ccp_options ccp_wantoptions[];
+extern ccp_options ccp_gotoptions[];
+extern ccp_options ccp_allowoptions[];
+extern ccp_options ccp_hisoptions[];
+
+extern struct protent ccp_protent;
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/chap.h
@@ -0,0 +1,173 @@
+//==========================================================================
+//
+//      include/chap.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/chap.h,v 1.7 1999/08/28 01:19:01 peter Exp $
+ */
+
+#ifndef __CHAP_INCLUDE__
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN		4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5		5	/* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE	16	/* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT		0x80	/* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN	49	/* Response length for MS-CHAP */
+
+#define CHAP_CHALLENGE		1
+#define CHAP_RESPONSE		2
+#define CHAP_SUCCESS		3
+#define CHAP_FAILURE    	4
+
+/*
+ *  Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH	32
+#define MAX_CHALLENGE_LENGTH	64
+#define MAX_RESPONSE_LENGTH	64	/* sufficient for MD5 or MS-CHAP */
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+    int unit;			/* Interface unit number */
+    int clientstate;		/* Client state */
+    int serverstate;		/* Server state */
+    u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+    u_char chal_len;		/* challenge length */
+    u_char chal_id;		/* ID of last challenge */
+    u_char chal_type;		/* hash algorithm for challenges */
+    u_char id;			/* Current id */
+    char *chal_name;		/* Our name to use with challenge */
+    int chal_interval;		/* Time until we challenge peer again */
+    int timeouttime;		/* Timeout time in seconds */
+    int max_transmits;		/* Maximum # of challenge transmissions */
+    int chal_transmits;		/* Number of transmissions of challenge */
+    int resp_transmits;		/* Number of transmissions of response */
+    u_char response[MAX_RESPONSE_LENGTH];	/* Response to send */
+    u_char resp_length;		/* length of response */
+    u_char resp_id;		/* ID for response messages */
+    u_char resp_type;		/* hash algorithm for responses */
+    char *resp_name;		/* Our name to send with response */
+} chap_state;
+
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL		0	/* Lower layer down, not opened */
+#define CHAPCS_CLOSED		1	/* Lower layer up, not opened */
+#define CHAPCS_PENDING		2	/* Auth us to peer when lower up */
+#define CHAPCS_LISTEN		3	/* Listening for a challenge */
+#define CHAPCS_RESPONSE		4	/* Sent response, waiting for status */
+#define CHAPCS_OPEN		5	/* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL		0	/* Lower layer down, not opened */
+#define CHAPSS_CLOSED		1	/* Lower layer up, not opened */
+#define CHAPSS_PENDING		2	/* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL	3	/* We've sent the first challenge */
+#define CHAPSS_OPEN		4	/* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE	5	/* We've sent another challenge */
+#define CHAPSS_BADAUTH		6	/* We've sent a Failure msg */
+
+/*
+ * Timeouts.
+ */
+#define CHAP_DEFTIMEOUT		3	/* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS	10	/* max # times to send challenge */
+
+extern chap_state chap[];
+
+void ChapAuthWithPeer __P((int, char *, int));
+void ChapAuthPeer __P((int, char *, int));
+
+extern struct protent chap_protent;
+
+#define __CHAP_INCLUDE__
+#endif /* __CHAP_INCLUDE__ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/chap_ms.h
@@ -0,0 +1,82 @@
+//==========================================================================
+//
+//      include/chap_ms.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/chap_ms.h,v 1.5 1999/08/28 01:19:02 peter Exp $
+ */
+
+#ifndef __CHAPMS_INCLUDE__
+
+#define MD4_SIGNATURE_SIZE	16	/* 16 bytes in a MD4 message digest */
+#define MAX_NT_PASSWORD	256	/* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS __P((chap_state *, char *, int, char *, int));
+
+#define __CHAPMS_INCLUDE__
+#endif /* __CHAPMS_INCLUDE__ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/fsm.h
@@ -0,0 +1,193 @@
+//==========================================================================
+//
+//      include/fsm.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/fsm.h,v 1.7 1999/08/28 01:19:03 peter Exp $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define HEADERLEN	(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ *  CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ		1	/* Configuration Request */
+#define CONFACK		2	/* Configuration Ack */
+#define CONFNAK		3	/* Configuration Nak */
+#define CONFREJ		4	/* Configuration Reject */
+#define TERMREQ		5	/* Termination Request */
+#define TERMACK		6	/* Termination Ack */
+#define CODEREJ		7	/* Code Reject */
+
+
+/*
+ * Each FSM is described by an fsm structure and fsm callbacks.
+ */
+typedef struct fsm {
+    int unit;			/* Interface unit number */
+    int protocol;		/* Data Link Layer Protocol field value */
+    int state;			/* State */
+    int flags;			/* Contains option bits */
+    u_char id;			/* Current id */
+    u_char reqid;		/* Current request id */
+    u_char seen_ack;		/* Have received valid Ack/Nak/Rej to Req */
+    int timeouttime;		/* Timeout time in milliseconds */
+    int maxconfreqtransmits;	/* Maximum Configure-Request transmissions */
+    int retransmits;		/* Number of retransmissions left */
+    int maxtermtransmits;	/* Maximum Terminate-Request transmissions */
+    int nakloops;		/* Number of nak loops since last ack */
+    int maxnakloops;		/* Maximum number of nak loops tolerated */
+    struct fsm_callbacks *callbacks;	/* Callback routines */
+    char *term_reason;		/* Reason for closing protocol */
+    int term_reason_len;	/* Length of term_reason */
+} fsm;
+
+
+typedef struct fsm_callbacks {
+    void (*resetci)		/* Reset our Configuration Information */
+		__P((fsm *));
+    int  (*cilen)		/* Length of our Configuration Information */
+		__P((fsm *));
+    void (*addci) 		/* Add our Configuration Information */
+		__P((fsm *, u_char *, int *));
+    int  (*ackci)		/* ACK our Configuration Information */
+		__P((fsm *, u_char *, int));
+    int  (*nakci)		/* NAK our Configuration Information */
+		__P((fsm *, u_char *, int));
+    int  (*rejci)		/* Reject our Configuration Information */
+		__P((fsm *, u_char *, int));
+    int  (*reqci)		/* Request peer's Configuration Information */
+		__P((fsm *, u_char *, int *, int));
+    void (*up)			/* Called when fsm reaches OPENED state */
+		__P((fsm *));
+    void (*down)		/* Called when fsm leaves OPENED state */
+		__P((fsm *));
+    void (*starting)		/* Called when we want the lower layer */
+		__P((fsm *));
+    void (*finished)		/* Called when we don't want the lower layer */
+		__P((fsm *));
+    void (*protreject)		/* Called when Protocol-Reject received */
+		__P((int));
+    void (*retransmit)		/* Retransmission is necessary */
+		__P((fsm *));
+    int  (*extcode)		/* Called when unknown code received */
+		__P((fsm *, int, int, u_char *, int));
+    char *proto_name;		/* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+/*
+ * Link states.
+ */
+#define INITIAL		0	/* Down, hasn't been opened */
+#define STARTING	1	/* Down, been opened */
+#define CLOSED		2	/* Up, hasn't been opened */
+#define STOPPED		3	/* Open, waiting for down event */
+#define CLOSING		4	/* Terminating the connection, not open */
+#define STOPPING	5	/* Terminating, but open */
+#define REQSENT		6	/* We've sent a Config Request */
+#define ACKRCVD		7	/* We've received a Config Ack */
+#define ACKSENT		8	/* We've sent a Config Ack */
+#define OPENED		9	/* Connection available */
+
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE	1	/* Don't die if we don't get a response */
+#define OPT_RESTART	2	/* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT	4	/* Wait for peer to speak first */
+
+
+/*
+ * Timeouts.
+ */
+#define DEFTIMEOUT	3	/* Timeout time in seconds */
+#define DEFMAXTERMREQS	2	/* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS	10	/* Maximum Configure-Request transmissions */
+#define DEFMAXNAKLOOPS	5	/* Maximum number of nak loops */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init __P((fsm *));
+void fsm_lowerup __P((fsm *));
+void fsm_lowerdown __P((fsm *));
+void fsm_open __P((fsm *));
+void fsm_close __P((fsm *, char *));
+void fsm_input __P((fsm *, u_char *, int));
+void fsm_protreject __P((fsm *));
+void fsm_sdata __P((fsm *, int, int, u_char *, int));
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[];		/* currently negotiated peer MRU (per unit) */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/ipcp.h
@@ -0,0 +1,119 @@
+//==========================================================================
+//
+//      include/ipcp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/ipcp.h,v 1.10 1999/08/28 01:19:03 peter Exp $
+ */
+
+/*
+ * Options.
+ */
+#define CI_ADDRS	1	/* IP Addresses */
+#define CI_COMPRESSTYPE	2	/* Compression Type */
+#define	CI_ADDR		3
+
+#define CI_MS_DNS1	129	/* Primary DNS value */
+#define CI_MS_WINS1	130	/* Primary WINS value */
+#define CI_MS_DNS2	131	/* Secondary DNS value */
+#define CI_MS_WINS2	132	/* Secondary WINS value */
+
+#define MAX_STATES 16		/* from slcompress.h */
+
+#define IPCP_VJMODE_OLD 1	/* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2	/* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3	/* "new-rfc"mode (option # = 0x002d, */
+                                /*  maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d	/* current value for VJ compression option*/
+#define IPCP_VJ_COMP_OLD 0x0037	/* "old" (i.e, broken) value for VJ */
+				/* compression option*/ 
+
+typedef struct ipcp_options {
+    int neg_addr : 1;		/* Negotiate IP Address? */
+    int old_addrs : 1;		/* Use old (IP-Addresses) option? */
+    int req_addr : 1;		/* Ask peer to send IP address? */
+    int default_route : 1;	/* Assign default route through interface? */
+    int proxy_arp : 1;		/* Make proxy ARP entry for peer? */
+    int neg_vj : 1;		/* Van Jacobson Compression? */
+    int old_vj : 1;		/* use old (short) form of VJ option? */
+    int accept_local : 1;	/* accept peer's value for ouraddr */
+    int accept_remote : 1;	/* accept peer's value for hisaddr */
+    u_short vj_protocol;	/* protocol value to use in VJ option */
+    u_char maxslotindex, cflag;	/* values for RFC1332 VJ compression neg. */
+    u_int32_t ouraddr, hisaddr;	/* Addresses in NETWORK BYTE ORDER */
+    u_int32_t dnsaddr[2];	/* Primary and secondary MS DNS entries */
+    u_int32_t winsaddr[2];	/* Primary and secondary MS WINS entries */
+} ipcp_options;
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+char *ip_ntoa __P((u_int32_t));
+
+extern struct protent ipcp_protent;
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/lcp.h
@@ -0,0 +1,137 @@
+//==========================================================================
+//
+//      include/lcp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/lcp.h,v 1.7 1999/08/28 01:19:05 peter Exp $
+ */
+
+/*
+ * Options.
+ */
+#define CI_MRU		1	/* Maximum Receive Unit */
+#define CI_ASYNCMAP	2	/* Async Control Character Map */
+#define CI_AUTHTYPE	3	/* Authentication Type */
+#define CI_QUALITY	4	/* Quality Protocol */
+#define CI_MAGICNUMBER	5	/* Magic Number */
+#define CI_PCOMPRESSION	7	/* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8	/* Address/Control Field Compression */
+#define CI_CALLBACK	13	/* callback */
+
+/*
+ * LCP-specific packet types.
+ */
+#define PROTREJ		8	/* Protocol Reject */
+#define ECHOREQ		9	/* Echo Request */
+#define ECHOREP		10	/* Echo Reply */
+#define DISCREQ		11	/* Discard Request */
+#define CBCP_OPT	6	/* Use callback control protocol */
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+    int passive : 1;		/* Don't die if we don't get a response */
+    int silent : 1;		/* Wait for the other end to start first */
+    int restart : 1;		/* Restart vs. exit after close */
+    int neg_mru : 1;		/* Negotiate the MRU? */
+    int neg_asyncmap : 1;	/* Negotiate the async map? */
+    int neg_upap : 1;		/* Ask for UPAP authentication? */
+    int neg_chap : 1;		/* Ask for CHAP authentication? */
+    int neg_magicnumber : 1;	/* Ask for magic number? */
+    int neg_pcompression : 1;	/* HDLC Protocol Field Compression? */
+    int neg_accompression : 1;	/* HDLC Address/Control Field Compression? */
+    int neg_lqr : 1;		/* Negotiate use of Link Quality Reports */
+    int neg_cbcp : 1;		/* Negotiate use of CBCP */
+    u_short mru;		/* Value of MRU */
+    u_char chap_mdtype;		/* which MD type (hashing algorithm) */
+    u_int32_t asyncmap;		/* Value of async map */
+    u_int32_t magicnumber;
+    int numloops;		/* Number of loops during magic number neg. */
+    u_int32_t lqr_period;	/* Reporting period for LQR 1/100ths second */
+} lcp_options;
+
+extern fsm lcp_fsm[];
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+extern u_int32_t xmit_accm[][8];
+
+#define DEFMRU	1500		/* Try for this */
+#define MINMRU	128		/* No MRUs below this */
+#define MAXMRU	16384		/* Normally limit MRU to this */
+
+void lcp_open __P((int));
+void lcp_close __P((int, char *));
+void lcp_lowerup __P((int));
+void lcp_lowerdown __P((int));
+void lcp_sprotrej __P((int, u_char *, int));	/* send protocol reject */
+
+extern struct protent lcp_protent;
+
+/* Default number of times we receive our magic number from the peer
+   before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL	10
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/magic.h
@@ -0,0 +1,72 @@
+//==========================================================================
+//
+//      include/magic.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/magic.h,v 1.7 1999/08/28 01:19:05 peter Exp $
+ */
+
+void magic_init __P((void));	/* Initialize the magic number generator */
+u_int32_t magic __P((void));	/* Returns the next magic number */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/names.h
@@ -0,0 +1,331 @@
+#ifndef CYGONCE_PPP_NAMES_H
+#define CYGONCE_PPP_NAMES_H
+// ====================================================================
+//
+//      names.h
+//
+//      PPP name remapping
+//
+// ====================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting the
+// copyright holder.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+// ====================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2003-06-01
+// Purpose:             Name Remapping
+// Description:         This header contains redefinitions of all the
+//                      external names defined in the PPP package. This 
+//                      avoids polluting the namespace with name that
+//                      might clash with application symbols.
+//
+//####DESCRIPTIONEND####
+//
+// ====================================================================
+
+// net/ppp/current/src/auth.c:
+#define auth_check_options cyg_ppp_auth_check_options
+#define auth_ip_addr cyg_ppp_auth_ip_addr
+#define auth_peer_fail cyg_ppp_auth_peer_fail
+#define auth_peer_success cyg_ppp_auth_peer_success
+#define auth_reset cyg_ppp_auth_reset
+#define auth_withpeer_fail cyg_ppp_auth_withpeer_fail
+#define auth_withpeer_success cyg_ppp_auth_withpeer_success
+#define bad_ip_adrs cyg_ppp_bad_ip_adrs
+#define check_access cyg_ppp_check_access
+#define check_passwd cyg_ppp_check_passwd
+#define get_secret cyg_ppp_get_secret
+#define link_down cyg_ppp_link_down
+#define link_established cyg_ppp_link_established
+#define link_required cyg_ppp_link_required
+#define link_terminated cyg_ppp_link_terminated
+#define np_down cyg_ppp_np_down
+#define np_finished cyg_ppp_np_finished
+#define np_up cyg_ppp_np_up
+#define peer_authname cyg_ppp_peer_authname
+
+// net/ppp/current/src/bsd_comp.c:
+#define ppp_bsd_compress cyg_ppp_ppp_bsd_compress
+
+// net/ppp/current/src/cbcp.c:
+#define cbcp cyg_ppp_cbcp
+#define cbcp_codenames cyg_ppp_cbcp_codenames
+#define cbcp_optionnames cyg_ppp_cbcp_optionnames
+#define cbcp_protent cyg_ppp_cbcp_protent
+
+// net/ppp/current/src/ccp.c:
+#define ccp_allowoptions cyg_ppp_ccp_allowoptions
+#define ccp_fsm cyg_ppp_ccp_fsm
+#define ccp_gotoptions cyg_ppp_ccp_gotoptions
+#define ccp_hisoptions cyg_ppp_ccp_hisoptions
+#define ccp_protent cyg_ppp_ccp_protent
+#define ccp_wantoptions cyg_ppp_ccp_wantoptions
+
+// net/ppp/current/src/chap.c:
+#define ChapAuthPeer cyg_ppp_ChapAuthPeer
+#define ChapAuthWithPeer cyg_ppp_ChapAuthWithPeer
+#define chap cyg_ppp_chap
+#define chap_protent cyg_ppp_chap_protent
+
+// net/ppp/current/src/fsm.c:
+#define fsm_close cyg_ppp_fsm_close
+#define fsm_init cyg_ppp_fsm_init
+#define fsm_input cyg_ppp_fsm_input
+#define fsm_lowerdown cyg_ppp_fsm_lowerdown
+#define fsm_lowerup cyg_ppp_fsm_lowerup
+#define fsm_open cyg_ppp_fsm_open
+#define fsm_protreject cyg_ppp_fsm_protreject
+#define fsm_sdata cyg_ppp_fsm_sdata
+#define peer_mru cyg_ppp_peer_mru
+
+// net/ppp/current/src/if_ppp.c:
+#define ppp_dequeue cyg_ppp_ppp_dequeue
+#define ppp_restart cyg_ppp_ppp_restart
+#define ppp_softc cyg_ppp_ppp_softc
+#define pppalloc cyg_ppp_pppalloc
+#define pppattach cyg_ppp_pppattach
+#define pppdealloc cyg_ppp_pppdealloc
+#define pppioctl cyg_ppp_pppioctl
+#define pppoutput cyg_ppp_pppoutput
+#define ppppktin cyg_ppp_ppppktin
+
+// net/ppp/current/src/ipcp.c:
+#define ip_ntoa cyg_ppp_ip_ntoa
+#define ipcp_allowoptions cyg_ppp_ipcp_allowoptions
+#define ipcp_fsm cyg_ppp_ipcp_fsm
+#define ipcp_gotoptions cyg_ppp_ipcp_gotoptions
+#define ipcp_hisoptions cyg_ppp_ipcp_hisoptions
+#define ipcp_protent cyg_ppp_ipcp_protent
+#define ipcp_wantoptions cyg_ppp_ipcp_wantoptions
+
+// net/ppp/current/src/lcp.c:
+#define lcp_allowoptions cyg_ppp_lcp_allowoptions
+#define lcp_close cyg_ppp_lcp_close
+#define lcp_fsm cyg_ppp_lcp_fsm
+#define lcp_gotoptions cyg_ppp_lcp_gotoptions
+#define lcp_hisoptions cyg_ppp_lcp_hisoptions
+#define lcp_loopbackfail cyg_ppp_lcp_loopbackfail
+#define lcp_lowerdown cyg_ppp_lcp_lowerdown
+#define lcp_lowerup cyg_ppp_lcp_lowerup
+#define lcp_open cyg_ppp_lcp_open
+#define lcp_protent cyg_ppp_lcp_protent
+#define lcp_sprotrej cyg_ppp_lcp_sprotrej
+#define lcp_wantoptions cyg_ppp_lcp_wantoptions
+#define xmit_accm cyg_ppp_xmit_accm
+
+// net/ppp/current/src/net_ppp_magic.o:
+#define magic cyg_ppp_magic
+#define magic_init cyg_ppp_magic_init
+
+// net/ppp/current/src/ppp_deflate.c:
+#define ppp_deflate cyg_ppp_ppp_deflate
+#define ppp_deflate_draft cyg_ppp_ppp_deflate_draft
+
+// net/ppp/current/src/pppd.c:
+#define auth_required cyg_ppp_auth_required
+#define baud_rate cyg_ppp_baud_rate
+#define connector cyg_ppp_connector
+#define flowctl cyg_ppp_flowctl
+#define cryptpap cyg_ppp_cryptpap
+#define debug cyg_ppp_debug
+#define default_device cyg_ppp_default_device
+#define devnam cyg_ppp_devnam
+#define die cyg_ppp_die
+#define disable_defaultip cyg_ppp_disable_defaultip
+#define disconnector cyg_ppp_disconnector
+#define etime cyg_ppp_etime
+#define explicit_remote cyg_ppp_explicit_remote
+#define fmtmsg cyg_ppp_fmtmsg
+#define format_packet cyg_ppp_format_packet
+#define holdoff cyg_ppp_holdoff
+#define hungup cyg_ppp_hungup
+#define idle_time_limit cyg_ppp_idle_time_limit
+#define ifname cyg_ppp_ifname
+//#define ifunit cyg_ppp_ifunit
+#define inpacket_buf cyg_ppp_inpacket_buf
+#define inspeed cyg_ppp_inspeed
+#define ipparam cyg_ppp_ipparam
+#define kdebugflag cyg_ppp_kdebugflag
+#define kill_link cyg_ppp_kill_link
+#define lcp_echo_fails cyg_ppp_lcp_echo_fails
+#define lcp_echo_interval cyg_ppp_lcp_echo_interval
+#define line cyg_ppp_line
+#define linep cyg_ppp_linep
+#define lockflag cyg_ppp_lockflag
+#define log_packet cyg_ppp_log_packet
+#define max_con_attempts cyg_ppp_max_con_attempts
+#define maxconnect cyg_ppp_maxconnect
+#define minutes cyg_ppp_minutes
+#define modem cyg_ppp_modem
+#define need_holdoff cyg_ppp_need_holdoff
+#define netmask cyg_ppp_netmask
+#define no_ppp_msg cyg_ppp_no_ppp_msg
+#define novm cyg_ppp_novm
+#define open_ccp_flag cyg_ppp_open_ccp_flag
+#define our_name cyg_ppp_our_name
+#define outpacket_buf cyg_ppp_outpacket_buf
+#define passwd cyg_ppp_passwd
+#define persist cyg_ppp_persist
+#define phase cyg_ppp_phase
+#define print_string cyg_ppp_print_string
+#define privileged cyg_ppp_privileged
+#define progname cyg_ppp_progname
+#define protocols cyg_ppp_protocols
+#define proxyarp cyg_ppp_proxyarp
+#define quit cyg_ppp_quit
+#define refuse_chap cyg_ppp_refuse_chap
+#define refuse_pap cyg_ppp_refuse_pap
+#define remote_name cyg_ppp_remote_name
+#define s_env_nalloc cyg_ppp_s_env_nalloc
+#define script cyg_ppp_script
+#define script_env cyg_ppp_script_env
+#define stime cyg_ppp_stime
+#define tty_handle cyg_ppp_tty_handle
+#define tty_mode cyg_ppp_tty_mode
+#define usehostname cyg_ppp_usehostname
+#define uselogin cyg_ppp_uselogin
+#define user cyg_ppp_user
+#define vfmtmsg cyg_ppp_vfmtmsg
+#define welcomer cyg_ppp_welcomer
+
+// net/ppp/current/src/slcompress.c:
+#define sl_compress_init cyg_ppp_sl_compress_init
+#define sl_compress_tcp cyg_ppp_sl_compress_tcp
+#define sl_uncompress_tcp cyg_ppp_sl_uncompress_tcp
+#define sl_uncompress_tcp_core cyg_ppp_sl_uncompress_tcp_core
+
+// net/ppp/current/src/sys-ecos.c:
+#define GetMask cyg_ppp_GetMask
+#define MD5Final cyg_MD5Final
+#define MD5Init cyg_MD5Init
+#define MD5Update cyg_MD5Update
+#define ccp_fatal_error cyg_ppp_ccp_fatal_error
+#define ccp_flags_set cyg_ppp_ccp_flags_set
+#define ccp_test cyg_ppp_ccp_test
+#define cifaddr cyg_ppp_cifaddr
+#define cifdefaultroute cyg_ppp_cifdefaultroute
+#define cifproxyarp cyg_ppp_cifproxyarp
+#define clean_check cyg_ppp_clean_check
+#define crypt cyg_ppp_crypt
+#define disestablish_ppp cyg_ppp_disestablish_ppp
+#define drand48 cyg_ppp_drand48
+#define establish_ppp cyg_ppp_establish_ppp
+#define get_host_seed cyg_ppp_get_host_seed
+#define get_idle_time cyg_ppp_get_idle_time
+#define gettimeofday cyg_ppp_gettimeofday
+#define mrand48 cyg_ppp_mrand48
+#define netmask cyg_ppp_netmask
+#define output cyg_ppp_output
+#define ppp_available cyg_ppp_ppp_available
+#define ppp_recv_config cyg_ppp_ppp_recv_config
+#define ppp_send_config cyg_ppp_ppp_send_config
+#define ppp_set_xaccm cyg_ppp_ppp_set_xaccm
+#define ppp_tty cyg_ppp_ppp_tty
+#define read_packet cyg_ppp_read_packet
+#define restore_loop cyg_ppp_restore_loop
+#define restore_tty cyg_ppp_restore_tty
+#define set_up_tty cyg_ppp_set_up_tty
+#define setdtr cyg_ppp_setdtr
+#define sifaddr cyg_ppp_sifaddr
+#define sifdefaultroute cyg_ppp_sifdefaultroute
+#define sifdown cyg_ppp_sifdown
+#define sifnpmode cyg_ppp_sifnpmode
+#define sifproxyarp cyg_ppp_sifproxyarp
+#define sifup cyg_ppp_sifup
+#define sifvjcomp cyg_ppp_sifvjcomp
+#define srand48 cyg_ppp_srand48
+#define sys_check_options cyg_ppp_sys_check_options
+#define sys_cleanup cyg_ppp_sys_cleanup
+#define sys_close cyg_ppp_sys_close
+#define sys_exit cyg_ppp_sys_exit
+#define sys_init cyg_ppp_sys_init
+#define syslog cyg_ppp_syslog
+#define wait_input cyg_ppp_wait_input
+#define wait_time cyg_ppp_wait_time
+
+// net/ppp/current/src/upap.c:
+#define pap_protent cyg_ppp_pap_protent
+#define upap cyg_ppp_upap
+#define upap_authpeer cyg_ppp_upap_authpeer
+#define upap_authwithpeer cyg_ppp_upap_authwithpeer
+
+// net/ppp/current/src/zlib.c:
+#define _tr_align cyg_ppp__tr_align
+#define _tr_flush_block cyg_ppp__tr_flush_block
+#define _tr_init cyg_ppp__tr_init
+#define _tr_stored_block cyg_ppp__tr_stored_block
+#define _tr_stored_type_only cyg_ppp__tr_stored_type_only
+#define _tr_tally cyg_ppp__tr_tally
+#define adler32 cyg_ppp_adler32
+#define deflate cyg_ppp_deflate
+#define deflateCopy cyg_ppp_deflateCopy
+#define deflateEnd cyg_ppp_deflateEnd
+#define deflateInit2_ cyg_ppp_deflateInit2_
+#define deflateInit_ cyg_ppp_deflateInit_
+#define deflateOutputPending cyg_ppp_deflateOutputPending
+#define deflateParams cyg_ppp_deflateParams
+#define deflateReset cyg_ppp_deflateReset
+#define deflateSetDictionary cyg_ppp_deflateSetDictionary
+#define deflate_copyright cyg_ppp_deflate_copyright
+#define inflateEnd cyg_ppp_inflateEnd
+#define inflateIncomp cyg_ppp_inflateIncomp
+#define inflateInit2_ cyg_ppp_inflateInit2_
+#define inflateInit_ cyg_ppp_inflateInit_
+#define inflateReset cyg_ppp_inflateReset
+#define inflateSetDictionary cyg_ppp_inflateSetDictionary
+#define inflateSync cyg_ppp_inflateSync
+#define inflate_addhistory cyg_ppp_inflate_addhistory
+#define inflate_blocks cyg_ppp_inflate_blocks
+#define inflate_blocks_free cyg_ppp_inflate_blocks_free
+#define inflate_blocks_new cyg_ppp_inflate_blocks_new
+#define inflate_blocks_reset cyg_ppp_inflate_blocks_reset
+#define inflate_codes cyg_ppp_inflate_codes
+#define inflate_codes_free cyg_ppp_inflate_codes_free
+#define inflate_codes_new cyg_ppp_inflate_codes_new
+#define inflate_copyright cyg_ppp_inflate_copyright
+#define inflate_fast cyg_ppp_inflate_fast
+#define inflate_flush cyg_ppp_inflate_flush
+#define inflate_mask cyg_ppp_inflate_mask
+#define inflate_packet_flush cyg_ppp_inflate_packet_flush
+#define inflate_ppp cyg_ppp_inflate_ppp
+#define inflate_set_dictionary cyg_ppp_inflate_set_dictionary
+#define inflate_trees_bits cyg_ppp_inflate_trees_bits
+#define inflate_trees_dynamic cyg_ppp_inflate_trees_dynamic
+#define inflate_trees_fixed cyg_ppp_inflate_trees_fixed
+#define inflate_trees_free cyg_ppp_inflate_trees_free
+#define zlibVersion cyg_ppp_zlibVersion
+
+// ====================================================================
+#endif // CYGONCE_PPP_NAMES_H
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/bpf.h
@@ -0,0 +1,371 @@
+//==========================================================================
+//
+//      include/net/bpf.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * Copyright (c) 1990, 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      @(#)bpf.h	8.1 (Berkeley) 6/10/93
+ *	@(#)bpf.h	1.34 (LBL)     6/16/96
+ *
+ * $FreeBSD: src/sys/net/bpf.h,v 1.21.2.3 2001/08/01 00:23:13 fenner Exp $
+ */
+
+#ifndef _NET_BPF_H_
+#define _NET_BPF_H_
+
+/* BSD style release date */
+#define	BPF_RELEASE 199606
+
+typedef	int32_t	  bpf_int32;
+typedef	u_int32_t bpf_u_int32;
+
+/*
+ * Alignment macros.  BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#define BPF_ALIGNMENT sizeof(long)
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x80000
+#define BPF_MINBUFSIZE 32
+
+/*
+ *  Structure for BIOCSETF.
+ */
+struct bpf_program {
+	u_int bf_len;
+	struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct returned by BIOCGSTATS.
+ */
+struct bpf_stat {
+	u_int bs_recv;		/* number of packets received */
+	u_int bs_drop;		/* number of packets dropped */
+};
+
+/*
+ * Struct return by BIOCVERSION.  This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded.  Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+	u_short bv_major;
+	u_short bv_minor;
+};
+/* Current version number of filter architecture. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+#define	BIOCGBLEN	_IOR('B',102, u_int)
+#define	BIOCSBLEN	_IOWR('B',102, u_int)
+#define	BIOCSETF	_IOW('B',103, struct bpf_program)
+#define	BIOCFLUSH	_IO('B',104)
+#define BIOCPROMISC	_IO('B',105)
+#define	BIOCGDLT	_IOR('B',106, u_int)
+#define BIOCGETIF	_IOR('B',107, struct ifreq)
+#define BIOCSETIF	_IOW('B',108, struct ifreq)
+#define BIOCSRTIMEOUT	_IOW('B',109, struct timeval)
+#define BIOCGRTIMEOUT	_IOR('B',110, struct timeval)
+#define BIOCGSTATS	_IOR('B',111, struct bpf_stat)
+#define BIOCIMMEDIATE	_IOW('B',112, u_int)
+#define BIOCVERSION	_IOR('B',113, struct bpf_version)
+#define BIOCGRSIG	_IOR('B',114, u_int)
+#define BIOCSRSIG	_IOW('B',115, u_int)
+#define BIOCGHDRCMPLT	_IOR('B',116, u_int)
+#define BIOCSHDRCMPLT	_IOW('B',117, u_int)
+#define BIOCGSEESENT	_IOR('B',118, u_int)
+#define BIOCSSEESENT	_IOW('B',119, u_int)
+
+/*
+ * Structure prepended to each packet.
+ */
+struct bpf_hdr {
+	struct timeval	bh_tstamp;	/* time stamp */
+	bpf_u_int32	bh_caplen;	/* length of captured portion */
+	bpf_u_int32	bh_datalen;	/* original length of packet */
+	u_short		bh_hdrlen;	/* length of bpf header (this struct
+					   plus alignment padding) */
+};
+/*
+ * Because the structure above is not a multiple of 4 bytes, some compilers
+ * will insist on inserting padding; hence, sizeof(struct bpf_hdr) won't work.
+ * Only the kernel needs to know about it; applications use bh_hdrlen.
+ */
+#ifdef _KERNEL
+#define	SIZEOF_BPF_HDR	(sizeof(struct bpf_hdr) <= 20 ? 18 : \
+    sizeof(struct bpf_hdr))
+#endif
+
+/*
+ * Data-link level type codes.
+ */
+#define DLT_NULL	0	/* no link-layer encapsulation */
+#define DLT_EN10MB	1	/* Ethernet (10Mb) */
+#define DLT_EN3MB	2	/* Experimental Ethernet (3Mb) */
+#define DLT_AX25	3	/* Amateur Radio AX.25 */
+#define DLT_PRONET	4	/* Proteon ProNET Token Ring */
+#define DLT_CHAOS	5	/* Chaos */
+#define DLT_IEEE802	6	/* IEEE 802 Networks */
+#define DLT_ARCNET	7	/* ARCNET */
+#define DLT_SLIP	8	/* Serial Line IP */
+#define DLT_PPP		9	/* Point-to-point Protocol */
+#define DLT_FDDI	10	/* FDDI */
+#define DLT_ATM_RFC1483	11	/* LLC/SNAP encapsulated atm */
+#define DLT_RAW		12	/* raw IP */
+
+/*
+ * These are values from BSD/OS's "bpf.h".
+ * These are not the same as the values from the traditional libpcap
+ * "bpf.h"; however, these values shouldn't be generated by any
+ * OS other than BSD/OS, so the correct values to use here are the
+ * BSD/OS values.
+ *
+ * Platforms that have already assigned these values to other
+ * DLT_ codes, however, should give these codes the values
+ * from that platform, so that programs that use these codes will
+ * continue to compile - even though they won't correctly read
+ * files of these types.
+ */
+#define DLT_SLIP_BSDOS	15	/* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS	16	/* BSD/OS Point-to-point Protocol */
+
+#define DLT_ATM_CLIP	19	/* Linux Classical-IP over ATM */
+
+/*
+ * This value is defined by NetBSD; other platforms should refrain from
+ * using it for other purposes, so that NetBSD savefiles with a link
+ * type of 50 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL	50	/* PPP over serial with HDLC encapsulation */
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC	104	/* Cisco HDLC */
+#define DLT_CHDLC	DLT_C_HDLC
+
+/*
+ * Reserved for future use.
+ * Do not pick other numerical value for these unless you have also
+ * picked up the tcpdump.org top-of-CVS-tree version of "savefile.c",
+ * which will arrange that capture files for these DLT_ types have
+ * the same "network" value on all platforms, regardless of what
+ * value is chosen for their DLT_ type (thus allowing captures made
+ * on one platform to be read on other platforms, even if the two
+ * platforms don't use the same numerical values for all DLT_ types).
+ */
+#define DLT_IEEE802_11	105	/* IEEE 802.11 wireless */
+
+/*
+ * Values between 106 and 107 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * OpenBSD defines it as 12, but that collides with DLT_RAW, so we
+ * define it as 108 here.  If OpenBSD picks up this file, it should
+ * define DLT_LOOP as 12 in its version, as per the comment above -
+ * and should not use 108 for any purpose.
+ */
+#define DLT_LOOP	108
+
+/*
+ * Values between 109 and 112 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL	113
+
+/*
+ * The instruction encodings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define		BPF_LD		0x00
+#define		BPF_LDX		0x01
+#define		BPF_ST		0x02
+#define		BPF_STX		0x03
+#define		BPF_ALU		0x04
+#define		BPF_JMP		0x05
+#define		BPF_RET		0x06
+#define		BPF_MISC	0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code)	((code) & 0x18)
+#define		BPF_W		0x00
+#define		BPF_H		0x08
+#define		BPF_B		0x10
+#define BPF_MODE(code)	((code) & 0xe0)
+#define		BPF_IMM 	0x00
+#define		BPF_ABS		0x20
+#define		BPF_IND		0x40
+#define		BPF_MEM		0x60
+#define		BPF_LEN		0x80
+#define		BPF_MSH		0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code)	((code) & 0xf0)
+#define		BPF_ADD		0x00
+#define		BPF_SUB		0x10
+#define		BPF_MUL		0x20
+#define		BPF_DIV		0x30
+#define		BPF_OR		0x40
+#define		BPF_AND		0x50
+#define		BPF_LSH		0x60
+#define		BPF_RSH		0x70
+#define		BPF_NEG		0x80
+#define		BPF_JA		0x00
+#define		BPF_JEQ		0x10
+#define		BPF_JGT		0x20
+#define		BPF_JGE		0x30
+#define		BPF_JSET	0x40
+#define BPF_SRC(code)	((code) & 0x08)
+#define		BPF_K		0x00
+#define		BPF_X		0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code)	((code) & 0x18)
+#define		BPF_A		0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define		BPF_TAX		0x00
+#define		BPF_TXA		0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+	u_short		code;
+	u_char		jt;
+	u_char		jf;
+	bpf_u_int32	k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#ifdef _KERNEL
+int	 bpf_validate __P((const struct bpf_insn *, int));
+void	 bpf_tap __P((struct ifnet *, u_char *, u_int));
+void	 bpf_mtap __P((struct ifnet *, struct mbuf *));
+void	 bpfattach __P((struct ifnet *, u_int, u_int));
+void	 bpfdetach __P((struct ifnet *));
+
+void	 bpfilterattach __P((int));
+u_int	 bpf_filter __P((const struct bpf_insn *, u_char *, u_int, u_int));
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#endif
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/if_ppp.h
@@ -0,0 +1,190 @@
+//==========================================================================
+//
+//      include/net/if_ppp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/sys/net/if_ppp.h,v 1.14 1999/08/28 00:48:20 peter Exp $
+ */
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+#include <cyg/ppp/names.h>
+
+#include <sys/ioccom.h>
+
+/* XXX this used to be self-contained. */
+#include <cyg/ppp/net/ppp_defs.h>
+#include <net/if.h>
+
+/*
+ * Packet sizes
+ */
+#define	PPP_MTU		1500	/* Default MTU (size of Info field) */
+#define PPP_MAXMRU	65000	/* Largest MRU we allow */
+#define PPP_MAXMTU	16384	/* Largest MTU we allow */
+
+/*
+ * Bit definitions for flags.
+ */
+#define SC_COMP_PROT	0x00000001	/* protocol compression (output) */
+#define SC_COMP_AC	0x00000002	/* header compression (output) */
+#define	SC_COMP_TCP	0x00000004	/* TCP (VJ) compression (output) */
+#define SC_NO_TCP_CCID	0x00000008	/* disable VJ connection-id comp. */
+#define SC_REJ_COMP_AC	0x00000010	/* reject adrs/ctrl comp. on input */
+#define SC_REJ_COMP_TCP	0x00000020	/* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN	0x00000040	/* Look at CCP packets */
+#define SC_CCP_UP	0x00000080	/* May send/recv compressed packets */
+#define SC_DEBUG	0x00010000	/* enable debug messages */
+#define SC_LOG_INPKT	0x00020000	/* log contents of good pkts recvd */
+#define SC_LOG_OUTPKT	0x00040000	/* log contents of pkts sent */
+#define SC_LOG_RAWIN	0x00080000	/* log all chars received */
+#define SC_LOG_FLUSH	0x00100000	/* log all chars flushed */
+#define SC_RCV_B7_0	0x01000000	/* have rcvd char with bit 7 = 0 */
+#define SC_RCV_B7_1	0x02000000	/* have rcvd char with bit 7 = 1 */
+#define SC_RCV_EVNP	0x04000000	/* have rcvd char with even parity */
+#define SC_RCV_ODDP	0x08000000	/* have rcvd char with odd parity */
+#define	SC_MASK		0x0fff00ff	/* bits that user can change */
+
+/*
+ * State bits in sc_flags, not changeable by user.
+ */
+#define SC_TIMEOUT	0x00000400	/* timeout is currently pending */
+#define SC_VJ_RESET	0x00000800	/* need to reset VJ decomp */
+#define SC_COMP_RUN	0x00001000	/* compressor has been initiated */
+#define SC_DECOMP_RUN	0x00002000	/* decompressor has been initiated */
+#define SC_DC_ERROR	0x00004000	/* non-fatal decomp error detected */
+#define SC_DC_FERROR	0x00008000	/* fatal decomp error detected */
+#define SC_TBUSY	0x10000000	/* xmitter doesn't need a packet yet */
+#define SC_PKTLOST	0x20000000	/* have lost or dropped a packet */
+#define	SC_FLUSH	0x40000000	/* flush input until next PPP_FLAG */
+#define	SC_ESCAPED	0x80000000	/* saw a PPP_ESCAPE */
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+    int		protocol;	/* PPP procotol, e.g. PPP_IP */
+    enum NPmode	mode;
+};
+
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+	u_char	*ptr;
+	u_int	length;
+	int	transmit;
+};
+
+struct ifpppstatsreq {
+    char ifr_name[IFNAMSIZ];
+    struct ppp_stats stats;
+};
+
+struct ifpppcstatsreq {
+    char ifr_name[IFNAMSIZ];
+    struct ppp_comp_stats stats;
+};
+
+/*
+ * Ioctl definitions.
+ */
+
+#define	PPPIOCGFLAGS	_IOR('t', 90, int)	/* get configuration flags */
+#define	PPPIOCSFLAGS	_IOW('t', 89, int)	/* set configuration flags */
+#define	PPPIOCGASYNCMAP	_IOR('t', 88, int)	/* get async map */
+#define	PPPIOCSASYNCMAP	_IOW('t', 87, int)	/* set async map */
+#define	PPPIOCGUNIT	_IOR('t', 86, int)	/* get ppp unit number */
+#define	PPPIOCGRASYNCMAP _IOR('t', 85, int)	/* get receive async map */
+#define	PPPIOCSRASYNCMAP _IOW('t', 84, int)	/* set receive async map */
+#define	PPPIOCGMRU	_IOR('t', 83, int)	/* get max receive unit */
+#define	PPPIOCSMRU	_IOW('t', 82, int)	/* set max receive unit */
+#define	PPPIOCSMAXCID	_IOW('t', 81, int)	/* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT	_IO('t', 78)		/* transfer PPP unit */
+#define PPPIOCSCOMPRESS	_IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE	_IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE	_IOW('t', 75, struct npioctl)  /* set NP mode */
+#define PPPIOCGIDLE	_IOR('t', 74, struct ppp_idle) /* get idle time */
+#define PPPIOCSPASS	_IOW('t', 71, struct bpf_program) /* set pass filter */
+#define PPPIOCSACTIVE	_IOW('t', 70, struct bpf_program) /* set active filt */
+
+/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */
+#define PPPIOCGMTU	_IOR('t', 73, int)	/* get interface MTU */
+#define PPPIOCSMTU	_IOW('t', 72, int)	/* set interface MTU */
+
+/*
+ * These two are interface ioctls so that pppstats can do them on
+ * a socket without having to open the serial device.
+ */
+#define SIOCGPPPSTATS	_IOWR('i', 123, struct ifpppstatsreq)
+#define SIOCGPPPCSTATS	_IOWR('i', 122, struct ifpppcstatsreq)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu	ifr_ifru.ifru_metric
+#endif
+
+#endif /* _IF_PPP_H_ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/if_pppvar.h
@@ -0,0 +1,161 @@
+//==========================================================================
+//
+//      include/net/if_pppvar.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/sys/net/if_pppvar.h,v 1.15 2000/01/29 16:56:23 peter Exp $
+ */
+
+/*
+ * Supported network protocols.  These values are used for
+ * indexing sc_npmode.
+ */
+#define NP_IP	0		/* Internet Protocol */
+#define NUM_NP	1		/* Number of NPs. */
+
+/*
+ * Structure describing each ppp unit.
+ */
+struct ppp_softc {
+	struct	ifnet sc_if;		/* network-visible interface */
+/*hi*/	u_int	sc_flags;		/* control/status bits; see if_ppp.h */
+//	struct	callout_handle sc_ch;	/* Used for scheduling timeouts */
+	void	*sc_devp;		/* pointer to device-dep structure */
+//        int     sc_fd;                  /* TTY file descriptor */
+	void	(*sc_start) __P((struct ppp_softc *));	/* start output proc */
+	void	(*sc_ctlp) __P((struct ppp_softc *)); /* rcvd control pkt */
+	void	(*sc_relinq) __P((struct ppp_softc *)); /* relinquish ifunit */
+	void	(*sc_setmtu) __P((struct ppp_softc *)); /* set mtu */
+	short	sc_mru;			/* max receive unit */
+	pid_t	sc_xfer;		/* used in transferring unit */
+/*hi*/	struct	ifqueue sc_rawq;	/* received packets */
+/*net*/	struct	ifqueue sc_inq;		/* queue of input packets for daemon */
+/*net*/	struct	ifqueue sc_fastq;	/* interactive output packet q */
+	struct	mbuf *sc_npqueue;	/* output packets not to be sent yet */
+	struct	mbuf **sc_npqtail;	/* ptr to last next ptr in npqueue */
+	struct	pppstat sc_stats;	/* count of bytes/pkts sent/rcvd */
+	enum	NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+	struct	compressor *sc_xcomp;	/* transmit compressor */
+	void	*sc_xc_state;		/* transmit compressor state */
+	struct	compressor *sc_rcomp;	/* receive decompressor */
+	void	*sc_rc_state;		/* receive decompressor state */
+	time_t	sc_last_sent;		/* time (secs) last NP pkt sent */
+	time_t	sc_last_recv;		/* time (secs) last NP pkt rcvd */
+#ifdef PPP_FILTER
+	struct	bpf_program sc_pass_filt;   /* filter for packets to pass */
+	struct	bpf_program sc_active_filt; /* filter for "non-idle" packets */
+#endif /* PPP_FILTER */
+#ifdef	VJC
+	struct	slcompress *sc_comp; 	/* vjc control buffer */
+#endif
+
+	/* Device-dependent part for async lines. */
+	ext_accm sc_asyncmap;		/* async control character map */
+	u_long	sc_rasyncmap;		/* receive async control char map */
+	struct	mbuf *sc_outm;		/* mbuf chain currently being output */
+	struct	mbuf *sc_m;		/* pointer to input mbuf chain */
+	struct	mbuf *sc_mc;		/* pointer to current input mbuf */
+	char	*sc_mp;			/* ptr to next char in input mbuf */
+	short	sc_ilen;		/* length of input packet so far */
+	u_short	sc_fcs;			/* FCS so far (input) */
+	u_short	sc_outfcs;		/* FCS so far for output packet */
+	u_char	sc_rawin[16];		/* chars as received */
+	int	sc_rawin_count;		/* # in sc_rawin */
+};
+
+extern struct ppp_softc ppp_softc[];
+
+struct	ppp_softc *pppalloc __P((pid_t pid));
+void	pppdealloc __P((struct ppp_softc *sc));
+int	pppioctl __P((struct ppp_softc *sc, u_long cmd, caddr_t data,
+		      int flag, struct proc *p));
+int	pppoutput __P((struct ifnet *ifp, struct mbuf *m0,
+		       struct sockaddr *dst, struct rtentry *rtp));
+void	ppp_restart __P((struct ppp_softc *sc));
+void	ppppktin __P((struct ppp_softc *sc, struct mbuf *m, int lost));
+struct	mbuf *ppp_dequeue __P((struct ppp_softc *sc));
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/ppp_comp.h
@@ -0,0 +1,216 @@
+//==========================================================================
+//
+//      include/net/ppp_comp.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ppp_comp.h - Definitions for doing PPP packet compression.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $FreeBSD: src/sys/net/ppp_comp.h,v 1.8 1999/08/28 00:48:25 peter Exp $
+ */
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+#include <cyg/ppp/names.h>
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS	1	/* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE	1	/* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1	0
+#define DO_PREDICTOR_2	0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+#ifdef PACKETPTR
+struct compressor {
+	int	compress_proto;	/* CCP compression protocol number */
+
+	/* Allocate space for a compressor (transmit side) */
+	void	*(*comp_alloc) __P((u_char *options, int opt_len));
+	/* Free space used by a compressor */
+	void	(*comp_free) __P((void *state));
+	/* Initialize a compressor */
+	int	(*comp_init) __P((void *state, u_char *options, int opt_len,
+				  int unit, int hdrlen, int debug));
+	/* Reset a compressor */
+	void	(*comp_reset) __P((void *state));
+	/* Compress a packet */
+	int	(*compress) __P((void *state, PACKETPTR *mret,
+				 PACKETPTR mp, int orig_len, int max_len));
+	/* Return compression statistics */
+	void	(*comp_stat) __P((void *state, struct compstat *stats));
+
+	/* Allocate space for a decompressor (receive side) */
+	void	*(*decomp_alloc) __P((u_char *options, int opt_len));
+	/* Free space used by a decompressor */
+	void	(*decomp_free) __P((void *state));
+	/* Initialize a decompressor */
+	int	(*decomp_init) __P((void *state, u_char *options, int opt_len,
+				    int unit, int hdrlen, int mru, int debug));
+	/* Reset a decompressor */
+	void	(*decomp_reset) __P((void *state));
+	/* Decompress a packet. */
+	int	(*decompress) __P((void *state, PACKETPTR mp,
+				   PACKETPTR *dmpp));
+	/* Update state for an incompressible packet received */
+	void	(*incomp) __P((void *state, PACKETPTR mp));
+	/* Return decompression statistics */
+	void	(*decomp_stat) __P((void *state, struct compstat *stats));
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression.  This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+#define DECOMP_OK		0	/* everything went OK */
+#define DECOMP_ERROR		1	/* error detected before decomp. */
+#define DECOMP_FATALERROR	2	/* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+#define CCP_CONFREQ	1
+#define CCP_CONFACK	2
+#define CCP_TERMREQ	5
+#define CCP_TERMACK	6
+#define CCP_RESETREQ	14
+#define CCP_RESETACK	15
+
+/*
+ * Max # bytes for a CCP option
+ */
+#define CCP_MAX_OPTION_LENGTH	32
+
+/*
+ * Parts of a CCP packet.
+ */
+#define CCP_CODE(dp)		((dp)[0])
+#define CCP_ID(dp)		((dp)[1])
+#define CCP_LENGTH(dp)		(((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN		4
+
+#define CCP_OPT_CODE(dp)	((dp)[0])
+#define CCP_OPT_LENGTH(dp)	((dp)[1])
+#define CCP_OPT_MINLEN		2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+#define CI_BSD_COMPRESS		21	/* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS	3	/* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x)		((x) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 5) | (n))
+
+#define BSD_MIN_BITS		9	/* smallest code size supported */
+#define BSD_MAX_BITS		15	/* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+#define CI_DEFLATE		26	/* config option for Deflate */
+#define CI_DEFLATE_DRAFT	24	/* value used in original draft RFC */
+#define CILEN_DEFLATE		4	/* length of its config option */
+
+#define DEFLATE_MIN_SIZE	8
+#define DEFLATE_MAX_SIZE	15
+#define DEFLATE_METHOD_VAL	8
+#define DEFLATE_SIZE(x)		(((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 4) \
+				 + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE	0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+#define CI_PREDICTOR_1		1	/* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1	2	/* length of its config option */
+#define CI_PREDICTOR_2		2	/* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2	2	/* length of its config option */
+
+#endif /* _NET_PPP_COMP_H */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/ppp_defs.h
@@ -0,0 +1,206 @@
+//==========================================================================
+//
+//      include/net/ppp_defs.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $FreeBSD: src/sys/net/ppp_defs.h,v 1.6.2.1 2001/07/03 11:01:41 ume Exp $
+ */
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN	4	/* octets for standard ppp header */
+#define PPP_FCSLEN	2	/* octets for FCS */
+#define PPP_MRU		1500	/* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p)	(((u_char *)(p))[0])
+#define PPP_CONTROL(p)	(((u_char *)(p))[1])
+#define PPP_PROTOCOL(p)	((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define	PPP_ALLSTATIONS	0xff	/* All-Stations broadcast address */
+#define	PPP_UI		0x03	/* Unnumbered Information */
+#define	PPP_FLAG	0x7e	/* Flag Sequence */
+#define	PPP_ESCAPE	0x7d	/* Asynchronous Control Escape */
+#define	PPP_TRANS	0x20	/* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP		0x21	/* Internet Protocol */
+#define	PPP_XNS		0x25	/* Xerox NS */
+#define PPP_AT		0x29	/* AppleTalk Protocol */
+#define PPP_IPX		0x2b	/* IPX Datagram (RFC1552) */
+#define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
+#define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_IPCP	0x8021	/* IP Control Protocol */
+#define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
+#define PPP_IPXCP	0x802b	/* IPX Control Protocol (RFC1552) */
+#define PPP_CCP		0x80fd	/* Compression Control Protocol */
+#define PPP_LCP		0xc021	/* Link Control Protocol */
+#define PPP_PAP		0xc023	/* Password Authentication Protocol */
+#define PPP_LQR		0xc025	/* Link Quality Report protocol */
+#define PPP_CHAP	0xc223	/* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP	0xc029	/* Callback Control Protocol */
+#define PPP_IPV6	0x57	/* Internet Protocol version 6*/
+#define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+#define PPP_INITFCS	0xffff	/* Initial FCS value */
+#define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
+#define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef u_int32_t	ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,		/* pass the packet through */
+    NPMODE_DROP,		/* silently drop the packet */
+    NPMODE_ERROR,		/* return an error */
+    NPMODE_QUEUE		/* save it up for later. */
+};
+
+/*
+ * Statistics.
+ */
+struct pppstat	{
+    unsigned int ppp_ibytes;	/* bytes received */
+    unsigned int ppp_ipackets;	/* packets received */
+    unsigned int ppp_ierrors;	/* receive errors */
+    unsigned int ppp_obytes;	/* bytes sent */
+    unsigned int ppp_opackets;	/* packets sent */
+    unsigned int ppp_oerrors;	/* transmit errors */
+};
+
+struct vjstat {
+    unsigned int vjs_packets;	/* outbound packets */
+    unsigned int vjs_compressed; /* outbound compressed packets */
+    unsigned int vjs_searches;	/* searches for connection state */
+    unsigned int vjs_misses;	/* times couldn't find conn. state */
+    unsigned int vjs_uncompressedin; /* inbound uncompressed packets */
+    unsigned int vjs_compressedin; /* inbound compressed packets */
+    unsigned int vjs_errorin;	/* inbound unknown type packets */
+    unsigned int vjs_tossed;	/* inbound packets tossed because of error */
+};
+
+struct ppp_stats {
+    struct pppstat p;		/* basic PPP statistics */
+    struct vjstat vj;		/* VJ header compression statistics */
+};
+
+struct compstat {
+    unsigned int unc_bytes;	/* total uncompressed bytes */
+    unsigned int unc_packets;	/* total uncompressed packets */
+    unsigned int comp_bytes;	/* compressed bytes */
+    unsigned int comp_packets;	/* compressed packets */
+    unsigned int inc_bytes;	/* incompressible bytes */
+    unsigned int inc_packets;	/* incompressible packets */
+    unsigned int ratio;		/* recent compression ratio << 8 */
+};
+
+struct ppp_comp_stats {
+    struct compstat c;		/* packet compression statistics */
+    struct compstat d;		/* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    time_t xmit_idle;		/* time since last NP packet sent */
+    time_t recv_idle;		/* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x)	x
+#else
+#define __P(x)	()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/net/zlib.h
@@ -0,0 +1,1064 @@
+//==========================================================================
+//
+//      include/net/zlib.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/* $FreeBSD: src/sys/net/zlib.h,v 1.7 1999/12/29 04:38:38 peter Exp $	*/
+
+/*
+ * This file is derived from zlib.h and zconf.h from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.
+ */
+
+/*
+ *  ==FILEVERSION 971127==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+
+/* +++ zlib.h */
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+  version 1.0.4, Jul 24th, 1996.
+
+  Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Jean-loup Gailly        Mark Adler
+  gzip@prep.ai.mit.edu    madler@alumni.caltech.edu
+
+
+  The data format used by the zlib library is described by RFCs (Request for
+  Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt
+  (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef _ZLIB_H
+#define _ZLIB_H
+
+#include <cyg/ppp/names.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* +++ zconf.h */
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zconf.h,v 1.20 1996/07/02 15:09:28 me Exp $ */
+
+#ifndef _ZCONF_H
+#define _ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+#  define deflateInit_	z_deflateInit_
+#  define deflate	z_deflate
+#  define deflateEnd	z_deflateEnd
+#  define inflateInit_ 	z_inflateInit_
+#  define inflate	z_inflate
+#  define inflateEnd	z_inflateEnd
+#  define deflateInit2_	z_deflateInit2_
+#  define deflateSetDictionary z_deflateSetDictionary
+#  define deflateCopy	z_deflateCopy
+#  define deflateReset	z_deflateReset
+#  define deflateParams	z_deflateParams
+#  define inflateInit2_	z_inflateInit2_
+#  define inflateSetDictionary z_inflateSetDictionary
+#  define inflateSync	z_inflateSync
+#  define inflateReset	z_inflateReset
+#  define compress	z_compress
+#  define uncompress	z_uncompress
+#  define adler32	z_adler32
+#  define crc32		z_crc32
+#  define get_crc_table z_get_crc_table
+
+#  define Byte		z_Byte
+#  define uInt		z_uInt
+#  define uLong		z_uLong
+#  define Bytef	        z_Bytef
+#  define charf		z_charf
+#  define intf		z_intf
+#  define uIntf		z_uIntf
+#  define uLongf	z_uLongf
+#  define voidpf	z_voidpf
+#  define voidp		z_voidp
+#endif
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
+#  define WIN32
+#endif
+#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386)
+#  ifndef __32BIT__
+#    define __32BIT__
+#  endif
+#endif
+#if defined(__MSDOS__) && !defined(MSDOS)
+#  define MSDOS
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#if defined(MSDOS) && !defined(__32BIT__)
+#  define MAXSEG_64K
+#endif
+#ifdef MSDOS
+#  define UNALIGNED_OK
+#endif
+
+#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32))  && !defined(STDC)
+#  define STDC
+#endif
+#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC)
+#  define STDC
+#endif
+
+#ifndef STDC
+#  ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+#    define const
+#  endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__)
+#  define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+#  ifdef MAXSEG_64K
+#    define MAX_MEM_LEVEL 8
+#  else
+#    define MAX_MEM_LEVEL 9
+#  endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2 */
+#ifndef MAX_WBITS
+#  define MAX_WBITS   15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+            1 << (windowBits+2)   +  1 << (memLevel+9)
+ that is: 128K for windowBits=15  +  128K for memLevel = 8  (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+     make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+   The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+                        /* Type declarations */
+
+#ifndef OF /* function prototypes */
+#  ifdef STDC
+#    define OF(args)  args
+#  else
+#    define OF(args)  ()
+#  endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h.  If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__)
+   /* MSC small or medium model */
+#  define SMALL_MEDIUM
+#  ifdef _MSC_VER
+#    define FAR __far
+#  else
+#    define FAR far
+#  endif
+#endif
+#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__))
+#  ifndef __32BIT__
+#    define SMALL_MEDIUM
+#    define FAR __far
+#  endif
+#endif
+#ifndef FAR
+#   define FAR
+#endif
+
+typedef unsigned char  Byte;  /* 8 bits */
+typedef unsigned int   uInt;  /* 16 bits or more */
+typedef unsigned long  uLong; /* 32 bits or more */
+
+#if defined(__BORLANDC__) && defined(SMALL_MEDIUM)
+   /* Borland C/C++ ignores FAR inside typedef */
+#  define Bytef Byte FAR
+#else
+   typedef Byte  FAR Bytef;
+#endif
+typedef char  FAR charf;
+typedef int   FAR intf;
+typedef uInt  FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+   typedef void FAR *voidpf;
+   typedef void     *voidp;
+#else
+   typedef Byte FAR *voidpf;
+   typedef Byte     *voidp;
+#endif
+
+
+/* Compile with -DZLIB_DLL for Windows DLL support */
+#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL)
+#  include <windows.h>
+#  define EXPORT  WINAPI
+#else
+#  define EXPORT
+#endif
+
+#endif /* _ZCONF_H */
+/* --- zconf.h */
+
+#define ZLIB_VERSION "1.0.4P"
+
+/* 
+     The 'zlib' compression library provides in-memory compression and
+  decompression functions, including integrity checks of the uncompressed
+  data.  This version of the library supports only one compression method
+  (deflation) but other algorithms may be added later and will have the same
+  stream interface.
+
+     For compression the application must provide the output buffer and
+  may optionally provide the input buffer for optimization. For decompression,
+  the application must provide the input buffer and may optionally provide
+  the output buffer for optimization.
+
+     Compression can be done in a single step if the buffers are large
+  enough (for example if an input file is mmap'ed), or can be done by
+  repeated calls of the compression function.  In the latter case, the
+  application must provide more input and/or consume the output
+  (providing more output space) before each call.
+
+     The library does not install any signal handler. It is recommended to
+  add at least a handler for SIGSEGV when decompressing; the library checks
+  the consistency of the input data whenever possible but may go nuts
+  for some forms of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void   (*free_func)  OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+    Bytef    *next_in;  /* next input byte */
+    uInt     avail_in;  /* number of bytes available at next_in */
+    uLong    total_in;  /* total nb of input bytes read so far */
+
+    Bytef    *next_out; /* next output byte should be put there */
+    uInt     avail_out; /* remaining free space at next_out */
+    uLong    total_out; /* total nb of bytes output so far */
+
+    const char     *msg; /* last error message, NULL if no error */
+    struct internal_state FAR *state; /* not visible by applications */
+
+    alloc_func zalloc;  /* used to allocate the internal state */
+    free_func  zfree;   /* used to free the internal state */
+    voidpf     opaque;  /* private data object passed to zalloc and zfree */
+
+    int     data_type;  /* best guess about the data type: ascii or binary */
+    uLong   adler;      /* adler32 value of the uncompressed data */
+    uLong   reserved;   /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+   The application must update next_in and avail_in when avail_in has
+   dropped to zero. It must update next_out and avail_out when avail_out
+   has dropped to zero. The application must initialize zalloc, zfree and
+   opaque before calling the init function. All other fields are set by the
+   compression library and must not be updated by the application.
+
+   The opaque value provided by the application will be passed as the first
+   parameter for calls of zalloc and zfree. This can be useful for custom
+   memory management. The compression library attaches no meaning to the
+   opaque value.
+
+   zalloc must return Z_NULL if there is not enough memory for the object.
+   On 16-bit systems, the functions zalloc and zfree must be able to allocate
+   exactly 65536 bytes, but will not be required to allocate more than this
+   if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+   pointers returned by zalloc for objects of exactly 65536 bytes *must*
+   have their offset normalized to zero. The default allocation function
+   provided by this library ensures this (see zutil.c). To reduce memory
+   requirements and avoid any allocation of 64K objects, at the expense of
+   compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+   The fields total_in and total_out can be used for statistics or
+   progress reports. After compression, total_in holds the total size of
+   the uncompressed data and may be saved for use in the decompressor
+   (particularly if the decompressor wants to decompress everything in
+   a single step).
+*/
+
+                        /* constants */
+
+#define Z_NO_FLUSH      0
+#define Z_PARTIAL_FLUSH 1
+#define Z_PACKET_FLUSH	2
+#define Z_SYNC_FLUSH    3
+#define Z_FULL_FLUSH    4
+#define Z_FINISH        5
+/* Allowed flush values; see deflate() below for details */
+
+#define Z_OK            0
+#define Z_STREAM_END    1
+#define Z_NEED_DICT     2
+#define Z_ERRNO        (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR   (-3)
+#define Z_MEM_ERROR    (-4)
+#define Z_BUF_ERROR    (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION         0
+#define Z_BEST_SPEED             1
+#define Z_BEST_COMPRESSION       9
+#define Z_DEFAULT_COMPRESSION  (-1)
+/* compression levels */
+
+#define Z_FILTERED            1
+#define Z_HUFFMAN_ONLY        2
+#define Z_DEFAULT_STRATEGY    0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY   0
+#define Z_ASCII    1
+#define Z_UNKNOWN  2
+/* Possible values of the data_type field */
+
+#define Z_DEFLATED   8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL  0  /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+                        /* basic functions */
+
+extern const char * EXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+   If the first character differs, the library code actually used is
+   not compatible with the zlib.h header file used by the application.
+   This check is automatically made by deflateInit and inflateInit.
+ */
+
+/* 
+extern int EXPORT deflateInit OF((z_streamp strm, int level));
+
+     Initializes the internal stream state for compression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.
+   If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+   use default allocation functions.
+
+     The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+   1 gives best speed, 9 gives best compression, 0 gives no compression at
+   all (the input data is simply copied a block at a time).
+   Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+   compression (currently equivalent to level 6).
+
+     deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+   Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+   with the version assumed by the caller (ZLIB_VERSION).
+   msg is set to null if there is no error message.  deflateInit does not
+   perform any compression: this will be done by deflate().
+*/
+
+
+extern int EXPORT deflate OF((z_streamp strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Compress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in and avail_in are updated and
+    processing will resume at this point for the next call of deflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly. This action is forced if the parameter flush is non zero.
+    Forcing flush frequently degrades the compression ratio, so this parameter
+    should be set only when necessary (in interactive applications).
+    Some output may be provided even if flush is not set.
+
+  Before the call of deflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating avail_in or avail_out accordingly; avail_out
+  should never be zero before the call. The application can consume the
+  compressed output when it wants, for example when the output buffer is full
+  (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+  and with zero avail_out, it must be called again after making room in the
+  output buffer because there might be more output pending.
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression
+  block is terminated and flushed to the output buffer so that the
+  decompressor can get all input data available so far. For method 9, a future
+  variant on method 8, the current block will be flushed but not terminated.
+  Z_SYNC_FLUSH has the same effect as partial flush except that the compressed
+  output is byte aligned (the compressor can clear its internal bit buffer)
+  and the current block is always terminated; this can be useful if the
+  compressor has to be restarted from scratch after an interruption (in which
+  case the internal state of the compressor may be lost).
+    If flush is set to Z_FULL_FLUSH, the compression block is terminated, a
+  special marker is output and the compression dictionary is discarded; this
+  is useful to allow the decompressor to synchronize if one compressed block
+  has been damaged (see inflateSync below).  Flushing degrades compression and
+  so should be used only when necessary.  Using Z_FULL_FLUSH too often can
+  seriously degrade the compression. If deflate returns with avail_out == 0,
+  this function must be called again with the same value of the flush
+  parameter and more output space (updated avail_out), until the flush is
+  complete (deflate returns with non-zero avail_out).
+
+    If the parameter flush is set to Z_PACKET_FLUSH, the compression
+  block is terminated, and a zero-length stored block is output,
+  omitting the length bytes (the effect of this is that the 3-bit type
+  code 000 for a stored block is output, and the output is then
+  byte-aligned).  This is designed for use at the end of a PPP packet.
+
+    If the parameter flush is set to Z_FINISH, pending input is processed,
+  pending output is flushed and deflate returns with Z_STREAM_END if there
+  was enough output space; if deflate returns with Z_OK, this function must be
+  called again with Z_FINISH and more output space (updated avail_out) but no
+  more input data, until it returns with Z_STREAM_END or an error. After
+  deflate has returned Z_STREAM_END, the only possible operations on the
+  stream are deflateReset or deflateEnd.
+  
+    Z_FINISH can be used immediately after deflateInit if all the compression
+  is to be done in a single step. In this case, avail_out must be at least
+  0.1% larger than avail_in plus 12 bytes.  If deflate does not return
+  Z_STREAM_END, then it must be called again as described above.
+
+    deflate() may update data_type if it can make a good guess about
+  the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered
+  binary. This field is only for information purposes and does not affect
+  the compression algorithm in any manner.
+
+    deflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if all input has been
+  consumed and all output has been produced (only when flush is set to
+  Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+  if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible.
+*/
+
+
+extern int EXPORT deflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+   stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+   prematurely (some input or output was discarded). In the error case,
+   msg may be set but then points to a static string (which must not be
+   deallocated).
+*/
+
+
+/* 
+extern int EXPORT inflateInit OF((z_streamp strm));
+
+     Initializes the internal stream state for decompression. The fields
+   zalloc, zfree and opaque must be initialized before by the caller.  If
+   zalloc and zfree are set to Z_NULL, inflateInit updates them to use default
+   allocation functions.
+
+     inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_VERSION_ERROR if the zlib library version is incompatible
+   with the version assumed by the caller.  msg is set to null if there is no
+   error message. inflateInit does not perform any decompression: this will be
+   done by inflate().
+*/
+
+#if 1 //defined(__FreeBSD__) && defined(_KERNEL)
+#define inflate       inflate_ppp     /* FreeBSD already has an inflate :-( */
+#endif
+
+extern int EXPORT inflate OF((z_streamp strm, int flush));
+/*
+  Performs one or both of the following actions:
+
+  - Decompress more input starting at next_in and update next_in and avail_in
+    accordingly. If not all input can be processed (because there is not
+    enough room in the output buffer), next_in is updated and processing
+    will resume at this point for the next call of inflate().
+
+  - Provide more output starting at next_out and update next_out and avail_out
+    accordingly.  inflate() provides as much output as possible, until there
+    is no more input data or no more space in the output buffer (see below
+    about the flush parameter).
+
+  Before the call of inflate(), the application should ensure that at least
+  one of the actions is possible, by providing more input and/or consuming
+  more output, and updating the next_* and avail_* values accordingly.
+  The application can consume the uncompressed output when it wants, for
+  example when the output buffer is full (avail_out == 0), or after each
+  call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+  must be called again after making room in the output buffer because there
+  might be more output pending.
+
+    If the parameter flush is set to Z_PARTIAL_FLUSH or Z_PACKET_FLUSH,
+  inflate flushes as much output as possible to the output buffer. The
+  flushing behavior of inflate is not specified for values of the flush
+  parameter other than Z_PARTIAL_FLUSH, Z_PACKET_FLUSH or Z_FINISH, but the
+  current implementation actually flushes as much output as possible
+  anyway.  For Z_PACKET_FLUSH, inflate checks that once all the input data
+  has been consumed, it is expecting to see the length field of a stored
+  block; if not, it returns Z_DATA_ERROR.
+
+    inflate() should normally be called until it returns Z_STREAM_END or an
+  error. However if all decompression is to be performed in a single step
+  (a single call of inflate), the parameter flush should be set to
+  Z_FINISH. In this case all pending input is processed and all pending
+  output is flushed; avail_out must be large enough to hold all the
+  uncompressed data. (The size of the uncompressed data may have been saved
+  by the compressor for this purpose.) The next operation on this stream must
+  be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+  is never required, but can be used to inform inflate that a faster routine
+  may be used for the single inflate() call.
+
+    inflate() returns Z_OK if some progress has been made (more input
+  processed or more output produced), Z_STREAM_END if the end of the
+  compressed data has been reached and all uncompressed output has been
+  produced, Z_NEED_DICT if a preset dictionary is needed at this point (see
+  inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted,
+  Z_STREAM_ERROR if the stream structure was inconsistent (for example if
+  next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+  Z_BUF_ERROR if no progress is possible or if there was not enough room in
+  the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the
+  application may then call inflateSync to look for a good compression block.
+  In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the
+  dictionary chosen by the compressor.
+*/
+
+
+extern int EXPORT inflateEnd OF((z_streamp strm));
+/*
+     All dynamically allocated data structures for this stream are freed.
+   This function discards any unprocessed input and does not flush any
+   pending output.
+
+     inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+   was inconsistent. In the error case, msg may be set but then points to a
+   static string (which must not be deallocated).
+*/
+
+                        /* Advanced functions */
+
+/*
+    The following functions are needed only in some special applications.
+*/
+
+/*   
+extern int EXPORT deflateInit2 OF((z_streamp strm,
+                                   int  level,
+                                   int  method,
+                                   int  windowBits,
+                                   int  memLevel,
+                                   int  strategy));
+
+     This is another version of deflateInit with more compression options. The
+   fields next_in, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The method parameter is the compression method. It must be Z_DEFLATED in
+   this version of the library. (Method 9 will allow a 64K history buffer and
+   partial block flushes.)
+
+     The windowBits parameter is the base two logarithm of the window size
+   (the size of the history buffer).  It should be in the range 8..15 for this
+   version of the library (the value 16 will be allowed for method 9). Larger
+   values of this parameter result in better compression at the expense of
+   memory usage. The default value is 15 if deflateInit is used instead.
+
+     The memLevel parameter specifies how much memory should be allocated
+   for the internal compression state. memLevel=1 uses minimum memory but
+   is slow and reduces compression ratio; memLevel=9 uses maximum memory
+   for optimal speed. The default value is 8. See zconf.h for total memory
+   usage as a function of windowBits and memLevel.
+
+     The strategy parameter is used to tune the compression algorithm. Use the
+   value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+   filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no
+   string match).  Filtered data consists mostly of small values with a
+   somewhat random distribution. In this case, the compression algorithm is
+   tuned to compress them better. The effect of Z_FILTERED is to force more
+   Huffman coding and less string matching; it is somewhat intermediate
+   between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects
+   the compression ratio but not the correctness of the compressed output even
+   if it is not set appropriately.
+
+     If next_in is not null, the library will use this buffer to hold also
+   some history information; the buffer must either hold the entire input
+   data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in
+   is null, the library will allocate its own history buffer (and leave next_in
+   null). next_out need not be provided here but must be provided by the
+   application for the next call of deflate().
+
+     If the history buffer is provided by the application, next_in must
+   must never be changed by the application since the compressor maintains
+   information inside this buffer from call to call; the application
+   must provide more input only by increasing avail_in. next_in is always
+   reset by the library in this case.
+
+      deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   an invalid method). msg is set to null if there is no error message.
+   deflateInit2 does not perform any compression: this will be done by
+   deflate(). 
+*/
+                            
+extern int EXPORT deflateSetDictionary OF((z_streamp strm,
+                                           const Bytef *dictionary,
+				           uInt  dictLength));
+/*
+     Initializes the compression dictionary (history buffer) from the given
+   byte sequence without producing any compressed output. This function must
+   be called immediately after deflateInit or deflateInit2, before any call
+   of deflate. The compressor and decompressor must use exactly the same
+   dictionary (see inflateSetDictionary).
+     The dictionary should consist of strings (byte sequences) that are likely
+   to be encountered later in the data to be compressed, with the most commonly
+   used strings preferably put towards the end of the dictionary. Using a
+   dictionary is most useful when the data to be compressed is short and
+   can be predicted with good accuracy; the data can then be compressed better
+   than with the default empty dictionary. In this version of the library,
+   only the last 32K bytes of the dictionary are used.
+     Upon return of this function, strm->adler is set to the Adler32 value
+   of the dictionary; the decompressor may later use this value to determine
+   which dictionary has been used by the compressor. (The Adler32 value
+   applies to the whole dictionary even if only a subset of the dictionary is
+   actually used by the compressor.)
+
+     deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state
+   is inconsistent (for example if deflate has already been called for this
+   stream). deflateSetDictionary does not perform any compression: this will
+   be done by deflate(). 
+*/
+
+extern int EXPORT deflateCopy OF((z_streamp dest,
+                                  z_streamp source));
+/*
+     Sets the destination stream as a complete copy of the source stream.  If
+   the source stream is using an application-supplied history buffer, a new
+   buffer is allocated for the destination stream.  The compressed output
+   buffer is always application-supplied. It's the responsibility of the
+   application to provide the correct values of next_out and avail_out for the
+   next call of deflate.
+
+     This function can be useful when several compression strategies will be
+   tried, for example when there are several ways of pre-processing the input
+   data with a filter. The streams that will be discarded should then be freed
+   by calling deflateEnd.  Note that deflateCopy duplicates the internal
+   compression state which can be quite large, so this strategy is slow and
+   can consume lots of memory.
+
+     deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+   (such as zalloc being NULL). msg is left unchanged in both source and
+   destination.
+*/
+
+extern int EXPORT deflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to deflateEnd followed by deflateInit,
+   but does not free and reallocate all the internal compression state.
+   The stream will keep the same compression level and any other attributes
+   that may have been set by deflateInit2.
+
+      deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy));
+/*
+     Dynamically update the compression level and compression strategy.
+   This can be used to switch between compression and straight copy of
+   the input data, or to switch to a different kind of input data requiring
+   a different strategy. If the compression level is changed, the input
+   available so far is compressed with the old level (and may be flushed);
+   the new level will take effect only at the next call of deflate().
+
+     Before the call of deflateParams, the stream state must be set as for
+   a call of deflate(), since the currently available input may have to
+   be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+     deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+   stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+   if strm->avail_out was zero.
+*/
+
+extern int EXPORT deflateOutputPending OF((z_streamp strm));
+/*
+     Returns the number of bytes of output which are immediately
+   available from the compressor (i.e. without any further input
+   or flush).
+*/
+
+/*   
+extern int EXPORT inflateInit2 OF((z_streamp strm,
+                                   int  windowBits));
+
+     This is another version of inflateInit with more compression options. The
+   fields next_out, zalloc, zfree and opaque must be initialized before by
+   the caller.
+
+     The windowBits parameter is the base two logarithm of the maximum window
+   size (the size of the history buffer).  It should be in the range 8..15 for
+   this version of the library (the value 16 will be allowed soon). The
+   default value is 15 if inflateInit is used instead. If a compressed stream
+   with a larger window size is given as input, inflate() will return with
+   the error code Z_DATA_ERROR instead of trying to allocate a larger window.
+
+     If next_out is not null, the library will use this buffer for the history
+   buffer; the buffer must either be large enough to hold the entire output
+   data, or have at least 1<<windowBits bytes.  If next_out is null, the
+   library will allocate its own buffer (and leave next_out null). next_in
+   need not be provided here but must be provided by the application for the
+   next call of inflate().
+
+     If the history buffer is provided by the application, next_out must
+   never be changed by the application since the decompressor maintains
+   history information inside this buffer from call to call; the application
+   can only reset next_out to the beginning of the history buffer when
+   avail_out is zero and all output has been consumed.
+
+      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was
+   not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as
+   windowBits < 8). msg is set to null if there is no error message.
+   inflateInit2 does not perform any decompression: this will be done by
+   inflate().
+*/
+
+extern int EXPORT inflateSetDictionary OF((z_streamp strm,
+				           const Bytef *dictionary,
+					   uInt  dictLength));
+/*
+     Initializes the decompression dictionary (history buffer) from the given
+   uncompressed byte sequence. This function must be called immediately after
+   a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen
+   by the compressor can be determined from the Adler32 value returned by this
+   call of inflate. The compressor and decompressor must use exactly the same
+   dictionary (see deflateSetDictionary).
+
+     inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+   parameter is invalid (such as NULL dictionary) or the stream state is
+   inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+   expected one (incorrect Adler32 value). inflateSetDictionary does not
+   perform any decompression: this will be done by subsequent calls of
+   inflate().
+*/
+
+extern int EXPORT inflateSync OF((z_streamp strm));
+/* 
+    Skips invalid compressed data until the special marker (see deflate()
+  above) can be found, or until all available input is skipped. No output
+  is provided.
+
+    inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR
+  if no more input was provided, Z_DATA_ERROR if no marker has been found,
+  or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+  case, the application may save the current current value of total_in which
+  indicates where valid compressed data was found. In the error case, the
+  application may repeatedly call inflateSync, providing more input each time,
+  until success or end of the input data.
+*/
+
+extern int EXPORT inflateReset OF((z_streamp strm));
+/*
+     This function is equivalent to inflateEnd followed by inflateInit,
+   but does not free and reallocate all the internal decompression state.
+   The stream will keep attributes that may have been set by inflateInit2.
+
+      inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+   stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+extern int inflateIncomp OF((z_stream *strm));
+/*
+     This function adds the data at next_in (avail_in bytes) to the output
+   history without performing any output.  There must be no pending output,
+   and the decompressor must be expecting to see the start of a block.
+   Calling this function is equivalent to decompressing a stored block
+   containing the data at next_in (except that the data is not output).
+*/
+
+                        /* utility functions */
+
+/*
+     The following utility functions are implemented on top of the
+   basic stream-oriented functions. To simplify the interface, some
+   default options are assumed (compression level, window size,
+   standard memory allocation functions). The source code of these
+   utility functions can easily be modified if you need special options.
+*/
+
+extern int EXPORT compress OF((Bytef *dest,   uLongf *destLen,
+			       const Bytef *source, uLong sourceLen));
+/*
+     Compresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be at least 0.1% larger than
+   sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the
+   compressed buffer.
+     This function can be used to compress a whole file at once if the
+   input file is mmap'ed.
+     compress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer.
+*/
+
+extern int EXPORT uncompress OF((Bytef *dest,   uLongf *destLen,
+				 const Bytef *source, uLong sourceLen));
+/*
+     Decompresses the source buffer into the destination buffer.  sourceLen is
+   the byte length of the source buffer. Upon entry, destLen is the total
+   size of the destination buffer, which must be large enough to hold the
+   entire uncompressed data. (The size of the uncompressed data must have
+   been saved previously by the compressor and transmitted to the decompressor
+   by some mechanism outside the scope of this compression library.)
+   Upon exit, destLen is the actual size of the compressed buffer.
+     This function can be used to decompress a whole file at once if the
+   input file is mmap'ed.
+
+     uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+   enough memory, Z_BUF_ERROR if there was not enough room in the output
+   buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+
+
+typedef voidp gzFile;
+
+extern gzFile EXPORT gzopen  OF((const char *path, const char *mode));
+/*
+     Opens a gzip (.gz) file for reading or writing. The mode parameter
+   is as in fopen ("rb" or "wb") but can also include a compression level
+   ("wb9").  gzopen can be used to read a file which is not in gzip format;
+   in this case gzread will directly read from the file without decompression.
+     gzopen returns NULL if the file could not be opened or if there was
+   insufficient memory to allocate the (de)compression state; errno
+   can be checked to distinguish the two cases (if errno is zero, the
+   zlib error is Z_MEM_ERROR).
+*/
+
+extern gzFile EXPORT gzdopen  OF((int fd, const char *mode));
+/*
+     gzdopen() associates a gzFile with the file descriptor fd.  File
+   descriptors are obtained from calls like open, dup, creat, pipe or
+   fileno (in the file has been previously opened with fopen).
+   The mode parameter is as in gzopen.
+     The next call of gzclose on the returned gzFile will also close the
+   file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+   descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+     gzdopen returns NULL if there was insufficient memory to allocate
+   the (de)compression state.
+*/
+
+extern int EXPORT    gzread  OF((gzFile file, voidp buf, unsigned len));
+/*
+     Reads the given number of uncompressed bytes from the compressed file.
+   If the input file was not in gzip format, gzread copies the given number
+   of bytes into the buffer.
+     gzread returns the number of uncompressed bytes actually read (0 for
+   end of file, -1 for error). */
+
+extern int EXPORT    gzwrite OF((gzFile file, const voidp buf, unsigned len));
+/*
+     Writes the given number of uncompressed bytes into the compressed file.
+   gzwrite returns the number of uncompressed bytes actually written
+   (0 in case of error).
+*/
+
+extern int EXPORT    gzflush OF((gzFile file, int flush));
+/*
+     Flushes all pending output into the compressed file. The parameter
+   flush is as in the deflate() function. The return value is the zlib
+   error number (see function gzerror below). gzflush returns Z_OK if
+   the flush parameter is Z_FINISH and all output could be flushed.
+     gzflush should be called only when strictly necessary because it can
+   degrade compression.
+*/
+
+extern int EXPORT    gzclose OF((gzFile file));
+/*
+     Flushes all pending output if necessary, closes the compressed file
+   and deallocates all the (de)compression state. The return value is the zlib
+   error number (see function gzerror below).
+*/
+
+extern const char * EXPORT gzerror OF((gzFile file, int *errnum));
+/*
+     Returns the error message for the last error which occurred on the
+   given compressed file. errnum is set to zlib error number. If an
+   error occurred in the file system and not in the compression library,
+   errnum is set to Z_ERRNO and the application may consult errno
+   to get the exact error code.
+*/
+
+                        /* checksum functions */
+
+/*
+     These functions are not related to compression but are exported
+   anyway because they might be useful in applications using the
+   compression library.
+*/
+
+extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+
+/*
+     Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+   return the updated checksum. If buf is NULL, this function returns
+   the required initial value for the checksum.
+   An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+   much faster. Usage example:
+
+     uLong adler = adler32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       adler = adler32(adler, buffer, length);
+     }
+     if (adler != original_adler) error();
+*/
+
+extern uLong EXPORT crc32   OF((uLong crc, const Bytef *buf, uInt len));
+/*
+     Update a running crc with the bytes buf[0..len-1] and return the updated
+   crc. If buf is NULL, this function returns the required initial value
+   for the crc. Pre- and post-conditioning (one's complement) is performed
+   within this function so it shouldn't be done by the application.
+   Usage example:
+
+     uLong crc = crc32(0L, Z_NULL, 0);
+
+     while (read_buffer(buffer, length) != EOF) {
+       crc = crc32(crc, buffer, length);
+     }
+     if (crc != original_crc) error();
+*/
+
+
+                        /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+extern int EXPORT deflateInit_ OF((z_streamp strm, int level,
+			           const char *version, int stream_size));
+extern int EXPORT inflateInit_ OF((z_streamp strm,
+				   const char *version, int stream_size));
+extern int EXPORT deflateInit2_ OF((z_streamp strm, int  level, int  method,
+				    int windowBits, int memLevel, int strategy,
+				    const char *version, int stream_size));
+extern int EXPORT inflateInit2_ OF((z_streamp strm, int  windowBits,
+				    const char *version, int stream_size));
+#define deflateInit(strm, level) \
+        deflateInit_((strm), (level),       ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+        inflateInit_((strm),                ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+        deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+		      (strategy),           ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+        inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+
+#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL)
+    struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZLIB_H */
+/* --- zlib.h */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/ppp.h
@@ -0,0 +1,138 @@
+#ifndef CYGONCE_PPP_PPP_H
+#define CYGONCE_PPP_PPP_H
+
+//==========================================================================
+//
+//      ppp.h
+//
+//      PPP system interface
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003, 2004 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting the copyright
+// holder.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):     nickg
+// Contributors:  nickg
+// Date:        2002-05-22
+// Purpose:     PPP interface
+// Description: PPP sybsystem interface definitions
+// Usage:       #include "cyg/ppp/ppp.h"
+//              ...
+//              
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/ppp.h>
+
+#include <cyg/infra/cyg_type.h>
+
+#include <cyg/io/serialio.h>
+
+#define MAXNAMELEN 256
+#define MAXSECRETLEN 256
+
+// -------------------------------------------------------------------------
+// PPP instance
+
+typedef CYG_ADDRWORD cyg_ppp_handle_t;
+
+// -------------------------------------------------------------------------
+
+typedef struct
+{
+    unsigned int
+        debug           : 1,            /* Debug flag */
+        kdebugflag      : 5,	        /* Tell kernel to print debug messages */
+        default_route   : 1,            /* Set up default route via PPP link */
+        modem           : 1,            /* Use modem control lines */
+        flowctl         : 2,            /* Flow control, see below */
+        refuse_pap      : 1,	        /* Don't wanna auth. ourselves with PAP */
+	refuse_chap     : 1	        /* Don't wanna auth. ourselves with CHAP */
+        ;
+
+    cyg_serial_baud_rate_t      baud;   /* serial line baud rate */
+    
+    int	        idle_time_limit;        /* Shut down link if idle for this long */
+    int         maxconnect;             /* Maximum connect time (seconds) */
+
+    cyg_uint32  our_address;            /* Our IP address */
+    cyg_uint32  his_address;            /* His IP address */
+
+    char        **script;               /* CHAT connection script */
+    
+    char	user[MAXNAMELEN];       /* Our name for authenticating ourselves */
+    char	passwd[MAXSECRETLEN];   /* Password for PAP and secret for CHAP */
+                          
+} cyg_ppp_options_t;
+
+// -------------------------------------------------------------------------
+/* Values for flowctl field */
+
+#define CYG_PPP_FLOWCTL_DEFAULT         0       /* Default to current setting        */
+#define CYG_PPP_FLOWCTL_NONE            1       /* No flow control - not recommended */
+#define CYG_PPP_FLOWCTL_HARDWARE        2       /* Hardware flow control - CTS/RTS   */
+#define CYG_PPP_FLOWCTL_SOFTWARE        3       /* Software flow control - XON/XOFF  */
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_options_init( cyg_ppp_options_t *options );
+
+// -------------------------------------------------------------------------
+
+externC cyg_ppp_handle_t cyg_ppp_up( const char *devnam,
+                                     const cyg_ppp_options_t *options );
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_down( const cyg_ppp_handle_t handle );
+
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_wait_up( cyg_ppp_handle_t handle );
+
+externC void cyg_ppp_wait_down( cyg_ppp_handle_t handle );
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_chat( const char *devname,
+                                const char *script[] );
+
+
+// -------------------------------------------------------------------------
+#endif // CYGONCE_PPP_PPP_H multiple inclusion protection
+// EOF ppp.h
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/ppp_io.h
@@ -0,0 +1,156 @@
+#ifndef CYGONCE_PPP_PPP_IO_H
+#define CYGONCE_PPP_PPP_IO_H
+// ====================================================================
+//
+//      ppp_io.h
+//
+//      PPP IO interface
+//
+// ====================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting the
+// copyright holder.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+// ====================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2003-06-01
+// Purpose:             Internal PPP interfaces
+// Description:         This header describes the interfaces between
+//                      the PPP daemon system dependent code in sys-ecos.c
+//                      and the PPP line-discipline-derived code in ppp_io.c.
+//
+//####DESCRIPTIONEND####
+//
+// ====================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/io_fileio.h>
+
+#include <sys/uio.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/serial.h>
+#include <cyg/io/serial.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/ppp/names.h>
+
+#include <cyg/ppp/ppp.h>
+
+// ====================================================================
+// Fake TTY structure
+//
+// This is passed into the line discipline code and pretends to be a
+// tty device. In actual fact we use it to store all the state for the
+// connection.
+
+struct tty
+{
+    // IO device handle.
+    cyg_io_handle_t             t_handle;
+
+    // Pointer to softc structure. This is the only field that the
+    // ex-BSD code actually accesses.
+    void                        *t_sc;
+
+    // Pointer to user's options
+    const cyg_ppp_options_t     *options;
+
+    // Parameters for PPPD thread
+    cyg_handle_t                pppd_thread;
+    volatile int                pppd_wakeup;
+    volatile cyg_bool_t         pppd_thread_running;
+
+    // Parameters for transmit thread
+    cyg_sem_t                   tx_sem;
+    cyg_handle_t                tx_thread;
+    volatile cyg_bool_t         tx_thread_running;
+
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+    // Serial line control
+    cyg_serial_line_status_callback_t serial_callbacks;
+    volatile cyg_uint32         carrier_detected;
+#endif
+    
+    // Alarm for implementing wait_input() timeout.
+    cyg_handle_t                alarm;
+    cyg_alarm                   alarm_obj;
+    
+};
+
+externC struct tty ppp_tty;
+
+// ====================================================================
+// This is called at the correct time in the PPPD to set up the
+// options from the user's request. This has to be done after the
+// protocols etc. have intitialized.
+
+externC void cyg_ppp_options_install( const cyg_ppp_options_t *options );
+
+// ====================================================================
+// Definition of serial callback function. Used for carrier detection
+// etc.
+
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+externC void cyg_ppp_serial_callback( cyg_serial_line_status_t *s,
+                                      CYG_ADDRWORD priv );
+#endif
+
+// ====================================================================
+// These are all renamed versions of the PPP line discipline
+// functions. The PPPD code calls these directly to control the PPP
+// driver and to send and receive control packets.
+
+extern int	cyg_ppp_pppopen __P((struct tty *tp));
+
+extern int	cyg_ppp_ppptioctl __P((struct tty *tp, u_long cmd, caddr_t data, int flag));
+                                       
+extern int	cyg_ppp_pppinput __P((int c, struct tty *tp));
+
+extern int	cyg_ppp_pppwrite __P((struct tty *tp, struct uio *uio, int flag));
+
+extern int	cyg_ppp_pppread __P((struct tty *tp, struct uio *uio, int flag));
+
+extern int	cyg_ppp_pppclose __P((struct tty *tp, int flag));
+
+// ====================================================================
+// Start PPP transmission. This is called from the TX thread to cause
+// any pending packets to be sent.
+
+extern int	cyg_ppp_pppstart __P((struct tty *tp));
+
+// ====================================================================
+#endif // CYGONCE_PPP_PPP_IO_H
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/pppd.h
@@ -0,0 +1,549 @@
+//==========================================================================
+//
+//      include/pppd.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/pppd.h,v 1.13 1999/08/28 01:19:08 peter Exp $
+ */
+
+/*
+ * TODO:
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+
+#include <cyg/io/io.h>
+#include <cyg/io/serialio.h>
+
+#include <cyg/ppp/names.h>
+
+#include <stdio.h>		/* for FILE */
+#include <sys/param.h>		/* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h>		/* for u_int32_t, if defined */
+#include <sys/time.h>		/* for struct timeval */
+#include <cyg/ppp/net/ppp_defs.h>
+
+#if __STDC__
+#include <stdarg.h>
+#define __V(x)	x
+#else
+#include <varargs.h>
+#define __V(x)	(va_alist) va_dcl
+#define const
+#endif
+
+/*
+ * Limits.
+ */
+
+#define NUM_PPP		1	/* One PPP interface supported (per process) */
+#define MAXWORDLEN	1024	/* max length of word in file (incl null) */
+#define MAXARGS		1	/* max # args to a command */
+#define MAXNAMELEN	256	/* max length of hostname or name for auth */
+#define MAXSECRETLEN	256	/* max length of password or secret */
+
+/*
+ * Global variables.
+ */
+
+extern int	hungup;		/* Physical layer has disconnected */
+extern int	ifunit;		/* Interface unit number */
+extern char	ifname[];	/* Interface name */
+extern int	ttyfd;		/* Serial device file descriptor */
+extern char	cyg_ppp_hostname[];	/* Our hostname */
+extern u_char	outpacket_buf[]; /* Buffer for outgoing packets */
+extern int	phase;		/* Current state of link - see values below */
+extern int	baud_rate;	/* Current link speed in bits/sec */
+extern char	*progname;	/* Name of this program */
+extern int	redirect_stderr;/* Connector's stderr should go to file */
+extern char	peer_authname[];/* Authenticated name of peer */
+extern int	privileged;	/* We were run by real-uid root */
+extern int	need_holdoff;	/* Need holdoff period after link terminates */
+extern char	**script_env;	/* Environment variables for scripts */
+extern int	detached;	/* Have detached from controlling tty */
+
+/*
+ * Variables set by command-line options.
+ */
+
+extern int	debug;		/* Debug flag */
+extern int	kdebugflag;	/* Tell kernel to print debug messages */
+extern int	default_device;	/* Using /dev/tty or equivalent */
+extern char	devnam[];	/* Device name */
+extern int      flowctl;        /* Flow control */
+extern int	modem;		/* Use modem control lines */
+extern cyg_serial_baud_rate_t	inspeed;	/* Input/Output speed requested */
+extern u_int32_t netmask;	/* IP netmask to set on interface */
+extern int	lockflag;	/* Create lock file to lock the serial dev */
+extern int	nodetach;	/* Don't detach from controlling tty */
+extern char	*connector;	/* Script to establish physical link */
+extern char	*disconnector;	/* Script to disestablish physical link */
+extern char	*welcomer;	/* Script to welcome client after connection */
+extern int	max_con_attempts;/* Maximum number of times to try dialing */
+extern int	maxconnect;	/* Maximum connect time (seconds) */
+extern char	user[];		/* Our name for authenticating ourselves */
+extern char	passwd[];	/* Password for PAP */
+extern int	auth_required;	/* Peer is required to authenticate */
+extern int	proxyarp;	/* Set up proxy ARP entry for peer */
+extern int	persist;	/* Reopen link after it goes down */
+extern int	uselogin;	/* Use /etc/passwd for checking PAP */
+extern int	lcp_echo_interval; /* Interval between LCP echo-requests */
+extern int	lcp_echo_fails;	/* Tolerance to unanswered echo-requests */
+extern char	our_name[];	/* Our name for authentication purposes */
+extern char	remote_name[];	/* Peer's name for authentication */
+extern int	explicit_remote;/* remote_name specified with remotename opt */
+extern int	usehostname;	/* Use hostname for our_name */
+extern int	disable_defaultip; /* Don't use hostname for default IP adrs */
+//extern int	demand;		/* Do dial-on-demand */
+#define demand 0
+extern char	*ipparam;	/* Extra parameter for ip up/down scripts */
+extern int	cryptpap;	/* Others' PAP passwords are encrypted */
+extern int	idle_time_limit;/* Shut down link if idle for this long */
+extern int	holdoff;	/* Dead time before restarting */
+extern int	refuse_pap;	/* Don't wanna auth. ourselves with PAP */
+extern int	refuse_chap;	/* Don't wanna auth. ourselves with CHAP */
+#ifdef PPP_FILTER
+extern struct	bpf_program pass_filter;   /* Filter for pkts to pass */
+extern struct	bpf_program active_filter; /* Filter for link-active pkts */
+#endif
+
+
+#ifdef MSLANMAN
+extern int	ms_lanman;	/* Nonzero if use LanMan password instead of NT */
+				/* Has meaning only with MS-CHAP challenges */
+#endif
+
+/*
+ * Values for phase.
+ */
+#define PHASE_DEAD		0
+#define PHASE_INITIALIZE	1
+#define PHASE_DORMANT		2
+#define PHASE_ESTABLISH		3
+#define PHASE_AUTHENTICATE	4
+#define PHASE_CALLBACK		5
+#define PHASE_NETWORK		6
+#define PHASE_TERMINATE		7
+#define PHASE_HOLDOFF		8
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+    u_short protocol;		/* PPP protocol number */
+    /* Initialization procedure */
+    void (*init) __P((int unit));
+    /* Process a received packet */
+    void (*input) __P((int unit, u_char *pkt, int len));
+    /* Process a received protocol-reject */
+    void (*protrej) __P((int unit));
+    /* Lower layer has come up */
+    void (*lowerup) __P((int unit));
+    /* Lower layer has gone down */
+    void (*lowerdown) __P((int unit));
+    /* Open the protocol */
+    void (*open) __P((int unit));
+    /* Close the protocol */
+    void (*close) __P((int unit, char *reason));
+    /* Print a packet in readable form */
+    int  (*printpkt) __P((u_char *pkt, int len,
+			  void (*printer) __P((void *, char *, ...)),
+			  void *arg));
+    /* Process a received data packet */
+    void (*datainput) __P((int unit, u_char *pkt, int len));
+    int  enabled_flag;		/* 0 iff protocol is disabled */
+    char *name;			/* Text name of protocol */
+    /* Check requested options, assign defaults */
+    void (*check_options) __P((void));
+    /* Configure interface for demand-dial */
+    int  (*demand_conf) __P((int unit));
+    /* Say whether to bring up link for this pkt */
+    int  (*active_pkt) __P((u_char *pkt, int len));
+};
+
+/* Table of pointers to supported protocols */
+extern struct protent *protocols[];
+
+/*
+ * Prototypes.
+ */
+
+/* Procedures exported from main.c. */
+void detach __P((void));	/* Detach from controlling tty */
+void die __P((int));		/* Cleanup and exit */
+void quit __P((void));		/* like die(1) */
+void novm __P((char *));	/* Say we ran out of memory, and die */
+void cyg_ppp_timeout __P((void (*func)(void *), void *arg, int t));
+				/* Call func(arg) after t seconds */
+void cyg_ppp_untimeout __P((void (*func)(void *), void *arg));
+				/* Cancel call to func(arg) */
+int run_program __P((char *prog, char **args, int must_exist));
+				/* Run program prog with args in child */
+void demuxprotrej __P((int, int));
+				/* Demultiplex a Protocol-Reject */
+void format_packet __P((u_char *, int, void (*) (void *, char *, ...),
+		void *));	/* Format a packet in human-readable form */
+void log_packet __P((u_char *, int, char *, int));
+				/* Format a packet and log it with syslog */
+void print_string __P((char *, int,  void (*) (void *, char *, ...),
+		void *));	/* Format a string for output */
+int fmtmsg __P((char *, int, char *, ...));		/* sprintf++ */
+int vfmtmsg __P((char *, int, char *, va_list));	/* vsprintf++ */
+void script_setenv __P((char *, char *));	/* set script env var */
+void script_unsetenv __P((char *));		/* unset script env var */
+
+/* Procedures exported from auth.c */
+void link_required __P((int));	  /* we are starting to use the link */
+void link_terminated __P((int));  /* we are finished with the link */
+void link_down __P((int));	  /* the LCP layer has left the Opened state */
+void link_established __P((int)); /* the link is up; authenticate now */
+void np_up __P((int, int));	  /* a network protocol has come up */
+void np_down __P((int, int));	  /* a network protocol has gone down */
+void np_finished __P((int, int)); /* a network protocol no longer needs link */
+void auth_peer_fail __P((int, int));
+				/* peer failed to authenticate itself */
+void auth_peer_success __P((int, int, char *, int));
+				/* peer successfully authenticated itself */
+void auth_withpeer_fail __P((int, int));
+				/* we failed to authenticate ourselves */
+void auth_withpeer_success __P((int, int));
+				/* we successfully authenticated ourselves */
+void auth_check_options __P((void));
+				/* check authentication options supplied */
+void auth_reset __P((int));	/* check what secrets we have */
+int  check_passwd __P((int, char *, int, char *, int, char **, int *));
+				/* Check peer-supplied username/password */
+int  get_secret __P((int, char *, char *, char *, int *, int));
+				/* get "secret" for chap */
+int  auth_ip_addr __P((int, u_int32_t));
+				/* check if IP address is authorized */
+int  bad_ip_adrs __P((u_int32_t));
+				/* check if IP address is unreasonable */
+void check_access __P((FILE *, char *));
+				/* check permissions on secrets file */
+
+/* Procedures exported from demand.c */
+void demand_conf __P((void));	/* config interface(s) for demand-dial */
+void demand_block __P((void));	/* set all NPs to queue up packets */
+void demand_unblock __P((void)); /* set all NPs to pass packets */
+void demand_discard __P((void)); /* set all NPs to discard packets */
+void demand_rexmit __P((int));	/* retransmit saved frames for an NP */
+int  loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+int  loop_frame __P((unsigned char *, int)); /* process frame from loopback */
+
+/* Procedures exported from sys-*.c */
+void sys_init __P((void));	/* Do system-dependent initialization */
+void sys_cleanup __P((void));	/* Restore system state before exiting */
+void sys_check_options __P((void)); /* Check options specified */
+void sys_close __P((void));	/* Clean up in a child before execing */
+int  ppp_available __P((void));	/* Test whether ppp kernel support exists */
+void open_ppp_loopback __P((void)); /* Open loopback for demand-dialling */
+void establish_ppp __P((cyg_io_handle_t));	/* Turn serial port into a ppp interface */
+void restore_loop __P((void));	/* Transfer ppp unit back to loopback */
+void disestablish_ppp __P((cyg_io_handle_t)); /* Restore port to normal operation */
+void clean_check __P((void));	/* Check if line was 8-bit clean */
+void set_up_tty __P((cyg_io_handle_t, int)); /* Set up port's speed, parameters, etc. */
+void restore_tty __P((cyg_io_handle_t));	/* Restore port's original parameters */
+void setdtr __P((int, int));	/* Raise or lower port's DTR line */
+void output __P((int, u_char *, int)); /* Output a PPP packet */
+void wait_input __P((struct timeval *));
+				/* Wait for input, with timeout */
+void wait_loop_output __P((struct timeval *));
+				/* Wait for pkt from loopback, with timeout */
+void wait_time __P((struct timeval *)); /* Wait for given length of time */
+int  read_packet __P((u_char *)); /* Read PPP packet */
+int  get_loop_output __P((void)); /* Read pkts from loopback */
+void ppp_send_config __P((int, int, u_int32_t, int, int));
+				/* Configure i/f transmit parameters */
+void ppp_set_xaccm __P((int, ext_accm));
+				/* Set extended transmit ACCM */
+void ppp_recv_config __P((int, int, u_int32_t, int, int));
+				/* Configure i/f receive parameters */
+int  ccp_test __P((int, u_char *, int, int));
+				/* Test support for compression scheme */
+void ccp_flags_set __P((int, int, int));
+				/* Set kernel CCP state */
+int  ccp_fatal_error __P((int)); /* Test for fatal decomp error in kernel */
+int  get_idle_time __P((int, struct ppp_idle *));
+				/* Find out how long link has been idle */
+int  sifvjcomp __P((int, int, int, int));
+				/* Configure VJ TCP header compression */
+int  sifup __P((int));		/* Configure i/f up (for IP) */
+int  sifnpmode __P((int u, int proto, enum NPmode mode));
+				/* Set mode for handling packets for proto */
+int  sifdown __P((int));	/* Configure i/f down (for IP) */
+int  sifaddr __P((int, u_int32_t, u_int32_t, u_int32_t));
+				/* Configure IP addresses for i/f */
+int  cifaddr __P((int, u_int32_t, u_int32_t));
+				/* Reset i/f IP addresses */
+int  sifdefaultroute __P((int, u_int32_t, u_int32_t));
+				/* Create default route through i/f */
+int  cifdefaultroute __P((int, u_int32_t, u_int32_t));
+				/* Delete default route through i/f */
+int  sifproxyarp __P((int, u_int32_t));
+				/* Add proxy ARP entry for peer */
+int  cifproxyarp __P((int, u_int32_t));
+				/* Delete proxy ARP entry for peer */
+u_int32_t GetMask __P((u_int32_t)); /* Get appropriate netmask for address */
+int  lock __P((char *));	/* Create lock file for device */
+void unlock __P((void));	/* Delete previously-created lock file */
+int  daemon __P((int, int));	/* Detach us from terminal session */
+void logwtmp __P((const char *, const char *, const char *));
+				/* Write entry to wtmp file */
+int  get_host_seed __P((void));	/* Get host-dependent random number seed */
+#ifdef PPP_FILTER
+int  set_filters __P((struct bpf_program *pass, struct bpf_program *active));
+				/* Set filter programs in kernel */
+#endif
+
+/* Procedures exported from options.c */
+int  parse_args __P((int argc, char **argv));
+				/* Parse options from arguments given */
+void usage __P((void));		/* Print a usage message */
+int  options_from_file __P((char *filename, int must_exist, int check_prot,
+			    int privileged));
+				/* Parse options from an options file */
+int  options_from_user __P((void)); /* Parse options from user's .ppprc */
+int  options_for_tty __P((void)); /* Parse options from /etc/ppp/options.tty */
+void scan_args __P((int argc, char **argv));
+				/* Look for tty name in command-line args */
+int  getword __P((FILE *f, char *word, int *newlinep, char *filename));
+				/* Read a word from a file */
+void option_error __P((char *fmt, ...));
+				/* Print an error message about an option */
+int setipaddr __P((char *));	/* set IP addresses */
+
+
+/*
+ * This structure is used to store information about certain
+ * options, such as where the option value came from (/etc/ppp/options,
+ * command line, etc.) and whether it came from a privileged source.
+ */
+
+struct option_info {
+    int	    priv;		/* was value set by sysadmin? */
+    char    *source;		/* where option came from */
+};
+
+extern struct option_info auth_req_info;
+extern struct option_info connector_info;
+extern struct option_info disconnector_info;
+extern struct option_info welcomer_info;
+extern struct option_info devnam_info;
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+	(c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+	*(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+	(s) = *(cp)++ << 8; \
+	(s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+	*(cp)++ = (u_char) ((s) >> 8); \
+	*(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+	(l) = *(cp)++ << 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+	*(cp)++ = (u_char) ((l) >> 24); \
+	*(cp)++ = (u_char) ((l) >> 16); \
+	*(cp)++ = (u_char) ((l) >> 8); \
+	*(cp)++ = (u_char) (l); \
+}
+
+#define INCPTR(n, cp)	((cp) += (n))
+#define DECPTR(n, cp)	((cp) -= (n))
+
+#undef  FALSE
+#define FALSE	0
+#undef  TRUE
+#define TRUE	1
+
+/*
+ * System dependent definitions for user-level 4.3BSD UNIX implementation.
+ */
+
+#define DEMUXPROTREJ(u, p)	demuxprotrej(u, p)
+
+#define TIMEOUT(r, f, t)	cyg_ppp_timeout((r), (f), (t))
+#define UNTIMEOUT(r, f)		cyg_ppp_untimeout((r), (f))
+
+#define BCOPY(s, d, l)		memcpy(d, s, l)
+#define BZERO(s, n)		memset(s, 0, n)
+#define EXIT(u)			quit()
+
+#define PRINTMSG(m, l)	{ m[l] = '\0'; syslog(LOG_INFO, "Remote message: %s", m); }
+
+/*
+ * MAKEHEADER - Add Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+    PUTCHAR(PPP_ALLSTATIONS, p); \
+    PUTCHAR(PPP_UI, p); \
+    PUTSHORT(t, p); }
+
+//#define DEBUGALL
+
+#ifdef DEBUGALL
+#define DEBUGMAIN	1
+#define DEBUGFSM	1
+#define DEBUGLCP	1
+#define DEBUGIPCP	1
+#define DEBUGUPAP	1
+#define DEBUGCHAP	1
+#endif
+
+#ifndef LOG_PPP			/* we use LOG_LOCAL2 for syslog by default */
+#if defined(DEBUGMAIN) || defined(DEBUGFSM) || defined(DEBUGSYS) \
+  || defined(DEBUGLCP) || defined(DEBUGIPCP) || defined(DEBUGUPAP) \
+  || defined(DEBUGCHAP) || defined(DEBUG)
+#define LOG_PPP LOG_LOCAL2
+#else
+#define LOG_PPP LOG_DAEMON
+#endif
+#endif /* LOG_PPP */
+
+#ifdef DEBUGMAIN
+#define MAINDEBUG(x)	if (debug) syslog x
+#else
+#define MAINDEBUG(x)
+#endif
+
+#ifdef DEBUGSYS
+#define SYSDEBUG(x)	if (debug) syslog x
+#else
+#define SYSDEBUG(x)
+#endif
+
+#ifdef DEBUGFSM
+#define FSMDEBUG(x)	if (debug) syslog x
+#else
+#define FSMDEBUG(x)
+#endif
+
+#ifdef DEBUGLCP
+#define LCPDEBUG(x)	if (debug) syslog x
+#else
+#define LCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPCP
+#define IPCPDEBUG(x)	if (debug) syslog x
+#else
+#define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGUPAP
+#define UPAPDEBUG(x)	if (debug) syslog x
+#else
+#define UPAPDEBUG(x)
+#endif
+
+#ifdef DEBUGCHAP
+#define CHAPDEBUG(x)	if (debug) syslog x
+#else
+#define CHAPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPXCP
+#define IPXCPDEBUG(x)	if (debug) syslog x
+#else
+#define IPXCPDEBUG(x)
+#endif
+
+#ifndef SIGTYPE
+#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
+#define SIGTYPE void
+#else
+#define SIGTYPE int
+#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
+#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)	((a) > (b)? (a): (b))
+#endif
+
+#endif /* __PPP_H__ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/slcompress.h
@@ -0,0 +1,209 @@
+//==========================================================================
+//
+//      include/slcompress.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * Definitions for tcp compression routines.
+ *
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *	- Initial distribution.
+ * $FreeBSD: src/sys/net/slcompress.h,v 1.14.2.1 2000/05/05 13:37:06 jlemon Exp $
+ */
+
+#ifndef _NET_SLCOMPRESS_H_
+#define _NET_SLCOMPRESS_H_
+
+#include <cyg/ppp/names.h>
+
+#define MAX_STATES 16		/* must be > 2 and < 256 */
+#define MAX_HDR 128
+
+/*
+ * Compressed packet format:
+ *
+ * The first octet contains the packet type (top 3 bits), TCP
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence
+ * numbers have changed (bottom 5 bits).  The next octet is a
+ * conversation number that associates a saved IP/TCP header with
+ * the compressed packet.  The next two octets are the TCP checksum
+ * from the original datagram.  The next 0 to 15 octets are
+ * sequence number changes, one change per bit set in the header
+ * (there may be no changes and there are two special cases where
+ * the receiver implicitly knows what changed -- see below).
+ *
+ * There are 5 numbers which can change (they are always inserted
+ * in the following order): TCP urgent pointer, window,
+ * acknowledgement, sequence number and IP ID.  (The urgent pointer
+ * is different from the others in that its value is sent, not the
+ * change in value.)  Since typical use of SLIP links is biased
+ * toward small packets (see comments on MTU/MSS below), changes
+ * use a variable length coding with one octet for numbers in the
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the
+ * range 256 - 65535 or 0.  (If the change in sequence number or
+ * ack is more than 65535, an uncompressed packet is sent.)
+ */
+
+/*
+ * Packet types (must not conflict with IP protocol version)
+ *
+ * The top nibble of the first octet is the packet type.  There are
+ * three possible types: IP (not proto TCP or tcp with one of the
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but
+ * with the 8-bit protocol field replaced by an 8-bit connection id --
+ * this type of packet syncs the sender & receiver); and compressed
+ * TCP (described above).
+ *
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and
+ * is logically part of the 4-bit "changes" field that follows.  Top
+ * three bits are actual packet type.  For backward compatibility
+ * and in the interest of conserving bits, numbers are chosen so the
+ * IP protocol version number (4) which normally appears in this nibble
+ * means "IP packet".
+ */
+
+/* packet types */
+#define TYPE_IP 0x40
+#define TYPE_UNCOMPRESSED_TCP 0x70
+#define TYPE_COMPRESSED_TCP 0x80
+#define TYPE_ERROR 0x00
+
+/* Bits in first octet of compressed packet */
+#define NEW_C	0x40	/* flag bits for what changed in a packet */
+#define NEW_I	0x20
+#define NEW_S	0x08
+#define NEW_A	0x04
+#define NEW_W	0x02
+#define NEW_U	0x01
+
+/* reserved, special-case values of above */
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U)		/* echoed interactive traffic */
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U)	/* unidirectional data */
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)
+
+#define TCP_PUSH_BIT 0x10
+
+
+/*
+ * "state" data for each active tcp conversation on the wire.  This is
+ * basically a copy of the entire IP/TCP header from the last packet
+ * we saw from the conversation together with a small identifier
+ * the transmit & receive ends of the line use to locate saved header.
+ */
+struct cstate {
+	struct cstate *cs_next;	/* next most recently used cstate (xmit only) */
+	u_int16_t cs_hlen;	/* size of hdr (receive only) */
+	u_char cs_id;		/* connection # associated with this state */
+	u_char cs_filler;
+	union {
+		char csu_hdr[MAX_HDR];
+		struct ip csu_ip;	/* ip/tcp hdr from most recent packet */
+	} slcs_u;
+};
+#define cs_ip slcs_u.csu_ip
+#define cs_hdr slcs_u.csu_hdr
+
+/*
+ * all the state data for one serial line (we need one of these
+ * per line).
+ */
+struct slcompress {
+	struct cstate *last_cs;	/* most recently used tstate */
+	u_char last_recv;	/* last rcvd conn. id */
+	u_char last_xmit;	/* last sent conn. id */
+	u_int16_t flags;
+#ifndef SL_NO_STATS
+	int sls_packets;	/* outbound packets */
+	int sls_compressed;	/* outbound compressed packets */
+	int sls_searches;	/* searches for connection state */
+	int sls_misses;		/* times couldn't find conn. state */
+	int sls_uncompressedin;	/* inbound uncompressed packets */
+	int sls_compressedin;	/* inbound compressed packets */
+	int sls_errorin;	/* inbound unknown type packets */
+	int sls_tossed;		/* inbound packets tossed because of error */
+#endif
+	struct cstate tstate[MAX_STATES];	/* xmit connection states */
+	struct cstate rstate[MAX_STATES];	/* receive connection states */
+};
+/* flag values */
+#define SLF_TOSS 1		/* tossing rcvd frames because of input err */
+
+void	 sl_compress_init __P((struct slcompress *, int));
+u_int	 sl_compress_tcp __P((struct mbuf *,
+	    struct ip *, struct slcompress *, int));
+int	 sl_uncompress_tcp __P((u_char **, int, u_int, struct slcompress *));
+int	 sl_uncompress_tcp_core __P((u_char *, int, int, u_int,
+	    struct slcompress *, u_char **, u_int *));
+
+#endif /* !_NET_SLCOMPRESS_H_ */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/syslog.h
@@ -0,0 +1,97 @@
+#ifndef CYGONCE_PPP_SYSLOG_H
+#define CYGONCE_PPP_SYSLOG_H
+// ====================================================================
+//
+//      syslog.h
+//
+//      PPP syslog stub
+//
+// ====================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting the
+// copyright holder.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+// ====================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):           nickg
+// Contributors:        nickg
+// Date:                2003-06-01
+// Purpose:             Syslog
+// Description:         This header contains definitions for using syslog
+//                      in the PPP code.
+//
+//####DESCRIPTIONEND####
+//
+// ====================================================================
+
+#include <cyg/infra/diag.h>
+
+#include <cyg/ppp/names.h>
+
+// ====================================================================
+// Syslog functions
+//
+// We ignore setlogmask() but syslog() is a simple stub that goes to
+// diag_printf(). 
+
+#define setlogmask(x)
+
+void syslog( int level, char *fmt, ... );
+
+// ====================================================================
+// Log level flags
+//
+// These are duplicates of the defines in sys/param.h.
+
+#define LOG_ERR      0x0001
+#define LOG_WARNING  0x0002
+#define LOG_NOTICE   0x0004
+#define LOG_INFO     0x0008
+#define LOG_DEBUG    0x0010
+#define LOG_MDEBUG   0x0020
+#define LOG_IOCTL    0x0040
+#define LOG_ADDR     0x0100
+#define LOG_FAIL     0x0200
+#define LOG_INIT     0x0080
+#define LOG_EMERG    0x4000
+#define LOG_CRIT     0x8000
+
+// ====================================================================
+// Debug facility
+//
+// Switch these defines over to enable some debugging messages
+
+//#define db_printf diag_printf
+#define db_printf(fmt, ... )
+
+// ====================================================================
+#endif // CYGONCE_PPP_SYSLOG_H
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/include/upap.h
@@ -0,0 +1,136 @@
+//==========================================================================
+//
+//      include/upap.h
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * upap.h - User/Password Authentication Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/usr.sbin/pppd/upap.h,v 1.7 1999/08/28 01:19:09 peter Exp $
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define UPAP_HEADERLEN	(sizeof (u_char) + sizeof (u_char) + sizeof (u_short))
+
+
+/*
+ * UPAP codes.
+ */
+#define UPAP_AUTHREQ	1	/* Authenticate-Request */
+#define UPAP_AUTHACK	2	/* Authenticate-Ack */
+#define UPAP_AUTHNAK	3	/* Authenticate-Nak */
+
+
+/*
+ * Each interface is described by upap structure.
+ */
+typedef struct upap_state {
+    int us_unit;		/* Interface unit number */
+    char *us_user;		/* User */
+    int us_userlen;		/* User length */
+    char *us_passwd;		/* Password */
+    int us_passwdlen;		/* Password length */
+    int us_clientstate;		/* Client state */
+    int us_serverstate;		/* Server state */
+    u_char us_id;		/* Current id */
+    int us_timeouttime;		/* Timeout (seconds) for auth-req retrans. */
+    int us_transmits;		/* Number of auth-reqs sent */
+    int us_maxtransmits;	/* Maximum number of auth-reqs to send */
+    int us_reqtimeout;		/* Time to wait for auth-req from peer */
+} upap_state;
+
+
+/*
+ * Client states.
+ */
+#define UPAPCS_INITIAL	0	/* Connection down */
+#define UPAPCS_CLOSED	1	/* Connection up, haven't requested auth */
+#define UPAPCS_PENDING	2	/* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ	3	/* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN	4	/* We've received an Ack */
+#define UPAPCS_BADAUTH	5	/* We've received a Nak */
+
+/*
+ * Server states.
+ */
+#define UPAPSS_INITIAL	0	/* Connection down */
+#define UPAPSS_CLOSED	1	/* Connection up, haven't requested auth */
+#define UPAPSS_PENDING	2	/* Connection down, have requested auth */
+#define UPAPSS_LISTEN	3	/* Listening for an Authenticate */
+#define UPAPSS_OPEN	4	/* We've sent an Ack */
+#define UPAPSS_BADAUTH	5	/* We've sent a Nak */
+
+
+/*
+ * Timeouts.
+ */
+#define UPAP_DEFTIMEOUT	3	/* Timeout (seconds) for retransmitting req */
+#define UPAP_DEFREQTIME	30	/* Time to wait for auth-req from peer */
+
+extern upap_state upap[];
+
+void upap_authwithpeer __P((int, char *, char *));
+void upap_authpeer __P((int));
+
+extern struct protent pap_protent;
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/auth.c
@@ -0,0 +1,890 @@
+//==========================================================================
+//
+//      src/auth.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/auth.c,v 1.24.2.1 2000/12/11 01:03:37 obrien Exp $";
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <cyg/ppp/syslog.h>
+#include <paths.h>
+//#include <pwd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+//#include <utmp.h>
+#include <fcntl.h>
+#if defined(_PATH_LASTLOG) && defined(_linux_)
+#include <lastlog.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/time.h>
+//#include <utmp.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#endif
+
+#ifdef HAS_SHADOW
+#include <shadow.h>
+#ifndef PW_PPP
+#define PW_PPP PW_LOGIN
+#endif
+#endif
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/lcp.h"
+#include "cyg/ppp/ipcp.h"
+#include "cyg/ppp/upap.h"
+#include "cyg/ppp/chap.h"
+#ifdef CBCP_SUPPORT
+#include "cyg/ppp/cbcp.h"
+#endif
+//#include "cyg/ppp/pathnames.h"
+
+/* Used for storing a sequence of words.  Usually malloced. */
+struct wordlist {
+    struct wordlist	*next;
+    char		word[1];
+};
+
+/* Bits in scan_authfile return value */
+#define NONWILD_SERVER	1
+#define NONWILD_CLIENT	2
+
+#define ISWILD(word)	(word[0] == '*' && word[1] == 0)
+
+#define FALSE	0
+#define TRUE	1
+
+/* The name by which the peer authenticated itself to us. */
+char peer_authname[MAXNAMELEN];
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+
+/* Set if we have successfully called plogin() */
+//static int logged_in;
+
+/* Set if not wild or blank */
+//static int non_wildclient;
+
+/* Set if we have run the /etc/ppp/auth-up script. */
+//static int did_authup;
+
+/* List of addresses which the peer may use. */
+static struct wordlist *addresses[NUM_PPP];
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+
+/* Bits in auth_pending[] */
+#define PAP_WITHPEER	1
+#define PAP_PEER	2
+#define CHAP_WITHPEER	4
+#define CHAP_PEER	8
+
+extern char *crypt __P((const char *, const char *));
+
+/* Prototypes for procedures local to this file. */
+
+static void network_phase __P((int));
+static void check_idle __P((void *));
+static void connect_time_expired __P((void *));
+static int  null_login __P((int));
+static int  get_pap_passwd __P((char *));
+static int  have_pap_secret __P((void));
+static int  have_chap_secret __P((char *, char *, u_int32_t));
+static int  ip_addr_check __P((u_int32_t, struct wordlist *));
+
+static void auth_set_ip_addr __P((int));
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(unit)
+    int unit;
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(unit)
+    int unit;
+{
+    extern	time_t	etime, stime;
+    extern	int	minutes;
+
+db_printf("%s()\n",__PRETTY_FUNCTION__);    
+    if (phase == PHASE_DEAD)
+	return;
+    phase = PHASE_DEAD;
+    etime = time((time_t *) NULL);
+    minutes = (etime-stime)/60;
+    syslog(LOG_NOTICE, "Connection terminated, connected for %d minutes\n",
+	minutes > 1 ? minutes : 1);
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void
+link_down(unit)
+    int unit;
+{
+    int i;
+    struct protent *protp;
+
+db_printf("%s()\n",__PRETTY_FUNCTION__);
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (!protp->enabled_flag)
+	    continue;
+        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+	    (*protp->lowerdown)(unit);
+        if (protp->protocol < 0xC000 && protp->close != NULL)
+	    (*protp->close)(unit, "LCP down");
+    }
+    num_np_open = 0;
+    num_np_up = 0;
+    if (phase != PHASE_DEAD)
+	phase = PHASE_TERMINATE;
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(unit)
+    int unit;
+{
+    int auth;
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ho = &lcp_hisoptions[unit];
+    int i;
+    struct protent *protp;
+
+    /*
+     * Tell higher-level protocols that LCP is up.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        if (protp->protocol != PPP_LCP && protp->enabled_flag
+	    && protp->lowerup != NULL)
+	    (*protp->lowerup)(unit);
+
+    if (auth_required && !(go->neg_chap || go->neg_upap)) {
+	/*
+	 * We wanted the peer to authenticate itself, and it refused:
+	 * treat it as though it authenticated with PAP using a username
+	 * of "" and a password of "".  If that's not OK, boot it out.
+	 */
+	if (!wo->neg_upap || !null_login(unit)) {
+	    syslog(LOG_WARNING, "peer refused to authenticate");
+	    lcp_close(unit, "peer refused to authenticate");
+	    return;
+	}
+    }
+
+    phase = PHASE_AUTHENTICATE;
+    auth = 0;
+    if (go->neg_chap) {
+	ChapAuthPeer(unit, our_name, go->chap_mdtype);
+	auth |= CHAP_PEER;
+    } else if (go->neg_upap) {
+	upap_authpeer(unit);
+	auth |= PAP_PEER;
+    }
+    if (ho->neg_chap) {
+	ChapAuthWithPeer(unit, user, ho->chap_mdtype);
+	auth |= CHAP_WITHPEER;
+    } else if (ho->neg_upap) {
+	if (passwd[0] == 0) {
+	    passwd_from_file = 1;
+	    if (!get_pap_passwd(passwd))
+		syslog(LOG_ERR, "No secret found for PAP login");
+	}
+	upap_authwithpeer(unit, user, passwd);
+	auth |= PAP_WITHPEER;
+    }
+    auth_pending[unit] = auth;
+
+    if (!auth)
+	network_phase(unit);
+}
+
+/*
+ * Proceed to the network phase.
+ */
+static void
+network_phase(unit)
+    int unit;
+{
+    int i;
+    struct protent *protp;
+    
+#ifdef CBCP_SUPPORT
+    /*
+     * If we negotiated callback, do it now.
+     */
+    if (go->neg_cbcp) {
+	phase = PHASE_CALLBACK;
+	(*cbcp_protent.open)(unit);
+	return;
+    }
+#endif
+
+    phase = PHASE_NETWORK;
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        if (protp->protocol < 0xC000 && protp->enabled_flag
+	    && protp->open != NULL) {
+	    (*protp->open)(unit);
+	    if (protp->protocol != PPP_CCP)
+		++num_np_open;
+	}
+
+    if (num_np_open == 0)
+	/* nothing to do */
+	lcp_close(0, "No network protocols running");
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(unit, protocol)
+    int unit, protocol;
+{
+    /*
+     * Authentication failure: take the link down
+     */
+    lcp_close(unit, "Authentication failed");
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(unit, protocol, name, namelen)
+    int unit, protocol;
+    char *name;
+    int namelen;
+{
+    int bit;
+
+    switch (protocol) {
+    case PPP_CHAP:
+	bit = CHAP_PEER;
+	break;
+    case PPP_PAP:
+	bit = PAP_PEER;
+	break;
+    default:
+	syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+	       protocol);
+	return;
+    }
+
+    /*
+     * Save the authenticated name of the peer for later.
+     */
+    if (namelen > sizeof(peer_authname) - 1)
+	namelen = sizeof(peer_authname) - 1;
+    BCOPY(name, peer_authname, namelen);
+    peer_authname[namelen] = 0;
+
+    /*
+     * If we have overridden addresses based on auth info
+     * then set that information now before continuing.
+     */
+    auth_set_ip_addr(unit);
+
+    /*
+     * If there is no more authentication still to be done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~bit) == 0)
+        network_phase(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(unit, protocol)
+    int unit, protocol;
+{
+    if (passwd_from_file)
+	BZERO(passwd, MAXSECRETLEN);
+    /*
+     * We've failed to authenticate ourselves to our peer.
+     * He'll probably take the link down, and there's not much
+     * we can do except wait for that.
+     */
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(unit, protocol)
+    int unit, protocol;
+{
+    int bit;
+
+    switch (protocol) {
+    case PPP_CHAP:
+	bit = CHAP_WITHPEER;
+	break;
+    case PPP_PAP:
+	if (passwd_from_file)
+	    BZERO(passwd, MAXSECRETLEN);
+	bit = PAP_WITHPEER;
+	break;
+    default:
+	syslog(LOG_WARNING, "auth_peer_success: unknown protocol %x",
+	       protocol);
+	bit = 0;
+    }
+
+    /*
+     * If we have overridden addresses based on auth info
+     * then set that information now before continuing.
+     */
+    auth_set_ip_addr(unit);
+
+    /*
+     * If there is no more authentication still being done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~bit) == 0)
+	network_phase(unit);
+}
+
+
+/*
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(unit, proto)
+    int unit, proto;
+{
+    if (num_np_up == 0) {
+	/*
+	 * At this point we consider that the link has come up successfully.
+	 */
+	need_holdoff = 0;
+
+	if (idle_time_limit > 0)
+	    TIMEOUT(check_idle, NULL, idle_time_limit);
+
+	/*
+	 * Set a timeout to close the connection once the maximum
+	 * connect time has expired.
+	 */
+	if (maxconnect > 0)
+	    TIMEOUT(connect_time_expired, 0, maxconnect);
+
+    }
+    ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(unit, proto)
+    int unit, proto;
+{
+    if (--num_np_up == 0 && idle_time_limit > 0) {
+	UNTIMEOUT(check_idle, NULL);
+    }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(unit, proto)
+    int unit, proto;
+{
+    if (--num_np_open <= 0) {
+	/* no further use for the link: shut up shop. */
+	lcp_close(0, "No network protocols running");
+    }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(arg)
+     void *arg;
+{
+    struct ppp_idle idle;
+    time_t itime;
+
+    if (!get_idle_time(0, &idle))
+	return;
+    itime = MIN(idle.xmit_idle, idle.recv_idle);
+    if (itime >= idle_time_limit) {
+	/* link is idle: shut it down. */
+	syslog(LOG_INFO, "Terminating connection due to lack of activity.");
+	lcp_close(0, "Link inactive");
+    } else {
+	TIMEOUT(check_idle, NULL, idle_time_limit - itime);
+    }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(arg)
+    void *arg;
+{
+    syslog(LOG_INFO, "Connect time expired");
+    lcp_close(0, "Connect time expired");	/* Close connection */
+}
+
+/*
+ * auth_check_options - called to check authentication options.
+ */
+void
+auth_check_options()
+{
+    lcp_options *wo = &lcp_wantoptions[0];
+    int can_auth;
+    ipcp_options *ipwo = &ipcp_wantoptions[0];
+    u_int32_t remote;
+
+    /* Default our_name to hostname, and user to our_name */
+    if (our_name[0] == 0 || usehostname)
+	strcpy(our_name, cyg_ppp_hostname);
+    if (user[0] == 0)
+	strcpy(user, our_name);
+
+    /* If authentication is required, ask peer for CHAP or PAP. */
+    if (auth_required && !wo->neg_chap && !wo->neg_upap) {
+	wo->neg_chap = 1;
+	wo->neg_upap = 1;
+    }
+
+    /*
+     * Check whether we have appropriate secrets to use
+     * to authenticate the peer.
+     */
+    can_auth = wo->neg_upap && (uselogin || have_pap_secret());
+    if (!can_auth && wo->neg_chap) {
+	remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+	can_auth = have_chap_secret(remote_name, our_name, remote);
+    }
+
+    if (auth_required && !can_auth) {
+	option_error("peer authentication required but no suitable secret(s) found\n");
+	if (remote_name[0] == 0)
+	    option_error("for authenticating any peer to us (%s)\n", our_name);
+	else
+	    option_error("for authenticating peer %s to us (%s)\n",
+			 remote_name, our_name);
+	exit(1);
+    }
+
+    /*
+     * Check whether the user tried to override certain values
+     * set by root.
+     */
+    if (!auth_required && auth_req_info.priv > 0) {
+	if (!default_device && devnam_info.priv == 0) {
+	    option_error("can't override device name when noauth option used");
+	    exit(1);
+	}
+	if ((connector != NULL && connector_info.priv == 0)
+	    || (disconnector != NULL && disconnector_info.priv == 0)
+	    || (welcomer != NULL && welcomer_info.priv == 0)) {
+	    option_error("can't override connect, disconnect or welcome");
+	    option_error("option values when noauth option used");
+	    exit(1);
+	}
+    }
+}
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void
+auth_reset(unit)
+    int unit;
+{
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[0];
+    ipcp_options *ipwo = &ipcp_wantoptions[0];
+    u_int32_t remote;
+    ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
+    ao->neg_chap = !refuse_chap
+	&& have_chap_secret(user, remote_name, (u_int32_t)0);
+    if (go->neg_upap && !uselogin && !have_pap_secret())
+	go->neg_upap = 0;
+    if (go->neg_chap) {
+	remote = ipwo->accept_remote? 0: ipwo->hisaddr;
+	if (!have_chap_secret(remote_name, our_name, remote))
+	    go->neg_chap = 0;
+    }
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file.  If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ *	UPAP_AUTHNAK: Authentication failed.
+ *	UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(unit, auser, userlen, apasswd, passwdlen, msg, msglen)
+    int unit;
+    char *auser;
+    int userlen;
+    char *apasswd;
+    int passwdlen;
+    char **msg;
+    int *msglen;
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return 0;
+}
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int
+null_login(unit)
+    int unit;
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return 0;
+}
+
+
+/*
+ * get_pap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password
+ * could be found.
+ */
+static int
+get_pap_passwd(passwd)
+    char *passwd;
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return 0;
+}
+
+
+/*
+ * have_pap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_pap_secret()
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return 0;
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'.  Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(client, server, remote)
+    char *client;
+    char *server;
+    u_int32_t remote;
+{
+//    db_printf("%s(%s,%s,%d) called\n", __PRETTY_FUNCTION__,client,server,remote);
+    return 1;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(unit, client, server, secret, secret_len, save_addrs)
+    int unit;
+    char *client;
+    char *server;
+    char *secret;
+    int *secret_len;
+    int save_addrs;
+{
+    db_printf("%s(%d,%s,%s,%08x,%d,%d) called\n", __PRETTY_FUNCTION__,
+                unit, client, server, secret, secret_len, save_addrs);
+    // We use the PAP password as the CHAP secret also.
+    strncpy( secret, passwd, MAXNAMELEN );
+    *secret_len = strlen(secret);
+    return 1;
+}
+
+static void
+auth_set_ip_addr(unit)
+    int unit;
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address.  Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(unit, addr)
+    int unit;
+    u_int32_t addr;
+{
+    return ip_addr_check(addr, addresses[unit]);
+}
+
+static int
+ip_addr_check(addr, addrs)
+    u_int32_t addr;
+    struct wordlist *addrs;
+{
+    int x, y;
+//    u_int32_t a, mask, ah;
+    u_int32_t a = -1, mask;    
+    int accept;
+    char *ptr_word, *ptr_mask;
+//    struct hostent *hp;
+//    struct netent *np;
+
+    /* don't allow loopback or multicast address */
+    if (bad_ip_adrs(addr))
+	return 0;
+
+    if (addrs == NULL)
+	return !auth_required;		/* no addresses authorized */
+
+    x = y = 0;
+    for (; addrs != NULL; addrs = addrs->next) {
+	y++;
+	/* "-" means no addresses authorized, "*" means any address allowed */
+	ptr_word = addrs->word;
+	if (strcmp(ptr_word, "-") == 0)
+	    break;
+	if (strcmp(ptr_word, "*") == 0)
+	    return 1;
+
+	/*
+	 * A colon in the string means that we wish to force a specific
+	 * local:remote address, but we ignore these for now.
+	 */
+	if (strchr(addrs->word, ':') != NULL)
+	    x++;
+	else {
+
+	accept = 1;
+	if (*ptr_word == '!') {
+	    accept = 0;
+	    ++ptr_word;
+	}
+
+	mask = ~ (u_int32_t) 0;
+	ptr_mask = strchr (ptr_word, '/');
+	if (ptr_mask != NULL) {
+	    int bit_count;
+
+	    bit_count = (int) strtol (ptr_mask+1, (char **) 0, 10);
+	    if (bit_count <= 0 || bit_count > 32) {
+		syslog (LOG_WARNING,
+			"invalid address length %s in auth. address list",
+			ptr_mask);
+		continue;
+	    }
+	    *ptr_mask = '\0';
+	    mask <<= 32 - bit_count;
+	}
+
+#ifndef __ECOS
+	hp = gethostbyname(ptr_word);
+	if (hp != NULL && hp->h_addrtype == AF_INET) {
+	    a = *(u_int32_t *)hp->h_addr;
+	} else {
+	    np = getnetbyname (ptr_word);
+	    if (np != NULL && np->n_addrtype == AF_INET) {
+		a = htonl (*(u_int32_t *)np->n_net);
+		if (ptr_mask == NULL) {
+		    /* calculate appropriate mask for net */
+		    ah = ntohl(a);
+		    if (IN_CLASSA(ah))
+			mask = IN_CLASSA_NET;
+		    else if (IN_CLASSB(ah))
+			mask = IN_CLASSB_NET;
+		    else if (IN_CLASSC(ah))
+			mask = IN_CLASSC_NET;
+		}
+	    } else {
+		a = inet_addr (ptr_word);
+	    }
+	}
+#endif
+        
+	if (ptr_mask != NULL)
+	    *ptr_mask = '/';
+
+	if (a == (u_int32_t)-1L)
+	    syslog (LOG_WARNING,
+		    "unknown host %s in auth. address list",
+		    addrs->word);
+	else
+	    /* Here a and addr are in network byte order,
+	       and mask is in host order. */
+	    if (((addr ^ a) & htonl(mask)) == 0)
+		return accept;
+    }	/* else */
+    }
+    return x == y;			/* not in list => can't have it */
+}
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int
+bad_ip_adrs(addr)
+    u_int32_t addr;
+{
+    addr = ntohl(addr);
+    return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+	|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+/*
+ * check_access - complain if a secret file has too-liberal permissions.
+ */
+void
+check_access(f, filename)
+    FILE *f;
+    char *filename;
+{
+    struct stat sbuf;
+
+    if (fstat(fileno(f), &sbuf) < 0) {
+	syslog(LOG_WARNING, "cannot stat secret file %s: %m", filename);
+    } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
+	syslog(LOG_WARNING, "Warning - secret file %s has world and/or group access", filename);
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/bsd_comp.c
@@ -0,0 +1,1160 @@
+//==========================================================================
+//
+//      src/bsd_comp.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/* Because this code is derived from the 4.3BSD compress source:
+ *
+ *
+ * Copyright (c) 1985, 1986 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * James A. Woods, derived from original work by Spencer Thomas
+ * and Joseph Orost.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This version is for use with mbufs on BSD-derived systems.
+ *
+ * $FreeBSD: src/sys/net/bsd_comp.c,v 1.11 1999/08/28 00:48:14 peter Exp $
+ */
+
+#define _KERNEL
+
+#include <sys/param.h>
+//#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <cyg/ppp/net/ppp_defs.h>
+
+#define PACKETPTR	struct mbuf *
+#include <cyg/ppp/net/ppp_comp.h>
+
+#if DO_BSD_COMPRESS
+/*
+ * PPP "BSD compress" compression
+ *  The differences between this compression and the classic BSD LZW
+ *  source are obvious from the requirement that the classic code worked
+ *  with files while this handles arbitrarily long streams that
+ *  are broken into packets.  They are:
+ *
+ *	When the code size expands, a block of junk is not emitted by
+ *	    the compressor and not expected by the decompressor.
+ *
+ *	New codes are not necessarily assigned every time an old
+ *	    code is output by the compressor.  This is because a packet
+ *	    end forces a code to be emitted, but does not imply that a
+ *	    new sequence has been seen.
+ *
+ *	The compression ratio is checked at the first end of a packet
+ *	    after the appropriate gap.	Besides simplifying and speeding
+ *	    things up, this makes it more likely that the transmitter
+ *	    and receiver will agree when the dictionary is cleared when
+ *	    compression is not going well.
+ */
+
+/*
+ * A dictionary for doing BSD compress.
+ */
+struct bsd_db {
+    int	    totlen;			/* length of this structure */
+    u_int   hsize;			/* size of the hash table */
+    u_char  hshift;			/* used in hash function */
+    u_char  n_bits;			/* current bits/code */
+    u_char  maxbits;
+    u_char  debug;
+    u_char  unit;
+    u_int16_t seqno;			/* sequence # of next packet */
+    u_int   hdrlen;			/* header length to preallocate */
+    u_int   mru;
+    u_int   maxmaxcode;			/* largest valid code */
+    u_int   max_ent;			/* largest code in use */
+    u_int   in_count;			/* uncompressed bytes, aged */
+    u_int   bytes_out;			/* compressed bytes, aged */
+    u_int   ratio;			/* recent compression ratio */
+    u_int   checkpoint;			/* when to next check the ratio */
+    u_int   clear_count;		/* times dictionary cleared */
+    u_int   incomp_count;		/* incompressible packets */
+    u_int   incomp_bytes;		/* incompressible bytes */
+    u_int   uncomp_count;		/* uncompressed packets */
+    u_int   uncomp_bytes;		/* uncompressed bytes */
+    u_int   comp_count;			/* compressed packets */
+    u_int   comp_bytes;			/* compressed bytes */
+    u_int16_t *lens;			/* array of lengths of codes */
+    struct bsd_dict {
+	union {				/* hash value */
+	    u_int32_t	fcode;
+	    struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+		u_int16_t prefix;	/* preceding code */
+		u_char	suffix;		/* last character of new code */
+		u_char	pad;
+#else
+		u_char	pad;
+		u_char	suffix;		/* last character of new code */
+		u_int16_t prefix;	/* preceding code */
+#endif
+	    } hs;
+	} f;
+	u_int16_t codem1;		/* output of hash table -1 */
+	u_int16_t cptr;			/* map code to hash table entry */
+    } dict[1];
+};
+
+#define BSD_OVHD	2		/* BSD compress overhead/packet */
+#define BSD_INIT_BITS	BSD_MIN_BITS
+
+static void	bsd_clear __P((struct bsd_db *db));
+static int	bsd_check __P((struct bsd_db *db));
+static void	*bsd_alloc __P((u_char *options, int opt_len, int decomp));
+static int	bsd_init __P((struct bsd_db *db, u_char *options, int opt_len,
+			      int unit, int hdrlen, int mru, int debug,
+			      int decomp));
+static void	*bsd_comp_alloc __P((u_char *options, int opt_len));
+static void	*bsd_decomp_alloc __P((u_char *options, int opt_len));
+static void	bsd_free __P((void *state));
+static int	bsd_comp_init __P((void *state, u_char *options, int opt_len,
+				   int unit, int hdrlen, int debug));
+static int	bsd_decomp_init __P((void *state, u_char *options, int opt_len,
+				     int unit, int hdrlen, int mru, int debug));
+static int	bsd_compress __P((void *state, struct mbuf **mret,
+				  struct mbuf *mp, int slen, int maxolen));
+static void	bsd_incomp __P((void *state, struct mbuf *dmsg));
+static int	bsd_decompress __P((void *state, struct mbuf *cmp,
+				    struct mbuf **dmpp));
+static void	bsd_reset __P((void *state));
+static void	bsd_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+struct compressor ppp_bsd_compress = {
+    CI_BSD_COMPRESS,		/* compress_proto */
+    bsd_comp_alloc,		/* comp_alloc */
+    bsd_free,			/* comp_free */
+    bsd_comp_init,		/* comp_init */
+    bsd_reset,			/* comp_reset */
+    bsd_compress,		/* compress */
+    bsd_comp_stats,		/* comp_stat */
+    bsd_decomp_alloc,		/* decomp_alloc */
+    bsd_free,			/* decomp_free */
+    bsd_decomp_init,		/* decomp_init */
+    bsd_reset,			/* decomp_reset */
+    bsd_decompress,		/* decompress */
+    bsd_incomp,			/* incomp */
+    bsd_comp_stats,		/* decomp_stat */
+};
+
+/*
+ * the next two codes should not be changed lightly, as they must not
+ * lie within the contiguous general code space.
+ */
+#define CLEAR	256			/* table clear output code */
+#define FIRST	257			/* first free entry */
+#define LAST	255
+
+#define MAXCODE(b)	((1 << (b)) - 1)
+#define BADCODEM1	MAXCODE(BSD_MAX_BITS)
+
+#define BSD_HASH(prefix,suffix,hshift)	((((u_int32_t)(suffix)) << (hshift)) \
+					 ^ (u_int32_t)(prefix))
+#define BSD_KEY(prefix,suffix)		((((u_int32_t)(suffix)) << 16) \
+					 + (u_int32_t)(prefix))
+
+#define CHECK_GAP	10000		/* Ratio check interval */
+
+#define RATIO_SCALE_LOG	8
+#define RATIO_SCALE	(1<<RATIO_SCALE_LOG)
+#define RATIO_MAX	(0x7fffffff>>RATIO_SCALE_LOG)
+
+/*
+ * clear the dictionary
+ */
+static void
+bsd_clear(db)
+    struct bsd_db *db;
+{
+    db->clear_count++;
+    db->max_ent = FIRST-1;
+    db->n_bits = BSD_INIT_BITS;
+    db->ratio = 0;
+    db->bytes_out = 0;
+    db->in_count = 0;
+    db->checkpoint = CHECK_GAP;
+}
+
+/*
+ * If the dictionary is full, then see if it is time to reset it.
+ *
+ * Compute the compression ratio using fixed-point arithmetic
+ * with 8 fractional bits.
+ *
+ * Since we have an infinite stream instead of a single file,
+ * watch only the local compression ratio.
+ *
+ * Since both peers must reset the dictionary at the same time even in
+ * the absence of CLEAR codes (while packets are incompressible), they
+ * must compute the same ratio.
+ */
+static int				/* 1=output CLEAR */
+bsd_check(db)
+    struct bsd_db *db;
+{
+    u_int new_ratio;
+
+    if (db->in_count >= db->checkpoint) {
+	/* age the ratio by limiting the size of the counts */
+	if (db->in_count >= RATIO_MAX
+	    || db->bytes_out >= RATIO_MAX) {
+	    db->in_count -= db->in_count/4;
+	    db->bytes_out -= db->bytes_out/4;
+	}
+
+	db->checkpoint = db->in_count + CHECK_GAP;
+
+	if (db->max_ent >= db->maxmaxcode) {
+	    /* Reset the dictionary only if the ratio is worse,
+	     * or if it looks as if it has been poisoned
+	     * by incompressible data.
+	     *
+	     * This does not overflow, because
+	     *	db->in_count <= RATIO_MAX.
+	     */
+	    new_ratio = db->in_count << RATIO_SCALE_LOG;
+	    if (db->bytes_out != 0)
+		new_ratio /= db->bytes_out;
+
+	    if (new_ratio < db->ratio || new_ratio < 1 * RATIO_SCALE) {
+		bsd_clear(db);
+		return 1;
+	    }
+	    db->ratio = new_ratio;
+	}
+    }
+    return 0;
+}
+
+/*
+ * Return statistics.
+ */
+static void
+bsd_comp_stats(state, stats)
+    void *state;
+    struct compstat *stats;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+    u_int out;
+
+    stats->unc_bytes = db->uncomp_bytes;
+    stats->unc_packets = db->uncomp_count;
+    stats->comp_bytes = db->comp_bytes;
+    stats->comp_packets = db->comp_count;
+    stats->inc_bytes = db->incomp_bytes;
+    stats->inc_packets = db->incomp_count;
+    stats->ratio = db->in_count;
+    out = db->bytes_out;
+    if (stats->ratio <= 0x7fffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->ratio /= out;
+}
+
+/*
+ * Reset state, as on a CCP ResetReq.
+ */
+static void
+bsd_reset(state)
+    void *state;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    db->seqno = 0;
+    bsd_clear(db);
+    db->clear_count = 0;
+}
+
+/*
+ * Allocate space for a (de) compressor.
+ */
+static void *
+bsd_alloc(options, opt_len, decomp)
+    u_char *options;
+    int opt_len, decomp;
+{
+    int bits;
+    u_int newlen, hsize, hshift, maxmaxcode;
+    struct bsd_db *db;
+
+    if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
+	|| options[1] != CILEN_BSD_COMPRESS
+	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION)
+	return NULL;
+    bits = BSD_NBITS(options[2]);
+    switch (bits) {
+    case 9:			/* needs 82152 for both directions */
+    case 10:			/* needs 84144 */
+    case 11:			/* needs 88240 */
+    case 12:			/* needs 96432 */
+	hsize = 5003;
+	hshift = 4;
+	break;
+    case 13:			/* needs 176784 */
+	hsize = 9001;
+	hshift = 5;
+	break;
+    case 14:			/* needs 353744 */
+	hsize = 18013;
+	hshift = 6;
+	break;
+    case 15:			/* needs 691440 */
+	hsize = 35023;
+	hshift = 7;
+	break;
+    case 16:			/* needs 1366160--far too much, */
+	/* hsize = 69001; */	/* and 69001 is too big for cptr */
+	/* hshift = 8; */	/* in struct bsd_db */
+	/* break; */
+    default:
+	return NULL;
+    }
+
+    maxmaxcode = MAXCODE(bits);
+    newlen = sizeof(*db) + (hsize-1) * (sizeof(db->dict[0]));
+    MALLOC(db, struct bsd_db *, newlen, M_DEVBUF, M_NOWAIT);
+    if (!db)
+	return NULL;
+    bzero(db, sizeof(*db) - sizeof(db->dict));
+
+    if (!decomp) {
+	db->lens = NULL;
+    } else {
+	MALLOC(db->lens, u_int16_t *, (maxmaxcode+1) * sizeof(db->lens[0]),
+	       M_DEVBUF, M_NOWAIT);
+	if (!db->lens) {
+	    FREE(db, M_DEVBUF);
+	    return NULL;
+	}
+    }
+
+    db->totlen = newlen;
+    db->hsize = hsize;
+    db->hshift = hshift;
+    db->maxmaxcode = maxmaxcode;
+    db->maxbits = bits;
+
+    return (void *) db;
+}
+
+static void
+bsd_free(state)
+    void *state;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+
+    if (db->lens)
+	FREE(db->lens, M_DEVBUF);
+    FREE(db, M_DEVBUF);
+}
+
+static void *
+bsd_comp_alloc(options, opt_len)
+    u_char *options;
+    int opt_len;
+{
+    return bsd_alloc(options, opt_len, 0);
+}
+
+static void *
+bsd_decomp_alloc(options, opt_len)
+    u_char *options;
+    int opt_len;
+{
+    return bsd_alloc(options, opt_len, 1);
+}
+
+/*
+ * Initialize the database.
+ */
+static int
+bsd_init(db, options, opt_len, unit, hdrlen, mru, debug, decomp)
+    struct bsd_db *db;
+    u_char *options;
+    int opt_len, unit, hdrlen, mru, debug, decomp;
+{
+    int i;
+
+    if (opt_len < CILEN_BSD_COMPRESS || options[0] != CI_BSD_COMPRESS
+	|| options[1] != CILEN_BSD_COMPRESS
+	|| BSD_VERSION(options[2]) != BSD_CURRENT_VERSION
+	|| BSD_NBITS(options[2]) != db->maxbits
+	|| (decomp && db->lens == NULL))
+	return 0;
+
+    if (decomp) {
+	i = LAST+1;
+	while (i != 0)
+	    db->lens[--i] = 1;
+    }
+    i = db->hsize;
+    while (i != 0) {
+	db->dict[--i].codem1 = BADCODEM1;
+	db->dict[i].cptr = 0;
+    }
+
+    db->unit = unit;
+    db->hdrlen = hdrlen;
+    db->mru = mru;
+#ifndef DEBUG
+    if (debug)
+#endif
+	db->debug = 1;
+
+    bsd_reset(db);
+
+    return 1;
+}
+
+static int
+bsd_comp_init(state, options, opt_len, unit, hdrlen, debug)
+    void *state;
+    u_char *options;
+    int opt_len, unit, hdrlen, debug;
+{
+    return bsd_init((struct bsd_db *) state, options, opt_len,
+		    unit, hdrlen, 0, debug, 0);
+}
+
+static int
+bsd_decomp_init(state, options, opt_len, unit, hdrlen, mru, debug)
+    void *state;
+    u_char *options;
+    int opt_len, unit, hdrlen, mru, debug;
+{
+    return bsd_init((struct bsd_db *) state, options, opt_len,
+		    unit, hdrlen, mru, debug, 1);
+}
+
+
+/*
+ * compress a packet
+ *	One change from the BSD compress command is that when the
+ *	code size expands, we do not output a bunch of padding.
+ */
+int					/* new slen */
+bsd_compress(state, mret, mp, slen, maxolen)
+    void *state;
+    struct mbuf **mret;		/* return compressed mbuf chain here */
+    struct mbuf *mp;		/* from here */
+    int slen;			/* uncompressed length */
+    int maxolen;		/* max compressed length */
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+    int hshift = db->hshift;
+    u_int max_ent = db->max_ent;
+    u_int n_bits = db->n_bits;
+    u_int bitno = 32;
+    u_int32_t accm = 0, fcode;
+    struct bsd_dict *dictp;
+    u_char c;
+    int hval, disp, ent, ilen;
+    u_char *rptr, *wptr;
+    u_char *cp_end;
+    int olen;
+    struct mbuf *m;
+
+#define PUTBYTE(v) {					\
+    ++olen;						\
+    if (wptr) {						\
+	*wptr++ = (v);					\
+	if (wptr >= cp_end) {				\
+	    m->m_len = wptr - mtod(m, u_char *);	\
+	    MGET(m->m_next, M_DONTWAIT, MT_DATA);	\
+	    m = m->m_next;				\
+	    if (m) {					\
+		m->m_len = 0;				\
+		if (maxolen - olen > MLEN)		\
+		    MCLGET(m, M_DONTWAIT);		\
+		wptr = mtod(m, u_char *);		\
+		cp_end = wptr + M_TRAILINGSPACE(m);	\
+	    } else					\
+		wptr = NULL;				\
+	}						\
+    }							\
+}
+
+#define OUTPUT(ent) {					\
+    bitno -= n_bits;					\
+    accm |= ((ent) << bitno);				\
+    do {						\
+	PUTBYTE(accm >> 24);				\
+	accm <<= 8;					\
+	bitno += 8;					\
+    } while (bitno <= 24);				\
+}
+
+    /*
+     * If the protocol is not in the range we're interested in,
+     * just return without compressing the packet.  If it is,
+     * the protocol becomes the first byte to compress.
+     */
+    rptr = mtod(mp, u_char *);
+    ent = PPP_PROTOCOL(rptr);
+    if (ent < 0x21 || ent > 0xf9) {
+	*mret = NULL;
+	return slen;
+    }
+
+    /* Don't generate compressed packets which are larger than
+       the uncompressed packet. */
+    if (maxolen > slen)
+	maxolen = slen;
+
+    /* Allocate one mbuf to start with. */
+    MGET(m, M_DONTWAIT, MT_DATA);
+    *mret = m;
+    if (m != NULL) {
+	m->m_len = 0;
+	if (maxolen + db->hdrlen > MLEN)
+	    MCLGET(m, M_DONTWAIT);
+	m->m_data += db->hdrlen;
+	wptr = mtod(m, u_char *);
+	cp_end = wptr + M_TRAILINGSPACE(m);
+    } else
+	wptr = cp_end = NULL;
+
+    /*
+     * Copy the PPP header over, changing the protocol,
+     * and install the 2-byte packet sequence number.
+     */
+    if (wptr) {
+	*wptr++ = PPP_ADDRESS(rptr);	/* assumes the ppp header is */
+	*wptr++ = PPP_CONTROL(rptr);	/* all in one mbuf */
+	*wptr++ = 0;			/* change the protocol */
+	*wptr++ = PPP_COMP;
+	*wptr++ = db->seqno >> 8;
+	*wptr++ = db->seqno;
+    }
+    ++db->seqno;
+
+    olen = 0;
+    rptr += PPP_HDRLEN;
+    slen = mp->m_len - PPP_HDRLEN;
+    ilen = slen + 1;
+    for (;;) {
+	if (slen <= 0) {
+	    mp = mp->m_next;
+	    if (!mp)
+		break;
+	    rptr = mtod(mp, u_char *);
+	    slen = mp->m_len;
+	    if (!slen)
+		continue;   /* handle 0-length buffers */
+	    ilen += slen;
+	}
+
+	slen--;
+	c = *rptr++;
+	fcode = BSD_KEY(ent, c);
+	hval = BSD_HASH(ent, c, hshift);
+	dictp = &db->dict[hval];
+
+	/* Validate and then check the entry. */
+	if (dictp->codem1 >= max_ent)
+	    goto nomatch;
+	if (dictp->f.fcode == fcode) {
+	    ent = dictp->codem1+1;
+	    continue;	/* found (prefix,suffix) */
+	}
+
+	/* continue probing until a match or invalid entry */
+	disp = (hval == 0) ? 1 : hval;
+	do {
+	    hval += disp;
+	    if (hval >= db->hsize)
+		hval -= db->hsize;
+	    dictp = &db->dict[hval];
+	    if (dictp->codem1 >= max_ent)
+		goto nomatch;
+	} while (dictp->f.fcode != fcode);
+	ent = dictp->codem1 + 1;	/* finally found (prefix,suffix) */
+	continue;
+
+    nomatch:
+	OUTPUT(ent);		/* output the prefix */
+
+	/* code -> hashtable */
+	if (max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    /* expand code size if needed */
+	    if (max_ent >= MAXCODE(n_bits))
+		db->n_bits = ++n_bits;
+
+	    /* Invalidate old hash table entry using
+	     * this code, and then take it over.
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent)
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	}
+	ent = c;
+    }
+
+    OUTPUT(ent);		/* output the last code */
+    db->bytes_out += olen;
+    db->in_count += ilen;
+    if (bitno < 32)
+	++db->bytes_out;	/* count complete bytes */
+
+    if (bsd_check(db))
+	OUTPUT(CLEAR);		/* do not count the CLEAR */
+
+    /*
+     * Pad dribble bits of last code with ones.
+     * Do not emit a completely useless byte of ones.
+     */
+    if (bitno != 32)
+	PUTBYTE((accm | (0xff << (bitno-8))) >> 24);
+
+    if (m != NULL) {
+	m->m_len = wptr - mtod(m, u_char *);
+	m->m_next = NULL;
+    }
+
+    /*
+     * Increase code size if we would have without the packet
+     * boundary and as the decompressor will.
+     */
+    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	db->n_bits++;
+
+    db->uncomp_bytes += ilen;
+    ++db->uncomp_count;
+    if (olen + PPP_HDRLEN + BSD_OVHD > maxolen) {
+	/* throw away the compressed stuff if it is longer than uncompressed */
+	if (*mret != NULL) {
+	    m_freem(*mret);
+	    *mret = NULL;
+	}
+	++db->incomp_count;
+	db->incomp_bytes += ilen;
+    } else {
+	++db->comp_count;
+	db->comp_bytes += olen + BSD_OVHD;
+    }
+
+    return olen + PPP_HDRLEN + BSD_OVHD;
+#undef OUTPUT
+#undef PUTBYTE
+}
+
+
+/*
+ * Update the "BSD Compress" dictionary on the receiver for
+ * incompressible data by pretending to compress the incoming data.
+ */
+static void
+bsd_incomp(state, dmsg)
+    void *state;
+    struct mbuf *dmsg;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+    u_int hshift = db->hshift;
+    u_int max_ent = db->max_ent;
+    u_int n_bits = db->n_bits;
+    struct bsd_dict *dictp;
+    u_int32_t fcode;
+    u_char c;
+    u_int32_t hval, disp;
+    int slen, ilen;
+    u_int bitno = 7;
+    u_char *rptr;
+    u_int ent;
+
+    /*
+     * If the protocol is not in the range we're interested in,
+     * just return without looking at the packet.  If it is,
+     * the protocol becomes the first byte to "compress".
+     */
+    rptr = mtod(dmsg, u_char *);
+    ent = PPP_PROTOCOL(rptr);
+    if (ent < 0x21 || ent > 0xf9)
+	return;
+
+    db->seqno++;
+    ilen = 1;		/* count the protocol as 1 byte */
+    rptr += PPP_HDRLEN;
+    slen = dmsg->m_len - PPP_HDRLEN;
+    for (;;) {
+	if (slen <= 0) {
+	    dmsg = dmsg->m_next;
+	    if (!dmsg)
+		break;
+	    rptr = mtod(dmsg, u_char *);
+	    slen = dmsg->m_len;
+	    continue;
+	}
+	ilen += slen;
+
+	do {
+	    c = *rptr++;
+	    fcode = BSD_KEY(ent, c);
+	    hval = BSD_HASH(ent, c, hshift);
+	    dictp = &db->dict[hval];
+
+	    /* validate and then check the entry */
+	    if (dictp->codem1 >= max_ent)
+		goto nomatch;
+	    if (dictp->f.fcode == fcode) {
+		ent = dictp->codem1+1;
+		continue;   /* found (prefix,suffix) */
+	    }
+
+	    /* continue probing until a match or invalid entry */
+	    disp = (hval == 0) ? 1 : hval;
+	    do {
+		hval += disp;
+		if (hval >= db->hsize)
+		    hval -= db->hsize;
+		dictp = &db->dict[hval];
+		if (dictp->codem1 >= max_ent)
+		    goto nomatch;
+	    } while (dictp->f.fcode != fcode);
+	    ent = dictp->codem1+1;
+	    continue;	/* finally found (prefix,suffix) */
+
+	nomatch:		/* output (count) the prefix */
+	    bitno += n_bits;
+
+	    /* code -> hashtable */
+	    if (max_ent < db->maxmaxcode) {
+		struct bsd_dict *dictp2;
+		/* expand code size if needed */
+		if (max_ent >= MAXCODE(n_bits))
+		    db->n_bits = ++n_bits;
+
+		/* Invalidate previous hash table entry
+		 * assigned this code, and then take it over.
+		 */
+		dictp2 = &db->dict[max_ent+1];
+		if (db->dict[dictp2->cptr].codem1 == max_ent)
+		    db->dict[dictp2->cptr].codem1 = BADCODEM1;
+		dictp2->cptr = hval;
+		dictp->codem1 = max_ent;
+		dictp->f.fcode = fcode;
+
+		db->max_ent = ++max_ent;
+		db->lens[max_ent] = db->lens[ent]+1;
+	    }
+	    ent = c;
+	} while (--slen != 0);
+    }
+    bitno += n_bits;		/* output (count) the last code */
+    db->bytes_out += bitno/8;
+    db->in_count += ilen;
+    (void)bsd_check(db);
+
+    ++db->incomp_count;
+    db->incomp_bytes += ilen;
+    ++db->uncomp_count;
+    db->uncomp_bytes += ilen;
+
+    /* Increase code size if we would have without the packet
+     * boundary and as the decompressor will.
+     */
+    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode)
+	db->n_bits++;
+}
+
+
+/*
+ * Decompress "BSD Compress".
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression.  For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+int
+bsd_decompress(state, cmp, dmpp)
+    void *state;
+    struct mbuf *cmp, **dmpp;
+{
+    struct bsd_db *db = (struct bsd_db *) state;
+    u_int max_ent = db->max_ent;
+    u_int32_t accm = 0;
+    u_int bitno = 32;		/* 1st valid bit in accm */
+    u_int n_bits = db->n_bits;
+    u_int tgtbitno = 32-n_bits;	/* bitno when we have a code */
+    struct bsd_dict *dictp;
+    int explen, i, seq, len;
+    u_int incode, oldcode, finchar;
+    u_char *p, *rptr, *wptr;
+    struct mbuf *m, *dmp, *mret;
+    int adrs, ctrl, ilen;
+    int space, codelen, extra;
+
+    /*
+     * Save the address/control from the PPP header
+     * and then get the sequence number.
+     */
+    *dmpp = NULL;
+    rptr = mtod(cmp, u_char *);
+    adrs = PPP_ADDRESS(rptr);
+    ctrl = PPP_CONTROL(rptr);
+    rptr += PPP_HDRLEN;
+    len = cmp->m_len - PPP_HDRLEN;
+    seq = 0;
+    for (i = 0; i < 2; ++i) {
+	while (len <= 0) {
+	    cmp = cmp->m_next;
+	    if (cmp == NULL)
+		return DECOMP_ERROR;
+	    rptr = mtod(cmp, u_char *);
+	    len = cmp->m_len;
+	}
+	seq = (seq << 8) + *rptr++;
+	--len;
+    }
+
+    /*
+     * Check the sequence number and give up if it differs from
+     * the value we're expecting.
+     */
+    if (seq != db->seqno) {
+	if (db->debug)
+	    printf("bsd_decomp%d: bad sequence # %d, expected %d\n",
+		   db->unit, seq, db->seqno - 1);
+	return DECOMP_ERROR;
+    }
+    ++db->seqno;
+
+    /*
+     * Allocate one mbuf to start with.
+     */
+    MGETHDR(dmp, M_DONTWAIT, MT_DATA);
+    if (dmp == NULL)
+	return DECOMP_ERROR;
+    mret = dmp;
+    dmp->m_len = 0;
+    dmp->m_next = NULL;
+    MCLGET(dmp, M_DONTWAIT);
+    dmp->m_data += db->hdrlen;
+    wptr = mtod(dmp, u_char *);
+    space = M_TRAILINGSPACE(dmp) - PPP_HDRLEN + 1;
+
+    /*
+     * Fill in the ppp header, but not the last byte of the protocol
+     * (that comes from the decompressed data).
+     */
+    wptr[0] = adrs;
+    wptr[1] = ctrl;
+    wptr[2] = 0;
+    wptr += PPP_HDRLEN - 1;
+
+    ilen = len;
+    oldcode = CLEAR;
+    explen = 0;
+    for (;;) {
+	if (len == 0) {
+	    cmp = cmp->m_next;
+	    if (!cmp)		/* quit at end of message */
+		break;
+	    rptr = mtod(cmp, u_char *);
+	    len = cmp->m_len;
+	    ilen += len;
+	    continue;		/* handle 0-length buffers */
+	}
+
+	/*
+	 * Accumulate bytes until we have a complete code.
+	 * Then get the next code, relying on the 32-bit,
+	 * unsigned accm to mask the result.
+	 */
+	bitno -= 8;
+	accm |= *rptr++ << bitno;
+	--len;
+	if (tgtbitno < bitno)
+	    continue;
+	incode = accm >> tgtbitno;
+	accm <<= n_bits;
+	bitno += n_bits;
+
+	if (incode == CLEAR) {
+	    /*
+	     * The dictionary must only be cleared at
+	     * the end of a packet.  But there could be an
+	     * empty mbuf at the end.
+	     */
+	    if (len > 0 || cmp->m_next != NULL) {
+		while ((cmp = cmp->m_next) != NULL)
+		    len += cmp->m_len;
+		if (len > 0) {
+		    m_freem(mret);
+		    if (db->debug)
+			printf("bsd_decomp%d: bad CLEAR\n", db->unit);
+		    return DECOMP_FATALERROR;	/* probably a bug */
+		}
+	    }
+	    bsd_clear(db);
+	    explen = ilen = 0;
+	    break;
+	}
+
+	if (incode > max_ent + 2 || incode > db->maxmaxcode
+	    || (incode > max_ent && oldcode == CLEAR)) {
+	    m_freem(mret);
+	    if (db->debug) {
+		printf("bsd_decomp%d: bad code 0x%x oldcode=0x%x ",
+		       db->unit, incode, oldcode);
+		printf("max_ent=0x%x explen=%d seqno=%d\n",
+		       max_ent, explen, db->seqno);
+	    }
+	    return DECOMP_FATALERROR;	/* probably a bug */
+	}
+
+	/* Special case for KwKwK string. */
+	if (incode > max_ent) {
+	    finchar = oldcode;
+	    extra = 1;
+	} else {
+	    finchar = incode;
+	    extra = 0;
+	}
+
+	codelen = db->lens[finchar];
+	explen += codelen + extra;
+	if (explen > db->mru + 1) {
+	    m_freem(mret);
+	    if (db->debug) {
+		printf("bsd_decomp%d: ran out of mru\n", db->unit);
+#ifdef DEBUG
+		while ((cmp = cmp->m_next) != NULL)
+		    len += cmp->m_len;
+		printf("  len=%d, finchar=0x%x, codelen=%d, explen=%d\n",
+		       len, finchar, codelen, explen);
+#endif
+	    }
+	    return DECOMP_FATALERROR;
+	}
+
+	/*
+	 * For simplicity, the decoded characters go in a single mbuf,
+	 * so we allocate a single extra cluster mbuf if necessary.
+	 */
+	if ((space -= codelen + extra) < 0) {
+	    dmp->m_len = wptr - mtod(dmp, u_char *);
+	    MGET(m, M_DONTWAIT, MT_DATA);
+	    if (m == NULL) {
+		m_freem(mret);
+		return DECOMP_ERROR;
+	    }
+	    m->m_len = 0;
+	    m->m_next = NULL;
+	    dmp->m_next = m;
+	    MCLGET(m, M_DONTWAIT);
+	    space = M_TRAILINGSPACE(m) - (codelen + extra);
+	    if (space < 0) {
+		/* now that's what I call *compression*. */
+		m_freem(mret);
+		return DECOMP_ERROR;
+	    }
+	    dmp = m;
+	    wptr = mtod(dmp, u_char *);
+	}
+
+	/*
+	 * Decode this code and install it in the decompressed buffer.
+	 */
+	p = (wptr += codelen);
+	while (finchar > LAST) {
+	    dictp = &db->dict[db->dict[finchar].cptr];
+#ifdef DEBUG
+	    if (--codelen <= 0 || dictp->codem1 != finchar-1)
+		goto bad;
+#endif
+	    *--p = dictp->f.hs.suffix;
+	    finchar = dictp->f.hs.prefix;
+	}
+	*--p = finchar;
+
+#ifdef DEBUG
+	if (--codelen != 0)
+	    printf("bsd_decomp%d: short by %d after code 0x%x, max_ent=0x%x\n",
+		   db->unit, codelen, incode, max_ent);
+#endif
+
+	if (extra)		/* the KwKwK case again */
+	    *wptr++ = finchar;
+
+	/*
+	 * If not first code in a packet, and
+	 * if not out of code space, then allocate a new code.
+	 *
+	 * Keep the hash table correct so it can be used
+	 * with uncompressed packets.
+	 */
+	if (oldcode != CLEAR && max_ent < db->maxmaxcode) {
+	    struct bsd_dict *dictp2;
+	    u_int32_t fcode;
+	    u_int32_t hval, disp;
+
+	    fcode = BSD_KEY(oldcode,finchar);
+	    hval = BSD_HASH(oldcode,finchar,db->hshift);
+	    dictp = &db->dict[hval];
+
+	    /* look for a free hash table entry */
+	    if (dictp->codem1 < max_ent) {
+		disp = (hval == 0) ? 1 : hval;
+		do {
+		    hval += disp;
+		    if (hval >= db->hsize)
+			hval -= db->hsize;
+		    dictp = &db->dict[hval];
+		} while (dictp->codem1 < max_ent);
+	    }
+
+	    /*
+	     * Invalidate previous hash table entry
+	     * assigned this code, and then take it over
+	     */
+	    dictp2 = &db->dict[max_ent+1];
+	    if (db->dict[dictp2->cptr].codem1 == max_ent) {
+		db->dict[dictp2->cptr].codem1 = BADCODEM1;
+	    }
+	    dictp2->cptr = hval;
+	    dictp->codem1 = max_ent;
+	    dictp->f.fcode = fcode;
+
+	    db->max_ent = ++max_ent;
+	    db->lens[max_ent] = db->lens[oldcode]+1;
+
+	    /* Expand code size if needed. */
+	    if (max_ent >= MAXCODE(n_bits) && max_ent < db->maxmaxcode) {
+		db->n_bits = ++n_bits;
+		tgtbitno = 32-n_bits;
+	    }
+	}
+	oldcode = incode;
+    }
+    dmp->m_len = wptr - mtod(dmp, u_char *);
+
+    /*
+     * Keep the checkpoint right so that incompressible packets
+     * clear the dictionary at the right times.
+     */
+    db->bytes_out += ilen;
+    db->in_count += explen;
+    if (bsd_check(db) && db->debug) {
+	printf("bsd_decomp%d: peer should have cleared dictionary\n",
+	       db->unit);
+    }
+
+    ++db->comp_count;
+    db->comp_bytes += ilen + BSD_OVHD;
+    ++db->uncomp_count;
+    db->uncomp_bytes += explen;
+
+    *dmpp = mret;
+    return DECOMP_OK;
+
+#ifdef DEBUG
+ bad:
+    if (codelen <= 0) {
+	printf("bsd_decomp%d: fell off end of chain ", db->unit);
+	printf("0x%x at 0x%x by 0x%x, max_ent=0x%x\n",
+	       incode, finchar, db->dict[finchar].cptr, max_ent);
+    } else if (dictp->codem1 != finchar-1) {
+	printf("bsd_decomp%d: bad code chain 0x%x finchar=0x%x ",
+	       db->unit, incode, finchar);
+	printf("oldcode=0x%x cptr=0x%x codem1=0x%x\n", oldcode,
+	       db->dict[finchar].cptr, dictp->codem1);
+    }
+    m_freem(mret);
+    return DECOMP_FATALERROR;
+#endif /* DEBUG */
+}
+#endif /* DO_BSD_COMPRESS */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/cbcp.c
@@ -0,0 +1,478 @@
+//==========================================================================
+//
+//      src/cbcp.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * cbcp - Call Back Configuration Protocol.
+ *
+ * Copyright (c) 1995 Pedro Roque Marques
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Pedro Roque Marques.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/cbcp.c,v 1.4 1999/08/28 01:19:00 peter Exp $";
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <cyg/ppp/syslog.h>
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/cbcp.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/lcp.h"
+#include "cyg/ppp/ipcp.h"
+
+/*
+ * Protocol entry points.
+ */
+static void cbcp_init      __P((int unit));
+static void cbcp_open      __P((int unit));
+static void cbcp_lowerup   __P((int unit));
+static void cbcp_input     __P((int unit, u_char *pkt, int len));
+static void cbcp_protrej   __P((int unit));
+static int  cbcp_printpkt  __P((u_char *pkt, int len,
+				void (*printer) __P((void *, char *, ...)),
+				void *arg));
+
+struct protent cbcp_protent = {
+    PPP_CBCP,
+    cbcp_init,
+    cbcp_input,
+    cbcp_protrej,
+    cbcp_lowerup,
+    NULL,
+    cbcp_open,
+    NULL,
+    cbcp_printpkt,
+    NULL,
+    0,
+    "CBCP",
+    NULL,
+    NULL,
+    NULL
+};
+
+cbcp_state cbcp[NUM_PPP];	
+
+/* internal prototypes */
+
+static void cbcp_recvreq __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_resp __P((cbcp_state *us));
+static void cbcp_up __P((cbcp_state *us));
+static void cbcp_recvack __P((cbcp_state *us, char *pckt, int len));
+static void cbcp_send __P((cbcp_state *us, u_char code, u_char *buf, int len));
+
+/* init state */
+static void
+cbcp_init(iface)
+    int iface;
+{
+    cbcp_state *us;
+
+    us = &cbcp[iface];
+    memset(us, 0, sizeof(cbcp_state));
+    us->us_unit = iface;
+    us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+static void
+cbcp_lowerup(iface)
+    int iface;
+{
+    cbcp_state *us = &cbcp[iface];
+
+    syslog(LOG_DEBUG, "cbcp_lowerup");
+    syslog(LOG_DEBUG, "want: %d", us->us_type);
+
+    if (us->us_type == CB_CONF_USER)
+        syslog(LOG_DEBUG, "phone no: %s", us->us_number);
+}
+
+static void
+cbcp_open(unit)
+    int unit;
+{
+    syslog(LOG_DEBUG, "cbcp_open");
+}
+
+/* process an incomming packet */
+static void
+cbcp_input(unit, inpacket, pktlen)
+    int unit;
+    u_char *inpacket;
+    int pktlen;
+{
+    u_char *inp;
+    u_char code, id;
+    u_short len;
+
+    cbcp_state *us = &cbcp[unit];
+
+    inp = inpacket;
+
+    if (pktlen < CBCP_MINLEN) {
+        syslog(LOG_ERR, "CBCP packet is too small");
+	return;
+    }
+
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+
+#if 0
+    if (len > pktlen) {
+        syslog(LOG_ERR, "CBCP packet: invalid length");
+        return;
+    }
+#endif
+
+    len -= CBCP_MINLEN;
+ 
+    switch(code) {
+    case CBCP_REQ:
+        us->us_id = id;
+	cbcp_recvreq(us, inp, len);
+	break;
+
+    case CBCP_RESP:
+	syslog(LOG_DEBUG, "CBCP_RESP received");
+	break;
+
+    case CBCP_ACK:
+	if (id != us->us_id)
+	    syslog(LOG_DEBUG, "id doesn't match: expected %d recv %d",
+		   us->us_id, id);
+
+	cbcp_recvack(us, inp, len);
+	break;
+
+    default:
+	break;
+    }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {
+    "Request", "Response", "Ack"
+};
+
+char *cbcp_optionnames[] = {
+    "NoCallback",
+    "UserDefined",
+    "AdminDefined",
+    "List"
+};
+
+/* pretty print a packet */
+static int
+cbcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, opt, id, len, olen, delay;
+    u_char *pstart;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+	printer(arg, " %s", cbcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code); 
+
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+
+    switch (code) {
+    case CBCP_REQ:
+    case CBCP_RESP:
+    case CBCP_ACK:
+        while(len >= 2) {
+	    GETCHAR(opt, p);
+	    GETCHAR(olen, p);
+
+	    if (olen < 2 || olen > len) {
+	        break;
+	    }
+
+	    printer(arg, " <");
+	    len -= olen;
+
+	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
+	    else
+	        printer(arg, " option=0x%x", opt); 
+
+	    if (olen > 2) {
+	        GETCHAR(delay, p);
+		printer(arg, " delay = %d", delay);
+	    }
+
+	    if (olen > 3) {
+	        int addrt;
+		char str[256];
+
+		GETCHAR(addrt, p);
+		memcpy(str, p, olen - 4);
+		str[olen - 4] = 0;
+		printer(arg, " number = %s", str);
+	    }
+	    printer(arg, ">");
+	    break;
+	}
+
+    default:
+	break;
+    }
+
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/* received CBCP request */
+static void
+cbcp_recvreq(us, pckt, pcktlen)
+    cbcp_state *us;
+    char *pckt;
+    int pcktlen;
+{
+    u_char type, opt_len, delay, addr_type;
+    char address[256];
+    int len = pcktlen;
+
+    address[0] = 0;
+
+    while (len) {
+        syslog(LOG_DEBUG, "length: %d", len);
+
+	GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	us->us_allowed |= (1 << type);
+
+	switch(type) {
+	case CB_CONF_NO:
+	    syslog(LOG_DEBUG, "no callback allowed");
+	    break;
+
+	case CB_CONF_USER:
+	    syslog(LOG_DEBUG, "user callback allowed");
+	    if (opt_len > 4) {
+	        GETCHAR(addr_type, pckt);
+		memcpy(address, pckt, opt_len - 4);
+		address[opt_len - 4] = 0;
+		if (address[0])
+		    syslog(LOG_DEBUG, "address: %s", address);
+	    }
+	    break;
+
+	case CB_CONF_ADMIN:
+	    syslog(LOG_DEBUG, "user admin defined allowed");
+	    break;
+
+	case CB_CONF_LIST:
+	    break;
+	}
+	len -= opt_len;
+    }
+
+    cbcp_resp(us);
+}
+
+static void
+cbcp_resp(us)
+    cbcp_state *us;
+{
+    u_char cb_type;
+    u_char buf[256];
+    u_char *bufp = buf;
+    int len = 0;
+
+    cb_type = us->us_allowed & us->us_type;
+    syslog(LOG_DEBUG, "cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+    if (!cb_type)
+        lcp_down(us->us_unit);
+#endif
+
+    if (cb_type & ( 1 << CB_CONF_USER ) ) {
+	syslog(LOG_DEBUG, "cbcp_resp CONF_USER");
+	PUTCHAR(CB_CONF_USER, bufp);
+	len = 3 + 1 + strlen(us->us_number) + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(1, bufp);
+	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
+	syslog(LOG_DEBUG, "cbcp_resp CONF_ADMIN");
+        PUTCHAR(CB_CONF_ADMIN, bufp);
+	len = 3 + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_NO ) ) {
+        syslog(LOG_DEBUG, "cbcp_resp CONF_NO");
+	PUTCHAR(CB_CONF_NO, bufp);
+	len = 3;
+	PUTCHAR(len , bufp);
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	(*ipcp_protent.open)(us->us_unit);
+	return;
+    }
+}
+
+static void
+cbcp_send(us, code, buf, len)
+    cbcp_state *us;
+    u_char code;
+    u_char *buf;
+    int len;
+{
+    u_char *outp;
+    int outlen;
+
+    outp = outpacket_buf;
+
+    outlen = 4 + len;
+    
+    MAKEHEADER(outp, PPP_CBCP);
+
+    PUTCHAR(code, outp);
+    PUTCHAR(us->us_id, outp);
+    PUTSHORT(outlen, outp);
+    
+    if (len)
+        BCOPY(buf, outp, len);
+
+    output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+static void
+cbcp_recvack(us, pckt, len)
+    cbcp_state *us;
+    char *pckt;
+    int len;
+{
+    u_char type, delay, addr_type;
+    int opt_len;
+    char address[256];
+
+    if (len) {
+        GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+     
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	if (opt_len > 4) {
+	    GETCHAR(addr_type, pckt);
+	    memcpy(address, pckt, opt_len - 4);
+	    address[opt_len - 4] = 0;
+	    if (address[0])
+	        syslog(LOG_DEBUG, "peer will call: %s", address);
+	}
+    }
+
+    cbcp_up(us);
+}
+
+extern int persist;
+
+/* ok peer will do callback */
+static void
+cbcp_up(us)
+    cbcp_state *us;
+{
+    persist = 0;
+    lcp_close(0, "Call me back, please");
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/ccp.c
@@ -0,0 +1,1162 @@
+//==========================================================================
+//
+//      src/ccp.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ccp.c - PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/ccp.c,v 1.10 1999/08/28 01:19:00 peter Exp $";
+#endif
+
+#include <string.h>
+#include <cyg/ppp/syslog.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/ccp.h"
+#include <cyg/ppp/net/ppp_comp.h>
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ccp_init __P((int unit));
+static void ccp_open __P((int unit));
+static void ccp_close __P((int unit, char *));
+static void ccp_lowerup __P((int unit));
+static void ccp_lowerdown __P((int));
+static void ccp_input __P((int unit, u_char *pkt, int len));
+static void ccp_protrej __P((int unit));
+static int  ccp_printpkt __P((u_char *pkt, int len,
+			      void (*printer) __P((void *, char *, ...)),
+			      void *arg));
+static void ccp_datainput __P((int unit, u_char *pkt, int len));
+
+struct protent ccp_protent = {
+    PPP_CCP,
+    ccp_init,
+    ccp_input,
+    ccp_protrej,
+    ccp_lowerup,
+    ccp_lowerdown,
+    ccp_open,
+    ccp_close,
+    ccp_printpkt,
+    ccp_datainput,
+    1,
+    "CCP",
+    NULL,
+    NULL,
+    NULL
+};
+
+fsm ccp_fsm[NUM_PPP];
+ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
+ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
+ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
+ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
+
+/*
+ * Callbacks for fsm code.
+ */
+static void ccp_resetci __P((fsm *));
+static int  ccp_cilen __P((fsm *));
+static void ccp_addci __P((fsm *, u_char *, int *));
+static int  ccp_ackci __P((fsm *, u_char *, int));
+static int  ccp_nakci __P((fsm *, u_char *, int));
+static int  ccp_rejci __P((fsm *, u_char *, int));
+static int  ccp_reqci __P((fsm *, u_char *, int *, int));
+static void ccp_up __P((fsm *));
+static void ccp_down __P((fsm *));
+static int  ccp_extcode __P((fsm *, int, int, u_char *, int));
+static void ccp_rack_timeout __P((void *));
+static char *method_name __P((ccp_options *, ccp_options *));
+
+static fsm_callbacks ccp_callbacks = {
+    ccp_resetci,
+    ccp_cilen,
+    ccp_addci,
+    ccp_ackci,
+    ccp_nakci,
+    ccp_rejci,
+    ccp_reqci,
+    ccp_up,
+    ccp_down,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ccp_extcode,
+    "CCP"
+};
+
+/*
+ * Do we want / did we get any compression?
+ */
+#define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
+				 || (opt).predictor_1 || (opt).predictor_2)
+
+/*
+ * Local state (mainly for handling reset-reqs and reset-acks).
+ */
+static int ccp_localstate[NUM_PPP];
+#define RACK_PENDING	1	/* waiting for reset-ack */
+#define RREQ_REPEAT	2	/* send another reset-req if no reset-ack */
+
+#define RACKTIMEOUT	1	/* second */
+
+static int all_rejected[NUM_PPP];	/* we rejected all peer's options */
+
+/*
+ * ccp_init - initialize CCP.
+ */
+static void
+ccp_init(unit)
+    int unit;
+{
+    fsm *f = &ccp_fsm[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_CCP;
+    f->callbacks = &ccp_callbacks;
+    fsm_init(f);
+
+    memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
+    memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
+    memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
+    memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
+
+    ccp_wantoptions[0].deflate = 1;
+    ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+    ccp_wantoptions[0].deflate_correct = 1;
+    ccp_wantoptions[0].deflate_draft = 1;
+    ccp_allowoptions[0].deflate = 1;
+    ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+    ccp_allowoptions[0].deflate_correct = 1;
+    ccp_allowoptions[0].deflate_draft = 1;
+
+    ccp_wantoptions[0].bsd_compress = 1;
+    ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
+    ccp_allowoptions[0].bsd_compress = 1;
+    ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+
+    ccp_allowoptions[0].predictor_1 = 1;
+}
+
+/*
+ * ccp_open - CCP is allowed to come up.
+ */
+static void
+ccp_open(unit)
+    int unit;
+{
+    fsm *f = &ccp_fsm[unit];
+
+    if (f->state != OPENED)
+	ccp_flags_set(unit, 1, 0);
+
+    /*
+     * Find out which compressors the kernel supports before
+     * deciding whether to open in silent mode.
+     */
+    ccp_resetci(f);
+    if (!ANY_COMPRESS(ccp_gotoptions[unit]))
+	f->flags |= OPT_SILENT;
+
+    fsm_open(f);
+}
+
+/*
+ * ccp_close - Terminate CCP.
+ */
+static void
+ccp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    ccp_flags_set(unit, 0, 0);
+    fsm_close(&ccp_fsm[unit], reason);
+}
+
+/*
+ * ccp_lowerup - we may now transmit CCP packets.
+ */
+static void
+ccp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerdown - we may not transmit CCP packets.
+ */
+static void
+ccp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_input - process a received CCP packet.
+ */
+static void
+ccp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm *f = &ccp_fsm[unit];
+    int oldstate;
+
+    /*
+     * Check for a terminate-request so we can print a message.
+     */
+    oldstate = f->state;
+    fsm_input(f, p, len);
+    if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
+	syslog(LOG_NOTICE, "Compression disabled by peer.");
+
+    /*
+     * If we get a terminate-ack and we're not asking for compression,
+     * close CCP.
+     */
+    if (oldstate == REQSENT && p[0] == TERMACK
+	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
+	ccp_close(unit, "No compression negotiated");
+}
+
+/*
+ * Handle a CCP-specific code.
+ */
+static int
+ccp_extcode(f, code, id, p, len)
+    fsm *f;
+    int code, id;
+    u_char *p;
+    int len;
+{
+    switch (code) {
+    case CCP_RESETREQ:
+	if (f->state != OPENED)
+	    break;
+	/* send a reset-ack, which the transmitter will see and
+	   reset its compression state. */
+	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+	break;
+
+    case CCP_RESETACK:
+	if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
+	    ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
+	    UNTIMEOUT(ccp_rack_timeout, f);
+	}
+	break;
+
+    default:
+	return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * ccp_protrej - peer doesn't talk CCP.
+ */
+static void
+ccp_protrej(unit)
+    int unit;
+{
+    ccp_flags_set(unit, 0, 0);
+    fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_resetci - initialize at start of negotiation.
+ */
+static void
+ccp_resetci(f)
+    fsm *f;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char opt_buf[16];
+
+    *go = ccp_wantoptions[f->unit];
+    all_rejected[f->unit] = 0;
+
+    /*
+     * Check whether the kernel knows about the various
+     * compression methods we might request.
+     */
+    if (go->bsd_compress) {
+	opt_buf[0] = CI_BSD_COMPRESS;
+	opt_buf[1] = CILEN_BSD_COMPRESS;
+	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
+	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
+	    go->bsd_compress = 0;
+    }
+    if (go->deflate) {
+	if (go->deflate_correct) {
+	    opt_buf[0] = CI_DEFLATE;
+	    opt_buf[1] = CILEN_DEFLATE;
+	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
+	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_correct = 0;
+	}
+	if (go->deflate_draft) {
+	    opt_buf[0] = CI_DEFLATE_DRAFT;
+	    opt_buf[1] = CILEN_DEFLATE;
+	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
+	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_draft = 0;
+	}
+	if (!go->deflate_correct && !go->deflate_draft)
+	    go->deflate = 0;
+    }
+    if (go->predictor_1) {
+	opt_buf[0] = CI_PREDICTOR_1;
+	opt_buf[1] = CILEN_PREDICTOR_1;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
+	    go->predictor_1 = 0;
+    }
+    if (go->predictor_2) {
+	opt_buf[0] = CI_PREDICTOR_2;
+	opt_buf[1] = CILEN_PREDICTOR_2;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
+	    go->predictor_2 = 0;
+    }
+}
+
+/*
+ * ccp_cilen - Return total length of our configuration info.
+ */
+static int
+ccp_cilen(f)
+    fsm *f;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+
+    return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
+	+ (go->deflate? CILEN_DEFLATE: 0)
+	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
+	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
+}
+
+/*
+ * ccp_addci - put our requests in a packet.
+ */
+static void
+ccp_addci(f, p, lenp)
+    fsm *f;
+    u_char *p;
+    int *lenp;
+{
+    int res;
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char *p0 = p;
+
+    /*
+     * Add the compression types that we can receive, in decreasing
+     * preference order.  Get the kernel to allocate the first one
+     * in case it gets Acked.
+     */
+    if (go->deflate) {
+	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+	p[1] = CILEN_DEFLATE;
+	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	p[3] = DEFLATE_CHK_SEQUENCE;
+	for (;;) {
+	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+	    if (res > 0) {
+		p += CILEN_DEFLATE;
+		break;
+	    }
+	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
+		go->deflate = 0;
+		break;
+	    }
+	    --go->deflate_size;
+	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	}
+	if (p != p0 && go->deflate_correct && go->deflate_draft) {
+	    p[0] = CI_DEFLATE_DRAFT;
+	    p[1] = CILEN_DEFLATE;
+	    p[2] = p[2 - CILEN_DEFLATE];
+	    p[3] = DEFLATE_CHK_SEQUENCE;
+	    p += CILEN_DEFLATE;
+	}
+    }
+    if (go->bsd_compress) {
+	p[0] = CI_BSD_COMPRESS;
+	p[1] = CILEN_BSD_COMPRESS;
+	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	if (p != p0) {
+	    p += CILEN_BSD_COMPRESS;	/* not the first option */
+	} else {
+	    for (;;) {
+		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
+		if (res > 0) {
+		    p += CILEN_BSD_COMPRESS;
+		    break;
+		}
+		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+		    go->bsd_compress = 0;
+		    break;
+		}
+		--go->bsd_bits;
+		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	    }
+	}
+    }
+    /* XXX Should Predictor 2 be preferable to Predictor 1? */
+    if (go->predictor_1) {
+	p[0] = CI_PREDICTOR_1;
+	p[1] = CILEN_PREDICTOR_1;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
+	    go->predictor_1 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_1;
+	}
+    }
+    if (go->predictor_2) {
+	p[0] = CI_PREDICTOR_2;
+	p[1] = CILEN_PREDICTOR_2;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
+	    go->predictor_2 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_2;
+	}
+    }
+
+    go->method = (p > p0)? p0[0]: -1;
+
+    *lenp = p - p0;
+}
+
+/*
+ * ccp_ackci - process a received configure-ack, and return
+ * 1 iff the packet was OK.
+ */
+static int
+ccp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char *p0 = p;
+
+    if (go->deflate) {
+	if (len < CILEN_DEFLATE
+	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	    || p[1] != CILEN_DEFLATE
+	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    return 0;
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	/* XXX Cope with first/fast ack */
+	if (len == 0)
+	    return 1;
+	if (go->deflate_correct && go->deflate_draft) {
+	    if (len < CILEN_DEFLATE
+		|| p[0] != CI_DEFLATE_DRAFT
+		|| p[1] != CILEN_DEFLATE
+		|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+		|| p[3] != DEFLATE_CHK_SEQUENCE)
+		return 0;
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+    if (go->bsd_compress) {
+	if (len < CILEN_BSD_COMPRESS
+	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
+	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_1) {
+	if (len < CILEN_PREDICTOR_1
+	    || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
+	    return 0;
+	p += CILEN_PREDICTOR_1;
+	len -= CILEN_PREDICTOR_1;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_2) {
+	if (len < CILEN_PREDICTOR_2
+	    || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
+	    return 0;
+	p += CILEN_PREDICTOR_2;
+	len -= CILEN_PREDICTOR_2;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+
+    if (len != 0)
+	return 0;
+    return 1;
+}
+
+/*
+ * ccp_nakci - process received configure-nak.
+ * Returns 1 iff the nak was OK.
+ */
+static int
+ccp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options no;		/* options we've seen already */
+    ccp_options try;		/* options to ask for next time */
+
+    memset(&no, 0, sizeof(no));
+    try = *go;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& p[1] == CILEN_DEFLATE) {
+	no.deflate = 1;
+	/*
+	 * Peer wants us to use a different code size or something.
+	 * Stop asking for Deflate if we don't understand his suggestion.
+	 */
+	if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+	    || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    try.deflate = 0;
+	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
+	    try.deflate_size = DEFLATE_SIZE(p[2]);
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+	no.bsd_compress = 1;
+	/*
+	 * Peer wants us to use a different number of bits
+	 * or a different version.
+	 */
+	if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
+	    try.bsd_compress = 0;
+	else if (BSD_NBITS(p[2]) < go->bsd_bits)
+	    try.bsd_bits = BSD_NBITS(p[2]);
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+    }
+
+    /*
+     * Predictor-1 and 2 have no options, so they can't be Naked.
+     *
+     * XXX What should we do with any remaining options?
+     */
+
+    if (len != 0)
+	return 0;
+
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+}
+
+/*
+ * ccp_rejci - reject some of our suggested compression methods.
+ */
+static int
+ccp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options try;		/* options to request next time */
+
+    try = *go;
+
+    /*
+     * Cope with empty configure-rejects by ceasing to send
+     * configure-requests.
+     */
+    if (len == 0 && all_rejected[f->unit])
+	return -1;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& p[1] == CILEN_DEFLATE) {
+	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    return 0;		/* Rej is bad */
+	if (go->deflate_correct)
+	    try.deflate_correct = 0;
+	else
+	    try.deflate_draft = 0;
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+		|| p[3] != DEFLATE_CHK_SEQUENCE)
+		return 0;		/* Rej is bad */
+	    try.deflate_draft = 0;
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+	if (!try.deflate_correct && !try.deflate_draft)
+	    try.deflate = 0;
+    }
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	try.bsd_compress = 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+    }
+    if (go->predictor_1 && len >= CILEN_PREDICTOR_1
+	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
+	try.predictor_1 = 0;
+	p += CILEN_PREDICTOR_1;
+	len -= CILEN_PREDICTOR_1;
+    }
+    if (go->predictor_2 && len >= CILEN_PREDICTOR_2
+	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
+	try.predictor_2 = 0;
+	p += CILEN_PREDICTOR_2;
+	len -= CILEN_PREDICTOR_2;
+    }
+
+    if (len != 0)
+	return 0;
+
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+}
+
+/*
+ * ccp_reqci - processed a received configure-request.
+ * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
+ * appropriately.
+ */
+static int
+ccp_reqci(f, p, lenp, dont_nak)
+    fsm *f;
+    u_char *p;
+    int *lenp;
+    int dont_nak;
+{
+    int ret, newret, res;
+    u_char *p0, *retp;
+    int len, clen, type, nb;
+    ccp_options *ho = &ccp_hisoptions[f->unit];
+    ccp_options *ao = &ccp_allowoptions[f->unit];
+
+    ret = CONFACK;
+    retp = p0 = p;
+    len = *lenp;
+
+    memset(ho, 0, sizeof(ccp_options));
+    ho->method = (len > 0)? p[0]: -1;
+
+    while (len > 0) {
+	newret = CONFACK;
+	if (len < 2 || p[1] < 2 || p[1] > len) {
+	    /* length is bad */
+	    clen = len;
+	    newret = CONFREJ;
+
+	} else {
+	    type = p[0];
+	    clen = p[1];
+
+	    switch (type) {
+	    case CI_DEFLATE:
+	    case CI_DEFLATE_DRAFT:
+		if (!ao->deflate || clen != CILEN_DEFLATE
+		    || (!ao->deflate_correct && type == CI_DEFLATE)
+		    || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->deflate = 1;
+		ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
+		if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+		    || p[3] != DEFLATE_CHK_SEQUENCE
+		    || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
+			p[3] = DEFLATE_CHK_SEQUENCE;
+			/* fall through to test this #bits below */
+		    } else
+			break;
+		}
+
+		/*
+		 * Check whether we can do Deflate with the window
+		 * size they want.  If the window is too big, reduce
+		 * it until the kernel can cope and nak with that.
+		 * We only check this for the first option.
+		 */
+		if (p == p0) {
+		    for (;;) {
+			res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
+			if (res > 0)
+			    break;		/* it's OK now */
+			if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = DEFLATE_MAKE_OPT(nb);
+		    }
+		}
+		break;
+
+	    case CI_BSD_COMPRESS:
+		if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->bsd_compress = 1;
+		ho->bsd_bits = nb = BSD_NBITS(p[2]);
+		if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
+		    || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
+			/* fall through to test this #bits below */
+		    } else
+			break;
+		}
+
+		/*
+		 * Check whether we can do BSD-Compress with the code
+		 * size they want.  If the code size is too big, reduce
+		 * it until the kernel can cope and nak with that.
+		 * We only check this for the first option.
+		 */
+		if (p == p0) {
+		    for (;;) {
+			res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
+			if (res > 0)
+			    break;
+			if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
+						ho->bsd_bits);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+		    }
+		}
+		break;
+
+	    case CI_PREDICTOR_1:
+		if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_1 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    case CI_PREDICTOR_2:
+		if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_2 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    default:
+		newret = CONFREJ;
+	    }
+	}
+
+	if (newret == CONFNAK && dont_nak)
+	    newret = CONFREJ;
+	if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
+	    /* we're returning this option */
+	    if (newret == CONFREJ && ret == CONFNAK)
+		retp = p0;
+	    ret = newret;
+	    if (p != retp)
+		BCOPY(p, retp, clen);
+	    retp += clen;
+	}
+
+	p += clen;
+	len -= clen;
+    }
+
+    if (ret != CONFACK) {
+	if (ret == CONFREJ && *lenp == retp - p0)
+	    all_rejected[f->unit] = 1;
+	else
+	    *lenp = retp - p0;
+    }
+    return ret;
+}
+
+/*
+ * Make a string name for a compression method (or 2).
+ */
+static char *
+method_name(opt, opt2)
+    ccp_options *opt, *opt2;
+{
+    static char result[64];
+
+    if (!ANY_COMPRESS(*opt))
+	return "(none)";
+    switch (opt->method) {
+    case CI_DEFLATE:
+    case CI_DEFLATE_DRAFT:
+	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+	    sprintf(result, "Deflate%s (%d/%d)",
+		    (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		    opt->deflate_size, opt2->deflate_size);
+	else
+	    sprintf(result, "Deflate%s (%d)",
+		    (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		    opt->deflate_size);
+	break;
+    case CI_BSD_COMPRESS:
+	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
+	    sprintf(result, "BSD-Compress (%d/%d)", opt->bsd_bits,
+		    opt2->bsd_bits);
+	else
+	    sprintf(result, "BSD-Compress (%d)", opt->bsd_bits);
+	break;
+    case CI_PREDICTOR_1:
+	return "Predictor 1";
+    case CI_PREDICTOR_2:
+	return "Predictor 2";
+    default:
+	sprintf(result, "Method %d", opt->method);
+    }
+    return result;
+}
+
+/*
+ * CCP has come up - inform the kernel driver and log a message.
+ */
+static void
+ccp_up(f)
+    fsm *f;
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options *ho = &ccp_hisoptions[f->unit];
+    char method1[64];
+
+    ccp_flags_set(f->unit, 1, 1);
+    if (ANY_COMPRESS(*go)) {
+	if (ANY_COMPRESS(*ho)) {
+	    if (go->method == ho->method) {
+		syslog(LOG_NOTICE, "%s compression enabled",
+		       method_name(go, ho));
+	    } else {
+		strcpy(method1, method_name(go, NULL));
+		syslog(LOG_NOTICE, "%s / %s compression enabled",
+		       method1, method_name(ho, NULL));
+	    }
+	} else
+	    syslog(LOG_NOTICE, "%s receive compression enabled",
+		   method_name(go, NULL));
+    } else if (ANY_COMPRESS(*ho))
+	syslog(LOG_NOTICE, "%s transmit compression enabled",
+	       method_name(ho, NULL));
+}
+
+/*
+ * CCP has gone down - inform the kernel driver.
+ */
+static void
+ccp_down(f)
+    fsm *f;
+{
+    if (ccp_localstate[f->unit] & RACK_PENDING)
+	UNTIMEOUT(ccp_rack_timeout, f);
+    ccp_localstate[f->unit] = 0;
+    ccp_flags_set(f->unit, 1, 0);
+}
+
+/*
+ * Print the contents of a CCP packet.
+ */
+static char *ccp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej",
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    "ResetReq", "ResetAck",
+};
+
+static int
+ccp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    u_char *p0, *optend;
+    int code, id, len;
+    int optlen;
+
+    p0 = p;
+    if (plen < HEADERLEN)
+	return 0;
+    code = p[0];
+    id = p[1];
+    len = (p[2] << 8) + p[3];
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
+	&& ccp_codenames[code-1] != NULL)
+	printer(arg, " %s", ccp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    p += HEADERLEN;
+
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print list of possible compression methods */
+	while (len >= 2) {
+	    code = p[0];
+	    optlen = p[1];
+	    if (optlen < 2 || optlen > len)
+		break;
+	    printer(arg, " <");
+	    len -= optlen;
+	    optend = p + optlen;
+	    switch (code) {
+	    case CI_DEFLATE:
+	    case CI_DEFLATE_DRAFT:
+		if (optlen >= CILEN_DEFLATE) {
+		    printer(arg, "deflate%s %d",
+			    (code == CI_DEFLATE_DRAFT? "(old#)": ""),
+			    DEFLATE_SIZE(p[2]));
+		    if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
+			printer(arg, " method %d", DEFLATE_METHOD(p[2]));
+		    if (p[3] != DEFLATE_CHK_SEQUENCE)
+			printer(arg, " check %d", p[3]);
+		    p += CILEN_DEFLATE;
+		}
+		break;
+	    case CI_BSD_COMPRESS:
+		if (optlen >= CILEN_BSD_COMPRESS) {
+		    printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
+			    BSD_NBITS(p[2]));
+		    p += CILEN_BSD_COMPRESS;
+		}
+		break;
+	    case CI_PREDICTOR_1:
+		if (optlen >= CILEN_PREDICTOR_1) {
+		    printer(arg, "predictor 1");
+		    p += CILEN_PREDICTOR_1;
+		}
+		break;
+	    case CI_PREDICTOR_2:
+		if (optlen >= CILEN_PREDICTOR_2) {
+		    printer(arg, "predictor 2");
+		    p += CILEN_PREDICTOR_2;
+		}
+		break;
+	    }
+	    while (p < optend)
+		printer(arg, " %.2x", *p++);
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* dump out the rest of the packet in hex */
+    while (--len >= 0)
+	printer(arg, " %.2x", *p++);
+
+    return p - p0;
+}
+
+/*
+ * We have received a packet that the decompressor failed to
+ * decompress.  Here we would expect to issue a reset-request, but
+ * Motorola has a patent on resetting the compressor as a result of
+ * detecting an error in the decompressed data after decompression.
+ * (See US patent 5,130,993; international patent publication number
+ * WO 91/10289; Australian patent 73296/91.)
+ *
+ * So we ask the kernel whether the error was detected after
+ * decompression; if it was, we take CCP down, thus disabling
+ * compression :-(, otherwise we issue the reset-request.
+ */
+static void
+ccp_datainput(unit, pkt, len)
+    int unit;
+    u_char *pkt;
+    int len;
+{
+    fsm *f;
+
+    f = &ccp_fsm[unit];
+    if (f->state == OPENED) {
+	if (ccp_fatal_error(unit)) {
+	    /*
+	     * Disable compression by taking CCP down.
+	     */
+	    syslog(LOG_ERR, "Lost compression sync: disabling compression");
+	    ccp_close(unit, "Lost compression sync");
+	} else {
+	    /*
+	     * Send a reset-request to reset the peer's compressor.
+	     * We don't do that if we are still waiting for an
+	     * acknowledgement to a previous reset-request.
+	     */
+	    if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
+		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
+		TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+		ccp_localstate[f->unit] |= RACK_PENDING;
+	    } else
+		ccp_localstate[f->unit] |= RREQ_REPEAT;
+	}
+    }
+}
+
+/*
+ * Timeout waiting for reset-ack.
+ */
+static void
+ccp_rack_timeout(arg)
+    void *arg;
+{
+    fsm *f = arg;
+
+    if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
+	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
+	TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+	ccp_localstate[f->unit] &= ~RREQ_REPEAT;
+    } else
+	ccp_localstate[f->unit] &= ~RACK_PENDING;
+}
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/chap.c
@@ -0,0 +1,919 @@
+//==========================================================================
+//
+//      src/chap.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/chap.c,v 1.10 1999/08/28 01:19:01 peter Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <cyg/ppp/syslog.h>
+#include <sys/md5.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/chap.h"
+//#include "md5.h"
+#ifdef CHAPMS
+#include "cyg/ppp/chap_ms.h"
+#endif
+
+/*
+ * Protocol entry points.
+ */
+static void ChapInit __P((int));
+static void ChapLowerUp __P((int));
+static void ChapLowerDown __P((int));
+static void ChapInput __P((int, u_char *, int));
+static void ChapProtocolReject __P((int));
+static int  ChapPrintPkt __P((u_char *, int,
+			      void (*) __P((void *, char *, ...)), void *));
+
+struct protent chap_protent = {
+    PPP_CHAP,
+    ChapInit,
+    ChapInput,
+    ChapProtocolReject,
+    ChapLowerUp,
+    ChapLowerDown,
+    NULL,
+    NULL,
+    ChapPrintPkt,
+    NULL,
+    1,
+    "CHAP",
+    NULL,
+    NULL,
+    NULL
+};
+
+chap_state chap[NUM_PPP];		/* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout __P((void *));
+static void ChapResponseTimeout __P((void *));
+static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
+static void ChapRechallenge __P((void *));
+static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
+static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
+static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
+static void ChapSendStatus __P((chap_state *, int));
+static void ChapSendChallenge __P((chap_state *));
+static void ChapSendResponse __P((chap_state *));
+static void ChapGenChallenge __P((chap_state *));
+
+extern double drand48 __P((void));
+extern void srand48 __P((long));
+
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+static void
+ChapInit(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+
+    BZERO(cstate, sizeof(*cstate));
+    cstate->unit = unit;
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+    cstate->timeouttime = CHAP_DEFTIMEOUT;
+    cstate->max_transmits = CHAP_DEFTRANSMITS;
+    /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void
+ChapAuthWithPeer(unit, our_name, digest)
+    int unit;
+    char *our_name;
+    int digest;
+{
+    chap_state *cstate = &chap[unit];
+
+    cstate->resp_name = our_name;
+    cstate->resp_type = digest;
+
+    if (cstate->clientstate == CHAPCS_INITIAL ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->clientstate = CHAPCS_PENDING;
+	return;
+    }
+
+    /*
+     * We get here as a result of LCP coming up.
+     * So even if CHAP was open before, we will 
+     * have to re-authenticate ourselves.
+     */
+    cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void
+ChapAuthPeer(unit, our_name, digest)
+    int unit;
+    char *our_name;
+    int digest;
+{
+    chap_state *cstate = &chap[unit];
+  
+    cstate->chal_name = our_name;
+    cstate->chal_type = digest;
+
+    if (cstate->serverstate == CHAPSS_INITIAL ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->serverstate = CHAPSS_PENDING;
+	return;
+    }
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);		/* crank it up dude! */
+    cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void
+ChapChallengeTimeout(arg)
+    void *arg;
+{
+    chap_state *cstate = (chap_state *) arg;
+  
+    /* if we aren't sending challenges, don't worry.  then again we */
+    /* probably shouldn't be here either */
+    if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+	cstate->serverstate != CHAPSS_RECHALLENGE)
+	return;
+
+    if (cstate->chal_transmits >= cstate->max_transmits) {
+	/* give up on peer */
+	syslog(LOG_ERR, "Peer failed to respond to CHAP challenge");
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->unit, PPP_CHAP);
+	return;
+    }
+
+    ChapSendChallenge(cstate);		/* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(arg)
+    void *arg;
+{
+    chap_state *cstate = (chap_state *) arg;
+
+    /* if we aren't sending a response, don't worry. */
+    if (cstate->clientstate != CHAPCS_RESPONSE)
+	return;
+
+    ChapSendResponse(cstate);		/* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(arg)
+    void *arg;
+{
+    chap_state *cstate = (chap_state *) arg;
+
+    /* if we aren't sending a response, don't worry. */
+    if (cstate->serverstate != CHAPSS_OPEN)
+	return;
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);
+    cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+static void
+ChapLowerUp(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+  
+    if (cstate->clientstate == CHAPCS_INITIAL)
+	cstate->clientstate = CHAPCS_CLOSED;
+    else if (cstate->clientstate == CHAPCS_PENDING)
+	cstate->clientstate = CHAPCS_LISTEN;
+
+    if (cstate->serverstate == CHAPSS_INITIAL)
+	cstate->serverstate = CHAPSS_CLOSED;
+    else if (cstate->serverstate == CHAPSS_PENDING) {
+	ChapGenChallenge(cstate);
+	ChapSendChallenge(cstate);
+	cstate->serverstate = CHAPSS_INITIAL_CHAL;
+    }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+ChapLowerDown(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+  
+    /* Timeout(s) pending?  Cancel if so. */
+    if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+	cstate->serverstate == CHAPSS_RECHALLENGE)
+	UNTIMEOUT(ChapChallengeTimeout, cstate);
+    else if (cstate->serverstate == CHAPSS_OPEN
+	     && cstate->chal_interval != 0)
+	UNTIMEOUT(ChapRechallenge, cstate);
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void
+ChapProtocolReject(unit)
+    int unit;
+{
+    chap_state *cstate = &chap[unit];
+
+    if (cstate->serverstate != CHAPSS_INITIAL &&
+	cstate->serverstate != CHAPSS_CLOSED)
+	auth_peer_fail(unit, PPP_CHAP);
+    if (cstate->clientstate != CHAPCS_INITIAL &&
+	cstate->clientstate != CHAPCS_CLOSED)
+	auth_withpeer_fail(unit, PPP_CHAP);
+    ChapLowerDown(unit);		/* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+static void
+ChapInput(unit, inpacket, packet_len)
+    int unit;
+    u_char *inpacket;
+    int packet_len;
+{
+    chap_state *cstate = &chap[unit];
+    u_char *inp;
+    u_char code, id;
+    int len;
+  
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (packet_len < CHAP_HEADERLEN) {
+	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < CHAP_HEADERLEN) {
+	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length."));
+	return;
+    }
+    if (len > packet_len) {
+	CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet."));
+	return;
+    }
+    len -= CHAP_HEADERLEN;
+  
+    /*
+     * Action depends on code (as in fact it usually does :-).
+     */
+    switch (code) {
+    case CHAP_CHALLENGE:
+	ChapReceiveChallenge(cstate, inp, id, len);
+	break;
+    
+    case CHAP_RESPONSE:
+	ChapReceiveResponse(cstate, inp, id, len);
+	break;
+    
+    case CHAP_FAILURE:
+	ChapReceiveFailure(cstate, inp, id, len);
+	break;
+
+    case CHAP_SUCCESS:
+	ChapReceiveSuccess(cstate, inp, id, len);
+	break;
+
+    default:				/* Need code reject? */
+	syslog(LOG_WARNING, "Unknown CHAP code (%d) received.", code);
+	break;
+    }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void
+ChapReceiveChallenge(cstate, inp, id, len)
+    chap_state *cstate;
+    u_char *inp;
+    int id;
+    int len;
+{
+    int rchallenge_len;
+    u_char *rchallenge;
+    int secret_len;
+    char secret[MAXSECRETLEN];
+    char rhostname[256];
+    MD5_CTX mdContext;
+    u_char hash[MD5_SIGNATURE_SIZE];
+ 
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.", id));
+    if (cstate->clientstate == CHAPCS_CLOSED ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d",
+		   cstate->clientstate));
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+
+    GETCHAR(rchallenge_len, inp);
+    len -= sizeof (u_char) + rchallenge_len;	/* now name field length */
+    if (len < 0) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+    rchallenge = inp;
+    INCPTR(rchallenge_len, inp);
+
+    if (len >= sizeof(rhostname))
+	len = sizeof(rhostname) - 1;
+    BCOPY(inp, rhostname, len);
+    rhostname[len] = '\000';
+
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'",
+	       rhostname));
+
+    /* Microsoft doesn't send their name back in the PPP packet */
+    if (remote_name[0] != 0 && (explicit_remote || rhostname[0] == 0)) {
+	strncpy(rhostname, remote_name, sizeof(rhostname));
+	rhostname[sizeof(rhostname) - 1] = 0;
+	CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name",
+		   rhostname));
+    }
+
+    /* get secret for authenticating ourselves with the specified host */
+    if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+		    secret, &secret_len, 0)) {
+	secret_len = 0;		/* assume null secret if can't find one */
+	syslog(LOG_WARNING, "No CHAP secret found for authenticating us to %s",
+	       rhostname);
+    }
+
+    /* cancel response send timeout if necessary */
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->resp_id = id;
+    cstate->resp_transmits = 0;
+
+    /*  generate MD based on negotiated type */
+    switch (cstate->resp_type) { 
+
+    case CHAP_DIGEST_MD5:
+	MD5Init(&mdContext);
+	MD5Update(&mdContext, &cstate->resp_id, 1);
+	MD5Update(&mdContext, secret, secret_len);
+	MD5Update(&mdContext, rchallenge, rchallenge_len);
+	MD5Final(hash, &mdContext);
+	BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+	cstate->resp_length = MD5_SIGNATURE_SIZE;
+	break;
+
+#ifdef CHAPMS
+    case CHAP_MICROSOFT:
+	ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+	break;
+#endif
+
+    default:
+	CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->resp_type));
+	return;
+    }
+
+    BZERO(secret, sizeof(secret));
+    ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(cstate, inp, id, len)
+    chap_state *cstate;
+    u_char *inp;
+    int id;
+    int len;
+{
+    u_char *remmd, remmd_len;
+    int secret_len, old_state;
+    int code;
+    char rhostname[256];
+    MD5_CTX mdContext;
+    char secret[MAXSECRETLEN];
+    u_char hash[MD5_SIGNATURE_SIZE];
+
+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.", id));
+
+    if (cstate->serverstate == CHAPSS_CLOSED ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d",
+		   cstate->serverstate));
+	return;
+    }
+
+    if (id != cstate->chal_id)
+	return;			/* doesn't match ID of last challenge */
+
+    /*
+     * If we have received a duplicate or bogus Response,
+     * we have to send the same answer (Success/Failure)
+     * as we did for the first Response we saw.
+     */
+    if (cstate->serverstate == CHAPSS_OPEN) {
+	ChapSendStatus(cstate, CHAP_SUCCESS);
+	return;
+    }
+    if (cstate->serverstate == CHAPSS_BADAUTH) {
+	ChapSendStatus(cstate, CHAP_FAILURE);
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+	return;
+    }
+    GETCHAR(remmd_len, inp);		/* get length of MD */
+    remmd = inp;			/* get pointer to MD */
+    INCPTR(remmd_len, inp);
+
+    len -= sizeof (u_char) + remmd_len;
+    if (len < 0) {
+	CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet."));
+	return;
+    }
+
+    UNTIMEOUT(ChapChallengeTimeout, cstate);
+
+    if (len >= sizeof(rhostname))
+	len = sizeof(rhostname) - 1;
+    BCOPY(inp, rhostname, len);
+    rhostname[len] = '\000';
+
+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s",
+	       rhostname));
+
+    /*
+     * Get secret for authenticating them with us,
+     * do the hash ourselves, and compare the result.
+     */
+    code = CHAP_FAILURE;
+    if (!get_secret(cstate->unit, rhostname, cstate->chal_name,
+		   secret, &secret_len, 1)) {
+	syslog(LOG_WARNING, "No CHAP secret found for authenticating %s",
+	       rhostname);
+    } else {
+
+	/*  generate MD based on negotiated type */
+	switch (cstate->chal_type) { 
+
+	case CHAP_DIGEST_MD5:		/* only MD5 is defined for now */
+	    if (remmd_len != MD5_SIGNATURE_SIZE)
+		break;			/* it's not even the right length */
+	    MD5Init(&mdContext);
+	    MD5Update(&mdContext, &cstate->chal_id, 1);
+	    MD5Update(&mdContext, secret, secret_len);
+	    MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+	    MD5Final(hash, &mdContext); 
+
+	    /* compare local and remote MDs and send the appropriate status */
+	    if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+		code = CHAP_SUCCESS;	/* they are the same! */
+	    break;
+
+	default:
+	    CHAPDEBUG((LOG_INFO, "unknown digest type %d", cstate->chal_type));
+	}
+    }
+
+    BZERO(secret, sizeof(secret));
+    ChapSendStatus(cstate, code);
+
+    if (code == CHAP_SUCCESS) {
+	old_state = cstate->serverstate;
+	cstate->serverstate = CHAPSS_OPEN;
+	if (old_state == CHAPSS_INITIAL_CHAL) {
+	    auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+	}
+	if (cstate->chal_interval != 0)
+	    TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+	syslog(LOG_NOTICE, "CHAP peer authentication succeeded for %s",
+	       rhostname);
+
+    } else {
+	syslog(LOG_ERR, "CHAP peer authentication failed for remote host %s",
+	       rhostname);
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->unit, PPP_CHAP);
+    }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void
+ChapReceiveSuccess(cstate, inp, id, len)
+    chap_state *cstate;
+    u_char *inp;
+    u_char id;
+    int len;
+{
+
+    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.", id));
+
+    if (cstate->clientstate == CHAPCS_OPEN)
+	/* presumably an answer to a duplicate response */
+	return;
+
+    if (cstate->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n",
+		   cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    cstate->clientstate = CHAPCS_OPEN;
+
+    auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void
+ChapReceiveFailure(cstate, inp, id, len)
+    chap_state *cstate;
+    u_char *inp;
+    u_char id;
+    int len;
+{
+    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.", id));
+
+    if (cstate->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n",
+		   cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    syslog(LOG_ERR, "CHAP authentication failed");
+    auth_withpeer_fail(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void
+ChapSendChallenge(cstate)
+    chap_state *cstate;
+{
+    u_char *outp;
+    int chal_len, name_len;
+    int outlen;
+
+    chal_len = cstate->chal_len;
+    name_len = strlen(cstate->chal_name);
+    outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);		/* paste in a CHAP header */
+
+    PUTCHAR(CHAP_CHALLENGE, outp);
+    PUTCHAR(cstate->chal_id, outp);
+    PUTSHORT(outlen, outp);
+
+    PUTCHAR(chal_len, outp);		/* put length of challenge */
+    BCOPY(cstate->challenge, outp, chal_len);
+    INCPTR(chal_len, outp);
+
+    BCOPY(cstate->chal_name, outp, name_len);	/* append hostname */
+
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+  
+    CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.", cstate->chal_id));
+
+    TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+    ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void
+ChapSendStatus(cstate, code)
+    chap_state *cstate;
+    int code;
+{
+    u_char *outp;
+    int outlen, msglen;
+    char msg[256];
+
+    if (code == CHAP_SUCCESS)
+	sprintf(msg, "Welcome to %s.", cyg_ppp_hostname);
+    else
+	sprintf(msg, "I don't like you.  Go 'way.");
+    msglen = strlen(msg);
+
+    outlen = CHAP_HEADERLEN + msglen;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);	/* paste in a header */
+  
+    PUTCHAR(code, outp);
+    PUTCHAR(cstate->chal_id, outp);
+    PUTSHORT(outlen, outp);
+    BCOPY(msg, outp, msglen);
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+  
+    CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.", code,
+	       cstate->chal_id));
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len.  The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void
+ChapGenChallenge(cstate)
+    chap_state *cstate;
+{
+    int chal_len;
+    u_char *ptr = cstate->challenge;
+    unsigned int i;
+
+    /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
+       MAX_CHALLENGE_LENGTH */  
+    chal_len =  (unsigned) ((drand48() *
+			     (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+			    MIN_CHALLENGE_LENGTH);
+    cstate->chal_len = chal_len;
+    cstate->chal_id = ++cstate->id;
+    cstate->chal_transmits = 0;
+
+    /* generate a random string */
+    for (i = 0; i < chal_len; i++ )
+	*ptr++ = (char) (drand48() * 0xff);
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void
+ChapSendResponse(cstate)
+    chap_state *cstate;
+{
+    u_char *outp;
+    int outlen, md_len, name_len;
+
+    md_len = cstate->resp_length;
+    name_len = strlen(cstate->resp_name);
+    outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);
+
+    PUTCHAR(CHAP_RESPONSE, outp);	/* we are a response */
+    PUTCHAR(cstate->resp_id, outp);	/* copy id from challenge packet */
+    PUTSHORT(outlen, outp);		/* packet length */
+
+    PUTCHAR(md_len, outp);		/* length of MD */
+    BCOPY(cstate->response, outp, md_len);	/* copy MD to buffer */
+    INCPTR(md_len, outp);
+
+    BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+    /* send the packet */
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    cstate->clientstate = CHAPCS_RESPONSE;
+    TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+    ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static char *ChapCodenames[] = {
+    "Challenge", "Response", "Success", "Failure"
+};
+
+static int
+ChapPrintPkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len;
+    int clen, nlen;
+    u_char x;
+
+    if (plen < CHAP_HEADERLEN)
+	return 0;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < CHAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+	printer(arg, " %s", ChapCodenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= CHAP_HEADERLEN;
+    switch (code) {
+    case CHAP_CHALLENGE:
+    case CHAP_RESPONSE:
+	if (len < 1)
+	    break;
+	clen = p[0];
+	if (len < clen + 1)
+	    break;
+	++p;
+	nlen = len - clen - 1;
+	printer(arg, " <");
+	for (; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, "%.2x", x);
+	}
+	printer(arg, ">, name = ");
+	print_string((char *)p, nlen, printer, arg);
+	break;
+    case CHAP_FAILURE:
+    case CHAP_SUCCESS:
+	printer(arg, " ");
+	print_string((char *)p, len, printer, arg);
+	break;
+    default:
+	for (clen = len; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, " %.2x", x);
+	}
+    }
+
+    return len + CHAP_HEADERLEN;
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/chap_ms.c
@@ -0,0 +1,384 @@
+//==========================================================================
+//
+//      src/chap_ms.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ *   Implemented LANManager type password response to MS-CHAP challenges.
+ *   Now pppd provides both NT style and LANMan style blocks, and the
+ *   prefered is set by option "ms-lanman". Default is to use NT.
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/chap_ms.c,v 1.8 2000/02/24 21:10:28 markm Exp $";
+#endif
+
+#ifdef CHAPMS
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <syslog.h>
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+#ifndef USE_CRYPT
+#include <openssl/des.h>
+#endif
+
+typedef struct {
+    u_char LANManResp[24];
+    u_char NTResp[24];
+    u_char UseNT;		/* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+   in case this struct gets padded. */
+
+
+static void	ChallengeResponse __P((u_char *, u_char *, u_char *));
+static void	DesEncrypt __P((u_char *, u_char *, u_char *));
+static void	MakeKey __P((u_char *, u_char *));
+static u_char	Get7Bits __P((u_char *, int));
+static void	ChapMS_NT __P((char *, int, char *, int, MS_ChapResponse *));
+#ifdef MSLANMAN
+static void	ChapMS_LANMan __P((char *, int, char *, int, MS_ChapResponse *));
+#endif
+
+#ifdef USE_CRYPT
+static void	Expand __P((u_char *, u_char *));
+static void	Collapse __P((u_char *, u_char *));
+#endif
+
+static void
+ChallengeResponse(challenge, pwHash, response)
+    u_char *challenge;	/* IN   8 octets */
+    u_char *pwHash;	/* IN  16 octets */
+    u_char *response;	/* OUT 24 octets */
+{
+    char    ZPasswordHash[21];
+
+    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+    BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
+
+#if 0
+    log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);
+#endif
+
+    DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
+    DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
+    DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+    log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void
+DesEncrypt(clear, key, cipher)
+    u_char *clear;	/* IN  8 octets */
+    u_char *key;	/* IN  7 octets */
+    u_char *cipher;	/* OUT 8 octets */
+{
+    u_char des_key[8];
+    u_char crypt_key[66];
+    u_char des_input[66];
+
+    MakeKey(key, des_key);
+
+    Expand(des_key, crypt_key);
+    setkey(crypt_key);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
+	       clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+    Expand(clear, des_input);
+    encrypt(des_input, 0);
+    Collapse(des_input, cipher);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
+	       cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void
+DesEncrypt(clear, key, cipher)
+    u_char *clear;	/* IN  8 octets */
+    u_char *key;	/* IN  7 octets */
+    u_char *cipher;	/* OUT 8 octets */
+{
+    des_cblock		des_key;
+    des_key_schedule	key_schedule;
+
+    MakeKey(key, des_key);
+
+    des_set_key(&des_key, key_schedule);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X",
+	       clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));
+#endif
+
+    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X",
+	       cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char Get7Bits(input, startBit)
+    u_char *input;
+    int startBit;
+{
+    register unsigned int	word;
+
+    word  = (unsigned)input[startBit / 8] << 8;
+    word |= (unsigned)input[startBit / 8 + 1];
+
+    word >>= 15 - (startBit % 8 + 7);
+
+    return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void Expand(in, out)
+    u_char *in;
+    u_char *out;
+{
+        int j, c;
+        int i;
+
+        for(i = 0; i < 64; in++){
+		c = *in;
+                for(j = 7; j >= 0; j--)
+                        *out++ = (c >> j) & 01;
+                i += 8;
+        }
+}
+
+/* The inverse of Expand
+ */
+static void Collapse(in, out)
+    u_char *in;
+    u_char *out;
+{
+        int j;
+        int i;
+	unsigned int c;
+
+	for (i = 0; i < 64; i += 8, out++) {
+	    c = 0;
+	    for (j = 7; j >= 0; j--, in++)
+		c |= *in << j;
+	    *out = c & 0xff;
+	}
+}
+#endif
+
+static void MakeKey(key, des_key)
+    u_char *key;	/* IN  56 bit DES key missing parity bits */
+    u_char *des_key;	/* OUT 64 bit DES key with parity bits added */
+{
+    des_key[0] = Get7Bits(key,  0);
+    des_key[1] = Get7Bits(key,  7);
+    des_key[2] = Get7Bits(key, 14);
+    des_key[3] = Get7Bits(key, 21);
+    des_key[4] = Get7Bits(key, 28);
+    des_key[5] = Get7Bits(key, 35);
+    des_key[6] = Get7Bits(key, 42);
+    des_key[7] = Get7Bits(key, 49);
+
+#ifndef USE_CRYPT
+    des_set_odd_parity((des_cblock *)des_key);
+#endif
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X",
+	       key[0], key[1], key[2], key[3], key[4], key[5], key[6]));
+    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X",
+	       des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));
+#endif
+}
+
+static void
+ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+    MS_ChapResponse    *response;
+{
+    int			i;
+    MD4_CTX		md4Context;
+    u_char		hash[MD4_SIGNATURE_SIZE];
+    u_char		unicodePassword[MAX_NT_PASSWORD * 2];
+
+    /* Initialize the Unicode version of the secret (== password). */
+    /* This implicitly supports 8-bit ISO8859/1 characters. */
+    BZERO(unicodePassword, sizeof(unicodePassword));
+    for (i = 0; i < secret_len; i++)
+	unicodePassword[i * 2] = (u_char)secret[i];
+
+    MD4Init(&md4Context);
+    MD4Update(&md4Context, unicodePassword, secret_len * 2);	/* Unicode is 2 bytes/char */
+
+    MD4Final(hash, &md4Context); 	/* Tell MD4 we're done */
+
+    ChallengeResponse(rchallenge, hash, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static void
+ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+    MS_ChapResponse	*response;
+{
+    int			i;
+    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+    u_char		PasswordHash[MD4_SIGNATURE_SIZE];
+
+    /* LANMan password is case insensitive */
+    BZERO(UcasePassword, sizeof(UcasePassword));
+    for (i = 0; i < secret_len; i++)
+       UcasePassword[i] = (u_char)toupper(secret[i]);
+    DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+    DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+    ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+void
+ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
+    chap_state *cstate;
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+{
+    MS_ChapResponse	response;
+#ifdef MSLANMAN
+    extern int ms_lanman;
+#endif
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+    BZERO(&response, sizeof(response));
+
+    /* Calculate both always */
+    ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+    ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+    /* prefered method is set by option  */
+    response.UseNT = !ms_lanman;
+#else
+    response.UseNT = 1;
+#endif
+
+    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+    cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+#endif /* CHAPMS */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/chat.c
@@ -0,0 +1,448 @@
+//==========================================================================
+//
+//      src/chat.c
+//
+//      PPP CHAT scripting
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// Alternative licenses for eCos may be arranged by contacting the
+// copyright holder.
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: nickg
+// Date:         2003-06-08
+// Purpose:      Chat script handling
+// Description: 
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+//=====================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/io_fileio.h>
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "cyg/ppp/syslog.h"
+
+#include <cyg/io/io.h>
+#include <cyg/io/serial.h>
+
+#include <cyg/kernel/kapi.h>
+
+#include <cyg/ppp/ppp.h>
+
+//=====================================================================
+
+//#undef db_printf
+//#define db_printf diag_printf
+
+//=====================================================================
+// Expect return values
+
+#define CHAT_MATCH      0
+#define CHAT_ABORT      1
+#define CHAT_TIMEOUT    2
+#define CHAT_FAIL       -1
+
+//=====================================================================
+// Configuration constants
+
+#define CHAT_MAX_ABORTS CYGNUM_PPP_CHAT_ABORTS_MAX
+#define CHAT_ABORT_SIZE CYGNUM_PPP_CHAT_ABORTS_SIZE
+
+#define CHAT_STRING_LENGTH CYGNUM_PPP_CHAT_STRING_LENGTH
+
+//=====================================================================
+// Local variables
+
+// Array of ABORT strings
+static char cyg_ppp_chat_abort[CHAT_MAX_ABORTS][CHAT_ABORT_SIZE];
+static int cyg_ppp_chat_abort_count;
+
+// Response timeout
+static int cyg_ppp_chat_timeout;
+// timeout alarm
+static cyg_alarm cyg_ppp_chat_alarm_obj;
+static cyg_handle_t cyg_ppp_chat_alarm;
+static cyg_handle_t cyg_ppp_chat_thread;
+
+// Handle on serial device
+static cyg_io_handle_t cyg_ppp_chat_handle;
+
+// String buffers
+static char cyg_ppp_chat_buffer[CHAT_STRING_LENGTH];
+static char cyg_ppp_chat_expect_buffer[CHAT_STRING_LENGTH];
+
+// success indicator
+static int cyg_ppp_chat_success;
+
+//=====================================================================
+// Timeout alarm function
+//
+// The alarm is set whenever we start looking for a match, if the alarm
+// goes off before we find a match, then it kicks the thread out of any
+// wait it is in.
+
+static void chat_alarm(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    db_printf("%s(%d)\n",__PRETTY_FUNCTION__,__LINE__);    
+    cyg_thread_release( cyg_ppp_chat_thread );
+}
+
+//=====================================================================
+// Match
+//
+// Looks for the supplied string in the input. Returns zero on timeout
+// or other error, 1 if a match is found.
+
+static int cyg_ppp_chat_match( char *str )
+{
+    cyg_uint64 trigger = (cyg_ppp_chat_timeout * 100) + cyg_current_time();
+    char *s = cyg_ppp_chat_buffer;
+    int matchlen = strlen(str);
+    int matched = 0;
+    int aborted = 0;
+
+    db_printf("%s(%d) timeout %d trigger %d\n",__PRETTY_FUNCTION__,__LINE__,
+              cyg_ppp_chat_timeout,(long)trigger);    
+    db_printf(" current time %d\n",(long)cyg_current_time());
+    
+    if( matchlen == 0 )
+        return 1;
+    
+    cyg_alarm_initialize( cyg_ppp_chat_alarm,
+                          trigger,
+                          0 );
+
+    while(!(matched || aborted))
+    {
+        Cyg_ErrNo err;
+        char c;
+        cyg_uint32 len = 1;
+        int i;
+
+        err = cyg_io_read( cyg_ppp_chat_handle, &c, &len );
+
+        if( err != 0 )
+        {
+            db_printf("%s(%d) err %d\n",__PRETTY_FUNCTION__,__LINE__,err);
+            break;
+        }
+
+        db_printf("%c",c);        
+
+        *s++ = c;
+
+        // If we have enough characters to match the expect string,
+        // and the current character matches the last character of the
+        // expect string, then it is worth trying to compare the strings.
+        
+        if( s - cyg_ppp_chat_buffer >= matchlen &&
+            c == str[matchlen - 1] &&
+            strncmp( s - matchlen, str, matchlen ) == 0 )
+        {
+            matched = 1;
+            break;
+        }
+
+        for( i = 0 ; i < cyg_ppp_chat_abort_count; i++ )
+        {
+            int abortlen = strlen( cyg_ppp_chat_abort[i] );
+
+            if( s - cyg_ppp_chat_buffer >= abortlen &&
+                strncmp( s - abortlen, cyg_ppp_chat_abort[i], abortlen ) == 0 )
+            {
+                syslog(LOG_ERR,"ABORT: %s\n",cyg_ppp_chat_abort[i]);
+                aborted = 1;
+                break;
+            }
+        }
+
+        // If we have reached the end of the buffer, shuffle it down
+        // leaving the last matchlen characters in place.
+        if( s >= &cyg_ppp_chat_buffer[sizeof(cyg_ppp_chat_buffer)-1] )
+        {
+            strncpy( cyg_ppp_chat_buffer, s-matchlen, matchlen );
+            s = cyg_ppp_chat_buffer + matchlen;
+        }
+    }
+
+    cyg_alarm_disable( cyg_ppp_chat_alarm );
+
+    return matched;
+}
+
+//=====================================================================
+// Send string
+//
+// Send the string to the remote end, dealing with any escapes or
+// special values. We currently implement the "EOT" and "BREAK"
+// strings (or would if the device drivers did), and just the \c
+// escape sequence.
+
+static int cyg_ppp_chat_send( const char *s )
+{
+    cyg_bool crlf = true;
+    
+    db_printf("%s(%d) %s\n",__PRETTY_FUNCTION__,__LINE__,s);    
+    
+    if( strcmp( s, "EOT" ) == 0 )
+    {
+        s = "\x04";
+        crlf = false;
+    }
+    else if( strcmp( s, "BREAK" ) == 0 )
+    {
+        // cannot do this at present
+    }
+
+    for( ; *s != 0 ; s++ )
+    {
+        char c = *s;
+        cyg_uint32 one = 1;
+
+        // Look for escape sequences and process them
+        if( c == '\\' )
+        {
+            c = *++s;
+
+            if( c == 0 )
+                break;
+            
+            switch( c )
+            {
+            case 'c':
+                crlf = false;
+                continue;
+            }
+        }
+
+        cyg_io_write( cyg_ppp_chat_handle, &c, &one );
+    }
+
+    if( crlf )
+    {
+        cyg_uint32 len = 2;
+        s = "\r\n";
+        cyg_io_write( cyg_ppp_chat_handle, s, &len );
+    }
+
+    return 0;
+}
+
+//=====================================================================
+// find_sep
+//
+// Split the pointed-to string at the next '-' character.
+
+static char *find_sep( char **str )
+{
+    char *s = *str;
+    char *res = s;
+
+    if( *s == 0 )
+        return NULL;
+    
+    while( *s != 0 && *s != '-' )
+        s++;
+
+    if( *s == '-' )
+        *s++ = 0;
+
+    *str = s;
+    return res;
+}
+
+
+//=====================================================================
+// expect processing
+//
+// Parse the expect string. The return value indicates what it is: a
+// match string, an ABORT, a TIMEOUT or a failure.
+
+static int cyg_ppp_chat_expect( const char *str )
+{
+    char *expect;
+    char *reply;
+    char *s;
+
+    db_printf("%s(%d) %s\n",__PRETTY_FUNCTION__,__LINE__,str);    
+
+    // Look for command strings
+    if( strcmp( str, "ABORT" ) == 0 )
+        return CHAT_ABORT;
+
+    if( strcmp( str, "TIMEOUT" ) == 0 )
+        return CHAT_TIMEOUT;
+
+    // Copy the string over to a writable buffer, so we can handle the
+    // sub-expect strings
+    strncpy( cyg_ppp_chat_expect_buffer, str, sizeof(cyg_ppp_chat_expect_buffer) );
+    s = cyg_ppp_chat_expect_buffer;
+    
+    while(1)
+    {
+        // Split the string at the next '-'
+        expect = find_sep( &s );
+
+        // All done, it looks like we succeeded!
+        if( expect == NULL )
+            return CHAT_MATCH;
+
+        db_printf("%s(%d) expect %s\n",__PRETTY_FUNCTION__,__LINE__,expect);
+
+        // Get and response string in case the match fails.
+        reply = find_sep( &s );
+
+        db_printf("%s(%d) reply %s\n",__PRETTY_FUNCTION__,__LINE__,reply);            
+
+        // Try a match.
+        if( cyg_ppp_chat_match( expect ) )
+            return CHAT_MATCH;
+
+        // The match failed. If there is no reply string, then the
+        // whole thing has failed.
+        if( reply == NULL )
+            break;
+
+        // Send the reply string an loop around to pick up the next
+        // expect string.
+        cyg_ppp_chat_send( reply );
+    }
+
+    return CHAT_FAIL;
+}
+
+//=====================================================================
+// Chat entry point
+//
+// This is the main CHAT entry point. It is given the name of a device
+// plus a pointer to the expect script in argv format. The device
+// should already have been set up to the correct baud rate, bits,
+// parity, flow control etc.
+
+externC cyg_int32 cyg_ppp_chat( const char *devname,
+                                const char *script[] )
+{
+    const char *s;
+    Cyg_ErrNo err;
+
+    cyg_ppp_chat_success = 0;
+    cyg_ppp_chat_thread = cyg_thread_self();
+    cyg_ppp_chat_abort_count = 0;
+    cyg_ppp_chat_timeout = 45;
+    
+    while ((err = cyg_io_lookup(devname, &cyg_ppp_chat_handle)) < 0) {
+        if (err != 0)
+            syslog(LOG_ERR, "Failed to open %s: %d", devname,err);
+    }
+
+    // Set up timeout alarm.
+    cyg_alarm_create( cyg_real_time_clock(),
+                      chat_alarm,
+                      (cyg_addrword_t)0,
+                      &cyg_ppp_chat_alarm,
+                      &cyg_ppp_chat_alarm_obj);
+
+
+    // Now loop over script handling the elements in turn
+    while( (s = *script++) != NULL && cyg_ppp_chat_success == 0 )
+    {
+        int what = cyg_ppp_chat_expect( s );
+
+        db_printf("%s(%d) what %d\n",__PRETTY_FUNCTION__,__LINE__,what);    
+
+        if( what == CHAT_FAIL )
+        {
+            cyg_ppp_chat_success = 1;
+            break;
+        }
+        
+        if( (s = *script++) != NULL )
+        {
+            if( what == CHAT_MATCH )
+                cyg_ppp_chat_send( s );
+            else switch( what )
+            {
+            case CHAT_ABORT:
+                // An abort string, add it to the table.
+                if( cyg_ppp_chat_abort_count >= CHAT_MAX_ABORTS )
+                {
+                    syslog(LOG_ERR,"Too many ABORT strings\n");
+                }
+                else if( strlen( s ) >= CHAT_ABORT_SIZE )
+                    syslog(LOG_ERR,"Abort string too long\n");
+                else
+                {
+                    strncpy( cyg_ppp_chat_abort[cyg_ppp_chat_abort_count++],
+                             s, CHAT_ABORT_SIZE );
+                }
+                break;
+                
+            case CHAT_TIMEOUT:
+                // A new timeout value
+                cyg_ppp_chat_timeout = atoi( s );
+                db_printf("New timeout >%s< %d\n",s,cyg_ppp_chat_timeout);
+                break;
+            }
+        }
+    }
+
+    // Finally, wait for the serial device to drain 
+    {
+        cyg_uint32 zero = 0;
+        cyg_uint32 len = sizeof(zero);
+        
+        cyg_io_get_config( cyg_ppp_chat_handle,
+                           CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
+                           &zero, &len);
+        
+    }
+    
+    return cyg_ppp_chat_success;
+}
+
+//=====================================================================
+// End of chat.c
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/fsm.c
@@ -0,0 +1,847 @@
+//==========================================================================
+//
+//      src/fsm.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/fsm.c,v 1.8 1999/08/28 01:19:02 peter Exp $";
+#endif
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <cyg/ppp/syslog.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+
+static void fsm_timeout __P((void *));
+static void fsm_rconfreq __P((fsm *, int, u_char *, int));
+static void fsm_rconfack __P((fsm *, int, u_char *, int));
+static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
+static void fsm_rtermreq __P((fsm *, int, u_char *, int));
+static void fsm_rtermack __P((fsm *));
+static void fsm_rcoderej __P((fsm *, u_char *, int));
+static void fsm_sconfreq __P((fsm *, int));
+
+#define PROTO_NAME(f)	((f)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(f)
+    fsm *f;
+{
+    f->state = INITIAL;
+    f->flags = 0;
+    f->id = 0;				/* XXX Start with random id? */
+    f->timeouttime = DEFTIMEOUT;
+    f->maxconfreqtransmits = DEFMAXCONFREQS;
+    f->maxtermtransmits = DEFMAXTERMREQS;
+    f->maxnakloops = DEFMAXNAKLOOPS;
+    f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = CLOSED;
+	break;
+
+    case STARTING:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case CLOSED:
+	f->state = INITIAL;
+	break;
+
+    case STOPPED:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSING:
+	f->state = INITIAL;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = STARTING;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+	f->state = STARTING;
+	break;
+
+    default:
+	FSMDEBUG((LOG_INFO, "%s: Down event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSED:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    case CLOSING:
+	f->state = STOPPING;
+	/* fall through */
+    case STOPPED:
+    case OPENED:
+	if( f->flags & OPT_RESTART ){
+	    fsm_lowerdown(f);
+	    fsm_lowerup(f);
+	}
+	break;
+    }
+}
+
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
+ */
+void
+fsm_close(f, reason)
+    fsm *f;
+    char *reason;
+{
+    f->term_reason = reason;
+    f->term_reason_len = (reason == NULL? 0: strlen(reason));
+    switch( f->state ){
+    case STARTING:
+	f->state = INITIAL;
+	break;
+    case STOPPED:
+	f->state = CLOSED;
+	break;
+    case STOPPING:
+	f->state = CLOSING;
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+    case OPENED:
+	if( f->state != OPENED )
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	else if( f->callbacks->down )
+	    (*f->callbacks->down)(f);	/* Inform upper layers we're down */
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = CLOSING;
+	break;
+    }
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(arg)
+    void *arg;
+{
+    fsm *f = (fsm *) arg;
+
+    switch (f->state) {
+    case CLOSING:
+    case STOPPING:
+	if( f->retransmits <= 0 ){
+	    /*
+	     * We've waited for an ack long enough.  Peer probably heard us.
+	     */
+	    f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+	    if( f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+	} else {
+	    /* Send Terminate-Request */
+	    fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		      (u_char *) f->term_reason, f->term_reason_len);
+	    TIMEOUT(fsm_timeout, f, f->timeouttime);
+	    --f->retransmits;
+	}
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	if (f->retransmits <= 0) {
+	    syslog(LOG_WARNING, "%s: timeout sending Config-Requests",
+		   PROTO_NAME(f));
+	    f->state = STOPPED;
+	    if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+
+	} else {
+	    /* Retransmit the configure-request */
+	    if (f->callbacks->retransmit)
+		(*f->callbacks->retransmit)(f);
+	    fsm_sconfreq(f, 1);		/* Re-send Configure-Request */
+	    if( f->state == ACKRCVD )
+		f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void
+fsm_input(f, inpacket, l)
+    fsm *f;
+    u_char *inpacket;
+    int l;
+{
+    u_char *inp;
+    u_char code, id;
+    int len;
+
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (l < HEADERLEN) {
+	FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.",
+		  f->protocol));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < HEADERLEN) {
+	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
+		  f->protocol));
+	return;
+    }
+    if (len > l) {
+	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
+		  f->protocol));
+	return;
+    }
+    len -= HEADERLEN;		/* subtract header length */
+
+    if( f->state == INITIAL || f->state == STARTING ){
+	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
+		  f->protocol, f->state));
+	return;
+    }
+
+    /*
+     * Action depends on code.
+     */
+    switch (code) {
+    case CONFREQ:
+	fsm_rconfreq(f, id, inp, len);
+	break;
+    
+    case CONFACK:
+	fsm_rconfack(f, id, inp, len);
+	break;
+    
+    case CONFNAK:
+    case CONFREJ:
+	fsm_rconfnakrej(f, code, id, inp, len);
+	break;
+    
+    case TERMREQ:
+	fsm_rtermreq(f, id, inp, len);
+	break;
+    
+    case TERMACK:
+	fsm_rtermack(f);
+	break;
+    
+    case CODEREJ:
+	fsm_rcoderej(f, inp, len);
+	break;
+    
+    default:
+	if( !f->callbacks->extcode
+	   || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+	    fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+	break;
+    }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void
+fsm_rconfreq(f, id, inp, len)
+    fsm *f;
+    u_char id;
+    u_char *inp;
+    int len;
+{
+    int code, reject_if_disagree;
+
+    FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
+    switch( f->state ){
+    case CLOSED:
+	/* Go away, we're closed */
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	return;
+    case CLOSING:
+    case STOPPING:
+	return;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	break;
+
+    case STOPPED:
+	/* Negotiation started by our peer */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+
+    /*
+     * Pass the requested configuration options
+     * to protocol-specific code for checking.
+     */
+    if (f->callbacks->reqci){		/* Check CI */
+	reject_if_disagree = (f->nakloops >= f->maxnakloops);
+	code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+    } else if (len)
+	code = CONFREJ;			/* Reject all CI */
+    else
+	code = CONFACK;
+
+    /* send the Ack, Nak or Rej to the peer */
+    fsm_sdata(f, code, id, inp, len);
+
+    if (code == CONFACK) {
+	if (f->state == ACKRCVD) {
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	    f->state = OPENED;
+	    if (f->callbacks->up)
+		(*f->callbacks->up)(f);	/* Inform upper layers */
+	} else
+	    f->state = ACKSENT;
+	f->nakloops = 0;
+
+    } else {
+	/* we sent CONFACK or CONFREJ */
+	if (f->state != ACKRCVD)
+	    f->state = REQSENT;
+	if( code == CONFNAK )
+	    ++f->nakloops;
+    }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void
+fsm_rconfack(f, id, inp, len)
+    fsm *f;
+    int id;
+    u_char *inp;
+    int len;
+{
+    FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.",
+	      PROTO_NAME(f), id));
+
+    if (id != f->reqid || f->seen_ack)		/* Expected id? */
+	return;					/* Nope, toss... */
+    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+	  (len == 0)) ){
+	/* Ack is bad - ignore it */
+	log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR);
+	FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
+		  PROTO_NAME(f), len));
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->state) {
+    case CLOSED:
+    case STOPPED:
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	break;
+
+    case REQSENT:
+	f->state = ACKRCVD;
+	f->retransmits = f->maxconfreqtransmits;
+	break;
+
+    case ACKRCVD:
+	/* Huh? an extra valid Ack? oh well... */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	fsm_sconfreq(f, 0);
+	f->state = REQSENT;
+	break;
+
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	f->state = OPENED;
+	f->retransmits = f->maxconfreqtransmits;
+	if (f->callbacks->up)
+	    (*f->callbacks->up)(f);	/* Inform upper layers */
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void
+fsm_rconfnakrej(f, code, id, inp, len)
+    fsm *f;
+    int code, id;
+    u_char *inp;
+    int len;
+{
+    int (*proc) __P((fsm *, u_char *, int));
+    int ret;
+
+    FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
+	      PROTO_NAME(f), id));
+
+    if (id != f->reqid || f->seen_ack)	/* Expected id? */
+	return;				/* Nope, toss... */
+    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+    if (!proc || !(ret = proc(f, inp, len))) {
+	/* Nak/reject is bad - ignore it */
+	log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR);
+	FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
+		  PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->state) {
+    case CLOSED:
+    case STOPPED:
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	break;
+
+    case REQSENT:
+    case ACKSENT:
+	/* They didn't agree to what we wanted - try another request */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	if (ret < 0)
+	    f->state = STOPPED;		/* kludge for stopping CCP */
+	else
+	    fsm_sconfreq(f, 0);		/* Send Configure-Request */
+	break;
+
+    case ACKRCVD:
+	/* Got a Nak/reject when we had already had an Ack?? oh well... */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	fsm_sconfreq(f, 0);
+	f->state = REQSENT;
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void
+fsm_rtermreq(f, id, p, len)
+    fsm *f;
+    int id;
+    u_char *p;
+    int len;
+{
+    char str[80];
+
+    FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
+	      PROTO_NAME(f), id));
+
+    switch (f->state) {
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = REQSENT;		/* Start over but keep trying */
+	break;
+
+    case OPENED:
+	if (len > 0) {
+	    fmtmsg(str, sizeof(str), "%0.*v", len, p);
+	    syslog(LOG_INFO, "%s terminated by peer (%s)", PROTO_NAME(f), str);
+	} else
+	    syslog(LOG_INFO, "%s terminated by peer", PROTO_NAME(f));
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	f->retransmits = 0;
+	f->state = STOPPING;
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	break;
+    }
+
+    fsm_sdata(f, TERMACK, id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(f)
+    fsm *f;
+{
+    FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
+
+    switch (f->state) {
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+    case STOPPING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case ACKRCVD:
+	f->state = REQSENT;
+	break;
+
+    case OPENED:
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);
+	break;
+    }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void
+fsm_rcoderej(f, inp, len)
+    fsm *f;
+    u_char *inp;
+    int len;
+{
+    u_char code, id;
+
+    FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
+
+    if (len < HEADERLEN) {
+	FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d",
+	   PROTO_NAME(f), code, id);
+
+    if( f->state == ACKRCVD )
+	f->state = REQSENT;
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void
+fsm_protreject(f)
+    fsm *f;
+{
+    switch( f->state ){
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case CLOSED:
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case STOPPED:
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = STOPPING;
+	break;
+
+    default:
+	FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(f, retransmit)
+    fsm *f;
+    int retransmit;
+{
+    u_char *outp;
+    int cilen;
+
+    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+	/* Not currently negotiating - reset options */
+	if( f->callbacks->resetci )
+	    (*f->callbacks->resetci)(f);
+	f->nakloops = 0;
+    }
+
+    if( !retransmit ){
+	/* New request - reset retransmission counter, use new ID */
+	f->retransmits = f->maxconfreqtransmits;
+	f->reqid = ++f->id;
+    }
+
+    f->seen_ack = 0;
+
+    /*
+     * Make up the request packet
+     */
+    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
+    if( f->callbacks->cilen && f->callbacks->addci ){
+	cilen = (*f->callbacks->cilen)(f);
+	if( cilen > peer_mru[f->unit] - HEADERLEN )
+	    cilen = peer_mru[f->unit] - HEADERLEN;
+	if (f->callbacks->addci)
+	    (*f->callbacks->addci)(f, outp, &cilen);
+    } else
+	cilen = 0;
+
+    /* send the request to our peer */
+    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+    /* start the retransmit timer */
+    --f->retransmits;
+    TIMEOUT(fsm_timeout, f, f->timeouttime);
+
+    FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
+	      PROTO_NAME(f), f->reqid));
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void
+fsm_sdata(f, code, id, data, datalen)
+    fsm *f;
+    u_char code, id;
+    u_char *data;
+    int datalen;
+{
+    u_char *outp;
+    int outlen;
+
+    /* Adjust length to be smaller than MTU */
+    outp = outpacket_buf;
+    if (datalen > peer_mru[f->unit] - HEADERLEN)
+	datalen = peer_mru[f->unit] - HEADERLEN;
+    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+	BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+    outlen = datalen + HEADERLEN;
+    MAKEHEADER(outp, f->protocol);
+    PUTCHAR(code, outp);
+    PUTCHAR(id, outp);
+    PUTSHORT(outlen, outp);
+    output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
+	      PROTO_NAME(f), code, id));
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/if_ppp.c
@@ -0,0 +1,1626 @@
+//==========================================================================
+//
+//      src/if_ppp.c
+//
+//==========================================================================
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Drew D. Perkins
+ * Carnegie Mellon University
+ * 4910 Forbes Ave.
+ * Pittsburgh, PA 15213
+ * (412) 268-8576
+ * ddp@andrew.cmu.edu
+ *
+ * Based on:
+ *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Serial Line interface
+ *
+ * Rick Adams
+ * Center for Seismic Studies
+ * 1300 N 17th Street, Suite 1450
+ * Arlington, Virginia 22209
+ * (703)276-7900
+ * rick@seismo.ARPA
+ * seismo!rick
+ *
+ * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
+ * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
+ *
+ * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
+ * Added VJ tcp header compression; more unified ioctls
+ *
+ * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
+ * Cleaned up a lot of the mbuf-related code to fix bugs that
+ * caused system crashes and packet corruption.  Changed pppstart
+ * so that it doesn't just give up with a collision if the whole
+ * packet doesn't fit in the output ring buffer.
+ *
+ * Added priority queueing for interactive IP packets, following
+ * the model of if_sl.c, plus hooks for bpf.
+ * Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+/* $FreeBSD: src/sys/net/if_ppp.c,v 1.67.2.1 2001/09/11 09:49:54 kris Exp $ */
+/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
+/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+//#include "ppp.h"
+#define NPPP 1
+#define _KERNEL
+
+#if 0 
+#include "opt_inet.h"
+#include "opt_ipx.h"
+#include "opt_ppp.h"
+#endif
+
+#ifdef INET
+#define VJC
+#endif
+#define PPP_COMPRESS
+
+#include <sys/param.h>
+//#include <sys/systm.h>
+//#include <sys/proc.h>
+#define suser(x) 0
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+//#include <sys/filio.h>
+#include <sys/sockio.h>
+//#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+//#include <net/bpf.h>
+
+#if INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#if 0 // IPX
+#include <netipx/ipx.h>
+#include <netipx/ipx_if.h>
+#endif
+
+#ifdef VJC
+#include <cyg/ppp/slcompress.h>
+#endif
+
+#include <cyg/ppp/net/if_ppp.h>
+#include <cyg/ppp/net/if_pppvar.h>
+
+/* minimise diffs */
+#ifndef splsoftnet
+#define splsoftnet	splnet
+#endif
+
+#ifdef PPP_COMPRESS
+#define PACKETPTR	struct mbuf *
+#include <cyg/ppp/net/ppp_comp.h>
+#endif
+
+struct ppp_softc ppp_softc[NPPP];
+
+/* XXX layering violation */
+extern void	pppasyncattach __P((void *));
+
+//static void	pppattach __P((void *));
+void	pppattach __P((void *));
+PSEUDO_SET(pppattach, if_ppp);
+
+static int	pppsioctl __P((struct ifnet *ifp, u_long cmd, caddr_t data));
+static void	pppintr __P((void));
+
+static void	ppp_requeue __P((struct ppp_softc *));
+static void	ppp_ccp __P((struct ppp_softc *, struct mbuf *m, int rcvd));
+static void	ppp_ccp_closed __P((struct ppp_softc *));
+static void	ppp_inproc __P((struct ppp_softc *, struct mbuf *));
+//static void	pppdumpm __P((struct mbuf *m0));
+
+/*
+ * Some useful mbuf macros not in mbuf.h.
+ */
+#define M_IS_CLUSTER(m)	((m)->m_flags & M_EXT)
+
+#define M_DATASTART(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
+	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
+
+#define M_DATASIZE(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
+	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+
+/*
+ * We steal two bits in the mbuf m_flags, to mark high-priority packets
+ * for output, and received packets following lost/corrupted packets.
+ */
+#define M_HIGHPRI	0x2000	/* output packet for sc_fastq */
+#define M_ERRMARK	0x4000	/* steal a bit in mbuf m_flags */
+
+
+#ifdef PPP_COMPRESS
+/*
+ * List of compressors we know about.
+ * We leave some space so maybe we can modload compressors.
+ */
+
+extern struct compressor ppp_bsd_compress;
+extern struct compressor ppp_deflate, ppp_deflate_draft;
+
+static struct compressor *ppp_compressors[8] = {
+#if DO_BSD_COMPRESS && defined(PPP_BSDCOMP)
+    &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE && defined(PPP_DEFLATE)
+    &ppp_deflate,
+    &ppp_deflate_draft,
+#endif
+    NULL
+};
+#endif /* PPP_COMPRESS */
+
+/*
+ * Called from boot code to establish ppp interfaces.
+ */
+//static void
+void
+pppattach(dummy)
+    void *dummy;
+{
+    register struct ppp_softc *sc;
+    register int i = 0;
+
+    for (sc = ppp_softc; i < NPPP; sc++) {
+	sc->sc_if.if_name = "ppp";
+	sc->sc_if.if_unit = i++;
+	sc->sc_if.if_mtu = PPP_MTU;
+	sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+	sc->sc_if.if_type = IFT_PPP;
+	sc->sc_if.if_hdrlen = PPP_HDRLEN;
+	sc->sc_if.if_ioctl = pppsioctl;
+	sc->sc_if.if_output = pppoutput;
+	sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
+//        sc->sc_fd = -1;
+	if_attach(&sc->sc_if);
+#ifdef BPF
+	bpfattach(&sc->sc_if, DLT_PPP, PPP_HDRLEN);
+#endif
+    }
+    register_netisr(NETISR_PPP, pppintr);
+    /*
+     * XXX layering violation - if_ppp can work over any lower level
+     * transport that cares to attach to it.
+     */
+//    pppasyncattach(dummy);
+}
+
+/*
+ * Allocate a ppp interface unit and initialize it.
+ */
+struct ppp_softc *
+pppalloc(pid)
+    pid_t pid;
+{
+    int nppp, i;
+    struct ppp_softc *sc;
+
+#ifndef __ECOS
+    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
+	if (sc->sc_xfer == pid) {
+	    sc->sc_xfer = 0;
+	    return sc;
+	}
+#endif
+    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
+	if (sc->sc_devp == NULL)
+	    break;
+
+    if (nppp >= NPPP)
+	return NULL;
+
+    sc->sc_flags = 0;
+    sc->sc_mru = PPP_MRU;
+    sc->sc_relinq = NULL;
+    bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
+#ifdef VJC
+    MALLOC(sc->sc_comp, struct slcompress *, sizeof(struct slcompress),
+	   M_DEVBUF, M_NOWAIT);
+    if (sc->sc_comp)
+	sl_compress_init(sc->sc_comp, -1);
+#endif
+#ifdef PPP_COMPRESS
+    sc->sc_xc_state = NULL;
+    sc->sc_rc_state = NULL;
+#endif /* PPP_COMPRESS */
+    for (i = 0; i < NUM_NP; ++i)
+	sc->sc_npmode[i] = NPMODE_ERROR;
+    sc->sc_npqueue = NULL;
+    sc->sc_npqtail = &sc->sc_npqueue;
+    sc->sc_last_sent = sc->sc_last_recv = time_second;
+
+    return sc;
+}
+
+/*
+ * Deallocate a ppp unit.  Must be called at splsoftnet or higher.
+ */
+void
+pppdealloc(sc)
+    struct ppp_softc *sc;
+{
+    struct mbuf *m;
+
+    if_down(&sc->sc_if);
+    sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+    getmicrotime(&sc->sc_if.if_lastchange);
+#if 1 //def __NEVER__
+    sc->sc_devp = NULL;
+#else
+    sc->sc_fd = -1;
+#endif
+    sc->sc_xfer = 0;
+    for (;;) {
+	IF_DEQUEUE(&sc->sc_rawq, m);
+	if (m == NULL)
+	    break;
+	m_freem(m);
+    }
+    for (;;) {
+	IF_DEQUEUE(&sc->sc_inq, m);
+	if (m == NULL)
+	    break;
+	m_freem(m);
+    }
+    for (;;) {
+	IF_DEQUEUE(&sc->sc_fastq, m);
+	if (m == NULL)
+	    break;
+	m_freem(m);
+    }
+    while ((m = sc->sc_npqueue) != NULL) {
+	sc->sc_npqueue = m->m_nextpkt;
+	m_freem(m);
+    }
+#ifdef PPP_COMPRESS
+    ppp_ccp_closed(sc);
+    sc->sc_xc_state = NULL;
+    sc->sc_rc_state = NULL;
+#endif /* PPP_COMPRESS */
+#ifdef PPP_FILTER
+    if (sc->sc_pass_filt.bf_insns != 0) {
+	FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF);
+	sc->sc_pass_filt.bf_insns = 0;
+	sc->sc_pass_filt.bf_len = 0;
+    }
+    if (sc->sc_active_filt.bf_insns != 0) {
+	FREE(sc->sc_active_filt.bf_insns, M_DEVBUF);
+	sc->sc_active_filt.bf_insns = 0;
+	sc->sc_active_filt.bf_len = 0;
+    }
+#endif /* PPP_FILTER */
+#ifdef VJC
+    if (sc->sc_comp != 0) {
+	FREE(sc->sc_comp, M_DEVBUF);
+	sc->sc_comp = 0;
+    }
+#endif
+}
+
+/*
+ * Ioctl routine for generic ppp devices.
+ */
+int
+pppioctl(sc, cmd, data, flag, p)
+    struct ppp_softc *sc;
+    u_long cmd;
+    caddr_t data;
+    int flag;
+    struct proc *p;
+{
+    int s, error, flags, mru, npx;
+    u_int nb;
+    struct ppp_option_data *odp;
+    struct compressor **cp;
+    struct npioctl *npi;
+    time_t t;
+#ifdef PPP_FILTER
+    struct bpf_program *bp, *nbp;
+    struct bpf_insn *newcode, *oldcode;
+    int newcodelen;
+#endif /* PPP_FILTER */
+#ifdef	PPP_COMPRESS
+    u_char ccp_option[CCP_MAX_OPTION_LENGTH];
+#endif
+
+    switch (cmd) {
+    case FIONREAD:
+	*(int *)data = sc->sc_inq.ifq_len;
+	break;
+
+    case PPPIOCGUNIT:
+	*(int *)data = sc->sc_if.if_unit;
+	break;
+
+    case PPPIOCGFLAGS:
+	*(u_int *)data = sc->sc_flags;
+	break;
+
+    case PPPIOCSFLAGS:
+	if ((error = suser(p)) != 0)
+	    return (error);
+	flags = *(int *)data & SC_MASK;
+	s = splsoftnet();
+#ifdef PPP_COMPRESS
+	if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
+	    ppp_ccp_closed(sc);
+#endif
+	splimp();
+	sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
+	splx(s);
+	break;
+
+    case PPPIOCSMRU:
+	if ((error = suser(p)) != 0)
+	    return (error);
+	mru = *(int *)data;
+	if (mru >= PPP_MRU && mru <= PPP_MAXMRU)
+	    sc->sc_mru = mru;
+	break;
+
+    case PPPIOCGMRU:
+	*(int *)data = sc->sc_mru;
+	break;
+
+#ifdef VJC
+    case PPPIOCSMAXCID:
+	if ((error = suser(p)) != 0)
+	    return (error);
+	if (sc->sc_comp) {
+	    s = splsoftnet();
+	    sl_compress_init(sc->sc_comp, *(int *)data);
+	    splx(s);
+	}
+	break;
+#endif
+
+    case PPPIOCXFERUNIT:
+	if ((error = suser(p)) != 0)
+	    return (error);
+//	sc->sc_xfer = p->p_pid;
+        sc->sc_xfer = 0;
+	break;
+
+#ifdef PPP_COMPRESS
+    case PPPIOCSCOMPRESS:
+	if ((error = suser(p)) != 0)
+	    return (error);
+	odp = (struct ppp_option_data *) data;
+	nb = odp->length;
+	if (nb > sizeof(ccp_option))
+	    nb = sizeof(ccp_option);
+	if ((error = copyin(odp->ptr, ccp_option, nb)) != 0)
+	    return (error);
+	if (ccp_option[1] < 2)	/* preliminary check on the length byte */
+	    return (EINVAL);
+	for (cp = ppp_compressors; *cp != NULL; ++cp)
+	    if ((*cp)->compress_proto == ccp_option[0]) {
+		/*
+		 * Found a handler for the protocol - try to allocate
+		 * a compressor or decompressor.
+		 */
+		error = 0;
+		if (odp->transmit) {
+		    s = splsoftnet();
+		    if (sc->sc_xc_state != NULL)
+			(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
+		    sc->sc_xcomp = *cp;
+		    sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
+		    if (sc->sc_xc_state == NULL) {
+			if (sc->sc_flags & SC_DEBUG)
+			    diag_printf("ppp%d: comp_alloc failed\n",
+			       sc->sc_if.if_unit);
+			error = ENOBUFS;
+		    }
+		    splimp();
+		    sc->sc_flags &= ~SC_COMP_RUN;
+		    splx(s);
+		} else {
+		    s = splsoftnet();
+		    if (sc->sc_rc_state != NULL)
+			(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
+		    sc->sc_rcomp = *cp;
+		    sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
+		    if (sc->sc_rc_state == NULL) {
+			if (sc->sc_flags & SC_DEBUG)
+			    diag_printf("ppp%d: decomp_alloc failed\n",
+			       sc->sc_if.if_unit);
+			error = ENOBUFS;
+		    }
+		    splimp();
+		    sc->sc_flags &= ~SC_DECOMP_RUN;
+		    splx(s);
+		}
+		return (error);
+	    }
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("ppp%d: no compressor for [%x %x %x], %x\n",
+		   sc->sc_if.if_unit, ccp_option[0], ccp_option[1],
+		   ccp_option[2], nb);
+	return (EINVAL);	/* no handler found */
+#endif /* PPP_COMPRESS */
+
+    case PPPIOCGNPMODE:
+    case PPPIOCSNPMODE:
+	npi = (struct npioctl *) data;
+	switch (npi->protocol) {
+	case PPP_IP:
+	    npx = NP_IP;
+	    break;
+	default:
+	    return EINVAL;
+	}
+	if (cmd == PPPIOCGNPMODE) {
+	    npi->mode = sc->sc_npmode[npx];
+	} else {
+	    if ((error = suser(p)) != 0)
+		return (error);
+	    if (npi->mode != sc->sc_npmode[npx]) {
+		s = splsoftnet();
+		sc->sc_npmode[npx] = npi->mode;
+		if (npi->mode != NPMODE_QUEUE) {
+		    ppp_requeue(sc);
+		    (*sc->sc_start)(sc);
+		}
+		splx(s);
+	    }
+	}
+	break;
+
+    case PPPIOCGIDLE:
+	s = splsoftnet();
+	t = time_second;
+	((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
+	((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
+	splx(s);
+	break;
+
+#ifdef PPP_FILTER
+    case PPPIOCSPASS:
+    case PPPIOCSACTIVE:
+	nbp = (struct bpf_program *) data;
+	if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
+	    return EINVAL;
+	newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
+	if (newcodelen != 0) {
+	    MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK);
+	    if (newcode == 0) {
+		return EINVAL;		/* or sumpin */
+	    }
+	    if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode,
+			       newcodelen)) != 0) {
+		FREE(newcode, M_DEVBUF);
+		return error;
+	    }
+	    if (!bpf_validate(newcode, nbp->bf_len)) {
+		FREE(newcode, M_DEVBUF);
+		return EINVAL;
+	    }
+	} else
+	    newcode = 0;
+	bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt;
+	oldcode = bp->bf_insns;
+	s = splimp();
+	bp->bf_len = nbp->bf_len;
+	bp->bf_insns = newcode;
+	splx(s);
+	if (oldcode != 0)
+	    FREE(oldcode, M_DEVBUF);
+	break;
+#endif
+
+    default:
+//	return (ENOIOCTL);
+        return ENOSYS;
+    }
+    return (0);
+}
+
+/*
+ * Process an ioctl request to the ppp network interface.
+ */
+static int
+pppsioctl(ifp, cmd, data)
+    register struct ifnet *ifp;
+    u_long cmd;
+    caddr_t data;
+{
+//    struct proc *p = curproc;	/* XXX */
+    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
+    register struct ifaddr *ifa = (struct ifaddr *)data;
+    register struct ifreq *ifr = (struct ifreq *)data;
+    struct ppp_stats *psp;
+#ifdef	PPP_COMPRESS
+    struct ppp_comp_stats *pcp;
+#endif
+    int s = splimp(), error = 0;
+
+    switch (cmd) {
+    case SIOCSIFFLAGS:
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
+	    ifp->if_flags &= ~IFF_UP;
+	break;
+
+    case SIOCSIFADDR:
+    case SIOCAIFADDR:
+	switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+	case AF_INET:
+	    break;
+#endif
+#ifdef IPX
+	case AF_IPX:
+	    break;
+#endif
+	default:
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	break;
+
+    case SIOCSIFDSTADDR:
+	switch(ifa->ifa_addr->sa_family) {
+#ifdef INET
+	case AF_INET:
+	    break;
+#endif
+#ifdef IPX
+	case AF_IPX:
+	    break;
+#endif
+	default:
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	break;
+
+    case SIOCSIFMTU:
+	if ((error = suser(p)) != 0)
+	    break;
+	if (ifr->ifr_mtu > PPP_MAXMTU)
+	    error = EINVAL;
+	else {
+	    sc->sc_if.if_mtu = ifr->ifr_mtu;
+	    if (sc->sc_setmtu)
+		    (*sc->sc_setmtu)(sc);
+	}
+	break;
+
+    case SIOCGIFMTU:
+	ifr->ifr_mtu = sc->sc_if.if_mtu;
+	break;
+
+    case SIOCADDMULTI:
+    case SIOCDELMULTI:
+	if (ifr == 0) {
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	switch(ifr->ifr_addr.sa_family) {
+#ifdef INET
+	case AF_INET:
+	    break;
+#endif
+	default:
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	break;
+
+    case SIOCGPPPSTATS:
+	psp = &((struct ifpppstatsreq *) data)->stats;
+	bzero(psp, sizeof(*psp));
+	psp->p = sc->sc_stats;
+#if defined(VJC) && !defined(SL_NO_STATS)
+	if (sc->sc_comp) {
+	    psp->vj.vjs_packets = sc->sc_comp->sls_packets;
+	    psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
+	    psp->vj.vjs_searches = sc->sc_comp->sls_searches;
+	    psp->vj.vjs_misses = sc->sc_comp->sls_misses;
+	    psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin;
+	    psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin;
+	    psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
+	    psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
+	}
+#endif /* VJC */
+	break;
+
+#ifdef PPP_COMPRESS
+    case SIOCGPPPCSTATS:
+	pcp = &((struct ifpppcstatsreq *) data)->stats;
+	bzero(pcp, sizeof(*pcp));
+	if (sc->sc_xc_state != NULL)
+	    (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
+	if (sc->sc_rc_state != NULL)
+	    (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
+	break;
+#endif /* PPP_COMPRESS */
+
+    default:
+	error = ENOTTY;
+    }
+    splx(s);
+    return (error);
+}
+
+/*
+ * Queue a packet.  Start transmission if not active.
+ * Packet is placed in Information field of PPP frame.
+ * Called at splnet as the if->if_output handler.
+ * Called at splnet from pppwrite().
+ */
+int
+pppoutput(ifp, m0, dst, rtp)
+    struct ifnet *ifp;
+    struct mbuf *m0;
+    struct sockaddr *dst;
+    struct rtentry *rtp;
+{
+    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
+    int protocol, address, control;
+    u_char *cp;
+    int s, error;
+    struct ip *ip;
+    struct ifqueue *ifq;
+    enum NPmode mode;
+    int len;
+    struct mbuf *m;
+
+    if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
+	|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
+	error = ENETDOWN;	/* sort of */
+	goto bad;
+    }
+
+    /*
+     * Compute PPP header.
+     */
+    m0->m_flags &= ~M_HIGHPRI;
+    switch (dst->sa_family) {
+#ifdef INET
+    case AF_INET:
+	address = PPP_ALLSTATIONS;
+	control = PPP_UI;
+	protocol = PPP_IP;
+	mode = sc->sc_npmode[NP_IP];
+
+	/*
+	 * If this packet has the "low delay" bit set in the IP header,
+	 * put it on the fastq instead.
+	 */
+	ip = mtod(m0, struct ip *);
+	if (ip->ip_tos & IPTOS_LOWDELAY)
+	    m0->m_flags |= M_HIGHPRI;
+	break;
+#endif
+#ifdef IPX
+    case AF_IPX:
+	/*
+	 * This is pretty bogus.. We dont have an ipxcp module in pppd
+	 * yet to configure the link parameters.  Sigh. I guess a
+	 * manual ifconfig would do....  -Peter
+	 */
+	address = PPP_ALLSTATIONS;
+	control = PPP_UI;
+	protocol = PPP_IPX;
+	mode = NPMODE_PASS;
+	break;
+#endif
+    case AF_UNSPEC:
+	address = PPP_ADDRESS(dst->sa_data);
+	control = PPP_CONTROL(dst->sa_data);
+	protocol = PPP_PROTOCOL(dst->sa_data);
+	mode = NPMODE_PASS;
+	break;
+    default:
+	diag_printf("ppp%d: af%d not supported\n", ifp->if_unit, dst->sa_family);
+	error = EAFNOSUPPORT;
+	goto bad;
+    }
+
+    /*
+     * Drop this packet, or return an error, if necessary.
+     */
+    if (mode == NPMODE_ERROR) {
+	error = ENETDOWN;
+	goto bad;
+    }
+    if (mode == NPMODE_DROP) {
+	error = 0;
+	goto bad;
+    }
+
+    /*
+     * Add PPP header.  If no space in first mbuf, allocate another.
+     * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
+     */
+    if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
+	m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
+	if (m0 == 0) {
+	    error = ENOBUFS;
+	    goto bad;
+	}
+	m0->m_len = 0;
+    } else
+	m0->m_data -= PPP_HDRLEN;
+
+    cp = mtod(m0, u_char *);
+    *cp++ = address;
+    *cp++ = control;
+    *cp++ = protocol >> 8;
+    *cp++ = protocol & 0xff;
+    m0->m_len += PPP_HDRLEN;
+
+    len = 0;
+    for (m = m0; m != 0; m = m->m_next)
+	len += m->m_len;
+
+    if (sc->sc_flags & SC_LOG_OUTPKT) {
+	diag_printf("ppp%d output: ", ifp->if_unit);
+//	pppdumpm(m0);
+    }
+
+    if ((protocol & 0x8000) == 0) {
+#ifdef PPP_FILTER
+	/*
+	 * Apply the pass and active filters to the packet,
+	 * but only if it is a data packet.
+	 */
+	*mtod(m0, u_char *) = 1;	/* indicates outbound */
+	if (sc->sc_pass_filt.bf_insns != 0
+	    && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0,
+			  len, 0) == 0) {
+	    error = 0;		/* drop this packet */
+	    goto bad;
+	}
+
+	/*
+	 * Update the time we sent the most recent packet.
+	 */
+	if (sc->sc_active_filt.bf_insns == 0
+	    || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0))
+	    sc->sc_last_sent = time_second;
+
+	*mtod(m0, u_char *) = address;
+#else
+	/*
+	 * Update the time we sent the most recent data packet.
+	 */
+	sc->sc_last_sent = time_second;
+#endif /* PPP_FILTER */
+    }
+
+#ifdef BPF    
+    /*
+     * See if bpf wants to look at the packet.
+     */
+    if (ifp->if_bpf)
+	bpf_mtap(ifp, m0);
+#endif
+    
+    /*
+     * Put the packet on the appropriate queue.
+     */
+    s = splsoftnet();	/* redundant */
+    if (mode == NPMODE_QUEUE) {
+	/* XXX we should limit the number of packets on this queue */
+	*sc->sc_npqtail = m0;
+	m0->m_nextpkt = NULL;
+	sc->sc_npqtail = &m0->m_nextpkt;
+    } else {
+	/* fastq and if_snd are emptied at spl[soft]net now */
+	ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd;
+	if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
+	    IF_DROP(ifq);
+	    splx(s);
+	    sc->sc_if.if_oerrors++;
+	    sc->sc_stats.ppp_oerrors++;
+	    error = ENOBUFS;
+	    goto bad;
+	}
+	IF_ENQUEUE(ifq, m0);
+	(*sc->sc_start)(sc);
+    }
+    getmicrotime(&ifp->if_lastchange);
+    ifp->if_opackets++;
+    ifp->if_obytes += len;
+
+    splx(s);
+    return (0);
+
+bad:
+    m_freem(m0);
+    return (error);
+}
+
+/*
+ * After a change in the NPmode for some NP, move packets from the
+ * npqueue to the send queue or the fast queue as appropriate.
+ * Should be called at spl[soft]net.
+ */
+static void
+ppp_requeue(sc)
+    struct ppp_softc *sc;
+{
+    struct mbuf *m, **mpp;
+    struct ifqueue *ifq;
+    enum NPmode mode;
+
+    for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
+	switch (PPP_PROTOCOL(mtod(m, u_char *))) {
+	case PPP_IP:
+	    mode = sc->sc_npmode[NP_IP];
+	    break;
+	default:
+	    mode = NPMODE_PASS;
+	}
+
+	switch (mode) {
+	case NPMODE_PASS:
+	    /*
+	     * This packet can now go on one of the queues to be sent.
+	     */
+	    *mpp = m->m_nextpkt;
+	    m->m_nextpkt = NULL;
+	    ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd;
+	    if (IF_QFULL(ifq)) {
+		IF_DROP(ifq);
+		sc->sc_if.if_oerrors++;
+		sc->sc_stats.ppp_oerrors++;
+	    } else
+		IF_ENQUEUE(ifq, m);
+	    break;
+
+	case NPMODE_DROP:
+	case NPMODE_ERROR:
+	    *mpp = m->m_nextpkt;
+	    m_freem(m);
+	    break;
+
+	case NPMODE_QUEUE:
+	    mpp = &m->m_nextpkt;
+	    break;
+	}
+    }
+    sc->sc_npqtail = mpp;
+}
+
+/*
+ * Transmitter has finished outputting some stuff;
+ * remember to call sc->sc_start later at splsoftnet.
+ */
+void
+ppp_restart(sc)
+    struct ppp_softc *sc;
+{
+    int s = splimp();
+
+    sc->sc_flags &= ~SC_TBUSY;
+    schednetisr(NETISR_PPP);
+    splx(s);
+}
+
+
+/*
+ * Get a packet to send.  This procedure is intended to be called at
+ * splsoftnet, since it may involve time-consuming operations such as
+ * applying VJ compression, packet compression, address/control and/or
+ * protocol field compression to the packet.
+ */
+struct mbuf *
+ppp_dequeue(sc)
+    struct ppp_softc *sc;
+{
+    struct mbuf *m, *mp;
+    u_char *cp;
+    int address, control, protocol;
+
+    /*
+     * Grab a packet to send: first try the fast queue, then the
+     * normal queue.
+     */
+    IF_DEQUEUE(&sc->sc_fastq, m);
+    if (m == NULL)
+	IF_DEQUEUE(&sc->sc_if.if_snd, m);
+    if (m == NULL)
+	return NULL;
+
+    ++sc->sc_stats.ppp_opackets;
+
+    /*
+     * Extract the ppp header of the new packet.
+     * The ppp header will be in one mbuf.
+     */
+    cp = mtod(m, u_char *);
+    address = PPP_ADDRESS(cp);
+    control = PPP_CONTROL(cp);
+    protocol = PPP_PROTOCOL(cp);
+
+    switch (protocol) {
+    case PPP_IP:
+#ifdef VJC
+	/*
+	 * If the packet is a TCP/IP packet, see if we can compress it.
+	 */
+	if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
+	    struct ip *ip;
+	    int type;
+
+	    mp = m;
+	    ip = (struct ip *) (cp + PPP_HDRLEN);
+	    if (mp->m_len <= PPP_HDRLEN) {
+		mp = mp->m_next;
+		if (mp == NULL)
+		    break;
+		ip = mtod(mp, struct ip *);
+	    }
+	    /* this code assumes the IP/TCP header is in one non-shared mbuf */
+	    if (ip->ip_p == IPPROTO_TCP) {
+		type = sl_compress_tcp(mp, ip, sc->sc_comp,
+				       !(sc->sc_flags & SC_NO_TCP_CCID));
+		switch (type) {
+		case TYPE_UNCOMPRESSED_TCP:
+		    protocol = PPP_VJC_UNCOMP;
+		    break;
+		case TYPE_COMPRESSED_TCP:
+		    protocol = PPP_VJC_COMP;
+		    cp = mtod(m, u_char *);
+		    cp[0] = address;	/* header has moved */
+		    cp[1] = control;
+		    cp[2] = 0;
+		    break;
+		}
+		cp[3] = protocol;	/* update protocol in PPP header */
+	    }
+	}
+#endif	/* VJC */
+	break;
+
+#ifdef PPP_COMPRESS
+    case PPP_CCP:
+	ppp_ccp(sc, m, 0);
+	break;
+#endif	/* PPP_COMPRESS */
+    }
+
+#ifdef PPP_COMPRESS
+    if (protocol != PPP_LCP && protocol != PPP_CCP
+	&& sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
+	struct mbuf *mcomp = NULL;
+	int slen, clen;
+
+	slen = 0;
+	for (mp = m; mp != NULL; mp = mp->m_next)
+	    slen += mp->m_len;
+	clen = (*sc->sc_xcomp->compress)
+	    (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
+	if (mcomp != NULL) {
+	    if (sc->sc_flags & SC_CCP_UP) {
+		/* Send the compressed packet instead of the original. */
+		m_freem(m);
+		m = mcomp;
+		cp = mtod(m, u_char *);
+		protocol = cp[3];
+	    } else {
+		/* Can't transmit compressed packets until CCP is up. */
+		m_freem(mcomp);
+	    }
+	}
+    }
+#endif	/* PPP_COMPRESS */
+
+    /*
+     * Compress the address/control and protocol, if possible.
+     */
+    if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
+	control == PPP_UI && protocol != PPP_ALLSTATIONS &&
+	protocol != PPP_LCP) {
+	/* can compress address/control */
+	m->m_data += 2;
+	m->m_len -= 2;
+    }
+    if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
+	/* can compress protocol */
+	if (mtod(m, u_char *) == cp) {
+	    cp[2] = cp[1];	/* move address/control up */
+	    cp[1] = cp[0];
+	}
+	++m->m_data;
+	--m->m_len;
+    }
+
+    return m;
+}
+
+/*
+ * Software interrupt routine, called at spl[soft]net.
+ */
+static void
+pppintr()
+{
+    struct ppp_softc *sc;
+    int i, s;
+    struct mbuf *m;
+
+    sc = ppp_softc;
+    for (i = 0; i < NPPP; ++i, ++sc) {
+	s = splimp();
+	if (!(sc->sc_flags & SC_TBUSY)
+	    && (sc->sc_if.if_snd.ifq_head || sc->sc_fastq.ifq_head)) {
+	    sc->sc_flags |= SC_TBUSY;
+	    splx(s);
+	    (*sc->sc_start)(sc);
+	} else
+	    splx(s);
+	for (;;) {
+	    s = splimp();
+	    IF_DEQUEUE(&sc->sc_rawq, m);
+	    splx(s);
+	    if (m == NULL)
+		break;
+	    ppp_inproc(sc, m);
+	}
+    }
+}
+
+#ifdef PPP_COMPRESS
+/*
+ * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
+ * 0 if it is about to be transmitted.
+ */
+static void
+ppp_ccp(sc, m, rcvd)
+    struct ppp_softc *sc;
+    struct mbuf *m;
+    int rcvd;
+{
+    u_char *dp, *ep;
+    struct mbuf *mp;
+    int slen, s;
+
+    /*
+     * Get a pointer to the data after the PPP header.
+     */
+    if (m->m_len <= PPP_HDRLEN) {
+	mp = m->m_next;
+	if (mp == NULL)
+	    return;
+	dp = (mp != NULL)? mtod(mp, u_char *): NULL;
+    } else {
+	mp = m;
+	dp = mtod(mp, u_char *) + PPP_HDRLEN;
+    }
+
+    ep = mtod(mp, u_char *) + mp->m_len;
+    if (dp + CCP_HDRLEN > ep)
+	return;
+    slen = CCP_LENGTH(dp);
+    if (dp + slen > ep) {
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n",
+		   dp, slen, mtod(mp, u_char *), mp->m_len);
+	return;
+    }
+
+    switch (CCP_CODE(dp)) {
+    case CCP_CONFREQ:
+    case CCP_TERMREQ:
+    case CCP_TERMACK:
+	/* CCP must be going down - disable compression */
+	if (sc->sc_flags & SC_CCP_UP) {
+	    s = splimp();
+	    sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
+	    splx(s);
+	}
+	break;
+
+    case CCP_CONFACK:
+	if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
+	    && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
+	    && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
+	    if (!rcvd) {
+		/* we're agreeing to send compressed packets. */
+		if (sc->sc_xc_state != NULL
+		    && (*sc->sc_xcomp->comp_init)
+			(sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
+			 sc->sc_if.if_unit, 0, sc->sc_flags & SC_DEBUG)) {
+		    s = splimp();
+		    sc->sc_flags |= SC_COMP_RUN;
+		    splx(s);
+		}
+	    } else {
+		/* peer is agreeing to send compressed packets. */
+		if (sc->sc_rc_state != NULL
+		    && (*sc->sc_rcomp->decomp_init)
+			(sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
+			 sc->sc_if.if_unit, 0, sc->sc_mru,
+			 sc->sc_flags & SC_DEBUG)) {
+		    s = splimp();
+		    sc->sc_flags |= SC_DECOMP_RUN;
+		    sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+		    splx(s);
+		}
+	    }
+	}
+	break;
+
+    case CCP_RESETACK:
+	if (sc->sc_flags & SC_CCP_UP) {
+	    if (!rcvd) {
+		if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
+		    (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
+	    } else {
+		if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
+		    (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
+		    s = splimp();
+		    sc->sc_flags &= ~SC_DC_ERROR;
+		    splx(s);
+		}
+	    }
+	}
+	break;
+    }
+}
+
+/*
+ * CCP is down; free (de)compressor state if necessary.
+ */
+static void
+ppp_ccp_closed(sc)
+    struct ppp_softc *sc;
+{
+    if (sc->sc_xc_state) {
+	(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
+	sc->sc_xc_state = NULL;
+    }
+    if (sc->sc_rc_state) {
+	(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
+	sc->sc_rc_state = NULL;
+    }
+}
+#endif /* PPP_COMPRESS */
+
+/*
+ * PPP packet input routine.
+ * The caller has checked and removed the FCS and has inserted
+ * the address/control bytes and the protocol high byte if they
+ * were omitted.
+ */
+void
+ppppktin(sc, m, lost)
+    struct ppp_softc *sc;
+    struct mbuf *m;
+    int lost;
+{
+    int s = splimp();
+
+    if (lost)
+	m->m_flags |= M_ERRMARK;
+    IF_ENQUEUE(&sc->sc_rawq, m);
+    schednetisr(NETISR_PPP);
+    splx(s);
+}
+
+/*
+ * Process a received PPP packet, doing decompression as necessary.
+ * Should be called at splsoftnet.
+ */
+#define COMPTYPE(proto)	((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
+			 TYPE_UNCOMPRESSED_TCP)
+
+static void
+ppp_inproc(sc, m)
+    struct ppp_softc *sc;
+    struct mbuf *m;
+{
+    struct ifnet *ifp = &sc->sc_if;
+    struct ifqueue *inq;
+    int s, ilen = 0, xlen, proto, rv;
+    u_char *cp, adrs, ctrl;
+    struct mbuf *mp, *dmp = NULL;
+    u_char *iphdr;
+    u_int hlen;
+
+    sc->sc_stats.ppp_ipackets++;
+
+    if (sc->sc_flags & SC_LOG_INPKT) {
+	ilen = 0;
+	for (mp = m; mp != NULL; mp = mp->m_next)
+	    ilen += mp->m_len;
+	diag_printf("ppp%d: got %d bytes\n", ifp->if_unit, ilen);
+//	pppdumpm(m);
+    }
+
+    cp = mtod(m, u_char *);
+    adrs = PPP_ADDRESS(cp);
+    ctrl = PPP_CONTROL(cp);
+    proto = PPP_PROTOCOL(cp);
+
+    if (m->m_flags & M_ERRMARK) {
+	m->m_flags &= ~M_ERRMARK;
+	s = splimp();
+	sc->sc_flags |= SC_VJ_RESET;
+	splx(s);
+    }
+
+#ifdef PPP_COMPRESS
+    /*
+     * Decompress this packet if necessary, update the receiver's
+     * dictionary, or take appropriate action on a CCP packet.
+     */
+    if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
+	&& !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
+	/* decompress this packet */
+	rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
+	if (rv == DECOMP_OK) {
+	    m_freem(m);
+	    if (dmp == NULL) {
+		/* no error, but no decompressed packet produced */
+		return;
+	    }
+	    m = dmp;
+	    cp = mtod(m, u_char *);
+	    proto = PPP_PROTOCOL(cp);
+
+	} else {
+	    /*
+	     * An error has occurred in decompression.
+	     * Pass the compressed packet up to pppd, which may take
+	     * CCP down or issue a Reset-Req.
+	     */
+	    if (sc->sc_flags & SC_DEBUG)
+		diag_printf("ppp%d: decompress failed %d\n", ifp->if_unit, rv);
+	    s = splimp();
+	    sc->sc_flags |= SC_VJ_RESET;
+	    if (rv == DECOMP_ERROR)
+		sc->sc_flags |= SC_DC_ERROR;
+	    else
+		sc->sc_flags |= SC_DC_FERROR;
+	    splx(s);
+	}
+
+    } else {
+	if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
+	    (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
+	}
+	if (proto == PPP_CCP) {
+	    ppp_ccp(sc, m, 1);
+	}
+    }
+#endif
+
+    ilen = 0;
+    for (mp = m; mp != NULL; mp = mp->m_next)
+	ilen += mp->m_len;
+
+#ifdef VJC
+    if (sc->sc_flags & SC_VJ_RESET) {
+	/*
+	 * If we've missed a packet, we must toss subsequent compressed
+	 * packets which don't have an explicit connection ID.
+	 */
+	if (sc->sc_comp)
+	    sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
+	s = splimp();
+	sc->sc_flags &= ~SC_VJ_RESET;
+	splx(s);
+    }
+
+    /*
+     * See if we have a VJ-compressed packet to uncompress.
+     */
+    if (proto == PPP_VJC_COMP) {
+	if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
+	    goto bad;
+
+	xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
+				      ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
+				      sc->sc_comp, &iphdr, &hlen);
+
+	if (xlen <= 0) {
+	    if (sc->sc_flags & SC_DEBUG)
+		diag_printf("ppp%d: VJ uncompress failed on type comp\n",
+			ifp->if_unit);
+	    goto bad;
+	}
+
+	/* Copy the PPP and IP headers into a new mbuf. */
+	MGETHDR(mp, M_DONTWAIT, MT_DATA);
+	if (mp == NULL)
+	    goto bad;
+	mp->m_len = 0;
+	mp->m_next = NULL;
+	if (hlen + PPP_HDRLEN > MHLEN) {
+	    MCLGET(mp, M_DONTWAIT);
+	    if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
+		m_freem(mp);
+		goto bad;	/* lose if big headers and no clusters */
+	    }
+	}
+	cp = mtod(mp, u_char *);
+	cp[0] = adrs;
+	cp[1] = ctrl;
+	cp[2] = 0;
+	cp[3] = PPP_IP;
+	proto = PPP_IP;
+	bcopy(iphdr, cp + PPP_HDRLEN, hlen);
+	mp->m_len = hlen + PPP_HDRLEN;
+
+	/*
+	 * Trim the PPP and VJ headers off the old mbuf
+	 * and stick the new and old mbufs together.
+	 */
+	m->m_data += PPP_HDRLEN + xlen;
+	m->m_len -= PPP_HDRLEN + xlen;
+	if (m->m_len <= M_TRAILINGSPACE(mp)) {
+	    bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
+	    mp->m_len += m->m_len;
+	    MFREE(m, mp->m_next);
+	} else
+	    mp->m_next = m;
+	m = mp;
+	ilen += hlen - xlen;
+
+    } else if (proto == PPP_VJC_UNCOMP) {
+	if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
+	    goto bad;
+
+	xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
+				      ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
+				      sc->sc_comp, &iphdr, &hlen);
+
+	if (xlen < 0) {
+	    if (sc->sc_flags & SC_DEBUG)
+		diag_printf("ppp%d: VJ uncompress failed on type uncomp\n",
+			ifp->if_unit);
+	    goto bad;
+	}
+
+	proto = PPP_IP;
+	cp[3] = PPP_IP;
+    }
+#endif /* VJC */
+
+    /*
+     * If the packet will fit in a header mbuf, don't waste a
+     * whole cluster on it.
+     */
+    if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
+	MGETHDR(mp, M_DONTWAIT, MT_DATA);
+	if (mp != NULL) {
+	    m_copydata(m, 0, ilen, mtod(mp, caddr_t));
+	    m_freem(m);
+	    m = mp;
+	    m->m_len = ilen;
+	}
+    }
+    m->m_pkthdr.len = ilen;
+    m->m_pkthdr.rcvif = ifp;
+
+    if ((proto & 0x8000) == 0) {
+#ifdef PPP_FILTER
+	/*
+	 * See whether we want to pass this packet, and
+	 * if it counts as link activity.
+	 */
+	adrs = *mtod(m, u_char *);	/* save address field */
+	*mtod(m, u_char *) = 0;		/* indicate inbound */
+	if (sc->sc_pass_filt.bf_insns != 0
+	    && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
+			  ilen, 0) == 0) {
+	    /* drop this packet */
+	    m_freem(m);
+	    return;
+	}
+	if (sc->sc_active_filt.bf_insns == 0
+	    || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0))
+	    sc->sc_last_recv = time_second;
+
+	*mtod(m, u_char *) = adrs;
+#else
+	/*
+	 * Record the time that we received this packet.
+	 */
+	sc->sc_last_recv = time_second;
+#endif /* PPP_FILTER */
+    }
+
+#ifdef BPF
+    /* See if bpf wants to look at the packet. */
+    if (sc->sc_if.if_bpf)
+	bpf_mtap(&sc->sc_if, m);
+#endif
+    
+    rv = 0;
+    switch (proto) {
+#ifdef INET
+    case PPP_IP:
+	/*
+	 * IP packet - take off the ppp header and pass it up to IP.
+	 */
+	if ((ifp->if_flags & IFF_UP) == 0
+	    || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
+	    /* interface is down - drop the packet. */
+	    m_freem(m);
+	    return;
+	}
+	m->m_pkthdr.len -= PPP_HDRLEN;
+	m->m_data += PPP_HDRLEN;
+	m->m_len -= PPP_HDRLEN;
+	if (ipflow_fastforward(m)) {
+	    sc->sc_last_recv = time_second;
+	    return;
+	}
+	schednetisr(NETISR_IP);
+	inq = &ipintrq;
+	sc->sc_last_recv = time_second;	/* update time of last pkt rcvd */
+	break;
+#endif
+#ifdef IPX
+    case PPP_IPX:
+	/*
+	 * IPX packet - take off the ppp header and pass it up to IPX.
+	 */
+	if ((sc->sc_if.if_flags & IFF_UP) == 0
+	    /* XXX: || sc->sc_npmode[NP_IPX] != NPMODE_PASS*/) {
+	    /* interface is down - drop the packet. */
+	    m_freem(m);
+	    return;
+	}
+	m->m_pkthdr.len -= PPP_HDRLEN;
+	m->m_data += PPP_HDRLEN;
+	m->m_len -= PPP_HDRLEN;
+	schednetisr(NETISR_IPX);
+	inq = &ipxintrq;
+	sc->sc_last_recv = time_second;	/* update time of last pkt rcvd */
+	break;
+#endif
+
+    default:
+	/*
+	 * Some other protocol - place on input queue for read().
+	 */
+	inq = &sc->sc_inq;
+	rv = 1;
+	break;
+    }
+
+    /*
+     * Put the packet on the appropriate input queue.
+     */
+    s = splimp();
+    if (IF_QFULL(inq)) {
+	IF_DROP(inq);
+	splx(s);
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("ppp%d: input queue full\n", ifp->if_unit);
+	ifp->if_iqdrops++;
+	goto bad;
+    }
+    IF_ENQUEUE(inq, m);
+    splx(s);
+    ifp->if_ipackets++;
+    ifp->if_ibytes += ilen;
+    getmicrotime(&ifp->if_lastchange);
+
+    if (rv)
+	(*sc->sc_ctlp)(sc);
+
+    return;
+
+ bad:
+    m_freem(m);
+    sc->sc_if.if_ierrors++;
+    sc->sc_stats.ppp_ierrors++;
+}
+
+#if 0
+
+#define MAX_DUMP_BYTES	128
+
+static void
+pppdumpm(m0)
+    struct mbuf *m0;
+{
+    char buf[3*MAX_DUMP_BYTES+4];
+    char *bp = buf;
+    struct mbuf *m;
+
+    for (m = m0; m; m = m->m_next) {
+	int l = m->m_len;
+	u_char *rptr = (u_char *)m->m_data;
+
+	while (l--) {
+	    if (bp > buf + sizeof(buf) - 4)
+		goto done;
+	    *bp++ = hex2ascii(*rptr >> 4);
+	    *bp++ = hex2ascii(*rptr++ & 0xf);
+	}
+
+	if (m->m_next) {
+	    if (bp > buf + sizeof(buf) - 3)
+		goto done;
+	    *bp++ = '|';
+	} else
+	    *bp++ = ' ';
+    }
+done:
+    if (m)
+	*bp++ = '>';
+    *bp = 0;
+    diag_printf("%s\n", buf);
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/ipcp.c
@@ -0,0 +1,1534 @@
+//==========================================================================
+//
+//      src/ipcp.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/ipcp.c,v 1.12 1999/08/28 01:19:03 peter Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cyg/ppp/syslog.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/ipcp.h"
+
+#define option_error(msg) db_printf("Option error: %s\n", msg )
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP];	/* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+
+/* local vars */
+static int cis_received[NUM_PPP];	/* # Conf-Reqs received */
+static int default_route_set[NUM_PPP];	/* Have set up a default route */
+static int proxy_arp_set[NUM_PPP];	/* Have created proxy arp entry */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void ipcp_resetci __P((fsm *));	/* Reset our CI */
+static int  ipcp_cilen __P((fsm *));	        /* Return length of our CI */
+static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */
+static int  ipcp_ackci __P((fsm *, u_char *, int));	/* Peer ack'd our CI */
+static int  ipcp_nakci __P((fsm *, u_char *, int));	/* Peer nak'd our CI */
+static int  ipcp_rejci __P((fsm *, u_char *, int));	/* Peer rej'd our CI */
+static int  ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */
+static void ipcp_up __P((fsm *));		/* We're UP */
+static void ipcp_down __P((fsm *));		/* We're DOWN */
+static void ipcp_finished __P((fsm *));	/* Don't need lower layer */
+
+fsm ipcp_fsm[NUM_PPP];		/* IPCP fsm structure */
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+    ipcp_resetci,		/* Reset our Configuration Information */
+    ipcp_cilen,			/* Length of our Configuration Information */
+    ipcp_addci,			/* Add our Configuration Information */
+    ipcp_ackci,			/* ACK our Configuration Information */
+    ipcp_nakci,			/* NAK our Configuration Information */
+    ipcp_rejci,			/* Reject our Configuration Information */
+    ipcp_reqci,			/* Request peer's Configuration Information */
+    ipcp_up,			/* Called when fsm reaches OPENED state */
+    ipcp_down,			/* Called when fsm leaves OPENED state */
+    NULL,			/* Called when we want the lower layer up */
+    ipcp_finished,		/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    NULL,			/* Called to handle protocol-specific codes */
+    "IPCP"			/* String name of protocol */
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init __P((int));
+static void ipcp_open __P((int));
+static void ipcp_close __P((int, char *));
+static void ipcp_lowerup __P((int));
+static void ipcp_lowerdown __P((int));
+static void ipcp_input __P((int, u_char *, int));
+static void ipcp_protrej __P((int));
+static int  ipcp_printpkt __P((u_char *, int,
+			       void (*) __P((void *, char *, ...)), void *));
+static void ip_check_options __P((void));
+static int  ip_demand_conf __P((int));
+static int  ip_active_pkt __P((u_char *, int));
+
+struct protent ipcp_protent = {
+    PPP_IPCP,
+    ipcp_init,
+    ipcp_input,
+    ipcp_protrej,
+    ipcp_lowerup,
+    ipcp_lowerdown,
+    ipcp_open,
+    ipcp_close,
+    ipcp_printpkt,
+    NULL,
+    1,
+    "IPCP",
+    ip_check_options,
+    ip_demand_conf,
+    ip_active_pkt
+};
+
+static void ipcp_clear_addrs __P((int));
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID	2
+#define CILEN_COMPRESS	4	/* min length for compression protocol opt. */
+#define CILEN_VJ	6	/* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR	6	/* new-style single address option */
+#define CILEN_ADDRS	10	/* old-style dual address option */
+
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * Make a string representation of a network IP address.
+ */
+char *
+ip_ntoa(ipaddr)
+u_int32_t ipaddr;
+{
+    static char b[64];
+
+    ipaddr = ntohl(ipaddr);
+
+    sprintf(b, "%d.%d.%d.%d",
+	    (u_char)(ipaddr >> 24),
+	    (u_char)(ipaddr >> 16),
+	    (u_char)(ipaddr >> 8),
+	    (u_char)(ipaddr));
+    return b;
+}
+
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+static void
+ipcp_init(unit)
+    int unit;
+{
+    fsm *f = &ipcp_fsm[unit];
+    ipcp_options *wo = &ipcp_wantoptions[unit];
+    ipcp_options *ao = &ipcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_IPCP;
+    f->callbacks = &ipcp_callbacks;
+    fsm_init(&ipcp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->neg_addr = 1;
+    wo->neg_vj = 1;
+    wo->vj_protocol = IPCP_VJ_COMP;
+    wo->maxslotindex = MAX_STATES - 1; /* really max index */
+    wo->cflag = 1;
+
+    /* max slots and slot-id compression are currently hardwired in */
+    /* ppp_if.c to 16 and 1, this needs to be changed (among other */
+    /* things) gmc */
+
+    ao->neg_addr = 1;
+    ao->neg_vj = 1;
+    ao->maxslotindex = MAX_STATES - 1;
+    ao->cflag = 1;
+
+    /*
+     * XXX These control whether the user may use the proxyarp
+     * and defaultroute options.
+     */
+    ao->proxy_arp = 1;
+    ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void
+ipcp_open(unit)
+    int unit;
+{
+    fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void
+ipcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void
+ipcp_lowerup(unit)
+    int unit;
+{
+    fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void
+ipcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void
+ipcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipcp_protrej(unit)
+    int unit;
+{
+    fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ */
+static void
+ipcp_resetci(f)
+    fsm *f;
+{
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+    wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+    if (wo->ouraddr == 0)
+	wo->accept_local = 1;
+    if (wo->hisaddr == 0)
+	wo->accept_remote = 1;
+    ipcp_gotoptions[f->unit] = *wo;
+    cis_received[f->unit] = 0;
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ */
+static int
+ipcp_cilen(f)
+    fsm *f;
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+
+#define LENCIVJ(neg, old)	(neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old)	(neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+
+    /*
+     * First see if we want to change our options to the old
+     * forms because we have received old forms from the peer.
+     */
+    if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+	/* use the old style of address negotiation */
+	go->neg_addr = 1;
+	go->old_addrs = 1;
+    }
+    if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+	/* try an older style of VJ negotiation */
+	if (cis_received[f->unit] == 0) {
+	    /* keep trying the new style until we see some CI from the peer */
+	    go->neg_vj = 1;
+	} else {
+	    /* use the old style only if the peer did */
+	    if (ho->neg_vj && ho->old_vj) {
+		go->neg_vj = 1;
+		go->old_vj = 1;
+		go->vj_protocol = ho->vj_protocol;
+	    }
+	}
+    }
+
+    return (LENCIADDR(go->neg_addr, go->old_addrs) +
+	    LENCIVJ(go->neg_vj, go->old_vj));
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ */
+static void
+ipcp_addci(f, ucp, lenp)
+    fsm *f;
+    u_char *ucp;
+    int *lenp;
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+    if (neg) { \
+	int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+	if (len >= vjlen) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(vjlen, ucp); \
+	    PUTSHORT(val, ucp); \
+	    if (!old) { \
+		PUTCHAR(maxslotindex, ucp); \
+		PUTCHAR(cflag, ucp); \
+	    } \
+	    len -= vjlen; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+    if (neg) { \
+	int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+	if (len >= addrlen) { \
+	    u_int32_t l; \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(addrlen, ucp); \
+	    l = ntohl(val1); \
+	    PUTLONG(l, ucp); \
+	    if (old) { \
+		l = ntohl(val2); \
+		PUTLONG(l, ucp); \
+	    } \
+	    len -= addrlen; \
+	} else \
+	    neg = 0; \
+    }
+
+    ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+ipcp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_short cilen, citype, cishort;
+    u_int32_t cilong;
+    u_char cimaxslotindex, cicflag;
+
+    /*
+     * CIs must be in exactly the same order that we sent...
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+    if (neg) { \
+	int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+	if ((len -= vjlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != vjlen || \
+	    citype != opt)  \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+	if (!old) { \
+	    GETCHAR(cimaxslotindex, p); \
+	    if (cimaxslotindex != maxslotindex) \
+		goto bad; \
+	    GETCHAR(cicflag, p); \
+	    if (cicflag != cflag) \
+		goto bad; \
+	} \
+    }
+
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+    if (neg) { \
+	int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+	u_int32_t l; \
+	if ((len -= addrlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != addrlen || \
+	    citype != opt) \
+	    goto bad; \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	if (val1 != cilong) \
+	    goto bad; \
+	if (old) { \
+	    GETLONG(l, p); \
+	    cilong = htonl(l); \
+	    if (val2 != cilong) \
+		goto bad; \
+	} \
+    }
+
+    ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"));
+    return (0);
+}
+
+/*
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+ipcp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char cimaxslotindex, cicflag;
+    u_char citype, cilen, *next;
+    u_short cishort;
+    u_int32_t ciaddr1, ciaddr2, l;
+    ipcp_options no;		/* options we've seen Naks for */
+    ipcp_options try;		/* options to request next time */
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIADDR(opt, neg, old, code) \
+    if (go->neg && \
+	len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	ciaddr1 = htonl(l); \
+	if (old) { \
+	    GETLONG(l, p); \
+	    ciaddr2 = htonl(l); \
+	    no.old_addrs = 1; \
+	} else \
+	    ciaddr2 = 0; \
+	no.neg = 1; \
+	code \
+    }
+
+#define NAKCIVJ(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+        code \
+    }
+
+    /*
+     * Accept the peer's idea of {our,his} address, if different
+     * from our idea, only if the accept_{local,remote} flag is set.
+     */
+    NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+	      if (go->accept_local && ciaddr1) { /* Do we know our address? */
+		  try.ouraddr = ciaddr1;
+		  IPCPDEBUG((LOG_INFO, "local IP address %s",
+			     ip_ntoa(ciaddr1)));
+	      }
+	      if (go->accept_remote && ciaddr2) { /* Does he know his? */
+		  try.hisaddr = ciaddr2;
+		  IPCPDEBUG((LOG_INFO, "remote IP address %s",
+			     ip_ntoa(ciaddr2)));
+	      }
+	      );
+
+    /*
+     * Accept the peer's value of maxslotindex provided that it
+     * is less than what we asked for.  Turn off slot-ID compression
+     * if the peer wants.  Send old-style compress-type option if
+     * the peer wants.
+     */
+    NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+	    if (cilen == CILEN_VJ) {
+		GETCHAR(cimaxslotindex, p);
+		GETCHAR(cicflag, p);
+		if (cishort == IPCP_VJ_COMP) {
+		    try.old_vj = 0;
+		    if (cimaxslotindex < go->maxslotindex)
+			try.maxslotindex = cimaxslotindex;
+		    if (!cicflag)
+			try.cflag = 0;
+		} else {
+		    try.neg_vj = 0;
+		}
+	    } else {
+		if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+		    try.old_vj = 1;
+		    try.vj_protocol = cishort;
+		} else {
+		    try.neg_vj = 0;
+		}
+	    }
+	    );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If they want to negotiate about IP addresses, we comply.
+     * If they want us to ask for compression, we refuse.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_COMPRESSTYPE:
+	    if (go->neg_vj || no.neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+		goto bad;
+	    no.neg_vj = 1;
+	    break;
+	case CI_ADDRS:
+	    if ((go->neg_addr && go->old_addrs) || no.old_addrs
+		|| cilen != CILEN_ADDRS)
+		goto bad;
+	    try.neg_addr = 1;
+	    try.old_addrs = 1;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (ciaddr1 && go->accept_local)
+		try.ouraddr = ciaddr1;
+	    GETLONG(l, p);
+	    ciaddr2 = htonl(l);
+	    if (ciaddr2 && go->accept_remote)
+		try.hisaddr = ciaddr2;
+	    no.old_addrs = 1;
+	    break;
+	case CI_ADDR:
+	    if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+		goto bad;
+	    try.old_addrs = 0;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (ciaddr1 && go->accept_local)
+		try.ouraddr = ciaddr1;
+	    if (try.ouraddr != 0)
+		try.neg_addr = 1;
+	    no.neg_addr = 1;
+	    break;
+	}
+	p = next;
+    }
+
+    /* If there is still anything left, this packet is bad. */
+    if (len != 0)
+	goto bad;
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ */
+static int
+ipcp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char cimaxslotindex, ciflag, cilen;
+    u_short cishort;
+    u_int32_t cilong;
+    ipcp_options try;		/* options to request next time */
+
+    try = *go;
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+    if (go->neg && \
+	len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	u_int32_t l; \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	/* Check rejected value. */ \
+	if (cilong != val1) \
+	    goto bad; \
+	if (old) { \
+	    GETLONG(l, p); \
+	    cilong = htonl(l); \
+	    /* Check rejected value. */ \
+	    if (cilong != val2) \
+		goto bad; \
+	} \
+	try.neg = 0; \
+    }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+    if (go->neg && \
+	p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+	len >= p[1] && \
+	p[0] == opt) { \
+	len -= p[1]; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */  \
+	if (cishort != val) \
+	    goto bad; \
+	if (!old) { \
+	   GETCHAR(cimaxslotindex, p); \
+	   if (cimaxslotindex != maxslot) \
+	     goto bad; \
+	   GETCHAR(ciflag, p); \
+	   if (ciflag != cflag) \
+	     goto bad; \
+        } \
+	try.neg = 0; \
+     }
+
+    REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipcp_reqci(f, inp, len, reject_if_disagree)
+    fsm *f;
+    u_char *inp;		/* Requested CIs */
+    int *len;			/* Length of requested CIs */
+    int reject_if_disagree;
+{
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    ipcp_options *ao = &ipcp_allowoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    u_short cilen, citype;	/* Parsed len, type */
+    u_short cishort;		/* Parsed short value */
+    u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *ucp = inp;		/* Pointer to current output char */
+    int l = *len;		/* Length left */
+    u_char maxslotindex, cflag;
+    int d;
+
+    cis_received[f->unit] = 1;
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+    
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+	case CI_ADDRS:
+	    IPCPDEBUG((LOG_INFO, "ipcp: received ADDRS "));
+	    if (!ao->neg_addr ||
+		cilen != CILEN_ADDRS) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+
+	    /*
+	     * If he has no address, or if we both have his address but
+	     * disagree about it, then NAK it with our idea.
+	     * In particular, if we don't know his address, but he does,
+	     * then accept it.
+	     */
+	    GETLONG(tl, p);		/* Parse source address (his) */
+	    ciaddr1 = htonl(tl);
+	    IPCPDEBUG((LOG_INFO, "(%s:", ip_ntoa(ciaddr1)));
+	    if (ciaddr1 != wo->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(u_int32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * If neither we nor he knows his address, reject the option.
+		 */
+		orc = CONFREJ;
+		wo->req_addr = 0;	/* don't NAK with 0.0.0.0 later */
+		break;
+	    }
+
+	    /*
+	     * If he doesn't know our address, or if we both have our address
+	     * but disagree about it, then NAK it with our idea.
+	     */
+	    GETLONG(tl, p);		/* Parse desination address (ours) */
+	    ciaddr2 = htonl(tl);
+	    IPCPDEBUG((LOG_INFO, "%s)", ip_ntoa(ciaddr2)));
+	    if (ciaddr2 != wo->ouraddr) {
+		if (ciaddr2 == 0 || !wo->accept_local) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree) {
+			DECPTR(sizeof(u_int32_t), p);
+			tl = ntohl(wo->ouraddr);
+			PUTLONG(tl, p);
+		    }
+		} else {
+		    go->ouraddr = ciaddr2;	/* accept peer's idea */
+		}
+	    }
+
+	    ho->neg_addr = 1;
+	    ho->old_addrs = 1;
+	    ho->hisaddr = ciaddr1;
+	    ho->ouraddr = ciaddr2;
+	    break;
+
+	case CI_ADDR:
+	    IPCPDEBUG((LOG_INFO, "ipcp: received ADDR "));
+
+	    if (!ao->neg_addr ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+
+	    /*
+	     * If he has no address, or if we both have his address but
+	     * disagree about it, then NAK it with our idea.
+	     * In particular, if we don't know his address, but he does,
+	     * then accept it.
+	     */
+	    GETLONG(tl, p);	/* Parse source address (his) */
+	    ciaddr1 = htonl(tl);
+	    IPCPDEBUG((LOG_INFO, "(%s)", ip_ntoa(ciaddr1)));
+	    if (ciaddr1 != wo->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(u_int32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * Don't ACK an address of 0.0.0.0 - reject it instead.
+		 */
+		orc = CONFREJ;
+		wo->req_addr = 0;	/* don't NAK with 0.0.0.0 later */
+		break;
+	    }
+	
+	    ho->neg_addr = 1;
+	    ho->hisaddr = ciaddr1;
+	    break;
+
+	case CI_MS_DNS1:
+	case CI_MS_DNS2:
+	    /* Microsoft primary or secondary DNS request */
+	    d = citype == CI_MS_DNS2;
+	    IPCPDEBUG((LOG_INFO, "ipcp: received DNS%d Request ", d+1));
+
+	    /* If we do not have a DNS address then we cannot send it */
+	    if (ao->dnsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->dnsaddr[d]) {
+                DECPTR(sizeof(u_int32_t), p);
+		tl = ntohl(ao->dnsaddr[d]);
+		PUTLONG(tl, p);
+		orc = CONFNAK;
+            }
+            break;
+
+	case CI_MS_WINS1:
+	case CI_MS_WINS2:
+	    /* Microsoft primary or secondary WINS request */
+	    d = citype == CI_MS_WINS2;
+	    IPCPDEBUG((LOG_INFO, "ipcp: received WINS%d Request ", d+1));
+
+	    /* If we do not have a DNS address then we cannot send it */
+	    if (ao->winsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->winsaddr[d]) {
+                DECPTR(sizeof(u_int32_t), p);
+		tl = ntohl(ao->winsaddr[d]);
+		PUTLONG(tl, p);
+		orc = CONFNAK;
+            }
+            break;
+	
+	case CI_COMPRESSTYPE:
+	    IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
+	    if (!ao->neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+	    IPCPDEBUG((LOG_INFO, "(%d)", cishort));
+
+	    if (!(cishort == IPCP_VJ_COMP ||
+		  (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->neg_vj = 1;
+	    ho->vj_protocol = cishort;
+	    if (cilen == CILEN_VJ) {
+		GETCHAR(maxslotindex, p);
+		if (maxslotindex > ao->maxslotindex) { 
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(ao->maxslotindex, p);
+		    }
+		}
+		GETCHAR(cflag, p);
+		if (cflag && !ao->cflag) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(wo->cflag, p);
+		    }
+		}
+		ho->maxslotindex = maxslotindex;
+		ho->cflag = cflag;
+	    } else {
+		ho->old_vj = 1;
+		ho->maxslotindex = MAX_STATES - 1;
+		ho->cflag = 1;
+	    }
+	    break;
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	IPCPDEBUG((LOG_INFO, " (%s)\n", CODENAME(orc)));
+
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree)	/* Getting fed up with sending NAKs? */
+		orc = CONFREJ;		/* Get tough if so */
+	    else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		if (rc == CONFACK) {	/* Ack'd all prior CIs? */
+		    rc = CONFNAK;	/* Not anymore... */
+		    ucp = inp;		/* Backup */
+		}
+	    }
+	}
+
+	if (orc == CONFREJ &&		/* Reject this CI */
+	    rc != CONFREJ) {		/*  but no prior ones? */
+	    rc = CONFREJ;
+	    ucp = inp;			/* Backup */
+	}
+
+	/* Need to move CI? */
+	if (ucp != cip)
+	    BCOPY(cip, ucp, cilen);	/* Move it */
+
+	/* Update output pointer */
+	INCPTR(cilen, ucp);
+    }
+
+    /*
+     * If we aren't rejecting this packet, and we want to negotiate
+     * their address, and they didn't send their address, then we
+     * send a NAK with a CI_ADDR option appended.  We assume the
+     * input buffer is long enough that we can append the extra
+     * option safely.
+     */
+    if (rc != CONFREJ && !ho->neg_addr &&
+	wo->req_addr && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    ucp = inp;			/* reset pointer */
+	    wo->req_addr = 0;		/* don't ask again */
+	}
+	PUTCHAR(CI_ADDR, ucp);
+	PUTCHAR(CILEN_ADDR, ucp);
+	tl = ntohl(wo->hisaddr);
+	PUTLONG(tl, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPCPDEBUG((LOG_INFO, "ipcp: returning Configure-%s", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ip_check_options()
+{
+    struct hostent *hp;
+    u_int32_t local;
+    ipcp_options *wo = &ipcp_wantoptions[0];
+
+    /*
+     * Default our local IP address based on our hostname.
+     * If local IP address already given, don't bother.
+     */
+    if (wo->ouraddr == 0 && !disable_defaultip) {
+	/*
+	 * Look up our hostname (possibly with domain name appended)
+	 * and take the first IP address as our local IP address.
+	 * If there isn't an IP address for our hostname, too bad.
+	 */
+	wo->accept_local = 1;	/* don't insist on this default value */
+	if ((hp = gethostbyname(cyg_ppp_hostname)) != NULL) {
+	    local = *(u_int32_t *)hp->h_addr;
+	    if (local != 0 && !bad_ip_adrs(local))
+		wo->ouraddr = local;
+	}
+    }
+
+    if (demand && wo->hisaddr == 0) {
+	option_error("remote IP address required for demand-dialling\n");
+    }
+}
+
+
+/*
+ * ip_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+static int
+ip_demand_conf(u)
+    int u;
+{
+    ipcp_options *wo = &ipcp_wantoptions[u];
+
+    if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+	return 0;
+    if (!sifup(u))
+	return 0;
+    if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+	return 0;
+    if (wo->default_route)
+	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
+	    default_route_set[u] = 1;
+    if (wo->proxy_arp)
+	if (sifproxyarp(u, wo->hisaddr))
+	    proxy_arp_set[u] = 1;
+
+    syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(wo->ouraddr));
+    syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr));
+
+    return 1;
+}
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+ipcp_up(f)
+    fsm *f;
+{
+    u_int32_t mask;
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+    np_up(f->unit, PPP_IP);
+    IPCPDEBUG((LOG_INFO, "ipcp: up"));
+
+    /*
+     * We must have a non-zero IP address for both ends of the link.
+     */
+    if (!ho->neg_addr)
+	ho->hisaddr = wo->hisaddr;
+
+    if (ho->hisaddr == 0) {
+	syslog(LOG_ERR, "Could not determine remote IP address");
+	ipcp_close(f->unit, "Could not determine remote IP address");
+	return;
+    }
+    if (go->ouraddr == 0) {
+	syslog(LOG_ERR, "Could not determine local IP address");
+	ipcp_close(f->unit, "Could not determine local IP address");
+	return;
+    }
+    
+    /*
+     * Check that the peer is allowed to use the IP address it wants.
+     */
+    if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+	syslog(LOG_ERR, "Peer is not authorized to use remote address %s",
+	       ip_ntoa(ho->hisaddr));
+	ipcp_close(f->unit, "Unauthorized remote IP address");
+	return;
+    }
+
+    /* set tcp compression */
+    sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+
+    /*
+     * If we are doing dial-on-demand, the interface is already
+     * configured, so we put out any saved-up packets, then set the
+     * interface to pass IP packets.
+     */
+    if (demand) {
+	if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+	    if (go->ouraddr != wo->ouraddr)
+		syslog(LOG_WARNING, "Local IP address changed to %s",
+		       ip_ntoa(go->ouraddr));
+	    if (ho->hisaddr != wo->hisaddr)
+		syslog(LOG_WARNING, "Remote IP address changed to %s",
+		       ip_ntoa(ho->hisaddr));
+	    ipcp_clear_addrs(f->unit);
+
+	    /* Set the interface to the new addresses */
+	    mask = GetMask(go->ouraddr);
+	    if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+		IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+		ipcp_close(f->unit, "Interface configuration failed");
+		return;
+	    }
+
+	    /* assign a default route through the interface if required */
+	    if (ipcp_wantoptions[f->unit].default_route) 
+		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		    default_route_set[f->unit] = 1;
+
+	    /* Make a proxy ARP entry if requested. */
+	    if (ipcp_wantoptions[f->unit].proxy_arp)
+		if (sifproxyarp(f->unit, ho->hisaddr))
+		    proxy_arp_set[f->unit] = 1;
+
+	}
+	demand_rexmit(PPP_IP);
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+    } else {
+	/*
+	 * Set IP addresses and (if specified) netmask.
+	 */
+	mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+
+	/* bring the interface up for IP */
+	if (!sifup(f->unit)) {
+	    IPCPDEBUG((LOG_WARNING, "sifup failed"));
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+	/* assign a default route through the interface if required */
+	if (ipcp_wantoptions[f->unit].default_route) 
+	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		default_route_set[f->unit] = 1;
+
+	/* Make a proxy ARP entry if requested. */
+	if (ipcp_wantoptions[f->unit].proxy_arp)
+	    if (sifproxyarp(f->unit, ho->hisaddr))
+		proxy_arp_set[f->unit] = 1;
+
+	syslog(LOG_NOTICE, "local  IP address %s", ip_ntoa(go->ouraddr));
+	syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr));
+    }
+
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipcp_down(f)
+    fsm *f;
+{
+    IPCPDEBUG((LOG_INFO, "ipcp: down"));
+    np_down(f->unit, PPP_IP);
+    sifvjcomp(f->unit, 0, 0, 0);
+
+    /*
+     * If we are doing dial-on-demand, set the interface
+     * to queue up outgoing packets (for now).
+     */
+    if (demand) {
+	sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
+    } else {
+	sifdown(f->unit);
+	ipcp_clear_addrs(f->unit);
+    }
+
+}
+
+
+/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes,
+ * proxy arp entries, etc.
+ */
+static void
+ipcp_clear_addrs(unit)
+    int unit;
+{
+    u_int32_t ouraddr, hisaddr;
+
+    ouraddr = ipcp_gotoptions[unit].ouraddr;
+    hisaddr = ipcp_hisoptions[unit].hisaddr;
+    if (proxy_arp_set[unit]) {
+	cifproxyarp(unit, hisaddr);
+	proxy_arp_set[unit] = 0;
+    }
+    if (default_route_set[unit]) {
+	cifdefaultroute(unit, ouraddr, hisaddr);
+	default_route_set[unit] = 0;
+    }
+    cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(f)
+    fsm *f;
+{
+    np_finished(f->unit, PPP_IP);
+}
+
+/*
+ * ipcp_printpkt - print the contents of an IPCP packet.
+ */
+static char *ipcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    u_int32_t cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_ADDRS:
+		if (olen == CILEN_ADDRS) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addrs %I", htonl(cilong));
+		    GETLONG(cilong, p);
+		    printer(arg, " %I", htonl(cilong));
+		}
+		break;
+	    case CI_COMPRESSTYPE:
+		if (olen >= CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "compress ");
+		    switch (cishort) {
+		    case IPCP_VJ_COMP:
+			printer(arg, "VJ");
+			break;
+		    case IPCP_VJ_COMP_OLD:
+			printer(arg, "old-VJ");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_ADDR:
+		if (olen == CILEN_ADDR) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addr %I", htonl(cilong));
+		}
+		break;
+	    case CI_MS_DNS1:
+	    case CI_MS_DNS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-dns %I", htonl(cilong));
+		break;
+	    case CI_MS_WINS1:
+	    case CI_MS_WINS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-wins %I", htonl(cilong));
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN	20	/* bytes */
+#define IP_OFFMASK	0x1fff
+#define IPPROTO_TCP	6
+#define TCP_HDRLEN	20
+#define TH_FIN		0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x)	(((x)[0] << 8) + (x)[1])
+#define get_iphl(x)	(((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x)	net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x)	(((unsigned char *)(x))[9])
+#define get_tcpoff(x)	(((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x)	(((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(pkt, len)
+    u_char *pkt;
+    int len;
+{
+    u_char *tcp;
+    int hlen;
+
+    len -= PPP_HDRLEN;
+    pkt += PPP_HDRLEN;
+    if (len < IP_HDRLEN)
+	return 0;
+    if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+	return 0;
+    if (get_ipproto(pkt) != IPPROTO_TCP)
+	return 1;
+    hlen = get_iphl(pkt) * 4;
+    if (len < hlen + TCP_HDRLEN)
+	return 0;
+    tcp = pkt + hlen;
+    if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+	return 0;
+    return 1;
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/lcp.c
@@ -0,0 +1,1910 @@
+//==========================================================================
+//
+//      src/lcp.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/lcp.c,v 1.9 1999/08/28 01:19:04 peter Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cyg/ppp/syslog.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/lcp.h"
+#include "cyg/ppp/chap.h"
+#include "cyg/ppp/magic.h"
+
+/* global vars */
+fsm lcp_fsm[NUM_PPP];			/* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NUM_PPP];	/* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+u_int32_t xmit_accm[NUM_PPP][8];		/* extended transmit ACCM */
+
+static u_int32_t lcp_echos_pending = 0;	/* Number of outstanding echo msgs */
+static u_int32_t lcp_echo_number   = 0;	/* ID number of next echo frame */
+static u_int32_t lcp_echo_timer_running = 0;  /* TRUE if a timer is running */
+
+static u_char nak_buffer[PPP_MRU];	/* where we construct a nak packet */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void lcp_resetci __P((fsm *));	/* Reset our CI */
+static int  lcp_cilen __P((fsm *));		/* Return length of our CI */
+static void lcp_addci __P((fsm *, u_char *, int *)); /* Add our CI to pkt */
+static int  lcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */
+static int  lcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */
+static int  lcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */
+static int  lcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv peer CI */
+static void lcp_up __P((fsm *));		/* We're UP */
+static void lcp_down __P((fsm *));		/* We're DOWN */
+static void lcp_starting __P((fsm *));	/* We need lower layer up */
+static void lcp_finished __P((fsm *));	/* We need lower layer down */
+static int  lcp_extcode __P((fsm *, int, int, u_char *, int));
+static void lcp_rprotrej __P((fsm *, u_char *, int));
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup __P((int));
+static void lcp_echo_lowerdown __P((int));
+static void LcpEchoTimeout __P((void *));
+static void lcp_received_echo_reply __P((fsm *, int, u_char *, int));
+static void LcpSendEchoRequest __P((fsm *));
+static void LcpLinkFailure __P((fsm *));
+static void LcpEchoCheck __P((fsm *));
+
+static fsm_callbacks lcp_callbacks = {	/* LCP callback routines */
+    lcp_resetci,		/* Reset our Configuration Information */
+    lcp_cilen,			/* Length of our Configuration Information */
+    lcp_addci,			/* Add our Configuration Information */
+    lcp_ackci,			/* ACK our Configuration Information */
+    lcp_nakci,			/* NAK our Configuration Information */
+    lcp_rejci,			/* Reject our Configuration Information */
+    lcp_reqci,			/* Request peer's Configuration Information */
+    lcp_up,			/* Called when fsm reaches OPENED state */
+    lcp_down,			/* Called when fsm leaves OPENED state */
+    lcp_starting,		/* Called when we want the lower layer up */
+    lcp_finished,		/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    lcp_extcode,		/* Called to handle LCP-specific codes */
+    "LCP"			/* String name of protocol */
+};
+
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+
+static void lcp_init __P((int));
+static void lcp_input __P((int, u_char *, int));
+static void lcp_protrej __P((int));
+static int  lcp_printpkt __P((u_char *, int,
+			      void (*) __P((void *, char *, ...)), void *));
+
+struct protent lcp_protent = {
+    PPP_LCP,
+    lcp_init,
+    lcp_input,
+    lcp_protrej,
+    lcp_lowerup,
+    lcp_lowerdown,
+    lcp_open,
+    lcp_close,
+    lcp_printpkt,
+    NULL,
+    1,
+    "LCP",
+    NULL,
+    NULL,
+    NULL
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID	2
+#define CILEN_CHAR	3
+#define CILEN_SHORT	4	/* CILEN_VOID + sizeof(short) */
+#define CILEN_CHAP	5	/* CILEN_VOID + sizeof(short) + 1 */
+#define CILEN_LONG	6	/* CILEN_VOID + sizeof(long) */
+#define CILEN_LQR	8	/* CILEN_VOID + sizeof(short) + sizeof(long) */
+#define CILEN_CBCP	3
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+static void
+lcp_init(unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_LCP;
+    f->callbacks = &lcp_callbacks;
+
+    fsm_init(f);
+
+    wo->passive = 0;
+    wo->silent = 0;
+    wo->restart = 0;			/* Set to 1 in kernels or multi-line
+					   implementations */
+    wo->neg_mru = 1;
+    wo->mru = DEFMRU;
+    wo->neg_asyncmap = 0;
+    wo->asyncmap = 0;
+    wo->neg_chap = 0;			/* Set to 1 on server */
+    wo->neg_upap = 0;			/* Set to 1 on server */
+    wo->chap_mdtype = CHAP_DIGEST_MD5;
+    wo->neg_magicnumber = 1;
+    wo->neg_pcompression = 1;
+    wo->neg_accompression = 1;
+    wo->neg_lqr = 0;			/* no LQR implementation yet */
+    wo->neg_cbcp = 0;
+
+    ao->neg_mru = 1;
+    ao->mru = MAXMRU;
+    ao->neg_asyncmap = 1;
+    ao->asyncmap = 0;
+    ao->neg_chap = 1;
+    ao->chap_mdtype = CHAP_DIGEST_MD5;
+    ao->neg_upap = 1;
+    ao->neg_magicnumber = 1;
+    ao->neg_pcompression = 1;
+    ao->neg_accompression = 1;
+    ao->neg_lqr = 0;			/* no LQR implementation yet */
+#ifdef CBCP_SUPPORT
+    ao->neg_cbcp = 1;
+#else
+    ao->neg_cbcp = 0;
+#endif
+    
+    memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+    xmit_accm[unit][3] = 0x60000000;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    f->flags = 0;
+    if (wo->passive)
+	f->flags |= OPT_PASSIVE;
+    if (wo->silent)
+	f->flags |= OPT_SILENT;
+    fsm_open(f);
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(unit, reason)
+    int unit;
+    char *reason;
+{
+    fsm *f = &lcp_fsm[unit];
+db_printf("%s()\n",__PRETTY_FUNCTION__);
+
+    if (phase != PHASE_DEAD)
+	phase = PHASE_TERMINATE;
+    if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+	/*
+	 * This action is not strictly according to the FSM in RFC1548,
+	 * but it does mean that the program terminates if you do a
+	 * lcp_close() in passive/silent mode when a connection hasn't
+	 * been established.
+	 */
+	f->state = CLOSED;
+	lcp_finished(f);
+
+    } else
+	fsm_close(&lcp_fsm[unit], reason);
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(unit)
+    int unit;
+{
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    /*
+     * Don't use A/C or protocol compression on transmission,
+     * but accept A/C and protocol compressed packets
+     * if we are going to ask for A/C and protocol compression.
+     */
+    ppp_set_xaccm(unit, xmit_accm[unit]);
+    ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
+    ppp_recv_config(unit, PPP_MRU, 0xffffffff,
+		    wo->neg_pcompression, wo->neg_accompression);
+    peer_mru[unit] = PPP_MRU;
+    lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
+
+    fsm_lowerup(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void
+lcp_lowerdown(unit)
+    int unit;
+{
+    fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_input - Input LCP packet.
+ */
+static void
+lcp_input(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    fsm *f = &lcp_fsm[unit];
+
+    fsm_input(f, p, len);
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(f, code, id, inp, len)
+    fsm *f;
+    int code, id;
+    u_char *inp;
+    int len;
+{
+    u_char *magp;
+
+    switch( code ){
+    case PROTREJ:
+	lcp_rprotrej(f, inp, len);
+	break;
+    
+    case ECHOREQ:
+	if (f->state != OPENED)
+	    break;
+	LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d", id));
+	magp = inp;
+	PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+	fsm_sdata(f, ECHOREP, id, inp, len);
+	break;
+    
+    case ECHOREP:
+	lcp_received_echo_reply(f, id, inp, len);
+	break;
+
+    case DISCREQ:
+	break;
+
+    default:
+	return 0;
+    }
+    return 1;
+}
+
+    
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(f, inp, len)
+    fsm *f;
+    u_char *inp;
+    int len;
+{
+    int i;
+    struct protent *protp;
+    u_short prot;
+
+    LCPDEBUG((LOG_INFO, "lcp_rprotrej."));
+
+    if (len < sizeof (u_short)) {
+	LCPDEBUG((LOG_INFO,
+		  "lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+	return;
+    }
+
+    GETSHORT(prot, inp);
+
+    LCPDEBUG((LOG_INFO,
+	      "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!",
+	      prot));
+
+    /*
+     * Protocol-Reject packets received in any state other than the LCP
+     * OPENED state SHOULD be silently discarded.
+     */
+    if( f->state != OPENED ){
+	LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d",
+		  f->state));
+	return;
+    }
+
+    /*
+     * Upcall the proper Protocol-Reject routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->protocol == prot && protp->enabled_flag) {
+	    (*protp->protrej)(f->unit);
+	    return;
+	}
+
+    syslog(LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x",
+	   prot);
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+/*ARGSUSED*/
+static void
+lcp_protrej(unit)
+    int unit;
+{
+    /*
+     * Can't reject LCP!
+     */
+    LCPDEBUG((LOG_WARNING,
+	      "lcp_protrej: Received Protocol-Reject for LCP!"));
+    fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void
+lcp_sprotrej(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    /*
+     * Send back the protocol and the information field of the
+     * rejected packet.  We only get here if LCP is in the OPENED state.
+     */
+    p += 2;
+    len -= 2;
+
+    fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
+	      p, len);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void
+lcp_resetci(f)
+    fsm *f;
+{
+    lcp_wantoptions[f->unit].magicnumber = magic();
+    lcp_wantoptions[f->unit].numloops = 0;
+    lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+    peer_mru[f->unit] = PPP_MRU;
+    auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(f)
+    fsm *f;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg)	((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg)	((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg)	((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg)	((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg)	((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg)	((neg) ? CILEN_CBCP: 0)
+    /*
+     * NB: we only ask for one of CHAP and UPAP, even if we will
+     * accept either.
+     */
+    return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) +
+	    LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
+	    LENCICHAP(go->neg_chap) +
+	    LENCISHORT(!go->neg_chap && go->neg_upap) +
+	    LENCILQR(go->neg_lqr) +
+	    LENCICBCP(go->neg_cbcp) +
+	    LENCILONG(go->neg_magicnumber) +
+	    LENCIVOID(go->neg_pcompression) +
+	    LENCIVOID(go->neg_accompression));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void
+lcp_addci(f, ucp, lenp)
+    fsm *f;
+    u_char *ucp;
+    int *lenp;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char *start_ucp = ucp;
+
+#define ADDCIVOID(opt, neg) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_VOID, ucp); \
+    }
+#define ADDCISHORT(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_SHORT, ucp); \
+	PUTSHORT(val, ucp); \
+    }
+#define ADDCICHAP(opt, neg, val, digest) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_CHAP, ucp); \
+	PUTSHORT(val, ucp); \
+	PUTCHAR(digest, ucp); \
+    }
+#define ADDCILONG(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_LONG, ucp); \
+	PUTLONG(val, ucp); \
+    }
+#define ADDCILQR(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_LQR, ucp); \
+	PUTSHORT(PPP_LQR, ucp); \
+	PUTLONG(val, ucp); \
+    }
+#define ADDCICHAR(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_CHAR, ucp); \
+	PUTCHAR(val, ucp); \
+    }
+
+    ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+    if (ucp - start_ucp != *lenp) {
+	/* this should never happen, because peer_mtu should be 1500 */
+	syslog(LOG_ERR, "Bug in lcp_addci: wrong length");
+    }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+lcp_ackci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char cilen, citype, cichar;
+    u_short cishort;
+    u_int32_t cilong;
+
+    /*
+     * CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define ACKCIVOID(opt, neg) \
+    if (neg) { \
+	if ((len -= CILEN_VOID) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_VOID || \
+	    citype != opt) \
+	    goto bad; \
+    }
+#define ACKCISHORT(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_SHORT) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_SHORT || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+    }
+#define ACKCICHAR(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_CHAR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_CHAR || \
+	    citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (cichar != val) \
+	    goto bad; \
+    }
+#define ACKCICHAP(opt, neg, val, digest) \
+    if (neg) { \
+	if ((len -= CILEN_CHAP) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_CHAP || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (cichar != digest) \
+	  goto bad; \
+    }
+#define ACKCILONG(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_LONG) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_LONG || \
+	    citype != opt) \
+	    goto bad; \
+	GETLONG(cilong, p); \
+	if (cilong != val) \
+	    goto bad; \
+    }
+#define ACKCILQR(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_LQR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_LQR || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != PPP_LQR) \
+	    goto bad; \
+	GETLONG(cilong, p); \
+	if (cilong != val) \
+	  goto bad; \
+    }
+
+    ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+bad:
+    LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!"));
+    return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+lcp_nakci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *wo = &lcp_wantoptions[f->unit];
+    u_char citype, cichar, *next;
+    u_short cishort;
+    u_int32_t cilong;
+    lcp_options no;		/* options we've seen Naks for */
+    lcp_options try;		/* options to request next time */
+    int looped_back = 0;
+    int cilen;
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIVOID(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCICHAP(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	p[0] == opt) { \
+	len -= CILEN_CHAP; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCICHAR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAR && \
+	p[1] == CILEN_CHAR && \
+	p[0] == opt) { \
+	len -= CILEN_CHAR; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCISHORT(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	p[0] == opt) { \
+	len -= CILEN_SHORT; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILONG(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	p[0] == opt) { \
+	len -= CILEN_LONG; \
+	INCPTR(2, p); \
+	GETLONG(cilong, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILQR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	p[0] == opt) { \
+	len -= CILEN_LQR; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETLONG(cilong, p); \
+	no.neg = 1; \
+	code \
+    }
+
+    /*
+     * We don't care if they want to send us smaller packets than
+     * we want.  Therefore, accept any MRU less than what we asked for,
+     * but then ignore the new value when setting the MRU in the kernel.
+     * If they send us a bigger MRU than what we asked, accept it, up to
+     * the limit of the default MRU we'd get if we didn't negotiate.
+     */
+    if (go->neg_mru && go->mru != DEFMRU) {
+	NAKCISHORT(CI_MRU, neg_mru,
+		   if (cishort <= wo->mru || cishort <= DEFMRU)
+		       try.mru = cishort;
+		   );
+    }
+
+    /*
+     * Add any characters they want to our (receive-side) asyncmap.
+     */
+    if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
+	NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+		  try.asyncmap = go->asyncmap | cilong;
+		  );
+    }
+
+    /*
+     * If they've nak'd our authentication-protocol, check whether
+     * they are proposing a different protocol, or a different
+     * hash algorithm for CHAP.
+     */
+    if ((go->neg_chap || go->neg_upap)
+	&& len >= CILEN_SHORT
+	&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+	cilen = p[1];
+	len -= cilen;
+	no.neg_chap = go->neg_chap;
+	no.neg_upap = go->neg_upap;
+	INCPTR(2, p);
+        GETSHORT(cishort, p);
+	if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+	    /*
+	     * If we were asking for CHAP, they obviously don't want to do it.
+	     * If we weren't asking for CHAP, then we were asking for PAP,
+	     * in which case this Nak is bad.
+	     */
+	    if (!go->neg_chap)
+		goto bad;
+	    try.neg_chap = 0;
+
+	} else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+	    GETCHAR(cichar, p);
+	    if (go->neg_chap) {
+		/*
+		 * We were asking for CHAP/MD5; they must want a different
+		 * algorithm.  If they can't do MD5, we'll have to stop
+		 * asking for CHAP.
+		 */
+		if (cichar != go->chap_mdtype)
+		    try.neg_chap = 0;
+	    } else {
+		/*
+		 * Stop asking for PAP if we were asking for it.
+		 */
+		try.neg_upap = 0;
+	    }
+
+	} else {
+	    /*
+	     * We don't recognize what they're suggesting.
+	     * Stop asking for what we were asking for.
+	     */
+	    if (go->neg_chap)
+		try.neg_chap = 0;
+	    else
+		try.neg_upap = 0;
+	    p += cilen - CILEN_SHORT;
+	}
+    }
+
+    /*
+     * If they can't cope with our link quality protocol, we'll have
+     * to stop asking for LQR.  We haven't got any other protocol.
+     * If they Nak the reporting period, take their value XXX ?
+     */
+    NAKCILQR(CI_QUALITY, neg_lqr,
+	     if (cishort != PPP_LQR)
+		 try.neg_lqr = 0;
+	     else
+		 try.lqr_period = cilong;
+	     );
+
+    /*
+     * Only implementing CBCP...not the rest of the callback options
+     */
+    NAKCICHAR(CI_CALLBACK, neg_cbcp,
+              try.neg_cbcp = 0;
+              );
+
+    /*
+     * Check for a looped-back line.
+     */
+    NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+	      try.magicnumber = magic();
+	      looped_back = 1;
+	      );
+
+    /*
+     * Peer shouldn't send Nak for protocol compression or
+     * address/control compression requests; they should send
+     * a Reject instead.  If they send a Nak, treat it as a Reject.
+     */
+    NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+	      try.neg_pcompression = 0;
+	      );
+    NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+	      try.neg_accompression = 0;
+	      );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If we see an option that we requested, or one we've already seen
+     * in this packet, then this packet is bad.
+     * If we wanted to respond by starting to negotiate on the requested
+     * option(s), we could, but we don't, because except for the
+     * authentication type and quality protocol, if we are not negotiating
+     * an option, it is because we were told not to.
+     * For the authentication type, the Nak from the peer means
+     * `let me authenticate myself with you' which is a bit pointless.
+     * For the quality protocol, the Nak means `ask me to send you quality
+     * reports', but if we didn't ask for them, we don't want them.
+     * An option we don't recognize represents the peer asking to
+     * negotiate some option we don't support, so ignore it.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if (cilen < CILEN_VOID || (len -= cilen) < 0)
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_MRU:
+	    if ((go->neg_mru && go->mru != DEFMRU)
+		|| no.neg_mru || cilen != CILEN_SHORT)
+		goto bad;
+	    GETSHORT(cishort, p);
+	    if (cishort < DEFMRU)
+		try.mru = cishort;
+	    break;
+	case CI_ASYNCMAP:
+	    if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
+		|| no.neg_asyncmap || cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_AUTHTYPE:
+	    if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+		goto bad;
+	    break;
+	case CI_MAGICNUMBER:
+	    if (go->neg_magicnumber || no.neg_magicnumber ||
+		cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_PCOMPRESSION:
+	    if (go->neg_pcompression || no.neg_pcompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_ACCOMPRESSION:
+	    if (go->neg_accompression || no.neg_accompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_QUALITY:
+	    if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+		goto bad;
+	    break;
+	}
+	p = next;
+    }
+
+    /* If there is still anything left, this packet is bad. */
+    if (len != 0)
+	goto bad;
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     */
+    if (f->state != OPENED) {
+	if (looped_back) {
+	    if (++try.numloops >= lcp_loopbackfail) {
+		syslog(LOG_NOTICE, "Serial line is looped back.");
+		lcp_close(f->unit, "Loopback detected");
+	    }
+	} else
+	    try.numloops = 0;
+	*go = try;
+    }
+
+    return 1;
+
+bad:
+    LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Reject was bad.
+ *	1 - Reject was good.
+ */
+static int
+lcp_rejci(f, p, len)
+    fsm *f;
+    u_char *p;
+    int len;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char cichar;
+    u_short cishort;
+    u_int32_t cilong;
+    lcp_options try;		/* options to request next time */
+
+    try = *go;
+
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIVOID(opt, neg) \
+    if (go->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO, "lcp_rejci rejected void opt %d", opt)); \
+    }
+#define REJCISHORT(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	p[0] == opt) { \
+	len -= CILEN_SHORT; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */ \
+	if (cishort != val) \
+	    goto bad; \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected short opt %d", opt)); \
+    }
+#define REJCICHAP(opt, neg, val, digest) \
+    if (go->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	p[0] == opt) { \
+	len -= CILEN_CHAP; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cishort != val || cichar != digest) \
+	    goto bad; \
+	try.neg = 0; \
+	try.neg_upap = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected chap opt %d", opt)); \
+    }
+#define REJCILONG(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	p[0] == opt) { \
+	len -= CILEN_LONG; \
+	INCPTR(2, p); \
+	GETLONG(cilong, p); \
+	/* Check rejected value. */ \
+	if (cilong != val) \
+	    goto bad; \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected long opt %d", opt)); \
+    }
+#define REJCILQR(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	p[0] == opt) { \
+	len -= CILEN_LQR; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETLONG(cilong, p); \
+	/* Check rejected value. */ \
+	if (cishort != PPP_LQR || cilong != val) \
+	    goto bad; \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected LQR opt %d", opt)); \
+    }
+#define REJCICBCP(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_CBCP && \
+	p[1] == CILEN_CBCP && \
+	p[0] == opt) { \
+	len -= CILEN_CBCP; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != val) \
+	    goto bad; \
+	try.neg = 0; \
+	LCPDEBUG((LOG_INFO,"lcp_rejci rejected Callback opt %d", opt)); \
+    }
+
+    REJCISHORT(CI_MRU, neg_mru, go->mru);
+    REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+    REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+    if (!go->neg_chap) {
+	REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+    }
+    REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+    REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+    REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+    REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+    REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+lcp_reqci(f, inp, lenp, reject_if_disagree)
+    fsm *f;
+    u_char *inp;		/* Requested CIs */
+    int *lenp;			/* Length of requested CIs */
+    int reject_if_disagree;
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    int cilen, citype, cichar;	/* Parsed len, type, char value */
+    u_short cishort;		/* Parsed short value */
+    u_int32_t cilong;		/* Parse long value */
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *rejp;		/* Pointer to next char in reject frame */
+    u_char *nakp;		/* Pointer to next char in Nak frame */
+    int l = *lenp;		/* Length left */
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    nakp = nak_buffer;
+    rejp = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    citype = 0;
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+	case CI_MRU:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MRU"));
+	    if (!ao->neg_mru ||		/* Allow option? */
+		cilen != CILEN_SHORT) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETSHORT(cishort, p);	/* Parse MRU */
+	    LCPDEBUG((LOG_INFO, "(%d)", cishort));
+
+	    /*
+	     * He must be able to receive at least our minimum.
+	     * No need to check a maximum.  If he sends a large number,
+	     * we'll just ignore it.
+	     */
+	    if (cishort < MINMRU) {
+		orc = CONFNAK;		/* Nak CI */
+		PUTCHAR(CI_MRU, nakp);
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(MINMRU, nakp);	/* Give him a hint */
+		break;
+	    }
+	    ho->neg_mru = 1;		/* Remember he sent MRU */
+	    ho->mru = cishort;		/* And remember value */
+	    break;
+
+	case CI_ASYNCMAP:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ASYNCMAP"));
+	    if (!ao->neg_asyncmap ||
+		cilen != CILEN_LONG) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETLONG(cilong, p);
+	    LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong));
+
+	    /*
+	     * Asyncmap must have set at least the bits
+	     * which are set in lcp_allowoptions[unit].asyncmap.
+	     */
+	    if ((ao->asyncmap & ~cilong) != 0) {
+		orc = CONFNAK;
+		PUTCHAR(CI_ASYNCMAP, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(ao->asyncmap | cilong, nakp);
+		break;
+	    }
+	    ho->neg_asyncmap = 1;
+	    ho->asyncmap = cilong;
+	    break;
+
+	case CI_AUTHTYPE:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd AUTHTYPE"));
+
+	    if (cilen < CILEN_SHORT ||
+		!(ao->neg_upap || ao->neg_chap)) {
+		/*
+		 * Reject the option if we're not willing to authenticate.
+		 */
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+	    LCPDEBUG((LOG_INFO, "(%x)", cishort));
+
+	    /*
+	     * Authtype must be UPAP or CHAP.
+	     *
+	     * Note: if both ao->neg_upap and ao->neg_chap are set,
+	     * and the peer sends a Configure-Request with two
+	     * authenticate-protocol requests, one for CHAP and one
+	     * for UPAP, then we will reject the second request.
+	     * Whether we end up doing CHAP or UPAP depends then on
+	     * the ordering of the CIs in the peer's Configure-Request.
+	     */
+
+	    if (cishort == PPP_PAP) {
+		if (ho->neg_chap ||	/* we've already accepted CHAP */
+		    cilen != CILEN_SHORT) {
+		    LCPDEBUG((LOG_WARNING,
+			      "lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->neg_upap) {	/* we don't want to do PAP */
+		    orc = CONFNAK;	/* NAK it and suggest CHAP */
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_CHAP, nakp);
+		    PUTSHORT(PPP_CHAP, nakp);
+		    PUTCHAR(ao->chap_mdtype, nakp);
+		    break;
+		}
+		ho->neg_upap = 1;
+		break;
+	    }
+	    if (cishort == PPP_CHAP) {
+		if (ho->neg_upap ||	/* we've already accepted PAP */
+		    cilen != CILEN_CHAP) {
+		    LCPDEBUG((LOG_INFO,
+			      "lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->neg_chap) {	/* we don't want to do CHAP */
+		    orc = CONFNAK;	/* NAK it and suggest PAP */
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_SHORT, nakp);
+		    PUTSHORT(PPP_PAP, nakp);
+		    break;
+		}
+		GETCHAR(cichar, p);	/* get digest type*/
+		if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+		    && cichar != CHAP_MICROSOFT
+#endif
+		    ) {
+		    orc = CONFNAK;
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_CHAP, nakp);
+		    PUTSHORT(PPP_CHAP, nakp);
+		    PUTCHAR(ao->chap_mdtype, nakp);
+		    break;
+		}
+		ho->chap_mdtype = cichar; /* save md type */
+		ho->neg_chap = 1;
+		break;
+	    }
+
+	    /*
+	     * We don't recognize the protocol they're asking for.
+	     * Nak it with something we're willing to do.
+	     * (At this point we know ao->neg_upap || ao->neg_chap.)
+	     */
+	    orc = CONFNAK;
+	    PUTCHAR(CI_AUTHTYPE, nakp);
+	    if (ao->neg_chap) {
+		PUTCHAR(CILEN_CHAP, nakp);
+		PUTSHORT(PPP_CHAP, nakp);
+		PUTCHAR(ao->chap_mdtype, nakp);
+	    } else {
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(PPP_PAP, nakp);
+	    }
+	    break;
+
+	case CI_QUALITY:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd QUALITY"));
+	    if (!ao->neg_lqr ||
+		cilen != CILEN_LQR) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    GETSHORT(cishort, p);
+	    GETLONG(cilong, p);
+	    LCPDEBUG((LOG_INFO, "(%x %x)", cishort, (unsigned int) cilong));
+
+	    /*
+	     * Check the protocol and the reporting period.
+	     * XXX When should we Nak this, and what with?
+	     */
+	    if (cishort != PPP_LQR) {
+		orc = CONFNAK;
+		PUTCHAR(CI_QUALITY, nakp);
+		PUTCHAR(CILEN_LQR, nakp);
+		PUTSHORT(PPP_LQR, nakp);
+		PUTLONG(ao->lqr_period, nakp);
+		break;
+	    }
+	    break;
+
+	case CI_MAGICNUMBER:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd MAGICNUMBER"));
+	    if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+		cilen != CILEN_LONG) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETLONG(cilong, p);
+	    LCPDEBUG((LOG_INFO, "(%x)", (unsigned int) cilong));
+
+	    /*
+	     * He must have a different magic number.
+	     */
+	    if (go->neg_magicnumber &&
+		cilong == go->magicnumber) {
+		cilong = magic();	/* Don't put magic() inside macro! */
+		orc = CONFNAK;
+		PUTCHAR(CI_MAGICNUMBER, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(cilong, nakp);
+		break;
+	    }
+	    ho->neg_magicnumber = 1;
+	    ho->magicnumber = cilong;
+	    break;
+
+
+	case CI_PCOMPRESSION:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd PCOMPRESSION"));
+	    if (!ao->neg_pcompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_pcompression = 1;
+	    break;
+
+	case CI_ACCOMPRESSION:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd ACCOMPRESSION"));
+	    if (!ao->neg_accompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_accompression = 1;
+	    break;
+
+	default:
+	    LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd unknown option %d",
+		      citype));
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	LCPDEBUG((LOG_INFO, " (%s)", CODENAME(orc)));
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree	/* Getting fed up with sending NAKs? */
+		&& citype != CI_MAGICNUMBER) {
+		orc = CONFREJ;		/* Get tough if so */
+	    } else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		rc = CONFNAK;
+	    }
+	}
+	if (orc == CONFREJ) {		/* Reject this CI */
+	    rc = CONFREJ;
+	    if (cip != rejp)		/* Need to move rejected CI? */
+		BCOPY(cip, rejp, cilen); /* Move it */
+	    INCPTR(cilen, rejp);	/* Update output pointer */
+	}
+    }
+
+    /*
+     * If we wanted to send additional NAKs (for unsent CIs), the
+     * code would go here.  The extra NAKs would go at *nakp.
+     * At present there are no cases where we want to ask the
+     * peer to negotiate an option.
+     */
+
+    switch (rc) {
+    case CONFACK:
+	*lenp = next - inp;
+	break;
+    case CONFNAK:
+	/*
+	 * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+	 */
+	*lenp = nakp - nak_buffer;
+	BCOPY(nak_buffer, inp, *lenp);
+	break;
+    case CONFREJ:
+	*lenp = rejp - inp;
+	break;
+    }
+
+    LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void
+lcp_up(f)
+    fsm *f;
+{
+    lcp_options *wo = &lcp_wantoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+
+    if (!go->neg_magicnumber)
+	go->magicnumber = 0;
+    if (!ho->neg_magicnumber)
+	ho->magicnumber = 0;
+
+    /*
+     * Set our MTU to the smaller of the MTU we wanted and
+     * the MRU our peer wanted.  If we negotiated an MRU,
+     * set our MRU to the larger of value we wanted and
+     * the value we got in the negotiation.
+     */
+    ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+		    (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+		    ho->neg_pcompression, ho->neg_accompression);
+    ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
+		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+
+    if (ho->neg_mru)
+	peer_mru[f->unit] = ho->mru;
+
+    lcp_echo_lowerup(f->unit);  /* Enable echo messages */
+
+    link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(f)
+    fsm *f;
+{
+db_printf("%s()\n",__PRETTY_FUNCTION__);
+    lcp_options *go = &lcp_gotoptions[f->unit];
+
+    lcp_echo_lowerdown(f->unit);
+
+    link_down(f->unit);
+
+    ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
+    ppp_recv_config(f->unit, PPP_MRU,
+		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+    peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(f)
+    fsm *f;
+{
+    link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(f)
+    fsm *f;
+{
+db_printf("%s()\n",__PRETTY_FUNCTION__);
+    link_terminated(f->unit);
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej", "ProtRej",
+    "EchoReq", "EchoRep", "DiscReq"
+};
+
+static int
+lcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    u_int32_t cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+	printer(arg, " %s", lcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_MRU:
+		if (olen == CILEN_SHORT) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "mru %d", cishort);
+		}
+		break;
+	    case CI_ASYNCMAP:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "asyncmap 0x%x", cilong);
+		}
+		break;
+	    case CI_AUTHTYPE:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "auth ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_PAP:
+			printer(arg, "pap");
+			break;
+		    case PPP_CHAP:
+			printer(arg, "chap");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_QUALITY:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "quality ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_LQR:
+			printer(arg, "lqr");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_CALLBACK:
+		if (olen >= CILEN_CHAR) {
+		    p += 2;
+		    printer(arg, "callback ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case CBCP_OPT:
+			printer(arg, "CBCP");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_MAGICNUMBER:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "magic 0x%x", cilong);
+		}
+		break;
+	    case CI_PCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "pcomp");
+		}
+		break;
+	    case CI_ACCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "accomp");
+		}
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+
+    case ECHOREQ:
+    case ECHOREP:
+    case DISCREQ:
+	if (len >= 4) {
+	    GETLONG(cilong, p);
+	    printer(arg, " magic=0x%x", cilong);
+	    p += 4;
+	    len -= 4;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+
+static
+void LcpLinkFailure (f)
+    fsm *f;
+{
+    if (f->state == OPENED) {
+	syslog(LOG_INFO, "No response to %d echo-requests", lcp_echos_pending);
+        syslog(LOG_NOTICE, "Serial link appears to be disconnected.");
+        lcp_close(f->unit, "Peer not responding");
+    }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (f)
+    fsm *f;
+{
+    LcpSendEchoRequest (f);
+
+    /*
+     * Start the timer for the next interval.
+     */
+    assert (lcp_echo_timer_running==0);
+    TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
+    lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+
+static void
+LcpEchoTimeout (arg)
+    void *arg;
+{
+    if (lcp_echo_timer_running != 0) {
+        lcp_echo_timer_running = 0;
+        LcpEchoCheck ((fsm *) arg);
+    }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+
+static void
+lcp_received_echo_reply (f, id, inp, len)
+    fsm *f;
+    int id; u_char *inp; int len;
+{
+    u_int32_t magic;
+
+    /* Check the magic number - don't count replies from ourselves. */
+    if (len < 4) {
+	syslog(LOG_DEBUG, "lcp: received short Echo-Reply, length %d", len);
+	return;
+    }
+    GETLONG(magic, inp);
+    if (lcp_gotoptions[f->unit].neg_magicnumber
+	&& magic == lcp_gotoptions[f->unit].magicnumber) {
+	syslog(LOG_WARNING, "appear to have received our own echo-reply!");
+	return;
+    }
+
+    /* Reset the number of outstanding echo frames */
+    lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+
+static void
+LcpSendEchoRequest (f)
+    fsm *f;
+{
+    u_int32_t lcp_magic;
+    u_char pkt[4], *pktp;
+
+    /*
+     * Detect the failure of the peer at this point.
+     */
+    if (lcp_echo_fails != 0) {
+        if (lcp_echos_pending >= lcp_echo_fails) {
+            LcpLinkFailure(f);
+	    lcp_echos_pending = 0;
+	}
+    }
+
+    /*
+     * Make and send the echo request frame.
+     */
+    if (f->state == OPENED) {
+        lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+	pktp = pkt;
+	PUTLONG(lcp_magic, pktp);
+        fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+	++lcp_echos_pending;
+    }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerup (unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+
+    /* Clear the parameters for generating echo frames */
+    lcp_echos_pending      = 0;
+    lcp_echo_number        = 0;
+    lcp_echo_timer_running = 0;
+  
+    /* If a timeout interval is specified then start the timer */
+    if (lcp_echo_interval != 0)
+        LcpEchoCheck (f);
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerdown (unit)
+    int unit;
+{
+    fsm *f = &lcp_fsm[unit];
+
+    if (lcp_echo_timer_running != 0) {
+        UNTIMEOUT (LcpEchoTimeout, f);
+        lcp_echo_timer_running = 0;
+    }
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/magic.c
@@ -0,0 +1,140 @@
+//==========================================================================
+//
+//      src/magic.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/magic.c,v 1.8 1999/08/28 01:19:05 peter Exp $";
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/magic.h"
+
+extern long mrand48 __P((void));
+extern void srand48 __P((long));
+
+/*
+ * magic_init - Initialize the magic number generator.
+ *
+ * Attempts to compute a random number seed which will not repeat.
+ * The current method uses the current hostid, current process ID
+ * and current time, currently.
+ */
+void
+magic_init()
+{
+    long seed;
+    struct timeval t;
+
+    gettimeofday(&t, NULL);
+#ifndef __ECOS
+    seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ getpid();
+#else
+    seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ 42;
+#endif
+    srand48(seed);
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+u_int32_t
+magic()
+{
+    return (u_int32_t) mrand48();
+}
+
+#ifdef NO_DRAND48
+/*
+ * Substitute procedures for those systems which don't have
+ * drand48 et al.
+ */
+
+double
+drand48()
+{
+    return (double)random() / (double)0x7fffffffL; /* 2**31-1 */
+}
+
+long
+mrand48()
+{
+    return random();
+}
+
+void
+srand48(seedval)
+long seedval;
+{
+    srandom((int)seedval);
+}
+
+#endif
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/ppp_deflate.c
@@ -0,0 +1,731 @@
+//==========================================================================
+//
+//      src/ppp_deflate.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/* $FreeBSD: src/sys/net/ppp_deflate.c,v 1.12 1999/08/28 00:48:26 peter Exp $	*/
+
+/*
+ * ppp_deflate.c - interface the zlib procedures for Deflate compression
+ * and decompression (as used by gzip) to the PPP code.
+ * This version is for use with mbufs on BSD-derived systems.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define _KERNEL
+
+#include <sys/param.h>
+//#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <cyg/ppp/net/ppp_defs.h>
+#include <cyg/ppp/net/zlib.h>
+
+#define PACKETPTR	struct mbuf *
+#include <cyg/ppp/net/ppp_comp.h>
+
+#if DO_DEFLATE
+
+#define DEFLATE_DEBUG	1
+
+/*
+ * State for a Deflate (de)compressor.
+ */
+struct deflate_state {
+    int		seqno;
+    int		w_size;
+    int		unit;
+    int		hdrlen;
+    int		mru;
+    int		debug;
+    z_stream	strm;
+    struct compstat stats;
+};
+
+#define DEFLATE_OVHD	2		/* Deflate overhead/packet */
+
+static void	*z_alloc __P((void *, u_int items, u_int size));
+static void	z_free __P((void *, void *ptr));
+static void	*z_comp_alloc __P((u_char *options, int opt_len));
+static void	*z_decomp_alloc __P((u_char *options, int opt_len));
+static void	z_comp_free __P((void *state));
+static void	z_decomp_free __P((void *state));
+static int	z_comp_init __P((void *state, u_char *options, int opt_len,
+				 int unit, int hdrlen, int debug));
+static int	z_decomp_init __P((void *state, u_char *options, int opt_len,
+				     int unit, int hdrlen, int mru, int debug));
+static int	z_compress __P((void *state, struct mbuf **mret,
+				  struct mbuf *mp, int slen, int maxolen));
+static void	z_incomp __P((void *state, struct mbuf *dmsg));
+static int	z_decompress __P((void *state, struct mbuf *cmp,
+				    struct mbuf **dmpp));
+static void	z_comp_reset __P((void *state));
+static void	z_decomp_reset __P((void *state));
+static void	z_comp_stats __P((void *state, struct compstat *stats));
+
+/*
+ * Procedures exported to if_ppp.c.
+ */
+struct compressor ppp_deflate = {
+    CI_DEFLATE,			/* compress_proto */
+    z_comp_alloc,		/* comp_alloc */
+    z_comp_free,		/* comp_free */
+    z_comp_init,		/* comp_init */
+    z_comp_reset,		/* comp_reset */
+    z_compress,			/* compress */
+    z_comp_stats,		/* comp_stat */
+    z_decomp_alloc,		/* decomp_alloc */
+    z_decomp_free,		/* decomp_free */
+    z_decomp_init,		/* decomp_init */
+    z_decomp_reset,		/* decomp_reset */
+    z_decompress,		/* decompress */
+    z_incomp,			/* incomp */
+    z_comp_stats,		/* decomp_stat */
+};
+
+struct compressor ppp_deflate_draft = {
+    CI_DEFLATE_DRAFT,		/* compress_proto */
+    z_comp_alloc,		/* comp_alloc */
+    z_comp_free,		/* comp_free */
+    z_comp_init,		/* comp_init */
+    z_comp_reset,		/* comp_reset */
+    z_compress,			/* compress */
+    z_comp_stats,		/* comp_stat */
+    z_decomp_alloc,		/* decomp_alloc */
+    z_decomp_free,		/* decomp_free */
+    z_decomp_init,		/* decomp_init */
+    z_decomp_reset,		/* decomp_reset */
+    z_decompress,		/* decompress */
+    z_incomp,			/* incomp */
+    z_comp_stats,		/* decomp_stat */
+};
+
+/*
+ * Space allocation and freeing routines for use by zlib routines.
+ */
+void *
+z_alloc(notused, items, size)
+    void *notused;
+    u_int items, size;
+{
+    void *ptr;
+
+    MALLOC(ptr, void *, items * size, M_DEVBUF, M_NOWAIT);
+    return ptr;
+}
+
+void
+z_free(notused, ptr)
+    void *notused;
+    void *ptr;
+{
+    FREE(ptr, M_DEVBUF);
+}
+
+/*
+ * Allocate space for a compressor.
+ */
+static void *
+z_comp_alloc(options, opt_len)
+    u_char *options;
+    int opt_len;
+{
+    struct deflate_state *state;
+    int w_size;
+
+    if (opt_len != CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return NULL;
+    w_size = DEFLATE_SIZE(options[2]);
+    if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
+	return NULL;
+
+    MALLOC(state, struct deflate_state *, sizeof(struct deflate_state),
+	   M_DEVBUF, M_NOWAIT);
+    if (state == NULL)
+	return NULL;
+
+    state->strm.next_in = NULL;
+    state->strm.zalloc = z_alloc;
+    state->strm.zfree = z_free;
+    if (deflateInit2(&state->strm, Z_DEFAULT_COMPRESSION, DEFLATE_METHOD_VAL,
+		     -w_size, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+	FREE(state, M_DEVBUF);
+	return NULL;
+    }
+
+    state->w_size = w_size;
+    bzero(&state->stats, sizeof(state->stats));
+    return (void *) state;
+}
+
+static void
+z_comp_free(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    deflateEnd(&state->strm);
+    FREE(state, M_DEVBUF);
+}
+
+static int
+z_comp_init(arg, options, opt_len, unit, hdrlen, debug)
+    void *arg;
+    u_char *options;
+    int opt_len, unit, hdrlen, debug;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    if (opt_len < CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| DEFLATE_SIZE(options[2]) != state->w_size
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return 0;
+
+    state->seqno = 0;
+    state->unit = unit;
+    state->hdrlen = hdrlen;
+    state->debug = debug;
+
+    deflateReset(&state->strm);
+
+    return 1;
+}
+
+static void
+z_comp_reset(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    state->seqno = 0;
+    deflateReset(&state->strm);
+}
+
+int
+z_compress(arg, mret, mp, orig_len, maxolen)
+    void *arg;
+    struct mbuf **mret;		/* compressed packet (out) */
+    struct mbuf *mp;		/* uncompressed packet (in) */
+    int orig_len, maxolen;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+    u_char *rptr, *wptr;
+    int proto, olen, wspace, r, flush;
+    struct mbuf *m;
+
+    /*
+     * Check that the protocol is in the range we handle.
+     */
+    rptr = mtod(mp, u_char *);
+    proto = PPP_PROTOCOL(rptr);
+    if (proto > 0x3fff || proto == 0xfd || proto == 0xfb) {
+	*mret = NULL;
+	return orig_len;
+    }
+
+    /* Allocate one mbuf initially. */
+    if (maxolen > orig_len)
+	maxolen = orig_len;
+    MGET(m, M_DONTWAIT, MT_DATA);
+    *mret = m;
+    if (m != NULL) {
+	m->m_len = 0;
+	if (maxolen + state->hdrlen > MLEN)
+	    MCLGET(m, M_DONTWAIT);
+	wspace = M_TRAILINGSPACE(m);
+	if (state->hdrlen + PPP_HDRLEN + 2 < wspace) {
+	    m->m_data += state->hdrlen;
+	    wspace -= state->hdrlen;
+	}
+	wptr = mtod(m, u_char *);
+
+	/*
+	 * Copy over the PPP header and store the 2-byte sequence number.
+	 */
+	wptr[0] = PPP_ADDRESS(rptr);
+	wptr[1] = PPP_CONTROL(rptr);
+	wptr[2] = PPP_COMP >> 8;
+	wptr[3] = PPP_COMP;
+	wptr += PPP_HDRLEN;
+	wptr[0] = state->seqno >> 8;
+	wptr[1] = state->seqno;
+	wptr += 2;
+	state->strm.next_out = wptr;
+	state->strm.avail_out = wspace - (PPP_HDRLEN + 2);
+    } else {
+	state->strm.next_out = NULL;
+	state->strm.avail_out = 1000000;
+	wptr = NULL;
+	wspace = 0;
+    }
+    ++state->seqno;
+
+    rptr += (proto > 0xff)? 2: 3;	/* skip 1st proto byte if 0 */
+    state->strm.next_in = rptr;
+    state->strm.avail_in = mtod(mp, u_char *) + mp->m_len - rptr;
+    mp = mp->m_next;
+    flush = (mp == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+    olen = 0;
+    for (;;) {
+	r = deflate(&state->strm, flush);
+	if (r != Z_OK) {
+	    printf("z_compress: deflate returned %d (%s)\n",
+		   r, (state->strm.msg? state->strm.msg: ""));
+	    break;
+	}
+	if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+	    break;		/* all done */
+	if (state->strm.avail_in == 0 && mp != NULL) {
+	    state->strm.next_in = mtod(mp, u_char *);
+	    state->strm.avail_in = mp->m_len;
+	    mp = mp->m_next;
+	    if (mp == NULL)
+		flush = Z_PACKET_FLUSH;
+	}
+	if (state->strm.avail_out == 0) {
+	    if (m != NULL) {
+		m->m_len = wspace;
+		olen += wspace;
+		MGET(m->m_next, M_DONTWAIT, MT_DATA);
+		m = m->m_next;
+		if (m != NULL) {
+		    m->m_len = 0;
+		    if (maxolen - olen > MLEN)
+			MCLGET(m, M_DONTWAIT);
+		    state->strm.next_out = mtod(m, u_char *);
+		    state->strm.avail_out = wspace = M_TRAILINGSPACE(m);
+		}
+	    }
+	    if (m == NULL) {
+		state->strm.next_out = NULL;
+		state->strm.avail_out = 1000000;
+	    }
+	}
+    }
+    if (m != NULL)
+	olen += (m->m_len = wspace - state->strm.avail_out);
+
+    /*
+     * See if we managed to reduce the size of the packet.
+     */
+    if (m != NULL && olen < orig_len) {
+	state->stats.comp_bytes += olen;
+	state->stats.comp_packets++;
+    } else {
+	if (*mret != NULL) {
+	    m_freem(*mret);
+	    *mret = NULL;
+	}
+	state->stats.inc_bytes += orig_len;
+	state->stats.inc_packets++;
+	olen = orig_len;
+    }
+    state->stats.unc_bytes += orig_len;
+    state->stats.unc_packets++;
+
+    return olen;
+}
+
+static void
+z_comp_stats(arg, stats)
+    void *arg;
+    struct compstat *stats;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+    u_int out;
+
+    *stats = state->stats;
+    stats->ratio = stats->unc_bytes;
+    out = stats->comp_bytes + stats->inc_bytes;
+    if (stats->ratio <= 0x7ffffff)
+	stats->ratio <<= 8;
+    else
+	out >>= 8;
+    if (out != 0)
+	stats->ratio /= out;
+}
+
+/*
+ * Allocate space for a decompressor.
+ */
+static void *
+z_decomp_alloc(options, opt_len)
+    u_char *options;
+    int opt_len;
+{
+    struct deflate_state *state;
+    int w_size;
+
+    if (opt_len != CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return NULL;
+    w_size = DEFLATE_SIZE(options[2]);
+    if (w_size < DEFLATE_MIN_SIZE || w_size > DEFLATE_MAX_SIZE)
+	return NULL;
+
+    MALLOC(state, struct deflate_state *, sizeof(struct deflate_state),
+	   M_DEVBUF, M_NOWAIT);
+    if (state == NULL)
+	return NULL;
+
+    state->strm.next_out = NULL;
+    state->strm.zalloc = z_alloc;
+    state->strm.zfree = z_free;
+    if (inflateInit2(&state->strm, -w_size) != Z_OK) {
+	FREE(state, M_DEVBUF);
+	return NULL;
+    }
+
+    state->w_size = w_size;
+    bzero(&state->stats, sizeof(state->stats));
+    return (void *) state;
+}
+
+static void
+z_decomp_free(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    inflateEnd(&state->strm);
+    FREE(state, M_DEVBUF);
+}
+
+static int
+z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug)
+    void *arg;
+    u_char *options;
+    int opt_len, unit, hdrlen, mru, debug;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    if (opt_len < CILEN_DEFLATE
+	|| (options[0] != CI_DEFLATE && options[0] != CI_DEFLATE_DRAFT)
+	|| options[1] != CILEN_DEFLATE
+	|| DEFLATE_METHOD(options[2]) != DEFLATE_METHOD_VAL
+	|| DEFLATE_SIZE(options[2]) != state->w_size
+	|| options[3] != DEFLATE_CHK_SEQUENCE)
+	return 0;
+
+    state->seqno = 0;
+    state->unit = unit;
+    state->hdrlen = hdrlen;
+    state->debug = debug;
+    state->mru = mru;
+
+    inflateReset(&state->strm);
+
+    return 1;
+}
+
+static void
+z_decomp_reset(arg)
+    void *arg;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+
+    state->seqno = 0;
+    inflateReset(&state->strm);
+}
+
+/*
+ * Decompress a Deflate-compressed packet.
+ *
+ * Because of patent problems, we return DECOMP_ERROR for errors
+ * found by inspecting the input data and for system problems, but
+ * DECOMP_FATALERROR for any errors which could possibly be said to
+ * be being detected "after" decompression.  For DECOMP_ERROR,
+ * we can issue a CCP reset-request; for DECOMP_FATALERROR, we may be
+ * infringing a patent of Motorola's if we do, so we take CCP down
+ * instead.
+ *
+ * Given that the frame has the correct sequence number and a good FCS,
+ * errors such as invalid codes in the input most likely indicate a
+ * bug, so we return DECOMP_FATALERROR for them in order to turn off
+ * compression, even though they are detected by inspecting the input.
+ */
+int
+z_decompress(arg, mi, mop)
+    void *arg;
+    struct mbuf *mi, **mop;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+    struct mbuf *mo, *mo_head;
+    u_char *rptr, *wptr;
+    int rlen, olen, ospace;
+    int seq, i, flush, r, decode_proto;
+    u_char hdr[PPP_HDRLEN + DEFLATE_OVHD];
+
+    *mop = NULL;
+    rptr = mtod(mi, u_char *);
+    rlen = mi->m_len;
+    for (i = 0; i < PPP_HDRLEN + DEFLATE_OVHD; ++i) {
+	while (rlen <= 0) {
+	    mi = mi->m_next;
+	    if (mi == NULL)
+		return DECOMP_ERROR;
+	    rptr = mtod(mi, u_char *);
+	    rlen = mi->m_len;
+	}
+	hdr[i] = *rptr++;
+	--rlen;
+    }
+
+    /* Check the sequence number. */
+    seq = (hdr[PPP_HDRLEN] << 8) + hdr[PPP_HDRLEN+1];
+    if (seq != state->seqno) {
+	if (state->debug)
+	    printf("z_decompress%d: bad seq # %d, expected %d\n",
+		   state->unit, seq, state->seqno);
+	return DECOMP_ERROR;
+    }
+    ++state->seqno;
+
+    /* Allocate an output mbuf. */
+    MGETHDR(mo, M_DONTWAIT, MT_DATA);
+    if (mo == NULL)
+	return DECOMP_ERROR;
+    mo_head = mo;
+    mo->m_len = 0;
+    mo->m_next = NULL;
+    MCLGET(mo, M_DONTWAIT);
+    ospace = M_TRAILINGSPACE(mo);
+    if (state->hdrlen + PPP_HDRLEN < ospace) {
+	mo->m_data += state->hdrlen;
+	ospace -= state->hdrlen;
+    }
+
+    /*
+     * Fill in the first part of the PPP header.  The protocol field
+     * comes from the decompressed data.
+     */
+    wptr = mtod(mo, u_char *);
+    wptr[0] = PPP_ADDRESS(hdr);
+    wptr[1] = PPP_CONTROL(hdr);
+    wptr[2] = 0;
+
+    /*
+     * Set up to call inflate.  We set avail_out to 1 initially so we can
+     * look at the first byte of the output and decide whether we have
+     * a 1-byte or 2-byte protocol field.
+     */
+    state->strm.next_in = rptr;
+    state->strm.avail_in = rlen;
+    mi = mi->m_next;
+    flush = (mi == NULL)? Z_PACKET_FLUSH: Z_NO_FLUSH;
+    rlen += PPP_HDRLEN + DEFLATE_OVHD;
+    state->strm.next_out = wptr + 3;
+    state->strm.avail_out = 1;
+    decode_proto = 1;
+    olen = PPP_HDRLEN;
+
+    /*
+     * Call inflate, supplying more input or output as needed.
+     */
+    for (;;) {
+	r = inflate(&state->strm, flush);
+	if (r != Z_OK) {
+#if !DEFLATE_DEBUG
+	    if (state->debug)
+#endif
+		printf("z_decompress%d: inflate returned %d (%s)\n",
+		       state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	    m_freem(mo_head);
+	    return DECOMP_FATALERROR;
+	}
+	if (flush != Z_NO_FLUSH && state->strm.avail_out != 0)
+	    break;		/* all done */
+	if (state->strm.avail_in == 0 && mi != NULL) {
+	    state->strm.next_in = mtod(mi, u_char *);
+	    state->strm.avail_in = mi->m_len;
+	    rlen += mi->m_len;
+	    mi = mi->m_next;
+	    if (mi == NULL)
+		flush = Z_PACKET_FLUSH;
+	}
+	if (state->strm.avail_out == 0) {
+	    if (decode_proto) {
+		state->strm.avail_out = ospace - PPP_HDRLEN;
+		if ((wptr[3] & 1) == 0) {
+		    /* 2-byte protocol field */
+		    wptr[2] = wptr[3];
+		    --state->strm.next_out;
+		    ++state->strm.avail_out;
+		    --olen;
+		}
+		decode_proto = 0;
+	    } else {
+		mo->m_len = ospace;
+		olen += ospace;
+		MGET(mo->m_next, M_DONTWAIT, MT_DATA);
+		mo = mo->m_next;
+		if (mo == NULL) {
+		    m_freem(mo_head);
+		    return DECOMP_ERROR;
+		}
+		MCLGET(mo, M_DONTWAIT);
+		state->strm.next_out = mtod(mo, u_char *);
+		state->strm.avail_out = ospace = M_TRAILINGSPACE(mo);
+	    }
+	}
+    }
+    if (decode_proto) {
+	m_freem(mo_head);
+	return DECOMP_ERROR;
+    }
+    olen += (mo->m_len = ospace - state->strm.avail_out);
+#if DEFLATE_DEBUG
+    if (state->debug && olen > state->mru + PPP_HDRLEN)
+	printf("ppp_deflate%d: exceeded mru (%d > %d)\n",
+	       state->unit, olen, state->mru + PPP_HDRLEN);
+#endif
+
+    state->stats.unc_bytes += olen;
+    state->stats.unc_packets++;
+    state->stats.comp_bytes += rlen;
+    state->stats.comp_packets++;
+
+    *mop = mo_head;
+    return DECOMP_OK;
+}
+
+/*
+ * Incompressible data has arrived - add it to the history.
+ */
+static void
+z_incomp(arg, mi)
+    void *arg;
+    struct mbuf *mi;
+{
+    struct deflate_state *state = (struct deflate_state *) arg;
+    u_char *rptr;
+    int rlen, proto, r;
+
+    /*
+     * Check that the protocol is one we handle.
+     */
+    rptr = mtod(mi, u_char *);
+    proto = PPP_PROTOCOL(rptr);
+    if (proto > 0x3fff || proto == 0xfd || proto == 0xfb)
+	return;
+
+    ++state->seqno;
+
+    /*
+     * Iterate through the mbufs, adding the characters in them
+     * to the decompressor's history.  For the first mbuf, we start
+     * at the either the 1st or 2nd byte of the protocol field,
+     * depending on whether the protocol value is compressible.
+     */
+    rlen = mi->m_len;
+    state->strm.next_in = rptr + 3;
+    state->strm.avail_in = rlen - 3;
+    if (proto > 0xff) {
+	--state->strm.next_in;
+	++state->strm.avail_in;
+    }
+    for (;;) {
+	r = inflateIncomp(&state->strm);
+	if (r != Z_OK) {
+	    /* gak! */
+#if !DEFLATE_DEBUG
+	    if (state->debug)
+#endif
+		printf("z_incomp%d: inflateIncomp returned %d (%s)\n",
+		       state->unit, r, (state->strm.msg? state->strm.msg: ""));
+	    return;
+	}
+	mi = mi->m_next;
+	if (mi == NULL)
+	    break;
+	state->strm.next_in = mtod(mi, u_char *);
+	state->strm.avail_in = mi->m_len;
+	rlen += mi->m_len;
+    }
+
+    /*
+     * Update stats.
+     */
+    state->stats.inc_bytes += rlen;
+    state->stats.inc_packets++;
+    state->stats.unc_bytes += rlen;
+    state->stats.unc_packets++;
+}
+
+#endif /* DO_DEFLATE */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/ppp_io.c
@@ -0,0 +1,1107 @@
+//==========================================================================
+//
+//      src/ppp_io.c
+//
+//==========================================================================
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003, 2004 eCosCentric Ltd.
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
+ * 	       tty devices.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Drew D. Perkins
+ * Carnegie Mellon University
+ * 4910 Forbes Ave.
+ * Pittsburgh, PA 15213
+ * (412) 268-8576
+ * ddp@andrew.cmu.edu
+ *
+ * Based on:
+ *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Serial Line interface
+ *
+ * Rick Adams
+ * Center for Seismic Studies
+ * 1300 N 17th Street, Suite 1450
+ * Arlington, Virginia 22209
+ * (703)276-7900
+ * rick@seismo.ARPA
+ * seismo!rick
+ *
+ * Pounded on heavily by Chris Torek (chris@mimsy.umd.edu, umcp-cs!chris).
+ * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
+ *
+ * Converted to 4.3BSD+ 386BSD by Brad Parker (brad@cayman.com)
+ * Added VJ tcp header compression; more unified ioctls
+ *
+ * Extensively modified by Paul Mackerras (paulus@cs.anu.edu.au).
+ * Cleaned up a lot of the mbuf-related code to fix bugs that
+ * caused system crashes and packet corruption.  Changed pppstart
+ * so that it doesn't just give up with a "collision" if the whole
+ * packet doesn't fit in the output ring buffer.
+ *
+ * Added priority queueing for interactive IP packets, following
+ * the model of if_sl.c, plus hooks for bpf.
+ * Paul Mackerras (paulus@cs.anu.edu.au).
+ */
+
+/* $FreeBSD: src/sys/net/ppp_tty.c,v 1.43 2000/01/29 16:56:24 peter Exp $ */
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+#define _KERNEL
+
+#define VJC			/* XXX for ppp_defs.h */
+
+#include <sys/param.h>
+#define suser(x) 0
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
+#include <cyg/ppp/net/if_ppp.h>
+#include <cyg/ppp/net/if_pppvar.h>
+
+//==========================================================================
+
+#ifdef __ECOS
+
+#include "cyg/ppp/ppp_io.h"
+
+//#define db_printf diag_printf
+#define db_printf(fmt, ... )
+
+#define spltty(x) splsoftnet(x)
+
+#define ENOIOCTL ENOSYS
+
+#endif
+
+//==========================================================================
+
+static u_short	pppfcs __P((u_short fcs, u_char *cp, int len));
+static void	pppasyncstart __P((struct ppp_softc *));
+static void	pppasyncctlp __P((struct ppp_softc *));
+static void	pppasyncrelinq __P((struct ppp_softc *));
+static void	pppasyncsetmtu __P((struct ppp_softc *));
+static void	pppgetm __P((struct ppp_softc *sc));
+static void	ppplogchar __P((struct ppp_softc *, int));
+
+/* XXX called from if_ppp.c - layering violation */
+void		pppasyncattach __P((void *));
+
+//==========================================================================
+/*
+ * Some useful mbuf macros not in mbuf.h.
+ */
+#define M_IS_CLUSTER(m)	((m)->m_flags & M_EXT)
+
+#define M_DATASTART(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
+	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
+
+#define M_DATASIZE(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
+	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+
+//==========================================================================
+/*
+ * Does c need to be escaped?
+ */
+#define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
+
+//==========================================================================
+/*
+ * Procedures for using an async tty interface for PPP.
+ */
+
+/* This is a FreeBSD-2.X kernel. */
+//#define CCOUNT(q)	((q)->c_cc)
+//#define PPP_LOWAT	100	/* Process more output when < LOWAT on queue */
+//#define	PPP_HIWAT	400	/* Don't start a new packet if HIWAT on que */
+
+
+//==========================================================================
+/*
+ * Line specific open routine for async tty devices.
+ * Attach the given tty to the first available ppp unit.
+ * Called from device open routine or ttioctl() at >= splsofttty()
+ */
+/* ARGSUSED */
+
+int
+cyg_ppp_pppopen(tp)
+    struct tty *tp;
+{
+    register struct ppp_softc *sc;
+    int error, s;
+
+    if ((error = suser(p)) != 0)
+	return (error);
+
+    s = spltty();
+
+    if ((sc = pppalloc(0)) == NULL) {
+	splx(s);
+	return ENXIO;
+    }
+    
+    if (sc->sc_relinq)
+	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
+
+    sc->sc_ilen = 0;
+    sc->sc_m = NULL;
+    bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
+    sc->sc_asyncmap[0] = 0xffffffff;
+    sc->sc_asyncmap[3] = 0x60000000;
+    sc->sc_rasyncmap = 0;
+    sc->sc_devp = (void *) tp;
+    sc->sc_start = pppasyncstart;
+    sc->sc_ctlp = pppasyncctlp;
+    sc->sc_relinq = pppasyncrelinq;
+    sc->sc_setmtu = pppasyncsetmtu;
+    sc->sc_outm = NULL;
+    pppgetm(sc);
+    sc->sc_if.if_flags |= IFF_RUNNING;
+    getmicrotime(&sc->sc_if.if_lastchange);
+    tp->t_sc = (caddr_t) sc;
+    
+    splx(s);
+
+    return (0);
+}
+
+//==========================================================================
+/*
+ * Line specific close routine, called from device close routine
+ * and from ttioctl at >= splsofttty().
+ * Detach the tty from the ppp unit.
+ * Mimics part of ttyclose().
+ */
+
+int
+cyg_ppp_pppclose(tp, flag)
+    struct tty *tp;
+    int flag;
+{
+    register struct ppp_softc *sc;
+    int s;
+
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    s = spltty();
+
+    sc = (struct ppp_softc *) tp->t_sc;
+    if (sc != NULL) {
+	tp->t_sc = NULL;
+	if (tp == (struct tty *) sc->sc_devp) {
+	    pppasyncrelinq(sc);
+	    pppdealloc(sc);
+	}
+    }
+    splx(s);
+    return 0;
+}
+
+//==========================================================================
+/*
+ * Relinquish the interface unit to another device.
+ */
+
+static void
+pppasyncrelinq(sc)
+    struct ppp_softc *sc;
+{
+    int s;
+
+    s = spltty();
+    if (sc->sc_outm) {
+	m_freem(sc->sc_outm);
+	sc->sc_outm = NULL;
+    }
+    if (sc->sc_m) {
+	m_freem(sc->sc_m);
+	sc->sc_m = NULL;
+    }
+    if (sc->sc_flags & SC_TIMEOUT) {
+	sc->sc_flags &= ~SC_TIMEOUT;
+    }
+    splx(s);
+}
+
+//==========================================================================
+/*
+ * This gets called from the upper layer to notify a mtu change
+ */
+
+static void
+pppasyncsetmtu(sc)
+register struct ppp_softc *sc;
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+//==========================================================================
+/*
+ * Line specific (tty) read routine.
+ * called at zero spl from the device driver in the response to user-level
+ * reads on the tty file descriptor (ie: pppd).
+ */
+
+int
+cyg_ppp_pppread(tp, uio, flag)
+    register struct tty *tp;
+    struct uio *uio;
+    int flag;
+{
+    register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
+    struct mbuf *m, *m0;
+    register int s;
+    int error = 0;
+
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+
+    if (sc == NULL)
+	return 0;
+
+    // Look for input. If there is none return EWOULDBLOCK, otherwise
+    // dequeue the next packet and return it.
+    
+    s = spltty();
+
+    if (tp != (struct tty *) sc->sc_devp ) {
+        splx(s);
+        return 0;
+    }
+    if (sc->sc_inq.ifq_head == NULL)
+    {
+        splx(s);
+        return EWOULDBLOCK;
+    }
+
+    /* Get the packet from the input queue */
+    IF_DEQUEUE(&sc->sc_inq, m0);
+    splx(s);
+
+ 
+    for (m = m0; m && uio->uio_resid; m = m->m_next)
+    {
+	if ((error = uiomove(mtod(m, u_char *), m->m_len, uio)) != 0)
+	    break;
+    }
+    m_freem(m0);
+    
+    return (error);    
+}
+
+//==========================================================================
+/*
+ * Line specific (tty) write routine.
+ * called at zero spl from the device driver in the response to user-level
+ * writes on the tty file descriptor (ie: pppd).
+ */
+
+int
+cyg_ppp_pppwrite(tp, uio, flag)
+    register struct tty *tp;
+    struct uio *uio;
+    int flag;
+{
+    register struct ppp_softc *sc = (struct ppp_softc *)tp->t_sc;
+    struct mbuf *m, *m0, **mp;
+    struct sockaddr dst;
+    int len, error, s;
+    
+    s = spltty();
+    for (mp = &m0; uio->uio_resid; mp = &m->m_next) {
+	MGET(m, M_WAIT, MT_DATA);
+	if ((*mp = m) == NULL) {
+	    m_freem(m0);
+	    splx(s);
+	    return (ENOBUFS);
+	}
+	m->m_len = 0;
+	if (uio->uio_resid >= MCLBYTES / 2)
+	    MCLGET(m, M_DONTWAIT);
+	len = M_TRAILINGSPACE(m);
+	if (len > uio->uio_resid)
+	    len = uio->uio_resid;
+	if ((error = uiomove(mtod(m, u_char *), len, uio)) != 0) {
+	    m_freem(m0);
+	    splx(s);
+	    return (error);
+	}
+	m->m_len = len;
+    }
+    dst.sa_family = AF_UNSPEC;
+    bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
+    m0->m_data += PPP_HDRLEN;
+    m0->m_len -= PPP_HDRLEN;
+
+    /* call the upper layer to "transmit" it... */
+    error = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
+    splx(s);
+    return (error);
+}
+
+//==========================================================================
+/*
+ * Line specific (tty) ioctl routine.
+ * This discipline requires that tty device drivers call
+ * the line specific l_ioctl routine from their ioctl routines.
+ */
+/* ARGSUSED */
+int
+cyg_ppp_ppptioctl(tp, cmd, data, flag)
+    struct tty *tp;
+    u_long cmd;
+    caddr_t data;
+    int flag;
+//    struct proc *p;
+{
+    struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
+    int error, s;
+
+    if (sc == NULL || tp != (struct tty *) sc->sc_devp)
+	return (ENOIOCTL);
+
+    error = 0;
+    switch (cmd) {
+    case PPPIOCSASYNCMAP:
+	sc->sc_asyncmap[0] = *(u_int *)data;
+	break;
+
+    case PPPIOCGASYNCMAP:
+	*(u_int *)data = sc->sc_asyncmap[0];
+	break;
+
+    case PPPIOCSRASYNCMAP:
+	if ((error = suser(p)) != 0)
+	    break;
+	sc->sc_rasyncmap = *(u_int *)data;
+	break;
+
+    case PPPIOCGRASYNCMAP:
+	*(u_int *)data = sc->sc_rasyncmap;
+	break;
+
+    case PPPIOCSXASYNCMAP:
+	s = spltty();
+	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
+	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
+	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
+	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
+	splx(s);
+	break;
+
+    case PPPIOCGXASYNCMAP:
+	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
+	break;
+
+    default:
+	error = pppioctl(sc, cmd, data, flag, 0);
+	if (error == 0 && cmd == PPPIOCSMRU)
+	    pppgetm(sc);
+    }
+
+    return error;
+}
+
+//==========================================================================
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
+	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
+	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
+	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
+	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
+	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
+	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
+	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
+	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
+	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
+	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
+	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
+	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
+	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
+	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
+	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
+	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
+	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
+	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
+	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
+	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
+	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
+	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
+	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
+	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
+	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
+	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
+	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
+	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
+	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
+	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
+	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
+};
+
+//==========================================================================
+/*
+ * Calculate a new FCS given the current FCS and the new data.
+ */
+static u_short
+pppfcs(u_short fcs, u_char *cp, int len)
+{
+    while (len--)
+	fcs = PPP_FCS(fcs, *cp++);
+    return (fcs);
+}
+
+//==========================================================================
+
+#ifdef __ECOS
+
+// Call pppasyncstart() to kick transmission into life. 
+int cyg_ppp_pppstart( struct tty *tp )
+{
+    struct ppp_softc *sc = (struct ppp_softc *) tp->t_sc;
+
+    while( sc->sc_outm != NULL )
+    {
+        // We wait for the output buffer to drain of all characters
+        // before we call pppasyncstart(). That way we know there will
+        // be room for some data. We would really like to just drain
+        // down to some low water mark, but the drivers don't provide
+        // that functionality. However, since most devices have
+        // hardware FIFO's, we have a grace period to get more
+        // characters into the device, so hopefully there won't be a
+        // gap on the line.
+        
+        cyg_uint32 nb = 0;
+        cyg_uint32 len = sizeof(nb);
+        int s;
+
+        cyg_io_get_config( tp->t_handle,
+                           CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN,
+                           &nb, &len);
+
+        s = splsoftnet();
+
+        pppasyncstart( sc );
+
+        splx(s);
+    }
+    
+    return 0;
+}
+
+#endif
+
+
+//==========================================================================
+/*
+ * This gets called at splsoftnet from if_ppp.c at various times
+ * when there is data ready to be sent.
+ */
+static void
+pppasyncstart(sc)
+    register struct ppp_softc *sc;
+{
+    register struct tty *tp = (struct tty *) sc->sc_devp;
+    register struct mbuf *m;
+    register int len;
+    register u_char *start, *stop, *cp;
+    int n, ndone, done, idle;
+    struct mbuf *m2;
+    int s;
+
+    idle = 0;
+
+    while (1) {        
+	/*
+	 * See if we have an existing packet partly sent.
+	 * If not, get a new packet and start sending it.
+	 */
+	m = sc->sc_outm;
+	if (m == NULL) {
+	    /*
+	     * Get another packet to be sent.
+	     */
+	    m = ppp_dequeue(sc);
+	    if (m == NULL) {
+		idle = 1;
+		break;
+	    }
+
+	    /* Calculate the FCS for the first mbuf's worth. */
+	    sc->sc_outfcs = pppfcs(PPP_INITFCS, mtod(m, u_char *), m->m_len);
+	    getmicrotime(&sc->sc_if.if_lastchange);
+	}
+
+	for (;;) {
+	    start = mtod(m, u_char *);
+	    len = m->m_len;
+	    stop = start + len;
+	    while (len > 0) {
+		/*
+		 * Find out how many bytes in the string we can
+		 * handle without doing something special.
+		 */
+		for (cp = start; cp < stop; cp++)
+		    if (ESCAPE_P(*cp))
+			break;
+		n = cp - start;
+		if (n) {
+#ifndef __ECOS        
+		    /* NetBSD (0.9 or later), 4.3-Reno or similar. */
+		    ndone = n - b_to_q(start, n, &tp->t_outq);
+#else
+                    ndone = 0;
+//                    db_printf("send: data %d\n",ndone);
+//                    db_dump_buf(start,ndone);
+                    {
+                        cyg_serial_buf_info_t info;
+                        cyg_uint32 ilen = sizeof(info);
+                        if( cyg_io_get_config( tp->t_handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO, &info, &ilen ) == 0 )
+                        {
+                            ndone = info.tx_bufsize-info.tx_count;
+                            if( ndone > n )
+                                ndone = n;
+                            cyg_io_write( tp->t_handle, start, &ndone);
+                        }
+                    }
+#endif
+		    len -= ndone;
+		    start += ndone;
+		    sc->sc_stats.ppp_obytes += ndone;
+
+		    if (ndone < n)
+			break;	/* packet doesn't fit */
+		}
+		/*
+		 * If there are characters left in the mbuf,
+		 * the first one must be special.
+		 * Put it out in a different form.
+		 */
+		if (len) {
+		    s = spltty();
+#ifndef __ECOS        
+		    if (putc(PPP_ESCAPE, &tp->t_outq)) {
+			splx(s);
+			break;
+		    }
+		    if (putc(*start ^ PPP_TRANS, &tp->t_outq)) {
+			(void) unputc(&tp->t_outq);
+			splx(s);
+			break;
+		    }
+#else
+                    {
+                        cyg_serial_buf_info_t info;
+                        cyg_uint32 ilen = sizeof(info);
+                        if( cyg_io_get_config( tp->t_handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO, &info, &ilen ) == 0 &&
+                            info.tx_bufsize-info.tx_count >= 2 )
+                        {
+                            char buf[2];
+                            int blen = 2;
+                            buf[0] = PPP_ESCAPE;
+                            buf[1] = *start ^ PPP_TRANS;
+                            if( cyg_io_write( tp->t_handle, buf, &blen) != 0 ) {
+                                splx(s);
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            splx(s);
+                            break;
+                        }
+                    }
+#endif
+		    splx(s);
+		    sc->sc_stats.ppp_obytes += 2;
+		    start++;
+		    len--;
+                } // if( len )
+            } // while (len > 0)
+
+	    /*
+	     * If we didn't empty this mbuf, remember where we're up to.
+	     * If we emptied the last mbuf, try to add the FCS and closing
+	     * flag, and if we can't, leave sc_outm pointing to m, but with
+	     * m->m_len == 0, to remind us to output the FCS and flag later.
+	     */
+	    done = len == 0;
+	    if (done && m->m_next == NULL) {
+		u_char *p, *q;
+		int c;
+		u_char endseq[8];
+
+		/*
+		 * We may have to escape the bytes in the FCS.
+		 */
+		p = endseq;
+		c = ~sc->sc_outfcs & 0xFF;
+		if (ESCAPE_P(c)) {
+		    *p++ = PPP_ESCAPE;
+		    *p++ = c ^ PPP_TRANS;
+		} else
+		    *p++ = c;
+		c = (~sc->sc_outfcs >> 8) & 0xFF;
+		if (ESCAPE_P(c)) {
+		    *p++ = PPP_ESCAPE;
+		    *p++ = c ^ PPP_TRANS;
+		} else
+		    *p++ = c;
+		*p++ = PPP_FLAG;
+
+		/*
+		 * Try to output the FCS and flag.  If the bytes
+		 * don't all fit, back out.
+		 */
+		s = spltty();
+#ifndef __ECOS
+		for (q = endseq; q < p; ++q)
+		    if (putc(*q, &tp->t_outq)) {
+			done = 0;
+			for (; q > endseq; --q)
+			    unputc(&tp->t_outq);
+			break;
+		    }
+#else
+                {
+                    int elen = p-endseq;
+                    cyg_serial_buf_info_t info;
+                    cyg_uint32 ilen = sizeof(info);
+                    q = p;
+                    if( (cyg_io_get_config( tp->t_handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO, &info, &ilen ) == 0) &&
+                        ((info.tx_bufsize-info.tx_count) >= elen) )
+                    {
+                        if( cyg_io_write( tp->t_handle, endseq, &elen) != 0 ) {
+                            done = 0;
+                        }
+                    }
+                    else
+                    {
+                        done = 0;
+                    }
+                }
+#endif
+		splx(s);
+		if (done)
+		    sc->sc_stats.ppp_obytes += q - endseq;
+            } // if (done && m->m_next == NULL)
+
+	    if (!done) {
+		/* remember where we got to */
+		m->m_data = start;
+		m->m_len = len;
+		break;
+	    }
+
+	    /* Finished with this mbuf; free it and move on. */
+	    MFREE(m, m2);
+	    m = m2;
+	    if (m == NULL) {
+		/* Finished a packet */
+		break;
+	    }
+	    sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
+        } // for(;;)
+
+	/*
+	 * If m == NULL, we have finished a packet.
+	 * If m != NULL, we've either done as much work this time
+	 * as we need to, or else we've filled up the output queue.
+	 */
+	sc->sc_outm = m;
+	if (m)
+	    break;
+    }
+
+#ifndef __ECOS        
+    /* Call pppstart to start output again if necessary. */
+    s = spltty();
+    pppstart(tp);
+
+    /*
+     * This timeout is needed for operation on a pseudo-tty,
+     * because the pty code doesn't call pppstart after it has
+     * drained the t_outq.
+     */
+    if (!idle && (sc->sc_flags & SC_TIMEOUT) == 0) {
+	sc->sc_ch = timeout(ppp_timeout, (void *) sc, 1);
+	sc->sc_flags |= SC_TIMEOUT;
+    }
+    
+    splx(s);
+
+#else
+
+    s = spltty();
+
+    if( sc->sc_outm != NULL &&
+        cyg_thread_self() != tp->tx_thread )
+    {
+        cyg_semaphore_post( &tp->tx_sem );
+    }
+    
+    splx(s);
+    
+#endif
+    
+}
+
+//==========================================================================
+/*
+ * This gets called when a received packet is placed on
+ * the inq, at splsoftnet. The pppd daemon is to be woken up to do a read().
+ */
+static void
+pppasyncctlp(sc)
+    struct ppp_softc *sc;
+{
+    struct tty *tp;
+    int s;
+
+    s = spltty();
+    tp = (struct tty *) sc->sc_devp;
+    
+    tp->pppd_wakeup = 1;
+    if( tp->pppd_thread != cyg_thread_self() )
+        cyg_thread_release( tp->pppd_thread );
+
+    splx(s);
+}
+
+//==========================================================================
+/*
+ * Allocate enough mbuf to handle current MRU.
+ */
+static void
+pppgetm(sc)
+    register struct ppp_softc *sc;
+{
+    struct mbuf *m, **mp;
+    int len;
+
+    mp = &sc->sc_m;
+    for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
+	if ((m = *mp) == NULL) {
+	    MGETHDR(m, M_DONTWAIT, MT_DATA);
+	    if (m == NULL)
+		break;
+	    *mp = m;
+	    MCLGET(m, M_DONTWAIT);
+	}
+	len -= M_DATASIZE(m);
+	mp = &m->m_next;
+    }
+}
+
+//==========================================================================
+/*
+ * tty interface receiver interrupt.
+ */
+
+static unsigned paritytab[8] = {
+    0x96696996, 0x69969669, 0x69969669, 0x96696996,
+    0x69969669, 0x96696996, 0x96696996, 0x69969669
+};
+
+/*
+ * Called when character is available from device driver.
+ * Only guaranteed to be at splsofttty() or spltty()
+ * This is safe to be called while the upper half's netisr is preempted.
+ */
+int
+cyg_ppp_pppinput(c, tp)
+    int c;
+    register struct tty *tp;
+{
+    register struct ppp_softc *sc;
+    struct mbuf *m;
+    int ilen, s;
+
+    sc = (struct ppp_softc *) tp->t_sc;
+    if (sc == NULL || tp != (struct tty *) sc->sc_devp)
+	return 0;
+
+//    ++tk_nin;
+    ++sc->sc_stats.ppp_ibytes;
+
+    s = spltty();
+    if (c & 0x80)
+	sc->sc_flags |= SC_RCV_B7_1;
+    else
+	sc->sc_flags |= SC_RCV_B7_0;
+    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
+	sc->sc_flags |= SC_RCV_ODDP;
+    else
+	sc->sc_flags |= SC_RCV_EVNP;
+    splx(s);
+
+    if (sc->sc_flags & SC_LOG_RAWIN)
+	ppplogchar(sc, c);
+
+    if (c == PPP_FLAG) {
+	ilen = sc->sc_ilen;
+	sc->sc_ilen = 0;
+	if (sc->sc_rawin_count > 0) 
+	    ppplogchar(sc, -1);
+
+	/*
+	 * If SC_ESCAPED is set, then we've seen the packet
+	 * abort sequence "}~".
+	 */
+	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
+	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
+	    s = spltty();
+	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
+	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
+#if 1
+		if (sc->sc_flags & SC_DEBUG)
+		    diag_printf("ppp%d: bad fcs %x, pkt len %d\n",
+                                sc->sc_if.if_unit, sc->sc_fcs, ilen);
+#endif
+		sc->sc_if.if_ierrors++;
+		sc->sc_stats.ppp_ierrors++;
+	    } else
+		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
+	    splx(s);
+	    return 0;
+	}
+
+	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
+	    if (ilen) {
+		if (sc->sc_flags & SC_DEBUG)
+		    diag_printf("ppp%d: too short (%d)\n", sc->sc_if.if_unit, ilen);
+		s = spltty();
+		sc->sc_if.if_ierrors++;
+		sc->sc_stats.ppp_ierrors++;
+		sc->sc_flags |= SC_PKTLOST;
+		splx(s);
+	    }
+	    return 0;
+	}
+
+	/*
+	 * Remove FCS trailer.  Somewhat painful...
+	 */
+	ilen -= 2;
+	if (--sc->sc_mc->m_len == 0) {
+	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next)
+		;
+	    sc->sc_mc = m;
+	}
+	sc->sc_mc->m_len--;
+
+	/* excise this mbuf chain */
+	m = sc->sc_m;
+	sc->sc_m = sc->sc_mc->m_next;
+	sc->sc_mc->m_next = NULL;
+
+	ppppktin(sc, m, sc->sc_flags & SC_PKTLOST);
+	if (sc->sc_flags & SC_PKTLOST) {
+	    s = spltty();
+	    sc->sc_flags &= ~SC_PKTLOST;
+	    splx(s);
+	}
+
+	pppgetm(sc);
+	return 0;
+    }
+
+    if (sc->sc_flags & SC_FLUSH) {
+	if (sc->sc_flags & SC_LOG_FLUSH)
+	    ppplogchar(sc, c);
+	return 0;
+    }
+
+    if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
+	return 0;
+
+    s = spltty();
+    if (sc->sc_flags & SC_ESCAPED) {
+	sc->sc_flags &= ~SC_ESCAPED;
+	c ^= PPP_TRANS;
+    } else if (c == PPP_ESCAPE) {
+	sc->sc_flags |= SC_ESCAPED;
+	splx(s);
+	return 0;
+    }
+    splx(s);
+
+    /*
+     * Initialize buffer on first octet received.
+     * First octet could be address or protocol (when compressing
+     * address/control).
+     * Second octet is control.
+     * Third octet is first or second (when compressing protocol)
+     * octet of protocol.
+     * Fourth octet is second octet of protocol.
+     */
+    if (sc->sc_ilen == 0) {
+	/* reset the first input mbuf */
+	if (sc->sc_m == NULL) {
+	    pppgetm(sc);
+	    if (sc->sc_m == NULL) {
+		if (sc->sc_flags & SC_DEBUG)
+		    diag_printf("ppp%d: no input mbufs!\n", sc->sc_if.if_unit);
+		goto flush;
+	    }
+	}
+	m = sc->sc_m;
+	m->m_len = 0;
+	m->m_data = M_DATASTART(sc->sc_m);
+	sc->sc_mc = m;
+	sc->sc_mp = mtod(m, char *);
+	sc->sc_fcs = PPP_INITFCS;
+	if (c != PPP_ALLSTATIONS) {
+	    if (sc->sc_flags & SC_REJ_COMP_AC) {
+		if (sc->sc_flags & SC_DEBUG)
+		    diag_printf("ppp%d: garbage received: 0x%x (need 0xFF)\n",
+			   sc->sc_if.if_unit, c);
+		goto flush;
+	    }
+	    *sc->sc_mp++ = PPP_ALLSTATIONS;
+	    *sc->sc_mp++ = PPP_UI;
+	    sc->sc_ilen += 2;
+	    m->m_len += 2;
+	}
+    }
+    if (sc->sc_ilen == 1 && c != PPP_UI) {
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("ppp%d: missing UI (0x3), got 0x%x\n",
+		   sc->sc_if.if_unit, c);
+	goto flush;
+    }
+    if (sc->sc_ilen == 2 && (c & 1) == 1) {
+	/* a compressed protocol */
+	*sc->sc_mp++ = 0;
+	sc->sc_ilen++;
+	sc->sc_mc->m_len++;
+    }
+    if (sc->sc_ilen == 3 && (c & 1) == 0) {
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("ppp%d: bad protocol %x\n", sc->sc_if.if_unit,
+                        (sc->sc_mp[-1] << 8) + c);
+	goto flush;
+    }
+
+    /* packet beyond configured mru? */
+    if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
+	if (sc->sc_flags & SC_DEBUG)
+	    diag_printf("ppp%d: packet too big\n", sc->sc_if.if_unit);
+	goto flush;
+    }
+
+    /* is this mbuf full? */
+    m = sc->sc_mc;
+    if (M_TRAILINGSPACE(m) <= 0) {
+	if (m->m_next == NULL) {
+	    pppgetm(sc);
+	    if (m->m_next == NULL) {
+		if (sc->sc_flags & SC_DEBUG)
+		    diag_printf("ppp%d: too few input mbufs!\n", sc->sc_if.if_unit);
+		goto flush;
+	    }
+	}
+	sc->sc_mc = m = m->m_next;
+	m->m_len = 0;
+	m->m_data = M_DATASTART(m);
+	sc->sc_mp = mtod(m, char *);
+    }
+
+    ++m->m_len;
+    *sc->sc_mp++ = c;
+    sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
+
+    return 0;
+
+ flush:
+    if (!(sc->sc_flags & SC_FLUSH)) {
+	s = spltty();
+	sc->sc_if.if_ierrors++;
+	sc->sc_stats.ppp_ierrors++;
+	sc->sc_flags |= SC_FLUSH;
+	splx(s);
+	if (sc->sc_flags & SC_LOG_FLUSH)
+	    ppplogchar(sc, c);
+    }
+    return 0;
+}
+
+//==========================================================================
+
+#define MAX_DUMP_BYTES	128
+
+static void
+ppplogchar(sc, c)
+    struct ppp_softc *sc;
+    int c;
+{
+    if (c >= 0)
+	sc->sc_rawin[sc->sc_rawin_count++] = c;
+    if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
+	|| (c < 0 && sc->sc_rawin_count > 0)) {
+        diag_printf("ppp%d input:\n");
+        diag_vdump_buf_with_offset( diag_printf, sc->sc_rawin, sc->sc_rawin_count, sc->sc_rawin );
+	sc->sc_rawin_count = 0;
+    }
+}
+
+//==========================================================================
+// End of ppp_io.c
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/pppd.c
@@ -0,0 +1,1070 @@
+//==========================================================================
+//
+//      src/pppd.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * main.c - Point-to-Point Protocol main module
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/main.c,v 1.19.6.1 2002/07/30 19:17:27 nectar Exp $";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <cyg/ppp/syslog.h>
+#include <sys/param.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#define MAXPATHLEN PATH_MAX
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/magic.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/lcp.h"
+#include "cyg/ppp/ipcp.h"
+#include "cyg/ppp/upap.h"
+#include "cyg/ppp/chap.h"
+#include "cyg/ppp/ccp.h"
+#include "cyg/ppp/ppp_io.h"
+
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#if defined(SUNOS4)
+extern char *strerror();
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
+#ifdef AT_CHANGE
+#include "atcp.h"
+#endif
+
+/* options */
+
+#define option_error(msg) db_printf("Option error: %s\n", msg )
+
+
+/*
+ * Variables set by command-line options.
+ */
+
+int	debug = 1;		/* Debug flag */
+int	kdebugflag = 1;	        /* Tell kernel to print debug messages */
+int	default_device = 0;	/* Using /dev/tty or equivalent */
+char	devnam[MAXPATHLEN] = "/dev/ser0";	/* Device name */
+int     flowctl = CYG_PPP_FLOWCTL_HARDWARE; /* flow control */
+int	modem  = 0;		/* Use modem control lines */
+cyg_serial_baud_rate_t	inspeed = 0;    	/* Input/Output speed requested */
+u_int32_t netmask = 0;	        /* IP netmask to set on interface */
+int	lockflag = 0;	        /* Create lock file to lock the serial dev */
+char	*connector = NULL;	/* Script to establish physical link */
+char	*disconnector = NULL;	/* Script to disestablish physical link */
+char	*welcomer = NULL;	/* Script to welcome client after connection */
+int	max_con_attempts = 10;  /* Maximum number of times to try dialing */
+int	maxconnect = 0;	        /* Maximum connect time (seconds) */
+char	user[MAXNAMELEN] = "nickg";	/* Our name for authenticating ourselves */
+char	passwd[MAXSECRETLEN] = "xsecretx";	/* Password for PAP */
+int	auth_required = 0;	/* Peer is required to authenticate */
+int	proxyarp = 0;	        /* Set up proxy ARP entry for peer */
+int	persist = 0;	        /* Reopen link after it goes down */
+int	uselogin = 0;	        /* Use /etc/passwd for checking PAP */
+int	lcp_echo_interval = 60; /* Interval between LCP echo-requests */
+int	lcp_echo_fails = 4;	/* Tolerance to unanswered echo-requests */
+char	our_name[20];	        /* Our name for authentication purposes */
+char	remote_name[20];	/* Peer's name for authentication */
+int	explicit_remote = 1;    /* remote_name specified with remotename opt */
+int	usehostname = 0;	/* Use hostname for our_name */
+int	disable_defaultip = 0;  /* Don't use hostname for default IP adrs */
+//int	demand = 0;		/* Do dial-on-demand */
+char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
+int	cryptpap = 0;	        /* Others' PAP passwords are encrypted */
+int	idle_time_limit = 60;   /* Shut down link if idle for this long */
+int	holdoff = 0;	        /* Dead time before restarting */
+int	refuse_pap = 0;	        /* Don't wanna auth. ourselves with PAP */
+int	refuse_chap = 0;	/* Don't wanna auth. ourselves with CHAP */
+
+const char    **script;               /* Chat connection script */
+
+
+/* interface vars */
+char ifname[32];		/* Interface name */
+static int ifunit;		/* Interface unit number */
+
+char *progname;			/* Name of this program */
+char cyg_ppp_hostname[MAXNAMELEN];	/* Our hostname */
+time_t		etime,stime;	/* End and Start time */
+int		minutes;	/* connection duration */
+
+cyg_io_handle_t tty_handle;     /* IO handle on serial stream */
+mode_t tty_mode = -1;		/* Original access permissions to tty */
+int baud_rate;			/* Actual bits/second for serial device */
+int hungup;			/* terminal has been hung up */
+int privileged;			/* we're running as real uid root */
+int need_holdoff;		/* need holdoff period before restarting */
+
+int phase;                      /* where the link is at */
+int kill_link;
+int open_ccp_flag;
+
+char **script_env;		/* Env. variable values for scripts */
+int s_env_nalloc;		/* # words avail at script_env */
+
+u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
+u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+
+char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
+
+/* Prototypes for procedures local to this file. */
+
+static void cleanup __P((void));
+static void close_tty __P((void));
+static void get_input __P((void));
+static void calltimeout __P((void));
+static struct timeval *timeleft __P((struct timeval *));
+//static void holdoff_end __P((void *));
+static void pr_log __P((void *, char *, ...));
+
+extern	char	*ttyname __P((int));
+extern	char	*getlogin __P((void));
+int main __P((int, char *[]));
+
+#ifdef ultrix
+#undef	O_NONBLOCK
+#define	O_NONBLOCK	O_NDELAY
+#endif
+
+#ifdef ULTRIX
+#define setlogmask(x)
+#endif
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *protocols[] = {
+    &lcp_protent,
+#ifdef CYGPKG_PPP_PAP
+    &pap_protent,
+#endif
+#ifdef CYGPKG_PPP_CHAP    
+    &chap_protent,
+#endif
+#ifdef CBCP_SUPPORT
+    &cbcp_protent,
+#endif
+    &ipcp_protent,
+    &ccp_protent,
+#ifdef IPX_CHANGE
+    &ipxcp_protent,
+#endif
+#ifdef AT_CHANGE
+    &atcp_protent,
+#endif
+    NULL
+};
+
+
+externC void
+cyg_pppd_main(CYG_ADDRWORD arg)
+{
+    int i;
+    struct timeval timo;
+    struct protent *protp;
+    int connect_attempts = 0;
+
+    phase = PHASE_INITIALIZE;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        (*protp->init)(0);
+
+    cyg_ppp_options_install( ((struct tty *)arg)->options );
+    
+    if (!ppp_available()) {
+	option_error(no_ppp_msg);
+	exit(1);
+    }
+    
+    /*
+     * Initialize system-dependent stuff and magic number package.
+     */
+    sys_init();
+    magic_init();
+    if (debug)
+	setlogmask(LOG_UPTO(LOG_DEBUG));
+
+   
+    for (;;) {
+
+	need_holdoff = 1;
+
+        {
+            Cyg_ErrNo err;
+            while ((err = cyg_io_lookup(devnam, &tty_handle)) < 0) {
+                if (err != 0)
+                    syslog(LOG_ERR, "Failed to open %s: %d", devnam,err);
+            }
+
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+            if( modem )
+            {
+                cyg_uint32 len = sizeof(ppp_tty.serial_callbacks);
+                ppp_tty.serial_callbacks.fn = cyg_ppp_serial_callback;
+                ppp_tty.serial_callbacks.priv = (CYG_ADDRWORD)&ppp_tty;
+
+                
+                err = cyg_io_set_config( tty_handle,
+                                         CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK,
+                                         &ppp_tty.serial_callbacks,
+                                         &len);
+
+                if( err != 0 ) {
+                    syslog(LOG_ERR, "cyg_io_set_config(serial callbacks): %d",err);
+                    die(1);
+                }
+
+            }
+#endif
+        }
+
+	hungup = 0;
+	kill_link = 0;
+
+	/* set line speed, flow control, etc.; clear CLOCAL if modem option */
+	set_up_tty(tty_handle, 0);
+
+        if( script != NULL )
+        {
+            if( !cyg_ppp_chat( devnam, script ) )
+            {
+                connect_attempts++;
+                goto fail;
+            }
+        }
+
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+        if( modem )
+        {
+            while( !ppp_tty.carrier_detected )
+                cyg_thread_delay(100);
+        }
+#endif
+        
+	connect_attempts = 0;	/* we made it through ok */
+
+	/* set up the serial device as a ppp interface */
+	establish_ppp(tty_handle);
+
+        syslog(LOG_INFO, "Using interface ppp%d", ifunit);
+        (void) sprintf(ifname, "ppp%d", ifunit);
+        
+	/*
+	 * Start opening the connection and wait for
+	 * incoming events (reply, timeout, etc.).
+	 */
+	syslog(LOG_NOTICE, "Connect: %s <--> %s", ifname, devnam);
+	stime = time((time_t *) NULL);
+        
+	lcp_lowerup(0);
+	lcp_open(0);		/* Start protocol */
+	for (phase = PHASE_ESTABLISH; phase != PHASE_DEAD; ) {
+	    wait_input(timeleft(&timo));
+	    calltimeout();
+	    get_input();
+	    if (kill_link) {
+		lcp_close(0, "User request");
+		kill_link = 0;
+	    }
+	    if (open_ccp_flag) {
+		if (phase == PHASE_NETWORK) {
+		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
+		    (*ccp_protent.open)(0);
+		}
+		open_ccp_flag = 0;
+	    }
+	}
+
+	clean_check();
+	disestablish_ppp(tty_handle);
+
+    fail:        
+	if (tty_handle != 0)
+	    close_tty();
+        
+	/* limit to retries? */
+	if (max_con_attempts)
+	    if (connect_attempts >= max_con_attempts)
+		break;
+
+	if (!persist)
+	    die(1);
+
+#if 0
+	if (holdoff > 0 && need_holdoff) {
+	    phase = PHASE_HOLDOFF;
+	    TIMEOUT(holdoff_end, NULL, holdoff);
+	    do {
+		wait_time(timeleft(&timo));
+		calltimeout();
+		if (kill_link) {
+		    if (!persist)
+			die(0);
+		    kill_link = 0;
+		    phase = PHASE_DORMANT; /* allow signal to end holdoff */
+		}
+
+	    } while (phase == PHASE_HOLDOFF);
+	}
+#endif
+        
+    }
+
+    die(0);
+}
+
+/*
+ * get_input - called when incoming data is available.
+ */
+static void
+get_input()
+{
+    int len, i;
+    u_char *p;
+    u_short protocol;
+    struct protent *protp;
+
+    p = inpacket_buf;	/* point to beginning of packet buffer */
+
+    len = read_packet(inpacket_buf);
+
+    if (len < 0)
+	return;
+
+    if (len == 0) {
+	etime = time((time_t *) NULL);
+	minutes = (etime-stime)/60;
+	syslog(LOG_NOTICE, "Modem hangup, connected for %d minutes", (minutes >1) ? minutes : 1);
+	hungup = 1;
+	lcp_lowerdown(0);	/* serial link is no longer available */
+	link_terminated(0);
+	return;
+    }
+
+    if (debug /*&& (debugflags & DBG_INPACKET)*/)
+	log_packet(p, len, "rcvd ", LOG_DEBUG);
+
+    if (len < PPP_HDRLEN) {
+	MAINDEBUG((LOG_INFO, "io(): Received short packet."));
+	return;
+    }
+
+    p += 2;				/* Skip address and control */
+    GETSHORT(protocol, p);
+    len -= PPP_HDRLEN;
+
+    /*
+     * Toss all non-LCP packets unless LCP is OPEN.
+     */
+    if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
+	MAINDEBUG((LOG_INFO,
+		   "get_input: Received non-LCP packet when LCP not open."));
+	return;
+    }
+
+    /*
+     * Until we get past the authentication phase, toss all packets
+     * except LCP, LQR and authentication packets.
+     */
+    if (phase <= PHASE_AUTHENTICATE
+	&& !(protocol == PPP_LCP || protocol == PPP_LQR
+	     || protocol == PPP_PAP || protocol == PPP_CHAP)) {
+	MAINDEBUG((LOG_INFO, "get_input: discarding proto 0x%x in phase %d",
+		   protocol, phase));
+	return;
+    }
+
+    /*
+     * Upcall the proper protocol input routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol == protocol && protp->enabled_flag) {
+	    (*protp->input)(0, p, len);
+	    return;
+	}
+        if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
+	    && protp->datainput != NULL) {
+	    (*protp->datainput)(0, p, len);
+	    return;
+	}
+    }
+
+    if (debug)
+    	syslog(LOG_WARNING, "Unsupported protocol (0x%x) received", protocol);
+    lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
+}
+
+
+/*
+ * quit - Clean up state and exit (with an error indication).
+ */
+void 
+quit()
+{
+    die(1);
+}
+
+/*
+ * die - like quit, except we can specify an exit status.
+ */
+void
+die(status)
+    int status;
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);    
+#ifndef __ECOS
+    cleanup();
+    syslog(LOG_INFO, "Exit.");
+    exit(status);
+#else
+    externC void sys_exit(void);
+    cleanup();    
+    sys_exit();
+#endif
+}
+
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+static void
+cleanup()
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);    
+    sys_cleanup();
+
+    if (tty_handle != 0)
+	close_tty();
+}
+
+/*
+ * close_tty - restore the terminal device and close it.
+ */
+static void
+close_tty()
+{
+    disestablish_ppp(tty_handle);
+
+#ifndef __ECOS
+    /* drop dtr to hang up */
+    if (modem) {
+	setdtr(ttyfd, FALSE);
+	/*
+	 * This sleep is in case the serial port has CLOCAL set by default,
+	 * and consequently will reassert DTR when we close the device.
+	 */
+	sleep(1);
+    }
+#endif
+    
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    
+    restore_tty(tty_handle);
+
+    if( ppp_tty.t_handle != 0 )
+    {
+        cyg_ppp_pppclose( &ppp_tty, 0 );
+        ppp_tty.t_handle = 0;
+    }
+
+    tty_handle = 0;
+}
+
+
+struct	callout {
+    struct timeval	c_time;		/* time at which to call routine */
+    void		*c_arg;		/* argument to routine */
+    void		(*c_func) __P((void *)); /* routine */
+    struct		callout *c_next;
+};
+
+static struct callout *callout = NULL;	/* Callout list */
+static struct timeval timenow;		/* Current time */
+
+/*
+ * timeout - Schedule a timeout.
+ *
+ * Note that this timeout takes the number of seconds, NOT hz (as in
+ * the kernel).
+ */
+void
+cyg_ppp_timeout(void (*func) __P((void *)),
+                void *arg,
+                int time)
+{
+    struct callout *newp, *p, **pp;
+  
+    MAINDEBUG((LOG_DEBUG, "Timeout %lx:%lx in %d seconds.",
+	       (long) func, (long) arg, time));
+    
+    /*
+     * Allocate timeout.
+     */
+    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL) {
+	syslog(LOG_ERR, "Out of memory in timeout()!");
+	die(1);
+    }
+    newp->c_arg = arg;
+    newp->c_func = func;
+    gettimeofday(&timenow, NULL);
+    newp->c_time.tv_sec = timenow.tv_sec + time;
+    newp->c_time.tv_usec = timenow.tv_usec;
+  
+    /*
+     * Find correct place and link it in.
+     */
+    for (pp = &callout; (p = *pp); pp = &p->c_next)
+	if (newp->c_time.tv_sec < p->c_time.tv_sec
+	    || (newp->c_time.tv_sec == p->c_time.tv_sec
+		&& newp->c_time.tv_usec < p->c_time.tv_sec))
+	    break;
+    newp->c_next = p;
+    *pp = newp;
+}
+
+
+/*
+ * untimeout - Unschedule a timeout.
+ */
+void
+cyg_ppp_untimeout(void (*func) __P((void *)),
+                  void *arg)
+{
+    struct callout **copp, *freep;
+  
+    MAINDEBUG((LOG_DEBUG, "Untimeout %lx:%lx.", (long) func, (long) arg));
+  
+    /*
+     * Find first matching timeout and remove it from the list.
+     */
+    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
+	if (freep->c_func == func && freep->c_arg == arg) {
+	    *copp = freep->c_next;
+	    (void) free((char *) freep);
+	    break;
+	}
+}
+
+
+/*
+ * calltimeout - Call any timeout routines which are now due.
+ */
+static void
+calltimeout()
+{
+    struct callout *p;
+
+    while (callout != NULL) {
+	p = callout;
+
+	if (gettimeofday(&timenow, NULL) < 0) {
+	    syslog(LOG_ERR, "Failed to get time of day: %m");
+	    die(1);
+	}
+	if (!(p->c_time.tv_sec < timenow.tv_sec
+	      || (p->c_time.tv_sec == timenow.tv_sec
+		  && p->c_time.tv_usec <= timenow.tv_usec)))
+	    break;		/* no, it's not time yet */
+	callout = p->c_next;
+	(*p->c_func)(p->c_arg);
+	free((char *) p);
+    }
+}
+
+
+/*
+ * timeleft - return the length of time until the next timeout is due.
+ */
+static struct timeval *
+timeleft(tvp)
+    struct timeval *tvp;
+{
+    if (callout == NULL)
+	return NULL;
+
+    gettimeofday(&timenow, NULL);
+    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
+    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
+    if (tvp->tv_usec < 0) {
+	tvp->tv_usec += 1000000;
+	tvp->tv_sec -= 1;
+    }
+    if (tvp->tv_sec < 0)
+	tvp->tv_sec = tvp->tv_usec = 0;
+
+    return tvp;
+}
+
+/*
+ * log_packet - format a packet and log it.
+ */
+
+char line[256];			/* line to be logged accumulated here */
+char *linep;
+
+void
+log_packet(p, len, prefix, level)
+    u_char *p;
+    int len;
+    char *prefix;
+    int level;
+{
+    strcpy(line, prefix);
+    linep = line + strlen(line);
+    format_packet(p, len, pr_log, NULL);
+    if (linep != line)
+	syslog(level, "%s", line);
+}
+
+/*
+ * format_packet - make a readable representation of a packet,
+ * calling `printer(arg, format, ...)' to output it.
+ */
+void
+format_packet(p, len, printer, arg)
+    u_char *p;
+    int len;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int i, n;
+    u_short proto;
+    u_char x;
+    struct protent *protp;
+
+    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+	p += 2;
+	GETSHORT(proto, p);
+	len -= PPP_HDRLEN;
+	for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	    if (proto == protp->protocol)
+		break;
+	if (protp != NULL) {
+	    printer(arg, "[%s", protp->name);
+	    n = (*protp->printpkt)(p, len, printer, arg);
+	    printer(arg, "]");
+	    p += n;
+	    len -= n;
+	} else {
+	    printer(arg, "[proto=0x%x]", proto);
+	}
+    }
+
+    for (; len > 0; --len) {
+	GETCHAR(x, p);
+	printer(arg, " %.2x", x);
+    }
+}
+
+static void
+pr_log __V((void *arg, char *fmt, ...))
+{
+    int n;
+    va_list pvar;
+    char buf[256];
+
+#if __STDC__
+    va_start(pvar, fmt);
+#else
+    void *arg;
+    char *fmt;
+    va_start(pvar);
+    arg = va_arg(pvar, void *);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    n = vfmtmsg(buf, sizeof(buf), fmt, pvar);
+    va_end(pvar);
+
+    if (linep + n + 1 > line + sizeof(line)) {
+	syslog(LOG_DEBUG, "%s", line);
+	linep = line;
+    }
+    strcpy(linep, buf);
+    linep += n;
+}
+
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+void
+print_string(p, len, printer, arg)
+    char *p;
+    int len;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int c;
+
+    printer(arg, "\"");
+    for (; len > 0; --len) {
+	c = *p++;
+	if (' ' <= c && c <= '~') {
+	    if (c == '\\' || c == '"')
+		printer(arg, "\\");
+	    printer(arg, "%c", c);
+	} else {
+	    switch (c) {
+	    case '\n':
+		printer(arg, "\\n");
+		break;
+	    case '\r':
+		printer(arg, "\\r");
+		break;
+	    case '\t':
+		printer(arg, "\\t");
+		break;
+	    default:
+		printer(arg, "\\%.3o", c);
+	    }
+	}
+    }
+    printer(arg, "\"");
+}
+
+/*
+ * novm - log an error message saying we ran out of memory, and die.
+ */
+void
+novm(msg)
+    char *msg;
+{
+    syslog(LOG_ERR, "Virtual memory exhausted allocating %s\n", msg);
+    die(1);
+}
+
+/*
+ * fmtmsg - format a message into a buffer.  Like sprintf except we
+ * also specify the length of the output buffer, and we handle
+ * %r (recursive format), %m (error message) and %I (IP address) formats.
+ * Doesn't do floating-point formats.
+ * Returns the number of chars put into buf.
+ */
+int
+fmtmsg __V((char *buf, int buflen, char *fmt, ...))
+{
+    va_list args;
+    int n;
+
+#if __STDC__
+    va_start(args, fmt);
+#else
+    char *buf;
+    int buflen;
+    char *fmt;
+    va_start(args);
+    buf = va_arg(args, char *);
+    buflen = va_arg(args, int);
+    fmt = va_arg(args, char *);
+#endif
+    n = vfmtmsg(buf, buflen, fmt, args);
+    va_end(args);
+    return n;
+}
+
+/*
+ * vfmtmsg - like fmtmsg, takes a va_list instead of a list of args.
+ */
+#define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
+
+int
+vfmtmsg(buf, buflen, fmt, args)
+    char *buf;
+    int buflen;
+    char *fmt;
+    va_list args;
+{
+    int c, i, n;
+    int width, prec, fillch;
+    int base, len, neg, quoted;
+    unsigned long val = 0;
+    char *str, *f, *buf0;
+    unsigned char *p;
+    char num[32];
+    time_t t;
+    static char hexchars[] = "0123456789abcdef";
+
+    buf0 = buf;
+    --buflen;
+    while (buflen > 0) {
+	for (f = fmt; *f != '%' && *f != 0; ++f)
+	    ;
+	if (f > fmt) {
+	    len = f - fmt;
+	    if (len > buflen)
+		len = buflen;
+	    memcpy(buf, fmt, len);
+	    buf += len;
+	    buflen -= len;
+	    fmt = f;
+	}
+	if (*fmt == 0)
+	    break;
+	c = *++fmt;
+	width = prec = 0;
+	fillch = ' ';
+	if (c == '0') {
+	    fillch = '0';
+	    c = *++fmt;
+	}
+	if (c == '*') {
+	    width = va_arg(args, int);
+	    c = *++fmt;
+	} else {
+	    while (isdigit(c)) {
+		width = width * 10 + c - '0';
+		c = *++fmt;
+	    }
+	}
+	if (c == '.') {
+	    c = *++fmt;
+	    if (c == '*') {
+		prec = va_arg(args, int);
+		c = *++fmt;
+	    } else {
+		while (isdigit(c)) {
+		    prec = prec * 10 + c - '0';
+		    c = *++fmt;
+		}
+	    }
+	}
+	str = 0;
+	base = 0;
+	neg = 0;
+	++fmt;
+	switch (c) {
+	case 'd':
+	    i = va_arg(args, int);
+	    if (i < 0) {
+		neg = 1;
+		val = -i;
+	    } else
+		val = i;
+	    base = 10;
+	    break;
+	case 'o':
+	    val = va_arg(args, unsigned int);
+	    base = 8;
+	    break;
+	case 'x':
+	    val = va_arg(args, unsigned int);
+	    base = 16;
+	    break;
+	case 'p':
+	    val = (unsigned long) va_arg(args, void *);
+	    base = 16;
+	    neg = 2;
+	    break;
+	case 's':
+	    str = va_arg(args, char *);
+	    break;
+	case 'c':
+	    num[0] = va_arg(args, int);
+	    num[1] = 0;
+	    str = num;
+	    break;
+	case 'm':
+	    str = strerror(errno);
+	    break;
+	case 'I':
+	    str = ip_ntoa(va_arg(args, u_int32_t));
+	    break;
+	case 'r':
+	    f = va_arg(args, char *);
+//#ifndef __powerpc__
+//	    n = vfmtmsg(buf, buflen + 1, f, va_arg(args, va_list));
+//#else
+	    /* On the powerpc, a va_list is an array of 1 structure */
+	    n = vfmtmsg(buf, buflen + 1, f, va_arg(args, void *));
+//#endif
+	    buf += n;
+	    buflen -= n;
+	    continue;
+	case 't':
+	    time(&t);
+	    str = ctime(&t);
+	    str += 4;		/* chop off the day name */
+	    str[15] = 0;	/* chop off year and newline */
+	    break;
+	case 'v':		/* "visible" string */
+	case 'q':		/* quoted string */
+	    quoted = c == 'q';
+	    p = va_arg(args, unsigned char *);
+	    if (fillch == '0' && prec > 0) {
+		n = prec;
+	    } else {
+		n = strlen((char *)p);
+		if (prec > 0 && prec < n)
+		    n = prec;
+	    }
+	    while (n > 0 && buflen > 0) {
+		c = *p++;
+		--n;
+		if (!quoted && c >= 0x80) {
+		    OUTCHAR('M');
+		    OUTCHAR('-');
+		    c -= 0x80;
+		}
+		if (quoted && (c == '"' || c == '\\'))
+		    OUTCHAR('\\');
+		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
+		    if (quoted) {
+			OUTCHAR('\\');
+			switch (c) {
+			case '\t':	OUTCHAR('t');	break;
+			case '\n':	OUTCHAR('n');	break;
+			case '\b':	OUTCHAR('b');	break;
+			case '\f':	OUTCHAR('f');	break;
+			default:
+			    OUTCHAR('x');
+			    OUTCHAR(hexchars[c >> 4]);
+			    OUTCHAR(hexchars[c & 0xf]);
+			}
+		    } else {
+			if (c == '\t')
+			    OUTCHAR(c);
+			else {
+			    OUTCHAR('^');
+			    OUTCHAR(c ^ 0x40);
+			}
+		    }
+		} else
+		    OUTCHAR(c);
+	    }
+	    continue;
+	default:
+	    *buf++ = '%';
+	    if (c != '%')
+		--fmt;		/* so %z outputs %z etc. */
+	    --buflen;
+	    continue;
+	}
+	if (base != 0) {
+	    str = num + sizeof(num);
+	    *--str = 0;
+	    while (str > num + neg) {
+		*--str = hexchars[val % base];
+		val = val / base;
+		if (--prec <= 0 && val == 0)
+		    break;
+	    }
+	    switch (neg) {
+	    case 1:
+		*--str = '-';
+		break;
+	    case 2:
+		*--str = 'x';
+		*--str = '0';
+		break;
+	    }
+	    len = num + sizeof(num) - 1 - str;
+	} else {
+	    len = strlen(str);
+	    if (prec > 0 && len > prec)
+		len = prec;
+	}
+	if (width > 0) {
+	    if (width > buflen)
+		width = buflen;
+	    if ((n = width - len) > 0) {
+		buflen -= n;
+		for (; n > 0; --n)
+		    *buf++ = fillch;
+	    }
+	}
+	if (len > buflen)
+	    len = buflen;
+	memcpy(buf, str, len);
+	buf += len;
+	buflen -= len;
+    }
+    *buf = 0;
+    return buf - buf0;
+}
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/slcompress.c
@@ -0,0 +1,664 @@
+//==========================================================================
+//
+//      src/slcompress.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*-
+ * Copyright (c) 1989, 1993, 1994
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)slcompress.c	8.2 (Berkeley) 4/16/94
+ * $FreeBSD: src/sys/net/slcompress.c,v 1.16 1999/12/29 04:38:37 peter Exp $
+ */
+
+/*
+ * Routines to compress and uncompess tcp packets (for transmission
+ * over low speed serial lines.
+ *
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
+ *	- Initial distribution.
+ *
+ */
+
+#define _KERNEL
+
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+//#include <sys/systm.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+
+#include <cyg/ppp/slcompress.h>
+
+typedef CYG_ADDRWORD intptr_t;
+
+#ifndef SL_NO_STATS
+#define INCR(counter) ++comp->counter;
+#else
+#define INCR(counter)
+#endif
+
+#define BCMP(p1, p2, n) bcmp((char *)(p1), (char *)(p2), (int)(n))
+#define BCOPY(p1, p2, n) bcopy((char *)(p1), (char *)(p2), (int)(n))
+#ifndef _KERNEL
+#define ovbcopy bcopy
+#endif
+
+void
+sl_compress_init(comp, max_state)
+	struct slcompress *comp;
+	int max_state;
+{
+	register u_int i;
+	register struct cstate *tstate = comp->tstate;
+
+	if (max_state == -1) {
+		max_state = MAX_STATES - 1;
+		bzero((char *)comp, sizeof(*comp));
+	} else {
+		/* Don't reset statistics */
+		bzero((char *)comp->tstate, sizeof(comp->tstate));
+		bzero((char *)comp->rstate, sizeof(comp->rstate));
+	}
+  	for (i = max_state; i > 0; --i) {
+		tstate[i].cs_id = i;
+		tstate[i].cs_next = &tstate[i - 1];
+	}
+	tstate[0].cs_next = &tstate[max_state];
+	tstate[0].cs_id = 0;
+	comp->last_cs = &tstate[0];
+	comp->last_recv = 255;
+	comp->last_xmit = 255;
+	comp->flags = SLF_TOSS;
+}
+
+
+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ
+ * checks for zero (since zero has to be encoded in the long, 3 byte
+ * form).
+ */
+#define ENCODE(n) { \
+	if ((u_int16_t)(n) >= 256) { \
+		*cp++ = 0; \
+		cp[1] = (n); \
+		cp[0] = (n) >> 8; \
+		cp += 2; \
+	} else { \
+		*cp++ = (n); \
+	} \
+}
+#define ENCODEZ(n) { \
+	if ((u_int16_t)(n) >= 256 || (u_int16_t)(n) == 0) { \
+		*cp++ = 0; \
+		cp[1] = (n); \
+		cp[0] = (n) >> 8; \
+		cp += 2; \
+	} else { \
+		*cp++ = (n); \
+	} \
+}
+
+#define DECODEL(f) { \
+	if (*cp == 0) {\
+		(f) = htonl(ntohl(f) + ((cp[1] << 8) | cp[2])); \
+		cp += 3; \
+	} else { \
+		(f) = htonl(ntohl(f) + (u_int32_t)*cp++); \
+	} \
+}
+
+#define DECODES(f) { \
+	if (*cp == 0) {\
+		(f) = htons(ntohs(f) + ((cp[1] << 8) | cp[2])); \
+		cp += 3; \
+	} else { \
+		(f) = htons(ntohs(f) + (u_int32_t)*cp++); \
+	} \
+}
+
+#define DECODEU(f) { \
+	if (*cp == 0) {\
+		(f) = htons((cp[1] << 8) | cp[2]); \
+		cp += 3; \
+	} else { \
+		(f) = htons((u_int32_t)*cp++); \
+	} \
+}
+
+/*
+ * Attempt to compress an outgoing TCP packet and return the type of
+ * the result.  The caller must have already verified that the protocol
+ * is TCP.  The first mbuf must contain the complete IP and TCP headers,
+ * and "ip" must be == mtod(m, struct ip *).  "comp" supplies the
+ * compression state, and "compress_cid" tells us whether it is OK
+ * to leave out the CID field when feasible.
+ *
+ * The caller is responsible for adjusting m->m_pkthdr.len upon return,
+ * if m is an M_PKTHDR mbuf.
+ */
+u_int
+sl_compress_tcp(m, ip, comp, compress_cid)
+	struct mbuf *m;
+	register struct ip *ip;
+	struct slcompress *comp;
+	int compress_cid;
+{
+	register struct cstate *cs = comp->last_cs->cs_next;
+	register u_int hlen = ip->ip_hl;
+	register struct tcphdr *oth;
+	register struct tcphdr *th;
+	register u_int deltaS, deltaA;
+	register u_int changes = 0;
+	u_char new_seq[16];
+	register u_char *cp = new_seq;
+
+	/*
+	 * Bail if this is an IP fragment or if the TCP packet isn't
+	 * `compressible' (i.e., ACK isn't set or some other control bit is
+	 * set).  (We assume that the caller has already made sure the
+	 * packet is IP proto TCP).
+	 */
+	if ((ip->ip_off & htons(0x3fff)) || m->m_len < 40)
+		return (TYPE_IP);
+
+	th = (struct tcphdr *)&((int32_t *)ip)[hlen];
+	if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
+		return (TYPE_IP);
+	/*
+	 * Packet is compressible -- we're going to send either a
+	 * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
+	 * to locate (or create) the connection state.  Special case the
+	 * most recently used connection since it's most likely to be used
+	 * again & we don't have to do any reordering if it's used.
+	 */
+	INCR(sls_packets)
+	if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr ||
+	    ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr ||
+	    *(int32_t *)th != ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl]) {
+		/*
+		 * Wasn't the first -- search for it.
+		 *
+		 * States are kept in a circularly linked list with
+		 * last_cs pointing to the end of the list.  The
+		 * list is kept in lru order by moving a state to the
+		 * head of the list whenever it is referenced.  Since
+		 * the list is short and, empirically, the connection
+		 * we want is almost always near the front, we locate
+		 * states via linear search.  If we don't find a state
+		 * for the datagram, the oldest state is (re-)used.
+		 */
+		register struct cstate *lcs;
+		register struct cstate *lastcs = comp->last_cs;
+
+		do {
+			lcs = cs; cs = cs->cs_next;
+			INCR(sls_searches)
+			if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr
+			    && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr
+			    && *(int32_t *)th ==
+			    ((int32_t *)&cs->cs_ip)[cs->cs_ip.ip_hl])
+				goto found;
+		} while (cs != lastcs);
+
+		/*
+		 * Didn't find it -- re-use oldest cstate.  Send an
+		 * uncompressed packet that tells the other side what
+		 * connection number we're using for this conversation.
+		 * Note that since the state list is circular, the oldest
+		 * state points to the newest and we only need to set
+		 * last_cs to update the lru linkage.
+		 */
+		INCR(sls_misses)
+		comp->last_cs = lcs;
+		hlen += th->th_off;
+		hlen <<= 2;
+		if (hlen > m->m_len)
+		    return TYPE_IP;
+		goto uncompressed;
+
+	found:
+		/*
+		 * Found it -- move to the front on the connection list.
+		 */
+		if (cs == lastcs)
+			comp->last_cs = lcs;
+		else {
+			lcs->cs_next = cs->cs_next;
+			cs->cs_next = lastcs->cs_next;
+			lastcs->cs_next = cs;
+		}
+	}
+
+	/*
+	 * Make sure that only what we expect to change changed. The first
+	 * line of the `if' checks the IP protocol version, header length &
+	 * type of service.  The 2nd line checks the "Don't fragment" bit.
+	 * The 3rd line checks the time-to-live and protocol (the protocol
+	 * check is unnecessary but costless).  The 4th line checks the TCP
+	 * header length.  The 5th line checks IP options, if any.  The 6th
+	 * line checks TCP options, if any.  If any of these things are
+	 * different between the previous & current datagram, we send the
+	 * current datagram `uncompressed'.
+	 */
+	oth = (struct tcphdr *)&((int32_t *)&cs->cs_ip)[hlen];
+	deltaS = hlen;
+	hlen += th->th_off;
+	hlen <<= 2;
+	if (hlen > m->m_len)
+	    return TYPE_IP;
+
+	if (((u_int16_t *)ip)[0] != ((u_int16_t *)&cs->cs_ip)[0] ||
+	    ((u_int16_t *)ip)[3] != ((u_int16_t *)&cs->cs_ip)[3] ||
+	    ((u_int16_t *)ip)[4] != ((u_int16_t *)&cs->cs_ip)[4] ||
+	    th->th_off != oth->th_off ||
+	    (deltaS > 5 &&
+	     BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) ||
+	    (th->th_off > 5 &&
+	     BCMP(th + 1, oth + 1, (th->th_off - 5) << 2)))
+		goto uncompressed;
+
+	/*
+	 * Figure out which of the changing fields changed.  The
+	 * receiver expects changes in the order: urgent, window,
+	 * ack, seq (the order minimizes the number of temporaries
+	 * needed in this section of code).
+	 */
+	if (th->th_flags & TH_URG) {
+		deltaS = ntohs(th->th_urp);
+		ENCODEZ(deltaS);
+		changes |= NEW_U;
+	} else if (th->th_urp != oth->th_urp)
+		/* argh! URG not set but urp changed -- a sensible
+		 * implementation should never do this but RFC793
+		 * doesn't prohibit the change so we have to deal
+		 * with it. */
+		 goto uncompressed;
+
+	deltaS = (u_int16_t)(ntohs(th->th_win) - ntohs(oth->th_win));
+	if (deltaS) {
+		ENCODE(deltaS);
+		changes |= NEW_W;
+	}
+
+	deltaA = ntohl(th->th_ack) - ntohl(oth->th_ack);
+	if (deltaA) {
+		if (deltaA > 0xffff)
+			goto uncompressed;
+		ENCODE(deltaA);
+		changes |= NEW_A;
+	}
+
+	deltaS = ntohl(th->th_seq) - ntohl(oth->th_seq);
+	if (deltaS) {
+		if (deltaS > 0xffff)
+			goto uncompressed;
+		ENCODE(deltaS);
+		changes |= NEW_S;
+	}
+
+	switch(changes) {
+
+	case 0:
+		/*
+		 * Nothing changed. If this packet contains data and the
+		 * last one didn't, this is probably a data packet following
+		 * an ack (normal on an interactive connection) and we send
+		 * it compressed.  Otherwise it's probably a retransmit,
+		 * retransmitted ack or window probe.  Send it uncompressed
+		 * in case the other side missed the compressed version.
+		 */
+		if (ip->ip_len != cs->cs_ip.ip_len &&
+		    ntohs(cs->cs_ip.ip_len) == hlen)
+			break;
+
+		/* (fall through) */
+
+	case SPECIAL_I:
+	case SPECIAL_D:
+		/*
+		 * actual changes match one of our special case encodings --
+		 * send packet uncompressed.
+		 */
+		goto uncompressed;
+
+	case NEW_S|NEW_A:
+		if (deltaS == deltaA &&
+		    deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+			/* special case for echoed terminal traffic */
+			changes = SPECIAL_I;
+			cp = new_seq;
+		}
+		break;
+
+	case NEW_S:
+		if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {
+			/* special case for data xfer */
+			changes = SPECIAL_D;
+			cp = new_seq;
+		}
+		break;
+	}
+
+	deltaS = ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id);
+	if (deltaS != 1) {
+		ENCODEZ(deltaS);
+		changes |= NEW_I;
+	}
+	if (th->th_flags & TH_PUSH)
+		changes |= TCP_PUSH_BIT;
+	/*
+	 * Grab the cksum before we overwrite it below.  Then update our
+	 * state with this packet's header.
+	 */
+	deltaA = ntohs(th->th_sum);
+	BCOPY(ip, &cs->cs_ip, hlen);
+
+	/*
+	 * We want to use the original packet as our compressed packet.
+	 * (cp - new_seq) is the number of bytes we need for compressed
+	 * sequence numbers.  In addition we need one byte for the change
+	 * mask, one for the connection id and two for the tcp checksum.
+	 * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
+	 * many bytes of the original packet to toss so subtract the two to
+	 * get the new packet size.
+	 */
+	deltaS = cp - new_seq;
+	cp = (u_char *)ip;
+	if (compress_cid == 0 || comp->last_xmit != cs->cs_id) {
+		comp->last_xmit = cs->cs_id;
+		hlen -= deltaS + 4;
+		cp += hlen;
+		*cp++ = changes | NEW_C;
+		*cp++ = cs->cs_id;
+	} else {
+		hlen -= deltaS + 3;
+		cp += hlen;
+		*cp++ = changes;
+	}
+	m->m_len -= hlen;
+	m->m_data += hlen;
+	*cp++ = deltaA >> 8;
+	*cp++ = deltaA;
+	BCOPY(new_seq, cp, deltaS);
+	INCR(sls_compressed)
+	return (TYPE_COMPRESSED_TCP);
+
+	/*
+	 * Update connection state cs & send uncompressed packet ('uncompressed'
+	 * means a regular ip/tcp packet but with the 'conversation id' we hope
+	 * to use on future compressed packets in the protocol field).
+	 */
+uncompressed:
+	BCOPY(ip, &cs->cs_ip, hlen);
+	ip->ip_p = cs->cs_id;
+	comp->last_xmit = cs->cs_id;
+	return (TYPE_UNCOMPRESSED_TCP);
+}
+
+
+int
+sl_uncompress_tcp(bufp, len, type, comp)
+	u_char **bufp;
+	int len;
+	u_int type;
+	struct slcompress *comp;
+{
+	u_char *hdr, *cp;
+	int hlen, vjlen;
+
+	cp = bufp? *bufp: NULL;
+	vjlen = sl_uncompress_tcp_core(cp, len, len, type, comp, &hdr, &hlen);
+	if (vjlen < 0)
+		return (0);	/* error */
+	if (vjlen == 0)
+		return (len);	/* was uncompressed already */
+
+	cp += vjlen;
+	len -= vjlen;
+
+	/*
+	 * At this point, cp points to the first byte of data in the
+	 * packet.  If we're not aligned on a 4-byte boundary, copy the
+	 * data down so the ip & tcp headers will be aligned.  Then back up
+	 * cp by the tcp/ip header length to make room for the reconstructed
+	 * header (we assume the packet we were handed has enough space to
+	 * prepend 128 bytes of header).
+	 */
+	if ((intptr_t)cp & 3) {
+		if (len > 0)
+			(void) ovbcopy(cp, (caddr_t)((intptr_t)cp &~ 3), len);
+		cp = (u_char *)((intptr_t)cp &~ 3);
+	}
+	cp -= hlen;
+	len += hlen;
+	BCOPY(hdr, cp, hlen);
+
+	*bufp = cp;
+	return (len);
+}
+
+/*
+ * Uncompress a packet of total length total_len.  The first buflen
+ * bytes are at buf; this must include the entire (compressed or
+ * uncompressed) TCP/IP header.  This procedure returns the length
+ * of the VJ header, with a pointer to the uncompressed IP header
+ * in *hdrp and its length in *hlenp.
+ */
+int
+sl_uncompress_tcp_core(buf, buflen, total_len, type, comp, hdrp, hlenp)
+	u_char *buf;
+	int buflen, total_len;
+	u_int type;
+	struct slcompress *comp;
+	u_char **hdrp;
+	u_int *hlenp;
+{
+	register u_char *cp;
+	register u_int hlen, changes;
+	register struct tcphdr *th;
+	register struct cstate *cs;
+	register struct ip *ip;
+	register u_int16_t *bp;
+	register u_int vjlen;
+
+	switch (type) {
+
+	case TYPE_UNCOMPRESSED_TCP:
+		ip = (struct ip *) buf;
+		if (ip->ip_p >= MAX_STATES)
+			goto bad;
+		cs = &comp->rstate[comp->last_recv = ip->ip_p];
+		comp->flags &=~ SLF_TOSS;
+		ip->ip_p = IPPROTO_TCP;
+		/*
+		 * Calculate the size of the TCP/IP header and make sure that
+		 * we don't overflow the space we have available for it.
+		 */
+		hlen = ip->ip_hl << 2;
+		if (hlen + sizeof(struct tcphdr) > buflen)
+			goto bad;
+		hlen += ((struct tcphdr *)&((char *)ip)[hlen])->th_off << 2;
+		if (hlen > MAX_HDR || hlen > buflen)
+			goto bad;
+		BCOPY(ip, &cs->cs_ip, hlen);
+		cs->cs_hlen = hlen;
+		INCR(sls_uncompressedin)
+		*hdrp = (u_char *) &cs->cs_ip;
+		*hlenp = hlen;
+		return (0);
+
+	default:
+		goto bad;
+
+	case TYPE_COMPRESSED_TCP:
+		break;
+	}
+	/* We've got a compressed packet. */
+	INCR(sls_compressedin)
+	cp = buf;
+	changes = *cp++;
+	if (changes & NEW_C) {
+		/* Make sure the state index is in range, then grab the state.
+		 * If we have a good state index, clear the 'discard' flag. */
+		if (*cp >= MAX_STATES)
+			goto bad;
+
+		comp->flags &=~ SLF_TOSS;
+		comp->last_recv = *cp++;
+	} else {
+		/* this packet has an implicit state index.  If we've
+		 * had a line error since the last time we got an
+		 * explicit state index, we have to toss the packet. */
+		if (comp->flags & SLF_TOSS) {
+			INCR(sls_tossed)
+			return (-1);
+		}
+	}
+	cs = &comp->rstate[comp->last_recv];
+	hlen = cs->cs_ip.ip_hl << 2;
+	th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];
+	th->th_sum = htons((*cp << 8) | cp[1]);
+	cp += 2;
+	if (changes & TCP_PUSH_BIT)
+		th->th_flags |= TH_PUSH;
+	else
+		th->th_flags &=~ TH_PUSH;
+
+	switch (changes & SPECIALS_MASK) {
+	case SPECIAL_I:
+		{
+		register u_int i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;
+		th->th_ack = htonl(ntohl(th->th_ack) + i);
+		th->th_seq = htonl(ntohl(th->th_seq) + i);
+		}
+		break;
+
+	case SPECIAL_D:
+		th->th_seq = htonl(ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len)
+				   - cs->cs_hlen);
+		break;
+
+	default:
+		if (changes & NEW_U) {
+			th->th_flags |= TH_URG;
+			DECODEU(th->th_urp)
+		} else
+			th->th_flags &=~ TH_URG;
+		if (changes & NEW_W)
+			DECODES(th->th_win)
+		if (changes & NEW_A)
+			DECODEL(th->th_ack)
+		if (changes & NEW_S)
+			DECODEL(th->th_seq)
+		break;
+	}
+	if (changes & NEW_I) {
+		DECODES(cs->cs_ip.ip_id)
+	} else
+		cs->cs_ip.ip_id = htons(ntohs(cs->cs_ip.ip_id) + 1);
+
+	/*
+	 * At this point, cp points to the first byte of data in the
+	 * packet.  Fill in the IP total length and update the IP
+	 * header checksum.
+	 */
+	vjlen = cp - buf;
+	buflen -= vjlen;
+	if (buflen < 0)
+		/* we must have dropped some characters (crc should detect
+		 * this but the old slip framing won't) */
+		goto bad;
+
+	total_len += cs->cs_hlen - vjlen;
+	cs->cs_ip.ip_len = htons(total_len);
+
+	/* recompute the ip header checksum */
+	bp = (u_int16_t *) &cs->cs_ip;
+	cs->cs_ip.ip_sum = 0;
+		for (changes = 0; hlen > 0; hlen -= 2)
+			changes += *bp++;
+		changes = (changes & 0xffff) + (changes >> 16);
+		changes = (changes & 0xffff) + (changes >> 16);
+	cs->cs_ip.ip_sum = ~ changes;
+
+	*hdrp = (u_char *) &cs->cs_ip;
+	*hlenp = cs->cs_hlen;
+	return vjlen;
+
+bad:
+	comp->flags |= SLF_TOSS;
+	INCR(sls_errorin)
+	return (-1);
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/sys-ecos.c
@@ -0,0 +1,1918 @@
+//==========================================================================
+//
+//      src/sys-ecos.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003, 2004 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * Copyright (c) 1995 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University and The Australian National University.
+ * The names of the Universities may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/sys-bsd.c,v 1.17 1999/08/28 01:19:08 peter Exp $";
+#endif
+/*	$NetBSD: sys-bsd.c,v 1.1.1.3 1997/09/26 18:53:04 christos Exp $	*/
+
+/*
+ * TODO:
+ */
+
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#define _KERNEL 1
+#include <sys/param.h>
+#undef _KERNEL
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef NetBSD1_2
+#include <util.h>
+#endif
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
+
+#include <cyg/ppp/syslog.h>
+
+#include <net/if.h>
+#include <cyg/ppp/net/ppp_defs.h>
+#include <cyg/ppp/net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#ifdef IPX_CHANGE
+#include <netipx/ipx.h>
+#endif
+
+#if RTM_VERSION >= 3
+#include <sys/param.h>
+#if defined(NetBSD) && (NetBSD >= 199703)
+#include <netinet/if_inarp.h>
+#else	/* NetBSD 1.2D or later */
+#include <netinet/if_ether.h>
+#endif
+#endif
+
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/fsm.h"
+#include "cyg/ppp/ipcp.h"
+
+#include "cyg/ppp/ppp_io.h"
+
+#include <cyg/ppp/ppp.h>
+
+//==========================================================================
+
+static int rtm_seq;
+
+static cyg_io_handle_t ppp_handle; /* IO subsystem handle to PPP stream */
+struct tty ppp_tty;             /* dummy TTY structure */
+
+static cyg_handle_t ppp_rtc;
+static cyg_resolution_t ppp_rtc_resolution;
+
+static int loop_slave = -1;
+static int loop_master;
+
+static unsigned char inbuf[PPP_MTU + PPP_HDRLEN + 100]; /* buffer for chars read from input */
+
+static int sockfd = -1;		/* socket for doing interface ioctls */
+
+static int if_is_up;		/* the interface is currently up */
+static u_int32_t ifaddrs[2];	/* local and remote addresses we set */
+static u_int32_t default_route_gateway;	/* gateway addr for default route */
+static u_int32_t proxy_arp_addr;	/* remote addr for proxy arp */
+
+/* Prototypes for procedures local to this file. */
+static int dodefaultroute __P((u_int32_t, int));
+static int get_ether_addr __P((u_int32_t, struct sockaddr_dl *));
+
+static void wait_input_alarm(cyg_handle_t alarm, cyg_addrword_t data);
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+void cyg_ppp_serial_callback( cyg_serial_line_status_t *s,
+                                     CYG_ADDRWORD priv );
+#endif
+
+u_int32_t netmask;	/* IP netmask to set on interface */
+
+//==========================================================================
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init()
+{
+    if( sockfd == -1 )
+    {
+        /* Get an internet socket for doing socket ioctl's on. */
+        if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+            syslog(LOG_ERR, "Couldn't create IP socket: %d",errno);
+            die(1);
+        }
+    }
+
+    ppp_tty.pppd_wakeup = 0;
+    ppp_tty.pppd_thread_running = true;
+    
+    ppp_rtc = cyg_real_time_clock();
+    ppp_rtc_resolution = cyg_clock_get_resolution( ppp_rtc );
+
+    cyg_alarm_create( ppp_rtc,
+                      wait_input_alarm,
+                      (cyg_addrword_t)&ppp_tty,
+                      &ppp_tty.alarm,
+                      &ppp_tty.alarm_obj);
+}
+
+//==========================================================================
+/*
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This should call die() because it's called from die().
+ */
+void
+sys_cleanup()
+{
+    struct ifreq ifr;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if (if_is_up) {
+	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
+	    && ((ifr.ifr_flags & IFF_UP) != 0)) {
+	    ifr.ifr_flags &= ~IFF_UP;
+	    ioctl(sockfd, SIOCSIFFLAGS, &ifr);
+	}
+    }
+    if (ifaddrs[0] != 0)
+	cifaddr(0, ifaddrs[0], ifaddrs[1]);
+    if (default_route_gateway)
+	cifdefaultroute(0, 0, default_route_gateway);
+    if (proxy_arp_addr)
+	cifproxyarp(0, proxy_arp_addr);
+
+    if( sockfd != -1 )
+    {
+        close(sockfd);
+        sockfd = -1;
+    }
+}
+
+//==========================================================================
+
+#ifdef __ECOS
+
+void
+sys_exit(void)
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);    
+    phase = PHASE_DEAD;
+    while( ppp_tty.tx_thread_running )
+    {
+        db_printf("kick tx thread\n");        
+        cyg_semaphore_post( &ppp_tty.tx_sem );
+        cyg_thread_delay(100);
+    }
+    ppp_tty.pppd_thread_running = false;
+    cyg_thread_exit();
+}
+#endif
+
+//==========================================================================
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close()
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if (loop_slave >= 0) {
+	close(loop_slave);
+	close(loop_master);
+    }
+}
+
+//==========================================================================
+/*
+ * sys_check_options - check the options that the user specified
+ */
+void
+sys_check_options()
+{
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+//==========================================================================
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+int
+ppp_available()
+{
+    int s, ok;
+    struct ifreq ifr;
+    extern char *no_ppp_msg;
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	return 1;		/* can't tell */
+
+    strncpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+    close(s);
+
+    no_ppp_msg = "\
+This system lacks kernel support for PPP.  To include PPP support\n\
+in the kernel, please follow the steps detailed in the README.bsd\n\
+file in the ppp-2.2 distribution.\n";
+    return ok;
+}
+
+//==========================================================================
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+void
+establish_ppp(cyg_io_handle_t handle)
+{
+    int s;
+    int x;
+    int err;
+    
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+
+    ppp_handle = ppp_tty.t_handle = handle;
+    ppp_tty.t_sc = NULL;
+
+    s = splsoftnet();
+
+    err = cyg_ppp_pppopen( &ppp_tty );
+    
+    if( err != 0 )
+        syslog( LOG_ERR, "Couldn't establish PPP interface: %d", err );
+
+    /*
+     * Enable debug in the driver if requested.
+     */
+    if (kdebugflag) {
+	if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
+	    syslog(LOG_WARNING, "ioctl (PPPIOCGFLAGS): %d",err);
+	} else {
+	    x |= (kdebugflag & 0xFF) * SC_DEBUG;
+	    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0)
+		syslog(LOG_WARNING, "ioctl(PPPIOCSFLAGS): %d",err);
+	}
+    }
+
+    splx(s);
+}
+
+//==========================================================================
+/*
+ * restore_loop - reattach the ppp unit to the loopback.
+ */
+void
+restore_loop()
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+
+//==========================================================================
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp(cyg_io_handle_t handle)
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+//==========================================================================
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check()
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+//==========================================================================
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc.  If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ *
+ * For *BSD, we assume that speed_t values numerically equal bits/second.
+ */
+void
+set_up_tty(cyg_io_handle_t handle, int local)
+{
+    cyg_serial_info_t   cfg;
+    int                 err;
+    int                 len = sizeof(cfg);
+
+    err = cyg_io_get_config( handle,
+                             CYG_IO_GET_CONFIG_SERIAL_INFO,
+                             &cfg,
+                             &len);
+
+    if( err != 0 ) {
+	syslog(LOG_ERR, "cyg_io_get_config: %d",err);
+	die(1);
+    }
+
+    switch ( flowctl )
+    {
+    case CYG_PPP_FLOWCTL_DEFAULT:
+        break;
+        
+    case CYG_PPP_FLOWCTL_NONE:
+        cfg.flags &= ~(CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX|
+                       CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX);
+        break;
+        
+    case CYG_PPP_FLOWCTL_HARDWARE:
+        cfg.flags &= ~(CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX);
+        cfg.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX;
+        break;
+        
+    case CYG_PPP_FLOWCTL_SOFTWARE:
+        cfg.flags &= ~(CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX);
+        cfg.flags |= CYGNUM_SERIAL_FLOW_XONXOFF_RX|CYGNUM_SERIAL_FLOW_XONXOFF_TX;
+        break;
+    }
+
+    if( inspeed != 0 )
+        cfg.baud = inspeed;
+    
+    err = cyg_io_set_config( handle,
+                             CYG_IO_SET_CONFIG_SERIAL_INFO,
+                             &cfg,
+                             &len);
+
+    if( err != 0 ) {
+	syslog(LOG_ERR, "cyg_io_set_config: %d",err);
+	die(1);
+    }
+}
+
+//==========================================================================
+/*
+ * restore_tty - restore the terminal to the saved settings.
+ */
+void
+restore_tty(cyg_io_handle_t handle)
+{
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+    if( modem )
+    {
+        // Restore callback handler if it was set.
+        
+        Cyg_ErrNo err;
+        cyg_uint32 len = sizeof(ppp_tty.serial_callbacks);
+
+        db_printf("%s called\n", __PRETTY_FUNCTION__);
+                
+        err = cyg_io_set_config( handle,
+                                 CYG_IO_SET_CONFIG_SERIAL_STATUS_CALLBACK,
+                                 &ppp_tty.serial_callbacks,
+                                 &len);
+
+        if( err != 0 ) {
+            syslog(LOG_ERR, "cyg_io_set_config(restore serial callbacks): %d",err);
+            die(1);
+        }
+    }
+#endif
+}
+
+//==========================================================================
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+void
+setdtr(fd, on)
+int fd, on;
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+//==========================================================================
+/*
+ * output - Output PPP packet.
+ */
+void
+output(unit, p, len)
+    int unit;
+    u_char *p;
+    int len;
+{
+    Cyg_ErrNo err;
+    struct uio uio;
+    struct iovec iov;
+    int s;
+    
+    if (debug)
+	log_packet(p, len, "sent ", LOG_DEBUG);
+
+
+    iov.iov_base    = p;
+    iov.iov_len     = len;
+    uio.uio_iov     = &iov;
+    uio.uio_iovcnt  = 1;
+    uio.uio_resid   = len;
+    uio.uio_segflg  = UIO_USERSPACE;
+    uio.uio_rw      = UIO_WRITE;
+
+    s = splsoftnet();
+    
+    err = cyg_ppp_pppwrite( &ppp_tty, &uio, 0 );
+
+    splx(s);
+    
+    if( err != 0 )
+        syslog(LOG_ERR, "write: %d",err);
+
+}
+
+//==========================================================================
+
+#ifdef __ECOS
+
+static void wait_input_alarm(cyg_handle_t alarm, cyg_addrword_t data)
+{
+    cyg_thread_release( ppp_tty.pppd_thread );
+    ppp_tty.pppd_wakeup = 1;
+}
+
+#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
+void cyg_ppp_serial_callback( cyg_serial_line_status_t *s,
+                                     CYG_ADDRWORD priv )
+{
+    externC int kill_link;
+
+//    db_printf("serial callback %d %x\n",s->which, s->value );
+
+    if( s->which == CYGNUM_SERIAL_STATUS_CARRIERDETECT )
+    {
+        if( s->value == 0 )
+        {
+            // CD lost
+            kill_link = 1;
+            cyg_thread_release( ppp_tty.pppd_thread );
+            ppp_tty.pppd_wakeup = 1;
+        }
+        else
+        {
+            // CD up
+            ppp_tty.carrier_detected = 1;
+        }
+    }
+}
+#endif
+
+static void cyg_ppp_tx_thread(CYG_ADDRWORD arg)
+{
+    ppp_tty.tx_thread_running = true;
+
+    // Wait for the PPPD thread to get going and start the PPP
+    // initialization phase.
+    while(phase == PHASE_DEAD )
+        cyg_thread_delay(100);
+
+    // Now loop until the link goes back down.
+    while( phase != PHASE_DEAD )
+    {
+        cyg_semaphore_wait( &ppp_tty.tx_sem );
+
+        if( phase == PHASE_DEAD )
+            break;
+        
+        // Call into PPP driver to get transmissions going. This is
+        // only called if some other thread has failed to transmit all
+        // of a packet due to a full buffer, or flow control.
+
+        cyg_ppp_pppstart( &ppp_tty );
+    }
+
+db_printf("%s exiting\n", __PRETTY_FUNCTION__);        
+    ppp_tty.tx_thread_running = false;
+    cyg_thread_exit();
+}
+
+#endif
+
+
+//==========================================================================
+/*
+ * wait_input - wait until there is data available on ttyfd,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_input(timo)
+    struct timeval *timo;
+{
+    if( timo != NULL )
+    {
+        cyg_tick_count_t trigger = timo->tv_sec*ppp_rtc_resolution.divisor;
+
+        // If the timeval has a microseconds value, just add another
+        // second on to the trigger time. These are after all just
+        // timeouts, not accurate timings, so a bit of imprecision
+        // will not hurt.
+        if( timo->tv_usec != 0 )
+            trigger += ppp_rtc_resolution.divisor;            
+
+        trigger += cyg_current_time();
+
+        // We set the alarm to retrigger after a second. This is in
+        // case it catches cyg_io_read() at an uninterruptible
+        // point. The alarm is disabled as soon as the read returns,
+        // so the retrigger will usually not happen.
+        cyg_alarm_initialize( ppp_tty.alarm,
+                              trigger,
+                              ppp_rtc_resolution.divisor );
+    }
+    
+    for(;;)
+    {
+        int s;
+        int len = 1;
+        Cyg_ErrNo err;
+        cyg_serial_buf_info_t info;
+        cyg_uint32 ilen = sizeof(info);
+
+#if 1
+        // Work out how many bytes are waiting in the serial device
+        // buffer and read them all at once. If there are none, we
+        // just wait for a single character to arrive.
+       
+        if( cyg_io_get_config( ppp_tty.t_handle, CYG_IO_GET_CONFIG_SERIAL_BUFFER_INFO,
+                               &info, &ilen ) == 0 && info.rx_count > 1 )
+        {
+            len = info.rx_count-1;
+            if( len > sizeof(inbuf) )
+                len = sizeof(inbuf);
+        }
+#endif
+        
+        if( timo != NULL )
+            cyg_alarm_enable( ppp_tty.alarm );
+
+        err = cyg_io_read( ppp_handle, &inbuf, &len );
+
+        if( timo != NULL )
+            cyg_alarm_disable( ppp_tty.alarm );
+        
+//        db_printf("read: err %d len %d byte %02x\n",err,len,inbuf[0]);
+        
+        if( err == 0 )
+        {
+            int i;
+            
+            // Pass all input data to PPP driver for analysis. If this
+            // turns out to be for the PPPD, it will call
+            // pppasyncctlp() which in turn will set
+            // ppp_tty.pppd_wakeup. We detect that on return from
+            // pppinput() and return to the caller to do pppd
+            // processing.
+
+            s = splsoftnet();
+            
+            for( i = 0; i < len; i++ )
+            {
+                err = cyg_ppp_pppinput( inbuf[i], &ppp_tty );
+                
+                if( err != 0 )
+                    syslog( LOG_ERR, "pppinput error: %d", err);
+
+            }
+
+            splx(s);
+            
+        }
+        else if( err != -EINTR )
+            syslog( LOG_ERR, "Read error: %d",err);
+
+        if( ppp_tty.pppd_wakeup )
+        {
+            ppp_tty.pppd_wakeup = 0;
+            break;
+        }
+    }
+}
+
+//==========================================================================
+/*
+ * wait_time - wait for a given length of time or until a
+ * signal is received.
+ */
+void
+wait_time(timo)
+    struct timeval *timo;
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+}
+
+
+//==========================================================================
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(buf)
+    u_char *buf;
+{
+    int err;
+    struct uio uio;
+    struct iovec iov;
+    int len = PPP_MTU + PPP_HDRLEN;
+    int s;
+    
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+    
+    iov.iov_base        = buf;
+    iov.iov_len         = len;
+    uio.uio_iov         = &iov;
+    uio.uio_iovcnt      = 1;
+    uio.uio_resid       = len;
+    uio.uio_segflg      = UIO_USERSPACE;
+    uio.uio_rw          = UIO_READ;
+
+    s = splsoftnet();
+    
+    err = cyg_ppp_pppread( &ppp_tty, &uio, 0 );
+
+    splx(s);
+    
+    if( err == EWOULDBLOCK )
+        return -1;
+    
+    if( err != 0 )
+    {
+        syslog(LOG_ERR, "pppread: %d",err);
+        die(1);
+    }
+
+    len -= uio.uio_resid;
+
+    return len;
+}
+
+//==========================================================================
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(unit, mtu, asyncmap, pcomp, accomp)
+    int unit, mtu;
+    u_int32_t asyncmap;
+    int pcomp, accomp;
+{
+    u_int x;
+    struct ifreq ifr;
+    int err;
+    int s;
+    
+//    db_printf("%s: unit %d mtu %d asyncmap %08x pcomp %08x accomp %08x\n", __PRETTY_FUNCTION__,
+//              unit,mtu,asyncmap,pcomp,accomp);
+    
+    strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    ifr.ifr_mtu = mtu;
+    if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0) {
+	syslog(LOG_ERR, "ioctl(SIOCSIFMTU): %d",errno);
+	quit();
+    }
+
+
+    s = splsoftnet();
+    
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSASYNCMAP, (caddr_t) &asyncmap, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSASYNCMAP): %d",err);
+    }
+
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
+    }
+    x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
+    x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
+    }
+
+    splx(s);
+}
+
+
+//==========================================================================
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+ppp_set_xaccm(unit, accm)
+    int unit;
+    ext_accm accm;
+{
+    int error;
+    int s;
+    
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+
+    s = splsoftnet();
+        
+    error = cyg_ppp_ppptioctl( &ppp_tty, PPPIOCSXASYNCMAP, (caddr_t)accm, 0 );
+
+    splx(s);
+    
+    if( error != 0 )
+	syslog(LOG_WARNING, "ioctl(set extended ACCM): %d",error);
+}
+
+
+//==========================================================================
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+ppp_recv_config(unit, mru, asyncmap, pcomp, accomp)
+    int unit, mru;
+    u_int32_t asyncmap;
+    int pcomp, accomp;
+{
+    int x;
+    int err;
+    int s;
+
+    s = splsoftnet();
+    
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSMRU, (caddr_t) &mru, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSMRU): %d",err);
+    }
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSRASYNCMAP): %d",err);
+    }
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
+    }
+    x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) < 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
+    }
+
+    splx(s);
+}
+
+//==========================================================================
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.  Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
+ */
+int
+ccp_test(unit, opt_ptr, opt_len, for_transmit)
+    int unit, opt_len, for_transmit;
+    u_char *opt_ptr;
+{
+    struct ppp_option_data data;
+    int s;
+    
+    data.ptr = opt_ptr;
+    data.length = opt_len;
+    data.transmit = for_transmit;
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+
+    s = splsoftnet();
+        
+    errno = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSCOMPRESS, (caddr_t) &data, 0 );
+
+    splx(s);
+    
+    if (errno == 0)        
+	return 1;
+    else return (errno == ENOBUFS)? 0: -1;
+    
+}
+
+//==========================================================================
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(unit, isopen, isup)
+    int unit, isopen, isup;
+{
+    int x;
+
+    int err;
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
+	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
+	return;
+    }
+    x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
+    x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x,0)) != 0)
+	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
+}
+
+//==========================================================================
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise.  This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(unit)
+    int unit;
+{
+    int x;
+    int err;
+    
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCGFLAGS): %d",err);
+	return 0;
+    }
+    return x & SC_DC_FERROR;
+}
+
+//==========================================================================
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(u, ip)
+    int u;
+    struct ppp_idle *ip;
+{
+    return cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGIDLE, (caddr_t)ip, 0) == 0;
+}
+
+
+//==========================================================================
+
+#ifdef PPP_FILTER
+/*
+ * set_filters - transfer the pass and active filters to the kernel.
+ */
+int
+set_filters(pass, active)
+    struct bpf_program *pass, *active;
+{
+    int ret = 1;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if (pass->bf_len > 0) {
+	if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) {
+	    syslog(LOG_ERR, "Couldn't set pass-filter in kernel: %m");
+	    ret = 0;
+	}
+    }
+    if (active->bf_len > 0) {
+	if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) {
+	    syslog(LOG_ERR, "Couldn't set active-filter in kernel: %m");
+	    ret = 0;
+	}
+    }
+    return ret;
+}
+#endif
+
+//==========================================================================
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(u, vjcomp, cidcomp, maxcid)
+    int u, vjcomp, cidcomp, maxcid;
+{
+    u_int x;
+    int err;
+    
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCGFLAGS, (caddr_t) &x, 0)) != 0) {
+	syslog(LOG_ERR, "ioctl (PPPIOCGFLAGS): %d",err);
+	return 0;
+    }
+    x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
+    x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
+    if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSFLAGS, (caddr_t) &x, 0)) != 0) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSFLAGS): %d",err);
+	return 0;
+    }
+    if (vjcomp && ((err=cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSMAXCID, (caddr_t) &maxcid, 0)) != 0)) {
+	syslog(LOG_ERR, "ioctl(PPPIOCSMAXCID): %d",err);
+	return 0;
+    }
+    return 1;
+}
+
+//==========================================================================
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int
+sifup(u)
+    int u;
+{
+    struct ifreq ifr;
+
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+    strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+	return 0;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+	return 0;
+    }
+    if_is_up = 1;
+    return 1;
+}
+
+//==========================================================================
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(u, proto, mode)
+    int u;
+    int proto;
+    enum NPmode mode;
+{
+    struct npioctl npi;
+
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+    npi.protocol = proto;
+    npi.mode = mode;
+    {
+        int err;
+    
+        if ((err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSNPMODE, (caddr_t)&npi, 0)) < 0) {
+            syslog(LOG_ERR, "ioctl(set NP %d mode to %d): %d", proto, mode,err);
+            return 0;
+        }
+    }
+    
+    return 1;
+}
+
+//==========================================================================
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(u)
+    int u;
+{
+    struct ifreq ifr;
+    int rv;
+    struct npioctl npi;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    rv = 1;
+    npi.protocol = PPP_IP;
+    npi.mode = NPMODE_ERROR;
+    {
+        int err = cyg_ppp_ppptioctl(&ppp_tty, PPPIOCSNPMODE, (caddr_t) &npi, 0);
+        if( err < 0 )
+            syslog(LOG_WARNING, "ioctl(PPPIOCSNPMODE): %d",err);
+    }
+    strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m");
+	rv = 0;
+    } else {
+	ifr.ifr_flags &= ~IFF_UP;
+	if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	    syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m");
+	    rv = 0;
+	} else
+	    if_is_up = 0;
+    }
+    return rv;
+    return 0;
+}
+
+//==========================================================================
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family)		\
+    BZERO((char *) &(addr), sizeof(addr));	\
+    addr.sa_family = (family); 			\
+    addr.sa_len = sizeof(addr);
+
+//==========================================================================
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(u, o, h, m)
+    int u;
+    u_int32_t o, h, m;
+{
+    struct ifaliasreq ifra;
+    struct ifreq ifr;
+
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+    strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+    if (m != 0) {
+	SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+	((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+    } else
+	BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+    BZERO(&ifr, sizeof(ifr));
+    strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
+	if (errno != EADDRNOTAVAIL)
+	    syslog(LOG_WARNING, "Couldn't remove interface address: %d",errno);
+    }
+    if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+	if (errno != EEXIST) {
+	    syslog(LOG_ERR, "Couldn't set interface address: %d",errno);
+	    return 0;
+	}
+	syslog(LOG_WARNING,
+	       "Couldn't set interface address: Address %s already exists",
+		ip_ntoa(o));
+    }
+    ifaddrs[0] = o;
+    ifaddrs[1] = h;
+    return 1;
+}
+
+//==========================================================================
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(u, o, h)
+    int u;
+    u_int32_t o, h;
+{
+    struct ifaliasreq ifra;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    ifaddrs[0] = 0;
+    strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+    BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+    if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+	if (errno != EADDRNOTAVAIL)
+	    syslog(LOG_WARNING, "Couldn't delete interface address: %m");
+	return 0;
+    }
+    return 1;
+}
+
+//==========================================================================
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(u, l, g)
+    int u;
+    u_int32_t l, g;
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return dodefaultroute(g, 's');
+}
+
+//==========================================================================
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(u, l, g)
+    int u;
+    u_int32_t l, g;
+{
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    return dodefaultroute(g, 'c');
+}
+
+//==========================================================================
+/*
+ * dodefaultroute - talk to a routing socket to add/delete a default route.
+ */
+static int
+dodefaultroute(g, cmd)
+    u_int32_t g;
+    int cmd;
+{
+    int routes;
+    struct {
+	struct rt_msghdr	hdr;
+	struct sockaddr_in	dst;
+	struct sockaddr_in	gway;
+	struct sockaddr_in	mask;
+    } rtmsg;
+
+db_printf("%s %08x %c\n", __PRETTY_FUNCTION__,g,cmd);
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+	syslog(LOG_ERR, "Couldn't %s default route: socket: %d",
+	       cmd=='s'? "add": "delete",errno);
+	return 0;
+    }
+
+    memset(&rtmsg, 0, sizeof(rtmsg));
+    rtmsg.hdr.rtm_type = cmd == 's'? RTM_ADD: RTM_DELETE;
+    rtmsg.hdr.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
+    rtmsg.hdr.rtm_version = RTM_VERSION;
+    rtmsg.hdr.rtm_seq = ++rtm_seq;
+    rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
+    rtmsg.dst.sin_len = sizeof(rtmsg.dst);
+    rtmsg.dst.sin_family = AF_INET;
+    rtmsg.gway.sin_len = sizeof(rtmsg.gway);
+    rtmsg.gway.sin_family = AF_INET;
+    rtmsg.gway.sin_addr.s_addr = g;
+    rtmsg.mask.sin_len = sizeof(rtmsg.dst);
+    rtmsg.mask.sin_family = AF_INET;
+
+    rtmsg.hdr.rtm_msglen = sizeof(rtmsg);
+    if (write(routes, &rtmsg, sizeof(rtmsg)) < 0) {
+	syslog(LOG_ERR, "Couldn't %s default route: %d",
+	       cmd=='s'? "add": "delete",errno);
+	close(routes);
+	return 0;
+    }
+
+    close(routes);
+    default_route_gateway = (cmd == 's')? g: 0;
+    return 1;
+}
+
+//==========================================================================
+
+#if RTM_VERSION >= 3
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+static struct {
+    struct rt_msghdr		hdr;
+    struct sockaddr_inarp	dst;
+    struct sockaddr_dl		hwa;
+    char			extra[128];
+} arpmsg;
+
+static int arpmsg_valid;
+
+int
+sifproxyarp(unit, hisaddr)
+    int unit;
+    u_int32_t hisaddr;
+{
+    int routes;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    /*
+     * Get the hardware address of an interface on the same subnet
+     * as our local address.
+     */
+    memset(&arpmsg, 0, sizeof(arpmsg));
+    if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
+	syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+	return 0;
+    }
+
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+	syslog(LOG_ERR, "Couldn't add proxy arp entry: socket: %m");
+	return 0;
+    }
+
+    arpmsg.hdr.rtm_type = RTM_ADD;
+    arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
+    arpmsg.hdr.rtm_version = RTM_VERSION;
+    arpmsg.hdr.rtm_seq = ++rtm_seq;
+    arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+    arpmsg.hdr.rtm_inits = RTV_EXPIRE;
+    arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
+    arpmsg.dst.sin_family = AF_INET;
+    arpmsg.dst.sin_addr.s_addr = hisaddr;
+    arpmsg.dst.sin_other = SIN_PROXY;
+
+    arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+	+ arpmsg.hwa.sdl_len;
+    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+	syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
+	close(routes);
+	return 0;
+    }
+
+    close(routes);
+    arpmsg_valid = 1;
+    proxy_arp_addr = hisaddr;
+    return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+    int unit;
+    u_int32_t hisaddr;
+{
+    int routes;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    if (!arpmsg_valid)
+	return 0;
+    arpmsg_valid = 0;
+
+    arpmsg.hdr.rtm_type = RTM_DELETE;
+    arpmsg.hdr.rtm_seq = ++rtm_seq;
+
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+	syslog(LOG_ERR, "Couldn't delete proxy arp entry: socket: %m");
+	return 0;
+    }
+
+    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+	syslog(LOG_ERR, "Couldn't delete proxy arp entry: %m");
+	close(routes);
+	return 0;
+    }
+
+    close(routes);
+    proxy_arp_addr = 0;
+    return 1;
+}
+
+//==========================================================================
+
+#else	/* RTM_VERSION */
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(unit, hisaddr)
+    int unit;
+    u_int32_t hisaddr;
+{
+    struct arpreq arpreq;
+    struct {
+	struct sockaddr_dl	sdl;
+	char			space[128];
+    } dls;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    BZERO(&arpreq, sizeof(arpreq));
+
+    /*
+     * Get the hardware address of an interface on the same subnet
+     * as our local address.
+     */
+    if (!get_ether_addr(hisaddr, &dls.sdl)) {
+	syslog(LOG_ERR, "Cannot determine ethernet address for proxy ARP");
+	return 0;
+    }
+
+    arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
+    arpreq.arp_ha.sa_family = AF_UNSPEC;
+    BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
+    SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+    ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+    arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+    if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+	syslog(LOG_ERR, "Couldn't add proxy arp entry: %m");
+	return 0;
+    }
+
+    proxy_arp_addr = hisaddr;
+    return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(unit, hisaddr)
+    int unit;
+    u_int32_t hisaddr;
+{
+    struct arpreq arpreq;
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    BZERO(&arpreq, sizeof(arpreq));
+    SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+    ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+    if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+	syslog(LOG_WARNING, "Couldn't delete proxy arp entry: %m");
+	return 0;
+    }
+    proxy_arp_addr = 0;
+    return 1;
+}
+#endif	/* RTM_VERSION */
+
+
+//==========================================================================
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS		32
+
+static int
+get_ether_addr(ipaddr, hwaddr)
+    u_int32_t ipaddr;
+    struct sockaddr_dl *hwaddr;
+{
+    struct ifreq *ifr, *ifend, *ifp;
+    u_int32_t ina, mask;
+    struct sockaddr_dl *dla;
+    struct ifreq ifreq;
+    struct ifconf ifc;
+    struct ifreq ifs[MAX_IFS];
+
+db_printf("%s called\n", __PRETTY_FUNCTION__);
+    ifc.ifc_len = sizeof(ifs);
+    ifc.ifc_req = ifs;
+    if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+	syslog(LOG_ERR, "ioctl(SIOCGIFCONF): %m");
+	return 0;
+    }
+
+    /*
+     * Scan through looking for an interface with an Internet
+     * address on the same subnet as `ipaddr'.
+     */
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend;
+		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
+		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
+	if (ifr->ifr_addr.sa_family == AF_INET) {
+	    ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+	    strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	    /*
+	     * Check that the interface is up, and not point-to-point
+	     * or loopback.
+	     */
+	    if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+		continue;
+	    if ((ifreq.ifr_flags &
+		 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+		 != (IFF_UP|IFF_BROADCAST))
+		continue;
+	    /*
+	     * Get its netmask and check that it's on the right subnet.
+	     */
+	    if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+		continue;
+	    mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+	    if ((ipaddr & mask) != (ina & mask))
+		continue;
+
+	    break;
+	}
+    }
+
+    if (ifr >= ifend)
+	return 0;
+    syslog(LOG_INFO, "found interface %s for proxy arp", ifr->ifr_name);
+
+    /*
+     * Now scan through again looking for a link-level address
+     * for this interface.
+     */
+    ifp = ifr;
+    for (ifr = ifc.ifc_req; ifr < ifend; ) {
+	if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+	    && ifr->ifr_addr.sa_family == AF_LINK) {
+	    /*
+	     * Found the link-level address - copy it out
+	     */
+	    dla = (struct sockaddr_dl *) &ifr->ifr_addr;
+	    BCOPY(dla, hwaddr, dla->sdl_len);
+	    return 1;
+	}
+	ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
+	    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)));
+    }
+
+    return 0;
+}
+
+//==========================================================================
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'.  If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+u_int32_t
+GetMask(addr)
+    u_int32_t addr;
+{
+    u_int32_t mask, nmask, ina;
+    struct ifreq *ifr, *ifend, ifreq;
+    struct ifconf ifc;
+    struct ifreq ifs[MAX_IFS];
+
+    addr = ntohl(addr);
+    if (IN_CLASSA(addr))	/* determine network mask for address class */
+	nmask = IN_CLASSA_NET;
+    else if (IN_CLASSB(addr))
+	nmask = IN_CLASSB_NET;
+    else
+	nmask = IN_CLASSC_NET;
+    /* class D nets are disallowed by bad_ip_adrs */
+    mask = netmask | htonl(nmask);
+
+    /*
+     * Scan through the system's network interfaces.
+     */
+    ifc.ifc_len = sizeof(ifs);
+    ifc.ifc_req = ifs;
+    if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+	syslog(LOG_WARNING, "ioctl(SIOCGIFCONF): %m");
+	return mask;
+    }
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend;
+		ifr = (struct ifreq *) ((char *)&ifr->ifr_addr
+		    + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr)))) {
+	/*
+	 * Check the interface's internet address.
+	 */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+	if ((ntohl(ina) & nmask) != (addr & nmask))
+	    continue;
+	/*
+	 * Check that the interface is up, and not point-to-point or loopback.
+	 */
+	strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+	    != IFF_UP)
+	    continue;
+	/*
+	 * Get its netmask and OR it into our mask.
+	 */
+	if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+	    continue;
+	mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
+    }
+
+    return mask;
+}
+
+//==========================================================================
+/*
+ * Use the hostid as part of the random number seed.
+ */
+int
+get_host_seed()
+{
+//db_printf("%s called\n", __PRETTY_FUNCTION__);
+#ifndef __ECOS
+    return gethostid();
+#endif
+    return 0;
+}
+
+//=====================================================================
+// PAP stubs
+//
+// When omitting PAP, these fill in the dangling references from auth.c
+//
+
+#ifndef CYGPKG_PPP_PAP
+
+void
+upap_authwithpeer(unit, user, password)
+    int unit;
+    char *user, *password;
+{
+    unit=unit;
+    user=user;
+    password=password;
+}
+
+void
+upap_authpeer(unit)
+    int unit;
+{
+    unit=unit;
+}
+
+#endif
+
+//=====================================================================
+// CHAP stubs
+//
+// When omitting CHAP, these fill in the dangling references from auth.c
+//
+
+#ifndef CYGPKG_PPP_CHAP
+
+void
+ChapAuthWithPeer(unit, our_name, digest)
+    int unit;
+    char *our_name;
+    int digest;
+{
+    unit=unit;
+    our_name=our_name;
+    digest=digest;
+}
+
+void
+ChapAuthPeer(unit, our_name, digest)
+    int unit;
+    char *our_name;
+    int digest;
+{
+    unit=unit;
+    our_name=our_name;
+    digest=digest;
+}
+
+#endif
+
+//=====================================================================
+// eCos API
+
+externC cyg_int32 cyg_ppp_options_init( cyg_ppp_options_t *options )
+{
+    if( options == NULL )
+        return -1;
+    
+    options->debug              = 0;
+    options->kdebugflag         = 0;
+    options->default_route      = 1;
+    options->modem              = 0;
+    options->flowctl            = CYG_PPP_FLOWCTL_HARDWARE;
+    options->refuse_pap         = 0;
+    options->refuse_chap        = 0;
+
+    options->baud               = CYGNUM_SERIAL_BAUD_115200;
+    
+    options->idle_time_limit    = 1*60;
+    options->maxconnect         = 0;
+
+    options->our_address        = 0;
+    options->his_address        = 0;
+
+    options->script             = NULL;
+    
+    strncpy( options->user, CYGPKG_PPP_AUTH_DEFAULT_USER, MAXNAMELEN );
+    strncpy( options->passwd, CYGPKG_PPP_AUTH_DEFAULT_PASSWD, MAXSECRETLEN );
+
+    return 0;
+}
+
+// -------------------------------------------------------------------------
+
+
+#define CYGNUM_PPP_PPPD_THREAD_STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL+0x1000)
+
+static char cyg_pppd_stack[CYGNUM_PPP_PPPD_THREAD_STACK_SIZE];
+static cyg_thread cyg_pppd_thread_obj;
+
+static char cyg_ppp_tx_thread_stack[CYGNUM_HAL_STACK_SIZE_TYPICAL];
+static cyg_thread cyg_ppp_tx_thread_obj;
+
+
+externC void cyg_pppd_main(CYG_ADDRWORD arg);
+
+
+externC cyg_ppp_handle_t cyg_ppp_up( const char *devnam_arg,
+                                     const cyg_ppp_options_t *options )
+{
+
+    if( options == NULL || phase != PHASE_DEAD )
+        return 0;
+    
+    strncpy( devnam, devnam_arg, PATH_MAX );
+
+    ppp_tty.options = options;
+
+    // Start the PPPD thread
+    cyg_thread_create(CYGNUM_PPP_PPPD_THREAD_PRIORITY,
+                      cyg_pppd_main,
+                      (CYG_ADDRWORD)&ppp_tty,
+                      "PPPD",
+                      &cyg_pppd_stack[0],
+                      CYGNUM_PPP_PPPD_THREAD_STACK_SIZE,
+                      &ppp_tty.pppd_thread,
+                      &cyg_pppd_thread_obj
+            );
+    cyg_thread_resume(ppp_tty.pppd_thread);
+
+    // Start the TX thread
+    cyg_semaphore_init( &ppp_tty.tx_sem,  0 );
+    
+    cyg_thread_create(CYGNUM_PPP_PPPD_THREAD_PRIORITY+1,
+                      cyg_ppp_tx_thread,
+                      (CYG_ADDRWORD)&ppp_tty,
+                      "PPP Tx Thread",
+                      &cyg_ppp_tx_thread_stack[0],
+                      sizeof(cyg_ppp_tx_thread_stack),
+                      &ppp_tty.tx_thread,
+                      &cyg_ppp_tx_thread_obj
+            );
+    cyg_thread_resume(ppp_tty.tx_thread);
+
+    // Wait for the PPPD thread to get going and start the PPP
+    // initialization phase.
+    while(phase == PHASE_DEAD )
+        cyg_thread_delay(100);
+    
+    return (cyg_ppp_handle_t)&ppp_tty;
+}
+
+// -------------------------------------------------------------------------
+
+externC char **script;
+
+externC void cyg_ppp_options_install( const cyg_ppp_options_t *options )
+{
+    debug               = options->debug;
+    kdebugflag          = options->kdebugflag;
+    
+    modem               = options->modem;
+    flowctl             = options->flowctl;
+    refuse_pap          = options->refuse_pap;
+    refuse_chap         = options->refuse_chap;
+
+    inspeed             = options->baud;
+    
+    idle_time_limit     = options->idle_time_limit;
+    maxconnect          = options->maxconnect;
+
+    {
+        ipcp_options *wo = &ipcp_wantoptions[0];
+
+        wo->ouraddr     = options->our_address;
+        wo->hisaddr     = options->his_address;
+
+        wo->default_route = options->default_route;
+        
+    }
+
+    script              = options->script;
+    
+    strncpy( user, &options->user[0], MAXNAMELEN );
+    strncpy( passwd, &options->passwd[0], MAXSECRETLEN );
+    
+}
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_down( const cyg_ppp_handle_t handle )
+{
+    if( phase != PHASE_DEAD )
+    {
+        externC int kill_link;
+        kill_link = 1;
+        cyg_thread_release( ppp_tty.pppd_thread );
+        ppp_tty.pppd_wakeup = 1;    
+        return 0;
+    }
+    else
+        return -1;
+}
+
+// -------------------------------------------------------------------------
+
+externC cyg_int32 cyg_ppp_wait_up( cyg_ppp_handle_t handle )
+{
+    while(!( (phase == PHASE_NETWORK && ifaddrs[0] != 0) ||
+             phase == PHASE_DEAD ) )
+        cyg_thread_delay(100);
+
+    return phase == PHASE_NETWORK ? 0 : -1;
+}
+
+// -------------------------------------------------------------------------
+
+externC void cyg_ppp_wait_down( cyg_ppp_handle_t handle )
+{
+    while( ppp_tty.tx_thread_running || ppp_tty.pppd_thread_running )
+        cyg_thread_delay(100);
+    
+    cyg_thread_delete( ppp_tty.tx_thread );
+    cyg_thread_delete( ppp_tty.pppd_thread );
+}
+
+//=====================================================================
+// eCos extras
+
+void syslog( int level, char *fmt, ... )
+{
+    va_list ap;
+    int ret;
+
+#ifdef CYGPKG_PPP_DEBUG_WARN_ONLY
+    if(!( level == LOG_ERR ||
+          level == LOG_WARNING ))
+        return;
+#endif
+    
+    va_start(ap, fmt);
+    diag_printf("SYSLOG %02x: ",level);
+    ret = diag_vprintf(fmt, ap);
+    diag_printf("\n");
+    va_end(ap);
+}
+
+//=====================================================================
+
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+    cyg_tick_count_t time = cyg_current_time();
+    
+    tv->tv_sec = time/CYGNUM_HAL_RTC_DENOMINATOR;
+    tv->tv_usec = (time%CYGNUM_HAL_RTC_DENOMINATOR)*10000;
+    
+//    db_printf("%s: %d %d\n", __PRETTY_FUNCTION__, tv->tv_sec, tv->tv_usec);
+
+    return 0;
+}
+
+//=====================================================================
+
+char *crypt (const char *key, const char *salt)
+{
+    static char res[13];
+
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    
+    return res;
+}
+
+
+//=====================================================================
+/*
+ * Substitute procedures for those systems which don't have
+ * drand48 et al.
+ */
+
+double
+drand48(void)
+{
+    return (double)rand() / (double)0x7fffffffL; /* 2**31-1 */
+}
+
+long
+mrand48(void)
+{
+    return rand();
+}
+
+void
+srand48(long seedval)
+{
+    srand(seedval);
+}
+
+
+//=====================================================================
+
+#if 0
+
+#undef MD5Init
+#undef MD5Update
+#undef MD5Final
+
+#include <sys/types.h>
+
+#include <sys/md5.h>
+
+
+void   cyg_MD5Init( MD5_CTX *ctx );
+void   cyg_MD5Update (MD5_CTX *ctx, const unsigned char *buf, unsigned int size);
+void   cyg_MD5Final (unsigned char hash[16], MD5_CTX *ctx);
+  
+
+void   cyg_ppp_MD5Init( MD5_CTX *ctx )
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    cyg_MD5Init( ctx );
+    return;
+}
+
+void   cyg_ppp_MD5Update (MD5_CTX *ctx, const unsigned char *buf, unsigned int size)
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    cyg_MD5Update( ctx, buf, size );
+    return;
+}
+
+void   cyg_ppp_MD5Final (unsigned char hash[16], MD5_CTX *ctx)
+{
+    db_printf("%s called\n", __PRETTY_FUNCTION__);
+    cyg_MD5Final( hash, ctx );
+    return;
+}
+
+#endif
+
+//=====================================================================
+// End of sys-ecos.c
+
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/upap.c
@@ -0,0 +1,666 @@
+//==========================================================================
+//
+//      src/upap.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+//static char rcsid[] = "$FreeBSD: src/usr.sbin/pppd/upap.c,v 1.8 1999/08/28 01:19:08 peter Exp $";
+#endif
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <cyg/ppp/syslog.h>
+#include "cyg/ppp/pppd.h"
+#include "cyg/ppp/upap.h"
+
+/*
+ * Protocol entry points.
+ */
+static void upap_init __P((int));
+static void upap_lowerup __P((int));
+static void upap_lowerdown __P((int));
+static void upap_input __P((int, u_char *, int));
+static void upap_protrej __P((int));
+static int  upap_printpkt __P((u_char *, int,
+			       void (*) __P((void *, char *, ...)), void *));
+
+struct protent pap_protent = {
+    PPP_PAP,
+    upap_init,
+    upap_input,
+    upap_protrej,
+    upap_lowerup,
+    upap_lowerdown,
+    NULL,
+    NULL,
+    upap_printpkt,
+    NULL,
+    1,
+    "PAP",
+    NULL,
+    NULL,
+    NULL
+};
+
+upap_state upap[NUM_PPP];		/* UPAP state; one for each unit */
+
+static void upap_timeout __P((void *));
+static void upap_reqtimeout __P((void *));
+static void upap_rauthreq __P((upap_state *, u_char *, int, int));
+static void upap_rauthack __P((upap_state *, u_char *, int, int));
+static void upap_rauthnak __P((upap_state *, u_char *, int, int));
+static void upap_sauthreq __P((upap_state *));
+static void upap_sresp __P((upap_state *, int, int, char *, int));
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void
+upap_init(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    u->us_unit = unit;
+    u->us_user = NULL;
+    u->us_userlen = 0;
+    u->us_passwd = NULL;
+    u->us_passwdlen = 0;
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->us_serverstate = UPAPSS_INITIAL;
+    u->us_id = 0;
+    u->us_timeouttime = UPAP_DEFTIMEOUT;
+    u->us_maxtransmits = 10;
+    u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void
+upap_authwithpeer(unit, user, password)
+    int unit;
+    char *user, *password;
+{
+    upap_state *u = &upap[unit];
+
+    /* Save the username and password we're given */
+    u->us_user = user;
+    u->us_userlen = strlen(user);
+    u->us_passwd = password;
+    u->us_passwdlen = strlen(password);
+    u->us_transmits = 0;
+
+    /* Lower layer up yet? */
+    if (u->us_clientstate == UPAPCS_INITIAL ||
+	u->us_clientstate == UPAPCS_PENDING) {
+	u->us_clientstate = UPAPCS_PENDING;
+	return;
+    }
+
+    upap_sauthreq(u);			/* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void
+upap_authpeer(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    /* Lower layer up yet? */
+    if (u->us_serverstate == UPAPSS_INITIAL ||
+	u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_PENDING;
+	return;
+    }
+
+    u->us_serverstate = UPAPSS_LISTEN;
+    if (u->us_reqtimeout > 0)
+	TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+}
+
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void
+upap_timeout(arg)
+    void *arg;
+{
+    upap_state *u = (upap_state *) arg;
+
+    if (u->us_clientstate != UPAPCS_AUTHREQ)
+	return;
+
+    if (u->us_transmits >= u->us_maxtransmits) {
+	/* give up in disgust */
+	syslog(LOG_ERR, "No response to PAP authenticate-requests");
+	u->us_clientstate = UPAPCS_BADAUTH;
+	auth_withpeer_fail(u->us_unit, PPP_PAP);
+	return;
+    }
+
+    upap_sauthreq(u);		/* Send Authenticate-Request */
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void
+upap_reqtimeout(arg)
+    void *arg;
+{
+    upap_state *u = (upap_state *) arg;
+
+    if (u->us_serverstate != UPAPSS_LISTEN)
+	return;			/* huh?? */
+
+    auth_peer_fail(u->us_unit, PPP_PAP);
+    u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void
+upap_lowerup(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_INITIAL)
+	u->us_clientstate = UPAPCS_CLOSED;
+    else if (u->us_clientstate == UPAPCS_PENDING) {
+	upap_sauthreq(u);	/* send an auth-request */
+    }
+
+    if (u->us_serverstate == UPAPSS_INITIAL)
+	u->us_serverstate = UPAPSS_CLOSED;
+    else if (u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_LISTEN;
+	if (u->us_reqtimeout > 0)
+	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+    }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+upap_lowerdown(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ)	/* Timeout pending? */
+	UNTIMEOUT(upap_timeout, u);		/* Cancel timeout */
+    if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+	UNTIMEOUT(upap_reqtimeout, u);
+
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen.  In any case, pretend lower layer went down.
+ */
+static void
+upap_protrej(unit)
+    int unit;
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ) {
+	syslog(LOG_ERR, "PAP authentication failed due to protocol-reject");
+	auth_withpeer_fail(unit, PPP_PAP);
+    }
+    if (u->us_serverstate == UPAPSS_LISTEN) {
+	syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)");
+	auth_peer_fail(unit, PPP_PAP);
+    }
+    upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void
+upap_input(unit, inpacket, l)
+    int unit;
+    u_char *inpacket;
+    int l;
+{
+    upap_state *u = &upap[unit];
+    u_char *inp;
+    u_char code, id;
+    int len;
+
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (l < UPAP_HEADERLEN) {
+	UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < UPAP_HEADERLEN) {
+	UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length."));
+	return;
+    }
+    if (len > l) {
+	UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet."));
+	return;
+    }
+    len -= UPAP_HEADERLEN;
+
+    /*
+     * Action depends on code.
+     */
+    switch (code) {
+    case UPAP_AUTHREQ:
+	upap_rauthreq(u, inp, id, len);
+	break;
+
+    case UPAP_AUTHACK:
+	upap_rauthack(u, inp, id, len);
+	break;
+
+    case UPAP_AUTHNAK:
+	upap_rauthnak(u, inp, id, len);
+	break;
+
+    default:				/* XXX Need code reject */
+	break;
+    }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void
+upap_rauthreq(u, inp, id, len)
+    upap_state *u;
+    u_char *inp;
+    int id;
+    int len;
+{
+    u_char ruserlen, rpasswdlen;
+    char *ruser, *rpasswd;
+    int retcode;
+    char *msg;
+    int msglen;
+
+    UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id));
+
+    if (u->us_serverstate < UPAPSS_LISTEN)
+	return;
+
+    /*
+     * If we receive a duplicate authenticate-request, we are
+     * supposed to return the same status as for the first request.
+     */
+    if (u->us_serverstate == UPAPSS_OPEN) {
+	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
+	return;
+    }
+    if (u->us_serverstate == UPAPSS_BADAUTH) {
+	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
+	return;
+    }
+
+    /*
+     * Parse user/passwd.
+     */
+    if (len < sizeof (u_char)) {
+	UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
+	return;
+    }
+    GETCHAR(ruserlen, inp);
+    len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+    if (len < 0) {
+	UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
+	return;
+    }
+    ruser = (char *) inp;
+    INCPTR(ruserlen, inp);
+    GETCHAR(rpasswdlen, inp);
+    if (len < rpasswdlen) {
+	UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet."));
+	return;
+    }
+    rpasswd = (char *) inp;
+
+    /*
+     * Check the username and password given.
+     */
+    retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+			   rpasswdlen, &msg, &msglen);
+    BZERO(rpasswd, rpasswdlen);
+
+    upap_sresp(u, retcode, id, msg, msglen);
+
+    if (retcode == UPAP_AUTHACK) {
+	u->us_serverstate = UPAPSS_OPEN;
+	auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+    } else {
+	u->us_serverstate = UPAPSS_BADAUTH;
+	auth_peer_fail(u->us_unit, PPP_PAP);
+    }
+
+    if (u->us_reqtimeout > 0)
+	UNTIMEOUT(upap_reqtimeout, u);
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void
+upap_rauthack(u, inp, id, len)
+    upap_state *u;
+    u_char *inp;
+    int id;
+    int len;
+{
+    u_char msglen;
+    char *msg;
+
+    UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id));
+    if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < sizeof (u_char)) {
+	UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
+	return;
+    }
+    GETCHAR(msglen, inp);
+    len -= sizeof (u_char);
+    if (len < msglen) {
+	UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet."));
+	return;
+    }
+    msg = (char *) inp;
+    PRINTMSG(msg, msglen);
+
+    u->us_clientstate = UPAPCS_OPEN;
+
+    auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nakk.
+ */
+static void
+upap_rauthnak(u, inp, id, len)
+    upap_state *u;
+    u_char *inp;
+    int id;
+    int len;
+{
+    u_char msglen;
+    char *msg;
+
+    UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id));
+    if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < sizeof (u_char)) {
+	UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
+	return;
+    }
+    GETCHAR(msglen, inp);
+    len -= sizeof (u_char);
+    if (len < msglen) {
+	UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet."));
+	return;
+    }
+    msg = (char *) inp;
+    PRINTMSG(msg, msglen);
+
+    u->us_clientstate = UPAPCS_BADAUTH;
+
+    syslog(LOG_ERR, "PAP authentication failed");
+    auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void
+upap_sauthreq(u)
+    upap_state *u;
+{
+    u_char *outp;
+    int outlen;
+
+    outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
+	u->us_userlen + u->us_passwdlen;
+    outp = outpacket_buf;
+    
+    MAKEHEADER(outp, PPP_PAP);
+
+    PUTCHAR(UPAP_AUTHREQ, outp);
+    PUTCHAR(++u->us_id, outp);
+    PUTSHORT(outlen, outp);
+    PUTCHAR(u->us_userlen, outp);
+    BCOPY(u->us_user, outp, u->us_userlen);
+    INCPTR(u->us_userlen, outp);
+    PUTCHAR(u->us_passwdlen, outp);
+    BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+    output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id));
+
+    TIMEOUT(upap_timeout, u, u->us_timeouttime);
+    ++u->us_transmits;
+    u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void
+upap_sresp(u, code, id, msg, msglen)
+    upap_state *u;
+    u_char code, id;
+    char *msg;
+    int msglen;
+{
+    u_char *outp;
+    int outlen;
+
+    outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+    outp = outpacket_buf;
+    MAKEHEADER(outp, PPP_PAP);
+
+    PUTCHAR(code, outp);
+    PUTCHAR(id, outp);
+    PUTSHORT(outlen, outp);
+    PUTCHAR(msglen, outp);
+    BCOPY(msg, outp, msglen);
+    output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id));
+}
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static char *upap_codenames[] = {
+    "AuthReq", "AuthAck", "AuthNak"
+};
+
+static int
+upap_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer) __P((void *, char *, ...));
+    void *arg;
+{
+    int code, id, len;
+    int mlen, ulen, wlen;
+    char *user, *pwd, *msg;
+    u_char *pstart;
+
+    if (plen < UPAP_HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < UPAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
+	printer(arg, " %s", upap_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= UPAP_HEADERLEN;
+    switch (code) {
+    case UPAP_AUTHREQ:
+	if (len < 1)
+	    break;
+	ulen = p[0];
+	if (len < ulen + 2)
+	    break;
+	wlen = p[ulen + 1];
+	if (len < ulen + wlen + 2)
+	    break;
+	user = (char *) (p + 1);
+	pwd = (char *) (p + ulen + 2);
+	p += ulen + wlen + 2;
+	len -= ulen + wlen + 2;
+	printer(arg, " user=");
+	print_string(user, ulen, printer, arg);
+	printer(arg, " password=");
+	print_string(pwd, wlen, printer, arg);
+	break;
+    case UPAP_AUTHACK:
+    case UPAP_AUTHNAK:
+	if (len < 1)
+	    break;
+	mlen = p[0];
+	if (len < mlen + 1)
+	    break;
+	msg = (char *) (p + 1);
+	p += mlen + 1;
+	len -= mlen + 1;
+	printer(arg, " ");
+	print_string(msg, mlen, printer, arg);
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/src/zlib.c
@@ -0,0 +1,5443 @@
+//==========================================================================
+//
+//      src/zlib.c
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+
+/*
+ * This file is derived from various .h and .c files from the zlib-1.0.4
+ * distribution by Jean-loup Gailly and Mark Adler, with some additions
+ * by Paul Mackerras to aid in implementing Deflate compression and
+ * decompression for PPP packets.  See zlib.h for conditions of
+ * distribution and use.
+ *
+ * Changes that have been made include:
+ * - added Z_PACKET_FLUSH (see zlib.h for details)
+ * - added inflateIncomp and deflateOutputPending
+ * - allow strm->next_out to be NULL, meaning discard the output
+ *
+ * $FreeBSD: src/sys/net/zlib.c,v 1.10.6.2 2002/03/24 23:23:58 jedgar Exp $
+ */
+
+/* 
+ *  ==FILEVERSION 971210==
+ *
+ * This marker is used by the Linux installation script to determine
+ * whether an up-to-date version of this file is already installed.
+ */
+
+#define _KERNEL
+
+#define NO_DUMMY_DECL
+#define NO_ZCFUNCS
+#define MY_ZCALLOC
+
+#if 1 //defined(__FreeBSD__) && defined(_KERNEL)
+#define inflate	inflate_ppp	/* FreeBSD already has an inflate :-( */
+#endif
+
+
+/* +++ zutil.h */
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: zutil.h,v 1.16 1996/07/24 13:41:13 me Exp $ */
+
+#ifndef _Z_UTIL_H
+#define _Z_UTIL_H
+
+#ifdef _KERNEL
+#include <cyg/ppp/net/zlib.h>
+#else
+#include "zlib.h"
+#endif
+
+#ifdef _KERNEL
+/* Assume this is a *BSD or SVR4 kernel */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+//#include <sys/systm.h>
+#ifndef __ECOS
+#  define HAVE_MEMCPY
+#  define memcpy(d, s, n)	bcopy((s), (d), (n))
+#  define memset(d, v, n)	bzero((d), (n))
+#  define memcmp		bcmp
+#else
+#  include <string.h>
+//#  include <stdlib.h>
+#endif
+
+#else
+#if defined(__KERNEL__)
+/* Assume this is a Linux kernel */
+#include <linux/string.h>
+#define HAVE_MEMCPY
+
+#else /* not kernel */
+
+#if defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS)
+#   include <stddef.h>
+#   include <errno.h>
+#else
+    extern int errno;
+#endif
+#ifdef STDC
+#  include <string.h>
+#  include <stdlib.h>
+#endif
+#endif /* __KERNEL__ */
+#endif /* _KERNEL */
+
+#ifndef local
+#  define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char  uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long  ulg;
+
+extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+  return (strm->msg = (const char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+        /* common constants */
+
+#ifndef DEF_WBITS
+#  define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+#  define DEF_MEM_LEVEL 8
+#else
+#  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES    2
+/* The three kinds of block type */
+
+#define MIN_MATCH  3
+#define MAX_MATCH  258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+        /* target dependencies */
+
+#ifdef MSDOS
+#  define OS_CODE  0x00
+#  ifdef __TURBOC__
+#    include <alloc.h>
+#  else /* MSC or DJGPP */
+#    include <malloc.h>
+#  endif
+#endif
+
+#ifdef OS2
+#  define OS_CODE  0x06
+#endif
+
+#ifdef WIN32 /* Window 95 & Windows NT */
+#  define OS_CODE  0x0b
+#endif
+
+#if defined(VAXC) || defined(VMS)
+#  define OS_CODE  0x02
+#  define FOPEN(name, mode) \
+     fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#ifdef AMIGA
+#  define OS_CODE  0x01
+#endif
+
+#if defined(ATARI) || defined(atarist)
+#  define OS_CODE  0x05
+#endif
+
+#ifdef MACOS
+#  define OS_CODE  0x07
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+#  define OS_CODE  0x0F
+#endif
+
+#ifdef TOPS20
+#  define OS_CODE  0x0a
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+#  define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+        /* Common defaults */
+
+#ifndef OS_CODE
+#  define OS_CODE  0x03  /* assume Unix */
+#endif
+
+#ifndef FOPEN
+#  define FOPEN(name, mode) fopen((name), (mode))
+#endif
+
+         /* functions */
+
+#ifdef HAVE_STRERROR
+   extern char *strerror OF((int));
+#  define zstrerror(errnum) strerror(errnum)
+#else
+#  define zstrerror(errnum) ""
+#endif
+
+#if defined(pyr)
+#  define NO_MEMCPY
+#endif
+#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+  * You may have to use the same strategy for Borland C (untested).
+  */
+#  define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+#  define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+#  ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+#    define zmemcpy _fmemcpy
+#    define zmemcmp _fmemcmp
+#    define zmemzero(dest, len) _fmemset(dest, 0, len)
+#  else
+#    define zmemcpy memcpy
+#    define zmemcmp memcmp
+#    define zmemzero(dest, len) memset(dest, 0, len)
+#  endif
+#else
+   extern void zmemcpy  OF((Bytef* dest, Bytef* source, uInt len));
+   extern int  zmemcmp  OF((Bytef* s1,   Bytef* s2, uInt len));
+   extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG_ZLIB
+#  include <stdio.h>
+#  ifndef verbose
+#    define verbose 0
+#  endif
+   extern void z_error    OF((char *m));
+#  define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+#  define Trace(x) fprintf x
+#  define Tracev(x) {if (verbose) fprintf x ;}
+#  define Tracevv(x) {if (verbose>1) fprintf x ;}
+#  define Tracec(c,x) {if (verbose && (c)) fprintf x ;}
+#  define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;}
+#else
+#  define Assert(cond,msg)
+#  define Trace(x)
+#  define Tracev(x)
+#  define Tracevv(x)
+#  define Tracec(c,x)
+#  define Tracecv(c,x)
+#endif
+
+
+typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len));
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void   zcfree  OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+           (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr)  (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* _Z_UTIL_H */
+/* --- zutil.h */
+
+/* +++ deflate.h */
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* From: deflate.h,v 1.10 1996/07/02 12:41:00 me Exp $ */
+
+#ifndef _DEFLATE_H
+#define _DEFLATE_H
+
+/* #include "zutil.h" */
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS  256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES   30
+/* number of distance codes */
+
+#define BL_CODES  19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE    42
+#define BUSY_STATE   113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+    union {
+        ush  freq;       /* frequency count */
+        ush  code;       /* bit string */
+    } fc;
+    union {
+        ush  dad;        /* father node in Huffman tree */
+        ush  len;        /* length of bit string */
+    } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad  dl.dad
+#define Len  dl.len
+
+typedef struct static_tree_desc_s  static_tree_desc;
+
+typedef struct tree_desc_s {
+    ct_data *dyn_tree;           /* the dynamic tree */
+    int     max_code;            /* largest code with non zero frequency */
+    static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct deflate_state {
+    z_streamp strm;      /* pointer back to this zlib stream */
+    int   status;        /* as the name implies */
+    Bytef *pending_buf;  /* output still pending */
+    ulg   pending_buf_size; /* size of pending_buf */
+    Bytef *pending_out;  /* next pending byte to output to the stream */
+    int   pending;       /* nb of bytes in the pending buffer */
+    int   noheader;      /* suppress zlib header and adler32 */
+    Byte  data_type;     /* UNKNOWN, BINARY or ASCII */
+    Byte  method;        /* STORED (for zip only) or DEFLATED */
+    int   last_flush;    /* value of flush param for previous deflate call */
+
+                /* used by deflate.c: */
+
+    uInt  w_size;        /* LZ77 window size (32K by default) */
+    uInt  w_bits;        /* log2(w_size)  (8..16) */
+    uInt  w_mask;        /* w_size - 1 */
+
+    Bytef *window;
+    /* Sliding window. Input bytes are read into the second half of the window,
+     * and move to the first half later to keep a dictionary of at least wSize
+     * bytes. With this organization, matches are limited to a distance of
+     * wSize-MAX_MATCH bytes, but this ensures that IO is always
+     * performed with a length multiple of the block size. Also, it limits
+     * the window size to 64K, which is quite useful on MSDOS.
+     * To do: use the user input buffer as sliding window.
+     */
+
+    ulg window_size;
+    /* Actual size of window: 2*wSize, except when the user input buffer
+     * is directly used as sliding window.
+     */
+
+    Posf *prev;
+    /* Link to older string with same hash index. To limit the size of this
+     * array to 64K, this link is maintained only for the last 32K strings.
+     * An index in this array is thus a window index modulo 32K.
+     */
+
+    Posf *head; /* Heads of the hash chains or NIL. */
+
+    uInt  ins_h;          /* hash index of string to be inserted */
+    uInt  hash_size;      /* number of elements in hash table */
+    uInt  hash_bits;      /* log2(hash_size) */
+    uInt  hash_mask;      /* hash_size-1 */
+
+    uInt  hash_shift;
+    /* Number of bits by which ins_h must be shifted at each input
+     * step. It must be such that after MIN_MATCH steps, the oldest
+     * byte no longer takes part in the hash key, that is:
+     *   hash_shift * MIN_MATCH >= hash_bits
+     */
+
+    long block_start;
+    /* Window position at the beginning of the current output block. Gets
+     * negative when the window is moved backwards.
+     */
+
+    uInt match_length;           /* length of best match */
+    IPos prev_match;             /* previous match */
+    int match_available;         /* set if previous match exists */
+    uInt strstart;               /* start of string to insert */
+    uInt match_start;            /* start of matching string */
+    uInt lookahead;              /* number of valid bytes ahead in window */
+
+    uInt prev_length;
+    /* Length of the best match at previous step. Matches not greater than this
+     * are discarded. This is used in the lazy match evaluation.
+     */
+
+    uInt max_chain_length;
+    /* To speed up deflation, hash chains are never searched beyond this
+     * length.  A higher limit improves compression ratio but degrades the
+     * speed.
+     */
+
+    uInt max_lazy_match;
+    /* Attempt to find a better match only when the current match is strictly
+     * smaller than this value. This mechanism is used only for compression
+     * levels >= 4.
+     */
+#   define max_insert_length  max_lazy_match
+    /* Insert new strings in the hash table only if the match length is not
+     * greater than this length. This saves time but degrades compression.
+     * max_insert_length is used only for compression levels <= 3.
+     */
+
+    int level;    /* compression level (1..9) */
+    int strategy; /* favor or force Huffman coding*/
+
+    uInt good_match;
+    /* Use a faster search when the previous match is longer than this */
+
+    int nice_match; /* Stop searching when current match exceeds this */
+
+                /* used by trees.c: */
+    /* Didn't use ct_data typedef below to supress compiler warning */
+    struct ct_data_s dyn_ltree[HEAP_SIZE];   /* literal and length tree */
+    struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+    struct ct_data_s bl_tree[2*BL_CODES+1];  /* Huffman tree for bit lengths */
+
+    struct tree_desc_s l_desc;               /* desc. for literal tree */
+    struct tree_desc_s d_desc;               /* desc. for distance tree */
+    struct tree_desc_s bl_desc;              /* desc. for bit length tree */
+
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    int heap[2*L_CODES+1];      /* heap used to build the Huffman trees */
+    int heap_len;               /* number of elements in the heap */
+    int heap_max;               /* element of largest frequency */
+    /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+     * The same heap array is used to build all trees.
+     */
+
+    uch depth[2*L_CODES+1];
+    /* Depth of each subtree used as tie breaker for trees of equal frequency
+     */
+
+    uchf *l_buf;          /* buffer for literals or lengths */
+
+    uInt  lit_bufsize;
+    /* Size of match buffer for literals/lengths.  There are 4 reasons for
+     * limiting lit_bufsize to 64K:
+     *   - frequencies can be kept in 16 bit counters
+     *   - if compression is not successful for the first block, all input
+     *     data is still in the window so we can still emit a stored block even
+     *     when input comes from standard input.  (This can also be done for
+     *     all blocks if lit_bufsize is not greater than 32K.)
+     *   - if compression is not successful for a file smaller than 64K, we can
+     *     even emit a stored file instead of a stored block (saving 5 bytes).
+     *     This is applicable only for zip (not gzip or zlib).
+     *   - creating new Huffman trees less frequently may not provide fast
+     *     adaptation to changes in the input data statistics. (Take for
+     *     example a binary file with poorly compressible code followed by
+     *     a highly compressible string table.) Smaller buffer sizes give
+     *     fast adaptation but have of course the overhead of transmitting
+     *     trees more frequently.
+     *   - I can't count above 4
+     */
+
+    uInt last_lit;      /* running index in l_buf */
+
+    ushf *d_buf;
+    /* Buffer for distances. To simplify the code, d_buf and l_buf have
+     * the same number of elements. To use different lengths, an extra flag
+     * array would be necessary.
+     */
+
+    ulg opt_len;        /* bit length of current block with optimal trees */
+    ulg static_len;     /* bit length of current block with static trees */
+    ulg compressed_len; /* total bit length of compressed file */
+    uInt matches;       /* number of string matches in current block */
+    int last_eob_len;   /* bit length of EOB code for last block */
+
+#ifdef DEBUG_ZLIB
+    ulg bits_sent;      /* bit length of the compressed data */
+#endif
+
+    ush bi_buf;
+    /* Output buffer. bits are inserted starting at the bottom (least
+     * significant bits).
+     */
+    int bi_valid;
+    /* Number of valid bits in bi_buf.  All bits above the last valid bit
+     * are always zero.
+     */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s)  ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+        /* in trees.c */
+void _tr_init         OF((deflate_state *s));
+int  _tr_tally        OF((deflate_state *s, unsigned dist, unsigned lc));
+ulg  _tr_flush_block  OF((deflate_state *s, charf *buf, ulg stored_len,
+			  int eof));
+void _tr_align        OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+                          int eof));
+void _tr_stored_type_only OF((deflate_state *));
+
+#endif
+/* --- deflate.h */
+
+/* +++ deflate.c */
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process depends on being able to identify portions
+ *      of the input text which are identical to earlier input (within a
+ *      sliding window trailing behind the input currently being processed).
+ *
+ *      The most straightforward technique turns out to be the fastest for
+ *      most input files: try all possible matches and select the longest.
+ *      The key feature of this algorithm is that insertions into the string
+ *      dictionary are very simple and thus fast, and deletions are avoided
+ *      completely. Insertions are performed at each input character, whereas
+ *      string matches are performed only when the previous match ends. So it
+ *      is preferable to spend more time in matches to allow very fast string
+ *      insertions and avoid deletions. The matching algorithm for small
+ *      strings is inspired from that of Rabin & Karp. A brute force approach
+ *      is used to find longer strings when a small match has been found.
+ *      A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ *      (by Leonid Broukhis).
+ *         A previous version of this file used a more sophisticated algorithm
+ *      (by Fiala and Greene) which is guaranteed to run in linear amortized
+ *      time, but has a larger average cost, uses more memory and is patented.
+ *      However the F&G algorithm may be faster for some highly redundant
+ *      files if the parameter max_chain_length (described below) is too large.
+ *
+ *  ACKNOWLEDGEMENTS
+ *
+ *      The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ *      I found it in 'freeze' written by Leonid Broukhis.
+ *      Thanks to many people for bug reports and testing.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ *      Available in ftp://ds.internic.net/rfc/rfc1951.txt
+ *
+ *      A description of the Rabin and Karp algorithm is given in the book
+ *         "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ *      Fiala,E.R., and Greene,D.H.
+ *         Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* From: deflate.c,v 1.15 1996/07/24 13:40:58 me Exp $ */
+
+/* #include "deflate.h" */
+
+char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ *  Function prototypes.
+ */
+typedef enum {
+    need_more,      /* block not completed, need more input or more output */
+    block_done,     /* block flush performed */
+    finish_started, /* finish started, need only more output at next deflate */
+    finish_done     /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window    OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast   OF((deflate_state *s, int flush));
+local block_state deflate_slow   OF((deflate_state *s, int flush));
+local void lm_init        OF((deflate_state *s));
+local void putShortMSB    OF((deflate_state *s, uInt b));
+local void flush_pending  OF((z_streamp strm));
+local int read_buf        OF((z_streamp strm, charf *buf, unsigned size));
+#ifdef ASMV
+      void match_init OF((void)); /* asm code initialization */
+      uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match  OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG_ZLIB
+local  void check_match OF((deflate_state *s, IPos start, IPos match,
+                            int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+#  define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+   ush good_length; /* reduce lazy search above this match length */
+   ush max_lazy;    /* do not perform lazy search above this match length */
+   ush nice_length; /* quit search above this match length */
+   ush max_chain;
+   compress_func func;
+} config;
+
+local config configuration_table[10] = {
+/*      good lazy nice chain */
+/* 0 */ {0,    0,  0,    0, deflate_stored},  /* store only */
+/* 1 */ {4,    4,  8,    4, deflate_fast}, /* maximum speed, no lazy matches */
+/* 2 */ {4,    5, 16,    8, deflate_fast},
+/* 3 */ {4,    6, 32,   32, deflate_fast},
+
+/* 4 */ {4,    4, 16,   16, deflate_slow},  /* lazy matches */
+/* 5 */ {8,   16, 32,   32, deflate_slow},
+/* 6 */ {8,   16, 128, 128, deflate_slow},
+/* 7 */ {8,   32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN  assertion: all calls to to UPDATE_HASH are made with consecutive
+ *    input characters, so that a running hash key can be computed from the
+ *    previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * IN  assertion: all calls to to INSERT_STRING are made with consecutive
+ *    input characters and the first MIN_MATCH bytes of str are valid
+ *    (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#define INSERT_STRING(s, str, match_head) \
+   (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+    s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \
+    s->head[s->ins_h] = (Pos)(str))
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+    s->head[s->hash_size-1] = NIL; \
+    zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int deflateInit_(strm, level, version, stream_size)
+    z_streamp strm;
+    int level;
+    const char *version;
+    int stream_size;
+{
+    return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+			 Z_DEFAULT_STRATEGY, version, stream_size);
+    /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+		  version, stream_size)
+    z_streamp strm;
+    int  level;
+    int  method;
+    int  windowBits;
+    int  memLevel;
+    int  strategy;
+    const char *version;
+    int stream_size;
+{
+    deflate_state *s;
+    int noheader = 0;
+    static char* my_version = ZLIB_VERSION;
+
+    ushf *overlay;
+    /* We overlay pending_buf and d_buf+l_buf. This works since the average
+     * output size for (length,distance) codes is <= 24 bits.
+     */
+
+    if (version == Z_NULL || version[0] != my_version[0] ||
+        stream_size != sizeof(z_stream)) {
+	return Z_VERSION_ERROR;
+    }
+    if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+    if (strm->zalloc == Z_NULL) {
+	strm->zalloc = zcalloc;
+	strm->opaque = (voidpf)0;
+    }
+    if (strm->zfree == Z_NULL) strm->zfree = zcfree;
+#endif
+
+    if (level == Z_DEFAULT_COMPRESSION) level = 6;
+
+    if (windowBits < 0) { /* undocumented feature: suppress zlib header */
+        noheader = 1;
+        windowBits = -windowBits;
+    }
+    if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+        windowBits < 9 || windowBits > 15 || level < 0 || level > 9 ||
+	strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+    if (s == Z_NULL) return Z_MEM_ERROR;
+    strm->state = (struct internal_state FAR *)s;
+    s->strm = strm;
+
+    s->noheader = noheader;
+    s->w_bits = windowBits;
+    s->w_size = 1 << s->w_bits;
+    s->w_mask = s->w_size - 1;
+
+    s->hash_bits = memLevel + 7;
+    s->hash_size = 1 << s->hash_bits;
+    s->hash_mask = s->hash_size - 1;
+    s->hash_shift =  ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+    s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+    s->prev   = (Posf *)  ZALLOC(strm, s->w_size, sizeof(Pos));
+    s->head   = (Posf *)  ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+    s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+    overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+    s->pending_buf = (uchf *) overlay;
+    s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+    if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+        s->pending_buf == Z_NULL) {
+        strm->msg = (const char*)ERR_MSG(Z_MEM_ERROR);
+        deflateEnd (strm);
+        return Z_MEM_ERROR;
+    }
+    s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+    s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+    s->level = level;
+    s->strategy = strategy;
+    s->method = (Byte)method;
+
+    return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int deflateSetDictionary (strm, dictionary, dictLength)
+    z_streamp strm;
+    const Bytef *dictionary;
+    uInt  dictLength;
+{
+    deflate_state *s;
+    uInt length = dictLength;
+    uInt n;
+    IPos hash_head = 0;
+
+    if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+	return Z_STREAM_ERROR;
+
+    s = (deflate_state *) strm->state;
+    if (s->status != INIT_STATE) return Z_STREAM_ERROR;
+
+    strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+    if (length < MIN_MATCH) return Z_OK;
+    if (length > MAX_DIST(s)) {
+	length = MAX_DIST(s);
+#ifndef USE_DICT_HEAD
+	dictionary += dictLength - length; /* use the tail of the dictionary */
+#endif
+    }
+    zmemcpy((charf *)s->window, dictionary, length);
+    s->strstart = length;
+    s->block_start = (long)length;
+
+    /* Insert all strings in the hash table (except for the last two bytes).
+     * s->lookahead stays null, so s->ins_h will be recomputed at the next
+     * call of fill_window.
+     */
+    s->ins_h = s->window[0];
+    UPDATE_HASH(s, s->ins_h, s->window[1]);
+    for (n = 0; n <= length - MIN_MATCH; n++) {
+	INSERT_STRING(s, n, hash_head);
+    }
+    if (hash_head) hash_head = 0;  /* to make compiler happy */
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateReset (strm)
+    z_streamp strm;
+{
+    deflate_state *s;
+    
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+        strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR;
+
+    strm->total_in = strm->total_out = 0;
+    strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+    strm->data_type = Z_UNKNOWN;
+
+    s = (deflate_state *)strm->state;
+    s->pending = 0;
+    s->pending_out = s->pending_buf;
+
+    if (s->noheader < 0) {
+        s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */
+    }
+    s->status = s->noheader ? BUSY_STATE : INIT_STATE;
+    strm->adler = 1;
+    s->last_flush = Z_NO_FLUSH;
+
+    _tr_init(s);
+    lm_init(s);
+
+    return Z_OK;
+}
+
+/* ========================================================================= */
+int deflateParams(strm, level, strategy)
+    z_streamp strm;
+    int level;
+    int strategy;
+{
+    deflate_state *s;
+    compress_func func;
+    int err = Z_OK;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    if (level == Z_DEFAULT_COMPRESSION) {
+	level = 6;
+    }
+    if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) {
+	return Z_STREAM_ERROR;
+    }
+    func = configuration_table[s->level].func;
+
+    if (func != configuration_table[level].func && strm->total_in != 0) {
+	/* Flush the last buffer: */
+	err = deflate(strm, Z_PARTIAL_FLUSH);
+    }
+    if (s->level != level) {
+	s->level = level;
+	s->max_lazy_match   = configuration_table[level].max_lazy;
+	s->good_match       = configuration_table[level].good_length;
+	s->nice_match       = configuration_table[level].nice_length;
+	s->max_chain_length = configuration_table[level].max_chain;
+    }
+    s->strategy = strategy;
+    return err;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+    deflate_state *s;
+    uInt b;
+{
+    put_byte(s, (Byte)(b >> 8));
+    put_byte(s, (Byte)(b & 0xff));
+}   
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+    z_streamp strm;
+{
+    deflate_state *s = (deflate_state *) strm->state;
+    unsigned len = s->pending;
+
+    if (len > strm->avail_out) len = strm->avail_out;
+    if (len == 0) return;
+
+    if (strm->next_out != Z_NULL) {
+	zmemcpy(strm->next_out, s->pending_out, len);
+	strm->next_out += len;
+    }
+    s->pending_out += len;
+    strm->total_out += len;
+    strm->avail_out  -= len;
+    s->pending -= len;
+    if (s->pending == 0) {
+        s->pending_out = s->pending_buf;
+    }
+}
+
+/* ========================================================================= */
+int deflate (strm, flush)
+    z_streamp strm;
+    int flush;
+{
+    int old_flush; /* value of flush param for previous deflate call */
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL ||
+	flush > Z_FINISH || flush < 0) {
+        return Z_STREAM_ERROR;
+    }
+    s = (deflate_state *) strm->state;
+
+    if ((strm->next_in == Z_NULL && strm->avail_in != 0) ||
+	(s->status == FINISH_STATE && flush != Z_FINISH)) {
+        ERR_RETURN(strm, Z_STREAM_ERROR);
+    }
+    if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+    s->strm = strm; /* just in case */
+    old_flush = s->last_flush;
+    s->last_flush = flush;
+
+    /* Write the zlib header */
+    if (s->status == INIT_STATE) {
+
+        uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+        uInt level_flags = (s->level-1) >> 1;
+
+        if (level_flags > 3) level_flags = 3;
+        header |= (level_flags << 6);
+	if (s->strstart != 0) header |= PRESET_DICT;
+        header += 31 - (header % 31);
+
+        s->status = BUSY_STATE;
+        putShortMSB(s, header);
+
+	/* Save the adler32 of the preset dictionary: */
+	if (s->strstart != 0) {
+	    putShortMSB(s, (uInt)(strm->adler >> 16));
+	    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+	}
+	strm->adler = 1L;
+    }
+
+    /* Flush as much pending output as possible */
+    if (s->pending != 0) {
+        flush_pending(strm);
+        if (strm->avail_out == 0) {
+	    /* Since avail_out is 0, deflate will be called again with
+	     * more output space, but possibly with both pending and
+	     * avail_in equal to zero. There won't be anything to do,
+	     * but this is not an error situation so make sure we
+	     * return OK instead of BUF_ERROR at next call of deflate:
+             */
+	    s->last_flush = -1;
+	    return Z_OK;
+	}
+
+    /* Make sure there is something to do and avoid duplicate consecutive
+     * flushes. For repeated and useless calls with Z_FINISH, we keep
+     * returning Z_STREAM_END instead of Z_BUFF_ERROR.
+     */
+    } else if (strm->avail_in == 0 && flush <= old_flush &&
+	       flush != Z_FINISH) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* User must not provide more input after the first FINISH: */
+    if (s->status == FINISH_STATE && strm->avail_in != 0) {
+        ERR_RETURN(strm, Z_BUF_ERROR);
+    }
+
+    /* Start a new block or continue the current one.
+     */
+    if (strm->avail_in != 0 || s->lookahead != 0 ||
+        (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+        block_state bstate;
+
+	bstate = (*(configuration_table[s->level].func))(s, flush);
+
+        if (bstate == finish_started || bstate == finish_done) {
+            s->status = FINISH_STATE;
+        }
+        if (bstate == need_more || bstate == finish_started) {
+	    if (strm->avail_out == 0) {
+	        s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+	    }
+	    return Z_OK;
+	    /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+	     * of deflate should use the same flush parameter to make sure
+	     * that the flush is complete. So we don't have to output an
+	     * empty block here, this will be done at next call. This also
+	     * ensures that for a very small output buffer, we emit at most
+	     * one empty block.
+	     */
+	}
+        if (bstate == block_done) {
+            if (flush == Z_PARTIAL_FLUSH) {
+                _tr_align(s);
+	    } else if (flush == Z_PACKET_FLUSH) {
+		/* Output just the 3-bit `stored' block type value,
+		   but not a zero length. */
+		_tr_stored_type_only(s);
+            } else { /* FULL_FLUSH or SYNC_FLUSH */
+                _tr_stored_block(s, (char*)0, 0L, 0);
+                /* For a full flush, this empty block will be recognized
+                 * as a special marker by inflate_sync().
+                 */
+                if (flush == Z_FULL_FLUSH) {
+                    CLEAR_HASH(s);             /* forget history */
+                }
+            }
+            flush_pending(strm);
+	    if (strm->avail_out == 0) {
+	      s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+	      return Z_OK;
+	    }
+        }
+    }
+    Assert(strm->avail_out > 0, "bug2");
+
+    if (flush != Z_FINISH) return Z_OK;
+    if (s->noheader) return Z_STREAM_END;
+
+    /* Write the zlib trailer (adler32) */
+    putShortMSB(s, (uInt)(strm->adler >> 16));
+    putShortMSB(s, (uInt)(strm->adler & 0xffff));
+    flush_pending(strm);
+    /* If avail_out is zero, the application will call deflate again
+     * to flush the rest.
+     */
+    s->noheader = -1; /* write the trailer only once! */
+    return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int deflateEnd (strm)
+    z_streamp strm;
+{
+    int status;
+    deflate_state *s;
+
+    if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+    s = (deflate_state *) strm->state;
+
+    status = s->status;
+    if (status != INIT_STATE && status != BUSY_STATE &&
+	status != FINISH_STATE) {
+      return Z_STREAM_ERROR;
+    }
+
+    /* Deallocate in reverse order of allocations: */
+    TRY_FREE(strm, s->pending_buf);
+    TRY_FREE(strm, s->head);
+    TRY_FREE(strm, s->prev);
+    TRY_FREE(strm, s->window);
+
+    ZFREE(strm, s);
+    strm->state = Z_NULL;
+
+    return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ */
+int deflateCopy (dest, source)
+    z_streamp dest;
+    z_streamp source;
+{
+    deflate_state *ds;
+    deflate_state *ss;
+    ushf *overlay;
+
+    if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL)
+        return Z_STREAM_ERROR;
+    ss = (deflate_state *) source->state;
+
+    zmemcpy(dest, source, sizeof(*dest));
+
+    ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+    if (ds == Z_NULL) return Z_MEM_ERROR;
+    dest->state = (struct internal_state FAR *) ds;
+    zmemcpy(ds, ss, sizeof(*ds));
+    ds->strm = dest;
+
+    ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+    ds->prev   = (Posf *)  ZALLOC(dest, ds->w_size, sizeof(Pos));
+    ds->head   = (Posf *)  ZALLOC(dest, ds->hash_size, sizeof(Pos));
+    overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+    ds->pending_buf = (uchf *) overlay;
+
+    if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+        ds->pending_buf == Z_NULL) {
+        deflateEnd (dest);
+        return Z_MEM_ERROR;
+    }
+    /* ??? following zmemcpy doesn't work for 16-bit MSDOS */
+    zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+    zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+    zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+    zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+    ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+    ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+    ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+    ds->l_desc.dyn_tree = ds->dyn_ltree;
+    ds->d_desc.dyn_tree = ds->dyn_dtree;
+    ds->bl_desc.dyn_tree = ds->bl_tree;
+
+    return Z_OK;
+}
+
+/* ===========================================================================
+ * Return the number of bytes of output which are immediately available
+ * for output from the decompressor.
+ */
+int deflateOutputPending (strm)
+    z_streamp strm;
+{
+    if (strm == Z_NULL || strm->state == Z_NULL) return 0;
+    
+    return ((deflate_state *)(strm->state))->pending;
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read.  All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+    z_streamp strm;
+    charf *buf;
+    unsigned size;
+{
+    unsigned len = strm->avail_in;
+
+    if (len > size) len = size;
+    if (len == 0) return 0;
+
+    strm->avail_in  -= len;
+
+    if (!((deflate_state *)(strm->state))->noheader) {
+        strm->adler = adler32(strm->adler, strm->next_in, len);
+    }
+    zmemcpy(buf, strm->next_in, len);
+    strm->next_in  += len;
+    strm->total_in += len;
+
+    return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+    deflate_state *s;
+{
+    s->window_size = (ulg)2L*s->w_size;
+
+    CLEAR_HASH(s);
+
+    /* Set the default configuration parameters:
+     */
+    s->max_lazy_match   = configuration_table[s->level].max_lazy;
+    s->good_match       = configuration_table[s->level].good_length;
+    s->nice_match       = configuration_table[s->level].nice_length;
+    s->max_chain_length = configuration_table[s->level].max_chain;
+
+    s->strstart = 0;
+    s->block_start = 0L;
+    s->lookahead = 0;
+    s->match_length = s->prev_length = MIN_MATCH-1;
+    s->match_available = 0;
+    s->ins_h = 0;
+#ifdef ASMV
+    match_init(); /* initialize the asm code */
+#endif
+}
+
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ *   string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+    deflate_state *s;
+    IPos cur_match;                             /* current match */
+{
+    unsigned chain_length = s->max_chain_length;/* max hash chain length */
+    register Bytef *scan = s->window + s->strstart; /* current string */
+    register Bytef *match;                       /* matched string */
+    register int len;                           /* length of current match */
+    int best_len = s->prev_length;              /* best match length so far */
+    int nice_match = s->nice_match;             /* stop if match long enough */
+    IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+        s->strstart - (IPos)MAX_DIST(s) : NIL;
+    /* Stop when cur_match becomes <= limit. To simplify the code,
+     * we prevent matches with the string of window index 0.
+     */
+    Posf *prev = s->prev;
+    uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+    /* Compare two bytes at a time. Note: this is not always beneficial.
+     * Try with and without -DUNALIGNED_OK to check.
+     */
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+    register ush scan_start = *(ushf*)scan;
+    register ush scan_end   = *(ushf*)(scan+best_len-1);
+#else
+    register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+    register Byte scan_end1  = scan[best_len-1];
+    register Byte scan_end   = scan[best_len];
+#endif
+
+    /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+     * It is easy to get rid of this optimization if necessary.
+     */
+    Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+    /* Do not waste too much time if we already have a good match: */
+    if (s->prev_length >= s->good_match) {
+        chain_length >>= 2;
+    }
+    /* Do not look for matches beyond the end of the input. This is necessary
+     * to make deflate deterministic.
+     */
+    if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+    Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+    do {
+        Assert(cur_match < s->strstart, "no future");
+        match = s->window + cur_match;
+
+        /* Skip to next match if the match length cannot increase
+         * or if the match length is less than 2:
+         */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+        /* This code assumes sizeof(unsigned short) == 2. Do not use
+         * UNALIGNED_OK if your compiler uses a different size.
+         */
+        if (*(ushf*)(match+best_len-1) != scan_end ||
+            *(ushf*)match != scan_start) continue;
+
+        /* It is not necessary to compare scan[2] and match[2] since they are
+         * always equal when the other bytes match, given that the hash keys
+         * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+         * strstart+3, +5, ... up to strstart+257. We check for insufficient
+         * lookahead only every 4th comparison; the 128th check will be made
+         * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+         * necessary to put more guard bytes at the end of the window, or
+         * to check more often for insufficient lookahead.
+         */
+        Assert(scan[2] == match[2], "scan[2]?");
+        scan++, match++;
+        do {
+        } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+                 scan < strend);
+        /* The funny "do {}" generates better code on most compilers */
+
+        /* Here, scan <= window+strstart+257 */
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+        if (*scan == *match) scan++;
+
+        len = (MAX_MATCH - 1) - (int)(strend-scan);
+        scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+        if (match[best_len]   != scan_end  ||
+            match[best_len-1] != scan_end1 ||
+            *match            != *scan     ||
+            *++match          != scan[1])      continue;
+
+        /* The check at best_len-1 can be removed because it will be made
+         * again later. (This heuristic is not always a win.)
+         * It is not necessary to compare scan[2] and match[2] since they
+         * are always equal when the other bytes match, given that
+         * the hash keys are equal and that HASH_BITS >= 8.
+         */
+        scan += 2, match++;
+        Assert(*scan == *match, "match[2]?");
+
+        /* We check for insufficient lookahead only every 8th comparison;
+         * the 256th check will be made at strstart+258.
+         */
+        do {
+        } while (*++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 *++scan == *++match && *++scan == *++match &&
+                 scan < strend);
+
+        Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+        len = MAX_MATCH - (int)(strend - scan);
+        scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+        if (len > best_len) {
+            s->match_start = cur_match;
+            best_len = len;
+            if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+            scan_end = *(ushf*)(scan+best_len-1);
+#else
+            scan_end1  = scan[best_len-1];
+            scan_end   = scan[best_len];
+#endif
+        }
+    } while ((cur_match = prev[cur_match & wmask]) > limit
+             && --chain_length != 0);
+
+    if ((uInt)best_len <= s->lookahead) return best_len;
+    return s->lookahead;
+}
+#endif /* ASMV */
+
+#ifdef DEBUG_ZLIB
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+    deflate_state *s;
+    IPos start, match;
+    int length;
+{
+    /* check that the match is indeed a match */
+    if (zmemcmp((charf *)s->window + match,
+                (charf *)s->window + start, length) != EQUAL) {
+        fprintf(stderr, " start %u, match %u, length %d\n",
+		start, match, length);
+        do {
+	    fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+	} while (--length != 0);
+        z_error("invalid match");
+    }
+    if (z_verbose > 1) {
+        fprintf(stderr,"\\[%d,%d]", start-match, length);
+        do { putc(s->window[start++], stderr); } while (--length != 0);
+    }
+}
+#else
+#  define check_match(s, start, match, length)
+#endif
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ *    At least one byte has been read, or avail_in == 0; reads are
+ *    performed for at least two bytes (required for the zip translate_eol
+ *    option -- not supported here).
+ */
+local void fill_window(s)
+    deflate_state *s;
+{
+    register unsigned n, m;
+    register Posf *p;
+    unsigned more;    /* Amount of free space at the end of the window. */
+    uInt wsize = s->w_size;
+
+    do {
+        more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+        /* Deal with !@#$% 64K limit: */
+        if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+            more = wsize;
+
+        } else if (more == (unsigned)(-1)) {
+            /* Very unlikely, but possible on 16 bit machine if strstart == 0
+             * and lookahead == 1 (input done one byte at time)
+             */
+            more--;
+
+        /* If the window is almost full and there is insufficient lookahead,
+         * move the upper half to the lower one to make room in the upper half.
+         */
+        } else if (s->strstart >= wsize+MAX_DIST(s)) {
+
+            zmemcpy((charf *)s->window, (charf *)s->window+wsize,
+                   (unsigned)wsize);
+            s->match_start -= wsize;
+            s->strstart    -= wsize; /* we now have strstart >= MAX_DIST */
+            s->block_start -= (long) wsize;
+
+            /* Slide the hash table (could be avoided with 32 bit values
+               at the expense of memory usage). We slide even when level == 0
+               to keep the hash table consistent if we switch back to level > 0
+               later. (Using level 0 permanently is not an optimal usage of
+               zlib, so we don't care about this pathological case.)
+             */
+            n = s->hash_size;
+            p = &s->head[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+            } while (--n);
+
+            n = wsize;
+            p = &s->prev[n];
+            do {
+                m = *--p;
+                *p = (Pos)(m >= wsize ? m-wsize : NIL);
+                /* If n is not on any hash chain, prev[n] is garbage but
+                 * its value will never be used.
+                 */
+            } while (--n);
+            more += wsize;
+        }
+        if (s->strm->avail_in == 0) return;
+
+        /* If there was no sliding:
+         *    strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+         *    more == window_size - lookahead - strstart
+         * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+         * => more >= window_size - 2*WSIZE + 2
+         * In the BIG_MEM or MMAP case (not yet supported),
+         *   window_size == input_size + MIN_LOOKAHEAD  &&
+         *   strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+         * Otherwise, window_size == 2*WSIZE so more >= 2.
+         * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+         */
+        Assert(more >= 2, "more < 2");
+
+        n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead,
+                     more);
+        s->lookahead += n;
+
+        /* Initialize the hash value now that we have some input: */
+        if (s->lookahead >= MIN_MATCH) {
+            s->ins_h = s->window[s->strstart];
+            UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+            Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+        }
+        /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+         * but this is not important since only literal bytes will be emitted.
+         */
+
+    } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+   _tr_flush_block(s, (s->block_start >= 0L ? \
+                   (charf *)&s->window[(unsigned)s->block_start] : \
+                   (charf *)Z_NULL), \
+		(ulg)((long)s->strstart - s->block_start), \
+		(eof)); \
+   s->block_start = s->strstart; \
+   flush_pending(s->strm); \
+   Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+   FLUSH_BLOCK_ONLY(s, eof); \
+   if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+     * to pending_buf_size, and each stored block has a 5 byte header:
+     */
+    ulg max_block_size = 0xffff;
+    ulg max_start;
+
+    if (max_block_size > s->pending_buf_size - 5) {
+        max_block_size = s->pending_buf_size - 5;
+    }
+
+    /* Copy as much as possible from input to output: */
+    for (;;) {
+        /* Fill the window as much as possible: */
+        if (s->lookahead <= 1) {
+
+            Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+		   s->block_start >= (long)s->w_size, "slide too late");
+
+            fill_window(s);
+            if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+	Assert(s->block_start >= 0L, "block gone");
+
+	s->strstart += s->lookahead;
+	s->lookahead = 0;
+
+	/* Emit a stored block if pending_buf will be full: */
+ 	max_start = s->block_start + max_block_size;
+        if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+	    /* strstart == 0 is possible when wraparound on 16-bit machine */
+	    s->lookahead = (uInt)(s->strstart - max_start);
+	    s->strstart = (uInt)max_start;
+            FLUSH_BLOCK(s, 0);
+	}
+	/* Flush if we may have to slide, otherwise block_start may become
+         * negative and the data will be gone:
+         */
+        if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+            FLUSH_BLOCK(s, 0);
+	}
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL; /* head of the hash chain */
+    int bflush;           /* set if current block must be flushed */
+
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         * At this point we have always match_length < MIN_MATCH
+         */
+        if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+        }
+        if (s->match_length >= MIN_MATCH) {
+            check_match(s, s->strstart, s->match_start, s->match_length);
+
+            bflush = _tr_tally(s, s->strstart - s->match_start,
+                               s->match_length - MIN_MATCH);
+
+            s->lookahead -= s->match_length;
+
+            /* Insert new strings in the hash table only if the match length
+             * is not too large. This saves time but degrades compression.
+             */
+            if (s->match_length <= s->max_insert_length &&
+                s->lookahead >= MIN_MATCH) {
+                s->match_length--; /* string at strstart already in hash table */
+                do {
+                    s->strstart++;
+                    INSERT_STRING(s, s->strstart, hash_head);
+                    /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+                     * always MIN_MATCH bytes ahead.
+                     */
+                } while (--s->match_length != 0);
+                s->strstart++; 
+            } else {
+                s->strstart += s->match_length;
+                s->match_length = 0;
+                s->ins_h = s->window[s->strstart];
+                UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+                Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+                /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+                 * matter since it will be recomputed at next deflate call.
+                 */
+            }
+        } else {
+            /* No match, output a literal byte */
+            Tracevv((stderr,"%c", s->window[s->strstart]));
+            bflush = _tr_tally (s, 0, s->window[s->strstart]);
+            s->lookahead--;
+            s->strstart++; 
+        }
+        if (bflush) FLUSH_BLOCK(s, 0);
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+    deflate_state *s;
+    int flush;
+{
+    IPos hash_head = NIL;    /* head of hash chain */
+    int bflush;              /* set if current block must be flushed */
+
+    /* Process the input block. */
+    for (;;) {
+        /* Make sure that we always have enough lookahead, except
+         * at the end of the input file. We need MAX_MATCH bytes
+         * for the next match, plus MIN_MATCH bytes to insert the
+         * string following the next match.
+         */
+        if (s->lookahead < MIN_LOOKAHEAD) {
+            fill_window(s);
+            if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+	        return need_more;
+	    }
+            if (s->lookahead == 0) break; /* flush the current block */
+        }
+
+        /* Insert the string window[strstart .. strstart+2] in the
+         * dictionary, and set hash_head to the head of the hash chain:
+         */
+        if (s->lookahead >= MIN_MATCH) {
+            INSERT_STRING(s, s->strstart, hash_head);
+        }
+
+        /* Find the longest match, discarding those <= prev_length.
+         */
+        s->prev_length = s->match_length, s->prev_match = s->match_start;
+        s->match_length = MIN_MATCH-1;
+
+        if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+            s->strstart - hash_head <= MAX_DIST(s)) {
+            /* To simplify the code, we prevent matches with the string
+             * of window index 0 (in particular we have to avoid a match
+             * of the string with itself at the start of the input file).
+             */
+            if (s->strategy != Z_HUFFMAN_ONLY) {
+                s->match_length = longest_match (s, hash_head);
+            }
+            /* longest_match() sets match_start */
+
+            if (s->match_length <= 5 && (s->strategy == Z_FILTERED ||
+                 (s->match_length == MIN_MATCH &&
+                  s->strstart - s->match_start > TOO_FAR))) {
+
+                /* If prev_match is also MIN_MATCH, match_start is garbage
+                 * but we will ignore the current match anyway.
+                 */
+                s->match_length = MIN_MATCH-1;
+            }
+        }
+        /* If there was a match at the previous step and the current
+         * match is not better, output the previous match:
+         */
+        if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+            uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+            /* Do not insert strings in hash table beyond this. */
+
+            check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+            bflush = _tr_tally(s, s->strstart -1 - s->prev_match,
+                               s->prev_length - MIN_MATCH);
+
+            /* Insert in hash table all strings up to the end of the match.
+             * strstart-1 and strstart are already inserted. If there is not
+             * enough lookahead, the last two strings are not inserted in
+             * the hash table.
+             */
+            s->lookahead -= s->prev_length-1;
+            s->prev_length -= 2;
+            do {
+                if (++s->strstart <= max_insert) {
+                    INSERT_STRING(s, s->strstart, hash_head);
+                }
+            } while (--s->prev_length != 0);
+            s->match_available = 0;
+            s->match_length = MIN_MATCH-1;
+            s->strstart++;
+
+            if (bflush) FLUSH_BLOCK(s, 0);
+
+        } else if (s->match_available) {
+            /* If there was no match at the previous position, output a
+             * single literal. If there was a match but the current match
+             * is longer, truncate the previous match to a single literal.
+             */
+            Tracevv((stderr,"%c", s->window[s->strstart-1]));
+            if (_tr_tally (s, 0, s->window[s->strstart-1])) {
+                FLUSH_BLOCK_ONLY(s, 0);
+            }
+            s->strstart++;
+            s->lookahead--;
+            if (s->strm->avail_out == 0) return need_more;
+        } else {
+            /* There is no previous match to compare with, wait for
+             * the next step to decide.
+             */
+            s->match_available = 1;
+            s->strstart++;
+            s->lookahead--;
+        }
+    }
+    Assert (flush != Z_NO_FLUSH, "no flush?");
+    if (s->match_available) {
+        Tracevv((stderr,"%c", s->window[s->strstart-1]));
+        _tr_tally (s, 0, s->window[s->strstart-1]);
+        s->match_available = 0;
+    }
+    FLUSH_BLOCK(s, flush == Z_FINISH);
+    return flush == Z_FINISH ? finish_done : block_done;
+}
+/* --- deflate.c */
+
+/* +++ trees.c */
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-1996 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/*
+ *  ALGORITHM
+ *
+ *      The "deflation" process uses several Huffman trees. The more
+ *      common source values are represented by shorter bit sequences.
+ *
+ *      Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values).  The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ *  REFERENCES
+ *
+ *      Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ *      Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ *      Storer, James A.
+ *          Data Compression:  Methods and Theory, pp. 49-50.
+ *          Computer Science Press, 1988.  ISBN 0-7167-8156-5.
+ *
+ *      Sedgewick, R.
+ *          Algorithms, p290.
+ *          Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */
+
+/* #include "deflate.h" */
+
+#ifdef DEBUG_ZLIB
+#  include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6      16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10    17
+/* repeat a zero length 3-10 times  (3 bits of repeat count) */
+
+#define REPZ_11_138  18
+/* repeat a zero length 11-138 times  (7 bits of repeat count) */
+
+local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+   = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local int extra_dbits[D_CODES] /* extra bits for each distance code */
+   = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+   = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local uch bl_order[BL_CODES]
+   = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+local uch dist_code[512];
+/* distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+local uch length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+struct static_tree_desc_s {
+    ct_data *static_tree;        /* static tree or NULL */
+    intf    *extra_bits;         /* extra bits for each code or NULL */
+    int     extra_base;          /* base index for extra_bits */
+    int     elems;               /* max number of elements in the tree */
+    int     max_length;          /* max bit length for the codes */
+};
+
+local static_tree_desc  static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc  static_d_desc =
+{static_dtree, extra_dbits, 0,          D_CODES, MAX_BITS};
+
+local static_tree_desc  static_bl_desc =
+{(ct_data *)0, extra_blbits, 0,      BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block     OF((deflate_state *s));
+local void pqdownheap     OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen     OF((deflate_state *s, tree_desc *desc));
+local void gen_codes      OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree     OF((deflate_state *s, tree_desc *desc));
+local void scan_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree      OF((deflate_state *s, ct_data *tree, int max_code));
+local int  build_bl_tree  OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+                              int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+                              ct_data *dtree));
+local void set_data_type  OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup      OF((deflate_state *s));
+local void bi_flush       OF((deflate_state *s));
+local void copy_block     OF((deflate_state *s, charf *buf, unsigned len,
+                              int header));
+
+#ifndef DEBUG_ZLIB
+#  define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+   /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG_ZLIB */
+#  define send_code(s, c, tree) \
+     { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+       send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+#define d_code(dist) \
+   ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. dist_code[256] and dist_code[257] are never
+ * used.
+ */
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+    put_byte(s, (uch)((w) & 0xff)); \
+    put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG_ZLIB
+local void send_bits      OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+    deflate_state *s;
+    int value;  /* value to send */
+    int length; /* number of bits */
+{
+    Tracevv((stderr," l %2d v %4x ", length, value));
+    Assert(length > 0 && length <= 15, "invalid length");
+    s->bits_sent += (ulg)length;
+
+    /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+     * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+     * unused bits in value.
+     */
+    if (s->bi_valid > (int)Buf_size - length) {
+        s->bi_buf |= (value << s->bi_valid);
+        put_short(s, s->bi_buf);
+        s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+        s->bi_valid += length - Buf_size;
+    } else {
+        s->bi_buf |= value << s->bi_valid;
+        s->bi_valid += length;
+    }
+}
+#else /* !DEBUG_ZLIB */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+  if (s->bi_valid > (int)Buf_size - len) {\
+    int val = value;\
+    s->bi_buf |= (val << s->bi_valid);\
+    put_short(s, s->bi_buf);\
+    s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+    s->bi_valid += len - Buf_size;\
+  } else {\
+    s->bi_buf |= (value) << s->bi_valid;\
+    s->bi_valid += len;\
+  }\
+}
+#endif /* DEBUG_ZLIB */
+
+
+#define MAX(a,b) (a >= b ? a : b)
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables. In a multi-threaded environment,
+ * this function may be called by two threads concurrently, but this is
+ * harmless since both invocations do exactly the same thing.
+ */
+local void tr_static_init()
+{
+    static int static_init_done = 0;
+    int n;        /* iterates over tree elements */
+    int bits;     /* bit counter */
+    int length;   /* length value */
+    int code;     /* code value */
+    int dist;     /* distance index */
+    ush bl_count[MAX_BITS+1];
+    /* number of codes at each bit length for an optimal tree */
+
+    if (static_init_done) return;
+
+    /* Initialize the mapping length (0..255) -> length code (0..28) */
+    length = 0;
+    for (code = 0; code < LENGTH_CODES-1; code++) {
+        base_length[code] = length;
+        for (n = 0; n < (1<<extra_lbits[code]); n++) {
+            length_code[length++] = (uch)code;
+        }
+    }
+    Assert (length == 256, "tr_static_init: length != 256");
+    /* Note that the length 255 (match length 258) can be represented
+     * in two different ways: code 284 + 5 bits or code 285, so we
+     * overwrite length_code[255] to use the best encoding:
+     */
+    length_code[length-1] = (uch)code;
+
+    /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+    dist = 0;
+    for (code = 0 ; code < 16; code++) {
+        base_dist[code] = dist;
+        for (n = 0; n < (1<<extra_dbits[code]); n++) {
+            dist_code[dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: dist != 256");
+    dist >>= 7; /* from now on, all distances are divided by 128 */
+    for ( ; code < D_CODES; code++) {
+        base_dist[code] = dist << 7;
+        for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+            dist_code[256 + dist++] = (uch)code;
+        }
+    }
+    Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+    /* Construct the codes of the static literal tree */
+    for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+    n = 0;
+    while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+    while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+    while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+    while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+    /* Codes 286 and 287 do not exist, but we must include them in the
+     * tree construction to get a canonical Huffman tree (longest code
+     * all ones)
+     */
+    gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+    /* The static distance tree is trivial: */
+    for (n = 0; n < D_CODES; n++) {
+        static_dtree[n].Len = 5;
+        static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+    }
+    static_init_done = 1;
+}
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+    deflate_state *s;
+{
+    tr_static_init();
+
+    s->compressed_len = 0L;
+
+    s->l_desc.dyn_tree = s->dyn_ltree;
+    s->l_desc.stat_desc = &static_l_desc;
+
+    s->d_desc.dyn_tree = s->dyn_dtree;
+    s->d_desc.stat_desc = &static_d_desc;
+
+    s->bl_desc.dyn_tree = s->bl_tree;
+    s->bl_desc.stat_desc = &static_bl_desc;
+
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG_ZLIB
+    s->bits_sent = 0L;
+#endif
+
+    /* Initialize the first block of the first file: */
+    init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+    deflate_state *s;
+{
+    int n; /* iterates over tree elements */
+
+    /* Initialize the trees. */
+    for (n = 0; n < L_CODES;  n++) s->dyn_ltree[n].Freq = 0;
+    for (n = 0; n < D_CODES;  n++) s->dyn_dtree[n].Freq = 0;
+    for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+    s->dyn_ltree[END_BLOCK].Freq = 1;
+    s->opt_len = s->static_len = 0L;
+    s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+    top = s->heap[SMALLEST]; \
+    s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+    pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+   (tree[n].Freq < tree[m].Freq || \
+   (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+    deflate_state *s;
+    ct_data *tree;  /* the tree to restore */
+    int k;               /* node to move down */
+{
+    int v = s->heap[k];
+    int j = k << 1;  /* left son of k */
+    while (j <= s->heap_len) {
+        /* Set j to the smallest of the two sons: */
+        if (j < s->heap_len &&
+            smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+            j++;
+        }
+        /* Exit if v is smaller than both sons */
+        if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+        /* Exchange v with the smallest son */
+        s->heap[k] = s->heap[j];  k = j;
+
+        /* And continue down the tree, setting j to the left son of k */
+        j <<= 1;
+    }
+    s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ *    above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ *     array bl_count contains the frequencies for each bit length.
+ *     The length opt_len is updated; static_len is also updated if stree is
+ *     not null.
+ */
+local void gen_bitlen(s, desc)
+    deflate_state *s;
+    tree_desc *desc;    /* the tree descriptor */
+{
+    ct_data *tree  = desc->dyn_tree;
+    int max_code   = desc->max_code;
+    ct_data *stree = desc->stat_desc->static_tree;
+    intf *extra    = desc->stat_desc->extra_bits;
+    int base       = desc->stat_desc->extra_base;
+    int max_length = desc->stat_desc->max_length;
+    int h;              /* heap index */
+    int n, m;           /* iterate over the tree elements */
+    int bits;           /* bit length */
+    int xbits;          /* extra bits */
+    ush f;              /* frequency */
+    int overflow = 0;   /* number of elements with bit length too large */
+
+    for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+    /* In a first pass, compute the optimal bit lengths (which may
+     * overflow in the case of the bit length tree).
+     */
+    tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+    for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+        n = s->heap[h];
+        bits = tree[tree[n].Dad].Len + 1;
+        if (bits > max_length) bits = max_length, overflow++;
+        tree[n].Len = (ush)bits;
+        /* We overwrite tree[n].Dad which is no longer needed */
+
+        if (n > max_code) continue; /* not a leaf node */
+
+        s->bl_count[bits]++;
+        xbits = 0;
+        if (n >= base) xbits = extra[n-base];
+        f = tree[n].Freq;
+        s->opt_len += (ulg)f * (bits + xbits);
+        if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+    }
+    if (overflow == 0) return;
+
+    Trace((stderr,"\nbit length overflow\n"));
+    /* This happens for example on obj2 and pic of the Calgary corpus */
+
+    /* Find the first bit length which could increase: */
+    do {
+        bits = max_length-1;
+        while (s->bl_count[bits] == 0) bits--;
+        s->bl_count[bits]--;      /* move one leaf down the tree */
+        s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+        s->bl_count[max_length]--;
+        /* The brother of the overflow item also moves one step up,
+         * but this does not affect bl_count[max_length]
+         */
+        overflow -= 2;
+    } while (overflow > 0);
+
+    /* Now recompute all bit lengths, scanning in increasing frequency.
+     * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+     * lengths instead of fixing only the wrong ones. This idea is taken
+     * from 'ar' written by Haruhiko Okumura.)
+     */
+    for (bits = max_length; bits != 0; bits--) {
+        n = s->bl_count[bits];
+        while (n != 0) {
+            m = s->heap[--h];
+            if (m > max_code) continue;
+            if (tree[m].Len != (unsigned) bits) {
+                Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+                s->opt_len += ((long)bits - (long)tree[m].Len)
+                              *(long)tree[m].Freq;
+                tree[m].Len = (ush)bits;
+            }
+            n--;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ *     zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+    ct_data *tree;             /* the tree to decorate */
+    int max_code;              /* largest code with non zero frequency */
+    ushf *bl_count;            /* number of codes at each bit length */
+{
+    ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+    ush code = 0;              /* running code value */
+    int bits;                  /* bit index */
+    int n;                     /* code index */
+
+    /* The distribution counts are first used to generate the code values
+     * without bit reversal.
+     */
+    for (bits = 1; bits <= MAX_BITS; bits++) {
+        next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+    }
+    /* Check that the bit counts in bl_count are consistent. The last code
+     * must be all ones.
+     */
+    Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+            "inconsistent bit counts");
+    Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+    for (n = 0;  n <= max_code; n++) {
+        int len = tree[n].Len;
+        if (len == 0) continue;
+        /* Now reverse the bits */
+        tree[n].Code = bi_reverse(next_code[len]++, len);
+
+        Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+             n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+    }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ *     and corresponding code. The length opt_len is updated; static_len is
+ *     also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+    deflate_state *s;
+    tree_desc *desc; /* the tree descriptor */
+{
+    ct_data *tree   = desc->dyn_tree;
+    ct_data *stree  = desc->stat_desc->static_tree;
+    int elems       = desc->stat_desc->elems;
+    int n, m;          /* iterate over heap elements */
+    int max_code = -1; /* largest code with non zero frequency */
+    int node;          /* new node being created */
+
+    /* Construct the initial heap, with least frequent element in
+     * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+     * heap[0] is not used.
+     */
+    s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+    for (n = 0; n < elems; n++) {
+        if (tree[n].Freq != 0) {
+            s->heap[++(s->heap_len)] = max_code = n;
+            s->depth[n] = 0;
+        } else {
+            tree[n].Len = 0;
+        }
+    }
+
+    /* The pkzip format requires that at least one distance code exists,
+     * and that at least one bit should be sent even if there is only one
+     * possible code. So to avoid special checks later on we force at least
+     * two codes of non zero frequency.
+     */
+    while (s->heap_len < 2) {
+        node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+        tree[node].Freq = 1;
+        s->depth[node] = 0;
+        s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+        /* node is 0 or 1 so it does not have extra bits */
+    }
+    desc->max_code = max_code;
+
+    /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+     * establish sub-heaps of increasing lengths:
+     */
+    for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+    /* Construct the Huffman tree by repeatedly combining the least two
+     * frequent nodes.
+     */
+    node = elems;              /* next internal node of the tree */
+    do {
+        pqremove(s, tree, n);  /* n = node of least frequency */
+        m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+        s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+        s->heap[--(s->heap_max)] = m;
+
+        /* Create a new node father of n and m */
+        tree[node].Freq = tree[n].Freq + tree[m].Freq;
+        s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1);
+        tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+        if (tree == s->bl_tree) {
+            fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+                    node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+        }
+#endif
+        /* and insert the new node in the heap */
+        s->heap[SMALLEST] = node++;
+        pqdownheap(s, tree, SMALLEST);
+
+    } while (s->heap_len >= 2);
+
+    s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+    /* At this point, the fields freq and dad are set. We can now
+     * generate the bit lengths.
+     */
+    gen_bitlen(s, (tree_desc *)desc);
+
+    /* The field len is now set, we can generate the bit codes */
+    gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree;   /* the tree to be scanned */
+    int max_code;    /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    if (nextlen == 0) max_count = 138, min_count = 3;
+    tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            s->bl_tree[curlen].Freq += count;
+        } else if (curlen != 0) {
+            if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+            s->bl_tree[REP_3_6].Freq++;
+        } else if (count <= 10) {
+            s->bl_tree[REPZ_3_10].Freq++;
+        } else {
+            s->bl_tree[REPZ_11_138].Freq++;
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+    deflate_state *s;
+    ct_data *tree; /* the tree to be scanned */
+    int max_code;       /* and its largest code of non zero frequency */
+{
+    int n;                     /* iterates over all tree elements */
+    int prevlen = -1;          /* last emitted length */
+    int curlen;                /* length of current code */
+    int nextlen = tree[0].Len; /* length of next code */
+    int count = 0;             /* repeat count of the current code */
+    int max_count = 7;         /* max repeat count */
+    int min_count = 4;         /* min repeat count */
+
+    /* tree[max_code+1].Len = -1; */  /* guard already set */
+    if (nextlen == 0) max_count = 138, min_count = 3;
+
+    for (n = 0; n <= max_code; n++) {
+        curlen = nextlen; nextlen = tree[n+1].Len;
+        if (++count < max_count && curlen == nextlen) {
+            continue;
+        } else if (count < min_count) {
+            do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+        } else if (curlen != 0) {
+            if (curlen != prevlen) {
+                send_code(s, curlen, s->bl_tree); count--;
+            }
+            Assert(count >= 3 && count <= 6, " 3_6?");
+            send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+        } else if (count <= 10) {
+            send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+        } else {
+            send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+        }
+        count = 0; prevlen = curlen;
+        if (nextlen == 0) {
+            max_count = 138, min_count = 3;
+        } else if (curlen == nextlen) {
+            max_count = 6, min_count = 3;
+        } else {
+            max_count = 7, min_count = 4;
+        }
+    }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+    deflate_state *s;
+{
+    int max_blindex;  /* index of last bit length code of non zero freq */
+
+    /* Determine the bit length frequencies for literal and distance trees */
+    scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+    scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+    /* Build the bit length tree: */
+    build_tree(s, (tree_desc *)(&(s->bl_desc)));
+    /* opt_len now includes the length of the tree representations, except
+     * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+     */
+
+    /* Determine the number of bit length codes to send. The pkzip format
+     * requires that at least 4 bit length codes be sent. (appnote.txt says
+     * 3 but the actual value used is 4.)
+     */
+    for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+        if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+    }
+    /* Update opt_len to include the bit length tree and counts */
+    s->opt_len += 3*(max_blindex+1) + 5+5+4;
+    Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+            s->opt_len, s->static_len));
+
+    return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+    deflate_state *s;
+    int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+    int rank;                    /* index in bl_order */
+
+    Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+    Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+            "too many codes");
+    Tracev((stderr, "\nbl counts: "));
+    send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+    send_bits(s, dcodes-1,   5);
+    send_bits(s, blcodes-4,  4); /* not -3 as stated in appnote.txt */
+    for (rank = 0; rank < blcodes; rank++) {
+        Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+        send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+    }
+    Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+    Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+    send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+    Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    send_bits(s, (STORED_BLOCK<<1)+eof, 3);  /* send block type */
+    s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+    s->compressed_len += (stored_len + 4) << 3;
+
+    copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* Send just the `stored block' type code without any length bytes or data.
+ */
+void _tr_stored_type_only(s)
+    deflate_state *s;
+{
+    send_bits(s, (STORED_BLOCK << 1), 3);
+    bi_windup(s);
+    s->compressed_len = (s->compressed_len + 3) & ~7L;
+}
+
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+    deflate_state *s;
+{
+    send_bits(s, STATIC_TREES<<1, 3);
+    send_code(s, END_BLOCK, static_ltree);
+    s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+    bi_flush(s);
+    /* Of the 10 bits for the empty block, we have already sent
+     * (10 - bi_valid) bits. The lookahead for the last real code (before
+     * the EOB of the previous block) was thus at least one plus the length
+     * of the EOB plus what we have just sent of the empty static block.
+     */
+    if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+        send_bits(s, STATIC_TREES<<1, 3);
+        send_code(s, END_BLOCK, static_ltree);
+        s->compressed_len += 10L;
+        bi_flush(s);
+    }
+    s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file. This function
+ * returns the total compressed length for the file so far.
+ */
+ulg _tr_flush_block(s, buf, stored_len, eof)
+    deflate_state *s;
+    charf *buf;       /* input block, or NULL if too old */
+    ulg stored_len;   /* length of input block */
+    int eof;          /* true if this is the last block for a file */
+{
+    ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+    int max_blindex = 0;  /* index of last bit length code of non zero freq */
+
+    /* Build the Huffman trees unless a stored block is forced */
+    if (s->level > 0) {
+
+	 /* Check if the file is ascii or binary */
+	if (s->data_type == Z_UNKNOWN) set_data_type(s);
+
+	/* Construct the literal and distance trees */
+	build_tree(s, (tree_desc *)(&(s->l_desc)));
+	Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+
+	build_tree(s, (tree_desc *)(&(s->d_desc)));
+	Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+		s->static_len));
+	/* At this point, opt_len and static_len are the total bit lengths of
+	 * the compressed block data, excluding the tree representations.
+	 */
+
+	/* Build the bit length tree for the above two trees, and get the index
+	 * in bl_order of the last bit length code to send.
+	 */
+	max_blindex = build_bl_tree(s);
+
+	/* Determine the best encoding. Compute first the block length in bytes*/
+	opt_lenb = (s->opt_len+3+7)>>3;
+	static_lenb = (s->static_len+3+7)>>3;
+
+	Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+		opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+		s->last_lit));
+
+	if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+    } else {
+        Assert(buf != (char*)0, "lost buf");
+	opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+    }
+
+    /* If compression failed and this is the first and last block,
+     * and if the .zip file can be seeked (to rewrite the local header),
+     * the whole file is transformed into a stored file:
+     */
+#ifdef STORED_FILE_OK
+#  ifdef FORCE_STORED_FILE
+    if (eof && s->compressed_len == 0L) { /* force stored file */
+#  else
+    if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) {
+#  endif
+        /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */
+        if (buf == (charf*)0) error ("block vanished");
+
+        copy_block(s, buf, (unsigned)stored_len, 0); /* without header */
+        s->compressed_len = stored_len << 3;
+        s->method = STORED;
+    } else
+#endif /* STORED_FILE_OK */
+
+#ifdef FORCE_STORED
+    if (buf != (char*)0) { /* force stored block */
+#else
+    if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+                       /* 4: two words for the lengths */
+#endif
+        /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+         * Otherwise we can't have processed more than WSIZE input bytes since
+         * the last block flush, because compression would have been
+         * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+         * transform a block into a stored block.
+         */
+        _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+    } else if (static_lenb >= 0) { /* force static trees */
+#else
+    } else if (static_lenb == opt_lenb) {
+#endif
+        send_bits(s, (STATIC_TREES<<1)+eof, 3);
+        compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+        s->compressed_len += 3 + s->static_len;
+    } else {
+        send_bits(s, (DYN_TREES<<1)+eof, 3);
+        send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+                       max_blindex+1);
+        compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+        s->compressed_len += 3 + s->opt_len;
+    }
+    Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+    init_block(s);
+
+    if (eof) {
+        bi_windup(s);
+        s->compressed_len += 7;  /* align on byte boundary */
+    }
+    Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+           s->compressed_len-7*eof));
+
+    return s->compressed_len >> 3;
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+    deflate_state *s;
+    unsigned dist;  /* distance of matched string */
+    unsigned lc;    /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+    s->d_buf[s->last_lit] = (ush)dist;
+    s->l_buf[s->last_lit++] = (uch)lc;
+    if (dist == 0) {
+        /* lc is the unmatched char */
+        s->dyn_ltree[lc].Freq++;
+    } else {
+        s->matches++;
+        /* Here, lc is the match length - MIN_MATCH */
+        dist--;             /* dist = match distance - 1 */
+        Assert((ush)dist < (ush)MAX_DIST(s) &&
+               (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+               (ush)d_code(dist) < (ush)D_CODES,  "_tr_tally: bad match");
+
+        s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++;
+        s->dyn_dtree[d_code(dist)].Freq++;
+    }
+
+    /* Try to guess if it is profitable to stop the current block here */
+    if (s->level > 2 && (s->last_lit & 0xfff) == 0) {
+        /* Compute an upper bound for the compressed length */
+        ulg out_length = (ulg)s->last_lit*8L;
+        ulg in_length = (ulg)((long)s->strstart - s->block_start);
+        int dcode;
+        for (dcode = 0; dcode < D_CODES; dcode++) {
+            out_length += (ulg)s->dyn_dtree[dcode].Freq *
+                (5L+extra_dbits[dcode]);
+        }
+        out_length >>= 3;
+        Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+               s->last_lit, in_length, out_length,
+               100L - out_length*100L/in_length));
+        if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+    }
+    return (s->last_lit == s->lit_bufsize-1);
+    /* We avoid equality with lit_bufsize because of wraparound at 64K
+     * on 16 bit machines and because stored blocks are restricted to
+     * 64K-1 bytes.
+     */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+    deflate_state *s;
+    ct_data *ltree; /* literal tree */
+    ct_data *dtree; /* distance tree */
+{
+    unsigned dist;      /* distance of matched string */
+    int lc;             /* match length or unmatched char (if dist == 0) */
+    unsigned lx = 0;    /* running index in l_buf */
+    unsigned code;      /* the code to send */
+    int extra;          /* number of extra bits to send */
+
+    if (s->last_lit != 0) do {
+        dist = s->d_buf[lx];
+        lc = s->l_buf[lx++];
+        if (dist == 0) {
+            send_code(s, lc, ltree); /* send a literal byte */
+            Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+        } else {
+            /* Here, lc is the match length - MIN_MATCH */
+            code = length_code[lc];
+            send_code(s, code+LITERALS+1, ltree); /* send the length code */
+            extra = extra_lbits[code];
+            if (extra != 0) {
+                lc -= base_length[code];
+                send_bits(s, lc, extra);       /* send the extra length bits */
+            }
+            dist--; /* dist is now the match distance - 1 */
+            code = d_code(dist);
+            Assert (code < D_CODES, "bad d_code");
+
+            send_code(s, code, dtree);       /* send the distance code */
+            extra = extra_dbits[code];
+            if (extra != 0) {
+                dist -= base_dist[code];
+                send_bits(s, dist, extra);   /* send the extra distance bits */
+            }
+        } /* literal or match pair ? */
+
+        /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+        Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow");
+
+    } while (lx < s->last_lit);
+
+    send_code(s, END_BLOCK, ltree);
+    s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to ASCII or BINARY, using a crude approximation:
+ * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise.
+ * IN assertion: the fields freq of dyn_ltree are set and the total of all
+ * frequencies does not exceed 64K (to fit in an int on 16 bit machines).
+ */
+local void set_data_type(s)
+    deflate_state *s;
+{
+    int n = 0;
+    unsigned ascii_freq = 0;
+    unsigned bin_freq = 0;
+    while (n < 7)        bin_freq += s->dyn_ltree[n++].Freq;
+    while (n < 128)    ascii_freq += s->dyn_ltree[n++].Freq;
+    while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq;
+    s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII);
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+    unsigned code; /* the value to invert */
+    int len;       /* its bit length */
+{
+    register unsigned res = 0;
+    do {
+        res |= code & 1;
+        code >>= 1, res <<= 1;
+    } while (--len > 0);
+    return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+    deflate_state *s;
+{
+    if (s->bi_valid == 16) {
+        put_short(s, s->bi_buf);
+        s->bi_buf = 0;
+        s->bi_valid = 0;
+    } else if (s->bi_valid >= 8) {
+        put_byte(s, (Byte)s->bi_buf);
+        s->bi_buf >>= 8;
+        s->bi_valid -= 8;
+    }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+    deflate_state *s;
+{
+    if (s->bi_valid > 8) {
+        put_short(s, s->bi_buf);
+    } else if (s->bi_valid > 0) {
+        put_byte(s, (Byte)s->bi_buf);
+    }
+    s->bi_buf = 0;
+    s->bi_valid = 0;
+#ifdef DEBUG_ZLIB
+    s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+    deflate_state *s;
+    charf    *buf;    /* the input data */
+    unsigned len;     /* its length */
+    int      header;  /* true if block header must be written */
+{
+    bi_windup(s);        /* align on byte boundary */
+    s->last_eob_len = 8; /* enough lookahead for inflate */
+
+    if (header) {
+        put_short(s, (ush)len);   
+        put_short(s, (ush)~len);
+#ifdef DEBUG_ZLIB
+        s->bits_sent += 2*16;
+#endif
+    }
+#ifdef DEBUG_ZLIB
+    s->bits_sent += (ulg)len<<3;
+#endif
+    /* bundle up the put_byte(s, *buf++) calls */
+    zmemcpy(&s->pending_buf[s->pending], buf, len);
+    s->pending += len;
+}
+/* --- trees.c */
+
+/* +++ inflate.c */
+/* inflate.c -- zlib interface to inflate modules
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+
+/* +++ infblock.h */
+/* infblock.h -- header to use infblock.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_blocks_state;
+typedef struct inflate_blocks_state FAR inflate_blocks_statef;
+
+extern inflate_blocks_statef * inflate_blocks_new OF((
+    z_streamp z,
+    check_func c,               /* check function */
+    uInt w));                   /* window size */
+
+extern int inflate_blocks OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));                      /* initial return code */
+
+extern void inflate_blocks_reset OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern int inflate_blocks_free OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    uLongf *));                  /* check value on output */
+
+extern void inflate_set_dictionary OF((
+    inflate_blocks_statef *s,
+    const Bytef *d,  /* dictionary */
+    uInt  n));       /* dictionary length */
+
+extern int inflate_addhistory OF((
+    inflate_blocks_statef *,
+    z_streamp));
+
+extern int inflate_packet_flush OF((
+    inflate_blocks_statef *));
+/* --- infblock.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_blocks_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* inflate private state */
+struct internal_state {
+
+  /* mode */
+  enum {
+      METHOD,   /* waiting for method byte */
+      FLAG,     /* waiting for flag byte */
+      DICT4,    /* four dictionary check bytes to go */
+      DICT3,    /* three dictionary check bytes to go */
+      DICT2,    /* two dictionary check bytes to go */
+      DICT1,    /* one dictionary check byte to go */
+      DICT0,    /* waiting for inflateSetDictionary */
+      BLOCKS,   /* decompressing blocks */
+      CHECK4,   /* four check bytes to go */
+      CHECK3,   /* three check bytes to go */
+      CHECK2,   /* two check bytes to go */
+      CHECK1,   /* one check byte to go */
+      DONE,     /* finished check, done */
+      BAD}      /* got an error--stay here */
+    mode;               /* current inflate mode */
+
+  /* mode dependent information */
+  union {
+    uInt method;        /* if FLAGS, method byte */
+    struct {
+      uLong was;                /* computed check value */
+      uLong need;               /* stream check value */
+    } check;            /* if CHECK, check values to compare */
+    uInt marker;        /* if BAD, inflateSync's marker bytes count */
+  } sub;        /* submode */
+
+  /* mode independent information */
+  int  nowrap;          /* flag for no wrapper */
+  uInt wbits;           /* log2(window size)  (8..15, defaults to 15) */
+  inflate_blocks_statef 
+    *blocks;            /* current inflate_blocks state */
+
+};
+
+
+int inflateReset(z)
+z_streamp z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->total_in = z->total_out = 0;
+  z->msg = Z_NULL;
+  z->state->mode = z->state->nowrap ? BLOCKS : METHOD;
+  inflate_blocks_reset(z->state->blocks, z, &c);
+  Trace((stderr, "inflate: reset\n"));
+  return Z_OK;
+}
+
+
+int inflateEnd(z)
+z_streamp z;
+{
+  uLong c;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->blocks != Z_NULL)
+    inflate_blocks_free(z->state->blocks, z, &c);
+  ZFREE(z, z->state);
+  z->state = Z_NULL;
+  Trace((stderr, "inflate: end\n"));
+  return Z_OK;
+}
+
+
+int inflateInit2_(z, w, version, stream_size)
+z_streamp z;
+int w;
+const char *version;
+int stream_size;
+{
+  if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+      stream_size != sizeof(z_stream))
+      return Z_VERSION_ERROR;
+
+  /* initialize state */
+  if (z == Z_NULL)
+    return Z_STREAM_ERROR;
+  z->msg = Z_NULL;
+#ifndef NO_ZCFUNCS
+  if (z->zalloc == Z_NULL)
+  {
+    z->zalloc = zcalloc;
+    z->opaque = (voidpf)0;
+  }
+  if (z->zfree == Z_NULL) z->zfree = zcfree;
+#endif
+  if ((z->state = (struct internal_state FAR *)
+       ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL)
+    return Z_MEM_ERROR;
+  z->state->blocks = Z_NULL;
+
+  /* handle undocumented nowrap option (no zlib header or check) */
+  z->state->nowrap = 0;
+  if (w < 0)
+  {
+    w = - w;
+    z->state->nowrap = 1;
+  }
+
+  /* set window size */
+  if (w < 8 || w > 15)
+  {
+    inflateEnd(z);
+    return Z_STREAM_ERROR;
+  }
+  z->state->wbits = (uInt)w;
+
+  /* create inflate_blocks state */
+  if ((z->state->blocks =
+      inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w))
+      == Z_NULL)
+  {
+    inflateEnd(z);
+    return Z_MEM_ERROR;
+  }
+  Trace((stderr, "inflate: allocated\n"));
+
+  /* reset state */
+  inflateReset(z);
+  return Z_OK;
+}
+
+
+int inflateInit_(z, version, stream_size)
+z_streamp z;
+const char *version;
+int stream_size;
+{
+  return inflateInit2_(z, DEF_WBITS, version, stream_size);
+}
+
+
+#define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;}
+#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++)
+
+int inflate(z, f)
+z_streamp z;
+int f;
+{
+  int r;
+  uInt b;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0)
+    return Z_STREAM_ERROR;
+  r = Z_BUF_ERROR;
+  while (1) switch (z->state->mode)
+  {
+    case METHOD:
+      NEEDBYTE
+      if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"unknown compression method";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      if ((z->state->sub.method >> 4) + 8 > z->state->wbits)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"invalid window size";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      z->state->mode = FLAG;
+    case FLAG:
+      NEEDBYTE
+      b = NEXTBYTE;
+      if (((z->state->sub.method << 8) + b) % 31)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect header check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib header ok\n"));
+      if (!(b & PRESET_DICT))
+      {
+        z->state->mode = BLOCKS;
+	break;
+      }
+      z->state->mode = DICT4;
+    case DICT4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = DICT3;
+    case DICT3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = DICT2;
+    case DICT2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = DICT1;
+    case DICT1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+      z->adler = z->state->sub.check.need;
+      z->state->mode = DICT0;
+      return Z_NEED_DICT;
+    case DICT0:
+      z->state->mode = BAD;
+      z->msg = (char*)"need dictionary";
+      z->state->sub.marker = 0;       /* can try inflateSync */
+      return Z_STREAM_ERROR;
+    case BLOCKS:
+      r = inflate_blocks(z->state->blocks, z, r);
+      if (f == Z_PACKET_FLUSH && z->avail_in == 0 && z->avail_out != 0)
+	  r = inflate_packet_flush(z->state->blocks);
+      if (r == Z_DATA_ERROR)
+      {
+        z->state->mode = BAD;
+        z->state->sub.marker = 0;       /* can try inflateSync */
+        break;
+      }
+      if (r != Z_STREAM_END)
+        return r;
+      r = Z_OK;
+      inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was);
+      if (z->state->nowrap)
+      {
+        z->state->mode = DONE;
+        break;
+      }
+      z->state->mode = CHECK4;
+    case CHECK4:
+      NEEDBYTE
+      z->state->sub.check.need = (uLong)NEXTBYTE << 24;
+      z->state->mode = CHECK3;
+    case CHECK3:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 16;
+      z->state->mode = CHECK2;
+    case CHECK2:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE << 8;
+      z->state->mode = CHECK1;
+    case CHECK1:
+      NEEDBYTE
+      z->state->sub.check.need += (uLong)NEXTBYTE;
+
+      if (z->state->sub.check.was != z->state->sub.check.need)
+      {
+        z->state->mode = BAD;
+        z->msg = (char*)"incorrect data check";
+        z->state->sub.marker = 5;       /* can't try inflateSync */
+        break;
+      }
+      Trace((stderr, "inflate: zlib check ok\n"));
+      z->state->mode = DONE;
+    case DONE:
+      return Z_STREAM_END;
+    case BAD:
+      return Z_DATA_ERROR;
+    default:
+      return Z_STREAM_ERROR;
+  }
+
+ empty:
+  if (f != Z_PACKET_FLUSH)
+    return r;
+  z->state->mode = BAD;
+  z->msg = (char *)"need more for packet flush";
+  z->state->sub.marker = 0;       /* can try inflateSync */
+  return Z_DATA_ERROR;
+}
+
+
+int inflateSetDictionary(z, dictionary, dictLength)
+z_streamp z;
+const Bytef *dictionary;
+uInt  dictLength;
+{
+  uInt length = dictLength;
+
+  if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0)
+    return Z_STREAM_ERROR;
+
+  if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR;
+  z->adler = 1L;
+
+  if (length >= ((uInt)1<<z->state->wbits))
+  {
+    length = (1<<z->state->wbits)-1;
+    dictionary += dictLength - length;
+  }
+  inflate_set_dictionary(z->state->blocks, dictionary, length);
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+
+int inflateIncomp(z)
+z_stream *z;
+{
+    if (z->state->mode != BLOCKS)
+	return Z_DATA_ERROR;
+    return inflate_addhistory(z->state->blocks, z);
+}
+
+
+int inflateSync(z)
+z_streamp z;
+{
+  uInt n;       /* number of bytes to look at */
+  Bytef *p;     /* pointer to bytes */
+  uInt m;       /* number of marker bytes found in a row */
+  uLong r, w;   /* temporaries to save total_in and total_out */
+
+  /* set up */
+  if (z == Z_NULL || z->state == Z_NULL)
+    return Z_STREAM_ERROR;
+  if (z->state->mode != BAD)
+  {
+    z->state->mode = BAD;
+    z->state->sub.marker = 0;
+  }
+  if ((n = z->avail_in) == 0)
+    return Z_BUF_ERROR;
+  p = z->next_in;
+  m = z->state->sub.marker;
+
+  /* search */
+  while (n && m < 4)
+  {
+    if (*p == (Byte)(m < 2 ? 0 : 0xff))
+      m++;
+    else if (*p)
+      m = 0;
+    else
+      m = 4 - m;
+    p++, n--;
+  }
+
+  /* restore */
+  z->total_in += p - z->next_in;
+  z->next_in = p;
+  z->avail_in = n;
+  z->state->sub.marker = m;
+
+  /* return no joy or set up to restart on a new block */
+  if (m != 4)
+    return Z_DATA_ERROR;
+  r = z->total_in;  w = z->total_out;
+  inflateReset(z);
+  z->total_in = r;  z->total_out = w;
+  z->state->mode = BLOCKS;
+  return Z_OK;
+}
+
+#undef NEEDBYTE
+#undef NEXTBYTE
+/* --- inflate.c */
+
+/* +++ infblock.c */
+/* infblock.c -- interpret and process block types to last block
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+
+/* +++ inftrees.h */
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+/* Huffman code lookup table entry--this entry is four bytes for machines
+   that have 16-bit pointers (e.g. PC's in the small or medium model). */
+
+typedef struct inflate_huft_s FAR inflate_huft;
+
+struct inflate_huft_s {
+  union {
+    struct {
+      Byte Exop;        /* number of extra bits or operation */
+      Byte Bits;        /* number of bits in this code or subcode */
+    } what;
+    Bytef *pad;         /* pad structure to a power of 2 (4 bytes for */
+  } word;               /*  16-bit, 8 bytes for 32-bit machines) */
+  union {
+    uInt Base;          /* literal, length base, or distance base */
+    inflate_huft *Next; /* pointer to next level of table */
+  } more;
+};
+
+#ifdef DEBUG_ZLIB
+  extern uInt inflate_hufts;
+#endif
+
+extern int inflate_trees_bits OF((
+    uIntf *,                    /* 19 code lengths */
+    uIntf *,                    /* bits tree desired/actual depth */
+    inflate_huft * FAR *,       /* bits tree result */
+    z_streamp ));               /* for zalloc, zfree functions */
+
+extern int inflate_trees_dynamic OF((
+    uInt,                       /* number of literal/length codes */
+    uInt,                       /* number of distance codes */
+    uIntf *,                    /* that many (total) code lengths */
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *,       /* distance tree result */
+    z_streamp ));               /* for zalloc, zfree functions */
+
+extern int inflate_trees_fixed OF((
+    uIntf *,                    /* literal desired/actual bit depth */
+    uIntf *,                    /* distance desired/actual bit depth */
+    inflate_huft * FAR *,       /* literal/length tree result */
+    inflate_huft * FAR *));     /* distance tree result */
+
+extern int inflate_trees_free OF((
+    inflate_huft *,             /* tables to free */
+    z_streamp ));               /* for zfree function */
+
+/* --- inftrees.h */
+
+/* +++ infcodes.h */
+/* infcodes.h -- header to use infcodes.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+struct inflate_codes_state;
+typedef struct inflate_codes_state FAR inflate_codes_statef;
+
+extern inflate_codes_statef *inflate_codes_new OF((
+    uInt, uInt,
+    inflate_huft *, inflate_huft *,
+    z_streamp ));
+
+extern int inflate_codes OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+extern void inflate_codes_free OF((
+    inflate_codes_statef *,
+    z_streamp ));
+
+/* --- infcodes.h */
+
+/* +++ infutil.h */
+/* infutil.h -- types and macros common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+#ifndef _INFUTIL_H
+#define _INFUTIL_H
+
+typedef enum {
+      TYPE,     /* get type bits (3, including end bit) */
+      LENS,     /* get lengths for stored */
+      STORED,   /* processing stored block */
+      TABLE,    /* get table lengths */
+      BTREE,    /* get bit lengths tree for a dynamic block */
+      DTREE,    /* get length, distance trees for a dynamic block */
+      CODES,    /* processing fixed or dynamic block */
+      DRY,      /* output remaining window bytes */
+      DONEB,    /* finished last block, done */
+      BADB}     /* got a data error--stuck here */
+inflate_block_mode;
+
+/* inflate blocks semi-private state */
+struct inflate_blocks_state {
+
+  /* mode */
+  inflate_block_mode  mode;     /* current inflate_block mode */
+
+  /* mode dependent information */
+  union {
+    uInt left;          /* if STORED, bytes left to copy */
+    struct {
+      uInt table;               /* table lengths (14 bits) */
+      uInt index;               /* index into blens (or border) */
+      uIntf *blens;             /* bit lengths of codes */
+      uInt bb;                  /* bit length tree depth */
+      inflate_huft *tb;         /* bit length decoding tree */
+    } trees;            /* if DTREE, decoding info for trees */
+    struct {
+      inflate_huft *tl;
+      inflate_huft *td;         /* trees to free */
+      inflate_codes_statef 
+         *codes;
+    } decode;           /* if CODES, current state */
+  } sub;                /* submode */
+  uInt last;            /* true if this block is the last block */
+
+  /* mode independent information */
+  uInt bitk;            /* bits in bit buffer */
+  uLong bitb;           /* bit buffer */
+  Bytef *window;        /* sliding window */
+  Bytef *end;           /* one byte after sliding window */
+  Bytef *read;          /* window read pointer */
+  Bytef *write;         /* window write pointer */
+  check_func checkfn;   /* check function */
+  uLong check;          /* check on output */
+
+};
+
+
+/* defines for inflate input/output */
+/*   update pointers and return */
+#define UPDBITS {s->bitb=b;s->bitk=k;}
+#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;}
+#define UPDOUT {s->write=q;}
+#define UPDATE {UPDBITS UPDIN UPDOUT}
+#define LEAVE {UPDATE return inflate_flush(s,z,r);}
+/*   get bytes and bits */
+#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;}
+#define NEEDBYTE {if(n)r=Z_OK;else LEAVE}
+#define NEXTBYTE (n--,*p++)
+#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define DUMPBITS(j) {b>>=(j);k-=(j);}
+/*   output bytes */
+#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q)
+#define LOADOUT {q=s->write;m=(uInt)WAVAIL;}
+#define WWRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}}
+#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT}
+#define NEEDOUT {if(m==0){WWRAP if(m==0){FLUSH WWRAP if(m==0) LEAVE}}r=Z_OK;}
+#define OUTBYTE(a) {*q++=(Byte)(a);m--;}
+/*   load local pointers */
+#define LOAD {LOADIN LOADOUT}
+
+/* masks for lower bits (size given to avoid silly warnings with Visual C++) */
+extern uInt inflate_mask[17];
+
+/* copy as much as possible from the sliding window to the output area */
+extern int inflate_flush OF((
+    inflate_blocks_statef *,
+    z_streamp ,
+    int));
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+#endif
+/* --- infutil.h */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* Table for deflate from PKZIP's appnote.txt. */
+local const uInt border[] = { /* Order of the bit length code lengths */
+        16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+/*
+   Notes beyond the 1.93a appnote.txt:
+
+   1. Distance pointers never point before the beginning of the output
+      stream.
+   2. Distance pointers can point back across blocks, up to 32k away.
+   3. There is an implied maximum of 7 bits for the bit length table and
+      15 bits for the actual data.
+   4. If only one code exists, then it is encoded using one bit.  (Zero
+      would be more efficient, but perhaps a little confusing.)  If two
+      codes exist, they are coded using one bit each (0 and 1).
+   5. There is no way of sending zero distance codes--a dummy must be
+      sent if there are none.  (History: a pre 2.0 version of PKZIP would
+      store blocks with no distance codes, but this was discovered to be
+      too harsh a criterion.)  Valid only for 1.93a.  2.04c does allow
+      zero distance codes, which is sent as one code of zero bits in
+      length.
+   6. There are up to 286 literal/length codes.  Code 256 represents the
+      end-of-block.  Note however that the static length tree defines
+      288 codes just to fill out the Huffman codes.  Codes 286 and 287
+      cannot be used though, since there is no length base or extra bits
+      defined for them.  Similarily, there are up to 30 distance codes.
+      However, static trees define 32 codes (all 5 bits) to fill out the
+      Huffman codes, but the last two had better not show up in the data.
+   7. Unzip can check dynamic Huffman blocks for complete code sets.
+      The exception is that a single code would not be complete (see #4).
+   8. The five bits following the block type is really the number of
+      literal codes sent minus 257.
+   9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits
+      (1+6+6).  Therefore, to output three times the length, you output
+      three codes (1+1+1), whereas to output four times the same length,
+      you only need two codes (1+3).  Hmm.
+  10. In the tree reconstruction algorithm, Code = Code + Increment
+      only if BitLength(i) is not zero.  (Pretty obvious.)
+  11. Correction: 4 Bits: # of Bit Length codes - 4     (4 - 19)
+  12. Note: length code 284 can represent 227-258, but length code 285
+      really is 258.  The last length deserves its own, short code
+      since it gets used a lot in very redundant files.  The length
+      258 is special since 258 - 3 (the min match length) is 255.
+  13. The literal/length and distance code bit lengths are read as a
+      single stream of lengths.  It is possible (and advantageous) for
+      a repeat code (16, 17, or 18) to go across the boundary between
+      the two sets of lengths.
+ */
+
+
+void inflate_blocks_reset(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  if (s->checkfn != Z_NULL)
+    *c = s->check;
+  if (s->mode == BTREE || s->mode == DTREE)
+    ZFREE(z, s->sub.trees.blens);
+  if (s->mode == CODES)
+  {
+    inflate_codes_free(s->sub.decode.codes, z);
+    inflate_trees_free(s->sub.decode.td, z);
+    inflate_trees_free(s->sub.decode.tl, z);
+  }
+  s->mode = TYPE;
+  s->bitk = 0;
+  s->bitb = 0;
+  s->read = s->write = s->window;
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0);
+  Trace((stderr, "inflate:   blocks reset\n"));
+}
+
+
+inflate_blocks_statef *inflate_blocks_new(z, c, w)
+z_streamp z;
+check_func c;
+uInt w;
+{
+  inflate_blocks_statef *s;
+
+  if ((s = (inflate_blocks_statef *)ZALLOC
+       (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL)
+    return s;
+  if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL)
+  {
+    ZFREE(z, s);
+    return Z_NULL;
+  }
+  s->end = s->window + w;
+  s->checkfn = c;
+  s->mode = TYPE;
+  Trace((stderr, "inflate:   blocks allocated\n"));
+  inflate_blocks_reset(s, z, &s->check);
+  return s;
+}
+
+
+#ifdef DEBUG_ZLIB
+  extern uInt inflate_hufts;
+#endif
+int inflate_blocks(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt t;               /* temporary storage */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input based on current state */
+  while (1) switch (s->mode)
+  {
+    case TYPE:
+      NEEDBITS(3)
+      t = (uInt)b & 7;
+      s->last = t & 1;
+      switch (t >> 1)
+      {
+        case 0:                         /* stored */
+          Trace((stderr, "inflate:     stored block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          t = k & 7;                    /* go to byte boundary */
+          DUMPBITS(t)
+          s->mode = LENS;               /* get length of stored block */
+          break;
+        case 1:                         /* fixed */
+          Trace((stderr, "inflate:     fixed codes block%s\n",
+                 s->last ? " (last)" : ""));
+          {
+            uInt bl, bd;
+            inflate_huft *tl, *td;
+
+            inflate_trees_fixed(&bl, &bd, &tl, &td);
+            s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z);
+            if (s->sub.decode.codes == Z_NULL)
+            {
+              r = Z_MEM_ERROR;
+              LEAVE
+            }
+            s->sub.decode.tl = Z_NULL;  /* don't try to free these */
+            s->sub.decode.td = Z_NULL;
+          }
+          DUMPBITS(3)
+          s->mode = CODES;
+          break;
+        case 2:                         /* dynamic */
+          Trace((stderr, "inflate:     dynamic codes block%s\n",
+                 s->last ? " (last)" : ""));
+          DUMPBITS(3)
+          s->mode = TABLE;
+          break;
+        case 3:                         /* illegal */
+          DUMPBITS(3)
+          s->mode = BADB;
+          z->msg = (char*)"invalid block type";
+          r = Z_DATA_ERROR;
+          LEAVE
+      }
+      break;
+    case LENS:
+      NEEDBITS(32)
+      if ((((~b) >> 16) & 0xffff) != (b & 0xffff))
+      {
+        s->mode = BADB;
+        z->msg = (char*)"invalid stored block lengths";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+      s->sub.left = (uInt)b & 0xffff;
+      b = k = 0;                      /* dump bits */
+      Tracev((stderr, "inflate:       stored length %u\n", s->sub.left));
+      s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE);
+      break;
+    case STORED:
+      if (n == 0)
+        LEAVE
+      NEEDOUT
+      t = s->sub.left;
+      if (t > n) t = n;
+      if (t > m) t = m;
+      zmemcpy(q, p, t);
+      p += t;  n -= t;
+      q += t;  m -= t;
+      if ((s->sub.left -= t) != 0)
+        break;
+      Tracev((stderr, "inflate:       stored end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      s->mode = s->last ? DRY : TYPE;
+      break;
+    case TABLE:
+      NEEDBITS(14)
+      s->sub.trees.table = t = (uInt)b & 0x3fff;
+#ifndef PKZIP_BUG_WORKAROUND
+      if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29)
+      {
+        s->mode = BADB;
+        z->msg = (char*)"too many length or distance symbols";
+        r = Z_DATA_ERROR;
+        LEAVE
+      }
+#endif
+      t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f);
+      if (t < 19)
+        t = 19;
+      if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL)
+      {
+        r = Z_MEM_ERROR;
+        LEAVE
+      }
+      DUMPBITS(14)
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       table sizes ok\n"));
+      s->mode = BTREE;
+    case BTREE:
+      while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10))
+      {
+        NEEDBITS(3)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7;
+        DUMPBITS(3)
+      }
+      while (s->sub.trees.index < 19)
+        s->sub.trees.blens[border[s->sub.trees.index++]] = 0;
+      s->sub.trees.bb = 7;
+      t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb,
+                             &s->sub.trees.tb, z);
+      if (t != Z_OK)
+      {
+        r = t;
+        if (r == Z_DATA_ERROR) {
+          ZFREE(z, s->sub.trees.blens);
+          s->mode = BADB;
+        }
+        LEAVE
+      }
+      s->sub.trees.index = 0;
+      Tracev((stderr, "inflate:       bits tree ok\n"));
+      s->mode = DTREE;
+    case DTREE:
+      while (t = s->sub.trees.table,
+             s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f))
+      {
+        inflate_huft *h;
+        uInt i, j, c;
+
+        t = s->sub.trees.bb;
+        NEEDBITS(t)
+        h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]);
+        t = h->word.what.Bits;
+        c = h->more.Base;
+        if (c < 16)
+        {
+          DUMPBITS(t)
+          s->sub.trees.blens[s->sub.trees.index++] = c;
+        }
+        else /* c == 16..18 */
+        {
+          i = c == 18 ? 7 : c - 14;
+          j = c == 18 ? 11 : 3;
+          NEEDBITS(t + i)
+          DUMPBITS(t)
+          j += (uInt)b & inflate_mask[i];
+          DUMPBITS(i)
+          i = s->sub.trees.index;
+          t = s->sub.trees.table;
+          if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) ||
+              (c == 16 && i < 1))
+          {
+            inflate_trees_free(s->sub.trees.tb, z);
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BADB;
+            z->msg = (char*)"invalid bit length repeat";
+            r = Z_DATA_ERROR;
+            LEAVE
+          }
+          c = c == 16 ? s->sub.trees.blens[i - 1] : 0;
+          do {
+            s->sub.trees.blens[i++] = c;
+          } while (--j);
+          s->sub.trees.index = i;
+        }
+      }
+      inflate_trees_free(s->sub.trees.tb, z);
+      s->sub.trees.tb = Z_NULL;
+      {
+        uInt bl, bd;
+        inflate_huft *tl, *td;
+        inflate_codes_statef *c;
+
+        bl = 9;         /* must be <= 9 for lookahead assumptions */
+        bd = 6;         /* must be <= 9 for lookahead assumptions */
+        t = s->sub.trees.table;
+#ifdef DEBUG_ZLIB
+      inflate_hufts = 0;
+#endif
+        t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f),
+                                  s->sub.trees.blens, &bl, &bd, &tl, &td, z);
+        if (t != Z_OK)
+        {
+          if (t == (uInt)Z_DATA_ERROR) {
+            ZFREE(z, s->sub.trees.blens);
+            s->mode = BADB;
+          }
+          r = t;
+          LEAVE
+        }
+        Tracev((stderr, "inflate:       trees ok, %d * %d bytes used\n",
+              inflate_hufts, sizeof(inflate_huft)));
+        if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL)
+        {
+          inflate_trees_free(td, z);
+          inflate_trees_free(tl, z);
+          r = Z_MEM_ERROR;
+          LEAVE
+        }
+	/*
+	 * this ZFREE must occur *BEFORE* we mess with sub.decode, because
+	 * sub.trees is union'd with sub.decode.
+	 */
+        ZFREE(z, s->sub.trees.blens);
+        s->sub.decode.codes = c;
+        s->sub.decode.tl = tl;
+        s->sub.decode.td = td;
+      }
+      s->mode = CODES;
+    case CODES:
+      UPDATE
+      if ((r = inflate_codes(s, z, r)) != Z_STREAM_END)
+        return inflate_flush(s, z, r);
+      r = Z_OK;
+      inflate_codes_free(s->sub.decode.codes, z);
+      inflate_trees_free(s->sub.decode.td, z);
+      inflate_trees_free(s->sub.decode.tl, z);
+      LOAD
+      Tracev((stderr, "inflate:       codes end, %lu total out\n",
+              z->total_out + (q >= s->read ? q - s->read :
+              (s->end - s->read) + (q - s->window))));
+      if (!s->last)
+      {
+        s->mode = TYPE;
+        break;
+      }
+      if (k > 7)              /* return unused byte, if any */
+      {
+        Assert(k < 16, "inflate_codes grabbed too many bytes")
+        k -= 8;
+        n++;
+        p--;                    /* can always return one */
+      }
+      s->mode = DRY;
+    case DRY:
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      s->mode = DONEB;
+    case DONEB:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADB:
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+int inflate_blocks_free(s, z, c)
+inflate_blocks_statef *s;
+z_streamp z;
+uLongf *c;
+{
+  inflate_blocks_reset(s, z, c);
+  ZFREE(z, s->window);
+  ZFREE(z, s);
+  Trace((stderr, "inflate:   blocks freed\n"));
+  return Z_OK;
+}
+
+
+void inflate_set_dictionary(s, d, n)
+inflate_blocks_statef *s;
+const Bytef *d;
+uInt  n;
+{
+  zmemcpy((charf *)s->window, d, n);
+  s->read = s->write = s->window + n;
+}
+
+/*
+ * This subroutine adds the data at next_in/avail_in to the output history
+ * without performing any output.  The output buffer must be "caught up";
+ * i.e. no pending output (hence s->read equals s->write), and the state must
+ * be BLOCKS (i.e. we should be willing to see the start of a series of
+ * BLOCKS).  On exit, the output will also be caught up, and the checksum
+ * will have been updated if need be.
+ */
+int inflate_addhistory(s, z)
+inflate_blocks_statef *s;
+z_stream *z;
+{
+    uLong b;              /* bit buffer */  /* NOT USED HERE */
+    uInt k;               /* bits in bit buffer */ /* NOT USED HERE */
+    uInt t;               /* temporary storage */
+    Bytef *p;             /* input data pointer */
+    uInt n;               /* bytes available there */
+    Bytef *q;             /* output window write pointer */
+    uInt m;               /* bytes to end of window or read pointer */
+
+    if (s->read != s->write)
+	return Z_STREAM_ERROR;
+    if (s->mode != TYPE)
+	return Z_DATA_ERROR;
+
+    /* we're ready to rock */
+    LOAD
+    /* while there is input ready, copy to output buffer, moving
+     * pointers as needed.
+     */
+    while (n) {
+	t = n;  /* how many to do */
+	/* is there room until end of buffer? */
+	if (t > m) t = m;
+	/* update check information */
+	if (s->checkfn != Z_NULL)
+	    s->check = (*s->checkfn)(s->check, q, t);
+	zmemcpy(q, p, t);
+	q += t;
+	p += t;
+	n -= t;
+	z->total_out += t;
+	s->read = q;    /* drag read pointer forward */
+/*      WWRAP  */ 	/* expand WWRAP macro by hand to handle s->read */
+	if (q == s->end) {
+	    s->read = q = s->window;
+	    m = WAVAIL;
+	}
+    }
+    UPDATE
+    return Z_OK;
+}
+
+
+/*
+ * At the end of a Deflate-compressed PPP packet, we expect to have seen
+ * a `stored' block type value but not the (zero) length bytes.
+ */
+int inflate_packet_flush(s)
+    inflate_blocks_statef *s;
+{
+    if (s->mode != LENS)
+	return Z_DATA_ERROR;
+    s->mode = TYPE;
+    return Z_OK;
+}
+/* --- infblock.c */
+
+/* +++ inftrees.c */
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+
+char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler ";
+/*
+  If you use the zlib library in a product, an acknowledgment is welcome
+  in the documentation of your product. If for some reason you cannot
+  include such an acknowledgment, I would appreciate that you keep this
+  copyright string in the executable of your product.
+ */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state  {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+
+local int huft_build OF((
+    uIntf *,            /* code lengths in bits */
+    uInt,               /* number of codes */
+    uInt,               /* number of "simple" codes */
+    const uIntf *,      /* list of base values for non-simple codes */
+    const uIntf *,      /* list of extra bits for non-simple codes */
+    inflate_huft * FAR*,/* result: starting table */
+    uIntf *,            /* maximum lookup bits (returns actual) */
+    z_streamp ));       /* for zalloc function */
+
+local voidpf falloc OF((
+    voidpf,             /* opaque pointer (not used) */
+    uInt,               /* number of items */
+    uInt));             /* size of item */
+
+/* Tables for deflate from PKZIP's appnote.txt. */
+local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */
+        3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+        35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+        /* see note #13 above about 258 */
+local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+        3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */
+local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */
+        1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+        257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+        8193, 12289, 16385, 24577};
+local const uInt cpdext[30] = { /* Extra bits for distance codes */
+        0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+        7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+        12, 12, 13, 13};
+
+/*
+   Huffman code decoding is performed using a multi-level table lookup.
+   The fastest way to decode is to simply build a lookup table whose
+   size is determined by the longest code.  However, the time it takes
+   to build this table can also be a factor if the data being decoded
+   is not very long.  The most common codes are necessarily the
+   shortest codes, so those codes dominate the decoding time, and hence
+   the speed.  The idea is you can have a shorter table that decodes the
+   shorter, more probable codes, and then point to subsidiary tables for
+   the longer codes.  The time it costs to decode the longer codes is
+   then traded against the time it takes to make longer tables.
+
+   This results of this trade are in the variables lbits and dbits
+   below.  lbits is the number of bits the first level table for literal/
+   length codes can decode in one step, and dbits is the same thing for
+   the distance codes.  Subsequent tables are also less than or equal to
+   those sizes.  These values may be adjusted either when all of the
+   codes are shorter than that, in which case the longest code length in
+   bits is used, or when the shortest code is *longer* than the requested
+   table size, in which case the length of the shortest code in bits is
+   used.
+
+   There are two different values for the two tables, since they code a
+   different number of possibilities each.  The literal/length table
+   codes 286 possible values, or in a flat code, a little over eight
+   bits.  The distance table codes 30 possible values, or a little less
+   than five bits, flat.  The optimum values for speed end up being
+   about one bit more than those, so lbits is 8+1 and dbits is 5+1.
+   The optimum values may differ though from machine to machine, and
+   possibly even between compilers.  Your mileage may vary.
+ */
+
+
+/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */
+#define BMAX 15         /* maximum bit length of any code */
+#define N_MAX 288       /* maximum number of codes in any set */
+
+#ifdef DEBUG_ZLIB
+  uInt inflate_hufts;
+#endif
+
+local int huft_build(b, n, s, d, e, t, m, zs)
+uIntf *b;               /* code lengths in bits (all assumed <= BMAX) */
+uInt n;                 /* number of codes (assumed <= N_MAX) */
+uInt s;                 /* number of simple-valued codes (0..s-1) */
+const uIntf *d;         /* list of base values for non-simple codes */
+const uIntf *e;         /* list of extra bits for non-simple codes */
+inflate_huft * FAR *t;  /* result: starting table */
+uIntf *m;               /* maximum lookup bits, returns actual */
+z_streamp zs;           /* for zalloc function */
+/* Given a list of code lengths and a maximum table size, make a set of
+   tables to decode that set of codes.  Return Z_OK on success, Z_BUF_ERROR
+   if the given code set is incomplete (the tables are still built in this
+   case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of
+   lengths), or Z_MEM_ERROR if not enough memory. */
+{
+
+  uInt a;                       /* counter for codes of length k */
+  uInt c[BMAX+1];               /* bit length count table */
+  uInt f;                       /* i repeats in table every f entries */
+  int g;                        /* maximum code length */
+  int h;                        /* table level */
+  register uInt i;              /* counter, current code */
+  register uInt j;              /* counter */
+  register int k;               /* number of bits in current code */
+  int l;                        /* bits per table (returned in m) */
+  register uIntf *p;            /* pointer into c[], b[], or v[] */
+  inflate_huft *q;              /* points to current table */
+  struct inflate_huft_s r;      /* table entry for structure assignment */
+  inflate_huft *u[BMAX];        /* table stack */
+  uInt v[N_MAX];                /* values in order of bit length */
+  register int w;               /* bits before this table == (l * h) */
+  uInt x[BMAX+1];               /* bit offsets, then code stack */
+  uIntf *xp;                    /* pointer into x */
+  int y;                        /* number of dummy codes added */
+  uInt z;                       /* number of entries in current table */
+
+
+  /* Generate counts for each bit length */
+  p = c;
+#define C0 *p++ = 0;
+#define C2 C0 C0 C0 C0
+#define C4 C2 C2 C2 C2
+  C4                            /* clear c[]--assume BMAX+1 is 16 */
+  p = b;  i = n;
+  do {
+    c[*p++]++;                  /* assume all entries <= BMAX */
+  } while (--i);
+  if (c[0] == n)                /* null input--all zero length codes */
+  {
+    *t = (inflate_huft *)Z_NULL;
+    *m = 0;
+    return Z_OK;
+  }
+
+
+  /* Find minimum and maximum length, bound *m by those */
+  l = *m;
+  for (j = 1; j <= BMAX; j++)
+    if (c[j])
+      break;
+  k = j;                        /* minimum code length */
+  if ((uInt)l < j)
+    l = j;
+  for (i = BMAX; i; i--)
+    if (c[i])
+      break;
+  g = i;                        /* maximum code length */
+  if ((uInt)l > i)
+    l = i;
+  *m = l;
+
+
+  /* Adjust last length count to fill out codes, if needed */
+  for (y = 1 << j; j < i; j++, y <<= 1)
+    if ((y -= c[j]) < 0)
+      return Z_DATA_ERROR;
+  if ((y -= c[i]) < 0)
+    return Z_DATA_ERROR;
+  c[i] += y;
+
+
+  /* Generate starting offsets into the value table for each length */
+  x[1] = j = 0;
+  p = c + 1;  xp = x + 2;
+  while (--i) {                 /* note that i == g from above */
+    *xp++ = (j += *p++);
+  }
+
+
+  /* Make a table of values in order of bit lengths */
+  p = b;  i = 0;
+  do {
+    if ((j = *p++) != 0)
+      v[x[j]++] = i;
+  } while (++i < n);
+  n = x[g];                   /* set n to length of v */
+
+
+  /* Generate the Huffman codes and for each, make the table entries */
+  x[0] = i = 0;                 /* first Huffman code is zero */
+  p = v;                        /* grab values in bit order */
+  h = -1;                       /* no tables yet--level -1 */
+  w = -l;                       /* bits decoded == (l * h) */
+  u[0] = (inflate_huft *)Z_NULL;        /* just to keep compilers happy */
+  q = (inflate_huft *)Z_NULL;   /* ditto */
+  z = 0;                        /* ditto */
+
+  /* go through the bit lengths (k already is bits in shortest code) */
+  for (; k <= g; k++)
+  {
+    a = c[k];
+    while (a--)
+    {
+      /* here i is the Huffman code of length k bits for value *p */
+      /* make tables up to required level */
+      while (k > w + l)
+      {
+        h++;
+        w += l;                 /* previous table always l bits */
+
+        /* compute minimum size table less than or equal to l bits */
+        z = g - w;
+        z = z > (uInt)l ? l : z;        /* table size upper limit */
+        if ((f = 1 << (j = k - w)) > a + 1)     /* try a k-w bit table */
+        {                       /* too few codes for k-w bit table */
+          f -= a + 1;           /* deduct codes from patterns left */
+          xp = c + k;
+          if (j < z)
+            while (++j < z)     /* try smaller tables up to z bits */
+            {
+              if ((f <<= 1) <= *++xp)
+                break;          /* enough codes to use up j bits */
+              f -= *xp;         /* else deduct codes from patterns */
+            }
+        }
+        z = 1 << j;             /* table entries for j-bit table */
+
+        /* allocate and link in new table */
+        if ((q = (inflate_huft *)ZALLOC
+             (zs,z + 1,sizeof(inflate_huft))) == Z_NULL)
+        {
+          if (h)
+            inflate_trees_free(u[0], zs);
+          return Z_MEM_ERROR;   /* not enough memory */
+        }
+#ifdef DEBUG_ZLIB
+        inflate_hufts += z + 1;
+#endif
+        *t = q + 1;             /* link to list for huft_free() */
+        *(t = &(q->next)) = Z_NULL;
+        u[h] = ++q;             /* table starts after link */
+
+        /* connect to last table, if there is one */
+        if (h)
+        {
+          x[h] = i;             /* save pattern for backing up */
+          r.bits = (Byte)l;     /* bits to dump before this table */
+          r.exop = (Byte)j;     /* bits in this table */
+          r.next = q;           /* pointer to this table */
+          j = i >> (w - l);     /* (get around Turbo C bug) */
+          u[h-1][j] = r;        /* connect to last table */
+        }
+      }
+
+      /* set up table entry in r */
+      r.bits = (Byte)(k - w);
+      if (p >= v + n)
+        r.exop = 128 + 64;      /* out of values--invalid code */
+      else if (*p < s)
+      {
+        r.exop = (Byte)(*p < 256 ? 0 : 32 + 64);     /* 256 is end-of-block */
+        r.base = *p++;          /* simple code is just the value */
+      }
+      else
+      {
+        r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */
+        r.base = d[*p++ - s];
+      }
+
+      /* fill code-like entries with r */
+      f = 1 << (k - w);
+      for (j = i >> w; j < z; j += f)
+        q[j] = r;
+
+      /* backwards increment the k-bit code i */
+      for (j = 1 << (k - 1); i & j; j >>= 1)
+        i ^= j;
+      i ^= j;
+
+      /* backup over finished tables */
+      while ((i & ((1 << w) - 1)) != x[h])
+      {
+        h--;                    /* don't need to update q */
+        w -= l;
+      }
+    }
+  }
+
+
+  /* Return Z_BUF_ERROR if we were given an incomplete table */
+  return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK;
+}
+
+
+int inflate_trees_bits(c, bb, tb, z)
+uIntf *c;               /* 19 code lengths */
+uIntf *bb;              /* bits tree desired/actual depth */
+inflate_huft * FAR *tb; /* bits tree result */
+z_streamp z;            /* for zfree function */
+{
+  int r;
+
+  r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z);
+  if (r == Z_DATA_ERROR)
+    z->msg = (char*)"oversubscribed dynamic bit lengths tree";
+  else if (r == Z_BUF_ERROR || *bb == 0)
+  {
+    inflate_trees_free(*tb, z);
+    z->msg = (char*)"incomplete dynamic bit lengths tree";
+    r = Z_DATA_ERROR;
+  }
+  return r;
+}
+
+
+int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z)
+uInt nl;                /* number of literal/length codes */
+uInt nd;                /* number of distance codes */
+uIntf *c;               /* that many (total) code lengths */
+uIntf *bl;              /* literal desired/actual bit depth */
+uIntf *bd;              /* distance desired/actual bit depth */
+inflate_huft * FAR *tl; /* literal/length tree result */
+inflate_huft * FAR *td; /* distance tree result */
+z_streamp z;            /* for zfree function */
+{
+  int r;
+
+  /* build literal/length tree */
+  r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z);
+  if (r != Z_OK || *bl == 0)
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed literal/length tree";
+    else if (r != Z_MEM_ERROR)
+    {
+      inflate_trees_free(*tl, z);
+      z->msg = (char*)"incomplete literal/length tree";
+      r = Z_DATA_ERROR;
+    }
+    return r;
+  }
+
+  /* build distance tree */
+  r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z);
+  if (r != Z_OK || (*bd == 0 && nl > 257))
+  {
+    if (r == Z_DATA_ERROR)
+      z->msg = (char*)"oversubscribed distance tree";
+    else if (r == Z_BUF_ERROR) {
+#ifdef PKZIP_BUG_WORKAROUND
+      r = Z_OK;
+    }
+#else
+      inflate_trees_free(*td, z);
+      z->msg = (char*)"incomplete distance tree";
+      r = Z_DATA_ERROR;
+    }
+    else if (r != Z_MEM_ERROR)
+    {
+      z->msg = (char*)"empty distance tree with lengths";
+      r = Z_DATA_ERROR;
+    }
+    inflate_trees_free(*tl, z);
+    return r;
+#endif
+  }
+
+  /* done */
+  return Z_OK;
+}
+
+
+/* build fixed tables only once--keep them here */
+local int fixed_built = 0;
+#define FIXEDH 530      /* number of hufts used by fixed tables */
+local inflate_huft fixed_mem[FIXEDH];
+local uInt fixed_bl;
+local uInt fixed_bd;
+local inflate_huft *fixed_tl;
+local inflate_huft *fixed_td;
+
+
+local voidpf falloc(q, n, s)
+voidpf q;       /* opaque pointer */
+uInt n;         /* number of items */
+uInt s;         /* size of item */
+{
+  Assert(s == sizeof(inflate_huft) && n <= *(intf *)q,
+         "inflate_trees falloc overflow");
+  *(intf *)q -= n+s-s; /* s-s to avoid warning */
+  return (voidpf)(fixed_mem + *(intf *)q);
+}
+
+
+int inflate_trees_fixed(bl, bd, tl, td)
+uIntf *bl;               /* literal desired/actual bit depth */
+uIntf *bd;               /* distance desired/actual bit depth */
+inflate_huft * FAR *tl;  /* literal/length tree result */
+inflate_huft * FAR *td;  /* distance tree result */
+{
+  /* build fixed tables if not already (multiple overlapped executions ok) */
+  if (!fixed_built)
+  {
+    int k;              /* temporary variable */
+    unsigned c[288];    /* length list for huft_build */
+    z_stream z;         /* for falloc function */
+    int f = FIXEDH;     /* number of hufts left in fixed_mem */
+
+    /* set up fake z_stream for memory routines */
+    z.zalloc = falloc;
+    z.zfree = Z_NULL;
+    z.opaque = (voidpf)&f;
+
+    /* literal table */
+    for (k = 0; k < 144; k++)
+      c[k] = 8;
+    for (; k < 256; k++)
+      c[k] = 9;
+    for (; k < 280; k++)
+      c[k] = 7;
+    for (; k < 288; k++)
+      c[k] = 8;
+    fixed_bl = 7;
+    huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z);
+
+    /* distance table */
+    for (k = 0; k < 30; k++)
+      c[k] = 5;
+    fixed_bd = 5;
+    huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z);
+
+    /* done */
+    Assert(f == 0, "invalid build of fixed tables");
+    fixed_built = 1;
+  }
+  *bl = fixed_bl;
+  *bd = fixed_bd;
+  *tl = fixed_tl;
+  *td = fixed_td;
+  return Z_OK;
+}
+
+
+int inflate_trees_free(t, z)
+inflate_huft *t;        /* table to free */
+z_streamp z;            /* for zfree function */
+/* Free the malloc'ed tables built by huft_build(), which makes a linked
+   list of the tables it made, with the links in a dummy first entry of
+   each table. */
+{
+  register inflate_huft *p, *q, *r;
+
+  /* Reverse linked list */
+  p = Z_NULL;
+  q = t;
+  while (q != Z_NULL)
+  {
+    r = (q - 1)->next;
+    (q - 1)->next = p;
+    p = q;
+    q = r;
+  }
+  /* Go through linked list, freeing from the malloced (t[-1]) address. */
+  while (p != Z_NULL)
+  {
+    q = (--p)->next;
+    ZFREE(z,p);
+    p = q;
+  } 
+  return Z_OK;
+}
+/* --- inftrees.c */
+
+/* +++ infcodes.c */
+/* infcodes.c -- process literals and length/distance pairs
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+/* +++ inffast.h */
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+   part of the implementation of the compression library and is
+   subject to change. Applications should only use zlib.h.
+ */
+
+extern int inflate_fast OF((
+    uInt,
+    uInt,
+    inflate_huft *,
+    inflate_huft *,
+    inflate_blocks_statef *,
+    z_streamp ));
+/* --- inffast.h */
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* inflate codes private state */
+struct inflate_codes_state {
+
+  /* mode */
+  enum {        /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+      START,    /* x: set up for LEN */
+      LEN,      /* i: get length/literal/eob next */
+      LENEXT,   /* i: getting length extra (have base) */
+      DIST,     /* i: get distance next */
+      DISTEXT,  /* i: getting distance extra */
+      COPY,     /* o: copying bytes in window, waiting for space */
+      LIT,      /* o: got literal, waiting for output space */
+      WASH,     /* o: got eob, possibly still output waiting */
+      END,      /* x: got eob and all data flushed */
+      BADCODE}  /* x: got error */
+    mode;               /* current inflate_codes mode */
+
+  /* mode dependent information */
+  uInt len;
+  union {
+    struct {
+      inflate_huft *tree;       /* pointer into tree */
+      uInt need;                /* bits needed */
+    } code;             /* if LEN or DIST, where in tree */
+    uInt lit;           /* if LIT, literal */
+    struct {
+      uInt get;                 /* bits to get for extra */
+      uInt dist;                /* distance back to copy from */
+    } copy;             /* if EXT or COPY, where and how much */
+  } sub;                /* submode */
+
+  /* mode independent information */
+  Byte lbits;           /* ltree bits decoded per branch */
+  Byte dbits;           /* dtree bits decoder per branch */
+  inflate_huft *ltree;          /* literal/length/eob tree */
+  inflate_huft *dtree;          /* distance tree */
+
+};
+
+
+inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+z_streamp z;
+{
+  inflate_codes_statef *c;
+
+  if ((c = (inflate_codes_statef *)
+       ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL)
+  {
+    c->mode = START;
+    c->lbits = (Byte)bl;
+    c->dbits = (Byte)bd;
+    c->ltree = tl;
+    c->dtree = td;
+    Tracev((stderr, "inflate:       codes new\n"));
+  }
+  return c;
+}
+
+
+int inflate_codes(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt j;               /* temporary storage */
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  Bytef *f;             /* pointer to copy strings from */
+  inflate_codes_statef *c = s->sub.decode.codes;  /* codes state */
+
+  /* copy input/output information to locals (UPDATE macro restores) */
+  LOAD
+
+  /* process input and output based on current state */
+  while (1) switch (c->mode)
+  {             /* waiting for "i:"=input, "o:"=output, "x:"=nothing */
+    case START:         /* x: set up for LEN */
+#ifndef SLOW
+      if (m >= 258 && n >= 10)
+      {
+        UPDATE
+        r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z);
+        LOAD
+        if (r != Z_OK)
+        {
+          c->mode = r == Z_STREAM_END ? WASH : BADCODE;
+          break;
+        }
+      }
+#endif /* !SLOW */
+      c->sub.code.need = c->lbits;
+      c->sub.code.tree = c->ltree;
+      c->mode = LEN;
+    case LEN:           /* i: get length/literal/eob next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e == 0)               /* literal */
+      {
+        c->sub.lit = t->base;
+        Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                 "inflate:         literal '%c'\n" :
+                 "inflate:         literal 0x%02x\n", t->base));
+        c->mode = LIT;
+        break;
+      }
+      if (e & 16)               /* length */
+      {
+        c->sub.copy.get = e & 15;
+        c->len = t->base;
+        c->mode = LENEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      if (e & 32)               /* end of block */
+      {
+        Tracevv((stderr, "inflate:         end of block\n"));
+        c->mode = WASH;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid literal/length code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case LENEXT:        /* i: getting length extra (have base) */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->len += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      c->sub.code.need = c->dbits;
+      c->sub.code.tree = c->dtree;
+      Tracevv((stderr, "inflate:         length %u\n", c->len));
+      c->mode = DIST;
+    case DIST:          /* i: get distance next */
+      j = c->sub.code.need;
+      NEEDBITS(j)
+      t = c->sub.code.tree + ((uInt)b & inflate_mask[j]);
+      DUMPBITS(t->bits)
+      e = (uInt)(t->exop);
+      if (e & 16)               /* distance */
+      {
+        c->sub.copy.get = e & 15;
+        c->sub.copy.dist = t->base;
+        c->mode = DISTEXT;
+        break;
+      }
+      if ((e & 64) == 0)        /* next table */
+      {
+        c->sub.code.need = e;
+        c->sub.code.tree = t->next;
+        break;
+      }
+      c->mode = BADCODE;        /* invalid code */
+      z->msg = (char*)"invalid distance code";
+      r = Z_DATA_ERROR;
+      LEAVE
+    case DISTEXT:       /* i: getting distance extra */
+      j = c->sub.copy.get;
+      NEEDBITS(j)
+      c->sub.copy.dist += (uInt)b & inflate_mask[j];
+      DUMPBITS(j)
+      Tracevv((stderr, "inflate:         distance %u\n", c->sub.copy.dist));
+      c->mode = COPY;
+    case COPY:          /* o: copying bytes in window, waiting for space */
+#ifndef __TURBOC__ /* Turbo C bug for following expression */
+      f = (uInt)(q - s->window) < c->sub.copy.dist ?
+          s->end - (c->sub.copy.dist - (q - s->window)) :
+          q - c->sub.copy.dist;
+#else
+      f = q - c->sub.copy.dist;
+      if ((uInt)(q - s->window) < c->sub.copy.dist)
+        f = s->end - (c->sub.copy.dist - (uInt)(q - s->window));
+#endif
+      while (c->len)
+      {
+        NEEDOUT
+        OUTBYTE(*f++)
+        if (f == s->end)
+          f = s->window;
+        c->len--;
+      }
+      c->mode = START;
+      break;
+    case LIT:           /* o: got literal, waiting for output space */
+      NEEDOUT
+      OUTBYTE(c->sub.lit)
+      c->mode = START;
+      break;
+    case WASH:          /* o: got eob, possibly more output */
+      FLUSH
+      if (s->read != s->write)
+        LEAVE
+      c->mode = END;
+    case END:
+      r = Z_STREAM_END;
+      LEAVE
+    case BADCODE:       /* x: got error */
+      r = Z_DATA_ERROR;
+      LEAVE
+    default:
+      r = Z_STREAM_ERROR;
+      LEAVE
+  }
+}
+
+
+void inflate_codes_free(c, z)
+inflate_codes_statef *c;
+z_streamp z;
+{
+  ZFREE(z, c);
+  Tracev((stderr, "inflate:       codes free\n"));
+}
+/* --- infcodes.c */
+
+/* +++ infutil.c */
+/* inflate_util.c -- data and routines common to blocks and codes
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "infblock.h" */
+/* #include "inftrees.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* And'ing with mask[n] masks the lower n bits */
+uInt inflate_mask[17] = {
+    0x0000,
+    0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
+    0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
+};
+
+
+/* copy as much as possible from the sliding window to the output area */
+int inflate_flush(s, z, r)
+inflate_blocks_statef *s;
+z_streamp z;
+int r;
+{
+  uInt n;
+  Bytef *p;
+  Bytef *q;
+
+  /* local copies of source and destination pointers */
+  p = z->next_out;
+  q = s->read;
+
+  /* compute number of bytes to copy as far as end of window */
+  n = (uInt)((q <= s->write ? s->write : s->end) - q);
+  if (n > z->avail_out) n = z->avail_out;
+  if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+  /* update counters */
+  z->avail_out -= n;
+  z->total_out += n;
+
+  /* update check information */
+  if (s->checkfn != Z_NULL)
+    z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+  /* copy as far as end of window */
+  if (p != Z_NULL) {
+    zmemcpy(p, q, n);
+    p += n;
+  }
+  q += n;
+
+  /* see if more to copy at beginning of window */
+  if (q == s->end)
+  {
+    /* wrap pointers */
+    q = s->window;
+    if (s->write == s->end)
+      s->write = s->window;
+
+    /* compute bytes to copy */
+    n = (uInt)(s->write - q);
+    if (n > z->avail_out) n = z->avail_out;
+    if (n && r == Z_BUF_ERROR) r = Z_OK;
+
+    /* update counters */
+    z->avail_out -= n;
+    z->total_out += n;
+
+    /* update check information */
+    if (s->checkfn != Z_NULL)
+      z->adler = s->check = (*s->checkfn)(s->check, q, n);
+
+    /* copy */
+    if (p != Z_NULL) {
+      zmemcpy(p, q, n);
+      p += n;
+    }
+    q += n;
+  }
+
+  /* update pointers */
+  z->next_out = p;
+  s->read = q;
+
+  /* done */
+  return r;
+}
+/* --- infutil.c */
+
+/* +++ inffast.c */
+/* inffast.c -- process literals and length/distance pairs fast
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* #include "zutil.h" */
+/* #include "inftrees.h" */
+/* #include "infblock.h" */
+/* #include "infcodes.h" */
+/* #include "infutil.h" */
+/* #include "inffast.h" */
+
+#ifndef NO_DUMMY_DECL
+struct inflate_codes_state {int dummy;}; /* for buggy compilers */
+#endif
+
+/* simplify the use of the inflate_huft type with some defines */
+#define base more.Base
+#define next more.Next
+#define exop word.what.Exop
+#define bits word.what.Bits
+
+/* macros for bit input with no checking and for returning unused bytes */
+#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}}
+#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;}
+
+/* Called with number of bytes left to write in window at least 258
+   (the maximum string length) and number of input bytes available
+   at least ten.  The ten bytes are six bytes for the longest length/
+   distance pair plus four bytes for overloading the bit buffer. */
+
+int inflate_fast(bl, bd, tl, td, s, z)
+uInt bl, bd;
+inflate_huft *tl;
+inflate_huft *td; /* need separate declaration for Borland C++ */
+inflate_blocks_statef *s;
+z_streamp z;
+{
+  inflate_huft *t;      /* temporary pointer */
+  uInt e;               /* extra bits or operation */
+  uLong b;              /* bit buffer */
+  uInt k;               /* bits in bit buffer */
+  Bytef *p;             /* input data pointer */
+  uInt n;               /* bytes available there */
+  Bytef *q;             /* output window write pointer */
+  uInt m;               /* bytes to end of window or read pointer */
+  uInt ml;              /* mask for literal/length tree */
+  uInt md;              /* mask for distance tree */
+  uInt c;               /* bytes to copy */
+  uInt d;               /* distance back to copy from */
+  Bytef *r;             /* copy source pointer */
+
+  /* load input, output, bit values */
+  LOAD
+
+  /* initialize masks */
+  ml = inflate_mask[bl];
+  md = inflate_mask[bd];
+
+  /* do until not enough input or output space for fast loop */
+  do {                          /* assume called with m >= 258 && n >= 10 */
+    /* get literal/length code */
+    GRABBITS(20)                /* max bits for literal/length code */
+    if ((e = (t = tl + ((uInt)b & ml))->exop) == 0)
+    {
+      DUMPBITS(t->bits)
+      Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                "inflate:         * literal '%c'\n" :
+                "inflate:         * literal 0x%02x\n", t->base));
+      *q++ = (Byte)t->base;
+      m--;
+      continue;
+    }
+    do {
+      DUMPBITS(t->bits)
+      if (e & 16)
+      {
+        /* get extra bits for length */
+        e &= 15;
+        c = t->base + ((uInt)b & inflate_mask[e]);
+        DUMPBITS(e)
+        Tracevv((stderr, "inflate:         * length %u\n", c));
+
+        /* decode distance base of block to copy */
+        GRABBITS(15);           /* max bits for distance code */
+        e = (t = td + ((uInt)b & md))->exop;
+        do {
+          DUMPBITS(t->bits)
+          if (e & 16)
+          {
+            /* get extra bits to add to distance base */
+            e &= 15;
+            GRABBITS(e)         /* get extra bits (up to 13) */
+            d = t->base + ((uInt)b & inflate_mask[e]);
+            DUMPBITS(e)
+            Tracevv((stderr, "inflate:         * distance %u\n", d));
+
+            /* do the copy */
+            m -= c;
+            if ((uInt)(q - s->window) >= d)     /* offset before dest */
+            {                                   /*  just copy */
+              r = q - d;
+              *q++ = *r++;  c--;        /* minimum count is three, */
+              *q++ = *r++;  c--;        /*  so unroll loop a little */
+            }
+            else                        /* else offset after destination */
+            {
+              e = d - (uInt)(q - s->window); /* bytes from offset to end */
+              r = s->end - e;           /* pointer to offset */
+              if (c > e)                /* if source crosses, */
+              {
+                c -= e;                 /* copy to end of window */
+                do {
+                  *q++ = *r++;
+                } while (--e);
+                r = s->window;          /* copy rest from start of window */
+              }
+            }
+            do {                        /* copy all or what's left */
+              *q++ = *r++;
+            } while (--c);
+            break;
+          }
+          else if ((e & 64) == 0)
+            e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop;
+          else
+          {
+            z->msg = (char*)"invalid distance code";
+            UNGRAB
+            UPDATE
+            return Z_DATA_ERROR;
+          }
+        } while (1);
+        break;
+      }
+      if ((e & 64) == 0)
+      {
+        if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0)
+        {
+          DUMPBITS(t->bits)
+          Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ?
+                    "inflate:         * literal '%c'\n" :
+                    "inflate:         * literal 0x%02x\n", t->base));
+          *q++ = (Byte)t->base;
+          m--;
+          break;
+        }
+      }
+      else if (e & 32)
+      {
+        Tracevv((stderr, "inflate:         * end of block\n"));
+        UNGRAB
+        UPDATE
+        return Z_STREAM_END;
+      }
+      else
+      {
+        z->msg = (char*)"invalid literal/length code";
+        UNGRAB
+        UPDATE
+        return Z_DATA_ERROR;
+      }
+    } while (1);
+  } while (m >= 258 && n >= 10);
+
+  /* not enough input or output--restore pointers and return */
+  UNGRAB
+  UPDATE
+  return Z_OK;
+}
+/* --- inffast.c */
+
+/* +++ zutil.c */
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-1996 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: zutil.c,v 1.17 1996/07/24 13:41:12 me Exp $ */
+
+#ifdef DEBUG_ZLIB
+#include <stdio.h>
+#endif
+
+/* #include "zutil.h" */
+
+#ifndef NO_DUMMY_DECL
+struct internal_state      {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef STDC
+extern void exit OF((int));
+#endif
+
+static const char *z_errmsg[10] = {
+"need dictionary",     /* Z_NEED_DICT       2  */
+"stream end",          /* Z_STREAM_END      1  */
+"",                    /* Z_OK              0  */
+"file error",          /* Z_ERRNO         (-1) */
+"stream error",        /* Z_STREAM_ERROR  (-2) */
+"data error",          /* Z_DATA_ERROR    (-3) */
+"insufficient memory", /* Z_MEM_ERROR     (-4) */
+"buffer error",        /* Z_BUF_ERROR     (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char *zlibVersion()
+{
+    return ZLIB_VERSION;
+}
+
+#ifdef DEBUG_ZLIB
+void z_error (m)
+    char *m;
+{
+    fprintf(stderr, "%s\n", m);
+    exit(1);
+}
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+    Bytef* dest;
+    Bytef* source;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = *source++; /* ??? to be unrolled */
+    } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+    Bytef* s1;
+    Bytef* s2;
+    uInt  len;
+{
+    uInt j;
+
+    for (j = 0; j < len; j++) {
+        if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+    }
+    return 0;
+}
+
+void zmemzero(dest, len)
+    Bytef* dest;
+    uInt  len;
+{
+    if (len == 0) return;
+    do {
+        *dest++ = 0;  /* ??? to be unrolled */
+    } while (--len != 0);
+}
+#endif
+
+#ifdef __TURBOC__
+#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__)
+/* Small and medium model in Turbo C are for now limited to near allocation
+ * with reduced MAX_WBITS and MAX_MEM_LEVEL
+ */
+#  define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+    voidpf org_ptr;
+    voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    voidpf buf = opaque; /* just to make some compilers happy */
+    ulg bsize = (ulg)items*size;
+
+    /* If we allocate less than 65520 bytes, we assume that farmalloc
+     * will return a usable pointer which doesn't have to be normalized.
+     */
+    if (bsize < 65520L) {
+        buf = farmalloc(bsize);
+        if (*(ush*)&buf != 0) return buf;
+    } else {
+        buf = farmalloc(bsize + 16L);
+    }
+    if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+    table[next_ptr].org_ptr = buf;
+
+    /* Normalize the pointer to seg:0 */
+    *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+    *(ush*)&buf = 0;
+    table[next_ptr++].new_ptr = buf;
+    return buf;
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    int n;
+    if (*(ush*)&ptr != 0) { /* object < 64K */
+        farfree(ptr);
+        return;
+    }
+    /* Find the original pointer */
+    for (n = 0; n < next_ptr; n++) {
+        if (ptr != table[n].new_ptr) continue;
+
+        farfree(table[n].org_ptr);
+        while (++n < next_ptr) {
+            table[n-1] = table[n];
+        }
+        next_ptr--;
+        return;
+    }
+    ptr = opaque; /* just to make some compilers happy */
+    Assert(0, "zcfree: ptr not found");
+}
+#endif
+#endif /* __TURBOC__ */
+
+
+#if defined(M_I86) && !defined(__32BIT__)
+/* Microsoft C in 16-bit mode */
+
+#  define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER < 600))
+#  define _halloc  halloc
+#  define _hfree   hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    return _halloc((long)items, size);
+}
+
+void  zcfree (voidpf opaque, voidpf ptr)
+{
+    if (opaque) opaque = 0; /* to make compiler happy */
+    _hfree(ptr);
+}
+
+#endif /* MSC */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp  calloc OF((uInt items, uInt size));
+extern void   free   OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+    voidpf opaque;
+    unsigned items;
+    unsigned size;
+{
+    if (opaque) items += size - size; /* make compiler happy */
+    return (voidpf)calloc(items, size);
+}
+
+void  zcfree (opaque, ptr)
+    voidpf opaque;
+    voidpf ptr;
+{
+    free(ptr);
+    if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+/* --- zutil.c */
+
+/* +++ adler32.c */
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-1996 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h 
+ */
+
+/* From: adler32.c,v 1.10 1996/05/22 11:52:18 me Exp $ */
+
+/* #include "zlib.h" */
+
+#define BASE 65521L /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
+#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf)   DO8(buf,0); DO8(buf,8);
+
+/* ========================================================================= */
+uLong adler32(adler, buf, len)
+    uLong adler;
+    const Bytef *buf;
+    uInt len;
+{
+    unsigned long s1 = adler & 0xffff;
+    unsigned long s2 = (adler >> 16) & 0xffff;
+    int k;
+
+    if (buf == Z_NULL) return 1L;
+
+    while (len > 0) {
+        k = len < NMAX ? len : NMAX;
+        len -= k;
+        while (k >= 16) {
+            DO16(buf);
+	    buf += 16;
+            k -= 16;
+        }
+        if (k != 0) do {
+            s1 += *buf++;
+	    s2 += s1;
+        } while (--k);
+        s1 %= BASE;
+        s2 %= BASE;
+    }
+    return (s2 << 16) | s1;
+}
+/* --- adler32.c */
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/chat.c
@@ -0,0 +1,192 @@
+//==========================================================================
+//
+//      tests/ppp_up.c
+//
+//      Simple test of PPP and networking support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2000-01-10
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test code
+
+#if 0
+#include <network.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+#include <cyg/ppp/ppp.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/serialio.h>
+
+#include <cyg/infra/testcase.h>
+#endif
+
+#include "ppp_test_support.inl"
+
+
+
+//==========================================================================
+    
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+//==========================================================================
+
+static const char *script1[] =
+{
+    "ABORT"             ,       "BUSY"          ,
+    "ABORT"             ,       "NO CARRIER"    ,
+    ""                  ,       "Chat Test"     ,
+    "CONNECT"           ,       "\\c"           ,
+    "TIMEOUT"           ,       "10"            ,
+    "ogin:--ogin:"      ,       "ppp"           ,
+    "TIMEOUT"           ,       "5"             ,
+    "assword:"          ,       "hithere"       ,
+    0
+};
+
+//==========================================================================
+
+static struct test_info
+{
+    char        *name;
+    const char  **script;
+    cyg_int32   result;
+} tests[] =
+{
+    { "CHAT_TEST_1"     , script1       , 0 },          // Simple test to completion
+    { "CHAT_TEST_2"     , script1       , 1 },          // Expects an ABORT
+    { "CHAT_TEST_3"     , script1       , 1 },          // Expects a timeout
+    { NULL              , NULL          , 0 }
+};
+
+//==========================================================================
+
+void
+chat_test(cyg_addrword_t p)
+{
+    cyg_serial_baud_rate_t old;
+    cyg_int32 failures = 0;
+    cyg_int32 result;
+    struct test_info *test;
+    
+    CYG_TEST_INIT();
+
+    CYG_TEST_INFO("Start CHAT test");
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_115200 );
+
+    for( test = &tests[0]; test->name != NULL; test++ )
+    {
+        CYG_TEST_INFO( test->name );
+        ppp_test_announce( test->name );
+
+        result = cyg_ppp_chat( CYGPKG_PPP_TEST_DEVICE, test->script );
+
+        diag_printf("chat result %d expected %d\n",result,test->result );
+        
+        if( result != test->result )
+        {
+            CYG_TEST_FAIL( test->name );
+            failures++;
+        }
+        else
+            CYG_TEST_PASS( test->name );
+
+        cyg_thread_delay( 300 );
+    }
+
+    ppp_test_set_baud( old );
+    
+    ppp_test_finish();
+    
+//    ppp_test_announce( "CHAT_TEST_1" );
+    
+//    success = cyg_ppp_chat( CYGPKG_PPP_TEST_DEVICE, script );
+
+//    if( !success )
+//        CYG_TEST_INFO("Chat script failed");
+    
+    CYG_TEST_FINISH("CHAT test done");
+}
+
+//==========================================================================
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      chat_test,          // entry
+                      0,                 // entry parameter
+                      "CHAT test",        // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/isp.c
@@ -0,0 +1,392 @@
+//==========================================================================
+//
+//      tests/isp.c
+//
+//      Test of PPP and CHAT connection to an ISP
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: gthomas (ping code), nickg
+// Date:         2003-06-01
+// Purpose:      
+// Description:  This test uses CHAT to set up a modem, dial, talk to an ISP
+//               and then ping some well known addresses. It then brings the
+//               link down.
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test code
+
+#include <network.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+#include <cyg/ppp/ppp.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/serialio.h>
+
+#include <cyg/infra/testcase.h>
+
+//==========================================================================
+
+#include <arpa/inet.h>
+
+// Fill in the blanks if necessary
+#ifndef TNR_OFF
+# define TNR_OFF()
+#endif
+#ifndef TNR_ON
+# define TNR_ON()
+#endif
+#ifndef TNR_INIT
+# define TNR_INIT()
+#endif
+#ifndef TNR_PRINT_ACTIVITY
+# define TNR_PRINT_ACTIVITY()
+#endif
+
+#define NUM_PINGS 16
+#define MAX_PACKET 4096
+#define MIN_PACKET   64
+#define MAX_SEND   4000
+
+#define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
+#define nPACKET_ADD  1 
+
+static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
+
+#define UNIQUEID 0x1234
+
+void
+pexit(char *s)
+{
+    CYG_TEST_FAIL_FINISH(s);
+}
+
+// Compute INET checksum
+int
+inet_cksum(u_short *addr, int len)
+{
+    register int nleft = len;
+    register u_short *w = addr;
+    register u_short answer;
+    register u_int sum = 0;
+    u_short odd_byte = 0;
+
+    /*
+     *  Our algorithm is simple, using a 32 bit accumulator (sum),
+     *  we add sequential 16 bit words to it, and at the end, fold
+     *  back all the carry bits from the top 16 bits into the lower
+     *  16 bits.
+     */
+    while( nleft > 1 )  {
+        sum += *w++;
+        nleft -= 2;
+    }
+
+    /* mop up an odd byte, if necessary */
+    if( nleft == 1 ) {
+        *(u_char *)(&odd_byte) = *(u_char *)w;
+        sum += odd_byte;
+    }
+
+    /*
+     * add back carry outs from top 16 bits to low 16 bits
+     */
+    sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
+    sum += (sum >> 16);                     /* add carry */
+    answer = ~sum;                          /* truncate to 16 bits */
+    return (answer);
+}
+
+static int
+show_icmp(unsigned char *pkt, int len, 
+          struct sockaddr_in *from, struct sockaddr_in *to)
+{
+    cyg_tick_count_t *tp, tv;
+    struct ip *ip;
+    struct icmp *icmp;
+    tv = cyg_current_time();
+    ip = (struct ip *)pkt;
+    if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
+        diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
+                    inet_ntoa(from->sin_addr), len, ip->ip_v);
+        return 0;
+    }
+    icmp = (struct icmp *)(pkt + sizeof(*ip));
+    len -= (sizeof(*ip) + 8);
+    tp = (cyg_tick_count_t *)&icmp->icmp_data;
+    if (icmp->icmp_type != ICMP_ECHOREPLY) {
+        diag_printf("%s: Invalid ICMP - type: %d\n", 
+                    inet_ntoa(from->sin_addr), icmp->icmp_type);
+        return 0;
+    }
+    if (icmp->icmp_id != UNIQUEID) {
+        diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
+                    inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
+    }
+    diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
+    diag_printf("icmp_seq=%d", icmp->icmp_seq);
+    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
+    return (from->sin_addr.s_addr == to->sin_addr.s_addr);
+}
+
+static void
+ping_host(int s, struct sockaddr_in *host)
+{
+    struct icmp *icmp = (struct icmp *)pkt1;
+    int icmp_len = MIN_PACKET;
+    int seq, ok_recv, bogus_recv;
+    cyg_tick_count_t *tp;
+    long *dp;
+    struct sockaddr_in from;
+    int i, len, fromlen;
+
+    ok_recv = 0;
+    bogus_recv = 0;
+    diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
+    for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
+        TNR_ON();
+        // Build ICMP packet
+        icmp->icmp_type = ICMP_ECHO;
+        icmp->icmp_code = 0;
+        icmp->icmp_cksum = 0;
+        icmp->icmp_seq = seq;
+        icmp->icmp_id = 0x1234;
+        // Set up ping data
+        tp = (cyg_tick_count_t *)&icmp->icmp_data;
+        *tp++ = cyg_current_time();
+        dp = (long *)tp;
+        for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
+            *dp++ = i;
+        }
+        // Add checksum
+        icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
+        // Send it off
+        if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
+            TNR_OFF();
+            perror("sendto");
+            continue;
+        }
+        // Wait for a response
+        fromlen = sizeof(from);
+        len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
+        TNR_OFF();
+        if (len < 0) {
+            perror("recvfrom");
+            icmp_len = MIN_PACKET - PACKET_ADD; // just in case - long routes
+        } else {
+            if (show_icmp(pkt2, len, &from, host)) {
+                ok_recv++;
+            } else {
+                bogus_recv++;
+            }
+        }
+    }
+    TNR_OFF();
+    diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
+}
+
+static void do_ping(char *addr)
+{
+    struct protoent *p;
+    struct timeval tv;
+    struct sockaddr_in host;
+    int s;
+
+    if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
+        pexit("getprotobyname");
+        return;
+    }
+    s = socket(AF_INET, SOCK_RAW, p->p_proto);
+    if (s < 0) {
+        pexit("socket");
+        return;
+    }
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    // Set up host address
+    host.sin_family = AF_INET;
+    host.sin_len = sizeof(host);
+    inet_aton(addr, &host.sin_addr);
+    host.sin_port = 0;
+
+    ping_host(s, &host);
+    
+}
+
+//==========================================================================
+
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+//==========================================================================
+/*
+
+Captured session:
+
+
+AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0                     
+OK                                                   
+ATD08440416662                                       
+CONNECT 42666/ARQ/V90/LAPM/V42BIS                    
+anchor-du-10.access.demon.net
+
+
+login: xxxxxx
+Password: yyyyyy
+Protocol: ppp
+xxxxxx: IP Address: XXX.XXX.XXX.XXX  Running PPP on 1223
+No operational problems reported.
+Finger status@gate.demon.co.uk for more info - Last change 16:30 Jun 08
+HELLO
+
+                                                                                
+                                                                                
+OK                                                                              
+ATH                                                                             
+OK                                                                              
+
+*/
+
+static char *script[] =
+{
+    "ABORT"             ,       "BUSY"                                  ,
+    "ABORT"             ,       "NO CARRIER"                            ,
+    "ABORT"             ,       "ERROR"                                 ,
+    ""                  ,       "ATZ"                                   ,
+    "OK"                ,       "AT S7=45 S0=0 L1 V1 X4 &C1 E1 Q0"      ,
+    "OK"                ,       "ATD" CYGPKG_PPP_DEFAULT_DIALUP_NUMBER  ,
+    "ogin:--ogin:"      ,       CYGPKG_PPP_AUTH_DEFAULT_USER            ,
+    "assword:"          ,       CYGPKG_PPP_AUTH_DEFAULT_PASSWD          ,
+    "otocol:"           ,       "ppp"                                   ,
+    "HELLO"             ,       "\\c"                                   ,
+    0
+};
+
+//==========================================================================
+
+void
+isp_test(cyg_addrword_t p)
+{
+    CYG_TEST_INIT();
+
+    diag_printf("Start ISP test\n");
+
+    init_all_network_interfaces();
+
+    {
+        cyg_ppp_options_t options;
+        cyg_ppp_handle_t ppp_handle;
+
+        cyg_ppp_options_init( &options );
+
+//        options.debug = 1;
+//        options.kdebugflag = 1;
+
+        options.modem = 1;
+        options.script = &script[0];
+        
+        ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+        CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+        cyg_ppp_wait_up( ppp_handle );
+
+        CYG_TEST_INFO( "Delaying for a while...");
+        
+        cyg_thread_delay(10*100);
+        
+        CYG_TEST_INFO( "Pinging");
+        
+        do_ping("195.173.57.10");       // anchor-du-10.access.demon.net
+        do_ping("194.154.160.254");     // fluffy.ecoscentric.com
+        do_ping("66.187.233.205");      // sources.redhat.com
+        
+        CYG_TEST_INFO( "Bringing PPP down");
+
+        cyg_ppp_down( ppp_handle );
+    
+        CYG_TEST_INFO( "Waiting for PPP to go down");
+
+        cyg_ppp_wait_down( ppp_handle );
+    }
+    
+    CYG_TEST_PASS_FINISH("ISP test OK");
+}
+
+//==========================================================================
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      isp_test,          // entry
+                      0,                 // entry parameter
+                      "ISP test",        // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/nc_test_framework.h
@@ -0,0 +1,202 @@
+//==========================================================================
+//
+//      tests/nc_test_framework.h
+//
+//      Network characterization tests framework
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2000-01-10
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#ifndef _TESTS_NC_TEST_FRAMEWORK_H_
+#define _TESTS_NC_TEST_FRAMEWORK_H_
+
+#ifdef __ECOS
+#include <network.h>
+#else
+#undef _KERNEL
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/errno.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+
+#include <netdb.h>
+#ifndef EAI_NONE
+#define EAI_NONE 0
+#endif
+#endif
+
+#ifdef __ECOS
+#define test_printf diag_printf
+typedef cyg_addrword_t test_param_t;
+#else
+#define test_printf printf
+typedef void *test_param_t;
+#endif
+
+#ifndef true
+#define false 0
+#define true  1
+#endif
+
+#define NC_SLAVE_PORT  7777
+#define NC_MASTER_PORT 7776
+
+#define NC_TESTING_SLAVE_PORT  8770
+#define NC_TESTING_MASTER_PORT 8771
+
+#define __string(s) #s
+#define _string(s) __string(s)
+
+//
+// The basic idea behind this test structure is that one end will run
+// in "slave" mode and the other in "master" mode.  Typically, the slave
+// will run on a target platform with the master running on a host.
+//
+// The slave starts up by listening for a connection on the "SLAVE_PORT".
+// In order for the testing to require the minimum stack support, this
+// connection (and the protocol) will use UDP.
+//
+// The master will connect to the slave and send it a request over this
+// connection.  Once the slave accepts the request, then master and slave
+// will execute the operation, typically a test.  The control connection
+// will remain active until the master sends a 'disconnect' request.  The
+// control connection will be broken after the reply to this request has
+// been sent.
+//
+
+#define MAX_ERRORS          5   // Give up after this many errors
+
+#define NC_REPLY_TIMEOUT    10  // The slave may be slow
+#define NC_TEST_TIMEOUT     3   // More generous for tests
+#define NC_RESULTS_TIMEOUT  (MAX_ERRORS+2)*NC_TEST_TIMEOUT
+
+struct nc_request {
+    int type;          // Description of request
+    int seq;           // Sequence number, used to build response
+    int nbufs;         // Number of "buffers" to send
+    int buflen;        // Length of each buffer
+    int slave_port;    // Network ports to use
+    int master_port;
+    int timeout;       // Max time to wait for any packet
+};
+
+#define NC_REQUEST_DISCONNECT 0x0001
+#define NC_REQUEST_UDP_SEND   0x0010  // Slave to send UDP data
+#define NC_REQUEST_UDP_RECV   0x0011  // Slave to receive UDP data
+#define NC_REQUEST_UDP_ECHO   0x0012  // Master->slave->master
+#define NC_REQUEST_TCP_SEND   0x0020  // Slave to send TCP data
+#define NC_REQUEST_TCP_RECV   0x0021  // Slave to receive TCP data
+#define NC_REQUEST_TCP_ECHO   0x0022  // Master->slave->master
+#define NC_REQUEST_START_IDLE 0x0100  // Start some idle processing
+#define NC_REQUEST_STOP_IDLE  0x0101  // Stop idle processing
+#define NC_REQUEST_SET_LOAD   0x0200  // Set the background load level
+
+struct nc_reply {
+    int  response; // ACK or NAK
+    int  seq;      // Must match request
+    int  reason;   // If NAK, why request turned down
+    union {        // Miscellaneous data, depending on request
+        struct {
+            long      elapsed_time;  // In 10ms "ticks"
+            long      count[2];      // Result 
+        } idle_results;
+    } misc;
+};
+
+#define NC_REPLY_ACK  0x0001    // Request accepted
+#define NC_REPLY_NAK  0x0000    // Request denied
+
+#define NC_REPLY_NAK_UNKNOWN_REQUEST 0x0001
+#define NC_REPLY_NAK_BAD_REQUEST     0x0002  // Slave can't handle
+#define NC_REPLY_NAK_NO_BACKGROUND   0x0003  // Slave can't do background/idle
+
+//
+// Test data 'packets' look like this
+
+struct nc_test_data {
+    long  key1;
+    int   seq;
+    int   len;
+    long  key2;
+    char  data[0];  // Actual data
+};
+
+#define NC_TEST_DATA_KEY1 0xC0DEADC0
+#define NC_TEST_DATA_KEY2 0xC0DEADC1
+
+struct nc_test_results {
+    long key1;         // Identify uniquely as a response record
+    int  seq;          // Matches request
+    int  nsent;
+    int  nrecvd;
+    long key2;         // Additional verification
+};
+
+#define NC_TEST_RESULT_KEY1 0xDEADC0DE
+#define NC_TEST_RESULT_KEY2 0xDEADC1DE
+
+#endif // _TESTS_NC_TEST_FRAMEWORK_H_
+
+
+
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/nc_test_slave.c
@@ -0,0 +1,867 @@
+//==========================================================================
+//
+//      tests/nc_test_slave.c
+//
+//      Network characterizations test (slave portion)
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas
+// Contributors: gthomas
+// Date:         2000-01-10
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// Network characterization test code - slave portion
+
+#include <cyg/ppp/ppp.h>
+
+#include <cyg/infra/testcase.h>
+
+#include "nc_test_framework.h"
+#include <math.h>
+
+#ifdef __ECOS
+
+#include "ppp_test_support.inl"
+
+#ifndef CYGPKG_LIBC_STDIO
+#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
+#endif
+#define STACK_SIZE               (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+#define MAX_LOAD_THREAD_LEVEL    20
+#define MIN_LOAD_THREAD_LEVEL    0
+#define NUM_LOAD_THREADS         10
+#define IDLE_THREAD_PRIORITY     CYGNUM_PPP_PPPD_THREAD_PRIORITY+3
+#define LOAD_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-1
+#define MAIN_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-2
+#define DESIRED_BACKGROUND_LOAD  20
+static char         main_thread_stack[CYGHWR_NET_DRIVERS][STACK_SIZE];
+static cyg_thread   main_thread_data[CYGHWR_NET_DRIVERS];
+static cyg_handle_t main_thread_handle[CYGHWR_NET_DRIVERS];
+static char         idle_thread_stack[STACK_SIZE];
+static cyg_thread   idle_thread_data;
+static cyg_handle_t idle_thread_handle;
+static cyg_sem_t    idle_thread_sem;
+volatile static long long    idle_thread_count;
+static cyg_tick_count_t idle_thread_start_time;
+static cyg_tick_count_t idle_thread_stop_time;
+static char         load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
+static cyg_thread   load_thread_data[NUM_LOAD_THREADS];
+static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
+static cyg_sem_t    load_thread_sem[NUM_LOAD_THREADS];
+static long         load_thread_level;
+static void calibrate_load(int load);
+static void start_load(int load);
+static void do_some_random_computation(int p);
+#define abs(n) ((n) < 0 ? -(n) : (n))
+#endif
+
+#ifdef __ECOS
+#define test_param_t cyg_addrword_t
+#ifdef CYGDBG_NET_TIMING_STATS
+extern void show_net_times(void);
+#endif
+#else
+#define test_param_t int
+#endif
+
+#define MAX_BUF 8192
+static unsigned char in_buf[MAX_BUF], out_buf[MAX_BUF];
+
+#ifdef __ECOS
+extern void
+cyg_test_exit(void);
+#else
+void
+cyg_test_exit(void)
+{
+    test_printf("... Done\n");
+    exit(1);
+}
+
+static void
+show_net_times(void)
+{
+}
+#endif
+
+#ifdef __ECOS
+static void
+test_delay(int ticks)
+{
+    cyg_thread_delay(ticks);
+}
+
+#else
+
+static void
+test_delay(int ticks)
+{
+    usleep(ticks * 10000);
+}
+#endif
+
+void
+pexit(char *s)
+{
+    perror(s);
+#ifdef CYGDBG_NET_TIMING_STATS
+    show_net_times();
+#endif
+    cyg_test_exit();
+}
+
+//
+// Generic UDP test
+//
+
+static void
+do_udp_test(int s1, struct nc_request *req, struct sockaddr_in *master)
+{
+    int i, s, td_len, seq, seq_errors, lost;
+    struct sockaddr_in test_chan_slave, test_chan_master;
+    fd_set fds;
+    struct timeval timeout;
+    struct nc_test_results results;
+    struct nc_test_data *tdp;
+    int nsent, nrecvd;
+    int need_recv, need_send;
+
+    need_recv = true;  need_send = true;
+    switch (ntohl(req->type)) {
+    case NC_REQUEST_UDP_SEND:
+        need_recv = false;
+        need_send = true;
+        break;
+    case NC_REQUEST_UDP_RECV:
+        need_recv = true;
+        need_send = false;
+        break;
+    case NC_REQUEST_UDP_ECHO:
+        break;
+    }
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        pexit("datagram socket");
+    }
+
+    memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
+    test_chan_slave.sin_family = AF_INET;
+#ifdef __ECOS
+    test_chan_slave.sin_len = sizeof(test_chan_slave);
+#endif
+    test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
+    test_chan_slave.sin_port = htons(ntohl(req->slave_port));
+    
+    if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
+        perror("bind");
+        close(s);
+    }
+
+    memcpy(&test_chan_master, master, sizeof(*master));
+    test_chan_master.sin_port = htons(ntohl(req->master_port));
+    nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
+    for (i = 0;  i < ntohl(req->nbufs);  i++) {
+        if (need_recv) {
+            FD_ZERO(&fds);
+            FD_SET(s, &fds);
+            timeout.tv_sec = NC_TEST_TIMEOUT;
+            timeout.tv_usec = 0;
+            if (select(s+1, &fds, 0, 0, &timeout) <= 0) {
+                test_printf("recvfrom timeout, expecting seq #%d\n", seq);            
+                if (++lost > MAX_ERRORS) {
+                    test_printf("... giving up\n");
+                    break;
+                }
+            } else {
+                nrecvd++;
+                tdp = (struct nc_test_data *)in_buf;
+                td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
+                if (recvfrom(s, tdp, td_len, 0, 0, 0) < 0) {
+                    perror("recvfrom");
+                    close(s);
+                    return;
+                }
+                if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
+                    (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
+                    if (ntohl(tdp->seq) != seq) {
+                        test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
+                                    ntohl(tdp->seq), seq);
+                        seq = ntohl(tdp->seq);
+                        seq_errors++;
+                    }
+                } else {
+                    test_printf("Bad data packet - key: %x/%x, seq: %d\n",
+                                ntohl(tdp->key1), ntohl(tdp->key2),
+                                ntohl(tdp->seq));
+                }
+            }
+        }
+        if (need_send) {
+            int retries = 10;
+            int sent = false;
+            int res;
+
+            tdp = (struct nc_test_data *)out_buf;
+            tdp->key1 = htonl(NC_TEST_DATA_KEY1);
+            tdp->key2 = htonl(NC_TEST_DATA_KEY2);
+            tdp->seq = htonl(seq);
+            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
+            tdp->len = htonl(td_len);
+            while (!sent && (--retries >= 0)) {
+                res = sendto(s, tdp, td_len, 0, 
+                             (struct sockaddr *)&test_chan_master, sizeof(test_chan_master));
+                if (res > 0) {
+                    sent = true;
+                    break;
+                }
+                if (errno == ENOBUFS) {
+                    // Saturated the system
+                    test_delay(1);   // Time for 200 500 byte 10-baseT packets 
+                } else {
+                    // What else to do?
+                    close(s);
+                    return;
+                }
+            }
+            if (sent) {
+                nsent++;
+            } else {
+                perror("sendto");
+            }
+        }
+        seq++;
+    }
+    results.key1 = htonl(NC_TEST_RESULT_KEY1);
+    results.key2 = htonl(NC_TEST_RESULT_KEY2);
+    results.seq = req->seq;
+    results.nsent = htonl(nsent);
+    results.nrecvd = htonl(nrecvd);
+    if (sendto(s, &results, sizeof(results), 0, 
+               (struct sockaddr *)&test_chan_master, sizeof(test_chan_master)) < 0) {
+        perror("sendto results");
+    }
+    close(s);
+}
+
+//
+// Read data from a stream, accounting for the fact that packet 'boundaries'
+// are not preserved.  This can also timeout (which would probably wreck the
+// data boundaries).
+//
+
+int
+do_read(int fd, void *buf, int buflen)
+{
+    char *p = (char *)buf;
+    int len = buflen;
+    int res;
+    while (len) {
+        res = read(fd, p, len);
+        if (res < 0) {
+            perror("read");
+        } else {
+            len -= res;
+            p += res;
+            if (res == 0) {
+                break;
+            }
+        }
+    }
+    return (buflen - len);
+}
+
+//
+// Generic TCP test
+//
+
+static void
+do_tcp_test(int s1, struct nc_request *req, struct sockaddr_in *master)
+{
+    int i, s, len, td_len, seq, seq_errors, lost, test_chan, res;
+    struct sockaddr_in test_chan_slave, test_chan_master;
+    struct nc_test_results results;
+    struct nc_test_data *tdp;
+    int nsent, nrecvd;
+    int need_recv, need_send;
+    int one = 1;
+    static int slave_tcp_port = -1;
+
+    need_recv = true;  need_send = true;
+    switch (ntohl(req->type)) {
+    case NC_REQUEST_TCP_SEND:
+        need_recv = false;
+        need_send = true;
+        break;
+    case NC_REQUEST_TCP_RECV:
+        need_recv = true;
+        need_send = false;
+        break;
+    case NC_REQUEST_TCP_ECHO:
+        break;
+    }
+
+    if (slave_tcp_port < 0) {
+        s = socket(AF_INET, SOCK_STREAM, 0);
+        if (s < 0) {
+            pexit("datagram socket");
+        }
+
+        if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
+            perror("setsockopt SO_REUSEADDR");
+            return;
+        }
+#ifdef SO_REUSEPORT
+        if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
+            perror("setsockopt SO_REUSEPORT");
+            return;
+        }
+#endif
+        memset((char *) &test_chan_slave, 0, sizeof(test_chan_slave));
+        test_chan_slave.sin_family = AF_INET;
+#ifdef __ECOS
+        test_chan_slave.sin_len = sizeof(test_chan_slave);
+#endif
+        test_chan_slave.sin_addr.s_addr = htonl(INADDR_ANY);
+        test_chan_slave.sin_port = htons(ntohl(req->slave_port));
+    
+        if (bind(s, (struct sockaddr *) &test_chan_slave, sizeof(test_chan_slave)) < 0) {
+            perror("bind");
+            close(s);
+        }
+        listen(s, SOMAXCONN);
+        slave_tcp_port = s;
+    }
+
+    s = slave_tcp_port;
+    len = sizeof(test_chan_master);
+    if ((test_chan = accept(s, (struct sockaddr *)&test_chan_master, &len)) < 0) {
+        pexit("accept");
+    }
+    len = sizeof(test_chan_master);
+    getpeername(test_chan, (struct sockaddr *)&test_chan_master, &len);
+    test_printf("connection from %s.%d\n", inet_ntoa(test_chan_master.sin_addr), 
+                ntohs(test_chan_master.sin_port));
+
+    nsent = 0;  nrecvd = 0;  seq = 0;  seq_errors = 0;  lost = 0;
+    for (i = 0;  i < ntohl(req->nbufs);  i++) {
+        if (need_recv) {
+            tdp = (struct nc_test_data *)in_buf;
+            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
+            res = do_read(test_chan, tdp, td_len);
+            if (res != td_len) {
+                test_printf("recvfrom timeout, expecting seq #%d\n", seq);            
+                if (++lost > MAX_ERRORS) {
+                    test_printf("... giving up\n");
+                    break;
+                }
+            } else {
+                nrecvd++;
+                if ((ntohl(tdp->key1) == NC_TEST_DATA_KEY1) &&
+                    (ntohl(tdp->key2) == NC_TEST_DATA_KEY2)) {
+                    if (ntohl(tdp->seq) != seq) {
+                        test_printf("Packets out of sequence - recvd: %d, expected: %d\n",
+                                    ntohl(tdp->seq), seq);
+                        seq = ntohl(tdp->seq);
+                        seq_errors++;
+                    }
+                } else {
+                    test_printf("Bad data packet - key: %x/%x, seq: %d\n",
+                                ntohl(tdp->key1), ntohl(tdp->key2),
+                                ntohl(tdp->seq));
+                }
+            }
+        }
+        if (need_send) {
+            tdp = (struct nc_test_data *)out_buf;
+            tdp->key1 = htonl(NC_TEST_DATA_KEY1);
+            tdp->key2 = htonl(NC_TEST_DATA_KEY2);
+            tdp->seq = htonl(seq);
+            td_len = ntohl(req->buflen) + sizeof(struct nc_test_data);
+            tdp->len = htonl(td_len);
+            if (write(test_chan, tdp, td_len) != td_len) {
+                perror("write");
+                if (errno == ENOBUFS) {
+                    // Saturated the system
+                    test_delay(25);
+                } else {
+                    // What else to do?
+                    close(test_chan);
+                    return;
+                }
+            } else {
+                nsent++;
+            }
+        }
+        seq++;
+    }
+    results.key1 = htonl(NC_TEST_RESULT_KEY1);
+    results.key2 = htonl(NC_TEST_RESULT_KEY2);
+    results.seq = req->seq;
+    results.nsent = htonl(nsent);
+    results.nrecvd = htonl(nrecvd);
+    if (write(test_chan, &results, sizeof(results)) != sizeof(results)) {
+        perror("write");
+    }
+    close(test_chan);
+}
+
+//
+// Protocol driver for testing slave.
+//
+// This function is the main routine running here, handling requests sent from
+// the master and providing various responses.
+//
+static void
+nc_slave(test_param_t param)
+{
+    int s, masterlen;
+    struct sockaddr_in my_addr, master;
+    struct nc_request req;
+    struct nc_reply reply;
+    int done = false;
+
+    test_printf("Start test for eth%d\n", param);
+
+    s = socket(AF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+        pexit("datagram socket");
+    }
+
+    memset((char *) &my_addr, 0, sizeof(my_addr));
+    my_addr.sin_family = AF_INET;
+#ifdef __ECOS
+    my_addr.sin_len = sizeof(my_addr);
+#endif
+    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+    my_addr.sin_port = htons(NC_SLAVE_PORT);
+    
+    if (bind(s, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
+        pexit("bind");
+    }
+
+    while (!done) {
+        masterlen = sizeof(master);
+        if (recvfrom(s, &req, sizeof(req), 0, (struct sockaddr *)&master, &masterlen) < 0) {
+            pexit("recvfrom");
+        }
+#if 0
+        test_printf("Request %d from %s:%d\n", ntohl(req.type), 
+                    inet_ntoa(master.sin_addr), ntohs(master.sin_port));
+#endif
+        reply.response = htonl(NC_REPLY_ACK);
+        reply.seq = req.seq;
+        switch (ntohl(req.type)) {
+        case NC_REQUEST_DISCONNECT:
+            done = true;
+            break;
+        case NC_REQUEST_UDP_SEND:
+            test_printf("UDP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+        case NC_REQUEST_UDP_RECV:
+            test_printf("UDP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+        case NC_REQUEST_UDP_ECHO:
+            test_printf("UDP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+        case NC_REQUEST_TCP_SEND:
+            test_printf("TCP send - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+        case NC_REQUEST_TCP_RECV:
+            test_printf("TCP recv - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+        case NC_REQUEST_TCP_ECHO:
+            test_printf("TCP echo - %d buffers, %d bytes\n", ntohl(req.nbufs), ntohl(req.buflen));
+            break;
+#ifdef __ECOS
+        case NC_REQUEST_SET_LOAD:
+            start_load(ntohl(req.nbufs));
+            break;
+        case NC_REQUEST_START_IDLE:
+            test_printf("Start IDLE thread\n");
+            idle_thread_count = 0;
+            idle_thread_start_time = cyg_current_time();
+            cyg_semaphore_post(&idle_thread_sem);
+            break;
+        case NC_REQUEST_STOP_IDLE:
+            cyg_semaphore_wait(&idle_thread_sem);
+            idle_thread_stop_time = cyg_current_time();
+            test_printf("Stop IDLE thread\n");
+            reply.misc.idle_results.elapsed_time = htonl(idle_thread_stop_time - idle_thread_start_time);
+            reply.misc.idle_results.count[0] = htonl(idle_thread_count >> 32);
+            reply.misc.idle_results.count[1] = htonl((long)idle_thread_count);
+            break;
+#endif
+        default:
+            test_printf("Unrecognized request: %d\n", ntohl(req.type));
+            reply.response = htonl(NC_REPLY_NAK);
+            reply.reason = htonl(NC_REPLY_NAK_UNKNOWN_REQUEST);
+            break;
+        }
+        if (sendto(s, &reply, sizeof(reply), 0, (struct sockaddr *)&master, masterlen) < 0) {
+            pexit("sendto");
+        }
+        if (reply.response == ntohl(NC_REPLY_NAK)) {
+            continue;
+        }
+        switch (ntohl(req.type)) {
+        case NC_REQUEST_UDP_SEND:
+        case NC_REQUEST_UDP_RECV:
+        case NC_REQUEST_UDP_ECHO:
+            do_udp_test(s, &req, &master);
+            break;
+        case NC_REQUEST_TCP_SEND:
+        case NC_REQUEST_TCP_RECV:
+        case NC_REQUEST_TCP_ECHO:
+            do_tcp_test(s, &req, &master);
+            break;
+        case NC_REQUEST_START_IDLE:
+        case NC_REQUEST_STOP_IDLE:
+        case NC_REQUEST_SET_LOAD:
+        default:
+            break;
+        }
+    }
+    close(s);
+}
+
+void
+net_test(test_param_t param)
+{
+#ifdef __ECOS
+    cyg_serial_baud_rate_t old;    
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+
+    CYG_TEST_INIT();
+#endif
+
+//    int i;
+    if (param == 0) {
+        test_printf("Start Network Characterization - SLAVE\n");
+#ifdef __ECOS
+        init_all_network_interfaces();
+        calibrate_load(DESIRED_BACKGROUND_LOAD);
+#if 0
+// I can see what this is trying to do, but I get "bind: Address already in
+// use" errors from the 2nd interface - and the parameter is not used
+// anyway, so one thread does quite well enough (but only tests one i/f at
+// once).
+
+// Comment in the 'int i' above too.
+        for (i = 1;  i < CYGHWR_NET_DRIVERS;  i++) {
+            cyg_thread_resume(main_thread_handle[i]);   // Start other threads
+        }
+#endif
+#endif
+    }
+
+#ifdef __ECOS
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_115200 );
+
+    ppp_test_announce( "NC_TEST_SLAVE" );
+    
+    cyg_ppp_options_init( &options );
+
+//    options.debug = 1;
+//    options.kdebugflag = 1;
+
+//    options.script = script;
+//    options.flowctl = CYG_PPP_FLOWCTL_SOFTWARE;
+
+    ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+    CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+    cyg_ppp_wait_up( ppp_handle );
+#endif
+    
+    nc_slave(param);
+#ifdef CYGDBG_NET_TIMING_STATS
+    show_net_times();
+#endif
+
+#ifdef __ECOS
+    CYG_TEST_INFO( "Bringing PPP down");
+
+    cyg_ppp_down( ppp_handle );
+    
+    CYG_TEST_INFO( "Waiting for PPP to go down");
+
+    cyg_ppp_wait_down( ppp_handle );
+
+    cyg_thread_delay( 200 );
+
+    ppp_test_set_baud( old );
+
+    ppp_test_finish();
+
+    CYG_TEST_PASS_FINISH( "Network Characterization - SLAVE" );
+    
+#endif
+    
+    cyg_test_exit();
+}
+
+#ifdef __ECOS
+
+//
+// This function is called to calibrate the "background load" which can be
+// applied during testing.  It will be called before any commands from the
+// host are managed.
+//
+static void
+calibrate_load(int desired_load)
+{
+    long long no_load_idle, load_idle;
+    int percent_load;
+    int high, low;
+
+    // Set limits
+    high = MAX_LOAD_THREAD_LEVEL;
+    low = MIN_LOAD_THREAD_LEVEL;
+
+    // Compute the "no load" idle value
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    cyg_thread_delay(1*100);               // Pause for one second
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    no_load_idle = idle_thread_count;
+    diag_printf("No load = %d\n", (int)idle_thread_count);
+
+    // First ensure that the HIGH level is indeed higher
+    while (true) {
+        load_thread_level = high;
+        start_load(desired_load);              // Start up a given load
+        idle_thread_count = 0;
+        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+        cyg_thread_delay(1*100);               // Pause for one second
+        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+        load_idle = idle_thread_count;
+        start_load(0);                         // Shut down background load
+        percent_load = 100 - ((load_idle * 100) / no_load_idle);
+        diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level, 
+                    (int)idle_thread_count, percent_load);
+        if ( percent_load > desired_load )
+            break; // HIGH level is indeed higher
+        low = load_thread_level; // known to be lower
+        high *= 2; // else double it and try again
+    }
+
+    // Now chop down to the level required
+    while (true) {
+        load_thread_level = (high + low) / 2;
+        start_load(desired_load);              // Start up a given load
+        idle_thread_count = 0;
+        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+        cyg_thread_delay(1*100);               // Pause for one second
+        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+        load_idle = idle_thread_count;
+        start_load(0);                         // Shut down background load
+        percent_load = 100 - ((load_idle * 100) / no_load_idle);
+        diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, 
+                    (int)idle_thread_count, percent_load);
+        if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
+        if (percent_load < desired_load) {
+            low = load_thread_level;
+        } else {            
+            high = load_thread_level;
+        }
+    }
+
+    // Now we are within a few percent of the target; scale the load
+    // factor to get a better fit, and test it, print the answer.
+    load_thread_level *= desired_load;
+    load_thread_level /= percent_load;
+    start_load(desired_load);              // Start up a given load
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    cyg_thread_delay(1*100);               // Pause for one second
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    load_idle = idle_thread_count;
+    start_load(0);                         // Shut down background load
+    percent_load = 100 - ((load_idle * 100) / no_load_idle);
+    diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, 
+                (int)idle_thread_count, percent_load);
+//    no_load_idle_count_1_second = no_load_idle;
+}
+
+//
+// This function is called to set up a load level of 'load' percent (given
+// as a whole number, e.g. start_load(20) would mean initiate a background
+// load of 20%, leaving the cpu 80% idle).
+//
+static void
+start_load(int load)
+{
+    static int prev_load = 0;
+    int i;
+    test_printf("Set background load = %d%%\n", load);
+    if (load == 0) {
+        if (prev_load == 0) return;  // Nothing out there to stop
+        for (i = 0;  i < prev_load/10;  i++) {
+            cyg_semaphore_wait(&load_thread_sem[i]);
+        }
+        prev_load = 0;
+    } else {
+        for (i = 0;  i < load/10;  i++) {
+            cyg_semaphore_post(&load_thread_sem[i]);
+        }
+        prev_load = load;
+    }
+}
+
+//
+// These thread(s) do some amount of "background" computing.  This is used
+// to simulate a given load level.  They need to be run at a higher priority 
+// than the network code itself.
+//
+// Like the "idle" thread, they run as long as their "switch" (aka semaphore)
+// is enabled.
+//
+void
+net_load(cyg_addrword_t who)
+{
+    int i;
+    while (true) {
+        cyg_semaphore_wait(&load_thread_sem[who]);
+        for (i = 0;  i < load_thread_level;  i++) {
+            do_some_random_computation(i);
+        }
+        cyg_thread_delay(1);  // Wait until the next 'tick'
+        cyg_semaphore_post(&load_thread_sem[who]);
+    }
+}
+
+//
+// Some arbitrary computation, designed to use up the CPU and cause associated
+// cache "thrash" behaviour - part of background load modelling.
+//
+static void
+do_some_random_computation(int p)
+{
+    // Just something that might be "hard"
+    volatile double x;
+    x = ((p * 10) * 3.14159) / 180.0;  // radians
+}
+
+//
+// This thread does nothing but count.  It will be allowed to count
+// as long as the semaphore is "free".  
+//
+void
+net_idle(cyg_addrword_t param)
+{
+    while (true) {
+        cyg_semaphore_wait(&idle_thread_sem);
+        idle_thread_count++;
+        cyg_semaphore_post(&idle_thread_sem);
+    }
+}
+
+void
+cyg_start(void)
+{
+    int i;
+    // Create processing threads
+    for (i = 0;  i < CYGHWR_NET_DRIVERS;  i++) {
+        cyg_thread_create(MAIN_THREAD_PRIORITY,     // Priority
+                          net_test,                 // entry
+                          i,                        // entry parameter
+                          "Network test",           // Name
+                          &main_thread_stack[i][0], // Stack
+                          STACK_SIZE,               // Size
+                          &main_thread_handle[i],   // Handle
+                          &main_thread_data[i]      // Thread data structure
+            );
+    }
+    cyg_thread_resume(main_thread_handle[0]);   // Start first one
+    // Create the idle thread environment
+    cyg_semaphore_init(&idle_thread_sem, 0);
+    cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority
+                      net_idle,                 // entry
+                      0,                        // entry parameter
+                      "Network idle",           // Name
+                      &idle_thread_stack[0],    // Stack
+                      STACK_SIZE,               // Size
+                      &idle_thread_handle,      // Handle
+                      &idle_thread_data         // Thread data structure
+            );
+    cyg_thread_resume(idle_thread_handle);      // Start it
+    // Create the load threads and their environment(s)
+    for (i = 0;  i < NUM_LOAD_THREADS;  i++) {
+        cyg_semaphore_init(&load_thread_sem[i], 0);
+        cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority
+                          net_load,                 // entry
+                          i,                        // entry parameter
+                          "Background load",        // Name
+                          &load_thread_stack[i][0], // Stack
+                          STACK_SIZE,               // Size
+                          &load_thread_handle[i],   // Handle
+                          &load_thread_data[i]      // Thread data structure
+            );
+        cyg_thread_resume(load_thread_handle[i]);   // Start it
+    }
+    cyg_scheduler_start();
+}
+
+#else
+
+int 
+main(int argc, char *argv[])
+{
+    net_test(0);
+}
+#endif
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/ppp_auth.c
@@ -0,0 +1,260 @@
+//==========================================================================
+//
+//      tests/ppp_auth.c
+//
+//      Simple test of PPP authentication support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: nickg
+// Date:         2003-06-01
+// Purpose:      
+// Description:  This test just brings the PPP link up and waits for the
+//               other end to bring it down. Meanwhile the other end can
+//               ping us, or talk to the HTTPD if it is configured.
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test code
+
+#include "ppp_test_support.inl"
+
+//==========================================================================
+
+typedef void pr_fun(char *fmt, ...);
+
+externC void show_network_tables(pr_fun *pr);
+
+//==========================================================================
+    
+
+#ifndef CYGPKG_LIBC_STDIO
+#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
+#endif
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+//==========================================================================
+// Tests
+//
+// The following table contains parameters for various tests permuting
+// the authentication requirements of the peer, the authentication
+// requirements of this end and the user name and password used.
+//
+// For this test to work the /etc/ppp/pap-secrets file on the remote
+// end should contain the following two lines:
+//
+// eCos       *         secret       *
+// eCosPAP    *         secretPAP    *
+//
+// The /etc/ppp/chap-secrets file should contain:
+//
+// eCos       *         secret       *
+// eCosCHAP   *         secretCHAP   *
+//
+
+static struct auth_info
+{
+    char                        *name;
+    cyg_serial_baud_rate_t      baud;
+    int                         refuse_pap;
+    int                         refuse_chap;
+    char	                user[MAXNAMELEN];
+    char	                passwd[MAXSECRETLEN];
+    cyg_int32                   result;
+} tests[] =
+{
+    // PPP_AUTH_1 just tries the default auth mechanism for the server
+    { "PPP_AUTH_1", CYGNUM_SERIAL_BAUD_115200, 0, 0, "eCos", "secret", 0 },
+    { "PPP_AUTH_1", CYGNUM_SERIAL_BAUD_115200, 0, 0, "eCos", "secretX", -1 },
+    { "PPP_AUTH_1", CYGNUM_SERIAL_BAUD_115200, 0, 0, "eCosX", "secret", -1 },
+
+    // PPP_AUTH_2 requires PAP authentication only
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCosCHAP", "secretCHAP", -1 },
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCosPAP", "secretPAP", -1 },
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCos", "secret", -1 },
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCosCHAP", "secretCHAP", -1 },
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCosPAP", "secretPAP", 0 },
+    { "PPP_AUTH_2", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCos", "secret", 0 },
+
+    // PPP_AUTH_3 requires CHAP authentication only
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCosPAP", "secretPAP", -1 },
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCosCHAP", "secretCHAP", -1 },
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 0, 1, "eCos", "secret", -1 },
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCosPAP", "secretPAP", -1 },
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCosCHAP", "secretCHAP", 0 },
+    { "PPP_AUTH_3", CYGNUM_SERIAL_BAUD_115200, 1, 0, "eCos", "secret", 0 },    
+    
+    { NULL }
+};
+
+//==========================================================================
+
+
+static int do_test( struct auth_info *test )
+{
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+    int i = 0;
+    cyg_int32 result;
+    
+    CYG_TEST_INFO( test->name );
+            
+    ppp_test_set_baud( test->baud );
+    
+    ppp_test_announce( test->name );
+    
+    cyg_ppp_options_init( &options );
+
+//    options.debug = 1;
+//    options.kdebugflag = 1;
+
+    options.baud = test->baud;
+    options.refuse_pap = test->refuse_pap;
+    options.refuse_chap = test->refuse_chap;
+    strncpy( options.user, test->user, MAXNAMELEN );
+    strncpy( options.passwd, test->passwd, MAXNAMELEN );
+    
+//    show_network_tables( diag_printf );
+    
+    ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+    CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+    result = cyg_ppp_wait_up( ppp_handle );
+
+    if( result != test->result )
+    {
+        CYG_TEST_INFO( "Failed" );
+
+        return 0;
+    }
+    else
+    {
+        CYG_TEST_INFO( "Waiting until remote end goes down");
+
+        while( cyg_ppp_wait_up( ppp_handle ) == 0 )
+        {
+            i++;
+
+//            if( (i % 60) == 0 )
+//                show_network_tables( diag_printf );
+
+            cyg_thread_delay(100);
+        }
+
+        cyg_ppp_wait_down( ppp_handle );
+
+        return 1;
+    }
+    
+}
+
+//==========================================================================
+
+void
+ppp_test(cyg_addrword_t p)
+{
+    cyg_serial_baud_rate_t old;
+    struct auth_info *test;
+    int failures = 0;
+    
+    CYG_TEST_INIT();
+    diag_printf("Start PPP test\n");
+
+    init_all_network_interfaces();
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_38400 );
+
+
+    for( test = &tests[0]; test->name != NULL; test++ )
+    {
+        if( !do_test( test ) )
+            failures++;
+
+        cyg_thread_delay(300);
+    }
+
+    ppp_test_set_baud( old );
+    
+    ppp_test_finish();
+
+    if( failures > 0 )
+        CYG_TEST_FAIL("Some tests failed");
+    else
+        CYG_TEST_PASS("OK");
+    
+    CYG_TEST_FINISH("PPP auth test");
+}
+
+//==========================================================================
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      ppp_test,          // entry
+                      0,                 // entry parameter
+                      "PPP test",        // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/ppp_test_support.inl
@@ -0,0 +1,225 @@
+//==========================================================================
+//
+//      tests/ppp_test_support.c
+//
+//      PPP testing support routines
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: nickg
+// Date:         2003-07-01
+// Purpose:      
+// Description:  This file contains routines that are used by the PPP tests.
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test support
+
+#include <network.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+#include <pkgconf/ppp.h>
+
+#include <cyg/ppp/ppp.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/serialio.h>
+
+#include <stdio.h>
+
+#include <cyg/infra/testcase.h>
+
+//==========================================================================
+
+static cyg_serial_baud_rate_t ppp_test_set_baud( cyg_serial_baud_rate_t baud )
+{
+#ifdef CYGPKG_PPP_TESTS_AUTOMATE
+    cyg_io_handle_t     handle;
+    cyg_serial_info_t   cfg;
+    int                 err;
+    int                 len = sizeof(cfg);
+    char                buf[30];
+    int                 blen;
+    cyg_serial_baud_rate_t old_baud;
+    
+
+    CYG_TEST_INFO( "Switching baud rate" );
+    
+    err = cyg_io_lookup( CYGPKG_PPP_TEST_DEVICE, &handle );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_lookup: failed");
+    }
+
+    sprintf( buf, "BAUD:%03d\r\n", baud );
+    blen = strlen(buf);
+    
+    err = cyg_io_write( handle, buf, &blen );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_write: failed");
+    }
+
+    // Wait for those characters to reach the remote end
+    cyg_thread_delay(200);
+
+    err = cyg_io_get_config( handle,
+                             CYG_IO_GET_CONFIG_SERIAL_INFO,
+                             &cfg,
+                             &len);
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_get_config: failed");
+    }
+
+    cfg.flags |= CYGNUM_SERIAL_FLOW_RTSCTS_RX|CYGNUM_SERIAL_FLOW_RTSCTS_TX;
+
+    old_baud = cfg.baud;
+    cfg.baud = baud;
+    
+    err = cyg_io_set_config( handle,
+                             CYG_IO_SET_CONFIG_SERIAL_INFO,
+                             &cfg,
+                             &len);
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_set_config failed");
+    }
+
+    // Wait for other end to switch...
+    cyg_thread_delay(100);
+
+    CYG_TEST_INFO( "Baud rate switched" );
+
+    return old_baud;
+
+#else
+    return 0;
+#endif
+
+
+}
+
+//==========================================================================
+
+static void ppp_test_announce( char *buf )
+{
+#ifdef CYGPKG_PPP_TESTS_AUTOMATE    
+    cyg_io_handle_t     handle;
+    int                 err;
+    int                 blen;
+
+//    cyg_thread_delay(200);
+
+    CYG_TEST_INFO( "Sending announce string" );
+    
+    err = cyg_io_lookup( CYGPKG_PPP_TEST_DEVICE, &handle );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_lookup: failed");
+    }
+
+    blen = strlen(buf);
+  
+    err = cyg_io_write( handle, buf, &blen );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_write: failed");
+    }
+
+    blen = 2;
+    err = cyg_io_write( handle, "\r\n", &blen );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_write: failed");
+    }
+
+    cyg_thread_delay(200);        
+
+    CYG_TEST_INFO( "Announce string sent" );
+#endif
+}
+
+//==========================================================================
+
+static void ppp_test_finish(void)
+{
+#ifdef CYGPKG_PPP_TESTS_AUTOMATE    
+    cyg_io_handle_t     handle;
+    int                 err;
+    char                *buf = "FINISH\r\n";
+    int                 blen;
+
+//    cyg_thread_delay(200);
+
+    CYG_TEST_INFO( "Sending FINISH" );
+    
+    err = cyg_io_lookup( CYGPKG_PPP_TEST_DEVICE, &handle );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_lookup: failed");
+    }
+
+    blen = strlen(buf);
+  
+    err = cyg_io_write( handle, buf, &blen );
+
+    if( err != 0 ) {
+        CYG_TEST_INFO("cyg_io_write: failed");
+    }
+
+    cyg_thread_delay(200);        
+
+    CYG_TEST_INFO( "FINISH sent" );
+#endif
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/ppp_up.c
@@ -0,0 +1,190 @@
+//==========================================================================
+//
+//      tests/ppp_up.c
+//
+//      Simple test of PPP and networking support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: nickg
+// Date:         2003-06-01
+// Purpose:      
+// Description:  This test just brings the PPP link up and waits for the
+//               other end to bring it down. Meanwhile the other end can
+//               ping us, or talk to the HTTPD if it is configured.
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test code
+
+#include "ppp_test_support.inl"
+
+//==========================================================================
+
+typedef void pr_fun(char *fmt, ...);
+
+externC void show_network_tables(pr_fun *pr);
+
+//==========================================================================
+    
+
+#ifndef CYGPKG_LIBC_STDIO
+#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
+#endif
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+//==========================================================================
+
+static void do_test( cyg_serial_baud_rate_t baud )
+{
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+    int i = 0;
+
+    ppp_test_announce( "PPP_UP" );
+    
+    cyg_ppp_options_init( &options );
+
+//    options.debug = 1;
+//    options.kdebugflag = 1;
+
+    options.baud = baud;
+    
+    show_network_tables( diag_printf );
+    
+    ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+    CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+    cyg_ppp_wait_up( ppp_handle );
+
+    CYG_TEST_INFO( "Waiting until remote end goes down");
+
+    while( cyg_ppp_wait_up( ppp_handle ) == 0 )
+    {
+        i++;
+
+        if( (i % 60) == 0 )
+            show_network_tables( diag_printf );
+
+        cyg_thread_delay(100);
+    }
+    
+    cyg_ppp_wait_down( ppp_handle );
+}
+
+//==========================================================================
+
+void
+ppp_test(cyg_addrword_t p)
+{
+    cyg_serial_baud_rate_t old;
+    
+    CYG_TEST_INIT();
+    diag_printf("Start PPP test\n");
+
+    init_all_network_interfaces();
+
+//    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_115200 );
+//    do_test( CYGNUM_SERIAL_BAUD_115200 );
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_19200 );
+    do_test( CYGNUM_SERIAL_BAUD_19200 );
+
+#ifdef CYGPKG_PPP_TESTS_AUTOMATE
+
+    {
+        static cyg_serial_baud_rate_t test_rates[] =
+            { CYGDAT_PPP_TEST_BAUD_RATES, 0 };
+
+        int i;
+
+        for( i = 0; test_rates[i] != 0; i++ )
+        {
+            ppp_test_set_baud( test_rates[i] );
+            do_test( test_rates[i] );
+        }
+
+        ppp_test_set_baud( old );
+    
+        ppp_test_finish();
+        
+    }
+           
+#endif
+    
+    CYG_TEST_PASS_FINISH("PPP test OK");
+}
+
+//==========================================================================
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      ppp_test,          // entry
+                      0,                 // entry parameter
+                      "PPP test",        // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/ppp_updown.c
@@ -0,0 +1,407 @@
+//==========================================================================
+//
+//      tests/ppp_updown.c
+//
+//      Simple test of PPP and networking support
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    nickg
+// Contributors: gthomas (ping code), nickg
+// Date:         2003-06-01
+// Purpose:      
+// Description:  
+//              
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+// PPP test code
+
+#include <network.h>
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#include "ppp_test_support.inl"
+
+//==========================================================================
+
+typedef void pr_fun(char *fmt, ...);
+
+externC void show_network_tables(pr_fun *pr);
+
+//==========================================================================
+
+#include <arpa/inet.h>
+
+// Fill in the blanks if necessary
+#ifndef TNR_OFF
+# define TNR_OFF()
+#endif
+#ifndef TNR_ON
+# define TNR_ON()
+#endif
+#ifndef TNR_INIT
+# define TNR_INIT()
+#endif
+#ifndef TNR_PRINT_ACTIVITY
+# define TNR_PRINT_ACTIVITY()
+#endif
+
+#define NUM_PINGS 16
+#define MAX_PACKET 4096
+#define MIN_PACKET   64
+#define MAX_SEND   4000
+
+#define PACKET_ADD  ((MAX_SEND - MIN_PACKET)/NUM_PINGS)
+#define nPACKET_ADD  1 
+
+static unsigned char pkt1[MAX_PACKET], pkt2[MAX_PACKET];
+
+#define UNIQUEID 0x1234
+
+void
+pexit(char *s)
+{
+    CYG_TEST_FAIL_FINISH(s);
+}
+
+// Compute INET checksum
+int
+inet_cksum(u_short *addr, int len)
+{
+    register int nleft = len;
+    register u_short *w = addr;
+    register u_short answer;
+    register u_int sum = 0;
+    u_short odd_byte = 0;
+
+    /*
+     *  Our algorithm is simple, using a 32 bit accumulator (sum),
+     *  we add sequential 16 bit words to it, and at the end, fold
+     *  back all the carry bits from the top 16 bits into the lower
+     *  16 bits.
+     */
+    while( nleft > 1 )  {
+        sum += *w++;
+        nleft -= 2;
+    }
+
+    /* mop up an odd byte, if necessary */
+    if( nleft == 1 ) {
+        *(u_char *)(&odd_byte) = *(u_char *)w;
+        sum += odd_byte;
+    }
+
+    /*
+     * add back carry outs from top 16 bits to low 16 bits
+     */
+    sum = (sum >> 16) + (sum & 0x0000ffff); /* add hi 16 to low 16 */
+    sum += (sum >> 16);                     /* add carry */
+    answer = ~sum;                          /* truncate to 16 bits */
+    return (answer);
+}
+
+static int
+show_icmp(unsigned char *pkt, int len, 
+          struct sockaddr_in *from, struct sockaddr_in *to)
+{
+#if 1
+    cyg_tick_count_t *tp, tv;
+    struct ip *ip;
+    struct icmp *icmp;
+    tv = cyg_current_time();
+    ip = (struct ip *)pkt;
+    if ((len < sizeof(*ip)) || ip->ip_v != IPVERSION) {
+        diag_printf("%s: Short packet or not IP! - Len: %d, Version: %d\n", 
+                    inet_ntoa(from->sin_addr), len, ip->ip_v);
+        return 0;
+    }
+    icmp = (struct icmp *)(pkt + sizeof(*ip));
+    len -= (sizeof(*ip) + 8);
+    tp = (cyg_tick_count_t *)&icmp->icmp_data;
+    if (icmp->icmp_type != ICMP_ECHOREPLY) {
+        diag_printf("%s: Invalid ICMP - type: %d\n", 
+                    inet_ntoa(from->sin_addr), icmp->icmp_type);
+        return 0;
+    }
+    if (icmp->icmp_id != UNIQUEID) {
+        diag_printf("%s: ICMP received for wrong id - sent: %x, recvd: %x\n", 
+                    inet_ntoa(from->sin_addr), UNIQUEID, icmp->icmp_id);
+    }
+    diag_printf("%d bytes from %s: ", len, inet_ntoa(from->sin_addr));
+    diag_printf("icmp_seq=%d", icmp->icmp_seq);
+    diag_printf(", time=%dms\n", (int)(tv - *tp)*10);
+    return (from->sin_addr.s_addr == to->sin_addr.s_addr);
+#else
+    return 1;
+#endif
+}
+
+static void
+ping_host(int s, struct sockaddr_in *host)
+{
+    struct icmp *icmp = (struct icmp *)pkt1;
+    int icmp_len = MIN_PACKET;
+    int seq, ok_recv, bogus_recv;
+    cyg_tick_count_t *tp;
+    long *dp;
+    struct sockaddr_in from;
+    int i, len, fromlen;
+
+    ok_recv = 0;
+    bogus_recv = 0;
+    diag_printf("PING server %s\n", inet_ntoa(host->sin_addr));
+    for (seq = 0;  seq < NUM_PINGS;  seq++, icmp_len += PACKET_ADD ) {
+        TNR_ON();
+        // Build ICMP packet
+        icmp->icmp_type = ICMP_ECHO;
+        icmp->icmp_code = 0;
+        icmp->icmp_cksum = 0;
+        icmp->icmp_seq = seq;
+        icmp->icmp_id = 0x1234;
+        // Set up ping data
+        tp = (cyg_tick_count_t *)&icmp->icmp_data;
+        *tp++ = cyg_current_time();
+        dp = (long *)tp;
+        for (i = sizeof(*tp);  i < icmp_len;  i += sizeof(*dp)) {
+            *dp++ = i;
+        }
+        // Add checksum
+        icmp->icmp_cksum = inet_cksum( (u_short *)icmp, icmp_len+8);
+        // Send it off
+        if (sendto(s, icmp, icmp_len+8, 0, (struct sockaddr *)host, sizeof(*host)) < 0) {
+            TNR_OFF();
+            perror("sendto");
+            continue;
+        }
+        // Wait for a response
+        fromlen = sizeof(from);
+        len = recvfrom(s, pkt2, sizeof(pkt2), 0, (struct sockaddr *)&from, &fromlen);
+        TNR_OFF();
+        if (len < 0) {
+            perror("recvfrom");
+            icmp_len = MIN_PACKET - PACKET_ADD; // just in case - long routes
+        } else {
+            if (show_icmp(pkt2, len, &from, host)) {
+                ok_recv++;
+            } else {
+                bogus_recv++;
+            }
+        }
+    }
+    TNR_OFF();
+    diag_printf("Sent %d packets, received %d OK, %d bad\n", NUM_PINGS, ok_recv, bogus_recv);
+}
+
+static void do_ping(void)
+{
+    struct protoent *p;
+    struct timeval tv;
+    struct sockaddr_in host;
+    int s;
+
+    if ((p = getprotobyname("icmp")) == (struct protoent *)0) {
+        pexit("getprotobyname");
+        return;
+    }
+    s = socket(AF_INET, SOCK_RAW, p->p_proto);
+    if (s < 0) {
+        pexit("socket");
+        return;
+    }
+    tv.tv_sec = 7;
+    tv.tv_usec = 0;
+    setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+    // Set up host address
+    host.sin_family = AF_INET;
+    host.sin_len = sizeof(host);
+    host.sin_port = 0;
+
+    // Set a default remote end address
+    inet_aton("10.0.0.100", &host.sin_addr);
+
+    // Now quiz the ppp0 interface for its destination address and use
+    // that as our ping-buddy.
+    {
+        struct ifreq ifr;
+        int sock = socket(AF_INET, SOCK_DGRAM, 0);
+
+        if( sock != -1 )
+        {
+            strncpy( ifr.ifr_name, "ppp0", sizeof(ifr.ifr_name));
+            if( ioctl( sock, SIOCGIFDSTADDR, &ifr ) == 0 )
+                host.sin_addr = ((struct sockaddr_in *)&ifr.ifr_dstaddr)->sin_addr;
+        
+            close(sock);
+        }
+    }
+    
+    ping_host(s, &host);
+    
+}
+
+//==========================================================================
+    
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+
+//==========================================================================
+
+static void do_test( cyg_serial_baud_rate_t baud )
+{
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+
+    ppp_test_announce( "PPP_UPDOWN" );
+    
+    cyg_ppp_options_init( &options );
+
+//    options.debug = 1;
+//    options.kdebugflag = 1;
+
+    options.baud = baud;
+    
+    ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+    CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+    cyg_ppp_wait_up( ppp_handle );
+
+//    show_network_tables( diag_printf );
+
+    CYG_TEST_INFO( "Delaying...");
+
+    cyg_thread_delay(10*100);
+    
+    CYG_TEST_INFO( "Pinging remote");
+
+    do_ping();
+
+//    show_network_tables( diag_printf );
+    
+    CYG_TEST_INFO( "Bringing PPP down");
+
+    cyg_ppp_down( ppp_handle );
+    
+    CYG_TEST_INFO( "Waiting for PPP to go down");
+
+    cyg_ppp_wait_down( ppp_handle );
+}
+
+//==========================================================================
+
+void
+ppp_test(cyg_addrword_t p)
+{
+    cyg_serial_baud_rate_t old;
+    
+    CYG_TEST_INIT();
+    diag_printf("Start PPP test\n");
+
+    init_all_network_interfaces();
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_115200 );
+    do_test( CYGNUM_SERIAL_BAUD_115200 );
+
+#ifdef CYGPKG_PPP_TESTS_AUTOMATE
+
+    CYG_TEST_INFO( "Delaying...");
+    cyg_thread_delay(10*100);
+    
+    {
+        static cyg_serial_baud_rate_t test_rates[] =
+            { CYGDAT_PPP_TEST_BAUD_RATES, 0 };
+
+        int i;
+
+        for( i = 0; test_rates[i] != 0; i++ )
+        {
+            ppp_test_set_baud( test_rates[i] );
+            do_test( test_rates[i] );
+
+            CYG_TEST_INFO( "Delaying...");
+            cyg_thread_delay(10*100);
+            
+        }
+
+        ppp_test_set_baud( old );
+    
+        ppp_test_finish();
+        
+    }
+           
+#endif
+    
+    CYG_TEST_PASS_FINISH("PPP test OK");
+}
+
+//==========================================================================
+
+void
+cyg_start(void)
+{
+    // Create a main thread, so we can run the scheduler and have time 'pass'
+    cyg_thread_create(10,                // Priority - just a number
+                      ppp_test,          // entry
+                      0,                 // entry parameter
+                      "PPP test",        // Name
+                      &stack[0],         // Stack
+                      STACK_SIZE,        // Size
+                      &thread_handle,    // Handle
+                      &thread_data       // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    cyg_scheduler_start();
+}
+
+//==========================================================================
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/tcp_echo.c
@@ -0,0 +1,642 @@
+//==========================================================================
+//
+//      tests/tcp_echo.c
+//
+//      Simple TCP throughput test - echo component
+//
+//==========================================================================
+//####ECOSGPLCOPYRIGHTBEGIN####
+// -------------------------------------------
+// This file is part of eCos, the Embedded Configurable Operating System.
+// Portions created by Nick Garnett are
+// Copyright (C) 2003 eCosCentric Ltd.
+//
+// eCos is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 or (at your option) any later version.
+//
+// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with eCos; if not, write to the Free Software Foundation, Inc.,
+// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+//
+// As a special exception, if other files instantiate templates or use macros
+// or inline functions from this file, or you compile this file and link it
+// with other works to produce a work based on this file, this file does not
+// by itself cause the resulting work to be covered by the GNU General Public
+// License. However the source code for this file must still be made available
+// in accordance with section (3) of the GNU General Public License.
+//
+// This exception does not invalidate any other reasons why a work based on
+// this file might be covered by the GNU General Public License.
+//
+// -------------------------------------------
+//####ECOSGPLCOPYRIGHTEND####
+//####BSDCOPYRIGHTBEGIN####
+//
+// -------------------------------------------
+//
+// Portions of this software may have been derived from OpenBSD, 
+// FreeBSD or other sources, and are covered by the appropriate
+// copyright disclaimers included herein.
+//
+// -------------------------------------------
+//
+//####BSDCOPYRIGHTEND####
+//==========================================================================
+//#####DESCRIPTIONBEGIN####
+//
+// Author(s):    gthomas, nickg
+// Contributors: gthomas, nickg
+// Date:         2000-01-10
+// Purpose:      
+// Description:  This is the middle part of a three part test.  The idea is
+//   to test the throughput of box in a configuration like this:
+//
+//      +------+   port   +----+     port    +----+
+//      |SOURCE|=========>|ECHO|============>|SINK|
+//      +------+   9990   +----+     9991    +----+
+// 
+//
+//####DESCRIPTIONEND####
+//
+//==========================================================================
+
+#include <pkgconf/system.h>
+#include <pkgconf/net.h>
+
+#include <cyg/io/io.h>
+#include <cyg/io/serialio.h>
+
+#include <cyg/ppp/ppp.h>
+
+#include <cyg/infra/testcase.h>
+
+#include "ppp_test_support.inl"
+
+
+// Network throughput test code
+
+#include <network.h>
+
+static __inline__ unsigned int
+max(unsigned int m, unsigned int n)
+{
+    return m > n ? m : n;
+}
+
+#define SOURCE_PORT 9990
+#define SINK_PORT   9991
+
+#define MAX_BUF 8192
+static unsigned char data_buf[MAX_BUF];
+
+struct test_params {
+    long nbufs;
+    long bufsize;
+    long load;
+};
+
+struct test_status {
+    long ok;
+};
+
+#ifndef CYGPKG_LIBC_STDIO
+#define perror(s) diag_printf(#s ": %s\n", strerror(errno))
+#endif
+
+#define STACK_SIZE (CYGNUM_HAL_STACK_SIZE_TYPICAL + 0x1000)
+static char stack[STACK_SIZE];
+static cyg_thread thread_data;
+static cyg_handle_t thread_handle;
+
+// Background load stuff
+#define NUM_LOAD_THREADS         20 // Get 5% granularity
+#define IDLE_THREAD_PRIORITY     CYGNUM_PPP_PPPD_THREAD_PRIORITY+3
+#define LOAD_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-3
+#define MAIN_THREAD_PRIORITY     CYGPKG_NET_THREAD_PRIORITY-4
+#define DESIRED_BACKGROUND_LOAD  50 // should be accurate enough over range
+
+// starting points for load calculation
+#define MAX_LOAD_THREAD_LEVEL    100
+#define MIN_LOAD_THREAD_LEVEL    0
+
+static char         idle_thread_stack[STACK_SIZE];
+static cyg_thread   idle_thread_data;
+static cyg_handle_t idle_thread_handle;
+static cyg_sem_t    idle_thread_sem;
+volatile static long long    idle_thread_count;
+static char         load_thread_stack[NUM_LOAD_THREADS][STACK_SIZE];
+static cyg_thread   load_thread_data[NUM_LOAD_THREADS];
+static cyg_handle_t load_thread_handle[NUM_LOAD_THREADS];
+static cyg_sem_t    load_thread_sem[NUM_LOAD_THREADS];
+static long         load_thread_level;
+static void calibrate_load(int load);
+static void start_load(int load);
+static void do_some_random_computation(int p,int id);
+#define abs(n) ((n) < 0 ? -(n) : (n))
+
+static long long no_load_idle_count_1_second;
+
+extern void
+cyg_test_exit(void);
+
+void
+pexit(char *s)
+{
+    perror(s);
+    cyg_test_exit();
+}
+
+int
+do_read(int s, void *_buf, int len)
+{
+    int total, slen, rlen;
+    unsigned char *buf = (unsigned char *)_buf;
+    total = 0;
+    rlen = len;
+    while (total < len) {
+        slen = read(s, buf, rlen);
+        if (slen != rlen) {
+            if (slen < 0) {
+                diag_printf("Error after reading %d bytes\n", total);
+                return -1;
+            }
+            rlen -= slen;
+            buf += slen;
+        }
+        total += slen;
+    }
+    return total;
+}
+
+int
+do_write(int s, void *_buf, int len)
+{
+    int total, slen, rlen;
+    unsigned char *buf = (unsigned char *)_buf;
+    total = 0;
+    rlen = len;
+    while (total < len) {
+        slen = write(s, buf, rlen);
+        if (slen != rlen) {
+            if (slen < 0) {
+                diag_printf("Error after writing %d bytes\n", total);
+                return -1;
+            }
+            rlen -= slen;
+            buf += slen;
+        }
+        total += slen;
+    }
+    return total;
+}
+
+//
+// This function is called to calibrate the "background load" which can be
+// applied during testing.  It will be called before any commands from the
+// host are managed.
+//
+static void
+calibrate_load(int desired_load)
+{
+    long long no_load_idle, load_idle;
+    int percent_load;
+    int high, low;
+
+    // Set limits
+    high = MAX_LOAD_THREAD_LEVEL;
+    low = MIN_LOAD_THREAD_LEVEL;
+
+    // Compute the "no load" idle value
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    cyg_thread_delay(1*100);               // Pause for one second
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    no_load_idle = idle_thread_count;
+    diag_printf("No load = %d\n", (int)idle_thread_count);
+
+    // First ensure that the HIGH level is indeed higher
+    while (true) {
+        load_thread_level = high;
+        start_load(desired_load);              // Start up a given load
+        idle_thread_count = 0;
+        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+        cyg_thread_delay(1*100);               // Pause for one second
+        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+        load_idle = idle_thread_count;
+        start_load(0);                         // Shut down background load
+        percent_load = 100 - ((load_idle * 100) / no_load_idle);
+        diag_printf("High Load[%d] = %d => %d%%\n", load_thread_level, 
+                    (int)idle_thread_count, percent_load);
+        if ( percent_load > desired_load )
+            break; // HIGH level is indeed higher
+        low = load_thread_level; // known to be lower
+        high *= 2; // else double it and try again
+    }
+
+    // Now chop down to the level required
+    while (true) {
+        load_thread_level = (high + low) / 2;
+        start_load(desired_load);              // Start up a given load
+        idle_thread_count = 0;
+        cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+        cyg_thread_delay(1*100);               // Pause for one second
+        cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+        load_idle = idle_thread_count;
+        start_load(0);                         // Shut down background load
+        percent_load = 100 - ((load_idle * 100) / no_load_idle);
+        diag_printf("Load[%d] = %d => %d%%\n", load_thread_level, 
+                    (int)idle_thread_count, percent_load);
+        if (((high-low) <= 1) || (abs(desired_load-percent_load) <= 2)) break;
+        if (percent_load < desired_load) {
+            low = load_thread_level;
+        } else {            
+            high = load_thread_level;
+        }
+    }
+
+    // Now we are within a few percent of the target; scale the load
+    // factor to get a better fit, and test it, print the answer.
+    load_thread_level *= desired_load;
+    load_thread_level /= percent_load;
+    start_load(desired_load);              // Start up a given load
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    cyg_thread_delay(1*100);               // Pause for one second
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    load_idle = idle_thread_count;
+    start_load(0);                         // Shut down background load
+    percent_load = 100 - ((load_idle * 100) / no_load_idle);
+    diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, 
+                (int)idle_thread_count, percent_load);
+    no_load_idle_count_1_second = no_load_idle;
+}
+
+//
+// This function is called to set up a load level of 'load' percent (given
+// as a whole number, e.g. start_load(20) would mean initiate a background
+// load of 20%, leaving the cpu 80% idle).
+//
+static void
+start_load(int load)
+{
+    static int prev_load = 0;
+    int i;
+    if (load == 0) {
+        diag_printf("Set no background load\n");
+        if (prev_load == 0) return;  // Nothing out there to stop
+        for (i = 0;  i < prev_load * NUM_LOAD_THREADS/100;  i++) {
+            cyg_semaphore_wait(&load_thread_sem[i]);
+        }
+        prev_load = 0;
+    } else {
+        diag_printf("Set background load = %d%% starting %d threads\n",
+                    load, load * NUM_LOAD_THREADS/100 );
+        for (i = 0;  i < load * NUM_LOAD_THREADS/100;  i++) {
+            cyg_semaphore_post(&load_thread_sem[i]);
+        }
+        prev_load = load;
+    }
+}
+
+//
+// These thread(s) do some amount of "background" computing.  This is used
+// to simulate a given load level.  They need to be run at a higher priority 
+// than the network code itself.
+//
+// Like the "idle" thread, they run as long as their "switch" (aka semaphore)
+// is enabled.
+//
+void
+net_load(cyg_addrword_t who)
+{
+    int i;
+    while (true) {
+        cyg_semaphore_wait(&load_thread_sem[who]);
+        for (i = 0;  i < load_thread_level;  i++) {
+            do_some_random_computation(i,who);
+        }
+        cyg_thread_delay(1);  // Wait until the next 'tick'
+        cyg_semaphore_post(&load_thread_sem[who]);
+    }
+}
+
+//
+// Some arbitrary computation, designed to use up the CPU and cause associated
+// cache "thrash" behaviour - part of background load modelling.
+//
+static void
+do_some_random_computation(int p,int id)
+{
+    // Just something that might be "hard"
+#if 0
+    {
+        volatile double x;
+        x = ((p * 10) * 3.14159) / 180.0;  // radians
+    }
+#endif
+#if 1
+    {
+        static int footle[0x10001];
+        static int counter = 0;
+        register int i;
+
+        i = (p << 8) + id + counter++;
+        i &= 0xffff;
+        footle[ i+1 ] += footle[ i ] + 1;
+    }
+#endif
+}
+
+//
+// This thread does nothing but count.  It will be allowed to count
+// as long as the semaphore is "free".  
+//
+void
+net_idle(cyg_addrword_t param)
+{
+    while (true) {
+        cyg_semaphore_wait(&idle_thread_sem);
+        idle_thread_count++;
+        cyg_semaphore_post(&idle_thread_sem);
+    }
+}
+
+static void
+echo_test(cyg_addrword_t p)
+{
+    int s_source, s_sink, e_source, e_sink;
+    struct sockaddr_in e_source_addr, e_sink_addr, local;
+    int one = 1;
+    fd_set in_fds;
+    int i, num, len;
+    struct test_params params,nparams;
+    struct test_status status,nstatus;
+
+    cyg_tick_count_t starttime, stoptime;
+
+    s_source = socket(AF_INET, SOCK_STREAM, 0);
+    if (s_source < 0) {
+        pexit("stream socket");
+    }
+    if (setsockopt(s_source, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
+        pexit("setsockopt /source/ SO_REUSEADDR");
+    }
+    if (setsockopt(s_source, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
+        pexit("setsockopt /source/ SO_REUSEPORT");
+    }
+    memset(&local, 0, sizeof(local));
+    local.sin_family = AF_INET;
+    local.sin_len = sizeof(local);
+    local.sin_port = ntohs(SOURCE_PORT);
+    local.sin_addr.s_addr = INADDR_ANY;
+    if(bind(s_source, (struct sockaddr *) &local, sizeof(local)) < 0) {
+        pexit("bind /source/ error");
+    }
+    listen(s_source, SOMAXCONN);
+
+    s_sink = socket(AF_INET, SOCK_STREAM, 0);
+    if (s_sink < 0) {
+        pexit("stream socket");
+    }
+    memset(&local, 0, sizeof(local));
+    local.sin_family = AF_INET;
+    local.sin_len = sizeof(local);
+    local.sin_port = ntohs(SINK_PORT);
+    local.sin_addr.s_addr = INADDR_ANY;
+    if(bind(s_sink, (struct sockaddr *) &local, sizeof(local)) < 0) {
+        pexit("bind /sink/ error");
+    }
+    if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) {
+        pexit("setsockopt /sink/ SO_REUSEADDR");
+    }
+    if (setsockopt(s_sink, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one))) {
+        pexit("setsockopt /sink/ SO_REUSEPORT");
+    }
+    listen(s_sink, SOMAXCONN);
+
+    e_source = 0;  e_sink = 0;
+    while (true) {
+        // Wait for a connection on either of the ports
+        FD_ZERO(&in_fds);
+        FD_SET(s_source, &in_fds);
+        FD_SET(s_sink, &in_fds);
+        num = select(max(s_sink,s_source)+1, &in_fds, 0, 0, 0);
+        if (FD_ISSET(s_source, &in_fds)) {
+            len = sizeof(e_source_addr);
+            if ((e_source = accept(s_source, (struct sockaddr *)&e_source_addr, &len)) < 0) {
+                pexit("accept /source/");
+            }
+            diag_printf("SOURCE connection from %s:%d\n", 
+                        inet_ntoa(e_source_addr.sin_addr), ntohs(e_source_addr.sin_port));
+        }
+        if (FD_ISSET(s_sink, &in_fds)) {
+            len = sizeof(e_sink_addr);
+            if ((e_sink = accept(s_sink, (struct sockaddr *)&e_sink_addr, &len)) < 0) {
+                pexit("accept /sink/");
+            }
+            diag_printf("SINK connection from %s:%d\n", 
+                        inet_ntoa(e_sink_addr.sin_addr), ntohs(e_sink_addr.sin_port));
+        }
+        // Continue with test once a connection is established in both directions
+        if ((e_source != 0) && (e_sink != 0)) {
+            break;
+        }
+    }
+
+    // Wait for "source" to tell us the testing paramters
+    if (do_read(e_source, &nparams, sizeof(nparams)) != sizeof(nparams)) {
+        pexit("Can't read initialization parameters");
+    }
+  
+    params.nbufs = ntohl(nparams.nbufs);
+    params.bufsize = ntohl(nparams.bufsize);
+    params.load = ntohl(nparams.load);
+  
+    diag_printf("Using %d buffers of %d bytes each, %d%% background load\n", 
+                params.nbufs, params.bufsize, params.load);
+
+    // Tell the sink what the parameters are
+    if (do_write(e_sink, &nparams, sizeof(nparams)) != sizeof(nparams)) {
+        pexit("Can't write initialization parameters");
+    }
+
+    status.ok = 1;
+    nstatus.ok = htonl(status.ok);
+  
+    // Tell the "source" to start - we're all connected and ready to go!
+    if (do_write(e_source, &nstatus, sizeof(nstatus)) != sizeof(nstatus)) {
+        pexit("Can't send ACK to 'source' host");
+    }
+
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    starttime = cyg_current_time();
+    start_load(params.load);
+
+    // Echo the data from the source to the sink hosts
+    for (i = 0;  i < params.nbufs;  i++) {
+        if ((len = do_read(e_source, data_buf, params.bufsize)) != params.bufsize) {
+            diag_printf("Can't read buf #%d: ", i+1);
+            if (len < 0) {
+                perror("I/O error");
+            } else {
+                diag_printf("short read - only %d bytes\n", len);
+            }
+        }
+//        else diag_printf("Got %d bytes\n",len);        
+        if ((len = do_write(e_sink, data_buf, params.bufsize)) != params.bufsize) {
+            diag_printf("Can't write buf #%d: ", i+1);
+            if (len < 0) {
+                perror("I/O error");
+            } else {
+                diag_printf("short write - only %d bytes\n", len);
+            }
+        }
+//        else diag_printf("Sent %d bytes\n",len);        
+    }
+
+    // Wait for the data to drain and the "sink" to tell us all is OK.
+    if (do_read(e_sink, &status, sizeof(status)) != sizeof(status)) {
+        pexit("Can't receive ACK from 'sink' host");
+    }
+
+    start_load(0);
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    stoptime = cyg_current_time();
+    stoptime -= starttime; // time taken in cS
+    // expected idle loops in that time period for an idle system:
+    starttime = no_load_idle_count_1_second * stoptime / 100;
+    diag_printf( "%d ticks elapsed, %d kloops predicted for an idle system\n",
+                 (int)stoptime, (int)(starttime/1000) );
+    diag_printf( "actual kloops %d, CPU was %d%% idle during transfer\n",
+                 (int)(idle_thread_count/1000),
+                 (int)(idle_thread_count * 100 / starttime) );
+
+    // Now examine how close that loading actually was:
+    start_load(params.load);              // Start up a given load
+    idle_thread_count = 0;
+    cyg_semaphore_post(&idle_thread_sem);  // Start idle thread
+    cyg_thread_delay(1*100);               // Pause for one second
+    cyg_semaphore_wait(&idle_thread_sem);  // Stop idle thread
+    start_load(0);                         // Shut down background load
+    i = 100 - ((idle_thread_count * 100) / no_load_idle_count_1_second );
+    diag_printf("Final load[%d] = %d => %d%%\n", load_thread_level, 
+                (int)idle_thread_count, i);
+
+//#ifdef CYGDBG_USE_ASSERTS
+#ifdef CYGDBG_NET_TIMING_STATS 
+    {
+        extern void show_net_times(void);
+        show_net_times();
+    }
+#endif
+//#endif
+}
+
+//==========================================================================
+
+void
+net_test(cyg_addrword_t param)
+{
+    cyg_serial_baud_rate_t old;    
+    cyg_ppp_options_t options;
+    cyg_ppp_handle_t ppp_handle;
+
+    CYG_TEST_INIT();
+    
+    diag_printf("Start TCP test - ECHO mode\n");
+    init_all_network_interfaces();
+    calibrate_load(DESIRED_BACKGROUND_LOAD);
+#ifdef CYGPKG_SNMPAGENT
+    {
+        extern void cyg_net_snmp_init(void);
+        cyg_net_snmp_init();
+    }
+#endif
+
+    old = ppp_test_set_baud( CYGNUM_SERIAL_BAUD_115200 );
+
+    ppp_test_announce( "TCP_ECHO" );
+    
+    cyg_ppp_options_init( &options );
+
+//    options.debug = 1;
+//    options.kdebugflag = 1;
+//    options.flowctl = CYG_PPP_FLOWCTL_SOFTWARE;
+
+    ppp_handle = cyg_ppp_up( CYGPKG_PPP_TEST_DEVICE, &options );
+
+    CYG_TEST_INFO( "Waiting for PPP to come up");
+    
+    cyg_ppp_wait_up( ppp_handle );
+
+    echo_test(param);
+
+    CYG_TEST_INFO( "Bringing PPP down");
+
+    cyg_ppp_down( ppp_handle );
+    
+    CYG_TEST_INFO( "Waiting for PPP to go down");
+
+    cyg_ppp_wait_down( ppp_handle );
+
+    cyg_thread_delay( 200 );
+    
+    ppp_test_set_baud( old );
+
+    ppp_test_finish();
+    
+    CYG_TEST_PASS_FINISH("TCP ECHO test OK");
+}
+
+void
+cyg_start(void)
+{
+    int i;
+    // Create a main thread which actually runs the test
+    cyg_thread_create(MAIN_THREAD_PRIORITY, // Priority
+                      net_test,             // entry
+                      0,                    // entry parameter
+                      "Network test",       // Name
+                      &stack[0],            // Stack
+                      STACK_SIZE,           // Size
+                      &thread_handle,       // Handle
+                      &thread_data          // Thread data structure
+            );
+    cyg_thread_resume(thread_handle);  // Start it
+    // Create the idle thread environment
+    cyg_semaphore_init(&idle_thread_sem, 0);
+    cyg_thread_create(IDLE_THREAD_PRIORITY,     // Priority
+                      net_idle,                 // entry
+                      0,                        // entry parameter
+                      "Network idle",           // Name
+                      &idle_thread_stack[0],    // Stack
+                      STACK_SIZE,               // Size
+                      &idle_thread_handle,      // Handle
+                      &idle_thread_data         // Thread data structure
+            );
+    cyg_thread_resume(idle_thread_handle);      // Start it
+    // Create the load threads and their environment(s)
+    for (i = 0;  i < NUM_LOAD_THREADS;  i++) {
+        cyg_semaphore_init(&load_thread_sem[i], 0);
+        cyg_thread_create(LOAD_THREAD_PRIORITY,     // Priority
+                          net_load,                 // entry
+                          i,                        // entry parameter
+                          "Background load",        // Name
+                          &load_thread_stack[i][0], // Stack
+                          STACK_SIZE,               // Size
+                          &load_thread_handle[i],   // Handle
+                          &load_thread_data[i]      // Thread data structure
+            );
+        cyg_thread_resume(load_thread_handle[i]);   // Start it
+    }
+    cyg_scheduler_start();
+}
+
+// EOF tcp_echo.c
new file mode 100644
--- /dev/null
+++ b/packages/net/ppp/current/tests/test_server.sh
@@ -0,0 +1,406 @@
+#! /bin/bash
+#==========================================================================
+#
+#      tests/test_server.sh
+#
+#      PPP test server script
+#
+#==========================================================================
+#####ECOSGPLCOPYRIGHTBEGIN####
+# -------------------------------------------
+# This file is part of eCos, the Embedded Configurable Operating System.
+# Copyright (C) 2003, 2004 eCosCentric Ltd.
+#
+# eCos is free software; you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 or (at your option) any later version.
+#
+# eCos is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with eCos; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+#
+# As a special exception, if other files instantiate templates or use macros
+# or inline functions from this file, or you compile this file and link it
+# with other works to produce a work based on this file, this file does not
+# by itself cause the resulting work to be covered by the GNU General Public
+# License. However the source code for this file must still be made available
+# in accordance with section (3) of the GNU General Public License.
+#
+# This exception does not invalidate any other reasons why a work based on
+# this file might be covered by the GNU General Public License.
+#
+# -------------------------------------------
+#####ECOSGPLCOPYRIGHTEND####
+#==========================================================================
+######DESCRIPTIONBEGIN####
+#
+# Author(s):    nickg
+# Contributors:
+# Date:         2003-06-26
+# Purpose:      
+# Description:  
+#              
+#
+#####DESCRIPTIONEND####
+#
+#==========================================================================
+
+# --------------------------------------------------------------------
+# Global variables
+
+ppp_prev=
+ppp_optarg=
+
+ppp_dev=
+ppp_myip=
+ppp_hisip=
+ppp_debug=
+ppp_redboot=
+ppp_redboot_baud=38400
+ppp_baud=$ppp_redboot_baud
+ppp_flow=crtscts
+ppp_ping_interval=1
+
+# --------------------------------------------------------------------
+# Parse the options:
+
+for ppp_option
+do
+
+  # If the previous option needs an argument, assign it.
+  if test -n "$ppp_prev"; then
+    eval "$ppp_prev=\$ppp_option"
+    ppp_prev=
+    continue
+  fi
+
+  # If this option is of the form --thing=value then store
+  # the value into $ppp_optarg.
+  case "$ppp_option" in
+  -*=*) ppp_optarg=`echo "$ppp_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+  *) ppp_optarg= ;;
+  esac
+
+  # Now parse the option
+
+  case "$ppp_option" in
+  
+  --dev) ppp_prev=ppp_dev ;;
+  --dev=*) ppp_dev=$ppp_optarg ;;
+
+  --myip) ppp_prev=ppp_myip ;;
+  --myip=*) ppp_myip=$ppp_optarg ;;
+
+  --hisip) ppp_prev=ppp_hisip ;;
+  --hisip=*) ppp_hisip=$ppp_optarg ;;
+
+  --baud) ppp_prev=ppp_baud ;;
+  --baud=*) ppp_baud=$ppp_optarg ;;
+
+  --flow) ppp_prev=ppp_flow ;;
+  --flow=*) ppp_flow=$ppp_optarg ;;
+
+  --redboot) ppp_redboot=y ;;
+
+  --redboot-baud) ppp_prev=ppp_redboot_baud ;;
+  --redboot-baud=*) ppp_redboot_baud=$ppp_optarg ;;
+
+  --debug) ppp_debug=y ;;
+
+  *)
+	  echo "test_server: Unrecognized option: \"$ppp_option\"." >&2
+	  exit 1
+	  ;;
+  esac
+done
+
+# --------------------------------------------------------------------
+# debug echo function. This only generates output if the --debug
+# flag was given.
+
+dbecho()
+{
+    if [ $ppp_debug ] ; then
+        echo $*
+    fi
+}
+
+# --------------------------------------------------------------------
+# Usage message
+
+usage()
+{
+    echo "test_server --dev=<devname>"
+    echo "            --myip=<myip_addr>"
+    echo "            --hisip=<hisip_addr>"
+    echo "            [--baud=<baud_rate>]"
+    echo "            [--flow=[crtscts|xonxoff|none]]"
+    echo "            [--redboot [--redboot-baud=<baud_rate>]]"
+    echo "            [--debug]"
+    exit 1
+}
+
+# --------------------------------------------------------------------
+# Check that all the required options are present, and report their
+# values.
+
+if [ -z "$ppp_dev" ] ; then usage ; fi
+if [ -z "$ppp_myip" ] ; then usage ; fi
+if [ -z "$ppp_hisip" ] ; then usage ; fi
+
+dbecho "Device : " $ppp_dev
+dbecho "My IP  : " $ppp_myip
+dbecho "His IP : " $ppp_hisip
+dbecho "Baud   : " $ppp_baud
+dbecho "Flow   : " $ppp_flow
+
+if [ "$ppp_flow" == "none" ] ; then ppp_flow="" ; fi
+
+# --------------------------------------------------------------------
+# Bring the PPP link up by calling pppd. The pid of the PPPD is
+# stored in pppd_pid for later use.
+
+pppup()
+{
+    dbecho pppd $ppp_dev $ppp_baud $ppp_flow local nodetach $ppp_myip:$ppp_hisip $* &
+    pppd $ppp_dev $ppp_baud $ppp_flow local nodetach $ppp_myip:$ppp_hisip $* &
+    pppd_pid=$!
+#    dbecho "PPPD Pid: " $pppd_pid
+}
+
+# --------------------------------------------------------------------
+# Simple test for bringing PPP up. Once the link is up the remote
+# end is pinged for a while and then we bring the link down by
+# signalling the PPPD.
+
+ppp_up_test()
+{
+    dbecho ppp_up_test
+    pppup
+    sleep 6
+    ping -i$ppp_ping_interval -w45 -s3000 -c20 $ppp_hisip
+    kill -SIGINT $pppd_pid
+    wait $pppd_pid
+}
+
+# --------------------------------------------------------------------
+# Up/down test. In this case the link is brought down by the remote
+# end.
+
+ppp_updown_test()
+{
+    dbecho ppp_updown_test
+    pppup
+    wait $pppd_pid
+}
+
+
+# --------------------------------------------------------------------
+# Chat tests. These use chat itself to test the chat scripts on the
+# remote end. The tests are:
+#
+# chat_test_1 - run throught the entire script
+# chat_test_2 - simulate a carrier drop
+# chat_test_3 - simulate a timeout
+
+chat_test_1()
+{
+    chat -V "Chat Test" "CONNECT\rlogin:\c"  ppp "Password:\c"  hithere ""  <$ppp_dev >$ppp_dev
+}
+
+chat_test_2()
+{
+    chat -V "Chat Test" "CONNECT\rlogin:\c"  ppp "NO CARRIER"  <$ppp_dev >$ppp_dev
+}
+
+chat_test_3()
+{
+    chat -V "Chat Test" "CONNECT\rlogin:\c"  ppp  <$ppp_dev >$ppp_dev
+}
+
+# --------------------------------------------------------------------
+# Authentication tests. These bring up the PPPD with different
+# authentication requirements against which the remote end tests
+# itself. The tests are:
+#
+# auth_test_1 - authenticate by default method (usually CHAP)
+# auth_test_2 - require PAP authentication
+# auth_test_3 - require CHAP authentication
+
+auth_test_1()
+{
+    dbecho ppp_up_test
+    pppup auth
+    sleep 6
+    ps -p $pppd_pid >/dev/null
+    if [ "$?" == "0" ] ; then
+        ping -i$ppp_ping_interval -w45 -s3000 -c5 $ppp_hisip
+        kill -SIGINT $pppd_pid
+        wait $pppd_pid
+    fi
+}
+
+auth_test_2()
+{
+    dbecho ppp_up_test
+    pppup auth require-pap
+    sleep 6
+    ps -p $pppd_pid >/dev/null
+    if [ "$?" == "0" ] ; then
+        ping -i$ppp_ping_interval -w45 -s3000 -c5 $ppp_hisip
+        kill -SIGINT $pppd_pid
+        wait $pppd_pid
+    fi
+}
+
+auth_test_3()
+{
+    dbecho ppp_up_test
+    pppup auth require-chap
+    sleep 6
+    ps -p $pppd_pid >/dev/null
+    if [ "$?" == "0" ] ; then
+        ping -i$ppp_ping_interval -w45 -s3000 -c5 $ppp_hisip
+        kill -SIGINT $pppd_pid
+        wait $pppd_pid
+    fi
+}
+
+
+# --------------------------------------------------------------------
+# TCP echo test. After bringing up the link this test runs the
+# tcp_source and tcp_sink test programs to exercise the link.  This
+# can take a long time so it is not really suitable for automated
+# testing.
+
+tcp_echo_test()
+{
+    local sink_pid
+    dbecho tcp_echo_test
+    pppup
+    sleep 10
+    tcp_sink $ppp_hisip &
+    sink_pid=$!
+    sleep 5
+    tcp_source $ppp_hisip 60
+    wait $sink_pid
+    sleep 5
+    wait $pppd_pid
+}
+
+# --------------------------------------------------------------------
+# Network characterisation test. After bringing up the link this test
+# runs the nc_test_master test program to exercise the link.  This can
+# take a long time so it is not really suitable for automated testing.
+
+nc_test_slave_test()
+{
+    dbecho nc_test_slave_test
+    pppup
+    sleep 10
+    nc_test_master $ppp_hisip
+    sleep 5
+    wait $pppd_pid
+}
+
+# --------------------------------------------------------------------
+# Change the baud rate. Depending on the value sent as part of the
+# BAUD message, change the link baudrate.
+
+new_baud()
+{
+    ppp_new_baud=`echo $ppp_test | sed 's/.*BAUD:\([0-9]*\).*/\1/'`
+    dbecho "New Baud " $ppp_new_baud
+    case $ppp_new_baud in
+        016) ppp_baud=14400; ppp_ping_interval=6 ;;
+        017) ppp_baud=19200; ppp_ping_interval=4 ;;
+        018) ppp_baud=38400; ppp_ping_interval=2 ;;
+        019) ppp_baud=57600; ppp_ping_interval=2 ;;
+        020) ppp_baud=115200; ppp_ping_interval=1 ;;
+        021) ppp_baud=230400 ;;
+
+        *) dbecho "Unknown baud rate: " $ppp_new_baud
+    esac
+    dbecho "New Baud Rate : " $ppp_baud
+}        
+        
+
+
+# --------------------------------------------------------------------
+# Look for a RedBoot> prompt.
+
+ppp_redboot_prompt()
+{
+    local done=
+    dbecho ppp_redboot_prompt
+    
+    stty -F $ppp_dev $ppp_redboot_baud
+
+    while [ ! $done ] ; do
+        chat -V "RedBoot>" "\c" <$ppp_dev >$ppp_dev
+        if [ "$?" == "0" ] ; then done=1; fi
+    done
+}
+
+# --------------------------------------------------------------------
+# Main loop.
+
+while true ; do
+
+    if [ $ppp_redboot ] ; then ppp_redboot_prompt; fi
+
+    ppp_running=y
+    
+    while [ $ppp_running ] ; do
+
+        dbecho ""
+
+        dbecho "Setting baud rate : " $ppp_baud
+        stty -F $ppp_dev $ppp_baud
+
+        dbecho "Waiting for test..."
+
+        read ppp_test ppp_junk < $ppp_dev
+
+        ppp_test=`echo $ppp_test | sed 's/\([a-zA-Z_:0-9]*\).*/\1/'`
+        
+        dbecho "PPP test: >" $ppp_test "<"
+    
+        case $ppp_test in
+        
+            PPP_UPDOWN) ppp_updown_test ;;
+        
+            PPP_UP) ppp_up_test ;;
+
+            CHAT_TEST_1) chat_test_1 ;;
+            CHAT_TEST_2) chat_test_2 ;;
+            CHAT_TEST_3) chat_test_3 ;;
+
+            PPP_AUTH_1) auth_test_1 ;;
+            PPP_AUTH_2) auth_test_2 ;;
+            PPP_AUTH_3) auth_test_3 ;;
+
+            TCP_ECHO) tcp_echo_test ;;
+
+            NC_TEST_SLAVE) nc_test_slave_test ;;
+
+            BAUD:*) new_baud ;;
+
+            FINISH) unset ppp_running ;;
+            
+            *) echo "Unknown test: " $ppp_test ;;
+        
+        esac
+
+    done
+
+done
+
+# --------------------------------------------------------------------
+# end of test_server.sh
+