From: Felix Fietkau <nbd@openwrt.org>
Date: Tue, 12 Jul 2005 09:38:18 +0000 (+0000)
Subject: add a lot of debian fixes to ppp (should fix persist and demand, too), clean up patches
X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=a7382605445a9292f0df34ef1668205c5013ecdb;p=openwrt%2Fstaging%2Fdedeckeh.git

add a lot of debian fixes to ppp (should fix persist and demand, too), clean up patches

SVN-Revision: 1417
---

diff --git a/openwrt/package/ppp/Makefile b/openwrt/package/ppp/Makefile
index 1b95a76c72..4314632838 100644
--- a/openwrt/package/ppp/Makefile
+++ b/openwrt/package/ppp/Makefile
@@ -4,7 +4,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=ppp
 PKG_VERSION:=2.4.3
-PKG_RELEASE:=4
+PKG_RELEASE:=5
 PKG_MD5SUM:=848f6c3cafeb6074ffeb293c3af79b7c
 
 PKG_SOURCE_URL:=ftp://ftp.samba.org/pub/ppp/
diff --git a/openwrt/package/ppp/patches/100-debian_close_dev_ppp.patch b/openwrt/package/ppp/patches/100-debian_close_dev_ppp.patch
new file mode 100644
index 0000000000..4e50118e87
--- /dev/null
+++ b/openwrt/package/ppp/patches/100-debian_close_dev_ppp.patch
@@ -0,0 +1,34 @@
+From: Simon Peter <dn.tlp@gmx.net>
+Subject: Bug#306261: pppd does not properly close /dev/ppp on persist
+
+When using the kernel PPPoE driver, pppd never
+closes /dev/ppp when the link has come down.
+
+It opens superfluous fds to the device each time it re-opens the
+connection, with the unclosed ones falsely reported always ready for
+data by select().
+
+This makes pppd eat up 100% CPU time after the first persist because of
+the always instantly returning select() on the unclosed fds.
+
+The problem also occurs with the upstream version, but does not occur
+when a pty/tty device is used for the ppp connection.
+
+
+diff -u -r ppp-2.4.3/pppd/sys-linux.c ppp-2.4.3/pppd/sys-linux.c
+--- ppp-2.4.3/pppd/sys-linux.c	2005-04-29 20:08:37.000000000 +0200
++++ ppp-2.4.3/pppd/sys-linux.c	2005-04-29 20:07:03.000000000 +0200
+@@ -455,6 +455,13 @@
+     if (new_style_driver) {
+ 	int flags;
+ 
++        /* if a ppp_fd is already open, close it first */
++        if(ppp_fd > 0) {
++          close(ppp_fd);
++          remove_fd(ppp_fd);
++          ppp_fd = -1;
++        }
++
+ 	/* Open an instance of /dev/ppp and connect the channel to it */
+ 	if (ioctl(fd, PPPIOCGCHAN, &chindex) == -1) {
+ 	    error("Couldn't get channel number: %m");
diff --git a/openwrt/package/ppp/patches/101-debian_ip-up_option.patch b/openwrt/package/ppp/patches/101-debian_ip-up_option.patch
new file mode 100644
index 0000000000..6033fda247
--- /dev/null
+++ b/openwrt/package/ppp/patches/101-debian_ip-up_option.patch
@@ -0,0 +1,88 @@
+diff -ruNp ppp-2.4.3.orig/pppd/ipcp.c ppp-2.4.3/pppd/ipcp.c
+--- ppp-2.4.3.orig/pppd/ipcp.c	2004-11-13 13:03:26.000000000 +0100
++++ ppp-2.4.3/pppd/ipcp.c	2005-02-20 18:45:22.241810136 +0100
+@@ -1846,7 +1846,7 @@ ipcp_up(f)
+      */
+     if (ipcp_script_state == s_down && ipcp_script_pid == 0) {
+ 	ipcp_script_state = s_up;
+-	ipcp_script(_PATH_IPUP);
++	ipcp_script(path_ipup);
+     }
+ }
+ 
+@@ -1896,7 +1896,7 @@ ipcp_down(f)
+     /* Execute the ip-down script */
+     if (ipcp_script_state == s_up && ipcp_script_pid == 0) {
+ 	ipcp_script_state = s_down;
+-	ipcp_script(_PATH_IPDOWN);
++	ipcp_script(path_ipdown);
+     }
+ }
+ 
+@@ -1950,13 +1950,13 @@ ipcp_script_done(arg)
+     case s_up:
+ 	if (ipcp_fsm[0].state != OPENED) {
+ 	    ipcp_script_state = s_down;
+-	    ipcp_script(_PATH_IPDOWN);
++	    ipcp_script(path_ipdown);
+ 	}
+ 	break;
+     case s_down:
+ 	if (ipcp_fsm[0].state == OPENED) {
+ 	    ipcp_script_state = s_up;
+-	    ipcp_script(_PATH_IPUP);
++	    ipcp_script(path_ipup);
+ 	}
+ 	break;
+     }
+diff -ruNp ppp-2.4.3.orig/pppd/main.c ppp-2.4.3/pppd/main.c
+--- ppp-2.4.3.orig/pppd/main.c	2005-02-20 18:46:14.409879384 +0100
++++ ppp-2.4.3/pppd/main.c	2005-02-20 18:45:22.243809832 +0100
+@@ -314,6 +314,9 @@ main(argc, argv)
+     struct protent *protp;
+     char numbuf[16];
+ 
++    strlcpy(path_ipup, _PATH_IPUP, sizeof(path_ipup));
++    strlcpy(path_ipdown, _PATH_IPDOWN, sizeof(path_ipdown));
++
+     link_stats_valid = 0;
+     new_phase(PHASE_INITIALIZE);
+ 
+diff -ruNp ppp-2.4.3.orig/pppd/options.c ppp-2.4.3/pppd/options.c
+--- ppp-2.4.3.orig/pppd/options.c	2005-02-20 18:46:14.410879232 +0100
++++ ppp-2.4.3/pppd/options.c	2005-02-20 18:46:02.154742448 +0100
+@@ -108,6 +108,8 @@ char	linkname[MAXPATHLEN];	/* logical na
+ bool	tune_kernel;		/* may alter kernel settings */
+ int	connect_delay = 1000;	/* wait this many ms after connect script */
+ int	req_unit = -1;		/* requested interface unit */
++char	path_ipup[MAXPATHLEN];	/* pathname of ip-up script */
++char	path_ipdown[MAXPATHLEN];/* pathname of ip-down script */
+ bool	multilink = 0;		/* Enable multilink operation */
+ char	*bundle_name = NULL;	/* bundle name for multilink */
+ bool	dump_options;		/* print out option values */
+@@ -276,6 +278,13 @@ option_t general_options[] = {
+       "Number of seconds to wait for child processes at exit",
+       OPT_PRIO },
+ 
++    { "ip-up-script", o_string, path_ipup,
++      "Set pathname of ip-up script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++    { "ip-down-script", o_string, path_ipdown,
++      "Set pathname of ip-down script",
++      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN },
++
+ #ifdef HAVE_MULTILINK
+     { "multilink", o_bool, &multilink,
+       "Enable multilink operation", OPT_PRIO | 1 },
+diff -ruNp ppp-2.4.3.orig/pppd/pppd.h ppp-2.4.3/pppd/pppd.h
+--- ppp-2.4.3.orig/pppd/pppd.h	2005-02-20 18:46:14.414878624 +0100
++++ ppp-2.4.3/pppd/pppd.h	2005-02-20 18:45:22.247809224 +0100
+@@ -312,6 +312,8 @@ extern bool	tune_kernel;	/* May alter ke
+ extern int	connect_delay;	/* Time to delay after connect script */
+ extern int	max_data_rate;	/* max bytes/sec through charshunt */
+ extern int	req_unit;	/* interface unit number to use */
++extern char	path_ipup[MAXPATHLEN]; /* pathname of ip-up script */
++extern char	path_ipdown[MAXPATHLEN]; /* pathname of ip-down script */
+ extern bool	multilink;	/* enable multilink operation */
+ extern bool	noendpoint;	/* don't send or accept endpt. discrim. */
+ extern char	*bundle_name;	/* bundle name for multilink */
diff --git a/openwrt/package/ppp/patches/102-debian_pppoe_multicast_pado.patch b/openwrt/package/ppp/patches/102-debian_pppoe_multicast_pado.patch
new file mode 100644
index 0000000000..ea5275c461
--- /dev/null
+++ b/openwrt/package/ppp/patches/102-debian_pppoe_multicast_pado.patch
@@ -0,0 +1,14 @@
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/discovery.c ppp-2.4.3/pppd/plugins/rp-pppoe/discovery.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/discovery.c	2004-11-04 11:07:37.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/discovery.c	2005-02-24 21:00:11.586697752 +0100
+@@ -365,8 +365,8 @@ waitForPADO(PPPoEConnection *conn, int t
+ 	if (!packetIsForMe(conn, &packet)) continue;
+ 
+ 	if (packet.code == CODE_PADO) {
+-	    if (NOT_UNICAST(packet.ethHdr.h_source)) {
+-		printErr("Ignoring PADO packet from non-unicast MAC address");
++	    if (BROADCAST(packet.ethHdr.h_source)) {
++		printErr("Ignoring PADO packet from broadcast MAC address");
+ 		continue;
+ 	    }
+ 	    parsePacket(&packet, parsePADOTags, &pc);
diff --git a/openwrt/package/ppp/patches/103-debian_pppoe_cleanup.patch b/openwrt/package/ppp/patches/103-debian_pppoe_cleanup.patch
new file mode 100644
index 0000000000..8a97a0b2e5
--- /dev/null
+++ b/openwrt/package/ppp/patches/103-debian_pppoe_cleanup.patch
@@ -0,0 +1,1079 @@
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/common.c ppp-2.4.3/pppd/plugins/rp-pppoe/common.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/common.c	2004-02-02 04:36:46.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/common.c	2005-03-11 02:09:19.000000000 +0100
+@@ -18,10 +18,6 @@ static char const RCSID[] =
+ 
+ #include "pppoe.h"
+ 
+-#ifdef HAVE_SYSLOG_H
+-#include <syslog.h>
+-#endif
+-
+ #include <string.h>
+ #include <errno.h>
+ #include <stdlib.h>
+@@ -50,17 +46,17 @@ parsePacket(PPPoEPacket *packet, ParseFu
+     UINT16_t tagType, tagLen;
+ 
+     if (packet->ver != 1) {
+-	syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
++	error("Invalid PPPoE version (%u)", packet->ver);
+ 	return -1;
+     }
+     if (packet->type != 1) {
+-	syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
++	error("Invalid PPPoE type (%u)", packet->type);
+ 	return -1;
+     }
+ 
+     /* Do some sanity checks on packet */
+     if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+-	syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
++	error("Invalid PPPoE packet length (%u)", len);
+ 	return -1;
+     }
+ 
+@@ -76,7 +72,7 @@ parsePacket(PPPoEPacket *packet, ParseFu
+ 	    return 0;
+ 	}
+ 	if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+-	    syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
++	    error("Invalid PPPoE tag length (%u)", tagLen);
+ 	    return -1;
+ 	}
+ 	func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra);
+@@ -105,17 +101,17 @@ findTag(PPPoEPacket *packet, UINT16_t ty
+     UINT16_t tagType, tagLen;
+ 
+     if (packet->ver != 1) {
+-	syslog(LOG_ERR, "Invalid PPPoE version (%d)", (int) packet->ver);
++	error("Invalid PPPoE version (%u)", packet->ver);
+ 	return NULL;
+     }
+     if (packet->type != 1) {
+-	syslog(LOG_ERR, "Invalid PPPoE type (%d)", (int) packet->type);
++	error("Invalid PPPoE type (%u)", packet->type);
+ 	return NULL;
+     }
+ 
+     /* Do some sanity checks on packet */
+     if (len > ETH_DATA_LEN - 6) { /* 6-byte overhead for PPPoE header */
+-	syslog(LOG_ERR, "Invalid PPPoE packet length (%u)", len);
++	error("Invalid PPPoE packet length (%u)", len);
+ 	return NULL;
+     }
+ 
+@@ -131,7 +127,7 @@ findTag(PPPoEPacket *packet, UINT16_t ty
+ 	    return NULL;
+ 	}
+ 	if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) {
+-	    syslog(LOG_ERR, "Invalid PPPoE tag length (%u)", tagLen);
++	    error("Invalid PPPoE tag length (%u)", tagLen);
+ 	    return NULL;
+ 	}
+ 	if (tagType == type) {
+@@ -143,6 +139,7 @@ findTag(PPPoEPacket *packet, UINT16_t ty
+     return NULL;
+ }
+ 
++#ifdef unused
+ /**********************************************************************
+ *%FUNCTION: printErr
+ *%ARGUMENTS:
+@@ -158,6 +155,7 @@ printErr(char const *str)
+     fprintf(stderr, "pppoe: %s\n", str);
+     syslog(LOG_ERR, "%s", str);
+ }
++#endif
+ 
+ 
+ /**********************************************************************
+@@ -172,7 +170,7 @@ strDup(char const *str)
+ {
+     char *copy = malloc(strlen(str)+1);
+     if (!copy) {
+-	rp_fatal("strdup failed");
++	fatal("strdup failed");
+     }
+     strcpy(copy, str);
+     return copy;
+@@ -467,9 +465,10 @@ sendPADT(PPPoEConnection *conn, char con
+ 	fprintf(conn->debugFile, "\n");
+ 	fflush(conn->debugFile);
+     }
+-    syslog(LOG_INFO,"Sent PADT");
++    info("Sent PADT");
+ }
+ 
++#ifdef unused
+ /**********************************************************************
+ *%FUNCTION: parseLogErrs
+ *%ARGUMENTS:
+@@ -501,4 +500,5 @@ parseLogErrs(UINT16_t type, UINT16_t len
+ 	break;
+     }
+ }
++#endif
+ 
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/discovery.c ppp-2.4.3/pppd/plugins/rp-pppoe/discovery.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/discovery.c	2005-03-11 02:12:52.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/discovery.c	2005-03-10 12:24:19.000000000 +0100
+@@ -13,10 +13,6 @@ static char const RCSID[] =
+ 
+ #include "pppoe.h"
+ 
+-#ifdef HAVE_SYSLOG_H
+-#include <syslog.h>
+-#endif
+-
+ #include <string.h>
+ #include <stdlib.h>
+ #include <errno.h>
+@@ -167,24 +163,21 @@ parsePADOTags(UINT16_t type, UINT16_t le
+ 	if (conn->printACNames) {
+ 	    printf("Got a Service-Name-Error tag: %.*s\n", (int) len, data);
+ 	} else {
+-	    syslog(LOG_ERR, "PADO: Service-Name-Error: %.*s", (int) len, data);
+-	    exit(1);
++	    fatal("PADO: Service-Name-Error: %.*s", (int) len, data);
+ 	}
+ 	break;
+     case TAG_AC_SYSTEM_ERROR:
+ 	if (conn->printACNames) {
+ 	    printf("Got a System-Error tag: %.*s\n", (int) len, data);
+ 	} else {
+-	    syslog(LOG_ERR, "PADO: System-Error: %.*s", (int) len, data);
+-	    exit(1);
++	    fatal("PADO: System-Error: %.*s", (int) len, data);
+ 	}
+ 	break;
+     case TAG_GENERIC_ERROR:
+ 	if (conn->printACNames) {
+ 	    printf("Got a Generic-Error tag: %.*s\n", (int) len, data);
+ 	} else {
+-	    syslog(LOG_ERR, "PADO: Generic-Error: %.*s", (int) len, data);
+-	    exit(1);
++	    fatal("PADO: Generic-Error: %.*s", (int) len, data);
+ 	}
+ 	break;
+     }
+@@ -209,20 +202,14 @@ parsePADSTags(UINT16_t type, UINT16_t le
+     PPPoEConnection *conn = (PPPoEConnection *) extra;
+     switch(type) {
+     case TAG_SERVICE_NAME:
+-	syslog(LOG_DEBUG, "PADS: Service-Name: '%.*s'", (int) len, data);
++	dbglog("PADS: Service-Name: '%.*s'", (int) len, data);
+ 	break;
+     case TAG_SERVICE_NAME_ERROR:
+-	syslog(LOG_ERR, "PADS: Service-Name-Error: %.*s", (int) len, data);
+-	fprintf(stderr, "PADS: Service-Name-Error: %.*s\n", (int) len, data);
+-	exit(1);
++	fatal("PADS: Service-Name-Error: %.*s", (int) len, data);
+     case TAG_AC_SYSTEM_ERROR:
+-	syslog(LOG_ERR, "PADS: System-Error: %.*s", (int) len, data);
+-	fprintf(stderr, "PADS: System-Error: %.*s\n", (int) len, data);
+-	exit(1);
++	fatal("PADS: System-Error: %.*s", (int) len, data);
+     case TAG_GENERIC_ERROR:
+-	syslog(LOG_ERR, "PADS: Generic-Error: %.*s", (int) len, data);
+-	fprintf(stderr, "PADS: Generic-Error: %.*s\n", (int) len, data);
+-	exit(1);
++	fatal("PADS: Generic-Error: %.*s", (int) len, data);
+     case TAG_RELAY_SESSION_ID:
+ 	conn->relayId.type = htons(type);
+ 	conn->relayId.length = htons(len);
+@@ -336,7 +323,7 @@ waitForPADO(PPPoEConnection *conn, int t
+ 		if (r >= 0 || errno != EINTR) break;
+ 	    }
+ 	    if (r < 0) {
+-		fatalSys("select (waitForPADO)");
++		fatal("waitForPADO: select: %m");
+ 	    }
+ 	    if (r == 0) return;        /* Timed out */
+ 	}
+@@ -346,8 +333,7 @@ waitForPADO(PPPoEConnection *conn, int t
+ 
+ 	/* Check length */
+ 	if (ntohs(packet.length) + HDR_SIZE > len) {
+-	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+-		   (unsigned int) ntohs(packet.length));
++	    error("Bogus PPPoE length field (%u)", ntohs(packet.length));
+ 	    continue;
+ 	}
+ 
+@@ -366,16 +352,16 @@ waitForPADO(PPPoEConnection *conn, int t
+ 
+ 	if (packet.code == CODE_PADO) {
+ 	    if (BROADCAST(packet.ethHdr.h_source)) {
+-		printErr("Ignoring PADO packet from broadcast MAC address");
++		error("Ignoring PADO packet from broadcast MAC address");
+ 		continue;
+ 	    }
+ 	    parsePacket(&packet, parsePADOTags, &pc);
+ 	    if (!pc.seenACName) {
+-		printErr("Ignoring PADO packet with no AC-Name tag");
++		error("Ignoring PADO packet with no AC-Name tag");
+ 		continue;
+ 	    }
+ 	    if (!pc.seenServiceName) {
+-		printErr("Ignoring PADO packet with no Service-Name tag");
++		error("Ignoring PADO packet with no Service-Name tag");
+ 		continue;
+ 	    }
+ 	    conn->numPADOs++;
+@@ -513,7 +499,7 @@ waitForPADS(PPPoEConnection *conn, int t
+ 		if (r >= 0 || errno != EINTR) break;
+ 	    }
+ 	    if (r < 0) {
+-		fatalSys("select (waitForPADS)");
++		fatal("waitForPADS: select: %m");
+ 	    }
+ 	    if (r == 0) return;
+ 	}
+@@ -523,8 +509,7 @@ waitForPADS(PPPoEConnection *conn, int t
+ 
+ 	/* Check length */
+ 	if (ntohs(packet.length) + HDR_SIZE > len) {
+-	    syslog(LOG_ERR, "Bogus PPPoE length field (%u)",
+-		   (unsigned int) ntohs(packet.length));
++	    error("Bogus PPPoE length field (%u)", ntohs(packet.length));
+ 	    continue;
+ 	}
+ 
+@@ -556,11 +541,12 @@ waitForPADS(PPPoEConnection *conn, int t
+     /* Don't bother with ntohs; we'll just end up converting it back... */
+     conn->session = packet.session;
+ 
+-    syslog(LOG_INFO, "PPP session is %d", (int) ntohs(conn->session));
++    info("PPP session is %d", ntohs(conn->session));
+ 
+     /* RFC 2516 says session id MUST NOT be zero or 0xFFFF */
+     if (ntohs(conn->session) == 0 || ntohs(conn->session) == 0xFFFF) {
+-	syslog(LOG_ERR, "Access concentrator used a session value of %x -- the AC is violating RFC 2516", (unsigned int) ntohs(conn->session));
++	error("Access concentrator used a session value of 0x%x"
++	    " -- the AC is violating RFC 2516", ntohs(conn->session));
+     }
+ }
+ 
+@@ -620,7 +606,7 @@ discovery(PPPoEConnection *conn)
+ 
+     /* If we're only printing access concentrator names, we're done */
+     if (conn->printACNames) {
+-	die(0);
++	exit(0);
+     }
+ 
+     timeout = PADI_TIMEOUT;
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/if.c ppp-2.4.3/pppd/plugins/rp-pppoe/if.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/if.c	2001-12-14 03:55:20.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/if.c	2005-03-10 13:32:43.000000000 +0100
+@@ -40,10 +40,6 @@ static char const RCSID[] =
+ #include <sys/ioctl.h>
+ #endif
+ 
+-#ifdef HAVE_SYSLOG_H
+-#include <syslog.h>
+-#endif
+-
+ #include <errno.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -127,7 +123,7 @@ etherType(PPPoEPacket *packet)
+ {
+     UINT16_t type = (UINT16_t) ntohs(packet->ethHdr.h_proto);
+     if (type != Eth_PPPOE_Discovery && type != Eth_PPPOE_Session) {
+-	syslog(LOG_ERR, "Invalid ether type 0x%x", type);
++	error("Invalid ethernet type 0x%x", type);
+     }
+     return type;
+ }
+@@ -156,7 +152,7 @@ getHWaddr(int sock, char const *ifname, 
+     ifc.ifc_len = sizeof(inbuf);
+     ifc.ifc_buf = inbuf;
+     if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) {
+-	fatalSys("SIOCGIFCONF");
++	fatal("SIOCGIFCONF: %m");
+     }
+     ifr = ifc.ifc_req;
+     ifreq.ifr_name[0] = '\0';
+@@ -172,9 +168,7 @@ getHWaddr(int sock, char const *ifname, 
+ 	        (sdl->sdl_alen == ETH_ALEN) &&
+ 		!strncmp(ifname, ifr->ifr_name, sizeof(ifr->ifr_name))) {
+ 		if (found) {
+-		    char buffer[256];
+-		    sprintf(buffer, "interface %.16s has more than one ethernet address", ifname);
+-		    rp_fatal(buffer);
++		    fatal("interface %s has more than one ethernet address", ifname);
+ 		} else {
+ 		    found = 1;
+ 	            memcpy(hwaddr, LLADDR(sdl), ETH_ALEN);
+@@ -183,9 +177,7 @@ getHWaddr(int sock, char const *ifname, 
+ 	}
+     }
+     if (!found) {
+-	char buffer[256];
+-        sprintf(buffer, "interface %.16s has no ethernet address", ifname);
+-	rp_fatal(buffer);
++        fatal("interface %s has no ethernet address", ifname);
+     }
+ }
+ 
+@@ -252,7 +244,7 @@ initFilter(int fd, UINT16_t type, unsign
+       
+       /* Apply the filter */
+       if (ioctl(fd, BIOCSETF, &bpfProgram) < 0) {
+-	fatalSys("ioctl(BIOCSETF)");
++	fatal("ioctl(BIOCSETF): %m");
+       }
+     }
+ }
+@@ -298,42 +290,36 @@ openInterface(char const *ifname, UINT16
+     if (fd < 0) {
+ 	switch (errno) {
+ 	case EACCES:		/* permission denied */
+-	    {
+-		char buffer[256];
+-		sprintf(buffer, "Cannot open %.32s -- pppoe must be run as root.", bpfName);
+-		rp_fatal(buffer);
+-	    }
++	    fatal("Cannot open %s -- pppoe must be run as root.", bpfName);
+ 	    break;
+ 	case EBUSY:
+ 	case ENOENT:		/* no such file */
+ 	    if (i == 0) {
+-		rp_fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
++		fatal("No /dev/bpf* devices (check your kernel configuration for BPF support)");
+ 	    } else {
+-		rp_fatal("All /dev/bpf* devices are in use");
++		fatal("All /dev/bpf* devices are in use");
+ 	    }
+ 	    break;
+ 	}
+-	fatalSys(bpfName);
++	fatal("%s: %m", bpfName);
+     }
+ 
+     if ((sock = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
+-	fatalSys("socket");
++	fatal("socket: %m");
+     }
+ 
+     /* Check that the interface is up */
+     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+     if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+-	fatalSys("ioctl(SIOCGIFFLAGS)");
++	fatal("ioctl(SIOCGIFFLAGS): %m");
+     }
+     if ((ifr.ifr_flags & IFF_UP) == 0) {
+-	char buffer[256];
+-	sprintf(buffer, "Interface %.16s is not up\n", ifname);
+-	rp_fatal(buffer);
++	fatal("Interface %s is not up", ifname);
+     }
+ 
+     /* Fill in hardware address and initialize the packet filter rules */
+     if (hwaddr == NULL) {
+-	rp_fatal("openInterface: no hwaddr arg.");
++	fatal("openInterface: no hwaddr arg.");
+     }
+     getHWaddr(sock, ifname, hwaddr);
+     initFilter(fd, type, hwaddr);
+@@ -342,58 +328,52 @@ openInterface(char const *ifname, UINT16
+ #if !defined(__OpenBSD__)
+     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+     if (ioctl(sock, SIOCGIFMTU, &ifr) < 0) {
+-	fatalSys("ioctl(SIOCGIFMTU)");
++	fatal("ioctl(SIOCGIFMTU): %m");
+     }
+     if (ifr.ifr_mtu < ETH_DATA_LEN) {
+-	char buffer[256];
+-	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
++	error("Interface %s has MTU of %d -- should be %d."
++		"  You may have serious connection problems.",
+ 		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+-	printErr(buffer);
+     }
+ #endif
+ 
+     /* done with the socket */
+     if (close(sock) < 0) {
+-	fatalSys("close");
++	fatal("close: %m");
+     }
+ 
+     /* Check the BPF version number */
+     if (ioctl(fd, BIOCVERSION, &bpf_ver) < 0) {
+-	fatalSys("ioctl(BIOCVERSION)");
++	fatal("ioctl(BIOCVERSION): %m");
+     }
+     if ((bpf_ver.bv_major != BPF_MAJOR_VERSION) ||
+         (bpf_ver.bv_minor < BPF_MINOR_VERSION)) {
+-	char buffer[256];
+-	sprintf(buffer, "Unsupported BPF version: %d.%d (kernel: %d.%d)", 
++	fatal("Unsupported BPF version: %d.%d (kernel: %d.%d)",
+ 			BPF_MAJOR_VERSION, BPF_MINOR_VERSION,
+ 			bpf_ver.bv_major, bpf_ver.bv_minor);
+-	rp_fatal(buffer);
+     }
+ 
+     /* allocate a receive packet buffer */
+     if (ioctl(fd, BIOCGBLEN, &bpfLength) < 0) {
+-	fatalSys("ioctl(BIOCGBLEN)");
++	fatal("ioctl(BIOCGBLEN): %m");
+     }
+     if (!(bpfBuffer = (unsigned char *) malloc(bpfLength))) {
+-	rp_fatal("malloc");
++	fatal("malloc");
+     }
+ 
+     /* reads should return as soon as there is a packet available */
+     optval = 1;
+     if (ioctl(fd, BIOCIMMEDIATE, &optval) < 0) {
+-	fatalSys("ioctl(BIOCIMMEDIATE)");
++	fatal("ioctl(BIOCIMMEDIATE): %m");
+     }
+ 
+     /* Bind the interface to the filter */
+     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+     if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
+-	char buffer[256];
+-	sprintf(buffer, "ioctl(BIOCSETIF) can't select interface %.16s",
+-		ifname);
+-	rp_fatal(buffer);
++	fatal("ioctl(BIOCSETIF) can't select interface %s: %m", ifname);
+     }
+ 
+-    syslog(LOG_INFO, "Interface=%.16s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%.32s Buffer size=%d",
++    info("Interface=%s HWaddr=%02X:%02X:%02X:%02X:%02X:%02X Device=%s Buffer size=%d",
+ 	   ifname, 
+ 	   hwaddr[0], hwaddr[1], hwaddr[2],
+ 	   hwaddr[3], hwaddr[4], hwaddr[5],
+@@ -442,48 +422,41 @@ openInterface(char const *ifname, UINT16
+     if ((fd = socket(domain, stype, htons(type))) < 0) {
+ 	/* Give a more helpful message for the common error case */
+ 	if (errno == EPERM) {
+-	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
++	    fatal("Cannot create raw socket -- pppoe must be run as root.");
+ 	}
+-	fatalSys("socket");
++	fatal("cannot create the raw socket: %m");
+     }
+ 
+     if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &optval, sizeof(optval)) < 0) {
+-	fatalSys("setsockopt");
++	fatal("setsockopt(SOL_SOCKET, SO_BROADCAST): %m");
+     }
+ 
+     /* Fill in hardware address */
+     if (hwaddr) {
+ 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+-	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
+-	    fatalSys("ioctl(SIOCGIFHWADDR)");
+-	}
++	if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
++	    fatal("ioctl(SIOCGIFHWADDR): %m");
+ 	memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ #ifdef ARPHRD_ETHER
+ 	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+-	    char buffer[256];
+-	    sprintf(buffer, "Interface %.16s is not Ethernet", ifname);
+-	    rp_fatal(buffer);
++	    fatal("Interface %s is not Ethernet", ifname);
+ 	}
+ #endif
+ 	if (NOT_UNICAST(hwaddr)) {
+-	    char buffer[256];
+-	    sprintf(buffer,
+-		    "Interface %.16s has broadcast/multicast MAC address??",
++	    fatal("Interface %s has broadcast/multicast MAC address",
+ 		    ifname);
+-	    rp_fatal(buffer);
+ 	}
+     }
+ 
+     /* Sanity check on MTU */
+     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+     if (ioctl(fd, SIOCGIFMTU, &ifr) < 0) {
+-	fatalSys("ioctl(SIOCGIFMTU)");
++	fatal("ioctl(SIOCGIFMTU): %m");
+     }
+     if (ifr.ifr_mtu < ETH_DATA_LEN) {
+-	char buffer[256];
+-	sprintf(buffer, "Interface %.16s has MTU of %d -- should be %d.  You may have serious connection problems.",
++	error("Interface %s has MTU of %d -- should be %d."
++		"  You may have serious connection problems.",
+ 		ifname, ifr.ifr_mtu, ETH_DATA_LEN);
+-	printErr(buffer);
+     }
+ 
+ #ifdef HAVE_STRUCT_SOCKADDR_LL
+@@ -493,7 +466,7 @@ openInterface(char const *ifname, UINT16
+ 
+     strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+     if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) {
+-	fatalSys("ioctl(SIOCFIGINDEX): Could not get interface index");
++	fatal("ioctl(SIOCFIGINDEX): Could not get interface index: %m");
+     }
+     sa.sll_ifindex = ifr.ifr_ifindex;
+ 
+@@ -503,7 +476,7 @@ openInterface(char const *ifname, UINT16
+ 
+     /* We're only interested in packets on specified interface */
+     if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
+-	fatalSys("bind");
++	fatal("bind: %m");
+     }
+ 
+     return fd;
+@@ -527,13 +500,11 @@ sendPacket(PPPoEConnection *conn, int so
+ {
+ #if defined(USE_BPF)
+     if (write(sock, pkt, size) < 0) {
+-	sysErr("write (sendPacket)");
+-	return -1;
++	fatal("sendPacket: write: %m");
+     }
+ #elif defined(HAVE_STRUCT_SOCKADDR_LL)
+     if (send(sock, pkt, size, 0) < 0) {
+-	sysErr("send (sendPacket)");
+-	return -1;
++	fatal("sendPacket: send: %m");
+     }
+ #else
+ #ifdef USE_DLPI
+@@ -577,12 +548,11 @@ sendPacket(PPPoEConnection *conn, int so
+     struct sockaddr sa;
+ 
+     if (!conn) {
+-	rp_fatal("relay and server not supported on Linux 2.0 kernels");
++	fatal("relay and server not supported on Linux 2.0 kernels");
+     }
+     strcpy(sa.sa_data, conn->ifName);
+     if (sendto(sock, pkt, size, 0, &sa, sizeof(sa)) < 0) {
+-	sysErr("sendto (sendPacket)");
+-	return -1;
++	fatal("sendPacket: sendto: %m");
+     }
+ #endif
+ #endif
+@@ -632,26 +602,24 @@ receivePacket(int sock, PPPoEPacket *pkt
+     if (bpfSize <= 0) {
+ 	bpfOffset = 0;
+ 	if ((bpfSize = read(sock, bpfBuffer, bpfLength)) < 0) {
+-	    sysErr("read (receivePacket)");
+-	    return -1;
++	    fatal("receivePacket: read: %m");
+ 	}
+     }
+     if (bpfSize < sizeof(hdr)) {
+-	syslog(LOG_ERR, "Truncated bpf packet header: len=%d", bpfSize);
++	error("Truncated bpf packet header: len=%d", bpfSize);
+ 	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+ 	return 0;
+     }
+     memcpy(&hdr, bpfBuffer + bpfOffset, sizeof(hdr));
+     if (hdr.bh_caplen != hdr.bh_datalen) {
+-	syslog(LOG_ERR, "Truncated bpf packet: caplen=%d, datalen=%d",
++	error("Truncated bpf packet: caplen=%d, datalen=%d",
+ 	       hdr.bh_caplen, hdr.bh_datalen);
+ 	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+ 	return 0;
+     }
+     seglen = hdr.bh_hdrlen + hdr.bh_caplen;
+     if (seglen > bpfSize) {
+-	syslog(LOG_ERR, "Truncated bpf packet: seglen=%d, bpfSize=%d",
+-	       seglen, bpfSize);
++	error("Truncated bpf packet: seglen=%d, bpfSize=%d", seglen, bpfSize);
+ 	clearPacketHeader(pkt);		/* resets bpfSize and bpfOffset */
+ 	return 0;
+     }
+@@ -676,16 +644,14 @@ receivePacket(int sock, PPPoEPacket *pkt
+ 	data.len = 0; 
+ 	
+ 	if ((retval = getmsg(sock, NULL, &data, &flags)) < 0) {
+-	    sysErr("read (receivePacket)");
+-	    return -1;
++	    fatal("receivePacket: getmsg: %m");
+ 	}
+ 
+ 	*size = data.len; 
+ 
+ #else
+     if ((*size = recv(sock, pkt, sizeof(PPPoEPacket), 0)) < 0) {
+-	sysErr("recv (receivePacket)");
+-	return -1;
++	fatal("receivePacket: recv: %m");
+     }
+ #endif
+ #endif
+@@ -716,7 +682,7 @@ openInterface(char const *ifname, UINT16
+     int ppa; 
+ 
+     if(strlen(ifname) > PATH_MAX) {
+-	rp_fatal("socket: string to long"); 
++	fatal("openInterface: interface name too long");
+     }
+ 
+     ppa = atoi(&ifname[strlen(ifname)-1]);
+@@ -729,9 +695,9 @@ openInterface(char const *ifname, UINT16
+     if (( fd = open(base_dev, O_RDWR)) < 0) {
+ 	/* Give a more helpful message for the common error case */
+ 	if (errno == EPERM) {
+-	    rp_fatal("Cannot create raw socket -- pppoe must be run as root.");
++	    fatal("Cannot create raw socket -- pppoe must be run as root.");
+ 	}
+-	fatalSys("socket");
++	fatal("open(%s): %m", base_dev);
+     }
+ 
+ /* rearranged order of DLPI code - delphys 20010803 */
+@@ -747,17 +713,18 @@ openInterface(char const *ifname, UINT16
+     dl_abssaplen = ABS(dlp->info_ack.dl_sap_length);
+     dl_saplen = dlp->info_ack.dl_sap_length;
+     if (ETHERADDRL != (dlp->info_ack.dl_addr_length - dl_abssaplen))
+-	fatalSys("invalid destination physical address length");
++	fatal("invalid destination physical address length");
+     dl_addrlen = dl_abssaplen + ETHERADDRL;
+ 
+ /* ethernet address retrieved as part of DL_INFO_ACK - delphys 20010803 */
+     memcpy(hwaddr, (u_char*)((char*)(dlp) + (int)(dlp->info_ack.dl_addr_offset)), ETHERADDRL);
+ 
+     if ( strioctl(fd, DLIOCRAW, -1, 0, NULL) < 0 ) { 
+-	fatalSys("DLIOCRAW"); 
++	fatal("DLIOCRAW: %m");
+     }
+ 
+-    if (ioctl(fd, I_FLUSH, FLUSHR) < 0) fatalSys("I_FLUSH");
++    if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
++	fatal("I_FLUSH: %m");
+ 
+     return fd;
+ }
+@@ -780,7 +747,7 @@ void dlpromisconreq(int fd, u_long level
+         flags = 0;
+ 
+         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+-                fatalSys("dlpromiscon:  putmsg");
++                fatal("dlpromiscon: putmsg: %m");
+ 
+ }
+ 
+@@ -799,7 +766,7 @@ void dlinforeq(int fd)
+         flags = RS_HIPRI;
+ 
+         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+-                fatalSys("dlinforeq:  putmsg");
++                fatal("dlinforeq: putmsg: %m");
+ }
+ 
+ void dlunitdatareq(int fd, u_char *addrp, int addrlen, u_long minpri, u_long maxpri, u_char *datap, int datalen)
+@@ -827,7 +794,7 @@ void dlunitdatareq(int fd, u_char *addrp
+         data.buf = (char *) datap;
+ 
+         if (putmsg(fd, &ctl, &data, 0) < 0)
+-                fatalSys("dlunitdatareq:  putmsg");
++                fatal("dlunitdatareq: putmsg: %m");
+ }
+ 
+ void dlinfoack(int fd, char *bufp)
+@@ -847,18 +814,14 @@ void dlinfoack(int fd, char *bufp)
+         expecting(DL_INFO_ACK, dlp);
+ 
+         if (ctl.len < sizeof (dl_info_ack_t)) {
+-		char buffer[256];
+-		sprintf(buffer, "dlinfoack:  response ctl.len too short:  %d", ctl.len); 
+-                rp_fatal(buffer); 
++		fatal("dlinfoack: response ctl.len too short: %d", ctl.len);
+ 	}
+ 
+         if (flags != RS_HIPRI)
+-                rp_fatal("dlinfoack:  DL_INFO_ACK was not M_PCPROTO");
++                fatal("dlinfoack: DL_INFO_ACK was not M_PCPROTO");
+ 
+         if (ctl.len < sizeof (dl_info_ack_t)) {
+-		char buffer[256];
+-		sprintf(buffer, "dlinfoack:  short response ctl.len:  %d", ctl.len); 
+-		rp_fatal(buffer); 
++		fatal("dlinfoack: short response ctl.len: %d", ctl.len);
+ 	}
+ }
+ 
+@@ -882,7 +845,7 @@ void dlbindreq(int fd, u_long sap, u_lon
+         flags = 0;
+ 
+         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+-                fatalSys("dlbindreq:  putmsg");
++                fatal("dlbindreq: putmsg: %m");
+ }
+ 
+ void dlattachreq(int fd, u_long ppa)
+@@ -901,7 +864,7 @@ void dlattachreq(int fd, u_long ppa)
+         flags = 0;
+ 
+         if (putmsg(fd, &ctl, (struct strbuf*) NULL, flags) < 0)
+-                fatalSys("dlattachreq:  putmsg");
++                fatal("dlattachreq: putmsg: %m");
+ }
+ 
+ void dlokack(int fd, char *bufp)
+@@ -921,18 +884,14 @@ void dlokack(int fd, char *bufp)
+         expecting(DL_OK_ACK, dlp);
+ 
+         if (ctl.len < sizeof (dl_ok_ack_t)) { 
+-		char buffer[256];
+-		sprintf(buffer, "dlokack:  response ctl.len too short:  %d", ctl.len);
+-		rp_fatal(buffer); 
++		fatal("dlokack: response ctl.len too short: %d", ctl.len);
+ 	}
+ 
+         if (flags != RS_HIPRI)
+-                rp_fatal("dlokack:  DL_OK_ACK was not M_PCPROTO");
++                fatal("dlokack: DL_OK_ACK was not M_PCPROTO");
+ 
+         if (ctl.len < sizeof (dl_ok_ack_t)) {
+-		char buffer[256]; 
+-		sprintf(buffer, "dlokack:  short response ctl.len:  %d", ctl.len);
+-		rp_fatal(buffer); 
++		fatal("dlokack: short response ctl.len: %d", ctl.len);
+ 	}
+ }
+ 
+@@ -953,12 +912,10 @@ void dlbindack(int fd, char *bufp)
+         expecting(DL_BIND_ACK, dlp);
+ 
+         if (flags != RS_HIPRI)
+-                rp_fatal("dlbindack:  DL_OK_ACK was not M_PCPROTO");
++                fatal("dlbindack: DL_OK_ACK was not M_PCPROTO");
+ 
+         if (ctl.len < sizeof (dl_bind_ack_t)) {
+-		char buffer[256];
+-		sprintf(buffer, "dlbindack:  short response ctl.len:  %d", ctl.len);
+-		rp_fatal(buffer); 
++		fatal("dlbindack: short response ctl.len: %d", ctl.len);
+ 	}
+ }
+ 
+@@ -989,8 +946,7 @@ void strgetmsg(int fd, struct strbuf *ct
+          */
+         (void) signal(SIGALRM, sigalrm);
+         if (alarm(MAXWAIT) < 0) {
+-                (void) sprintf(errmsg, "%s:  alarm", caller);
+-                fatalSys(errmsg);
++                fatal("%s: alarm", caller);
+         }
+ 
+         /*
+@@ -998,61 +954,48 @@ void strgetmsg(int fd, struct strbuf *ct
+          */
+         *flagsp = 0;
+         if ((rc = getmsg(fd, ctlp, datap, flagsp)) < 0) {
+-                (void) sprintf(errmsg, "%s:  getmsg", caller);
+-                fatalSys(errmsg);
++                fatal(errmsg, "%s: getmsg: %m", caller);
+         }
+ 
+         /*
+          * Stop timer.
+          */
+         if (alarm(0) < 0) {
+-                (void) sprintf(errmsg, "%s:  alarm", caller);
+-                fatalSys(errmsg);
++                fatal("%s: alarm", caller);
+         }
+ 
+         /*
+          * Check for MOREDATA and/or MORECTL.
+          */
+         if ((rc & (MORECTL | MOREDATA)) == (MORECTL | MOREDATA)) {
+-		char buffer[256]; 
+-		sprintf(buffer, "%s:  MORECTL|MOREDATA", caller);
+-		rp_fatal(buffer);
++		fatal("%s: MORECTL|MOREDATA", caller);
+ 	}
+                 
+         if (rc & MORECTL) {
+-		char buffer[256];
+-		sprintf(buffer, "%s:  MORECTL", caller);
+-		rp_fatal(buffer); 
++		fatal("%s: MORECTL", caller);
+ 	}
+         
+         if (rc & MOREDATA) {
+-		char buffer[256]; 
+-		sprintf(buffer, "%s:  MOREDATA", caller);
+-		rp_fatal(buffer);
++		fatal("%s: MOREDATA", caller);
+ 	}
+ 
+         /*
+          * Check for at least sizeof (long) control data portion.
+          */
+         if (ctlp->len < sizeof (long)) {
+-		char buffer[256]; 
+-		sprintf(buffer, "getmsg:  control portion length < sizeof (long):  %d", ctlp->len);
+-		rp_fatal(buffer); 
++		fatal("getmsg: control portion length < sizeof (long): %d", ctlp->len);
+ 	}
+ }
+ 
+ void sigalrm(int sig)
+ {
+-        (void) rp_fatal("sigalrm:  TIMEOUT");
++        fatal("sigalrm: TIMEOUT");
+ }
+ 
+ void expecting(int prim, union DL_primitives *dlp)
+ {
+         if (dlp->dl_primitive != (u_long)prim) {
+-		char buffer[256]; 
+-		sprintf(buffer, "expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
+-		rp_fatal(buffer); 
+-		exit(1); 
++		fatal("expected %s got %s", dlprim(prim), dlprim(dlp->dl_primitive));
+ 	}
+ }
+ 
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/Makefile.linux ppp-2.4.3/pppd/plugins/rp-pppoe/Makefile.linux
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/Makefile.linux	2004-11-14 08:58:37.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/Makefile.linux	2005-03-11 01:48:27.000000000 +0100
+@@ -28,8 +28,8 @@ COPTS=-O2 -g
+ CFLAGS=$(COPTS) -I../../../include/linux
+ all: rp-pppoe.so pppoe-discovery
+ 
+-pppoe-discovery: libplugin.a pppoe-discovery.o
+-	$(CC) -o pppoe-discovery pppoe-discovery.o libplugin.a
++pppoe-discovery: pppoe-discovery.o utils.o libplugin.a
++	$(CC) -o pppoe-discovery pppoe-discovery.o utils.o libplugin.a
+ 
+ pppoe-discovery.o: pppoe-discovery.c
+ 	$(CC) $(CFLAGS) '-DVERSION="$(VERSION)"' -c -o pppoe-discovery.o pppoe-discovery.c
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/plugin.c ppp-2.4.3/pppd/plugins/rp-pppoe/plugin.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/plugin.c	2004-11-04 11:07:37.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/plugin.c	2005-03-11 02:12:39.000000000 +0100
+@@ -35,7 +35,6 @@ static char const RCSID[] =
+ #include "pppd/pathnames.h"
+ 
+ #include <linux/types.h>
+-#include <syslog.h>
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/socket.h>
+@@ -173,10 +172,8 @@ PPPOEConnectDevice(void)
+ 	    (unsigned) conn->peerEth[5]);
+ 
+     if (connect(conn->sessionSocket, (struct sockaddr *) &sp,
+-		sizeof(struct sockaddr_pppox)) < 0) {
++		sizeof(struct sockaddr_pppox)) < 0)
+ 	fatal("Failed to connect PPPoE socket: %d %m", errno);
+-	return -1;
+-    }
+ 
+     return conn->sessionSocket;
+ }
+@@ -365,11 +362,9 @@ plugin_init(void)
+     }
+ 
+     add_options(Options);
+-
+-    info("RP-PPPoE plugin version %s compiled against pppd %s",
+-	 RP_VERSION, VERSION);
+ }
+ 
++#ifdef unused
+ /**********************************************************************
+ *%FUNCTION: fatalSys
+ *%ARGUMENTS:
+@@ -423,6 +418,7 @@ sysErr(char const *str)
+ {
+     rp_fatal(str);
+ }
++#endif
+ 
+ 
+ struct channel pppoe_channel = {
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/pppoe-discovery.c ppp-2.4.3/pppd/plugins/rp-pppoe/pppoe-discovery.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/pppoe-discovery.c	2004-11-13 13:12:05.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/pppoe-discovery.c	2005-03-11 02:06:13.000000000 +0100
+@@ -17,14 +17,8 @@
+ 
+ #include "pppoe.h"
+ 
+-char *xstrdup(const char *s);
+ void usage(void);
+ 
+-void die(int status)
+-{
+-	exit(status);
+-}
+-
+ int main(int argc, char *argv[])
+ {
+     int opt;
+@@ -32,17 +26,17 @@ int main(int argc, char *argv[])
+ 
+     conn = malloc(sizeof(PPPoEConnection));
+     if (!conn)
+-	fatalSys("malloc");
++	fatal("malloc");
+ 
+     memset(conn, 0, sizeof(PPPoEConnection));
+ 
+     while ((opt = getopt(argc, argv, "I:D:VUAS:C:h")) > 0) {
+ 	switch(opt) {
+ 	case 'S':
+-	    conn->serviceName = xstrdup(optarg);
++	    conn->serviceName = strDup(optarg);
+ 	    break;
+ 	case 'C':
+-	    conn->acName = xstrdup(optarg);
++	    conn->acName = strDup(optarg);
+ 	    break;
+ 	case 'U':
+ 	    conn->useHostUniq = 1;
+@@ -57,7 +51,7 @@ int main(int argc, char *argv[])
+ 	    fprintf(conn->debugFile, "pppoe-discovery %s\n", VERSION);
+ 	    break;
+ 	case 'I':
+-	    conn->ifName = xstrdup(optarg);
++	    conn->ifName = strDup(optarg);
+ 	    break;
+ 	case 'A':
+ 	    /* this is the default */
+@@ -74,7 +68,7 @@ int main(int argc, char *argv[])
+ 
+     /* default interface name */
+     if (!conn->ifName)
+-	conn->ifName = strdup("eth0");
++	conn->ifName = strDup("eth0");
+ 
+     conn->discoverySocket = -1;
+     conn->sessionSocket = -1;
+@@ -84,39 +78,6 @@ int main(int argc, char *argv[])
+     exit(0);
+ }
+ 
+-void rp_fatal(char const *str)
+-{
+-    char buf[1024];
+-
+-    printErr(str);
+-    sprintf(buf, "pppoe-discovery: %.256s", str);
+-    exit(1);
+-}
+-
+-void fatalSys(char const *str)
+-{
+-    char buf[1024];
+-    int i = errno;
+-
+-    sprintf(buf, "%.256s: %.256s", str, strerror(i));
+-    printErr(buf);
+-    sprintf(buf, "pppoe-discovery: %.256s: %.256s", str, strerror(i));
+-    exit(1);
+-}
+-
+-void sysErr(char const *str)
+-{
+-    rp_fatal(str);
+-}
+-
+-char *xstrdup(const char *s)
+-{
+-    register char *ret = strdup(s);
+-    if (!ret)
+-	sysErr("strdup");
+-    return ret;
+-}
+-
+ void usage(void)
+ {
+     fprintf(stderr, "Usage: pppoe-discovery [options]\n");
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/pppoe.h ppp-2.4.3/pppd/plugins/rp-pppoe/pppoe.h
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/pppoe.h	2004-11-04 11:07:37.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/pppoe.h	2005-03-11 02:08:00.000000000 +0100
+@@ -307,12 +307,18 @@ void discovery(PPPoEConnection *conn);
+ unsigned char *findTag(PPPoEPacket *packet, UINT16_t tagType,
+ 		       PPPoETag *tag);
+ 
++void dbglog(char *, ...);	/* log a debug message */
++void info(char *, ...);		/* log an informational message */
++void warn(char *, ...);		/* log a warning message */
++void error(char *, ...);	/* log an error message */
++void fatal(char *, ...);	/* log an error message and die(1) */
++
+ #define SET_STRING(var, val) do { if (var) free(var); var = strDup(val); } while(0);
+ 
+ #define CHECK_ROOM(cursor, start, len) \
+ do {\
+     if (((cursor)-(start))+(len) > MAX_PPPOE_PAYLOAD) { \
+-        syslog(LOG_ERR, "Would create too-long packet"); \
++        error("Would create too-long packet"); \
+         return; \
+     } \
+ } while(0)
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/rp-pppoe/utils.c ppp-2.4.3/pppd/plugins/rp-pppoe/utils.c
+--- ppp-2.4.3.orig/pppd/plugins/rp-pppoe/utils.c	1970-01-01 01:00:00.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/rp-pppoe/utils.c	2005-03-11 02:07:57.000000000 +0100
+@@ -0,0 +1,62 @@
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <stdarg.h>
++#include <syslog.h>
++
++void dbglog(const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    vsyslog(LOG_DEBUG, fmt, ap);
++    vfprintf(stderr, fmt, ap);
++    fputs("\n", stderr);
++    va_end(ap);
++}
++
++void info(const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    vsyslog(LOG_INFO, fmt, ap);
++    vfprintf(stderr, fmt, ap);
++    fputs("\n", stderr);
++    va_end(ap);
++}
++
++void warn(const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    vsyslog(LOG_WARNING, fmt, ap);
++    vfprintf(stderr, fmt, ap);
++    fputs("\n", stderr);
++    va_end(ap);
++}
++
++void error(const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    vsyslog(LOG_ERR, fmt, ap);
++    vfprintf(stderr, fmt, ap);
++    fputs("\n", stderr);
++    va_end(ap);
++}
++
++void fatal(const char *fmt, ...)
++{
++    va_list ap;
++
++    va_start(ap, fmt);
++    vsyslog(LOG_ERR, fmt, ap);
++    vfprintf(stderr, fmt, ap);
++    fputs("\n", stderr);
++    va_end(ap);
++    exit(1);
++}
++
diff --git a/openwrt/package/ppp/patches/104-debian_fix_linkpidfile.patch b/openwrt/package/ppp/patches/104-debian_fix_linkpidfile.patch
new file mode 100644
index 0000000000..9e32adcae1
--- /dev/null
+++ b/openwrt/package/ppp/patches/104-debian_fix_linkpidfile.patch
@@ -0,0 +1,43 @@
+Subject: Bug#284382: ppp: linkpidfile is not created upon detachment
+From: <herbert@gondor.apana.org.au>
+
+Package: ppp
+Version: 2.4.2+20040428-2
+Severity: wishlist
+
+When pppd detaches from the parent normally, that is, without nodetach
+or updetach set, the linkpidfile is not created even when linkname is
+set.
+
+This is because the create_linkpidfile call in detach() is only made
+if the linkpidfile is filled in.  However, linkpidfile is never filled
+in until create_linkpidfile has been called.
+
+IMHO the call should be made uncondtionally in detach() since
+create_linkpidfile does its own check on linkname anyway.
+
+Please note that the version of pppd in woody always wrote the
+linkpidfile after detaching.  It did so in main() however.  That
+call has now been removed which is why I'm seeing this problem.
+
+[...]
+
+--
+Index: pppd/main.c
+===================================================================
+RCS file: /var/cvs/snwb/packages/ppp/pppd/main.c,v
+retrieving revision 1.11
+diff -u -r1.11 main.c
+--- ppp/pppd/main.c	29 Nov 2004 22:49:23 -0000	1.11
++++ ppp/pppd/main.c	5 Dec 2004 23:59:58 -0000
+@@ -819,8 +819,7 @@
+ 	/* update pid files if they have been written already */
+ 	if (pidfilename[0])
+ 	    create_pidfile(pid);
+-	if (linkpidfile[0])
+-	    create_linkpidfile(pid);
++	create_linkpidfile(pid);
+ 	exit(0);		/* parent dies */
+     }
+     setsid();
+
diff --git a/openwrt/package/ppp/patches/105-debian_pppoatm_cleanup.patch b/openwrt/package/ppp/patches/105-debian_pppoatm_cleanup.patch
new file mode 100644
index 0000000000..2437a12003
--- /dev/null
+++ b/openwrt/package/ppp/patches/105-debian_pppoatm_cleanup.patch
@@ -0,0 +1,95 @@
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/pppoatm/pppoatm.c ppp-2.4.3/pppd/plugins/pppoatm/pppoatm.c
+--- ppp-2.4.3.orig/pppd/plugins/pppoatm/pppoatm.c	2005-03-22 14:44:18.000000000 +0100
++++ ppp-2.4.3/pppd/plugins/pppoatm/pppoatm.c	2005-03-22 14:44:02.000000000 +0100
+@@ -70,18 +70,20 @@ static int setdevname_pppoatm(const char
+ {
+ 	struct sockaddr_atmpvc addr;
+ 	extern struct stat devstat;
++
+ 	if (device_got_set)
+ 		return 0;
+-	//info("PPPoATM setdevname_pppoatm: '%s'", cp);
++
+ 	memset(&addr, 0, sizeof addr);
+ 	if (text2atm(cp, (struct sockaddr *) &addr, sizeof(addr),
+ 	    T2A_PVC | T2A_NAME) < 0) {
+-               if(doit)
+-                   info("atm does not recognize: %s", cp);
++		if (doit)
++			info("cannot parse the ATM address: %s", cp);
+ 		return 0;
+-           }
+-	if (!doit) return 1;
+-	//if (!dev_set_ok()) return -1;
++	}
++	if (!doit)
++		return 1;
++
+ 	memcpy(&pvcaddr, &addr, sizeof pvcaddr);
+ 	strlcpy(devnam, cp, sizeof devnam);
+ 	devstat.st_mode = S_IFSOCK;
+@@ -93,7 +95,6 @@ static int setdevname_pppoatm(const char
+ 		lcp_allowoptions[0].neg_asyncmap = 0;
+ 		lcp_wantoptions[0].neg_pcompression = 0;
+ 	}
+-	info("PPPoATM setdevname_pppoatm - SUCCESS:%s", cp);
+ 	device_got_set = 1;
+ 	return 1;
+ }
+@@ -108,6 +109,7 @@ static void no_device_given_pppoatm(void
+ static void set_line_discipline_pppoatm(int fd)
+ {
+ 	struct atm_backend_ppp be;
++
+ 	be.backend_num = ATM_BACKEND_PPP;
+ 	if (!llc_encaps)
+ 		be.encaps = PPPOATM_ENCAPS_VC;
+@@ -115,6 +117,7 @@ static void set_line_discipline_pppoatm(
+ 		be.encaps = PPPOATM_ENCAPS_LLC;
+ 	else
+ 		be.encaps = PPPOATM_ENCAPS_AUTODETECT;
++
+ 	if (ioctl(fd, ATM_SETBACKEND, &be) < 0)
+ 		fatal("ioctl(ATM_SETBACKEND): %m");
+ }
+@@ -179,16 +182,19 @@ static void send_config_pppoa(int mtu,
+ {
+ 	int sock;
+ 	struct ifreq ifr;
++
+ 	if (mtu > pppoatm_max_mtu)
+ 		error("Couldn't increase MTU to %d", mtu);
++
+ 	sock = socket(AF_INET, SOCK_DGRAM, 0);
+ 	if (sock < 0)
+ 		fatal("Couldn't create IP socket: %m");
++
+ 	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ 	ifr.ifr_mtu = mtu;
+ 	if (ioctl(sock, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+ 		fatal("ioctl(SIOCSIFMTU): %m");
+-	(void) close (sock);
++	close(sock);
+ }
+ 
+ static void recv_config_pppoa(int mru,
+@@ -202,7 +208,7 @@ static void recv_config_pppoa(int mru,
+ 
+ void plugin_init(void)
+ {
+-#if defined(__linux__)
++#ifdef linux
+ 	extern int new_style_driver;	/* From sys-linux.c */
+ 	if (!ppp_available() && !new_style_driver)
+ 		fatal("Kernel doesn't support ppp_generic - "
+@@ -210,9 +216,9 @@ void plugin_init(void)
+ #else
+ 	fatal("No PPPoATM support on this OS");
+ #endif
+-	info("PPPoATM plugin_init");
+ 	add_options(pppoa_options);
+ }
++
+ struct channel pppoa_channel = {
+     options: pppoa_options,
+     process_extra_options: NULL,
diff --git a/openwrt/package/ppp/patches/106-debian_pppoatm_fix_mtu.patch b/openwrt/package/ppp/patches/106-debian_pppoatm_fix_mtu.patch
new file mode 100644
index 0000000000..ef28b5cf2b
--- /dev/null
+++ b/openwrt/package/ppp/patches/106-debian_pppoatm_fix_mtu.patch
@@ -0,0 +1,31 @@
+diff -ruNp ppp-2.4.3.orig/pppd/plugins/pppoatm/pppoatm.c ppp-2.4.3/pppd/plugins/pppoatm/pppoatm.c
+--- ppp-2.4.3.orig/pppd/plugins/pppoatm/pppoatm.c	2005-05-04 02:00:28.000000000 +0200
++++ ppp-2.4.3/pppd/plugins/pppoatm/pppoatm.c	2005-05-04 01:59:11.000000000 +0200
+@@ -183,8 +183,11 @@ static void send_config_pppoa(int mtu,
+ 	int sock;
+ 	struct ifreq ifr;
+ 
+-	if (mtu > pppoatm_max_mtu)
+-		error("Couldn't increase MTU to %d", mtu);
++	if (pppoatm_max_mtu && mtu > pppoatm_max_mtu) {
++		warn("Couldn't increase MTU to %d. Using %d",
++			mtu, pppoatm_max_mtu);
++		mtu = pppoatm_max_mtu;
++	}
+ 
+ 	sock = socket(AF_INET, SOCK_DGRAM, 0);
+ 	if (sock < 0)
+@@ -202,8 +205,11 @@ static void recv_config_pppoa(int mru,
+ 			      int pcomp,
+ 			      int accomp)
+ {
+-	if (mru > pppoatm_max_mru)
+-		error("Couldn't increase MRU to %d", mru);
++	if (pppoatm_max_mru && mru > pppoatm_max_mru) {
++		warn("Couldn't increase MRU to %d. Using %d",
++			mru, pppoatm_max_mru);
++		mru = pppoatm_max_mru;
++	}
+ }
+ 
+ void plugin_init(void)
diff --git a/openwrt/package/ppp/patches/107-debian_stripMSdomain.patch b/openwrt/package/ppp/patches/107-debian_stripMSdomain.patch
new file mode 100644
index 0000000000..d52e38645d
--- /dev/null
+++ b/openwrt/package/ppp/patches/107-debian_stripMSdomain.patch
@@ -0,0 +1,35 @@
+diff -ruN ppp.orig/pppd/chap-new.c ppp/pppd/chap-new.c
+--- ppp.orig/pppd/chap-new.c	2003-11-27 23:25:17.000000000 +0100
++++ ppp/pppd/chap-new.c	2003-12-02 12:26:21.000000000 +0100
+@@ -57,6 +57,7 @@
+ int chap_timeout_time = 3;
+ int chap_max_transmits = 10;
+ int chap_rechallenge_time = 0;
++int chapms_strip_domain = 0;
+ 
+ /*
+  * Command-line options.
+@@ -68,6 +69,8 @@
+ 	  "Set max #xmits for challenge", OPT_PRIO },
+ 	{ "chap-interval", o_int, &chap_rechallenge_time,
+ 	  "Set interval for rechallenge", OPT_PRIO },
++	{ "chapms-strip-domain", o_bool, &chapms_strip_domain,
++	  "Strip the domain prefix before the Username", 1 },
+ 	{ NULL }
+ };
+ 
+@@ -338,6 +341,14 @@
+ 			/* Null terminate and clean remote name. */
+ 			slprintf(rname, sizeof(rname), "%.*v", len, name);
+ 			name = rname;
++
++			/* strip the MS domain name */
++			if (chapms_strip_domain && strrchr(rname, '\\')) {
++				char tmp[MAXNAMELEN+1];
++
++				strcpy(tmp, strrchr(rname, '\\') + 1);
++				strcpy(rname, tmp);
++			}
+ 		}
+ 
+ 		if (chap_verify_hook)
diff --git a/openwrt/package/ppp/patches/108-debian_defaultroute.patch b/openwrt/package/ppp/patches/108-debian_defaultroute.patch
new file mode 100644
index 0000000000..76b444e4b2
--- /dev/null
+++ b/openwrt/package/ppp/patches/108-debian_defaultroute.patch
@@ -0,0 +1,253 @@
+--- ppp/pppd/ipcp.c	Wed May 31 17:20:41 2000
++++ ppp/pppd/ipcp.c	Wed May 31 17:27:19 2000
+@@ -145,7 +145,17 @@
+     { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+       "disable defaultroute option", OPT_A2COPY,
+       &ipcp_wantoptions[0].default_route },
+
++#ifdef __linux__
++    { "replacedefaultroute", o_bool,
++				&ipcp_wantoptions[0].replace_default_route,
++      "Replace default route", 1
++    },
++    { "noreplacedefaultroute", o_bool,
++				&ipcp_allowoptions[0].replace_default_route,
++      "Never replace default route", OPT_A2COPY,
++				&ipcp_wantoptions[0].replace_default_route },
++#endif
+     { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
+       "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
+     { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+@@ -195,7 +205,7 @@
+     ip_active_pkt
+ };
+ 
+-static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t));
++static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t, bool));
+ static void ipcp_script __P((char *));		/* Run an up/down script */
+ static void ipcp_script_done __P((void *));
+ 
+@@ -1344,7 +1354,12 @@
+     if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+ 	return 0;
+     if (wo->default_route)
++#ifndef __linux__
+ 	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
++#else
++	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr,
++					    wo->replace_default_route))
++#endif
+ 	    default_route_set[u] = 1;
+     if (wo->proxy_arp)
+ 	if (sifproxyarp(u, wo->hisaddr))
+@@ -1420,7 +1435,8 @@
+      */
+     if (demand) {
+ 	if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+-	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
++	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr,
++				      wo->replace_default_route);
+ 	    if (go->ouraddr != wo->ouraddr) {
+ 		warn("Local IP address changed to %I", go->ouraddr);
+ 		script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr));
+@@ -1445,7 +1461,12 @@
+ 
+ 	    /* assign a default route through the interface if required */
+ 	    if (ipcp_wantoptions[f->unit].default_route) 
++#ifndef __linux__
+ 		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
++#else
++		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
++					     wo->replace_default_route))
++#endif
+ 		    default_route_set[f->unit] = 1;
+ 
+ 	    /* Make a proxy ARP entry if requested. */
+@@ -1492,7 +1513,12 @@
+ 
+ 	/* assign a default route through the interface if required */
+ 	if (ipcp_wantoptions[f->unit].default_route) 
++#ifndef __linux__
+ 	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
++#else
++	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
++					 wo->replace_default_route))
++#endif
+ 		default_route_set[f->unit] = 1;
+ 
+ 	/* Make a proxy ARP entry if requested. */
+@@ -1559,7 +1585,7 @@
+ 	sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
+ 	sifdown(f->unit);
+ 	ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
+-			 ipcp_hisoptions[f->unit].hisaddr);
++			 ipcp_hisoptions[f->unit].hisaddr, 0);
+     }
+ 
+     /* Execute the ip-down script */
+@@ -1575,16 +1601,25 @@
+  * proxy arp entries, etc.
+  */
+ static void
+-ipcp_clear_addrs(unit, ouraddr, hisaddr)
++ipcp_clear_addrs(unit, ouraddr, hisaddr, replacedefaultroute)
+     int unit;
+     u_int32_t ouraddr;  /* local address */
+     u_int32_t hisaddr;  /* remote address */
++    bool replacedefaultroute;
+ {
+     if (proxy_arp_set[unit]) {
+ 	cifproxyarp(unit, hisaddr);
+ 	proxy_arp_set[unit] = 0;
+     }
+-    if (default_route_set[unit]) {
++    /* If replacedefaultroute, sifdefaultroute will be called soon
++     * with replacedefaultroute set and that will overwrite the current
++     * default route. This is the case only when doing demand, otherwise
++     * during demand, this cifdefaultroute would restore the old default
++     * route which is not what we want in this case. In the non-demand
++     * case, we'll delete the default route and restore the old if there
++     * is one saved by an sifdefaultroute with replacedefaultroute.
++     */
++    if (!replacedefaultroute && default_route_set[unit]) {
+ 	cifdefaultroute(unit, ouraddr, hisaddr);
+ 	default_route_set[unit] = 0;
+     }
+--- ppp/pppd/ipcp.h	Wed May 31 17:20:41 2000
++++ ppp/pppd/ipcp.h	Wed May 31 15:56:17 2000
+@@ -47,6 +47,7 @@
+     bool old_addrs;		/* Use old (IP-Addresses) option? */
+     bool req_addr;		/* Ask peer to send IP address? */
+     bool default_route;		/* Assign default route through interface? */
++    bool replace_default_route;	/* Replace default route through interface? */
+     bool proxy_arp;		/* Make proxy ARP entry for peer? */
+     bool neg_vj;		/* Van Jacobson Compression? */
+     bool old_vj;		/* use old (short) form of VJ option? */
+--- ppp/pppd/pppd.h	Wed May 31 17:20:41 2000
++++ ppp/pppd/pppd.h	Wed May 31 15:56:17 2000
+@@ -416,7 +416,11 @@
+ int  cif6addr __P((int, eui64_t, eui64_t));
+ 				/* Remove an IPv6 address from i/f */
+ #endif
++#ifndef __linux__
+ int  sifdefaultroute __P((int, u_int32_t, u_int32_t));
++#else
++int  sifdefaultroute __P((int, u_int32_t, u_int32_t, bool replace_default_rt));
++#endif
+ 				/* Create default route through i/f */
+ int  cifdefaultroute __P((int, u_int32_t, u_int32_t));
+ 				/* Delete default route through i/f */
+--- ppp/pppd/sys-linux.c	Wed May 31 17:20:41 2000
++++ ppp/pppd/sys-linux.c	Wed May 31 17:37:23 2000
+@@ -143,6 +143,8 @@
+ 
+ static int	if_is_up;	/* Interface has been marked up */
+ static u_int32_t default_route_gateway;	/* Gateway for default route added */
++static struct rtentry old_def_rt;       /* Old default route */
++static int       default_rt_repl_rest;  /* replace and restore old default rt */
+ static u_int32_t proxy_arp_addr;	/* Addr for proxy arp entry added */
+ static char proxy_arp_dev[16];		/* Device for proxy arp entry */
+ static u_int32_t our_old_addr;		/* for detecting address changes */
+@@ -1209,6 +1211,9 @@
+ 	p = NULL;
+     }
+ 
++    SET_SA_FAMILY (rt->rt_dst,     AF_INET);
++    SET_SA_FAMILY (rt->rt_gateway, AF_INET);
++
+     SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16);
+     SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16);
+     SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16);
+@@ -1278,19 +1283,53 @@
+ /********************************************************************
+  *
+  * sifdefaultroute - assign a default route through the address given.
++ *
++ * If the global default_rt_repl_rest flag is set, then this function
++ * already replaced the original system defaultroute with some other
++ * route and it should just replace the current defaultroute with
++ * another one, without saving the current route. Use: demand mode,
++ * when pppd sets first a defaultroute it it's temporary ppp0 addresses
++ * and then changes the temporary addresses to the addresses for the real
++ * ppp connection when it has come up.
+  */
+ 
+-int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
++int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway, bool replace)
+ {
+-    struct rtentry rt;
+-
+-    if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) {
+-	u_int32_t old_gateway = SIN_ADDR(rt.rt_gateway);
++    struct rtentry rt, tmp_rt;
++    struct rtentry *del_rt = NULL;
+ 
+-	if (old_gateway != gateway)
+-	    error("not replacing existing default route to %s [%I]",
+-		  rt.rt_dev, old_gateway);
+-	return 0;
++    
++    if (default_rt_repl_rest) {
++	/* We have already reclaced the original defaultroute, if we
++         * are called again, we will delete the current default route
++         * and set the new default route in this function.  
++         * - this is normally only the case the doing demand: */
++	if (defaultroute_exists( &tmp_rt ))
++		del_rt = &tmp_rt;
++    } else if ( defaultroute_exists( &old_def_rt                ) &&
++	                     strcmp(  old_def_rt.rt_dev, ifname ) != 0) {
++	/* We did not yet replace an existing default route, let's
++	 * check if we should save and replace a default route:
++         */
++	u_int32_t old_gateway = SIN_ADDR(old_def_rt.rt_gateway);
++
++	if (old_gateway != gateway) {
++	    if (!replace) {
++	        error("not replacing default route to %s [%I]",
++			old_def_rt.rt_dev, old_gateway);
++		return 0;
++	    } else {
++		// we need to copy rt_dev because we need it permanent too:
++		char * tmp_dev = malloc(strlen(old_def_rt.rt_dev)+1);
++		strcpy(tmp_dev, old_def_rt.rt_dev);
++		old_def_rt.rt_dev = tmp_dev;
++
++		notice("replacing old default route to %s [%I]",
++			old_def_rt.rt_dev, old_gateway);
++	        default_rt_repl_rest = 1;
++		del_rt = &old_def_rt;
++	    }
++	}
+     }
+ 
+     memset (&rt, '\0', sizeof (rt));
+@@ -1310,6 +1349,12 @@
+ 	    error("default route ioctl(SIOCADDRT): %m(%d)", errno);
+ 	return 0;
+     }
++    if (default_rt_repl_rest && del_rt)
++        if (ioctl(sock_fd, SIOCDELRT, del_rt) < 0) {
++	    if ( ! ok_error ( errno ))
++	        error("del old default route ioctl(SIOCDELRT): %m(%d)", errno);
++	    return 0;
++        }
+ 
+     default_route_gateway = gateway;
+     return 1;
+@@ -1344,6 +1389,16 @@
+ 		error("default route ioctl(SIOCDELRT): %m (%d)", errno);
+ 	    return 0;
+ 	}
++    }
++    if (default_rt_repl_rest) {
++	notice("restoring old default route to %s [%I]",
++			old_def_rt.rt_dev, SIN_ADDR(old_def_rt.rt_gateway));
++        if (ioctl(sock_fd, SIOCADDRT, &old_def_rt) < 0) {
++	    if ( ! ok_error ( errno ))
++	        error("restore default route ioctl(SIOCADDRT): %m(%d)", errno);
++	    return 0;
++        }
++        default_rt_repl_rest = 0;
+     }
+ 
+     return 1;
diff --git a/openwrt/package/ppp/patches/109-debian_demand.patch b/openwrt/package/ppp/patches/109-debian_demand.patch
new file mode 100644
index 0000000000..e024696697
--- /dev/null
+++ b/openwrt/package/ppp/patches/109-debian_demand.patch
@@ -0,0 +1,172 @@
+--- ppp/pppd/demand.c
++++ ppp/pppd/demand.c	2000/06/28 14:54:04
+@@ -25,6 +25,8 @@
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <netdb.h>
++#include <unistd.h>
++#include <syslog.h>
+ #include <sys/param.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -32,6 +34,8 @@
+ #include <sys/resource.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
+ #ifdef PPP_FILTER
+ #include <net/if.h>
+ #include <net/bpf.h>
+@@ -210,6 +214,14 @@
+     int c, rv;
+ 
+     rv = 0;
++
++/* check for synchronous connection... */
++
++    if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
++        rv = loop_frame(p,n);
++        return rv;
++    }
++
+     for (; n > 0; --n) {
+ 	c = *p++;
+ 	if (c == PPP_FLAG) {
+@@ -288,17 +300,102 @@
+  * loopback, now that the real serial link is up.
+  */
+ void
+-demand_rexmit(proto)
++demand_rexmit(proto, newip)
+     int proto;
++    u_int32_t newip;
+ {
+     struct packet *pkt, *prev, *nextpkt;
++    unsigned short checksum;
++    unsigned short pkt_checksum = 0;
++    unsigned iphdr;
++    struct timeval tv;
++    char cv = 0;
++    char ipstr[16];
+ 
+     prev = NULL;
+     pkt = pend_q;
+     pend_q = NULL;
++    tv.tv_sec = 1;
++    tv.tv_usec = 0;
++    select(0,NULL,NULL,NULL,&tv);	/* Sleep for 1 Seconds */
+     for (; pkt != NULL; pkt = nextpkt) {
+ 	nextpkt = pkt->next;
+ 	if (PPP_PROTOCOL(pkt->data) == proto) {
++            if ( (proto == PPP_IP) && newip ) {
++		/* Get old checksum */
++
++		iphdr = (pkt->data[4] & 15) << 2;
++		checksum = *((unsigned short *) (pkt->data+14));
++                if (checksum == 0xFFFF) {
++                    checksum = 0;
++                }
++
++ 
++                if (pkt->data[13] == 17) {
++                    pkt_checksum =  *((unsigned short *) (pkt->data+10+iphdr));
++		    if (pkt_checksum) {
++                        cv = 1;
++                        if (pkt_checksum == 0xFFFF) {
++                            pkt_checksum = 0;
++                        }
++                    }
++                    else {
++                       cv = 0;
++                    }
++                }
++
++		if (pkt->data[13] == 6) {
++		    pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
++		    cv = 1;
++                    if (pkt_checksum == 0xFFFF) {
++                        pkt_checksum = 0;
++                    }
++		}
++
++		/* Delete old Source-IP-Address */
++                checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++		pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		/* Change Source-IP-Address */
++                * ((u_int32_t *) (pkt->data + 16)) = newip;
++
++		/* Add new Source-IP-Address */
++                checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++                pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
++                pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
++
++		/* Write new checksum */
++                if (!checksum) {
++                    checksum = 0xFFFF;
++                }
++                *((unsigned short *) (pkt->data+14)) = checksum;
++		if (pkt->data[13] == 6) {
++		    *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
++		}
++		if (cv && (pkt->data[13] == 17) ) {
++		    *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
++		}
++
++		/* Log Packet */
++		strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
++		if (pkt->data[13] == 1) {
++		    syslog(LOG_INFO,"Open ICMP %s -> %s\n",
++			ipstr,
++			inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
++		} else {
++		    syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
++			pkt->data[13] == 6 ? "TCP" : "UDP",
++			ipstr,
++			ntohs(*( (short *) (pkt->data+iphdr+4))),
++			inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
++			ntohs(*( (short *) (pkt->data+iphdr+6))));
++                }
++            }
+ 	    output(0, pkt->data, pkt->length);
+ 	    free(pkt);
+ 	} else {
+--- ppp/pppd/ipcp.c
++++ ppp/pppd/ipcp.c	2000/06/28 12:32:05
+@@ -1454,7 +1454,7 @@
+ 		    proxy_arp_set[f->unit] = 1;
+ 
+ 	}
+-	demand_rexmit(PPP_IP);
++	demand_rexmit(PPP_IP,go->ouraddr);
+ 	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+ 
+     } else {
+--- ppp/pppd/ipv6cp.c
++++ ppp/pppd/ipv6cp.c	2000/06/28 12:32:06
+@@ -1153,7 +1153,7 @@
+ 	    }
+ 
+ 	}
+-	demand_rexmit(PPP_IPV6);
++	demand_rexmit(PPP_IPV6,0);
+ 	sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
+ 
+     } else {
+--- ppp/pppd/pppd.h
++++ ppp/pppd/pppd.h	2000/06/28 12:32:06
+@@ -359,7 +359,7 @@
+ 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 */
++void demand_rexmit __P((int, u_int32_t)); /* retransmit saved frames for an NP*/
+ int  loop_chars __P((unsigned char *, int)); /* process chars from loopback */
+ int  loop_frame __P((unsigned char *, int)); /* should we bring link up? */
+ 
diff --git a/openwrt/package/ppp/patches/200-makefile.patch b/openwrt/package/ppp/patches/200-makefile.patch
new file mode 100644
index 0000000000..5bbf8602d1
--- /dev/null
+++ b/openwrt/package/ppp/patches/200-makefile.patch
@@ -0,0 +1,53 @@
+diff -ruN ppp-2.4.3-orig/pppd/Makefile.linux ppp-2.4.3-3/pppd/Makefile.linux
+--- ppp-2.4.3-orig/pppd/Makefile.linux	2004-11-13 13:02:22.000000000 +0100
++++ ppp-2.4.3-3/pppd/Makefile.linux	2004-12-16 04:43:41.000000000 +0100
+@@ -48,19 +48,19 @@
+ # Uncomment the next line to include support for PPP packet filtering.
+ # This requires that the libpcap library and headers be installed
+ # and that the kernel driver support PPP packet filtering.
+-FILTER=y
++#FILTER=y
+ 
+ # Uncomment the next line to enable multilink PPP (enabled by default)
+ # Linux distributions: Please leave multilink ENABLED in your builds
+ # of pppd!
+-HAVE_MULTILINK=y
++#HAVE_MULTILINK=y
+ 
+ # Uncomment the next line to enable the TDB database (enabled by default.)
+ # If you enable multilink, then TDB is automatically enabled also.
+ # Linux distributions: Please leave TDB ENABLED in your builds.
+-USE_TDB=y
++#USE_TDB=y
+ 
+-HAS_SHADOW=y
++#HAS_SHADOW=y
+ #USE_PAM=y
+ #HAVE_INET6=y
+ 
+@@ -77,7 +77,7 @@
+ 
+ INCLUDE_DIRS= -I../include
+ 
+-COMPILE_FLAGS= -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MMAP
++COMPILE_FLAGS= -DHAVE_PATHS_H -DHAVE_MMAP
+ 
+ CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
+ 
+@@ -117,12 +117,12 @@
+ #LIBS     += -lshadow $(LIBS)
+ endif
+ 
+-ifneq ($(wildcard /usr/include/crypt.h),)
++#ifneq ($(wildcard /usr/include/crypt.h),)
+ CFLAGS   += -DHAVE_CRYPT_H=1
+-endif
+-ifneq ($(wildcard /usr/lib/libcrypt.*),)
++#endif
++#ifneq ($(wildcard /usr/lib/libcrypt.*),)
+ LIBS	+= -lcrypt
+-endif
++#endif
+ 
+ ifdef NEEDDES
+ ifndef USE_CRYPT
diff --git a/openwrt/package/ppp/patches/201-mppe_mppc_1.1.patch b/openwrt/package/ppp/patches/201-mppe_mppc_1.1.patch
new file mode 100644
index 0000000000..7e09f1a792
--- /dev/null
+++ b/openwrt/package/ppp/patches/201-mppe_mppc_1.1.patch
@@ -0,0 +1,1585 @@
+diff -ruN ppp-2.4.3.orig/include/linux/ppp-comp.h ppp-2.4.3/include/linux/ppp-comp.h
+--- ppp-2.4.3.orig/include/linux/ppp-comp.h	2002-12-06 10:49:15.000000000 +0100
++++ ppp-2.4.3/include/linux/ppp-comp.h	2004-11-21 13:54:09.000000000 +0100
+@@ -36,7 +36,7 @@
+  */
+ 
+ /*
+- *  ==FILEVERSION 20020319==
++ *  ==FILEVERSION 20020715==
+  *
+  *  NOTE TO MAINTAINERS:
+  *     If you modify this file at all, please set the above date.
+@@ -86,7 +86,7 @@
+ 
+ 	/* Compress a packet */
+ 	int     (*compress) (void *state, unsigned char *rptr,
+-			      unsigned char *obuf, int isize, int osize);
++			     unsigned char *obuf, int isize, int osize);
+ 
+ 	/* Return compression statistics */
+ 	void	(*comp_stat) (void *state, struct compstat *stats);
+@@ -107,7 +107,7 @@
+ 
+ 	/* Decompress a packet. */
+ 	int	(*decompress) (void *state, unsigned char *ibuf, int isize,
+-				unsigned char *obuf, int osize);
++			       unsigned char *obuf, int osize);
+ 
+ 	/* Update state for an incompressible packet received */
+ 	void	(*incomp) (void *state, unsigned char *ibuf, int icnt);
+@@ -288,6 +288,33 @@
+ 	    opts |= MPPE_OPT_UNKNOWN;		\
+     } while (/* CONSTCOND */ 0)
+ 
++/* MPPE/MPPC definitions by J.D.*/
++#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
++#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
++#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
++#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
++#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
++
++/*
++ * Definitions for Stac LZS.
++ */
++
++#define CI_LZS			17	/* config option for Stac LZS */
++#define CILEN_LZS		5	/* length of config option */
++
++#define LZS_OVHD		4	/* max. LZS overhead */
++#define LZS_HIST_LEN		2048	/* LZS history size */
++#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
++
++#define LZS_MODE_NONE		0
++#define LZS_MODE_LCB		1
++#define LZS_MODE_CRC		2
++#define LZS_MODE_SEQ		3
++#define LZS_MODE_EXT		4
++
++#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
++#define LZS_EXT_BIT_COMP	0x20	/* bit C */
++
+ /*
+  * Definitions for other, as yet unsupported, compression methods.
+  */
+diff -ruN ppp-2.4.3.orig/include/net/ppp-comp.h ppp-2.4.3/include/net/ppp-comp.h
+--- ppp-2.4.3.orig/include/net/ppp-comp.h	2002-12-06 10:49:15.000000000 +0100
++++ ppp-2.4.3/include/net/ppp-comp.h	2004-11-21 13:54:09.000000000 +0100
+@@ -255,6 +255,33 @@
+ 	    opts |= MPPE_OPT_UNKNOWN;		\
+     } while (/* CONSTCOND */ 0)
+ 
++/* MPPE/MPPC definitions by J.D.*/
++#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
++#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
++#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
++#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
++#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
++
++/*
++ * Definitions for Stac LZS.
++ */
++
++#define CI_LZS			17	/* config option for Stac LZS */
++#define CILEN_LZS		5	/* length of config option */
++
++#define LZS_OVHD		4	/* max. LZS overhead */
++#define LZS_HIST_LEN		2048	/* LZS history size */
++#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
++
++#define LZS_MODE_NONE		0
++#define LZS_MODE_LCB		1
++#define LZS_MODE_CRC		2
++#define LZS_MODE_SEQ		3
++#define LZS_MODE_EXT		4
++
++#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
++#define LZS_EXT_BIT_COMP	0x20	/* bit C */
++
+ /*
+  * Definitions for other, as yet unsupported, compression methods.
+  */
+diff -ruN ppp-2.4.3.orig/pppd/ccp.c ppp-2.4.3/pppd/ccp.c
+--- ppp-2.4.3.orig/pppd/ccp.c	2004-11-13 03:28:15.000000000 +0100
++++ ppp-2.4.3/pppd/ccp.c	2004-11-21 13:54:09.000000000 +0100
+@@ -62,12 +62,10 @@
+ static char bsd_value[8];
+ static char deflate_value[8];
+ 
+-/*
+- * Option variables.
+- */
+ #ifdef MPPE
+-bool refuse_mppe_stateful = 1;		/* Allow stateful mode? */
+-#endif
++static int setmppe(char **);
++static int setnomppe(void);
++#endif /* MPPE */
+ 
+ static option_t ccp_option_list[] = {
+     { "noccp", o_bool, &ccp_protent.enabled_flag,
+@@ -108,54 +106,36 @@
+       "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
+       &ccp_allowoptions[0].predictor_1 },
+ 
++    { "lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_PRIO },
++    { "+lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_ALIAS | OPT_PRIO },
++    { "nolzs", o_bool, &ccp_wantoptions[0].lzs,
++      "don't allow Stac LZS", OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].lzs },
++    { "-lzs", o_bool, &ccp_wantoptions[0].lzs,
++      "don't allow Stac LZS", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].lzs },
++
+ #ifdef MPPE
+-    /* MPPE options are symmetrical ... we only set wantoptions here */
+-    { "require-mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "require MPPE encryption",
+-      OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+-    { "+mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "require MPPE encryption",
+-      OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
+-    { "nomppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "don't allow MPPE encryption", OPT_PRIO },
+-    { "-mppe", o_bool, &ccp_wantoptions[0].mppe,
+-      "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO },
+-
+-    /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */
+-    { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-    { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-    { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 40-bit encryption",
+-      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe },
+-    { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 40-bit encryption",
+-      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40,
+-      &ccp_wantoptions[0].mppe },
+-
+-    { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-    { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "require MPPE 128-bit encryption",
+-      OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-    { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 128-bit encryption",
+-      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe },
+-    { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
+-      "don't allow MPPE 128-bit encryption",
+-      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128,
+-      &ccp_wantoptions[0].mppe },
+-
+-    /* strange one; we always request stateless, but will we allow stateful? */
+-    { "mppe-stateful", o_bool, &refuse_mppe_stateful,
+-      "allow MPPE stateful mode", OPT_PRIO },
+-    { "nomppe-stateful", o_bool, &refuse_mppe_stateful,
+-      "disallow MPPE stateful mode", OPT_PRIO | 1 },
++    { "mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "request MPPC compression", 1, &ccp_allowoptions[0].mppc },
++    { "+mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "request MPPC compression", 1, &ccp_allowoptions[0].mppc, OPT_ALIAS },
++    { "nomppc", o_bool, &ccp_wantoptions[0].mppc,
++      "don't allow MPPC compression", OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].mppc },
++    { "-mppc", o_bool, &ccp_wantoptions[0].mppc,
++      "don't allow MPPC compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
++      &ccp_allowoptions[0].mppc },
++    { "mppe", o_special, (void *)setmppe,
++      "request MPPE encryption" },
++    { "+mppe", o_special, (void *)setmppe,
++      "request MPPE encryption" },
++    { "nomppe", o_special_noarg, (void *)setnomppe,
++      "don't allow MPPE encryption" },
++    { "-mppe", o_special_noarg, (void *)setnomppe,
++      "don't allow MPPE encryption" },
+ #endif /* MPPE */
+ 
+     { NULL }
+@@ -241,7 +221,7 @@
+  */
+ #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
+ 				 || (opt).predictor_1 || (opt).predictor_2 \
+-				 || (opt).mppe)
++				 || (opt).lzs || (opt).mppc || (opt).mppe)
+ 
+ /*
+  * Local state (mainly for handling reset-reqs and reset-acks).
+@@ -344,6 +324,100 @@
+     return 1;
+ }
+ 
++#ifdef MPPE
++/*
++ * Functions called from config options
++ */
++/* 
++   MPPE suboptions:
++	required - require MPPE; disconnect if peer doesn't support it
++	stateless - use stateless mode
++	no40 - disable 40 bit keys
++	no56 - disable 56 bit keys
++	no128 - disable 128 bit keys
++*/
++int setmppe(char **argv)
++{
++    int i;
++    char *str, cmdbuf[16];
++
++    ccp_allowoptions[0].mppe = 1;
++    ccp_allowoptions[0].mppe_40 = 1;
++    ccp_allowoptions[0].mppe_56 = 1;
++    ccp_allowoptions[0].mppe_128 = 1;
++    ccp_allowoptions[0].mppe_stateless = 0;
++    ccp_wantoptions[0].mppe = 0;
++
++    str = *argv;
++
++    while (1) {
++	i = 0;
++	memset(cmdbuf, '\0', 16);
++	while ((i < 16) && (*str != ',') && (*str != '\0'))
++	    cmdbuf[i++] = *str++;
++	cmdbuf[i] = '\0';
++	if (!strncasecmp(cmdbuf, "no40", strlen("no40"))) {
++	    ccp_allowoptions[0].mppe_40 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "no56", strlen("no56"))) {
++	    ccp_allowoptions[0].mppe_56 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "no128", strlen("no128"))) {
++	    ccp_allowoptions[0].mppe_128 = 0;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "stateless", strlen("stateless"))) {
++	    ccp_allowoptions[0].mppe_stateless = 1;
++	    goto next_param;
++	} else if (!strncasecmp(cmdbuf, "required", strlen("required"))) {
++	    ccp_wantoptions[0].mppe = 1;
++	    goto next_param;
++	} else {
++	    option_error("invalid parameter '%s' for mppe option", cmdbuf);
++	    return 0;
++	}
++
++    next_param:
++	if (*str == ',') {
++	    str++;
++	    continue;
++	}
++	if (*str == '\0') {
++	    if (!(ccp_allowoptions[0].mppe_40 || ccp_allowoptions[0].mppe_56 ||
++		  ccp_allowoptions[0].mppe_128)) {
++		if (ccp_wantoptions[0].mppe == 1) {
++		    option_error("You require MPPE but you have switched off "
++				 "all encryption key lengths.");
++		    return 0;
++		}
++		ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
++		ccp_wantoptions[0].mppe_stateless =
++		    ccp_allowoptions[0].mppe_stateless = 0;
++	    } else {
++		ccp_allowoptions[0].mppe = 1;
++		ccp_wantoptions[0].mppe_stateless =
++		    ccp_allowoptions[0].mppe_stateless;
++		if (ccp_wantoptions[0].mppe == 1) {
++		    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40;
++		    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56;
++		    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128;
++		}
++	    }
++	    return 1;
++	}
++    }
++}
++
++int setnomppe(void)
++{
++    ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
++    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40 = 0;
++    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56 = 0;
++    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128 = 0;
++    ccp_wantoptions[0].mppe_stateless = ccp_allowoptions[0].mppe_stateless = 0;
++    return 1;
++}
++#endif /* MPPE */
++
+ /*
+  * ccp_init - initialize CCP.
+  */
+@@ -378,6 +452,30 @@
+     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+ 
+     ccp_allowoptions[0].predictor_1 = 1;
++
++    ccp_wantoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
++    ccp_wantoptions[0].lzs_mode = LZS_MODE_SEQ;
++    ccp_wantoptions[0].lzs_hists = 1;
++    ccp_allowoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
++    ccp_allowoptions[0].lzs_mode = LZS_MODE_SEQ;
++    ccp_allowoptions[0].lzs_hists = 1;
++
++#ifdef MPPE
++    /* by default allow and request MPPC... */
++    ccp_wantoptions[0].mppc = ccp_allowoptions[0].mppc = 1;
++
++    /* ... and allow but don't request MPPE */
++    ccp_allowoptions[0].mppe = 1;
++    ccp_allowoptions[0].mppe_40 = 1;
++    ccp_allowoptions[0].mppe_56 = 1;
++    ccp_allowoptions[0].mppe_128 = 1;
++    ccp_allowoptions[0].mppe_stateless = 1;
++    ccp_wantoptions[0].mppe = 0;
++    ccp_wantoptions[0].mppe_40 = 0;
++    ccp_wantoptions[0].mppe_56 = 0;
++    ccp_wantoptions[0].mppe_128 = 0;
++    ccp_wantoptions[0].mppe_stateless = 0;
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -455,11 +553,11 @@
+     if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) {
+ 	notice("Compression disabled by peer.");
+ #ifdef MPPE
+-	if (ccp_gotoptions[unit].mppe) {
++	if (ccp_wantoptions[unit].mppe) {
+ 	    error("MPPE disabled, closing LCP");
+ 	    lcp_close(unit, "MPPE disabled by peer");
+ 	}
+-#endif
++#endif /* MPPE */
+     }
+ 
+     /*
+@@ -487,6 +585,15 @@
+ 	    break;
+ 	/* send a reset-ack, which the transmitter will see and
+ 	   reset its compression state. */
++
++	/* In case of MPPE/MPPC or LZS we shouldn't send CCP_RESETACK,
++	   but we do it in order to reset compressor; CCP_RESETACK is
++	   then silently discarded. See functions ppp_send_frame and
++	   ppp_ccp_peek in ppp_generic.c (Linux only !!!). All the
++	   confusion is caused by the fact that CCP code is splited
++	   into two parts - one part is handled by pppd, the other one
++	   is handled by kernel. */
++
+ 	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+ 	break;
+ 
+@@ -515,12 +622,11 @@
+     fsm_lowerdown(&ccp_fsm[unit]);
+ 
+ #ifdef MPPE
+-    if (ccp_gotoptions[unit].mppe) {
++    if (ccp_wantoptions[unit].mppe) {
+ 	error("MPPE required but peer negotiation failed");
+ 	lcp_close(unit, "MPPE required but peer negotiation failed");
+     }
+-#endif
+-
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -537,7 +643,7 @@
+     all_rejected[f->unit] = 0;
+ 
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc) {
+ 	ccp_options *ao = &ccp_allowoptions[f->unit];
+ 	int auth_mschap_bits = auth_done[f->unit];
+ 	int numbits;
+@@ -551,80 +657,109 @@
+ 	 * NB: If MPPE is required, all other compression opts are invalid.
+ 	 *     So, we return right away if we can't do it.
+ 	 */
++	if (ccp_wantoptions[f->unit].mppe) {
++	    /* Leave only the mschap auth bits set */
++	    auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
++				 CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
++	    /* Count the mschap auths */
++	    auth_mschap_bits >>= CHAP_MS_SHIFT;
++	    numbits = 0;
++	    do {
++		numbits += auth_mschap_bits & 1;
++		auth_mschap_bits >>= 1;
++	    } while (auth_mschap_bits);
++	    if (numbits > 1) {
++		error("MPPE required, but auth done in both directions.");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
++	    }
++	    if (!numbits) {
++		error("MPPE required, but MS-CHAP[v2] auth not performed.");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
++	    }
+ 
+-	/* Leave only the mschap auth bits set */
+-	auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
+-			     CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
+-	/* Count the mschap auths */
+-	auth_mschap_bits >>= CHAP_MS_SHIFT;
+-	numbits = 0;
+-	do {
+-	    numbits += auth_mschap_bits & 1;
+-	    auth_mschap_bits >>= 1;
+-	} while (auth_mschap_bits);
+-	if (numbits > 1) {
+-	    error("MPPE required, but auth done in both directions.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-	if (!numbits) {
+-	    error("MPPE required, but MS-CHAP[v2] auth not performed.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-
+-	/* A plugin (eg radius) may not have obtained key material. */
+-	if (!mppe_keys_set) {
+-	    error("MPPE required, but keys are not available.  "
+-		  "Possible plugin problem?");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
+-	}
+-
+-	/* LM auth not supported for MPPE */
+-	if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
+-	    /* This might be noise */
+-	    if (go->mppe & MPPE_OPT_40) {
+-		notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
+-		go->mppe &= ~MPPE_OPT_40;
+-		ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40;
++	    /* A plugin (eg radius) may not have obtained key material. */
++	    if (!mppe_keys_set) {
++		error("MPPE required, but keys are not available.  "
++		      "Possible plugin problem?");
++		lcp_close(f->unit, "MPPE required but not available");
++		return;
+ 	    }
+ 	}
+ 
+-	/* Last check: can we actually negotiate something? */
+-	if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
+-	    /* Could be misconfig, could be 40-bit disabled above. */
+-	    error("MPPE required, but both 40-bit and 128-bit disabled.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	    return;
++	/*
++	 * Check whether the kernel knows about the various
++	 * compression methods we might request. Key material
++	 * unimportant here.
++	 */
++	if (go->mppc) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = 0;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_MPPC;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 0) <= 0)
++		go->mppc = 0;
++	}
++	if (go->mppe_40) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_40BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_40 = 0;
++	}
++	if (go->mppe_56) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_56BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_56 = 0;
++	}
++	if (go->mppe_128) {
++	    opt_buf[0] = CI_MPPE;
++	    opt_buf[1] = CILEN_MPPE;
++	    opt_buf[2] = MPPE_STATELESS;
++	    opt_buf[3] = 0;
++	    opt_buf[4] = 0;
++	    opt_buf[5] = MPPE_128BIT;
++	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
++		go->mppe_128 = 0;
++	}
++	if (!go->mppe_40 && !go->mppe_56 && !go->mppe_128) {
++	    if (ccp_wantoptions[f->unit].mppe) {
++		error("MPPE required, but kernel has no support.");
++		lcp_close(f->unit, "MPPE required but not available");
++	    }
++	    go->mppe = go->mppe_stateless = 0;
++	} else {
++	    /* MPPE is not compatible with other compression types */
++	    if (ccp_wantoptions[f->unit].mppe) {
++		ao->bsd_compress = go->bsd_compress = 0;
++		ao->predictor_1  = go->predictor_1  = 0;
++		ao->predictor_2  = go->predictor_2  = 0;
++		ao->deflate	 = go->deflate	    = 0;
++		ao->lzs		 = go->lzs	    = 0;
++	    }
+ 	}
+-
+-	/* sync options */
+-	ao->mppe = go->mppe;
+-	/* MPPE is not compatible with other compression types */
+-	ao->bsd_compress = go->bsd_compress = 0;
+-	ao->predictor_1  = go->predictor_1  = 0;
+-	ao->predictor_2  = go->predictor_2  = 0;
+-	ao->deflate      = go->deflate      = 0;
+     }
+ #endif /* MPPE */
+-
+-    /*
+-     * Check whether the kernel knows about the various
+-     * compression methods we might request.
+-     */
+-#ifdef MPPE
+-    if (go->mppe) {
+-	opt_buf[0] = CI_MPPE;
+-	opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+-	/* Key material unimportant here. */
+-	if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) {
+-	    error("MPPE required, but kernel has no support.");
+-	    lcp_close(f->unit, "MPPE required but not available");
+-	}
++    if (go->lzs) {
++	opt_buf[0] = CI_LZS;
++	opt_buf[1] = CILEN_LZS;
++	opt_buf[2] = go->lzs_hists >> 8;
++	opt_buf[3] = go->lzs_hists & 0xff;
++	opt_buf[4] = LZS_MODE_SEQ;
++	if (ccp_test(f->unit, opt_buf, CILEN_LZS, 0) <= 0)
++	    go->lzs = 0;
+     }
+-#endif
+     if (go->bsd_compress) {
+ 	opt_buf[0] = CI_BSD_COMPRESS;
+ 	opt_buf[1] = CILEN_BSD_COMPRESS;
+@@ -679,7 +814,8 @@
+ 	+ (go->deflate? CILEN_DEFLATE: 0)
+ 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
+ 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0)
+-	+ (go->mppe? CILEN_MPPE: 0);
++	+ (go->lzs? CILEN_LZS: 0)
++	+ ((go->mppe || go->mppc)? CILEN_MPPE: 0);
+ }
+ 
+ /*
+@@ -693,6 +829,8 @@
+ {
+     int res;
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     u_char *p0 = p;
+ 
+     /*
+@@ -701,22 +839,43 @@
+      * in case it gets Acked.
+      */
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
+ 	u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+ 
+-	p[0] = opt_buf[0] = CI_MPPE;
+-	p[1] = opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &p[2]);
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
++	p[0] = CI_MPPE;
++	p[1] = CILEN_MPPE;
++	p[2] = (go->mppe_stateless ? MPPE_STATELESS : 0);
++	p[3] = 0;
++	p[4] = 0;
++	p[5] = (go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_56 ? MPPE_56BIT : 0) |
++	    (go->mppe_128 ? MPPE_128BIT : 0) | (go->mppc ? MPPE_MPPC : 0);
++
++	BCOPY(p, opt_buf, CILEN_MPPE);
+ 	BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
+ 	res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0);
+-	if (res > 0)
++	if (res > 0) {
+ 	    p += CILEN_MPPE;
+-	else
++	} else {
+ 	    /* This shouldn't happen, we've already tested it! */
+-	    lcp_close(f->unit, "MPPE required but not available in kernel");
++	    go->mppe = go->mppe_40 = go->mppe_56 = go->mppe_128 =
++		go->mppe_stateless = go->mppc = 0;
++	    if (ccp_wantoptions[f->unit].mppe)
++		lcp_close(f->unit, "MPPE required but not available in kernel");
++	}
++    }
++#endif /* MPPE */
++    if (go->lzs) {
++	p[0] = CI_LZS;
++	p[1] = CILEN_LZS;
++	p[2] = go->lzs_hists >> 8;
++	p[3] = go->lzs_hists & 0xff;
++	p[4] = LZS_MODE_SEQ;
++	res = ccp_test(f->unit, p, CILEN_LZS, 0);
++	if (res > 0) {
++	    p += CILEN_LZS;
++	} else
++	    go->lzs = 0;
+     }
+-#endif
+     if (go->deflate) {
+ 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+ 	p[1] = CILEN_DEFLATE;
+@@ -802,7 +961,7 @@
+ 
+ /*
+  * ccp_ackci - process a received configure-ack, and return
+- * 1 iff the packet was OK.
++ * 1 if the packet was OK.
+  */
+ static int
+ ccp_ackci(f, p, len)
+@@ -811,24 +970,44 @@
+     int len;
+ {
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     u_char *p0 = p;
+ 
+ #ifdef MPPE
+-    if (go->mppe) {
+-	u_char opt_buf[CILEN_MPPE];
+-
+-	opt_buf[0] = CI_MPPE;
+-	opt_buf[1] = CILEN_MPPE;
+-	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
+-	if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE))
++    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
++	if (len < CILEN_MPPE
++	    || p[1] != CILEN_MPPE || p[0] != CI_MPPE
++	    || p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0)
++	    || p[3] != 0
++	    || p[4] != 0
++	    || (p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
++			 (go->mppc ? MPPE_MPPC : 0))
++		&& p[5] != ((go->mppe_56 ? MPPE_56BIT : 0) |
++			    (go->mppc ? MPPE_MPPC : 0))
++		&& p[5] != ((go->mppe_128 ? MPPE_128BIT : 0) |
++			    (go->mppc ? MPPE_MPPC : 0))))
+ 	    return 0;
++	if (go->mppe_40 || go->mppe_56 || go->mppe_128)
++	    go->mppe = 1;
+ 	p += CILEN_MPPE;
+ 	len -= CILEN_MPPE;
++	/* Cope with first/fast ack */
++	if (p == p0 && len == 0)
++	    return 1;
++    }
++#endif /* MPPE */
++    if (go->lzs) {
++	if (len < CILEN_LZS || p[0] != CI_LZS || p[1] != CILEN_LZS
++	    || p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff)
++	    || p[4] != LZS_MODE_SEQ)
++	    return 0;
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
+ 	/* XXX Cope with first/fast ack */
+-	if (len == 0)
++	if (p == p0 && len == 0)
+ 	    return 1;
+     }
+-#endif
+     if (go->deflate) {
+ 	if (len < CILEN_DEFLATE
+ 	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+@@ -891,7 +1070,7 @@
+ 
+ /*
+  * ccp_nakci - process received configure-nak.
+- * Returns 1 iff the nak was OK.
++ * Returns 1 if the nak was OK.
+  */
+ static int
+ ccp_nakci(f, p, len, treat_as_reject)
+@@ -900,6 +1079,8 @@
+     int len;
+ {
+     ccp_options *go = &ccp_gotoptions[f->unit];
++    ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+     ccp_options no;		/* options we've seen already */
+     ccp_options try;		/* options to ask for next time */
+ 
+@@ -907,28 +1088,100 @@
+     try = *go;
+ 
+ #ifdef MPPE
+-    if (go->mppe && len >= CILEN_MPPE
+-	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+-	no.mppe = 1;
+-	/*
+-	 * Peer wants us to use a different strength or other setting.
+-	 * Fail if we aren't willing to use his suggestion.
+-	 */
+-	MPPE_CI_TO_OPTS(&p[2], try.mppe);
+-	if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) {
+-	    error("Refusing MPPE stateful mode offered by peer");
+-	    try.mppe = 0;
+-	} else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) {
+-	    /* Peer must have set options we didn't request (suggest) */
+-	    try.mppe = 0;
+-	}
++    if ((go->mppe || go->mppc || (!wo->mppe && ao->mppe)) &&
++	len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+ 
+-	if (!try.mppe) {
+-	    error("MPPE required but peer negotiation failed");
+-	    lcp_close(f->unit, "MPPE required but peer negotiation failed");
++	if (go->mppc) {
++	    no.mppc = 1;
++	    if (!(p[5] & MPPE_MPPC))
++		try.mppc = 0;
++	}
++
++	if (go->mppe)
++	    no.mppe = 1;
++	if (go->mppe_40)
++	    no.mppe_40 = 1;
++	if (go->mppe_56)
++	    no.mppe_56 = 1;
++	if (go->mppe_128)
++	    no.mppe_128 = 1;
++	if (go->mppe_stateless)
++	    no.mppe_stateless = 1;
++
++	if (ao->mppe_40) {
++	    if ((p[5] & MPPE_40BIT))
++		try.mppe_40 = 1;
++	    else
++		try.mppe_40 = (p[5] == 0) ? 1 : 0;
++	}
++	if (ao->mppe_56) {
++	    if ((p[5] & MPPE_56BIT))
++		try.mppe_56 = 1;
++	    else
++		try.mppe_56 = (p[5] == 0) ? 1 : 0;
++	}
++	if (ao->mppe_128) {
++	    if ((p[5] & MPPE_128BIT))
++		try.mppe_128 = 1;
++	    else
++		try.mppe_128 = (p[5] == 0) ? 1 : 0;
++	}
++
++	if (ao->mppe_stateless) {
++	    if ((p[2] & MPPE_STATELESS) || wo->mppe_stateless)
++		try.mppe_stateless = 1;
++	    else
++		try.mppe_stateless = 0;
++	}
++
++	if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128) {
++	    try.mppe = try.mppe_stateless = 0;
++	    if (wo->mppe) {
++		/* we require encryption, but peer doesn't support it
++		   so we close connection */
++		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		    wo->mppe_56 = wo->mppe_128 = 0;
++		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
++			  "key length");
++	    }
++        }
++	if (wo->mppe && (wo->mppe_40 != try.mppe_40) &&
++	    (wo->mppe_56 != try.mppe_56) && (wo->mppe_128 != try.mppe_128)) {
++	    /* cannot negotiate key length */
++	    wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		wo->mppe_56 = wo->mppe_128 = 0;
++	    lcp_close(f->unit, "Cannot negotiate MPPE key length");
+ 	}
++	if (try.mppe_40 && try.mppe_56 && try.mppe_128)
++	    try.mppe_40 = try.mppe_56 = 0;
++	else
++	    if (try.mppe_56 && try.mppe_128)
++		try.mppe_56 = 0;
++	    else
++		if (try.mppe_40 && try.mppe_128)
++		    try.mppe_40 = 0;
++		else
++		    if (try.mppe_40 && try.mppe_56)
++			try.mppe_40 = 0;
++
++	p += CILEN_MPPE;
++	len -= CILEN_MPPE;
+     }
+ #endif /* MPPE */
++
++    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
++	no.lzs = 1;
++	if (((p[2]<<8)|p[3]) > 1 || (p[4] != LZS_MODE_SEQ &&
++				     p[4] != LZS_MODE_EXT))
++	    try.lzs = 0;
++	else {
++	    try.lzs_mode = p[4];
++	    try.lzs_hists = (p[2] << 8) | p[3];
++	}
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
++    }
++
+     if (go->deflate && len >= CILEN_DEFLATE
+ 	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+ 	&& p[1] == CILEN_DEFLATE) {
+@@ -1001,14 +1254,50 @@
+ 	return -1;
+ 
+ #ifdef MPPE
+-    if (go->mppe && len >= CILEN_MPPE
++    if ((go->mppe || go->mppc) && len >= CILEN_MPPE
+ 	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
+-	error("MPPE required but peer refused");
+-	lcp_close(f->unit, "MPPE required but peer refused");
++	ccp_options *wo = &ccp_wantoptions[f->unit];
++	if (p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0) ||
++	    p[3] != 0 ||
++	    p[4] != 0 ||
++	    p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
++		     (go->mppe_56 ? MPPE_56BIT : 0) |
++		     (go->mppe_128 ? MPPE_128BIT : 0) |
++		     (go->mppc ? MPPE_MPPC : 0)))
++	    return 0;
++	if (go->mppc)
++	    try.mppc = 0;
++	if (go->mppe) {
++	    try.mppe = 0;
++	    if (go->mppe_40)
++		try.mppe_40 = 0;
++	    if (go->mppe_56)
++		try.mppe_56 = 0;
++	    if (go->mppe_128)
++		try.mppe_128 = 0;
++	    if (go->mppe_stateless)
++		try.mppe_stateless = 0;
++	    if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128)
++		try.mppe = try.mppe_stateless = 0;
++	    if (wo->mppe) { /* we want MPPE but cannot negotiate key length */
++		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
++		    wo->mppe_56 = wo->mppe_128 = 0;
++		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
++			  "key length");
++	    }
++	}
+ 	p += CILEN_MPPE;
+ 	len -= CILEN_MPPE;
+     }
+-#endif
++#endif /* MPPE */
++    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
++	if (p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff) 
++	    || p[4] != go->lzs_mode)
++	    return 0;
++	try.lzs = 0;
++	p += CILEN_LZS;
++	len -= CILEN_LZS;
++    }
+     if (go->deflate_correct && len >= CILEN_DEFLATE
+ 	&& p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
+ 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+@@ -1072,14 +1361,15 @@
+     int dont_nak;
+ {
+     int ret, newret, res;
+-    u_char *p0, *retp;
++    u_char *p0, *retp, p2, p5;
+     int len, clen, type, nb;
+     ccp_options *ho = &ccp_hisoptions[f->unit];
+     ccp_options *ao = &ccp_allowoptions[f->unit];
++    ccp_options *wo = &ccp_wantoptions[f->unit];
+ #ifdef MPPE
+-    bool rej_for_ci_mppe = 1;	/* Are we rejecting based on a bad/missing */
+-				/* CI_MPPE, or due to other options?       */
+-#endif
++    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
++/*     int mtu; */
++#endif /* MPPE */
+ 
+     ret = CONFACK;
+     retp = p0 = p;
+@@ -1102,103 +1392,305 @@
+ 	    switch (type) {
+ #ifdef MPPE
+ 	    case CI_MPPE:
+-		if (!ao->mppe || clen != CILEN_MPPE) {
++		if ((!ao->mppc && !ao->mppe) || clen != CILEN_MPPE) {
+ 		    newret = CONFREJ;
+ 		    break;
+ 		}
+-		MPPE_CI_TO_OPTS(&p[2], ho->mppe);
+ 
+-		/* Nak if anything unsupported or unknown are set. */
+-		if (ho->mppe & MPPE_OPT_UNSUPPORTED) {
+-		    newret = CONFNAK;
+-		    ho->mppe &= ~MPPE_OPT_UNSUPPORTED;
+-		}
+-		if (ho->mppe & MPPE_OPT_UNKNOWN) {
++		p2 = p[2];
++		p5 = p[5];
++		/* not sure what they want, tell 'em what we got */
++		if (((p[2] & ~MPPE_STATELESS) != 0 || p[3] != 0 || p[4] != 0 ||
++		     (p[5] & ~(MPPE_40BIT | MPPE_56BIT | MPPE_128BIT |
++			       MPPE_MPPC)) != 0 || p[5] == 0) ||
++		    (p[2] == 0 && p[3] == 0 && p[4] == 0 &&  p[5] == 0)) {
+ 		    newret = CONFNAK;
+-		    ho->mppe &= ~MPPE_OPT_UNKNOWN;
++		    p[2] = (wo->mppe_stateless ? MPPE_STATELESS : 0);
++		    p[3] = 0;
++		    p[4] = 0;
++		    p[5] = (wo->mppe_40 ? MPPE_40BIT : 0) |
++			(wo->mppe_56 ? MPPE_56BIT : 0) |
++			(wo->mppe_128 ? MPPE_128BIT : 0) |
++			(wo->mppc ? MPPE_MPPC : 0);
++		    break;
+ 		}
+ 
+-		/* Check state opt */
+-		if (ho->mppe & MPPE_OPT_STATEFUL) {
+-		    /*
+-		     * We can Nak and request stateless, but it's a
+-		     * lot easier to just assume the peer will request
+-		     * it if he can do it; stateful mode is bad over
+-		     * the Internet -- which is where we expect MPPE.
+-		     */
+-		   if (refuse_mppe_stateful) {
+-			error("Refusing MPPE stateful mode offered by peer");
++		if ((p[5] & MPPE_MPPC)) {
++		    if (ao->mppc) {
++			ho->mppc = 1;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			opt_buf[2] = opt_buf[3] = opt_buf[4] = 0;
++			opt_buf[5] = MPPE_MPPC;
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 1) <= 0) {
++			    ho->mppc = 0;
++			    p[5] &= ~MPPE_MPPC;
++			    newret = CONFNAK;
++			}
++		    } else {
+ 			newret = CONFREJ;
+-			break;
++			if (wo->mppe || ao->mppe) {
++			    p[5] &= ~MPPE_MPPC;
++			    newret = CONFNAK;
++			}
++		    }
++		}
++
++		if (ao->mppe)
++		    ho->mppe = 1;
++
++		if ((p[2] & MPPE_STATELESS)) {
++		    if (ao->mppe_stateless) {
++			if (wo->mppe_stateless)
++			    ho->mppe_stateless = 1;
++			else {
++			    newret = CONFNAK;
++			    if (!dont_nak)
++				p[2] &= ~MPPE_STATELESS;
++			}
++		    } else {
++			newret = CONFNAK;
++			if (!dont_nak)
++			    p[2] &= ~MPPE_STATELESS;
++		    }
++		} else {
++		    if (wo->mppe_stateless && !dont_nak) {
++			wo->mppe_stateless = 0;
++			newret = CONFNAK;
++			p[2] |= MPPE_STATELESS;
+ 		    }
+ 		}
+ 
+-		/* Find out which of {S,L} are set. */
+-		if ((ho->mppe & MPPE_OPT_128)
+-		     && (ho->mppe & MPPE_OPT_40)) {
+-		    /* Both are set, negotiate the strongest. */
++		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT|MPPE_128BIT)) {
+ 		    newret = CONFNAK;
+-		    if (ao->mppe & MPPE_OPT_128)
+-			ho->mppe &= ~MPPE_OPT_40;
+-		    else if (ao->mppe & MPPE_OPT_40)
+-			ho->mppe &= ~MPPE_OPT_128;
+-		    else {
+-			newret = CONFREJ;
+-			break;
++		    if (ao->mppe_128) {
++			ho->mppe_128 = 1;
++			p[5] &= ~(MPPE_40BIT|MPPE_56BIT);
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_128 = 0;
++			    p[5] |= (MPPE_40BIT|MPPE_56BIT);
++			    p[5] &= ~MPPE_128BIT;
++			    goto check_mppe_56_40;
++			}
++			goto check_mppe;
+ 		    }
+-		} else if (ho->mppe & MPPE_OPT_128) {
+-		    if (!(ao->mppe & MPPE_OPT_128)) {
+-			newret = CONFREJ;
+-			break;
++		    p[5] &= ~MPPE_128BIT;
++		    goto check_mppe_56_40;
++		}
++		if ((p[5] & ~MPPE_MPPC) == (MPPE_56BIT|MPPE_128BIT)) {
++		    newret = CONFNAK;
++		    if (ao->mppe_128) {
++			ho->mppe_128 = 1;
++			p[5] &= ~MPPE_56BIT;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_128 = 0;
++			    p[5] |= MPPE_56BIT;
++			    p[5] &= ~MPPE_128BIT;
++			    goto check_mppe_56;
++			}
++			goto check_mppe;
+ 		    }
+-		} else if (ho->mppe & MPPE_OPT_40) {
+-		    if (!(ao->mppe & MPPE_OPT_40)) {
+-			newret = CONFREJ;
+-			break;
++		    p[5] &= ~MPPE_128BIT;
++		    goto check_mppe_56;
++		}
++		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_128BIT)) {
++		    newret = CONFNAK;
++		    if (ao->mppe_128) {
++			ho->mppe_128 = 1;
++			p[5] &= ~MPPE_40BIT;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_128 = 0;
++			    p[5] |= MPPE_40BIT;
++			    p[5] &= ~MPPE_128BIT;
++			    goto check_mppe_40;
++			}
++			goto check_mppe;
++		    }
++		    p[5] &= ~MPPE_128BIT;
++		    goto check_mppe_40;
++		}
++		if ((p[5] & ~MPPE_MPPC) == MPPE_128BIT) {
++		    if (ao->mppe_128) {
++			ho->mppe_128 = 1;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_128 = 0;
++			    p[5] &= ~MPPE_128BIT;
++			    newret = CONFNAK;
++			}
++			goto check_mppe;
++		    }
++		    p[5] &= ~MPPE_128BIT;
++		    newret = CONFNAK;
++		    goto check_mppe;
++		}
++	    check_mppe_56_40:
++		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT)) {
++		    newret = CONFNAK;
++		    if (ao->mppe_56) {
++			ho->mppe_56 = 1;
++			p[5] &= ~MPPE_40BIT;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_56 = 0;
++			    p[5] |= MPPE_40BIT;
++			    p[5] &= ~MPPE_56BIT;
++			    newret = CONFNAK;
++			    goto check_mppe_40;
++			}
++			goto check_mppe;
++		    }
++		    p[5] &= ~MPPE_56BIT;
++		    goto check_mppe_40;
++		}
++	    check_mppe_56:
++		if ((p[5] & ~MPPE_MPPC) == MPPE_56BIT) {
++		    if (ao->mppe_56) {
++			ho->mppe_56 = 1;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_56 = 0;
++			    p[5] &= ~MPPE_56BIT;
++			    newret = CONFNAK;
++			}
++			goto check_mppe;
++		    }
++		    p[5] &= ~MPPE_56BIT;
++		    newret = CONFNAK;
++		    goto check_mppe;
++		}
++	    check_mppe_40:
++		if ((p[5] & ~MPPE_MPPC) == MPPE_40BIT) {
++		    if (ao->mppe_40) {
++			ho->mppe_40 = 1;
++			BCOPY(p, opt_buf, CILEN_MPPE);
++			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
++			      MPPE_MAX_KEY_LEN);
++			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
++				     MPPE_MAX_KEY_LEN, 1) <= 0) {
++			    ho->mppe_40 = 0;
++			    p[5] &= ~MPPE_40BIT;
++			    newret = CONFNAK;
++			}
++			goto check_mppe;
++		    }
++		    p[5] &= ~MPPE_40BIT;
++		}
++
++	    check_mppe:
++		if (!ho->mppe_40 && !ho->mppe_56 && !ho->mppe_128) {
++		    if (wo->mppe_40 || wo->mppe_56 || wo->mppe_128) {
++			newret = CONFNAK;
++			p[2] |= (wo->mppe_stateless ? MPPE_STATELESS : 0);
++			p[5] |= (wo->mppe_40 ? MPPE_40BIT : 0) |
++			    (wo->mppe_56 ? MPPE_56BIT : 0) |
++			    (wo->mppe_128 ? MPPE_128BIT : 0) |
++			    (wo->mppc ? MPPE_MPPC : 0);
++		    } else {
++			ho->mppe = ho->mppe_stateless = 0;
+ 		    }
+ 		} else {
+-		    /* Neither are set. */
++		    /* MPPE is not compatible with other compression types */
++		    if (wo->mppe) {
++			ao->bsd_compress = 0;
++			ao->predictor_1 = 0;
++			ao->predictor_2 = 0;
++			ao->deflate = 0;
++			ao->lzs = 0;
++		    }
++		}
++		if ((!ho->mppc || !ao->mppc) && !ho->mppe) {
++		    p[2] = p2;
++		    p[5] = p5;
+ 		    newret = CONFREJ;
+ 		    break;
+ 		}
+ 
+-		/* rebuild the opts */
+-		MPPE_OPTS_TO_CI(ho->mppe, &p[2]);
+-		if (newret == CONFACK) {
+-		    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
+-		    int mtu;
+-
+-		    BCOPY(p, opt_buf, CILEN_MPPE);
+-		    BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
+-			  MPPE_MAX_KEY_LEN);
+-		    if (ccp_test(f->unit, opt_buf,
+-				 CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) {
+-			/* This shouldn't happen, we've already tested it! */
+-			error("MPPE required, but kernel has no support.");
+-			lcp_close(f->unit, "MPPE required but not available");
+-			newret = CONFREJ;
+-			break;
+-		    }
+-		    /*
+-		     * We need to decrease the interface MTU by MPPE_PAD
+-		     * because MPPE frames **grow**.  The kernel [must]
+-		     * allocate MPPE_PAD extra bytes in xmit buffers.
+-		     */
+-		    mtu = netif_get_mtu(f->unit);
+-		    if (mtu)
+-			netif_set_mtu(f->unit, mtu - MPPE_PAD);
+-		    else
+-			newret = CONFREJ;
+-		}
++		/*
++		 * I have commented the code below because according to RFC1547
++		 * MTU is only information for higher level protocols about
++		 * "the maximum allowable length for a packet (q.v.) transmitted
++		 * over a point-to-point link without incurring network layer
++		 * fragmentation." Of course a PPP implementation should be able
++		 * to handle overhead added by MPPE - in our case apropriate code
++		 * is located in drivers/net/ppp_generic.c in the kernel sources.
++		 *
++		 * According to RFC1661:
++		 * - when negotiated MRU is less than 1500 octets, a PPP
++		 *   implementation must still be able to receive at least 1500
++		 *   octets,
++		 * - when PFC is negotiated, a PPP implementation is still
++		 *   required to receive frames with uncompressed protocol field.
++		 *
++		 * So why not to handle MPPE overhead without changing MTU value?
++		 * I am sure that RFC3078, unfortunately silently, assumes that.
++		 */
+ 
+ 		/*
+-		 * We have accepted MPPE or are willing to negotiate
+-		 * MPPE parameters.  A CONFREJ is due to subsequent
+-		 * (non-MPPE) processing.
++		 * We need to decrease the interface MTU by MPPE_PAD
++		 * because MPPE frames **grow**.  The kernel [must]
++		 * allocate MPPE_PAD extra bytes in xmit buffers.
+ 		 */
+-		rej_for_ci_mppe = 0;
++/*
++		mtu = netif_get_mtu(f->unit);
++		if (mtu) {
++		    netif_set_mtu(f->unit, mtu - MPPE_PAD);
++		} else {
++		    newret = CONFREJ;
++		    if (ccp_wantoptions[f->unit].mppe) {
++			error("Cannot adjust MTU needed by MPPE.");
++			lcp_close(f->unit, "Cannot adjust MTU needed by MPPE.");
++		    }
++		}
++*/
+ 		break;
+ #endif /* MPPE */
++
++	    case CI_LZS:
++		if (!ao->lzs || clen != CILEN_LZS) {
++		    newret = CONFREJ;
++		    break;
++		}
++
++		ho->lzs = 1;
++		ho->lzs_hists = (p[2] << 8) | p[3];
++		ho->lzs_mode = p[4];
++		if ((ho->lzs_hists != ao->lzs_hists) ||
++		    (ho->lzs_mode != ao->lzs_mode)) {
++		    newret = CONFNAK;
++		    if (!dont_nak) {
++			p[2] = ao->lzs_hists >> 8;
++			p[3] = ao->lzs_hists & 0xff;
++			p[4] = ao->lzs_mode;
++		    } else
++			break;
++		}
++
++		if (p == p0 && ccp_test(f->unit, p, CILEN_LZS, 1) <= 0) {
++		    newret = CONFREJ;
++		}
++		break;
++
+ 	    case CI_DEFLATE:
+ 	    case CI_DEFLATE_DRAFT:
+ 		if (!ao->deflate || clen != CILEN_DEFLATE
+@@ -1340,12 +1832,6 @@
+ 	else
+ 	    *lenp = retp - p0;
+     }
+-#ifdef MPPE
+-    if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) {
+-	error("MPPE required but peer negotiation failed");
+-	lcp_close(f->unit, "MPPE required but peer negotiation failed");
+-    }
+-#endif
+     return ret;
+ }
+ 
+@@ -1367,24 +1853,35 @@
+ 	char *p = result;
+ 	char *q = result + sizeof(result); /* 1 past result */
+ 
+-	slprintf(p, q - p, "MPPE ");
+-	p += 5;
+-	if (opt->mppe & MPPE_OPT_128) {
+-	    slprintf(p, q - p, "128-bit ");
+-	    p += 8;
+-	}
+-	if (opt->mppe & MPPE_OPT_40) {
+-	    slprintf(p, q - p, "40-bit ");
+-	    p += 7;
+-	}
+-	if (opt->mppe & MPPE_OPT_STATEFUL)
+-	    slprintf(p, q - p, "stateful");
+-	else
+-	    slprintf(p, q - p, "stateless");
+-
++	if (opt->mppe) {
++	    if (opt->mppc) {
++		slprintf(p, q - p, "MPPC/MPPE ");
++		p += 10;
++	    } else {
++		slprintf(p, q - p, "MPPE ");
++		p += 5;
++	    }
++	    if (opt->mppe_128) {
++		slprintf(p, q - p, "128-bit ");
++		p += 8;
++	    } else if (opt->mppe_56) {
++		slprintf(p, q - p, "56-bit ");
++		p += 7;
++	    } else if (opt->mppe_40) {
++		slprintf(p, q - p, "40-bit ");
++		p += 7;
++	    }
++	    if (opt->mppe_stateless)
++		slprintf(p, q - p, "stateless");
++	    else
++		slprintf(p, q - p, "stateful");
++	} else if (opt->mppc)
++	    slprintf(p, q - p, "MPPC");
+ 	break;
+     }
+-#endif
++#endif /* MPPE */
++    case CI_LZS:
++	return "Stac LZS";
+     case CI_DEFLATE:
+     case CI_DEFLATE_DRAFT:
+ 	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+@@ -1440,12 +1937,12 @@
+     } else if (ANY_COMPRESS(*ho))
+ 	notice("%s transmit compression enabled", method_name(ho, NULL));
+ #ifdef MPPE
+-    if (go->mppe) {
++    if (go->mppe || go->mppc) {
+ 	BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN);
+ 	BZERO(mppe_send_key, MPPE_MAX_KEY_LEN);
+ 	continue_networks(f->unit);		/* Bring up IP et al */
+     }
+-#endif
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -1468,7 +1965,7 @@
+ 	    lcp_close(f->unit, "MPPE disabled");
+ 	}
+     }
+-#endif
++#endif /* MPPE */
+ }
+ 
+ /*
+@@ -1528,24 +2025,28 @@
+ #ifdef MPPE
+ 	    case CI_MPPE:
+ 		if (optlen >= CILEN_MPPE) {
+-		    u_char mppe_opts;
+-
+-		    MPPE_CI_TO_OPTS(&p[2], mppe_opts);
+-		    printer(arg, "mppe %s %s %s %s %s %s%s",
+-			    (p[2] & MPPE_H_BIT)? "+H": "-H",
+-			    (p[5] & MPPE_M_BIT)? "+M": "-M",
+-			    (p[5] & MPPE_S_BIT)? "+S": "-S",
+-			    (p[5] & MPPE_L_BIT)? "+L": "-L",
++		    printer(arg, "mppe %s %s %s %s %s %s",
++			    (p[2] & MPPE_STATELESS)? "+H": "-H",
++			    (p[5] & MPPE_56BIT)? "+M": "-M",
++			    (p[5] & MPPE_128BIT)? "+S": "-S",
++			    (p[5] & MPPE_40BIT)? "+L": "-L",
+ 			    (p[5] & MPPE_D_BIT)? "+D": "-D",
+-			    (p[5] & MPPE_C_BIT)? "+C": "-C",
+-			    (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": "");
+-		    if (mppe_opts & MPPE_OPT_UNKNOWN)
++			    (p[5] & MPPE_MPPC)? "+C": "-C");
++		    if ((p[5] & ~(MPPE_56BIT | MPPE_128BIT | MPPE_40BIT |
++				  MPPE_D_BIT | MPPE_MPPC)) ||
++			(p[2] & ~MPPE_STATELESS))
+ 			printer(arg, " (%.2x %.2x %.2x %.2x)",
+ 				p[2], p[3], p[4], p[5]);
+ 		    p += CILEN_MPPE;
+ 		}
+ 		break;
+-#endif
++#endif /* MPPE */
++	    case CI_LZS:
++		if (optlen >= CILEN_LZS) {
++		    printer(arg, "lzs %.2x %.2x %.2x", p[2], p[3], p[4]);
++		    p += CILEN_LZS;
++		}
++		break;
+ 	    case CI_DEFLATE:
+ 	    case CI_DEFLATE_DRAFT:
+ 		if (optlen >= CILEN_DEFLATE) {
+@@ -1631,6 +2132,7 @@
+ 	    error("Lost compression sync: disabling compression");
+ 	    ccp_close(unit, "Lost compression sync");
+ #ifdef MPPE
++	    /* My module dosn't need this. J.D., 2003-07-06 */
+ 	    /*
+ 	     * If we were doing MPPE, we must also take the link down.
+ 	     */
+@@ -1638,9 +2140,18 @@
+ 		error("Too many MPPE errors, closing LCP");
+ 		lcp_close(unit, "Too many MPPE errors");
+ 	    }
+-#endif
++#endif /* MPPE */
+ 	} else {
+ 	    /*
++	     * When LZS or MPPE/MPPC is negotiated we just send CCP_RESETREQ
++	     * and don't wait for CCP_RESETACK
++	     */
++	    if ((ccp_gotoptions[f->unit].method == CI_LZS) ||
++		(ccp_gotoptions[f->unit].method == CI_MPPE)) {
++		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
++		return;
++	    }
++	    /*
+ 	     * 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.
+@@ -1671,4 +2182,3 @@
+     } else
+ 	ccp_localstate[f->unit] &= ~RACK_PENDING;
+ }
+-
+diff -ruN ppp-2.4.3.orig/pppd/ccp.h ppp-2.4.3/pppd/ccp.h
+--- ppp-2.4.3.orig/pppd/ccp.h	2004-11-04 11:02:26.000000000 +0100
++++ ppp-2.4.3/pppd/ccp.h	2004-11-21 13:54:09.000000000 +0100
+@@ -37,9 +37,17 @@
+     bool predictor_2;		/* do Predictor-2? */
+     bool deflate_correct;	/* use correct code for deflate? */
+     bool deflate_draft;		/* use draft RFC code for deflate? */
++    bool lzs;			/* do Stac LZS? */
++    bool mppc;			/* do MPPC? */
+     bool mppe;			/* do MPPE? */
++    bool mppe_40;		/* allow 40 bit encryption? */
++    bool mppe_56;		/* allow 56 bit encryption? */
++    bool mppe_128;		/* allow 128 bit encryption? */
++    bool mppe_stateless;	/* allow stateless encryption */
+     u_short bsd_bits;		/* # bits/code for BSD Compress */
+     u_short deflate_size;	/* lg(window size) for Deflate */
++    u_short lzs_mode;		/* LZS check mode */
++    u_short lzs_hists;		/* number of LZS histories */
+     short method;		/* code for chosen compression method */
+ } ccp_options;
+ 
+diff -ruN ppp-2.4.3.orig/pppd/chap_ms.c ppp-2.4.3/pppd/chap_ms.c
+--- ppp-2.4.3.orig/pppd/chap_ms.c	2004-11-12 10:57:43.000000000 +0100
++++ ppp-2.4.3/pppd/chap_ms.c	2004-11-21 13:54:09.000000000 +0100
+@@ -895,13 +895,17 @@
+     /*
+      * Disable undesirable encryption types.  Note that we don't ENABLE
+      * any encryption types, to avoid overriding manual configuration.
++     *
++     * It seems that 56 bit keys are unsupported in MS-RADIUS (see RFC 2548)
+      */
+     switch(types) {
+ 	case MPPE_ENC_TYPES_RC4_40:
+-	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
++	    ccp_wantoptions[0].mppe_128 = 0;	/* disable 128-bit */
++	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
+ 	    break;
+ 	case MPPE_ENC_TYPES_RC4_128:
+-	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
++	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
++	    ccp_wantoptions[0].mppe_40 = 0;	/* disable 40-bit */
+ 	    break;
+ 	default:
+ 	    break;
+diff -ruN ppp-2.4.3.orig/pppd/pppd.8 ppp-2.4.3/pppd/pppd.8
+--- ppp-2.4.3.orig/pppd/pppd.8	2004-11-13 13:22:49.000000000 +0100
++++ ppp-2.4.3/pppd/pppd.8	2004-11-21 14:24:47.000000000 +0100
+@@ -622,9 +622,29 @@
+ Enables the use of PPP multilink; this is an alias for the `multilink'
+ option.  This option is currently only available under Linux.
+ .TP
+-.B mppe\-stateful
+-Allow MPPE to use stateful mode.  Stateless mode is still attempted first.
+-The default is to disallow stateful mode.  
++.B mppc
++Enables MPPC (Microsoft Point to Point Compression).  This is the default.
++.TP
++.B mppe \fIsubopt1[,subopt2[,subopt3[..]]]
++Modify MPPE (Microsoft Point to Point Encryption) parameters. In order
++for MPPE to successfully come up, you must have authenticated with either
++MS-CHAP or MS-CHAPv2. By default MPPE is optional, it means that pppd will
++not propose MPPE to the peer, but will negotiate MPPE if peer wants that.
++You can change this using \fIrequired\fR suboption.
++This option is presently only supported under Linux, and only if your
++kernel has been configured to include MPPE support.
++.IP
++MPPE suboptions:
++.br
++\fIrequired\fR - require MPPE; disconnect if peer doesn't support it,
++.br
++\fIstateless\fR - try to negotiate stateless mode; default is stateful,
++.br
++\fIno40\fR - disable 40 bit keys,
++.br
++\fIno56\fR - disable 56 bit keys,
++.br
++\fIno128\fR - disable 128 bit keys
+ .TP
+ .B mpshortseq
+ Enables the use of short (12-bit) sequence numbers in multilink
+@@ -757,17 +777,11 @@
+ Disables the use of PPP multilink.  This option is currently only
+ available under Linux.
+ .TP
+-.B nomppe
+-Disables MPPE (Microsoft Point to Point Encryption).  This is the default.
+-.TP
+-.B nomppe\-40
+-Disable 40-bit encryption with MPPE.
++.B nomppc
++Disables MPPC (Microsoft Point to Point Compression).
+ .TP
+-.B nomppe\-128
+-Disable 128-bit encryption with MPPE.
+-.TP
+-.B nomppe\-stateful
+-Disable MPPE stateful mode.  This is the default.
++.B nomppe
++Disables MPPE (Microsoft Point to Point Encryption).
+ .TP
+ .B nompshortseq
+ Disables the use of short (12-bit) sequence numbers in the PPP
+@@ -948,19 +962,6 @@
+ Require the peer to authenticate itself using CHAP [Challenge
+ Handshake Authentication Protocol] authentication.
+ .TP
+-.B require\-mppe
+-Require the use of MPPE (Microsoft Point to Point Encryption).  This
+-option disables all other compression types.  This option enables
+-both 40-bit and 128-bit encryption.  In order for MPPE to successfully
+-come up, you must have authenticated with either MS\-CHAP or MS\-CHAPv2.
+-This option is presently only supported under Linux, and only if your
+-kernel has been configured to include MPPE support.
+-.TP
+-.B require\-mppe\-40
+-Require the use of MPPE, with 40-bit encryption.
+-.TP
+-.B require\-mppe\-128
+-Require the use of MPPE, with 128-bit encryption.
+ .TP
+ .B require\-mschap
+ Require the peer to authenticate itself using MS\-CHAP [Microsoft Challenge
diff --git a/openwrt/package/ppp/patches/202-no_atm.patch b/openwrt/package/ppp/patches/202-no_atm.patch
new file mode 100644
index 0000000000..a737cfa23a
--- /dev/null
+++ b/openwrt/package/ppp/patches/202-no_atm.patch
@@ -0,0 +1,12 @@
+diff -ruN ppp-2.4.3-orig/pppd/plugins/Makefile.linux ppp-2.4.3-3/pppd/plugins/Makefile.linux
+--- ppp-2.4.3-orig/pppd/plugins/Makefile.linux	2004-11-14 08:57:35.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/Makefile.linux	2004-12-05 17:03:59.000000000 +0100
+@@ -9,7 +9,7 @@
+ MANDIR = $(DESTDIR)/share/man/man8
+ LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
+ 
+-SUBDIRS := rp-pppoe pppoatm radius
++SUBDIRS := rp-pppoe radius
+ # Uncomment the next line to include the radius authentication plugin
+ # SUBDIRS += radius
+ PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
diff --git a/openwrt/package/ppp/patches/203-no_strip.patch b/openwrt/package/ppp/patches/203-no_strip.patch
new file mode 100644
index 0000000000..216973cf59
--- /dev/null
+++ b/openwrt/package/ppp/patches/203-no_strip.patch
@@ -0,0 +1,86 @@
+diff -ruN ppp-2.4.3-orig/chat/Makefile.linux ppp-2.4.3-3/chat/Makefile.linux
+--- ppp-2.4.3-orig/chat/Makefile.linux	2004-11-03 12:51:47.000000000 +0100
++++ ppp-2.4.3-3/chat/Makefile.linux	2004-12-05 17:42:43.000000000 +0100
+@@ -25,7 +25,7 @@
+ 
+ install: chat
+ 	mkdir -p $(BINDIR)
+-	$(INSTALL) -s -c chat $(BINDIR)
++	$(INSTALL) -c chat $(BINDIR)
+ 	$(INSTALL) -c -m 644 chat.8 $(MANDIR)
+ 
+ clean:
+diff -ruN ppp-2.4.3-orig/pppd/Makefile.linux ppp-2.4.3-3/pppd/Makefile.linux
+--- ppp-2.4.3-orig/pppd/Makefile.linux	2004-11-13 13:02:22.000000000 +0100
++++ ppp-2.4.3-3/pppd/Makefile.linux	2004-12-16 04:43:41.000000000 +0100
+@@ -99,7 +99,7 @@
+ CFLAGS	+= -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
+ LIBS	+= -lsrp -L/usr/local/ssl/lib -lcrypto
+ TARGETS	+= srp-entry
+-EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
++EXTRAINSTALL = $(INSTALL) -c -m 555 srp-entry $(BINDIR)/srp-entry
+ MANPAGES += srp-entry.8
+ EXTRACLEAN += srp-entry.o
+ NEEDDES=y
+@@ -202,7 +202,7 @@
+ install: pppd
+ 	mkdir -p $(BINDIR) $(MANDIR)
+ 	$(EXTRAINSTALL)
+-	$(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd
++	$(INSTALL) -c -m 555 pppd $(BINDIR)/pppd
+ 	if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \
+ 	  chmod o-rx,u+s $(BINDIR)/pppd; fi
+ 	$(INSTALL) -c -m 444 pppd.8 $(MANDIR)
+diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux
+--- ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux	2004-11-14 08:02:31.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux	2004-12-05 17:43:17.000000000 +0100
+@@ -36,9 +37,9 @@
+ 
+ install: all
+ 	$(INSTALL) -d -m 755 $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radius.so $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radattr.so $(LIBDIR)
+-	$(INSTALL) -s -c -m 755 radrealms.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radius.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radattr.so $(LIBDIR)
++	$(INSTALL) -c -m 755 radrealms.so $(LIBDIR)
+ 	$(INSTALL) -c -m 444 pppd-radius.8 $(MANDIR)
+ 	$(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
+ 
+diff -ruN ppp-2.4.3-orig/pppd/plugins/rp-pppoe/Makefile.linux ppp-2.4.3-3/pppd/plugins/rp-pppoe/Makefile.linux
+--- ppp-2.4.3-orig/pppd/plugins/rp-pppoe/Makefile.linux	2004-11-14 08:58:37.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/rp-pppoe/Makefile.linux	2004-12-05 17:43:23.000000000 +0100
+@@ -39,9 +39,9 @@
+ 
+ install: all
+ 	$(INSTALL) -d -m 755 $(LIBDIR)
+-	$(INSTALL) -s -c -m 4550 rp-pppoe.so $(LIBDIR)
++	$(INSTALL) -c -m 4550 rp-pppoe.so $(LIBDIR)
+ 	$(INSTALL) -d -m 755 $(BINDIR)
+-	$(INSTALL) -s -c -m 555 pppoe-discovery $(BINDIR)
++	$(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
+ 
+ clean:
+ 	rm -f *.o *.so
+diff -ruN ppp-2.4.3-orig/pppdump/Makefile.linux ppp-2.4.3-3/pppdump/Makefile.linux
+--- ppp-2.4.3-orig/pppdump/Makefile.linux	2004-10-31 02:36:52.000000000 +0200
++++ ppp-2.4.3-3/pppdump/Makefile.linux	2004-12-05 17:50:34.000000000 +0100
+@@ -17,5 +18,5 @@
+ 
+ install:
+ 	mkdir -p $(BINDIR) $(MANDIR)
+-	$(INSTALL) -s -c pppdump $(BINDIR)
++	$(INSTALL) -c pppdump $(BINDIR)
+ 	$(INSTALL) -c -m 444 pppdump.8 $(MANDIR)
+diff -ruN ppp-2.4.3-orig/pppstats/Makefile.linux ppp-2.4.3-3/pppstats/Makefile.linux
+--- ppp-2.4.3-orig/pppstats/Makefile.linux	2004-10-31 23:09:03.000000000 +0100
++++ ppp-2.4.3-3/pppstats/Makefile.linux	2004-12-05 17:43:38.000000000 +0100
+@@ -22,7 +22,7 @@
+ 
+ install: pppstats
+ 	-mkdir -p $(MANDIR)
+-	$(INSTALL) -s -c pppstats $(BINDIR)
++	$(INSTALL) -c pppstats $(BINDIR)
+ 	$(INSTALL) -c -m 444 pppstats.8 $(MANDIR)
+ 
+ pppstats: $(PPPSTATSRCS)
diff --git a/openwrt/package/ppp/patches/204-opt_flags.patch b/openwrt/package/ppp/patches/204-opt_flags.patch
new file mode 100644
index 0000000000..200e76b5b5
--- /dev/null
+++ b/openwrt/package/ppp/patches/204-opt_flags.patch
@@ -0,0 +1,26 @@
+diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux
+--- ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux	2004-11-14 08:02:31.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux	2004-12-05 17:43:17.000000000 +0100
+@@ -12,7 +12,8 @@
+ INSTALL	= install
+ 
+ PLUGIN=radius.so radattr.so radrealms.so
+-CFLAGS=-I. -I../.. -I../../../include -O2 -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
++COPTS = -O2
++CFLAGS=-I. -I../.. -I../../../include $(COPTS) -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
+ 
+ # Uncomment the next line to include support for Microsoft's
+ # MS-CHAP authentication protocol.
+diff -ruN ppp-2.4.3-orig/pppdump/Makefile.linux ppp-2.4.3-3/pppdump/Makefile.linux
+--- ppp-2.4.3-orig/pppdump/Makefile.linux	2004-10-31 02:36:52.000000000 +0200
++++ ppp-2.4.3-3/pppdump/Makefile.linux	2004-12-05 17:50:34.000000000 +0100
+@@ -2,7 +2,8 @@
+ BINDIR = $(DESTDIR)/sbin
+ MANDIR = $(DESTDIR)/share/man/man8
+ 
+-CFLAGS= -O -I../include/net
++COPTS = -O
++CFLAGS= $(COPTS) -I../include/net
+ OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
+ 
+ INSTALL= install
diff --git a/openwrt/package/ppp/patches/205-pppoe_iface_name.patch b/openwrt/package/ppp/patches/205-pppoe_iface_name.patch
new file mode 100644
index 0000000000..522d5878a4
--- /dev/null
+++ b/openwrt/package/ppp/patches/205-pppoe_iface_name.patch
@@ -0,0 +1,12 @@
+diff -ruN ppp-2.4.3-orig/pppd/plugins/rp-pppoe/plugin.c ppp-2.4.3-3/pppd/plugins/rp-pppoe/plugin.c
+--- ppp-2.4.3-orig/pppd/plugins/rp-pppoe/plugin.c	2004-11-04 11:07:37.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/rp-pppoe/plugin.c	2004-12-16 01:07:22.000000000 +0100
+@@ -286,7 +286,7 @@
+ 	/* Strip off "nic-" */
+ 	cmd += 4;
+     } else if (strlen(cmd) < 4
+-	       || (strncmp(cmd, "eth", 3) && strncmp(cmd, "nas", 3)
++	       || (strncmp(cmd, "eth", 3) && strncmp(cmd, "nas", 3) && strncmp(cmd, "vlan", 4)
+ 		   && strncmp(cmd, "tap", 3) && strncmp(cmd, "br", 2))) {
+ 	return 0;
+     }
diff --git a/openwrt/package/ppp/patches/206-radius_config.patch b/openwrt/package/ppp/patches/206-radius_config.patch
new file mode 100644
index 0000000000..90c02af4c1
--- /dev/null
+++ b/openwrt/package/ppp/patches/206-radius_config.patch
@@ -0,0 +1,74 @@
+diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/config.c ppp-2.4.3-3/pppd/plugins/radius/config.c
+--- ppp-2.4.3-orig/pppd/plugins/radius/config.c	2004-11-14 08:26:26.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/radius/config.c	2004-12-16 04:03:46.000000000 +0100
+@@ -369,31 +369,37 @@
+ 	}
+ #endif
+ 
++#if 0
+ 	if (rc_conf_int("login_tries") <= 0)
+ 	{
+ 		error("%s: login_tries <= 0 is illegal", filename);
+ 		return (-1);
+ 	}
++#endif
+ 	if (rc_conf_str("seqfile") == NULL)
+ 	{
+ 		error("%s: seqfile not specified", filename);
+ 		return (-1);
+ 	}
++#if 0
+ 	if (rc_conf_int("login_timeout") <= 0)
+ 	{
+ 		error("%s: login_timeout <= 0 is illegal", filename);
+ 		return (-1);
+ 	}
++#endif
+ 	if (rc_conf_str("mapfile") == NULL)
+ 	{
+ 		error("%s: mapfile not specified", filename);
+ 		return (-1);
+ 	}
++#if 0
+ 	if (rc_conf_str("nologin") == NULL)
+ 	{
+ 		error("%s: nologin not specified", filename);
+ 		return (-1);
+ 	}
++#endif
+ 
+ 	return 0;
+ }
+diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/options.h ppp-2.4.3-3/pppd/plugins/radius/options.h
+--- ppp-2.4.3-orig/pppd/plugins/radius/options.h	2004-11-14 08:26:26.000000000 +0100
++++ ppp-2.4.3-3/pppd/plugins/radius/options.h	2004-12-16 04:09:16.000000000 +0100
+@@ -31,24 +31,21 @@
+ static SERVER acctserver = {0};
+ static SERVER authserver = {0};
+ 
+-int default_tries = 4;
+-int default_timeout = 60;
+-
+ static OPTION config_options[] = {
+ /* internally used options */
+ {"config_file",		OT_STR, ST_UNDEF, NULL},
+ /* General options */
+ {"auth_order",	 	OT_AUO, ST_UNDEF, NULL},
+-{"login_tries",	 	OT_INT, ST_UNDEF, &default_tries},
+-{"login_timeout",	OT_INT, ST_UNDEF, &default_timeout},
+-{"nologin",		OT_STR, ST_UNDEF, "/etc/nologin"},
+-{"issue",		OT_STR, ST_UNDEF, "/etc/radiusclient/issue"},
++{"login_tries",	 	OT_INT, ST_UNDEF, NULL},
++{"login_timeout",	OT_INT, ST_UNDEF, NULL},
++{"nologin",		OT_STR, ST_UNDEF, NULL},
++{"issue",		OT_STR, ST_UNDEF, NULL},
+ /* RADIUS specific options */
+ {"authserver",		OT_SRV, ST_UNDEF, &authserver},
+ {"acctserver",		OT_SRV, ST_UNDEF, &acctserver},
+ {"servers",		OT_STR, ST_UNDEF, NULL},
+ {"dictionary",		OT_STR, ST_UNDEF, NULL},
+-{"login_radius",	OT_STR, ST_UNDEF, "/usr/sbin/login.radius"},
++{"login_radius",	OT_STR, ST_UNDEF, NULL},
+ {"seqfile",		OT_STR, ST_UNDEF, NULL},
+ {"mapfile",		OT_STR, ST_UNDEF, NULL},
+ {"default_realm",	OT_STR, ST_UNDEF, NULL},
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-makefile.patch b/openwrt/package/ppp/patches/ppp-2.4.3-makefile.patch
deleted file mode 100644
index 5bbf8602d1..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-makefile.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-diff -ruN ppp-2.4.3-orig/pppd/Makefile.linux ppp-2.4.3-3/pppd/Makefile.linux
---- ppp-2.4.3-orig/pppd/Makefile.linux	2004-11-13 13:02:22.000000000 +0100
-+++ ppp-2.4.3-3/pppd/Makefile.linux	2004-12-16 04:43:41.000000000 +0100
-@@ -48,19 +48,19 @@
- # Uncomment the next line to include support for PPP packet filtering.
- # This requires that the libpcap library and headers be installed
- # and that the kernel driver support PPP packet filtering.
--FILTER=y
-+#FILTER=y
- 
- # Uncomment the next line to enable multilink PPP (enabled by default)
- # Linux distributions: Please leave multilink ENABLED in your builds
- # of pppd!
--HAVE_MULTILINK=y
-+#HAVE_MULTILINK=y
- 
- # Uncomment the next line to enable the TDB database (enabled by default.)
- # If you enable multilink, then TDB is automatically enabled also.
- # Linux distributions: Please leave TDB ENABLED in your builds.
--USE_TDB=y
-+#USE_TDB=y
- 
--HAS_SHADOW=y
-+#HAS_SHADOW=y
- #USE_PAM=y
- #HAVE_INET6=y
- 
-@@ -77,7 +77,7 @@
- 
- INCLUDE_DIRS= -I../include
- 
--COMPILE_FLAGS= -DHAVE_PATHS_H -DIPX_CHANGE -DHAVE_MMAP
-+COMPILE_FLAGS= -DHAVE_PATHS_H -DHAVE_MMAP
- 
- CFLAGS= $(COPTS) $(COMPILE_FLAGS) $(INCLUDE_DIRS)
- 
-@@ -117,12 +117,12 @@
- #LIBS     += -lshadow $(LIBS)
- endif
- 
--ifneq ($(wildcard /usr/include/crypt.h),)
-+#ifneq ($(wildcard /usr/include/crypt.h),)
- CFLAGS   += -DHAVE_CRYPT_H=1
--endif
--ifneq ($(wildcard /usr/lib/libcrypt.*),)
-+#endif
-+#ifneq ($(wildcard /usr/lib/libcrypt.*),)
- LIBS	+= -lcrypt
--endif
-+#endif
- 
- ifdef NEEDDES
- ifndef USE_CRYPT
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-mppe-mppc-1.1.patch b/openwrt/package/ppp/patches/ppp-2.4.3-mppe-mppc-1.1.patch
deleted file mode 100644
index 7e09f1a792..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-mppe-mppc-1.1.patch
+++ /dev/null
@@ -1,1585 +0,0 @@
-diff -ruN ppp-2.4.3.orig/include/linux/ppp-comp.h ppp-2.4.3/include/linux/ppp-comp.h
---- ppp-2.4.3.orig/include/linux/ppp-comp.h	2002-12-06 10:49:15.000000000 +0100
-+++ ppp-2.4.3/include/linux/ppp-comp.h	2004-11-21 13:54:09.000000000 +0100
-@@ -36,7 +36,7 @@
-  */
- 
- /*
-- *  ==FILEVERSION 20020319==
-+ *  ==FILEVERSION 20020715==
-  *
-  *  NOTE TO MAINTAINERS:
-  *     If you modify this file at all, please set the above date.
-@@ -86,7 +86,7 @@
- 
- 	/* Compress a packet */
- 	int     (*compress) (void *state, unsigned char *rptr,
--			      unsigned char *obuf, int isize, int osize);
-+			     unsigned char *obuf, int isize, int osize);
- 
- 	/* Return compression statistics */
- 	void	(*comp_stat) (void *state, struct compstat *stats);
-@@ -107,7 +107,7 @@
- 
- 	/* Decompress a packet. */
- 	int	(*decompress) (void *state, unsigned char *ibuf, int isize,
--				unsigned char *obuf, int osize);
-+			       unsigned char *obuf, int osize);
- 
- 	/* Update state for an incompressible packet received */
- 	void	(*incomp) (void *state, unsigned char *ibuf, int icnt);
-@@ -288,6 +288,33 @@
- 	    opts |= MPPE_OPT_UNKNOWN;		\
-     } while (/* CONSTCOND */ 0)
- 
-+/* MPPE/MPPC definitions by J.D.*/
-+#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
-+#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
-+#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
-+#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
-+#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
-+
-+/*
-+ * Definitions for Stac LZS.
-+ */
-+
-+#define CI_LZS			17	/* config option for Stac LZS */
-+#define CILEN_LZS		5	/* length of config option */
-+
-+#define LZS_OVHD		4	/* max. LZS overhead */
-+#define LZS_HIST_LEN		2048	/* LZS history size */
-+#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
-+
-+#define LZS_MODE_NONE		0
-+#define LZS_MODE_LCB		1
-+#define LZS_MODE_CRC		2
-+#define LZS_MODE_SEQ		3
-+#define LZS_MODE_EXT		4
-+
-+#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
-+#define LZS_EXT_BIT_COMP	0x20	/* bit C */
-+
- /*
-  * Definitions for other, as yet unsupported, compression methods.
-  */
-diff -ruN ppp-2.4.3.orig/include/net/ppp-comp.h ppp-2.4.3/include/net/ppp-comp.h
---- ppp-2.4.3.orig/include/net/ppp-comp.h	2002-12-06 10:49:15.000000000 +0100
-+++ ppp-2.4.3/include/net/ppp-comp.h	2004-11-21 13:54:09.000000000 +0100
-@@ -255,6 +255,33 @@
- 	    opts |= MPPE_OPT_UNKNOWN;		\
-     } while (/* CONSTCOND */ 0)
- 
-+/* MPPE/MPPC definitions by J.D.*/
-+#define MPPE_STATELESS          MPPE_H_BIT	/* configuration bit H */
-+#define MPPE_40BIT              MPPE_L_BIT	/* configuration bit L */
-+#define MPPE_56BIT              MPPE_M_BIT	/* configuration bit M */
-+#define MPPE_128BIT             MPPE_S_BIT	/* configuration bit S */
-+#define MPPE_MPPC               MPPE_C_BIT	/* configuration bit C */
-+
-+/*
-+ * Definitions for Stac LZS.
-+ */
-+
-+#define CI_LZS			17	/* config option for Stac LZS */
-+#define CILEN_LZS		5	/* length of config option */
-+
-+#define LZS_OVHD		4	/* max. LZS overhead */
-+#define LZS_HIST_LEN		2048	/* LZS history size */
-+#define LZS_MAX_CCOUNT		0x0FFF	/* max. coherency counter value */
-+
-+#define LZS_MODE_NONE		0
-+#define LZS_MODE_LCB		1
-+#define LZS_MODE_CRC		2
-+#define LZS_MODE_SEQ		3
-+#define LZS_MODE_EXT		4
-+
-+#define LZS_EXT_BIT_FLUSHED	0x80	/* bit A */
-+#define LZS_EXT_BIT_COMP	0x20	/* bit C */
-+
- /*
-  * Definitions for other, as yet unsupported, compression methods.
-  */
-diff -ruN ppp-2.4.3.orig/pppd/ccp.c ppp-2.4.3/pppd/ccp.c
---- ppp-2.4.3.orig/pppd/ccp.c	2004-11-13 03:28:15.000000000 +0100
-+++ ppp-2.4.3/pppd/ccp.c	2004-11-21 13:54:09.000000000 +0100
-@@ -62,12 +62,10 @@
- static char bsd_value[8];
- static char deflate_value[8];
- 
--/*
-- * Option variables.
-- */
- #ifdef MPPE
--bool refuse_mppe_stateful = 1;		/* Allow stateful mode? */
--#endif
-+static int setmppe(char **);
-+static int setnomppe(void);
-+#endif /* MPPE */
- 
- static option_t ccp_option_list[] = {
-     { "noccp", o_bool, &ccp_protent.enabled_flag,
-@@ -108,54 +106,36 @@
-       "don't allow Predictor-1", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
-       &ccp_allowoptions[0].predictor_1 },
- 
-+    { "lzs", o_bool, &ccp_wantoptions[0].lzs,
-+      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_PRIO },
-+    { "+lzs", o_bool, &ccp_wantoptions[0].lzs,
-+      "request Stac LZS", 1, &ccp_allowoptions[0].lzs, OPT_ALIAS | OPT_PRIO },
-+    { "nolzs", o_bool, &ccp_wantoptions[0].lzs,
-+      "don't allow Stac LZS", OPT_PRIOSUB | OPT_A2CLR,
-+      &ccp_allowoptions[0].lzs },
-+    { "-lzs", o_bool, &ccp_wantoptions[0].lzs,
-+      "don't allow Stac LZS", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
-+      &ccp_allowoptions[0].lzs },
-+
- #ifdef MPPE
--    /* MPPE options are symmetrical ... we only set wantoptions here */
--    { "require-mppe", o_bool, &ccp_wantoptions[0].mppe,
--      "require MPPE encryption",
--      OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
--    { "+mppe", o_bool, &ccp_wantoptions[0].mppe,
--      "require MPPE encryption",
--      OPT_ALIAS | OPT_PRIO | MPPE_OPT_40 | MPPE_OPT_128 },
--    { "nomppe", o_bool, &ccp_wantoptions[0].mppe,
--      "don't allow MPPE encryption", OPT_PRIO },
--    { "-mppe", o_bool, &ccp_wantoptions[0].mppe,
--      "don't allow MPPE encryption", OPT_ALIAS | OPT_PRIO },
--
--    /* We use ccp_allowoptions[0].mppe as a junk var ... it is reset later */
--    { "require-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
--      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
--      &ccp_wantoptions[0].mppe },
--    { "+mppe-40", o_bool, &ccp_allowoptions[0].mppe,
--      "require MPPE 40-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_40,
--      &ccp_wantoptions[0].mppe },
--    { "nomppe-40", o_bool, &ccp_allowoptions[0].mppe,
--      "don't allow MPPE 40-bit encryption",
--      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40, &ccp_wantoptions[0].mppe },
--    { "-mppe-40", o_bool, &ccp_allowoptions[0].mppe,
--      "don't allow MPPE 40-bit encryption",
--      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_40,
--      &ccp_wantoptions[0].mppe },
--
--    { "require-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
--      "require MPPE 128-bit encryption", OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
--      &ccp_wantoptions[0].mppe },
--    { "+mppe-128", o_bool, &ccp_allowoptions[0].mppe,
--      "require MPPE 128-bit encryption",
--      OPT_ALIAS | OPT_PRIO | OPT_A2OR | MPPE_OPT_128,
--      &ccp_wantoptions[0].mppe },
--    { "nomppe-128", o_bool, &ccp_allowoptions[0].mppe,
--      "don't allow MPPE 128-bit encryption",
--      OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128, &ccp_wantoptions[0].mppe },
--    { "-mppe-128", o_bool, &ccp_allowoptions[0].mppe,
--      "don't allow MPPE 128-bit encryption",
--      OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLRB | MPPE_OPT_128,
--      &ccp_wantoptions[0].mppe },
--
--    /* strange one; we always request stateless, but will we allow stateful? */
--    { "mppe-stateful", o_bool, &refuse_mppe_stateful,
--      "allow MPPE stateful mode", OPT_PRIO },
--    { "nomppe-stateful", o_bool, &refuse_mppe_stateful,
--      "disallow MPPE stateful mode", OPT_PRIO | 1 },
-+    { "mppc", o_bool, &ccp_wantoptions[0].mppc,
-+      "request MPPC compression", 1, &ccp_allowoptions[0].mppc },
-+    { "+mppc", o_bool, &ccp_wantoptions[0].mppc,
-+      "request MPPC compression", 1, &ccp_allowoptions[0].mppc, OPT_ALIAS },
-+    { "nomppc", o_bool, &ccp_wantoptions[0].mppc,
-+      "don't allow MPPC compression", OPT_PRIOSUB | OPT_A2CLR,
-+      &ccp_allowoptions[0].mppc },
-+    { "-mppc", o_bool, &ccp_wantoptions[0].mppc,
-+      "don't allow MPPC compression", OPT_ALIAS | OPT_PRIOSUB | OPT_A2CLR,
-+      &ccp_allowoptions[0].mppc },
-+    { "mppe", o_special, (void *)setmppe,
-+      "request MPPE encryption" },
-+    { "+mppe", o_special, (void *)setmppe,
-+      "request MPPE encryption" },
-+    { "nomppe", o_special_noarg, (void *)setnomppe,
-+      "don't allow MPPE encryption" },
-+    { "-mppe", o_special_noarg, (void *)setnomppe,
-+      "don't allow MPPE encryption" },
- #endif /* MPPE */
- 
-     { NULL }
-@@ -241,7 +221,7 @@
-  */
- #define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
- 				 || (opt).predictor_1 || (opt).predictor_2 \
--				 || (opt).mppe)
-+				 || (opt).lzs || (opt).mppc || (opt).mppe)
- 
- /*
-  * Local state (mainly for handling reset-reqs and reset-acks).
-@@ -344,6 +324,100 @@
-     return 1;
- }
- 
-+#ifdef MPPE
-+/*
-+ * Functions called from config options
-+ */
-+/* 
-+   MPPE suboptions:
-+	required - require MPPE; disconnect if peer doesn't support it
-+	stateless - use stateless mode
-+	no40 - disable 40 bit keys
-+	no56 - disable 56 bit keys
-+	no128 - disable 128 bit keys
-+*/
-+int setmppe(char **argv)
-+{
-+    int i;
-+    char *str, cmdbuf[16];
-+
-+    ccp_allowoptions[0].mppe = 1;
-+    ccp_allowoptions[0].mppe_40 = 1;
-+    ccp_allowoptions[0].mppe_56 = 1;
-+    ccp_allowoptions[0].mppe_128 = 1;
-+    ccp_allowoptions[0].mppe_stateless = 0;
-+    ccp_wantoptions[0].mppe = 0;
-+
-+    str = *argv;
-+
-+    while (1) {
-+	i = 0;
-+	memset(cmdbuf, '\0', 16);
-+	while ((i < 16) && (*str != ',') && (*str != '\0'))
-+	    cmdbuf[i++] = *str++;
-+	cmdbuf[i] = '\0';
-+	if (!strncasecmp(cmdbuf, "no40", strlen("no40"))) {
-+	    ccp_allowoptions[0].mppe_40 = 0;
-+	    goto next_param;
-+	} else if (!strncasecmp(cmdbuf, "no56", strlen("no56"))) {
-+	    ccp_allowoptions[0].mppe_56 = 0;
-+	    goto next_param;
-+	} else if (!strncasecmp(cmdbuf, "no128", strlen("no128"))) {
-+	    ccp_allowoptions[0].mppe_128 = 0;
-+	    goto next_param;
-+	} else if (!strncasecmp(cmdbuf, "stateless", strlen("stateless"))) {
-+	    ccp_allowoptions[0].mppe_stateless = 1;
-+	    goto next_param;
-+	} else if (!strncasecmp(cmdbuf, "required", strlen("required"))) {
-+	    ccp_wantoptions[0].mppe = 1;
-+	    goto next_param;
-+	} else {
-+	    option_error("invalid parameter '%s' for mppe option", cmdbuf);
-+	    return 0;
-+	}
-+
-+    next_param:
-+	if (*str == ',') {
-+	    str++;
-+	    continue;
-+	}
-+	if (*str == '\0') {
-+	    if (!(ccp_allowoptions[0].mppe_40 || ccp_allowoptions[0].mppe_56 ||
-+		  ccp_allowoptions[0].mppe_128)) {
-+		if (ccp_wantoptions[0].mppe == 1) {
-+		    option_error("You require MPPE but you have switched off "
-+				 "all encryption key lengths.");
-+		    return 0;
-+		}
-+		ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
-+		ccp_wantoptions[0].mppe_stateless =
-+		    ccp_allowoptions[0].mppe_stateless = 0;
-+	    } else {
-+		ccp_allowoptions[0].mppe = 1;
-+		ccp_wantoptions[0].mppe_stateless =
-+		    ccp_allowoptions[0].mppe_stateless;
-+		if (ccp_wantoptions[0].mppe == 1) {
-+		    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40;
-+		    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56;
-+		    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128;
-+		}
-+	    }
-+	    return 1;
-+	}
-+    }
-+}
-+
-+int setnomppe(void)
-+{
-+    ccp_wantoptions[0].mppe = ccp_allowoptions[0].mppe = 0;
-+    ccp_wantoptions[0].mppe_40 = ccp_allowoptions[0].mppe_40 = 0;
-+    ccp_wantoptions[0].mppe_56 = ccp_allowoptions[0].mppe_56 = 0;
-+    ccp_wantoptions[0].mppe_128 = ccp_allowoptions[0].mppe_128 = 0;
-+    ccp_wantoptions[0].mppe_stateless = ccp_allowoptions[0].mppe_stateless = 0;
-+    return 1;
-+}
-+#endif /* MPPE */
-+
- /*
-  * ccp_init - initialize CCP.
-  */
-@@ -378,6 +452,30 @@
-     ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
- 
-     ccp_allowoptions[0].predictor_1 = 1;
-+
-+    ccp_wantoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
-+    ccp_wantoptions[0].lzs_mode = LZS_MODE_SEQ;
-+    ccp_wantoptions[0].lzs_hists = 1;
-+    ccp_allowoptions[0].lzs = 0; /* Stac LZS  - will be enabled in the future */
-+    ccp_allowoptions[0].lzs_mode = LZS_MODE_SEQ;
-+    ccp_allowoptions[0].lzs_hists = 1;
-+
-+#ifdef MPPE
-+    /* by default allow and request MPPC... */
-+    ccp_wantoptions[0].mppc = ccp_allowoptions[0].mppc = 1;
-+
-+    /* ... and allow but don't request MPPE */
-+    ccp_allowoptions[0].mppe = 1;
-+    ccp_allowoptions[0].mppe_40 = 1;
-+    ccp_allowoptions[0].mppe_56 = 1;
-+    ccp_allowoptions[0].mppe_128 = 1;
-+    ccp_allowoptions[0].mppe_stateless = 1;
-+    ccp_wantoptions[0].mppe = 0;
-+    ccp_wantoptions[0].mppe_40 = 0;
-+    ccp_wantoptions[0].mppe_56 = 0;
-+    ccp_wantoptions[0].mppe_128 = 0;
-+    ccp_wantoptions[0].mppe_stateless = 0;
-+#endif /* MPPE */
- }
- 
- /*
-@@ -455,11 +553,11 @@
-     if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED) {
- 	notice("Compression disabled by peer.");
- #ifdef MPPE
--	if (ccp_gotoptions[unit].mppe) {
-+	if (ccp_wantoptions[unit].mppe) {
- 	    error("MPPE disabled, closing LCP");
- 	    lcp_close(unit, "MPPE disabled by peer");
- 	}
--#endif
-+#endif /* MPPE */
-     }
- 
-     /*
-@@ -487,6 +585,15 @@
- 	    break;
- 	/* send a reset-ack, which the transmitter will see and
- 	   reset its compression state. */
-+
-+	/* In case of MPPE/MPPC or LZS we shouldn't send CCP_RESETACK,
-+	   but we do it in order to reset compressor; CCP_RESETACK is
-+	   then silently discarded. See functions ppp_send_frame and
-+	   ppp_ccp_peek in ppp_generic.c (Linux only !!!). All the
-+	   confusion is caused by the fact that CCP code is splited
-+	   into two parts - one part is handled by pppd, the other one
-+	   is handled by kernel. */
-+
- 	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
- 	break;
- 
-@@ -515,12 +622,11 @@
-     fsm_lowerdown(&ccp_fsm[unit]);
- 
- #ifdef MPPE
--    if (ccp_gotoptions[unit].mppe) {
-+    if (ccp_wantoptions[unit].mppe) {
- 	error("MPPE required but peer negotiation failed");
- 	lcp_close(unit, "MPPE required but peer negotiation failed");
-     }
--#endif
--
-+#endif /* MPPE */
- }
- 
- /*
-@@ -537,7 +643,7 @@
-     all_rejected[f->unit] = 0;
- 
- #ifdef MPPE
--    if (go->mppe) {
-+    if (go->mppe || go->mppc) {
- 	ccp_options *ao = &ccp_allowoptions[f->unit];
- 	int auth_mschap_bits = auth_done[f->unit];
- 	int numbits;
-@@ -551,80 +657,109 @@
- 	 * NB: If MPPE is required, all other compression opts are invalid.
- 	 *     So, we return right away if we can't do it.
- 	 */
-+	if (ccp_wantoptions[f->unit].mppe) {
-+	    /* Leave only the mschap auth bits set */
-+	    auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
-+				 CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
-+	    /* Count the mschap auths */
-+	    auth_mschap_bits >>= CHAP_MS_SHIFT;
-+	    numbits = 0;
-+	    do {
-+		numbits += auth_mschap_bits & 1;
-+		auth_mschap_bits >>= 1;
-+	    } while (auth_mschap_bits);
-+	    if (numbits > 1) {
-+		error("MPPE required, but auth done in both directions.");
-+		lcp_close(f->unit, "MPPE required but not available");
-+		return;
-+	    }
-+	    if (!numbits) {
-+		error("MPPE required, but MS-CHAP[v2] auth not performed.");
-+		lcp_close(f->unit, "MPPE required but not available");
-+		return;
-+	    }
- 
--	/* Leave only the mschap auth bits set */
--	auth_mschap_bits &= (CHAP_MS_WITHPEER  | CHAP_MS_PEER |
--			     CHAP_MS2_WITHPEER | CHAP_MS2_PEER);
--	/* Count the mschap auths */
--	auth_mschap_bits >>= CHAP_MS_SHIFT;
--	numbits = 0;
--	do {
--	    numbits += auth_mschap_bits & 1;
--	    auth_mschap_bits >>= 1;
--	} while (auth_mschap_bits);
--	if (numbits > 1) {
--	    error("MPPE required, but auth done in both directions.");
--	    lcp_close(f->unit, "MPPE required but not available");
--	    return;
--	}
--	if (!numbits) {
--	    error("MPPE required, but MS-CHAP[v2] auth not performed.");
--	    lcp_close(f->unit, "MPPE required but not available");
--	    return;
--	}
--
--	/* A plugin (eg radius) may not have obtained key material. */
--	if (!mppe_keys_set) {
--	    error("MPPE required, but keys are not available.  "
--		  "Possible plugin problem?");
--	    lcp_close(f->unit, "MPPE required but not available");
--	    return;
--	}
--
--	/* LM auth not supported for MPPE */
--	if (auth_done[f->unit] & (CHAP_MS_WITHPEER | CHAP_MS_PEER)) {
--	    /* This might be noise */
--	    if (go->mppe & MPPE_OPT_40) {
--		notice("Disabling 40-bit MPPE; MS-CHAP LM not supported");
--		go->mppe &= ~MPPE_OPT_40;
--		ccp_wantoptions[f->unit].mppe &= ~MPPE_OPT_40;
-+	    /* A plugin (eg radius) may not have obtained key material. */
-+	    if (!mppe_keys_set) {
-+		error("MPPE required, but keys are not available.  "
-+		      "Possible plugin problem?");
-+		lcp_close(f->unit, "MPPE required but not available");
-+		return;
- 	    }
- 	}
- 
--	/* Last check: can we actually negotiate something? */
--	if (!(go->mppe & (MPPE_OPT_40 | MPPE_OPT_128))) {
--	    /* Could be misconfig, could be 40-bit disabled above. */
--	    error("MPPE required, but both 40-bit and 128-bit disabled.");
--	    lcp_close(f->unit, "MPPE required but not available");
--	    return;
-+	/*
-+	 * Check whether the kernel knows about the various
-+	 * compression methods we might request. Key material
-+	 * unimportant here.
-+	 */
-+	if (go->mppc) {
-+	    opt_buf[0] = CI_MPPE;
-+	    opt_buf[1] = CILEN_MPPE;
-+	    opt_buf[2] = 0;
-+	    opt_buf[3] = 0;
-+	    opt_buf[4] = 0;
-+	    opt_buf[5] = MPPE_MPPC;
-+	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 0) <= 0)
-+		go->mppc = 0;
-+	}
-+	if (go->mppe_40) {
-+	    opt_buf[0] = CI_MPPE;
-+	    opt_buf[1] = CILEN_MPPE;
-+	    opt_buf[2] = MPPE_STATELESS;
-+	    opt_buf[3] = 0;
-+	    opt_buf[4] = 0;
-+	    opt_buf[5] = MPPE_40BIT;
-+	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
-+		go->mppe_40 = 0;
-+	}
-+	if (go->mppe_56) {
-+	    opt_buf[0] = CI_MPPE;
-+	    opt_buf[1] = CILEN_MPPE;
-+	    opt_buf[2] = MPPE_STATELESS;
-+	    opt_buf[3] = 0;
-+	    opt_buf[4] = 0;
-+	    opt_buf[5] = MPPE_56BIT;
-+	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
-+		go->mppe_56 = 0;
-+	}
-+	if (go->mppe_128) {
-+	    opt_buf[0] = CI_MPPE;
-+	    opt_buf[1] = CILEN_MPPE;
-+	    opt_buf[2] = MPPE_STATELESS;
-+	    opt_buf[3] = 0;
-+	    opt_buf[4] = 0;
-+	    opt_buf[5] = MPPE_128BIT;
-+	    if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0)
-+		go->mppe_128 = 0;
-+	}
-+	if (!go->mppe_40 && !go->mppe_56 && !go->mppe_128) {
-+	    if (ccp_wantoptions[f->unit].mppe) {
-+		error("MPPE required, but kernel has no support.");
-+		lcp_close(f->unit, "MPPE required but not available");
-+	    }
-+	    go->mppe = go->mppe_stateless = 0;
-+	} else {
-+	    /* MPPE is not compatible with other compression types */
-+	    if (ccp_wantoptions[f->unit].mppe) {
-+		ao->bsd_compress = go->bsd_compress = 0;
-+		ao->predictor_1  = go->predictor_1  = 0;
-+		ao->predictor_2  = go->predictor_2  = 0;
-+		ao->deflate	 = go->deflate	    = 0;
-+		ao->lzs		 = go->lzs	    = 0;
-+	    }
- 	}
--
--	/* sync options */
--	ao->mppe = go->mppe;
--	/* MPPE is not compatible with other compression types */
--	ao->bsd_compress = go->bsd_compress = 0;
--	ao->predictor_1  = go->predictor_1  = 0;
--	ao->predictor_2  = go->predictor_2  = 0;
--	ao->deflate      = go->deflate      = 0;
-     }
- #endif /* MPPE */
--
--    /*
--     * Check whether the kernel knows about the various
--     * compression methods we might request.
--     */
--#ifdef MPPE
--    if (go->mppe) {
--	opt_buf[0] = CI_MPPE;
--	opt_buf[1] = CILEN_MPPE;
--	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
--	/* Key material unimportant here. */
--	if (ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0) <= 0) {
--	    error("MPPE required, but kernel has no support.");
--	    lcp_close(f->unit, "MPPE required but not available");
--	}
-+    if (go->lzs) {
-+	opt_buf[0] = CI_LZS;
-+	opt_buf[1] = CILEN_LZS;
-+	opt_buf[2] = go->lzs_hists >> 8;
-+	opt_buf[3] = go->lzs_hists & 0xff;
-+	opt_buf[4] = LZS_MODE_SEQ;
-+	if (ccp_test(f->unit, opt_buf, CILEN_LZS, 0) <= 0)
-+	    go->lzs = 0;
-     }
--#endif
-     if (go->bsd_compress) {
- 	opt_buf[0] = CI_BSD_COMPRESS;
- 	opt_buf[1] = CILEN_BSD_COMPRESS;
-@@ -679,7 +814,8 @@
- 	+ (go->deflate? CILEN_DEFLATE: 0)
- 	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
- 	+ (go->predictor_2? CILEN_PREDICTOR_2: 0)
--	+ (go->mppe? CILEN_MPPE: 0);
-+	+ (go->lzs? CILEN_LZS: 0)
-+	+ ((go->mppe || go->mppc)? CILEN_MPPE: 0);
- }
- 
- /*
-@@ -693,6 +829,8 @@
- {
-     int res;
-     ccp_options *go = &ccp_gotoptions[f->unit];
-+    ccp_options *ao = &ccp_allowoptions[f->unit];
-+    ccp_options *wo = &ccp_wantoptions[f->unit];
-     u_char *p0 = p;
- 
-     /*
-@@ -701,22 +839,43 @@
-      * in case it gets Acked.
-      */
- #ifdef MPPE
--    if (go->mppe) {
-+    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
- 	u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
- 
--	p[0] = opt_buf[0] = CI_MPPE;
--	p[1] = opt_buf[1] = CILEN_MPPE;
--	MPPE_OPTS_TO_CI(go->mppe, &p[2]);
--	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
-+	p[0] = CI_MPPE;
-+	p[1] = CILEN_MPPE;
-+	p[2] = (go->mppe_stateless ? MPPE_STATELESS : 0);
-+	p[3] = 0;
-+	p[4] = 0;
-+	p[5] = (go->mppe_40 ? MPPE_40BIT : 0) | (go->mppe_56 ? MPPE_56BIT : 0) |
-+	    (go->mppe_128 ? MPPE_128BIT : 0) | (go->mppc ? MPPE_MPPC : 0);
-+
-+	BCOPY(p, opt_buf, CILEN_MPPE);
- 	BCOPY(mppe_recv_key, &opt_buf[CILEN_MPPE], MPPE_MAX_KEY_LEN);
- 	res = ccp_test(f->unit, opt_buf, CILEN_MPPE + MPPE_MAX_KEY_LEN, 0);
--	if (res > 0)
-+	if (res > 0) {
- 	    p += CILEN_MPPE;
--	else
-+	} else {
- 	    /* This shouldn't happen, we've already tested it! */
--	    lcp_close(f->unit, "MPPE required but not available in kernel");
-+	    go->mppe = go->mppe_40 = go->mppe_56 = go->mppe_128 =
-+		go->mppe_stateless = go->mppc = 0;
-+	    if (ccp_wantoptions[f->unit].mppe)
-+		lcp_close(f->unit, "MPPE required but not available in kernel");
-+	}
-+    }
-+#endif /* MPPE */
-+    if (go->lzs) {
-+	p[0] = CI_LZS;
-+	p[1] = CILEN_LZS;
-+	p[2] = go->lzs_hists >> 8;
-+	p[3] = go->lzs_hists & 0xff;
-+	p[4] = LZS_MODE_SEQ;
-+	res = ccp_test(f->unit, p, CILEN_LZS, 0);
-+	if (res > 0) {
-+	    p += CILEN_LZS;
-+	} else
-+	    go->lzs = 0;
-     }
--#endif
-     if (go->deflate) {
- 	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
- 	p[1] = CILEN_DEFLATE;
-@@ -802,7 +961,7 @@
- 
- /*
-  * ccp_ackci - process a received configure-ack, and return
-- * 1 iff the packet was OK.
-+ * 1 if the packet was OK.
-  */
- static int
- ccp_ackci(f, p, len)
-@@ -811,24 +970,44 @@
-     int len;
- {
-     ccp_options *go = &ccp_gotoptions[f->unit];
-+    ccp_options *ao = &ccp_allowoptions[f->unit];
-+    ccp_options *wo = &ccp_wantoptions[f->unit];
-     u_char *p0 = p;
- 
- #ifdef MPPE
--    if (go->mppe) {
--	u_char opt_buf[CILEN_MPPE];
--
--	opt_buf[0] = CI_MPPE;
--	opt_buf[1] = CILEN_MPPE;
--	MPPE_OPTS_TO_CI(go->mppe, &opt_buf[2]);
--	if (len < CILEN_MPPE || memcmp(opt_buf, p, CILEN_MPPE))
-+    if (go->mppe || go->mppc || (!wo->mppe && ao->mppe)) {
-+	if (len < CILEN_MPPE
-+	    || p[1] != CILEN_MPPE || p[0] != CI_MPPE
-+	    || p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0)
-+	    || p[3] != 0
-+	    || p[4] != 0
-+	    || (p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
-+			 (go->mppc ? MPPE_MPPC : 0))
-+		&& p[5] != ((go->mppe_56 ? MPPE_56BIT : 0) |
-+			    (go->mppc ? MPPE_MPPC : 0))
-+		&& p[5] != ((go->mppe_128 ? MPPE_128BIT : 0) |
-+			    (go->mppc ? MPPE_MPPC : 0))))
- 	    return 0;
-+	if (go->mppe_40 || go->mppe_56 || go->mppe_128)
-+	    go->mppe = 1;
- 	p += CILEN_MPPE;
- 	len -= CILEN_MPPE;
-+	/* Cope with first/fast ack */
-+	if (p == p0 && len == 0)
-+	    return 1;
-+    }
-+#endif /* MPPE */
-+    if (go->lzs) {
-+	if (len < CILEN_LZS || p[0] != CI_LZS || p[1] != CILEN_LZS
-+	    || p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff)
-+	    || p[4] != LZS_MODE_SEQ)
-+	    return 0;
-+	p += CILEN_LZS;
-+	len -= CILEN_LZS;
- 	/* XXX Cope with first/fast ack */
--	if (len == 0)
-+	if (p == p0 && len == 0)
- 	    return 1;
-     }
--#endif
-     if (go->deflate) {
- 	if (len < CILEN_DEFLATE
- 	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
-@@ -891,7 +1070,7 @@
- 
- /*
-  * ccp_nakci - process received configure-nak.
-- * Returns 1 iff the nak was OK.
-+ * Returns 1 if the nak was OK.
-  */
- static int
- ccp_nakci(f, p, len, treat_as_reject)
-@@ -900,6 +1079,8 @@
-     int len;
- {
-     ccp_options *go = &ccp_gotoptions[f->unit];
-+    ccp_options *ao = &ccp_allowoptions[f->unit];
-+    ccp_options *wo = &ccp_wantoptions[f->unit];
-     ccp_options no;		/* options we've seen already */
-     ccp_options try;		/* options to ask for next time */
- 
-@@ -907,28 +1088,100 @@
-     try = *go;
- 
- #ifdef MPPE
--    if (go->mppe && len >= CILEN_MPPE
--	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
--	no.mppe = 1;
--	/*
--	 * Peer wants us to use a different strength or other setting.
--	 * Fail if we aren't willing to use his suggestion.
--	 */
--	MPPE_CI_TO_OPTS(&p[2], try.mppe);
--	if ((try.mppe & MPPE_OPT_STATEFUL) && refuse_mppe_stateful) {
--	    error("Refusing MPPE stateful mode offered by peer");
--	    try.mppe = 0;
--	} else if (((go->mppe | MPPE_OPT_STATEFUL) & try.mppe) != try.mppe) {
--	    /* Peer must have set options we didn't request (suggest) */
--	    try.mppe = 0;
--	}
-+    if ((go->mppe || go->mppc || (!wo->mppe && ao->mppe)) &&
-+	len >= CILEN_MPPE && p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
- 
--	if (!try.mppe) {
--	    error("MPPE required but peer negotiation failed");
--	    lcp_close(f->unit, "MPPE required but peer negotiation failed");
-+	if (go->mppc) {
-+	    no.mppc = 1;
-+	    if (!(p[5] & MPPE_MPPC))
-+		try.mppc = 0;
-+	}
-+
-+	if (go->mppe)
-+	    no.mppe = 1;
-+	if (go->mppe_40)
-+	    no.mppe_40 = 1;
-+	if (go->mppe_56)
-+	    no.mppe_56 = 1;
-+	if (go->mppe_128)
-+	    no.mppe_128 = 1;
-+	if (go->mppe_stateless)
-+	    no.mppe_stateless = 1;
-+
-+	if (ao->mppe_40) {
-+	    if ((p[5] & MPPE_40BIT))
-+		try.mppe_40 = 1;
-+	    else
-+		try.mppe_40 = (p[5] == 0) ? 1 : 0;
-+	}
-+	if (ao->mppe_56) {
-+	    if ((p[5] & MPPE_56BIT))
-+		try.mppe_56 = 1;
-+	    else
-+		try.mppe_56 = (p[5] == 0) ? 1 : 0;
-+	}
-+	if (ao->mppe_128) {
-+	    if ((p[5] & MPPE_128BIT))
-+		try.mppe_128 = 1;
-+	    else
-+		try.mppe_128 = (p[5] == 0) ? 1 : 0;
-+	}
-+
-+	if (ao->mppe_stateless) {
-+	    if ((p[2] & MPPE_STATELESS) || wo->mppe_stateless)
-+		try.mppe_stateless = 1;
-+	    else
-+		try.mppe_stateless = 0;
-+	}
-+
-+	if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128) {
-+	    try.mppe = try.mppe_stateless = 0;
-+	    if (wo->mppe) {
-+		/* we require encryption, but peer doesn't support it
-+		   so we close connection */
-+		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
-+		    wo->mppe_56 = wo->mppe_128 = 0;
-+		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
-+			  "key length");
-+	    }
-+        }
-+	if (wo->mppe && (wo->mppe_40 != try.mppe_40) &&
-+	    (wo->mppe_56 != try.mppe_56) && (wo->mppe_128 != try.mppe_128)) {
-+	    /* cannot negotiate key length */
-+	    wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
-+		wo->mppe_56 = wo->mppe_128 = 0;
-+	    lcp_close(f->unit, "Cannot negotiate MPPE key length");
- 	}
-+	if (try.mppe_40 && try.mppe_56 && try.mppe_128)
-+	    try.mppe_40 = try.mppe_56 = 0;
-+	else
-+	    if (try.mppe_56 && try.mppe_128)
-+		try.mppe_56 = 0;
-+	    else
-+		if (try.mppe_40 && try.mppe_128)
-+		    try.mppe_40 = 0;
-+		else
-+		    if (try.mppe_40 && try.mppe_56)
-+			try.mppe_40 = 0;
-+
-+	p += CILEN_MPPE;
-+	len -= CILEN_MPPE;
-     }
- #endif /* MPPE */
-+
-+    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
-+	no.lzs = 1;
-+	if (((p[2]<<8)|p[3]) > 1 || (p[4] != LZS_MODE_SEQ &&
-+				     p[4] != LZS_MODE_EXT))
-+	    try.lzs = 0;
-+	else {
-+	    try.lzs_mode = p[4];
-+	    try.lzs_hists = (p[2] << 8) | p[3];
-+	}
-+	p += CILEN_LZS;
-+	len -= CILEN_LZS;
-+    }
-+
-     if (go->deflate && len >= CILEN_DEFLATE
- 	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
- 	&& p[1] == CILEN_DEFLATE) {
-@@ -1001,14 +1254,50 @@
- 	return -1;
- 
- #ifdef MPPE
--    if (go->mppe && len >= CILEN_MPPE
-+    if ((go->mppe || go->mppc) && len >= CILEN_MPPE
- 	&& p[0] == CI_MPPE && p[1] == CILEN_MPPE) {
--	error("MPPE required but peer refused");
--	lcp_close(f->unit, "MPPE required but peer refused");
-+	ccp_options *wo = &ccp_wantoptions[f->unit];
-+	if (p[2] != (go->mppe_stateless ? MPPE_STATELESS : 0) ||
-+	    p[3] != 0 ||
-+	    p[4] != 0 ||
-+	    p[5] != ((go->mppe_40 ? MPPE_40BIT : 0) |
-+		     (go->mppe_56 ? MPPE_56BIT : 0) |
-+		     (go->mppe_128 ? MPPE_128BIT : 0) |
-+		     (go->mppc ? MPPE_MPPC : 0)))
-+	    return 0;
-+	if (go->mppc)
-+	    try.mppc = 0;
-+	if (go->mppe) {
-+	    try.mppe = 0;
-+	    if (go->mppe_40)
-+		try.mppe_40 = 0;
-+	    if (go->mppe_56)
-+		try.mppe_56 = 0;
-+	    if (go->mppe_128)
-+		try.mppe_128 = 0;
-+	    if (go->mppe_stateless)
-+		try.mppe_stateless = 0;
-+	    if (!try.mppe_56 && !try.mppe_40 && !try.mppe_128)
-+		try.mppe = try.mppe_stateless = 0;
-+	    if (wo->mppe) { /* we want MPPE but cannot negotiate key length */
-+		wo->mppc = wo->mppe = wo->mppe_stateless = wo->mppe_40 =
-+		    wo->mppe_56 = wo->mppe_128 = 0;
-+		lcp_close(f->unit, "MPPE required but cannot negotiate MPPE "
-+			  "key length");
-+	    }
-+	}
- 	p += CILEN_MPPE;
- 	len -= CILEN_MPPE;
-     }
--#endif
-+#endif /* MPPE */
-+    if (go->lzs && len >= CILEN_LZS && p[0] == CI_LZS && p[1] == CILEN_LZS) {
-+	if (p[2] != go->lzs_hists>>8 || p[3] != (go->lzs_hists&0xff) 
-+	    || p[4] != go->lzs_mode)
-+	    return 0;
-+	try.lzs = 0;
-+	p += CILEN_LZS;
-+	len -= CILEN_LZS;
-+    }
-     if (go->deflate_correct && len >= CILEN_DEFLATE
- 	&& p[0] == CI_DEFLATE && p[1] == CILEN_DEFLATE) {
- 	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
-@@ -1072,14 +1361,15 @@
-     int dont_nak;
- {
-     int ret, newret, res;
--    u_char *p0, *retp;
-+    u_char *p0, *retp, p2, p5;
-     int len, clen, type, nb;
-     ccp_options *ho = &ccp_hisoptions[f->unit];
-     ccp_options *ao = &ccp_allowoptions[f->unit];
-+    ccp_options *wo = &ccp_wantoptions[f->unit];
- #ifdef MPPE
--    bool rej_for_ci_mppe = 1;	/* Are we rejecting based on a bad/missing */
--				/* CI_MPPE, or due to other options?       */
--#endif
-+    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
-+/*     int mtu; */
-+#endif /* MPPE */
- 
-     ret = CONFACK;
-     retp = p0 = p;
-@@ -1102,103 +1392,305 @@
- 	    switch (type) {
- #ifdef MPPE
- 	    case CI_MPPE:
--		if (!ao->mppe || clen != CILEN_MPPE) {
-+		if ((!ao->mppc && !ao->mppe) || clen != CILEN_MPPE) {
- 		    newret = CONFREJ;
- 		    break;
- 		}
--		MPPE_CI_TO_OPTS(&p[2], ho->mppe);
- 
--		/* Nak if anything unsupported or unknown are set. */
--		if (ho->mppe & MPPE_OPT_UNSUPPORTED) {
--		    newret = CONFNAK;
--		    ho->mppe &= ~MPPE_OPT_UNSUPPORTED;
--		}
--		if (ho->mppe & MPPE_OPT_UNKNOWN) {
-+		p2 = p[2];
-+		p5 = p[5];
-+		/* not sure what they want, tell 'em what we got */
-+		if (((p[2] & ~MPPE_STATELESS) != 0 || p[3] != 0 || p[4] != 0 ||
-+		     (p[5] & ~(MPPE_40BIT | MPPE_56BIT | MPPE_128BIT |
-+			       MPPE_MPPC)) != 0 || p[5] == 0) ||
-+		    (p[2] == 0 && p[3] == 0 && p[4] == 0 &&  p[5] == 0)) {
- 		    newret = CONFNAK;
--		    ho->mppe &= ~MPPE_OPT_UNKNOWN;
-+		    p[2] = (wo->mppe_stateless ? MPPE_STATELESS : 0);
-+		    p[3] = 0;
-+		    p[4] = 0;
-+		    p[5] = (wo->mppe_40 ? MPPE_40BIT : 0) |
-+			(wo->mppe_56 ? MPPE_56BIT : 0) |
-+			(wo->mppe_128 ? MPPE_128BIT : 0) |
-+			(wo->mppc ? MPPE_MPPC : 0);
-+		    break;
- 		}
- 
--		/* Check state opt */
--		if (ho->mppe & MPPE_OPT_STATEFUL) {
--		    /*
--		     * We can Nak and request stateless, but it's a
--		     * lot easier to just assume the peer will request
--		     * it if he can do it; stateful mode is bad over
--		     * the Internet -- which is where we expect MPPE.
--		     */
--		   if (refuse_mppe_stateful) {
--			error("Refusing MPPE stateful mode offered by peer");
-+		if ((p[5] & MPPE_MPPC)) {
-+		    if (ao->mppc) {
-+			ho->mppc = 1;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			opt_buf[2] = opt_buf[3] = opt_buf[4] = 0;
-+			opt_buf[5] = MPPE_MPPC;
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE, 1) <= 0) {
-+			    ho->mppc = 0;
-+			    p[5] &= ~MPPE_MPPC;
-+			    newret = CONFNAK;
-+			}
-+		    } else {
- 			newret = CONFREJ;
--			break;
-+			if (wo->mppe || ao->mppe) {
-+			    p[5] &= ~MPPE_MPPC;
-+			    newret = CONFNAK;
-+			}
-+		    }
-+		}
-+
-+		if (ao->mppe)
-+		    ho->mppe = 1;
-+
-+		if ((p[2] & MPPE_STATELESS)) {
-+		    if (ao->mppe_stateless) {
-+			if (wo->mppe_stateless)
-+			    ho->mppe_stateless = 1;
-+			else {
-+			    newret = CONFNAK;
-+			    if (!dont_nak)
-+				p[2] &= ~MPPE_STATELESS;
-+			}
-+		    } else {
-+			newret = CONFNAK;
-+			if (!dont_nak)
-+			    p[2] &= ~MPPE_STATELESS;
-+		    }
-+		} else {
-+		    if (wo->mppe_stateless && !dont_nak) {
-+			wo->mppe_stateless = 0;
-+			newret = CONFNAK;
-+			p[2] |= MPPE_STATELESS;
- 		    }
- 		}
- 
--		/* Find out which of {S,L} are set. */
--		if ((ho->mppe & MPPE_OPT_128)
--		     && (ho->mppe & MPPE_OPT_40)) {
--		    /* Both are set, negotiate the strongest. */
-+		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT|MPPE_128BIT)) {
- 		    newret = CONFNAK;
--		    if (ao->mppe & MPPE_OPT_128)
--			ho->mppe &= ~MPPE_OPT_40;
--		    else if (ao->mppe & MPPE_OPT_40)
--			ho->mppe &= ~MPPE_OPT_128;
--		    else {
--			newret = CONFREJ;
--			break;
-+		    if (ao->mppe_128) {
-+			ho->mppe_128 = 1;
-+			p[5] &= ~(MPPE_40BIT|MPPE_56BIT);
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_128 = 0;
-+			    p[5] |= (MPPE_40BIT|MPPE_56BIT);
-+			    p[5] &= ~MPPE_128BIT;
-+			    goto check_mppe_56_40;
-+			}
-+			goto check_mppe;
- 		    }
--		} else if (ho->mppe & MPPE_OPT_128) {
--		    if (!(ao->mppe & MPPE_OPT_128)) {
--			newret = CONFREJ;
--			break;
-+		    p[5] &= ~MPPE_128BIT;
-+		    goto check_mppe_56_40;
-+		}
-+		if ((p[5] & ~MPPE_MPPC) == (MPPE_56BIT|MPPE_128BIT)) {
-+		    newret = CONFNAK;
-+		    if (ao->mppe_128) {
-+			ho->mppe_128 = 1;
-+			p[5] &= ~MPPE_56BIT;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_128 = 0;
-+			    p[5] |= MPPE_56BIT;
-+			    p[5] &= ~MPPE_128BIT;
-+			    goto check_mppe_56;
-+			}
-+			goto check_mppe;
- 		    }
--		} else if (ho->mppe & MPPE_OPT_40) {
--		    if (!(ao->mppe & MPPE_OPT_40)) {
--			newret = CONFREJ;
--			break;
-+		    p[5] &= ~MPPE_128BIT;
-+		    goto check_mppe_56;
-+		}
-+		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_128BIT)) {
-+		    newret = CONFNAK;
-+		    if (ao->mppe_128) {
-+			ho->mppe_128 = 1;
-+			p[5] &= ~MPPE_40BIT;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_128 = 0;
-+			    p[5] |= MPPE_40BIT;
-+			    p[5] &= ~MPPE_128BIT;
-+			    goto check_mppe_40;
-+			}
-+			goto check_mppe;
-+		    }
-+		    p[5] &= ~MPPE_128BIT;
-+		    goto check_mppe_40;
-+		}
-+		if ((p[5] & ~MPPE_MPPC) == MPPE_128BIT) {
-+		    if (ao->mppe_128) {
-+			ho->mppe_128 = 1;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_128 = 0;
-+			    p[5] &= ~MPPE_128BIT;
-+			    newret = CONFNAK;
-+			}
-+			goto check_mppe;
-+		    }
-+		    p[5] &= ~MPPE_128BIT;
-+		    newret = CONFNAK;
-+		    goto check_mppe;
-+		}
-+	    check_mppe_56_40:
-+		if ((p[5] & ~MPPE_MPPC) == (MPPE_40BIT|MPPE_56BIT)) {
-+		    newret = CONFNAK;
-+		    if (ao->mppe_56) {
-+			ho->mppe_56 = 1;
-+			p[5] &= ~MPPE_40BIT;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_56 = 0;
-+			    p[5] |= MPPE_40BIT;
-+			    p[5] &= ~MPPE_56BIT;
-+			    newret = CONFNAK;
-+			    goto check_mppe_40;
-+			}
-+			goto check_mppe;
-+		    }
-+		    p[5] &= ~MPPE_56BIT;
-+		    goto check_mppe_40;
-+		}
-+	    check_mppe_56:
-+		if ((p[5] & ~MPPE_MPPC) == MPPE_56BIT) {
-+		    if (ao->mppe_56) {
-+			ho->mppe_56 = 1;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_56 = 0;
-+			    p[5] &= ~MPPE_56BIT;
-+			    newret = CONFNAK;
-+			}
-+			goto check_mppe;
-+		    }
-+		    p[5] &= ~MPPE_56BIT;
-+		    newret = CONFNAK;
-+		    goto check_mppe;
-+		}
-+	    check_mppe_40:
-+		if ((p[5] & ~MPPE_MPPC) == MPPE_40BIT) {
-+		    if (ao->mppe_40) {
-+			ho->mppe_40 = 1;
-+			BCOPY(p, opt_buf, CILEN_MPPE);
-+			BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
-+			      MPPE_MAX_KEY_LEN);
-+			if (ccp_test(f->unit, opt_buf, CILEN_MPPE +
-+				     MPPE_MAX_KEY_LEN, 1) <= 0) {
-+			    ho->mppe_40 = 0;
-+			    p[5] &= ~MPPE_40BIT;
-+			    newret = CONFNAK;
-+			}
-+			goto check_mppe;
-+		    }
-+		    p[5] &= ~MPPE_40BIT;
-+		}
-+
-+	    check_mppe:
-+		if (!ho->mppe_40 && !ho->mppe_56 && !ho->mppe_128) {
-+		    if (wo->mppe_40 || wo->mppe_56 || wo->mppe_128) {
-+			newret = CONFNAK;
-+			p[2] |= (wo->mppe_stateless ? MPPE_STATELESS : 0);
-+			p[5] |= (wo->mppe_40 ? MPPE_40BIT : 0) |
-+			    (wo->mppe_56 ? MPPE_56BIT : 0) |
-+			    (wo->mppe_128 ? MPPE_128BIT : 0) |
-+			    (wo->mppc ? MPPE_MPPC : 0);
-+		    } else {
-+			ho->mppe = ho->mppe_stateless = 0;
- 		    }
- 		} else {
--		    /* Neither are set. */
-+		    /* MPPE is not compatible with other compression types */
-+		    if (wo->mppe) {
-+			ao->bsd_compress = 0;
-+			ao->predictor_1 = 0;
-+			ao->predictor_2 = 0;
-+			ao->deflate = 0;
-+			ao->lzs = 0;
-+		    }
-+		}
-+		if ((!ho->mppc || !ao->mppc) && !ho->mppe) {
-+		    p[2] = p2;
-+		    p[5] = p5;
- 		    newret = CONFREJ;
- 		    break;
- 		}
- 
--		/* rebuild the opts */
--		MPPE_OPTS_TO_CI(ho->mppe, &p[2]);
--		if (newret == CONFACK) {
--		    u_char opt_buf[CILEN_MPPE + MPPE_MAX_KEY_LEN];
--		    int mtu;
--
--		    BCOPY(p, opt_buf, CILEN_MPPE);
--		    BCOPY(mppe_send_key, &opt_buf[CILEN_MPPE],
--			  MPPE_MAX_KEY_LEN);
--		    if (ccp_test(f->unit, opt_buf,
--				 CILEN_MPPE + MPPE_MAX_KEY_LEN, 1) <= 0) {
--			/* This shouldn't happen, we've already tested it! */
--			error("MPPE required, but kernel has no support.");
--			lcp_close(f->unit, "MPPE required but not available");
--			newret = CONFREJ;
--			break;
--		    }
--		    /*
--		     * We need to decrease the interface MTU by MPPE_PAD
--		     * because MPPE frames **grow**.  The kernel [must]
--		     * allocate MPPE_PAD extra bytes in xmit buffers.
--		     */
--		    mtu = netif_get_mtu(f->unit);
--		    if (mtu)
--			netif_set_mtu(f->unit, mtu - MPPE_PAD);
--		    else
--			newret = CONFREJ;
--		}
-+		/*
-+		 * I have commented the code below because according to RFC1547
-+		 * MTU is only information for higher level protocols about
-+		 * "the maximum allowable length for a packet (q.v.) transmitted
-+		 * over a point-to-point link without incurring network layer
-+		 * fragmentation." Of course a PPP implementation should be able
-+		 * to handle overhead added by MPPE - in our case apropriate code
-+		 * is located in drivers/net/ppp_generic.c in the kernel sources.
-+		 *
-+		 * According to RFC1661:
-+		 * - when negotiated MRU is less than 1500 octets, a PPP
-+		 *   implementation must still be able to receive at least 1500
-+		 *   octets,
-+		 * - when PFC is negotiated, a PPP implementation is still
-+		 *   required to receive frames with uncompressed protocol field.
-+		 *
-+		 * So why not to handle MPPE overhead without changing MTU value?
-+		 * I am sure that RFC3078, unfortunately silently, assumes that.
-+		 */
- 
- 		/*
--		 * We have accepted MPPE or are willing to negotiate
--		 * MPPE parameters.  A CONFREJ is due to subsequent
--		 * (non-MPPE) processing.
-+		 * We need to decrease the interface MTU by MPPE_PAD
-+		 * because MPPE frames **grow**.  The kernel [must]
-+		 * allocate MPPE_PAD extra bytes in xmit buffers.
- 		 */
--		rej_for_ci_mppe = 0;
-+/*
-+		mtu = netif_get_mtu(f->unit);
-+		if (mtu) {
-+		    netif_set_mtu(f->unit, mtu - MPPE_PAD);
-+		} else {
-+		    newret = CONFREJ;
-+		    if (ccp_wantoptions[f->unit].mppe) {
-+			error("Cannot adjust MTU needed by MPPE.");
-+			lcp_close(f->unit, "Cannot adjust MTU needed by MPPE.");
-+		    }
-+		}
-+*/
- 		break;
- #endif /* MPPE */
-+
-+	    case CI_LZS:
-+		if (!ao->lzs || clen != CILEN_LZS) {
-+		    newret = CONFREJ;
-+		    break;
-+		}
-+
-+		ho->lzs = 1;
-+		ho->lzs_hists = (p[2] << 8) | p[3];
-+		ho->lzs_mode = p[4];
-+		if ((ho->lzs_hists != ao->lzs_hists) ||
-+		    (ho->lzs_mode != ao->lzs_mode)) {
-+		    newret = CONFNAK;
-+		    if (!dont_nak) {
-+			p[2] = ao->lzs_hists >> 8;
-+			p[3] = ao->lzs_hists & 0xff;
-+			p[4] = ao->lzs_mode;
-+		    } else
-+			break;
-+		}
-+
-+		if (p == p0 && ccp_test(f->unit, p, CILEN_LZS, 1) <= 0) {
-+		    newret = CONFREJ;
-+		}
-+		break;
-+
- 	    case CI_DEFLATE:
- 	    case CI_DEFLATE_DRAFT:
- 		if (!ao->deflate || clen != CILEN_DEFLATE
-@@ -1340,12 +1832,6 @@
- 	else
- 	    *lenp = retp - p0;
-     }
--#ifdef MPPE
--    if (ret == CONFREJ && ao->mppe && rej_for_ci_mppe) {
--	error("MPPE required but peer negotiation failed");
--	lcp_close(f->unit, "MPPE required but peer negotiation failed");
--    }
--#endif
-     return ret;
- }
- 
-@@ -1367,24 +1853,35 @@
- 	char *p = result;
- 	char *q = result + sizeof(result); /* 1 past result */
- 
--	slprintf(p, q - p, "MPPE ");
--	p += 5;
--	if (opt->mppe & MPPE_OPT_128) {
--	    slprintf(p, q - p, "128-bit ");
--	    p += 8;
--	}
--	if (opt->mppe & MPPE_OPT_40) {
--	    slprintf(p, q - p, "40-bit ");
--	    p += 7;
--	}
--	if (opt->mppe & MPPE_OPT_STATEFUL)
--	    slprintf(p, q - p, "stateful");
--	else
--	    slprintf(p, q - p, "stateless");
--
-+	if (opt->mppe) {
-+	    if (opt->mppc) {
-+		slprintf(p, q - p, "MPPC/MPPE ");
-+		p += 10;
-+	    } else {
-+		slprintf(p, q - p, "MPPE ");
-+		p += 5;
-+	    }
-+	    if (opt->mppe_128) {
-+		slprintf(p, q - p, "128-bit ");
-+		p += 8;
-+	    } else if (opt->mppe_56) {
-+		slprintf(p, q - p, "56-bit ");
-+		p += 7;
-+	    } else if (opt->mppe_40) {
-+		slprintf(p, q - p, "40-bit ");
-+		p += 7;
-+	    }
-+	    if (opt->mppe_stateless)
-+		slprintf(p, q - p, "stateless");
-+	    else
-+		slprintf(p, q - p, "stateful");
-+	} else if (opt->mppc)
-+	    slprintf(p, q - p, "MPPC");
- 	break;
-     }
--#endif
-+#endif /* MPPE */
-+    case CI_LZS:
-+	return "Stac LZS";
-     case CI_DEFLATE:
-     case CI_DEFLATE_DRAFT:
- 	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
-@@ -1440,12 +1937,12 @@
-     } else if (ANY_COMPRESS(*ho))
- 	notice("%s transmit compression enabled", method_name(ho, NULL));
- #ifdef MPPE
--    if (go->mppe) {
-+    if (go->mppe || go->mppc) {
- 	BZERO(mppe_recv_key, MPPE_MAX_KEY_LEN);
- 	BZERO(mppe_send_key, MPPE_MAX_KEY_LEN);
- 	continue_networks(f->unit);		/* Bring up IP et al */
-     }
--#endif
-+#endif /* MPPE */
- }
- 
- /*
-@@ -1468,7 +1965,7 @@
- 	    lcp_close(f->unit, "MPPE disabled");
- 	}
-     }
--#endif
-+#endif /* MPPE */
- }
- 
- /*
-@@ -1528,24 +2025,28 @@
- #ifdef MPPE
- 	    case CI_MPPE:
- 		if (optlen >= CILEN_MPPE) {
--		    u_char mppe_opts;
--
--		    MPPE_CI_TO_OPTS(&p[2], mppe_opts);
--		    printer(arg, "mppe %s %s %s %s %s %s%s",
--			    (p[2] & MPPE_H_BIT)? "+H": "-H",
--			    (p[5] & MPPE_M_BIT)? "+M": "-M",
--			    (p[5] & MPPE_S_BIT)? "+S": "-S",
--			    (p[5] & MPPE_L_BIT)? "+L": "-L",
-+		    printer(arg, "mppe %s %s %s %s %s %s",
-+			    (p[2] & MPPE_STATELESS)? "+H": "-H",
-+			    (p[5] & MPPE_56BIT)? "+M": "-M",
-+			    (p[5] & MPPE_128BIT)? "+S": "-S",
-+			    (p[5] & MPPE_40BIT)? "+L": "-L",
- 			    (p[5] & MPPE_D_BIT)? "+D": "-D",
--			    (p[5] & MPPE_C_BIT)? "+C": "-C",
--			    (mppe_opts & MPPE_OPT_UNKNOWN)? " +U": "");
--		    if (mppe_opts & MPPE_OPT_UNKNOWN)
-+			    (p[5] & MPPE_MPPC)? "+C": "-C");
-+		    if ((p[5] & ~(MPPE_56BIT | MPPE_128BIT | MPPE_40BIT |
-+				  MPPE_D_BIT | MPPE_MPPC)) ||
-+			(p[2] & ~MPPE_STATELESS))
- 			printer(arg, " (%.2x %.2x %.2x %.2x)",
- 				p[2], p[3], p[4], p[5]);
- 		    p += CILEN_MPPE;
- 		}
- 		break;
--#endif
-+#endif /* MPPE */
-+	    case CI_LZS:
-+		if (optlen >= CILEN_LZS) {
-+		    printer(arg, "lzs %.2x %.2x %.2x", p[2], p[3], p[4]);
-+		    p += CILEN_LZS;
-+		}
-+		break;
- 	    case CI_DEFLATE:
- 	    case CI_DEFLATE_DRAFT:
- 		if (optlen >= CILEN_DEFLATE) {
-@@ -1631,6 +2132,7 @@
- 	    error("Lost compression sync: disabling compression");
- 	    ccp_close(unit, "Lost compression sync");
- #ifdef MPPE
-+	    /* My module dosn't need this. J.D., 2003-07-06 */
- 	    /*
- 	     * If we were doing MPPE, we must also take the link down.
- 	     */
-@@ -1638,9 +2140,18 @@
- 		error("Too many MPPE errors, closing LCP");
- 		lcp_close(unit, "Too many MPPE errors");
- 	    }
--#endif
-+#endif /* MPPE */
- 	} else {
- 	    /*
-+	     * When LZS or MPPE/MPPC is negotiated we just send CCP_RESETREQ
-+	     * and don't wait for CCP_RESETACK
-+	     */
-+	    if ((ccp_gotoptions[f->unit].method == CI_LZS) ||
-+		(ccp_gotoptions[f->unit].method == CI_MPPE)) {
-+		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
-+		return;
-+	    }
-+	    /*
- 	     * 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.
-@@ -1671,4 +2182,3 @@
-     } else
- 	ccp_localstate[f->unit] &= ~RACK_PENDING;
- }
--
-diff -ruN ppp-2.4.3.orig/pppd/ccp.h ppp-2.4.3/pppd/ccp.h
---- ppp-2.4.3.orig/pppd/ccp.h	2004-11-04 11:02:26.000000000 +0100
-+++ ppp-2.4.3/pppd/ccp.h	2004-11-21 13:54:09.000000000 +0100
-@@ -37,9 +37,17 @@
-     bool predictor_2;		/* do Predictor-2? */
-     bool deflate_correct;	/* use correct code for deflate? */
-     bool deflate_draft;		/* use draft RFC code for deflate? */
-+    bool lzs;			/* do Stac LZS? */
-+    bool mppc;			/* do MPPC? */
-     bool mppe;			/* do MPPE? */
-+    bool mppe_40;		/* allow 40 bit encryption? */
-+    bool mppe_56;		/* allow 56 bit encryption? */
-+    bool mppe_128;		/* allow 128 bit encryption? */
-+    bool mppe_stateless;	/* allow stateless encryption */
-     u_short bsd_bits;		/* # bits/code for BSD Compress */
-     u_short deflate_size;	/* lg(window size) for Deflate */
-+    u_short lzs_mode;		/* LZS check mode */
-+    u_short lzs_hists;		/* number of LZS histories */
-     short method;		/* code for chosen compression method */
- } ccp_options;
- 
-diff -ruN ppp-2.4.3.orig/pppd/chap_ms.c ppp-2.4.3/pppd/chap_ms.c
---- ppp-2.4.3.orig/pppd/chap_ms.c	2004-11-12 10:57:43.000000000 +0100
-+++ ppp-2.4.3/pppd/chap_ms.c	2004-11-21 13:54:09.000000000 +0100
-@@ -895,13 +895,17 @@
-     /*
-      * Disable undesirable encryption types.  Note that we don't ENABLE
-      * any encryption types, to avoid overriding manual configuration.
-+     *
-+     * It seems that 56 bit keys are unsupported in MS-RADIUS (see RFC 2548)
-      */
-     switch(types) {
- 	case MPPE_ENC_TYPES_RC4_40:
--	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
-+	    ccp_wantoptions[0].mppe_128 = 0;	/* disable 128-bit */
-+	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
- 	    break;
- 	case MPPE_ENC_TYPES_RC4_128:
--	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
-+	    ccp_wantoptions[0].mppe_56 = 0;	/* disable 56-bit */
-+	    ccp_wantoptions[0].mppe_40 = 0;	/* disable 40-bit */
- 	    break;
- 	default:
- 	    break;
-diff -ruN ppp-2.4.3.orig/pppd/pppd.8 ppp-2.4.3/pppd/pppd.8
---- ppp-2.4.3.orig/pppd/pppd.8	2004-11-13 13:22:49.000000000 +0100
-+++ ppp-2.4.3/pppd/pppd.8	2004-11-21 14:24:47.000000000 +0100
-@@ -622,9 +622,29 @@
- Enables the use of PPP multilink; this is an alias for the `multilink'
- option.  This option is currently only available under Linux.
- .TP
--.B mppe\-stateful
--Allow MPPE to use stateful mode.  Stateless mode is still attempted first.
--The default is to disallow stateful mode.  
-+.B mppc
-+Enables MPPC (Microsoft Point to Point Compression).  This is the default.
-+.TP
-+.B mppe \fIsubopt1[,subopt2[,subopt3[..]]]
-+Modify MPPE (Microsoft Point to Point Encryption) parameters. In order
-+for MPPE to successfully come up, you must have authenticated with either
-+MS-CHAP or MS-CHAPv2. By default MPPE is optional, it means that pppd will
-+not propose MPPE to the peer, but will negotiate MPPE if peer wants that.
-+You can change this using \fIrequired\fR suboption.
-+This option is presently only supported under Linux, and only if your
-+kernel has been configured to include MPPE support.
-+.IP
-+MPPE suboptions:
-+.br
-+\fIrequired\fR - require MPPE; disconnect if peer doesn't support it,
-+.br
-+\fIstateless\fR - try to negotiate stateless mode; default is stateful,
-+.br
-+\fIno40\fR - disable 40 bit keys,
-+.br
-+\fIno56\fR - disable 56 bit keys,
-+.br
-+\fIno128\fR - disable 128 bit keys
- .TP
- .B mpshortseq
- Enables the use of short (12-bit) sequence numbers in multilink
-@@ -757,17 +777,11 @@
- Disables the use of PPP multilink.  This option is currently only
- available under Linux.
- .TP
--.B nomppe
--Disables MPPE (Microsoft Point to Point Encryption).  This is the default.
--.TP
--.B nomppe\-40
--Disable 40-bit encryption with MPPE.
-+.B nomppc
-+Disables MPPC (Microsoft Point to Point Compression).
- .TP
--.B nomppe\-128
--Disable 128-bit encryption with MPPE.
--.TP
--.B nomppe\-stateful
--Disable MPPE stateful mode.  This is the default.
-+.B nomppe
-+Disables MPPE (Microsoft Point to Point Encryption).
- .TP
- .B nompshortseq
- Disables the use of short (12-bit) sequence numbers in the PPP
-@@ -948,19 +962,6 @@
- Require the peer to authenticate itself using CHAP [Challenge
- Handshake Authentication Protocol] authentication.
- .TP
--.B require\-mppe
--Require the use of MPPE (Microsoft Point to Point Encryption).  This
--option disables all other compression types.  This option enables
--both 40-bit and 128-bit encryption.  In order for MPPE to successfully
--come up, you must have authenticated with either MS\-CHAP or MS\-CHAPv2.
--This option is presently only supported under Linux, and only if your
--kernel has been configured to include MPPE support.
--.TP
--.B require\-mppe\-40
--Require the use of MPPE, with 40-bit encryption.
--.TP
--.B require\-mppe\-128
--Require the use of MPPE, with 128-bit encryption.
- .TP
- .B require\-mschap
- Require the peer to authenticate itself using MS\-CHAP [Microsoft Challenge
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-no-atm.patch b/openwrt/package/ppp/patches/ppp-2.4.3-no-atm.patch
deleted file mode 100644
index a737cfa23a..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-no-atm.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ruN ppp-2.4.3-orig/pppd/plugins/Makefile.linux ppp-2.4.3-3/pppd/plugins/Makefile.linux
---- ppp-2.4.3-orig/pppd/plugins/Makefile.linux	2004-11-14 08:57:35.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/Makefile.linux	2004-12-05 17:03:59.000000000 +0100
-@@ -9,7 +9,7 @@
- MANDIR = $(DESTDIR)/share/man/man8
- LIBDIR = $(DESTDIR)/lib/pppd/$(VERSION)
- 
--SUBDIRS := rp-pppoe pppoatm radius
-+SUBDIRS := rp-pppoe radius
- # Uncomment the next line to include the radius authentication plugin
- # SUBDIRS += radius
- PLUGINS := minconn.so passprompt.so passwordfd.so winbind.so
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-no-strip.patch b/openwrt/package/ppp/patches/ppp-2.4.3-no-strip.patch
deleted file mode 100644
index 216973cf59..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-no-strip.patch
+++ /dev/null
@@ -1,86 +0,0 @@
-diff -ruN ppp-2.4.3-orig/chat/Makefile.linux ppp-2.4.3-3/chat/Makefile.linux
---- ppp-2.4.3-orig/chat/Makefile.linux	2004-11-03 12:51:47.000000000 +0100
-+++ ppp-2.4.3-3/chat/Makefile.linux	2004-12-05 17:42:43.000000000 +0100
-@@ -25,7 +25,7 @@
- 
- install: chat
- 	mkdir -p $(BINDIR)
--	$(INSTALL) -s -c chat $(BINDIR)
-+	$(INSTALL) -c chat $(BINDIR)
- 	$(INSTALL) -c -m 644 chat.8 $(MANDIR)
- 
- clean:
-diff -ruN ppp-2.4.3-orig/pppd/Makefile.linux ppp-2.4.3-3/pppd/Makefile.linux
---- ppp-2.4.3-orig/pppd/Makefile.linux	2004-11-13 13:02:22.000000000 +0100
-+++ ppp-2.4.3-3/pppd/Makefile.linux	2004-12-16 04:43:41.000000000 +0100
-@@ -99,7 +99,7 @@
- CFLAGS	+= -DUSE_SRP -DOPENSSL -I/usr/local/ssl/include
- LIBS	+= -lsrp -L/usr/local/ssl/lib -lcrypto
- TARGETS	+= srp-entry
--EXTRAINSTALL = $(INSTALL) -s -c -m 555 srp-entry $(BINDIR)/srp-entry
-+EXTRAINSTALL = $(INSTALL) -c -m 555 srp-entry $(BINDIR)/srp-entry
- MANPAGES += srp-entry.8
- EXTRACLEAN += srp-entry.o
- NEEDDES=y
-@@ -202,7 +202,7 @@
- install: pppd
- 	mkdir -p $(BINDIR) $(MANDIR)
- 	$(EXTRAINSTALL)
--	$(INSTALL) -s -c -m 555 pppd $(BINDIR)/pppd
-+	$(INSTALL) -c -m 555 pppd $(BINDIR)/pppd
- 	if chgrp pppusers $(BINDIR)/pppd 2>/dev/null; then \
- 	  chmod o-rx,u+s $(BINDIR)/pppd; fi
- 	$(INSTALL) -c -m 444 pppd.8 $(MANDIR)
-diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux
---- ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux	2004-11-14 08:02:31.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux	2004-12-05 17:43:17.000000000 +0100
-@@ -36,9 +37,9 @@
- 
- install: all
- 	$(INSTALL) -d -m 755 $(LIBDIR)
--	$(INSTALL) -s -c -m 755 radius.so $(LIBDIR)
--	$(INSTALL) -s -c -m 755 radattr.so $(LIBDIR)
--	$(INSTALL) -s -c -m 755 radrealms.so $(LIBDIR)
-+	$(INSTALL) -c -m 755 radius.so $(LIBDIR)
-+	$(INSTALL) -c -m 755 radattr.so $(LIBDIR)
-+	$(INSTALL) -c -m 755 radrealms.so $(LIBDIR)
- 	$(INSTALL) -c -m 444 pppd-radius.8 $(MANDIR)
- 	$(INSTALL) -c -m 444 pppd-radattr.8 $(MANDIR)
- 
-diff -ruN ppp-2.4.3-orig/pppd/plugins/rp-pppoe/Makefile.linux ppp-2.4.3-3/pppd/plugins/rp-pppoe/Makefile.linux
---- ppp-2.4.3-orig/pppd/plugins/rp-pppoe/Makefile.linux	2004-11-14 08:58:37.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/rp-pppoe/Makefile.linux	2004-12-05 17:43:23.000000000 +0100
-@@ -39,9 +39,9 @@
- 
- install: all
- 	$(INSTALL) -d -m 755 $(LIBDIR)
--	$(INSTALL) -s -c -m 4550 rp-pppoe.so $(LIBDIR)
-+	$(INSTALL) -c -m 4550 rp-pppoe.so $(LIBDIR)
- 	$(INSTALL) -d -m 755 $(BINDIR)
--	$(INSTALL) -s -c -m 555 pppoe-discovery $(BINDIR)
-+	$(INSTALL) -c -m 555 pppoe-discovery $(BINDIR)
- 
- clean:
- 	rm -f *.o *.so
-diff -ruN ppp-2.4.3-orig/pppdump/Makefile.linux ppp-2.4.3-3/pppdump/Makefile.linux
---- ppp-2.4.3-orig/pppdump/Makefile.linux	2004-10-31 02:36:52.000000000 +0200
-+++ ppp-2.4.3-3/pppdump/Makefile.linux	2004-12-05 17:50:34.000000000 +0100
-@@ -17,5 +18,5 @@
- 
- install:
- 	mkdir -p $(BINDIR) $(MANDIR)
--	$(INSTALL) -s -c pppdump $(BINDIR)
-+	$(INSTALL) -c pppdump $(BINDIR)
- 	$(INSTALL) -c -m 444 pppdump.8 $(MANDIR)
-diff -ruN ppp-2.4.3-orig/pppstats/Makefile.linux ppp-2.4.3-3/pppstats/Makefile.linux
---- ppp-2.4.3-orig/pppstats/Makefile.linux	2004-10-31 23:09:03.000000000 +0100
-+++ ppp-2.4.3-3/pppstats/Makefile.linux	2004-12-05 17:43:38.000000000 +0100
-@@ -22,7 +22,7 @@
- 
- install: pppstats
- 	-mkdir -p $(MANDIR)
--	$(INSTALL) -s -c pppstats $(BINDIR)
-+	$(INSTALL) -c pppstats $(BINDIR)
- 	$(INSTALL) -c -m 444 pppstats.8 $(MANDIR)
- 
- pppstats: $(PPPSTATSRCS)
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-opt-flags.patch b/openwrt/package/ppp/patches/ppp-2.4.3-opt-flags.patch
deleted file mode 100644
index 200e76b5b5..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-opt-flags.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux
---- ppp-2.4.3-orig/pppd/plugins/radius/Makefile.linux	2004-11-14 08:02:31.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/radius/Makefile.linux	2004-12-05 17:43:17.000000000 +0100
-@@ -12,7 +12,8 @@
- INSTALL	= install
- 
- PLUGIN=radius.so radattr.so radrealms.so
--CFLAGS=-I. -I../.. -I../../../include -O2 -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
-+COPTS = -O2
-+CFLAGS=-I. -I../.. -I../../../include $(COPTS) -fPIC -DRC_LOG_FACILITY=LOG_DAEMON
- 
- # Uncomment the next line to include support for Microsoft's
- # MS-CHAP authentication protocol.
-diff -ruN ppp-2.4.3-orig/pppdump/Makefile.linux ppp-2.4.3-3/pppdump/Makefile.linux
---- ppp-2.4.3-orig/pppdump/Makefile.linux	2004-10-31 02:36:52.000000000 +0200
-+++ ppp-2.4.3-3/pppdump/Makefile.linux	2004-12-05 17:50:34.000000000 +0100
-@@ -2,7 +2,8 @@
- BINDIR = $(DESTDIR)/sbin
- MANDIR = $(DESTDIR)/share/man/man8
- 
--CFLAGS= -O -I../include/net
-+COPTS = -O
-+CFLAGS= $(COPTS) -I../include/net
- OBJS = pppdump.o bsd-comp.o deflate.o zlib.o
- 
- INSTALL= install
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-pppoe-iface-name.patch b/openwrt/package/ppp/patches/ppp-2.4.3-pppoe-iface-name.patch
deleted file mode 100644
index 522d5878a4..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-pppoe-iface-name.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -ruN ppp-2.4.3-orig/pppd/plugins/rp-pppoe/plugin.c ppp-2.4.3-3/pppd/plugins/rp-pppoe/plugin.c
---- ppp-2.4.3-orig/pppd/plugins/rp-pppoe/plugin.c	2004-11-04 11:07:37.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/rp-pppoe/plugin.c	2004-12-16 01:07:22.000000000 +0100
-@@ -286,7 +286,7 @@
- 	/* Strip off "nic-" */
- 	cmd += 4;
-     } else if (strlen(cmd) < 4
--	       || (strncmp(cmd, "eth", 3) && strncmp(cmd, "nas", 3)
-+	       || (strncmp(cmd, "eth", 3) && strncmp(cmd, "nas", 3) && strncmp(cmd, "vlan", 4)
- 		   && strncmp(cmd, "tap", 3) && strncmp(cmd, "br", 2))) {
- 	return 0;
-     }
diff --git a/openwrt/package/ppp/patches/ppp-2.4.3-radius-config.patch b/openwrt/package/ppp/patches/ppp-2.4.3-radius-config.patch
deleted file mode 100644
index 90c02af4c1..0000000000
--- a/openwrt/package/ppp/patches/ppp-2.4.3-radius-config.patch
+++ /dev/null
@@ -1,74 +0,0 @@
-diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/config.c ppp-2.4.3-3/pppd/plugins/radius/config.c
---- ppp-2.4.3-orig/pppd/plugins/radius/config.c	2004-11-14 08:26:26.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/radius/config.c	2004-12-16 04:03:46.000000000 +0100
-@@ -369,31 +369,37 @@
- 	}
- #endif
- 
-+#if 0
- 	if (rc_conf_int("login_tries") <= 0)
- 	{
- 		error("%s: login_tries <= 0 is illegal", filename);
- 		return (-1);
- 	}
-+#endif
- 	if (rc_conf_str("seqfile") == NULL)
- 	{
- 		error("%s: seqfile not specified", filename);
- 		return (-1);
- 	}
-+#if 0
- 	if (rc_conf_int("login_timeout") <= 0)
- 	{
- 		error("%s: login_timeout <= 0 is illegal", filename);
- 		return (-1);
- 	}
-+#endif
- 	if (rc_conf_str("mapfile") == NULL)
- 	{
- 		error("%s: mapfile not specified", filename);
- 		return (-1);
- 	}
-+#if 0
- 	if (rc_conf_str("nologin") == NULL)
- 	{
- 		error("%s: nologin not specified", filename);
- 		return (-1);
- 	}
-+#endif
- 
- 	return 0;
- }
-diff -ruN ppp-2.4.3-orig/pppd/plugins/radius/options.h ppp-2.4.3-3/pppd/plugins/radius/options.h
---- ppp-2.4.3-orig/pppd/plugins/radius/options.h	2004-11-14 08:26:26.000000000 +0100
-+++ ppp-2.4.3-3/pppd/plugins/radius/options.h	2004-12-16 04:09:16.000000000 +0100
-@@ -31,24 +31,21 @@
- static SERVER acctserver = {0};
- static SERVER authserver = {0};
- 
--int default_tries = 4;
--int default_timeout = 60;
--
- static OPTION config_options[] = {
- /* internally used options */
- {"config_file",		OT_STR, ST_UNDEF, NULL},
- /* General options */
- {"auth_order",	 	OT_AUO, ST_UNDEF, NULL},
--{"login_tries",	 	OT_INT, ST_UNDEF, &default_tries},
--{"login_timeout",	OT_INT, ST_UNDEF, &default_timeout},
--{"nologin",		OT_STR, ST_UNDEF, "/etc/nologin"},
--{"issue",		OT_STR, ST_UNDEF, "/etc/radiusclient/issue"},
-+{"login_tries",	 	OT_INT, ST_UNDEF, NULL},
-+{"login_timeout",	OT_INT, ST_UNDEF, NULL},
-+{"nologin",		OT_STR, ST_UNDEF, NULL},
-+{"issue",		OT_STR, ST_UNDEF, NULL},
- /* RADIUS specific options */
- {"authserver",		OT_SRV, ST_UNDEF, &authserver},
- {"acctserver",		OT_SRV, ST_UNDEF, &acctserver},
- {"servers",		OT_STR, ST_UNDEF, NULL},
- {"dictionary",		OT_STR, ST_UNDEF, NULL},
--{"login_radius",	OT_STR, ST_UNDEF, "/usr/sbin/login.radius"},
-+{"login_radius",	OT_STR, ST_UNDEF, NULL},
- {"seqfile",		OT_STR, ST_UNDEF, NULL},
- {"mapfile",		OT_STR, ST_UNDEF, NULL},
- {"default_realm",	OT_STR, ST_UNDEF, NULL},