You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/09/30 00:30:49 UTC

[06/51] [abbrv] [partial] incubator-mynewt-core git commit: net/ip/lwip_base; LwIP.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f5a0f2a0/net/ip/lwip_base/src/netif/ppp/chap_ms.c
----------------------------------------------------------------------
diff --git a/net/ip/lwip_base/src/netif/ppp/chap_ms.c b/net/ip/lwip_base/src/netif/ppp/chap_ms.c
new file mode 100644
index 0000000..5a989c9
--- /dev/null
+++ b/net/ip/lwip_base/src/netif/ppp/chap_ms.c
@@ -0,0 +1,962 @@
+/*
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.
+ *
+ * Copyright (c) 1995 Eric Rosenquist.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997
+ *
+ *   Implemented LANManager type password response to MS-CHAP challenges.
+ *   Now pppd provides both NT style and LANMan style blocks, and the
+ *   prefered is set by option "ms-lanman". Default is to use NT.
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.
+ *
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80
+ */
+
+/*
+ * Modifications by Frank Cusack, frank@google.com, March 2002.
+ *
+ *   Implemented MS-CHAPv2 functionality, heavily based on sample
+ *   implementation in RFC 2759.  Implemented MPPE functionality,
+ *   heavily based on sample implementation in RFC 3079.
+ *
+ * Copyright (c) 2002 Google, Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "netif/ppp/ppp_opts.h"
+#if PPP_SUPPORT && MSCHAP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
+
+#if 0 /* UNUSED */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif /* UNUSED */
+
+#include "netif/ppp/ppp_impl.h"
+
+#include "netif/ppp/chap-new.h"
+#include "netif/ppp/chap_ms.h"
+#include "netif/ppp/pppcrypt.h"
+#include "netif/ppp/magic.h"
+#if MPPE_SUPPORT
+#include "netif/ppp/mppe.h" /* For mppe_sha1_pad*, mppe_set_key() */
+#endif /* MPPE_SUPPORT */
+
+#define SHA1_SIGNATURE_SIZE	20
+#define MD4_SIGNATURE_SIZE	16	/* 16 bytes in a MD4 message digest */
+#define MAX_NT_PASSWORD		256	/* Max (Unicode) chars in an NT pass */
+
+#define MS_CHAP_RESPONSE_LEN	49	/* Response length for MS-CHAP */
+#define MS_CHAP2_RESPONSE_LEN	49	/* Response length for MS-CHAPv2 */
+#define MS_AUTH_RESPONSE_LENGTH	40	/* MS-CHAPv2 authenticator response, */
+					/* as ASCII */
+
+/* Error codes for MS-CHAP failure messages. */
+#define MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS	646
+#define MS_CHAP_ERROR_ACCT_DISABLED		647
+#define MS_CHAP_ERROR_PASSWD_EXPIRED		648
+#define MS_CHAP_ERROR_NO_DIALIN_PERMISSION	649
+#define MS_CHAP_ERROR_AUTHENTICATION_FAILURE	691
+#define MS_CHAP_ERROR_CHANGING_PASSWORD		709
+
+/*
+ * Offsets within the response field for MS-CHAP
+ */
+#define MS_CHAP_LANMANRESP	0
+#define MS_CHAP_LANMANRESP_LEN	24
+#define MS_CHAP_NTRESP		24
+#define MS_CHAP_NTRESP_LEN	24
+#define MS_CHAP_USENT		48
+
+/*
+ * Offsets within the response field for MS-CHAP2
+ */
+#define MS_CHAP2_PEER_CHALLENGE	0
+#define MS_CHAP2_PEER_CHAL_LEN	16
+#define MS_CHAP2_RESERVED_LEN	8
+#define MS_CHAP2_NTRESP		24
+#define MS_CHAP2_NTRESP_LEN	24
+#define MS_CHAP2_FLAGS		48
+
+#if MPPE_SUPPORT
+#if 0 /* UNUSED */
+/* These values are the RADIUS attribute values--see RFC 2548. */
+#define MPPE_ENC_POL_ENC_ALLOWED 1
+#define MPPE_ENC_POL_ENC_REQUIRED 2
+#define MPPE_ENC_TYPES_RC4_40 2
+#define MPPE_ENC_TYPES_RC4_128 4
+
+/* used by plugins (using above values) */
+extern void set_mppe_enc_types(int, int);
+#endif /* UNUSED */
+#endif /* MPPE_SUPPORT */
+
+/* Are we the authenticator or authenticatee?  For MS-CHAPv2 key derivation. */
+#define MS_CHAP2_AUTHENTICATEE 0
+#define MS_CHAP2_AUTHENTICATOR 1
+
+static void	ascii2unicode (const char[], int, u_char[]);
+static void	NTPasswordHash (u_char *, int, u_char[MD4_SIGNATURE_SIZE]);
+static void	ChallengeResponse (const u_char *, const u_char *, u_char[24]);
+static void	ChallengeHash (const u_char[16], const u_char *, const char *, u_char[8]);
+static void	ChapMS_NT (const u_char *, const char *, int, u_char[24]);
+static void	ChapMS2_NT (const u_char *, const u_char[16], const char *, const char *, int,
+				u_char[24]);
+static void	GenerateAuthenticatorResponsePlain
+			(const char*, int, u_char[24], const u_char[16], const u_char *,
+			     const char *, u_char[41]);
+#ifdef MSLANMAN
+static void	ChapMS_LANMan (u_char *, char *, int, u_char *);
+#endif
+
+static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+			u_char NTResponse[24], const u_char PeerChallenge[16],
+			const u_char *rchallenge, const char *username,
+			u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]);
+
+#if MPPE_SUPPORT
+static void	Set_Start_Key (ppp_pcb *pcb, const u_char *, const char *, int);
+static void	SetMasterKeys (ppp_pcb *pcb, const char *, int, u_char[24], int);
+#endif /* MPPE_SUPPORT */
+
+static void ChapMS (ppp_pcb *pcb, const u_char *, const char *, int, u_char *);
+static void ChapMS2 (ppp_pcb *pcb, const u_char *, const u_char *, const char *, const char *, int,
+		  u_char *, u_char[MS_AUTH_RESPONSE_LENGTH+1], int);
+
+#ifdef MSLANMAN
+bool	ms_lanman = 0;    	/* Use LanMan password instead of NT */
+			  	/* Has meaning only with MS-CHAP challenges */
+#endif
+
+#if MPPE_SUPPORT
+#ifdef DEBUGMPPEKEY
+/* For MPPE debug */
+/* Use "[]|}{?/><,`!2&&(" (sans quotes) for RFC 3079 MS-CHAPv2 test value */
+static char *mschap_challenge = NULL;
+/* Use "!@\#$%^&*()_+:3|~" (sans quotes, backslash is to escape #) for ... */
+static char *mschap2_peer_challenge = NULL;
+#endif
+
+#include "netif/ppp/fsm.h"		/* Need to poke MPPE options */
+#include "netif/ppp/ccp.h"
+#endif /* MPPE_SUPPORT */
+
+#if PPP_OPTIONS
+/*
+ * Command-line options.
+ */
+static option_t chapms_option_list[] = {
+#ifdef MSLANMAN
+	{ "ms-lanman", o_bool, &ms_lanman,
+	  "Use LanMan passwd when using MS-CHAP", 1 },
+#endif
+#ifdef DEBUGMPPEKEY
+	{ "mschap-challenge", o_string, &mschap_challenge,
+	  "specify CHAP challenge" },
+	{ "mschap2-peer-challenge", o_string, &mschap2_peer_challenge,
+	  "specify CHAP peer challenge" },
+#endif
+	{ NULL }
+};
+#endif /* PPP_OPTIONS */
+
+#if PPP_SERVER
+/*
+ * chapms_generate_challenge - generate a challenge for MS-CHAP.
+ * For MS-CHAP the challenge length is fixed at 8 bytes.
+ * The length goes in challenge[0] and the actual challenge starts
+ * at challenge[1].
+ */
+static void chapms_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
+	LWIP_UNUSED_ARG(pcb);
+
+	*challenge++ = 8;
+#ifdef DEBUGMPPEKEY
+	if (mschap_challenge && strlen(mschap_challenge) == 8)
+		memcpy(challenge, mschap_challenge, 8);
+	else
+#endif
+		magic_random_bytes(challenge, 8);
+}
+
+static void chapms2_generate_challenge(ppp_pcb *pcb, unsigned char *challenge) {
+	LWIP_UNUSED_ARG(pcb);
+
+	*challenge++ = 16;
+#ifdef DEBUGMPPEKEY
+	if (mschap_challenge && strlen(mschap_challenge) == 16)
+		memcpy(challenge, mschap_challenge, 16);
+	else
+#endif
+		magic_random_bytes(challenge, 16);
+}
+
+static int chapms_verify_response(ppp_pcb *pcb, int id, const char *name,
+		       const unsigned char *secret, int secret_len,
+		       const unsigned char *challenge, const unsigned char *response,
+		       char *message, int message_space) {
+	unsigned char md[MS_CHAP_RESPONSE_LEN];
+	int diff;
+	int challenge_len, response_len;
+	LWIP_UNUSED_ARG(id);
+	LWIP_UNUSED_ARG(name);
+
+	challenge_len = *challenge++;	/* skip length, is 8 */
+	response_len = *response++;
+	if (response_len != MS_CHAP_RESPONSE_LEN)
+		goto bad;
+
+#ifndef MSLANMAN
+	if (!response[MS_CHAP_USENT]) {
+		/* Should really propagate this into the error packet. */
+		ppp_notice("Peer request for LANMAN auth not supported");
+		goto bad;
+	}
+#endif
+
+	/* Generate the expected response. */
+	ChapMS(pcb, (const u_char *)challenge, (const char *)secret, secret_len, md);
+
+#ifdef MSLANMAN
+	/* Determine which part of response to verify against */
+	if (!response[MS_CHAP_USENT])
+		diff = memcmp(&response[MS_CHAP_LANMANRESP],
+			      &md[MS_CHAP_LANMANRESP], MS_CHAP_LANMANRESP_LEN);
+	else
+#endif
+		diff = memcmp(&response[MS_CHAP_NTRESP], &md[MS_CHAP_NTRESP],
+			      MS_CHAP_NTRESP_LEN);
+
+	if (diff == 0) {
+		ppp_slprintf(message, message_space, "Access granted");
+		return 1;
+	}
+
+ bad:
+	/* See comments below for MS-CHAP V2 */
+	ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0",
+		 challenge_len, challenge);
+	return 0;
+}
+
+static int chapms2_verify_response(ppp_pcb *pcb, int id, const char *name,
+			const unsigned char *secret, int secret_len,
+			const unsigned char *challenge, const unsigned char *response,
+			char *message, int message_space) {
+	unsigned char md[MS_CHAP2_RESPONSE_LEN];
+	char saresponse[MS_AUTH_RESPONSE_LENGTH+1];
+	int challenge_len, response_len;
+	LWIP_UNUSED_ARG(id);
+
+	challenge_len = *challenge++;	/* skip length, is 16 */
+	response_len = *response++;
+	if (response_len != MS_CHAP2_RESPONSE_LEN)
+		goto bad;	/* not even the right length */
+
+	/* Generate the expected response and our mutual auth. */
+	ChapMS2(pcb, (const u_char*)challenge, (const u_char*)&response[MS_CHAP2_PEER_CHALLENGE], name,
+		(const char *)secret, secret_len, md,
+		(unsigned char *)saresponse, MS_CHAP2_AUTHENTICATOR);
+
+	/* compare MDs and send the appropriate status */
+	/*
+	 * Per RFC 2759, success message must be formatted as
+	 *     "S=<auth_string> M=<message>"
+	 * where
+	 *     <auth_string> is the Authenticator Response (mutual auth)
+	 *     <message> is a text message
+	 *
+	 * However, some versions of Windows (win98 tested) do not know
+	 * about the M=<message> part (required per RFC 2759) and flag
+	 * it as an error (reported incorrectly as an encryption error
+	 * to the user).  Since the RFC requires it, and it can be
+	 * useful information, we supply it if the peer is a conforming
+	 * system.  Luckily (?), win98 sets the Flags field to 0x04
+	 * (contrary to RFC requirements) so we can use that to
+	 * distinguish between conforming and non-conforming systems.
+	 *
+	 * Special thanks to Alex Swiridov <sa...@real.kharkov.ua> for
+	 * help debugging this.
+	 */
+	if (memcmp(&md[MS_CHAP2_NTRESP], &response[MS_CHAP2_NTRESP],
+		   MS_CHAP2_NTRESP_LEN) == 0) {
+		if (response[MS_CHAP2_FLAGS])
+			ppp_slprintf(message, message_space, "S=%s", saresponse);
+		else
+			ppp_slprintf(message, message_space, "S=%s M=%s",
+				 saresponse, "Access granted");
+		return 1;
+	}
+
+ bad:
+	/*
+	 * Failure message must be formatted as
+	 *     "E=e R=r C=c V=v M=m"
+	 * where
+	 *     e = error code (we use 691, ERROR_AUTHENTICATION_FAILURE)
+	 *     r = retry (we use 1, ok to retry)
+	 *     c = challenge to use for next response, we reuse previous
+	 *     v = Change Password version supported, we use 0
+	 *     m = text message
+	 *
+	 * The M=m part is only for MS-CHAPv2.  Neither win2k nor
+	 * win98 (others untested) display the message to the user anyway.
+	 * They also both ignore the E=e code.
+	 *
+	 * Note that it's safe to reuse the same challenge as we don't
+	 * actually accept another response based on the error message
+	 * (and no clients try to resend a response anyway).
+	 *
+	 * Basically, this whole bit is useless code, even the small
+	 * implementation here is only because of overspecification.
+	 */
+	ppp_slprintf(message, message_space, "E=691 R=1 C=%0.*B V=0 M=%s",
+		 challenge_len, challenge, "Access denied");
+	return 0;
+}
+#endif /* PPP_SERVER */
+
+static void chapms_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
+		     const unsigned char *challenge, const char *secret, int secret_len,
+		     unsigned char *private_) {
+	LWIP_UNUSED_ARG(id);
+	LWIP_UNUSED_ARG(our_name);
+	LWIP_UNUSED_ARG(private_);
+	challenge++;	/* skip length, should be 8 */
+	*response++ = MS_CHAP_RESPONSE_LEN;
+	ChapMS(pcb, challenge, secret, secret_len, response);
+}
+
+static void chapms2_make_response(ppp_pcb *pcb, unsigned char *response, int id, const char *our_name,
+		      const unsigned char *challenge, const char *secret, int secret_len,
+		      unsigned char *private_) {
+	LWIP_UNUSED_ARG(id);
+	challenge++;	/* skip length, should be 16 */
+	*response++ = MS_CHAP2_RESPONSE_LEN;
+	ChapMS2(pcb, challenge,
+#ifdef DEBUGMPPEKEY
+		mschap2_peer_challenge,
+#else
+		NULL,
+#endif
+		our_name, secret, secret_len, response, private_,
+		MS_CHAP2_AUTHENTICATEE);
+}
+
+static int chapms2_check_success(ppp_pcb *pcb, unsigned char *msg, int len, unsigned char *private_) {
+	LWIP_UNUSED_ARG(pcb);
+
+	if ((len < MS_AUTH_RESPONSE_LENGTH + 2) ||
+	    strncmp((char *)msg, "S=", 2) != 0) {
+		/* Packet does not start with "S=" */
+		ppp_error("MS-CHAPv2 Success packet is badly formed.");
+		return 0;
+	}
+	msg += 2;
+	len -= 2;
+	if (len < MS_AUTH_RESPONSE_LENGTH
+	    || memcmp(msg, private_, MS_AUTH_RESPONSE_LENGTH)) {
+		/* Authenticator Response did not match expected. */
+		ppp_error("MS-CHAPv2 mutual authentication failed.");
+		return 0;
+	}
+	/* Authenticator Response matches. */
+	msg += MS_AUTH_RESPONSE_LENGTH; /* Eat it */
+	len -= MS_AUTH_RESPONSE_LENGTH;
+	if ((len >= 3) && !strncmp((char *)msg, " M=", 3)) {
+		msg += 3; /* Eat the delimiter */
+	} else if (len) {
+		/* Packet has extra text which does not begin " M=" */
+		ppp_error("MS-CHAPv2 Success packet is badly formed.");
+		return 0;
+	}
+	return 1;
+}
+
+static void chapms_handle_failure(ppp_pcb *pcb, unsigned char *inp, int len) {
+	int err;
+	const char *p;
+	char msg[64];
+	LWIP_UNUSED_ARG(pcb);
+
+	/* We want a null-terminated string for strxxx(). */
+	len = LWIP_MIN(len, 63);
+	MEMCPY(msg, inp, len);
+	msg[len] = 0;
+	p = msg;
+
+	/*
+	 * Deal with MS-CHAP formatted failure messages; just print the
+	 * M=<message> part (if any).  For MS-CHAP we're not really supposed
+	 * to use M=<message>, but it shouldn't hurt.  See
+	 * chapms[2]_verify_response.
+	 */
+	if (!strncmp(p, "E=", 2))
+		err = strtol(p+2, NULL, 10); /* Remember the error code. */
+	else
+		goto print_msg; /* Message is badly formatted. */
+
+	if (len && ((p = strstr(p, " M=")) != NULL)) {
+		/* M=<message> field found. */
+		p += 3;
+	} else {
+		/* No M=<message>; use the error code. */
+		switch (err) {
+		case MS_CHAP_ERROR_RESTRICTED_LOGON_HOURS:
+			p = "E=646 Restricted logon hours";
+			break;
+
+		case MS_CHAP_ERROR_ACCT_DISABLED:
+			p = "E=647 Account disabled";
+			break;
+
+		case MS_CHAP_ERROR_PASSWD_EXPIRED:
+			p = "E=648 Password expired";
+			break;
+
+		case MS_CHAP_ERROR_NO_DIALIN_PERMISSION:
+			p = "E=649 No dialin permission";
+			break;
+
+		case MS_CHAP_ERROR_AUTHENTICATION_FAILURE:
+			p = "E=691 Authentication failure";
+			break;
+
+		case MS_CHAP_ERROR_CHANGING_PASSWORD:
+			/* Should never see this, we don't support Change Password. */
+			p = "E=709 Error changing password";
+			break;
+
+		default:
+			ppp_error("Unknown MS-CHAP authentication failure: %.*v",
+			      len, inp);
+			return;
+		}
+	}
+print_msg:
+	if (p != NULL)
+		ppp_error("MS-CHAP authentication failed: %v", p);
+}
+
+static void ChallengeResponse(const u_char *challenge,
+		  const u_char PasswordHash[MD4_SIGNATURE_SIZE],
+		  u_char response[24]) {
+    u_char    ZPasswordHash[21];
+    lwip_des_context des;
+    u_char des_key[8];
+
+    BZERO(ZPasswordHash, sizeof(ZPasswordHash));
+    MEMCPY(ZPasswordHash, PasswordHash, MD4_SIGNATURE_SIZE);
+
+#if 0
+    dbglog("ChallengeResponse - ZPasswordHash %.*B",
+	   sizeof(ZPasswordHash), ZPasswordHash);
+#endif
+
+    pppcrypt_56_to_64_bit_key(ZPasswordHash + 0, des_key);
+    lwip_des_init(&des);
+    lwip_des_setkey_enc(&des, des_key);
+    lwip_des_crypt_ecb(&des, challenge, response +0);
+    lwip_des_free(&des);
+
+    pppcrypt_56_to_64_bit_key(ZPasswordHash + 7, des_key);
+    lwip_des_init(&des);
+    lwip_des_setkey_enc(&des, des_key);
+    lwip_des_crypt_ecb(&des, challenge, response +8);
+    lwip_des_free(&des);
+
+    pppcrypt_56_to_64_bit_key(ZPasswordHash + 14, des_key);
+    lwip_des_init(&des);
+    lwip_des_setkey_enc(&des, des_key);
+    lwip_des_crypt_ecb(&des, challenge, response +16);
+    lwip_des_free(&des);
+
+#if 0
+    dbglog("ChallengeResponse - response %.24B", response);
+#endif
+}
+
+static void ChallengeHash(const u_char PeerChallenge[16], const u_char *rchallenge,
+	      const char *username, u_char Challenge[8]) {
+    lwip_sha1_context	sha1Context;
+    u_char	sha1Hash[SHA1_SIGNATURE_SIZE];
+    const char	*user;
+
+    /* remove domain from "domain\username" */
+    if ((user = strrchr(username, '\\')) != NULL)
+	++user;
+    else
+	user = username;
+
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, PeerChallenge, 16);
+    lwip_sha1_update(&sha1Context, rchallenge, 16);
+    lwip_sha1_update(&sha1Context, (const unsigned char*)user, strlen(user));
+    lwip_sha1_finish(&sha1Context, sha1Hash);
+    lwip_sha1_free(&sha1Context);
+
+    MEMCPY(Challenge, sha1Hash, 8);
+}
+
+/*
+ * Convert the ASCII version of the password to Unicode.
+ * This implicitly supports 8-bit ISO8859/1 characters.
+ * This gives us the little-endian representation, which
+ * is assumed by all M$ CHAP RFCs.  (Unicode byte ordering
+ * is machine-dependent.)
+ */
+static void ascii2unicode(const char ascii[], int ascii_len, u_char unicode[]) {
+    int i;
+
+    BZERO(unicode, ascii_len * 2);
+    for (i = 0; i < ascii_len; i++)
+	unicode[i * 2] = (u_char) ascii[i];
+}
+
+static void NTPasswordHash(u_char *secret, int secret_len, u_char hash[MD4_SIGNATURE_SIZE]) {
+    lwip_md4_context		md4Context;
+
+    lwip_md4_init(&md4Context);
+    lwip_md4_starts(&md4Context);
+    lwip_md4_update(&md4Context, secret, secret_len);
+    lwip_md4_finish(&md4Context, hash);
+    lwip_md4_free(&md4Context);
+}
+
+static void ChapMS_NT(const u_char *rchallenge, const char *secret, int secret_len,
+	  u_char NTResponse[24]) {
+    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
+
+    /* Hash the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+
+    ChallengeResponse(rchallenge, PasswordHash, NTResponse);
+}
+
+static void ChapMS2_NT(const u_char *rchallenge, const u_char PeerChallenge[16], const char *username,
+	   const char *secret, int secret_len, u_char NTResponse[24]) {
+    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char	Challenge[8];
+
+    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
+
+    /* Hash the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+
+    ChallengeResponse(Challenge, PasswordHash, NTResponse);
+}
+
+#ifdef MSLANMAN
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */
+
+static void ChapMS_LANMan(u_char *rchallenge, char *secret, int secret_len,
+	      unsigned char *response) {
+    int			i;
+    u_char		UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */
+    u_char		PasswordHash[MD4_SIGNATURE_SIZE];
+    lwip_des_context des;
+    u_char des_key[8];
+
+    /* LANMan password is case insensitive */
+    BZERO(UcasePassword, sizeof(UcasePassword));
+    for (i = 0; i < secret_len; i++)
+       UcasePassword[i] = (u_char)toupper(secret[i]);
+
+    pppcrypt_56_to_64_bit_key(UcasePassword +0, des_key);
+    lwip_des_init(&des);
+    lwip_des_setkey_enc(&des, des_key);
+    lwip_des_crypt_ecb(&des, StdText, PasswordHash +0);
+    lwip_des_free(&des);
+
+    pppcrypt_56_to_64_bit_key(UcasePassword +7, des_key);
+    lwip_des_init(&des);
+    lwip_des_setkey_enc(&des, des_key);
+    lwip_des_crypt_ecb(&des, StdText, PasswordHash +8);
+    lwip_des_free(&des);
+
+    ChallengeResponse(rchallenge, PasswordHash, &response[MS_CHAP_LANMANRESP]);
+}
+#endif
+
+
+static void GenerateAuthenticatorResponse(const u_char PasswordHashHash[MD4_SIGNATURE_SIZE],
+			      u_char NTResponse[24], const u_char PeerChallenge[16],
+			      const u_char *rchallenge, const char *username,
+			      u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
+    /*
+     * "Magic" constants used in response generation, from RFC 2759.
+     */
+    static const u_char Magic1[39] = /* "Magic server to client signing constant" */
+	{ 0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+	  0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+	  0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+	  0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74 };
+    static const u_char Magic2[41] = /* "Pad to make it do more than one iteration" */
+	{ 0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+	  0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+	  0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+	  0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+	  0x6E };
+
+    int		i;
+    lwip_sha1_context	sha1Context;
+    u_char	Digest[SHA1_SIGNATURE_SIZE];
+    u_char	Challenge[8];
+
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+    lwip_sha1_update(&sha1Context, NTResponse, 24);
+    lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
+    lwip_sha1_finish(&sha1Context, Digest);
+    lwip_sha1_free(&sha1Context);
+
+    ChallengeHash(PeerChallenge, rchallenge, username, Challenge);
+
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, Digest, sizeof(Digest));
+    lwip_sha1_update(&sha1Context, Challenge, sizeof(Challenge));
+    lwip_sha1_update(&sha1Context, Magic2, sizeof(Magic2));
+    lwip_sha1_finish(&sha1Context, Digest);
+    lwip_sha1_free(&sha1Context);
+
+    /* Convert to ASCII hex string. */
+    for (i = 0; i < LWIP_MAX((MS_AUTH_RESPONSE_LENGTH / 2), (int)sizeof(Digest)); i++)
+	sprintf((char *)&authResponse[i * 2], "%02X", Digest[i]);
+}
+
+
+static void GenerateAuthenticatorResponsePlain(
+		 const char *secret, int secret_len,
+		 u_char NTResponse[24], const u_char PeerChallenge[16],
+		 const u_char *rchallenge, const char *username,
+		 u_char authResponse[MS_AUTH_RESPONSE_LENGTH+1]) {
+    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
+
+    /* Hash (x2) the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(PasswordHash, sizeof(PasswordHash),
+		   PasswordHashHash);
+
+    GenerateAuthenticatorResponse(PasswordHashHash, NTResponse, PeerChallenge,
+				  rchallenge, username, authResponse);
+}
+
+
+#if MPPE_SUPPORT
+/*
+ * Set mppe_xxxx_key from MS-CHAP credentials. (see RFC 3079)
+ */
+static void Set_Start_Key(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len) {
+    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
+    lwip_sha1_context	sha1Context;
+    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
+
+    /* Hash (x2) the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
+
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+    lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+    lwip_sha1_update(&sha1Context, rchallenge, 8);
+    lwip_sha1_finish(&sha1Context, Digest);
+    lwip_sha1_free(&sha1Context);
+
+    /* Same key in both directions. */
+    mppe_set_key(pcb, &pcb->mppe_comp, Digest);
+    mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
+
+    pcb->mppe_keys_set = 1;
+}
+
+/*
+ * Set mppe_xxxx_key from MS-CHAPv2 credentials. (see RFC 3079)
+ */
+static void SetMasterKeys(ppp_pcb *pcb, const char *secret, int secret_len, u_char NTResponse[24], int IsServer) {
+    u_char	unicodePassword[MAX_NT_PASSWORD * 2];
+    u_char	PasswordHash[MD4_SIGNATURE_SIZE];
+    u_char	PasswordHashHash[MD4_SIGNATURE_SIZE];
+    lwip_sha1_context	sha1Context;
+    u_char	MasterKey[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
+    u_char	Digest[SHA1_SIGNATURE_SIZE];	/* >= MPPE_MAX_KEY_LEN */
+    const u_char *s;
+
+    /* "This is the MPPE Master Key" */
+    static const u_char Magic1[27] =
+	{ 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+	  0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+	  0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
+    /* "On the client side, this is the send key; "
+       "on the server side, it is the receive key." */
+    static const u_char Magic2[84] =
+	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+	  0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+	  0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+	  0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+	  0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+	  0x6b, 0x65, 0x79, 0x2e };
+    /* "On the client side, this is the receive key; "
+       "on the server side, it is the send key." */
+    static const u_char Magic3[84] =
+	{ 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+	  0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+	  0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+	  0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+	  0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+	  0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+	  0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+	  0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+	  0x6b, 0x65, 0x79, 0x2e };
+
+    /* Hash (x2) the Unicode version of the secret (== password). */
+    ascii2unicode(secret, secret_len, unicodePassword);
+    NTPasswordHash(unicodePassword, secret_len * 2, PasswordHash);
+    NTPasswordHash(PasswordHash, sizeof(PasswordHash), PasswordHashHash);
+
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, PasswordHashHash, MD4_SIGNATURE_SIZE);
+    lwip_sha1_update(&sha1Context, NTResponse, 24);
+    lwip_sha1_update(&sha1Context, Magic1, sizeof(Magic1));
+    lwip_sha1_finish(&sha1Context, MasterKey);
+    lwip_sha1_free(&sha1Context);
+
+    /*
+     * generate send key
+     */
+    if (IsServer)
+	s = Magic3;
+    else
+	s = Magic2;
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, MasterKey, 16);
+    lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
+    lwip_sha1_update(&sha1Context, s, 84);
+    lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
+    lwip_sha1_finish(&sha1Context, Digest);
+    lwip_sha1_free(&sha1Context);
+
+    mppe_set_key(pcb, &pcb->mppe_comp, Digest);
+
+    /*
+     * generate recv key
+     */
+    if (IsServer)
+	s = Magic2;
+    else
+	s = Magic3;
+    lwip_sha1_init(&sha1Context);
+    lwip_sha1_starts(&sha1Context);
+    lwip_sha1_update(&sha1Context, MasterKey, 16);
+    lwip_sha1_update(&sha1Context, mppe_sha1_pad1, SHA1_PAD_SIZE);
+    lwip_sha1_update(&sha1Context, s, 84);
+    lwip_sha1_update(&sha1Context, mppe_sha1_pad2, SHA1_PAD_SIZE);
+    lwip_sha1_finish(&sha1Context, Digest);
+    lwip_sha1_free(&sha1Context);
+
+    mppe_set_key(pcb, &pcb->mppe_decomp, Digest);
+
+    pcb->mppe_keys_set = 1;
+}
+
+#endif /* MPPE_SUPPORT */
+
+
+static void ChapMS(ppp_pcb *pcb, const u_char *rchallenge, const char *secret, int secret_len,
+       unsigned char *response) {
+#if !MPPE_SUPPORT
+    LWIP_UNUSED_ARG(pcb);
+#endif /* !MPPE_SUPPORT */
+    BZERO(response, MS_CHAP_RESPONSE_LEN);
+
+    ChapMS_NT(rchallenge, secret, secret_len, &response[MS_CHAP_NTRESP]);
+
+#ifdef MSLANMAN
+    ChapMS_LANMan(rchallenge, secret, secret_len,
+		  &response[MS_CHAP_LANMANRESP]);
+
+    /* preferred method is set by option  */
+    response[MS_CHAP_USENT] = !ms_lanman;
+#else
+    response[MS_CHAP_USENT] = 1;
+#endif
+
+#if MPPE_SUPPORT
+    Set_Start_Key(pcb, rchallenge, secret, secret_len);
+#endif /* MPPE_SUPPORT */
+}
+
+
+/*
+ * If PeerChallenge is NULL, one is generated and the PeerChallenge
+ * field of response is filled in.  Call this way when generating a response.
+ * If PeerChallenge is supplied, it is copied into the PeerChallenge field.
+ * Call this way when verifying a response (or debugging).
+ * Do not call with PeerChallenge = response.
+ *
+ * The PeerChallenge field of response is then used for calculation of the
+ * Authenticator Response.
+ */
+static void ChapMS2(ppp_pcb *pcb, const u_char *rchallenge, const u_char *PeerChallenge,
+	const char *user, const char *secret, int secret_len, unsigned char *response,
+	u_char authResponse[], int authenticator) {
+    /* ARGSUSED */
+    LWIP_UNUSED_ARG(authenticator);
+#if !MPPE_SUPPORT
+    LWIP_UNUSED_ARG(pcb);
+#endif /* !MPPE_SUPPORT */
+
+    BZERO(response, MS_CHAP2_RESPONSE_LEN);
+
+    /* Generate the Peer-Challenge if requested, or copy it if supplied. */
+    if (!PeerChallenge)
+	magic_random_bytes(&response[MS_CHAP2_PEER_CHALLENGE], MS_CHAP2_PEER_CHAL_LEN);
+    else
+	MEMCPY(&response[MS_CHAP2_PEER_CHALLENGE], PeerChallenge,
+	      MS_CHAP2_PEER_CHAL_LEN);
+
+    /* Generate the NT-Response */
+    ChapMS2_NT(rchallenge, &response[MS_CHAP2_PEER_CHALLENGE], user,
+	       secret, secret_len, &response[MS_CHAP2_NTRESP]);
+
+    /* Generate the Authenticator Response. */
+    GenerateAuthenticatorResponsePlain(secret, secret_len,
+				       &response[MS_CHAP2_NTRESP],
+				       &response[MS_CHAP2_PEER_CHALLENGE],
+				       rchallenge, user, authResponse);
+
+#if MPPE_SUPPORT
+    SetMasterKeys(pcb, secret, secret_len,
+		  &response[MS_CHAP2_NTRESP], authenticator);
+#endif /* MPPE_SUPPORT */
+}
+
+#if 0 /* UNUSED */
+#if MPPE_SUPPORT
+/*
+ * Set MPPE options from plugins.
+ */
+void set_mppe_enc_types(int policy, int types) {
+    /* Early exit for unknown policies. */
+    if (policy != MPPE_ENC_POL_ENC_ALLOWED ||
+	policy != MPPE_ENC_POL_ENC_REQUIRED)
+	return;
+
+    /* Don't modify MPPE if it's optional and wasn't already configured. */
+    if (policy == MPPE_ENC_POL_ENC_ALLOWED && !ccp_wantoptions[0].mppe)
+	return;
+
+    /*
+     * Disable undesirable encryption types.  Note that we don't ENABLE
+     * any encryption types, to avoid overriding manual configuration.
+     */
+    switch(types) {
+	case MPPE_ENC_TYPES_RC4_40:
+	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_128;	/* disable 128-bit */
+	    break;
+	case MPPE_ENC_TYPES_RC4_128:
+	    ccp_wantoptions[0].mppe &= ~MPPE_OPT_40;	/* disable 40-bit */
+	    break;
+	default:
+	    break;
+    }
+}
+#endif /* MPPE_SUPPORT */
+#endif /* UNUSED */
+
+const struct chap_digest_type chapms_digest = {
+	CHAP_MICROSOFT,		/* code */
+#if PPP_SERVER
+	chapms_generate_challenge,
+	chapms_verify_response,
+#endif /* PPP_SERVER */
+	chapms_make_response,
+	NULL,			/* check_success */
+	chapms_handle_failure,
+};
+
+const struct chap_digest_type chapms2_digest = {
+	CHAP_MICROSOFT_V2,	/* code */
+#if PPP_SERVER
+	chapms2_generate_challenge,
+	chapms2_verify_response,
+#endif /* PPP_SERVER */
+	chapms2_make_response,
+	chapms2_check_success,
+	chapms_handle_failure,
+};
+
+#endif /* PPP_SUPPORT && MSCHAP_SUPPORT */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/f5a0f2a0/net/ip/lwip_base/src/netif/ppp/demand.c
----------------------------------------------------------------------
diff --git a/net/ip/lwip_base/src/netif/ppp/demand.c b/net/ip/lwip_base/src/netif/ppp/demand.c
new file mode 100644
index 0000000..26c6c30
--- /dev/null
+++ b/net/ip/lwip_base/src/netif/ppp/demand.c
@@ -0,0 +1,465 @@
+/*
+ * demand.c - Support routines for demand-dialling.
+ *
+ * Copyright (c) 1996-2002 Paul Mackerras. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. The name(s) of the authors of this software must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission.
+ *
+ * 3. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by Paul Mackerras
+ *     <pa...@samba.org>".
+ *
+ * THE AUTHORS OF THIS SOFTWARE DISCLAIM ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "netif/ppp/ppp_opts.h"
+#if PPP_SUPPORT && DEMAND_SUPPORT  /* don't build if not configured for use in lwipopts.h */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef PPP_FILTER
+#include <pcap-bpf.h>
+#endif
+
+#include "netif/ppp/ppp_impl.h"
+
+#include "netif/ppp/fsm.h"
+#include "netif/ppp/ipcp.h"
+#include "netif/ppp/lcp.h"
+
+char *frame;
+int framelen;
+int framemax;
+int escape_flag;
+int flush_flag;
+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()
+{
+    int i;
+    const 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;
+
+    netif_set_mtu(pcb, LWIP_MIN(lcp_allowoptions[0].mru, PPP_MRU));
+    if (ppp_send_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0
+	|| ppp_recv_config(pcb, PPP_MRU, (u32_t) 0, 0, 0) < 0)
+	    fatal("Couldn't set up demand-dialled PPP interface: %m");
+
+#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->demand_conf != NULL)
+	    ((*protp->demand_conf)(pcb));
+/* FIXME: find a way to die() here */
+#if 0
+	    if (!((*protp->demand_conf)(pcb)))
+		die(1);
+#endif
+}
+
+
+/*
+ * demand_block - set each network protocol to block further packets.
+ */
+void
+demand_block()
+{
+    int i;
+    const struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->demand_conf != NULL)
+	    sifnpmode(pcb, protp->protocol & ~0x8000, NPMODE_QUEUE);
+    get_loop_output();
+}
+
+/*
+ * demand_discard - set each network protocol to discard packets
+ * with an error.
+ */
+void
+demand_discard()
+{
+    struct packet *pkt, *nextpkt;
+    int i;
+    const struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->demand_conf != NULL)
+	    sifnpmode(pcb, 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()
+{
+    int i;
+    const struct protent *protp;
+
+    for (i = 0; (protp = protocols[i]) != NULL; ++i)
+	if (protp->demand_conf != NULL)
+	    sifnpmode(pcb, 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(p, n)
+    unsigned char *p;
+    int n;
+{
+    int c, rv;
+
+    rv = 0;
+
+/* check for synchronous connection... */
+
+    if ( (p[0] == 0xFF) && (p[1] == 0x03) ) {
+        rv = loop_frame(p,n);
+        return rv;
+    }
+
+    for (; n > 0; --n) {
+	c = *p++;
+	if (c == PPP_FLAG) {
+	    if (!escape_flag && !flush_flag
+		&& framelen > 2 && fcs == PPP_GOODFCS) {
+		framelen -= 2;
+		if (loop_frame((unsigned char *)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(frame, len)
+    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(proto, newip)
+    int proto;
+    u32_t newip;
+{
+    struct packet *pkt, *prev, *nextpkt;
+    unsigned short checksum;
+    unsigned short pkt_checksum = 0;
+    unsigned iphdr;
+    struct timeval tv;
+    char cv = 0;
+    char ipstr[16];
+
+    prev = NULL;
+    pkt = pend_q;
+    pend_q = NULL;
+    tv.tv_sec = 1;
+    tv.tv_usec = 0;
+    select(0,NULL,NULL,NULL,&tv);	/* Sleep for 1 Seconds */
+    for (; pkt != NULL; pkt = nextpkt) {
+	nextpkt = pkt->next;
+	if (PPP_PROTOCOL(pkt->data) == proto) {
+            if ( (proto == PPP_IP) && newip ) {
+		/* Get old checksum */
+
+		iphdr = (pkt->data[4] & 15) << 2;
+		checksum = *((unsigned short *) (pkt->data+14));
+                if (checksum == 0xFFFF) {
+                    checksum = 0;
+                }
+
+ 
+                if (pkt->data[13] == 17) {
+                    pkt_checksum =  *((unsigned short *) (pkt->data+10+iphdr));
+		    if (pkt_checksum) {
+                        cv = 1;
+                        if (pkt_checksum == 0xFFFF) {
+                            pkt_checksum = 0;
+                        }
+                    }
+                    else {
+                       cv = 0;
+                    }
+                }
+
+		if (pkt->data[13] == 6) {
+		    pkt_checksum = *((unsigned short *) (pkt->data+20+iphdr));
+		    cv = 1;
+                    if (pkt_checksum == 0xFFFF) {
+                        pkt_checksum = 0;
+                    }
+		}
+
+		/* Delete old Source-IP-Address */
+                checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
+                checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
+
+		pkt_checksum -= *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
+		pkt_checksum -= *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
+
+		/* Change Source-IP-Address */
+                * ((u32_t *) (pkt->data + 16)) = newip;
+
+		/* Add new Source-IP-Address */
+                checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
+                checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
+
+                pkt_checksum += *((unsigned short *) (pkt->data+16)) ^ 0xFFFF;
+                pkt_checksum += *((unsigned short *) (pkt->data+18)) ^ 0xFFFF;
+
+		/* Write new checksum */
+                if (!checksum) {
+                    checksum = 0xFFFF;
+                }
+                *((unsigned short *) (pkt->data+14)) = checksum;
+		if (pkt->data[13] == 6) {
+		    *((unsigned short *) (pkt->data+20+iphdr)) = pkt_checksum;
+		}
+		if (cv && (pkt->data[13] == 17) ) {
+		    *((unsigned short *) (pkt->data+10+iphdr)) = pkt_checksum;
+		}
+
+		/* Log Packet */
+		strcpy(ipstr,inet_ntoa(*( (struct in_addr *) (pkt->data+16))));
+		if (pkt->data[13] == 1) {
+		    syslog(LOG_INFO,"Open ICMP %s -> %s\n",
+			ipstr,
+			inet_ntoa(*( (struct in_addr *) (pkt->data+20))));
+		} else {
+		    syslog(LOG_INFO,"Open %s %s:%d -> %s:%d\n",
+			pkt->data[13] == 6 ? "TCP" : "UDP",
+			ipstr,
+			ntohs(*( (short *) (pkt->data+iphdr+4))),
+			inet_ntoa(*( (struct in_addr *) (pkt->data+20))),
+			ntohs(*( (short *) (pkt->data+iphdr+6))));
+                }
+            }
+	    output(pcb, 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(p, len)
+    unsigned char *p;
+    int len;
+{
+    int proto, i;
+    const struct protent *protp;
+
+    if (len < PPP_HDRLEN)
+	return 0;
+    proto = PPP_PROTOCOL(p);
+#ifdef PPP_FILTER
+    p[0] = 1;		/* outbound packet indicator */
+    if ((pass_filter.bf_len != 0
+	 && bpf_filter(pass_filter.bf_insns, p, len, len) == 0)
+	|| (active_filter.bf_len != 0
+	    && bpf_filter(active_filter.bf_insns, p, len, len) == 0)) {
+	p[0] = 0xff;
+	return 0;
+    }
+    p[0] = 0xff;
+#endif
+    for (i = 0; (protp = protocols[i]) != NULL; ++i) {
+	if (protp->protocol < 0xC000 && (protp->protocol & ~0x8000) == proto) {
+	    if (protp->active_pkt == NULL)
+		return 1;
+	    return (*protp->active_pkt)(p, len);
+	}
+    }
+    return 0;			/* not a supported protocol !!?? */
+}
+
+#endif /* PPP_SUPPORT && DEMAND_SUPPORT */