[rtems-libbsd commit] ppp: Import from RTEMS sources

Sebastian Huber sebh at rtems.org
Wed Oct 8 13:06:49 UTC 2014


Module:    rtems-libbsd
Branch:    master
Commit:    70fa95a2e888475a51cf6cbdca26947a65e59716
Changeset: http://git.rtems.org/rtems-libbsd/commit/?id=70fa95a2e888475a51cf6cbdca26947a65e59716

Author:    Sebastian Huber <sebastian.huber at embedded-brains.de>
Date:      Tue Sep 30 14:46:12 2014 +0200

ppp: Import from RTEMS sources

---

 rtemsbsd/include/rtems/bsd/local/opt_ppp.h |   10 +
 rtemsbsd/include/rtems/rtemsdialer.h       |   24 +
 rtemsbsd/include/rtems/rtemspppd.h         |   49 +
 rtemsbsd/pppd/auth.c                       | 1128 ++++++++++++++++
 rtemsbsd/pppd/cbcp.c                       |  456 +++++++
 rtemsbsd/pppd/cbcp.h                       |   26 +
 rtemsbsd/pppd/ccp.c                        | 1228 +++++++++++++++++
 rtemsbsd/pppd/ccp.h                        |   48 +
 rtemsbsd/pppd/chap.c                       |  858 ++++++++++++
 rtemsbsd/pppd/chap.h                       |  124 ++
 rtemsbsd/pppd/chap_ms.c                    |  338 +++++
 rtemsbsd/pppd/chap_ms.h                    |   33 +
 rtemsbsd/pppd/chat.c                       |  854 ++++++++++++
 rtemsbsd/pppd/demand.c                     |  347 +++++
 rtemsbsd/pppd/fsm.c                        |  764 +++++++++++
 rtemsbsd/pppd/fsm.h                        |  144 ++
 rtemsbsd/pppd/ipcp.c                       | 1772 +++++++++++++++++++++++++
 rtemsbsd/pppd/ipcp.h                       |   73 +
 rtemsbsd/pppd/lcp.c                        | 1953 ++++++++++++++++++++++++++++
 rtemsbsd/pppd/lcp.h                        |   88 ++
 rtemsbsd/pppd/magic.c                      |   58 +
 rtemsbsd/pppd/magic.h                      |   23 +
 rtemsbsd/pppd/options.c                    | 1519 +++++++++++++++++++++
 rtemsbsd/pppd/patchlevel.h                 |    6 +
 rtemsbsd/pppd/pathnames.h                  |   43 +
 rtemsbsd/pppd/pppd.h                       |  663 ++++++++++
 rtemsbsd/pppd/rtemsmain.c                  |  896 +++++++++++++
 rtemsbsd/pppd/rtemspppd.c                  |  228 ++++
 rtemsbsd/pppd/sys-rtems.c                  | 1340 +++++++++++++++++++
 rtemsbsd/pppd/upap.c                       |  631 +++++++++
 rtemsbsd/pppd/upap.h                       |   87 ++
 rtemsbsd/pppd/utils.c                      |  827 ++++++++++++
 rtemsbsd/sys/net/if_ppp.c                  | 1765 +++++++++++++++++++++++++
 rtemsbsd/sys/net/if_ppp.h                  |  141 ++
 rtemsbsd/sys/net/if_pppvar.h               |  161 +++
 rtemsbsd/sys/net/ppp_comp.h                |  165 +++
 rtemsbsd/sys/net/ppp_defs.h                |  159 +++
 rtemsbsd/sys/net/ppp_tty.c                 |  954 ++++++++++++++
 38 files changed, 19983 insertions(+), 0 deletions(-)

diff --git a/rtemsbsd/include/rtems/bsd/local/opt_ppp.h b/rtemsbsd/include/rtems/bsd/local/opt_ppp.h
new file mode 100644
index 0000000..37e2068
--- /dev/null
+++ b/rtemsbsd/include/rtems/bsd/local/opt_ppp.h
@@ -0,0 +1,10 @@
+#ifndef _PPP_H_
+#define _PPP_H_
+
+#define NPPP        1
+#define NBPFILTER   0
+#undef  VJC
+#undef  PPP_FILTER
+#undef  PPP_COMPRESS
+
+#endif
diff --git a/rtemsbsd/include/rtems/rtemsdialer.h b/rtemsbsd/include/rtems/rtemsdialer.h
new file mode 100644
index 0000000..611986b
--- /dev/null
+++ b/rtemsbsd/include/rtems/rtemsdialer.h
@@ -0,0 +1,24 @@
+
+#ifndef DIALER_H
+#define DIALER_H
+
+/* define constant mode values */
+#define DIALER_INIT         0
+#define DIALER_CONNECT      1
+#define DIALER_WELCOME      2
+#define DIALER_DISCONNECT   3
+
+/* define constant return values */
+#define DIALER_SUCCESS      0
+#define DIALER_INVALIDARG   1
+#define DIALER_UNEXPECTED   2
+#define DIALER_TIMEOUT      3
+#define DIALER_CMDFAILED    4
+
+/* define typedef for dialer function prototype */
+typedef int  (*dialerfp)(int tty, int mode, char *pScript);
+
+/* declare default chat program dialer */
+extern int chatmain(int tty, int mode, char *pScript);
+
+#endif
diff --git a/rtemsbsd/include/rtems/rtemspppd.h b/rtemsbsd/include/rtems/rtemspppd.h
new file mode 100644
index 0000000..a6c8d0b
--- /dev/null
+++ b/rtemsbsd/include/rtems/rtemspppd.h
@@ -0,0 +1,49 @@
+/*
+ * COPYRIGHT (c) 2001, Michael Siers <mikes at poliac.com>.
+ *                     Poliac Research, Burnsville, Minnesota USA.
+ * COPYRIGHT (c) 2001, On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef RTEMSPPPD_H
+#define RTEMSPPPD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* define hook function identifiers */
+#define RTEMS_PPPD_LINKUP_HOOK      1
+#define RTEMS_PPPD_LINKDOWN_HOOK    2
+#define RTEMS_PPPD_IPUP_HOOK        3
+#define RTEMS_PPPD_IPDOWN_HOOK      4
+#define RTEMS_PPPD_ERROR_HOOK       5
+#define RTEMS_PPPD_EXIT_HOOK        6
+
+/* define hook function pointer prototype */
+typedef void (*rtems_pppd_hookfunction)(void);
+typedef int  (*rtems_pppd_dialerfunction)(int tty, int mode, char *pScript);
+
+
+/* define pppd function prototyes */
+int rtems_pppd_initialize(void);
+int rtems_pppd_terminate(void);
+int rtems_pppd_reset_options(void);
+int rtems_pppd_set_hook(int id, rtems_pppd_hookfunction hookfp);
+int rtems_pppd_set_dialer(rtems_pppd_dialerfunction dialerfp);
+int rtems_pppd_set_option(const char *pOption, const char *pValue);
+int rtems_pppd_connect(void);
+int rtems_pppd_disconnect(void);
+
+struct rtems_bsdnet_ifconfig;
+
+int rtems_ppp_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/rtemsbsd/pppd/auth.c b/rtemsbsd/pppd/auth.c
new file mode 100644
index 0000000..fb84f1e
--- /dev/null
+++ b/rtemsbsd/pppd/auth.c
@@ -0,0 +1,1128 @@
+/*
+ * auth.c - PPP authentication and phase control.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#if defined(_PATH_LASTLOG) && defined(_linux_)
+#include <lastlog.h>
+#endif
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#ifdef USE_PAM
+#include <security/pam_appl.h>
+#endif
+
+#ifdef HAS_SHADOW
+#include <shadow.h>
+#ifndef PW_PPP
+#define PW_PPP PW_LOGIN
+#endif
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+#include "pathnames.h"
+
+static const char rcsid[] = RCSID;
+
+/* The name by which the peer authenticated itself to us. */
+char peer_authname[MAXNAMELEN];
+
+/* Records which authentication operations haven't completed yet. */
+static int auth_pending[NUM_PPP];
+
+/* List of addresses which the peer may use. */
+static struct permitted_ip *addresses[NUM_PPP];
+
+/* Wordlist giving addresses which the peer may use
+   without authenticating itself. */
+static struct wordlist *noauth_addrs;
+
+/* Extra options to apply, from the secrets file entry for the peer. */
+static struct wordlist *extra_options;
+
+/* Number of network protocols which we have opened. */
+static int num_np_open;
+
+/* Number of network protocols which have come up. */
+static int num_np_up;
+
+/* Set if we got the contents of passwd[] from the pap-secrets file. */
+static int passwd_from_file;
+
+/* Set if we require authentication only because we have a default route. */
+static bool default_auth;
+
+/* Hook for a link status */
+void (*auth_linkup_hook)(void) = NULL;
+void (*auth_linkdown_hook)(void) = NULL;
+
+/* Hook to enable a plugin to control the idle time limit */
+int (*idle_time_hook)(struct ppp_idle *) = NULL;
+
+/* Hook for a plugin to say whether we can possibly authenticate any peer */
+int (*pap_check_hook)(void) = NULL;
+
+/* Hook for a plugin to check the PAP user and password */
+int (*pap_auth_hook)(char *user, char *passwd/*, char **msgp,
+			  struct wordlist **paddrs,
+			  struct wordlist **popts*/) = NULL;
+
+/* Hook for a plugin to know about the PAP user logout */
+void (*pap_logout_hook)(void) = NULL;
+
+/* Hook for a plugin to get the PAP password for authenticating us */
+int (*pap_passwd_hook)(char *user, char *passwd) = NULL;
+
+/*
+ * This is used to ensure that we don't start an auth-up/down
+ * script while one is already running.
+ */
+enum script_state {
+    s_down,
+    s_up
+};
+
+static enum script_state auth_state = s_down;
+static enum script_state auth_script_state = s_down;
+
+/*
+ * Option variables.
+ */
+bool uselogin = 0;		/* Use /etc/passwd for checking PAP */
+bool cryptpap = 0;		/* Passwords in pap-secrets are encrypted */
+bool refuse_pap = 0;		/* Don't wanna auth. ourselves with PAP */
+bool refuse_chap = 0;		/* Don't wanna auth. ourselves with CHAP */
+bool usehostname = 0;		/* Use hostname for our_name */
+bool auth_required = 0;		/* Always require authentication from peer */
+bool allow_any_ip = 0;		/* Allow peer to use any IP address */
+bool explicit_remote = 0;	/* User specified explicit remote name */
+char remote_name[MAXNAMELEN];	/* Peer's name for authentication */
+
+/* Bits in auth_pending[] */
+#define PAP_WITHPEER	1
+#define PAP_PEER	2
+#define CHAP_WITHPEER	4
+#define CHAP_PEER	8
+
+extern char *crypt(const char *, const char *);
+
+/* Prototypes for procedures local to this file. */
+
+static void network_phase(int);
+static void check_idle(void *);
+static void connect_time_expired(void *);
+static int  null_login(int);
+static int  get_pap_passwd(char *);
+static int  have_pap_secret(int *);
+static int  have_chap_secret(char *, char *, int, int *);
+#if 0
+static int  ip_addr_check(uint32_t, struct permitted_ip *);
+#endif
+static void free_wordlist(struct wordlist *);
+static void auth_script(enum script_state s);
+static void set_allowed_addrs(int, struct wordlist *, struct wordlist *);
+
+
+/*
+ * Authentication-related options.
+ */
+option_t auth_options[] = {
+    { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer", 1, &auth_required, 0, 0 },
+    { "+pap", o_bool, &lcp_wantoptions[0].neg_upap,
+      "Require PAP authentication from peer", 1, &auth_required, 0, 0 },
+    { "refuse-pap", o_bool, &refuse_pap,
+      "Don't agree to auth to peer with PAP", 1, NULL, 0, 0 },
+    { "-pap", o_bool, &refuse_pap,
+      "Don't allow PAP authentication with peer", 1, NULL, 0, 0 },
+    { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer", 1, &auth_required, 0, 0 },
+    { "+chap", o_bool, &lcp_wantoptions[0].neg_chap,
+      "Require CHAP authentication from peer", 1, &auth_required, 0, 0 },
+    { "refuse-chap", o_bool, &refuse_chap,
+      "Don't agree to auth to peer with CHAP", 1, NULL, 0, 0 },
+    { "-chap", o_bool, &refuse_chap,
+      "Don't allow CHAP authentication with peer", 1, NULL, 0, 0 },
+    { "name", o_string, our_name,
+      "Set local name for authentication",
+      OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN, 0 },
+    { "user", o_string, user,
+      "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN, 0 },
+    { "usehostname", o_bool, &usehostname,
+      "Must use hostname for authentication", 1, NULL, 0, 0 },
+    { "remotename", o_string, remote_name,
+      "Set remote name for authentication", OPT_STATIC,
+      &explicit_remote, MAXNAMELEN, 0 },
+    { "auth", o_bool, &auth_required,
+      "Require authentication from peer", 1, NULL, 0, 0 },
+    { "noauth", o_bool, &auth_required,
+      "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip, 0, 0 },
+    {  "login", o_bool, &uselogin,
+      "Use system password database for PAP", 1, NULL, 0, 0 },
+    { "papcrypt", o_bool, &cryptpap,
+      "PAP passwords are encrypted", 1, NULL, 0, 0 },
+/* Removed for RTEMS PORT
+    { "+ua", o_special, setupapfile,
+      "Get PAP user and password from file" },
+*/
+    { "password", o_string, passwd,
+      "Password for authenticating us to the peer", OPT_STATIC,
+      NULL, MAXSECRETLEN, 0 },
+/* Removed for RTEMS_PORT
+    { "privgroup", o_special, privgroup,
+      "Allow group members to use privileged options", OPT_PRIV },
+    { "allow-ip", o_special, set_noauth_addr,
+      "Set IP address(es) which can be used without authentication",
+      OPT_PRIV },
+*/
+    { NULL, 0, NULL, NULL, 0,  NULL, 0, 0 }
+};
+
+/*
+ * An Open on LCP has requested a change from Dead to Establish phase.
+ * Do what's necessary to bring the physical layer up.
+ */
+void
+link_required(
+    int unit )
+{
+}
+
+/*
+ * LCP has terminated the link; go to the Dead phase and take the
+ * physical layer down.
+ */
+void
+link_terminated(
+    int unit)
+{
+    if (pppd_phase == PHASE_DEAD)
+	return;
+    if (pap_logout_hook) {
+	pap_logout_hook();
+    }
+    new_phase(PHASE_DEAD);
+    notice("Connection terminated.");
+}
+
+/*
+ * LCP has gone down; it will either die or try to re-establish.
+ */
+void
+link_down(
+    int unit)
+{
+    int i;
+    struct protent *protp;
+
+    auth_state = s_down;
+    if (auth_script_state == s_up) {
+	update_link_stats(unit);
+	auth_script(s_down);
+    }
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (!protp->enabled_flag)
+	    continue;
+        if (protp->protocol != PPP_LCP && protp->lowerdown != NULL)
+	    (*protp->lowerdown)(unit);
+        if (protp->protocol < 0xC000 && protp->close != NULL)
+	    (*protp->close)(unit, "LCP down");
+    }
+    num_np_open = 0;
+    num_np_up = 0;
+    if (pppd_phase != PHASE_DEAD)
+	new_phase(PHASE_TERMINATE);
+}
+
+/*
+ * The link is established.
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.
+ */
+void
+link_established(
+    int unit )
+{
+    int auth;
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ho = &lcp_hisoptions[unit];
+    int i;
+    struct protent *protp;
+
+    /*
+     * Tell higher-level protocols that LCP is up.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        if (protp->protocol != PPP_LCP && protp->enabled_flag
+	    && protp->lowerup != NULL)
+	    (*protp->lowerup)(unit);
+
+    if (auth_required && !(go->neg_chap || go->neg_upap)) {
+	/*
+	 * We wanted the peer to authenticate itself, and it refused:
+	 * if we have some address(es) it can use without auth, fine,
+	 * otherwise treat it as though it authenticated with PAP using
+	 * a username * of "" and a password of "".  If that's not OK,
+	 * boot it out.
+	 */
+	if (noauth_addrs != NULL) {
+	    set_allowed_addrs(unit, noauth_addrs, NULL);
+	} else if (!wo->neg_upap || !null_login(unit)) {
+	    warn("peer refused to authenticate: terminating link");
+	    lcp_close(unit, "peer refused to authenticate");
+	    pppd_status = EXIT_PEER_AUTH_FAILED;
+	    return;
+	}
+    }
+
+    new_phase(PHASE_AUTHENTICATE);
+    auth = 0;
+    if (go->neg_chap) {
+	ChapAuthPeer(unit, our_name, go->chap_mdtype);
+	auth |= CHAP_PEER;
+    } else if (go->neg_upap) {
+	upap_authpeer(unit);
+	auth |= PAP_PEER;
+    }
+    if (ho->neg_chap) {
+	ChapAuthWithPeer(unit, user, ho->chap_mdtype);
+	auth |= CHAP_WITHPEER;
+    } else if (ho->neg_upap) {
+	if (passwd[0] == 0) {
+	    passwd_from_file = 1;
+	    if (!get_pap_passwd(passwd))
+		error("No secret found for PAP login");
+	}
+	upap_authwithpeer(unit, user, passwd);
+	auth |= PAP_WITHPEER;
+    }
+    auth_pending[unit] = auth;
+
+    if (!auth)
+	network_phase(unit);
+}
+
+/*
+ * Proceed to the network phase.
+ */
+static void
+network_phase(
+    int unit )
+{
+#ifdef CBCP_SUPPORT
+    lcp_options *go = &lcp_gotoptions[unit];
+#endif
+
+    /* always run the auth-up script */
+    auth_state = s_up;
+    if (auth_script_state == s_down) {
+        auth_script(s_up);
+    }
+
+#ifdef CBCP_SUPPORT
+    /*
+     * If we negotiated callback, do it now.
+     */
+    if (go->neg_cbcp) {
+	new_phase(PHASE_CALLBACK);
+	(*cbcp_protent.open)(unit);
+	return;
+    }
+#endif
+
+    /*
+     * Process extra options from the secrets file
+     */
+    if (extra_options) {
+	options_from_list(extra_options, 1);
+	free_wordlist(extra_options);
+	extra_options = 0;
+    }
+    start_networks();
+}
+
+void
+start_networks(void)
+{
+    int i;
+    struct protent *protp;
+
+    new_phase(PHASE_NETWORK);
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        if (protp->protocol < 0xC000 && protp->enabled_flag
+	    && protp->open != NULL) {
+	    (*protp->open)(0);
+	    if (protp->protocol != PPP_CCP)
+		++num_np_open;
+	}
+
+    if (num_np_open == 0)
+	/* nothing to do */
+	lcp_close(0, "No network protocols running");
+}
+
+/*
+ * The peer has failed to authenticate himself using `protocol'.
+ */
+void
+auth_peer_fail(
+    int unit,
+    int protocol)
+{
+    /*
+     * Authentication failure: take the link down
+     */
+    lcp_close(unit, "Authentication failed");
+    pppd_status = EXIT_PEER_AUTH_FAILED;
+}
+
+/*
+ * The peer has been successfully authenticated using `protocol'.
+ */
+void
+auth_peer_success(
+    int unit,
+    int protocol,
+    char *name,
+    int namelen)
+{
+    int bit;
+
+    switch (protocol) {
+    case PPP_CHAP:
+	bit = CHAP_PEER;
+	break;
+    case PPP_PAP:
+	bit = PAP_PEER;
+	break;
+    default:
+	warn("auth_peer_success: unknown protocol %x", protocol);
+	return;
+    }
+
+    /*
+     * Save the authenticated name of the peer for later.
+     */
+    if (namelen > sizeof(peer_authname) - 1)
+	namelen = sizeof(peer_authname) - 1;
+    BCOPY(name, peer_authname, namelen);
+    peer_authname[namelen] = 0;
+
+    /*
+     * If there is no more authentication still to be done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~bit) == 0)
+        network_phase(unit);
+}
+
+/*
+ * We have failed to authenticate ourselves to the peer using `protocol'.
+ */
+void
+auth_withpeer_fail(
+    int unit,
+    int protocol )
+{
+    if (passwd_from_file)
+	BZERO(passwd, MAXSECRETLEN);
+    /*
+     * We've failed to authenticate ourselves to our peer.
+     * Some servers keep sending CHAP challenges, but there
+     * is no point in persisting without any way to get updated
+     * authentication secrets.
+     */
+    lcp_close(unit, "Failed to authenticate ourselves to peer");
+    pppd_status = EXIT_AUTH_TOPEER_FAILED;
+}
+
+/*
+ * We have successfully authenticated ourselves with the peer using `protocol'.
+ */
+void
+auth_withpeer_success(
+    int unit,
+    int protocol )
+{
+    int bit;
+
+    switch (protocol) {
+    case PPP_CHAP:
+	bit = CHAP_WITHPEER;
+	break;
+    case PPP_PAP:
+	if (passwd_from_file)
+	    BZERO(passwd, MAXSECRETLEN);
+	bit = PAP_WITHPEER;
+	break;
+    default:
+	warn("auth_withpeer_success: unknown protocol %x", protocol);
+	bit = 0;
+    }
+
+    /*
+     * If there is no more authentication still being done,
+     * proceed to the network (or callback) phase.
+     */
+    if ((auth_pending[unit] &= ~bit) == 0)
+	network_phase(unit);
+}
+
+
+/*
+ * np_up - a network protocol has come up.
+ */
+void
+np_up(
+    int unit,
+    int proto )
+{
+    int tlim;
+
+    if (num_np_up == 0) {
+	/*
+	 * At this point we consider that the link has come up successfully.
+	 */
+	pppd_status = EXIT_OK;
+	unsuccess = 0;
+	new_phase(PHASE_RUNNING);
+
+	if (idle_time_hook != 0)
+	    tlim = (*idle_time_hook)(NULL);
+	else
+	    tlim = idle_time_limit;
+	if (tlim > 0)
+	    TIMEOUT(check_idle, NULL, tlim);
+
+	/*
+	 * Set a timeout to close the connection once the maximum
+	 * connect time has expired.
+	 */
+	if (maxconnect > 0)
+	    TIMEOUT(connect_time_expired, 0, maxconnect);
+    }
+    ++num_np_up;
+}
+
+/*
+ * np_down - a network protocol has gone down.
+ */
+void
+np_down(
+    int unit,
+    int proto)
+{
+    if (--num_np_up == 0) {
+	UNTIMEOUT(check_idle, NULL);
+	new_phase(PHASE_NETWORK);
+    }
+}
+
+/*
+ * np_finished - a network protocol has finished using the link.
+ */
+void
+np_finished(
+    int unit,
+    int proto )
+{
+    if (--num_np_open <= 0) {
+	/* no further use for the link: shut up shop. */
+	lcp_close(0, "No network protocols running");
+    }
+}
+
+/*
+ * check_idle - check whether the link has been idle for long
+ * enough that we can shut it down.
+ */
+static void
+check_idle(
+    void *arg )
+{
+    struct ppp_idle idle;
+    time_t itime;
+    int tlim;
+
+    if (!get_idle_time(0, &idle))
+	return;
+    if (idle_time_hook != 0) {
+	tlim = idle_time_hook(&idle);
+    } else {
+	itime = MIN(idle.xmit_idle, idle.recv_idle);
+	tlim = idle_time_limit - itime;
+    }
+    if (tlim <= 0) {
+	/* link is idle: shut it down. */
+	notice("Terminating connection due to lack of activity.");
+	lcp_close(0, "Link inactive");
+	need_holdoff = 0;
+	pppd_status = EXIT_IDLE_TIMEOUT;
+    } else {
+	TIMEOUT(check_idle, NULL, tlim);
+    }
+}
+
+/*
+ * connect_time_expired - log a message and close the connection.
+ */
+static void
+connect_time_expired(
+    void *arg)
+{
+    info("Connect time expired");
+    lcp_close(0, "Connect time expired");	/* Close connection */
+    pppd_status = EXIT_CONNECT_TIME;
+}
+
+/*
+ * auth_check_options - called to check authentication options.
+ */
+int
+auth_check_options(void)
+{
+    lcp_options *wo = &lcp_wantoptions[0];
+    int status      = 1;
+    int can_auth;
+    int lacks_ip;
+
+    /* Default our_name to hostname, and user to our_name */
+    if (our_name[0] == 0 || usehostname)
+	strlcpy(our_name, hostname, sizeof(our_name));
+    if (user[0] == 0)
+	strlcpy(user, our_name, sizeof(user));
+
+    /*
+     * If we have a default route, require the peer to authenticate
+     * unless the noauth option was given or the real user is root.
+     */
+    if (!auth_required && !allow_any_ip && have_route_to(0) && !privileged) {
+        printf("auth_check_options: turning on\n");
+	auth_required = 1;
+	default_auth = 1;
+    }
+
+    /* If authentication is required, ask peer for CHAP or PAP. */
+    if (auth_required) {
+	if (!wo->neg_chap && !wo->neg_upap) {
+	    wo->neg_chap = 1;
+	    wo->neg_upap = 1;
+	}
+    } else {
+	wo->neg_chap = 0;
+	wo->neg_upap = 0;
+    }
+
+    /*
+     * Check whether we have appropriate secrets to use
+     * to authenticate the peer.
+     */
+    lacks_ip = 0;
+    can_auth = wo->neg_upap && (uselogin || have_pap_secret(&lacks_ip));
+    if (!can_auth && wo->neg_chap) {
+	can_auth = have_chap_secret((explicit_remote? remote_name: NULL),
+				    our_name, 1, &lacks_ip);
+    }
+
+    if (auth_required && !can_auth && noauth_addrs == NULL) {
+	if (default_auth) {
+	    option_error(
+"By default the remote system is required to authenticate itself");
+	    option_error(
+"(because this system has a default route to the internet)");
+	} else if (explicit_remote)
+	    option_error(
+"The remote system (%s) is required to authenticate itself",
+			 remote_name);
+	else
+	    option_error(
+"The remote system is required to authenticate itself");
+	option_error(
+"but I couldn't find any suitable secret (password) for it to use to do so.");
+	if (lacks_ip)
+	    option_error(
+"(None of the available passwords would let it use an IP address.)");
+
+        status = 0;
+    }
+    return ( status );
+}
+
+/*
+ * auth_reset - called when LCP is starting negotiations to recheck
+ * authentication options, i.e. whether we have appropriate secrets
+ * to use for authenticating ourselves and/or the peer.
+ */
+void
+auth_reset(
+    int unit)
+{
+    lcp_options *go = &lcp_gotoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[0];
+
+    ao->neg_upap = !refuse_pap && (passwd[0] != 0 || get_pap_passwd(NULL));
+    ao->neg_chap = !refuse_chap
+	&& (passwd[0] != 0
+	    || have_chap_secret(user, (explicit_remote? remote_name: NULL),
+				0, NULL));
+
+    if (go->neg_upap && !uselogin && !have_pap_secret(NULL))
+	go->neg_upap = 0;
+    if (go->neg_chap) {
+	if (!have_chap_secret((explicit_remote? remote_name: NULL),
+			      our_name, 1, NULL))
+	    go->neg_chap = 0;
+    }
+}
+
+
+/*
+ * check_passwd - Check the user name and passwd against the PAP secrets
+ * file.  If requested, also check against the system password database,
+ * and login the user if OK.
+ *
+ * returns:
+ *	UPAP_AUTHNAK: Authentication failed.
+ *	UPAP_AUTHACK: Authentication succeeded.
+ * In either case, msg points to an appropriate message.
+ */
+int
+check_passwd(
+    int unit,
+    char *auser,
+    int userlen,
+    char *apasswd,
+    int passwdlen,
+    char **msg)
+{
+    char passwd[64], user[64];
+
+    if (pap_auth_hook)
+    {
+	slprintf(passwd, sizeof(passwd), "%.*v", passwdlen, apasswd);
+	slprintf(user, sizeof(user), "%.*v", userlen, auser);
+
+	return (*pap_auth_hook)(user, passwd/*, NULL, NULL, NULL*/) ?
+	    UPAP_AUTHACK : UPAP_AUTHNAK;
+    }
+
+    return UPAP_AUTHACK;
+
+#if 0
+    int    ret = (int)UPAP_AUTHNAK;
+
+    if (( userlen == 0 ) && ( passwdlen == 0 )) {
+      ret = (int)UPAP_AUTHACK;
+    }
+    printf("check_passwd: %d\n", ret);
+
+    return ret;
+#endif
+}
+
+/*
+ * null_login - Check if a username of "" and a password of "" are
+ * acceptable, and iff so, set the list of acceptable IP addresses
+ * and return 1.
+ */
+static int
+null_login(
+    int unit)
+{
+    return 0;
+}
+
+
+/*
+ * get_pap_passwd - get a password for authenticating ourselves with
+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password
+ * could be found.
+ * Assumes passwd points to MAXSECRETLEN bytes of space (if non-null).
+ */
+static int
+get_pap_passwd(
+    char *passwd)
+{
+    int ret = (int)0;
+
+    /*
+     * Check whether a plugin wants to supply this.
+     */
+    if (pap_passwd_hook) {
+	ret = (*pap_passwd_hook)(user, passwd);
+    }
+
+    return ( ret );
+}
+
+
+/*
+ * have_pap_secret - check whether we have a PAP file with any
+ * secrets that we could possibly use for authenticating the peer.
+ */
+static int
+have_pap_secret(
+    int *lacks_ipp)
+{
+    return 1;
+
+#if 0
+    int ret = (int)0;
+
+    /* let the plugin decide, if there is one */
+    printf("have_pap_secret:\n");
+    if (pap_check_hook) {
+	ret = (*pap_check_hook)();
+    }
+
+    return ( ret );
+#endif
+}
+
+
+/*
+ * have_chap_secret - check whether we have a CHAP file with a
+ * secret that we could possibly use for authenticating `client'
+ * on `server'.  Either can be the null string, meaning we don't
+ * know the identity yet.
+ */
+static int
+have_chap_secret(
+    char *client,
+    char *server,
+    int need_ip,
+    int *lacks_ipp)
+{
+    return 0;
+}
+
+
+/*
+ * get_secret - open the CHAP secret file and return the secret
+ * for authenticating the given client on the given server.
+ * (We could be either client or server).
+ */
+int
+get_secret(
+    int unit,
+    char *client,
+    char *server,
+    unsigned char *secret,
+    int *secret_len,
+    int am_server)
+{
+    int len;
+    char secbuf[MAXWORDLEN];
+
+    if (!am_server && passwd[0] != 0) {
+	strlcpy(secbuf, passwd, sizeof(secbuf));
+    } else {
+        return 0;
+    }
+
+    len = strlen(secbuf);
+    if (len > MAXSECRETLEN) {
+	error("Secret for %s on %s is too long", client, server);
+	len = MAXSECRETLEN;
+    }
+    BCOPY(secbuf, secret, len);
+    BZERO(secbuf, sizeof(secbuf));
+    *secret_len = len;
+
+    return 1;
+}
+
+/*
+ * set_allowed_addrs() - set the list of allowed addresses.
+ * Also looks for `--' indicating options to apply for this peer
+ * and leaves the following words in extra_options.
+ */
+static void
+set_allowed_addrs(
+    int unit,
+    struct wordlist *addrs,
+    struct wordlist *opts)
+{
+    int n;
+    struct wordlist *ap, **pap;
+    struct permitted_ip *ip;
+    char *ptr_word, *ptr_mask;
+    struct hostent *hp;
+    struct netent *np;
+    uint32_t a, mask, ah, offset;
+    struct ipcp_options *wo = &ipcp_wantoptions[unit];
+    uint32_t suggested_ip = 0;
+
+    if (addresses[unit] != NULL)
+	free(addresses[unit]);
+    addresses[unit] = NULL;
+    if (extra_options != NULL)
+	free_wordlist(extra_options);
+    extra_options = opts;
+
+    /*
+     * Count the number of IP addresses given.
+     */
+    for (n = 0, pap = &addrs; (ap = *pap) != NULL; pap = &ap->next)
+	++n;
+    if (n == 0)
+	return;
+    ip = (struct permitted_ip *) malloc((n + 1) * sizeof(struct permitted_ip));
+    if (ip == 0)
+	return;
+
+    n = 0;
+    for (ap = addrs; ap != NULL; ap = ap->next) {
+	/* "-" means no addresses authorized, "*" means any address allowed */
+	ptr_word = ap->word;
+	if (strcmp(ptr_word, "-") == 0)
+	    break;
+	if (strcmp(ptr_word, "*") == 0) {
+	    ip[n].permit = 1;
+	    ip[n].base = ip[n].mask = 0;
+	    ++n;
+	    break;
+	}
+
+	ip[n].permit = 1;
+	if (*ptr_word == '!') {
+	    ip[n].permit = 0;
+	    ++ptr_word;
+	}
+
+	mask = ~ (uint32_t) 0;
+	offset = 0;
+	ptr_mask = strchr (ptr_word, '/');
+	if (ptr_mask != NULL) {
+	    int bit_count;
+	    char *endp;
+
+	    bit_count = (int) strtol (ptr_mask+1, &endp, 10);
+	    if (bit_count <= 0 || bit_count > 32) {
+		warn("invalid address length %v in auth. address list",
+		     ptr_mask+1);
+		continue;
+	    }
+	    bit_count = 32 - bit_count;	/* # bits in host part */
+	    if (*endp == '+') {
+		offset = pppifunit + 1;
+		++endp;
+	    }
+	    if (*endp != 0) {
+		warn("invalid address length syntax: %v", ptr_mask+1);
+		continue;
+	    }
+	    *ptr_mask = '\0';
+	    mask <<= bit_count;
+	}
+
+	hp = gethostbyname(ptr_word);
+	if (hp != NULL && hp->h_addrtype == AF_INET) {
+	    a = *(uint32_t *)hp->h_addr;
+	} else {
+	    np = getnetbyname (ptr_word);
+	    if (np != NULL && np->n_addrtype == AF_INET) {
+		a = htonl (np->n_net);
+		if (ptr_mask == NULL) {
+		    /* calculate appropriate mask for net */
+		    ah = ntohl(a);
+		    if (IN_CLASSA(ah))
+			mask = IN_CLASSA_NET;
+		    else if (IN_CLASSB(ah))
+			mask = IN_CLASSB_NET;
+		    else if (IN_CLASSC(ah))
+			mask = IN_CLASSC_NET;
+		}
+	    } else {
+		a = inet_addr (ptr_word);
+	    }
+	}
+
+	if (ptr_mask != NULL)
+	    *ptr_mask = '/';
+
+	if (a == (uint32_t)-1L) {
+	    warn("unknown host %s in auth. address list", ap->word);
+	    continue;
+	}
+	if (offset != 0) {
+	    if (offset >= ~mask) {
+		warn("interface unit %d too large for subnet %v",
+		     pppifunit, ptr_word);
+		continue;
+	    }
+	    a = htonl((ntohl(a) & mask) + offset);
+	    mask = ~(uint32_t)0;
+	}
+	ip[n].mask = htonl(mask);
+	ip[n].base = a & ip[n].mask;
+	++n;
+	if (~mask == 0 && suggested_ip == 0)
+	    suggested_ip = a;
+    }
+
+    ip[n].permit = 0;		/* make the last entry forbid all addresses */
+    ip[n].base = 0;		/* to terminate the list */
+    ip[n].mask = 0;
+
+    addresses[unit] = ip;
+
+    /*
+     * If the address given for the peer isn't authorized, or if
+     * the user hasn't given one, AND there is an authorized address
+     * which is a single host, then use that if we find one.
+     */
+    if (suggested_ip != 0
+	&& (wo->hisaddr == 0 || !auth_ip_addr(unit, wo->hisaddr)))
+	wo->hisaddr = suggested_ip;
+}
+
+/*
+ * auth_ip_addr - check whether the peer is authorized to use
+ * a given IP address.  Returns 1 if authorized, 0 otherwise.
+ */
+int
+auth_ip_addr(
+    int unit,
+    uint32_t addr)
+{
+#if 0
+    int ok;
+#endif
+
+    /* don't allow loopback or multicast address */
+    if (bad_ip_adrs(addr))
+	return 0;
+	
+    return 1;
+
+#if 0
+    if (addresses[unit] != NULL) {
+	ok = ip_addr_check(addr, addresses[unit]);
+	if (ok >= 0)
+	    return ok;
+    }
+    if (auth_required)
+	return 0;		/* no addresses authorized */
+    return allow_any_ip || !have_route_to(addr);
+#endif
+}
+
+#if 0
+static int
+ip_addr_check(
+    uint32_t addr,
+    struct permitted_ip *addrs)
+{
+    for (; ; ++addrs)
+	if ((addr & addrs->mask) == addrs->base)
+	    return addrs->permit;
+}
+#endif
+
+/*
+ * bad_ip_adrs - return 1 if the IP address is one we don't want
+ * to use, such as an address in the loopback net or a multicast address.
+ * addr is in network byte order.
+ */
+int
+bad_ip_adrs(
+    uint32_t addr)
+{
+    addr = ntohl(addr);
+    return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET
+	|| IN_MULTICAST(addr) || IN_BADCLASS(addr);
+}
+
+/*
+ * free_wordlist - release memory allocated for a wordlist.
+ */
+static void
+free_wordlist(
+    struct wordlist *wp)
+{
+    struct wordlist *next;
+
+    while (wp != NULL) {
+	next = wp->next;
+	free(wp);
+	wp = next;
+    }
+}
+
+/*
+ * auth_script - execute a script with arguments
+ * interface-name peer-name real-user tty speed
+ */
+static void
+auth_script(
+    enum script_state s)
+{
+    switch (s) {
+    case s_up:
+	auth_script_state = s_up;
+	if ( auth_linkup_hook ) {
+	  (*auth_linkup_hook)();
+        }
+        break;
+    case s_down:
+	auth_script_state = s_down;
+	if ( auth_linkdown_hook ) {
+	  (*auth_linkdown_hook)();
+        }
+	break;
+    }
+}
diff --git a/rtemsbsd/pppd/cbcp.c b/rtemsbsd/pppd/cbcp.c
new file mode 100644
index 0000000..eb75083
--- /dev/null
+++ b/rtemsbsd/pppd/cbcp.c
@@ -0,0 +1,456 @@
+/*
+ * cbcp - Call Back Configuration Protocol.
+ *
+ * Copyright (c) 1995 Pedro Roque Marques
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Pedro Roque Marques.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "cbcp.h"
+#include "fsm.h"
+#include "lcp.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Options.
+ */
+static int setcbcp(char **);
+
+static option_t cbcp_option_list[] = {
+    { "callback", o_special, setcbcp,
+      "Ask for callback" },
+    { NULL }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void cbcp_init     (int unit);
+static void cbcp_open     (int unit);
+static void cbcp_lowerup  (int unit);
+static void cbcp_input    (int unit, u_char *pkt, int len);
+static void cbcp_protrej  (int unit);
+static int  cbcp_printpkt (u_char *pkt, int len,
+				void (*printer)(void *, char *, ...),
+				void *arg);
+
+struct protent cbcp_protent = {
+    PPP_CBCP,
+    cbcp_init,
+    cbcp_input,
+    cbcp_protrej,
+    cbcp_lowerup,
+    NULL,
+    cbcp_open,
+    NULL,
+    cbcp_printpkt,
+    NULL,
+    0,
+    "CBCP",
+    NULL,
+    cbcp_option_list,
+    NULL,
+    NULL,
+    NULL
+};
+
+cbcp_state cbcp[NUM_PPP];	
+
+/* internal prototypes */
+
+static void cbcp_recvreq(cbcp_state *us, char *pckt, int len);
+static void cbcp_resp(cbcp_state *us);
+static void cbcp_up(cbcp_state *us);
+static void cbcp_recvack(cbcp_state *us, char *pckt, int len);
+static void cbcp_send(cbcp_state *us, u_char code, u_char *buf, int len);
+
+/* option processing */
+static int
+setcbcp(argv)
+    char **argv;
+{
+    lcp_wantoptions[0].neg_cbcp = 1;
+    cbcp_protent.enabled_flag = 1;
+    cbcp[0].us_number = strdup(*argv);
+    if (cbcp[0].us_number == 0)
+	novm("callback number");
+    cbcp[0].us_type |= (1 << CB_CONF_USER);
+    cbcp[0].us_type |= (1 << CB_CONF_ADMIN);
+    return (1);
+}
+
+/* init state */
+static void
+cbcp_init(iface)
+    int iface;
+{
+    cbcp_state *us;
+
+    us = &cbcp[iface];
+    memset(us, 0, sizeof(cbcp_state));
+    us->us_unit = iface;
+    us->us_type |= (1 << CB_CONF_NO);
+}
+
+/* lower layer is up */
+static void
+cbcp_lowerup(iface)
+    int iface;
+{
+    cbcp_state *us = &cbcp[iface];
+
+    dbglog("cbcp_lowerup");
+    dbglog("want: %d", us->us_type);
+
+    if (us->us_type == CB_CONF_USER)
+        dbglog("phone no: %s", us->us_number);
+}
+
+static void
+cbcp_open(unit)
+    int unit;
+{
+    dbglog("cbcp_open");
+}
+
+/* process an incomming packet */
+static void
+cbcp_input(unit, inpacket, pktlen)
+    int unit;
+    u_char *inpacket;
+    int pktlen;
+{
+    u_char *inp;
+    u_char code, id;
+    u_short len;
+
+    cbcp_state *us = &cbcp[unit];
+
+    inp = inpacket;
+
+    if (pktlen < CBCP_MINLEN) {
+        error("CBCP packet is too small");
+	return;
+    }
+
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+
+#if 0
+    if (len > pktlen) {
+        error("CBCP packet: invalid length");
+        return;
+    }
+#endif
+
+    len -= CBCP_MINLEN;
+
+    switch(code) {
+    case CBCP_REQ:
+        us->us_id = id;
+	cbcp_recvreq(us, inp, len);
+	break;
+
+    case CBCP_RESP:
+	dbglog("CBCP_RESP received");
+	break;
+
+    case CBCP_ACK:
+	if (id != us->us_id)
+	    dbglog("id doesn't match: expected %d recv %d",
+		   us->us_id, id);
+
+	cbcp_recvack(us, inp, len);
+	break;
+
+    default:
+	break;
+    }
+}
+
+/* protocol was rejected by foe */
+void cbcp_protrej(int iface)
+{
+}
+
+char *cbcp_codenames[] = {
+    "Request", "Response", "Ack"
+};
+
+char *cbcp_optionnames[] = {
+    "NoCallback",
+    "UserDefined",
+    "AdminDefined",
+    "List"
+};
+
+/* pretty print a packet */
+static int
+cbcp_printpkt(p, plen, printer, arg)
+    u_char *p;
+    int plen;
+    void (*printer)(void *, char *, ...);
+    void *arg;
+{
+    int code, opt, id, len, olen, delay;
+    u_char *pstart;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(cbcp_codenames) / sizeof(char *))
+	printer(arg, " %s", cbcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+
+    switch (code) {
+    case CBCP_REQ:
+    case CBCP_RESP:
+    case CBCP_ACK:
+        while(len >= 2) {
+	    GETCHAR(opt, p);
+	    GETCHAR(olen, p);
+
+	    if (olen < 2 || olen > len) {
+	        break;
+	    }
+
+	    printer(arg, " <");
+	    len -= olen;
+
+	    if (opt >= 1 && opt <= sizeof(cbcp_optionnames) / sizeof(char *))
+	    	printer(arg, " %s", cbcp_optionnames[opt-1]);
+	    else
+	        printer(arg, " option=0x%x", opt);
+
+	    if (olen > 2) {
+	        GETCHAR(delay, p);
+		printer(arg, " delay = %d", delay);
+	    }
+
+	    if (olen > 3) {
+	        int addrt;
+		char str[256];
+
+		GETCHAR(addrt, p);
+		memcpy(str, p, olen - 4);
+		str[olen - 4] = 0;
+		printer(arg, " number = %s", str);
+	    }
+	    printer(arg, ">");
+	    break;
+	}
+
+    default:
+	break;
+    }
+
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/* received CBCP request */
+static void
+cbcp_recvreq(us, pckt, pcktlen)
+    cbcp_state *us;
+    char *pckt;
+    int pcktlen;
+{
+    u_char type, opt_len, delay, addr_type;
+    char address[256];
+    int len = pcktlen;
+
+    address[0] = 0;
+
+    while (len) {
+        dbglog("length: %d", len);
+
+	GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	us->us_allowed |= (1 << type);
+
+	switch(type) {
+	case CB_CONF_NO:
+	    dbglog("no callback allowed");
+	    break;
+
+	case CB_CONF_USER:
+	    dbglog("user callback allowed");
+	    if (opt_len > 4) {
+	        GETCHAR(addr_type, pckt);
+		memcpy(address, pckt, opt_len - 4);
+		address[opt_len - 4] = 0;
+		if (address[0])
+		    dbglog("address: %s", address);
+	    }
+	    break;
+
+	case CB_CONF_ADMIN:
+	    dbglog("user admin defined allowed");
+	    break;
+
+	case CB_CONF_LIST:
+	    break;
+	}
+	len -= opt_len;
+    }
+
+    cbcp_resp(us);
+}
+
+static void
+cbcp_resp(us)
+    cbcp_state *us;
+{
+    u_char cb_type;
+    u_char buf[256];
+    u_char *bufp = buf;
+    int len = 0;
+
+    cb_type = us->us_allowed & us->us_type;
+    dbglog("cbcp_resp cb_type=%d", cb_type);
+
+#if 0
+    if (!cb_type)
+        lcp_down(us->us_unit);
+#endif
+
+    if (cb_type & ( 1 << CB_CONF_USER ) ) {
+	dbglog("cbcp_resp CONF_USER");
+	PUTCHAR(CB_CONF_USER, bufp);
+	len = 3 + 1 + strlen(us->us_number) + 1;
+	PUTCHAR(len , bufp);
+	PUTCHAR(5, bufp); /* delay */
+	PUTCHAR(1, bufp);
+	BCOPY(us->us_number, bufp, strlen(us->us_number) + 1);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_ADMIN ) ) {
+	dbglog("cbcp_resp CONF_ADMIN");
+        PUTCHAR(CB_CONF_ADMIN, bufp);
+	len = 3;
+	PUTCHAR(len, bufp);
+	PUTCHAR(5, bufp); /* delay */
+	cbcp_send(us, CBCP_RESP, buf, len);
+	return;
+    }
+
+    if (cb_type & ( 1 << CB_CONF_NO ) ) {
+        dbglog("cbcp_resp CONF_NO");
+	PUTCHAR(CB_CONF_NO, bufp);
+	len = 3;
+	PUTCHAR(len , bufp);
+	PUTCHAR(0, bufp);
+	cbcp_send(us, CBCP_RESP, buf, len);
+	start_networks();
+	return;
+    }
+}
+
+static void
+cbcp_send(us, code, buf, len)
+    cbcp_state *us;
+    u_char code;
+    u_char *buf;
+    int len;
+{
+    u_char *outp;
+    int outlen;
+
+    outp = outpacket_buf;
+
+    outlen = 4 + len;
+
+    MAKEHEADER(outp, PPP_CBCP);
+
+    PUTCHAR(code, outp);
+    PUTCHAR(us->us_id, outp);
+    PUTSHORT(outlen, outp);
+
+    if (len)
+        BCOPY(buf, outp, len);
+
+    output(us->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+static void
+cbcp_recvack(us, pckt, len)
+    cbcp_state *us;
+    char *pckt;
+    int len;
+{
+    u_char type, delay, addr_type;
+    int opt_len;
+    char address[256];
+
+    if (len) {
+        GETCHAR(type, pckt);
+	GETCHAR(opt_len, pckt);
+
+	if (opt_len > 2)
+	    GETCHAR(delay, pckt);
+
+	if (opt_len > 4) {
+	    GETCHAR(addr_type, pckt);
+	    memcpy(address, pckt, opt_len - 4);
+	    address[opt_len - 4] = 0;
+	    if (address[0])
+	        dbglog("peer will call: %s", address);
+	}
+	if (type == CB_CONF_NO)
+	    return;
+    }
+
+    cbcp_up(us);
+}
+
+/* ok peer will do callback */
+static void
+cbcp_up(us)
+    cbcp_state *us;
+{
+    persist = 0;
+    lcp_close(0, "Call me back, please");
+    status = EXIT_CALLBACK;
+}
diff --git a/rtemsbsd/pppd/cbcp.h b/rtemsbsd/pppd/cbcp.h
new file mode 100644
index 0000000..c2ab3f6
--- /dev/null
+++ b/rtemsbsd/pppd/cbcp.h
@@ -0,0 +1,26 @@
+#ifndef CBCP_H
+#define CBCP_H
+
+typedef struct cbcp_state {
+    int    us_unit;	/* Interface unit number */
+    u_char us_id;		/* Current id */
+    u_char us_allowed;
+    int    us_type;
+    char   *us_number;    /* Telefone Number */
+} cbcp_state;
+
+extern cbcp_state cbcp[];
+
+extern struct protent cbcp_protent;
+
+#define CBCP_MINLEN 4
+
+#define CBCP_REQ    1
+#define CBCP_RESP   2
+#define CBCP_ACK    3
+
+#define CB_CONF_NO     1
+#define CB_CONF_USER   2
+#define CB_CONF_ADMIN  3
+#define CB_CONF_LIST   4
+#endif
diff --git a/rtemsbsd/pppd/ccp.c b/rtemsbsd/pppd/ccp.c
new file mode 100644
index 0000000..d80df27
--- /dev/null
+++ b/rtemsbsd/pppd/ccp.c
@@ -0,0 +1,1228 @@
+/*
+ * ccp.c - PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ccp.h"
+#include <net/ppp_comp.h>
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Command-line options.
+ */
+static int setbsdcomp(char **);
+static int setdeflate(char **);
+
+static option_t ccp_option_list[] = {
+    { "noccp", o_bool, &ccp_protent.enabled_flag,
+      "Disable CCP negotiation", 0, NULL, 0, 0 },
+    { "-ccp", o_bool, &ccp_protent.enabled_flag,
+      "Disable CCP negotiation", 0, NULL, 0, 0  },
+    { "bsdcomp", o_special, setbsdcomp,
+      "Request BSD-Compress packet compression", 0, NULL, 0, 0  },
+    { "nobsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+      "don't allow BSD-Compress", OPT_A2COPY,
+      &ccp_allowoptions[0].bsd_compress, 0, 0 },
+    { "-bsdcomp", o_bool, &ccp_wantoptions[0].bsd_compress,
+      "don't allow BSD-Compress", OPT_A2COPY,
+      &ccp_allowoptions[0].bsd_compress, 0, 0 },
+    { "deflate", 1, setdeflate,
+      "request Deflate compression", 0, NULL, 0, 0  },
+    { "nodeflate", o_bool, &ccp_wantoptions[0].deflate,
+      "don't allow Deflate compression", OPT_A2COPY,
+      &ccp_allowoptions[0].deflate, 0, 0 },
+    { "-deflate", o_bool, &ccp_wantoptions[0].deflate,
+      "don't allow Deflate compression", OPT_A2COPY,
+      &ccp_allowoptions[0].deflate, 0, 0 },
+    { "nodeflatedraft", o_bool, &ccp_wantoptions[0].deflate_draft,
+      "don't use draft deflate #", OPT_A2COPY,
+      &ccp_allowoptions[0].deflate_draft, 0, 0 },
+    { "predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "request Predictor-1", 1,
+      &ccp_allowoptions[0].predictor_1, 0, 0 },
+    { "nopredictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "don't allow Predictor-1", OPT_A2COPY,
+      &ccp_allowoptions[0].predictor_1, 0, 0 },
+    { "-predictor1", o_bool, &ccp_wantoptions[0].predictor_1,
+      "don't allow Predictor-1", OPT_A2COPY,
+      &ccp_allowoptions[0].predictor_1, 0, 0 },
+
+    { NULL, 0, NULL, NULL, 0,  NULL, 0, 0 }
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ccp_init(int unit);
+static void ccp_open(int unit);
+static void ccp_close(int unit, char *);
+static void ccp_lowerup(int unit);
+static void ccp_lowerdown(int);
+static void ccp_input(int unit, u_char *pkt, int len);
+static void ccp_protrej(int unit);
+static int  ccp_printpkt(u_char *pkt, int len,
+			      void (*printer)(void *, char *, ...),
+			      void *arg);
+static void ccp_datainput(int unit, u_char *pkt, int len);
+
+struct protent ccp_protent = {
+    PPP_CCP,
+    ccp_init,
+    ccp_input,
+    ccp_protrej,
+    ccp_lowerup,
+    ccp_lowerdown,
+    ccp_open,
+    ccp_close,
+    ccp_printpkt,
+    ccp_datainput,
+    1,
+    "CCP",
+    "Compressed",
+    ccp_option_list,
+    NULL,
+    NULL,
+    NULL
+};
+
+fsm ccp_fsm[NUM_PPP];
+ccp_options ccp_wantoptions[NUM_PPP];	/* what to request the peer to use */
+ccp_options ccp_gotoptions[NUM_PPP];	/* what the peer agreed to do */
+ccp_options ccp_allowoptions[NUM_PPP];	/* what we'll agree to do */
+ccp_options ccp_hisoptions[NUM_PPP];	/* what we agreed to do */
+
+/*
+ * Callbacks for fsm code.
+ */
+static void ccp_resetci(fsm *);
+static int  ccp_cilen(fsm *);
+static void ccp_addci(fsm *, u_char *, int *);
+static int  ccp_ackci(fsm *, u_char *, int);
+static int  ccp_nakci(fsm *, u_char *, int);
+static int  ccp_rejci(fsm *, u_char *, int);
+static int  ccp_reqci(fsm *, u_char *, int *, int);
+static void ccp_up(fsm *);
+static void ccp_down(fsm *);
+static int  ccp_extcode(fsm *, int, int, u_char *, int);
+static void ccp_rack_timeout(void *);
+static char *method_name(ccp_options *, ccp_options *);
+
+static fsm_callbacks ccp_callbacks = {
+    ccp_resetci,
+    ccp_cilen,
+    ccp_addci,
+    ccp_ackci,
+    ccp_nakci,
+    ccp_rejci,
+    ccp_reqci,
+    ccp_up,
+    ccp_down,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    ccp_extcode,
+    "CCP"
+};
+
+/*
+ * Do we want / did we get any compression?
+ */
+#define ANY_COMPRESS(opt)	((opt).deflate || (opt).bsd_compress \
+				 || (opt).predictor_1 || (opt).predictor_2)
+
+/*
+ * Local state (mainly for handling reset-reqs and reset-acks).
+ */
+static int ccp_localstate[NUM_PPP];
+#define RACK_PENDING	1	/* waiting for reset-ack */
+#define RREQ_REPEAT	2	/* send another reset-req if no reset-ack */
+
+#define RACKTIMEOUT	1	/* second */
+
+static int all_rejected[NUM_PPP];	/* we rejected all peer's options */
+
+/*
+ * Option parsing.
+ */
+static int
+setbsdcomp(
+    char **argv)
+{
+    int rbits, abits;
+    char *str, *endp;
+
+    str = *argv;
+    abits = rbits = strtol(str, &endp, 0);
+    if (endp != str && *endp == ',') {
+	str = endp + 1;
+	abits = strtol(str, &endp, 0);
+    }
+    if (*endp != 0 || endp == str) {
+	option_error("invalid parameter '%s' for bsdcomp option", *argv);
+	return 0;
+    }
+    if ((rbits != 0 && (rbits < BSD_MIN_BITS || rbits > BSD_MAX_BITS))
+	|| (abits != 0 && (abits < BSD_MIN_BITS || abits > BSD_MAX_BITS))) {
+	option_error("bsdcomp option values must be 0 or %d .. %d",
+		     BSD_MIN_BITS, BSD_MAX_BITS);
+	return 0;
+    }
+    if (rbits > 0) {
+	ccp_wantoptions[0].bsd_compress = 1;
+	ccp_wantoptions[0].bsd_bits = rbits;
+    } else
+	ccp_wantoptions[0].bsd_compress = 0;
+    if (abits > 0) {
+	ccp_allowoptions[0].bsd_compress = 1;
+	ccp_allowoptions[0].bsd_bits = abits;
+    } else
+	ccp_allowoptions[0].bsd_compress = 0;
+    return 1;
+}
+
+static int
+setdeflate(
+    char **argv)
+{
+    int rbits, abits;
+    char *str, *endp;
+
+    str = *argv;
+    abits = rbits = strtol(str, &endp, 0);
+    if (endp != str && *endp == ',') {
+	str = endp + 1;
+	abits = strtol(str, &endp, 0);
+    }
+    if (*endp != 0 || endp == str) {
+	option_error("invalid parameter '%s' for deflate option", *argv);
+	return 0;
+    }
+    if ((rbits != 0 && (rbits < DEFLATE_MIN_SIZE || rbits > DEFLATE_MAX_SIZE))
+	|| (abits != 0 && (abits < DEFLATE_MIN_SIZE
+			  || abits > DEFLATE_MAX_SIZE))) {
+	option_error("deflate option values must be 0 or %d .. %d",
+		     DEFLATE_MIN_SIZE, DEFLATE_MAX_SIZE);
+	return 0;
+    }
+    if (rbits > 0) {
+	ccp_wantoptions[0].deflate = 1;
+	ccp_wantoptions[0].deflate_size = rbits;
+    } else
+	ccp_wantoptions[0].deflate = 0;
+    if (abits > 0) {
+	ccp_allowoptions[0].deflate = 1;
+	ccp_allowoptions[0].deflate_size = abits;
+    } else
+	ccp_allowoptions[0].deflate = 0;
+    return 1;
+}
+
+
+/*
+ * ccp_init - initialize CCP.
+ */
+static void
+ccp_init(
+    int unit)
+{
+    fsm *f = &ccp_fsm[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_CCP;
+    f->callbacks = &ccp_callbacks;
+    fsm_init(f);
+
+    memset(&ccp_wantoptions[unit],  0, sizeof(ccp_options));
+    memset(&ccp_gotoptions[unit],   0, sizeof(ccp_options));
+    memset(&ccp_allowoptions[unit], 0, sizeof(ccp_options));
+    memset(&ccp_hisoptions[unit],   0, sizeof(ccp_options));
+
+    ccp_wantoptions[0].deflate = 1;
+    ccp_wantoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+    ccp_wantoptions[0].deflate_correct = 1;
+    ccp_wantoptions[0].deflate_draft = 1;
+    ccp_allowoptions[0].deflate = 1;
+    ccp_allowoptions[0].deflate_size = DEFLATE_MAX_SIZE;
+    ccp_allowoptions[0].deflate_correct = 1;
+    ccp_allowoptions[0].deflate_draft = 1;
+
+    ccp_wantoptions[0].bsd_compress = 1;
+    ccp_wantoptions[0].bsd_bits = BSD_MAX_BITS;
+    ccp_allowoptions[0].bsd_compress = 1;
+    ccp_allowoptions[0].bsd_bits = BSD_MAX_BITS;
+
+    ccp_allowoptions[0].predictor_1 = 1;
+}
+
+/*
+ * ccp_open - CCP is allowed to come up.
+ */
+static void
+ccp_open(
+    int unit)
+{
+    fsm *f = &ccp_fsm[unit];
+
+    if (f->state != OPENED)
+	ccp_flags_set(unit, 1, 0);
+
+    /*
+     * Find out which compressors the kernel supports before
+     * deciding whether to open in silent mode.
+     */
+    ccp_resetci(f);
+    if (!ANY_COMPRESS(ccp_gotoptions[unit]))
+	f->flags |= OPT_SILENT;
+
+    fsm_open(f);
+}
+
+/*
+ * ccp_close - Terminate CCP.
+ */
+static void
+ccp_close(
+    int unit,
+    char *reason)
+{
+    ccp_flags_set(unit, 0, 0);
+    fsm_close(&ccp_fsm[unit], reason);
+}
+
+/*
+ * ccp_lowerup - we may now transmit CCP packets.
+ */
+static void
+ccp_lowerup(
+    int unit)
+{
+    fsm_lowerup(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_lowerdown - we may not transmit CCP packets.
+ */
+static void
+ccp_lowerdown(
+    int unit)
+{
+    fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_input - process a received CCP packet.
+ */
+static void
+ccp_input(
+    int unit,
+    u_char *p,
+    int len)
+{
+    fsm *f = &ccp_fsm[unit];
+    int oldstate;
+
+    /*
+     * Check for a terminate-request so we can print a message.
+     */
+    oldstate = f->state;
+    fsm_input(f, p, len);
+    if (oldstate == OPENED && p[0] == TERMREQ && f->state != OPENED)
+	notice("Compression disabled by peer.");
+
+    /*
+     * If we get a terminate-ack and we're not asking for compression,
+     * close CCP.
+     */
+    if (oldstate == REQSENT && p[0] == TERMACK
+	&& !ANY_COMPRESS(ccp_gotoptions[unit]))
+	ccp_close(unit, "No compression negotiated");
+}
+
+/*
+ * Handle a CCP-specific code.
+ */
+static int
+ccp_extcode(
+    fsm *f,
+    int code, int id,
+    u_char *p,
+    int len)
+{
+    switch (code) {
+    case CCP_RESETREQ:
+	if (f->state != OPENED)
+	    break;
+	/* send a reset-ack, which the transmitter will see and
+	   reset its compression state. */
+	fsm_sdata(f, CCP_RESETACK, id, NULL, 0);
+	break;
+
+    case CCP_RESETACK:
+	if (ccp_localstate[f->unit] & RACK_PENDING && id == f->reqid) {
+	    ccp_localstate[f->unit] &= ~(RACK_PENDING | RREQ_REPEAT);
+	    UNTIMEOUT(ccp_rack_timeout, f);
+	}
+	break;
+
+    default:
+	return 0;
+    }
+
+    return 1;
+}
+
+/*
+ * ccp_protrej - peer doesn't talk CCP.
+ */
+static void
+ccp_protrej(
+    int unit)
+{
+    ccp_flags_set(unit, 0, 0);
+    fsm_lowerdown(&ccp_fsm[unit]);
+}
+
+/*
+ * ccp_resetci - initialize at start of negotiation.
+ */
+static void
+ccp_resetci(
+    fsm *f)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char opt_buf[16];
+
+    *go = ccp_wantoptions[f->unit];
+    all_rejected[f->unit] = 0;
+
+    /*
+     * Check whether the kernel knows about the various
+     * compression methods we might request.
+     */
+    if (go->bsd_compress) {
+	opt_buf[0] = CI_BSD_COMPRESS;
+	opt_buf[1] = CILEN_BSD_COMPRESS;
+	opt_buf[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, BSD_MIN_BITS);
+	if (ccp_test(f->unit, opt_buf, CILEN_BSD_COMPRESS, 0) <= 0)
+	    go->bsd_compress = 0;
+    }
+    if (go->deflate) {
+	if (go->deflate_correct) {
+	    opt_buf[0] = CI_DEFLATE;
+	    opt_buf[1] = CILEN_DEFLATE;
+	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
+	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_correct = 0;
+	}
+	if (go->deflate_draft) {
+	    opt_buf[0] = CI_DEFLATE_DRAFT;
+	    opt_buf[1] = CILEN_DEFLATE;
+	    opt_buf[2] = DEFLATE_MAKE_OPT(DEFLATE_MIN_SIZE);
+	    opt_buf[3] = DEFLATE_CHK_SEQUENCE;
+	    if (ccp_test(f->unit, opt_buf, CILEN_DEFLATE, 0) <= 0)
+		go->deflate_draft = 0;
+	}
+	if (!go->deflate_correct && !go->deflate_draft)
+	    go->deflate = 0;
+    }
+    if (go->predictor_1) {
+	opt_buf[0] = CI_PREDICTOR_1;
+	opt_buf[1] = CILEN_PREDICTOR_1;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_1, 0) <= 0)
+	    go->predictor_1 = 0;
+    }
+    if (go->predictor_2) {
+	opt_buf[0] = CI_PREDICTOR_2;
+	opt_buf[1] = CILEN_PREDICTOR_2;
+	if (ccp_test(f->unit, opt_buf, CILEN_PREDICTOR_2, 0) <= 0)
+	    go->predictor_2 = 0;
+    }
+}
+
+/*
+ * ccp_cilen - Return total length of our configuration info.
+ */
+static int
+ccp_cilen(
+    fsm *f)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+
+    return (go->bsd_compress? CILEN_BSD_COMPRESS: 0)
+	+ (go->deflate? CILEN_DEFLATE: 0)
+	+ (go->predictor_1? CILEN_PREDICTOR_1: 0)
+	+ (go->predictor_2? CILEN_PREDICTOR_2: 0);
+}
+
+/*
+ * ccp_addci - put our requests in a packet.
+ */
+static void
+ccp_addci(
+    fsm *f,
+    u_char *p,
+    int *lenp)
+{
+    int res;
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char *p0 = p;
+
+    /*
+     * Add the compression types that we can receive, in decreasing
+     * preference order.  Get the kernel to allocate the first one
+     * in case it gets Acked.
+     */
+    if (go->deflate) {
+	p[0] = go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT;
+	p[1] = CILEN_DEFLATE;
+	p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	p[3] = DEFLATE_CHK_SEQUENCE;
+	for (;;) {
+	    res = ccp_test(f->unit, p, CILEN_DEFLATE, 0);
+	    if (res > 0) {
+		p += CILEN_DEFLATE;
+		break;
+	    }
+	    if (res < 0 || go->deflate_size <= DEFLATE_MIN_SIZE) {
+		go->deflate = 0;
+		break;
+	    }
+	    --go->deflate_size;
+	    p[2] = DEFLATE_MAKE_OPT(go->deflate_size);
+	}
+	if (p != p0 && go->deflate_correct && go->deflate_draft) {
+	    p[0] = CI_DEFLATE_DRAFT;
+	    p[1] = CILEN_DEFLATE;
+	    p[2] = p[2 - CILEN_DEFLATE];
+	    p[3] = DEFLATE_CHK_SEQUENCE;
+	    p += CILEN_DEFLATE;
+	}
+    }
+    if (go->bsd_compress) {
+	p[0] = CI_BSD_COMPRESS;
+	p[1] = CILEN_BSD_COMPRESS;
+	p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	if (p != p0) {
+	    p += CILEN_BSD_COMPRESS;	/* not the first option */
+	} else {
+	    for (;;) {
+		res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 0);
+		if (res > 0) {
+		    p += CILEN_BSD_COMPRESS;
+		    break;
+		}
+		if (res < 0 || go->bsd_bits <= BSD_MIN_BITS) {
+		    go->bsd_compress = 0;
+		    break;
+		}
+		--go->bsd_bits;
+		p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits);
+	    }
+	}
+    }
+    /* XXX Should Predictor 2 be preferable to Predictor 1? */
+    if (go->predictor_1) {
+	p[0] = CI_PREDICTOR_1;
+	p[1] = CILEN_PREDICTOR_1;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 0) <= 0) {
+	    go->predictor_1 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_1;
+	}
+    }
+    if (go->predictor_2) {
+	p[0] = CI_PREDICTOR_2;
+	p[1] = CILEN_PREDICTOR_2;
+	if (p == p0 && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 0) <= 0) {
+	    go->predictor_2 = 0;
+	} else {
+	    p += CILEN_PREDICTOR_2;
+	}
+    }
+
+    go->method = (p > p0)? p0[0]: -1;
+
+    *lenp = p - p0;
+}
+
+/*
+ * ccp_ackci - process a received configure-ack, and return
+ * 1 iff the packet was OK.
+ */
+static int
+ccp_ackci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    u_char *p0 = p;
+
+    if (go->deflate) {
+	if (len < CILEN_DEFLATE
+	    || p[0] != (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	    || p[1] != CILEN_DEFLATE
+	    || p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    return 0;
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	/* XXX Cope with first/fast ack */
+	if (len == 0)
+	    return 1;
+	if (go->deflate_correct && go->deflate_draft) {
+	    if (len < CILEN_DEFLATE
+		|| p[0] != CI_DEFLATE_DRAFT
+		|| p[1] != CILEN_DEFLATE
+		|| p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+		|| p[3] != DEFLATE_CHK_SEQUENCE)
+		return 0;
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+    if (go->bsd_compress) {
+	if (len < CILEN_BSD_COMPRESS
+	    || p[0] != CI_BSD_COMPRESS || p[1] != CILEN_BSD_COMPRESS
+	    || p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_1) {
+	if (len < CILEN_PREDICTOR_1
+	    || p[0] != CI_PREDICTOR_1 || p[1] != CILEN_PREDICTOR_1)
+	    return 0;
+	p += CILEN_PREDICTOR_1;
+	len -= CILEN_PREDICTOR_1;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+    if (go->predictor_2) {
+	if (len < CILEN_PREDICTOR_2
+	    || p[0] != CI_PREDICTOR_2 || p[1] != CILEN_PREDICTOR_2)
+	    return 0;
+	p += CILEN_PREDICTOR_2;
+	len -= CILEN_PREDICTOR_2;
+	/* XXX Cope with first/fast ack */
+	if (p == p0 && len == 0)
+	    return 1;
+    }
+
+    if (len != 0)
+	return 0;
+    return 1;
+}
+
+/*
+ * ccp_nakci - process received configure-nak.
+ * Returns 1 iff the nak was OK.
+ */
+static int
+ccp_nakci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options no;		/* options we've seen already */
+    ccp_options try;		/* options to ask for next time */
+
+    memset(&no, 0, sizeof(no));
+    try = *go;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& p[1] == CILEN_DEFLATE) {
+	no.deflate = 1;
+	/*
+	 * Peer wants us to use a different code size or something.
+	 * Stop asking for Deflate if we don't understand his suggestion.
+	 */
+	if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+	    || DEFLATE_SIZE(p[2]) < DEFLATE_MIN_SIZE
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    try.deflate = 0;
+	else if (DEFLATE_SIZE(p[2]) < go->deflate_size)
+	    try.deflate_size = DEFLATE_SIZE(p[2]);
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+    }
+
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+	no.bsd_compress = 1;
+	/*
+	 * Peer wants us to use a different number of bits
+	 * or a different version.
+	 */
+	if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION)
+	    try.bsd_compress = 0;
+	else if (BSD_NBITS(p[2]) < go->bsd_bits)
+	    try.bsd_bits = BSD_NBITS(p[2]);
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+    }
+
+    /*
+     * Predictor-1 and 2 have no options, so they can't be Naked.
+     *
+     * There may be remaining options but we ignore them.
+     */
+
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+}
+
+/*
+ * ccp_rejci - reject some of our suggested compression methods.
+ */
+static int
+ccp_rejci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options try;		/* options to request next time */
+
+    try = *go;
+
+    /*
+     * Cope with empty configure-rejects by ceasing to send
+     * configure-requests.
+     */
+    if (len == 0 && all_rejected[f->unit])
+	return -1;
+
+    if (go->deflate && len >= CILEN_DEFLATE
+	&& p[0] == (go->deflate_correct? CI_DEFLATE: CI_DEFLATE_DRAFT)
+	&& p[1] == CILEN_DEFLATE) {
+	if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+	    || p[3] != DEFLATE_CHK_SEQUENCE)
+	    return 0;		/* Rej is bad */
+	if (go->deflate_correct)
+	    try.deflate_correct = 0;
+	else
+	    try.deflate_draft = 0;
+	p += CILEN_DEFLATE;
+	len -= CILEN_DEFLATE;
+	if (go->deflate_correct && go->deflate_draft
+	    && len >= CILEN_DEFLATE && p[0] == CI_DEFLATE_DRAFT
+	    && p[1] == CILEN_DEFLATE) {
+	    if (p[2] != DEFLATE_MAKE_OPT(go->deflate_size)
+		|| p[3] != DEFLATE_CHK_SEQUENCE)
+		return 0;		/* Rej is bad */
+	    try.deflate_draft = 0;
+	    p += CILEN_DEFLATE;
+	    len -= CILEN_DEFLATE;
+	}
+	if (!try.deflate_correct && !try.deflate_draft)
+	    try.deflate = 0;
+    }
+    if (go->bsd_compress && len >= CILEN_BSD_COMPRESS
+	&& p[0] == CI_BSD_COMPRESS && p[1] == CILEN_BSD_COMPRESS) {
+	if (p[2] != BSD_MAKE_OPT(BSD_CURRENT_VERSION, go->bsd_bits))
+	    return 0;
+	try.bsd_compress = 0;
+	p += CILEN_BSD_COMPRESS;
+	len -= CILEN_BSD_COMPRESS;
+    }
+    if (go->predictor_1 && len >= CILEN_PREDICTOR_1
+	&& p[0] == CI_PREDICTOR_1 && p[1] == CILEN_PREDICTOR_1) {
+	try.predictor_1 = 0;
+	p += CILEN_PREDICTOR_1;
+	len -= CILEN_PREDICTOR_1;
+    }
+    if (go->predictor_2 && len >= CILEN_PREDICTOR_2
+	&& p[0] == CI_PREDICTOR_2 && p[1] == CILEN_PREDICTOR_2) {
+	try.predictor_2 = 0;
+	p += CILEN_PREDICTOR_2;
+	len -= CILEN_PREDICTOR_2;
+    }
+
+    if (len != 0)
+	return 0;
+
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+}
+
+/*
+ * ccp_reqci - processed a received configure-request.
+ * Returns CONFACK, CONFNAK or CONFREJ and the packet modified
+ * appropriately.
+ */
+static int
+ccp_reqci(
+    fsm *f,
+    u_char *p,
+    int *lenp,
+    int dont_nak)
+{
+    int ret, newret, res;
+    u_char *p0, *retp;
+    int len, clen, type, nb;
+    ccp_options *ho = &ccp_hisoptions[f->unit];
+    ccp_options *ao = &ccp_allowoptions[f->unit];
+
+    ret = CONFACK;
+    retp = p0 = p;
+    len = *lenp;
+
+    memset(ho, 0, sizeof(ccp_options));
+    ho->method = (len > 0)? p[0]: -1;
+
+    while (len > 0) {
+	newret = CONFACK;
+	if (len < 2 || p[1] < 2 || p[1] > len) {
+	    /* length is bad */
+	    clen = len;
+	    newret = CONFREJ;
+
+	} else {
+	    type = p[0];
+	    clen = p[1];
+
+	    switch (type) {
+	    case CI_DEFLATE:
+	    case CI_DEFLATE_DRAFT:
+		if (!ao->deflate || clen != CILEN_DEFLATE
+		    || (!ao->deflate_correct && type == CI_DEFLATE)
+		    || (!ao->deflate_draft && type == CI_DEFLATE_DRAFT)) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->deflate = 1;
+		ho->deflate_size = nb = DEFLATE_SIZE(p[2]);
+		if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL
+		    || p[3] != DEFLATE_CHK_SEQUENCE
+		    || nb > ao->deflate_size || nb < DEFLATE_MIN_SIZE) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = DEFLATE_MAKE_OPT(ao->deflate_size);
+			p[3] = DEFLATE_CHK_SEQUENCE;
+			/* fall through to test this #bits below */
+		    } else
+			break;
+		}
+
+		/*
+		 * Check whether we can do Deflate with the window
+		 * size they want.  If the window is too big, reduce
+		 * it until the kernel can cope and nak with that.
+		 * We only check this for the first option.
+		 */
+		if (p == p0) {
+		    for (;;) {
+			res = ccp_test(f->unit, p, CILEN_DEFLATE, 1);
+			if (res > 0)
+			    break;		/* it's OK now */
+			if (res < 0 || nb == DEFLATE_MIN_SIZE || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = DEFLATE_MAKE_OPT(ho->deflate_size);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = DEFLATE_MAKE_OPT(nb);
+		    }
+		}
+		break;
+
+	    case CI_BSD_COMPRESS:
+		if (!ao->bsd_compress || clen != CILEN_BSD_COMPRESS) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->bsd_compress = 1;
+		ho->bsd_bits = nb = BSD_NBITS(p[2]);
+		if (BSD_VERSION(p[2]) != BSD_CURRENT_VERSION
+		    || nb > ao->bsd_bits || nb < BSD_MIN_BITS) {
+		    newret = CONFNAK;
+		    if (!dont_nak) {
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, ao->bsd_bits);
+			/* fall through to test this #bits below */
+		    } else
+			break;
+		}
+
+		/*
+		 * Check whether we can do BSD-Compress with the code
+		 * size they want.  If the code size is too big, reduce
+		 * it until the kernel can cope and nak with that.
+		 * We only check this for the first option.
+		 */
+		if (p == p0) {
+		    for (;;) {
+			res = ccp_test(f->unit, p, CILEN_BSD_COMPRESS, 1);
+			if (res > 0)
+			    break;
+			if (res < 0 || nb == BSD_MIN_BITS || dont_nak) {
+			    newret = CONFREJ;
+			    p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION,
+						ho->bsd_bits);
+			    break;
+			}
+			newret = CONFNAK;
+			--nb;
+			p[2] = BSD_MAKE_OPT(BSD_CURRENT_VERSION, nb);
+		    }
+		}
+		break;
+
+	    case CI_PREDICTOR_1:
+		if (!ao->predictor_1 || clen != CILEN_PREDICTOR_1) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_1 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_1, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    case CI_PREDICTOR_2:
+		if (!ao->predictor_2 || clen != CILEN_PREDICTOR_2) {
+		    newret = CONFREJ;
+		    break;
+		}
+
+		ho->predictor_2 = 1;
+		if (p == p0
+		    && ccp_test(f->unit, p, CILEN_PREDICTOR_2, 1) <= 0) {
+		    newret = CONFREJ;
+		}
+		break;
+
+	    default:
+		newret = CONFREJ;
+	    }
+	}
+
+	if (newret == CONFNAK && dont_nak)
+	    newret = CONFREJ;
+	if (!(newret == CONFACK || (newret == CONFNAK && ret == CONFREJ))) {
+	    /* we're returning this option */
+	    if (newret == CONFREJ && ret == CONFNAK)
+		retp = p0;
+	    ret = newret;
+	    if (p != retp)
+		BCOPY(p, retp, clen);
+	    retp += clen;
+	}
+
+	p += clen;
+	len -= clen;
+    }
+
+    if (ret != CONFACK) {
+	if (ret == CONFREJ && *lenp == retp - p0)
+	    all_rejected[f->unit] = 1;
+	else
+	    *lenp = retp - p0;
+    }
+    return ret;
+}
+
+/*
+ * Make a string name for a compression method (or 2).
+ */
+static char *
+method_name(
+    ccp_options *opt,
+    ccp_options *opt2)
+{
+    static char result[64];
+
+    if (!ANY_COMPRESS(*opt))
+	return "(none)";
+    switch (opt->method) {
+    case CI_DEFLATE:
+    case CI_DEFLATE_DRAFT:
+	if (opt2 != NULL && opt2->deflate_size != opt->deflate_size)
+	    slprintf(result, sizeof(result), "Deflate%s (%d/%d)",
+		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		     opt->deflate_size, opt2->deflate_size);
+	else
+	    slprintf(result, sizeof(result), "Deflate%s (%d)",
+		     (opt->method == CI_DEFLATE_DRAFT? "(old#)": ""),
+		     opt->deflate_size);
+	break;
+    case CI_BSD_COMPRESS:
+	if (opt2 != NULL && opt2->bsd_bits != opt->bsd_bits)
+	    slprintf(result, sizeof(result), "BSD-Compress (%d/%d)",
+		     opt->bsd_bits, opt2->bsd_bits);
+	else
+	    slprintf(result, sizeof(result), "BSD-Compress (%d)",
+		     opt->bsd_bits);
+	break;
+    case CI_PREDICTOR_1:
+	return "Predictor 1";
+    case CI_PREDICTOR_2:
+	return "Predictor 2";
+    default:
+	slprintf(result, sizeof(result), "Method %d", opt->method);
+    }
+    return result;
+}
+
+/*
+ * CCP has come up - inform the kernel driver and log a message.
+ */
+static void
+ccp_up(
+    fsm *f)
+{
+    ccp_options *go = &ccp_gotoptions[f->unit];
+    ccp_options *ho = &ccp_hisoptions[f->unit];
+    char method1[64];
+
+    ccp_flags_set(f->unit, 1, 1);
+    if (ANY_COMPRESS(*go)) {
+	if (ANY_COMPRESS(*ho)) {
+	    if (go->method == ho->method) {
+		notice("%s compression enabled", method_name(go, ho));
+	    } else {
+		strlcpy(method1, method_name(go, NULL), sizeof(method1));
+		notice("%s / %s compression enabled",
+		       method1, method_name(ho, NULL));
+	    }
+	} else
+	    notice("%s receive compression enabled", method_name(go, NULL));
+    } else if (ANY_COMPRESS(*ho))
+	notice("%s transmit compression enabled", method_name(ho, NULL));
+}
+
+/*
+ * CCP has gone down - inform the kernel driver.
+ */
+static void
+ccp_down(
+    fsm *f)
+{
+    if (ccp_localstate[f->unit] & RACK_PENDING)
+	UNTIMEOUT(ccp_rack_timeout, f);
+    ccp_localstate[f->unit] = 0;
+    ccp_flags_set(f->unit, 1, 0);
+}
+
+/*
+ * Print the contents of a CCP packet.
+ */
+static char *ccp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej",
+    NULL, NULL, NULL, NULL, NULL, NULL,
+    "ResetReq", "ResetAck",
+};
+
+static int
+ccp_printpkt(
+    u_char *p,
+    int plen,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    u_char *p0, *optend;
+    int code, id, len;
+    int optlen;
+
+    p0 = p;
+    if (plen < HEADERLEN)
+	return 0;
+    code = p[0];
+    id = p[1];
+    len = (p[2] << 8) + p[3];
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ccp_codenames) / sizeof(char *)
+	&& ccp_codenames[code-1] != NULL)
+	printer(arg, " %s", ccp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    p += HEADERLEN;
+
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print list of possible compression methods */
+	while (len >= 2) {
+	    code = p[0];
+	    optlen = p[1];
+	    if (optlen < 2 || optlen > len)
+		break;
+	    printer(arg, " <");
+	    len -= optlen;
+	    optend = p + optlen;
+	    switch (code) {
+	    case CI_DEFLATE:
+	    case CI_DEFLATE_DRAFT:
+		if (optlen >= CILEN_DEFLATE) {
+		    printer(arg, "deflate%s %d",
+			    (code == CI_DEFLATE_DRAFT? "(old#)": ""),
+			    DEFLATE_SIZE(p[2]));
+		    if (DEFLATE_METHOD(p[2]) != DEFLATE_METHOD_VAL)
+			printer(arg, " method %d", DEFLATE_METHOD(p[2]));
+		    if (p[3] != DEFLATE_CHK_SEQUENCE)
+			printer(arg, " check %d", p[3]);
+		    p += CILEN_DEFLATE;
+		}
+		break;
+	    case CI_BSD_COMPRESS:
+		if (optlen >= CILEN_BSD_COMPRESS) {
+		    printer(arg, "bsd v%d %d", BSD_VERSION(p[2]),
+			    BSD_NBITS(p[2]));
+		    p += CILEN_BSD_COMPRESS;
+		}
+		break;
+	    case CI_PREDICTOR_1:
+		if (optlen >= CILEN_PREDICTOR_1) {
+		    printer(arg, "predictor 1");
+		    p += CILEN_PREDICTOR_1;
+		}
+		break;
+	    case CI_PREDICTOR_2:
+		if (optlen >= CILEN_PREDICTOR_2) {
+		    printer(arg, "predictor 2");
+		    p += CILEN_PREDICTOR_2;
+		}
+		break;
+	    }
+	    while (p < optend)
+		printer(arg, " %.2x", *p++);
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* dump out the rest of the packet in hex */
+    while (--len >= 0)
+	printer(arg, " %.2x", *p++);
+
+    return p - p0;
+}
+
+/*
+ * We have received a packet that the decompressor failed to
+ * decompress.  Here we would expect to issue a reset-request, but
+ * Motorola has a patent on resetting the compressor as a result of
+ * detecting an error in the decompressed data after decompression.
+ * (See US patent 5,130,993; international patent publication number
+ * WO 91/10289; Australian patent 73296/91.)
+ *
+ * So we ask the kernel whether the error was detected after
+ * decompression; if it was, we take CCP down, thus disabling
+ * compression :-(, otherwise we issue the reset-request.
+ */
+static void
+ccp_datainput(
+    int unit,
+    u_char *pkt,
+    int len)
+{
+    fsm *f;
+
+    f = &ccp_fsm[unit];
+    if (f->state == OPENED) {
+	if (ccp_fatal_error(unit)) {
+	    /*
+	     * Disable compression by taking CCP down.
+	     */
+	    error("Lost compression sync: disabling compression");
+	    ccp_close(unit, "Lost compression sync");
+	} else {
+	    /*
+	     * Send a reset-request to reset the peer's compressor.
+	     * We don't do that if we are still waiting for an
+	     * acknowledgement to a previous reset-request.
+	     */
+	    if (!(ccp_localstate[f->unit] & RACK_PENDING)) {
+		fsm_sdata(f, CCP_RESETREQ, f->reqid = ++f->id, NULL, 0);
+		TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+		ccp_localstate[f->unit] |= RACK_PENDING;
+	    } else
+		ccp_localstate[f->unit] |= RREQ_REPEAT;
+	}
+    }
+}
+
+/*
+ * Timeout waiting for reset-ack.
+ */
+static void
+ccp_rack_timeout(
+    void *arg)
+{
+    fsm *f = arg;
+
+    if (f->state == OPENED && ccp_localstate[f->unit] & RREQ_REPEAT) {
+	fsm_sdata(f, CCP_RESETREQ, f->reqid, NULL, 0);
+	TIMEOUT(ccp_rack_timeout, f, RACKTIMEOUT);
+	ccp_localstate[f->unit] &= ~RREQ_REPEAT;
+    } else
+	ccp_localstate[f->unit] &= ~RACK_PENDING;
+}
diff --git a/rtemsbsd/pppd/ccp.h b/rtemsbsd/pppd/ccp.h
new file mode 100644
index 0000000..609d858
--- /dev/null
+++ b/rtemsbsd/pppd/ccp.h
@@ -0,0 +1,48 @@
+/*
+ * ccp.h - Definitions for PPP Compression Control Protocol.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $Id$
+ */
+
+typedef struct ccp_options {
+    bool bsd_compress;		/* do BSD Compress? */
+    bool deflate;		/* do Deflate? */
+    bool predictor_1;		/* do Predictor-1? */
+    bool predictor_2;		/* do Predictor-2? */
+    bool deflate_correct;	/* use correct code for deflate? */
+    bool deflate_draft;		/* use draft RFC code for deflate? */
+    u_short bsd_bits;		/* # bits/code for BSD Compress */
+    u_short deflate_size;	/* lg(window size) for Deflate */
+    short method;		/* code for chosen compression method */
+} ccp_options;
+
+extern fsm ccp_fsm[];
+extern ccp_options ccp_wantoptions[];
+extern ccp_options ccp_gotoptions[];
+extern ccp_options ccp_allowoptions[];
+extern ccp_options ccp_hisoptions[];
+
+extern struct protent ccp_protent;
diff --git a/rtemsbsd/pppd/chap.c b/rtemsbsd/pppd/chap.c
new file mode 100644
index 0000000..3fe766f
--- /dev/null
+++ b/rtemsbsd/pppd/chap.c
@@ -0,0 +1,858 @@
+/*
+ * chap.c - Challenge Handshake Authentication Protocol.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Gregory M. Christy.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>	/* drand48, srand48 */
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "chap.h"
+#include "md5.h"
+#ifdef CHAPMS
+#include "chap_ms.h"
+#endif
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Command-line options.
+ */
+static option_t chap_option_list[] = {
+    { "chap-restart", o_int, &chap[0].timeouttime,
+      "Set timeout for CHAP", 0, NULL, 0, 0 },
+    { "chap-max-challenge", o_int, &chap[0].max_transmits,
+      "Set max #xmits for challenge", 0, NULL, 0, 0 },
+    { "chap-interval", o_int, &chap[0].chal_interval,
+      "Set interval for rechallenge", 0, NULL, 0, 0 },
+#ifdef MSLANMAN
+    { "ms-lanman", o_bool, &ms_lanman,
+      "Use LanMan passwd when using MS-CHAP", 1, NULL, 0, 0 },
+#endif
+    { NULL, 0, NULL, NULL, 0,  NULL, 0, 0 }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void ChapInit(int);
+static void ChapLowerUp(int);
+static void ChapLowerDown(int);
+static void ChapInput(int, u_char *, int);
+static void ChapProtocolReject(int);
+static int  ChapPrintPkt(u_char *, int,
+			      void (*)(void *, char *, ...), void *);
+
+struct protent chap_protent = {
+    PPP_CHAP,
+    ChapInit,
+    ChapInput,
+    ChapProtocolReject,
+    ChapLowerUp,
+    ChapLowerDown,
+    NULL,
+    NULL,
+    ChapPrintPkt,
+    NULL,
+    1,
+    "CHAP",
+    NULL,
+    chap_option_list,
+    NULL,
+    NULL,
+    NULL
+};
+
+chap_state chap[NUM_PPP];		/* CHAP state; one for each unit */
+
+static void ChapChallengeTimeout(void *);
+static void ChapResponseTimeout(void *);
+static void ChapReceiveChallenge(chap_state *, u_char *, int, int);
+static void ChapRechallenge(void *);
+static void ChapReceiveResponse(chap_state *, u_char *, int, int);
+static void ChapReceiveSuccess(chap_state *, u_char *, u_char, int);
+static void ChapReceiveFailure(chap_state *, u_char *, u_char, int);
+static void ChapSendStatus(chap_state *, int);
+static void ChapSendChallenge(chap_state *);
+static void ChapSendResponse(chap_state *);
+static void ChapGenChallenge(chap_state *);
+
+/*
+ * ChapInit - Initialize a CHAP unit.
+ */
+static void
+ChapInit(
+    int unit)
+{
+    chap_state *cstate = &chap[unit];
+
+    BZERO(cstate, sizeof(*cstate));
+    cstate->unit = unit;
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+    cstate->timeouttime = CHAP_DEFTIMEOUT;
+    cstate->max_transmits = CHAP_DEFTRANSMITS;
+    /* random number generator is initialized in magic_init */
+}
+
+
+/*
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).
+ *
+ */
+void
+ChapAuthWithPeer(
+    int unit,
+    char *our_name,
+    int digest)
+{
+    chap_state *cstate = &chap[unit];
+
+    cstate->resp_name = our_name;
+    cstate->resp_type = digest;
+
+    if (cstate->clientstate == CHAPCS_INITIAL ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->clientstate = CHAPCS_PENDING;
+	return;
+    }
+
+    /*
+     * We get here as a result of LCP coming up.
+     * So even if CHAP was open before, we will
+     * have to re-authenticate ourselves.
+     */
+    cstate->clientstate = CHAPCS_LISTEN;
+}
+
+
+/*
+ * ChapAuthPeer - Authenticate our peer (start server).
+ */
+void
+ChapAuthPeer(
+    int unit,
+    char *our_name,
+    int digest)
+{
+    chap_state *cstate = &chap[unit];
+
+    cstate->chal_name = our_name;
+    cstate->chal_type = digest;
+
+    if (cstate->serverstate == CHAPSS_INITIAL ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	/* lower layer isn't up - wait until later */
+	cstate->serverstate = CHAPSS_PENDING;
+	return;
+    }
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);		/* crank it up dude! */
+    cstate->serverstate = CHAPSS_INITIAL_CHAL;
+}
+
+
+/*
+ * ChapChallengeTimeout - Timeout expired on sending challenge.
+ */
+static void
+ChapChallengeTimeout(
+    void *arg)
+{
+    chap_state *cstate = (chap_state *) arg;
+
+    /* if we aren't sending challenges, don't worry.  then again we */
+    /* probably shouldn't be here either */
+    if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
+	cstate->serverstate != CHAPSS_RECHALLENGE)
+	return;
+
+    if (cstate->chal_transmits >= cstate->max_transmits) {
+	/* give up on peer */
+	error("Peer failed to respond to CHAP challenge");
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->unit, PPP_CHAP);
+	return;
+    }
+
+    ChapSendChallenge(cstate);		/* Re-send challenge */
+}
+
+
+/*
+ * ChapResponseTimeout - Timeout expired on sending response.
+ */
+static void
+ChapResponseTimeout(
+    void *arg)
+{
+    chap_state *cstate = (chap_state *) arg;
+
+    /* if we aren't sending a response, don't worry. */
+    if (cstate->clientstate != CHAPCS_RESPONSE)
+	return;
+
+    ChapSendResponse(cstate);		/* re-send response */
+}
+
+
+/*
+ * ChapRechallenge - Time to challenge the peer again.
+ */
+static void
+ChapRechallenge(
+    void *arg)
+{
+    chap_state *cstate = (chap_state *) arg;
+
+    /* if we aren't sending a response, don't worry. */
+    if (cstate->serverstate != CHAPSS_OPEN)
+	return;
+
+    ChapGenChallenge(cstate);
+    ChapSendChallenge(cstate);
+    cstate->serverstate = CHAPSS_RECHALLENGE;
+}
+
+
+/*
+ * ChapLowerUp - The lower layer is up.
+ *
+ * Start up if we have pending requests.
+ */
+static void
+ChapLowerUp(
+    int unit)
+{
+    chap_state *cstate = &chap[unit];
+
+    if (cstate->clientstate == CHAPCS_INITIAL)
+	cstate->clientstate = CHAPCS_CLOSED;
+    else if (cstate->clientstate == CHAPCS_PENDING)
+	cstate->clientstate = CHAPCS_LISTEN;
+
+    if (cstate->serverstate == CHAPSS_INITIAL)
+	cstate->serverstate = CHAPSS_CLOSED;
+    else if (cstate->serverstate == CHAPSS_PENDING) {
+	ChapGenChallenge(cstate);
+	ChapSendChallenge(cstate);
+	cstate->serverstate = CHAPSS_INITIAL_CHAL;
+    }
+}
+
+
+/*
+ * ChapLowerDown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+ChapLowerDown(
+    int unit)
+{
+    chap_state *cstate = &chap[unit];
+
+    /* Timeout(s) pending?  Cancel if so. */
+    if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
+	cstate->serverstate == CHAPSS_RECHALLENGE)
+	UNTIMEOUT(ChapChallengeTimeout, cstate);
+    else if (cstate->serverstate == CHAPSS_OPEN
+	     && cstate->chal_interval != 0)
+	UNTIMEOUT(ChapRechallenge, cstate);
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->clientstate = CHAPCS_INITIAL;
+    cstate->serverstate = CHAPSS_INITIAL;
+}
+
+
+/*
+ * ChapProtocolReject - Peer doesn't grok CHAP.
+ */
+static void
+ChapProtocolReject(
+    int unit)
+{
+    chap_state *cstate = &chap[unit];
+
+    if (cstate->serverstate != CHAPSS_INITIAL &&
+	cstate->serverstate != CHAPSS_CLOSED)
+	auth_peer_fail(unit, PPP_CHAP);
+    if (cstate->clientstate != CHAPCS_INITIAL &&
+	cstate->clientstate != CHAPCS_CLOSED)
+	auth_withpeer_fail(unit, PPP_CHAP);
+    ChapLowerDown(unit);		/* shutdown chap */
+}
+
+
+/*
+ * ChapInput - Input CHAP packet.
+ */
+static void
+ChapInput(
+    int unit,
+    u_char *inpacket,
+    int packet_len)
+{
+    chap_state *cstate = &chap[unit];
+    u_char *inp;
+    u_char code, id;
+    int len;
+
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (packet_len < CHAP_HEADERLEN) {
+	CHAPDEBUG(("ChapInput: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < CHAP_HEADERLEN) {
+	CHAPDEBUG(("ChapInput: rcvd illegal length."));
+	return;
+    }
+    if (len > packet_len) {
+	CHAPDEBUG(("ChapInput: rcvd short packet."));
+	return;
+    }
+    len -= CHAP_HEADERLEN;
+
+    /*
+     * Action depends on code (as in fact it usually does :-).
+     */
+    switch (code) {
+    case CHAP_CHALLENGE:
+	ChapReceiveChallenge(cstate, inp, id, len);
+	break;
+
+    case CHAP_RESPONSE:
+	ChapReceiveResponse(cstate, inp, id, len);
+	break;
+
+    case CHAP_FAILURE:
+	ChapReceiveFailure(cstate, inp, id, len);
+	break;
+
+    case CHAP_SUCCESS:
+	ChapReceiveSuccess(cstate, inp, id, len);
+	break;
+
+    default:				/* Need code reject? */
+	warn("Unknown CHAP code (%d) received.", code);
+	break;
+    }
+}
+
+
+/*
+ * ChapReceiveChallenge - Receive Challenge and send Response.
+ */
+static void
+ChapReceiveChallenge(
+    chap_state *cstate,
+    u_char *inp,
+    int id,
+    int len)
+{
+    int rchallenge_len;
+    u_char *rchallenge;
+    int secret_len;
+    unsigned char secret[MAXSECRETLEN];
+    char rhostname[256];
+    MD5_CTX mdContext;
+    u_char hash[MD5_SIGNATURE_SIZE];
+
+    if (cstate->clientstate == CHAPCS_CLOSED ||
+	cstate->clientstate == CHAPCS_PENDING) {
+	CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+
+    GETCHAR(rchallenge_len, inp);
+    len -= sizeof (u_char) + rchallenge_len;	/* now name field length */
+    if (len < 0) {
+	CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
+	return;
+    }
+    rchallenge = inp;
+    INCPTR(rchallenge_len, inp);
+
+    if (len >= sizeof(rhostname))
+	len = sizeof(rhostname) - 1;
+    BCOPY(inp, rhostname, len);
+    rhostname[len] = '\000';
+
+    /* Microsoft doesn't send their name back in the PPP packet */
+    if (explicit_remote || (remote_name[0] != 0 && rhostname[0] == 0)) {
+	strlcpy(rhostname, remote_name, sizeof(rhostname));
+	CHAPDEBUG(("ChapReceiveChallenge: using '%q' as remote name",
+		   rhostname));
+    }
+
+    /* get secret for authenticating ourselves with the specified host */
+    if (!get_secret(cstate->unit, cstate->resp_name, rhostname,
+		    secret, &secret_len, 0)) {
+	secret_len = 0;		/* assume null secret if can't find one */
+	warn("No CHAP secret found for authenticating us to %q", rhostname);
+    }
+
+    /* cancel response send timeout if necessary */
+    if (cstate->clientstate == CHAPCS_RESPONSE)
+	UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    cstate->resp_id = id;
+    cstate->resp_transmits = 0;
+
+    /*  generate MD based on negotiated type */
+    switch (cstate->resp_type) {
+
+    case CHAP_DIGEST_MD5:
+	MD5Init(&mdContext);
+	MD5Update(&mdContext, &cstate->resp_id, 1);
+	MD5Update(&mdContext, secret, secret_len);
+	MD5Update(&mdContext, rchallenge, rchallenge_len);
+	MD5Final(hash, &mdContext);
+	BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
+	cstate->resp_length = MD5_SIGNATURE_SIZE;
+	break;
+
+#ifdef CHAPMS
+    case CHAP_MICROSOFT:
+	ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
+	break;
+#endif
+
+    default:
+	CHAPDEBUG(("unknown digest type %d", cstate->resp_type));
+	return;
+    }
+
+    BZERO(secret, sizeof(secret));
+    ChapSendResponse(cstate);
+}
+
+
+/*
+ * ChapReceiveResponse - Receive and process response.
+ */
+static void
+ChapReceiveResponse(
+    chap_state *cstate,
+    u_char *inp,
+    int id,
+    int len)
+{
+    u_char *remmd, remmd_len;
+    int secret_len, old_state;
+    int code;
+    char rhostname[256];
+    MD5_CTX mdContext;
+    unsigned char secret[MAXSECRETLEN];
+    u_char hash[MD5_SIGNATURE_SIZE];
+
+    if (cstate->serverstate == CHAPSS_CLOSED ||
+	cstate->serverstate == CHAPSS_PENDING) {
+	CHAPDEBUG(("ChapReceiveResponse: in state %d", cstate->serverstate));
+	return;
+    }
+
+    if (id != cstate->chal_id)
+	return;			/* doesn't match ID of last challenge */
+
+    /*
+     * If we have received a duplicate or bogus Response,
+     * we have to send the same answer (Success/Failure)
+     * as we did for the first Response we saw.
+     */
+    if (cstate->serverstate == CHAPSS_OPEN) {
+	ChapSendStatus(cstate, CHAP_SUCCESS);
+	return;
+    }
+    if (cstate->serverstate == CHAPSS_BADAUTH) {
+	ChapSendStatus(cstate, CHAP_FAILURE);
+	return;
+    }
+
+    if (len < 2) {
+	CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+	return;
+    }
+    GETCHAR(remmd_len, inp);		/* get length of MD */
+    remmd = inp;			/* get pointer to MD */
+    INCPTR(remmd_len, inp);
+
+    len -= sizeof (u_char) + remmd_len;
+    if (len < 0) {
+	CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
+	return;
+    }
+
+    UNTIMEOUT(ChapChallengeTimeout, cstate);
+
+    if (len >= sizeof(rhostname))
+	len = sizeof(rhostname) - 1;
+    BCOPY(inp, rhostname, len);
+    rhostname[len] = '\000';
+
+    /*
+     * Get secret for authenticating them with us,
+     * do the hash ourselves, and compare the result.
+     */
+    code = CHAP_FAILURE;
+    if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname),
+		    cstate->chal_name, secret, &secret_len, 1)) {
+	warn("No CHAP secret found for authenticating %q", rhostname);
+    } else {
+
+	/*  generate MD based on negotiated type */
+	switch (cstate->chal_type) {
+
+	case CHAP_DIGEST_MD5:		/* only MD5 is defined for now */
+	    if (remmd_len != MD5_SIGNATURE_SIZE)
+		break;			/* it's not even the right length */
+	    MD5Init(&mdContext);
+	    MD5Update(&mdContext, &cstate->chal_id, 1);
+	    MD5Update(&mdContext, secret, secret_len);
+	    MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
+	    MD5Final(hash, &mdContext);
+
+	    /* compare local and remote MDs and send the appropriate status */
+	    if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
+		code = CHAP_SUCCESS;	/* they are the same! */
+	    break;
+
+	default:
+	    CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
+	}
+    }
+
+    BZERO(secret, sizeof(secret));
+    ChapSendStatus(cstate, code);
+
+    if (code == CHAP_SUCCESS) {
+	old_state = cstate->serverstate;
+	cstate->serverstate = CHAPSS_OPEN;
+	if (old_state == CHAPSS_INITIAL_CHAL) {
+	    auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
+	}
+	if (cstate->chal_interval != 0)
+	    TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
+	notice("CHAP peer authentication succeeded for %q", rhostname);
+
+    } else {
+	error("CHAP peer authentication failed for remote host %q", rhostname);
+	cstate->serverstate = CHAPSS_BADAUTH;
+	auth_peer_fail(cstate->unit, PPP_CHAP);
+    }
+}
+
+/*
+ * ChapReceiveSuccess - Receive Success
+ */
+static void
+ChapReceiveSuccess(
+    chap_state *cstate,
+    u_char *inp,
+    u_char id,
+    int len)
+{
+
+    if (cstate->clientstate == CHAPCS_OPEN)
+	/* presumably an answer to a duplicate response */
+	return;
+
+    if (cstate->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG(("ChapReceiveSuccess: in state %d\n", cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    cstate->clientstate = CHAPCS_OPEN;
+
+    auth_withpeer_success(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapReceiveFailure - Receive failure.
+ */
+static void
+ChapReceiveFailure(
+    chap_state *cstate,
+    u_char *inp,
+    u_char id,
+    int len)
+{
+    if (cstate->clientstate != CHAPCS_RESPONSE) {
+	/* don't know what this is */
+	CHAPDEBUG(("ChapReceiveFailure: in state %d\n", cstate->clientstate));
+	return;
+    }
+
+    UNTIMEOUT(ChapResponseTimeout, cstate);
+
+    /*
+     * Print message.
+     */
+    if (len > 0)
+	PRINTMSG(inp, len);
+
+    error("CHAP authentication failed");
+    auth_withpeer_fail(cstate->unit, PPP_CHAP);
+}
+
+
+/*
+ * ChapSendChallenge - Send an Authenticate challenge.
+ */
+static void
+ChapSendChallenge(
+    chap_state *cstate)
+{
+    u_char *outp;
+    int chal_len, name_len;
+    int outlen;
+
+    chal_len = cstate->chal_len;
+    name_len = strlen(cstate->chal_name);
+    outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);		/* paste in a CHAP header */
+
+    PUTCHAR(CHAP_CHALLENGE, outp);
+    PUTCHAR(cstate->chal_id, outp);
+    PUTSHORT(outlen, outp);
+
+    PUTCHAR(chal_len, outp);		/* put length of challenge */
+    BCOPY(cstate->challenge, outp, chal_len);
+    INCPTR(chal_len, outp);
+
+    BCOPY(cstate->chal_name, outp, name_len);	/* append hostname */
+
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
+    ++cstate->chal_transmits;
+}
+
+
+/*
+ * ChapSendStatus - Send a status response (ack or nak).
+ */
+static void
+ChapSendStatus(
+    chap_state *cstate,
+    int code)
+{
+    u_char *outp;
+    int outlen, msglen;
+    char msg[256];
+
+    if (code == CHAP_SUCCESS)
+	slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
+    else
+	slprintf(msg, sizeof(msg), "I don't like you.  Go 'way.");
+    msglen = strlen(msg);
+
+    outlen = CHAP_HEADERLEN + msglen;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);	/* paste in a header */
+
+    PUTCHAR(code, outp);
+    PUTCHAR(cstate->chal_id, outp);
+    PUTSHORT(outlen, outp);
+    BCOPY(msg, outp, msglen);
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+/*
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of
+ * a pseudo-random length between min_len and max_len.  The challenge
+ * string and its length are stored in *cstate, and various other fields of
+ * *cstate are initialized.
+ */
+
+static void
+ChapGenChallenge(
+    chap_state *cstate)
+{
+    int chal_len;
+    u_char *ptr = cstate->challenge;
+    int i;
+
+    /* pick a random challenge length between MIN_CHALLENGE_LENGTH and
+       MAX_CHALLENGE_LENGTH */
+    chal_len =  (unsigned) ((drand48() *
+			     (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
+			    MIN_CHALLENGE_LENGTH);
+    cstate->chal_len = chal_len;
+    cstate->chal_id = ++cstate->id;
+    cstate->chal_transmits = 0;
+
+    /* generate a random string */
+    for (i = 0; i < chal_len; i++)
+	*ptr++ = (char) (drand48() * 0xff);
+}
+
+/*
+ * ChapSendResponse - send a response packet with values as specified
+ * in *cstate.
+ */
+/* ARGSUSED */
+static void
+ChapSendResponse(
+    chap_state *cstate)
+{
+    u_char *outp;
+    int outlen, md_len, name_len;
+
+    md_len = cstate->resp_length;
+    name_len = strlen(cstate->resp_name);
+    outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_CHAP);
+
+    PUTCHAR(CHAP_RESPONSE, outp);	/* we are a response */
+    PUTCHAR(cstate->resp_id, outp);	/* copy id from challenge packet */
+    PUTSHORT(outlen, outp);		/* packet length */
+
+    PUTCHAR(md_len, outp);		/* length of MD */
+    BCOPY(cstate->response, outp, md_len);	/* copy MD to buffer */
+    INCPTR(md_len, outp);
+
+    BCOPY(cstate->resp_name, outp, name_len); /* append our name */
+
+    /* send the packet */
+    output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    cstate->clientstate = CHAPCS_RESPONSE;
+    TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
+    ++cstate->resp_transmits;
+}
+
+/*
+ * ChapPrintPkt - print the contents of a CHAP packet.
+ */
+static char *ChapCodenames[] = {
+    "Challenge", "Response", "Success", "Failure"
+};
+
+static int
+ChapPrintPkt(
+    u_char *p,
+    int plen,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int code, id, len;
+    int clen, nlen;
+    u_char x;
+
+    if (plen < CHAP_HEADERLEN)
+	return 0;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < CHAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
+	printer(arg, " %s", ChapCodenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= CHAP_HEADERLEN;
+    switch (code) {
+    case CHAP_CHALLENGE:
+    case CHAP_RESPONSE:
+	if (len < 1)
+	    break;
+	clen = p[0];
+	if (len < clen + 1)
+	    break;
+	++p;
+	nlen = len - clen - 1;
+	printer(arg, " <");
+	for (; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, "%.2x", x);
+	}
+	printer(arg, ">, name = ");
+	print_string((char *)p, nlen, printer, arg);
+	break;
+    case CHAP_FAILURE:
+    case CHAP_SUCCESS:
+	printer(arg, " ");
+	print_string((char *)p, len, printer, arg);
+	break;
+    default:
+	for (clen = len; clen > 0; --clen) {
+	    GETCHAR(x, p);
+	    printer(arg, " %.2x", x);
+	}
+    }
+
+    return len + CHAP_HEADERLEN;
+}
diff --git a/rtemsbsd/pppd/chap.h b/rtemsbsd/pppd/chap.h
new file mode 100644
index 0000000..7883355
--- /dev/null
+++ b/rtemsbsd/pppd/chap.h
@@ -0,0 +1,124 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Copyright (c) 1991 Gregory M. Christy
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the author.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+#ifndef __CHAP_INCLUDE__
+
+/* Code + ID + length */
+#define CHAP_HEADERLEN		4
+
+/*
+ * CHAP codes.
+ */
+
+#define CHAP_DIGEST_MD5		5	/* use MD5 algorithm */
+#define MD5_SIGNATURE_SIZE	16	/* 16 bytes in a MD5 message digest */
+#define CHAP_MICROSOFT		0x80	/* use Microsoft-compatible alg. */
+#define MS_CHAP_RESPONSE_LEN	49	/* Response length for MS-CHAP */
+
+#define CHAP_CHALLENGE		1
+#define CHAP_RESPONSE		2
+#define CHAP_SUCCESS		3
+#define CHAP_FAILURE    	4
+
+/*
+ *  Challenge lengths (for challenges we send) and other limits.
+ */
+#define MIN_CHALLENGE_LENGTH	16
+#define MAX_CHALLENGE_LENGTH	24
+#define MAX_RESPONSE_LENGTH	64	/* sufficient for MD5 or MS-CHAP */
+
+/*
+ * Each interface is described by a chap structure.
+ */
+
+typedef struct chap_state {
+    int unit;			/* Interface unit number */
+    int clientstate;		/* Client state */
+    int serverstate;		/* Server state */
+    u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */
+    u_char chal_len;		/* challenge length */
+    u_char chal_id;		/* ID of last challenge */
+    u_char chal_type;		/* hash algorithm for challenges */
+    u_char id;			/* Current id */
+    char *chal_name;		/* Our name to use with challenge */
+    int chal_interval;		/* Time until we challenge peer again */
+    int timeouttime;		/* Timeout time in seconds */
+    int max_transmits;		/* Maximum # of challenge transmissions */
+    int chal_transmits;		/* Number of transmissions of challenge */
+    int resp_transmits;		/* Number of transmissions of response */
+    u_char response[MAX_RESPONSE_LENGTH];	/* Response to send */
+    u_char resp_length;		/* length of response */
+    u_char resp_id;		/* ID for response messages */
+    u_char resp_type;		/* hash algorithm for responses */
+    char *resp_name;		/* Our name to send with response */
+} chap_state;
+
+
+/*
+ * Client (peer) states.
+ */
+#define CHAPCS_INITIAL		0	/* Lower layer down, not opened */
+#define CHAPCS_CLOSED		1	/* Lower layer up, not opened */
+#define CHAPCS_PENDING		2	/* Auth us to peer when lower up */
+#define CHAPCS_LISTEN		3	/* Listening for a challenge */
+#define CHAPCS_RESPONSE		4	/* Sent response, waiting for status */
+#define CHAPCS_OPEN		5	/* We've received Success */
+
+/*
+ * Server (authenticator) states.
+ */
+#define CHAPSS_INITIAL		0	/* Lower layer down, not opened */
+#define CHAPSS_CLOSED		1	/* Lower layer up, not opened */
+#define CHAPSS_PENDING		2	/* Auth peer when lower up */
+#define CHAPSS_INITIAL_CHAL	3	/* We've sent the first challenge */
+#define CHAPSS_OPEN		4	/* We've sent a Success msg */
+#define CHAPSS_RECHALLENGE	5	/* We've sent another challenge */
+#define CHAPSS_BADAUTH		6	/* We've sent a Failure msg */
+
+/*
+ * Timeouts.
+ */
+#define CHAP_DEFTIMEOUT		5	/* Timeout time in seconds */
+#define CHAP_DEFTRANSMITS	10	/* max # times to send challenge */
+
+extern chap_state chap[];
+
+void ChapAuthWithPeer(int, char *, int);
+void ChapAuthPeer(int, char *, int);
+
+extern struct protent chap_protent;
+
+#define __CHAP_INCLUDE__
+#endif /* __CHAP_INCLUDE__ */
diff --git a/rtemsbsd/pppd/chap_ms.c b/rtemsbsd/pppd/chap_ms.c
new file mode 100644
index 0000000..3ccf83a
--- /dev/null
+++ b/rtemsbsd/pppd/chap_ms.c
@@ -0,0 +1,338 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen at clinet.fi, april 1997
+ *
+ *   Implemented LANManager type password response to MS-CHAP challenges.
+ *   Now pppd provides both NT style and LANMan style blocks, and the
+ *   prefered is set by option "ms-lanman". Default is to use NT.
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+#define RCSID	"$Id$"
+
+#ifdef CHAPMS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#ifdef HAVE_CRYPT_H
+#include <crypt.h>
+#endif
+
+#include "pppd.h"
+#include "chap.h"
+#include "chap_ms.h"
+#include "md4.h"
+
+#ifndef USE_CRYPT
+#include <des.h>
+#endif
+
+static const char rcsid[] = RCSID;
+
+typedef struct {
+    u_char LANManResp[24];
+    u_char NTResp[24];
+    u_char UseNT;		/* If 1, ignore the LANMan response field */
+} MS_ChapResponse;
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),
+   in case this struct gets padded. */
+
+
+static void	ChallengeResponse(u_char *, u_char *, u_char *);
+static void	DesEncrypt(u_char *, u_char *, u_char *);
+static void	MakeKey(u_char *, u_char *);
+static u_char	Get7Bits(u_char *, int);
+static void	ChapMS_NT(char *, int, char *, int, MS_ChapResponse *);
+#ifdef MSLANMAN
+static void	ChapMS_LANMan(char *, int, char *, int, MS_ChapResponse *);
+#endif
+
+#ifdef USE_CRYPT
+static void	Expand(u_char *, u_char *);
+static void	Collapse(u_char *, u_char *);
+#endif
+
+#ifdef MSLANMAN
+bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
+			  	/* Has meaning only with MS-CHAP challenges */
+#endif
+
+static void
+ChallengeResponse(challenge, pwHash, response)
+    u_char *challenge;	/* IN   8 octets */
+    u_char *pwHash;	/* IN  16 octets */
+    u_char *response;	/* OUT 24 octets */
+{
+    char    ZPasswordHash[21];
+
+    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+    BCOPY(pwHash, ZPasswordHash, MD4_SIGNATURE_SIZE);
+
+#if 0
+    dbglog("ChallengeResponse - ZPasswordHash %.*B",
+	   sizeof(ZPasswordHash), ZPasswordHash);
+#endif
+
+    DesEncrypt(challenge, ZPasswordHash +  0, response + 0);
+    DesEncrypt(challenge, ZPasswordHash +  7, response + 8);
+    DesEncrypt(challenge, ZPasswordHash + 14, response + 16);
+
+#if 0
+    dbglog("ChallengeResponse - response %.24B", response);
+#endif
+}
+
+
+#ifdef USE_CRYPT
+static void
+DesEncrypt(clear, key, cipher)
+    u_char *clear;	/* IN  8 octets */
+    u_char *key;	/* IN  7 octets */
+    u_char *cipher;	/* OUT 8 octets */
+{
+    u_char des_key[8];
+    u_char crypt_key[66];
+    u_char des_input[66];
+
+    MakeKey(key, des_key);
+
+    Expand(des_key, crypt_key);
+    setkey(crypt_key);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+    Expand(clear, des_input);
+    encrypt(des_input, 0);
+    Collapse(des_input, cipher);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
+#endif
+}
+
+#else /* USE_CRYPT */
+
+static void
+DesEncrypt(clear, key, cipher)
+    u_char *clear;	/* IN  8 octets */
+    u_char *key;	/* IN  7 octets */
+    u_char *cipher;	/* OUT 8 octets */
+{
+    des_cblock		des_key;
+    des_key_schedule	key_schedule;
+
+    MakeKey(key, des_key);
+
+    des_set_key(&des_key, key_schedule);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %.8B", clear));
+#endif
+
+    des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %.8B", cipher));
+#endif
+}
+
+#endif /* USE_CRYPT */
+
+
+static u_char Get7Bits(input, startBit)
+    u_char *input;
+    int startBit;
+{
+    register unsigned int	word;
+
+    word  = (unsigned)input[startBit / 8] << 8;
+    word |= (unsigned)input[startBit / 8 + 1];
+
+    word >>= 15 - (startBit % 8 + 7);
+
+    return word & 0xFE;
+}
+
+#ifdef USE_CRYPT
+
+/* in == 8-byte string (expanded version of the 56-bit key)
+ * out == 64-byte string where each byte is either 1 or 0
+ * Note that the low-order "bit" is always ignored by by setkey()
+ */
+static void Expand(in, out)
+    u_char *in;
+    u_char *out;
+{
+        int j, c;
+        int i;
+
+        for(i = 0; i < 64; in++){
+		c = *in;
+                for(j = 7; j >= 0; j--)
+                        *out++ = (c >> j) & 01;
+                i += 8;
+        }
+}
+
+/* The inverse of Expand
+ */
+static void Collapse(in, out)
+    u_char *in;
+    u_char *out;
+{
+        int j;
+        int i;
+	unsigned int c;
+
+	for (i = 0; i < 64; i += 8, out++) {
+	    c = 0;
+	    for (j = 7; j >= 0; j--, in++)
+		c |= *in << j;
+	    *out = c & 0xff;
+	}
+}
+#endif
+
+static void MakeKey(key, des_key)
+    u_char *key;	/* IN  56 bit DES key missing parity bits */
+    u_char *des_key;	/* OUT 64 bit DES key with parity bits added */
+{
+    des_key[0] = Get7Bits(key,  0);
+    des_key[1] = Get7Bits(key,  7);
+    des_key[2] = Get7Bits(key, 14);
+    des_key[3] = Get7Bits(key, 21);
+    des_key[4] = Get7Bits(key, 28);
+    des_key[5] = Get7Bits(key, 35);
+    des_key[6] = Get7Bits(key, 42);
+    des_key[7] = Get7Bits(key, 49);
+
+#ifndef USE_CRYPT
+    des_set_odd_parity((des_cblock *)des_key);
+#endif
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %.7B", key));
+    CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %.8B", des_key));
+#endif
+}
+
+static void
+ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, response)
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+    MS_ChapResponse    *response;
+{
+    int			i;
+#ifdef __NetBSD__
+    /* NetBSD uses the libc md4 routines which take bytes instead of bits */
+    int			mdlen = secret_len * 2;
+#else
+    int			mdlen = secret_len * 2 * 8;
+#endif
+    MD4_CTX		md4Context;
+    u_char		hash[MD4_SIGNATURE_SIZE];
+    u_char		unicodePassword[MAX_NT_PASSWORD * 2];
+
+    /* Initialize the Unicode version of the secret (== password). */
+    /* This implicitly supports 8-bit ISO8859/1 characters. */
+    BZERO(unicodePassword, sizeof(unicodePassword));
+    for (i = 0; i < secret_len; i++)
+	unicodePassword[i * 2] = (u_char)secret[i];
+
+    MD4Init(&md4Context);
+    MD4Update(&md4Context, unicodePassword, mdlen);
+
+    MD4Final(hash, &md4Context); 	/* Tell MD4 we're done */
+
+    ChallengeResponse(rchallenge, hash, response->NTResp);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static void
+ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, response)
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+    MS_ChapResponse	*response;
+{
+    int			i;
+    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+    u_char		PasswordHash[MD4_SIGNATURE_SIZE];
+
+    /* LANMan password is case insensitive */
+    BZERO(UcasePassword, sizeof(UcasePassword));
+    for (i = 0; i < secret_len; i++)
+       UcasePassword[i] = (u_char)toupper(secret[i]);
+    DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );
+    DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );
+    ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);
+}
+#endif
+
+void
+ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len)
+    chap_state *cstate;
+    char *rchallenge;
+    int rchallenge_len;
+    char *secret;
+    int secret_len;
+{
+    MS_ChapResponse	response;
+
+#if 0
+    CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'", secret_len, secret));
+#endif
+    BZERO(&response, sizeof(response));
+
+    /* Calculate both always */
+    ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+#ifdef MSLANMAN
+    ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);
+
+    /* prefered method is set by option  */
+    response.UseNT = !ms_lanman;
+#else
+    response.UseNT = 1;
+#endif
+
+    BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);
+    cstate->resp_length = MS_CHAP_RESPONSE_LEN;
+}
+
+#endif /* CHAPMS */
diff --git a/rtemsbsd/pppd/chap_ms.h b/rtemsbsd/pppd/chap_ms.h
new file mode 100644
index 0000000..5776251
--- /dev/null
+++ b/rtemsbsd/pppd/chap_ms.h
@@ -0,0 +1,33 @@
+/*
+ * chap.h - Challenge Handshake Authentication Protocol definitions.
+ *
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.
+ * http://www.strataware.com/
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Eric Rosenquist.  The name of the author may not be used to
+ * endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+#ifndef __CHAPMS_INCLUDE__
+
+#define MD4_SIGNATURE_SIZE	16	/* 16 bytes in a MD4 message digest */
+#define MAX_NT_PASSWORD	256	/* Maximum number of (Unicode) chars in an NT password */
+
+void ChapMS(chap_state *, char *, int, char *, int);
+
+#define __CHAPMS_INCLUDE__
+#endif /* __CHAPMS_INCLUDE__ */
diff --git a/rtemsbsd/pppd/chat.c b/rtemsbsd/pppd/chat.c
new file mode 100644
index 0000000..45e2707
--- /dev/null
+++ b/rtemsbsd/pppd/chat.c
@@ -0,0 +1,854 @@
+/*
+ *	Chat -- a program for automatic session establishment (i.e. dial
+ *		the phone and log in).
+ *
+ * Standard termination codes:
+ *  0 - successful completion of the script
+ *  1 - invalid argument, expect string too large, etc.
+ *  2 - error on an I/O operation or fatal error condition.
+ *  3 - timeout waiting for a simple string.
+ *  4 - the first string declared as "ABORT"
+ *  5 - the second string declared as "ABORT"
+ *  6 - ... and so on for successive ABORT strings.
+ *
+ *	This software is in the public domain.
+ *
+ * -----------------
+ *	22-May-99 added environment substitutuion, enabled with -E switch.
+ *	Andreas Arens <andras at cityweb.de>.
+ *
+ *	12-May-99 added a feature to read data to be sent from a file,
+ *	if the send string starts with @.  Idea from gpk <gpk at onramp.net>.
+ *
+ *	added -T and -U option and \T and \U substitution to pass a phone
+ *	number into chat script. Two are needed for some ISDN TA applications.
+ *	Keith Dart <kdart at cisco.com>
+ *	
+ *
+ *	Added SAY keyword to send output to stderr.
+ *      This allows to turn ECHO OFF and to output specific, user selected,
+ *      text to give progress messages. This best works when stderr
+ *      exists (i.e.: pppd in nodetach mode).
+ *
+ * 	Added HANGUP directives to allow for us to be called
+ *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
+ *      We rely on timeouts in that case.
+ *
+ *      Added CLR_ABORT to clear previously set ABORT string. This has been
+ *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
+ *      an ABORT condition until we know the other host is going to close
+ *      the connection for call back. As soon as we have completed the
+ *      first stage of the call back sequence, "NO CARRIER" is a valid, non
+ *      fatal string. As soon as we got called back (probably get "CONNECT"),
+ *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
+ *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
+ *      have unused entries not being reclaimed.
+ *
+ *      In the same vein as above, added CLR_REPORT keyword.
+ *
+ *      Allow for comments. Line starting with '#' are comments and are
+ *      ignored. If a '#' is to be expected as the first character, the
+ *      expect string must be quoted.
+ *
+ *
+ *		Francis Demierre <Francis at SwissMail.Com>
+ * 		Thu May 15 17:15:40 MET DST 1997
+ *
+ *
+ *      Added -r "report file" switch & REPORT keyword.
+ *              Robert Geer <bgeer at xmission.com>
+ *
+ *      Added -s "use stderr" and -S "don't use syslog" switches.
+ *              June 18, 1997
+ *              Karl O. Pinc <kop at meme.com>
+ *
+ *
+ *	Added -e "echo" switch & ECHO keyword
+ *		Dick Streefland <dicks at tasking.nl>
+ *
+ *
+ *	Considerable updates and modifications by
+ *		Al Longyear <longyear at pobox.com>
+ *		Paul Mackerras <paulus at cs.anu.edu.au>
+ *
+ *
+ *	The original author is:
+ *
+ *		Karl Fox <karl at MorningStar.Com>
+ *		Morning Star Technologies, Inc.
+ *		1760 Zollinger Road
+ *		Columbus, OH  43221
+ *		(614)451-1883
+ *
+ */
+
+/*	$Id$ */
+
+/*
+	Fixes and some Changes by Wilfried Busalski Lancier-Monitoring GmbH Germany
+	wilfried.busalski at muenster.de
+	
+	Fixes:	put_string()		Free memory allocated by clean()
+			get_string()		Free memory allocated by clean()
+			chat_main()			Will Distroy's no more the chat-script
+			getnextcommand()	sepatator changed to '@'
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <syslog.h>
+#include <termios.h>
+#include "pppd.h"
+
+#undef	TERMIOS
+#define TERMIOS
+
+
+#define	STR_LEN	1024
+char temp2[STR_LEN];
+
+#ifndef SIGTYPE
+#define SIGTYPE void
+#endif
+
+#undef __V
+
+#ifdef __STDC__
+#include <stdarg.h>
+#define __V(x)	x
+#else
+#include <varargs.h>
+#define __V(x)	(va_alist) va_dcl
+#define const
+#endif
+
+#ifndef O_NONBLOCK
+#define O_NONBLOCK	O_NDELAY
+#endif
+
+
+/*************** Micro getopt() *********************************************/
+#define	OPTION(c,v)	(_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
+				(--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
+				&&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
+#define	OPTARG(c,v)	(_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
+				(_O=4,(char*)0):(char*)0)
+#define	OPTONLYARG(c,v)	(_O&2&&**v?(_O=1,--c,*v++):(char*)0)
+#define	ARG(c,v)	(c?(--c,*v++):(char*)0)
+
+#if 0
+static int _O = 0;		/* Internal state */
+#endif
+/*************** Micro getopt() *********************************************/
+
+#define	MAX_ABORTS		16
+#define	MAX_REPORTS		16
+#define	DEFAULT_CHAT_TIMEOUT	45
+#define MAX_TIMEOUTS            10
+
+static int echo             = 0;
+static int quiet            = 0;
+static int use_env          = 0;
+static int exit_code        = 0;
+static char *phone_num      = (char *) 0;
+static char *phone_num2     = (char *) 0;
+static int ttyfd;
+static int timeout   = DEFAULT_CHAT_TIMEOUT;
+
+#ifdef TERMIOS
+#define term_parms struct termios
+#define get_term_param(param) tcgetattr(0, param)
+#define set_term_param(param) tcsetattr(0, TCSANOW, param)
+struct termios saved_tty_parameters;
+#endif
+
+char *fail_reason = (char *)0;
+char  fail_buffer[50];
+char *abort_string[MAX_ABORTS]={"BUSY","NO DIALTONE","NO CARRIER","NO ANSWER","RING\r\nRING"};
+int n_aborts = 5;
+int abort_next = 0, timeout_next = 0, echo_next = 0;
+int clear_abort_next = 0;
+
+char *report_string[MAX_REPORTS] ;
+char  report_buffer[50] ;
+int n_reports = 0, report_next = 0, report_gathering = 0 ;
+int clear_report_next = 0;
+
+int say_next = 0, hup_next = 0;
+
+void *dup_mem(void *b, size_t c);
+void *copy_of(char *s);
+void break_sequence(void);
+static int  get_string(register char *string);
+static int  put_string(register char *s);
+static int  write_char(int c);
+static int  put_char(int c);
+static int  get_char(void);
+void chat_send(register char *s);
+/* static char *character(int c); */
+void chat_expect(register char *s);
+static char *clean(register char *s, int sending);
+char *expect_strtok(char *, char *);
+int chatmain(int, int, char *);
+
+
+void *dup_mem(
+  void *b,
+  size_t c)
+{
+    void *ans = malloc (c);
+    if (!ans)
+	return NULL;
+
+    memcpy(ans, b, c);
+    return ans;
+}
+
+void *copy_of(
+  char *s)
+{
+    return dup_mem(s, strlen (s) + 1);
+}
+
+char *getnextcommand(char *string,char *buff)
+{
+	char *token;
+	int len;
+	
+	token=strchr(string,'@');
+	if (token==NULL){
+		return NULL;
+	}
+	len=token-string;
+	if(len > 78 ){
+		len=78;
+	}
+	memcpy(buff,string,len);
+	buff[len]=0;
+	return(token+1);
+}
+
+int chatmain(int fd, int mode, char *pScript)
+{
+  char    arg[80];
+  char 	  *script;
+
+  /* initialize exit code */
+  exit_code = 0;
+  ttyfd     = fd;
+
+  script=pScript;
+
+  if ( debug ) {
+    dbglog("chat_main: %s\n", script);
+  }
+
+  /* get first expect string */
+  script = getnextcommand(script,arg);
+  while (( script != NULL ) && ( exit_code == 0 )) {
+    /* process the expect string */
+    chat_expect(arg);
+    if ( exit_code == 0 ) {
+      /* get the next send string */
+      script = getnextcommand(script,arg);
+      if ( script != NULL ) {
+        /* process the send string */
+        chat_send(arg);
+
+        /* get the next expect string */
+        script = getnextcommand(script,arg);
+      }
+    }
+  }
+  ttyfd = (int)-1;
+
+  return ( exit_code );
+}
+
+void break_sequence(void)
+{
+  tcsendbreak(ttyfd, 0);
+}
+
+/*
+ *	'Clean up' this string.
+ */
+static char *clean(
+  char *s,
+  int sending )  /* set to 1 when sending (putting) this string. */
+{
+    char temp[STR_LEN], env_str[STR_LEN], cur_chr;
+    register char *s1, *phchar;
+    int add_return = sending;
+#define isoctal(chr)	(((chr) >= '0') && ((chr) <= '7'))
+#define isalnumx(chr)	((((chr) >= '0') && ((chr) <= '9')) \
+			 || (((chr) >= 'a') && ((chr) <= 'z')) \
+			 || (((chr) >= 'A') && ((chr) <= 'Z')) \
+			 || (chr) == '_')
+
+    s1 = temp;
+    while (*s) {
+	cur_chr = *s++;
+	if (cur_chr == '^') {
+	    cur_chr = *s++;
+	    if (cur_chr == '\0') {
+		*s1++ = '^';
+		break;
+	    }
+	    cur_chr &= 0x1F;
+	    if (cur_chr != 0) {
+		*s1++ = cur_chr;
+	    }
+	    continue;
+	}
+	
+	if (use_env && cur_chr == '$') {		/* ARI */
+	    phchar = env_str;
+	    while (isalnumx(*s))
+		*phchar++ = *s++;
+	    *phchar = '\0';
+	    phchar = getenv(env_str);
+	    if (phchar)
+		while (*phchar)
+		    *s1++ = *phchar++;
+	    continue;
+	}
+
+	if (cur_chr != '\\') {
+	    *s1++ = cur_chr;
+	    continue;
+	}
+
+	cur_chr = *s++;
+	if (cur_chr == '\0') {
+	    if (sending) {
+		*s1++ = '\\';
+		*s1++ = '\\';
+	    }
+	    break;
+	}
+
+	switch (cur_chr) {
+	case 'b':
+	    *s1++ = '\b';
+	    break;
+
+	case 'c':
+	    if (sending && *s == '\0')
+		add_return = 0;
+	    else
+		*s1++ = cur_chr;
+	    break;
+
+	case '\\':
+	case 'K':
+	case 'p':
+	case 'd':
+	    if (sending)
+		*s1++ = '\\';
+	    *s1++ = cur_chr;
+	    break;
+
+	case 'T':
+	    if (sending && phone_num) {
+		for (phchar = phone_num; *phchar != '\0'; phchar++)
+		    *s1++ = *phchar;
+	    }
+	    else {
+		*s1++ = '\\';
+		*s1++ = 'T';
+	    }
+	    break;
+
+	case 'U':
+	    if (sending && phone_num2) {
+		for (phchar = phone_num2; *phchar != '\0'; phchar++)
+		    *s1++ = *phchar;
+	    }
+	    else {
+		*s1++ = '\\';
+		*s1++ = 'U';
+	    }
+	    break;
+
+	case 'q':
+	    quiet = 1;
+	    break;
+
+	case 'r':
+	    *s1++ = '\r';
+	    break;
+
+	case 'n':
+	    *s1++ = '\n';
+	    break;
+
+	case 's':
+	    *s1++ = ' ';
+	    break;
+
+	case 't':
+	    *s1++ = '\t';
+	    break;
+
+	case 'N':
+	    if (sending) {
+		*s1++ = '\\';
+		*s1++ = '\0';
+	    }
+	    else
+		*s1++ = 'N';
+	    break;
+	
+	case '$':			/* ARI */
+	    if (use_env) {
+		*s1++ = cur_chr;
+		break;
+	    }
+	    /* FALL THROUGH */
+
+	default:
+	    if (isoctal (cur_chr)) {
+		cur_chr &= 0x07;
+		if (isoctal (*s)) {
+		    cur_chr <<= 3;
+		    cur_chr |= *s++ - '0';
+		    if (isoctal (*s)) {
+			cur_chr <<= 3;
+			cur_chr |= *s++ - '0';
+		    }
+		}
+
+		if (cur_chr != 0 || sending) {
+		    if (sending && (cur_chr == '\\' || cur_chr == 0))
+			*s1++ = '\\';
+		    *s1++ = cur_chr;
+		}
+		break;
+	    }
+
+	    if (sending)
+		*s1++ = '\\';
+	    *s1++ = cur_chr;
+	    break;
+	}
+    }
+
+    if (add_return)
+	*s1++ = '\r';
+
+    *s1++ = '\0'; /* guarantee closure */
+    *s1++ = '\0'; /* terminate the string */
+    return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
+}
+
+/*
+ * A modified version of 'strtok'. This version skips \ sequences.
+ */
+char *expect_strtok (
+     char *s, char *term)
+{
+    static  char *str   = "";
+    int	    escape_flag = 0;
+    char   *result;
+
+/*
+ * If a string was specified then do initial processing.
+ */
+    if (s)
+	str = s;
+
+/*
+ * If this is the escape flag then reset it and ignore the character.
+ */
+    if (*str)
+	result = str;
+    else
+	result = (char *) 0;
+
+    while (*str) {
+	if (escape_flag) {
+	    escape_flag = 0;
+	    ++str;
+	    continue;
+	}
+
+	if (*str == '\\') {
+	    ++str;
+	    escape_flag = 1;
+	    continue;
+	}
+
+/*
+ * If this is not in the termination string, continue.
+ */
+	if (strchr (term, *str) == (char *) 0) {
+	    ++str;
+	    continue;
+	}
+
+/*
+ * This is the terminator. Mark the end of the string and stop.
+ */
+	*str++ = '\0';
+	break;
+    }
+    return (result);
+}
+
+/*
+ * Process the expect string
+ */
+void chat_expect (
+  char *s)
+{
+    char *expect;
+    char *reply;
+
+    if (strcmp(s, "HANGUP") == 0) {
+		++hup_next;
+        return;
+    }
+
+    if (strcmp(s, "ABORT") == 0) {
+		++abort_next;
+		return;
+    }
+
+    if (strcmp(s, "CLR_ABORT") == 0) {
+		++clear_abort_next;
+		return;
+    }
+
+    if (strcmp(s, "REPORT") == 0) {
+		++report_next;
+		return;
+    }
+
+    if (strcmp(s, "CLR_REPORT") == 0) {
+		++clear_report_next;
+		return;
+    }
+
+    if (strcmp(s, "TIMEOUT") == 0) {
+		++timeout_next;
+		return;
+    }
+
+    if (strcmp(s, "ECHO") == 0) {
+		++echo_next;
+		return;
+    }
+
+    if (strcmp(s, "SAY") == 0) {
+		++say_next;
+		return;
+    }
+
+/*
+ * Fetch the expect and reply string.
+ */
+    for (;;) {
+	expect = expect_strtok (s, "-");
+	s      = (char *) 0;
+
+	if (expect == (char *) 0)
+	    return;
+
+	reply = expect_strtok (s, "-");
+
+/*
+ * Handle the expect string. If successful then exit.
+ */
+	if (get_string (expect))
+	    return;
+
+/*
+ * If there is a sub-reply string then send it. Otherwise any condition
+ * is terminal.
+ */
+	if (reply == (char *) 0 || exit_code != 3)
+	    break;
+
+	chat_send (reply);
+    }
+}
+
+#if 0
+/*
+ * Translate the input character to the appropriate string for printing
+ * the data.
+ */
+
+static char *character(
+  int c)
+{
+    static char string[10];
+    char *meta;
+
+    meta = (c & 0x80) ? "M-" : "";
+    c &= 0x7F;
+
+    if (c < 32)
+	sprintf(string, "%s^%c", meta, (int)c + '@');
+    else if (c == 127)
+	sprintf(string, "%s^?", meta);
+    else
+	sprintf(string, "%s%c", meta, c);
+
+    return (string);
+}
+#endif
+
+/*
+ *  process the reply string
+ */
+void chat_send (
+  char *s)
+{
+/*  char file_data[STR_LEN];  */
+
+    if (say_next) {
+		say_next = 0;
+		s = clean(s, 1);
+		write(2, s, strlen(s));
+        free(s);
+		return;
+    }
+
+    if (hup_next) {
+        hup_next = 0;
+        return;
+    }
+
+    if (echo_next) {
+	echo_next = 0;
+	echo = (strcmp(s, "ON") == 0);
+	return;
+    }
+
+    if (abort_next) {
+		abort_next = 0;
+		if ( n_aborts < MAX_ABORTS ) {
+			char *s1;
+			s1 = clean(s, 0);
+			if (( strlen(s1) <= strlen(s) ) && ( strlen(s1) <  sizeof(fail_buffer)))
+				abort_string[n_aborts++] = s1;
+			else
+				free(s1);
+        	}
+		return;
+    }
+
+    if (clear_abort_next) {
+		clear_abort_next = 0;
+		return;
+    }
+
+    if (report_next) {
+		report_next = 0;
+		return;
+    }
+
+    if (clear_report_next) {
+		clear_report_next = 0;
+		return;
+    }
+
+    if (timeout_next) {
+		timeout_next = 0;
+		timeout = atoi(s);
+	
+		if (timeout <= 0){
+	    	timeout = DEFAULT_CHAT_TIMEOUT;
+	    }
+		return;
+    }
+
+    if (strcmp(s, "EOT") == 0){
+		s = "^D\\c";
+	}
+    else{
+    	if (strcmp(s, "BREAK") == 0){
+			s = "\\K\\c";
+		}
+
+    	if (!put_string(s)) {
+      		exit_code = 2;
+    	}
+	}
+}
+
+static int get_char(void)
+{
+    int status;
+    char c;
+    int tries=MAX_TIMEOUTS;
+
+	while(tries)
+	{
+	    status = read(ttyfd, &c, 1);
+	    switch (status) {
+		   case 1:
+				return ((int)c & 0x7F);
+		    default:
+				tries--;			
+	    }
+    }
+	return -1;						
+}
+
+static int put_char(
+  int c)
+{
+  char ch = c;
+
+  return(write(ttyfd, &ch, 1));
+}
+
+static int write_char (
+  int c)
+{
+    if (put_char(c) < 1) {
+		return (0);
+    }
+    return (1);
+}
+
+static int put_string (
+  char *s)
+{
+	char *out,*free_ptr=0;
+	
+    quiet = 0;
+    out = free_ptr = clean(s, 1);
+    while (*out) {
+		register char c = *out++;
+
+		if (c != '\\') {
+	    	if (!write_char (c)){
+	    		free(free_ptr);
+				return 0;
+			}
+	    	continue;
+		}
+
+		c = *out++;
+
+		switch (c) {
+			case 'd':
+	    		sleep(1);
+		    break;
+
+			case 'K':
+	    		break_sequence();
+	    	break;
+
+			case 'p':
+#if 0 /* FIXME!!! */
+	    		usleep(10000); 	/* 1/100th of a second (arg is microseconds) */
+#else
+	    		sleep(1);
+#endif
+	    	break;
+
+			default:
+	    		if (!write_char (c)){
+	    			free(free_ptr);
+					return 0;
+				}
+	    	break;
+		}
+    }
+    free(free_ptr);
+
+    return (1);
+}
+
+/*
+ *	'Wait for' this string to appear on this file descriptor.
+ */
+static int get_string(
+    char *in_string)
+{
+    int c, len, minlen;
+    register char *s = temp2, *end = s + STR_LEN;
+    char *logged = temp2;
+    char *string=0;
+    struct termios tios;
+
+    memset(temp2, 0, sizeof(temp2));
+
+    tcgetattr(ttyfd, &tios);
+    tios.c_cc[VMIN] = 0;
+    tios.c_cc[VTIME] = timeout*10/MAX_TIMEOUTS;
+    tcsetattr(ttyfd, TCSANOW, &tios);
+		
+    string = clean(in_string, 0);
+    len = strlen(string);
+    minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
+	
+    if (len > STR_LEN) {
+		exit_code = 1;
+		free(string);
+		return 0;
+    }
+
+    if (len == 0) {
+	free(string);
+	return (1);
+    }
+
+   while ( (c = get_char()) >= 0) {
+		int n, abort_len;
+
+	if(c == '\n' || c == '\r'){
+		s = temp2;
+		*s=0;
+	}
+	else{
+		*s++ = c;
+		*s=0;
+	}
+
+	if (s - temp2 >= len &&
+	    c == string[len - 1] &&
+	    strncmp(s - len, string, len) == 0) {
+	    free(string);
+	    return (1);
+	}
+
+	for (n = 0; n < n_aborts; ++n) {
+	    if (s - temp2 >= (abort_len = strlen(abort_string[n])) &&
+		strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
+
+		exit_code = n + 4;
+		strcpy(fail_reason = fail_buffer, abort_string[n]);
+		free(string);
+		return (0);
+	    }
+	}
+
+	if (s >= end) {
+	    if (logged < s - minlen) {
+		logged = s;
+	    }
+	    s -= minlen;
+	    memmove(temp2, s, minlen);
+	    logged = temp2 + (logged - s);
+	    s = temp2 + minlen;
+	}
+    }
+
+    exit_code = 3;
+    free(string);
+    return (0);
+}
diff --git a/rtemsbsd/pppd/demand.c b/rtemsbsd/pppd/demand.c
new file mode 100644
index 0000000..a094a15
--- /dev/null
+++ b/rtemsbsd/pppd/demand.c
@@ -0,0 +1,347 @@
+/*
+ * demand.c - Support routines for demand-dialling.
+ *
+ * Copyright (c) 1993 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#ifdef PPP_FILTER
+#include <net/if.h>
+#include <net/bpf.h>
+#include <pcap.h>
+#endif
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "lcp.h"
+
+static const char rcsid[] = RCSID;
+
+static unsigned char *frame;
+static int framelen;
+static int framemax;
+static int escape_flag;
+static int flush_flag;
+static int fcs;
+
+struct packet {
+    int length;
+    struct packet *next;
+    unsigned char data[1];
+};
+
+struct packet *pend_q;
+struct packet *pend_qtail;
+
+static int active_packet(unsigned char *, int);
+
+/*
+ * demand_conf - configure the interface for doing dial-on-demand.
+ */
+void
+demand_conf(void)
+{
+    int i;
+    struct protent *protp;
+
+/*    framemax = lcp_allowoptions[0].mru;
+    if (framemax < PPP_MRU) */
+	framemax = PPP_MRU;
+    framemax += PPP_HDRLEN + PPP_FCSLEN;
+    frame = malloc(framemax);
+    if (frame == NULL)
+	novm("demand frame");
+    framelen = 0;
+    pend_q = NULL;
+    escape_flag = 0;
+    flush_flag = 0;
+    fcs = PPP_INITFCS;
+
+    ppp_send_config(0, PPP_MRU, (uint32_t) 0, 0, 0);
+    ppp_recv_config(0, PPP_MRU, (uint32_t) 0, 0, 0);
+
+#ifdef PPP_FILTER
+    set_filters(&pass_filter, &active_filter);
+#endif
+
+    /*
+     * Call the demand_conf procedure for each protocol that's got one.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->enabled_flag && protp->demand_conf != NULL)
+	    if (!((*protp->demand_conf)(0)))
+		die(1);
+}
+
+
+/*
+ * demand_block - set each network protocol to block further packets.
+ */
+void
+demand_block(void)
+{
+    int i;
+    struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_QUEUE);
+    get_loop_output();
+}
+
+/*
+ * demand_discard - set each network protocol to discard packets
+ * with an error.
+ */
+void
+demand_discard(void)
+{
+    struct packet *pkt, *nextpkt;
+    int i;
+    struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_ERROR);
+    get_loop_output();
+
+    /* discard all saved packets */
+    for (pkt = pend_q; pkt != NULL; pkt = nextpkt) {
+	nextpkt = pkt->next;
+	free(pkt);
+    }
+    pend_q = NULL;
+    framelen = 0;
+    flush_flag = 0;
+    escape_flag = 0;
+    fcs = PPP_INITFCS;
+}
+
+/*
+ * demand_unblock - set each enabled network protocol to pass packets.
+ */
+void
+demand_unblock(void)
+{
+    int i;
+    struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->enabled_flag && protp->demand_conf != NULL)
+	    sifnpmode(0, protp->protocol & ~0x8000, NPMODE_PASS);
+}
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
+	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
+	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
+	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
+	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
+	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
+	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
+	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
+	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
+	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
+	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
+	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
+	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
+	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
+	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
+	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
+	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
+	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
+	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
+	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
+	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
+	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
+	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
+	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
+	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
+	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
+	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
+	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
+	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
+	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
+	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
+	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
+};
+
+/*
+ * loop_chars - process characters received from the loopback.
+ * Calls loop_frame when a complete frame has been accumulated.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+loop_chars(
+    unsigned char *p,
+    int n)
+{
+    int c, rv;
+
+    rv = 0;
+    for (; n > 0; --n) {
+	c = *p++;
+	if (c == PPP_FLAG) {
+	    if (!escape_flag && !flush_flag
+		&& framelen > 2 && fcs == PPP_GOODFCS) {
+		framelen -= 2;
+		if (loop_frame(frame, framelen))
+		    rv = 1;
+	    }
+	    framelen = 0;
+	    flush_flag = 0;
+	    escape_flag = 0;
+	    fcs = PPP_INITFCS;
+	    continue;
+	}
+	if (flush_flag)
+	    continue;
+	if (escape_flag) {
+	    c ^= PPP_TRANS;
+	    escape_flag = 0;
+	} else if (c == PPP_ESCAPE) {
+	    escape_flag = 1;
+	    continue;
+	}
+	if (framelen >= framemax) {
+	    flush_flag = 1;
+	    continue;
+	}
+	frame[framelen++] = c;
+	fcs = PPP_FCS(fcs, c);
+    }
+    return rv;
+}
+
+/*
+ * loop_frame - given a frame obtained from the loopback,
+ * decide whether to bring up the link or not, and, if we want
+ * to transmit this frame later, put it on the pending queue.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ * We assume that the kernel driver has already applied the
+ * pass_filter, so we won't get packets it rejected.
+ * We apply the active_filter to see if we want this packet to
+ * bring up the link.
+ */
+int
+loop_frame(
+    unsigned char *frame,
+    int len)
+{
+    struct packet *pkt;
+
+    /* dbglog("from loop: %P", frame, len); */
+    if (len < PPP_HDRLEN)
+	return 0;
+    if ((PPP_PROTOCOL(frame) & 0x8000) != 0)
+	return 0;		/* shouldn't get any of these anyway */
+    if (!active_packet(frame, len))
+	return 0;
+
+    pkt = (struct packet *) malloc(sizeof(struct packet) + len);
+    if (pkt != NULL) {
+	pkt->length = len;
+	pkt->next = NULL;
+	memcpy(pkt->data, frame, len);
+	if (pend_q == NULL)
+	    pend_q = pkt;
+	else
+	    pend_qtail->next = pkt;
+	pend_qtail = pkt;
+    }
+    return 1;
+}
+
+/*
+ * demand_rexmit - Resend all those frames which we got via the
+ * loopback, now that the real serial link is up.
+ */
+void
+demand_rexmit(
+    int proto)
+{
+    struct packet *pkt, *prev, *nextpkt;
+
+    prev = NULL;
+    pkt = pend_q;
+    pend_q = NULL;
+    for (; pkt != NULL; pkt = nextpkt) {
+	nextpkt = pkt->next;
+	if (PPP_PROTOCOL(pkt->data) == proto) {
+	    output(0, pkt->data, pkt->length);
+	    free(pkt);
+	} else {
+	    if (prev == NULL)
+		pend_q = pkt;
+	    else
+		prev->next = pkt;
+	    prev = pkt;
+	}
+    }
+    pend_qtail = prev;
+    if (prev != NULL)
+	prev->next = NULL;
+}
+
+/*
+ * Scan a packet to decide whether it is an "active" packet,
+ * that is, whether it is worth bringing up the link for.
+ */
+static int
+active_packet(
+    unsigned char *p,
+    int len)
+{
+    int proto, i;
+    struct protent *protp;
+
+    if (len < PPP_HDRLEN)
+	return 0;
+    proto = PPP_PROTOCOL(p);
+#ifdef PPP_FILTER
+    if (active_filter.bf_len != 0
+	&& bpf_filter(active_filter.bf_insns, frame, len, len) == 0)
+	return 0;
+#endif
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+	    if (!protp->enabled_flag)
+		return 0;
+	    if (protp->active_pkt == NULL)
+		return 1;
+	    return (*protp->active_pkt)(p, len);
+	}
+    }
+    return 0;			/* not a supported protocol !!?? */
+}
diff --git a/rtemsbsd/pppd/fsm.c b/rtemsbsd/pppd/fsm.c
new file mode 100644
index 0000000..ce06401
--- /dev/null
+++ b/rtemsbsd/pppd/fsm.c
@@ -0,0 +1,764 @@
+/*
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+/*
+ * TODO:
+ * Randomize fsm id on link/init.
+ * Deal with variable outgoing MTU.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pppd.h"
+#include "fsm.h"
+
+static const char rcsid[] = RCSID;
+
+static void fsm_timeout(void *);
+static void fsm_rconfreq(fsm *, u_char, u_char *, int);
+static void fsm_rconfack(fsm *, int, u_char *, int);
+static void fsm_rconfnakrej(fsm *, int, int, u_char *, int);
+static void fsm_rtermreq(fsm *, int, u_char *, int);
+static void fsm_rtermack(fsm *);
+static void fsm_rcoderej(fsm *, u_char *, int);
+static void fsm_sconfreq(fsm *, int);
+
+#define PROTO_NAME(f)	((f)->callbacks->proto_name)
+
+int peer_mru[NUM_PPP];
+
+
+/*
+ * fsm_init - Initialize fsm.
+ *
+ * Initialize fsm state.
+ */
+void
+fsm_init(
+    fsm *f)
+{
+    f->state = INITIAL;
+    f->flags = 0;
+    f->id = 100;		/* XXX Start with random id? */
+    f->timeouttime = DEFTIMEOUT;
+    f->maxconfreqtransmits = DEFMAXCONFREQS;
+    f->maxtermtransmits = DEFMAXTERMREQS;
+    f->maxnakloops = DEFMAXNAKLOOPS;
+    f->term_reason_len = 0;
+}
+
+
+/*
+ * fsm_lowerup - The lower layer is up.
+ */
+void
+fsm_lowerup(
+    fsm *f)
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = CLOSED;
+	break;
+
+    case STARTING:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts and inform upper layers.
+ */
+void
+fsm_lowerdown(
+    fsm *f)
+{
+    switch( f->state ){
+    case CLOSED:
+	f->state = INITIAL;
+	break;
+
+    case STOPPED:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSING:
+	f->state = INITIAL;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = STARTING;
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+	f->state = STARTING;
+	break;
+
+    default:
+	FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_open - Link is allowed to come up.
+ */
+void
+fsm_open(
+    fsm *f)
+{
+    switch( f->state ){
+    case INITIAL:
+	f->state = STARTING;
+	if( f->callbacks->starting )
+	    (*f->callbacks->starting)(f);
+	break;
+
+    case CLOSED:
+	if( f->flags & OPT_SILENT )
+	    f->state = STOPPED;
+	else {
+	    /* Send an initial configure-request */
+	    fsm_sconfreq(f, 0);
+	    f->state = REQSENT;
+	}
+	break;
+
+    case CLOSING:
+	f->state = STOPPING;
+	/* fall through */
+    case STOPPED:
+    case OPENED:
+	if( f->flags & OPT_RESTART ){
+	    fsm_lowerdown(f);
+	    fsm_lowerup(f);
+	}
+	break;
+    }
+}
+
+
+/*
+ * fsm_close - Start closing connection.
+ *
+ * Cancel timeouts and either initiate close or possibly go directly to
+ * the CLOSED state.
+ */
+void
+fsm_close(
+    fsm *f,
+    char *reason)
+{
+    f->term_reason = reason;
+    f->term_reason_len = (reason == NULL? 0: strlen(reason));
+    switch( f->state ){
+    case STARTING:
+	f->state = INITIAL;
+	break;
+    case STOPPED:
+	f->state = CLOSED;
+	break;
+    case STOPPING:
+	f->state = CLOSING;
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+    case OPENED:
+	if( f->state != OPENED )
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	else if( f->callbacks->down )
+	    (*f->callbacks->down)(f);	/* Inform upper layers we're down */
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = CLOSING;
+	break;
+    }
+}
+
+
+/*
+ * fsm_timeout - Timeout expired.
+ */
+static void
+fsm_timeout(
+    void *arg)
+{
+    fsm *f = (fsm *) arg;
+
+    switch (f->state) {
+    case CLOSING:
+    case STOPPING:
+	if( f->retransmits <= 0 ){
+	    /*
+	     * We've waited for an ack long enough.  Peer probably heard us.
+	     */
+	    f->state = (f->state == CLOSING)? CLOSED: STOPPED;
+	    if( f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+	} else {
+	    /* Send Terminate-Request */
+	    fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		      (u_char *) f->term_reason, f->term_reason_len);
+	    TIMEOUT(fsm_timeout, f, f->timeouttime);
+	    --f->retransmits;
+	}
+	break;
+
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	if (f->retransmits <= 0) {
+	    warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
+	    f->state = STOPPED;
+	    if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
+		(*f->callbacks->finished)(f);
+
+	} else {
+	    /* Retransmit the configure-request */
+	    if (f->callbacks->retransmit)
+		(*f->callbacks->retransmit)(f);
+	    fsm_sconfreq(f, 1);		/* Re-send Configure-Request */
+	    if( f->state == ACKRCVD )
+		f->state = REQSENT;
+	}
+	break;
+
+    default:
+	FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_input - Input packet.
+ */
+void
+fsm_input(
+    fsm *f,
+    u_char *inpacket,
+    int l)
+{
+    u_char *inp;
+    u_char code, id;
+    int len;
+
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (l < HEADERLEN) {
+	FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < HEADERLEN) {
+	FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
+	return;
+    }
+    if (len > l) {
+	FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
+	return;
+    }
+    len -= HEADERLEN;		/* subtract header length */
+
+    if( f->state == INITIAL || f->state == STARTING ){
+	FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
+		  f->protocol, f->state));
+	return;
+    }
+
+    /*
+     * Action depends on code.
+     */
+    switch (code) {
+    case CONFREQ:
+	fsm_rconfreq(f, id, inp, len);
+	break;
+
+    case CONFACK:
+	fsm_rconfack(f, id, inp, len);
+	break;
+
+    case CONFNAK:
+    case CONFREJ:
+	fsm_rconfnakrej(f, code, id, inp, len);
+	break;
+
+    case TERMREQ:
+	fsm_rtermreq(f, id, inp, len);
+	break;
+
+    case TERMACK:
+	fsm_rtermack(f);
+	break;
+
+    case CODEREJ:
+	fsm_rcoderej(f, inp, len);
+	break;
+
+    default:
+	if( !f->callbacks->extcode
+	   || !(*f->callbacks->extcode)(f, code, id, inp, len) )
+	    fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
+	break;
+    }
+}
+
+
+/*
+ * fsm_rconfreq - Receive Configure-Request.
+ */
+static void
+fsm_rconfreq(
+    fsm *f,
+    u_char id,
+    u_char *inp,
+    int len)
+{
+    int code, reject_if_disagree;
+
+    switch( f->state ){
+    case CLOSED:
+	/* Go away, we're closed */
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	return;
+    case CLOSING:
+    case STOPPING:
+	return;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	break;
+
+    case STOPPED:
+	/* Negotiation started by our peer */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+
+    /*
+     * Pass the requested configuration options
+     * to protocol-specific code for checking.
+     */
+    if (f->callbacks->reqci){		/* Check CI */
+	reject_if_disagree = (f->nakloops >= f->maxnakloops);
+	code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
+    } else if (len)
+	code = CONFREJ;			/* Reject all CI */
+    else
+	code = CONFACK;
+
+    /* send the Ack, Nak or Rej to the peer */
+    fsm_sdata(f, code, id, inp, len);
+
+    if (code == CONFACK) {
+	if (f->state == ACKRCVD) {
+	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	    f->state = OPENED;
+	    if (f->callbacks->up)
+		(*f->callbacks->up)(f);	/* Inform upper layers */
+	} else {
+	    f->state = ACKSENT;
+            ppp_delay();
+        }
+	f->nakloops = 0;
+
+    } else {
+	/* we sent CONFACK or CONFREJ */
+	if (f->state != ACKRCVD)
+	    f->state = REQSENT;
+	if( code == CONFNAK )
+	    ++f->nakloops;
+    }
+}
+
+
+/*
+ * fsm_rconfack - Receive Configure-Ack.
+ */
+static void
+fsm_rconfack(
+    fsm *f,
+    int id,
+    u_char *inp,
+    int len)
+{
+    if (id != f->reqid || f->seen_ack)		/* Expected id? */
+	return;					/* Nope, toss... */
+    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
+	  (len == 0)) ){
+	/* Ack is bad - ignore it */
+	error("Received bad configure-ack: %P", inp, len);
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->state) {
+    case CLOSED:
+    case STOPPED:
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	break;
+
+    case REQSENT:
+	f->state = ACKRCVD;
+	f->retransmits = f->maxconfreqtransmits;
+	break;
+
+    case ACKRCVD:
+	/* Huh? an extra valid Ack? oh well... */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	fsm_sconfreq(f, 0);
+	f->state = REQSENT;
+	break;
+
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	f->state = OPENED;
+	f->retransmits = f->maxconfreqtransmits;
+	if (f->callbacks->up)
+	    (*f->callbacks->up)(f);	/* Inform upper layers */
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+}
+
+
+/*
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ */
+static void
+fsm_rconfnakrej(
+    fsm *f,
+    int code, int id,
+    u_char *inp,
+    int len)
+{
+    int (*proc)(fsm *, u_char *, int);
+    int ret;
+
+    if (id != f->reqid || f->seen_ack)	/* Expected id? */
+	return;				/* Nope, toss... */
+    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
+    if (!proc || !(ret = proc(f, inp, len))) {
+	/* Nak/reject is bad - ignore it */
+	error("Received bad configure-nak/rej: %P", inp, len);
+	return;
+    }
+    f->seen_ack = 1;
+
+    switch (f->state) {
+    case CLOSED:
+    case STOPPED:
+	fsm_sdata(f, TERMACK, id, NULL, 0);
+	break;
+
+    case REQSENT:
+    case ACKSENT:
+	/* They didn't agree to what we wanted - try another request */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	if (ret < 0)
+	    f->state = STOPPED;		/* kludge for stopping CCP */
+	else
+	    fsm_sconfreq(f, 0);		/* Send Configure-Request */
+	break;
+
+    case ACKRCVD:
+	/* Got a Nak/reject when we had already had an Ack?? oh well... */
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	fsm_sconfreq(f, 0);
+	f->state = REQSENT;
+	break;
+
+    case OPENED:
+	/* Go down and restart negotiation */
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
+	f->state = REQSENT;
+	break;
+    }
+}
+
+
+/*
+ * fsm_rtermreq - Receive Terminate-Req.
+ */
+static void
+fsm_rtermreq(
+    fsm *f,
+    int id,
+    u_char *p,
+    int len)
+{
+    switch (f->state) {
+    case ACKRCVD:
+    case ACKSENT:
+	f->state = REQSENT;		/* Start over but keep trying */
+	break;
+
+    case OPENED:
+	if (len > 0) {
+	    info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
+	} else
+	    info("%s terminated by peer", PROTO_NAME(f));
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	f->retransmits = 0;
+	f->state = STOPPING;
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	break;
+    }
+
+    fsm_sdata(f, TERMACK, id, NULL, 0);
+}
+
+
+/*
+ * fsm_rtermack - Receive Terminate-Ack.
+ */
+static void
+fsm_rtermack(
+    fsm *f)
+{
+    switch (f->state) {
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+    case STOPPING:
+	UNTIMEOUT(fsm_timeout, f);
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case ACKRCVD:
+	f->state = REQSENT;
+	break;
+
+    case OPENED:
+	if (f->callbacks->down)
+	    (*f->callbacks->down)(f);	/* Inform upper layers */
+	fsm_sconfreq(f, 0);
+	break;
+    }
+}
+
+
+/*
+ * fsm_rcoderej - Receive an Code-Reject.
+ */
+static void
+fsm_rcoderej(
+    fsm *f,
+    u_char *inp,
+    int len)
+{
+    u_char code, id;
+
+    if (len < HEADERLEN) {
+	FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
+
+    if( f->state == ACKRCVD )
+	f->state = REQSENT;
+}
+
+
+/*
+ * fsm_protreject - Peer doesn't speak this protocol.
+ *
+ * Treat this as a catastrophic error (RXJ-).
+ */
+void
+fsm_protreject(
+    fsm *f)
+{
+    switch( f->state ){
+    case CLOSING:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case CLOSED:
+	f->state = CLOSED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case STOPPING:
+    case REQSENT:
+    case ACKRCVD:
+    case ACKSENT:
+	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
+	/* fall through */
+    case STOPPED:
+	f->state = STOPPED;
+	if( f->callbacks->finished )
+	    (*f->callbacks->finished)(f);
+	break;
+
+    case OPENED:
+	if( f->callbacks->down )
+	    (*f->callbacks->down)(f);
+
+	/* Init restart counter, send Terminate-Request */
+	f->retransmits = f->maxtermtransmits;
+	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
+		  (u_char *) f->term_reason, f->term_reason_len);
+	TIMEOUT(fsm_timeout, f, f->timeouttime);
+	--f->retransmits;
+
+	f->state = STOPPING;
+	break;
+
+    default:
+	FSMDEBUG(("%s: Protocol-reject event in state %d!",
+		  PROTO_NAME(f), f->state));
+    }
+}
+
+
+/*
+ * fsm_sconfreq - Send a Configure-Request.
+ */
+static void
+fsm_sconfreq(
+    fsm *f,
+    int retransmit)
+{
+    u_char *outp;
+    int cilen;
+
+    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
+	/* Not currently negotiating - reset options */
+	if( f->callbacks->resetci )
+	    (*f->callbacks->resetci)(f);
+	f->nakloops = 0;
+    }
+
+    if( !retransmit ){
+	/* New request - reset retransmission counter, use new ID */
+	f->retransmits = f->maxconfreqtransmits;
+	f->reqid = ++f->id;
+    }
+
+    f->seen_ack = 0;
+
+    /*
+     * Make up the request packet
+     */
+    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
+    if( f->callbacks->cilen && f->callbacks->addci ){
+	cilen = (*f->callbacks->cilen)(f);
+	if( cilen > peer_mru[f->unit] - HEADERLEN )
+	    cilen = peer_mru[f->unit] - HEADERLEN;
+	if (f->callbacks->addci)
+	    (*f->callbacks->addci)(f, outp, &cilen);
+    } else
+	cilen = 0;
+
+    /* send the request to our peer */
+    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
+
+    /* start the retransmit timer */
+    --f->retransmits;
+    TIMEOUT(fsm_timeout, f, f->timeouttime);
+}
+
+
+/*
+ * fsm_sdata - Send some data.
+ *
+ * Used for all packets sent to our peer by this module.
+ */
+void
+fsm_sdata(
+    fsm *f,
+    u_char code, u_char id,
+    u_char *data,
+    int datalen)
+{
+    u_char *outp;
+    int outlen;
+
+    /* Adjust length to be smaller than MTU */
+    outp = outpacket_buf;
+    if (datalen > peer_mru[f->unit] - HEADERLEN)
+	datalen = peer_mru[f->unit] - HEADERLEN;
+    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
+	BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
+    outlen = datalen + HEADERLEN;
+    MAKEHEADER(outp, f->protocol);
+    PUTCHAR(code, outp);
+    PUTCHAR(id, outp);
+    PUTSHORT(outlen, outp);
+    output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
diff --git a/rtemsbsd/pppd/fsm.h b/rtemsbsd/pppd/fsm.h
new file mode 100644
index 0000000..6b82951
--- /dev/null
+++ b/rtemsbsd/pppd/fsm.h
@@ -0,0 +1,144 @@
+/*
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define HEADERLEN	4
+
+
+/*
+ *  CP (LCP, IPCP, etc.) codes.
+ */
+#define CONFREQ		1	/* Configuration Request */
+#define CONFACK		2	/* Configuration Ack */
+#define CONFNAK		3	/* Configuration Nak */
+#define CONFREJ		4	/* Configuration Reject */
+#define TERMREQ		5	/* Termination Request */
+#define TERMACK		6	/* Termination Ack */
+#define CODEREJ		7	/* Code Reject */
+
+
+/*
+ * Each FSM is described by an fsm structure and fsm callbacks.
+ */
+typedef struct fsm {
+    int unit;			/* Interface unit number */
+    int protocol;		/* Data Link Layer Protocol field value */
+    int state;			/* State */
+    int flags;			/* Contains option bits */
+    u_char id;			/* Current id */
+    u_char reqid;		/* Current request id */
+    u_char seen_ack;		/* Have received valid Ack/Nak/Rej to Req */
+    int timeouttime;		/* Timeout time in milliseconds */
+    int maxconfreqtransmits;	/* Maximum Configure-Request transmissions */
+    int retransmits;		/* Number of retransmissions left */
+    int maxtermtransmits;	/* Maximum Terminate-Request transmissions */
+    int nakloops;		/* Number of nak loops since last ack */
+    int maxnakloops;		/* Maximum number of nak loops tolerated */
+    struct fsm_callbacks *callbacks;	/* Callback routines */
+    char *term_reason;		/* Reason for closing protocol */
+    int term_reason_len;	/* Length of term_reason */
+} fsm;
+
+
+typedef struct fsm_callbacks {
+    void (*resetci)		/* Reset our Configuration Information */
+		(fsm *);
+    int  (*cilen)		/* Length of our Configuration Information */
+		(fsm *);
+    void (*addci) 		/* Add our Configuration Information */
+		(fsm *, u_char *, int *);
+    int  (*ackci)		/* ACK our Configuration Information */
+		(fsm *, u_char *, int);
+    int  (*nakci)		/* NAK our Configuration Information */
+		(fsm *, u_char *, int);
+    int  (*rejci)		/* Reject our Configuration Information */
+		(fsm *, u_char *, int);
+    int  (*reqci)		/* Request peer's Configuration Information */
+		(fsm *, u_char *, int *, int);
+    void (*up)			/* Called when fsm reaches OPENED state */
+		(fsm *);
+    void (*down)		/* Called when fsm leaves OPENED state */
+		(fsm *);
+    void (*starting)		/* Called when we want the lower layer */
+		(fsm *);
+    void (*finished)		/* Called when we don't want the lower layer */
+		(fsm *);
+    void (*protreject)		/* Called when Protocol-Reject received */
+		(int);
+    void (*retransmit)		/* Retransmission is necessary */
+		(fsm *);
+    int  (*extcode)		/* Called when unknown code received */
+		(fsm *, int, int, u_char *, int);
+    char *proto_name;		/* String name for protocol (for messages) */
+} fsm_callbacks;
+
+
+/*
+ * Link states.
+ */
+#define INITIAL		0	/* Down, hasn't been opened */
+#define STARTING	1	/* Down, been opened */
+#define CLOSED		2	/* Up, hasn't been opened */
+#define STOPPED		3	/* Open, waiting for down event */
+#define CLOSING		4	/* Terminating the connection, not open */
+#define STOPPING	5	/* Terminating, but open */
+#define REQSENT		6	/* We've sent a Config Request */
+#define ACKRCVD		7	/* We've received a Config Ack */
+#define ACKSENT		8	/* We've sent a Config Ack */
+#define OPENED		9	/* Connection available */
+
+
+/*
+ * Flags - indicate options controlling FSM operation
+ */
+#define OPT_PASSIVE	1	/* Don't die if we don't get a response */
+#define OPT_RESTART	2	/* Treat 2nd OPEN as DOWN, UP */
+#define OPT_SILENT	4	/* Wait for peer to speak first */
+
+
+/*
+ * Timeouts.
+ */
+#define DEFTIMEOUT	5	/* Timeout time in seconds */
+#define DEFMAXTERMREQS	2	/* Maximum Terminate-Request transmissions */
+#define DEFMAXCONFREQS	10	/* Maximum Configure-Request transmissions */
+#define DEFMAXNAKLOOPS	5	/* Maximum number of nak loops */
+
+
+/*
+ * Prototypes
+ */
+void fsm_init(fsm *);
+void fsm_lowerup(fsm *);
+void fsm_lowerdown(fsm *);
+void fsm_open(fsm *);
+void fsm_close(fsm *, char *);
+void fsm_input(fsm *, u_char *, int);
+void fsm_protreject(fsm *);
+void fsm_sdata(fsm *, u_char, u_char, u_char *, int);
+
+
+/*
+ * Variables
+ */
+extern int peer_mru[];		/* currently negotiated peer MRU (per unit) */
diff --git a/rtemsbsd/pppd/ipcp.c b/rtemsbsd/pppd/ipcp.c
new file mode 100644
index 0000000..fd23ddd
--- /dev/null
+++ b/rtemsbsd/pppd/ipcp.c
@@ -0,0 +1,1772 @@
+/*
+ * ipcp.c - PPP IP Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+#include "pathnames.h"
+
+#include <rtems/bsdnet/servers.h>
+
+static const char rcsid[] = RCSID;
+
+/* global vars */
+ipcp_options ipcp_wantoptions[NUM_PPP];	/* Options that we want to request */
+ipcp_options ipcp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+ipcp_options ipcp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
+ipcp_options ipcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+
+bool	disable_defaultip = 0;	/* Don't use hostname for default IP adrs */
+
+/* Hook for a plugin to know when IP protocol has come up */
+void (*ip_up_hook)(void) = NULL;
+
+/* Hook for a plugin to know when IP protocol has come down */
+void (*ip_down_hook)(void) = NULL;
+
+/* local vars */
+static int default_route_set[NUM_PPP];	/* Have set up a default route */
+static int proxy_arp_set[NUM_PPP];	/* Have created proxy arp entry */
+static bool usepeerdns;			/* Ask peer for DNS addrs */
+static int ipcp_is_up;			/* have called np_up() */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void ipcp_resetci(fsm *);	/* Reset our CI */
+static int  ipcp_cilen(fsm *);	        /* Return length of our CI */
+static void ipcp_addci(fsm *, u_char *, int *); /* Add our CI */
+static int  ipcp_ackci(fsm *, u_char *, int);	/* Peer ack'd our CI */
+static int  ipcp_nakci(fsm *, u_char *, int);	/* Peer nak'd our CI */
+static int  ipcp_rejci(fsm *, u_char *, int);	/* Peer rej'd our CI */
+static int  ipcp_reqci(fsm *, u_char *, int *, int); /* Rcv CI */
+static void ipcp_up(fsm *);		/* We're UP */
+static void ipcp_down(fsm *);		/* We're DOWN */
+static void ipcp_finished(fsm *);	/* Don't need lower layer */
+
+fsm ipcp_fsm[NUM_PPP];		/* IPCP fsm structure */
+
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
+    ipcp_resetci,		/* Reset our Configuration Information */
+    ipcp_cilen,			/* Length of our Configuration Information */
+    ipcp_addci,			/* Add our Configuration Information */
+    ipcp_ackci,			/* ACK our Configuration Information */
+    ipcp_nakci,			/* NAK our Configuration Information */
+    ipcp_rejci,			/* Reject our Configuration Information */
+    ipcp_reqci,			/* Request peer's Configuration Information */
+    ipcp_up,			/* Called when fsm reaches OPENED state */
+    ipcp_down,			/* Called when fsm leaves OPENED state */
+    NULL,			/* Called when we want the lower layer up */
+    ipcp_finished,		/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    NULL,			/* Called to handle protocol-specific codes */
+    "IPCP"			/* String name of protocol */
+};
+
+/*
+ * Command-line options.
+ */
+static int setvjslots(char **);
+static int setdnsaddr(char **);
+static int setwinsaddr(char **);
+
+static option_t ipcp_option_list[] = {
+    { "noip", o_bool, &ipcp_protent.enabled_flag,
+      "Disable IP and IPCP", 0, NULL, 0, 0 },
+    { "-ip", o_bool, &ipcp_protent.enabled_flag,
+      "Disable IP and IPCP", 0, NULL, 0, 0 },
+    { "novj", o_bool, &ipcp_wantoptions[0].neg_vj,
+      "Disable VJ compression", OPT_A2COPY,
+      &ipcp_allowoptions[0].neg_vj, 0, 0 },
+    { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj,
+      "Disable VJ compression", OPT_A2COPY,
+      &ipcp_allowoptions[0].neg_vj, 0, 0 },
+    { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+      "Disable VJ connection-ID compression", OPT_A2COPY,
+      &ipcp_allowoptions[0].cflag, 0, 0 },
+    { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
+      "Disable VJ connection-ID compression", OPT_A2COPY,
+      &ipcp_allowoptions[0].cflag, 0, 0 },
+    { "vj-max-slots", 1, setvjslots,
+      "Set maximum VJ header slots", 0, NULL, 0, 0 },
+    { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
+      "Accept peer's address for us", 1, NULL, 0, 0 },
+    { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote,
+      "Accept peer's address for it", 1, NULL, 0, 0 },
+    { "ipparam", o_string, &ipparam,
+      "Set ip script parameter", 0, NULL, 0, 0 },
+    { "noipdefault", o_bool, &disable_defaultip,
+      "Don't use name for default IP adrs", 1, NULL, 0, 0 },
+    { "ms-dns", 1, setdnsaddr,
+      "DNS address for the peer's use", 0, NULL, 0, 0 },
+    { "ms-wins", 1, setwinsaddr,
+      "Nameserver for SMB over TCP/IP for peer", 0, NULL, 0, 0 },
+    { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime,
+      "Set timeout for IPCP", 0, NULL, 0, 0 },
+    { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits,
+      "Set max #xmits for term-reqs", 0, NULL, 0, 0 },
+    { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits,
+      "Set max #xmits for conf-reqs", 0, NULL, 0, 0 },
+    { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops,
+      "Set max #conf-naks for IPCP", 0, NULL, 0, 0 },
+    { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route,
+      "Add default route", OPT_ENABLE|1,
+      &ipcp_allowoptions[0].default_route, 0, 0 },
+    { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+      "disable defaultroute option", OPT_A2COPY,
+      &ipcp_wantoptions[0].default_route, 0, 0 },
+    { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
+      "disable defaultroute option", OPT_A2COPY,
+      &ipcp_wantoptions[0].default_route, 0, 0 },
+    { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
+      "Add proxy ARP entry", OPT_ENABLE|1,
+      &ipcp_allowoptions[0].proxy_arp, 0, 0 },
+    { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+      "disable proxyarp option", OPT_A2COPY,
+      &ipcp_wantoptions[0].proxy_arp, 0, 0 },
+    { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
+      "disable proxyarp option", OPT_A2COPY,
+      &ipcp_wantoptions[0].proxy_arp, 0, 0 },
+    { "usepeerdns", o_bool, &usepeerdns,
+      "Ask peer for DNS address(es)", 1, NULL, 0, 0 },
+    { NULL, 0, NULL, NULL, 0,  NULL, 0, 0 }
+};
+
+/*
+ * Protocol entry points from main code.
+ */
+static void ipcp_init(int);
+static void ipcp_open(int);
+static void ipcp_close(int, char *);
+static void ipcp_lowerup(int);
+static void ipcp_lowerdown(int);
+static void ipcp_input(int, u_char *, int);
+static void ipcp_protrej(int);
+static int  ipcp_printpkt(u_char *, int,
+			       void (*)(void *, char *, ...), void *);
+static void ip_check_options(void);
+static int  ip_demand_conf(int);
+static int  ip_active_pkt(u_char *, int);
+static void create_resolv(uint32_t, uint32_t);
+
+struct protent ipcp_protent = {
+    PPP_IPCP,
+    ipcp_init,
+    ipcp_input,
+    ipcp_protrej,
+    ipcp_lowerup,
+    ipcp_lowerdown,
+    ipcp_open,
+    ipcp_close,
+    ipcp_printpkt,
+    NULL,
+    1,
+    "IPCP",
+    "IP",
+    ipcp_option_list,
+    ip_check_options,
+    ip_demand_conf,
+    ip_active_pkt
+};
+
+static void ipcp_clear_addrs(int, uint32_t, uint32_t);
+
+/*
+ * Lengths of configuration options.
+ */
+#define CILEN_VOID	2
+#define CILEN_COMPRESS	4	/* min length for compression protocol opt. */
+#define CILEN_VJ	6	/* length for RFC1332 Van-Jacobson opt. */
+#define CILEN_ADDR	6	/* new-style single address option */
+#define CILEN_ADDRS	10	/* old-style dual address option */
+
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+/*
+ * Make a string representation of a network IP address.
+ */
+char *
+ip_ntoa(
+  uint32_t ipaddr)
+{
+    static char b[64];
+
+    slprintf(b, sizeof(b), "%I", ipaddr);
+    return b;
+}
+
+/*
+ * Option parsing.
+ */
+
+/*
+ * setvjslots - set maximum number of connection slots for VJ compression
+ */
+static int
+setvjslots(
+    char **argv)
+{
+    int value;
+
+    if (!int_option(*argv, &value))
+	return 0;
+    if (value < 2 || value > 16) {
+	option_error("vj-max-slots value must be between 2 and 16");
+	return 0;
+    }
+    ipcp_wantoptions [0].maxslotindex =
+        ipcp_allowoptions[0].maxslotindex = value - 1;
+    return 1;
+}
+
+/*
+ * setdnsaddr - set the dns address(es)
+ */
+static int
+setdnsaddr(
+    char **argv)
+{
+    uint32_t dns;
+    struct hostent *hp;
+
+    dns = inet_addr(*argv);
+    if (dns == (uint32_t) -1) {
+	if ((hp = gethostbyname(*argv)) == NULL) {
+	    option_error("invalid address parameter '%s' for ms-dns option",
+			 *argv);
+	    return 0;
+	}
+	dns = *(uint32_t *)hp->h_addr;
+    }
+
+    /* if there is no primary then update it. */
+    if (ipcp_allowoptions[0].dnsaddr[0] == 0)
+	ipcp_allowoptions[0].dnsaddr[0] = dns;
+
+    /* always set the secondary address value to the same value. */
+    ipcp_allowoptions[0].dnsaddr[1] = dns;
+
+    return (1);
+}
+
+/*
+ * setwinsaddr - set the wins address(es)
+ * This is primrarly used with the Samba package under UNIX or for pointing
+ * the caller to the existing WINS server on a Windows NT platform.
+ */
+static int
+setwinsaddr(
+    char **argv)
+{
+    uint32_t wins;
+    struct hostent *hp;
+
+    wins = inet_addr(*argv);
+    if (wins == (uint32_t) -1) {
+	if ((hp = gethostbyname(*argv)) == NULL) {
+	    option_error("invalid address parameter '%s' for ms-wins option",
+			 *argv);
+	    return 0;
+	}
+	wins = *(uint32_t *)hp->h_addr;
+    }
+
+    /* if there is no primary then update it. */
+    if (ipcp_allowoptions[0].winsaddr[0] == 0)
+	ipcp_allowoptions[0].winsaddr[0] = wins;
+
+    /* always set the secondary address value to the same value. */
+    ipcp_allowoptions[0].winsaddr[1] = wins;
+
+    return (1);
+}
+
+
+/*
+ * ipcp_init - Initialize IPCP.
+ */
+static void
+ipcp_init(
+    int unit)
+{
+    fsm *f = &ipcp_fsm[unit];
+    ipcp_options *wo = &ipcp_wantoptions[unit];
+    ipcp_options *ao = &ipcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_IPCP;
+    f->callbacks = &ipcp_callbacks;
+    fsm_init(&ipcp_fsm[unit]);
+
+    memset(wo, 0, sizeof(*wo));
+    memset(ao, 0, sizeof(*ao));
+
+    wo->neg_addr = 1;
+    wo->neg_vj = 1;
+    wo->vj_protocol = IPCP_VJ_COMP;
+    wo->maxslotindex = MAX_STATES - 1; /* really max index */
+    wo->cflag = 1;
+
+    /* max slots and slot-id compression are currently hardwired in */
+    /* ppp_if.c to 16 and 1, this needs to be changed (among other */
+    /* things) gmc */
+
+    ao->neg_addr = 1;
+    ao->neg_vj = 1;
+    ao->maxslotindex = MAX_STATES - 1;
+    ao->cflag = 1;
+
+    /*
+     * XXX These control whether the user may use the proxyarp
+     * and defaultroute options.
+     */
+    ao->proxy_arp = 1;
+    ao->default_route = 1;
+}
+
+
+/*
+ * ipcp_open - IPCP is allowed to come up.
+ */
+static void
+ipcp_open(
+    int unit)
+{
+    fsm_open(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_close - Take IPCP down.
+ */
+static void
+ipcp_close(
+    int unit,
+    char *reason)
+{
+    fsm_close(&ipcp_fsm[unit], reason);
+}
+
+
+/*
+ * ipcp_lowerup - The lower layer is up.
+ */
+static void
+ipcp_lowerup(
+    int unit)
+{
+    fsm_lowerup(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_lowerdown - The lower layer is down.
+ */
+static void
+ipcp_lowerdown(
+    int unit)
+{
+    fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_input - Input IPCP packet.
+ */
+static void
+ipcp_input(
+    int unit,
+    u_char *p,
+    int len)
+{
+    fsm_input(&ipcp_fsm[unit], p, len);
+}
+
+
+/*
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.
+ *
+ * Pretend the lower layer went down, so we shut up.
+ */
+static void
+ipcp_protrej(
+    int unit)
+{
+    fsm_lowerdown(&ipcp_fsm[unit]);
+}
+
+
+/*
+ * ipcp_resetci - Reset our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+ipcp_resetci(
+    fsm *f)
+{
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+
+    wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
+    if (wo->ouraddr == 0 || disable_defaultip)
+	wo->accept_local = 1;
+    if (wo->hisaddr == 0)
+	wo->accept_remote = 1;
+    wo->req_dns1 = usepeerdns;	/* Request DNS addresses from the peer */
+    wo->req_dns2 = usepeerdns;
+    *go = *wo;
+    if (disable_defaultip)
+	go->ouraddr = 0;
+}
+
+
+/*
+ * ipcp_cilen - Return length of our CI.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static int
+ipcp_cilen(
+    fsm *f)
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+
+#define LENCIVJ(neg, old)	(neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
+#define LENCIADDR(neg, old)	(neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
+#define LENCIDNS(neg)		(neg ? (CILEN_ADDR) : 0)
+
+    /*
+     * First see if we want to change our options to the old
+     * forms because we have received old forms from the peer.
+     */
+    if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
+	/* use the old style of address negotiation */
+	go->neg_addr = 1;
+	go->old_addrs = 1;
+    }
+    if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
+	/* try an older style of VJ negotiation */
+	/* use the old style only if the peer did */
+	if (ho->neg_vj && ho->old_vj) {
+	    go->neg_vj = 1;
+	    go->old_vj = 1;
+	    go->vj_protocol = ho->vj_protocol;
+	}
+    }
+
+    return (LENCIADDR(go->neg_addr, go->old_addrs) +
+	    LENCIVJ(go->neg_vj, go->old_vj) +
+	    LENCIDNS(go->req_dns1) +
+	    LENCIDNS(go->req_dns2)) ;
+}
+
+
+/*
+ * ipcp_addci - Add our desired CIs to a packet.
+ * Called by fsm_sconfreq, Send Configure Request.
+ */
+static void
+ipcp_addci(
+    fsm *f,
+    u_char *ucp,
+    int *lenp)
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    int len = *lenp;
+
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+    if (neg) { \
+	int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+	if (len >= vjlen) { \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(vjlen, ucp); \
+	    PUTSHORT(val, ucp); \
+	    if (!old) { \
+		PUTCHAR(maxslotindex, ucp); \
+		PUTCHAR(cflag, ucp); \
+	    } \
+	    len -= vjlen; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIADDR(opt, neg, old, val1, val2) \
+    if (neg) { \
+	int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+	if (len >= addrlen) { \
+	    uint32_t l; \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(addrlen, ucp); \
+	    l = ntohl(val1); \
+	    PUTLONG(l, ucp); \
+	    if (old) { \
+		l = ntohl(val2); \
+		PUTLONG(l, ucp); \
+	    } \
+	    len -= addrlen; \
+	} else \
+	    neg = 0; \
+    }
+
+#define ADDCIDNS(opt, neg, addr) \
+    if (neg) { \
+	if (len >= CILEN_ADDR) { \
+	    uint32_t l; \
+	    PUTCHAR(opt, ucp); \
+	    PUTCHAR(CILEN_ADDR, ucp); \
+	    l = ntohl(addr); \
+	    PUTLONG(l, ucp); \
+	    len -= CILEN_ADDR; \
+	} else \
+	    neg = 0; \
+    }
+
+    ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+    ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+    *lenp -= len;
+}
+
+
+/*
+ * ipcp_ackci - Ack our CIs.
+ * Called by fsm_rconfack, Receive Configure ACK.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+ipcp_ackci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_short cilen, citype, cishort;
+    uint32_t cilong;
+    u_char cimaxslotindex, cicflag;
+
+    /*
+     * CIs must be in exactly the same order that we sent...
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
+    if (neg) { \
+	int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
+	if ((len -= vjlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != vjlen || \
+	    citype != opt)  \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+	if (!old) { \
+	    GETCHAR(cimaxslotindex, p); \
+	    if (cimaxslotindex != maxslotindex) \
+		goto bad; \
+	    GETCHAR(cicflag, p); \
+	    if (cicflag != cflag) \
+		goto bad; \
+	} \
+    }
+
+#define ACKCIADDR(opt, neg, old, val1, val2) \
+    if (neg) { \
+	int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
+	uint32_t l; \
+	if ((len -= addrlen) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != addrlen || \
+	    citype != opt) \
+	    goto bad; \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	if (val1 != cilong) \
+	    goto bad; \
+	if (old) { \
+	    GETLONG(l, p); \
+	    cilong = htonl(l); \
+	    if (val2 != cilong) \
+		goto bad; \
+	} \
+    }
+
+#define ACKCIDNS(opt, neg, addr) \
+    if (neg) { \
+	uint32_t l; \
+	if ((len -= CILEN_ADDR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_ADDR || citype != opt) \
+	    goto bad; \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	if (addr != cilong) \
+	    goto bad; \
+    }
+
+    ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
+
+    ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+
+bad:
+    IPCPDEBUG(("ipcp_ackci: received bad Ack!"));
+    return (0);
+}
+
+/*
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if IPCP is in the OPENED state.
+ * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+ipcp_nakci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char cimaxslotindex, cicflag;
+    u_char citype, cilen, *next;
+    u_short cishort;
+    uint32_t ciaddr1, ciaddr2, l, cidnsaddr;
+    ipcp_options no;		/* options we've seen Naks for */
+    ipcp_options try;		/* options to request next time */
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIADDR(opt, neg, old, code) \
+    if (go->neg && \
+	len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	ciaddr1 = htonl(l); \
+	if (old) { \
+	    GETLONG(l, p); \
+	    ciaddr2 = htonl(l); \
+	    no.old_addrs = 1; \
+	} else \
+	    ciaddr2 = 0; \
+	no.neg = 1; \
+	code \
+    }
+
+#define NAKCIVJ(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+        code \
+    }
+
+#define NAKCIDNS(opt, neg, code) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_ADDR) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	cidnsaddr = htonl(l); \
+	no.neg = 1; \
+	code \
+    }
+
+    /*
+     * Accept the peer's idea of {our,his} address, if different
+     * from our idea, only if the accept_{local,remote} flag is set.
+     */
+    NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
+	      if (go->accept_local && ciaddr1) { /* Do we know our address? */
+		  try.ouraddr = ciaddr1;
+	      }
+	      if (go->accept_remote && ciaddr2) { /* Does he know his? */
+		  try.hisaddr = ciaddr2;
+	      }
+	      );
+
+    /*
+     * Accept the peer's value of maxslotindex provided that it
+     * is less than what we asked for.  Turn off slot-ID compression
+     * if the peer wants.  Send old-style compress-type option if
+     * the peer wants.
+     */
+    NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
+	    if (cilen == CILEN_VJ) {
+		GETCHAR(cimaxslotindex, p);
+		GETCHAR(cicflag, p);
+		if (cishort == IPCP_VJ_COMP) {
+		    try.old_vj = 0;
+		    if (cimaxslotindex < go->maxslotindex)
+			try.maxslotindex = cimaxslotindex;
+		    if (!cicflag)
+			try.cflag = 0;
+		} else {
+		    try.neg_vj = 0;
+		}
+	    } else {
+		if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
+		    try.old_vj = 1;
+		    try.vj_protocol = cishort;
+		} else {
+		    try.neg_vj = 0;
+		}
+	    }
+	    );
+
+    NAKCIDNS(CI_MS_DNS1, req_dns1,
+	    try.dnsaddr[0] = cidnsaddr;
+	    );
+
+    NAKCIDNS(CI_MS_DNS2, req_dns2,
+	    try.dnsaddr[1] = cidnsaddr;
+	    );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If they want to negotiate about IP addresses, we comply.
+     * If they want us to ask for compression, we refuse.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if( (len -= cilen) < 0 )
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_COMPRESSTYPE:
+	    if (go->neg_vj || no.neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
+		goto bad;
+	    no.neg_vj = 1;
+	    break;
+	case CI_ADDRS:
+	    if ((go->neg_addr && go->old_addrs) || no.old_addrs
+		|| cilen != CILEN_ADDRS)
+		goto bad;
+	    try.neg_addr = 1;
+	    try.old_addrs = 1;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (ciaddr1 && go->accept_local)
+		try.ouraddr = ciaddr1;
+	    GETLONG(l, p);
+	    ciaddr2 = htonl(l);
+	    if (ciaddr2 && go->accept_remote)
+		try.hisaddr = ciaddr2;
+	    no.old_addrs = 1;
+	    break;
+	case CI_ADDR:
+	    if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
+		goto bad;
+	    try.old_addrs = 0;
+	    GETLONG(l, p);
+	    ciaddr1 = htonl(l);
+	    if (ciaddr1 && go->accept_local)
+		try.ouraddr = ciaddr1;
+	    if (try.ouraddr != 0)
+		try.neg_addr = 1;
+	    no.neg_addr = 1;
+	    break;
+	}
+	p = next;
+    }
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     * If there are any remaining options, we ignore them.
+     */
+    if (f->state != OPENED)
+	*go = try;
+
+    return 1;
+
+bad:
+    IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * ipcp_rejci - Reject some of our CIs.
+ * Callback from fsm_rconfnakrej.
+ */
+static int
+ipcp_rejci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char cimaxslotindex, ciflag, cilen;
+    u_short cishort;
+    uint32_t cilong;
+    ipcp_options try;		/* options to request next time */
+
+    try = *go;
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIADDR(opt, neg, old, val1, val2) \
+    if (go->neg && \
+	len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
+	p[1] == cilen && \
+	p[0] == opt) { \
+	uint32_t l; \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	/* Check rejected value. */ \
+	if (cilong != val1) \
+	    goto bad; \
+	if (old) { \
+	    GETLONG(l, p); \
+	    cilong = htonl(l); \
+	    /* Check rejected value. */ \
+	    if (cilong != val2) \
+		goto bad; \
+	} \
+	try.neg = 0; \
+    }
+
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
+    if (go->neg && \
+	p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
+	len >= p[1] && \
+	p[0] == opt) { \
+	len -= p[1]; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */  \
+	if (cishort != val) \
+	    goto bad; \
+	if (!old) { \
+	   GETCHAR(cimaxslotindex, p); \
+	   if (cimaxslotindex != maxslot) \
+	     goto bad; \
+	   GETCHAR(ciflag, p); \
+	   if (ciflag != cflag) \
+	     goto bad; \
+        } \
+	try.neg = 0; \
+     }
+
+#define REJCIDNS(opt, neg, dnsaddr) \
+    if (go->neg && \
+	((cilen = p[1]) == CILEN_ADDR) && \
+	len >= cilen && \
+	p[0] == opt) { \
+	uint32_t l; \
+	len -= cilen; \
+	INCPTR(2, p); \
+	GETLONG(l, p); \
+	cilong = htonl(l); \
+	/* Check rejected value. */ \
+	if (cilong != dnsaddr) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+
+    REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
+	      go->old_addrs, go->ouraddr, go->hisaddr);
+
+    REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
+	    go->maxslotindex, go->cflag);
+
+    REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
+
+    REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    IPCPDEBUG(("ipcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
+ * Callback from fsm_rconfreq, Receive Configure Request
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+ipcp_reqci(
+    fsm *f,
+    u_char *inp,		/* Requested CIs */
+    int *len,			/* Length of requested CIs */
+    int reject_if_disagree)
+{
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    ipcp_options *ao = &ipcp_allowoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    u_short cilen, citype;	/* Parsed len, type */
+    u_short cishort;		/* Parsed short value */
+    uint32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *ucp = inp;		/* Pointer to current output char */
+    int l = *len;		/* Length left */
+    u_char maxslotindex, cflag;
+    int d;
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    IPCPDEBUG(("ipcp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+	case CI_ADDRS:
+	    if (!ao->neg_addr ||
+		cilen != CILEN_ADDRS) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+
+	    /*
+	     * If he has no address, or if we both have his address but
+	     * disagree about it, then NAK it with our idea.
+	     * In particular, if we don't know his address, but he does,
+	     * then accept it.
+	     */
+	    GETLONG(tl, p);		/* Parse source address (his) */
+	    ciaddr1 = htonl(tl);
+	    if (ciaddr1 != wo->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(uint32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * If neither we nor he knows his address, reject the option.
+		 */
+		orc = CONFREJ;
+		wo->req_addr = 0;	/* don't NAK with 0.0.0.0 later */
+		break;
+	    }
+
+	    /*
+	     * If he doesn't know our address, or if we both have our address
+	     * but disagree about it, then NAK it with our idea.
+	     */
+	    GETLONG(tl, p);		/* Parse desination address (ours) */
+	    ciaddr2 = htonl(tl);
+	    if (ciaddr2 != wo->ouraddr) {
+		if (ciaddr2 == 0 || !wo->accept_local) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree) {
+			DECPTR(sizeof(uint32_t), p);
+			tl = ntohl(wo->ouraddr);
+			PUTLONG(tl, p);
+		    }
+		} else {
+		    go->ouraddr = ciaddr2;	/* accept peer's idea */
+		}
+	    }
+
+	    ho->neg_addr = 1;
+	    ho->old_addrs = 1;
+	    ho->hisaddr = ciaddr1;
+	    ho->ouraddr = ciaddr2;
+	    break;
+
+	case CI_ADDR:
+	    if (!ao->neg_addr ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+
+	    /*
+	     * If he has no address, or if we both have his address but
+	     * disagree about it, then NAK it with our idea.
+	     * In particular, if we don't know his address, but he does,
+	     * then accept it.
+	     */
+	    GETLONG(tl, p);	/* Parse source address (his) */
+	    ciaddr1 = htonl(tl);
+	    if (ciaddr1 != wo->hisaddr
+		&& (ciaddr1 == 0 || !wo->accept_remote)) {
+		orc = CONFNAK;
+		if (!reject_if_disagree) {
+		    DECPTR(sizeof(uint32_t), p);
+		    tl = ntohl(wo->hisaddr);
+		    PUTLONG(tl, p);
+		}
+	    } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
+		/*
+		 * Don't ACK an address of 0.0.0.0 - reject it instead.
+		 */
+		orc = CONFREJ;
+		wo->req_addr = 0;	/* don't NAK with 0.0.0.0 later */
+		break;
+	    }
+	
+	    ho->neg_addr = 1;
+	    ho->hisaddr = ciaddr1;
+	    break;
+
+	case CI_MS_DNS1:
+	case CI_MS_DNS2:
+	    /* Microsoft primary or secondary DNS request */
+	    d = citype == CI_MS_DNS2;
+
+	    /* If we do not have a DNS address then we cannot send it */
+	    if (ao->dnsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->dnsaddr[d]) {
+                DECPTR(sizeof(uint32_t), p);
+		tl = ntohl(ao->dnsaddr[d]);
+		PUTLONG(tl, p);
+		orc = CONFNAK;
+            }
+            break;
+
+	case CI_MS_WINS1:
+	case CI_MS_WINS2:
+	    /* Microsoft primary or secondary WINS request */
+	    d = citype == CI_MS_WINS2;
+
+	    /* If we do not have a DNS address then we cannot send it */
+	    if (ao->winsaddr[d] == 0 ||
+		cilen != CILEN_ADDR) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETLONG(tl, p);
+	    if (htonl(tl) != ao->winsaddr[d]) {
+                DECPTR(sizeof(uint32_t), p);
+		tl = ntohl(ao->winsaddr[d]);
+		PUTLONG(tl, p);
+		orc = CONFNAK;
+            }
+            break;
+	
+	case CI_COMPRESSTYPE:
+	    if (!ao->neg_vj ||
+		(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+
+	    if (!(cishort == IPCP_VJ_COMP ||
+		  (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    ho->neg_vj = 1;
+	    ho->vj_protocol = cishort;
+	    if (cilen == CILEN_VJ) {
+		GETCHAR(maxslotindex, p);
+		if (maxslotindex > ao->maxslotindex) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(ao->maxslotindex, p);
+		    }
+		}
+		GETCHAR(cflag, p);
+		if (cflag && !ao->cflag) {
+		    orc = CONFNAK;
+		    if (!reject_if_disagree){
+			DECPTR(1, p);
+			PUTCHAR(wo->cflag, p);
+		    }
+		}
+		ho->maxslotindex = maxslotindex;
+		ho->cflag = cflag;
+	    } else {
+		ho->old_vj = 1;
+		ho->maxslotindex = MAX_STATES - 1;
+		ho->cflag = 1;
+	    }
+	    break;
+
+	default:
+	    orc = CONFREJ;
+	    break;
+	}
+endswitch:
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree)	/* Getting fed up with sending NAKs? */
+		orc = CONFREJ;		/* Get tough if so */
+	    else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		if (rc == CONFACK) {	/* Ack'd all prior CIs? */
+		    rc = CONFNAK;	/* Not anymore... */
+		    ucp = inp;		/* Backup */
+		}
+	    }
+	}
+
+	if (orc == CONFREJ &&		/* Reject this CI */
+	    rc != CONFREJ) {		/*  but no prior ones? */
+	    rc = CONFREJ;
+	    ucp = inp;			/* Backup */
+	}
+
+	/* Need to move CI? */
+	if (ucp != cip)
+	    BCOPY(cip, ucp, cilen);	/* Move it */
+
+	/* Update output pointer */
+	INCPTR(cilen, ucp);
+    }
+
+    /*
+     * If we aren't rejecting this packet, and we want to negotiate
+     * their address, and they didn't send their address, then we
+     * send a NAK with a CI_ADDR option appended.  We assume the
+     * input buffer is long enough that we can append the extra
+     * option safely.
+     */
+    if (rc != CONFREJ && !ho->neg_addr &&
+	wo->req_addr && !reject_if_disagree) {
+	if (rc == CONFACK) {
+	    rc = CONFNAK;
+	    ucp = inp;			/* reset pointer */
+	    wo->req_addr = 0;		/* don't ask again */
+	}
+	PUTCHAR(CI_ADDR, ucp);
+	PUTCHAR(CILEN_ADDR, ucp);
+	tl = ntohl(wo->hisaddr);
+	PUTLONG(tl, ucp);
+    }
+
+    *len = ucp - inp;			/* Compute output length */
+    IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+static void
+ip_check_options(void)
+{
+    struct hostent *hp;
+    uint32_t local;
+    ipcp_options *wo = &ipcp_wantoptions[0];
+
+    /*
+     * Default our local IP address based on our hostname.
+     * If local IP address already given, don't bother.
+     */
+    if (wo->ouraddr == 0 && !disable_defaultip) {
+	/*
+	 * Look up our hostname (possibly with domain name appended)
+	 * and take the first IP address as our local IP address.
+	 * If there isn't an IP address for our hostname, too bad.
+	 */
+	wo->accept_local = 1;	/* don't insist on this default value */
+	if ((hp = gethostbyname(hostname)) != NULL) {
+	    local = *(uint32_t *)hp->h_addr;
+	    if (local != 0 && !bad_ip_adrs(local))
+		wo->ouraddr = local;
+	}
+    }
+}
+
+
+/*
+ * ip_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+static int
+ip_demand_conf(
+    int u)
+{
+    ipcp_options *wo = &ipcp_wantoptions[u];
+
+    if (wo->hisaddr == 0) {
+	/* make up an arbitrary address for the peer */
+	wo->hisaddr = htonl(0x0a707070 + pppifunit);
+	wo->accept_remote = 1;
+    }
+    if (wo->ouraddr == 0) {
+	/* make up an arbitrary address for us */
+	wo->ouraddr = htonl(0x0a404040 + pppifunit);
+	wo->accept_local = 1;
+	disable_defaultip = 1;	/* don't tell the peer this address */
+    }
+    if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr)))
+	return 0;
+    if (!sifup(u))
+	return 0;
+    if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+	return 0;
+    if (wo->default_route)
+	if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
+	    default_route_set[u] = 1;
+    if (wo->proxy_arp)
+	if (sifproxyarp(u, wo->hisaddr))
+	    proxy_arp_set[u] = 1;
+
+    notice("local  IP address %I", wo->ouraddr);
+    notice("remote IP address %I", wo->hisaddr);
+
+    return 1;
+}
+
+
+/*
+ * ipcp_up - IPCP has come UP.
+ *
+ * Configure the IP network interface appropriately and bring it up.
+ */
+static void
+ipcp_up(
+    fsm *f)
+{
+    uint32_t mask;
+    ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    ipcp_options *go = &ipcp_gotoptions[f->unit];
+    ipcp_options *wo = &ipcp_wantoptions[f->unit];
+
+    IPCPDEBUG(("ipcp: up"));
+
+    /*
+     * We must have a non-zero IP address for both ends of the link.
+     */
+    if (!ho->neg_addr)
+	ho->hisaddr = wo->hisaddr;
+
+    if (ho->hisaddr == 0) {
+	error("Could not determine remote IP address");
+	ipcp_close(f->unit, "Could not determine remote IP address");
+	return;
+    }
+    if (go->ouraddr == 0) {
+	error("Could not determine local IP address");
+	ipcp_close(f->unit, "Could not determine local IP address");
+	return;
+    }
+
+    if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
+	create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
+    }
+
+    /*
+     * Check that the peer is allowed to use the IP address it wants.
+     */
+    if (!auth_ip_addr(f->unit, ho->hisaddr)) {
+	error("Peer is not authorized to use remote address %I", ho->hisaddr);
+	ipcp_close(f->unit, "Unauthorized remote IP address");
+	return;
+    }
+
+    /* set tcp compression */
+    sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
+
+    /*
+     * If we are doing dial-on-demand, the interface is already
+     * configured, so we put out any saved-up packets, then set the
+     * interface to pass IP packets.
+     */
+    if (demand) {
+	if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
+	    ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
+	    if (go->ouraddr != wo->ouraddr) {
+		warn("Local IP address changed to %I", go->ouraddr);
+		wo->ouraddr = go->ouraddr;
+	    }
+	    if (ho->hisaddr != wo->hisaddr) {
+		warn("Remote IP address changed to %I", ho->hisaddr);
+		wo->hisaddr = ho->hisaddr;
+	    }
+
+	    /* Set the interface to the new addresses */
+	    mask = GetMask(go->ouraddr);
+	    if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+		if (debug)
+		    warn("Interface configuration failed");
+		ipcp_close(f->unit, "Interface configuration failed");
+		return;
+	    }
+
+	    /* assign a default route through the interface if required */
+	    if (ipcp_wantoptions[f->unit].default_route)
+		if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		    default_route_set[f->unit] = 1;
+
+	    /* Make a proxy ARP entry if requested. */
+	    if (ipcp_wantoptions[f->unit].proxy_arp)
+		if (sifproxyarp(f->unit, ho->hisaddr))
+		    proxy_arp_set[f->unit] = 1;
+
+	}
+	demand_rexmit(PPP_IP);
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+    } else {
+	/*
+	 * Set IP addresses and (if specified) netmask.
+	 */
+	mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    if (debug)
+		warn("Interface configuration failed");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+
+	/* bring the interface up for IP */
+	if (!sifup(f->unit)) {
+	    if (debug)
+		warn("Interface failed to come up");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+	if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+	    if (debug)
+		warn("Interface configuration failed");
+	    ipcp_close(f->unit, "Interface configuration failed");
+	    return;
+	}
+#endif
+	sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
+
+	/* assign a default route through the interface if required */
+	if (ipcp_wantoptions[f->unit].default_route)
+	    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+		default_route_set[f->unit] = 1;
+
+	/* Make a proxy ARP entry if requested. */
+	if (ipcp_wantoptions[f->unit].proxy_arp)
+	    if (sifproxyarp(f->unit, ho->hisaddr))
+		proxy_arp_set[f->unit] = 1;
+
+	ipcp_wantoptions[0].ouraddr = go->ouraddr;
+
+	notice("local  IP address %I", go->ouraddr);
+	notice("remote IP address %I", ho->hisaddr);
+	if (go->dnsaddr[0])
+	    notice("primary   DNS address %I", go->dnsaddr[0]);
+	if (go->dnsaddr[1])
+	    notice("secondary DNS address %I", go->dnsaddr[1]);
+    }
+
+    np_up(f->unit, PPP_IP);
+    ipcp_is_up = 1;
+
+    if (ip_up_hook)
+	ip_up_hook();
+}
+
+
+/*
+ * ipcp_down - IPCP has gone DOWN.
+ *
+ * Take the IP network interface down, clear its addresses
+ * and delete routes through it.
+ */
+static void
+ipcp_down(
+    fsm *f)
+{
+    IPCPDEBUG(("ipcp: down"));
+    /* XXX a bit IPv4-centric here, we only need to get the stats
+     * before the interface is marked down. */
+    update_link_stats(f->unit);
+    if (ip_down_hook)
+	ip_down_hook();
+    if (ipcp_is_up) {
+	ipcp_is_up = 0;
+	np_down(f->unit, PPP_IP);
+    }
+    sifvjcomp(f->unit, 0, 0, 0);
+
+    /*
+     * If we are doing dial-on-demand, set the interface
+     * to queue up outgoing packets (for now).
+     */
+    if (demand) {
+	sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE);
+    } else {
+	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_clear_addrs() - clear the interface addresses, routes,
+ * proxy arp entries, etc.
+ */
+static void
+ipcp_clear_addrs(
+    int unit,
+    uint32_t ouraddr,  /* local address */
+    uint32_t hisaddr  /* remote address */)
+{
+    if (proxy_arp_set[unit]) {
+	cifproxyarp(unit, hisaddr);
+	proxy_arp_set[unit] = 0;
+    }
+    if (default_route_set[unit]) {
+	cifdefaultroute(unit, ouraddr, hisaddr);
+	default_route_set[unit] = 0;
+    }
+    cifaddr(unit, ouraddr, hisaddr);
+}
+
+
+/*
+ * ipcp_finished - possibly shut down the lower layers.
+ */
+static void
+ipcp_finished(
+    fsm *f)
+{
+    np_finished(f->unit, PPP_IP);
+}
+
+/*
+ * create_resolv - create the replacement resolv.conf file
+ */
+static void
+create_resolv(
+    uint32_t peerdns1, uint32_t peerdns2)
+{
+  /* initialize values */
+  rtems_bsdnet_nameserver_count = 0;
+
+  /* check to see if primary was specified */
+  if ( peerdns1 ) {
+    rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count].s_addr = peerdns1;
+    rtems_bsdnet_nameserver_count++;
+  }
+
+  /* check to see if secondary was specified */
+  if ( peerdns2 ) {
+    rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count].s_addr = peerdns2;
+    rtems_bsdnet_nameserver_count++;
+  }
+
+  /* initialize resolver */
+  __res_init();
+}
+
+/*
+ * ipcp_printpkt - print the contents of an IPCP packet.
+ */
+static char *ipcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej"
+};
+
+static int
+ipcp_printpkt(
+    u_char *p,
+    int plen,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    uint32_t cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(ipcp_codenames) / sizeof(char *))
+	printer(arg, " %s", ipcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_ADDRS:
+		if (olen == CILEN_ADDRS) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addrs %I", htonl(cilong));
+		    GETLONG(cilong, p);
+		    printer(arg, " %I", htonl(cilong));
+		}
+		break;
+	    case CI_COMPRESSTYPE:
+		if (olen >= CILEN_COMPRESS) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "compress ");
+		    switch (cishort) {
+		    case IPCP_VJ_COMP:
+			printer(arg, "VJ");
+			break;
+		    case IPCP_VJ_COMP_OLD:
+			printer(arg, "old-VJ");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_ADDR:
+		if (olen == CILEN_ADDR) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "addr %I", htonl(cilong));
+		}
+		break;
+	    case CI_MS_DNS1:
+	    case CI_MS_DNS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-dns%d %I", code - CI_MS_DNS1 + 1,
+			htonl(cilong));
+		break;
+	    case CI_MS_WINS1:
+	    case CI_MS_WINS2:
+	        p += 2;
+		GETLONG(cilong, p);
+		printer(arg, "ms-wins %I", htonl(cilong));
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/*
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.
+ * We don't bring the link up for IP fragments or for TCP FIN packets
+ * with no data.
+ */
+#define IP_HDRLEN	20	/* bytes */
+#define IP_OFFMASK	0x1fff
+#define IPPROTO_TCP	6
+#define TCP_HDRLEN	20
+#define TH_FIN		0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x)	(((x)[0] << 8) + (x)[1])
+#define get_iphl(x)	(((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x)	net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x)	(((unsigned char *)(x))[9])
+#define get_tcpoff(x)	(((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x)	(((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(
+    u_char *pkt,
+    int len)
+{
+    u_char *tcp;
+    int hlen;
+
+    len -= PPP_HDRLEN;
+    pkt += PPP_HDRLEN;
+    if (len < IP_HDRLEN)
+	return 0;
+    if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+	return 0;
+    if (get_ipproto(pkt) != IPPROTO_TCP)
+	return 1;
+    hlen = get_iphl(pkt) * 4;
+    if (len < hlen + TCP_HDRLEN)
+	return 0;
+    tcp = pkt + hlen;
+    if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+	return 0;
+    return 1;
+}
diff --git a/rtemsbsd/pppd/ipcp.h b/rtemsbsd/pppd/ipcp.h
new file mode 100644
index 0000000..e841cf8
--- /dev/null
+++ b/rtemsbsd/pppd/ipcp.h
@@ -0,0 +1,73 @@
+/*
+ * ipcp.h - IP Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+/*
+ * Options.
+ */
+#define CI_ADDRS	1	/* IP Addresses */
+#define CI_COMPRESSTYPE	2	/* Compression Type */
+#define	CI_ADDR		3
+
+#define CI_MS_DNS1	129	/* Primary DNS value */
+#define CI_MS_WINS1	130	/* Primary WINS value */
+#define CI_MS_DNS2	131	/* Secondary DNS value */
+#define CI_MS_WINS2	132	/* Secondary WINS value */
+
+#define MAX_STATES 16		/* from slcompress.h */
+
+#define IPCP_VJMODE_OLD 1	/* "old" mode (option # = 0x0037) */
+#define IPCP_VJMODE_RFC1172 2	/* "old-rfc"mode (option # = 0x002d) */
+#define IPCP_VJMODE_RFC1332 3	/* "new-rfc"mode (option # = 0x002d, */
+                                /*  maxslot and slot number compression) */
+
+#define IPCP_VJ_COMP 0x002d	/* current value for VJ compression option*/
+#define IPCP_VJ_COMP_OLD 0x0037	/* "old" (i.e, broken) value for VJ */
+				/* compression option*/
+
+typedef struct ipcp_options {
+    bool neg_addr;		/* Negotiate IP Address? */
+    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 proxy_arp;		/* Make proxy ARP entry for peer? */
+    bool neg_vj;		/* Van Jacobson Compression? */
+    bool old_vj;		/* use old (short) form of VJ option? */
+    bool accept_local;		/* accept peer's value for ouraddr */
+    bool accept_remote;		/* accept peer's value for hisaddr */
+    bool req_dns1;		/* Ask peer to send primary DNS address? */
+    bool req_dns2;		/* Ask peer to send secondary DNS address? */
+    int  vj_protocol;		/* protocol value to use in VJ option */
+    int  maxslotindex;		/* values for RFC1332 VJ compression neg. */
+    bool cflag;
+    uint32_t ouraddr, hisaddr;	/* Addresses in NETWORK BYTE ORDER */
+    uint32_t dnsaddr[2];	/* Primary and secondary MS DNS entries */
+    uint32_t winsaddr[2];	/* Primary and secondary MS WINS entries */
+} ipcp_options;
+
+extern fsm ipcp_fsm[];
+extern ipcp_options ipcp_wantoptions[];
+extern ipcp_options ipcp_gotoptions[];
+extern ipcp_options ipcp_allowoptions[];
+extern ipcp_options ipcp_hisoptions[];
+
+char *ip_ntoa(uint32_t);
+
+extern struct protent ipcp_protent;
diff --git a/rtemsbsd/pppd/lcp.c b/rtemsbsd/pppd/lcp.c
new file mode 100644
index 0000000..9da1326
--- /dev/null
+++ b/rtemsbsd/pppd/lcp.c
@@ -0,0 +1,1953 @@
+/*
+ * lcp.c - PPP Link Control Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$";
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pppd.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "chap.h"
+#include "magic.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * LCP-related command-line options.
+ */
+static int	lcp_echo_interval = 0; 	/* Interval between LCP echo-requests */
+static int	lcp_echo_fails = 0;	/* Tolerance to unanswered echo-requests */
+static bool	lax_recv = false;	/* accept control chars in asyncmap */
+
+static int setescape(char **);
+
+static option_t lcp_option_list[] = {
+    /* LCP options */
+    { "noaccomp", o_bool, &lcp_wantoptions[0].neg_accompression,
+      "Disable address/control compression",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_accompression, 0, 0 },
+    { "-ac", o_bool, &lcp_wantoptions[0].neg_accompression,
+      "Disable address/control compression",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_accompression, 0, 0 },
+    { "default-asyncmap", o_bool, &lcp_wantoptions[0].neg_asyncmap,
+      "Disable asyncmap negotiation",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap, 0, 0 },
+    { "-am", o_bool, &lcp_wantoptions[0].neg_asyncmap,
+      "Disable asyncmap negotiation",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_asyncmap, 0, 0 },
+    { "asyncmap", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Set asyncmap (for received packets)",
+      OPT_OR, &lcp_wantoptions[0].neg_asyncmap, 0, 0 },
+    { "-as", o_uint32, &lcp_wantoptions[0].asyncmap,
+      "Set asyncmap (for received packets)",
+      OPT_OR, &lcp_wantoptions[0].neg_asyncmap, 0, 0 },
+    { "nomagic", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+      "Disable magic number negotiation (looped-back line detection)",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber, 0, 0 },
+    { "-mn", o_bool, &lcp_wantoptions[0].neg_magicnumber,
+      "Disable magic number negotiation (looped-back line detection)",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_magicnumber, 0, 0 },
+    { "default-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+      "Disable MRU negotiation (use default 1500)",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_mru, 0, 0 },
+    { "-mru", o_bool, &lcp_wantoptions[0].neg_mru,
+      "Disable MRU negotiation (use default 1500)",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_mru, 0, 0 },
+    { "mru", o_int, &lcp_wantoptions[0].mru,
+      "Set MRU (maximum received packet size) for negotiation",
+      0, &lcp_wantoptions[0].neg_mru, 0, 0 },
+    { "nopcomp", o_bool, &lcp_wantoptions[0].neg_pcompression,
+      "Disable protocol field compression",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression, 0, 0 },
+    { "-pc", o_bool, &lcp_wantoptions[0].neg_pcompression,
+      "Disable protocol field compression",
+      OPT_A2COPY, &lcp_allowoptions[0].neg_pcompression, 0, 0 },
+    { "-p", o_bool, &lcp_wantoptions[0].passive,
+      "Set passive mode", 1, NULL, 0, 0 },
+    { "passive", o_bool, &lcp_wantoptions[0].passive,
+      "Set passive mode", 1, NULL, 0, 0 },
+    { "silent", o_bool, &lcp_wantoptions[0].silent,
+      "Set silent mode", 1, NULL, 0, 0 },
+    { "escape", o_special, setescape,
+      "List of character codes to escape on transmission", 0, NULL, 0, 0 },
+    { "lcp-echo-failure", o_int, &lcp_echo_fails,
+      "Set number of consecutive echo failures to indicate link failure", 0, NULL, 0, 0 },
+    { "lcp-echo-interval", o_int, &lcp_echo_interval,
+      "Set time in seconds between LCP echo requests", 0, NULL, 0, 0 },
+    { "lcp-restart", o_int, &lcp_fsm[0].timeouttime,
+      "Set time in seconds between LCP retransmissions", 0, NULL, 0, 0 },
+    { "lcp-max-terminate", o_int, &lcp_fsm[0].maxtermtransmits,
+      "Set maximum number of LCP terminate-request transmissions", 0, NULL, 0, 0 },
+    { "lcp-max-configure", o_int, &lcp_fsm[0].maxconfreqtransmits,
+      "Set maximum number of LCP configure-request transmissions", 0, NULL, 0, 0 },
+    { "lcp-max-failure", o_int, &lcp_fsm[0].maxnakloops,
+      "Set limit on number of LCP configure-naks", 0, NULL, 0, 0 },
+    { "receive-all", o_bool, &lax_recv,
+      "Accept all received control characters", 1, NULL, 0, 0 },
+    {NULL, 0, NULL, NULL, 0,  NULL, 0, 0}
+};
+
+/* global vars */
+fsm lcp_fsm[NUM_PPP];			/* LCP fsm structure (global)*/
+lcp_options lcp_wantoptions[NUM_PPP];	/* Options that we want to request */
+lcp_options lcp_gotoptions[NUM_PPP];	/* Options that peer ack'd */
+lcp_options lcp_allowoptions[NUM_PPP];	/* Options we allow peer to request */
+lcp_options lcp_hisoptions[NUM_PPP];	/* Options that we ack'd */
+uint32_t xmit_accm[NUM_PPP][8];		/* extended transmit ACCM */
+
+static int lcp_echos_pending = 0;	/* Number of outstanding echo msgs */
+static int lcp_echo_number   = 0;	/* ID number of next echo frame */
+static int lcp_echo_timer_running = 0;  /* set if a timer is running */
+
+static u_char nak_buffer[PPP_MRU];	/* where we construct a nak packet */
+
+/*
+ * Callbacks for fsm code.  (CI = Configuration Information)
+ */
+static void lcp_resetci(fsm *);	/* Reset our CI */
+static int  lcp_cilen(fsm *);		/* Return length of our CI */
+static void lcp_addci(fsm *, u_char *, int *); /* Add our CI to pkt */
+static int  lcp_ackci(fsm *, u_char *, int); /* Peer ack'd our CI */
+static int  lcp_nakci(fsm *, u_char *, int); /* Peer nak'd our CI */
+static int  lcp_rejci(fsm *, u_char *, int); /* Peer rej'd our CI */
+static int  lcp_reqci(fsm *, u_char *, int *, int); /* Rcv peer CI */
+static void lcp_up(fsm *);		/* We're UP */
+static void lcp_down(fsm *);		/* We're DOWN */
+static void lcp_starting(fsm *);	/* We need lower layer up */
+static void lcp_finished(fsm *);	/* We need lower layer down */
+static int  lcp_extcode(fsm *, int, int, u_char *, int);
+static void lcp_rprotrej(fsm *, u_char *, int);
+
+/*
+ * routines to send LCP echos to peer
+ */
+
+static void lcp_echo_lowerup(int);
+static void lcp_echo_lowerdown(int);
+static void LcpEchoTimeout(void *);
+static void lcp_received_echo_reply(fsm *, int, u_char *, int);
+static void LcpSendEchoRequest(fsm *);
+static void LcpLinkFailure(fsm *);
+static void LcpEchoCheck(fsm *);
+
+static fsm_callbacks lcp_callbacks = {	/* LCP callback routines */
+    lcp_resetci,		/* Reset our Configuration Information */
+    lcp_cilen,			/* Length of our Configuration Information */
+    lcp_addci,			/* Add our Configuration Information */
+    lcp_ackci,			/* ACK our Configuration Information */
+    lcp_nakci,			/* NAK our Configuration Information */
+    lcp_rejci,			/* Reject our Configuration Information */
+    lcp_reqci,			/* Request peer's Configuration Information */
+    lcp_up,			/* Called when fsm reaches OPENED state */
+    lcp_down,			/* Called when fsm leaves OPENED state */
+    lcp_starting,		/* Called when we want the lower layer up */
+    lcp_finished,		/* Called when we want the lower layer down */
+    NULL,			/* Called when Protocol-Reject received */
+    NULL,			/* Retransmission is necessary */
+    lcp_extcode,		/* Called to handle LCP-specific codes */
+    "LCP"			/* String name of protocol */
+};
+
+/*
+ * Protocol entry points.
+ * Some of these are called directly.
+ */
+
+static void lcp_init(int);
+static void lcp_input(int, u_char *, int);
+static void lcp_protrej(int);
+static int  lcp_printpkt(u_char *, int,
+			      void (*)(void *, char *, ...), void *);
+
+struct protent lcp_protent = {
+    PPP_LCP,
+    lcp_init,
+    lcp_input,
+    lcp_protrej,
+    lcp_lowerup,
+    lcp_lowerdown,
+    lcp_open,
+    lcp_close,
+    lcp_printpkt,
+    NULL,
+    1,
+    "LCP",
+    NULL,
+    lcp_option_list,
+    NULL,
+    NULL,
+    NULL
+};
+
+int lcp_loopbackfail = DEFLOOPBACKFAIL;
+
+/*
+ * Length of each type of configuration option (in octets)
+ */
+#define CILEN_VOID	2
+#define CILEN_CHAR	3
+#define CILEN_SHORT	4	/* CILEN_VOID + 2 */
+#define CILEN_CHAP	5	/* CILEN_VOID + 2 + 1 */
+#define CILEN_LONG	6	/* CILEN_VOID + 4 */
+#define CILEN_LQR	8	/* CILEN_VOID + 2 + 4 */
+#define CILEN_CBCP	3
+
+#define CODENAME(x)	((x) == CONFACK ? "ACK" : \
+			 (x) == CONFNAK ? "NAK" : "REJ")
+
+
+/*
+ * setescape - add chars to the set we escape on transmission.
+ */
+static int
+setescape(
+    char **argv)
+{
+    int n, ret;
+    char *p, *endp;
+
+    p = *argv;
+    ret = 1;
+    while (*p) {
+	n = strtol(p, &endp, 16);
+	if (p == endp) {
+	    option_error("escape parameter contains invalid hex number '%s'",
+			 p);
+	    return 0;
+	}
+	p = endp;
+	if (n < 0 || n == 0x5E || n > 0xFF) {
+	    option_error("can't escape character 0x%x", n);
+	    ret = 0;
+	} else
+	    xmit_accm[0][n >> 5] |= 1 << (n & 0x1F);
+	while (*p == ',' || *p == ' ')
+	    ++p;
+    }
+    return ret;
+}
+
+/*
+ * lcp_init - Initialize LCP.
+ */
+static void
+lcp_init(
+    int unit)
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+    lcp_options *ao = &lcp_allowoptions[unit];
+
+    f->unit = unit;
+    f->protocol = PPP_LCP;
+    f->callbacks = &lcp_callbacks;
+
+    fsm_init(f);
+
+    wo->passive = 0;
+    wo->silent = 0;
+    wo->restart = 0;			/* Set to 1 in kernels or multi-line
+					   implementations */
+    wo->neg_mru = 1;
+    wo->mru = DEFMRU;
+    wo->neg_asyncmap = 1;
+    wo->asyncmap = 0;
+    wo->neg_chap = 0;			/* Set to 1 on server */
+    wo->neg_upap = 0;			/* Set to 1 on server */
+    wo->chap_mdtype = CHAP_DIGEST_MD5;
+    wo->neg_magicnumber = 1;
+    wo->neg_pcompression = 1;
+    wo->neg_accompression = 1;
+    wo->neg_lqr = 0;			/* no LQR implementation yet */
+    wo->neg_cbcp = 0;
+
+    ao->neg_mru = 1;
+    ao->mru = MAXMRU;
+    ao->neg_asyncmap = 1;
+    ao->asyncmap = 0;
+    ao->neg_chap = 1;
+    ao->chap_mdtype = CHAP_DIGEST_MD5;
+    ao->neg_upap = 1;
+    ao->neg_magicnumber = 1;
+    ao->neg_pcompression = 1;
+    ao->neg_accompression = 1;
+    ao->neg_lqr = 0;			/* no LQR implementation yet */
+#ifdef CBCP_SUPPORT
+    ao->neg_cbcp = 1;
+#else
+    ao->neg_cbcp = 0;
+#endif
+
+    memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));
+    xmit_accm[unit][3] = 0x60000000;
+}
+
+
+/*
+ * lcp_open - LCP is allowed to come up.
+ */
+void
+lcp_open(
+    int unit)
+{
+    fsm *f = &lcp_fsm[unit];
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    f->flags = 0;
+    if (wo->passive)
+	f->flags |= OPT_PASSIVE;
+    if (wo->silent)
+	f->flags |= OPT_SILENT;
+    fsm_open(f);
+}
+
+
+/*
+ * lcp_close - Take LCP down.
+ */
+void
+lcp_close(
+    int unit,
+    char *reason)
+{
+    fsm *f = &lcp_fsm[unit];
+
+    if (pppd_phase != PHASE_DEAD)
+	new_phase(PHASE_TERMINATE);
+    if (f->state == STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {
+	/*
+	 * This action is not strictly according to the FSM in RFC1548,
+	 * but it does mean that the program terminates if you do a
+	 * lcp_close() in passive/silent mode when a connection hasn't
+	 * been established.
+	 */
+	f->state = CLOSED;
+	lcp_finished(f);
+
+    } else
+	fsm_close(&lcp_fsm[unit], reason);
+}
+
+
+/*
+ * lcp_lowerup - The lower layer is up.
+ */
+void
+lcp_lowerup(
+    int unit)
+{
+    lcp_options *wo = &lcp_wantoptions[unit];
+
+    /*
+     * Don't use A/C or protocol compression on transmission,
+     * but accept A/C and protocol compressed packets
+     * if we are going to ask for A/C and protocol compression.
+     */
+    ppp_set_xaccm(unit, xmit_accm[unit]);
+    ppp_send_config(unit, PPP_MRU, 0xffffffff, 0, 0);
+    ppp_recv_config(unit, PPP_MRU, (lax_recv? 0: 0xffffffff),
+		    wo->neg_pcompression, wo->neg_accompression);
+    peer_mru[unit] = PPP_MRU;
+    lcp_allowoptions[unit].asyncmap = xmit_accm[unit][0];
+
+    fsm_lowerup(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_lowerdown - The lower layer is down.
+ */
+void
+lcp_lowerdown(
+    int unit)
+{
+    fsm_lowerdown(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_input - Input LCP packet.
+ */
+static void
+lcp_input(
+    int unit,
+    u_char *p,
+    int len)
+{
+    fsm *f = &lcp_fsm[unit];
+
+    fsm_input(f, p, len);
+}
+
+
+/*
+ * lcp_extcode - Handle a LCP-specific code.
+ */
+static int
+lcp_extcode(
+    fsm *f,
+    int code, int id,
+    u_char *inp,
+    int len)
+{
+    u_char *magp;
+
+    switch( code ){
+    case PROTREJ:
+	lcp_rprotrej(f, inp, len);
+	break;
+
+    case ECHOREQ:
+	if (f->state != OPENED)
+	    break;
+	magp = inp;
+	PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);
+	fsm_sdata(f, ECHOREP, id, inp, len);
+	break;
+
+    case ECHOREP:
+	lcp_received_echo_reply(f, id, inp, len);
+	break;
+
+    case DISCREQ:
+	break;
+
+    default:
+	return 0;
+    }
+    return 1;
+}
+
+
+/*
+ * lcp_rprotrej - Receive an Protocol-Reject.
+ *
+ * Figure out which protocol is rejected and inform it.
+ */
+static void
+lcp_rprotrej(
+    fsm *f,
+    u_char *inp,
+    int len)
+{
+    int i;
+    struct protent *protp;
+    u_short prot;
+
+    if (len < 2) {
+	LCPDEBUG(("lcp_rprotrej: Rcvd short Protocol-Reject packet!"));
+	return;
+    }
+
+    GETSHORT(prot, inp);
+
+    /*
+     * Protocol-Reject packets received in any state other than the LCP
+     * OPENED state SHOULD be silently discarded.
+     */
+    if( f->state != OPENED ){
+	LCPDEBUG(("Protocol-Reject discarded: LCP in state %d", f->state));
+	return;
+    }
+
+    /*
+     * Upcall the proper Protocol-Reject routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->protocol == prot && protp->enabled_flag) {
+	    (*protp->protrej)(f->unit);
+	    return;
+	}
+
+    warn("Protocol-Reject for unsupported protocol 0x%x", prot);
+}
+
+
+/*
+ * lcp_protrej - A Protocol-Reject was received.
+ */
+/*ARGSUSED*/
+static void
+lcp_protrej(
+    int unit)
+{
+    /*
+     * Can't reject LCP!
+     */
+    error("Received Protocol-Reject for LCP!");
+    fsm_protreject(&lcp_fsm[unit]);
+}
+
+
+/*
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.
+ */
+void
+lcp_sprotrej(
+    int unit,
+    u_char *p,
+    int len)
+{
+    /*
+     * Send back the protocol and the information field of the
+     * rejected packet.  We only get here if LCP is in the OPENED state.
+     */
+    p += 2;
+    len -= 2;
+
+    fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id,
+	      p, len);
+}
+
+
+/*
+ * lcp_resetci - Reset our CI.
+ */
+static void
+lcp_resetci(
+    fsm *f)
+{
+    lcp_wantoptions[f->unit].magicnumber = magic();
+    lcp_wantoptions[f->unit].numloops = 0;
+    lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];
+    peer_mru[f->unit] = PPP_MRU;
+    auth_reset(f->unit);
+}
+
+
+/*
+ * lcp_cilen - Return length of our CI.
+ */
+static int
+lcp_cilen(
+    fsm *f)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+
+#define LENCIVOID(neg)	((neg) ? CILEN_VOID : 0)
+#define LENCICHAP(neg)	((neg) ? CILEN_CHAP : 0)
+#define LENCISHORT(neg)	((neg) ? CILEN_SHORT : 0)
+#define LENCILONG(neg)	((neg) ? CILEN_LONG : 0)
+#define LENCILQR(neg)	((neg) ? CILEN_LQR: 0)
+#define LENCICBCP(neg)	((neg) ? CILEN_CBCP: 0)
+    /*
+     * NB: we only ask for one of CHAP and UPAP, even if we will
+     * accept either.
+     */
+    return (LENCISHORT(go->neg_mru && go->mru != DEFMRU) +
+	    LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) +
+	    LENCICHAP(go->neg_chap) +
+	    LENCISHORT(!go->neg_chap && go->neg_upap) +
+	    LENCILQR(go->neg_lqr) +
+	    LENCICBCP(go->neg_cbcp) +
+	    LENCILONG(go->neg_magicnumber) +
+	    LENCIVOID(go->neg_pcompression) +
+	    LENCIVOID(go->neg_accompression));
+}
+
+
+/*
+ * lcp_addci - Add our desired CIs to a packet.
+ */
+static void
+lcp_addci(
+    fsm *f,
+    u_char *ucp,
+    int *lenp)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char *start_ucp = ucp;
+
+#define ADDCIVOID(opt, neg) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_VOID, ucp); \
+    }
+#define ADDCISHORT(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_SHORT, ucp); \
+	PUTSHORT(val, ucp); \
+    }
+#define ADDCICHAP(opt, neg, val, digest) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_CHAP, ucp); \
+	PUTSHORT(val, ucp); \
+	PUTCHAR(digest, ucp); \
+    }
+#define ADDCILONG(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_LONG, ucp); \
+	PUTLONG(val, ucp); \
+    }
+#define ADDCILQR(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_LQR, ucp); \
+	PUTSHORT(PPP_LQR, ucp); \
+	PUTLONG(val, ucp); \
+    }
+#define ADDCICHAR(opt, neg, val) \
+    if (neg) { \
+	PUTCHAR(opt, ucp); \
+	PUTCHAR(CILEN_CHAR, ucp); \
+	PUTCHAR(val, ucp); \
+    }
+
+    ADDCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+    if (ucp - start_ucp != *lenp) {
+	/* this should never happen, because peer_mtu should be 1500 */
+	error("Bug in lcp_addci: wrong length");
+    }
+}
+
+
+/*
+ * lcp_ackci - Ack our CIs.
+ * This should not modify any state if the Ack is bad.
+ *
+ * Returns:
+ *	0 - Ack was bad.
+ *	1 - Ack was good.
+ */
+static int
+lcp_ackci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char cilen, citype, cichar;
+    u_short cishort;
+    uint32_t cilong;
+
+    /*
+     * CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define ACKCIVOID(opt, neg) \
+    if (neg) { \
+	if ((len -= CILEN_VOID) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_VOID || \
+	    citype != opt) \
+	    goto bad; \
+    }
+#define ACKCISHORT(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_SHORT) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_SHORT || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+    }
+#define ACKCICHAR(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_CHAR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_CHAR || \
+	    citype != opt) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (cichar != val) \
+	    goto bad; \
+    }
+#define ACKCICHAP(opt, neg, val, digest) \
+    if (neg) { \
+	if ((len -= CILEN_CHAP) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_CHAP || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != val) \
+	    goto bad; \
+	GETCHAR(cichar, p); \
+	if (cichar != digest) \
+	  goto bad; \
+    }
+#define ACKCILONG(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_LONG) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_LONG || \
+	    citype != opt) \
+	    goto bad; \
+	GETLONG(cilong, p); \
+	if (cilong != val) \
+	    goto bad; \
+    }
+#define ACKCILQR(opt, neg, val) \
+    if (neg) { \
+	if ((len -= CILEN_LQR) < 0) \
+	    goto bad; \
+	GETCHAR(citype, p); \
+	GETCHAR(cilen, p); \
+	if (cilen != CILEN_LQR || \
+	    citype != opt) \
+	    goto bad; \
+	GETSHORT(cishort, p); \
+	if (cishort != PPP_LQR) \
+	    goto bad; \
+	GETLONG(cilong, p); \
+	if (cilong != val) \
+	  goto bad; \
+    }
+
+    ACKCISHORT(CI_MRU, go->neg_mru && go->mru != DEFMRU, go->mru);
+    ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF,
+	      go->asyncmap);
+    ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);
+    ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);
+    ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);
+    ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);
+    ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);
+    ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);
+    ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    return (1);
+bad:
+    LCPDEBUG(("lcp_acki: received bad Ack!"));
+    return (0);
+}
+
+
+/*
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.
+ * This should not modify any state if the Nak is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Nak was bad.
+ *	1 - Nak was good.
+ */
+static int
+lcp_nakci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *wo = &lcp_wantoptions[f->unit];
+    u_char citype, cichar, *next;
+    u_short cishort;
+    uint32_t cilong;
+    lcp_options no;		/* options we've seen Naks for */
+    lcp_options try;		/* options to request next time */
+    int looped_back = 0;
+    int cilen;
+
+    BZERO(&no, sizeof(no));
+    try = *go;
+
+    /*
+     * Any Nak'd CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define NAKCIVOID(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCICHAP(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	p[0] == opt) { \
+	len -= CILEN_CHAP; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCICHAR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_CHAR && \
+	p[1] == CILEN_CHAR && \
+	p[0] == opt) { \
+	len -= CILEN_CHAR; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCISHORT(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	p[0] == opt) { \
+	len -= CILEN_SHORT; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILONG(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	p[0] == opt) { \
+	len -= CILEN_LONG; \
+	INCPTR(2, p); \
+	GETLONG(cilong, p); \
+	no.neg = 1; \
+	code \
+    }
+#define NAKCILQR(opt, neg, code) \
+    if (go->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	p[0] == opt) { \
+	len -= CILEN_LQR; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETLONG(cilong, p); \
+	no.neg = 1; \
+	code \
+    }
+
+    /*
+     * We don't care if they want to send us smaller packets than
+     * we want.  Therefore, accept any MRU less than what we asked for,
+     * but then ignore the new value when setting the MRU in the kernel.
+     * If they send us a bigger MRU than what we asked, accept it, up to
+     * the limit of the default MRU we'd get if we didn't negotiate.
+     */
+    if (go->neg_mru && go->mru != DEFMRU) {
+	NAKCISHORT(CI_MRU, neg_mru,
+		   if (cishort <= wo->mru || cishort <= DEFMRU)
+		       try.mru = cishort;
+		   );
+    }
+
+    /*
+     * Add any characters they want to our (receive-side) asyncmap.
+     */
+    if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF) {
+	NAKCILONG(CI_ASYNCMAP, neg_asyncmap,
+		  try.asyncmap = go->asyncmap | cilong;
+		  );
+    }
+
+    /*
+     * If they've nak'd our authentication-protocol, check whether
+     * they are proposing a different protocol, or a different
+     * hash algorithm for CHAP.
+     */
+    if ((go->neg_chap || go->neg_upap)
+	&& len >= CILEN_SHORT
+	&& p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {
+	cilen = p[1];
+	len -= cilen;
+	no.neg_chap = go->neg_chap;
+	no.neg_upap = go->neg_upap;
+	INCPTR(2, p);
+        GETSHORT(cishort, p);
+	if (cishort == PPP_PAP && cilen == CILEN_SHORT) {
+	    /*
+	     * If we were asking for CHAP, they obviously don't want to do it.
+	     * If we weren't asking for CHAP, then we were asking for PAP,
+	     * in which case this Nak is bad.
+	     */
+	    if (!go->neg_chap)
+		goto bad;
+	    try.neg_chap = 0;
+
+	} else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {
+	    GETCHAR(cichar, p);
+	    if (go->neg_chap) {
+		/*
+		 * We were asking for CHAP/MD5; they must want a different
+		 * algorithm.  If they can't do MD5, we can ask for M$-CHAP
+		 * if we support it, otherwise we'll have to stop
+		 * asking for CHAP.
+		 */
+		if (cichar != go->chap_mdtype) {
+#ifdef CHAPMS
+		    if (cichar == CHAP_MICROSOFT)
+			go->chap_mdtype = CHAP_MICROSOFT;
+		    else
+#endif /* CHAPMS */
+			try.neg_chap = 0;
+		}
+	    } else {
+		/*
+		 * Stop asking for PAP if we were asking for it.
+		 */
+		try.neg_upap = 0;
+	    }
+
+	} else {
+	    /*
+	     * We don't recognize what they're suggesting.
+	     * Stop asking for what we were asking for.
+	     */
+	    if (go->neg_chap)
+		try.neg_chap = 0;
+	    else
+		try.neg_upap = 0;
+	    p += cilen - CILEN_SHORT;
+	}
+    }
+
+    /*
+     * If they can't cope with our link quality protocol, we'll have
+     * to stop asking for LQR.  We haven't got any other protocol.
+     * If they Nak the reporting period, take their value XXX ?
+     */
+    NAKCILQR(CI_QUALITY, neg_lqr,
+	     if (cishort != PPP_LQR)
+		 try.neg_lqr = 0;
+	     else
+		 try.lqr_period = cilong;
+	     );
+
+    /*
+     * Only implementing CBCP...not the rest of the callback options
+     */
+    NAKCICHAR(CI_CALLBACK, neg_cbcp,
+              try.neg_cbcp = 0;
+              );
+
+    /*
+     * Check for a looped-back line.
+     */
+    NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,
+	      try.magicnumber = magic();
+	      looped_back = 1;
+	      );
+
+    /*
+     * Peer shouldn't send Nak for protocol compression or
+     * address/control compression requests; they should send
+     * a Reject instead.  If they send a Nak, treat it as a Reject.
+     */
+    NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,
+	      try.neg_pcompression = 0;
+	      );
+    NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,
+	      try.neg_accompression = 0;
+	      );
+
+    /*
+     * There may be remaining CIs, if the peer is requesting negotiation
+     * on an option that we didn't include in our request packet.
+     * If we see an option that we requested, or one we've already seen
+     * in this packet, then this packet is bad.
+     * If we wanted to respond by starting to negotiate on the requested
+     * option(s), we could, but we don't, because except for the
+     * authentication type and quality protocol, if we are not negotiating
+     * an option, it is because we were told not to.
+     * For the authentication type, the Nak from the peer means
+     * `let me authenticate myself with you' which is a bit pointless.
+     * For the quality protocol, the Nak means `ask me to send you quality
+     * reports', but if we didn't ask for them, we don't want them.
+     * An option we don't recognize represents the peer asking to
+     * negotiate some option we don't support, so ignore it.
+     */
+    while (len > CILEN_VOID) {
+	GETCHAR(citype, p);
+	GETCHAR(cilen, p);
+	if (cilen < CILEN_VOID || (len -= cilen) < 0)
+	    goto bad;
+	next = p + cilen - 2;
+
+	switch (citype) {
+	case CI_MRU:
+	    if ((go->neg_mru && go->mru != DEFMRU)
+		|| no.neg_mru || cilen != CILEN_SHORT)
+		goto bad;
+	    GETSHORT(cishort, p);
+	    if (cishort < DEFMRU)
+		try.mru = cishort;
+	    break;
+	case CI_ASYNCMAP:
+	    if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFF)
+		|| no.neg_asyncmap || cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_AUTHTYPE:
+	    if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap)
+		goto bad;
+	    break;
+	case CI_MAGICNUMBER:
+	    if (go->neg_magicnumber || no.neg_magicnumber ||
+		cilen != CILEN_LONG)
+		goto bad;
+	    break;
+	case CI_PCOMPRESSION:
+	    if (go->neg_pcompression || no.neg_pcompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_ACCOMPRESSION:
+	    if (go->neg_accompression || no.neg_accompression
+		|| cilen != CILEN_VOID)
+		goto bad;
+	    break;
+	case CI_QUALITY:
+	    if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR)
+		goto bad;
+	    break;
+	}
+	p = next;
+    }
+
+    /*
+     * OK, the Nak is good.  Now we can update state.
+     * If there are any options left we ignore them.
+     */
+    if (f->state != OPENED) {
+	if (looped_back) {
+	    if (++try.numloops >= lcp_loopbackfail) {
+		notice("Serial line is looped back.");
+		lcp_close(f->unit, "Loopback detected");
+		pppd_status = EXIT_LOOPBACK;
+	    }
+	} else
+	    try.numloops = 0;
+	*go = try;
+    }
+
+    return 1;
+
+bad:
+    LCPDEBUG(("lcp_nakci: received bad Nak!"));
+    return 0;
+}
+
+
+/*
+ * lcp_rejci - Peer has Rejected some of our CIs.
+ * This should not modify any state if the Reject is bad
+ * or if LCP is in the OPENED state.
+ *
+ * Returns:
+ *	0 - Reject was bad.
+ *	1 - Reject was good.
+ */
+static int
+lcp_rejci(
+    fsm *f,
+    u_char *p,
+    int len)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    u_char cichar;
+    u_short cishort;
+    uint32_t cilong;
+    lcp_options try;		/* options to request next time */
+
+    try = *go;
+
+    /*
+     * Any Rejected CIs must be in exactly the same order that we sent.
+     * Check packet length and CI length at each step.
+     * If we find any deviations, then this packet is bad.
+     */
+#define REJCIVOID(opt, neg) \
+    if (go->neg && \
+	len >= CILEN_VOID && \
+	p[1] == CILEN_VOID && \
+	p[0] == opt) { \
+	len -= CILEN_VOID; \
+	INCPTR(CILEN_VOID, p); \
+	try.neg = 0; \
+    }
+#define REJCISHORT(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_SHORT && \
+	p[1] == CILEN_SHORT && \
+	p[0] == opt) { \
+	len -= CILEN_SHORT; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	/* Check rejected value. */ \
+	if (cishort != val) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+#define REJCICHAP(opt, neg, val, digest) \
+    if (go->neg && \
+	len >= CILEN_CHAP && \
+	p[1] == CILEN_CHAP && \
+	p[0] == opt) { \
+	len -= CILEN_CHAP; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cishort != val || cichar != digest) \
+	    goto bad; \
+	try.neg = 0; \
+	try.neg_upap = 0; \
+    }
+#define REJCILONG(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_LONG && \
+	p[1] == CILEN_LONG && \
+	p[0] == opt) { \
+	len -= CILEN_LONG; \
+	INCPTR(2, p); \
+	GETLONG(cilong, p); \
+	/* Check rejected value. */ \
+	if (cilong != val) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+#define REJCILQR(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_LQR && \
+	p[1] == CILEN_LQR && \
+	p[0] == opt) { \
+	len -= CILEN_LQR; \
+	INCPTR(2, p); \
+	GETSHORT(cishort, p); \
+	GETLONG(cilong, p); \
+	/* Check rejected value. */ \
+	if (cishort != PPP_LQR || cilong != val) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+#define REJCICBCP(opt, neg, val) \
+    if (go->neg && \
+	len >= CILEN_CBCP && \
+	p[1] == CILEN_CBCP && \
+	p[0] == opt) { \
+	len -= CILEN_CBCP; \
+	INCPTR(2, p); \
+	GETCHAR(cichar, p); \
+	/* Check rejected value. */ \
+	if (cichar != val) \
+	    goto bad; \
+	try.neg = 0; \
+    }
+
+    REJCISHORT(CI_MRU, neg_mru, go->mru);
+    REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);
+    REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);
+    if (!go->neg_chap) {
+	REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);
+    }
+    REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);
+    REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);
+    REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);
+    REJCIVOID(CI_PCOMPRESSION, neg_pcompression);
+    REJCIVOID(CI_ACCOMPRESSION, neg_accompression);
+
+    /*
+     * If there are any remaining CIs, then this packet is bad.
+     */
+    if (len != 0)
+	goto bad;
+    /*
+     * Now we can update state.
+     */
+    if (f->state != OPENED)
+	*go = try;
+    return 1;
+
+bad:
+    LCPDEBUG(("lcp_rejci: received bad Reject!"));
+    return 0;
+}
+
+
+/*
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.
+ *
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.
+ */
+static int
+lcp_reqci(
+    fsm *f,
+    u_char *inp,		/* Requested CIs */
+    int *lenp,			/* Length of requested CIs */
+    int reject_if_disagree)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+    u_char *cip, *next;		/* Pointer to current and next CIs */
+    int cilen, citype, cichar;	/* Parsed len, type, char value */
+    u_short cishort;		/* Parsed short value */
+    uint32_t cilong;		/* Parse long value */
+    int rc = CONFACK;		/* Final packet return code */
+    int orc;			/* Individual option return code */
+    u_char *p;			/* Pointer to next char to parse */
+    u_char *rejp;		/* Pointer to next char in reject frame */
+    u_char *nakp;		/* Pointer to next char in Nak frame */
+    int l = *lenp;		/* Length left */
+
+    /*
+     * Reset all his options.
+     */
+    BZERO(ho, sizeof(*ho));
+
+    /*
+     * Process all his options.
+     */
+    next = inp;
+    nakp = nak_buffer;
+    rejp = inp;
+    while (l) {
+	orc = CONFACK;			/* Assume success */
+	cip = p = next;			/* Remember begining of CI */
+	if (l < 2 ||			/* Not enough data for CI header or */
+	    p[1] < 2 ||			/*  CI length too small or */
+	    p[1] > l) {			/*  CI length too big? */
+	    LCPDEBUG(("lcp_reqci: bad CI length!"));
+	    orc = CONFREJ;		/* Reject bad CI */
+	    cilen = l;			/* Reject till end of packet */
+	    l = 0;			/* Don't loop again */
+	    citype = 0;
+	    goto endswitch;
+	}
+	GETCHAR(citype, p);		/* Parse CI type */
+	GETCHAR(cilen, p);		/* Parse CI length */
+	l -= cilen;			/* Adjust remaining length */
+	next += cilen;			/* Step to next CI */
+
+	switch (citype) {		/* Check CI type */
+	case CI_MRU:
+	    if (!ao->neg_mru ||		/* Allow option? */
+		cilen != CILEN_SHORT) {	/* Check CI length */
+		orc = CONFREJ;		/* Reject CI */
+		break;
+	    }
+	    GETSHORT(cishort, p);	/* Parse MRU */
+
+	    /*
+	     * He must be able to receive at least our minimum.
+	     * No need to check a maximum.  If he sends a large number,
+	     * we'll just ignore it.
+	     */
+	    if (cishort < MINMRU) {
+		orc = CONFNAK;		/* Nak CI */
+		PUTCHAR(CI_MRU, nakp);
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(MINMRU, nakp);	/* Give him a hint */
+		break;
+	    }
+	    ho->neg_mru = 1;		/* Remember he sent MRU */
+	    ho->mru = cishort;		/* And remember value */
+	    break;
+
+	case CI_ASYNCMAP:
+	    if (!ao->neg_asyncmap ||
+		cilen != CILEN_LONG) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETLONG(cilong, p);
+
+	    /*
+	     * Asyncmap must have set at least the bits
+	     * which are set in lcp_allowoptions[unit].asyncmap.
+	     */
+	    if ((ao->asyncmap & ~cilong) != 0) {
+		orc = CONFNAK;
+		PUTCHAR(CI_ASYNCMAP, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(ao->asyncmap | cilong, nakp);
+		break;
+	    }
+	    ho->neg_asyncmap = 1;
+	    ho->asyncmap = cilong;
+	    break;
+
+	case CI_AUTHTYPE:
+	    if (cilen < CILEN_SHORT ||
+		!(ao->neg_upap || ao->neg_chap)) {
+		/*
+		 * Reject the option if we're not willing to authenticate.
+		 */
+		orc = CONFREJ;
+		break;
+	    }
+	    GETSHORT(cishort, p);
+
+	    /*
+	     * Authtype must be PAP or CHAP.
+	     *
+	     * Note: if both ao->neg_upap and ao->neg_chap are set,
+	     * and the peer sends a Configure-Request with two
+	     * authenticate-protocol requests, one for CHAP and one
+	     * for UPAP, then we will reject the second request.
+	     * Whether we end up doing CHAP or UPAP depends then on
+	     * the ordering of the CIs in the peer's Configure-Request.
+	     */
+
+	    if (cishort == PPP_PAP) {
+		if (ho->neg_chap ||	/* we've already accepted CHAP */
+		    cilen != CILEN_SHORT) {
+		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE PAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->neg_upap) {	/* we don't want to do PAP */
+		    orc = CONFNAK;	/* NAK it and suggest CHAP */
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_CHAP, nakp);
+		    PUTSHORT(PPP_CHAP, nakp);
+		    PUTCHAR(ao->chap_mdtype, nakp);
+		    /* XXX if we can do CHAP_MICROSOFT as well, we should
+		       probably put in another option saying so */
+		    break;
+		}
+		ho->neg_upap = 1;
+		break;
+	    }
+	    if (cishort == PPP_CHAP) {
+		if (ho->neg_upap ||	/* we've already accepted PAP */
+		    cilen != CILEN_CHAP) {
+		    LCPDEBUG(("lcp_reqci: rcvd AUTHTYPE CHAP, rejecting..."));
+		    orc = CONFREJ;
+		    break;
+		}
+		if (!ao->neg_chap) {	/* we don't want to do CHAP */
+		    orc = CONFNAK;	/* NAK it and suggest PAP */
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_SHORT, nakp);
+		    PUTSHORT(PPP_PAP, nakp);
+		    break;
+		}
+		GETCHAR(cichar, p);	/* get digest type*/
+		if (cichar != CHAP_DIGEST_MD5
+#ifdef CHAPMS
+		    && cichar != CHAP_MICROSOFT
+#endif
+		    ) {
+		    orc = CONFNAK;
+		    PUTCHAR(CI_AUTHTYPE, nakp);
+		    PUTCHAR(CILEN_CHAP, nakp);
+		    PUTSHORT(PPP_CHAP, nakp);
+		    PUTCHAR(ao->chap_mdtype, nakp);
+		    break;
+		}
+		ho->chap_mdtype = cichar; /* save md type */
+		ho->neg_chap = 1;
+		break;
+	    }
+
+	    /*
+	     * We don't recognize the protocol they're asking for.
+	     * Nak it with something we're willing to do.
+	     * (At this point we know ao->neg_upap || ao->neg_chap.)
+	     */
+	    orc = CONFNAK;
+	    PUTCHAR(CI_AUTHTYPE, nakp);
+	    if (ao->neg_chap) {
+		PUTCHAR(CILEN_CHAP, nakp);
+		PUTSHORT(PPP_CHAP, nakp);
+		PUTCHAR(ao->chap_mdtype, nakp);
+	    } else {
+		PUTCHAR(CILEN_SHORT, nakp);
+		PUTSHORT(PPP_PAP, nakp);
+	    }
+	    break;
+
+	case CI_QUALITY:
+	    if (!ao->neg_lqr ||
+		cilen != CILEN_LQR) {
+		orc = CONFREJ;
+		break;
+	    }
+
+	    GETSHORT(cishort, p);
+	    GETLONG(cilong, p);
+
+	    /*
+	     * Check the protocol and the reporting period.
+	     * XXX When should we Nak this, and what with?
+	     */
+	    if (cishort != PPP_LQR) {
+		orc = CONFNAK;
+		PUTCHAR(CI_QUALITY, nakp);
+		PUTCHAR(CILEN_LQR, nakp);
+		PUTSHORT(PPP_LQR, nakp);
+		PUTLONG(ao->lqr_period, nakp);
+		break;
+	    }
+	    break;
+
+	case CI_MAGICNUMBER:
+	    if (!(ao->neg_magicnumber || go->neg_magicnumber) ||
+		cilen != CILEN_LONG) {
+		orc = CONFREJ;
+		break;
+	    }
+	    GETLONG(cilong, p);
+
+	    /*
+	     * He must have a different magic number.
+	     */
+	    if (go->neg_magicnumber &&
+		cilong == go->magicnumber) {
+		cilong = magic();	/* Don't put magic() inside macro! */
+		orc = CONFNAK;
+		PUTCHAR(CI_MAGICNUMBER, nakp);
+		PUTCHAR(CILEN_LONG, nakp);
+		PUTLONG(cilong, nakp);
+		break;
+	    }
+	    ho->neg_magicnumber = 1;
+	    ho->magicnumber = cilong;
+	    break;
+
+
+	case CI_PCOMPRESSION:
+	    if (!ao->neg_pcompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_pcompression = 1;
+	    break;
+
+	case CI_ACCOMPRESSION:
+	    if (!ao->neg_accompression ||
+		cilen != CILEN_VOID) {
+		orc = CONFREJ;
+		break;
+	    }
+	    ho->neg_accompression = 1;
+	    break;
+
+	default:
+	    LCPDEBUG(("lcp_reqci: rcvd unknown option %d", citype));
+	    orc = CONFREJ;
+	    break;
+	}
+
+endswitch:
+	if (orc == CONFACK &&		/* Good CI */
+	    rc != CONFACK)		/*  but prior CI wasnt? */
+	    continue;			/* Don't send this one */
+
+	if (orc == CONFNAK) {		/* Nak this CI? */
+	    if (reject_if_disagree	/* Getting fed up with sending NAKs? */
+		&& citype != CI_MAGICNUMBER) {
+		orc = CONFREJ;		/* Get tough if so */
+	    } else {
+		if (rc == CONFREJ)	/* Rejecting prior CI? */
+		    continue;		/* Don't send this one */
+		rc = CONFNAK;
+	    }
+	}
+	if (orc == CONFREJ) {		/* Reject this CI */
+	    rc = CONFREJ;
+	    if (cip != rejp)		/* Need to move rejected CI? */
+		BCOPY(cip, rejp, cilen); /* Move it */
+	    INCPTR(cilen, rejp);	/* Update output pointer */
+	}
+    }
+
+    /*
+     * If we wanted to send additional NAKs (for unsent CIs), the
+     * code would go here.  The extra NAKs would go at *nakp.
+     * At present there are no cases where we want to ask the
+     * peer to negotiate an option.
+     */
+
+    switch (rc) {
+    case CONFACK:
+	*lenp = next - inp;
+	break;
+    case CONFNAK:
+	/*
+	 * Copy the Nak'd options from the nak_buffer to the caller's buffer.
+	 */
+	*lenp = nakp - nak_buffer;
+	BCOPY(nak_buffer, inp, *lenp);
+	break;
+    case CONFREJ:
+	*lenp = rejp - inp;
+	break;
+    }
+
+    LCPDEBUG(("lcp_reqci: returning CONF%s.", CODENAME(rc)));
+    return (rc);			/* Return final code */
+}
+
+
+/*
+ * lcp_up - LCP has come UP.
+ */
+static void
+lcp_up(
+    fsm *f)
+{
+    lcp_options *wo = &lcp_wantoptions[f->unit];
+    lcp_options *ho = &lcp_hisoptions[f->unit];
+    lcp_options *go = &lcp_gotoptions[f->unit];
+    lcp_options *ao = &lcp_allowoptions[f->unit];
+
+    if (!go->neg_magicnumber)
+	go->magicnumber = 0;
+    if (!ho->neg_magicnumber)
+	ho->magicnumber = 0;
+
+    /*
+     * Set our MTU to the smaller of the MTU we wanted and
+     * the MRU our peer wanted.  If we negotiated an MRU,
+     * set our MRU to the larger of value we wanted and
+     * the value we got in the negotiation.
+     */
+    ppp_send_config(f->unit, MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),
+		    (ho->neg_asyncmap? ho->asyncmap: 0xffffffff),
+		    ho->neg_pcompression, ho->neg_accompression);
+    ppp_recv_config(f->unit, (go->neg_mru? MAX(wo->mru, go->mru): PPP_MRU),
+		    (lax_recv? 0: go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+
+    if (ho->neg_mru)
+	peer_mru[f->unit] = ho->mru;
+
+    lcp_echo_lowerup(f->unit);  /* Enable echo messages */
+
+    link_established(f->unit);
+}
+
+
+/*
+ * lcp_down - LCP has gone DOWN.
+ *
+ * Alert other protocols.
+ */
+static void
+lcp_down(
+    fsm *f)
+{
+    lcp_options *go = &lcp_gotoptions[f->unit];
+
+    lcp_echo_lowerdown(f->unit);
+
+    link_down(f->unit);
+
+    ppp_send_config(f->unit, PPP_MRU, 0xffffffff, 0, 0);
+    ppp_recv_config(f->unit, PPP_MRU,
+		    (go->neg_asyncmap? go->asyncmap: 0xffffffff),
+		    go->neg_pcompression, go->neg_accompression);
+    peer_mru[f->unit] = PPP_MRU;
+}
+
+
+/*
+ * lcp_starting - LCP needs the lower layer up.
+ */
+static void
+lcp_starting(
+    fsm *f)
+{
+    link_required(f->unit);
+}
+
+
+/*
+ * lcp_finished - LCP has finished with the lower layer.
+ */
+static void
+lcp_finished(
+    fsm *f)
+{
+    link_terminated(f->unit);
+}
+
+
+/*
+ * lcp_printpkt - print the contents of an LCP packet.
+ */
+static char *lcp_codenames[] = {
+    "ConfReq", "ConfAck", "ConfNak", "ConfRej",
+    "TermReq", "TermAck", "CodeRej", "ProtRej",
+    "EchoReq", "EchoRep", "DiscReq"
+};
+
+static int
+lcp_printpkt(
+    u_char *p,
+    int plen,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int code, id, len, olen;
+    u_char *pstart, *optend;
+    u_short cishort;
+    uint32_t cilong;
+
+    if (plen < HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *))
+	printer(arg, " %s", lcp_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= HEADERLEN;
+    switch (code) {
+    case CONFREQ:
+    case CONFACK:
+    case CONFNAK:
+    case CONFREJ:
+	/* print option list */
+	while (len >= 2) {
+	    GETCHAR(code, p);
+	    GETCHAR(olen, p);
+	    p -= 2;
+	    if (olen < 2 || olen > len) {
+		break;
+	    }
+	    printer(arg, " <");
+	    len -= olen;
+	    optend = p + olen;
+	    switch (code) {
+	    case CI_MRU:
+		if (olen == CILEN_SHORT) {
+		    p += 2;
+		    GETSHORT(cishort, p);
+		    printer(arg, "mru %d", cishort);
+		}
+		break;
+	    case CI_ASYNCMAP:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "asyncmap 0x%x", cilong);
+		}
+		break;
+	    case CI_AUTHTYPE:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "auth ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_PAP:
+			printer(arg, "pap");
+			break;
+		    case PPP_CHAP:
+			printer(arg, "chap");
+			if (p < optend) {
+			    switch (*p) {
+			    case CHAP_DIGEST_MD5:
+				printer(arg, " MD5");
+				++p;
+				break;
+#ifdef CHAPMS
+			    case CHAP_MICROSOFT:
+				printer(arg, " m$oft");
+				++p;
+				break;
+#endif
+			    }
+			}
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_QUALITY:
+		if (olen >= CILEN_SHORT) {
+		    p += 2;
+		    printer(arg, "quality ");
+		    GETSHORT(cishort, p);
+		    switch (cishort) {
+		    case PPP_LQR:
+			printer(arg, "lqr");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_CALLBACK:
+		if (olen >= CILEN_CHAR) {
+		    p += 2;
+		    printer(arg, "callback ");
+		    GETCHAR(cishort, p);
+		    switch (cishort) {
+		    case CBCP_OPT:
+			printer(arg, "CBCP");
+			break;
+		    default:
+			printer(arg, "0x%x", cishort);
+		    }
+		}
+		break;
+	    case CI_MAGICNUMBER:
+		if (olen == CILEN_LONG) {
+		    p += 2;
+		    GETLONG(cilong, p);
+		    printer(arg, "magic 0x%x", cilong);
+		}
+		break;
+	    case CI_PCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "pcomp");
+		}
+		break;
+	    case CI_ACCOMPRESSION:
+		if (olen == CILEN_VOID) {
+		    p += 2;
+		    printer(arg, "accomp");
+		}
+		break;
+	    }
+	    while (p < optend) {
+		GETCHAR(code, p);
+		printer(arg, " %.2x", code);
+	    }
+	    printer(arg, ">");
+	}
+	break;
+
+    case TERMACK:
+    case TERMREQ:
+	if (len > 0 && *p >= ' ' && *p < 0x7f) {
+	    printer(arg, " ");
+	    print_string(p, len, printer, arg);
+	    p += len;
+	    len = 0;
+	}
+	break;
+
+    case ECHOREQ:
+    case ECHOREP:
+    case DISCREQ:
+	if (len >= 4) {
+	    GETLONG(cilong, p);
+	    printer(arg, " magic=0x%x", cilong);
+	    p += 4;
+	    len -= 4;
+	}
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
+
+/*
+ * Time to shut down the link because there is nothing out there.
+ */
+
+static
+void LcpLinkFailure (
+    fsm *f)
+{
+    if (f->state == OPENED) {
+	info("No response to %d echo-requests", lcp_echos_pending);
+        notice("Serial link appears to be disconnected.");
+        lcp_close(f->unit, "Peer not responding");
+	pppd_status = EXIT_PEER_DEAD;
+    }
+}
+
+/*
+ * Timer expired for the LCP echo requests from this process.
+ */
+
+static void
+LcpEchoCheck (
+    fsm *f)
+{
+    LcpSendEchoRequest (f);
+    if (f->state != OPENED)
+	return;
+
+    /*
+     * Start the timer for the next interval.
+     */
+    if (lcp_echo_timer_running)
+	warn("assertion lcp_echo_timer_running==0 failed");
+    TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);
+    lcp_echo_timer_running = 1;
+}
+
+/*
+ * LcpEchoTimeout - Timer expired on the LCP echo
+ */
+
+static void
+LcpEchoTimeout (
+    void *arg)
+{
+    if (lcp_echo_timer_running != 0) {
+        lcp_echo_timer_running = 0;
+        LcpEchoCheck ((fsm *) arg);
+    }
+}
+
+/*
+ * LcpEchoReply - LCP has received a reply to the echo
+ */
+
+static void
+lcp_received_echo_reply (
+    fsm *f,
+    int id,
+    u_char *inp,
+    int len)
+{
+    uint32_t magic;
+
+    /* Check the magic number - don't count replies from ourselves. */
+    if (len < 4) {
+	dbglog("lcp: received short Echo-Reply, length %d", len);
+	return;
+    }
+    GETLONG(magic, inp);
+    if (lcp_gotoptions[f->unit].neg_magicnumber
+	&& magic == lcp_gotoptions[f->unit].magicnumber) {
+	warn("appear to have received our own echo-reply!");
+	return;
+    }
+
+    /* Reset the number of outstanding echo frames */
+    lcp_echos_pending = 0;
+}
+
+/*
+ * LcpSendEchoRequest - Send an echo request frame to the peer
+ */
+
+static void
+LcpSendEchoRequest (
+    fsm *f)
+{
+    uint32_t lcp_magic;
+    u_char pkt[4], *pktp;
+
+    /*
+     * Detect the failure of the peer at this point.
+     */
+    if (lcp_echo_fails != 0) {
+        if (lcp_echos_pending >= lcp_echo_fails) {
+            LcpLinkFailure(f);
+	    lcp_echos_pending = 0;
+	}
+    }
+
+    /*
+     * Make and send the echo request frame.
+     */
+    if (f->state == OPENED) {
+        lcp_magic = lcp_gotoptions[f->unit].magicnumber;
+	pktp = pkt;
+	PUTLONG(lcp_magic, pktp);
+        fsm_sdata(f, ECHOREQ, lcp_echo_number++ & 0xFF, pkt, pktp - pkt);
+	++lcp_echos_pending;
+    }
+}
+
+/*
+ * lcp_echo_lowerup - Start the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerup (
+    int unit)
+{
+    fsm *f = &lcp_fsm[unit];
+
+    /* Clear the parameters for generating echo frames */
+    lcp_echos_pending      = 0;
+    lcp_echo_number        = 0;
+    lcp_echo_timer_running = 0;
+
+    /* If a timeout interval is specified then start the timer */
+    if (lcp_echo_interval != 0)
+        LcpEchoCheck (f);
+}
+
+/*
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame
+ */
+
+static void
+lcp_echo_lowerdown (
+    int unit)
+{
+    fsm *f = &lcp_fsm[unit];
+
+    if (lcp_echo_timer_running != 0) {
+        UNTIMEOUT (LcpEchoTimeout, f);
+        lcp_echo_timer_running = 0;
+    }
+}
diff --git a/rtemsbsd/pppd/lcp.h b/rtemsbsd/pppd/lcp.h
new file mode 100644
index 0000000..6231d27
--- /dev/null
+++ b/rtemsbsd/pppd/lcp.h
@@ -0,0 +1,88 @@
+/*
+ * lcp.h - Link Control Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+/*
+ * Options.
+ */
+#define CI_MRU		1	/* Maximum Receive Unit */
+#define CI_ASYNCMAP	2	/* Async Control Character Map */
+#define CI_AUTHTYPE	3	/* Authentication Type */
+#define CI_QUALITY	4	/* Quality Protocol */
+#define CI_MAGICNUMBER	5	/* Magic Number */
+#define CI_PCOMPRESSION	7	/* Protocol Field Compression */
+#define CI_ACCOMPRESSION 8	/* Address/Control Field Compression */
+#define CI_CALLBACK	13	/* callback */
+
+/*
+ * LCP-specific packet types.
+ */
+#define PROTREJ		8	/* Protocol Reject */
+#define ECHOREQ		9	/* Echo Request */
+#define ECHOREP		10	/* Echo Reply */
+#define DISCREQ		11	/* Discard Request */
+#define CBCP_OPT	6	/* Use callback control protocol */
+
+/*
+ * The state of options is described by an lcp_options structure.
+ */
+typedef struct lcp_options {
+    bool passive;		/* Don't die if we don't get a response */
+    bool silent;		/* Wait for the other end to start first */
+    bool restart;		/* Restart vs. exit after close */
+    bool neg_mru;		/* Negotiate the MRU? */
+    bool neg_asyncmap;		/* Negotiate the async map? */
+    bool neg_upap;		/* Ask for UPAP authentication? */
+    bool neg_chap;		/* Ask for CHAP authentication? */
+    bool neg_magicnumber;	/* Ask for magic number? */
+    bool neg_pcompression;	/* HDLC Protocol Field Compression? */
+    bool neg_accompression;	/* HDLC Address/Control Field Compression? */
+    bool neg_lqr;		/* Negotiate use of Link Quality Reports */
+    bool neg_cbcp;		/* Negotiate use of CBCP */
+    int  mru;			/* Value of MRU */
+    u_char chap_mdtype;		/* which MD type (hashing algorithm) */
+    uint32_t asyncmap;		/* Value of async map */
+    uint32_t magicnumber;
+    int numloops;		/* Number of loops during magic number neg. */
+    uint32_t lqr_period;	/* Reporting period for LQR 1/100ths second */
+} lcp_options;
+
+extern fsm lcp_fsm[];
+extern lcp_options lcp_wantoptions[];
+extern lcp_options lcp_gotoptions[];
+extern lcp_options lcp_allowoptions[];
+extern lcp_options lcp_hisoptions[];
+extern uint32_t xmit_accm[][8];
+
+#define DEFMRU	1500		/* Try for this */
+#define MINMRU	128		/* No MRUs below this */
+#define MAXMRU	16384		/* Normally limit MRU to this */
+
+void lcp_open(int);
+void lcp_close(int, char *);
+void lcp_lowerup(int);
+void lcp_lowerdown(int);
+void lcp_sprotrej(int, u_char *, int);	/* send protocol reject */
+
+extern struct protent lcp_protent;
+
+/* Default number of times we receive our magic number from the peer
+   before deciding the link is looped-back. */
+#define DEFLOOPBACKFAIL	10
diff --git a/rtemsbsd/pppd/magic.c b/rtemsbsd/pppd/magic.c
new file mode 100644
index 0000000..3d297e5
--- /dev/null
+++ b/rtemsbsd/pppd/magic.c
@@ -0,0 +1,58 @@
+/*
+ * magic.c - PPP Magic Number routines.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include "pppd.h"
+#include "magic.h"
+
+static const char rcsid[] = RCSID;
+
+/*
+ * magic_init - Initialize the magic number generator.
+ *
+ * Attempts to compute a random number seed which will not repeat.
+ * The current method uses the current hostid, current process ID
+ * and current time, currently.
+ */
+void
+magic_init(void)
+{
+    long seed;
+    struct timeval t;
+
+    gettimeofday(&t, NULL);
+    seed = get_host_seed() ^ t.tv_sec ^ t.tv_usec ^ getpid();
+    srand48(seed);
+}
+
+/*
+ * magic - Returns the next magic number.
+ */
+uint32_t
+magic(void)
+{
+    return (uint32_t) mrand48();
+}
diff --git a/rtemsbsd/pppd/magic.h b/rtemsbsd/pppd/magic.h
new file mode 100644
index 0000000..572a550
--- /dev/null
+++ b/rtemsbsd/pppd/magic.h
@@ -0,0 +1,23 @@
+/*
+ * magic.h - PPP Magic Number definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+void magic_init(void);	/* Initialize the magic number generator */
+uint32_t magic(void);	/* Returns the next magic number */
diff --git a/rtemsbsd/pppd/options.c b/rtemsbsd/pppd/options.c
new file mode 100644
index 0000000..8a39266
--- /dev/null
+++ b/rtemsbsd/pppd/options.c
@@ -0,0 +1,1519 @@
+/*
+ * options.c - handles option processing for PPP.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <string.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef PLUGIN
+#include <dlfcn.h>
+#endif
+#ifdef PPP_FILTER
+#include <pcap.h>
+#include <pcap-int.h>	/* XXX: To get struct pcap */
+#endif
+
+#include "pppd.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+
+#include <net/ppp_comp.h>
+
+static const char rcsid[] = RCSID;
+
+/*
+ * Option variables and default values.
+ */
+#ifdef PPP_FILTER
+int	dflag = 0;		/* Tell libpcap we want debugging */
+#endif
+int	debug = 0;		/* Debug flag */
+int	kdebugflag = 0;		/* Tell kernel to print debug messages */
+int	default_device = 1;	/* Using /dev/tty or equivalent */
+char	devnam[MAXPATHLEN];	/* Device name */
+int	crtscts = 0;		/* Use hardware flow control */
+bool	modem = 1;		/* Use modem control lines */
+int	inspeed = 0;		/* Input/Output speed requested */
+uint32_t netmask = 0;		/* IP netmask to set on interface */
+bool	lockflag = 0;		/* Create lock file to lock the serial dev */
+bool	nodetach = 0;		/* Don't detach from controlling tty */
+bool	updetach = 0;		/* Detach once link is up */
+char	*initializer = NULL;	/* Script to initialize physical link */
+char	*connect_script = NULL;	/* Script to establish physical link */
+char	*disconnect_script = NULL; /* Script to disestablish physical link */
+char	*welcomer = NULL;	/* Script to run after phys link estab. */
+char	*ptycommand = NULL;	/* Command to run on other side of pty */
+int	maxconnect = 0;		/* Maximum connect time */
+char	user[MAXNAMELEN];	/* Username for PAP */
+char	passwd[MAXSECRETLEN];	/* Password for PAP */
+bool	persist = 0;		/* Reopen link after it goes down */
+char	our_name[MAXNAMELEN];	/* Our name for authentication purposes */
+bool	demand = 0;		/* do dial-on-demand */
+char	*ipparam = NULL;	/* Extra parameter for ip up/down scripts */
+int	idle_time_limit = 0;	/* Disconnect if idle for this many seconds */
+int	holdoff = 30;		/* # seconds to pause before reconnecting */
+bool	holdoff_specified;	/* true if a holdoff value has been given */
+bool	notty = 0;		/* Stdin/out is not a tty */
+char	*record_file = NULL;	/* File to record chars sent/received */
+int	using_pty = 0;
+bool	sync_serial = 0;	/* Device is synchronous serial device */
+int	log_to_fd = 1;		/* send log messages to this fd too */
+int	maxfail = 10;		/* max # of unsuccessful connection attempts */
+char	linkname[MAXPATHLEN];	/* logical name for link */
+bool	tune_kernel;		/* may alter kernel settings */
+int	connect_delay = 1000;	/* wait this many ms after connect script */
+
+extern option_t auth_options[];
+extern struct stat devstat;
+extern int prepass;		/* Doing pre-pass to find device name */
+
+struct option_info initializer_info;
+struct option_info connect_script_info;
+struct option_info disconnect_script_info;
+struct option_info welcomer_info;
+struct option_info devnam_info;
+struct option_info ptycommand_info;
+
+#ifdef PPP_FILTER
+struct	bpf_program pass_filter;/* Filter program for packets to pass */
+struct	bpf_program active_filter; /* Filter program for link-active pkts */
+pcap_t  pc;			/* Fake struct pcap so we can compile expr */
+#endif
+
+char *current_option;		/* the name of the option being parsed */
+int  privileged_option;		/* set iff the current option came from root */
+char *option_source;		/* string saying where the option came from */
+bool log_to_file;		/* log_to_fd is a file opened by us */
+
+/*
+ * Prototypes
+ */
+static int setdevname(char *);
+static int setipaddr(char *);
+static int setspeed(char *);
+static int noopt(char **);
+static int setdomain(char **);
+static int setnetmask(char **);
+static int setxonxoff(char **);
+static int readfile(char **);
+static int callfile(char **);
+static void usage(void);
+static int setlogfile(char **);
+#ifdef PLUGIN
+static int loadplugin(char **);
+#endif
+
+#ifdef PPP_FILTER
+static int setpassfilter(char **);
+static int setactivefilter(char **);
+#endif
+
+static option_t *find_option(char *name);
+static int process_option(option_t *, char **);
+static int n_arguments(option_t *);
+static int number_option(char *, uint32_t *, int);
+
+/*
+ * Structure to store extra lists of options.
+ */
+struct option_list {
+    option_t *options;
+    struct option_list *next;
+};
+
+static struct option_list *extra_options = NULL;
+
+/*
+ * Valid arguments.
+ */
+option_t general_options[] = {
+    { "debug", o_int, &debug,
+      "Increase debugging level", OPT_INC|OPT_NOARG|1, NULL, 0, 0 },
+    { "-d", o_int, &debug,
+      "Increase debugging level", OPT_INC|OPT_NOARG|1, NULL, 0, 0 },
+    { "kdebug", o_int, &kdebugflag,
+      "Set kernel driver debug level", 0, NULL, 0, 0 },
+    { "nodetach", o_bool, &nodetach,
+      "Don't detach from controlling tty", 1, NULL, 0, 0 },
+    { "-detach", o_bool, &nodetach,
+      "Don't detach from controlling tty", 1, NULL, 0, 0 },
+    { "updetach", o_bool, &updetach,
+      "Detach from controlling tty once link is up", 1, NULL, 0, 0 },
+    { "holdoff", o_int, &holdoff,
+      "Set time in seconds before retrying connection", 0, NULL, 0, 0 },
+    { "idle", o_int, &idle_time_limit,
+      "Set time in seconds before disconnecting idle link", 0, NULL, 0, 0 },
+    { "lock", o_bool, &lockflag,
+      "Lock serial device with UUCP-style lock file", 1, NULL, 0, 0 },
+    { "-all", o_special_noarg, noopt,
+      "Don't request/allow any LCP or IPCP options (useless)", 0, NULL, 0, 0 },
+    { "init", o_string, &initializer,
+      "A program to initialize the device",
+      OPT_A2INFO | OPT_PRIVFIX, &initializer_info, 0, 0 },
+    { "connect", o_string, &connect_script,
+      "A program to set up a connection",
+      OPT_A2INFO | OPT_PRIVFIX, &connect_script_info, 0, 0 },
+    { "disconnect", o_string, &disconnect_script,
+      "Program to disconnect serial device",
+      OPT_A2INFO | OPT_PRIVFIX, &disconnect_script_info, 0, 0 },
+    { "welcome", o_string, &welcomer,
+      "Script to welcome client",
+      OPT_A2INFO | OPT_PRIVFIX, &welcomer_info, 0, 0 },
+    { "pty", o_string, &ptycommand,
+      "Script to run on pseudo-tty master side",
+      OPT_A2INFO | OPT_PRIVFIX | OPT_DEVNAM, &ptycommand_info, 0, 0 },
+    { "notty", o_bool, &notty,
+      "Input/output is not a tty", OPT_DEVNAM | 1, NULL, 0, 0 },
+    { "record", o_string, &record_file,
+      "Record characters sent/received to file", 0, NULL, 0, 0 },
+    { "maxconnect", o_int, &maxconnect,
+      "Set connection time limit", OPT_LLIMIT|OPT_NOINCR|OPT_ZEROINF, NULL, 0, 0 },
+    { "crtscts", o_int, &crtscts,
+      "Set hardware (RTS/CTS) flow control", OPT_NOARG|OPT_VAL(1), NULL, 0, 0 },
+    { "nocrtscts", o_int, &crtscts,
+      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1), NULL, 0, 0 },
+    { "-crtscts", o_int, &crtscts,
+      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1), NULL, 0, 0 },
+    { "cdtrcts", o_int, &crtscts,
+      "Set alternate hardware (DTR/CTS) flow control", OPT_NOARG|OPT_VAL(2), NULL, 0, 0 },
+    { "nocdtrcts", o_int, &crtscts,
+      "Disable hardware flow control", OPT_NOARG|OPT_VAL(-1), NULL, 0, 0 },
+    { "xonxoff", o_special_noarg, setxonxoff,
+      "Set software (XON/XOFF) flow control", 0, NULL, 0, 0 },
+    { "domain", o_special, setdomain,
+      "Add given domain name to hostname", 0, NULL, 0, 0 },
+    { "mtu", o_int, &lcp_allowoptions[0].mru,
+      "Set our MTU", OPT_LIMITS, NULL, MAXMRU, MINMRU },
+    { "netmask", o_special, setnetmask,
+      "set netmask", 0, NULL, 0, 0 },
+    { "modem", o_bool, &modem,
+      "Use modem control lines", 1, NULL, 0, 0 },
+    { "local", o_bool, &modem,
+      "Don't use modem control lines", 0, NULL, 0, 0 },
+    { "file", o_special, readfile,
+      "Take options from a file", OPT_PREPASS, NULL, 0, 0 },
+    { "call", o_special, callfile,
+      "Take options from a privileged file", OPT_PREPASS, NULL, 0, 0 },
+    { "persist", o_bool, &persist,
+      "Keep on reopening connection after close", 1, NULL, 0, 0 },
+    { "nopersist", o_bool, &persist,
+      "Turn off persist option", 0, NULL, 0, 0 },
+    { "demand", o_bool, &demand,
+      "Dial on demand", OPT_INITONLY | 1, &persist, 0, 0 },
+    { "sync", o_bool, &sync_serial,
+      "Use synchronous HDLC serial encoding", 1, NULL, 0, 0 },
+    { "logfd", o_int, &log_to_fd,
+      "Send log messages to this file descriptor", 0, NULL, 0, 0 },
+    { "logfile", o_special, setlogfile,
+      "Append log messages to this file", 0, NULL, 0, 0 },
+    { "nolog", o_int, &log_to_fd,
+      "Don't send log messages to any file",
+      OPT_NOARG | OPT_VAL(-1), NULL, 0, 0 },
+    { "nologfd", o_int, &log_to_fd,
+      "Don't send log messages to any file descriptor",
+      OPT_NOARG | OPT_VAL(-1), NULL, 0, 0 },
+    { "linkname", o_string, linkname,
+      "Set logical name for link",
+      OPT_PRIV|OPT_STATIC, NULL, MAXPATHLEN, 0 },
+    { "maxfail", o_int, &maxfail,
+      "Maximum number of unsuccessful connection attempts to allow", 0, NULL, 0, 0 },
+    { "ktune", o_bool, &tune_kernel,
+      "Alter kernel settings as necessary", 1, NULL, 0, 0 },
+    { "noktune", o_bool, &tune_kernel,
+      "Don't alter kernel settings", 0, NULL, 0, 0 },
+    { "connect-delay", o_int, &connect_delay,
+      "Maximum time (in ms) to wait after connect script finishes", 0, NULL, 0, 0 },
+#ifdef PLUGIN
+    { "plugin", o_special, loadplugin,
+      "Load a plug-in module into pppd", OPT_PRIV, NULL, 0, 0 },
+#endif
+
+#ifdef PPP_FILTER
+    { "pdebug", o_int, &dflag,
+      "libpcap debugging", 0, NULL, 0, 0 },
+    { "pass-filter", 1, setpassfilter,
+      "set filter for packets to pass", 0, NULL, 0, 0 },
+    { "active-filter", 1, setactivefilter,
+      "set filter for active pkts", 0, NULL, 0, 0 },
+#endif
+
+    { NULL, 0, NULL, NULL, 0,  NULL, 0, 0 }
+};
+
+#ifndef IMPLEMENTATION
+#define IMPLEMENTATION ""
+#endif
+
+static char *usage_string = "\
+pppd version %s.%d%s\n\
+Usage: %s [ options ], where options are:\n\
+	<device>	Communicate over the named device\n\
+	<speed>		Set the baud rate to <speed>\n\
+	<loc>:<rem>	Set the local and/or remote interface IP\n\
+			addresses.  Either one may be omitted.\n\
+	asyncmap <n>	Set the desired async map to hex <n>\n\
+	auth		Require authentication from peer\n\
+        connect <p>     Invoke shell command <p> to set up the serial line\n\
+	crtscts		Use hardware RTS/CTS flow control\n\
+	defaultroute	Add default route through interface\n\
+	file <f>	Take options from file <f>\n\
+	modem		Use modem control lines\n\
+	mru <n>		Set MRU value to <n> for negotiation\n\
+See pppd(8) for more options.\n\
+";
+
+/*
+ * parse_args - parse a string of arguments from the command line.
+ * If prepass is true, we are scanning for the device name and only
+ * processing a few options, so error messages are suppressed.
+ */
+int
+parse_args(
+    int argc,
+    char **argv)
+{
+    char *arg;
+    option_t *opt;
+    int ret;
+
+    privileged_option = privileged;
+    option_source = "command line";
+    while (argc > 0) {
+	arg = *argv++;
+	--argc;
+
+	/*
+	 * First see if it's an option in the new option list.
+	 */
+	opt = find_option(arg);
+	if (opt != NULL) {
+	    int n = n_arguments(opt);
+	    if (argc < n) {
+		option_error("too few parameters for option %s", arg);
+		return 0;
+	    }
+	    current_option = arg;
+	    if (!process_option(opt, argv))
+		return 0;
+	    argc -= n;
+	    argv += n;
+	    continue;
+	}
+
+	/*
+	 * Maybe a tty name, speed or IP address?
+	 */
+	if ((ret = setdevname(arg)) == 0
+	    && (ret = setspeed(arg)) == 0
+	    && (ret = setipaddr(arg)) == 0
+	    && !prepass) {
+	    option_error("unrecognized option '%s'", arg);
+	    usage();
+	    return 0;
+	}
+	if (ret < 0)	/* error */
+	    return 0;
+    }
+    return 1;
+}
+
+#if 0
+/*
+ * scan_args - scan the command line arguments to get the tty name,
+ * if specified.  Also checks whether the notty or pty option was given.
+ */
+void
+scan_args(argc, argv)
+    int argc;
+    char **argv;
+{
+    char *arg;
+    option_t *opt;
+
+    privileged_option = privileged;
+    while (argc > 0) {
+	arg = *argv++;
+	--argc;
+
+	if (strcmp(arg, "notty") == 0 || strcmp(arg, "pty") == 0)
+	    using_pty = 1;
+
+	/* Skip options and their arguments */
+	opt = find_option(arg);
+	if (opt != NULL) {
+	    int n = n_arguments(opt);
+	    argc -= n;
+	    argv += n;
+	    continue;
+	}
+
+	/* Check if it's a tty name and copy it if so */
+	(void) setdevname(arg, 1);
+    }
+}
+#endif
+
+/*
+ * options_from_file - Read a string of options from a file,
+ * and interpret them.
+ */
+int
+options_from_file(
+    char *filename,
+    int must_exist,
+    int check_prot,
+    int priv)
+{
+    FILE *f;
+    int i, newline, ret, err;
+    option_t *opt;
+    int oldpriv;
+    char *oldsource;
+    char *argv[MAXARGS];
+    char args[MAXARGS][MAXWORDLEN];
+    char cmd[MAXWORDLEN];
+
+    f = fopen(filename, "r");
+    err = errno;
+    if (f == NULL) {
+	if (!must_exist && err == ENOENT)
+	    return 1;
+	errno = err;
+	option_error("Can't open options file %s: %m", filename);
+	return 0;
+    }
+
+    oldpriv = privileged_option;
+    privileged_option = priv;
+    oldsource = option_source;
+    option_source = strdup(filename);
+    if (option_source == NULL)
+	option_source = "file";
+    ret = 0;
+    while (getword(f, cmd, &newline, filename)) {
+	/*
+	 * First see if it's a command.
+	 */
+	opt = find_option(cmd);
+	if (opt != NULL) {
+	    int n = n_arguments(opt);
+	    for (i = 0; i < n; ++i) {
+		if (!getword(f, args[i], &newline, filename)) {
+		    option_error(
+			"In file %s: too few parameters for option '%s'",
+			filename, cmd);
+		    goto err;
+		}
+		argv[i] = args[i];
+	    }
+	    current_option = cmd;
+	    if ((opt->flags & OPT_DEVEQUIV) && devnam_fixed) {
+		option_error("the %s option may not be used in the %s file",
+			     cmd, filename);
+		goto err;
+	    }
+	    if (!process_option(opt, argv))
+		goto err;
+	    continue;
+	}
+
+	/*
+	 * Maybe a tty name, speed or IP address?
+	 */
+	if ((i = setdevname(cmd)) == 0
+	    && (i = setspeed(cmd)) == 0
+	    && (i = setipaddr(cmd)) == 0) {
+	    option_error("In file %s: unrecognized option '%s'",
+			 filename, cmd);
+	    goto err;
+	}
+	if (i < 0)		/* error */
+	    goto err;
+    }
+    ret = 1;
+
+err:
+    fclose(f);
+    privileged_option = oldpriv;
+    option_source = oldsource;
+    return ret;
+}
+
+/*
+ * options_from_user - See if the use has a ~/.ppprc file,
+ * and if so, interpret options from it.
+ */
+int
+options_from_user(void)
+{
+    return 0;
+}
+
+/*
+ * options_for_tty - See if an options file exists for the serial
+ * device, and if so, interpret options from it.
+ */
+int
+options_for_tty(void)
+{
+    char *dev, *path, *p;
+    int ret;
+    size_t pl;
+
+    dev = devnam;
+    if (strncmp(dev, "/dev/", 5) == 0)
+	dev += 5;
+    if (dev[0] == 0 || strcmp(dev, "tty") == 0)
+	return 1;		/* don't look for /etc/ppp/options.tty */
+    pl = strlen(_PATH_TTYOPT) + strlen(dev) + 1;
+    path = malloc(pl);
+    if (path == NULL)
+	novm("tty init file name");
+    slprintf(path, pl, "%s%s", _PATH_TTYOPT, dev);
+    /* Turn slashes into dots, for Solaris case (e.g. /dev/term/a) */
+    for (p = path + strlen(_PATH_TTYOPT); *p != 0; ++p)
+	if (*p == '/')
+	    *p = '.';
+    ret = options_from_file(path, 0, 0, 1);
+    free(path);
+    return ret;
+}
+
+/*
+ * options_from_list - process a string of options in a wordlist.
+ */
+int
+options_from_list(
+    struct wordlist *w,
+    int priv)
+{
+    char *argv[MAXARGS];
+    option_t *opt;
+    int i, ret = 0;
+
+    privileged_option = priv;
+    option_source = "secrets file";
+
+    while (w != NULL) {
+	/*
+	 * First see if it's a command.
+	 */
+	opt = find_option(w->word);
+	if (opt != NULL) {
+	    int n = n_arguments(opt);
+	    struct wordlist *w0 = w;
+	    for (i = 0; i < n; ++i) {
+		w = w->next;
+		if (w == NULL) {
+		    option_error(
+			"In secrets file: too few parameters for option '%s'",
+			w0->word);
+		    goto err;
+		}
+		argv[i] = w->word;
+	    }
+	    current_option = w0->word;
+	    if (!process_option(opt, argv))
+		goto err;
+            w = w->next;
+	    continue;
+	}
+
+	/*
+	 * Maybe a tty name, speed or IP address?
+	 */
+	if ((i = setdevname(w->word)) == 0
+	    && (i = setspeed(w->word)) == 0
+	    && (i = setipaddr(w->word)) == 0) {
+	    option_error("In secrets file: unrecognized option '%s'",
+			 w->word);
+	    goto err;
+	}
+	if (i < 0)		/* error */
+	    goto err;
+        w = w->next;
+    }
+    ret = 1;
+
+err:
+    return ret;
+}
+
+/*
+ * find_option - scan the option lists for the various protocols
+ * looking for an entry with the given name.
+ * This could be optimized by using a hash table.
+ */
+static option_t *
+find_option(char *name)
+{
+    option_t *opt;
+    struct option_list *list;
+    int i;
+
+    for (list = extra_options; list != NULL; list = list->next)
+	for (opt = list->options; opt->name != NULL; ++opt)
+	    if (strcmp(name, opt->name) == 0)
+		return opt;
+    for (opt = general_options; opt->name != NULL; ++opt)
+	if (strcmp(name, opt->name) == 0)
+	    return opt;
+    for (opt = auth_options; opt->name != NULL; ++opt)
+	if (strcmp(name, opt->name) == 0)
+	    return opt;
+    for (i = 0; protocols[i] != NULL; ++i)
+	if ((opt = protocols[i]->options) != NULL)
+	    for (; opt->name != NULL; ++opt)
+		if (strcmp(name, opt->name) == 0)
+		    return opt;
+    return NULL;
+}
+
+/*
+ * process_option - process one new-style option.
+ */
+static int
+process_option(
+    option_t *opt,
+    char **argv)
+{
+    uint32_t v;
+    int iv, a;
+    char *sv;
+    int (*parser)(char **);
+
+    if ((opt->flags & OPT_PREPASS) == 0 && prepass)
+	return 1;
+    if ((opt->flags & OPT_INITONLY) && pppd_phase != PHASE_INITIALIZE) {
+	option_error("it's too late to use the %s option", opt->name);
+	return 0;
+    }
+    if ((opt->flags & OPT_PRIV) && !privileged_option) {
+	option_error("using the %s option requires root privilege", opt->name);
+	return 0;
+    }
+    if ((opt->flags & OPT_ENABLE) && *(bool *)(opt->addr2) == 0) {
+	option_error("%s option is disabled", opt->name);
+	return 0;
+    }
+    if ((opt->flags & OPT_PRIVFIX) && !privileged_option) {
+	struct option_info *ip = (struct option_info *) opt->addr2;
+	if (ip && ip->priv) {
+	    option_error("%s option cannot be overridden", opt->name);
+	    return 0;
+	}
+    }
+
+    switch (opt->type) {
+    case o_bool:
+	v = opt->flags & OPT_VALUE;
+	*(bool *)(opt->addr) = v;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(bool *)(opt->addr2) = v;
+	break;
+
+    case o_int:
+	iv = 0;
+	if ((opt->flags & OPT_NOARG) == 0) {
+	    if (!int_option(*argv, &iv))
+		return 0;
+	    if ((((opt->flags & OPT_LLIMIT) && iv < opt->lower_limit)
+		 || ((opt->flags & OPT_ULIMIT) && iv > opt->upper_limit))
+		&& !((opt->flags & OPT_ZEROOK && iv == 0))) {
+		char *zok = (opt->flags & OPT_ZEROOK)? " zero or": "";
+		switch (opt->flags & OPT_LIMITS) {
+		case OPT_LLIMIT:
+		    option_error("%s value must be%s >= %d",
+				 opt->name, zok, opt->lower_limit);
+		    break;
+		case OPT_ULIMIT:
+		    option_error("%s value must be%s <= %d",
+				 opt->name, zok, opt->upper_limit);
+		    break;
+		case OPT_LIMITS:
+		    option_error("%s value must be%s between %d and %d",
+				opt->name, opt->lower_limit, opt->upper_limit);
+		    break;
+		}
+		return 0;
+	    }
+	}
+	a = opt->flags & OPT_VALUE;
+	if (a >= 128)
+	    a -= 256;		/* sign extend */
+	iv += a;
+	if (opt->flags & OPT_INC)
+	    iv += *(int *)(opt->addr);
+	if ((opt->flags & OPT_NOINCR) && !privileged_option) {
+	    int oldv = *(int *)(opt->addr);
+	    if ((opt->flags & OPT_ZEROINF) ?
+		(oldv != 0 && (iv == 0 || iv > oldv)) : (iv > oldv)) {
+		option_error("%s value cannot be increased", opt->name);
+		return 0;
+	    }
+	}
+	*(int *)(opt->addr) = iv;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(int *)(opt->addr2) = iv;
+	break;
+
+    case o_uint32:
+	if (opt->flags & OPT_NOARG) {
+	    v = opt->flags & OPT_VALUE;
+	} else if (!number_option(*argv, &v, 16))
+	    return 0;
+	if (opt->flags & OPT_OR)
+	    v |= *(uint32_t *)(opt->addr);
+	*(uint32_t *)(opt->addr) = v;
+	if (opt->addr2 && (opt->flags & OPT_A2COPY))
+	    *(uint32_t *)(opt->addr2) = v;
+	break;
+
+    case o_string:
+	if (opt->flags & OPT_STATIC) {
+	    strlcpy((char *)(opt->addr), *argv, opt->upper_limit);
+	} else {
+	    sv = strdup(*argv);
+	    if (sv == NULL)
+		novm("option argument");
+            if ( *(char **)(opt->addr) != NULL ) {
+                free((void *)*(char **)(opt->addr));
+                *(char **)(opt->addr) = NULL;
+            }
+	    *(char **)(opt->addr) = sv;
+	}
+	break;
+
+    case o_special_noarg:
+    case o_special:
+	parser = (int (*)(char **)) opt->addr;
+	if (!(*parser)(argv))
+	    return 0;
+	break;
+    }
+
+    if (opt->addr2) {
+	if (opt->flags & OPT_A2INFO) {
+	    struct option_info *ip = (struct option_info *) opt->addr2;
+	    ip->priv = privileged_option;
+	    ip->source = option_source;
+	} else if ((opt->flags & (OPT_A2COPY|OPT_ENABLE)) == 0)
+	    *(bool *)(opt->addr2) = 1;
+    }
+
+    return 1;
+}
+
+/*
+ * n_arguments - tell how many arguments an option takes
+ */
+static int
+n_arguments(
+    option_t *opt)
+{
+    return (opt->type == o_bool || opt->type == o_special_noarg
+	    || (opt->flags & OPT_NOARG))? 0: 1;
+}
+
+/*
+ * add_options - add a list of options to the set we grok.
+ */
+void
+add_options(
+    option_t *opt)
+{
+    struct option_list *list;
+
+    list = malloc(sizeof(*list));
+    if (list == 0)
+	novm("option list entry");
+    list->options = opt;
+    list->next = extra_options;
+    extra_options = list;
+}
+
+/*
+ * usage - print out a message telling how to use the program.
+ */
+static void
+usage(void)
+{
+    if (pppd_phase == PHASE_INITIALIZE)
+	fprintf(stderr, usage_string, VERSION, PATCHLEVEL, IMPLEMENTATION,
+		"rtems_pppd");
+}
+
+/*
+ * option_error - print a message about an error in an option.
+ * The message is logged, and also sent to
+ * stderr if pppd_phase == PHASE_INITIALIZE.
+ */
+void
+option_error __V((char *fmt, ...))
+{
+    va_list args;
+    char buf[256];
+
+#if defined(__STDC__)
+    va_start(args, fmt);
+#else
+    char *fmt;
+    va_start(args);
+    fmt = va_arg(args, char *);
+#endif
+    if (prepass) {
+	va_end(args);
+	return;
+    }
+    vslprintf(buf, sizeof(buf), fmt, args);
+    va_end(args);
+
+    fprintf(stderr, "pppd: %s\n", buf);
+}
+
+/*
+ * Read a word from a file.
+ * Words are delimited by white-space or by quotes (" or ').
+ * Quotes, white-space and \ may be escaped with \.
+ * \<newline> is ignored.
+ */
+int
+getword(
+    FILE *f,
+    char *word,
+    int *newlinep,
+    char *filename)
+{
+    int c, len, escape;
+    int quoted, comment;
+    int value, digit, got, n;
+
+#define isoctal(c) ((c) >= '0' && (c) < '8')
+
+    *newlinep = 0;
+    len = 0;
+    escape = 0;
+    comment = 0;
+
+    /*
+     * First skip white-space and comments.
+     */
+    for (;;) {
+	c = getc(f);
+	if (c == EOF)
+	    break;
+
+	/*
+	 * A newline means the end of a comment; backslash-newline
+	 * is ignored.  Note that we cannot have escape && comment.
+	 */
+	if (c == '\n') {
+	    if (!escape) {
+		*newlinep = 1;
+		comment = 0;
+	    } else
+		escape = 0;
+	    continue;
+	}
+
+	/*
+	 * Ignore characters other than newline in a comment.
+	 */
+	if (comment)
+	    continue;
+
+	/*
+	 * If this character is escaped, we have a word start.
+	 */
+	if (escape)
+	    break;
+
+	/*
+	 * If this is the escape character, look at the next character.
+	 */
+	if (c == '\\') {
+	    escape = 1;
+	    continue;
+	}
+
+	/*
+	 * If this is the start of a comment, ignore the rest of the line.
+	 */
+	if (c == '#') {
+	    comment = 1;
+	    continue;
+	}
+
+	/*
+	 * A non-whitespace character is the start of a word.
+	 */
+	if (!isspace(c))
+	    break;
+    }
+
+    /*
+     * Save the delimiter for quoted strings.
+     */
+    if (!escape && (c == '"' || c == '\'')) {
+        quoted = c;
+	c = getc(f);
+    } else
+        quoted = 0;
+
+    /*
+     * Process characters until the end of the word.
+     */
+    while (c != EOF) {
+	if (escape) {
+	    /*
+	     * This character is escaped: backslash-newline is ignored,
+	     * various other characters indicate particular values
+	     * as for C backslash-escapes.
+	     */
+	    escape = 0;
+	    if (c == '\n') {
+	        c = getc(f);
+		continue;
+	    }
+
+	    got = 0;
+	    switch (c) {
+	    case 'a':
+		value = '\a';
+		break;
+	    case 'b':
+		value = '\b';
+		break;
+	    case 'f':
+		value = '\f';
+		break;
+	    case 'n':
+		value = '\n';
+		break;
+	    case 'r':
+		value = '\r';
+		break;
+	    case 's':
+		value = ' ';
+		break;
+	    case 't':
+		value = '\t';
+		break;
+
+	    default:
+		if (isoctal(c)) {
+		    /*
+		     * \ddd octal sequence
+		     */
+		    value = 0;
+		    for (n = 0; n < 3 && isoctal(c); ++n) {
+			value = (value << 3) + (c & 07);
+			c = getc(f);
+		    }
+		    got = 1;
+		    break;
+		}
+
+		if (c == 'x') {
+		    /*
+		     * \x<hex_string> sequence
+		     */
+		    value = 0;
+		    c = getc(f);
+		    for (n = 0; n < 2 && isxdigit(c); ++n) {
+			digit = toupper(c) - '0';
+			if (digit > 10)
+			    digit += '0' + 10 - 'A';
+			value = (value << 4) + digit;
+			c = getc (f);
+		    }
+		    got = 1;
+		    break;
+		}
+
+		/*
+		 * Otherwise the character stands for itself.
+		 */
+		value = c;
+		break;
+	    }
+
+	    /*
+	     * Store the resulting character for the escape sequence.
+	     */
+	    if (len < MAXWORDLEN-1)
+		word[len] = value;
+	    ++len;
+
+	    if (!got)
+		c = getc(f);
+	    continue;
+
+	}
+
+	/*
+	 * Not escaped: see if we've reached the end of the word.
+	 */
+	if (quoted) {
+	    if (c == quoted)
+		break;
+	} else {
+	    if (isspace(c) || c == '#') {
+		ungetc (c, f);
+		break;
+	    }
+	}
+
+	/*
+	 * Backslash starts an escape sequence.
+	 */
+	if (c == '\\') {
+	    escape = 1;
+	    c = getc(f);
+	    continue;
+	}
+
+	/*
+	 * An ordinary character: store it in the word and get another.
+	 */
+	if (len < MAXWORDLEN-1)
+	    word[len] = c;
+	++len;
+
+	c = getc(f);
+    }
+
+    /*
+     * End of the word: check for errors.
+     */
+    if (c == EOF) {
+	if (ferror(f)) {
+	    if (errno == 0)
+		errno = EIO;
+	    option_error("Error reading %s: %m", filename);
+	    die(1);
+	}
+	/*
+	 * If len is zero, then we didn't find a word before the
+	 * end of the file.
+	 */
+	if (len == 0)
+	    return 0;
+    }
+
+    /*
+     * Warn if the word was too long, and append a terminating null.
+     */
+    if (len >= MAXWORDLEN) {
+	option_error("warning: word in file %s too long (%.20s...)",
+		     filename, word);
+	len = MAXWORDLEN - 1;
+    }
+    word[len] = 0;
+
+    return 1;
+
+#undef isoctal
+
+}
+
+/*
+ * number_option - parse an unsigned numeric parameter for an option.
+ */
+static int
+number_option(
+    char *str,
+    uint32_t *valp,
+    int base)
+{
+    char *ptr;
+
+    *valp = strtoul(str, &ptr, base);
+    if (ptr == str) {
+	option_error("invalid numeric parameter '%s' for %s option",
+		     str, current_option);
+	return 0;
+    }
+    return 1;
+}
+
+
+/*
+ * int_option - like number_option, but valp is int *,
+ * the base is assumed to be 0, and *valp is not changed
+ * if there is an error.
+ */
+int
+int_option(
+    char *str,
+    int *valp)
+{
+    uint32_t v;
+
+    if (!number_option(str, &v, 0))
+	return 0;
+    *valp = (int) v;
+    return 1;
+}
+
+
+/*
+ * The following procedures parse options.
+ */
+
+/*
+ * readfile - take commands from a file.
+ */
+static int
+readfile(
+    char **argv)
+{
+    return options_from_file(*argv, 1, 1, privileged_option);
+}
+
+/*
+ * callfile - take commands from /etc/ppp/peers/<name>.
+ * Name may not contain /../, start with / or ../, or end in /..
+ */
+static int
+callfile(
+    char **argv)
+{
+    char *fname, *arg, *p;
+    int l, ok;
+
+    arg = *argv;
+    ok = 1;
+    if (arg[0] == '/' || arg[0] == 0)
+	ok = 0;
+    else {
+	for (p = arg; *p != 0; ) {
+	    if (p[0] == '.' && p[1] == '.' && (p[2] == '/' || p[2] == 0)) {
+		ok = 0;
+		break;
+	    }
+	    while (*p != '/' && *p != 0)
+		++p;
+	    if (*p == '/')
+		++p;
+	}
+    }
+    if (!ok) {
+	option_error("call option value may not contain .. or start with /");
+	return 0;
+    }
+
+    l = strlen(arg) + strlen(_PATH_PEERFILES) + 1;
+    if ((fname = (char *) malloc(l)) == NULL)
+	novm("call file name");
+    slprintf(fname, l, "%s%s", _PATH_PEERFILES, arg);
+
+    ok = options_from_file(fname, 1, 1, 1);
+
+    free(fname);
+    return ok;
+}
+
+#ifdef PPP_FILTER
+/*
+ * setpdebug - Set libpcap debugging level.
+ */
+static int
+setpdebug(
+    char **argv)
+{
+    return int_option(*argv, &dflag);
+}
+
+/*
+ * setpassfilter - Set the pass filter for packets
+ */
+static int
+setpassfilter(
+    char **argv)
+{
+    pc.linktype = DLT_PPP;
+    pc.snapshot = PPP_HDRLEN;
+
+    if (pcap_compile(&pc, &pass_filter, *argv, 1, netmask) == 0)
+	return 1;
+    option_error("error in pass-filter expression: %s\n", pcap_geterr(&pc));
+    return 0;
+}
+
+/*
+ * setactivefilter - Set the active filter for packets
+ */
+static int
+setactivefilter(
+    char **argv)
+{
+    pc.linktype = DLT_PPP;
+    pc.snapshot = PPP_HDRLEN;
+
+    if (pcap_compile(&pc, &active_filter, *argv, 1, netmask) == 0)
+	return 1;
+    option_error("error in active-filter expression: %s\n", pcap_geterr(&pc));
+    return 0;
+}
+#endif
+
+/*
+ * noopt - Disable all options.
+ */
+static int
+noopt(
+    char **argv)
+{
+    BZERO((char *) &lcp_wantoptions[0], sizeof (struct lcp_options));
+    BZERO((char *) &lcp_allowoptions[0], sizeof (struct lcp_options));
+    BZERO((char *) &ipcp_wantoptions[0], sizeof (struct ipcp_options));
+    BZERO((char *) &ipcp_allowoptions[0], sizeof (struct ipcp_options));
+
+    return (1);
+}
+
+/*
+ * setdomain - Set domain name to append to hostname
+ */
+static int
+setdomain(
+    char **argv)
+{
+    if (!privileged_option) {
+	option_error("using the domain option requires root privilege");
+	return 0;
+    }
+    gethostname(hostname, MAXNAMELEN);
+    if (**argv != 0) {
+	if (**argv != '.')
+	    strncat(hostname, ".", MAXNAMELEN - strlen(hostname));
+	strncat(hostname, *argv, MAXNAMELEN - strlen(hostname));
+    }
+    hostname[MAXNAMELEN-1] = 0;
+    return (1);
+}
+
+
+/*
+ * setspeed - Set the speed.
+ */
+static int
+setspeed(
+    char *arg)
+{
+  long     spd;
+  uint32_t ret      = 1;
+  speed_t  spdValue = 0;
+  char    *ptr;
+
+  if ( !prepass ) {
+    spd = strtol(arg, &ptr, 0);
+    if (ptr == arg || *ptr != 0 || spd == 0) {
+      ret = 0;
+    }
+    else {
+      switch ( spd ) {
+        case 2400L:
+          spdValue = B2400;
+          break;
+        case 4800L:
+          spdValue = B4800;
+          break;
+        case 9600L:
+          spdValue = B9600;
+          break;
+        case 19200L:
+          spdValue = B19200;
+          break;
+        case 38400L:
+          spdValue = B38400;
+          break;
+        case 57600L:
+          spdValue = B57600;
+          break;
+        case 115200L:
+          spdValue = B115200;
+          break;
+        default:
+          ret = 0;
+          break;
+      }
+
+      if ( spdValue ) {
+        inspeed = spdValue;
+      }
+    }
+  }
+
+  return ( ret );
+}
+
+
+/*
+ * setdevname - Set the device name.
+ */
+static int
+setdevname(
+    char *cp)
+{
+    struct stat statbuf;
+    char dev[MAXPATHLEN];
+
+    if (*cp == 0)
+	return 0;
+
+    if (strncmp("/dev/", cp, 5) != 0) {
+	strlcpy(dev, "/dev/", sizeof(dev));
+	strlcat(dev, cp, sizeof(dev));
+	cp = dev;
+    }
+
+    /*
+     * Check if there is a character device by this name.
+     */
+    if (stat(cp, &statbuf) < 0) {
+	if (errno == ENOENT)
+	    return 0;
+	option_error("Couldn't stat %s: %m", cp);
+	return -1;
+    }
+    if (!S_ISCHR(statbuf.st_mode)) {
+	option_error("%s is not a character device", cp);
+	return -1;
+    }
+
+    if (pppd_phase != PHASE_INITIALIZE) {
+	option_error("device name cannot be changed after initialization");
+	return -1;
+    } else if (devnam_fixed) {
+	option_error("per-tty options file may not specify device name");
+	return -1;
+    }
+
+    if (devnam_info.priv && !privileged_option) {
+	option_error("device name cannot be overridden");
+	return -1;
+    }
+
+    strlcpy(devnam, cp, sizeof(devnam));
+    devstat = statbuf;
+    default_device = 0;
+    devnam_info.priv = privileged_option;
+    devnam_info.source = option_source;
+
+    return 1;
+}
+
+
+/*
+ * setipaddr - Set the IP address
+ */
+static int
+setipaddr(
+    char *arg)
+{
+    struct hostent *hp;
+    char *colon;
+    uint32_t local, remote;
+    ipcp_options *wo = &ipcp_wantoptions[0];
+
+    /*
+     * IP address pair separated by ":".
+     */
+    if ((colon = strchr(arg, ':')) == NULL)
+	return 0;
+    if (prepass)
+	return 1;
+
+    /*
+     * If colon first character, then no local addr.
+     */
+    if (colon != arg) {
+	*colon = '\0';
+	if ((local = inet_addr(arg)) == (uint32_t) -1) {
+	    if ((hp = gethostbyname(arg)) == NULL) {
+		option_error("unknown host: %s", arg);
+		return -1;
+	    } else {
+		local = *(uint32_t *)hp->h_addr;
+	    }
+	}
+	if (bad_ip_adrs(local)) {
+	    option_error("bad local IP address %s", ip_ntoa(local));
+	    return -1;
+	}
+	if (local != 0)
+	    wo->ouraddr = local;
+	*colon = ':';
+    }
+
+    /*
+     * If colon last character, then no remote addr.
+     */
+    if (*++colon != '\0') {
+	if ((remote = inet_addr(colon)) == (uint32_t) -1) {
+	    if ((hp = gethostbyname(colon)) == NULL) {
+		option_error("unknown host: %s", colon);
+		return -1;
+	    } else {
+		remote = *(uint32_t *)hp->h_addr;
+		if (remote_name[0] == 0)
+		    strlcpy(remote_name, colon, sizeof(remote_name));
+	    }
+	}
+	if (bad_ip_adrs(remote)) {
+	    option_error("bad remote IP address %s", ip_ntoa(remote));
+	    return -1;
+	}
+	if (remote != 0)
+	    wo->hisaddr = remote;
+    }
+
+    return 1;
+}
+
+
+/*
+ * setnetmask - set the netmask to be used on the interface.
+ */
+static int
+setnetmask(
+    char **argv)
+{
+    uint32_t mask, b;
+    int n;
+    char *p, *endp;
+
+    /*
+     * Unfortunately, if we use inet_addr, we can't tell whether
+     * a result of all 1s is an error or a valid 255.255.255.255.
+     */
+    p = *argv;
+    mask = 0;
+    for (n = 3;; --n) {
+	b = strtoul(p, &endp, 0);
+	if (endp == p)
+	    break;
+	if (b > 255) {
+	    if (n == 3) {
+		/* accept e.g. 0xffffff00 */
+		p = endp;
+		mask = b;
+	    }
+	    break;
+	}
+	mask |= b << (n * 8);
+	p = endp;
+	if (*p != '.' || n == 0)
+	    break;
+	++p;
+    }
+
+    mask = htonl(mask);
+
+    if (*p != 0 || (netmask & ~mask) != 0) {
+	option_error("invalid netmask value '%s'", *argv);
+	return 0;
+    }
+
+    netmask = mask;
+    return (1);
+}
+
+static int
+setxonxoff(
+    char **argv)
+{
+    lcp_wantoptions[0].asyncmap |= 0x000A0000;	/* escape ^S and ^Q */
+    lcp_wantoptions[0].neg_asyncmap = 1;
+
+    crtscts = -2;
+    return (1);
+}
+
+static int
+setlogfile(
+    char **argv)
+{
+    int fd, err;
+
+    fd = open(*argv, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0644);
+    if (fd < 0 && errno == EEXIST)
+	fd = open(*argv, O_WRONLY | O_APPEND);
+    err = errno;
+    if (fd < 0) {
+	errno = err;
+	option_error("Can't open log file %s: %m", *argv);
+	return 0;
+    }
+    if (log_to_file && log_to_fd >= 0)
+	close(log_to_fd);
+    log_to_fd = fd;
+    log_to_file = 1;
+    return 1;
+}
+
+#ifdef PLUGIN
+static int
+loadplugin(
+    char **argv)
+{
+    char *arg = *argv;
+    void *handle;
+    const char *err;
+    void (*init)(void);
+
+    handle = dlopen(arg, RTLD_GLOBAL | RTLD_NOW);
+    if (handle == 0) {
+	err = dlerror();
+	if (err != 0)
+	    option_error("%s", err);
+	option_error("Couldn't load plugin %s", arg);
+	return 0;
+    }
+    init = dlsym(handle, "plugin_init");
+    if (init == 0) {
+	option_error("%s has no initialization entry point", arg);
+	dlclose(handle);
+	return 0;
+    }
+    info("Plugin %s loaded.", arg);
+    (*init)();
+    return 1;
+}
+#endif /* PLUGIN */
diff --git a/rtemsbsd/pppd/patchlevel.h b/rtemsbsd/pppd/patchlevel.h
new file mode 100644
index 0000000..54d88b8
--- /dev/null
+++ b/rtemsbsd/pppd/patchlevel.h
@@ -0,0 +1,6 @@
+/* $Id$ */
+#define	PATCHLEVEL	11
+
+#define VERSION		"2.3"
+#define IMPLEMENTATION	""
+#define DATE		"23 December 1999"
diff --git a/rtemsbsd/pppd/pathnames.h b/rtemsbsd/pppd/pathnames.h
new file mode 100644
index 0000000..0a4f6e6
--- /dev/null
+++ b/rtemsbsd/pppd/pathnames.h
@@ -0,0 +1,43 @@
+/*
+ * define path names
+ *
+ * $Id$
+ */
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+
+#else
+#ifndef _PATH_VARRUN
+#define _PATH_VARRUN 	"/etc/ppp/"
+#endif
+#define _PATH_DEVNULL	"/dev/null"
+#endif
+
+#ifndef _ROOT_PATH
+#define _ROOT_PATH
+#endif
+
+#define _PATH_UPAPFILE 	 _ROOT_PATH "/etc/ppp/pap-secrets"
+#define _PATH_CHAPFILE 	 _ROOT_PATH "/etc/ppp/chap-secrets"
+#define _PATH_SYSOPTIONS _ROOT_PATH "/etc/ppp/options"
+#define _PATH_IPUP	 _ROOT_PATH "/etc/ppp/ip-up"
+#define _PATH_IPDOWN	 _ROOT_PATH "/etc/ppp/ip-down"
+#define _PATH_AUTHUP	 _ROOT_PATH "/etc/ppp/auth-up"
+#define _PATH_AUTHDOWN	 _ROOT_PATH "/etc/ppp/auth-down"
+#define _PATH_TTYOPT	 _ROOT_PATH "/etc/ppp/options."
+#define _PATH_CONNERRS	 _ROOT_PATH "/etc/ppp/connect-errors"
+#define _PATH_PEERFILES	 _ROOT_PATH "/etc/ppp/peers/"
+#define _PATH_RESOLV	 _ROOT_PATH "/etc/ppp/resolv.conf"
+
+#define _PATH_USEROPT	 ".ppprc"
+
+#ifdef INET6
+#define _PATH_IPV6UP     _ROOT_PATH "/etc/ppp/ipv6-up"
+#define _PATH_IPV6DOWN   _ROOT_PATH "/etc/ppp/ipv6-down"
+#endif
+
+#ifdef IPX_CHANGE
+#define _PATH_IPXUP	 _ROOT_PATH "/etc/ppp/ipx-up"
+#define _PATH_IPXDOWN	 _ROOT_PATH "/etc/ppp/ipx-down"
+#endif /* IPX_CHANGE */
diff --git a/rtemsbsd/pppd/pppd.h b/rtemsbsd/pppd/pppd.h
new file mode 100644
index 0000000..8655f82
--- /dev/null
+++ b/rtemsbsd/pppd/pppd.h
@@ -0,0 +1,663 @@
+/*
+ * pppd.h - PPP daemon global declarations.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+#ifndef __PPPD_H__
+#define __PPPD_H__
+
+#include <stdbool.h>		/* bool */
+#include <stdio.h>		/* for FILE */
+#include <limits.h>		/* for NGROUPS_MAX */
+#include <sys/param.h>		/* for MAXPATHLEN and BSD4_4, if defined */
+#include <sys/types.h>		/* for uint32_t, if defined */
+#include <sys/time.h>		/* for struct timeval */
+#include <net/ppp_defs.h>
+#include <rtems/rtemsdialer.h>
+#include <stdint.h>
+
+#if defined(__STDC__)
+#include <stdarg.h>
+#define __V(x)	x
+#else
+#include <varargs.h>
+#define __V(x)	(va_alist) va_dcl
+#define const
+#define volatile
+#endif
+
+#ifdef INET6
+#include "eui64.h"
+#endif
+
+/*
+ * Limits.
+ */
+
+#define NUM_PPP		1	/* One PPP interface supported (per process) */
+#define MAXWORDLEN	1024	/* max length of word in file (incl null) */
+#define MAXARGS		1	/* max # args to a command */
+#define MAXNAMELEN	256	/* max length of hostname or name for auth */
+#define MAXSECRETLEN	256	/* max length of password or secret */
+
+/*
+ * Option descriptor structure.
+ */
+
+enum opt_type {
+	o_special_noarg = 0,
+	o_special = 1,
+	o_bool,
+	o_int,
+	o_uint32,
+	o_string,
+};
+
+typedef struct {
+	char	*name;		/* name of the option */
+	enum opt_type type;
+	void	*addr;
+	char	*description;
+	uint32_t flags;
+	void	*addr2;
+	int	upper_limit;
+	int	lower_limit;
+} option_t;
+
+/* Values for flags */
+#define OPT_VALUE	0xffL	/* mask for presupplied value */
+#define OPT_HEX		0x100L	/* int option is in hex */
+#define OPT_NOARG	0x200L	/* option doesn't take argument */
+#define OPT_OR		0x400L	/* OR in argument to value */
+#define OPT_INC		0x800L	/* increment value */
+#define OPT_PRIV	0x1000L	/* privileged option */
+#define OPT_STATIC	0x2000L	/* string option goes into static array */
+#define OPT_LLIMIT	0x4000L	/* check value against lower limit */
+#define OPT_ULIMIT	0x8000L	/* check value against upper limit */
+#define OPT_LIMITS	(OPT_LLIMIT|OPT_ULIMIT)
+#define OPT_ZEROOK	0x10000L	/* 0 value is OK even if not within limits */
+#define OPT_NOINCR	0x20000L	/* value mustn't be increased */
+#define OPT_ZEROINF	0x40000L	/* with OPT_NOINCR, 0 == infinity */
+#define OPT_A2INFO	0x100000L /* addr2 -> option_info to update */
+#define OPT_A2COPY	0x200000L /* addr2 -> second location to rcv value */
+#define OPT_ENABLE	0x400000L /* use *addr2 as enable for option */
+#define OPT_PRIVFIX	0x800000L /* can't be overridden if noauth */
+#define OPT_PREPASS	0x1000000L /* do this opt in pre-pass to find device */
+#define OPT_INITONLY	0x2000000L /* option can only be set in init phase */
+#define OPT_DEVEQUIV	0x4000000L /* equiv to device name */
+#define OPT_DEVNAM	(OPT_PREPASS | OPT_INITONLY | OPT_DEVEQUIV)
+
+#define OPT_VAL(x)	((x) & OPT_VALUE)
+
+#ifndef GIDSET_TYPE
+#define GIDSET_TYPE	gid_t
+#endif
+
+/* Structure representing a list of permitted IP addresses. */
+struct permitted_ip {
+    int		permit;		/* 1 = permit, 0 = forbid */
+    uint32_t	base;		/* match if (addr & mask) == base */
+    uint32_t	mask;		/* base and mask are in network byte order */
+};
+
+/*
+ * Unfortunately, the linux kernel driver uses a different structure
+ * for statistics from the rest of the ports.
+ * This structure serves as a common representation for the bits
+ * pppd needs.
+ */
+struct pppd_stats {
+    unsigned int	bytes_in;
+    unsigned int	bytes_out;
+};
+
+/* Used for storing a sequence of words.  Usually malloced. */
+struct wordlist {
+    struct wordlist	*next;
+    char		*word;
+};
+
+/*
+ * Global variables.
+ */
+
+extern int	pppd_kill_link;	/* Signal to terminate processing loop */
+extern int	hungup;		/* Physical layer has disconnected */
+extern int	pppifunit;	/* Interface unit number */
+extern char	ifname[];	/* Interface name */
+extern int	pppd_ttyfd;	/* Serial device file descriptor */
+extern char	hostname[];	/* Our hostname */
+extern u_char	outpacket_buf[]; /* Buffer for outgoing packets */
+extern int	pppd_phase;		/* Current state of link - see values below */
+extern int	baud_rate;	/* Current link speed in bits/sec */
+extern int	redirect_stderr;/* Connector's stderr should go to file */
+extern char	peer_authname[];/* Authenticated name of peer */
+extern int	privileged;	/* We were run by real-uid root */
+extern int	need_holdoff;	/* Need holdoff period after link terminates */
+extern char	**script_env;	/* Environment variables for scripts */
+extern int	detached;	/* Have detached from controlling tty */
+extern GIDSET_TYPE groups[NGROUPS_MAX];	/* groups the user is in */
+extern int	ngroups;	/* How many groups valid in groups */
+extern struct pppd_stats link_stats; /* byte/packet counts etc. for link */
+extern int	using_pty;	/* using pty as device (notty or pty opt.) */
+extern int	log_to_fd;	/* logging to this fd as well as syslog */
+extern char	*no_ppp_msg;	/* message to print if ppp not in kernel */
+extern volatile int pppd_status;	/* exit status for pppd */
+extern int	devnam_fixed;	/* can no longer change devnam */
+extern int	unsuccess;	/* # unsuccessful connection attempts */
+extern int	do_callback;	/* set if we want to do callback next */
+extern int	doing_callback;	/* set if this is a callback */
+extern dialerfp pppd_dialer;    /* script dialer function callback */
+
+/* Values for do_callback and doing_callback */
+#define CALLBACK_DIALIN		1	/* we are expecting the call back */
+#define CALLBACK_DIALOUT	2	/* we are dialling out to call back */
+
+/*
+ * Variables set by command-line options.
+ */
+
+extern int	debug;		/* Debug flag */
+extern int	kdebugflag;	/* Tell kernel to print debug messages */
+extern int	default_device;	/* Using /dev/tty or equivalent */
+extern char	devnam[MAXPATHLEN];	/* Device name */
+extern int	crtscts;	/* Use hardware flow control */
+extern bool	modem;		/* Use modem control lines */
+extern int	inspeed;	/* Input/Output speed requested */
+extern uint32_t netmask;	/* IP netmask to set on interface */
+extern bool	lockflag;	/* Create lock file to lock the serial dev */
+extern bool	nodetach;	/* Don't detach from controlling tty */
+extern bool	updetach;	/* Detach from controlling tty when link up */
+extern char	*initializer;	/* Script to initialize physical link */
+extern char	*connect_script; /* Script to establish physical link */
+extern char	*disconnect_script; /* Script to disestablish physical link */
+extern char	*welcomer;	/* Script to welcome client after connection */
+extern char	*ptycommand;	/* Command to run on other side of pty */
+extern int	maxconnect;	/* Maximum connect time (seconds) */
+extern char	user[MAXNAMELEN];/* Our name for authenticating ourselves */
+extern char	passwd[MAXSECRETLEN];	/* Password for PAP or CHAP */
+extern bool	auth_required;	/* Peer is required to authenticate */
+extern bool	persist;	/* Reopen link after it goes down */
+extern bool	uselogin;	/* Use /etc/passwd for checking PAP */
+extern char	our_name[MAXNAMELEN];/* Our name for authentication purposes */
+extern char	remote_name[MAXNAMELEN]; /* Peer's name for authentication */
+extern bool	explicit_remote;/* remote_name specified with remotename opt */
+extern bool	demand;		/* Do dial-on-demand */
+extern char	*ipparam;	/* Extra parameter for ip up/down scripts */
+extern bool	cryptpap;	/* Others' PAP passwords are encrypted */
+extern int	idle_time_limit;/* Shut down link if idle for this long */
+extern int	holdoff;	/* Dead time before restarting */
+extern bool	holdoff_specified; /* true if user gave a holdoff value */
+extern bool	notty;		/* Stdin/out is not a tty */
+extern char	*record_file;	/* File to record chars sent/received */
+extern bool	sync_serial;	/* Device is synchronous serial device */
+extern int	maxfail;	/* Max # of unsuccessful connection attempts */
+extern char	linkname[MAXPATHLEN]; /* logical name for link */
+extern bool	tune_kernel;	/* May alter kernel settings as necessary */
+extern int	connect_delay;	/* Time to delay after connect script */
+
+#ifdef PPP_FILTER
+extern struct	bpf_program pass_filter;   /* Filter for pkts to pass */
+extern struct	bpf_program active_filter; /* Filter for link-active pkts */
+#endif
+
+#ifdef MSLANMAN
+extern bool	ms_lanman;	/* Use LanMan password instead of NT */
+				/* Has meaning only with MS-CHAP challenges */
+#endif
+
+extern char *current_option;	/* the name of the option being parsed */
+extern int  privileged_option;	/* set iff the current option came from root */
+extern char *option_source;	/* string saying where the option came from */
+
+/*
+ * Values for phase.
+ */
+#define PHASE_DEAD		0
+#define PHASE_INITIALIZE	1
+#define PHASE_SERIALCONN	2
+#define PHASE_DORMANT		3
+#define PHASE_ESTABLISH		4
+#define PHASE_AUTHENTICATE	5
+#define PHASE_CALLBACK		6
+#define PHASE_NETWORK		7
+#define PHASE_RUNNING		8
+#define PHASE_TERMINATE		9
+#define PHASE_DISCONNECT	10
+#define PHASE_HOLDOFF		11
+
+/*
+ * The following struct gives the addresses of procedures to call
+ * for a particular protocol.
+ */
+struct protent {
+    u_short protocol;		/* PPP protocol number */
+    /* Initialization procedure */
+    void (*init)(int unit);
+    /* Process a received packet */
+    void (*input)(int unit, u_char *pkt, int len);
+    /* Process a received protocol-reject */
+    void (*protrej)(int unit);
+    /* Lower layer has come up */
+    void (*lowerup)(int unit);
+    /* Lower layer has gone down */
+    void (*lowerdown)(int unit);
+    /* Open the protocol */
+    void (*open)(int unit);
+    /* Close the protocol */
+    void (*close)(int unit, char *reason);
+    /* Print a packet in readable form */
+    int  (*printpkt)(u_char *pkt, int len,
+			  void (*printer)(void *, char *, ...),
+			  void *arg);
+    /* Process a received data packet */
+    void (*datainput)(int unit, u_char *pkt, int len);
+    bool enabled_flag;		/* 0 iff protocol is disabled */
+    char *name;			/* Text name of protocol */
+    char *data_name;		/* Text name of corresponding data protocol */
+    option_t *options;		/* List of command-line options */
+    /* Check requested options, assign defaults */
+    void (*check_options)(void);
+    /* Configure interface for demand-dial */
+    int  (*demand_conf)(int unit);
+    /* Say whether to bring up link for this pkt */
+    int  (*active_pkt)(u_char *pkt, int len);
+};
+
+/* Table of pointers to supported protocols */
+extern struct protent *protocols[];
+
+/*
+ * Prototypes.
+ */
+
+/* Procedures exported from main.c. */
+void die(int);		/* Cleanup and exit */
+void quit(void);		/* like die(1) */
+void novm(char *);	/* Say we ran out of memory, and die */
+void ppptimeout(void (*func)(void *), void *arg, int t);
+				/* Call func(arg) after t seconds */
+void pppuntimeout(void (*func)(void *), void *arg);
+				/* Cancel call to func(arg) */
+void update_link_stats(int); /* Get stats at link termination */
+void new_phase(int);	/* signal start of new phase */
+
+/* Procedures exported from utils.c. */
+void log_packet(u_char *, int, char *, int);
+				/* Format a packet and log it with syslog */
+void print_string(void *, int,  void (*) (void *, char *, ...),
+		void *);	/* Format a string for output */
+int slprintf(char *, int, char *, ...);		/* sprintf++ */
+int vslprintf(char *, int, char *, va_list);	/* vsprintf++ */
+size_t strlcpy(char *, const char *, size_t);	/* safe strcpy */
+size_t strlcat(char *, const char *, size_t);	/* safe strncpy */
+void pppd_dbglog(char *, ...);	/* log a debug message */
+void pppd_info(char *, ...);	/* log an informational message */
+void pppd_notice(char *, ...);	/* log a notice-level message */
+void pppd_warn(char *, ...);	/* log a warning message */
+void pppd_error(char *, ...);	/* log an error message */
+void pppd_fatal(char *, ...);	/* log an error message and die(1) */
+
+#define dbglog pppd_dbglog
+#define info   pppd_info
+#define notice pppd_notice
+#define warn   pppd_warn
+#define error  pppd_error
+#define fatal  pppd_fatal
+
+/* Procedures exported from auth.c */
+void link_required(int);	  /* we are starting to use the link */
+void link_terminated(int);  /* we are finished with the link */
+void link_down(int);	  /* the LCP layer has left the Opened state */
+void link_established(int); /* the link is up; authenticate now */
+void start_networks(void);  /* start all the network control protos */
+void np_up(int, int);	  /* a network protocol has come up */
+void np_down(int, int);	  /* a network protocol has gone down */
+void np_finished(int, int); /* a network protocol no longer needs link */
+void auth_peer_fail(int, int);
+				/* peer failed to authenticate itself */
+void auth_peer_success(int, int, char *, int);
+				/* peer successfully authenticated itself */
+void auth_withpeer_fail(int, int);
+				/* we failed to authenticate ourselves */
+void auth_withpeer_success(int, int);
+				/* we successfully authenticated ourselves */
+int  auth_check_options(void);
+				/* check authentication options supplied */
+void auth_reset(int);	/* check what secrets we have */
+int  check_passwd(int, char *, int, char *, int, char **);
+				/* Check peer-supplied username/password */
+int  get_secret(int, char *, char *, unsigned char *, int *, int);
+				/* get "secret" for chap */
+int  auth_ip_addr(int, uint32_t);
+				/* check if IP address is authorized */
+int  bad_ip_adrs(uint32_t);
+				/* check if IP address is unreasonable */
+
+/* Procedures exported from demand.c */
+void demand_conf(void);	/* config interface(s) for demand-dial */
+void demand_block(void);	/* set all NPs to queue up packets */
+void demand_unblock(void); /* set all NPs to pass packets */
+void demand_discard(void); /* set all NPs to discard packets */
+void demand_rexmit(int);	/* retransmit saved frames for an NP */
+int  loop_chars(unsigned char *, int); /* process chars from loopback */
+int  loop_frame(unsigned char *, int); /* should we bring link up? */
+
+/* Procedures exported from sys-*.c */
+void sys_init(void);	/* Do system-dependent initialization */
+void sys_cleanup(void);	/* Restore system state before exiting */
+int  sys_check_options(void); /* Check options specified */
+void sys_close(void);	/* Clean up in a child before execing */
+int  ppp_available(void);	/* Test whether ppp kernel support exists */
+int  get_pty(int *, int *, char *, int);	/* Get pty master/slave */
+int  open_ppp_loopback(void); /* Open loopback for demand-dialling */
+int  establish_ppp(int);	/* Turn serial port into a ppp interface */
+void restore_loop(void);	/* Transfer ppp unit back to loopback */
+void disestablish_ppp(int); /* Restore port to normal operation */
+void clean_check(void);	/* Check if line was 8-bit clean */
+void set_up_tty(int, int); /* Set up port's speed, parameters, etc. */
+void restore_tty(int);	/* Restore port's original parameters */
+void setdtr(int, int);	/* Raise or lower port's DTR line */
+void output(int, u_char *, int); /* Output a PPP packet */
+void wait_input(struct timeval *); /* Wait for input, with timeout */
+
+void ppp_delay(void);       /* delay task for a little while */
+int  read_packet(u_char *); /* Read PPP packet */
+int  get_loop_output(void); /* Read pkts from loopback */
+void ppp_send_config(int, int, uint32_t, int, int);
+				/* Configure i/f transmit parameters */
+void ppp_set_xaccm(int, ext_accm);
+				/* Set extended transmit ACCM */
+void ppp_recv_config(int, int, uint32_t, int, int);
+				/* Configure i/f receive parameters */
+int  ccp_test(int, u_char *, int, int);
+				/* Test support for compression scheme */
+void ccp_flags_set(int, int, int);
+				/* Set kernel CCP state */
+int  ccp_fatal_error(int); /* Test for fatal decomp error in kernel */
+int  get_idle_time(int, struct ppp_idle *);
+				/* Find out how long link has been idle */
+int  get_ppp_stats(int, struct pppd_stats *);
+				/* Return link statistics */
+int  sifvjcomp(int, int, int, int);
+				/* Configure VJ TCP header compression */
+int  sifup(int);		/* Configure i/f up for one protocol */
+int  sifnpmode(int u, int proto, enum NPmode mode);
+				/* Set mode for handling packets for proto */
+int  sifdown(int);	/* Configure i/f down for one protocol */
+int  sifaddr(int, uint32_t, uint32_t, uint32_t);
+				/* Configure IPv4 addresses for i/f */
+int  cifaddr(int, uint32_t, uint32_t);
+				/* Reset i/f IP addresses */
+#ifdef INET6
+int  sif6addr(int, eui64_t, eui64_t);
+				/* Configure IPv6 addresses for i/f */
+int  cif6addr(int, eui64_t, eui64_t);
+				/* Remove an IPv6 address from i/f */
+#endif
+int  sifdefaultroute(int, uint32_t, uint32_t);
+				/* Create default route through i/f */
+int  cifdefaultroute(int, uint32_t, uint32_t);
+				/* Delete default route through i/f */
+int  sifproxyarp(int, uint32_t);
+				/* Add proxy ARP entry for peer */
+int  cifproxyarp(int, uint32_t);
+				/* Delete proxy ARP entry for peer */
+uint32_t GetMask(uint32_t); /* Get appropriate netmask for address */
+int  lock(char *);	/* Create lock file for device */
+int  relock(int);		/* Rewrite lock file with new pid */
+void unlock(void);	/* Delete previously-created lock file */
+void logwtmp(const char *, const char *, const char *);
+				/* Write entry to wtmp file */
+int  get_host_seed(void);	/* Get host-dependent random number seed */
+int  have_route_to(uint32_t); /* Check if route to addr exists */
+#ifdef PPP_FILTER
+int  set_filters(struct bpf_program *pass, struct bpf_program *active);
+				/* Set filter programs in kernel */
+#endif
+#ifdef IPX_CHANGE
+int  sipxfaddr(int, unsigned long, unsigned char *);
+int  cipxfaddr(int);
+#endif
+
+/* Procedures exported from options.c */
+int  parse_args(int argc, char **argv);
+				/* Parse options from arguments given */
+int  options_from_file(char *filename, int must_exist, int check_prot,
+			    int privileged);
+				/* Parse options from an options file */
+int  options_from_user(void); /* Parse options from user's .ppprc */
+int  options_for_tty(void); /* Parse options from /etc/ppp/options.tty */
+int  options_from_list(struct wordlist *, int privileged);
+				/* Parse options from a wordlist */
+int  getword(FILE *f, char *word, int *newlinep, char *filename);
+				/* Read a word from a file */
+void option_error(char *fmt, ...);
+				/* Print an error message about an option */
+int int_option(char *, int *);
+				/* Simplified number_option for decimal ints */
+void add_options(option_t *); /* Add extra options */
+
+/*
+ * This structure is used to store information about certain
+ * options, such as where the option value came from (/etc/ppp/options,
+ * command line, etc.) and whether it came from a privileged source.
+ */
+
+struct option_info {
+    int	    priv;		/* was value set by sysadmin? */
+    char    *source;		/* where option came from */
+};
+
+extern struct option_info devnam_info;
+extern struct option_info initializer_info;
+extern struct option_info connect_script_info;
+extern struct option_info disconnect_script_info;
+extern struct option_info welcomer_info;
+extern struct option_info ptycommand_info;
+
+/*
+ * Hooks to enable plugins to change various things.
+ */
+extern int (*new_phase_hook)(int);
+extern int (*idle_time_hook)(struct ppp_idle *);
+extern int (*holdoff_hook)(void);
+extern int (*pap_check_hook)(void);
+extern int (*pap_auth_hook)(char *user, char *passwd/*, char **msgp,
+				 struct wordlist **paddrs,
+				 struct wordlist **popts*/);
+extern void (*pap_logout_hook)(void);
+extern int (*pap_passwd_hook)(char *user, char *passwd);
+extern void (*ip_up_hook)(void);
+extern void (*ip_down_hook)(void);
+extern void (*auth_linkup_hook)(void);
+extern void (*auth_linkdown_hook)(void);
+
+/*
+ * Inline versions of get/put char/short/long.
+ * Pointer is advanced; we assume that both arguments
+ * are lvalues and will already be in registers.
+ * cp MUST be u_char *.
+ */
+#define GETCHAR(c, cp) { \
+	(c) = *(cp)++; \
+}
+#define PUTCHAR(c, cp) { \
+	*(cp)++ = (u_char) (c); \
+}
+
+
+#define GETSHORT(s, cp) { \
+	(s) = *(cp)++ << 8; \
+	(s) |= *(cp)++; \
+}
+#define PUTSHORT(s, cp) { \
+	*(cp)++ = (u_char) ((s) >> 8); \
+	*(cp)++ = (u_char) (s); \
+}
+
+#define GETLONG(l, cp) { \
+	(l) = *(cp)++ << 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; (l) <<= 8; \
+	(l) |= *(cp)++; \
+}
+#define PUTLONG(l, cp) { \
+	*(cp)++ = (u_char) ((l) >> 24); \
+	*(cp)++ = (u_char) ((l) >> 16); \
+	*(cp)++ = (u_char) ((l) >> 8); \
+	*(cp)++ = (u_char) (l); \
+}
+
+#define INCPTR(n, cp)	((cp) += (n))
+#define DECPTR(n, cp)	((cp) -= (n))
+
+/*
+ * System dependent definitions for user-level 4.3BSD UNIX implementation.
+ */
+
+#define TIMEOUT(r, f, t)	ppptimeout((r), (f), (t))
+#define UNTIMEOUT(r, f)	pppuntimeout((r), (f))
+
+#define BCOPY(s, d, l)		memcpy(d, s, l)
+#define BZERO(s, n)		memset(s, 0, n)
+
+#define PRINTMSG(m, l)		{ info("Remote message: %0.*v", l, m); }
+
+/*
+ * MAKEHEADER - Add Header fields to a packet.
+ */
+#define MAKEHEADER(p, t) { \
+    PUTCHAR(PPP_ALLSTATIONS, p); \
+    PUTCHAR(PPP_UI, p); \
+    PUTSHORT(t, p); }
+
+/*
+ * Exit status values.
+ */
+#define EXIT_OK			0
+#define EXIT_FATAL_ERROR	1
+#define EXIT_OPTION_ERROR	2
+#define EXIT_NOT_ROOT		3
+#define EXIT_NO_KERNEL_SUPPORT	4
+#define EXIT_USER_REQUEST	5
+#define EXIT_LOCK_FAILED	6
+#define EXIT_OPEN_FAILED	7
+#define EXIT_CONNECT_FAILED	8
+#define EXIT_PTYCMD_FAILED	9
+#define EXIT_NEGOTIATION_FAILED	10
+#define EXIT_PEER_AUTH_FAILED	11
+#define EXIT_IDLE_TIMEOUT	12
+#define EXIT_CONNECT_TIME	13
+#define EXIT_CALLBACK		14
+#define EXIT_PEER_DEAD		15
+#define EXIT_HANGUP		16
+#define EXIT_LOOPBACK		17
+#define EXIT_INIT_FAILED	18
+#define EXIT_AUTH_TOPEER_FAILED	19
+
+/*
+ * Debug macros.  Slightly useful for finding bugs in pppd, not particularly
+ * useful for finding out why your connection isn't being established.
+ */
+
+#ifdef DEBUGALL
+#define DEBUGMAIN	1
+#define DEBUGFSM	1
+#define DEBUGLCP	1
+#define DEBUGIPCP	1
+#define DEBUGIPV6CP	1
+#define DEBUGUPAP	1
+#define DEBUGCHAP	1
+#endif
+#define DEBUGMAIN	1
+#define DEBUGUPAP	1
+#define DEBUGCHAP	1
+
+
+#ifdef DEBUGMAIN
+#define MAINDEBUG(x)	if (debug) dbglog x
+#else
+#define MAINDEBUG(x)
+#endif
+
+#ifdef DEBUGSYS
+#define SYSDEBUG(x)	if (debug) dbglog x
+#else
+#define SYSDEBUG(x)
+#endif
+
+#ifdef DEBUGFSM
+#define FSMDEBUG(x)	if (debug) dbglog x
+#else
+#define FSMDEBUG(x)
+#endif
+
+#ifdef DEBUGLCP
+#define LCPDEBUG(x)	if (debug) dbglog x
+#else
+#define LCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPCP
+#define IPCPDEBUG(x)	if (debug) dbglog x
+#else
+#define IPCPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPV6CP
+#define IPV6CPDEBUG(x)  if (debug) dbglog x
+#else
+#define IPV6CPDEBUG(x)
+#endif
+
+#ifdef DEBUGUPAP
+#define UPAPDEBUG(x)	if (debug) dbglog x
+#else
+#define UPAPDEBUG(x)
+#endif
+
+#ifdef DEBUGCHAP
+#define CHAPDEBUG(x)	if (debug) dbglog x
+#else
+#define CHAPDEBUG(x)
+#endif
+
+#ifdef DEBUGIPXCP
+#define IPXCPDEBUG(x)	if (debug) dbglog x
+#else
+#define IPXCPDEBUG(x)
+#endif
+
+#ifndef SIGTYPE
+#if defined(sun) || defined(SYSV) || defined(POSIX_SOURCE)
+#define SIGTYPE void
+#else
+#define SIGTYPE int
+#endif /* defined(sun) || defined(SYSV) || defined(POSIX_SOURCE) */
+#endif /* SIGTYPE */
+
+#ifndef MIN
+#define MIN(a, b)	((a) < (b)? (a): (b))
+#endif
+#ifndef MAX
+#define MAX(a, b)	((a) > (b)? (a): (b))
+#endif
+
+#endif /* __PPP_H__ */
diff --git a/rtemsbsd/pppd/rtemsmain.c b/rtemsbsd/pppd/rtemsmain.c
new file mode 100644
index 0000000..89ed776
--- /dev/null
+++ b/rtemsbsd/pppd/rtemsmain.c
@@ -0,0 +1,896 @@
+/*
+ * main.c - Point-to-Point Protocol main module
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+
+#include "pppd.h"
+#include "magic.h"
+#include "fsm.h"
+#include "lcp.h"
+#include "ipcp.h"
+#ifdef INET6
+#include "ipv6cp.h"
+#endif
+#include "upap.h"
+#include "chap.h"
+#include "ccp.h"
+#include "pathnames.h"
+#include "patchlevel.h"
+#include "rtemsdialer.h"
+
+#ifdef CBCP_SUPPORT
+#include "cbcp.h"
+#endif
+
+#ifdef IPX_CHANGE
+#include "ipxcp.h"
+#endif /* IPX_CHANGE */
+#ifdef AT_CHANGE
+#include "atcp.h"
+#endif
+
+static const char rcsid[] = RCSID;
+
+/* interface vars */
+char ifname[32];		/* Interface name */
+int pppifunit;			/* Interface unit number */
+
+char hostname[MAXNAMELEN];	/* Our hostname */
+static char ppp_devnam[MAXPATHLEN]; /* name of PPP tty (maybe ttypx) */
+
+int pppd_ttyfd;			/* Serial port file descriptor */
+int baud_rate;			/* Actual bits/second for serial device */
+int hungup;			/* terminal has been hung up */
+int privileged;			/* we're running as real uid root */
+int need_holdoff;		/* need holdoff period before restarting */
+int detached;			/* have detached from terminal */
+struct stat devstat;		/* result of stat() on devnam */
+int prepass = 0;		/* doing prepass to find device name */
+int devnam_fixed;		/* set while in options.ttyxx file */
+volatile int pppd_status;		/* exit status for pppd */
+int unsuccess;			/* # unsuccessful connection attempts */
+int do_callback;		/* != 0 if we should do callback next */
+int doing_callback;		/* != 0 if we are doing callback */
+char *callback_script;		/* script for doing callback */
+dialerfp pppd_dialer;
+
+int (*holdoff_hook)(void) = NULL;
+int (*new_phase_hook)(int) = NULL;
+
+static int fd_ppp = -1;		/* fd for talking PPP */
+static int pty_master;		/* fd for master side of pty */
+static int pty_slave;		/* fd for slave side of pty */
+static int real_ttyfd;		/* fd for actual serial port (not pty) */
+
+int pppd_phase;			/* where the link is at */
+int pppd_kill_link;
+int open_ccp_flag;
+
+char **script_env;		/* Env. variable values for scripts */
+int s_env_nalloc;		/* # words avail at script_env */
+
+u_char outpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for outgoing packet */
+u_char inpacket_buf[PPP_MRU+PPP_HDRLEN]; /* buffer for incoming packet */
+
+char *no_ppp_msg = "Sorry - this system lacks PPP kernel support\n";
+
+static struct timeval start_time;	/* Time when link was started. */
+
+struct pppd_stats link_stats;
+int link_connect_time;
+int link_stats_valid;
+
+/* Prototypes for procedures local to this file. */
+
+static void cleanup(void);
+static void close_tty(void);
+static void get_input(void);
+static void calltimeout(void);
+static struct timeval *timeleft(struct timeval *);
+static void holdoff_end(void *);
+static int device_script(int, int, char *);
+
+extern	char	*ttyname(int);
+extern	char	*getlogin(void);
+int pppdmain(int, char *[]);
+
+/*
+ * PPP Data Link Layer "protocol" table.
+ * One entry per supported protocol.
+ * The last entry must be NULL.
+ */
+struct protent *protocols[] = {
+    &lcp_protent,
+    &pap_protent,
+    &chap_protent,
+#ifdef CBCP_SUPPORT
+    &cbcp_protent,
+#endif
+    &ipcp_protent,
+#ifdef INET6
+    &ipv6cp_protent,
+#endif
+    &ccp_protent,
+#ifdef IPX_CHANGE
+    &ipxcp_protent,
+#endif
+#ifdef AT_CHANGE
+    &atcp_protent,
+#endif
+    NULL
+};
+
+int
+pppdmain(
+    int argc,
+    char *argv[])
+{
+    int i, fdflags, t;
+    char *connector;
+    struct timeval timo;
+    struct protent *protp;
+
+    new_phase(PHASE_INITIALIZE);
+
+    script_env = NULL;
+    hostname[MAXNAMELEN-1] = 0;
+    privileged = 1;
+    privileged_option = 1;
+
+    /*
+     * Initialize magic number generator now so that protocols may
+     * use magic numbers in initialization.
+     */
+    magic_init();
+
+#ifdef XXX_XXX
+    /* moved code the the rtems_pppd_reset_options function */
+
+    /*
+     * Initialize to the standard option set, then parse, in order,
+     * the system options file, the user's options file,
+     * the tty's options file, and the command line arguments.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        (*protp->init)(0);
+#endif
+
+
+    if (!ppp_available()) {
+	option_error(no_ppp_msg);
+	return(EXIT_NO_KERNEL_SUPPORT);
+    }
+
+    /*
+     * Check that the options given are valid and consistent.
+     */
+    if (!sys_check_options()) {
+	return(EXIT_OPTION_ERROR);
+    }
+    if (!auth_check_options()) {
+	return(EXIT_OPTION_ERROR);
+    }
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->check_options != NULL)
+	    (*protp->check_options)();
+
+    /* default holdoff to 0 if no connect script has been given */
+    if (connect_script == 0 && !holdoff_specified)
+	holdoff = 0;
+
+    if (default_device)
+	nodetach = 1;
+
+    /*
+     * Initialize system-dependent stuff.
+     */
+    sys_init();
+    /* if (debug)
+	setlogmask(LOG_UPTO(LOG_DEBUG));
+    */
+
+    do_callback = 0;
+    for (;;) {
+
+	need_holdoff = 1;
+	pppd_ttyfd = -1;
+	real_ttyfd = -1;
+	pppd_status = EXIT_OK;
+	++unsuccess;
+	doing_callback = do_callback;
+	do_callback = 0;
+
+	new_phase(PHASE_SERIALCONN);
+
+	/*
+	 * Get a pty master/slave pair if the pty, notty, or record
+	 * options were specified.
+	 */
+	strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));
+	pty_master = -1;
+	pty_slave = -1;
+
+	/*
+	 * Open the serial device and set it up to be the ppp interface.
+	 * First we open it in non-blocking mode so we can set the
+	 * various termios flags appropriately.  If we aren't dialling
+	 * out and we want to use the modem lines, we reopen it later
+	 * in order to wait for the carrier detect signal from the modem.
+	 */
+	hungup = 0;
+	pppd_kill_link = 0;
+	connector = doing_callback? callback_script: connect_script;
+	if (devnam[0] != 0) {
+	    for (;;) {
+		/* If the user specified the device name, become the
+		   user before opening it. */
+		int err;
+		pppd_ttyfd = open(devnam, O_NONBLOCK | O_RDWR, 0);
+		err = errno;
+		if (pppd_ttyfd >= 0) {
+		    break;
+		}
+		errno = err;
+		if (err != EINTR) {
+		    error("Failed to open %s: %m", devnam);
+		    pppd_status = EXIT_OPEN_FAILED;
+		}
+		if (!persist || err != EINTR)
+		    goto fail;
+	    }
+	    if ((fdflags = fcntl(pppd_ttyfd, F_GETFL)) == -1
+		|| fcntl(pppd_ttyfd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
+		warn("Couldn't reset non-blocking mode on device: %m");
+
+	    /*
+	     * Set line speed, flow control, etc.
+	     * If we have a non-null connection or initializer script,
+	     * on most systems we set CLOCAL for now so that we can talk
+	     * to the modem before carrier comes up.  But this has the
+	     * side effect that we might miss it if CD drops before we
+	     * get to clear CLOCAL below.  On systems where we can talk
+	     * successfully to the modem with CLOCAL clear and CD down,
+	     * we could clear CLOCAL at this point.
+	     */
+	    set_up_tty(pppd_ttyfd, ((connector != NULL && connector[0] != 0)
+			       || initializer != NULL));
+	    real_ttyfd = pppd_ttyfd;
+	}
+
+	/* run connection script */
+	if ((connector && connector[0]) || initializer) {
+	    if (real_ttyfd != -1) {
+		/* XXX do this if doing_callback == CALLBACK_DIALIN? */
+		if (!default_device && modem) {
+		    setdtr(real_ttyfd, 0);	/* in case modem is off hook */
+		    sleep(1);
+		    setdtr(real_ttyfd, 1);
+		}
+	    }
+
+	    if (initializer && initializer[0]) {
+		if (device_script(pppd_ttyfd, DIALER_INIT, initializer) < 0) {
+		    error("Initializer script failed");
+		    pppd_status = EXIT_INIT_FAILED;
+		    goto fail;
+		}
+		if (pppd_kill_link)
+		    goto disconnect;
+
+		info("Serial port initialized.");
+	    }
+
+	    if (connector && connector[0]) {
+		if (device_script(pppd_ttyfd, DIALER_CONNECT, connector) < 0) {
+		    error("Connect script failed");
+		    pppd_status = EXIT_CONNECT_FAILED;
+		    goto fail;
+		}
+		if (pppd_kill_link)
+		    goto disconnect;
+
+		info("Serial connection established.");
+	    }
+
+	    /* set line speed, flow control, etc.;
+	       clear CLOCAL if modem option */
+	    if (real_ttyfd != -1)
+		set_up_tty(real_ttyfd, 0);
+
+	    if (doing_callback == CALLBACK_DIALIN)
+		connector = NULL;
+	}
+
+	/* reopen tty if necessary to wait for carrier */
+	if (connector == NULL && modem && devnam[0] != 0) {
+	    for (;;) {
+		if ((i = open(devnam, O_RDWR)) >= 0)
+		    break;
+		if (errno != EINTR) {
+		    error("Failed to reopen %s: %m", devnam);
+		    pppd_status = EXIT_OPEN_FAILED;
+		}
+		if (!persist || errno != EINTR || hungup || pppd_kill_link)
+		    goto fail;
+	    }
+	    close(i);
+	}
+
+        info("Serial connection established.");
+        sleep(1);
+
+	/* run welcome script, if any */
+	if (welcomer && welcomer[0]) {
+	    if (device_script(pppd_ttyfd, DIALER_WELCOME, welcomer) < 0)
+		warn("Welcome script failed");
+	}
+
+	/* set up the serial device as a ppp interface */
+	fd_ppp = establish_ppp(pppd_ttyfd);
+	if (fd_ppp < 0) {
+	    pppd_status = EXIT_FATAL_ERROR;
+	    goto disconnect;
+	}
+
+	if (!demand) {
+	    info("Using interface ppp%d", pppifunit);
+	    slprintf(ifname, sizeof(ifname), "ppp%d", pppifunit);
+	}
+
+	/*
+	 * Start opening the connection and wait for
+	 * incoming events (reply, timeout, etc.).
+	 */
+	notice("Connect: %s <--> %s", ifname, ppp_devnam);
+	gettimeofday(&start_time, NULL);
+
+	lcp_lowerup(0);
+	lcp_open(0);		/* Start protocol */
+
+	open_ccp_flag = 0;
+	pppd_status = EXIT_NEGOTIATION_FAILED;
+	new_phase(PHASE_ESTABLISH);
+	while (pppd_phase != PHASE_DEAD) {
+   	    wait_input(timeleft(&timo));
+	    calltimeout();
+            get_input();
+
+	    if (pppd_kill_link) {
+		lcp_close(0, "User request");
+		pppd_kill_link = 0;
+	    }
+	    if (open_ccp_flag) {
+		if (pppd_phase == PHASE_NETWORK || pppd_phase == PHASE_RUNNING) {
+		    ccp_fsm[0].flags = OPT_RESTART; /* clears OPT_SILENT */
+		    (*ccp_protent.open)(0);
+		}
+		open_ccp_flag = 0;
+	    }
+	}
+
+	/*
+	 * If we may want to bring the link up again, transfer
+	 * the ppp unit back to the loopback.  Set the
+	 * real serial device back to its normal mode of operation.
+	 */
+	clean_check();
+	if (demand)
+	    restore_loop();
+	disestablish_ppp(pppd_ttyfd);
+	fd_ppp = -1;
+	if (!hungup)
+	    lcp_lowerdown(0);
+
+	/*
+	 * Run disconnector script, if requested.
+	 * XXX we may not be able to do this if the line has hung up!
+	 */
+    disconnect:
+	if (disconnect_script && !hungup) {
+	    new_phase(PHASE_DISCONNECT);
+	    if (real_ttyfd >= 0)
+		set_up_tty(real_ttyfd, 1);
+	    if (device_script(pppd_ttyfd, DIALER_DISCONNECT, disconnect_script) < 0) {
+		warn("disconnect script failed");
+	    } else {
+		info("Serial link disconnected.");
+	    }
+	}
+
+    fail:
+	if (pty_master >= 0)
+	    close(pty_master);
+	if (pty_slave >= 0)
+	    close(pty_slave);
+	if (real_ttyfd >= 0)
+	    close_tty();
+
+	if (!persist || (maxfail > 0 && unsuccess >= maxfail))
+	    break;
+
+	pppd_kill_link = 0;
+	if (demand)
+	    demand_discard();
+	t = need_holdoff? holdoff: 0;
+	if (holdoff_hook)
+	    t = (*holdoff_hook)();
+	if (t > 0) {
+	    new_phase(PHASE_HOLDOFF);
+	    TIMEOUT(holdoff_end, NULL, t);
+	    do {
+   	        wait_input(timeleft(&timo));
+
+		calltimeout();
+		if (pppd_kill_link) {
+		    pppd_kill_link = 0;
+		    new_phase(PHASE_DORMANT); /* allow signal to end holdoff */
+		}
+	    } while (pppd_phase == PHASE_HOLDOFF);
+	    if (!persist)
+		break;
+	}
+    }
+
+    die(pppd_status);
+    return pppd_status;
+}
+
+/*
+ * holdoff_end - called via a timeout when the holdoff period ends.
+ */
+static void
+holdoff_end(
+    void *arg)
+{
+    new_phase(PHASE_DORMANT);
+}
+
+/* List of protocol names, to make our messages a little more informative. */
+struct protocol_list {
+    u_short	proto;
+    const char	*name;
+} protocol_list[] = {
+    { 0x21,	"IP" },
+    { 0x23,	"OSI Network Layer" },
+    { 0x25,	"Xerox NS IDP" },
+    { 0x27,	"DECnet Phase IV" },
+    { 0x29,	"Appletalk" },
+    { 0x2b,	"Novell IPX" },
+    { 0x2d,	"VJ compressed TCP/IP" },
+    { 0x2f,	"VJ uncompressed TCP/IP" },
+    { 0x31,	"Bridging PDU" },
+    { 0x33,	"Stream Protocol ST-II" },
+    { 0x35,	"Banyan Vines" },
+    { 0x39,	"AppleTalk EDDP" },
+    { 0x3b,	"AppleTalk SmartBuffered" },
+    { 0x3d,	"Multi-Link" },
+    { 0x3f,	"NETBIOS Framing" },
+    { 0x41,	"Cisco Systems" },
+    { 0x43,	"Ascom Timeplex" },
+    { 0x45,	"Fujitsu Link Backup and Load Balancing (LBLB)" },
+    { 0x47,	"DCA Remote Lan" },
+    { 0x49,	"Serial Data Transport Protocol (PPP-SDTP)" },
+    { 0x4b,	"SNA over 802.2" },
+    { 0x4d,	"SNA" },
+    { 0x4f,	"IP6 Header Compression" },
+    { 0x6f,	"Stampede Bridging" },
+    { 0xfb,	"single-link compression" },
+    { 0xfd,	"1st choice compression" },
+    { 0x0201,	"802.1d Hello Packets" },
+    { 0x0203,	"IBM Source Routing BPDU" },
+    { 0x0205,	"DEC LANBridge100 Spanning Tree" },
+    { 0x0231,	"Luxcom" },
+    { 0x0233,	"Sigma Network Systems" },
+    { 0x8021,	"Internet Protocol Control Protocol" },
+    { 0x8023,	"OSI Network Layer Control Protocol" },
+    { 0x8025,	"Xerox NS IDP Control Protocol" },
+    { 0x8027,	"DECnet Phase IV Control Protocol" },
+    { 0x8029,	"Appletalk Control Protocol" },
+    { 0x802b,	"Novell IPX Control Protocol" },
+    { 0x8031,	"Bridging NCP" },
+    { 0x8033,	"Stream Protocol Control Protocol" },
+    { 0x8035,	"Banyan Vines Control Protocol" },
+    { 0x803d,	"Multi-Link Control Protocol" },
+    { 0x803f,	"NETBIOS Framing Control Protocol" },
+    { 0x8041,	"Cisco Systems Control Protocol" },
+    { 0x8043,	"Ascom Timeplex" },
+    { 0x8045,	"Fujitsu LBLB Control Protocol" },
+    { 0x8047,	"DCA Remote Lan Network Control Protocol (RLNCP)" },
+    { 0x8049,	"Serial Data Control Protocol (PPP-SDCP)" },
+    { 0x804b,	"SNA over 802.2 Control Protocol" },
+    { 0x804d,	"SNA Control Protocol" },
+    { 0x804f,	"IP6 Header Compression Control Protocol" },
+    { 0x006f,	"Stampede Bridging Control Protocol" },
+    { 0x80fb,	"Single Link Compression Control Protocol" },
+    { 0x80fd,	"Compression Control Protocol" },
+    { 0xc021,	"Link Control Protocol" },
+    { 0xc023,	"Password Authentication Protocol" },
+    { 0xc025,	"Link Quality Report" },
+    { 0xc027,	"Shiva Password Authentication Protocol" },
+    { 0xc029,	"CallBack Control Protocol (CBCP)" },
+    { 0xc081,	"Container Control Protocol" },
+    { 0xc223,	"Challenge Handshake Authentication Protocol" },
+    { 0xc281,	"Proprietary Authentication Protocol" },
+    { 0,	NULL },
+};
+
+/*
+ * protocol_name - find a name for a PPP protocol.
+ */
+const char *
+protocol_name(
+    int proto)
+{
+    struct protocol_list *lp;
+
+    for (lp = protocol_list; lp->proto != 0; ++lp)
+	if (proto == lp->proto)
+	    return lp->name;
+    return NULL;
+}
+
+/*
+ * get_input - called when incoming data is available.
+ */
+static void
+get_input(void)
+{
+    int len, i;
+    u_char *p;
+    u_short protocol;
+    struct protent *protp;
+
+    p = inpacket_buf;	/* point to beginning of packet buffer */
+
+    len = read_packet(inpacket_buf);
+    if (len < 0)
+	return;
+
+    if (len == 0) {
+	notice("Modem hangup");
+	hungup = 1;
+	pppd_status = EXIT_HANGUP;
+	lcp_lowerdown(0);	/* serial link is no longer available */
+	link_terminated(0);
+	return;
+    }
+
+    if (debug /*&& (debugflags & DBG_INPACKET)*/)
+	dbglog("rcvd %P", p, len);
+
+    if (len < PPP_HDRLEN) {
+	MAINDEBUG(("io(): Received short packet."));
+	return;
+    }
+
+    p += 2;				/* Skip address and control */
+    GETSHORT(protocol, p);
+    len -= PPP_HDRLEN;
+
+    /*
+     * Toss all non-LCP packets unless LCP is OPEN.
+     */
+    if (protocol != PPP_LCP && lcp_fsm[0].state != OPENED) {
+	MAINDEBUG(("get_input: Received non-LCP packet when LCP not open."));
+	return;
+    }
+
+    /*
+     * Until we get past the authentication phase, toss all packets
+     * except LCP, LQR and authentication packets.
+     */
+    if (pppd_phase <= PHASE_AUTHENTICATE
+	&& !(protocol == PPP_LCP || protocol == PPP_LQR
+	     || protocol == PPP_PAP || protocol == PPP_CHAP)) {
+	MAINDEBUG(("get_input: discarding proto 0x%x in phase %d",
+		   protocol, pppd_phase));
+	return;
+    }
+
+    /*
+     * Upcall the proper protocol input routine.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol == protocol && protp->enabled_flag) {
+	    (*protp->input)(0, p, len);
+	    return;
+	}
+        if (protocol == (protp->protocol & ~0x8000) && protp->enabled_flag
+	    && protp->datainput != NULL) {
+	    (*protp->datainput)(0, p, len);
+	    return;
+	}
+    }
+
+    if (debug) {
+	const char *pname = protocol_name(protocol);
+	if (pname != NULL)
+	    warn("Unsupported protocol '%s' (0x%x) received", pname, protocol);
+	else
+	    warn("Unsupported protocol 0x%x received", protocol);
+    }
+    lcp_sprotrej(0, p - PPP_HDRLEN, len + PPP_HDRLEN);
+
+    return;
+}
+
+/*
+ * new_phase - signal the start of a new phase of pppd's operation.
+ */
+void
+new_phase(
+    int p)
+{
+    pppd_phase = p;
+    if (new_phase_hook)
+	(*new_phase_hook)(p);
+}
+
+/*
+ * die - clean up state and exit with the specified status.
+ */
+void
+die(
+    int status)
+{
+    cleanup();
+}
+
+/*
+ * cleanup - restore anything which needs to be restored before we exit
+ */
+/* ARGSUSED */
+static void
+cleanup(void)
+{
+    sys_cleanup();
+
+    if (fd_ppp >= 0)
+	disestablish_ppp(pppd_ttyfd);
+    if (real_ttyfd >= 0)
+	close_tty();
+
+    sys_close();
+}
+
+/*
+ * close_tty - restore the terminal device and close it.
+ */
+static void
+close_tty(void)
+{
+    /* drop dtr to hang up */
+    if (!default_device && modem) {
+	setdtr(real_ttyfd, 0);
+	/*
+	 * This sleep is in case the serial port has CLOCAL set by default,
+	 * and consequently will reassert DTR when we close the device.
+	 */
+	sleep(1);
+    }
+
+    restore_tty(real_ttyfd);
+
+    close(real_ttyfd);
+    real_ttyfd = -1;
+}
+
+/*
+ * update_link_stats - get stats at link termination.
+ */
+void
+update_link_stats(
+    int u)
+{
+    struct timeval now;
+    char numbuf[32];
+
+    if (!get_ppp_stats(u, &link_stats)
+	|| gettimeofday(&now, NULL) < 0)
+	return;
+    link_connect_time = now.tv_sec - start_time.tv_sec;
+    link_stats_valid = 1;
+
+    slprintf(numbuf, sizeof(numbuf), "%d", link_connect_time);
+    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_out);
+    slprintf(numbuf, sizeof(numbuf), "%d", link_stats.bytes_in);
+}
+
+struct	callout {
+    struct timeval	c_time;		/* time at which to call routine */
+    void		*c_arg;		/* argument to routine */
+    void		(*c_func)(void *); /* routine */
+    struct		callout *c_next;
+};
+
+static struct callout *callout = NULL;	/* Callout list */
+static struct timeval timenow;		/* Current time */
+
+/*
+ * timeout - Schedule a timeout.
+ *
+ * Note that this timeout takes the number of seconds, NOT hz (as in
+ * the kernel).
+ */
+void
+ppptimeout(
+    void (*func)(void *),
+    void *arg,
+    int time)
+{
+    struct callout *newp, *p, **pp;
+
+    MAINDEBUG(("Timeout %p:%p in %d seconds.", func, arg, time));
+
+    /*
+     * Allocate timeout.
+     */
+    if ((newp = (struct callout *) malloc(sizeof(struct callout))) == NULL)
+	fatal("Out of memory in timeout()!");
+    newp->c_arg = arg;
+    newp->c_func = func;
+    gettimeofday(&timenow, NULL);
+    newp->c_time.tv_sec = timenow.tv_sec + time;
+    newp->c_time.tv_usec = timenow.tv_usec;
+
+    /*
+     * Find correct place and link it in.
+     */
+    for (pp = &callout; (p = *pp); pp = &p->c_next)
+	if (newp->c_time.tv_sec < p->c_time.tv_sec
+	    || (newp->c_time.tv_sec == p->c_time.tv_sec
+		&& newp->c_time.tv_usec < p->c_time.tv_usec))
+	    break;
+    newp->c_next = p;
+    *pp = newp;
+}
+
+
+/*
+ * untimeout - Unschedule a timeout.
+ */
+void
+pppuntimeout(
+    void (*func)(void *),
+    void *arg)
+{
+    struct callout **copp, *freep;
+
+    MAINDEBUG(("Untimeout %p:%p.", func, arg));
+
+    /*
+     * Find first matching timeout and remove it from the list.
+     */
+    for (copp = &callout; (freep = *copp); copp = &freep->c_next)
+	if (freep->c_func == func && freep->c_arg == arg) {
+	    *copp = freep->c_next;
+	    free((char *) freep);
+	    break;
+	}
+}
+
+
+/*
+ * calltimeout - Call any timeout routines which are now due.
+ */
+static void
+calltimeout(void)
+{
+    struct callout *p;
+
+    while (callout != NULL) {
+	p = callout;
+
+	if (gettimeofday(&timenow, NULL) < 0)
+	    fatal("Failed to get time of day: %m");
+	if (!(p->c_time.tv_sec < timenow.tv_sec
+	      || (p->c_time.tv_sec == timenow.tv_sec
+		  && p->c_time.tv_usec <= timenow.tv_usec)))
+	    break;		/* no, it's not time yet */
+
+	callout = p->c_next;
+	(*p->c_func)(p->c_arg);
+
+	free((char *) p);
+    }
+}
+
+
+/*
+ * timeleft - return the length of time until the next timeout is due.
+ */
+static struct timeval *
+timeleft(
+    struct timeval *tvp)
+{
+    if (callout == NULL)
+	return NULL;
+
+    gettimeofday(&timenow, NULL);
+    tvp->tv_sec = callout->c_time.tv_sec - timenow.tv_sec;
+    tvp->tv_usec = callout->c_time.tv_usec - timenow.tv_usec;
+    if (tvp->tv_usec < 0) {
+	tvp->tv_usec += 1000000;
+	tvp->tv_sec -= 1;
+    }
+    if (tvp->tv_sec < 0)
+	tvp->tv_sec = tvp->tv_usec = 0;
+
+    return tvp;
+}
+
+/*
+ * device_script - run a program to talk to the serial device
+ * (e.g. to run the connector or disconnector script).
+ */
+static int device_script(int fd, int mode, char *program)
+{
+    int    iReturn = -1;
+    char   pScript[128];
+
+    /* copyt script into temporary location */
+    strcpy(pScript, program);
+
+    /* check to see if dialer was initialized */
+    if ( !pppd_dialer ) {
+      /* set default dialer to chatmain */
+      pppd_dialer = chatmain;
+    }
+
+    /* check to see if dialer is set */
+    if ( pppd_dialer ) {
+      /* call the dialer */
+      iReturn = (*pppd_dialer)(fd, mode, program);
+    }
+
+    return ( -iReturn );
+}
+
+/*
+ * novm - log an error message saying we ran out of memory, and die.
+ */
+void
+novm(
+    char *msg)
+{
+    fatal("Virtual memory exhausted allocating %s\n", msg);
+}
diff --git a/rtemsbsd/pppd/rtemspppd.c b/rtemsbsd/pppd/rtemspppd.c
new file mode 100644
index 0000000..64e4284
--- /dev/null
+++ b/rtemsbsd/pppd/rtemspppd.c
@@ -0,0 +1,228 @@
+/*
+ * COPYRIGHT (c) 2001, Michael Siers <mikes at poliac.com>.
+ *                     Poliac Research, Burnsville, Minnesota USA.
+ * COPYRIGHT (c) 2001, On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ *
+ *  $Id$
+ */
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include "pppd.h"
+#include "rtemspppd.h"
+
+
+/* define pppd function prototypes */
+extern void pppasyncattach(void);
+extern int  pppdmain(int, char **);
+
+/* define global variables */
+rtems_id                   rtems_pppd_taskid;
+rtems_pppd_hookfunction    rtems_pppd_errorfp;
+rtems_pppd_hookfunction    rtems_pppd_exitfp;
+
+
+static rtems_task pppTask(rtems_task_argument arg)
+{
+  rtems_status_code   sc = RTEMS_SUCCESSFUL;
+  rtems_option        options;
+  rtems_event_set     in;
+  rtems_event_set     out;
+  int                 iStatus;
+
+  /* call function to setup ppp line discipline */
+  pppasyncattach();
+
+  /* enter processing loop */
+  in      = (RTEMS_EVENT_29 | RTEMS_EVENT_30);
+  options = (RTEMS_EVENT_ANY | RTEMS_WAIT);
+  while ( sc == RTEMS_SUCCESSFUL ) {
+    /* wait for the next event */
+    sc = rtems_event_receive(in, options, RTEMS_NO_TIMEOUT, &out);
+    if ( sc == RTEMS_SUCCESSFUL ) {
+      /* determine which event was sent */
+      if ( out & RTEMS_EVENT_29 ) {
+        /* terminate event received */
+        /* set value to break out of event loop */
+        sc = RTEMS_UNSATISFIED;
+      }
+      else if ( out & RTEMS_EVENT_30 ) {
+        /* connect request */
+        /* execute the pppd main code */
+        iStatus = pppdmain(0, NULL);
+        if ( iStatus == EXIT_OK ) {
+          /* check exit callback */
+          if ( rtems_pppd_exitfp ) {
+            (*rtems_pppd_exitfp)();
+          }
+        }
+        else {
+          /* check error callback */
+          if ( rtems_pppd_errorfp ) {
+            (*rtems_pppd_errorfp)();
+          }
+        }
+      }
+    }
+  }
+
+  /* terminate myself */
+  rtems_pppd_taskid = 0;
+  rtems_task_delete(RTEMS_SELF);
+}
+
+int rtems_pppd_initialize(void)
+{
+  int                 iReturn  = (int)-1;
+  rtems_task_priority priority = 100;
+  rtems_status_code   status;
+  rtems_name          taskName;
+
+  /* determine priority value */
+  if ( rtems_bsdnet_config.network_task_priority ) {
+    priority = rtems_bsdnet_config.network_task_priority;
+  }
+
+  /* initialize the exit hook */
+  rtems_pppd_exitfp = (rtems_pppd_hookfunction)0;
+
+  /* create the rtems task */
+  taskName = rtems_build_name( 'p', 'p', 'p', 'd' );
+  status   = rtems_task_create(taskName, priority, 8192,
+                               (RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0)),
+                               RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+                               &rtems_pppd_taskid);
+  if ( status == RTEMS_SUCCESSFUL ) {
+    status = rtems_task_start(rtems_pppd_taskid, pppTask, 0);
+    if ( status == RTEMS_SUCCESSFUL ) {
+      iReturn = rtems_pppd_reset_options();
+    }
+  }
+
+  return ( iReturn );
+}
+
+int rtems_pppd_terminate(void)
+{
+  /* send terminate signal to pppd task */
+  rtems_event_send(rtems_pppd_taskid, RTEMS_EVENT_29);
+
+  /* call the disconnect function */
+  rtems_pppd_disconnect();
+
+  return ( 0 );
+}
+
+int rtems_pppd_reset_options(void)
+{
+    int i;
+    struct protent *protp;
+
+    /*
+     * Initialize to the standard option set, then parse, in order,
+     * the system options file, the user's options file,
+     * the tty's options file, and the command line arguments.
+     */
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+        (*protp->init)(0);
+
+  return ( 0 );
+}
+
+int rtems_pppd_set_hook(int id, rtems_pppd_hookfunction hookfp)
+{
+  int     iReturn = (int)0;
+
+  switch ( id ) {
+  case RTEMS_PPPD_LINKUP_HOOK:
+    auth_linkup_hook = hookfp;
+    break;
+  case RTEMS_PPPD_LINKDOWN_HOOK:
+    auth_linkdown_hook = hookfp;
+    break;
+  case RTEMS_PPPD_IPUP_HOOK:
+    ip_up_hook = hookfp;
+    break;
+  case RTEMS_PPPD_IPDOWN_HOOK:
+    ip_down_hook = hookfp;
+    break;
+  case RTEMS_PPPD_ERROR_HOOK:
+    rtems_pppd_errorfp = hookfp;
+    break;
+  case RTEMS_PPPD_EXIT_HOOK:
+    rtems_pppd_exitfp = hookfp;
+    break;
+  default:
+    iReturn = (int)-1;
+    break;
+  }
+
+  return ( iReturn );
+}
+
+int rtems_pppd_set_dialer(rtems_pppd_dialerfunction dialerfp)
+{
+  pppd_dialer = dialerfp;
+  return ( (int)0 );
+}
+
+int rtems_pppd_set_option(const char *pOption, const char *pValue)
+{
+  int                iReturn = (int)0;
+  int                prevPhase;
+  struct wordlist    option;
+  struct wordlist    value;
+
+  if ( pOption != (const char *)0 ) {
+    /* initialize the values */
+    option.word = (char *)pOption;
+    option.next = (struct wordlist *)0;
+    if ( pValue != (const char *)0 ) {
+      option.next = &value;
+      value.word  = (char *)pValue;
+      value.next  = (struct wordlist *)0;
+    }
+
+    /* save current phase value */
+    prevPhase = pppd_phase;
+    pppd_phase     = PHASE_INITIALIZE;
+
+    /* process option and reset phase value */
+    iReturn = options_from_list(&option, 1);
+    pppd_phase   = prevPhase;
+  }
+
+  return ( iReturn );
+}
+
+int rtems_pppd_connect(void)
+{
+  /* send connect signal to pppd task */
+  rtems_event_send(rtems_pppd_taskid, RTEMS_EVENT_30);
+
+  return ( 0 );
+}
+
+static void timeout_terminate(void *arg)
+{
+  /* set pppd global variables to disconnect */
+  persist   = 0;
+  pppd_kill_link = 1;
+}
+
+int rtems_pppd_disconnect(void)
+{
+  /* need to wait a little time before we can bring the link down */
+  /* set up time out in 1 seconds */
+  TIMEOUT(timeout_terminate, NULL, 1);
+
+  /* send event to wake up the pppd code */
+  /* pretend its a serial interrput */
+  rtems_event_send(rtems_pppd_taskid, RTEMS_EVENT_31);
+
+  return ( 0 );
+}
diff --git a/rtemsbsd/pppd/sys-rtems.c b/rtemsbsd/pppd/sys-rtems.c
new file mode 100644
index 0000000..ac87957
--- /dev/null
+++ b/rtemsbsd/pppd/sys-rtems.c
@@ -0,0 +1,1340 @@
+/*
+ * sys-bsd.c - System-dependent procedures for setting up
+ * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.)
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * Copyright (c) 1995 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University and The Australian National University.
+ * The names of the Universities may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
+
+#include <net/if.h>
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <netinet/in.h>
+
+#if RTM_VERSION >= 3
+#include <sys/param.h>
+#if defined(NetBSD) && (NetBSD >= 199703)
+#include <netinet/if_inarp.h>
+#else	/* NetBSD 1.2D or later */
+#include <netinet/if_ether.h>
+#endif
+#endif
+
+#include <rtems.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/termiostypes.h>
+extern int      rtems_bsdnet_microseconds_per_tick;
+extern rtems_id rtems_pppd_taskid;
+
+#include "pppd.h"
+#include "fsm.h"
+#include "ipcp.h"
+
+static const char rcsid[] = RCSID;
+
+
+static int initdisc = -1;	/* Initial TTY discipline for ppp_fd */
+static int initfdflags = -1;	/* Initial file descriptor flags for ppp_fd */
+static int ppp_fd = -1;		/* fd which is set to PPP discipline */
+static int rtm_seq;
+
+static int restore_term;	/* 1 => we've munged the terminal */
+static struct termios inittermios; /* Initial TTY termios */
+static struct winsize wsinfo;	/* Initial window size info */
+
+static int loop_slave = -1;
+static int loop_master;
+
+static unsigned char inbuf[512]; /* buffer for chars read from loopback */
+
+static int sockfd;		/* socket for doing interface ioctls */
+
+static int if_is_up;		/* the interface is currently up */
+static uint32_t ifaddrs[2];	/* local and remote addresses we set */
+static uint32_t default_route_gateway;	/* gateway addr for default route */
+static uint32_t proxy_arp_addr;	/* remote addr for proxy arp */
+
+/* Prototypes for procedures local to this file. */
+static int dodefaultroute(uint32_t, int);
+static int get_ether_addr(uint32_t, struct sockaddr_dl *);
+
+
+/*
+ * sys_init - System-dependent initialization.
+ */
+void
+sys_init(void)
+{
+    /* Get an internet socket for doing socket ioctl's on. */
+    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	fatal("Couldn't create IP socket: %m");
+}
+
+/*
+ * sys_cleanup - restore any system state we modified before exiting:
+ * mark the interface down, delete default route and/or proxy arp entry.
+ * This should call die() because it's called from die().
+ */
+void
+sys_cleanup(void)
+{
+    struct ifreq ifr;
+
+    if (if_is_up) {
+	strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+	if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) >= 0
+	    && ((ifr.ifr_flags & IFF_UP) != 0)) {
+	    ifr.ifr_flags &= ~IFF_UP;
+	    ioctl(sockfd, SIOCSIFFLAGS, &ifr);
+	}
+    }
+    if (ifaddrs[0] != 0)
+	cifaddr(0, ifaddrs[0], ifaddrs[1]);
+    if (default_route_gateway)
+	cifdefaultroute(0, 0, default_route_gateway);
+    if (proxy_arp_addr)
+	cifproxyarp(0, proxy_arp_addr);
+}
+
+/*
+ * sys_close - Clean up in a child process before execing.
+ */
+void
+sys_close(void)
+{
+    close(sockfd);
+    if (loop_slave >= 0) {
+	close(loop_slave);
+	close(loop_master);
+    }
+}
+
+/*
+ * sys_check_options - check the options that the user specified
+ */
+int
+sys_check_options(void)
+{
+    return 1;
+}
+
+/*
+ * ppp_available - check whether the system has any ppp interfaces
+ * (in fact we check whether we can do an ioctl on ppp0).
+ */
+int
+ppp_available(void)
+{
+    int s, ok;
+    struct ifreq ifr;
+
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+	return 1;		/* can't tell */
+
+    strlcpy(ifr.ifr_name, "ppp0", sizeof (ifr.ifr_name));
+    ok = ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) >= 0;
+    close(s);
+
+    return ok;
+}
+
+/*
+ * establish_ppp - Turn the serial port into a ppp interface.
+ */
+int
+establish_ppp(
+    int fd)
+{
+    int taskid  = (int)rtems_pppd_taskid;
+    int pppdisc = PPPDISC;
+    int x;
+
+    if (demand) {
+	/*
+	 * Demand mode - prime the old ppp device to relinquish the unit.
+	 */
+	if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0)
+	    fatal("ioctl(transfer ppp unit): %m");
+    }
+
+    /*
+     * Save the old line discipline of fd, and set it to PPP.
+     */
+    if (ioctl(fd, TIOCGETD, &initdisc) < 0)
+	fatal("ioctl(TIOCGETD): %m");
+    if (ioctl(fd, TIOCSETD, &pppdisc) < 0)
+	fatal("ioctl(TIOCSETD): %m");
+
+    /* set pppd taskid into the driver */
+    ioctl(fd, PPPIOCSTASK, &taskid);
+
+    if (!demand) {
+	/*
+	 * Find out which interface we were given.
+	 */
+	if (ioctl(fd, PPPIOCGUNIT, &pppifunit) < 0)
+	    fatal("ioctl(PPPIOCGUNIT): %m");
+    } else {
+	/*
+	 * Check that we got the same unit again.
+	 */
+	if (ioctl(fd, PPPIOCGUNIT, &x) < 0)
+	    fatal("ioctl(PPPIOCGUNIT): %m");
+	if (x != pppifunit)
+	    fatal("transfer_ppp failed: wanted unit %d, got %d", pppifunit, x);
+	x = TTYDISC;
+	ioctl(loop_slave, TIOCSETD, &x);
+    }
+
+    ppp_fd = fd;
+
+    /*
+     * Enable debug in the driver if requested.
+     */
+    if (kdebugflag) {
+	if (ioctl(fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+	    warn("ioctl (PPPIOCGFLAGS): %m");
+	} else {
+	    x |= (kdebugflag & 0xFF) * SC_DEBUG;
+	    if (ioctl(fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+		warn("ioctl(PPPIOCSFLAGS): %m");
+	}
+    }
+
+    /*
+     * Set device for non-blocking reads.
+     */
+    if ((initfdflags = fcntl(fd, F_GETFL)) == -1
+	|| fcntl(fd, F_SETFL, initfdflags | O_NONBLOCK) == -1) {
+	warn("Couldn't set device to non-blocking mode: %m");
+    }
+
+    return fd;
+}
+
+/*
+ * restore_loop - reattach the ppp unit to the loopback.
+ */
+void
+restore_loop(void)
+{
+    int x;
+
+    /*
+     * Transfer the ppp interface back to the loopback.
+     */
+    if (ioctl(ppp_fd, PPPIOCXFERUNIT, 0) < 0)
+	fatal("ioctl(transfer ppp unit): %m");
+    x = PPPDISC;
+    if (ioctl(loop_slave, TIOCSETD, &x) < 0)
+	fatal("ioctl(TIOCSETD): %m");
+
+    /*
+     * Check that we got the same unit again.
+     */
+    if (ioctl(loop_slave, PPPIOCGUNIT, &x) < 0)
+	fatal("ioctl(PPPIOCGUNIT): %m");
+    if (x != pppifunit)
+	fatal("transfer_ppp failed: wanted unit %d, got %d", pppifunit, x);
+    ppp_fd = loop_slave;
+}
+
+
+/*
+ * disestablish_ppp - Restore the serial port to normal operation.
+ * This shouldn't call die() because it's called from die().
+ */
+void
+disestablish_ppp(
+    int fd)
+{
+    int taskid = (int)0;
+
+    /* clear pppd taskid from the driver */
+    ioctl(fd, PPPIOCSTASK, &taskid);
+
+    /* Reset non-blocking mode on fd. */
+    if (initfdflags != -1 && fcntl(fd, F_SETFL, initfdflags) < 0)
+	warn("Couldn't restore device fd flags: %m");
+    initfdflags = -1;
+
+    /* Restore old line discipline. */
+    if (initdisc >= 0 && ioctl(fd, TIOCSETD, &initdisc) < 0)
+	error("ioctl(TIOCSETD): %m");
+    initdisc = -1;
+
+    if (fd == ppp_fd)
+	ppp_fd = -1;
+}
+
+/*
+ * Check whether the link seems not to be 8-bit clean.
+ */
+void
+clean_check(void)
+{
+    int x;
+    char *s;
+
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) == 0) {
+	s = NULL;
+	switch (~x & (SC_RCV_B7_0|SC_RCV_B7_1|SC_RCV_EVNP|SC_RCV_ODDP)) {
+	case SC_RCV_B7_0:
+	    s = "bit 7 set to 1";
+	    break;
+	case SC_RCV_B7_1:
+	    s = "bit 7 set to 0";
+	    break;
+	case SC_RCV_EVNP:
+	    s = "odd parity";
+	    break;
+	case SC_RCV_ODDP:
+	    s = "even parity";
+	    break;
+	}
+	if (s != NULL) {
+	    warn("Serial link is not 8-bit clean:");
+	    warn("All received characters had %s", s);
+	}
+    }
+}
+
+/*
+ * set_up_tty: Set up the serial port on `fd' for 8 bits, no parity,
+ * at the requested speed, etc.  If `local' is true, set CLOCAL
+ * regardless of whether the modem option was specified.
+ *
+ * For *BSD, we assume that speed_t values numerically equal bits/second.
+ */
+void
+set_up_tty(
+    int fd, int local)
+{
+    struct termios     tios;
+
+    if (tcgetattr(fd, &tios) < 0)
+	fatal("tcgetattr: %m");
+
+    if (!restore_term) {
+	inittermios = tios;
+	ioctl(fd, TIOCGWINSZ, &wsinfo);
+    }
+
+    tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB | CLOCAL);
+    if (crtscts > 0 && !local) {
+        if (crtscts == 2) {
+#ifdef CDTRCTS
+            tios.c_cflag |= CDTRCTS;
+#endif
+	} else
+	    tios.c_cflag |= CRTSCTS;
+    } else if (crtscts < 0) {
+	tios.c_cflag &= ~CRTSCTS;
+#ifdef CDTRCTS
+	tios.c_cflag &= ~CDTRCTS;
+#endif
+    }
+
+    tios.c_cflag |= CS8 | CREAD | HUPCL;
+    if (local || !modem)
+	tios.c_cflag |= CLOCAL;
+    tios.c_iflag = IGNBRK | IGNPAR;
+    tios.c_oflag = 0;
+    tios.c_lflag = 0;
+    tios.c_cc[VMIN] = 1;
+    tios.c_cc[VTIME] = 0;
+
+    if (crtscts == -2) {
+	tios.c_iflag |= IXON | IXOFF;
+	tios.c_cc[VSTOP] = 0x13;	/* DC3 = XOFF = ^S */
+	tios.c_cc[VSTART] = 0x11;	/* DC1 = XON  = ^Q */
+    }
+
+    if (inspeed) {
+	cfsetospeed(&tios, inspeed);
+	cfsetispeed(&tios, inspeed);
+    } else {
+	inspeed = cfgetospeed(&tios);
+	/*
+	 * We can't proceed if the serial port speed is 0,
+	 * since that implies that the serial port is disabled.
+	 */
+	if (inspeed == 0)
+	    fatal("Baud rate for %s is 0; need explicit baud rate", devnam);
+    }
+    baud_rate = inspeed;
+
+/*    if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {  */
+    if (tcsetattr(fd, TCSADRAIN, &tios) < 0) {
+	fatal("tcsetattr: %m");
+    }
+
+    restore_term = 1;
+}
+
+/*
+ * restore_tty - restore the terminal to the saved settings.
+ */
+void
+restore_tty(
+    int fd)
+{
+    if (restore_term) {
+	if (!default_device) {
+	    /*
+	     * Turn off echoing, because otherwise we can get into
+	     * a loop with the tty and the modem echoing to each other.
+	     * We presume we are the sole user of this tty device, so
+	     * when we close it, it will revert to its defaults anyway.
+	     */
+	    inittermios.c_lflag &= ~(ECHO | ECHONL);
+	}
+/*	if (tcsetattr(fd, TCSAFLUSH, &inittermios) < 0) { */
+	if (tcsetattr(fd, TCSADRAIN, &inittermios) < 0) {
+	    if (errno != ENXIO)
+		warn("tcsetattr: %m");
+        }
+	ioctl(fd, TIOCSWINSZ, &wsinfo);
+	restore_term = 0;
+    }
+}
+
+/*
+ * setdtr - control the DTR line on the serial port.
+ * This is called from die(), so it shouldn't call die().
+ */
+void
+setdtr(
+  int fd, int on )
+{
+    int modembits = TIOCM_DTR;
+
+    ioctl(fd, (on? TIOCMBIS: TIOCMBIC), &modembits);
+}
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given.  Assumes slave_name points to >= 12 bytes of space.
+ */
+int
+get_pty(
+    int *master_fdp,
+    int *slave_fdp,
+    char *slave_name,
+    int uid)
+{
+    return 1;
+}
+
+
+/*
+ * open_ppp_loopback - open the device we use for getting
+ * packets in demand mode, and connect it to a ppp interface.
+ * Here we use a pty.
+ */
+int
+open_ppp_loopback(void)
+{
+    return loop_master;
+}
+
+
+/*
+ * output - Output PPP packet.
+ */
+void
+output(
+    int unit,
+    u_char *p,
+    int len)
+{
+    if (debug)
+	dbglog("sent %P", p, len);
+/*    printf("sent packet [%d]\n", len); */
+
+    if (write(pppd_ttyfd, p, len) < 0) {
+	if (errno != EIO)
+	    error("write: %m");
+    }
+}
+
+void
+ppp_delay(void)
+{
+  rtems_interval     ticks;
+
+  /* recommended delay to help negotiation */
+  ticks = 300000/rtems_bsdnet_microseconds_per_tick;
+  rtems_task_wake_after(ticks);
+}
+
+/*
+ * wait_input - wait until there is data available,
+ * for the length of time specified by *timo (indefinite
+ * if timo is NULL).
+ */
+void
+wait_input(
+    struct timeval *timo)
+{
+  rtems_event_set    events;
+  rtems_interval     ticks = 0;
+  rtems_option       wait = RTEMS_WAIT;
+
+  if(timo) {
+    if(timo->tv_sec == 0 && timo->tv_usec == 0)
+      wait = RTEMS_NO_WAIT;
+    else {
+      ticks = (timo->tv_sec * 1000000 + timo->tv_usec) /
+        rtems_bsdnet_microseconds_per_tick;
+      if(ticks <= 0)
+        ticks = 1;
+    }
+  }
+  rtems_event_receive(RTEMS_EVENT_31, RTEMS_EVENT_ANY | wait, ticks, &events);
+}
+
+/*
+ * read_packet - get a PPP packet from the serial device.
+ */
+int
+read_packet(
+    u_char *buf)
+{
+    int len;
+
+    if ((len = read(pppd_ttyfd, buf, PPP_MTU + PPP_HDRLEN)) < 0) {
+	if (errno == EWOULDBLOCK || errno == EINTR) len = -1;
+	/*fatal("read: %m"); */
+    }
+
+/*    printf("read packet [%d]\n", len); */
+    return len;
+}
+
+
+/*
+ * get_loop_output - read characters from the loopback, form them
+ * into frames, and detect when we want to bring the real link up.
+ * Return value is 1 if we need to bring up the link, 0 otherwise.
+ */
+int
+get_loop_output(void)
+{
+    int rv = 0;
+    int n;
+
+    while ((n = read(loop_master, inbuf, sizeof(inbuf))) >= 0) {
+	if (loop_chars(inbuf, n))
+	    rv = 1;
+    }
+
+    if (n == 0)
+	fatal("eof on loopback");
+    if (errno != EWOULDBLOCK)
+	fatal("read from loopback: %m");
+
+    return rv;
+}
+
+
+/*
+ * ppp_send_config - configure the transmit characteristics of
+ * the ppp interface.
+ */
+void
+ppp_send_config(
+    int unit,
+    int mtu,
+    uint32_t asyncmap,
+    int pcomp,
+    int accomp)
+{
+    u_int x;
+    struct ifreq ifr;
+
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    ifr.ifr_mtu = mtu;
+    if (ioctl(sockfd, SIOCSIFMTU, (caddr_t) &ifr) < 0)
+	fatal("ioctl(SIOCSIFMTU): %m");
+
+    if (ioctl(ppp_fd, PPPIOCSASYNCMAP, (caddr_t) &asyncmap) < 0)
+	fatal("ioctl(PPPIOCSASYNCMAP): %m");
+
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
+	fatal("ioctl (PPPIOCGFLAGS): %m");
+    x = pcomp? x | SC_COMP_PROT: x &~ SC_COMP_PROT;
+    x = accomp? x | SC_COMP_AC: x &~ SC_COMP_AC;
+/*    x = sync_serial ? x | SC_SYNC : x & ~SC_SYNC; */
+    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+	fatal("ioctl(PPPIOCSFLAGS): %m");
+}
+
+
+/*
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.
+ */
+void
+ppp_set_xaccm(
+    int unit,
+    ext_accm accm)
+{
+    if (ioctl(ppp_fd, PPPIOCSXASYNCMAP, accm) < 0 && errno != ENOTTY)
+	warn("ioctl(set extended ACCM): %m");
+}
+
+
+/*
+ * ppp_recv_config - configure the receive-side characteristics of
+ * the ppp interface.
+ */
+void
+ppp_recv_config(
+    int unit,
+    int mru,
+    uint32_t asyncmap,
+    int pcomp, int accomp)
+{
+    int x;
+
+    if (ioctl(ppp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
+	fatal("ioctl(PPPIOCSMRU): %m");
+    if (ioctl(ppp_fd, PPPIOCSRASYNCMAP, (caddr_t) &asyncmap) < 0)
+	fatal("ioctl(PPPIOCSRASYNCMAP): %m");
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0)
+	fatal("ioctl (PPPIOCGFLAGS): %m");
+    x = !accomp? x | SC_REJ_COMP_AC: x &~ SC_REJ_COMP_AC;
+    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+	fatal("ioctl(PPPIOCSFLAGS): %m");
+}
+
+/*
+ * ccp_test - ask kernel whether a given compression method
+ * is acceptable for use.  Returns 1 if the method and parameters
+ * are OK, 0 if the method is known but the parameters are not OK
+ * (e.g. code size should be reduced), or -1 if the method is unknown.
+ */
+int
+ccp_test(
+    int unit, u_char *opt_ptr, int opt_len, int for_transmit)
+{
+    struct ppp_option_data data;
+
+    data.ptr = opt_ptr;
+    data.length = opt_len;
+    data.transmit = for_transmit;
+    if (ioctl(pppd_ttyfd, PPPIOCSCOMPRESS, (caddr_t) &data) >= 0)
+	return 1;
+    return (errno == ENOBUFS)? 0: -1;
+}
+
+/*
+ * ccp_flags_set - inform kernel about the current state of CCP.
+ */
+void
+ccp_flags_set(
+    int unit, int isopen, int isup)
+{
+    int x;
+
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+	error("ioctl (PPPIOCGFLAGS): %m");
+	return;
+    }
+    x = isopen? x | SC_CCP_OPEN: x &~ SC_CCP_OPEN;
+    x = isup? x | SC_CCP_UP: x &~ SC_CCP_UP;
+    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0)
+	error("ioctl(PPPIOCSFLAGS): %m");
+}
+
+/*
+ * ccp_fatal_error - returns 1 if decompression was disabled as a
+ * result of an error detected after decompression of a packet,
+ * 0 otherwise.  This is necessary because of patent nonsense.
+ */
+int
+ccp_fatal_error(
+    int unit)
+{
+    int x;
+
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+	error("ioctl(PPPIOCGFLAGS): %m");
+	return 0;
+    }
+    return x & SC_DC_FERROR;
+}
+
+/*
+ * get_idle_time - return how long the link has been idle.
+ */
+int
+get_idle_time(
+    int u,
+    struct ppp_idle *ip)
+{
+    return ioctl(ppp_fd, PPPIOCGIDLE, ip) >= 0;
+}
+
+/*
+ * get_ppp_stats - return statistics for the link.
+ */
+int
+get_ppp_stats(
+    int u,
+    struct pppd_stats *stats)
+{
+    struct ifpppstatsreq req;
+
+    memset (&req, 0, sizeof (req));
+    strlcpy(req.ifr_name, ifname, sizeof(req.ifr_name));
+    if (ioctl(sockfd, SIOCGPPPSTATS, &req) < 0) {
+	error("Couldn't get PPP statistics: %m");
+	return 0;
+    }
+    stats->bytes_in = req.stats.p.ppp_ibytes;
+    stats->bytes_out = req.stats.p.ppp_obytes;
+    return 1;
+}
+
+
+#ifdef PPP_FILTER
+/*
+ * set_filters - transfer the pass and active filters to the kernel.
+ */
+int
+set_filters(
+    struct bpf_program *pass, struct bpf_program *active)
+{
+    int ret = 1;
+
+    if (pass->bf_len > 0) {
+	if (ioctl(ppp_fd, PPPIOCSPASS, pass) < 0) {
+	    error("Couldn't set pass-filter in kernel: %m");
+	    ret = 0;
+	}
+    }
+    if (active->bf_len > 0) {
+	if (ioctl(ppp_fd, PPPIOCSACTIVE, active) < 0) {
+	    error("Couldn't set active-filter in kernel: %m");
+	    ret = 0;
+	}
+    }
+    return ret;
+}
+#endif
+
+/*
+ * sifvjcomp - config tcp header compression
+ */
+int
+sifvjcomp(
+    int u, int vjcomp, int cidcomp, int maxcid)
+{
+    u_int x;
+
+    if (ioctl(ppp_fd, PPPIOCGFLAGS, (caddr_t) &x) < 0) {
+	error("ioctl (PPPIOCGFLAGS): %m");
+	return 0;
+    }
+    x = vjcomp ? x | SC_COMP_TCP: x &~ SC_COMP_TCP;
+    x = cidcomp? x & ~SC_NO_TCP_CCID: x | SC_NO_TCP_CCID;
+    if (ioctl(ppp_fd, PPPIOCSFLAGS, (caddr_t) &x) < 0) {
+	error("ioctl(PPPIOCSFLAGS): %m");
+	return 0;
+    }
+    if (vjcomp && ioctl(ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0) {
+	error("ioctl(PPPIOCSMAXCID): %m");
+	return 0;
+    }
+    return 1;
+}
+
+/*
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+int
+sifup(
+    int u)
+{
+    struct ifreq ifr;
+
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	error("ioctl (SIOCGIFFLAGS): %m");
+	return 0;
+    }
+    ifr.ifr_flags |= IFF_UP;
+    if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	error("ioctl(SIOCSIFFLAGS): %m");
+	return 0;
+    }
+    if_is_up = 1;
+    return 1;
+}
+
+/*
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+int
+sifnpmode(
+    int u,
+    int proto,
+    enum NPmode mode)
+{
+    struct npioctl npi;
+
+    npi.protocol = proto;
+    npi.mode = mode;
+    if (ioctl(ppp_fd, PPPIOCSNPMODE, &npi) < 0) {
+	error("ioctl(set NP %d mode to %d): %m", proto, mode);
+	return 0;
+    }
+    return 1;
+}
+
+/*
+ * sifdown - Config the interface down and disable IP.
+ */
+int
+sifdown(
+    int u)
+{
+    struct ifreq ifr;
+    int rv;
+    struct npioctl npi;
+
+    rv = 1;
+    npi.protocol = PPP_IP;
+    npi.mode = NPMODE_ERROR;
+    ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi);
+    /* ignore errors, because ppp_fd might have been closed by now. */
+
+    strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+    if (ioctl(sockfd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+	error("ioctl (SIOCGIFFLAGS): %m");
+	rv = 0;
+    } else {
+	ifr.ifr_flags &= ~IFF_UP;
+	if (ioctl(sockfd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+	    error("ioctl(SIOCSIFFLAGS): %m");
+	    rv = 0;
+	} else
+	    if_is_up = 0;
+    }
+    return rv;
+}
+
+/*
+ * SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
+ * if it exists.
+ */
+#define SET_SA_FAMILY(addr, family)		\
+    BZERO((char *) &(addr), sizeof(addr));	\
+    addr.sa_family = (family); 			\
+    addr.sa_len = sizeof(addr);
+
+/*
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+int
+sifaddr(
+    int u,
+    uint32_t o, uint32_t h, uint32_t m )
+{
+    struct ifaliasreq ifra;
+    struct ifreq ifr;
+
+    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+    if (m != 0) {
+	SET_SA_FAMILY(ifra.ifra_mask, AF_INET);
+	((struct sockaddr_in *) &ifra.ifra_mask)->sin_addr.s_addr = m;
+    } else
+	BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+    BZERO(&ifr, sizeof(ifr));
+    strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+    if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifr) < 0) {
+	if (errno != EADDRNOTAVAIL)
+	    warn("Couldn't remove interface address: %m");
+    }
+    if (ioctl(sockfd, SIOCAIFADDR, (caddr_t) &ifra) < 0) {
+	if (errno != EEXIST) {
+	    error("Couldn't set interface address: %m");
+	    return 0;
+	}
+	warn("Couldn't set interface address: Address %I already exists", o);
+    }
+    ifaddrs[0] = o;
+    ifaddrs[1] = h;
+    return 1;
+}
+
+/*
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+int
+cifaddr(
+    int u,
+    uint32_t o, uint32_t h )
+{
+    struct ifaliasreq ifra;
+
+    ifaddrs[0] = 0;
+    strlcpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
+    SET_SA_FAMILY(ifra.ifra_addr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_addr)->sin_addr.s_addr = o;
+    SET_SA_FAMILY(ifra.ifra_broadaddr, AF_INET);
+    ((struct sockaddr_in *) &ifra.ifra_broadaddr)->sin_addr.s_addr = h;
+    BZERO(&ifra.ifra_mask, sizeof(ifra.ifra_mask));
+    if (ioctl(sockfd, SIOCDIFADDR, (caddr_t) &ifra) < 0) {
+	if (errno != EADDRNOTAVAIL)
+	    warn("Couldn't delete interface address: %m");
+	return 0;
+    }
+    return 1;
+}
+
+/*
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int
+sifdefaultroute(
+    int u,
+    uint32_t l, uint32_t g)
+{
+    return dodefaultroute(g, 's');
+}
+
+/*
+ * cifdefaultroute - delete a default route through the address given.
+ */
+int
+cifdefaultroute(
+    int u,
+    uint32_t l, uint32_t g)
+{
+    return dodefaultroute(g, 'c');
+}
+
+/*
+ * dodefaultroute - talk to a routing socket to add/delete a default route.
+ */
+static int
+dodefaultroute(
+    uint32_t g,
+    int cmd)
+{
+/*    int    status;  */
+    struct sockaddr_in address;
+    struct sockaddr_in netmask;
+    struct sockaddr_in gateway;
+
+    memset((void *) &address, 0, sizeof(address));
+    address.sin_len = sizeof address;
+    address.sin_family = AF_INET;
+    address.sin_addr.s_addr = INADDR_ANY;
+
+    memset((void *) &netmask, 0, sizeof(netmask));
+    netmask.sin_len = sizeof netmask;
+    netmask.sin_addr.s_addr = INADDR_ANY;
+    netmask.sin_family = AF_INET;
+
+    if (cmd=='s') {	
+      memset((void *) &gateway, 0, sizeof(gateway));
+      gateway.sin_len = sizeof gateway;
+      gateway.sin_family = AF_INET;
+      gateway.sin_addr.s_addr = g;
+
+      rtems_bsdnet_rtrequest(RTM_ADD,
+                             (struct sockaddr *)&address,
+                             (struct sockaddr *)&gateway,
+                             (struct sockaddr *)&netmask,
+                             (RTF_UP|RTF_GATEWAY|RTF_STATIC), NULL);
+    }
+    else {
+      memset((void *) &gateway, 0, sizeof(gateway));
+      gateway.sin_len = sizeof gateway;
+      gateway.sin_family = AF_INET;
+      gateway.sin_addr.s_addr =  INADDR_ANY;
+
+      rtems_bsdnet_rtrequest(RTM_DELETE,
+                             (struct sockaddr *)&address,
+                             (struct sockaddr *)&gateway,
+                             (struct sockaddr *)&netmask,
+                             (RTF_UP|RTF_STATIC), NULL);
+    }
+
+    default_route_gateway = (cmd == 's')? g: 0;
+
+    return 1;
+}
+
+#if RTM_VERSION >= 3
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+static struct {
+    struct rt_msghdr		hdr;
+    struct sockaddr_inarp	dst;
+    struct sockaddr_dl		hwa;
+    char			extra[128];
+} arpmsg;
+
+static int arpmsg_valid;
+
+int
+sifproxyarp(
+    int unit,
+    uint32_t hisaddr)
+{
+    int routes;
+
+    /*
+     * Get the hardware address of an interface on the same subnet
+     * as our local address.
+     */
+    memset(&arpmsg, 0, sizeof(arpmsg));
+    if (!get_ether_addr(hisaddr, &arpmsg.hwa)) {
+	error("Cannot determine ethernet address for proxy ARP");
+	return 0;
+    }
+
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+	error("Couldn't add proxy arp entry: socket: %m");
+	return 0;
+    }
+
+    arpmsg.hdr.rtm_type = RTM_ADD;
+    arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC;
+    arpmsg.hdr.rtm_version = RTM_VERSION;
+    arpmsg.hdr.rtm_seq = ++rtm_seq;
+    arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+    arpmsg.hdr.rtm_inits = RTV_EXPIRE;
+    arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp);
+    arpmsg.dst.sin_family = AF_INET;
+    arpmsg.dst.sin_addr.s_addr = hisaddr;
+    arpmsg.dst.sin_other = SIN_PROXY;
+
+    arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg
+	+ arpmsg.hwa.sdl_len;
+    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+	error("Couldn't add proxy arp entry: %m");
+	close(routes);
+	return 0;
+    }
+
+    close(routes);
+    arpmsg_valid = 1;
+    proxy_arp_addr = hisaddr;
+    return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(
+    int unit,
+    uint32_t hisaddr)
+{
+    int routes;
+
+    if (!arpmsg_valid)
+	return 0;
+    arpmsg_valid = 0;
+
+    arpmsg.hdr.rtm_type = RTM_DELETE;
+    arpmsg.hdr.rtm_seq = ++rtm_seq;
+
+    if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) {
+	error("Couldn't delete proxy arp entry: socket: %m");
+	return 0;
+    }
+
+    if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) {
+	error("Couldn't delete proxy arp entry: %m");
+	close(routes);
+	return 0;
+    }
+
+    close(routes);
+    proxy_arp_addr = 0;
+    return 1;
+}
+
+#else	/* RTM_VERSION */
+
+/*
+ * sifproxyarp - Make a proxy ARP entry for the peer.
+ */
+int
+sifproxyarp(
+    int unit,
+    uint32_t hisaddr)
+{
+    struct arpreq arpreq;
+    struct {
+	struct sockaddr_dl	sdl;
+	char			space[128];
+    } dls;
+
+    BZERO(&arpreq, sizeof(arpreq));
+
+    /*
+     * Get the hardware address of an interface on the same subnet
+     * as our local address.
+     */
+    if (!get_ether_addr(hisaddr, &dls.sdl)) {
+	error("Cannot determine ethernet address for proxy ARP");
+	return 0;
+    }
+
+    arpreq.arp_ha.sa_len = sizeof(struct sockaddr);
+    arpreq.arp_ha.sa_family = AF_UNSPEC;
+    BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen);
+    SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+    ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+    arpreq.arp_flags = ATF_PERM | ATF_PUBL;
+    if (ioctl(sockfd, SIOCSARP, (caddr_t)&arpreq) < 0) {
+	error("Couldn't add proxy arp entry: %m");
+	return 0;
+    }
+
+    proxy_arp_addr = hisaddr;
+    return 1;
+}
+
+/*
+ * cifproxyarp - Delete the proxy ARP entry for the peer.
+ */
+int
+cifproxyarp(
+    int unit,
+    uint32_t hisaddr)
+{
+    struct arpreq arpreq;
+
+    BZERO(&arpreq, sizeof(arpreq));
+    SET_SA_FAMILY(arpreq.arp_pa, AF_INET);
+    ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr;
+    if (ioctl(sockfd, SIOCDARP, (caddr_t)&arpreq) < 0) {
+	warn("Couldn't delete proxy arp entry: %m");
+	return 0;
+    }
+    proxy_arp_addr = 0;
+    return 1;
+}
+#endif	/* RTM_VERSION */
+
+
+/*
+ * get_ether_addr - get the hardware address of an interface on the
+ * the same subnet as ipaddr.
+ */
+#define MAX_IFS		32
+
+static int
+get_ether_addr(
+    uint32_t ipaddr,
+    struct sockaddr_dl *hwaddr)
+{
+    struct ifreq *ifr, *ifend, *ifp;
+    uint32_t ina, mask;
+    struct sockaddr_dl *dla;
+    struct ifreq ifreq;
+    struct ifconf ifc;
+    struct ifreq ifs[MAX_IFS];
+
+    ifc.ifc_len = sizeof(ifs);
+    ifc.ifc_req = ifs;
+    if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+	error("ioctl(SIOCGIFCONF): %m");
+	return 0;
+    }
+
+    /*
+     * Scan through looking for an interface with an Internet
+     * address on the same subnet as `ipaddr'.
+     */
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+	 	((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
+	if (ifr->ifr_addr.sa_family == AF_INET) {
+	    ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+	    strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	    /*
+	     * Check that the interface is up, and not point-to-point
+	     * or loopback.
+	     */
+	    if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+		continue;
+	    if ((ifreq.ifr_flags &
+		 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP))
+		 != (IFF_UP|IFF_BROADCAST))
+		continue;
+	    /*
+	     * Get its netmask and check that it's on the right subnet.
+	     */
+	    if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+		continue;
+	    mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr;
+	    if ((ipaddr & mask) != (ina & mask))
+		continue;
+
+	    break;
+	}
+    }
+
+    if (ifr >= ifend)
+	return 0;
+    info("found interface %s for proxy arp", ifr->ifr_name);
+
+    /*
+     * Now scan through again looking for a link-level address
+     * for this interface.
+     */
+    ifp = ifr;
+    for (ifr = ifc.ifc_req; ifr < ifend; ) {
+	if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
+	    && ifr->ifr_addr.sa_family == AF_LINK) {
+	    /*
+	     * Found the link-level address - copy it out
+	     */
+	    dla = (struct sockaddr_dl *) &ifr->ifr_addr;
+	    BCOPY(dla, hwaddr, dla->sdl_len);
+	    return 1;
+	}
+	ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
+    }
+
+    return 0;
+}
+
+/*
+ * Return user specified netmask, modified by any mask we might determine
+ * for address `addr' (in network byte order).
+ * Here we scan through the system's list of interfaces, looking for
+ * any non-point-to-point interfaces which might appear to be on the same
+ * network as `addr'.  If we find any, we OR in their netmask to the
+ * user-specified netmask.
+ */
+uint32_t
+GetMask(
+    uint32_t addr)
+{
+    uint32_t mask, nmask, ina;
+    struct ifreq *ifr, *ifend, ifreq;
+    struct ifconf ifc;
+    struct ifreq ifs[MAX_IFS];
+
+    addr = ntohl(addr);
+    if (IN_CLASSA(addr))	/* determine network mask for address class */
+	nmask = IN_CLASSA_NET;
+    else if (IN_CLASSB(addr))
+	nmask = IN_CLASSB_NET;
+    else
+	nmask = IN_CLASSC_NET;
+    /* class D nets are disallowed by bad_ip_adrs */
+    mask = netmask | htonl(nmask);
+
+    /*
+     * Scan through the system's network interfaces.
+     */
+    ifc.ifc_len = sizeof(ifs);
+    ifc.ifc_req = ifs;
+    if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
+	warn("ioctl(SIOCGIFCONF): %m");
+	return mask;
+    }
+    ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
+    for (ifr = ifc.ifc_req; ifr < ifend; ifr = (struct ifreq *)
+	 	((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len)) {
+	/*
+	 * Check the interface's internet address.
+	 */
+	if (ifr->ifr_addr.sa_family != AF_INET)
+	    continue;
+	ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr;
+	if ((ntohl(ina) & nmask) != (addr & nmask))
+	    continue;
+	/*
+	 * Check that the interface is up, and not point-to-point or loopback.
+	 */
+	strlcpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
+	if (ioctl(sockfd, SIOCGIFFLAGS, &ifreq) < 0)
+	    continue;
+	if ((ifreq.ifr_flags & (IFF_UP|IFF_POINTOPOINT|IFF_LOOPBACK))
+	    != IFF_UP)
+	    continue;
+	/*
+	 * Get its netmask and OR it into our mask.
+	 */
+	if (ioctl(sockfd, SIOCGIFNETMASK, &ifreq) < 0)
+	    continue;
+	mask |= ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr.s_addr;
+    }
+
+    return mask;
+}
+
+/*
+ * have_route_to - determine if the system has any route to
+ * a given IP address.
+ * For demand mode to work properly, we have to ignore routes
+ * through our own interface.
+ */
+int have_route_to(uint32_t addr)
+{
+    return -1;
+}
+
+/*
+ * Use the hostid as part of the random number seed.
+ */
+int
+get_host_seed(void)
+{
+    return 17;
+}
diff --git a/rtemsbsd/pppd/upap.c b/rtemsbsd/pppd/upap.c
new file mode 100644
index 0000000..e8115a6
--- /dev/null
+++ b/rtemsbsd/pppd/upap.c
@@ -0,0 +1,631 @@
+/*
+ * upap.c - User/Password Authentication Protocol.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+/*
+ * TODO:
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "pppd.h"
+#include "upap.h"
+
+static const char rcsid[] = RCSID;
+
+static bool hide_password = true;
+
+/*
+ * Command-line options.
+ */
+static option_t pap_option_list[] = {
+    { "hide-password", o_bool, &hide_password,
+      "Don't output passwords to log", 1, NULL, 0, 0 },
+    { "show-password", o_bool, &hide_password,
+      "Show password string in debug log messages", 0, NULL, 0, 0 },
+    { "pap-restart", o_int, &upap[0].us_timeouttime,
+      "Set retransmit timeout for PAP", 0, NULL, 0, 0 },
+    { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
+      "Set max number of transmissions for auth-reqs", 0, NULL, 0, 0 },
+    { "pap-timeout", o_int, &upap[0].us_reqtimeout,
+      "Set time limit for peer PAP authentication", 0, NULL, 0, 0 },
+    { NULL, 0, NULL, NULL, 0, NULL, 0, 0 }
+};
+
+/*
+ * Protocol entry points.
+ */
+static void upap_init(int);
+static void upap_lowerup(int);
+static void upap_lowerdown(int);
+static void upap_input(int, u_char *, int);
+static void upap_protrej(int);
+static int  upap_printpkt(u_char *, int,
+			       void (*)(void *, char *, ...), void *);
+
+struct protent pap_protent = {
+    PPP_PAP,
+    upap_init,
+    upap_input,
+    upap_protrej,
+    upap_lowerup,
+    upap_lowerdown,
+    NULL,
+    NULL,
+    upap_printpkt,
+    NULL,
+    1,
+    "PAP",
+    NULL,
+    pap_option_list,
+    NULL,
+    NULL,
+    NULL
+};
+
+upap_state upap[NUM_PPP];		/* UPAP state; one for each unit */
+
+static void upap_timeout(void *);
+static void upap_reqtimeout(void *);
+static void upap_rauthreq(upap_state *, u_char *, int, int);
+static void upap_rauthack(upap_state *, u_char *, int, int);
+static void upap_rauthnak(upap_state *, u_char *, int, int);
+static void upap_sauthreq(upap_state *);
+static void upap_sresp(upap_state *, u_char, u_char, char *, int);
+
+
+/*
+ * upap_init - Initialize a UPAP unit.
+ */
+static void
+upap_init(int unit)
+{
+    upap_state *u = &upap[unit];
+
+    u->us_unit = unit;
+    u->us_user = NULL;
+    u->us_userlen = 0;
+    u->us_passwd = NULL;
+    u->us_passwdlen = 0;
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->us_serverstate = UPAPSS_INITIAL;
+    u->us_id = 0;
+    u->us_timeouttime = UPAP_DEFTIMEOUT;
+    u->us_maxtransmits = 10;
+    u->us_reqtimeout = UPAP_DEFREQTIME;
+}
+
+
+/*
+ * upap_authwithpeer - Authenticate us with our peer (start client).
+ *
+ * Set new state and send authenticate's.
+ */
+void
+upap_authwithpeer(
+    int unit,
+    char *user,
+    char *password)
+{
+    upap_state *u = &upap[unit];
+
+    /* Save the username and password we're given */
+    u->us_user = user;
+    u->us_userlen = strlen(user);
+    u->us_passwd = password;
+    u->us_passwdlen = strlen(password);
+    u->us_transmits = 0;
+
+    /* Lower layer up yet? */
+    if (u->us_clientstate == UPAPCS_INITIAL ||
+	u->us_clientstate == UPAPCS_PENDING) {
+	u->us_clientstate = UPAPCS_PENDING;
+	return;
+    }
+
+    upap_sauthreq(u);			/* Start protocol */
+}
+
+
+/*
+ * upap_authpeer - Authenticate our peer (start server).
+ *
+ * Set new state.
+ */
+void
+upap_authpeer(int unit)
+{
+    upap_state *u = &upap[unit];
+
+    /* Lower layer up yet? */
+    if (u->us_serverstate == UPAPSS_INITIAL ||
+	u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_PENDING;
+	return;
+    }
+
+    u->us_serverstate = UPAPSS_LISTEN;
+    if (u->us_reqtimeout > 0)
+	TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+}
+
+
+/*
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.
+ */
+static void
+upap_timeout(void *arg)
+{
+    upap_state *u = (upap_state *) arg;
+
+    if (u->us_clientstate != UPAPCS_AUTHREQ)
+	return;
+
+    if (u->us_transmits >= u->us_maxtransmits) {
+	/* give up in disgust */
+	error("No response to PAP authenticate-requests");
+	u->us_clientstate = UPAPCS_BADAUTH;
+	auth_withpeer_fail(u->us_unit, PPP_PAP);
+	return;
+    }
+
+    upap_sauthreq(u);		/* Send Authenticate-Request */
+}
+
+
+/*
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
+ */
+static void
+upap_reqtimeout(void *arg)
+{
+    upap_state *u = (upap_state *) arg;
+
+    if (u->us_serverstate != UPAPSS_LISTEN)
+	return;			/* huh?? */
+
+    auth_peer_fail(u->us_unit, PPP_PAP);
+    u->us_serverstate = UPAPSS_BADAUTH;
+}
+
+
+/*
+ * upap_lowerup - The lower layer is up.
+ *
+ * Start authenticating if pending.
+ */
+static void
+upap_lowerup(int unit)
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_INITIAL)
+	u->us_clientstate = UPAPCS_CLOSED;
+    else if (u->us_clientstate == UPAPCS_PENDING) {
+	upap_sauthreq(u);	/* send an auth-request */
+    }
+
+    if (u->us_serverstate == UPAPSS_INITIAL)
+	u->us_serverstate = UPAPSS_CLOSED;
+    else if (u->us_serverstate == UPAPSS_PENDING) {
+	u->us_serverstate = UPAPSS_LISTEN;
+	if (u->us_reqtimeout > 0)
+	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
+    }
+}
+
+
+/*
+ * upap_lowerdown - The lower layer is down.
+ *
+ * Cancel all timeouts.
+ */
+static void
+upap_lowerdown(int unit)
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ)	/* Timeout pending? */
+	UNTIMEOUT(upap_timeout, u);		/* Cancel timeout */
+    if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
+	UNTIMEOUT(upap_reqtimeout, u);
+
+    u->us_clientstate = UPAPCS_INITIAL;
+    u->us_serverstate = UPAPSS_INITIAL;
+}
+
+
+/*
+ * upap_protrej - Peer doesn't speak this protocol.
+ *
+ * This shouldn't happen.  In any case, pretend lower layer went down.
+ */
+static void
+upap_protrej(int unit)
+{
+    upap_state *u = &upap[unit];
+
+    if (u->us_clientstate == UPAPCS_AUTHREQ) {
+	error("PAP authentication failed due to protocol-reject");
+	auth_withpeer_fail(unit, PPP_PAP);
+    }
+    if (u->us_serverstate == UPAPSS_LISTEN) {
+	error("PAP authentication of peer failed (protocol-reject)");
+	auth_peer_fail(unit, PPP_PAP);
+    }
+    upap_lowerdown(unit);
+}
+
+
+/*
+ * upap_input - Input UPAP packet.
+ */
+static void
+upap_input(
+    int unit,
+    u_char *inpacket,
+    int l)
+{
+    upap_state *u = &upap[unit];
+    u_char *inp;
+    u_char code, id;
+    int len;
+
+    /*
+     * Parse header (code, id and length).
+     * If packet too short, drop it.
+     */
+    inp = inpacket;
+    if (l < UPAP_HEADERLEN) {
+	UPAPDEBUG(("pap_input: rcvd short header."));
+	return;
+    }
+    GETCHAR(code, inp);
+    GETCHAR(id, inp);
+    GETSHORT(len, inp);
+    if (len < UPAP_HEADERLEN) {
+	UPAPDEBUG(("pap_input: rcvd illegal length."));
+	return;
+    }
+    if (len > l) {
+	UPAPDEBUG(("pap_input: rcvd short packet."));
+	return;
+    }
+    len -= UPAP_HEADERLEN;
+
+    /*
+     * Action depends on code.
+     */
+    switch (code) {
+    case UPAP_AUTHREQ:
+	upap_rauthreq(u, inp, id, len);
+	break;
+
+    case UPAP_AUTHACK:
+	upap_rauthack(u, inp, id, len);
+	break;
+
+    case UPAP_AUTHNAK:
+	upap_rauthnak(u, inp, id, len);
+	break;
+
+    default:				/* XXX Need code reject */
+	break;
+    }
+}
+
+
+/*
+ * upap_rauth - Receive Authenticate.
+ */
+static void
+upap_rauthreq(
+    upap_state *u,
+    u_char *inp,
+    int id,
+    int len)
+{
+    u_char ruserlen, rpasswdlen;
+    char *ruser, *rpasswd;
+    int retcode;
+    char *msg;
+    int msglen;
+
+    if (u->us_serverstate < UPAPSS_LISTEN)
+	return;
+
+    /*
+     * If we receive a duplicate authenticate-request, we are
+     * supposed to return the same status as for the first request.
+     */
+    if (u->us_serverstate == UPAPSS_OPEN) {
+	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
+	return;
+    }
+    if (u->us_serverstate == UPAPSS_BADAUTH) {
+	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
+	return;
+    }
+
+    /*
+     * Parse user/passwd.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    GETCHAR(ruserlen, inp);
+    len -= sizeof (u_char) + ruserlen + sizeof (u_char);
+    if (len < 0) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    ruser = (char *) inp;
+    INCPTR(ruserlen, inp);
+    GETCHAR(rpasswdlen, inp);
+    if (len < rpasswdlen) {
+	UPAPDEBUG(("pap_rauth: rcvd short packet."));
+	return;
+    }
+    rpasswd = (char *) inp;
+
+    /*
+     * Check the username and password given.
+     */
+    retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
+			   rpasswdlen, &msg);
+    BZERO(rpasswd, rpasswdlen);
+    msglen = strlen(msg);
+    if (msglen > 255)
+	msglen = 255;
+
+    upap_sresp(u, retcode, id, msg, msglen);
+
+    if (retcode == UPAP_AUTHACK) {
+	u->us_serverstate = UPAPSS_OPEN;
+	auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
+    } else {
+	u->us_serverstate = UPAPSS_BADAUTH;
+	auth_peer_fail(u->us_unit, PPP_PAP);
+    }
+
+    if (u->us_reqtimeout > 0)
+	UNTIMEOUT(upap_reqtimeout, u);
+}
+
+
+/*
+ * upap_rauthack - Receive Authenticate-Ack.
+ */
+static void
+upap_rauthack(
+    upap_state *u,
+    u_char *inp,
+    int id,
+    int len)
+{
+    u_char msglen;
+    char *msg;
+
+    if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
+    } else {
+	GETCHAR(msglen, inp);
+	if (msglen > 0) {
+	    len -= sizeof (u_char);
+	    if (len < msglen) {
+		UPAPDEBUG(("pap_rauthack: rcvd short packet."));
+		return;
+	    }
+	    msg = (char *) inp;
+	    PRINTMSG(msg, msglen);
+	}
+    }
+
+    u->us_clientstate = UPAPCS_OPEN;
+
+    auth_withpeer_success(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_rauthnak - Receive Authenticate-Nakk.
+ */
+static void
+upap_rauthnak(
+    upap_state *u,
+    u_char *inp,
+    int id,
+    int len)
+{
+    u_char msglen;
+    char *msg;
+
+    if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
+	return;
+
+    /*
+     * Parse message.
+     */
+    if (len < 1) {
+	UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
+    } else {
+	GETCHAR(msglen, inp);
+	if (msglen > 0) {
+	    len -= sizeof (u_char);
+	    if (len < msglen) {
+		UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
+		return;
+	    }
+	    msg = (char *) inp;
+	    PRINTMSG(msg, msglen);
+	}
+    }
+
+    u->us_clientstate = UPAPCS_BADAUTH;
+
+    error("PAP authentication failed");
+    auth_withpeer_fail(u->us_unit, PPP_PAP);
+}
+
+
+/*
+ * upap_sauthreq - Send an Authenticate-Request.
+ */
+static void
+upap_sauthreq(upap_state *u)
+{
+    u_char *outp;
+    int outlen;
+
+    outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
+	u->us_userlen + u->us_passwdlen;
+    outp = outpacket_buf;
+
+    MAKEHEADER(outp, PPP_PAP);
+
+    PUTCHAR(UPAP_AUTHREQ, outp);
+    PUTCHAR(++u->us_id, outp);
+    PUTSHORT(outlen, outp);
+    PUTCHAR(u->us_userlen, outp);
+    BCOPY(u->us_user, outp, u->us_userlen);
+    INCPTR(u->us_userlen, outp);
+    PUTCHAR(u->us_passwdlen, outp);
+    BCOPY(u->us_passwd, outp, u->us_passwdlen);
+
+    output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+
+    TIMEOUT(upap_timeout, u, u->us_timeouttime);
+    ++u->us_transmits;
+    u->us_clientstate = UPAPCS_AUTHREQ;
+}
+
+
+/*
+ * upap_sresp - Send a response (ack or nak).
+ */
+static void
+upap_sresp(
+    upap_state *u,
+    u_char code, u_char id,
+    char *msg,
+    int msglen)
+{
+    u_char *outp;
+    int outlen;
+
+    outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
+    outp = outpacket_buf;
+    MAKEHEADER(outp, PPP_PAP);
+
+    PUTCHAR(code, outp);
+    PUTCHAR(id, outp);
+    PUTSHORT(outlen, outp);
+    PUTCHAR(msglen, outp);
+    BCOPY(msg, outp, msglen);
+    output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
+}
+
+/*
+ * upap_printpkt - print the contents of a PAP packet.
+ */
+static char *upap_codenames[] = {
+    "AuthReq", "AuthAck", "AuthNak"
+};
+
+static int
+upap_printpkt(
+    u_char *p,
+    int plen,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int code, id, len;
+    int mlen, ulen, wlen;
+    char *user, *pwd, *msg;
+    u_char *pstart;
+
+    if (plen < UPAP_HEADERLEN)
+	return 0;
+    pstart = p;
+    GETCHAR(code, p);
+    GETCHAR(id, p);
+    GETSHORT(len, p);
+    if (len < UPAP_HEADERLEN || len > plen)
+	return 0;
+
+    if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
+	printer(arg, " %s", upap_codenames[code-1]);
+    else
+	printer(arg, " code=0x%x", code);
+    printer(arg, " id=0x%x", id);
+    len -= UPAP_HEADERLEN;
+    switch (code) {
+    case UPAP_AUTHREQ:
+	if (len < 1)
+	    break;
+	ulen = p[0];
+	if (len < ulen + 2)
+	    break;
+	wlen = p[ulen + 1];
+	if (len < ulen + wlen + 2)
+	    break;
+	user = (char *) (p + 1);
+	pwd = (char *) (p + ulen + 2);
+	p += ulen + wlen + 2;
+	len -= ulen + wlen + 2;
+	printer(arg, " user=");
+	print_string(user, ulen, printer, arg);
+	printer(arg, " password=");
+	if (!hide_password)
+	    print_string(pwd, wlen, printer, arg);
+	else
+	    printer(arg, "<hidden>");
+	break;
+    case UPAP_AUTHACK:
+    case UPAP_AUTHNAK:
+	if (len < 1)
+	    break;
+	mlen = p[0];
+	if (len < mlen + 1)
+	    break;
+	msg = (char *) (p + 1);
+	p += mlen + 1;
+	len -= mlen + 1;
+	printer(arg, " ");
+	print_string(msg, mlen, printer, arg);
+	break;
+    }
+
+    /* print the rest of the bytes in the packet */
+    for (; len > 0; --len) {
+	GETCHAR(code, p);
+	printer(arg, " %.2x", code);
+    }
+
+    return p - pstart;
+}
diff --git a/rtemsbsd/pppd/upap.h b/rtemsbsd/pppd/upap.h
new file mode 100644
index 0000000..6ba0900
--- /dev/null
+++ b/rtemsbsd/pppd/upap.h
@@ -0,0 +1,87 @@
+/*
+ * upap.h - User/Password Authentication Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $Id$
+ */
+
+/*
+ * Packet header = Code, id, length.
+ */
+#define UPAP_HEADERLEN	4
+
+
+/*
+ * UPAP codes.
+ */
+#define UPAP_AUTHREQ	1	/* Authenticate-Request */
+#define UPAP_AUTHACK	2	/* Authenticate-Ack */
+#define UPAP_AUTHNAK	3	/* Authenticate-Nak */
+
+
+/*
+ * Each interface is described by upap structure.
+ */
+typedef struct upap_state {
+    int us_unit;		/* Interface unit number */
+    char *us_user;		/* User */
+    int us_userlen;		/* User length */
+    char *us_passwd;		/* Password */
+    int us_passwdlen;		/* Password length */
+    int us_clientstate;		/* Client state */
+    int us_serverstate;		/* Server state */
+    u_char us_id;		/* Current id */
+    int us_timeouttime;		/* Timeout (seconds) for auth-req retrans. */
+    int us_transmits;		/* Number of auth-reqs sent */
+    int us_maxtransmits;	/* Maximum number of auth-reqs to send */
+    int us_reqtimeout;		/* Time to wait for auth-req from peer */
+} upap_state;
+
+
+/*
+ * Client states.
+ */
+#define UPAPCS_INITIAL	0	/* Connection down */
+#define UPAPCS_CLOSED	1	/* Connection up, haven't requested auth */
+#define UPAPCS_PENDING	2	/* Connection down, have requested auth */
+#define UPAPCS_AUTHREQ	3	/* We've sent an Authenticate-Request */
+#define UPAPCS_OPEN	4	/* We've received an Ack */
+#define UPAPCS_BADAUTH	5	/* We've received a Nak */
+
+/*
+ * Server states.
+ */
+#define UPAPSS_INITIAL	0	/* Connection down */
+#define UPAPSS_CLOSED	1	/* Connection up, haven't requested auth */
+#define UPAPSS_PENDING	2	/* Connection down, have requested auth */
+#define UPAPSS_LISTEN	3	/* Listening for an Authenticate */
+#define UPAPSS_OPEN	4	/* We've sent an Ack */
+#define UPAPSS_BADAUTH	5	/* We've sent a Nak */
+
+
+/*
+ * Timeouts.
+ */
+#define UPAP_DEFTIMEOUT	5	/* Timeout (seconds) for retransmitting req */
+#define UPAP_DEFREQTIME	30	/* Time to wait for auth-req from peer */
+
+extern upap_state upap[];
+
+void upap_authwithpeer(int, char *, char *);
+void upap_authpeer(int);
+
+extern struct protent pap_protent;
diff --git a/rtemsbsd/pppd/utils.c b/rtemsbsd/pppd/utils.c
new file mode 100644
index 0000000..af39226
--- /dev/null
+++ b/rtemsbsd/pppd/utils.c
@@ -0,0 +1,827 @@
+/*
+ * utils.c - various utility functions used in pppd.
+ *
+ * Copyright (c) 1999 The Australian National University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the Australian National University.  The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#define RCSID	"$Id$"
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <syslog.h>
+#include <pwd.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#ifdef SVR4
+#include <sys/mkdev.h>
+#endif
+
+#include "pppd.h"
+
+static const char rcsid[] = RCSID;
+
+static void pr_log(void *, char *, ...);
+static void logit(int, char *, va_list);
+static void vslp_printer(void *, char *, ...);
+static void format_packet(u_char *, int, void (*) (void *, char *, ...),
+			       void *);
+
+struct buffer_info {
+    char *ptr;
+    int len;
+};
+
+/*
+ * slprintf - format a message into a buffer.  Like sprintf except we
+ * also specify the length of the output buffer, and we handle
+ * %r (recursive format), %m (error message), %v (visible string),
+ * %q (quoted string), %t (current time) and %I (IP address) formats.
+ * Doesn't do floating-point formats.
+ * Returns the number of chars put into buf.
+ */
+int
+slprintf __V((char *buf, int buflen, char *fmt, ...))
+{
+    va_list args;
+    int n;
+
+#if defined(__STDC__)
+    va_start(args, fmt);
+#else
+    char *buf;
+    int buflen;
+    char *fmt;
+    va_start(args);
+    buf = va_arg(args, char *);
+    buflen = va_arg(args, int);
+    fmt = va_arg(args, char *);
+#endif
+    n = vslprintf(buf, buflen, fmt, args);
+    va_end(args);
+    return n;
+}
+
+/*
+ * vslprintf - like slprintf, takes a va_list instead of a list of args.
+ */
+#define OUTCHAR(c)	(buflen > 0? (--buflen, *buf++ = (c)): 0)
+
+int
+vslprintf(
+    char *buf,
+    int buflen,
+    char *fmt,
+    va_list args)
+{
+    int c, i, n;
+    int width, prec, fillch;
+    int base, len, neg, quoted;
+    uintptr_t val = 0;
+    char *str, *f, *buf0;
+    unsigned char *p;
+    char num[32];
+    time_t t;
+    uint32_t ip;
+    static char hexchars[] = "0123456789abcdef";
+    struct buffer_info bufinfo;
+
+    buf0 = buf;
+    --buflen;
+    while (buflen > 0) {
+	for (f = fmt; *f != '%' && *f != 0; ++f)
+	    ;
+	if (f > fmt) {
+	    len = f - fmt;
+	    if (len > buflen)
+		len = buflen;
+	    memcpy(buf, fmt, len);
+	    buf += len;
+	    buflen -= len;
+	    fmt = f;
+	}
+	if (*fmt == 0)
+	    break;
+	c = *++fmt;
+	width = 0;
+	prec = -1;
+	fillch = ' ';
+	if (c == '0') {
+	    fillch = '0';
+	    c = *++fmt;
+	}
+	if (c == '*') {
+	    width = va_arg(args, int);
+	    c = *++fmt;
+	} else {
+	    while (isdigit(c)) {
+		width = width * 10 + c - '0';
+		c = *++fmt;
+	    }
+	}
+	if (c == '.') {
+	    c = *++fmt;
+	    if (c == '*') {
+		prec = va_arg(args, int);
+		c = *++fmt;
+	    } else {
+		prec = 0;
+		while (isdigit(c)) {
+		    prec = prec * 10 + c - '0';
+		    c = *++fmt;
+		}
+	    }
+	}
+	str = 0;
+	base = 0;
+	neg = 0;
+	++fmt;
+	switch (c) {
+	case 'd':
+	    i = va_arg(args, int);
+	    if (i < 0) {
+		neg = 1;
+		val = -i;
+	    } else
+		val = i;
+	    base = 10;
+	    break;
+	case 'o':
+	    val = va_arg(args, unsigned int);
+	    base = 8;
+	    break;
+	case 'x':
+	case 'X':
+	    val = va_arg(args, unsigned int);
+	    base = 16;
+	    break;
+	case 'p':
+	    val = (uintptr_t) va_arg(args, void *);
+	    base = 16;
+	    neg = 2;
+	    break;
+	case 's':
+	    str = va_arg(args, char *);
+	    break;
+	case 'c':
+	    num[0] = va_arg(args, int);
+	    num[1] = 0;
+	    str = num;
+	    break;
+	case 'm':
+	    str = strerror(errno);
+	    break;
+	case 'I':
+	    ip = va_arg(args, uint32_t);
+	    ip = ntohl(ip);
+	    slprintf(num, sizeof(num), "%d.%d.%d.%d", (ip >> 24) & 0xff,
+		     (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
+	    str = num;
+	    break;
+	case 'r':
+	    f = va_arg(args, char *);
+#if !defined(__PPC__)
+	    n = vslprintf(buf, buflen + 1, f, va_arg(args, va_list));
+#else
+	    /* HACK: On the powerpc, a va_list is an array of 1 structure */
+	    n = vslprintf(buf, buflen + 1, f, va_arg(args, void *));
+#endif
+	    buf += n;
+	    buflen -= n;
+	    continue;
+	case 't':
+	    time(&t);
+	    str = ctime(&t);
+	    str += 4;		/* chop off the day name */
+	    str[15] = 0;	/* chop off year and newline */
+	    break;
+	case 'v':		/* "visible" string */
+	case 'q':		/* quoted string */
+	    quoted = c == 'q';
+	    p = va_arg(args, unsigned char *);
+	    if (fillch == '0' && prec >= 0) {
+		n = prec;
+	    } else {
+		n = strlen((char *)p);
+		if (prec >= 0 && n > prec)
+		    n = prec;
+	    }
+	    while (n > 0 && buflen > 0) {
+		c = *p++;
+		--n;
+		if (!quoted && c >= 0x80) {
+		    OUTCHAR('M');
+		    OUTCHAR('-');
+		    c -= 0x80;
+		}
+		if (quoted && (c == '"' || c == '\\'))
+		    OUTCHAR('\\');
+		if (c < 0x20 || (0x7f <= c && c < 0xa0)) {
+		    if (quoted) {
+			OUTCHAR('\\');
+			switch (c) {
+			case '\t':	OUTCHAR('t');	break;
+			case '\n':	OUTCHAR('n');	break;
+			case '\b':	OUTCHAR('b');	break;
+			case '\f':	OUTCHAR('f');	break;
+			default:
+			    OUTCHAR('x');
+			    OUTCHAR(hexchars[c >> 4]);
+			    OUTCHAR(hexchars[c & 0xf]);
+			}
+		    } else {
+			if (c == '\t')
+			    OUTCHAR(c);
+			else {
+			    OUTCHAR('^');
+			    OUTCHAR(c ^ 0x40);
+			}
+		    }
+		} else
+		    OUTCHAR(c);
+	    }
+	    continue;
+	case 'P':		/* print PPP packet */
+	    bufinfo.ptr = buf;
+	    bufinfo.len = buflen + 1;
+	    p = va_arg(args, unsigned char *);
+	    n = va_arg(args, int);
+	    format_packet(p, n, vslp_printer, &bufinfo);
+	    buf = bufinfo.ptr;
+	    buflen = bufinfo.len - 1;
+	    continue;
+	case 'B':
+	    p = va_arg(args, unsigned char *);
+	    for (n = prec; n > 0; --n) {
+		c = *p++;
+		if (fillch == ' ')
+		    OUTCHAR(' ');
+		OUTCHAR(hexchars[(c >> 4) & 0xf]);
+		OUTCHAR(hexchars[c & 0xf]);
+	    }
+	    continue;
+	default:
+	    *buf++ = '%';
+	    if (c != '%')
+		--fmt;		/* so %z outputs %z etc. */
+	    --buflen;
+	    continue;
+	}
+	if (base != 0) {
+	    str = num + sizeof(num);
+	    *--str = 0;
+	    while (str > num + neg) {
+		*--str = hexchars[val % base];
+		val = val / base;
+		if (--prec <= 0 && val == 0)
+		    break;
+	    }
+	    switch (neg) {
+	    case 1:
+		*--str = '-';
+		break;
+	    case 2:
+		*--str = 'x';
+		*--str = '0';
+		break;
+	    }
+	    len = num + sizeof(num) - 1 - str;
+	} else {
+	    len = strlen(str);
+	    if (prec >= 0 && len > prec)
+		len = prec;
+	}
+	if (width > 0) {
+	    if (width > buflen)
+		width = buflen;
+	    if ((n = width - len) > 0) {
+		buflen -= n;
+		for (; n > 0; --n)
+		    *buf++ = fillch;
+	    }
+	}
+	if (len > buflen)
+	    len = buflen;
+	memcpy(buf, str, len);
+	buf += len;
+	buflen -= len;
+    }
+    *buf = 0;
+    return buf - buf0;
+}
+
+/*
+ * vslp_printer - used in processing a %P format
+ */
+static void
+vslp_printer __V((void *arg, char *fmt, ...))
+{
+    int n;
+    va_list pvar;
+    struct buffer_info *bi;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    void *arg;
+    char *fmt;
+    va_start(pvar);
+    arg = va_arg(pvar, void *);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    bi = (struct buffer_info *) arg;
+    n = vslprintf(bi->ptr, bi->len, fmt, pvar);
+    va_end(pvar);
+
+    bi->ptr += n;
+    bi->len -= n;
+}
+
+/*
+ * log_packet - format a packet and log it.
+ */
+
+char line[256];			/* line to be logged accumulated here */
+char *linep;
+
+void
+log_packet(
+    u_char *p,
+    int len,
+    char *prefix,
+    int level)
+{
+    strlcpy(line, prefix, sizeof(line));
+    linep = line + strlen(line);
+    format_packet(p, len, pr_log, NULL);
+}
+
+/*
+ * format_packet - make a readable representation of a packet,
+ * calling `printer(arg, format, ...)' to output it.
+ */
+static void
+format_packet(
+    u_char *p,
+    int len,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int i, n;
+    u_short proto;
+    struct protent *protp;
+
+    if (len >= PPP_HDRLEN && p[0] == PPP_ALLSTATIONS && p[1] == PPP_UI) {
+	p += 2;
+	GETSHORT(proto, p);
+	len -= PPP_HDRLEN;
+	for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	    if (proto == protp->protocol)
+		break;
+	if (protp != NULL) {
+	    printer(arg, "[%s", protp->name);
+	    n = (*protp->printpkt)(p, len, printer, arg);
+	    printer(arg, "]");
+	    p += n;
+	    len -= n;
+	} else {
+	    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+		if (proto == (protp->protocol & ~0x8000))
+		    break;
+	    if (protp != 0 && protp->data_name != 0) {
+		printer(arg, "[%s data]", protp->data_name);
+		if (len > 8)
+		    printer(arg, "%.8B ...", p);
+		else
+		    printer(arg, "%.*B", len, p);
+		len = 0;
+	    } else
+		printer(arg, "[proto=0x%x]", proto);
+	}
+    }
+
+    if (len > 32)
+	printer(arg, "%.32B ...", p);
+    else
+	printer(arg, "%.*B", len, p);
+}
+
+static void
+pr_log __V((void *arg, char *fmt, ...))
+{
+    int n;
+    va_list pvar;
+    char buf[256];
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    void *arg;
+    char *fmt;
+    va_start(pvar);
+    arg = va_arg(pvar, void *);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    n = vslprintf(buf, sizeof(buf), fmt, pvar);
+    va_end(pvar);
+
+    if (linep + n + 1 > line + sizeof(line)) {
+	linep = line;
+    }
+    strlcpy(linep, buf, line + sizeof(line) - linep);
+    linep += n;
+}
+
+/*
+ * print_string - print a readable representation of a string using
+ * printer.
+ */
+void
+print_string(
+    void *p_arg,
+    int len,
+    void (*printer)(void *, char *, ...),
+    void *arg)
+{
+    int c;
+    unsigned char *p = (unsigned char *)p_arg;
+
+    printer(arg, "\"");
+    for (; len > 0; --len) {
+	c = *p++;
+	if (' ' <= c && c <= '~') {
+	    if (c == '\\' || c == '"')
+		printer(arg, "\\");
+	    printer(arg, "%c", c);
+	} else {
+	    switch (c) {
+	    case '\n':
+		printer(arg, "\\n");
+		break;
+	    case '\r':
+		printer(arg, "\\r");
+		break;
+	    case '\t':
+		printer(arg, "\\t");
+		break;
+	    default:
+		printer(arg, "\\%.3o", c);
+	    }
+	}
+    }
+    printer(arg, "\"");
+}
+
+/*
+ * logit - does the hard work for fatal et al.
+ */
+static void
+logit(
+    int level,
+    char *fmt,
+    va_list args)
+{
+    int n;
+    char buf[256];
+
+    n = vslprintf(buf, sizeof(buf), fmt, args);
+/*    if (log_to_fd >= 0 && (level != LOG_DEBUG || debug)) { */
+    if (log_to_fd >= 0 && (debug)) {
+	if (buf[n-1] != '\n')
+	    buf[n++] = '\n';
+	if (write(log_to_fd, buf, n) != n)
+	    log_to_fd = -1;
+    }
+}
+
+/*
+ * fatal - log an error message and die horribly.
+ */
+void
+pppd_fatal __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_ERR, fmt, pvar);
+    va_end(pvar);
+
+    die(1);			/* as promised */
+}
+
+/*
+ * error - log an error message.
+ */
+void
+pppd_error __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_ERR, fmt, pvar);
+    va_end(pvar);
+}
+
+/*
+ * warn - log a warning message.
+ */
+void
+pppd_warn __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_WARNING, fmt, pvar);
+    va_end(pvar);
+}
+
+/*
+ * notice - log a notice-level message.
+ */
+void
+pppd_notice __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_NOTICE, fmt, pvar);
+    va_end(pvar);
+}
+
+/*
+ * info - log an informational message.
+ */
+void
+pppd_info __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_INFO, fmt, pvar);
+    va_end(pvar);
+}
+
+/*
+ * dbglog - log a debug message.
+ */
+void
+pppd_dbglog __V((char *fmt, ...))
+{
+    va_list pvar;
+
+#if defined(__STDC__)
+    va_start(pvar, fmt);
+#else
+    char *fmt;
+    va_start(pvar);
+    fmt = va_arg(pvar, char *);
+#endif
+
+    logit(LOG_DEBUG, fmt, pvar);
+    va_end(pvar);
+}
+
+/* Procedures for locking the serial device using a lock file. */
+#ifndef LOCK_DIR
+#ifdef _linux_
+#define LOCK_DIR	"/var/lock"
+#else
+#ifdef SVR4
+#define LOCK_DIR	"/var/spool/locks"
+#else
+#define LOCK_DIR	"/var/spool/lock"
+#endif
+#endif
+#endif /* LOCK_DIR */
+
+static char lock_file[MAXPATHLEN];
+
+/*
+ * lock - create a lock file for the named device
+ */
+int
+lock(char *dev)
+{
+#ifdef LOCKLIB
+    int result;
+
+    result = mklock (dev, (void *) 0);
+    if (result == 0) {
+	strlcpy(lock_file, sizeof(lock_file), dev);
+	return 0;
+    }
+
+    if (result > 0)
+        notice("Device %s is locked by pid %d", dev, result);
+    else
+	error("Can't create lock file %s", lock_file);
+    return -1;
+
+#else /* LOCKLIB */
+
+    char lock_buffer[12];
+    int fd, pid, n;
+
+#ifdef SVR4
+    struct stat sbuf;
+
+    if (stat(dev, &sbuf) < 0) {
+	error("Can't get device number for %s: %m", dev);
+	return -1;
+    }
+    if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
+	error("Can't lock %s: not a character device", dev);
+	return -1;
+    }
+    slprintf(lock_file, sizeof(lock_file), "%s/LK.%03d.%03d.%03d",
+	     LOCK_DIR, major(sbuf.st_dev),
+	     major(sbuf.st_rdev), minor(sbuf.st_rdev));
+#else
+    char *p;
+
+    if ((p = strrchr(dev, '/')) != NULL)
+	dev = p + 1;
+    slprintf(lock_file, sizeof(lock_file), "%s/LCK..%s", LOCK_DIR, dev);
+#endif
+
+    while ((fd = open(lock_file, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
+	if (errno != EEXIST) {
+	    error("Can't create lock file %s: %m", lock_file);
+	    break;
+	}
+
+	/* Read the lock file to find out who has the device locked. */
+	fd = open(lock_file, O_RDONLY, 0);
+	if (fd < 0) {
+	    if (errno == ENOENT) /* This is just a timing problem. */
+		continue;
+	    error("Can't open existing lock file %s: %m", lock_file);
+	    break;
+	}
+#ifndef LOCK_BINARY
+	n = read(fd, lock_buffer, 11);
+#else
+	n = read(fd, &pid, sizeof(pid));
+#endif /* LOCK_BINARY */
+	close(fd);
+	fd = -1;
+	if (n <= 0) {
+	    error("Can't read pid from lock file %s", lock_file);
+	    break;
+	}
+
+	/* See if the process still exists. */
+#ifndef LOCK_BINARY
+	lock_buffer[n] = 0;
+	pid = atoi(lock_buffer);
+#endif /* LOCK_BINARY */
+	if (pid == getpid())
+	    return 1;		/* somebody else locked it for us */
+	if (pid == 0
+	    || (kill(pid, 0) == -1 && errno == ESRCH)) {
+	    if (unlink (lock_file) == 0) {
+		notice("Removed stale lock on %s (pid %d)", dev, pid);
+		continue;
+	    }
+	    warn("Couldn't remove stale lock on %s", dev);
+	} else
+	    notice("Device %s is locked by pid %d", dev, pid);
+	break;
+    }
+
+    if (fd < 0) {
+	lock_file[0] = 0;
+	return -1;
+    }
+
+    pid = getpid();
+#ifndef LOCK_BINARY
+    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+    write (fd, lock_buffer, 11);
+#else
+    write(fd, &pid, sizeof (pid));
+#endif
+    close(fd);
+    return 0;
+
+#endif
+}
+
+/*
+ * relock - called to update our lockfile when we are about to detach,
+ * thus changing our pid (we fork, the child carries on, and the parent dies).
+ * Note that this is called by the parent, with pid equal to the pid
+ * of the child.  This avoids a potential race which would exist if
+ * we had the child rewrite the lockfile (the parent might die first,
+ * and another process could think the lock was stale if it checked
+ * between when the parent died and the child rewrote the lockfile).
+ */
+int
+relock(int pid)
+{
+#ifdef LOCKLIB
+    /* XXX is there a way to do this? */
+    return -1;
+#else /* LOCKLIB */
+
+    int fd;
+    char lock_buffer[12];
+
+    if (lock_file[0] == 0)
+	return -1;
+    fd = open(lock_file, O_WRONLY, 0);
+    if (fd < 0) {
+	error("Couldn't reopen lock file %s: %m", lock_file);
+	lock_file[0] = 0;
+	return -1;
+    }
+
+#ifndef LOCK_BINARY
+    slprintf(lock_buffer, sizeof(lock_buffer), "%10d\n", pid);
+    write (fd, lock_buffer, 11);
+#else
+    write(fd, &pid, sizeof(pid));
+#endif /* LOCK_BINARY */
+    close(fd);
+    return 0;
+
+#endif /* LOCKLIB */
+}
+
+/*
+ * unlock - remove our lockfile
+ */
+void
+unlock(void)
+{
+    if (lock_file[0]) {
+#ifdef LOCKLIB
+	(void) rmlock(lock_file, (void *) 0);
+#else
+	unlink(lock_file);
+#endif
+	lock_file[0] = 0;
+    }
+}
diff --git a/rtemsbsd/sys/net/if_ppp.c b/rtemsbsd/sys/net/if_ppp.c
new file mode 100644
index 0000000..4549910
--- /dev/null
+++ b/rtemsbsd/sys/net/if_ppp.c
@@ -0,0 +1,1765 @@
+/*
+ * if_ppp.c - Point-to-Point Protocol (PPP) Asynchronous driver.
+ */
+
+/*-
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Drew D. Perkins
+ * Carnegie Mellon University
+ * 4910 Forbes Ave.
+ * Pittsburgh, PA 15213
+ * (412) 268-8576
+ * ddp at andrew.cmu.edu
+ *
+ * Based on:
+ *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Serial Line interface
+ *
+ * Rick Adams
+ * Center for Seismic Studies
+ * 1300 N 17th Street, Suite 1450
+ * Arlington, Virginia 22209
+ * (703)276-7900
+ * rick at seismo.ARPA
+ * seismo!rick
+ *
+ * Pounded on heavily by Chris Torek (chris at mimsy.umd.edu, umcp-cs!chris).
+ * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
+ *
+ * Converted to 4.3BSD+ 386BSD by Brad Parker (brad at cayman.com)
+ * Added VJ tcp header compression; more unified ioctls
+ *
+ * Extensively modified by Paul Mackerras (paulus at cs.anu.edu.au).
+ * Cleaned up a lot of the mbuf-related code to fix bugs that
+ * caused system crashes and packet corruption.  Changed pppstart
+ * so that it doesn't just give up with a collision if the whole
+ * packet doesn't fit in the output ring buffer.
+ *
+ * Added priority queueing for interactive IP packets, following
+ * the model of if_sl.c, plus hooks for bpf.
+ * Paul Mackerras (paulus at cs.anu.edu.au).
+ */
+
+/* $FreeBSD: src/sys/net/if_ppp.c,v 1.109 2005/10/12 19:52:16 thompsa Exp $ */
+/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
+/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opt_inet.h"
+#include "opt_ipx.h"
+#include "opt_mac.h"
+#include "opt_ppp.h"
+
+#if NPPP > 0
+
+#include <termios.h>
+#include <rtems/termiostypes.h>
+#include <rtems/rtems_bsdnet.h>
+#include <rtems/rtemspppd.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/kernel.h>
+#include <sys/time.h>
+#include <sys/malloc.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <net/netisr.h>
+#include <net/route.h>
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
+
+#if INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#endif
+
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifdef VJC
+#include <net/slcompress.h>
+#endif
+
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#include <net/if_pppvar.h>
+#include <machine/cpu.h>
+
+#define splsoftnet	splnet
+
+#ifdef PPP_COMPRESS
+#define PACKETPTR	struct mbuf *
+#include <net/ppp-comp.h>
+#endif
+
+static struct	ppp_softc ppp_softc[NPPP];
+
+static int	pppsioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data);
+static void	ppp_requeue(struct ppp_softc *);
+#ifdef PPP_COMPRESS
+static void	ppp_ccp(struct ppp_softc *, struct mbuf *m, int rcvd);
+static void	ppp_ccp_closed(struct ppp_softc *);
+#endif
+static struct mbuf *ppp_inproc(struct ppp_softc *, struct mbuf *);
+static void	pppdumpm(struct mbuf *m0);
+
+/*
+ * Some useful mbuf macros not in mbuf.h.
+ */
+#define M_IS_CLUSTER(m)	((m)->m_flags & M_EXT)
+
+#define M_DATASTART(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
+	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
+
+#define M_DATASIZE(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
+	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+
+/*
+ * We steal two bits in the mbuf m_flags, to mark high-priority packets
+ * for output, and received packets following lost/corrupted packets.
+ */
+#define M_HIGHPRI	0x2000	/* output packet for sc_fastq */
+#define M_ERRMARK	0x4000	/* steal a bit in mbuf m_flags */
+
+
+#ifdef PPP_COMPRESS
+/*
+ * List of compressors we know about.
+ * We leave some space so maybe we can modload compressors.
+ */
+
+extern struct compressor ppp_bsd_compress;
+extern struct compressor ppp_deflate, ppp_deflate_draft;
+
+struct compressor *ppp_compressors[8] = {
+#if DO_BSD_COMPRESS
+    &ppp_bsd_compress,
+#endif
+#if DO_DEFLATE
+    &ppp_deflate,
+    &ppp_deflate_draft,
+#endif
+    NULL
+};
+#endif /* PPP_COMPRESS */
+
+extern struct ifqueue    ipintrq;
+static struct timeval    ppp_time;
+
+#ifndef __rtems__
+TEXT_SET(pseudo_set, ppp_rxdaemon);
+#endif
+
+static int
+ppp_unit(struct ppp_softc *sc)
+{
+  return sc->sc_if.if_unit;
+}
+
+static rtems_task ppp_rxdaemon(rtems_task_argument arg)
+{
+  rtems_event_set             events;
+  rtems_interrupt_level       level;
+  struct ppp_softc           *sc = (struct ppp_softc *)arg;
+  struct mbuf                *mp = (struct mbuf      *)0;
+  struct mbuf                *m;
+
+  /* enter processing loop */
+  while ( 1 ) {
+    /* wait for event */
+    rtems_event_receive(RX_PACKET|RX_MBUF|RX_EMPTY,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events);
+    if ( events & RX_EMPTY ) {
+      printf("RX: QUEUE is EMPTY\n");
+      events &= ~RX_EMPTY;
+    }
+
+    if ( events ) {
+      /* get the network semaphore */
+      rtems_bsdnet_semaphore_obtain();
+
+      /* check to see if new packet was received */
+      if ( events & RX_PACKET ) {
+        /* get received packet mbuf chain */
+        rtems_interrupt_disable(level);
+        IF_DEQUEUE(&sc->sc_rawq, m);
+        rtems_interrupt_enable(level);
+
+        /* ensure packet was retrieved */
+        if ( m != (struct mbuf *)0 ) {
+          /* process the received packet */
+          mp = ppp_inproc(sc, m);
+        }
+      }
+
+      /* allocate a new mbuf to replace one */
+      if ( mp == NULL ) {
+        pppallocmbuf(sc, &mp);
+      }
+
+      /* place mbuf on freeq */
+      rtems_interrupt_disable(level);
+      IF_ENQUEUE(&sc->sc_freeq, mp);
+      rtems_interrupt_enable(level);
+      mp = (struct mbuf *)0;
+
+      /* release the network semaphore */
+      rtems_bsdnet_semaphore_release();
+
+      /* check to see if queue is empty */
+      if ( sc->sc_rawq.ifq_head ) {
+        /* queue is not empty - post another event */
+        rtems_event_send(sc->sc_rxtask, RX_PACKET);
+      }
+    }
+  }
+}
+
+static rtems_task ppp_txdaemon(rtems_task_argument arg)
+{
+  rtems_event_set             events;
+  int                         iprocess = (int               )0;
+  struct ppp_softc           *sc       = (struct ppp_softc *)arg;
+#ifdef LALL_X
+  struct mbuf                *mp;
+#endif
+  struct mbuf                *mf;
+  struct mbuf                *m;
+  struct rtems_termios_tty   *tp;
+  
+  int frag;
+
+  /* enter processing loop */
+  while ( 1 ) {
+    /* wait for event */
+    rtems_event_receive(TX_PACKET|TX_TRANSMIT,RTEMS_WAIT|RTEMS_EVENT_ANY,RTEMS_NO_TIMEOUT,&events);
+    if ( events & TX_TRANSMIT ) {
+      /* received event from interrupt handler - free current mbuf */
+      rtems_bsdnet_semaphore_obtain();
+
+      m_freem(sc->sc_outm);
+      
+      rtems_bsdnet_semaphore_release();
+
+      /* chain is done - clear the values */
+      sc->sc_outm  = (struct mbuf *)0;
+      sc->sc_outmc = (struct mbuf *)0;
+
+      /* now set flag to fake receive of TX_PACKET event */
+      /* this will check to see if we have any pending packets */
+      events |= TX_PACKET;
+    }
+
+    /* received event from pppasyncstart */
+    if ( events & TX_PACKET ) {
+      /* ensure we are not busy */
+      if ( sc->sc_outm == (struct mbuf *)0 ) {
+        /* try dequeuing a packet */
+        sc->sc_outm = ppp_dequeue(sc);
+        if ( sc->sc_outm == NULL ) {
+          /* clear output flags */
+          sc->sc_outflag      = 0;
+          sc->sc_if.if_flags &= ~IFF_OACTIVE;
+        }
+        else {
+          /* set flag to start process */
+          iprocess            = 1;
+          sc->sc_outflag      = SC_TX_BUSY;
+          sc->sc_if.if_flags |= IFF_OACTIVE;
+        }
+      }
+    }
+
+    /* check to see if there is any processing required */
+    if ( iprocess ) {
+      /* clear process flag */
+      iprocess = (int)0;
+      frag=0;
+
+      /* initialize output values */
+      sc->sc_outfcs    = PPP_INITFCS;
+      sc->sc_outbuf    = (u_char *)0;
+      sc->sc_outlen    = (short   )0;
+      sc->sc_outoff    = (short   )0;
+      sc->sc_outfcslen = (short   )0;
+
+/*	  printf("Start Transmit Packet..\n"); */
+
+      /* loop over all mbufs in chain */
+      mf     = NULL;
+#ifdef LALL_X
+      mp     = NULL;
+#endif
+      m      = sc->sc_outm;
+
+      sc->sc_outmc  = m;
+      sc->sc_outlen = m->m_len;
+      sc->sc_outbuf = mtod(m, u_char *);
+
+      while (( m != (struct mbuf *)0 ) && ( m->m_len > 0 )) {
+      	frag++;
+
+        /* update the FCS value and then check next packet length */
+        if(m->m_len){
+       	 sc->sc_outfcs = pppfcs(sc->sc_outfcs, mtod(m, u_char *), m->m_len);
+       	}
+
+        if(( m->m_next != NULL ) && ( m->m_next->m_len == 0 )) {
+			if(mf){
+				printf(" if_ppp.c : MBUF Error !!!!\n");
+			}
+			else{
+            	mf = m->m_next;
+	        	m->m_next = NULL;
+			}
+		}
+
+#ifdef LALL_X
+        /* check next packet to see if it is empty */
+        while (( m->m_next != NULL ) && ( m->m_next->m_len == 0 )) {
+          /* next mbuf is zero length */
+          /* add empty mbuf to free chain */
+          if ( mp == NULL ) {
+            /* item is head of free list */
+            mf = m->m_next;
+            mp = mf;
+          }
+          else {
+            /* add item to end of the free list */
+            mp->m_next = m->m_next;
+            mp         = m->m_next;
+          }
+
+          /* remove empty item from process chain */
+          m->m_next  = m->m_next->m_next;
+          mp->m_next = NULL;
+        }
+#endif
+        /* move to next packet */
+        m = m->m_next;
+      }
+
+      /* ensure there is data to be sent out */
+      tp = (struct rtems_termios_tty *)sc->sc_devp;
+      if (( tp != NULL ) && ( sc->sc_outmc != (struct mbuf *)0 )) {
+        /* place FCS value into buffer */
+        sc->sc_outfcsbuf[sc->sc_outfcslen++] = ~sc->sc_outfcs & 0xff;
+        sc->sc_outfcsbuf[sc->sc_outfcslen++] = (~sc->sc_outfcs >> 8) & 0xff;
+        microtime(&sc->sc_if.if_lastchange);
+  
+        /* write out frame byte to start the transmission */
+		sc->sc_outchar = (u_char)PPP_FLAG;
+        (*tp->handler.write)(tp->device_context, (char *)&sc->sc_outchar, 1);
+      }
+
+      /* check to see if we need to free some empty mbufs */
+      if ( mf != (struct mbuf *)0 ) {
+        /* free empty mbufs */
+        rtems_bsdnet_semaphore_obtain();
+        m_freem(mf);
+        rtems_bsdnet_semaphore_release();
+      }
+    }
+  }
+}
+
+static void ppp_init(struct ppp_softc *sc)
+{
+  rtems_status_code   status;
+  uint32_t      priority = 100;
+
+  /* determine priority value */
+  if ( rtems_bsdnet_config.network_task_priority ) {
+    priority = rtems_bsdnet_config.network_task_priority;
+  }
+
+  /* check to see if we need to start up daemons */
+  if ( sc->sc_rxtask == 0 ) {
+    /* start rx daemon task */
+    status = rtems_task_create(rtems_build_name('R','x','P','0'+ppp_unit(sc)), priority, 2048,
+                               RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+                               RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+                               &sc->sc_rxtask);
+    if (status != RTEMS_SUCCESSFUL) {
+      rtems_fatal_error_occurred(status);
+    }
+    else {
+      status = rtems_task_start(sc->sc_rxtask, ppp_rxdaemon, (rtems_task_argument)sc);
+      if (status != RTEMS_SUCCESSFUL) {
+        rtems_fatal_error_occurred(status);
+      }
+    }
+
+    /* start tx daemon task */
+    status = rtems_task_create(rtems_build_name('T','x','P','0'+ppp_unit(sc)), priority, 2048,
+                               RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0),
+                               RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL,
+                               &sc->sc_txtask);
+    if (status != RTEMS_SUCCESSFUL) {
+      rtems_fatal_error_occurred(status);
+    }
+    else {
+      status = rtems_task_start(sc->sc_txtask, ppp_txdaemon, (rtems_task_argument)sc);
+      if (status != RTEMS_SUCCESSFUL) {
+        rtems_fatal_error_occurred(status);
+      }
+    }
+  }
+
+  /* mark driver running and output inactive */
+  /* ilya: IFF_RUNNING flag will be marked after the IPCP goes up */
+/*  sc->sc_if.if_flags |= IFF_RUNNING;	*/
+}
+
+/*
+ * Called from boot code to establish ppp interfaces.
+ */
+int rtems_ppp_driver_attach(struct rtems_bsdnet_ifconfig *config, int attaching)
+{
+/*    int                 i = (int)0;	*/
+    struct ppp_softc   *sc;
+    char               *name;
+    int                 number;
+    
+    
+    number = rtems_bsdnet_parse_driver_name (config, &name);
+    
+    if (!attaching || (number >= NPPP))
+        return 0;
+	
+    sc = &ppp_softc[number];
+    
+    if (sc->sc_if.if_name != NULL)
+	return 0;	/* interface is already attached */
+    
+/*    for (sc = ppp_softc; i < NPPP; sc++) {	*/
+	sc->sc_if.if_name = name /*"ppp"*/;
+	sc->sc_if.if_unit = number /*i++*/;
+	sc->sc_if.if_mtu = PPP_MTU;
+	sc->sc_if.if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
+	sc->sc_if.if_type = IFT_PPP;
+	sc->sc_if.if_hdrlen = PPP_HDRLEN;
+	sc->sc_if.if_ioctl = pppsioctl;
+	sc->sc_if.if_output = pppoutput;
+	sc->sc_if.if_snd.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_inq.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_fastq.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_rawq.ifq_maxlen = IFQ_MAXLEN;
+	sc->sc_freeq.ifq_maxlen = NUM_MBUFQ;
+
+        /* initialize and attach */
+	ppp_init(sc);
+	if_attach(&sc->sc_if);
+#if NBPFILTER > 0
+	bpfattach(&sc->sc_bpf, &sc->sc_if, DLT_PPP, PPP_HDRLEN);
+#endif
+/*    }	*/
+
+    return ( 1 );
+}
+
+/*
+ * Allocate a ppp interface unit and initialize it.
+ */
+struct ppp_softc *
+pppalloc(pid_t pid)
+{
+    int nppp, i;
+    struct ppp_softc *sc;
+
+    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
+	if (sc->sc_xfer == pid) {
+	    sc->sc_xfer = 0;
+	    return sc;
+	}
+    for (nppp = 0, sc = ppp_softc; nppp < NPPP; nppp++, sc++)
+	if (sc->sc_devp == NULL)
+	    break;
+    if (nppp >= NPPP)
+	return NULL;
+
+    sc->sc_flags = 0;
+    sc->sc_mru = PPP_MRU;
+    sc->sc_relinq = NULL;
+    bzero((char *)&sc->sc_stats, sizeof(sc->sc_stats));
+#ifdef VJC
+    MALLOC(sc->sc_comp, struct vjcompress *, sizeof(struct vjcompress),
+	   M_DEVBUF, M_NOWAIT);
+    if (sc->sc_comp)
+	sl_compress_init(sc->sc_comp, -1);
+#endif
+#ifdef PPP_COMPRESS
+    sc->sc_xc_state = NULL;
+    sc->sc_rc_state = NULL;
+#endif /* PPP_COMPRESS */
+    for (i = 0; i < NUM_NP; ++i)
+	sc->sc_npmode[i] = NPMODE_ERROR;
+    sc->sc_npqueue = NULL;
+    sc->sc_npqtail = &sc->sc_npqueue;
+    microtime(&ppp_time);
+    sc->sc_last_sent = sc->sc_last_recv = ppp_time.tv_sec;
+
+    return sc;
+}
+
+/*
+ * Deallocate a ppp unit.  Must be called at splsoftnet or higher.
+ */
+void
+pppdealloc(struct ppp_softc *sc)
+{
+    struct mbuf *m;
+    rtems_interrupt_level       level;
+
+    if_down(&sc->sc_if);
+    sc->sc_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
+    sc->sc_devp = NULL;
+    sc->sc_xfer = 0;
+
+    rtems_interrupt_disable(level);
+    if ( sc->sc_m != NULL ) {
+	m_freem(sc->sc_m);
+        sc->sc_m = (struct mbuf *)0;
+    }
+    if ( sc->sc_outm != NULL ) {
+	m_freem(sc->sc_outm);
+        sc->sc_outm    = (struct mbuf *)0;
+        sc->sc_outmc   = (struct mbuf *)0;
+        sc->sc_outflag = 0;
+    }
+    do {
+      IF_DEQUEUE(&sc->sc_freeq, m);
+      if (m != NULL) {
+        m_freem(m);
+      }
+    } while ( m != NULL );
+    do {
+      IF_DEQUEUE(&sc->sc_rawq, m);
+      if (m != NULL) {
+        m_freem(m);
+      }
+    } while ( m != NULL );
+    rtems_interrupt_enable(level);
+
+    for (;;) {
+	IF_DEQUEUE(&sc->sc_inq, m);
+	if (m == NULL)
+	    break;
+	m_freem(m);
+    }
+    for (;;) {
+	IF_DEQUEUE(&sc->sc_fastq, m);
+	if (m == NULL)
+	    break;
+	m_freem(m);
+    }
+    while ((m = sc->sc_npqueue) != NULL) {
+	sc->sc_npqueue = m->m_nextpkt;
+	m_freem(m);
+    }
+#ifdef PPP_COMPRESS
+    ppp_ccp_closed(sc);
+    sc->sc_xc_state = NULL;
+    sc->sc_rc_state = NULL;
+#endif /* PPP_COMPRESS */
+#ifdef PPP_FILTER
+    if (sc->sc_pass_filt.bf_insns != 0) {
+	FREE(sc->sc_pass_filt.bf_insns, M_DEVBUF);
+	sc->sc_pass_filt.bf_insns = 0;
+	sc->sc_pass_filt.bf_len = 0;
+    }
+    if (sc->sc_active_filt.bf_insns != 0) {
+	FREE(sc->sc_active_filt.bf_insns, M_DEVBUF);
+	sc->sc_active_filt.bf_insns = 0;
+	sc->sc_active_filt.bf_len = 0;
+    }
+#endif /* PPP_FILTER */
+#ifdef VJC
+    if (sc->sc_comp != 0) {
+	FREE(sc->sc_comp, M_DEVBUF);
+	sc->sc_comp = 0;
+    }
+#endif
+}
+
+/*
+ * Ioctl routine for generic ppp devices.
+ */
+int
+pppioctl(struct ppp_softc *sc, ioctl_command_t cmd, caddr_t data,
+    int flag, struct proc *p)
+{
+    int s, flags, mru, npx, taskid;
+    struct npioctl *npi;
+    time_t t;
+#ifdef PPP_FILTER
+    int error;
+    struct bpf_program *bp, *nbp;
+    struct bpf_insn *newcode, *oldcode;
+    int newcodelen;
+#endif /* PPP_FILTER */
+#ifdef	PPP_COMPRESS
+    int nb;
+    struct ppp_option_data *odp;
+    struct compressor **cp;
+    u_char ccp_option[CCP_MAX_OPTION_LENGTH];
+#endif
+
+    switch (cmd) {
+    case FIONREAD:
+	*(int *)data = sc->sc_inq.ifq_len;
+	break;
+
+    case PPPIOCSTASK:
+	taskid = *(int *)data;
+	sc->sc_pppdtask = taskid;
+	break;
+
+    case PPPIOCGUNIT:
+	*(int *)data = ppp_unit(sc);
+	break;
+
+    case PPPIOCGFLAGS:
+	*(u_int *)data = sc->sc_flags;
+	break;
+
+    case PPPIOCSFLAGS:
+	flags = *(int *)data & SC_MASK;
+	s = splsoftnet();
+#ifdef PPP_COMPRESS
+	if (sc->sc_flags & SC_CCP_OPEN && !(flags & SC_CCP_OPEN))
+	    ppp_ccp_closed(sc);
+#endif
+	s = splimp();
+	sc->sc_flags = (sc->sc_flags & ~SC_MASK) | flags;
+	splx(s);
+	break;
+
+    case PPPIOCSMRU:
+	mru = *(int *)data;
+        if ( mru >= MCLBYTES ) {
+          /* error - currently only handle 1 culster sized MRU */
+          /* if we want to handle up to PPP_MAXMRU then we */
+          /*   need to reallocate all mbufs on the freeq */
+          /*   this can only be done with iterrupts disabled */
+          return ( -1 );
+        }
+        else if ( mru >= PPP_MRU ) {
+          /* update the size */
+          sc->sc_mru = mru;
+        }
+	break;
+
+    case PPPIOCGMRU:
+	*(int *)data = sc->sc_mru;
+	break;
+
+#ifdef VJC
+    case PPPIOCSMAXCID:
+	if (sc->sc_comp) {
+	    s = splsoftnet();
+	    sl_compress_init(sc->sc_comp, *(int *)data);
+	    splx(s);
+	}
+	break;
+#endif
+
+    case PPPIOCXFERUNIT:
+	sc->sc_xfer = 0; /* Always root p->p_pid;*/
+	break;
+
+#ifdef PPP_COMPRESS
+    case PPPIOCSCOMPRESS:
+	odp = (struct ppp_option_data *) data;
+	nb = odp->length;
+	if (nb > sizeof(ccp_option))
+	    nb = sizeof(ccp_option);
+	if ((error = copyin(odp->ptr, ccp_option, nb)) != 0)
+	    return (error);
+	if (ccp_option[1] < 2)	/* preliminary check on the length byte */
+	    return (EINVAL);
+	for (cp = ppp_compressors; *cp != NULL; ++cp)
+	    if ((*cp)->compress_proto == ccp_option[0]) {
+		/*
+		 * Found a handler for the protocol - try to allocate
+		 * a compressor or decompressor.
+		 */
+		error = 0;
+		if (odp->transmit) {
+		    s = splsoftnet();
+		    if (sc->sc_xc_state != NULL)
+			(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
+		    sc->sc_xcomp = *cp;
+		    sc->sc_xc_state = (*cp)->comp_alloc(ccp_option, nb);
+		    if (sc->sc_xc_state == NULL) {
+			if (sc->sc_flags & SC_DEBUG)
+			    printf("ppp%d: comp_alloc failed\n",
+			       ppp_unit(sc));
+			error = ENOBUFS;
+		    }
+		    splimp();
+		    sc->sc_flags &= ~SC_COMP_RUN;
+		    splx(s);
+		} else {
+		    s = splsoftnet();
+		    if (sc->sc_rc_state != NULL)
+			(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
+		    sc->sc_rcomp = *cp;
+		    sc->sc_rc_state = (*cp)->decomp_alloc(ccp_option, nb);
+		    if (sc->sc_rc_state == NULL) {
+			if (sc->sc_flags & SC_DEBUG)
+			    printf("ppp%d: decomp_alloc failed\n",
+			       ppp_unit(sc));
+			error = ENOBUFS;
+		    }
+		    splimp();
+		    sc->sc_flags &= ~SC_DECOMP_RUN;
+		    splx(s);
+		}
+		return (error);
+	    }
+	if (sc->sc_flags & SC_DEBUG)
+	    printf("ppp%d: no compressor for [%x %x %x], %x\n",
+		   ppp_unit(sc), ccp_option[0], ccp_option[1],
+		   ccp_option[2], nb);
+	return (EINVAL);	/* no handler found */
+#endif /* PPP_COMPRESS */
+
+    case PPPIOCGNPMODE:
+    case PPPIOCSNPMODE:
+	npi = (struct npioctl *) data;
+	switch (npi->protocol) {
+	case PPP_IP:
+	    npx = NP_IP;
+	    break;
+	default:
+	    return EINVAL;
+	}
+	if (cmd == PPPIOCGNPMODE) {
+	    npi->mode = sc->sc_npmode[npx];
+	} else {
+	    if (npi->mode != sc->sc_npmode[npx]) {
+		s = splsoftnet();
+		sc->sc_npmode[npx] = npi->mode;
+		if (npi->mode != NPMODE_QUEUE) {
+		    ppp_requeue(sc);
+		    (*sc->sc_start)(sc);
+		}
+		splx(s);
+	    }
+	}
+	break;
+
+    case PPPIOCGIDLE:
+	s = splsoftnet();
+        microtime(&ppp_time);
+	t = ppp_time.tv_sec;
+	((struct ppp_idle *)data)->xmit_idle = t - sc->sc_last_sent;
+	((struct ppp_idle *)data)->recv_idle = t - sc->sc_last_recv;
+	splx(s);
+	break;
+
+#ifdef PPP_FILTER
+    case PPPIOCSPASS:
+    case PPPIOCSACTIVE:
+	nbp = (struct bpf_program *) data;
+	if ((unsigned) nbp->bf_len > BPF_MAXINSNS)
+	    return EINVAL;
+	newcodelen = nbp->bf_len * sizeof(struct bpf_insn);
+	if (newcodelen != 0) {
+	    MALLOC(newcode, struct bpf_insn *, newcodelen, M_DEVBUF, M_WAITOK);
+	    if (newcode == 0) {
+		return EINVAL;		/* or sumpin */
+	    }
+	    if ((error = copyin((caddr_t)nbp->bf_insns, (caddr_t)newcode,
+			       newcodelen)) != 0) {
+		FREE(newcode, M_DEVBUF);
+		return error;
+	    }
+	    if (!bpf_validate(newcode, nbp->bf_len)) {
+		FREE(newcode, M_DEVBUF);
+		return EINVAL;
+	    }
+	} else
+	    newcode = 0;
+	bp = (cmd == PPPIOCSPASS)? &sc->sc_pass_filt: &sc->sc_active_filt;
+	oldcode = bp->bf_insns;
+	s = splimp();
+	bp->bf_len = nbp->bf_len;
+	bp->bf_insns = newcode;
+	splx(s);
+	if (oldcode != 0)
+	    FREE(oldcode, M_DEVBUF);
+	break;
+#endif
+
+    default:
+	return (-1);
+    }
+    return (0);
+}
+
+/*
+ * Process an ioctl request to the ppp network interface.
+ */
+static int
+pppsioctl(struct ifnet *ifp, ioctl_command_t cmd, caddr_t data)
+{
+    /*struct proc *p = curproc;*/	/* XXX */
+    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
+    register struct ifaddr *ifa = (struct ifaddr *)data;
+    register struct ifreq *ifr = (struct ifreq *)data;
+    struct ppp_stats *psp;
+#ifdef	PPP_COMPRESS
+    struct ppp_comp_stats *pcp;
+#endif
+    int s = splimp(), error = 0;
+
+    switch (cmd) {
+    case SIOCSIFFLAGS:
+	if ((ifp->if_flags & IFF_RUNNING) == 0)
+	    ifp->if_flags &= ~IFF_UP;
+	break;
+
+    case SIOCSIFADDR:
+	if (ifa->ifa_addr->sa_family != AF_INET)
+	    error = EAFNOSUPPORT;
+	break;
+
+    case SIOCSIFDSTADDR:
+	if (ifa->ifa_addr->sa_family != AF_INET)
+	    error = EAFNOSUPPORT;
+	break;
+
+    case SIOCSIFMTU:
+	sc->sc_if.if_mtu = ifr->ifr_mtu;
+	break;
+
+    case SIOCGIFMTU:
+	ifr->ifr_mtu = sc->sc_if.if_mtu;
+	break;
+
+    case SIOCADDMULTI:
+    case SIOCDELMULTI:
+	if (ifr == 0) {
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	switch(ifr->ifr_addr.sa_family) {
+#ifdef INET
+	case AF_INET:
+	    break;
+#endif
+	default:
+	    error = EAFNOSUPPORT;
+	    break;
+	}
+	break;
+
+    case SIO_RTEMS_SHOW_STATS:
+        printf("              MRU:%-8u",   sc->sc_mru);
+        printf("   Bytes received:%-8u",   sc->sc_stats.ppp_ibytes);
+        printf(" Packets received:%-8u",   sc->sc_stats.ppp_ipackets);
+        printf("   Receive errors:%-8u\n", sc->sc_stats.ppp_ierrors);
+        printf("       Bytes sent:%-8u",   sc->sc_stats.ppp_obytes);
+        printf("     Packets sent:%-8u",   sc->sc_stats.ppp_opackets);
+        printf("  Transmit errors:%-8u\n", sc->sc_stats.ppp_oerrors);
+	break;
+
+    case SIOCGPPPSTATS:
+	psp = &((struct ifpppstatsreq *) data)->stats;
+	bzero(psp, sizeof(*psp));
+	psp->p = sc->sc_stats;
+#if defined(VJC) && !defined(SL_NO_STATS)
+	if (sc->sc_comp) {
+	    psp->vj.vjs_packets = sc->sc_comp->sls_packets;
+	    psp->vj.vjs_compressed = sc->sc_comp->sls_compressed;
+	    psp->vj.vjs_searches = sc->sc_comp->sls_searches;
+	    psp->vj.vjs_misses = sc->sc_comp->sls_misses;
+	    psp->vj.vjs_uncompressedin = sc->sc_comp->sls_uncompressedin;
+	    psp->vj.vjs_compressedin = sc->sc_comp->sls_compressedin;
+	    psp->vj.vjs_errorin = sc->sc_comp->sls_errorin;
+	    psp->vj.vjs_tossed = sc->sc_comp->sls_tossed;
+	}
+#endif /* VJC */
+	break;
+
+#ifdef PPP_COMPRESS
+    case SIOCGPPPCSTATS:
+	pcp = &((struct ifpppcstatsreq *) data)->stats;
+	bzero(pcp, sizeof(*pcp));
+	if (sc->sc_xc_state != NULL)
+	    (*sc->sc_xcomp->comp_stat)(sc->sc_xc_state, &pcp->c);
+	if (sc->sc_rc_state != NULL)
+	    (*sc->sc_rcomp->decomp_stat)(sc->sc_rc_state, &pcp->d);
+	break;
+#endif /* PPP_COMPRESS */
+
+    default:
+	error = EINVAL;
+    }
+    splx(s);
+    return (error);
+}
+
+/*
+ * Queue a packet.  Start transmission if not active.
+ * Packet is placed in Information field of PPP frame.
+ */
+int
+pppoutput(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
+    struct rtentry *rtp)
+{
+    register struct ppp_softc *sc = &ppp_softc[ifp->if_unit];
+    int protocol, address, control;
+    u_char *cp;
+    int s, error;
+    struct ip *ip;
+    struct ifqueue *ifq;
+    enum NPmode mode;
+    int len;
+    struct mbuf *m;
+
+    if (sc->sc_devp == NULL || (ifp->if_flags & IFF_RUNNING) == 0
+	|| ((ifp->if_flags & IFF_UP) == 0 && dst->sa_family != AF_UNSPEC)) {
+	error = ENETDOWN;	/* sort of */
+	goto bad;
+    }
+
+    /*
+     * Compute PPP header.
+     */
+    m0->m_flags &= ~M_HIGHPRI;
+    switch (dst->sa_family) {
+#ifdef INET
+    case AF_INET:
+	address = PPP_ALLSTATIONS;
+	control = PPP_UI;
+	protocol = PPP_IP;
+	mode = sc->sc_npmode[NP_IP];
+
+	/*
+	 * If this packet has the "low delay" bit set in the IP header,
+	 * put it on the fastq instead.
+	 */
+	ip = mtod(m0, struct ip *);
+	if (ip->ip_tos & IPTOS_LOWDELAY)
+	    m0->m_flags |= M_HIGHPRI;
+	break;
+#endif
+    case AF_UNSPEC:
+	address = PPP_ADDRESS(dst->sa_data);
+	control = PPP_CONTROL(dst->sa_data);
+	protocol = PPP_PROTOCOL(dst->sa_data);
+	mode = NPMODE_PASS;
+	break;
+    default:
+	printf("ppp%d: af%d not supported\n", ppp_unit(sc), dst->sa_family);
+	error = EAFNOSUPPORT;
+	goto bad;
+    }
+
+    /*
+     * Drop this packet, or return an error, if necessary.
+     */
+    if (mode == NPMODE_ERROR) {
+	error = ENETDOWN;
+	goto bad;
+    }
+    if (mode == NPMODE_DROP) {
+	error = 0;
+	goto bad;
+    }
+
+    /*
+     * Add PPP header.  If no space in first mbuf, allocate another.
+     * (This assumes M_LEADINGSPACE is always 0 for a cluster mbuf.)
+     */
+    if (M_LEADINGSPACE(m0) < PPP_HDRLEN) {
+	m0 = m_prepend(m0, PPP_HDRLEN, M_DONTWAIT);
+	if (m0 == 0) {
+	    error = ENOBUFS;
+	    goto bad;
+	}
+	m0->m_len = 0;
+    } else
+	m0->m_data -= PPP_HDRLEN;
+
+    cp = mtod(m0, u_char *);
+    *cp++ = address;
+    *cp++ = control;
+    *cp++ = protocol >> 8;
+    *cp++ = protocol & 0xff;
+    m0->m_len += PPP_HDRLEN;
+
+    len = 0;
+    for (m = m0; m != 0; m = m->m_next)
+	len += m->m_len;
+
+    if (sc->sc_flags & SC_LOG_OUTPKT) {
+	printf("ppp%d output: ", ppp_unit(sc));
+	pppdumpm(m0);
+    }
+
+    if ((protocol & 0x8000) == 0) {
+#ifdef PPP_FILTER
+	/*
+	 * Apply the pass and active filters to the packet,
+	 * but only if it is a data packet.
+	 */
+	*mtod(m0, u_char *) = 1;	/* indicates outbound */
+	if (sc->sc_pass_filt.bf_insns != 0
+	    && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m0,
+			  len, 0) == 0) {
+	    error = 0;		/* drop this packet */
+	    goto bad;
+	}
+
+	/*
+	 * Update the time we sent the most recent packet.
+	 */
+	if (sc->sc_active_filt.bf_insns == 0
+	    || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m0, len, 0))
+	    sc->sc_last_sent = time.tv_sec;
+
+	*mtod(m0, u_char *) = address;
+#else
+	/*
+	 * Update the time we sent the most recent data packet.
+	 */
+	microtime(&ppp_time);
+	sc->sc_last_sent = ppp_time.tv_sec;
+#endif /* PPP_FILTER */
+    }
+
+#if NBPFILTER > 0
+    /*
+     * See if bpf wants to look at the packet.
+     */
+    if (sc->sc_bpf)
+	bpf_mtap(sc->sc_bpf, m0);
+#endif
+
+    /*
+     * Put the packet on the appropriate queue.
+     */
+    s = splsoftnet();
+    if (mode == NPMODE_QUEUE) {
+	/* XXX we should limit the number of packets on this queue */
+	*sc->sc_npqtail = m0;
+	m0->m_nextpkt = NULL;
+	sc->sc_npqtail = &m0->m_nextpkt;
+    } else {
+	ifq = (m0->m_flags & M_HIGHPRI)? &sc->sc_fastq: &ifp->if_snd;
+	if (IF_QFULL(ifq) && dst->sa_family != AF_UNSPEC) {
+	    IF_DROP(ifq);
+	    splx(s);
+	    sc->sc_if.if_oerrors++;
+	    sc->sc_stats.ppp_oerrors++;
+	    error = ENOBUFS;
+	    goto bad;
+	}
+	IF_ENQUEUE(ifq, m0);
+	(*sc->sc_start)(sc);
+    }
+    ifp->if_lastchange = ppp_time;
+    ifp->if_opackets++;
+    ifp->if_obytes += len;
+
+    splx(s);
+    return (0);
+
+bad:
+    m_freem(m0);
+    return (error);
+}
+
+/*
+ * After a change in the NPmode for some NP, move packets from the
+ * npqueue to the send queue or the fast queue as appropriate.
+ * Should be called at spl[soft]net.
+ */
+static void
+ppp_requeue(struct ppp_softc *sc)
+{
+    struct mbuf *m, **mpp;
+    struct ifqueue *ifq;
+    enum NPmode mode;
+
+    for (mpp = &sc->sc_npqueue; (m = *mpp) != NULL; ) {
+	switch (PPP_PROTOCOL(mtod(m, u_char *))) {
+	case PPP_IP:
+	    mode = sc->sc_npmode[NP_IP];
+	    break;
+	default:
+	    mode = NPMODE_PASS;
+	}
+
+	switch (mode) {
+	case NPMODE_PASS:
+	    /*
+	     * This packet can now go on one of the queues to be sent.
+	     */
+	    *mpp = m->m_nextpkt;
+	    m->m_nextpkt = NULL;
+	    ifq = (m->m_flags & M_HIGHPRI)? &sc->sc_fastq: &sc->sc_if.if_snd;
+	    if (IF_QFULL(ifq)) {
+		IF_DROP(ifq);
+		sc->sc_if.if_oerrors++;
+		sc->sc_stats.ppp_oerrors++;
+	    } else
+		IF_ENQUEUE(ifq, m);
+	    break;
+
+	case NPMODE_DROP:
+	case NPMODE_ERROR:
+	    *mpp = m->m_nextpkt;
+	    m_freem(m);
+	    break;
+
+	case NPMODE_QUEUE:
+	    mpp = &m->m_nextpkt;
+	    break;
+	}
+    }
+    sc->sc_npqtail = mpp;
+}
+
+/*
+ * Get a packet to send.  This procedure is intended to be called at
+ * splsoftnet, since it may involve time-consuming operations such as
+ * applying VJ compression, packet compression, address/control and/or
+ * protocol field compression to the packet.
+ */
+struct mbuf *
+ppp_dequeue(struct ppp_softc *sc)
+{
+#ifdef PPP_COMPRESS
+    struct mbuf *mp;
+#endif
+    struct mbuf *m;
+    u_char *cp;
+    int address, control, protocol;
+
+    /*
+     * Grab a packet to send: first try the fast queue, then the
+     * normal queue.
+     */
+    rtems_bsdnet_semaphore_obtain();
+    IF_DEQUEUE(&sc->sc_fastq, m);
+    if (m == NULL)
+	IF_DEQUEUE(&sc->sc_if.if_snd, m);
+    rtems_bsdnet_semaphore_release();
+
+    if (m == NULL)
+	return NULL;
+
+    ++sc->sc_stats.ppp_opackets;
+
+    /*
+     * Extract the ppp header of the new packet.
+     * The ppp header will be in one mbuf.
+     */
+    cp = mtod(m, u_char *);
+    address = PPP_ADDRESS(cp);
+    control = PPP_CONTROL(cp);
+    protocol = PPP_PROTOCOL(cp);
+
+    switch (protocol) {
+    case PPP_IP:
+#ifdef VJC
+	/*
+	 * If the packet is a TCP/IP packet, see if we can compress it.
+	 */
+	if ((sc->sc_flags & SC_COMP_TCP) && sc->sc_comp != NULL) {
+	    struct ip *ip;
+	    int type;
+
+	    mp = m;
+	    ip = (struct ip *) (cp + PPP_HDRLEN);
+	    if (mp->m_len <= PPP_HDRLEN) {
+		mp = mp->m_next;
+		if (mp == NULL)
+		    break;
+		ip = mtod(mp, struct ip *);
+	    }
+	    /* this code assumes the IP/TCP header is in one non-shared mbuf */
+	    if (ip->ip_p == IPPROTO_TCP) {
+		type = sl_compress_tcp(mp, ip, sc->sc_comp,
+				       !(sc->sc_flags & SC_NO_TCP_CCID));
+		switch (type) {
+		case TYPE_UNCOMPRESSED_TCP:
+		    protocol = PPP_VJC_UNCOMP;
+		    break;
+		case TYPE_COMPRESSED_TCP:
+		    protocol = PPP_VJC_COMP;
+		    cp = mtod(m, u_char *);
+		    cp[0] = address;	/* header has moved */
+		    cp[1] = control;
+		    cp[2] = 0;
+		    break;
+		}
+		cp[3] = protocol;	/* update protocol in PPP header */
+	    }
+	}
+#endif	/* VJC */
+	break;
+
+#ifdef PPP_COMPRESS
+    case PPP_CCP:
+	ppp_ccp(sc, m, 0);
+	break;
+#endif	/* PPP_COMPRESS */
+    }
+
+#ifdef PPP_COMPRESS
+    if (protocol != PPP_LCP && protocol != PPP_CCP
+	&& sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN)) {
+	struct mbuf *mcomp = NULL;
+	int slen, clen;
+
+	slen = 0;
+	for (mp = m; mp != NULL; mp = mp->m_next)
+	    slen += mp->m_len;
+	clen = (*sc->sc_xcomp->compress)
+	    (sc->sc_xc_state, &mcomp, m, slen, sc->sc_if.if_mtu + PPP_HDRLEN);
+	if (mcomp != NULL) {
+	    if (sc->sc_flags & SC_CCP_UP) {
+		/* Send the compressed packet instead of the original. */
+		m_freem(m);
+		m = mcomp;
+		cp = mtod(m, u_char *);
+		protocol = cp[3];
+	    } else {
+		/* Can't transmit compressed packets until CCP is up. */
+		m_freem(mcomp);
+	    }
+	}
+    }
+#endif	/* PPP_COMPRESS */
+
+    /*
+     * Compress the address/control and protocol, if possible.
+     */
+    if (sc->sc_flags & SC_COMP_AC && address == PPP_ALLSTATIONS &&
+	control == PPP_UI && protocol != PPP_ALLSTATIONS &&
+	protocol != PPP_LCP) {
+	/* can compress address/control */
+	m->m_data += 2;
+	m->m_len -= 2;
+    }
+    if (sc->sc_flags & SC_COMP_PROT && protocol < 0xFF) {
+	/* can compress protocol */
+	if (mtod(m, u_char *) == cp) {
+	    cp[2] = cp[1];	/* move address/control up */
+	    cp[1] = cp[0];
+	}
+	++m->m_data;
+	--m->m_len;
+    }
+
+    return m;
+}
+
+#ifdef PPP_COMPRESS
+/*
+ * Handle a CCP packet.  `rcvd' is 1 if the packet was received,
+ * 0 if it is about to be transmitted.
+ */
+static void
+ppp_ccp(struct ppp_softc *sc, struct mbuf *m, int rcvd)
+{
+    u_char *dp, *ep;
+    struct mbuf *mp;
+    int slen, s;
+
+    /*
+     * Get a pointer to the data after the PPP header.
+     */
+    if (m->m_len <= PPP_HDRLEN) {
+	mp = m->m_next;
+	if (mp == NULL)
+	    return;
+	dp = (mp != NULL)? mtod(mp, u_char *): NULL;
+    } else {
+	mp = m;
+	dp = mtod(mp, u_char *) + PPP_HDRLEN;
+    }
+
+    ep = mtod(mp, u_char *) + mp->m_len;
+    if (dp + CCP_HDRLEN > ep)
+	return;
+    slen = CCP_LENGTH(dp);
+    if (dp + slen > ep) {
+	if (sc->sc_flags & SC_DEBUG)
+	    printf("if_ppp/ccp: not enough data in mbuf (%p+%x > %p+%x)\n",
+		   dp, slen, mtod(mp, u_char *), mp->m_len);
+	return;
+    }
+
+    switch (CCP_CODE(dp)) {
+    case CCP_CONFREQ:
+    case CCP_TERMREQ:
+    case CCP_TERMACK:
+	/* CCP must be going down - disable compression */
+	if (sc->sc_flags & SC_CCP_UP) {
+	    s = splimp();
+	    sc->sc_flags &= ~(SC_CCP_UP | SC_COMP_RUN | SC_DECOMP_RUN);
+	    splx(s);
+	}
+	break;
+
+    case CCP_CONFACK:
+	if (sc->sc_flags & SC_CCP_OPEN && !(sc->sc_flags & SC_CCP_UP)
+	    && slen >= CCP_HDRLEN + CCP_OPT_MINLEN
+	    && slen >= CCP_OPT_LENGTH(dp + CCP_HDRLEN) + CCP_HDRLEN) {
+	    if (!rcvd) {
+		/* we're agreeing to send compressed packets. */
+		if (sc->sc_xc_state != NULL
+		    && (*sc->sc_xcomp->comp_init)
+			(sc->sc_xc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
+			 ppp_unit(sc), 0, sc->sc_flags & SC_DEBUG)) {
+		    s = splimp();
+		    sc->sc_flags |= SC_COMP_RUN;
+		    splx(s);
+		}
+	    } else {
+		/* peer is agreeing to send compressed packets. */
+		if (sc->sc_rc_state != NULL
+		    && (*sc->sc_rcomp->decomp_init)
+			(sc->sc_rc_state, dp + CCP_HDRLEN, slen - CCP_HDRLEN,
+			 ppp_unit(sc), 0, sc->sc_mru,
+			 sc->sc_flags & SC_DEBUG)) {
+		    s = splimp();
+		    sc->sc_flags |= SC_DECOMP_RUN;
+		    sc->sc_flags &= ~(SC_DC_ERROR | SC_DC_FERROR);
+		    splx(s);
+		}
+	    }
+	}
+	break;
+
+    case CCP_RESETACK:
+	if (sc->sc_flags & SC_CCP_UP) {
+	    if (!rcvd) {
+		if (sc->sc_xc_state && (sc->sc_flags & SC_COMP_RUN))
+		    (*sc->sc_xcomp->comp_reset)(sc->sc_xc_state);
+	    } else {
+		if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
+		    (*sc->sc_rcomp->decomp_reset)(sc->sc_rc_state);
+		    s = splimp();
+		    sc->sc_flags &= ~SC_DC_ERROR;
+		    splx(s);
+		}
+	    }
+	}
+	break;
+    }
+}
+
+/*
+ * CCP is down; free (de)compressor state if necessary.
+ */
+static void
+ppp_ccp_closed(struct ppp_softc *sc)
+{
+    if (sc->sc_xc_state) {
+	(*sc->sc_xcomp->comp_free)(sc->sc_xc_state);
+	sc->sc_xc_state = NULL;
+    }
+    if (sc->sc_rc_state) {
+	(*sc->sc_rcomp->decomp_free)(sc->sc_rc_state);
+	sc->sc_rc_state = NULL;
+    }
+}
+#endif /* PPP_COMPRESS */
+
+/*
+ * Process a received PPP packet, doing decompression as necessary.
+ * Should be called at splsoftnet.
+ */
+#define COMPTYPE(proto)	((proto) == PPP_VJC_COMP? TYPE_COMPRESSED_TCP: \
+			 TYPE_UNCOMPRESSED_TCP)
+
+static struct mbuf *
+ppp_inproc(struct ppp_softc *sc, struct mbuf *m)
+{
+    struct mbuf  *mf = (struct mbuf *)0;
+    struct ifnet *ifp = &sc->sc_if;
+    struct ifqueue *inq;
+    int s, ilen, proto, rv; 
+    u_char *cp;
+#ifdef VJC
+    u_char adrs, ctrl;
+#endif
+    struct mbuf *mp;
+#ifdef PPP_COMPRESS
+    struct mbuf *dmp = NULL;
+#endif
+#ifdef VJC
+    u_char *iphdr;
+    u_int hlen; 
+    int xlen;
+#endif
+
+    sc->sc_stats.ppp_ipackets++;
+
+    if (sc->sc_flags & SC_LOG_INPKT) {
+	ilen = 0;
+	for (mp = m; mp != NULL; mp = mp->m_next)
+	    ilen += mp->m_len;
+	printf("ppp%d: got %d bytes\n", ppp_unit(sc), ilen);
+	pppdumpm(m);
+    }
+
+    cp = mtod(m, u_char *);
+#ifdef VJC
+    adrs = PPP_ADDRESS(cp);
+    ctrl = PPP_CONTROL(cp);
+#endif
+    proto = PPP_PROTOCOL(cp);
+
+    if (m->m_flags & M_ERRMARK) {
+	m->m_flags &= ~M_ERRMARK;
+	s = splimp();
+	sc->sc_flags |= SC_VJ_RESET;
+	splx(s);
+    }
+
+#ifdef PPP_COMPRESS
+    /*
+     * Decompress this packet if necessary, update the receiver's
+     * dictionary, or take appropriate action on a CCP packet.
+     */
+    if (proto == PPP_COMP && sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)
+	&& !(sc->sc_flags & SC_DC_ERROR) && !(sc->sc_flags & SC_DC_FERROR)) {
+	/* decompress this packet */
+	rv = (*sc->sc_rcomp->decompress)(sc->sc_rc_state, m, &dmp);
+	if (rv == DECOMP_OK) {
+	    m_freem(m);
+	    if (dmp == NULL) {
+		/* no error, but no decompressed packet produced */
+		return mf;
+	    }
+	    m = dmp;
+	    cp = mtod(m, u_char *);
+	    proto = PPP_PROTOCOL(cp);
+
+	} else {
+	    /*
+	     * An error has occurred in decompression.
+	     * Pass the compressed packet up to pppd, which may take
+	     * CCP down or issue a Reset-Req.
+	     */
+	    if (sc->sc_flags & SC_DEBUG)
+		printf("ppp%d: decompress failed %d\n", ppp_unit(sc), rv);
+	    s = splimp();
+	    sc->sc_flags |= SC_VJ_RESET;
+	    if (rv == DECOMP_ERROR)
+		sc->sc_flags |= SC_DC_ERROR;
+	    else
+		sc->sc_flags |= SC_DC_FERROR;
+	    splx(s);
+	}
+
+    } else {
+	if (sc->sc_rc_state && (sc->sc_flags & SC_DECOMP_RUN)) {
+	    (*sc->sc_rcomp->incomp)(sc->sc_rc_state, m);
+	}
+	if (proto == PPP_CCP) {
+	    ppp_ccp(sc, m, 1);
+	}
+    }
+#endif
+
+    ilen = 0;
+    for (mp = m; mp != NULL; mp = mp->m_next)
+	ilen += mp->m_len;
+
+#ifdef VJC
+    if (sc->sc_flags & SC_VJ_RESET) {
+	/*
+	 * If we've missed a packet, we must toss subsequent compressed
+	 * packets which don't have an explicit connection ID.
+	 */
+	if (sc->sc_comp)
+	    sl_uncompress_tcp(NULL, 0, TYPE_ERROR, sc->sc_comp);
+	s = splimp();
+	sc->sc_flags &= ~SC_VJ_RESET;
+	splx(s);
+    }
+
+    /*
+     * See if we have a VJ-compressed packet to uncompress.
+     */
+    if (proto == PPP_VJC_COMP) {
+	if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
+	    goto bad;
+
+	xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
+				      ilen - PPP_HDRLEN, TYPE_COMPRESSED_TCP,
+				      sc->sc_comp, &iphdr, &hlen);
+
+	if (xlen <= 0) {
+	    if (sc->sc_flags & SC_DEBUG)
+		printf("ppp%d: VJ uncompress failed on type comp\n",
+			ppp_unit(sc));
+	    goto bad;
+	}
+
+	/* Copy the PPP and IP headers into a new mbuf. */
+	MGETHDR(mp, M_DONTWAIT, MT_DATA);
+	if (mp == NULL)
+	    goto bad;
+	mp->m_len = 0;
+	mp->m_next = NULL;
+	if (hlen + PPP_HDRLEN > MHLEN) {
+	    MCLGET(mp, M_DONTWAIT);
+	    if (M_TRAILINGSPACE(mp) < hlen + PPP_HDRLEN) {
+		m_freem(mp);
+		goto bad;	/* lose if big headers and no clusters */
+	    }
+	}
+#ifdef MAC
+	mac_create_mbuf_from_mbuf(m, mp);
+#endif
+	cp = mtod(mp, u_char *);
+	cp[0] = adrs;
+	cp[1] = ctrl;
+	cp[2] = 0;
+	cp[3] = PPP_IP;
+	proto = PPP_IP;
+	bcopy(iphdr, cp + PPP_HDRLEN, hlen);
+	mp->m_len = hlen + PPP_HDRLEN;
+
+	/*
+	 * Trim the PPP and VJ headers off the old mbuf
+	 * and stick the new and old mbufs together.
+	 */
+	m->m_data += PPP_HDRLEN + xlen;
+	m->m_len -= PPP_HDRLEN + xlen;
+	if (m->m_len <= M_TRAILINGSPACE(mp)) {
+	    bcopy(mtod(m, u_char *), mtod(mp, u_char *) + mp->m_len, m->m_len);
+	    mp->m_len += m->m_len;
+	    MFREE(m, mp->m_next);
+	} else
+	    mp->m_next = m;
+	m = mp;
+	ilen += hlen - xlen;
+
+    } else if (proto == PPP_VJC_UNCOMP) {
+	if ((sc->sc_flags & SC_REJ_COMP_TCP) || sc->sc_comp == 0)
+	    goto bad;
+
+	xlen = sl_uncompress_tcp_core(cp + PPP_HDRLEN, m->m_len - PPP_HDRLEN,
+				      ilen - PPP_HDRLEN, TYPE_UNCOMPRESSED_TCP,
+				      sc->sc_comp, &iphdr, &hlen);
+
+	if (xlen < 0) {
+	    if (sc->sc_flags & SC_DEBUG)
+		printf("ppp%d: VJ uncompress failed on type uncomp\n",
+			ppp_unit(sc));
+	    goto bad;
+	}
+
+	proto = PPP_IP;
+	cp[3] = PPP_IP;
+    }
+#endif /* VJC */
+
+    /*
+     * If the packet will fit in a header mbuf, don't waste a
+     * whole cluster on it.
+     */
+    if (ilen <= MHLEN && M_IS_CLUSTER(m)) {
+	MGETHDR(mp, M_DONTWAIT, MT_DATA);
+	if (mp != NULL) {
+	    m_copydata(m, 0, ilen, mtod(mp, caddr_t));
+            /* instead of freeing - return cluster mbuf so it can be reused */
+            /* m_freem(m); */
+            mf = m;
+	    m = mp;
+	    m->m_len = ilen;
+	}
+    }
+    m->m_pkthdr.len = ilen;
+    m->m_pkthdr.rcvif = ifp;
+
+    if ((proto & 0x8000) == 0) {
+#ifdef PPP_FILTER
+	/*
+	 * See whether we want to pass this packet, and
+	 * if it counts as link activity.
+	 */
+	adrs = *mtod(m, u_char *);	/* save address field */
+	*mtod(m, u_char *) = 0;		/* indicate inbound */
+	if (sc->sc_pass_filt.bf_insns != 0
+	    && bpf_filter(sc->sc_pass_filt.bf_insns, (u_char *) m,
+			  ilen, 0) == 0) {
+	    /* drop this packet */
+	    m_freem(m);
+	    return mf;
+	}
+	if (sc->sc_active_filt.bf_insns == 0
+	    || bpf_filter(sc->sc_active_filt.bf_insns, (u_char *) m, ilen, 0))
+	    sc->sc_last_recv = time.tv_sec;
+
+	*mtod(m, u_char *) = adrs;
+#else
+	/*
+	 * Record the time that we received this packet.
+	 */
+	microtime(&ppp_time);
+	sc->sc_last_recv = ppp_time.tv_sec;
+#endif /* PPP_FILTER */
+    }
+
+#if NBPFILTER > 0
+    /* See if bpf wants to look at the packet. */
+    if (sc->sc_bpf)
+	bpf_mtap(sc->sc_bpf, m);
+#endif
+
+    rv = 0;
+    switch (proto) {
+#ifdef INET
+    case PPP_IP:
+	/*
+	 * IP packet - take off the ppp header and pass it up to IP.
+	 */
+	if ((ifp->if_flags & IFF_UP) == 0
+	    || sc->sc_npmode[NP_IP] != NPMODE_PASS) {
+	    /* interface is down - drop the packet. */
+	    m_freem(m);
+	    return mf;
+	}
+	m->m_pkthdr.len -= PPP_HDRLEN;
+	m->m_data += PPP_HDRLEN;
+	m->m_len -= PPP_HDRLEN;
+	schednetisr(NETISR_IP);
+	inq = &ipintrq;
+	break;
+#endif
+
+    default:
+	/*
+	 * Some other protocol - place on input queue for read().
+	 */
+	inq = &sc->sc_inq;
+	rv = 1;
+	break;
+    }
+
+    /*
+     * Put the packet on the appropriate input queue.
+     */
+    s = splimp();
+    if (IF_QFULL(inq)) {
+	IF_DROP(inq);
+	splx(s);
+	if (sc->sc_flags & SC_DEBUG)
+	    printf("ppp%d: input queue full\n", ppp_unit(sc));
+	ifp->if_iqdrops++;
+	goto bad;
+    }
+    IF_ENQUEUE(inq, m);
+    splx(s);
+
+    ifp->if_ipackets++;
+    ifp->if_ibytes += ilen;
+    microtime(&ppp_time);
+    ifp->if_lastchange = ppp_time;
+
+    if (rv) {
+      (*sc->sc_ctlp)(sc);
+    }
+
+    return mf;
+
+ bad:
+    m_freem(m);
+    sc->sc_if.if_ierrors++;
+    sc->sc_stats.ppp_ierrors++;
+    return mf;
+}
+
+#define MAX_DUMP_BYTES	128
+
+static void
+pppdumpm(struct mbuf *m0)
+{
+    char buf[3*MAX_DUMP_BYTES+4];
+    char *bp = buf;
+    struct mbuf *m;
+    static char digits[] = "0123456789abcdef";
+
+    for (m = m0; m; m = m->m_next) {
+	int l = m->m_len;
+	u_char *rptr = (u_char *)m->m_data;
+
+	while (l--) {
+	    if (bp > buf + sizeof(buf) - 4)
+		goto done;
+	    *bp++ = digits[*rptr >> 4]; /* convert byte to ascii hex */
+	    *bp++ = digits[*rptr++ & 0xf];
+	}
+
+	if (m->m_next) {
+	    if (bp > buf + sizeof(buf) - 3)
+		goto done;
+	    *bp++ = '|';
+	} else
+	    *bp++ = ' ';
+    }
+done:
+    if (m)
+	*bp++ = '>';
+    *bp = 0;
+    printf("%s\n", buf);
+}
+
+#endif	/* NPPP > 0 */
diff --git a/rtemsbsd/sys/net/if_ppp.h b/rtemsbsd/sys/net/if_ppp.h
new file mode 100644
index 0000000..c8dcfc8
--- /dev/null
+++ b/rtemsbsd/sys/net/if_ppp.h
@@ -0,0 +1,141 @@
+/*
+ * if_ppp.h - Point-to-Point Protocol definitions.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/sys/net/if_ppp.h,v 1.15 2005/01/07 01:45:34 imp Exp $
+ */
+
+
+#ifndef _IF_PPP_H_
+#define _IF_PPP_H_
+
+#include <net/ppp_defs.h> /* NPmode */
+#include <net/if.h> /* IFNAMSIZ */
+
+/*
+ * Packet sizes
+ */
+#define	PPP_MTU		1500	/* Default MTU (size of Info field) */
+#define PPP_MAXMRU	65000	/* Largest MRU we allow */
+#define PPP_MAXMTU	16384	/* Largest MTU we allow */
+
+/*
+ * Bit definitions for flags.
+ */
+#define SC_COMP_PROT	0x00000001	/* protocol compression (output) */
+#define SC_COMP_AC	0x00000002	/* header compression (output) */
+#define	SC_COMP_TCP	0x00000004	/* TCP (VJ) compression (output) */
+#define SC_NO_TCP_CCID	0x00000008	/* disable VJ connection-id comp. */
+#define SC_REJ_COMP_AC	0x00000010	/* reject adrs/ctrl comp. on input */
+#define SC_REJ_COMP_TCP	0x00000020	/* reject TCP (VJ) comp. on input */
+#define SC_CCP_OPEN	0x00000040	/* Look at CCP packets */
+#define SC_CCP_UP	0x00000080	/* May send/recv compressed packets */
+#define SC_DEBUG	0x00010000	/* enable debug messages */
+#define SC_LOG_INPKT	0x00020000	/* log contents of good pkts recvd */
+#define SC_LOG_OUTPKT	0x00040000	/* log contents of pkts sent */
+#define SC_LOG_RAWIN	0x00080000	/* log all chars received */
+#define SC_LOG_FLUSH	0x00100000	/* log all chars flushed */
+#define SC_RCV_B7_0	0x01000000	/* have rcvd char with bit 7 = 0 */
+#define SC_RCV_B7_1	0x02000000	/* have rcvd char with bit 7 = 1 */
+#define SC_RCV_EVNP	0x04000000	/* have rcvd char with even parity */
+#define SC_RCV_ODDP	0x08000000	/* have rcvd char with odd parity */
+#define SC_SYNC		0x00200000	/* use synchronous HDLC framing */
+#define	SC_MASK		0x0fff00ff	/* bits that user can change */
+
+/*
+ * State bits in sc_flags, not changeable by user.
+ */
+#define SC_TIMEOUT	0x00000400	/* timeout is currently pending */
+#define SC_VJ_RESET	0x00000800	/* need to reset VJ decomp */
+#define SC_COMP_RUN	0x00001000	/* compressor has been initiated */
+#define SC_DECOMP_RUN	0x00002000	/* decompressor has been initiated */
+#define SC_DC_ERROR	0x00004000	/* non-fatal decomp error detected */
+#define SC_DC_FERROR	0x00008000	/* fatal decomp error detected */
+#define SC_TBUSY	0x10000000	/* xmitter doesn't need a packet yet */
+#define SC_PKTLOST	0x20000000	/* have lost or dropped a packet */
+#define	SC_FLUSH	0x40000000	/* flush input until next PPP_FLAG */
+#define	SC_ESCAPED	0x80000000	/* saw a PPP_ESCAPE */
+
+/*
+ * Ioctl definitions.
+ */
+
+struct npioctl {
+    int		protocol;	/* PPP procotol, e.g. PPP_IP */
+    enum NPmode	mode;
+};
+
+/* Structure describing a CCP configuration option, for PPPIOCSCOMPRESS */
+struct ppp_option_data {
+	u_char	*ptr;
+	u_int	length;
+	int	transmit;
+};
+
+struct ifpppstatsreq {
+    char ifr_name[IFNAMSIZ];
+    struct ppp_stats stats;
+};
+
+struct ifpppcstatsreq {
+    char ifr_name[IFNAMSIZ];
+    struct ppp_comp_stats stats;
+};
+
+/*
+ * Ioctl definitions.
+ */
+
+#define	PPPIOCSTASK 	_IOW('t', 91, int)	/* set pppd task id */
+#define	PPPIOCGFLAGS	_IOR('t', 90, int)	/* get configuration flags */
+#define	PPPIOCSFLAGS	_IOW('t', 89, int)	/* set configuration flags */
+#define	PPPIOCGASYNCMAP	_IOR('t', 88, int)	/* get async map */
+#define	PPPIOCSASYNCMAP	_IOW('t', 87, int)	/* set async map */
+#define	PPPIOCGUNIT	_IOR('t', 86, int)	/* get ppp unit number */
+#define	PPPIOCGRASYNCMAP _IOR('t', 85, int)	/* get receive async map */
+#define	PPPIOCSRASYNCMAP _IOW('t', 84, int)	/* set receive async map */
+#define	PPPIOCGMRU	_IOR('t', 83, int)	/* get max receive unit */
+#define	PPPIOCSMRU	_IOW('t', 82, int)	/* set max receive unit */
+#define	PPPIOCSMAXCID	_IOW('t', 81, int)	/* set VJ max slot ID */
+#define PPPIOCGXASYNCMAP _IOR('t', 80, ext_accm) /* get extended ACCM */
+#define PPPIOCSXASYNCMAP _IOW('t', 79, ext_accm) /* set extended ACCM */
+#define PPPIOCXFERUNIT	_IO('t', 78)		/* transfer PPP unit */
+#define PPPIOCSCOMPRESS	_IOW('t', 77, struct ppp_option_data)
+#define PPPIOCGNPMODE	_IOWR('t', 76, struct npioctl) /* get NP mode */
+#define PPPIOCSNPMODE	_IOW('t', 75, struct npioctl)  /* set NP mode */
+#define PPPIOCGIDLE	_IOR('t', 74, struct ppp_idle) /* get idle time */
+#ifdef PPP_FILTER
+#define PPPIOCSPASS	_IOW('t', 71, struct bpf_program) /* set pass filter */
+#define PPPIOCSACTIVE	_IOW('t', 70, struct bpf_program) /* set active filt */
+#endif /* PPP_FILTER */
+
+/* PPPIOC[GS]MTU are alternatives to SIOC[GS]IFMTU, used under Ultrix */
+#define PPPIOCGMTU	_IOR('t', 73, int)	/* get interface MTU */
+#define PPPIOCSMTU	_IOW('t', 72, int)	/* set interface MTU */
+
+/*
+ * These two are interface ioctls so that pppstats can do them on
+ * a socket without having to open the serial device.
+ */
+#define SIOCGPPPSTATS	_IOWR('i', 123, struct ifpppstatsreq)
+#define SIOCGPPPCSTATS	_IOWR('i', 122, struct ifpppcstatsreq)
+
+#if !defined(ifr_mtu)
+#define ifr_mtu	ifr_ifru.ifru_metric
+#endif
+
+#endif /* _IF_PPP_H_ */
diff --git a/rtemsbsd/sys/net/if_pppvar.h b/rtemsbsd/sys/net/if_pppvar.h
new file mode 100644
index 0000000..9d708a4
--- /dev/null
+++ b/rtemsbsd/sys/net/if_pppvar.h
@@ -0,0 +1,161 @@
+/*
+ * if_pppvar.h - private structures and declarations for PPP.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD: src/sys/net/if_pppvar.h,v 1.26 2006/12/05 18:54:21 ume Exp $
+ */
+
+ 
+#ifndef _NET_IF_PPPVAR_H_
+#define _NET_IF_PPPVAR_H_
+
+#include <net/if_var.h> /* struct ifnet */
+#include <net/ppp_defs.h> /* struct pppstat */
+#include <rtems/rtems/types.h> /* rtems_id */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct proc;
+
+/*
+ * Supported network protocols.  These values are used for
+ * indexing sc_npmode.
+ */
+#define NP_IP	0		/* Internet Protocol */
+#define NUM_NP	1		/* Number of NPs. */
+#define NUM_MBUFQ	64
+
+
+/*
+ * Structure describing each ppp unit.
+ */
+struct ppp_softc {
+	struct	ifnet sc_if;		/* network-visible interface */
+	u_int	sc_flags;		/* control/status bits; see if_ppp.h */
+	void	*sc_devp;		/* pointer to device-dep structure */
+	void	(*sc_start)(struct ppp_softc *);	/* start output proc */
+	void	(*sc_ctlp)(struct ppp_softc *); /* rcvd control pkt */
+	void	(*sc_relinq)(struct ppp_softc *); /* relinquish ifunit */
+	short	sc_mru;			/* max receive unit */
+	pid_t	sc_xfer;		/* used in transferring unit */
+	struct	ifqueue sc_rawq;	/* received packets */
+	struct	ifqueue sc_inq;		/* queue of input packets for daemon */
+	struct	ifqueue sc_fastq;	/* interactive output packet q */
+	struct	mbuf *sc_npqueue;	/* output packets not to be sent yet */
+	struct	mbuf **sc_npqtail;	/* ptr to last next ptr in npqueue */
+	struct	pppstat sc_stats;	/* count of bytes/pkts sent/rcvd */
+	caddr_t	sc_bpf;			/* hook for BPF */
+	enum	NPmode sc_npmode[NUM_NP]; /* what to do with each NP */
+	struct	compressor *sc_xcomp;	/* transmit compressor */
+	void	*sc_xc_state;		/* transmit compressor state */
+	struct	compressor *sc_rcomp;	/* receive decompressor */
+	void	*sc_rc_state;		/* receive decompressor state */
+	time_t	sc_last_sent;		/* time (secs) last NP pkt sent */
+	time_t	sc_last_recv;		/* time (secs) last NP pkt rcvd */
+#ifdef PPP_FILTER
+	struct	bpf_program sc_pass_filt;   /* filter for packets to pass */
+	struct	bpf_program sc_active_filt; /* filter for "non-idle" packets */
+#endif /* PPP_FILTER */
+#ifdef	VJC
+	struct	vjcompress *sc_comp; 	/* vjc control buffer */
+#endif
+
+	/* Device-dependent part for async lines. */
+	ext_accm sc_asyncmap;		/* async control character map */
+	u_long	sc_rasyncmap;		/* receive async control char map */
+	struct	mbuf *sc_outm;		/* mbuf chain currently being output */
+	struct	mbuf *sc_outmc;		/* mbuf currently being output */
+	struct	mbuf *sc_m;		/* pointer to input mbuf chain */
+	struct	mbuf *sc_mc;		/* pointer to current input mbuf */
+	char	*sc_mp;			/* ptr to next char in input mbuf */
+	short	sc_ilen;		/* length of input packet so far */
+	u_short	sc_fcs;			/* FCS so far (input) */
+	u_short	sc_outfcs;		/* FCS so far for output packet */
+	u_char	sc_rawin[16];		/* chars as received */
+	int	sc_rawin_count;		/* # in sc_rawin */
+
+	struct	ifqueue sc_freeq;       /* free packets */
+	short	sc_outoff;		/* output packet byte offset */
+	short	sc_outflag;		/* output status flag */
+	short	sc_outlen;		/* length of output packet */
+	short	sc_outfcslen;		/* length of output fcs data */
+	u_char	sc_outfcsbuf[8];	/* output packet fcs buffer */
+	u_char *sc_outbuf;		/* pointer to output data */
+	u_char  sc_outchar;
+
+	rtems_id sc_rxtask;
+	rtems_id sc_txtask;
+	rtems_id sc_pppdtask;
+};
+
+struct	ppp_softc *pppalloc(pid_t pid);
+void	pppdealloc(struct ppp_softc *sc);
+int	pppoutput(struct ifnet *, struct mbuf *,
+		       struct sockaddr *, struct rtentry *);
+int	pppioctl(struct ppp_softc *sc, ioctl_command_t cmd, caddr_t data,
+		      int flag, struct proc *p);
+struct	mbuf *ppp_dequeue(struct ppp_softc *sc);
+u_short pppfcs(u_short fcs, u_char *cp, int len);
+void    pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp);
+
+
+/* define event values */
+#define RX_PACKET    RTEMS_EVENT_1
+#define RX_MBUF      RTEMS_EVENT_2
+#define RX_EMPTY     RTEMS_EVENT_3
+#define TX_PACKET    RTEMS_EVENT_1
+#define TX_TRANSMIT  RTEMS_EVENT_2
+#define PPPD_EVENT   RTEMS_EVENT_31
+
+/* define out flag values */
+#define SC_TX_BUSY      0x0001
+#define SC_TX_FCS       0x0002
+#define SC_TX_ESCAPE    0x0004
+#define SC_TX_LASTCHAR	0x0008
+#define SC_TX_PENDING   0x0010
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _NET_IF_PPPVAR_H_ */
+
diff --git a/rtemsbsd/sys/net/ppp_comp.h b/rtemsbsd/sys/net/ppp_comp.h
new file mode 100644
index 0000000..c78997d
--- /dev/null
+++ b/rtemsbsd/sys/net/ppp_comp.h
@@ -0,0 +1,165 @@
+/*
+ * ppp-comp.h - Definitions for doing PPP packet compression.
+ */
+/*
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ * $FreeBSD: src/sys/net/ppp_comp.h,v 1.12 2005/01/07 01:45:35 imp Exp $
+ */
+
+
+#ifndef _NET_PPP_COMP_H
+#define _NET_PPP_COMP_H
+
+/*
+ * The following symbols control whether we include code for
+ * various compression methods.
+ */
+#ifndef DO_BSD_COMPRESS
+#define DO_BSD_COMPRESS	0	/* by default, include BSD-Compress */
+#endif
+#ifndef DO_DEFLATE
+#define DO_DEFLATE	0	/* by default, include Deflate */
+#endif
+#define DO_PREDICTOR_1	0
+#define DO_PREDICTOR_2	0
+
+/*
+ * Structure giving methods for compression/decompression.
+ */
+#ifdef PACKETPTR
+struct compressor {
+	int	compress_proto;	/* CCP compression protocol number */
+
+	/* Allocate space for a compressor (transmit side) */
+	void	*(*comp_alloc)(u_char *options, int opt_len);
+	/* Free space used by a compressor */
+	void	(*comp_free)(void *state);
+	/* Initialize a compressor */
+	int	(*comp_init)(void *state, u_char *options, int opt_len,
+		    int unit, int hdrlen, int debug);
+	/* Reset a compressor */
+	void	(*comp_reset)(void *state);
+	/* Compress a packet */
+	int	(*compress)(void *state, PACKETPTR *mret, PACKETPTR mp,
+		    int orig_len, int max_len);
+	/* Return compression statistics */
+	void	(*comp_stat)(void *state, struct compstat *stats);
+
+	/* Allocate space for a decompressor (receive side) */
+	void	*(*decomp_alloc)(u_char *options, int opt_len);
+	/* Free space used by a decompressor */
+	void	(*decomp_free)(void *state);
+	/* Initialize a decompressor */
+	int	(*decomp_init)(void *state, u_char *options, int opt_len,
+		    int unit, int hdrlen, int mru, int debug);
+	/* Reset a decompressor */
+	void	(*decomp_reset)(void *state);
+	/* Decompress a packet. */
+	int	(*decompress)(void *state, PACKETPTR mp, PACKETPTR *dmpp);
+	/* Update state for an incompressible packet received */
+	void	(*incomp)(void *state, PACKETPTR mp);
+	/* Return decompression statistics */
+	void	(*decomp_stat)(void *state, struct compstat *stats);
+};
+#endif /* PACKETPTR */
+
+/*
+ * Return values for decompress routine.
+ * We need to make these distinctions so that we can disable certain
+ * useful functionality, namely sending a CCP reset-request as a result
+ * of an error detected after decompression.  This is to avoid infringing
+ * a patent held by Motorola.
+ * Don't you just lurve software patents.
+ */
+#define DECOMP_OK		0	/* everything went OK */
+#define DECOMP_ERROR		1	/* error detected before decomp. */
+#define DECOMP_FATALERROR	2	/* error detected after decomp. */
+
+/*
+ * CCP codes.
+ */
+#define CCP_CONFREQ	1
+#define CCP_CONFACK	2
+#define CCP_TERMREQ	5
+#define CCP_TERMACK	6
+#define CCP_RESETREQ	14
+#define CCP_RESETACK	15
+
+/*
+ * Max # bytes for a CCP option
+ */
+#define CCP_MAX_OPTION_LENGTH	32
+
+/*
+ * Parts of a CCP packet.
+ */
+#define CCP_CODE(dp)		((dp)[0])
+#define CCP_ID(dp)		((dp)[1])
+#define CCP_LENGTH(dp)		(((dp)[2] << 8) + (dp)[3])
+#define CCP_HDRLEN		4
+
+#define CCP_OPT_CODE(dp)	((dp)[0])
+#define CCP_OPT_LENGTH(dp)	((dp)[1])
+#define CCP_OPT_MINLEN		2
+
+/*
+ * Definitions for BSD-Compress.
+ */
+#define CI_BSD_COMPRESS		21	/* config. option for BSD-Compress */
+#define CILEN_BSD_COMPRESS	3	/* length of config. option */
+
+/* Macros for handling the 3rd byte of the BSD-Compress config option. */
+#define BSD_NBITS(x)		((x) & 0x1F)	/* number of bits requested */
+#define BSD_VERSION(x)		((x) >> 5)	/* version of option format */
+#define BSD_CURRENT_VERSION	1		/* current version number */
+#define BSD_MAKE_OPT(v, n)	(((v) << 5) | (n))
+
+#define BSD_MIN_BITS		9	/* smallest code size supported */
+#define BSD_MAX_BITS		15	/* largest code size supported */
+
+/*
+ * Definitions for Deflate.
+ */
+#define CI_DEFLATE		26	/* config option for Deflate */
+#define CI_DEFLATE_DRAFT	24	/* value used in original draft RFC */
+#define CILEN_DEFLATE		4	/* length of its config option */
+
+#define DEFLATE_MIN_SIZE	8
+#define DEFLATE_MAX_SIZE	15
+#define DEFLATE_METHOD_VAL	8
+#define DEFLATE_SIZE(x)		(((x) >> 4) + DEFLATE_MIN_SIZE)
+#define DEFLATE_METHOD(x)	((x) & 0x0F)
+#define DEFLATE_MAKE_OPT(w)	((((w) - DEFLATE_MIN_SIZE) << 4) \
+				 + DEFLATE_METHOD_VAL)
+#define DEFLATE_CHK_SEQUENCE	0
+
+/*
+ * Definitions for other, as yet unsupported, compression methods.
+ */
+#define CI_PREDICTOR_1		1	/* config option for Predictor-1 */
+#define CILEN_PREDICTOR_1	2	/* length of its config option */
+#define CI_PREDICTOR_2		2	/* config option for Predictor-2 */
+#define CILEN_PREDICTOR_2	2	/* length of its config option */
+
+#endif /* _NET_PPP_COMP_H */
diff --git a/rtemsbsd/sys/net/ppp_defs.h b/rtemsbsd/sys/net/ppp_defs.h
new file mode 100644
index 0000000..3636bf9
--- /dev/null
+++ b/rtemsbsd/sys/net/ppp_defs.h
@@ -0,0 +1,159 @@
+/*
+ * ppp_defs.h - PPP definitions.
+ *
+ * Copyright (c) 1994 The Australian National University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation is hereby granted, provided that the above copyright
+ * notice appears in all copies.  This software is provided without any
+ * warranty, express or implied. The Australian National University
+ * makes no representations about the suitability of this software for
+ * any purpose.
+ *
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ *
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
+ * OR MODIFICATIONS.
+ *
+ * $FreeBSD: src/sys/net/ppp_defs.h,v 1.8 2005/01/07 01:45:35 imp Exp $
+ */
+
+
+#ifndef _PPP_DEFS_H_
+#define _PPP_DEFS_H_
+
+#include <stdint.h>
+
+/*
+ * The basic PPP frame.
+ */
+#define PPP_HDRLEN	4	/* octets for standard ppp header */
+#define PPP_FCSLEN	2	/* octets for FCS */
+#define PPP_MRU		1500	/* default MRU = max length of info field */
+
+#define PPP_ADDRESS(p)	(((u_char *)(p))[0])
+#define PPP_CONTROL(p)	(((u_char *)(p))[1])
+#define PPP_PROTOCOL(p)	((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])
+
+/*
+ * Significant octet values.
+ */
+#define	PPP_ALLSTATIONS	0xff	/* All-Stations broadcast address */
+#define	PPP_UI		0x03	/* Unnumbered Information */
+#define	PPP_FLAG	0x7e	/* Flag Sequence */
+#define	PPP_ESCAPE	0x7d	/* Asynchronous Control Escape */
+#define	PPP_TRANS	0x20	/* Asynchronous transparency modifier */
+
+/*
+ * Protocol field values.
+ */
+#define PPP_IP		0x21	/* Internet Protocol */
+#define PPP_AT		0x29	/* AppleTalk Protocol */
+#define PPP_IPX		0x2b	/* IPX protocol */
+#define	PPP_VJC_COMP	0x2d	/* VJ compressed TCP */
+#define	PPP_VJC_UNCOMP	0x2f	/* VJ uncompressed TCP */
+#define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
+#define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_IPCP	0x8021	/* IP Control Protocol */
+#define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
+#define PPP_IPXCP	0x802b	/* IPX Control Protocol */
+#define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
+#define PPP_CCP		0x80fd	/* Compression Control Protocol */
+#define PPP_LCP		0xc021	/* Link Control Protocol */
+#define PPP_PAP		0xc023	/* Password Authentication Protocol */
+#define PPP_LQR		0xc025	/* Link Quality Report protocol */
+#define PPP_CHAP	0xc223	/* Cryptographic Handshake Auth. Protocol */
+#define PPP_CBCP	0xc029	/* Callback Control Protocol */
+
+/*
+ * Values for FCS calculations.
+ */
+#define PPP_INITFCS	0xffff	/* Initial FCS value */
+#define PPP_GOODFCS	0xf0b8	/* Good final FCS value */
+#define PPP_FCS(fcs, c)	(((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])
+
+/*
+ * Extended asyncmap - allows any character to be escaped.
+ */
+typedef uint32_t	ext_accm[8];
+
+/*
+ * What to do with network protocol (NP) packets.
+ */
+enum NPmode {
+    NPMODE_PASS,		/* pass the packet through */
+    NPMODE_DROP,		/* silently drop the packet */
+    NPMODE_ERROR,		/* return an error */
+    NPMODE_QUEUE		/* save it up for later. */
+};
+
+/*
+ * Statistics.
+ */
+struct pppstat	{
+    unsigned int ppp_ibytes;	/* bytes received */
+    unsigned int ppp_ipackets;	/* packets received */
+    unsigned int ppp_ierrors;	/* receive errors */
+    unsigned int ppp_obytes;	/* bytes sent */
+    unsigned int ppp_opackets;	/* packets sent */
+    unsigned int ppp_oerrors;	/* transmit errors */
+};
+
+struct vjstat {
+    unsigned int vjs_packets;	/* outbound packets */
+    unsigned int vjs_compressed; /* outbound compressed packets */
+    unsigned int vjs_searches;	/* searches for connection state */
+    unsigned int vjs_misses;	/* times couldn't find conn. state */
+    unsigned int vjs_uncompressedin; /* inbound uncompressed packets */
+    unsigned int vjs_compressedin; /* inbound compressed packets */
+    unsigned int vjs_errorin;	/* inbound unknown type packets */
+    unsigned int vjs_tossed;	/* inbound packets tossed because of error */
+};
+
+struct ppp_stats {
+    struct pppstat p;		/* basic PPP statistics */
+    struct vjstat vj;		/* VJ header compression statistics */
+};
+
+struct compstat {
+    unsigned int unc_bytes;	/* total uncompressed bytes */
+    unsigned int unc_packets;	/* total uncompressed packets */
+    unsigned int comp_bytes;	/* compressed bytes */
+    unsigned int comp_packets;	/* compressed packets */
+    unsigned int inc_bytes;	/* incompressible bytes */
+    unsigned int inc_packets;	/* incompressible packets */
+    unsigned int ratio;		/* recent compression ratio << 8 */
+};
+
+struct ppp_comp_stats {
+    struct compstat c;		/* packet compression statistics */
+    struct compstat d;		/* packet decompression statistics */
+};
+
+/*
+ * The following structure records the time in seconds since
+ * the last NP packet was sent or received.
+ */
+struct ppp_idle {
+    time_t xmit_idle;		/* time since last NP packet sent */
+    time_t recv_idle;		/* time since last NP packet received */
+};
+
+#ifndef __P
+#ifdef __STDC__
+#define __P(x)	x
+#else
+#define __P(x)	()
+#endif
+#endif
+
+#endif /* _PPP_DEFS_H_ */
diff --git a/rtemsbsd/sys/net/ppp_tty.c b/rtemsbsd/sys/net/ppp_tty.c
new file mode 100644
index 0000000..45fb499
--- /dev/null
+++ b/rtemsbsd/sys/net/ppp_tty.c
@@ -0,0 +1,954 @@
+/*
+ * ppp_tty.c - Point-to-Point Protocol (PPP) driver for asynchronous
+ * 	       tty devices.
+ *
+ * Copyright (c) 1989 Carnegie Mellon University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by Carnegie Mellon University.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Drew D. Perkins
+ * Carnegie Mellon University
+ * 4910 Forbes Ave.
+ * Pittsburgh, PA 15213
+ * (412) 268-8576
+ * ddp at andrew.cmu.edu
+ *
+ * Based on:
+ *	@(#)if_sl.c	7.6.1.2 (Berkeley) 2/15/89
+ *
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Serial Line interface
+ *
+ * Rick Adams
+ * Center for Seismic Studies
+ * 1300 N 17th Street, Suite 1450
+ * Arlington, Virginia 22209
+ * (703)276-7900
+ * rick at seismo.ARPA
+ * seismo!rick
+ *
+ * Pounded on heavily by Chris Torek (chris at mimsy.umd.edu, umcp-cs!chris).
+ * Converted to 4.3BSD Beta by Chris Torek.
+ * Other changes made at Berkeley, based in part on code by Kirk Smith.
+ *
+ * Converted to 4.3BSD+ 386BSD by Brad Parker (brad at cayman.com)
+ * Added VJ tcp header compression; more unified ioctls
+ *
+ * Extensively modified by Paul Mackerras (paulus at cs.anu.edu.au).
+ * Cleaned up a lot of the mbuf-related code to fix bugs that
+ * caused system crashes and packet corruption.  Changed pppstart
+ * so that it doesn't just give up with a "collision" if the whole
+ * packet doesn't fit in the output ring buffer.
+ *
+ * Added priority queueing for interactive IP packets, following
+ * the model of if_sl.c, plus hooks for bpf.
+ * Paul Mackerras (paulus at cs.anu.edu.au).
+ */
+
+/* $FreeBSD: src/sys/net/ppp_tty.c,v 1.69 2005/10/16 20:44:18 phk Exp $ */
+/* from if_sl.c,v 1.11 84/10/04 12:54:47 rick Exp */
+/* from NetBSD: if_ppp.c,v 1.15.2.2 1994/07/28 05:17:58 cgd Exp */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "opt_ppp.h"		/* XXX for ppp_defs.h */
+
+#if NPPP > 0
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/kernel.h>
+
+#include <net/if.h>
+#include <net/if_types.h>
+
+#ifdef VJC
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <net/slcompress.h>
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <sys/ttycom.h>
+#include <termios.h>
+#include <rtems/termiostypes.h>
+
+#ifdef PPP_FILTER
+#include <net/bpf.h>
+#endif
+#include <net/ppp_defs.h>
+#include <net/if_ppp.h>
+#include <net/if_pppvar.h>
+
+
+void	pppasyncattach(void);
+int     pppopen(struct rtems_termios_tty *tty);
+int     pppclose(struct rtems_termios_tty *tty);
+int     pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args);
+int     pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args);
+int     ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args);
+int     pppinput(int c, struct rtems_termios_tty *tty);
+int     pppstart(struct rtems_termios_tty *tp);
+u_short pppfcs(u_short fcs, u_char *cp, int len);
+void    pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp);
+
+static void pppasyncstart(struct ppp_softc *);
+static void pppasyncctlp(struct ppp_softc *);
+static void pppasyncrelinq(struct ppp_softc *);
+/*static void ppp_timeout __P((void *)); */
+/*static void pppdumpb __P((u_char *b, int l)); */
+/*static void ppplogchar __P((struct ppp_softc *, int)); */
+
+/*
+ * Some useful mbuf macros not in mbuf.h.
+ */
+#define M_IS_CLUSTER(m)	((m)->m_flags & M_EXT)
+
+#define M_DATASTART(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_buf : \
+	    (m)->m_flags & M_PKTHDR ? (m)->m_pktdat : (m)->m_dat)
+
+#define M_DATASIZE(m)	\
+	(M_IS_CLUSTER(m) ? (m)->m_ext.ext_size : \
+	    (m)->m_flags & M_PKTHDR ? MHLEN: MLEN)
+
+/*
+ * We steal two bits in the mbuf m_flags, to mark high-priority packets
+ * for output, and received packets following lost/corrupted packets.
+ */
+#define M_HIGHPRI	0x2000	/* output packet for sc_fastq */
+#define M_ERRMARK	0x4000	/* steal a bit in mbuf m_flags */
+
+/*
+ * Does c need to be escaped?
+ */
+#define ESCAPE_P(c)	(sc->sc_asyncmap[(c) >> 5] & (1 << ((c) & 0x1F)))
+
+/*
+ * Procedures for using an async tty interface for PPP.
+ */
+
+/* This is a FreeBSD-2.0 kernel. */
+#define CCOUNT(rb)      (((rb).Size+(rb).Head-(rb).Tail) % (rb).Size)
+#define FCOUNT(rb)      ((rb).Size-CCOUNT(rb)-1)
+#define PPP_LOWAT	100	/* Process more output when < LOWAT on queue */
+#define	PPP_HIWAT	400	/* Don't start a new packet if HIWAT on que */
+
+/*
+ * Define the PPP line discipline.
+ */
+
+static struct rtems_termios_linesw pppdisc = {
+	pppopen, pppclose, pppread, pppwrite,
+	pppinput, pppstart, ppptioctl, NULL
+};
+
+void
+pppasyncattach(void)
+{
+    rtems_termios_linesw[PPPDISC] = pppdisc;
+}
+
+TEXT_SET(pseudo_set, pppasyncattach);
+
+/*
+ * Line specific open routine for async tty devices.
+ * Attach the given tty to the first available ppp unit.
+ * Called from device open routine or ttioctl.
+ */
+/* ARGSUSED */
+int
+pppopen(struct rtems_termios_tty *tty)
+{
+    int                        i;
+    register struct ppp_softc *sc;
+    struct mbuf *m = (struct mbuf *)0;
+
+    if (tty->t_line == PPPDISC) {
+	sc = (struct ppp_softc *)tty->t_sc;
+	if (sc != NULL && sc->sc_devp == (void *)tty) {
+	    return (0);
+	}
+    }
+
+    if ((sc = pppalloc(1)) == NULL) {
+	return ENXIO;
+    }
+
+    if (sc->sc_relinq)
+	(*sc->sc_relinq)(sc);	/* get previous owner to relinquish the unit */
+
+    sc->sc_ilen = 0;
+    sc->sc_m = NULL;
+    bzero(sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
+    sc->sc_asyncmap[0] = 0xffffffff;
+    sc->sc_asyncmap[3] = 0x60000000;
+    sc->sc_rasyncmap = 0;
+    sc->sc_devp = tty;
+    sc->sc_start = pppasyncstart;
+    sc->sc_ctlp = pppasyncctlp;
+    sc->sc_relinq = pppasyncrelinq;
+    sc->sc_outm = NULL;
+    sc->sc_outmc = NULL;
+    
+    /* preallocate mbufs for free queue */
+    rtems_bsdnet_semaphore_obtain();
+    for (i=0; i<NUM_MBUFQ; i++) {
+      pppallocmbuf(sc, &m);
+      if ( i == 0 ) {
+        /* use first mbuf for rx iterrupt handling */
+        sc->sc_m = m;
+      }
+      else {
+        /* enqueue mbuf for later use */
+        IF_ENQUEUE(&sc->sc_freeq, m);
+      }
+      m = (struct mbuf *)0;
+    }
+    rtems_bsdnet_semaphore_release();
+
+    /* initialize values */
+    sc->sc_if.if_flags |= IFF_RUNNING;
+    sc->sc_if.if_baudrate =
+	rtems_termios_baud_to_number(tty->termios.c_cflag & CBAUD);
+
+    tty->t_sc = (void *)sc;
+
+    return ( RTEMS_SUCCESSFUL );
+}
+
+/*
+ * Line specific close routine, called from device close routine
+ * and from ttioctl.
+ * Detach the tty from the ppp unit.
+ * Mimics part of ttyclose().
+ */
+int
+pppclose(struct rtems_termios_tty *tty)
+{
+    register struct ppp_softc *sc;
+
+    tty->t_line = 0;
+    sc = (struct ppp_softc *)tty->t_sc;
+    if (sc != NULL) {
+	tty->t_sc = NULL;
+	if (tty == (struct rtems_termios_tty *)sc->sc_devp) {
+            rtems_bsdnet_semaphore_obtain();
+	    pppasyncrelinq(sc);
+	    pppdealloc(sc);
+            rtems_bsdnet_semaphore_release();
+	}
+    }
+    return ( RTEMS_SUCCESSFUL );
+}
+
+/*
+ * Relinquish the interface unit to another device.
+ */
+static void
+pppasyncrelinq(struct ppp_softc *sc)
+{
+#ifdef XXX_XXX
+    if (sc->sc_outm) {
+	m_freem(sc->sc_outm);
+	sc->sc_outm = NULL;
+    }
+    if (sc->sc_m) {
+	m_freem(sc->sc_m);
+	sc->sc_m = NULL;
+    }
+    if (sc->sc_flags & SC_TIMEOUT) {
+	untimeout(ppp_timeout, (void *) sc);
+	sc->sc_flags &= ~SC_TIMEOUT;
+    }
+#endif
+}
+
+/*
+ * Line specific (tty) read routine.
+ */
+int
+pppread(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args)
+{
+    rtems_status_code            status  = RTEMS_UNSATISFIED;
+    int                          count   = 0;
+    int                          maximum = rw_args->count;
+    char                        *buffer  = rw_args->buffer;
+    register struct ppp_softc   *sc      = (struct ppp_softc *)tty->t_sc;
+    struct mbuf                 *m;
+    struct mbuf                 *m0;
+    u_char                      *p;
+
+    if (sc == NULL)
+        return 0;
+
+    /*
+     * Loop waiting for input, checking that nothing disasterous
+     * happens in the meantime.
+     */
+    if (tty != (struct rtems_termios_tty *)sc->sc_devp || tty->t_line != PPPDISC) {
+        return ( status );
+    }
+    if (sc->sc_inq.ifq_head == NULL) {
+      return ( status );
+    }
+
+    /* Get the packet from the input queue */
+    rtems_bsdnet_semaphore_obtain();
+    IF_DEQUEUE(&sc->sc_inq, m0);
+
+    /* loop over mbuf chain */
+    m = m0;
+    while (( m != NULL ) && ( m->m_len > 0 ) && ( count+m->m_len < maximum )) {
+      /* copy data into buffer */
+      p = mtod(m, u_char *);
+      memcpy(buffer, p, m->m_len);
+      memset(p, 0, m->m_len);
+      count  += m->m_len;
+      buffer += m->m_len;
+
+      /* increment loop index */
+      m = m->m_next;
+    }
+
+    /* free mbuf chain */
+    m_freem(m0);
+    rtems_bsdnet_semaphore_release();
+
+    /* update return values */
+    rw_args->bytes_moved = count;
+    if ( count >= 0 ) {
+      status = RTEMS_SUCCESSFUL;
+    }
+
+    /* check to see if queue is empty */
+    if (sc->sc_inq.ifq_head != NULL) {
+      /* queue is not empty - post another event to ourself */
+      rtems_event_send(sc->sc_pppdtask, PPPD_EVENT);
+    }
+
+    return ( status );
+}
+
+/*
+ * Line specific (tty) write routine.
+ */
+int
+pppwrite(struct rtems_termios_tty *tty, rtems_libio_rw_args_t *rw_args)
+{
+    struct sockaddr               dst;
+    int                           n;
+    int                           len;
+    int                           maximum    = rw_args->count;
+    char                         *out_buffer = rw_args->buffer; 
+    register struct ppp_softc    *sc         = (struct ppp_softc *)tty->t_sc;
+    struct mbuf                  *m;
+    struct mbuf                  *m0;
+    struct mbuf                 **mp;
+
+    rtems_bsdnet_semaphore_obtain();
+    for (mp = &m0; maximum; mp = &m->m_next) {
+	MGET(m, M_WAIT, MT_DATA);
+	if ((*mp = m) == NULL) {
+	    m_freem(m0);
+	    return (ENOBUFS);
+	}
+	m->m_len = 0;
+	if (maximum >= MCLBYTES / 2) {
+	    MCLGET(m, M_DONTWAIT);
+        }
+	len = M_TRAILINGSPACE(m);
+	if (len > maximum) {
+          memcpy(mtod(m, u_char *),out_buffer,maximum);
+          m->m_len = maximum;
+          maximum  = 0;
+        }
+        else {
+          memcpy(mtod(m, u_char *),out_buffer,len);
+          m->m_len    = len;
+          maximum    -= len;
+          out_buffer += len;
+        }
+    }
+
+    dst.sa_family = AF_UNSPEC;
+    bcopy(mtod(m0, u_char *), dst.sa_data, PPP_HDRLEN);
+    m0->m_data += PPP_HDRLEN;
+    m0->m_len  -= PPP_HDRLEN;
+
+    n = pppoutput(&sc->sc_if, m0, &dst, (struct rtentry *)0);
+    rtems_bsdnet_semaphore_release();
+
+    return ( n );
+}
+
+/*
+ * Line specific (tty) ioctl routine.
+ * This discipline requires that tty device drivers call
+ * the line specific l_ioctl routine from their ioctl routines.
+ */
+/* ARGSUSED */
+int
+ppptioctl(struct rtems_termios_tty *tty, rtems_libio_ioctl_args_t *args)
+{
+/*    int                 i;	*/
+    int                 error = RTEMS_SUCCESSFUL;
+    ioctl_command_t     cmd   = args->command;
+    caddr_t             data  = args->buffer;
+    struct ppp_softc   *sc    = tty->t_sc;
+
+    switch (cmd) {
+    case RTEMS_IO_GET_ATTRIBUTES:
+    case RTEMS_IO_SET_ATTRIBUTES:
+    case RTEMS_IO_TCDRAIN:
+    case RTEMS_IO_SNDWAKEUP:
+    case RTEMS_IO_RCVWAKEUP:
+    case TIOCGETD:
+    case TIOCSETD:
+        error = rtems_termios_ioctl(args);
+	break;
+
+    case PPPIOCSASYNCMAP:
+	sc->sc_asyncmap[0] = *(u_int *)data;
+	break;
+
+    case PPPIOCGASYNCMAP:
+	*(u_int *)data = sc->sc_asyncmap[0];
+	break;
+
+    case PPPIOCSRASYNCMAP:
+	sc->sc_rasyncmap = *(u_int *)data;
+	break;
+
+    case PPPIOCGRASYNCMAP:
+	*(u_int *)data = sc->sc_rasyncmap;
+	break;
+
+    case PPPIOCSXASYNCMAP:
+	bcopy(data, sc->sc_asyncmap, sizeof(sc->sc_asyncmap));
+	sc->sc_asyncmap[1] = 0;		    /* mustn't escape 0x20 - 0x3f */
+	sc->sc_asyncmap[2] &= ~0x40000000;  /* mustn't escape 0x5e */
+	sc->sc_asyncmap[3] |= 0x60000000;   /* must escape 0x7d, 0x7e */
+	break;
+
+    case PPPIOCGXASYNCMAP:
+	bcopy(sc->sc_asyncmap, data, sizeof(sc->sc_asyncmap));
+	break;
+
+    default:
+        rtems_bsdnet_semaphore_obtain();
+	error = pppioctl(sc, cmd, data, 0, NULL);
+        rtems_bsdnet_semaphore_release();
+    }
+    return error;
+}
+
+/*
+ * FCS lookup table as calculated by genfcstab.
+ */
+static u_short fcstab[256] = {
+	0x0000,	0x1189,	0x2312,	0x329b,	0x4624,	0x57ad,	0x6536,	0x74bf,
+	0x8c48,	0x9dc1,	0xaf5a,	0xbed3,	0xca6c,	0xdbe5,	0xe97e,	0xf8f7,
+	0x1081,	0x0108,	0x3393,	0x221a,	0x56a5,	0x472c,	0x75b7,	0x643e,
+	0x9cc9,	0x8d40,	0xbfdb,	0xae52,	0xdaed,	0xcb64,	0xf9ff,	0xe876,
+	0x2102,	0x308b,	0x0210,	0x1399,	0x6726,	0x76af,	0x4434,	0x55bd,
+	0xad4a,	0xbcc3,	0x8e58,	0x9fd1,	0xeb6e,	0xfae7,	0xc87c,	0xd9f5,
+	0x3183,	0x200a,	0x1291,	0x0318,	0x77a7,	0x662e,	0x54b5,	0x453c,
+	0xbdcb,	0xac42,	0x9ed9,	0x8f50,	0xfbef,	0xea66,	0xd8fd,	0xc974,
+	0x4204,	0x538d,	0x6116,	0x709f,	0x0420,	0x15a9,	0x2732,	0x36bb,
+	0xce4c,	0xdfc5,	0xed5e,	0xfcd7,	0x8868,	0x99e1,	0xab7a,	0xbaf3,
+	0x5285,	0x430c,	0x7197,	0x601e,	0x14a1,	0x0528,	0x37b3,	0x263a,
+	0xdecd,	0xcf44,	0xfddf,	0xec56,	0x98e9,	0x8960,	0xbbfb,	0xaa72,
+	0x6306,	0x728f,	0x4014,	0x519d,	0x2522,	0x34ab,	0x0630,	0x17b9,
+	0xef4e,	0xfec7,	0xcc5c,	0xddd5,	0xa96a,	0xb8e3,	0x8a78,	0x9bf1,
+	0x7387,	0x620e,	0x5095,	0x411c,	0x35a3,	0x242a,	0x16b1,	0x0738,
+	0xffcf,	0xee46,	0xdcdd,	0xcd54,	0xb9eb,	0xa862,	0x9af9,	0x8b70,
+	0x8408,	0x9581,	0xa71a,	0xb693,	0xc22c,	0xd3a5,	0xe13e,	0xf0b7,
+	0x0840,	0x19c9,	0x2b52,	0x3adb,	0x4e64,	0x5fed,	0x6d76,	0x7cff,
+	0x9489,	0x8500,	0xb79b,	0xa612,	0xd2ad,	0xc324,	0xf1bf,	0xe036,
+	0x18c1,	0x0948,	0x3bd3,	0x2a5a,	0x5ee5,	0x4f6c,	0x7df7,	0x6c7e,
+	0xa50a,	0xb483,	0x8618,	0x9791,	0xe32e,	0xf2a7,	0xc03c,	0xd1b5,
+	0x2942,	0x38cb,	0x0a50,	0x1bd9,	0x6f66,	0x7eef,	0x4c74,	0x5dfd,
+	0xb58b,	0xa402,	0x9699,	0x8710,	0xf3af,	0xe226,	0xd0bd,	0xc134,
+	0x39c3,	0x284a,	0x1ad1,	0x0b58,	0x7fe7,	0x6e6e,	0x5cf5,	0x4d7c,
+	0xc60c,	0xd785,	0xe51e,	0xf497,	0x8028,	0x91a1,	0xa33a,	0xb2b3,
+	0x4a44,	0x5bcd,	0x6956,	0x78df,	0x0c60,	0x1de9,	0x2f72,	0x3efb,
+	0xd68d,	0xc704,	0xf59f,	0xe416,	0x90a9,	0x8120,	0xb3bb,	0xa232,
+	0x5ac5,	0x4b4c,	0x79d7,	0x685e,	0x1ce1,	0x0d68,	0x3ff3,	0x2e7a,
+	0xe70e,	0xf687,	0xc41c,	0xd595,	0xa12a,	0xb0a3,	0x8238,	0x93b1,
+	0x6b46,	0x7acf,	0x4854,	0x59dd,	0x2d62,	0x3ceb,	0x0e70,	0x1ff9,
+	0xf78f,	0xe606,	0xd49d,	0xc514,	0xb1ab,	0xa022,	0x92b9,	0x8330,
+	0x7bc7,	0x6a4e,	0x58d5,	0x495c,	0x3de3,	0x2c6a,	0x1ef1,	0x0f78
+};
+
+/*
+ * Calculate a new FCS given the current FCS and the new data.
+ */
+u_short
+pppfcs(u_short fcs, u_char *cp, int len)
+{
+    while (len--)
+	fcs = PPP_FCS(fcs, *cp++);
+    return (fcs);
+}
+
+/*
+ * This gets called at splsoftnet from if_ppp.c at various times
+ * when there is data ready to be sent.
+ */
+void pppasyncstart(struct ppp_softc *sc)
+{
+  /* check to see if output is not active */
+  if ( sc->sc_outflag == 0 ) {
+    /* mark active and post tx event to daemon */
+    sc->sc_outflag |= SC_TX_PENDING;
+    rtems_event_send(sc->sc_txtask, TX_PACKET);
+  }
+}
+
+/*
+ * This gets called when a received packet is placed on
+ * the inq, at splsoftnet.
+ */
+static void
+pppasyncctlp(
+    struct ppp_softc *sc)
+{
+  /* check to see if task id was set */
+  if ( sc->sc_pppdtask != 0 ) {
+    /* post event to daemon */
+    rtems_event_send(sc->sc_pppdtask, PPPD_EVENT);
+  }
+}
+
+/*
+ * Start output on async tty interface.  If the transmit queue
+ * has drained sufficiently, arrange for pppasyncstart to be
+ * called later at splsoftnet.
+ * Called at spltty or higher.
+ */
+int
+pppstart(struct rtems_termios_tty *tp)
+{
+  u_char             *sendBegin;
+  u_long              ioffset = (u_long       )0;
+  struct mbuf        *m       = (struct mbuf *)0;
+  struct ppp_softc   *sc      = tp->t_sc;
+  rtems_termios_device_context *ctx = rtems_termios_get_device_context(tp);
+
+  /* ensure input is valid and we are busy */
+  if (( sc != NULL ) && ( sc->sc_outflag & SC_TX_BUSY )) {
+    /* check to see if we need to get the next buffer */
+
+    /* Ready with PPP_FLAG Character ? */
+    if(sc->sc_outflag & SC_TX_LASTCHAR){
+        sc->sc_outflag &= ~(SC_TX_BUSY | SC_TX_FCS | SC_TX_LASTCHAR);
+
+        /* Notify driver that we have nothing to transmit */
+        (*tp->handler.write)(ctx, NULL, 0);
+
+        rtems_event_send(sc->sc_txtask, TX_TRANSMIT);	/* Ready for the next Packet */
+        return(0);
+    }
+
+    if ( sc->sc_outoff >= sc->sc_outlen ) {
+      /* loop to get next non-zero length buffer */
+      if ( sc->sc_outmc != NULL ) {
+        m = sc->sc_outmc->m_next;
+      }
+
+      /* check for next mbuf in chain */
+      if ( m != NULL ) {
+        /* update values to use this mbuf */
+        sc->sc_outmc  = m;
+        sc->sc_outbuf = mtod(m, u_char *);
+        sc->sc_outlen = m->m_len;
+        sc->sc_outoff = (short)0;
+      }
+      else if ( (sc->sc_outflag & SC_TX_FCS) == 0 ) {
+        /* setup to use FCS buffer */
+        sc->sc_outflag |= SC_TX_FCS;
+        sc->sc_outbuf   = sc->sc_outfcsbuf;
+        sc->sc_outlen   = sc->sc_outfcslen;
+        sc->sc_outoff   = (short)0;
+      }
+      else {
+        /* done with this packet */
+        sc->sc_outflag |= SC_TX_LASTCHAR;
+        sc->sc_outflag &=~(SC_TX_FCS);
+		sc->sc_outchar = (u_char)PPP_FLAG;
+        (*tp->handler.write)(ctx, (char *)&sc->sc_outchar, 1);
+        return(0);
+      }
+    }
+
+    /* check to see if there is some data to write out */
+    if ( sc->sc_outoff < sc->sc_outlen ) {
+      /* check to see if character needs to be escaped */
+      sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff];
+      if ( ESCAPE_P(sc->sc_outchar) ) {
+        if ( sc->sc_outflag & SC_TX_ESCAPE ) {
+          /* last sent character was the escape character */
+          sc->sc_outchar = sc->sc_outchar ^ PPP_TRANS;
+
+          /* clear the escape flag and increment the offset */
+          sc->sc_outflag &= ~SC_TX_ESCAPE;
+          ioffset++;
+        }
+        else {
+          /* need to send the escape character */
+          sc->sc_outchar = PPP_ESCAPE;
+
+          /* set the escape flag */
+          sc->sc_outflag |= SC_TX_ESCAPE;
+        }
+	sendBegin = &sc->sc_outchar;
+      }
+      else {
+        /* escape not needed - increment the offset as much as possible */
+	while ((!ESCAPE_P(sc->sc_outchar)) && ((sc->sc_outoff + ioffset) < sc->sc_outlen)) {
+	    ioffset++;
+	    sc->sc_outchar = sc->sc_outbuf[sc->sc_outoff + ioffset];
+	}
+	sendBegin = &sc->sc_outbuf[sc->sc_outoff];
+      }
+
+      /* write out the character(s) and update the stats */
+      (*tp->handler.write)(ctx, (char *)sendBegin, (ioffset > 0) ? ioffset : 1);
+      sc->sc_stats.ppp_obytes += (ioffset > 0) ? ioffset : 1;
+      sc->sc_outoff += ioffset;
+
+      return (0);
+    }
+  }
+
+  /* Notify driver that we have nothing to transmit */
+  (*tp->handler.write)(ctx, NULL, 0);
+
+  return (0);
+}
+
+#ifdef XXX_XXX
+/*
+ * Timeout routine - try to start some more output.
+ */
+static void
+ppp_timeout(void *x)
+{
+    struct rtems_termios_tty *tty = (struct rtems_termios_tty *)x;
+    struct ppp_softc         *sc  = tty->t_sc;
+/*    struct rtems_termios_tty *tp  = (struct rtems_termios_tty *)sc->sc_devp; */
+
+    sc->sc_flags &= ~SC_TIMEOUT;
+/*    pppstart(tp); */
+}
+#endif
+
+/*
+ * Allocate enough mbuf to handle current MRU.
+ */
+#ifdef XXX_XXX
+static void
+pppgetm(struct ppp_softc *sc)
+{
+    struct mbuf *m, **mp;
+    int len;
+
+    mp = &sc->sc_m;
+    for (len = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN; len > 0; ){
+	if ((m = *mp) == NULL) {
+	    MGETHDR(m, M_DONTWAIT, MT_DATA);
+	    if (m == NULL)
+		break;
+	    *mp = m;
+	    MCLGET(m, M_DONTWAIT);
+	}
+	len -= M_DATASIZE(m);
+	mp = &m->m_next;
+    }
+}
+#endif
+
+void
+pppallocmbuf(struct ppp_softc *sc, struct mbuf **mp)
+{
+  int            ilen;
+  struct mbuf   *m;
+
+  /* loop over length value */
+  ilen = sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN;
+  while ( ilen > 0 ) {
+    /* see if this is end of the chain */
+    m = *mp;
+    if ( m == NULL ) {
+      /* get mbuf header */
+      MGETHDR(m, M_WAIT, MT_DATA);
+      MCLGET(m, M_WAIT);
+      *mp = m;
+    }
+
+    /* update loop variables */
+    mp    = &m->m_next;
+    ilen -= M_DATASIZE(m);
+  }
+}
+
+/*
+ * tty interface receiver interrupt.
+ */
+static uint32_t paritytab[8] = {
+    0x96696996L, 0x69969669L, 0x69969669L, 0x96696996L,
+    0x69969669L, 0x96696996L, 0x96696996L, 0x69969669L
+};
+
+int
+pppinput(int c, struct rtems_termios_tty *tp)
+{
+    register struct ppp_softc *sc = tp->t_sc;
+    struct mbuf *m;
+    int ilen;
+
+    if (sc == NULL || tp != (struct rtems_termios_tty *)sc->sc_devp)
+	return 0;
+    if (sc->sc_m == NULL) {
+        rtems_event_send(sc->sc_rxtask, RX_EMPTY);
+        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
+        if ( sc->sc_m == NULL ) {
+          return 0;
+        }
+    }
+
+    ++sc->sc_stats.ppp_ibytes;
+
+    c &= 0xff;
+    if (c & 0x80)
+	sc->sc_flags |= SC_RCV_B7_1;
+    else
+	sc->sc_flags |= SC_RCV_B7_0;
+    if (paritytab[c >> 5] & (1 << (c & 0x1F)))
+	sc->sc_flags |= SC_RCV_ODDP;
+    else
+	sc->sc_flags |= SC_RCV_EVNP;
+
+    if (c == PPP_FLAG) {
+	ilen = sc->sc_ilen;
+	sc->sc_ilen = 0;
+
+	/*
+	 * If SC_ESCAPED is set, then we've seen the packet
+	 * abort sequence "}~".
+	 */
+	if (sc->sc_flags & (SC_FLUSH | SC_ESCAPED)
+	    || (ilen > 0 && sc->sc_fcs != PPP_GOODFCS)) {
+	    sc->sc_flags |= SC_PKTLOST;	/* note the dropped packet */
+	    if ((sc->sc_flags & (SC_FLUSH | SC_ESCAPED)) == 0){
+                /* bad fcs error */
+		sc->sc_if.if_ierrors++;
+		sc->sc_stats.ppp_ierrors++;
+	    } else
+		sc->sc_flags &= ~(SC_FLUSH | SC_ESCAPED);
+	    return 0;
+	}
+
+	if (ilen < PPP_HDRLEN + PPP_FCSLEN) {
+	    if (ilen) {
+                /* too short error */
+		sc->sc_if.if_ierrors++;
+		sc->sc_stats.ppp_ierrors++;
+		sc->sc_flags |= SC_PKTLOST;
+	    }
+	    return 0;
+	}
+
+	/* Remove FCS trailer.  Somewhat painful... */
+	ilen -= 2;
+	if (--sc->sc_mc->m_len == 0) {
+	    for (m = sc->sc_m; m->m_next != sc->sc_mc; m = m->m_next);
+	    sc->sc_mc = m;
+	}
+	sc->sc_mc->m_len--;
+
+	/* excise this mbuf chain - place on raw queue */
+	m = sc->sc_m;
+        if ( sc->sc_flags & SC_PKTLOST ) {
+          m->m_flags   |= M_ERRMARK;
+          sc->sc_flags &= ~SC_PKTLOST;
+        }
+        IF_ENQUEUE(&sc->sc_rawq, m);
+
+        /* setup next mbuf chain */
+        IF_DEQUEUE(&sc->sc_freeq, sc->sc_m);
+
+        /* send rx packet event */
+        rtems_event_send(sc->sc_rxtask, RX_PACKET);
+	return 0;
+    }
+
+    if (c < 0x20 && (sc->sc_rasyncmap & (1 << c)))
+	return 0;
+
+    if (sc->sc_flags & SC_ESCAPED) {
+	sc->sc_flags &= ~SC_ESCAPED;
+	c ^= PPP_TRANS;
+    } else if (c == PPP_ESCAPE) {
+	sc->sc_flags |= SC_ESCAPED;
+	return 0;
+    }
+
+    /*
+     * Initialize buffer on first octet received.
+     * First octet could be address or protocol (when compressing
+     * address/control).
+     * Second octet is control.
+     * Third octet is first or second (when compressing protocol)
+     * octet of protocol.
+     * Fourth octet is second octet of protocol.
+     */
+    if (sc->sc_ilen == 0) {
+	m = sc->sc_m;
+	m->m_len = 0;
+	m->m_data = M_DATASTART(sc->sc_m);
+	sc->sc_mc = m;
+	sc->sc_mp = mtod(m, char *);
+	sc->sc_fcs = PPP_INITFCS;
+	if (c != PPP_ALLSTATIONS) {
+	    if (sc->sc_flags & SC_REJ_COMP_AC) {
+                /* garbage received error */
+		goto flush;
+	    }
+	    *sc->sc_mp++ = PPP_ALLSTATIONS;
+	    *sc->sc_mp++ = PPP_UI;
+	    sc->sc_ilen += 2;
+	    m->m_len += 2;
+	}
+    }
+    if (sc->sc_ilen == 1 && c != PPP_UI) {
+        /* missing UI error */
+	goto flush;
+    }
+    if (sc->sc_ilen == 2 && (c & 1) == 1) {
+	/* a compressed protocol */
+	*sc->sc_mp++ = 0;
+	sc->sc_ilen++;
+	sc->sc_mc->m_len++;
+    }
+    if (sc->sc_ilen == 3 && (c & 1) == 0) {
+        /* bad protocol error */
+	goto flush;
+    }
+
+    /* packet beyond configured mru? */
+    if (++sc->sc_ilen > sc->sc_mru + PPP_HDRLEN + PPP_FCSLEN) {
+        /* packet too big error */
+	goto flush;
+    }
+
+    /* is this mbuf full? */
+    m = sc->sc_mc;
+    if (M_TRAILINGSPACE(m) <= 0) {
+	if (m->m_next == NULL) {
+          /* get next available mbuf for the chain */
+          IF_DEQUEUE(&sc->sc_freeq, m->m_next);
+          if (m->m_next == NULL) {
+            /* too few mbufs */
+            goto flush;
+          }
+          else {
+            /* send rx mbuf event */
+            rtems_event_send(sc->sc_rxtask, RX_MBUF);
+          }
+	}
+	sc->sc_mc = m = m->m_next;
+	m->m_len  = 0;
+	m->m_next = 0;
+	m->m_data = M_DATASTART(m);
+	sc->sc_mp = mtod(m, char *);
+    }
+
+    ++m->m_len;
+    *sc->sc_mp++ = c;
+    sc->sc_fcs = PPP_FCS(sc->sc_fcs, c);
+    return 0;
+
+ flush:
+    if (!(sc->sc_flags & SC_FLUSH)) {
+	sc->sc_if.if_ierrors++;
+	sc->sc_stats.ppp_ierrors++;
+	sc->sc_flags |= SC_FLUSH;
+    }
+    return 0;
+}
+
+#ifdef XXX_XXX
+#define MAX_DUMP_BYTES	128
+
+static void
+ppplogchar(struct ppp_softc *sc, int c)
+{
+    if (c >= 0)
+	sc->sc_rawin[sc->sc_rawin_count++] = c;
+    if (sc->sc_rawin_count >= sizeof(sc->sc_rawin)
+	|| (c < 0 && sc->sc_rawin_count > 0)) {
+	printf("ppp%d input: ", sc->sc_if.if_unit);
+	pppdumpb(sc->sc_rawin, sc->sc_rawin_count);
+	sc->sc_rawin_count = 0;
+    }
+}
+
+static void
+pppdumpb(u_char *b, int l)
+{
+    char buf[3*MAX_DUMP_BYTES+4];
+    char *bp = buf;
+    static char digits[] = "0123456789abcdef";
+
+    while (l--) {
+	if (bp >= buf + sizeof(buf) - 3) {
+	    *bp++ = '>';
+	    break;
+	}
+	*bp++ = digits[*b >> 4]; /* convert byte to ascii hex */
+	*bp++ = digits[*b++ & 0xf];
+	*bp++ = ' ';
+    }
+
+    *bp = 0;
+    printf("%s\n", buf);
+}
+#endif
+
+#endif	/* NPPP > 0 */



More information about the vc mailing list