[pkg-wpa-devel] r1186 - in /wpasupplicant/branches/upstream/current: patches/ src/common/ src/crypto/ src/drivers/ src/eap_common/ src/eap_peer/ src/eap_server/ src/radius/ src/rsn_supp/ src/tls/ src/utils/ wpa_supplicant/ wpa_supplicant/doc/docbook/ wpa_supplicant/examples/ wpa_supplicant/wpa_gui/

kelmo-guest at users.alioth.debian.org kelmo-guest at users.alioth.debian.org
Sat Jun 14 00:26:58 UTC 2008


Author: kelmo-guest
Date: Sat Jun 14 00:26:56 2008
New Revision: 1186

URL: http://svn.debian.org/wsvn/?sc=1&rev=1186
Log:
[svn-upgrade] Integrating new upstream version, wpasupplicant (0.6.4~git20080614.f598194)

Added:
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch
    wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c
    wpasupplicant/branches/upstream/current/src/eap_server/tncs.c
    wpasupplicant/branches/upstream/current/src/eap_server/tncs.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf
Removed:
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_tlv.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tlv.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
Modified:
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
    wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
    wpasupplicant/branches/upstream/current/src/common/wpa_common.h
    wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
    wpasupplicant/branches/upstream/current/src/crypto/sha1.c
    wpasupplicant/branches/upstream/current/src/crypto/tls.h
    wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h
    wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h
    wpasupplicant/branches/upstream/current/src/drivers/drivers.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h
    wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
    wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
    wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
    wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c
    wpasupplicant/branches/upstream/current/src/radius/radius.c
    wpasupplicant/branches/upstream/current/src/radius/radius.h
    wpasupplicant/branches/upstream/current/src/radius/radius_client.c
    wpasupplicant/branches/upstream/current/src/radius/radius_client.h
    wpasupplicant/branches/upstream/current/src/radius/radius_server.c
    wpasupplicant/branches/upstream/current/src/radius/radius_server.h
    wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c
    wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c
    wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c
    wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h
    wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
    wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h
    wpasupplicant/branches/upstream/current/src/tls/libtommath.c
    wpasupplicant/branches/upstream/current/src/utils/base64.c
    wpasupplicant/branches/upstream/current/src/utils/common.h
    wpasupplicant/branches/upstream/current/src/utils/eloop.c
    wpasupplicant/branches/upstream/current/src/utils/eloop.h
    wpasupplicant/branches/upstream/current/src/utils/eloop_none.c
    wpasupplicant/branches/upstream/current/src/utils/eloop_win.c
    wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
    wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
    wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
    wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
    wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/main.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c

Modified: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch (original)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8g-tls-extensions.patch Sat Jun 14 00:26:56 2008
@@ -1,4 +1,4 @@
-This patch adds support for TLS SessionTicket extension (RFC 4507) for
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
 the parts used by EAP-FAST (RFC 4851).
 
 This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
@@ -10,25 +10,14 @@
 
 
 diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
---- openssl-0.9.8g.orig/ssl/s3_clnt.c	2007-08-30 17:28:51.000000000 -0700
-+++ openssl-0.9.8g/ssl/s3_clnt.c	2007-11-01 20:08:08.000000000 -0700
-@@ -660,7 +660,7 @@ int ssl3_get_server_hello(SSL *s)
- 	STACK_OF(SSL_CIPHER) *sk;
- 	SSL_CIPHER *c;
- 	unsigned char *p,*d;
--	int i,al,ok;
-+	int i,al,ok,pre_shared;
- 	unsigned int j;
- 	long n;
- #ifndef OPENSSL_NO_COMP
-@@ -727,7 +727,26 @@ int ssl3_get_server_hello(SSL *s)
+--- openssl-0.9.8g.orig/ssl/s3_clnt.c	2007-08-31 03:28:51.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_clnt.c	2008-04-15 17:11:46.000000000 +0300
+@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s)
  		goto f_err;
  		}
  
--	if (j != 0 && j == s->session->session_id_length
++#ifndef OPENSSL_NO_TLSEXT
 +	/* check if we want to resume the session based on external pre-shared secret */
-+	pre_shared = 0;
-+#ifndef OPENSSL_NO_TLSEXT
 +	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
 +	{
 +		SSL_CIPHER *pref_cipher=NULL;
@@ -36,22 +25,17 @@
 +		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
 +			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
 +		{
-+			s->hit=1;
 +			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+			s->session->session_id_length = j;
-+			memcpy(s->session->session_id, p, j);
-+			pre_shared = 1;
 +		}
 +	}
 +#endif /* OPENSSL_NO_TLSEXT */
 +
-+	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	if (j != 0 && j == s->session->session_id_length
  	    && memcmp(p,s->session->session_id,j) == 0)
  	    {
- 	    if(s->sid_ctx_length != s->session->sid_ctx_length
 diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
---- openssl-0.9.8g.orig/ssl/s3_srvr.c	2007-09-30 11:55:59.000000000 -0700
-+++ openssl-0.9.8g/ssl/s3_srvr.c	2007-11-02 19:24:20.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/s3_srvr.c	2007-09-30 21:55:59.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_srvr.c	2008-04-15 17:10:37.000000000 +0300
 @@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
  			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
  			goto err;
@@ -137,8 +121,8 @@
  		d=p= &(buf[4]);
  
 diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
---- openssl-0.9.8g.orig/ssl/ssl.h	2007-10-19 00:42:38.000000000 -0700
-+++ openssl-0.9.8g/ssl/ssl.h	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/ssl.h	2007-10-19 10:42:38.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl.h	2008-04-15 17:10:37.000000000 +0300
 @@ -342,6 +342,7 @@ extern "C" {
   * 'struct ssl_st *' function parameters used to prototype callbacks
   * in SSL_CTX. */
@@ -193,8 +177,8 @@
  /* Reason codes. */
  #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
 diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
---- openssl-0.9.8g.orig/ssl/ssl_err.c	2007-10-11 07:36:59.000000000 -0700
-+++ openssl-0.9.8g/ssl/ssl_err.c	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/ssl_err.c	2007-10-11 17:36:59.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_err.c	2008-04-15 17:10:37.000000000 +0300
 @@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
  {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
  {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
@@ -204,8 +188,8 @@
  	};
  
 diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
---- openssl-0.9.8g.orig/ssl/ssl_sess.c	2007-10-19 00:36:34.000000000 -0700
-+++ openssl-0.9.8g/ssl/ssl_sess.c	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/ssl_sess.c	2007-10-19 10:36:34.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_sess.c	2008-04-15 17:10:37.000000000 +0300
 @@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
  	return(s->session_timeout);
  	}
@@ -260,8 +244,8 @@
  	{
  	SSL_CTX *ctx;
 diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
---- openssl-0.9.8g.orig/ssl/t1_lib.c	2007-10-19 00:44:10.000000000 -0700
-+++ openssl-0.9.8g/ssl/t1_lib.c	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/t1_lib.c	2007-10-19 10:44:10.000000000 +0300
++++ openssl-0.9.8g/ssl/t1_lib.c	2008-04-15 17:10:37.000000000 +0300
 @@ -105,6 +105,12 @@ int tls1_new(SSL *s)
  
  void tls1_free(SSL *s)
@@ -318,8 +302,8 @@
  									ret);
  			}
 diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
---- openssl-0.9.8g.orig/ssl/tls1.h	2007-08-27 18:12:44.000000000 -0700
-+++ openssl-0.9.8g/ssl/tls1.h	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/ssl/tls1.h	2007-08-28 04:12:44.000000000 +0300
++++ openssl-0.9.8g/ssl/tls1.h	2008-04-15 17:10:37.000000000 +0300
 @@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
  #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
  #endif
@@ -336,8 +320,8 @@
  }
  #endif
 diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
---- openssl-0.9.8g.orig/util/ssleay.num	2007-08-12 15:31:16.000000000 -0700
-+++ openssl-0.9.8g/util/ssleay.num	2007-11-01 20:08:08.000000000 -0700
+--- openssl-0.9.8g.orig/util/ssleay.num	2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8g/util/ssleay.num	2008-04-15 17:10:37.000000000 +0300
 @@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb              
  SSL_set_SSL_CTX                         290	EXIST::FUNCTION:
  SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT

Added: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch (added)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8h-tls-extensions.patch Sat Jun 14 00:26:56 2008
@@ -1,0 +1,344 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8h does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c
+--- openssl-0.9.8h.orig/ssl/s3_clnt.c	2008-05-28 10:29:27.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_clnt.c	2008-05-29 10:44:25.000000000 +0300
+@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++		}
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c
+--- openssl-0.9.8h.orig/ssl/s3_srvr.c	2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_srvr.c	2008-05-28 18:49:34.000000000 +0300
+@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++		{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++		}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h
+--- openssl-0.9.8h.orig/ssl/ssl.h	2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl.h	2008-05-28 18:49:34.000000000 +0300
+@@ -343,6 +343,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1027,6 +1030,14 @@ struct ssl_st
+ 
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS extensions */
++	TLS_EXTENSION *tls_extension;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION			 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c
+--- openssl-0.9.8h.orig/ssl/ssl_err.c	2007-10-12 03:00:30.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_err.c	2008-05-28 18:49:34.000000000 +0300
+@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c
+--- openssl-0.9.8h.orig/ssl/ssl_sess.c	2007-10-17 20:30:15.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_sess.c	2008-05-28 18:49:34.000000000 +0300
+@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++		if(!s->tls_extension)
++		{
++			SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++			return 0;
++		}
++
++		s->tls_extension->type = ext_type;
++
++		if(ext_data)
++		{
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		} else {
++			s->tls_extension->length = 0;
++			s->tls_extension->data = NULL;
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c
+--- openssl-0.9.8h.orig/ssl/t1_lib.c	2008-05-28 10:26:33.000000000 +0300
++++ openssl-0.9.8h/ssl/t1_lib.c	2008-05-28 18:49:34.000000000 +0300
+@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tls_extension &&
++			s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++			s->tls_extension->data)
++		{
++			ticklen = s->tls_extension->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++		}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tls_extension &&
++		    s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++		    s->tls_extension->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ 		{
+@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				return 0;
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h
+--- openssl-0.9.8h.orig/ssl/tls1.h	2008-04-30 19:11:33.000000000 +0300
++++ openssl-0.9.8h/ssl/tls1.h	2008-05-28 18:49:34.000000000 +0300
+@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num
+--- openssl-0.9.8h.orig/util/ssleay.num	2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8h/util/ssleay.num	2008-05-28 18:49:34.000000000 +0300
+@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb              
+ SSL_set_SSL_CTX                         290	EXIST::FUNCTION:
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
++SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT

Modified: wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch (original)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch Sat Jun 14 00:26:56 2008
@@ -1,4 +1,4 @@
-This patch adds support for TLS SessionTicket extension (RFC 4507) for
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
 the parts used by EAP-FAST (RFC 4851).
 
 This is based on the patch from Alexey Kobozev <akobozev at cisco.com>
@@ -6,26 +6,15 @@
 
 
 
-diff -upr openssl-SNAP-20071101.orig/ssl/s3_clnt.c openssl-SNAP-20071101/ssl/s3_clnt.c
---- openssl-SNAP-20071101.orig/ssl/s3_clnt.c	2007-10-26 06:00:28.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/s3_clnt.c	2007-11-01 19:19:43.000000000 -0700
-@@ -715,7 +715,7 @@ int ssl3_get_server_hello(SSL *s)
- 	STACK_OF(SSL_CIPHER) *sk;
- 	SSL_CIPHER *c;
- 	unsigned char *p,*d;
--	int i,al,ok;
-+	int i,al,ok,pre_shared;
- 	unsigned int j;
- 	long n;
- #ifndef OPENSSL_NO_COMP
-@@ -782,7 +782,26 @@ int ssl3_get_server_hello(SSL *s)
+diff -upr openssl-SNAP-20080528.orig/ssl/s3_clnt.c openssl-SNAP-20080528/ssl/s3_clnt.c
+--- openssl-SNAP-20080528.orig/ssl/s3_clnt.c	2008-04-29 21:00:17.000000000 +0300
++++ openssl-SNAP-20080528/ssl/s3_clnt.c	2008-05-29 10:55:43.000000000 +0300
+@@ -785,6 +785,20 @@ int ssl3_get_server_hello(SSL *s)
  		goto f_err;
  		}
  
--	if (j != 0 && j == s->session->session_id_length
++#ifndef OPENSSL_NO_TLSEXT
 +	/* check if we want to resume the session based on external pre-shared secret */
-+	pre_shared = 0;
-+#ifndef OPENSSL_NO_TLSEXT
 +	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
 +	{
 +		SSL_CIPHER *pref_cipher=NULL;
@@ -33,23 +22,32 @@
 +		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
 +			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
 +		{
-+			s->hit=1;
 +			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
-+			s->session->session_id_length = j;
-+			memcpy(s->session->session_id, p, j);
-+			pre_shared = 1;
 +		}
 +	}
 +#endif /* OPENSSL_NO_TLSEXT */
 +
-+	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	if (j != 0 && j == s->session->session_id_length
  	    && memcmp(p,s->session->session_id,j) == 0)
  	    {
- 	    if(s->sid_ctx_length != s->session->sid_ctx_length
-diff -upr openssl-SNAP-20071101.orig/ssl/s3_srvr.c openssl-SNAP-20071101/ssl/s3_srvr.c
---- openssl-SNAP-20071101.orig/ssl/s3_srvr.c	2007-10-26 06:00:29.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/s3_srvr.c	2007-11-01 19:19:43.000000000 -0700
-@@ -992,6 +992,59 @@ int ssl3_get_client_hello(SSL *s)
+@@ -2918,11 +2932,8 @@ static int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+diff -upr openssl-SNAP-20080528.orig/ssl/s3_srvr.c openssl-SNAP-20080528/ssl/s3_srvr.c
+--- openssl-SNAP-20080528.orig/ssl/s3_srvr.c	2008-04-30 20:00:38.000000000 +0300
++++ openssl-SNAP-20080528/ssl/s3_srvr.c	2008-05-29 10:49:25.000000000 +0300
+@@ -1004,6 +1004,59 @@ int ssl3_get_client_hello(SSL *s)
  			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
  			goto err;
  		}
@@ -109,7 +107,7 @@
  #endif
  
  	/* Worst case, we will use the NULL compression, but if we have other
-@@ -1118,16 +1171,22 @@ int ssl3_send_server_hello(SSL *s)
+@@ -1130,16 +1183,22 @@ int ssl3_send_server_hello(SSL *s)
  	unsigned char *buf;
  	unsigned char *p,*d;
  	int i,sl;
@@ -133,10 +131,10 @@
  		/* Do the message type and length last */
  		d=p= &(buf[4]);
  
-diff -upr openssl-SNAP-20071101.orig/ssl/ssl.h openssl-SNAP-20071101/ssl/ssl.h
---- openssl-SNAP-20071101.orig/ssl/ssl.h	2007-10-26 17:01:28.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/ssl.h	2007-11-01 19:20:47.000000000 -0700
-@@ -353,6 +353,7 @@ extern "C" {
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl.h openssl-SNAP-20080528/ssl/ssl.h
+--- openssl-SNAP-20080528.orig/ssl/ssl.h	2008-05-26 15:00:37.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl.h	2008-05-29 10:49:25.000000000 +0300
+@@ -354,6 +354,7 @@ extern "C" {
   * 'struct ssl_st *' function parameters used to prototype callbacks
   * in SSL_CTX. */
  typedef struct ssl_st *ssl_crock_st;
@@ -144,7 +142,7 @@
  
  /* used to hold info on the particular ciphers used */
  typedef struct ssl_cipher_st
-@@ -379,6 +380,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+@@ -380,6 +381,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
  typedef struct ssl_st SSL;
  typedef struct ssl_ctx_st SSL_CTX;
  
@@ -153,7 +151,7 @@
  /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
  typedef struct ssl_method_st
  	{
-@@ -1121,6 +1124,13 @@ struct ssl_st
+@@ -1128,6 +1131,13 @@ struct ssl_st
  	void *tlsext_opaque_prf_input;
  	size_t tlsext_opaque_prf_input_len;
  
@@ -167,7 +165,7 @@
  	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
  #define session_ctx initial_ctx
  #else
-@@ -1721,6 +1731,12 @@ void *SSL_COMP_get_compression_methods(v
+@@ -1729,6 +1739,12 @@ void *SSL_COMP_get_compression_methods(v
  int SSL_COMP_add_compression_method(int id,void *cm);
  #endif
  
@@ -180,7 +178,7 @@
  /* BEGIN ERROR CODES */
  /* The following lines are auto generated by the script mkerr.pl. Any changes
   * made after this point may be overwritten when the script is next run.
-@@ -1920,6 +1936,7 @@ void ERR_load_SSL_strings(void);
+@@ -1928,6 +1944,7 @@ void ERR_load_SSL_strings(void);
  #define SSL_F_TLS1_PRF					 284
  #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
  #define SSL_F_WRITE_PENDING				 212
@@ -188,9 +186,9 @@
  
  /* Reason codes. */
  #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
-diff -upr openssl-SNAP-20071101.orig/ssl/ssl_err.c openssl-SNAP-20071101/ssl/ssl_err.c
---- openssl-SNAP-20071101.orig/ssl/ssl_err.c	2007-10-26 17:01:29.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/ssl_err.c	2007-11-01 19:19:43.000000000 -0700
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl_err.c openssl-SNAP-20080528/ssl/ssl_err.c
+--- openssl-SNAP-20080528.orig/ssl/ssl_err.c	2007-10-27 03:01:29.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl_err.c	2008-05-29 10:49:25.000000000 +0300
 @@ -260,6 +260,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
  {ERR_FUNC(SSL_F_TLS1_PRF),	"tls1_prf"},
  {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
@@ -199,9 +197,9 @@
  {0,NULL}
  	};
  
-diff -upr openssl-SNAP-20071101.orig/ssl/ssl_sess.c openssl-SNAP-20071101/ssl/ssl_sess.c
---- openssl-SNAP-20071101.orig/ssl/ssl_sess.c	2007-10-17 11:00:45.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/ssl_sess.c	2007-11-01 19:19:43.000000000 -0700
+diff -upr openssl-SNAP-20080528.orig/ssl/ssl_sess.c openssl-SNAP-20080528/ssl/ssl_sess.c
+--- openssl-SNAP-20080528.orig/ssl/ssl_sess.c	2008-05-26 15:00:37.000000000 +0300
++++ openssl-SNAP-20080528/ssl/ssl_sess.c	2008-05-29 10:49:25.000000000 +0300
 @@ -831,6 +831,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
  	return(s->session_timeout);
  	}
@@ -255,9 +253,9 @@
  typedef struct timeout_param_st
  	{
  	SSL_CTX *ctx;
-diff -upr openssl-SNAP-20071101.orig/ssl/t1_lib.c openssl-SNAP-20071101/ssl/t1_lib.c
---- openssl-SNAP-20071101.orig/ssl/t1_lib.c	2007-10-26 06:00:29.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/t1_lib.c	2007-11-01 19:19:43.000000000 -0700
+diff -upr openssl-SNAP-20080528.orig/ssl/t1_lib.c openssl-SNAP-20080528/ssl/t1_lib.c
+--- openssl-SNAP-20080528.orig/ssl/t1_lib.c	2008-04-30 20:00:39.000000000 +0300
++++ openssl-SNAP-20080528/ssl/t1_lib.c	2008-05-29 10:49:25.000000000 +0300
 @@ -154,6 +154,12 @@ int tls1_new(SSL *s)
  
  void tls1_free(SSL *s)
@@ -271,7 +269,7 @@
  	ssl3_free(s);
  	}
  
-@@ -355,8 +361,24 @@ unsigned char *ssl_add_clienthello_tlsex
+@@ -357,8 +363,24 @@ unsigned char *ssl_add_clienthello_tlsex
  		int ticklen;
  		if (s->session && s->session->tlsext_tick)
  			ticklen = s->session->tlsext_ticklen;
@@ -296,7 +294,7 @@
  		/* Check for enough room 2 for extension type, 2 for len
   		 * rest for ticket
    		 */
-@@ -369,6 +391,7 @@ unsigned char *ssl_add_clienthello_tlsex
+@@ -371,6 +393,7 @@ unsigned char *ssl_add_clienthello_tlsex
  			ret += ticklen;
  			}
  		}
@@ -304,7 +302,7 @@
  
  #ifdef TLSEXT_TYPE_opaque_prf_input
  	if (s->s3->client_opaque_prf_input != NULL)
-@@ -1422,6 +1445,8 @@ int tls1_process_ticket(SSL *s, unsigned
+@@ -1427,6 +1450,8 @@ int tls1_process_ticket(SSL *s, unsigned
  				s->tlsext_ticket_expected = 1;
  				return 0;	/* Cache miss */
  				}
@@ -313,10 +311,10 @@
  			return tls_decrypt_ticket(s, p, size, session_id, len,
  									ret);
  			}
-diff -upr openssl-SNAP-20071101.orig/ssl/tls1.h openssl-SNAP-20071101/ssl/tls1.h
---- openssl-SNAP-20071101.orig/ssl/tls1.h	2007-09-26 15:01:39.000000000 -0700
-+++ openssl-SNAP-20071101/ssl/tls1.h	2007-11-01 19:19:43.000000000 -0700
-@@ -509,6 +509,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_OPA
+diff -upr openssl-SNAP-20080528.orig/ssl/tls1.h openssl-SNAP-20080528/ssl/tls1.h
+--- openssl-SNAP-20080528.orig/ssl/tls1.h	2008-04-30 20:00:39.000000000 +0300
++++ openssl-SNAP-20080528/ssl/tls1.h	2008-05-29 10:49:25.000000000 +0300
+@@ -512,6 +512,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
  #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
  #endif
  
@@ -331,9 +329,9 @@
  #ifdef  __cplusplus
  }
  #endif
-diff -upr openssl-SNAP-20071101.orig/util/ssleay.num openssl-SNAP-20071101/util/ssleay.num
---- openssl-SNAP-20071101.orig/util/ssleay.num	2007-08-31 06:03:14.000000000 -0700
-+++ openssl-SNAP-20071101/util/ssleay.num	2007-11-01 19:19:43.000000000 -0700
+diff -upr openssl-SNAP-20080528.orig/util/ssleay.num openssl-SNAP-20080528/util/ssleay.num
+--- openssl-SNAP-20080528.orig/util/ssleay.num	2007-08-31 16:03:14.000000000 +0300
++++ openssl-SNAP-20080528/util/ssleay.num	2008-05-29 10:49:25.000000000 +0300
 @@ -253,3 +253,5 @@ PEM_write_bio_SSL_SESSION               
  PEM_read_SSL_SESSION                    302	EXIST:!WIN16:FUNCTION:
  PEM_read_bio_SSL_SESSION                303	EXIST::FUNCTION:

Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h Sat Jun 14 00:26:56 2008
@@ -112,9 +112,9 @@
 #define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
 #define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
 /* 802.11g */
-#define WLAN_STATUS_ASSOC_DENOED_NO_SHORT_SLOT_TIME 25
-#define WLAN_STATUS_ASSOC_DENOED_NO_ER_PBCC 26
-#define WLAN_STATUS_ASSOC_DENOED_NO_DSSS_OFDM 27
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_ER_PBCC 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
 /* IEEE 802.11i */
 #define WLAN_STATUS_INVALID_IE 40
 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
@@ -123,6 +123,11 @@
 #define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
 #define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
 #define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
 /* IEEE 802.11r */
 #define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
 #define WLAN_STATUS_EXPECTED_RESOURCE_REQ_FT 53

Modified: wpasupplicant/branches/upstream/current/src/common/wpa_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_common.h Sat Jun 14 00:26:56 2008
@@ -87,8 +87,8 @@
 
 #define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
 
-#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((a), (val))
-#define RSN_SELECTOR_GET(a) WPA_GET_BE32((a))
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
 
 #define RSN_NUM_REPLAY_COUNTERS_1 0
 #define RSN_NUM_REPLAY_COUNTERS_2 1
@@ -188,8 +188,7 @@
 struct wpa_ie_hdr {
 	u8 elem_id;
 	u8 len;
-	u8 oui[3];
-	u8 oui_type;
+	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
 	u8 version[2]; /* little endian */
 } STRUCT_PACKED;
 

Modified: wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c Sat Jun 14 00:26:56 2008
@@ -22,6 +22,7 @@
 #include "aes.h"
 #include "tls/rsa.h"
 #include "tls/bignum.h"
+#include "tls/asn1.h"
 
 
 #ifdef EAP_TLS_FUNCS
@@ -434,9 +435,122 @@
 }
 
 
+static struct crypto_private_key *
+crypto_pkcs8_key_import(const u8 *buf, size_t len)
+{
+	struct asn1_hdr hdr;
+	const u8 *pos, *end;
+	struct bignum *zero;
+	struct asn1_oid oid;
+	char obuf[80];
+
+	/* PKCS #8, Chapter 6 */
+
+	/* PrivateKeyInfo ::= SEQUENCE */
+	if (asn1_get_next(buf, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
+			   "header (SEQUENCE); assume PKCS #8 not used");
+		return NULL;
+	}
+	pos = hdr.payload;
+	end = pos + hdr.length;
+
+	/* version Version (Version ::= INTEGER) */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
+			   "class %d tag 0x%x; assume PKCS #8 not used",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	zero = bignum_init();
+	if (zero == NULL)
+		return NULL;
+
+	if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
+		bignum_deinit(zero);
+		return NULL;
+	}
+	pos = hdr.payload + hdr.length;
+
+	if (bignum_cmp_d(zero, 0) != 0) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
+			   "beginning of private key; not found; assume "
+			   "PKCS #8 not used");
+		bignum_deinit(zero);
+		return NULL;
+	}
+	bignum_deinit(zero);
+
+	/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
+	 * (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
+	if (asn1_get_next(pos, len, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_SEQUENCE) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
+			   "(AlgorithmIdentifier) - found class %d tag 0x%x; "
+			   "assume PKCS #8 not used",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+
+	if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
+			   "(algorithm); assume PKCS #8 not used");
+		return NULL;
+	}
+
+	asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+	wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
+
+	if (oid.len != 7 ||
+	    oid.oid[0] != 1 /* iso */ ||
+	    oid.oid[1] != 2 /* member-body */ ||
+	    oid.oid[2] != 840 /* us */ ||
+	    oid.oid[3] != 113549 /* rsadsi */ ||
+	    oid.oid[4] != 1 /* pkcs */ ||
+	    oid.oid[5] != 1 /* pkcs-1 */ ||
+	    oid.oid[6] != 1 /* rsaEncryption */) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
+			   "algorithm %s", obuf);
+		return NULL;
+	}
+
+	pos = hdr.payload + hdr.length;
+
+	/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
+	if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+	    hdr.class != ASN1_CLASS_UNIVERSAL ||
+	    hdr.tag != ASN1_TAG_OCTETSTRING) {
+		wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
+			   "(privateKey) - found class %d tag 0x%x",
+			   hdr.class, hdr.tag);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
+
+	return (struct crypto_private_key *)
+		crypto_rsa_import_private_key(hdr.payload, hdr.length);
+}
+
+
 struct crypto_private_key * crypto_private_key_import(const u8 *key,
 						      size_t len)
 {
+	struct crypto_private_key *res;
+
+	/* First, check for possible PKCS #8 encoding */
+	res = crypto_pkcs8_key_import(key, len);
+	if (res)
+		return res;
+
+	/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
+	wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
+		   "key");
 	return (struct crypto_private_key *)
 		crypto_rsa_import_private_key(key, len);
 }

Modified: wpasupplicant/branches/upstream/current/src/crypto/sha1.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/sha1.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/sha1.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/sha1.c Sat Jun 14 00:26:56 2008
@@ -265,6 +265,10 @@
 	L_S1 = L_S2 = (secret_len + 1) / 2;
 	S1 = secret;
 	S2 = secret + L_S1;
+	if (secret_len & 1) {
+		/* The last byte of S1 will be shared with S2 */
+		S2--;
+	}
 
 	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
 	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls.h (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls.h Sat Jun 14 00:26:56 2008
@@ -63,7 +63,10 @@
  * @engine_id: engine id string (this is OpenSSL specific for now)
  * @ppin: pointer to the pin variable in the configuration
  * (this is OpenSSL specific for now)
- * @key_id: the private key's key id (this is OpenSSL specific for now)
+ * @key_id: the private key's id when using engine (this is OpenSSL
+ * specific for now)
+ * @cert_id: the certificate's id when using engine
+ * @ca_cert_id: the CA certificate's id when using engine
  * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
@@ -98,6 +101,8 @@
 	const char *engine_id;
 	const char *pin;
 	const char *key_id;
+	const char *cert_id;
+	const char *ca_cert_id;
 };
 
 

Modified: wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c Sat Jun 14 00:26:56 2008
@@ -777,7 +777,8 @@
 
 
 static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
-			   const char *pin, const char *key_id)
+			   const char *pin, const char *key_id,
+			   const char *cert_id, const char *ca_cert_id)
 {
 #ifndef OPENSSL_NO_ENGINE
 	int ret = -1;
@@ -814,6 +815,7 @@
 			   ERR_error_string(ERR_get_error(), NULL));
 		goto err;
 	}
+	/* load private key first in-case PIN is required for cert */
 	conn->private_key = ENGINE_load_private_key(conn->engine,
 						    key_id, NULL, NULL);
 	if (!conn->private_key) {
@@ -823,6 +825,21 @@
 		ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 		goto err;
 	}
+
+	/* handle a certificate and/or CA certificate */
+	if (cert_id || ca_cert_id) {
+		const char *cmd_name = "LOAD_CERT_CTRL";
+
+		/* test if the engine supports a LOAD_CERT_CTRL */
+		if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+				 0, (void *)cmd_name, NULL)) {
+			wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
+				   " loading certificates");
+			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+			goto err;
+		}
+	}
+
 	return 0;
 
 err:
@@ -877,6 +894,7 @@
 {
 	SSL_CTX *ssl = ssl_ctx;
 	struct tls_connection *conn;
+	long options;
 
 	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
@@ -890,9 +908,12 @@
 	}
 
 	SSL_set_app_data(conn->ssl, conn);
-	SSL_set_options(conn->ssl,
-			SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
-			SSL_OP_SINGLE_DH_USE);
+	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+		SSL_OP_SINGLE_DH_USE;
+#ifdef SSL_OP_NO_COMPRESSION
+	options |= SSL_OP_NO_COMPRESSION;
+#endif /* SSL_OP_NO_COMPRESSION */
+	SSL_set_options(conn->ssl, options);
 
 	conn->ssl_in = BIO_new(BIO_s_mem());
 	if (!conn->ssl_in) {
@@ -1261,6 +1282,8 @@
 int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
 			      int verify_peer)
 {
+	static int counter = 0;
+
 	if (conn == NULL)
 		return -1;
 
@@ -1273,6 +1296,19 @@
 	}
 
 	SSL_set_accept_state(conn->ssl);
+
+	/*
+	 * Set session id context in order to avoid fatal errors when client
+	 * tries to resume a session. However, set the context to a unique
+	 * value in order to effectively disable session resumption for now
+	 * since not all areas of the server code are ready for it (e.g.,
+	 * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
+	 * handshake).
+	 */
+	counter++;
+	SSL_set_session_id_context(conn->ssl,
+				   (const unsigned char *) &counter,
+				   sizeof(counter));
 
 	return 0;
 }
@@ -1488,6 +1524,110 @@
 		   "p12/pfx blobs");
 	return -1;
 #endif  /* PKCS12_FUNCS */
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+static int tls_engine_get_cert(struct tls_connection *conn,
+			       const char *cert_id,
+			       X509 **cert)
+{
+	/* this runs after the private key is loaded so no PIN is required */
+	struct {
+		const char *cert_id;
+		X509 *cert;
+	} params;
+	params.cert_id = cert_id;
+	params.cert = NULL;
+
+	if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
+			     0, &params, NULL, 1)) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
+			   " '%s' [%s]", cert_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	if (!params.cert) {
+		wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
+			   " '%s'", cert_id);
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	*cert = params.cert;
+	return 0;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+static int tls_connection_engine_client_cert(struct tls_connection *conn,
+					     const char *cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+
+	if (tls_engine_get_cert(conn, cert_id, &cert))
+		return -1;
+
+	if (!SSL_use_certificate(conn->ssl, cert)) {
+		tls_show_errors(MSG_ERROR, __func__,
+				"SSL_use_certificate failed");
+                X509_free(cert);
+		return -1;
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+		   "OK");
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+					 struct tls_connection *conn,
+					 const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+		return -1;
+
+	/* start off the same as tls_connection_ca_cert */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		X509_free(cert);
+		return -1;
+	}
+	if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+		unsigned long err = ERR_peek_error();
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed to add CA certificate from engine "
+				"to certificate store");
+		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
+				   " already in hash table error",
+				   __func__);
+		} else {
+			X509_free(cert);
+			return -1;
+		}
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
+		   "to certificate store", __func__);
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
 }
 
 
@@ -1976,8 +2116,11 @@
 {
 	int res;
 	u8 *out_data;
-	char buf[10];
-
+
+	/*
+	 * Give TLS handshake data from the client (if available) to OpenSSL
+	 * for processing.
+	 */
 	if (in_data &&
 	    BIO_write(conn->ssl_in, in_data, in_len) < 0) {
 		tls_show_errors(MSG_INFO, __func__,
@@ -1985,12 +2128,23 @@
 		return NULL;
 	}
 
-	res = SSL_read(conn->ssl, buf, sizeof(buf));
-	if (res >= 0) {
-		wpa_printf(MSG_DEBUG, "SSL: Unexpected data from SSL_read "
-			   "(res=%d)", res);
-	}
-
+	/* Initiate TLS handshake or continue the existing handshake */
+	res = SSL_accept(conn->ssl);
+	if (res != 1) {
+		int err = SSL_get_error(conn->ssl, res);
+		if (err == SSL_ERROR_WANT_READ)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want "
+				   "more data");
+		else if (err == SSL_ERROR_WANT_WRITE)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_accept - want to "
+				   "write");
+		else {
+			tls_show_errors(MSG_INFO, __func__, "SSL_accept");
+			return NULL;
+		}
+	}
+
+	/* Get the TLS handshake data to be sent to the client */
 	res = BIO_ctrl_pending(conn->ssl_out);
 	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
 	out_data = os_malloc(res == 0 ? 1 : res);
@@ -2229,26 +2383,39 @@
 			   __func__, ERR_error_string(err, NULL));
 	}
 
+	if (params->engine) {
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		ret = tls_engine_init(conn, params->engine_id, params->pin,
+				      params->key_id, params->cert_id,
+				      params->ca_cert_id);
+		if (ret)
+			return ret;
+	}
 	if (tls_connection_set_subject_match(conn,
 					     params->subject_match,
 					     params->altsubject_match))
 		return -1;
-	if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
-				   params->ca_cert_blob,
-				   params->ca_cert_blob_len,
-				   params->ca_path))
-		return -1;
-	if (tls_connection_client_cert(conn, params->client_cert,
-				       params->client_cert_blob,
-				       params->client_cert_blob_len))
-		return -1;
-
-	if (params->engine) {
-		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
-		ret = tls_engine_init(conn, params->engine_id, params->pin,
-				      params->key_id);
-		if (ret)
-			return ret;
+
+	if (params->engine && params->ca_cert_id) {
+		if (tls_connection_engine_ca_cert(tls_ctx, conn,
+						  params->ca_cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+					  params->ca_cert_blob,
+					  params->ca_cert_blob_len,
+					  params->ca_path))
+		return -1;
+
+	if (params->engine && params->cert_id) {
+		if (tls_connection_engine_client_cert(conn, params->cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_client_cert(conn, params->client_cert,
+					      params->client_cert_blob,
+					      params->client_cert_blob_len))
+		return -1;
+
+	if (params->engine && params->key_id) {
+		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
 		if (tls_connection_engine_private_key(conn))
 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 	} else if (tls_connection_private_key(tls_ctx, conn,

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_hostap.h Sat Jun 14 00:26:56 2008
@@ -84,9 +84,9 @@
 
 #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
 #define PRISM2_HOSTAPD_RID_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
 #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
-((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
 
 /* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
  */

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c Sat Jun 14 00:26:56 2008
@@ -1317,8 +1317,7 @@
 
 	if (wpa_driver_ndis_get_bssid(drv, bssid)) {
 		/* Disconnected */
-		if (os_memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
-		    != 0) {
+		if (!is_zero_ether_addr(drv->bssid)) {
 			os_memset(drv->bssid, 0, ETH_ALEN);
 			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
 		}

Added: wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,2098 @@
+/*
+ * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <linux/nl80211.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+
+struct wpa_driver_nl80211_data {
+	void *ctx;
+	int event_sock;
+	int ioctl_sock;
+	char ifname[IFNAMSIZ + 1];
+	int ifindex;
+	u8 *assoc_req_ies;
+	size_t assoc_req_ies_len;
+	u8 *assoc_resp_ies;
+	size_t assoc_resp_ies_len;
+	struct wpa_driver_capa capa;
+	int has_capability;
+	int we_version_compiled;
+
+	/* for set_auth_alg fallback */
+	int use_crypt;
+	int auth_alg_fallback;
+
+	int operstate;
+
+	char mlmedev[IFNAMSIZ + 1];
+
+	int scan_complete_events;
+
+	struct nl_handle *nl_handle;
+	struct nl_cache *nl_cache;
+	struct nl_cb *nl_cb;
+	struct genl_family *nl80211;
+};
+
+
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
+					    void *timeout_ctx);
+static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_flush_pmkid(void *priv);
+static int wpa_driver_nl80211_get_range(void *priv);
+
+static int wpa_driver_nl80211_send_oper_ifla(
+	struct wpa_driver_nl80211_data *drv,
+	int linkmode, int operstate)
+{
+	struct {
+		struct nlmsghdr hdr;
+		struct ifinfomsg ifinfo;
+		char opts[16];
+	} req;
+	struct rtattr *rta;
+	static int nl_seq;
+	ssize_t ret;
+
+	os_memset(&req, 0, sizeof(req));
+
+	req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+	req.hdr.nlmsg_type = RTM_SETLINK;
+	req.hdr.nlmsg_flags = NLM_F_REQUEST;
+	req.hdr.nlmsg_seq = ++nl_seq;
+	req.hdr.nlmsg_pid = 0;
+
+	req.ifinfo.ifi_family = AF_UNSPEC;
+	req.ifinfo.ifi_type = 0;
+	req.ifinfo.ifi_index = drv->ifindex;
+	req.ifinfo.ifi_flags = 0;
+	req.ifinfo.ifi_change = 0;
+
+	if (linkmode != -1) {
+		rta = (struct rtattr *)
+			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+		rta->rta_type = IFLA_LINKMODE;
+		rta->rta_len = RTA_LENGTH(sizeof(char));
+		*((char *) RTA_DATA(rta)) = linkmode;
+		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+			RTA_LENGTH(sizeof(char));
+	}
+	if (operstate != -1) {
+		rta = (struct rtattr *)
+			((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+		rta->rta_type = IFLA_OPERSTATE;
+		rta->rta_len = RTA_LENGTH(sizeof(char));
+		*((char *) RTA_DATA(rta)) = operstate;
+		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+			RTA_LENGTH(sizeof(char));
+	}
+
+	wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+		   linkmode, operstate);
+
+	ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
+	if (ret < 0) {
+		wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+			   "%s (assume operstate is not supported)",
+			   strerror(errno));
+	}
+
+	return ret < 0 ? -1 : 0;
+}
+
+
+static int wpa_driver_nl80211_set_auth_param(
+	struct wpa_driver_nl80211_data *drv, int idx, u32 value)
+{
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.param.flags = idx & IW_AUTH_INDEX;
+	iwr.u.param.value = value;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+		if (errno != EOPNOTSUPP) {
+			wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+				   "value 0x%x) failed: %s)",
+				   idx, value, strerror(errno));
+		}
+		ret = errno == EOPNOTSUPP ? -2 : -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+		perror("ioctl[SIOCGIWAP]");
+		ret = -1;
+	}
+	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+	if (bssid)
+		os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+	else
+		os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+		perror("ioctl[SIOCSIWAP]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.essid.pointer = (caddr_t) ssid;
+	iwr.u.essid.length = 32;
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCGIWESSID]");
+		ret = -1;
+	} else {
+		ret = iwr.u.essid.length;
+		if (ret > 32)
+			ret = 32;
+		/* Some drivers include nul termination in the SSID, so let's
+		 * remove it here before further processing. WE-21 changes this
+		 * to explicitly require the length _not_ to include nul
+		 * termination. */
+		if (ret > 0 && ssid[ret - 1] == '\0' &&
+		    drv->we_version_compiled < 21)
+			ret--;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid,
+				       size_t ssid_len)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+	char buf[33];
+
+	if (ssid_len > 32)
+		return -1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	/* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+	iwr.u.essid.flags = (ssid_len != 0);
+	os_memset(buf, 0, sizeof(buf));
+	os_memcpy(buf, ssid, ssid_len);
+	iwr.u.essid.pointer = (caddr_t) buf;
+	if (drv->we_version_compiled < 21) {
+		/* For historic reasons, set SSID length to include one extra
+		 * character, C string nul termination, even though SSID is
+		 * really an octet string that should not be presented as a C
+		 * string. Some Linux drivers decrement the length by one and
+		 * can thus end up missing the last octet of the SSID if the
+		 * length is not incremented here. WE-21 changes this to
+		 * explicitly require the length _not_ to include nul
+		 * termination. */
+		if (ssid_len)
+			ssid_len++;
+	}
+	iwr.u.essid.length = ssid_len;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+		perror("ioctl[SIOCSIWESSID]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_freq(void *priv, int freq)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.freq.m = freq * 100000;
+	iwr.u.freq.e = 1;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+		perror("ioctl[SIOCSIWFREQ]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static void
+wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+		   custom);
+
+	os_memset(&data, 0, sizeof(data));
+	/* Host AP driver */
+	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+		data.michael_mic_failure.unicast =
+			os_strstr(custom, " unicast ") != NULL;
+		/* TODO: parse parameters(?) */
+		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+	} else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+		char *spos;
+		int bytes;
+
+		spos = custom + 17;
+
+		bytes = strspn(spos, "0123456789abcdefABCDEF");
+		if (!bytes || (bytes & 1))
+			return;
+		bytes /= 2;
+
+		data.assoc_info.req_ies = os_malloc(bytes);
+		if (data.assoc_info.req_ies == NULL)
+			return;
+
+		data.assoc_info.req_ies_len = bytes;
+		hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+		spos += bytes * 2;
+
+		data.assoc_info.resp_ies = NULL;
+		data.assoc_info.resp_ies_len = 0;
+
+		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+			spos += 9;
+
+			bytes = strspn(spos, "0123456789abcdefABCDEF");
+			if (!bytes || (bytes & 1))
+				goto done;
+			bytes /= 2;
+
+			data.assoc_info.resp_ies = os_malloc(bytes);
+			if (data.assoc_info.resp_ies == NULL)
+				goto done;
+
+			data.assoc_info.resp_ies_len = bytes;
+			hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+		}
+
+		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+	done:
+		os_free(data.assoc_info.resp_ies);
+		os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+	} else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+		if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+			wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+				   "STKSTART.request '%s'", custom + 17);
+			return;
+		}
+		wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+	}
+}
+
+
+static int wpa_driver_nl80211_event_wireless_michaelmicfailure(
+	void *ctx, const char *ev, size_t len)
+{
+	const struct iw_michaelmicfailure *mic;
+	union wpa_event_data data;
+
+	if (len < sizeof(*mic))
+		return -1;
+
+	mic = (const struct iw_michaelmicfailure *) ev;
+
+	wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+		   "flags=0x%x src_addr=" MACSTR, mic->flags,
+		   MAC2STR(mic->src_addr.sa_data));
+
+	os_memset(&data, 0, sizeof(data));
+	data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+	wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_pmkidcand(
+	struct wpa_driver_nl80211_data *drv, const char *ev, size_t len)
+{
+	const struct iw_pmkid_cand *cand;
+	union wpa_event_data data;
+	const u8 *addr;
+
+	if (len < sizeof(*cand))
+		return -1;
+
+	cand = (const struct iw_pmkid_cand *) ev;
+	addr = (const u8 *) cand->bssid.sa_data;
+
+	wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+		   "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+		   cand->index, MAC2STR(addr));
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+	data.pmkid_candidate.index = cand->index;
+	data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocreqie(
+	struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+	if (len < 0)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+		    len);
+	os_free(drv->assoc_req_ies);
+	drv->assoc_req_ies = os_malloc(len);
+	if (drv->assoc_req_ies == NULL) {
+		drv->assoc_req_ies_len = 0;
+		return -1;
+	}
+	os_memcpy(drv->assoc_req_ies, ev, len);
+	drv->assoc_req_ies_len = len;
+
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocrespie(
+	struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+	if (len < 0)
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+		    len);
+	os_free(drv->assoc_resp_ies);
+	drv->assoc_resp_ies = os_malloc(len);
+	if (drv->assoc_resp_ies == NULL) {
+		drv->assoc_resp_ies_len = 0;
+		return -1;
+	}
+	os_memcpy(drv->assoc_resp_ies, ev, len);
+	drv->assoc_resp_ies_len = len;
+
+	return 0;
+}
+
+
+static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv)
+{
+	union wpa_event_data data;
+
+	if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	if (drv->assoc_req_ies) {
+		data.assoc_info.req_ies = drv->assoc_req_ies;
+		drv->assoc_req_ies = NULL;
+		data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+	}
+	if (drv->assoc_resp_ies) {
+		data.assoc_info.resp_ies = drv->assoc_resp_ies;
+		drv->assoc_resp_ies = NULL;
+		data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+	os_free(data.assoc_info.req_ies);
+	os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv,
+					   void *ctx, char *data, int len)
+{
+	struct iw_event iwe_buf, *iwe = &iwe_buf;
+	char *pos, *end, *custom, *buf;
+
+	pos = data;
+	end = data + len;
+
+	while (pos + IW_EV_LCP_LEN <= end) {
+		/* Event data may be unaligned, so make a local, aligned copy
+		 * before processing. */
+		os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+		wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+			   iwe->cmd, iwe->len);
+		if (iwe->len <= IW_EV_LCP_LEN)
+			return;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (drv->we_version_compiled > 18 &&
+		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
+		     iwe->cmd == IWEVCUSTOM ||
+		     iwe->cmd == IWEVASSOCREQIE ||
+		     iwe->cmd == IWEVASSOCRESPIE ||
+		     iwe->cmd == IWEVPMKIDCAND)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+				  sizeof(struct iw_event) - dlen);
+		} else {
+			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case SIOCGIWAP:
+			wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+				   MACSTR,
+				   MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+			if (is_zero_ether_addr(
+				    (const u8 *) iwe->u.ap_addr.sa_data) ||
+			    os_memcmp(iwe->u.ap_addr.sa_data,
+				      "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+			    0) {
+				os_free(drv->assoc_req_ies);
+				drv->assoc_req_ies = NULL;
+				os_free(drv->assoc_resp_ies);
+				drv->assoc_resp_ies = NULL;
+				wpa_supplicant_event(ctx, EVENT_DISASSOC,
+						     NULL);
+			
+			} else {
+				wpa_driver_nl80211_event_assoc_ies(drv);
+				wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+			}
+			break;
+		case IWEVMICHAELMICFAILURE:
+			wpa_driver_nl80211_event_wireless_michaelmicfailure(
+				ctx, custom, iwe->u.data.length);
+			break;
+		case IWEVCUSTOM:
+			if (custom + iwe->u.data.length > end)
+				return;
+			buf = os_malloc(iwe->u.data.length + 1);
+			if (buf == NULL)
+				return;
+			os_memcpy(buf, custom, iwe->u.data.length);
+			buf[iwe->u.data.length] = '\0';
+			wpa_driver_nl80211_event_wireless_custom(ctx, buf);
+			os_free(buf);
+			break;
+		case SIOCGIWSCAN:
+			drv->scan_complete_events = 1;
+			eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout,
+					     drv, ctx);
+			wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+			break;
+		case IWEVASSOCREQIE:
+			wpa_driver_nl80211_event_wireless_assocreqie(
+				drv, custom, iwe->u.data.length);
+			break;
+		case IWEVASSOCRESPIE:
+			wpa_driver_nl80211_event_wireless_assocrespie(
+				drv, custom, iwe->u.data.length);
+			break;
+		case IWEVPMKIDCAND:
+			wpa_driver_nl80211_event_wireless_pmkidcand(
+				drv, custom, iwe->u.data.length);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+}
+
+
+static void wpa_driver_nl80211_event_link(void *ctx, char *buf, size_t len,
+				       int del)
+{
+	union wpa_event_data event;
+
+	os_memset(&event, 0, sizeof(event));
+	if (len > sizeof(event.interface_status.ifname))
+		len = sizeof(event.interface_status.ifname) - 1;
+	os_memcpy(event.interface_status.ifname, buf, len);
+	event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+		EVENT_INTERFACE_ADDED;
+
+	wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+		   del ? "DEL" : "NEW",
+		   event.interface_status.ifname,
+		   del ? "removed" : "added");
+
+	wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
+					      void *ctx, struct nlmsghdr *h,
+					      size_t len)
+{
+	struct ifinfomsg *ifi;
+	int attrlen, _nlmsg_len, rta_len;
+	struct rtattr * attr;
+
+	if (len < sizeof(*ifi))
+		return;
+
+	ifi = NLMSG_DATA(h);
+
+	if (drv->ifindex != ifi->ifi_index) {
+		wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+			   ifi->ifi_index);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+		   "(%s%s%s%s)",
+		   drv->operstate, ifi->ifi_flags,
+		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+	/*
+	 * Some drivers send the association event before the operup event--in
+	 * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+	 * fails. This will hit us when wpa_supplicant does not need to do
+	 * IEEE 802.1X authentication
+	 */
+	if (drv->operstate == 1 &&
+	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+	    !(ifi->ifi_flags & IFF_RUNNING))
+		wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+	_nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+	attrlen = h->nlmsg_len - _nlmsg_len;
+	if (attrlen < 0)
+		return;
+
+	attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_WIRELESS) {
+			wpa_driver_nl80211_event_wireless(
+				drv, ctx, ((char *) attr) + rta_len,
+				attr->rta_len - rta_len);
+		} else if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_nl80211_event_link(ctx,
+						   ((char *) attr) + rta_len,
+						   attr->rta_len - rta_len, 0);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
+					      void *ctx, struct nlmsghdr *h,
+					      size_t len)
+{
+	struct ifinfomsg *ifi;
+	int attrlen, _nlmsg_len, rta_len;
+	struct rtattr * attr;
+
+	if (len < sizeof(*ifi))
+		return;
+
+	ifi = NLMSG_DATA(h);
+
+	_nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+	attrlen = h->nlmsg_len - _nlmsg_len;
+	if (attrlen < 0)
+		return;
+
+	attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		if (attr->rta_type == IFLA_IFNAME) {
+			wpa_driver_nl80211_event_link(ctx,
+						   ((char *) attr) + rta_len,
+						   attr->rta_len - rta_len, 1);
+		}
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+					  void *sock_ctx)
+{
+	char buf[8192];
+	int left;
+	struct sockaddr_nl from;
+	socklen_t fromlen;
+	struct nlmsghdr *h;
+	int max_events = 10;
+
+try_again:
+	fromlen = sizeof(from);
+	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+			(struct sockaddr *) &from, &fromlen);
+	if (left < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			perror("recvfrom(netlink)");
+		return;
+	}
+
+	h = (struct nlmsghdr *) buf;
+	while (left >= (int) sizeof(*h)) {
+		int len, plen;
+
+		len = h->nlmsg_len;
+		plen = len - sizeof(*h);
+		if (len > left || plen < 0) {
+			wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+				   "len=%d left=%d plen=%d",
+				   len, left, plen);
+			break;
+		}
+
+		switch (h->nlmsg_type) {
+		case RTM_NEWLINK:
+			wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
+							  h, plen);
+			break;
+		case RTM_DELLINK:
+			wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
+							  h, plen);
+			break;
+		}
+
+		len = NLMSG_ALIGN(len);
+		left -= len;
+		h = (struct nlmsghdr *) ((char *) h + len);
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+			   "message", left);
+	}
+
+	if (--max_events > 0) {
+		/*
+		 * Try to receive all events in one eloop call in order to
+		 * limit race condition on cases where AssocInfo event, Assoc
+		 * event, and EAPOL frames are received more or less at the
+		 * same time. We want to process the event messages first
+		 * before starting EAPOL processing.
+		 */
+		goto try_again;
+	}
+}
+
+
+static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
+					      const char *ifname, int *flags)
+{
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+		perror("ioctl[SIOCGIFFLAGS]");
+		return -1;
+	}
+	*flags = ifr.ifr_flags & 0xffff;
+	return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
+					  int *flags)
+{
+	return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_nl80211_set_ifflags_ifname(
+	struct wpa_driver_nl80211_data *drv,
+	const char *ifname, int flags)
+{
+	struct ifreq ifr;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	ifr.ifr_flags = flags & 0xffff;
+	if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+		perror("SIOCSIFFLAGS");
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
+					  int flags)
+{
+	return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+{
+	int s, flags;
+	struct sockaddr_nl local;
+	struct wpa_driver_nl80211_data *drv;
+
+	drv = os_zalloc(sizeof(*drv));
+	if (drv == NULL)
+		return NULL;
+	drv->ctx = ctx;
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (drv->nl_cb == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks");
+		goto err1;
+	}
+
+	drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+	if (drv->nl_handle == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks");
+		goto err2;
+	}
+
+	if (genl_connect(drv->nl_handle)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+			   "netlink");
+		goto err3;
+	}
+
+	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+	if (drv->nl_cache == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+			   "netlink cache");
+		goto err3;
+	}
+
+	drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+	if (drv->nl80211 == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+			   "found");
+		goto err4;
+	}
+
+	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->ioctl_sock < 0) {
+		perror("socket(PF_INET,SOCK_DGRAM)");
+		goto err5;
+	}
+
+	s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (s < 0) {
+		perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+		goto err6;
+	}
+
+	os_memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+	local.nl_groups = RTMGRP_LINK;
+	if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+		perror("bind(netlink)");
+		close(s);
+		goto err6;
+	}
+
+	eloop_register_read_sock(s, wpa_driver_nl80211_event_receive, drv,
+				 ctx);
+	drv->event_sock = s;
+
+	if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
+		printf("Could not get interface '%s' flags\n", drv->ifname);
+	else if (!(flags & IFF_UP)) {
+		if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
+			printf("Could not set interface '%s' UP\n",
+			       drv->ifname);
+		} else {
+			/*
+			 * Wait some time to allow driver to initialize before
+			 * starting configuring the driver. This seems to be
+			 * needed at least some drivers that load firmware etc.
+			 * when the interface is set up.
+			 */
+			wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
+				   "a second for the driver to complete "
+				   "initialization", drv->ifname);
+			sleep(1);
+		}
+	}
+
+	/*
+	 * Make sure that the driver does not have any obsolete PMKID entries.
+	 */
+	wpa_driver_nl80211_flush_pmkid(drv);
+
+	if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
+		printf("Could not configure driver to use managed mode\n");
+	}
+
+	wpa_driver_nl80211_get_range(drv);
+
+	drv->ifindex = if_nametoindex(drv->ifname);
+
+	wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+
+	return drv;
+
+err6:
+	close(drv->ioctl_sock);
+err5:
+	genl_family_put(drv->nl80211);
+err4:
+	nl_cache_free(drv->nl_cache);
+err3:
+	nl_handle_destroy(drv->nl_handle);
+err2:
+	nl_cb_put(drv->nl_cb);
+err1:
+	os_free(drv);
+	return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+void wpa_driver_nl80211_deinit(void *priv)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	int flags;
+
+	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+	/*
+	 * Clear possibly configured driver parameters in order to make it
+	 * easier to use the driver after wpa_supplicant has been terminated.
+	 */
+	(void) wpa_driver_nl80211_set_bssid(drv,
+					 (u8 *) "\x00\x00\x00\x00\x00\x00");
+
+	wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+	eloop_unregister_read_sock(drv->event_sock);
+
+	if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
+		(void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+	close(drv->event_sock);
+	close(drv->ioctl_sock);
+	os_free(drv->assoc_req_ies);
+	os_free(drv->assoc_resp_ies);
+
+	genl_family_put(drv->nl80211);
+	nl_cache_free(drv->nl_cache);
+	nl_handle_destroy(drv->nl_handle);
+	nl_cb_put(drv->nl_cb);
+
+	os_free(drv);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ *	all SSIDs (either active scan with broadcast SSID or passive
+ *	scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0, timeout;
+	struct iw_scan_req req;
+
+	if (ssid_len > IW_ESSID_MAX_SIZE) {
+		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+			   __FUNCTION__, (unsigned long) ssid_len);
+		return -1;
+	}
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	if (ssid && ssid_len) {
+		os_memset(&req, 0, sizeof(req));
+		req.essid_len = ssid_len;
+		req.bssid.sa_family = ARPHRD_ETHER;
+		os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+		os_memcpy(req.essid, ssid, ssid_len);
+		iwr.u.data.pointer = (caddr_t) &req;
+		iwr.u.data.length = sizeof(req);
+		iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+	}
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+		perror("ioctl[SIOCSIWSCAN]");
+		ret = -1;
+	}
+
+	/* Not all drivers generate "scan completed" wireless event, so try to
+	 * read results after a timeout. */
+	timeout = 5;
+	if (drv->scan_complete_events) {
+		/*
+		 * The driver seems to deliver SIOCGIWSCAN events to notify
+		 * when scan is complete, so use longer timeout to avoid race
+		 * conditions with scanning and following association request.
+		 */
+		timeout = 30;
+	}
+	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+		   "seconds", ret, timeout);
+	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout, drv,
+			       drv->ctx);
+
+	return ret;
+}
+
+
+static u8 * wpa_driver_nl80211_giwscan(struct wpa_driver_nl80211_data *drv,
+				    size_t *len)
+{
+	struct iwreq iwr;
+	u8 *res_buf;
+	size_t res_buf_len;
+
+	res_buf_len = IW_SCAN_MAX_DATA;
+	for (;;) {
+		res_buf = os_malloc(res_buf_len);
+		if (res_buf == NULL)
+			return NULL;
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+		iwr.u.data.pointer = res_buf;
+		iwr.u.data.length = res_buf_len;
+
+		if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+			break;
+
+		if (errno == E2BIG && res_buf_len < 100000) {
+			os_free(res_buf);
+			res_buf = NULL;
+			res_buf_len *= 2;
+			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+				   "trying larger buffer (%lu bytes)",
+				   (unsigned long) res_buf_len);
+		} else {
+			perror("ioctl[SIOCGIWSCAN]");
+			os_free(res_buf);
+			return NULL;
+		}
+	}
+
+	if (iwr.u.data.length > res_buf_len) {
+		os_free(res_buf);
+		return NULL;
+	}
+	*len = iwr.u.data.length;
+
+	return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+	struct wpa_scan_res res;
+	u8 *ie;
+	size_t ie_len;
+	u8 ssid[32];
+	size_t ssid_len;
+	int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	if (iwe->u.mode == IW_MODE_ADHOC)
+		res->res.caps |= IEEE80211_CAP_IBSS;
+	else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+		res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+			       struct wext_scan_data *res, char *custom,
+			       char *end)
+{
+	int ssid_len = iwe->u.essid.length;
+	if (custom + ssid_len > end)
+		return;
+	if (iwe->u.essid.flags &&
+	    ssid_len > 0 &&
+	    ssid_len <= IW_ESSID_MAX_SIZE) {
+		os_memcpy(res->ssid, custom, ssid_len);
+		res->ssid_len = ssid_len;
+	}
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	int divi = 1000000, i;
+
+	if (iwe->u.freq.e == 0) {
+		/*
+		 * Some drivers do not report frequency, but a channel.
+		 * Try to map this to frequency by assuming they are using
+		 * IEEE 802.11b/g.  But don't overwrite a previously parsed
+		 * frequency if the driver sends both frequency and channel,
+		 * since the driver may be sending an A-band channel that we
+		 * don't handle here.
+		 */
+
+		if (res->res.freq)
+			return;
+
+		if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+			res->res.freq = 2407 + 5 * iwe->u.freq.m;
+			return;
+		} else if (iwe->u.freq.m == 14) {
+			res->res.freq = 2484;
+			return;
+		}
+	}
+
+	if (iwe->u.freq.e > 6) {
+		wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+			   MACSTR " m=%d e=%d)",
+			   MAC2STR(res->res.bssid), iwe->u.freq.m,
+			   iwe->u.freq.e);
+		return;
+	}
+
+	for (i = 0; i < iwe->u.freq.e; i++)
+		divi /= 10;
+	res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct iw_event *iwe,
+			       struct wext_scan_data *res)
+{
+	res->res.qual = iwe->u.qual.qual;
+	res->res.noise = iwe->u.qual.noise;
+	res->res.level = iwe->u.qual.level;
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+				 struct wext_scan_data *res)
+{
+	if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+		res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+			       struct wext_scan_data *res, char *pos,
+			       char *end)
+{
+	int maxrate;
+	char *custom = pos + IW_EV_LCP_LEN;
+	struct iw_param p;
+	size_t clen;
+
+	clen = iwe->len;
+	if (custom + clen > end)
+		return;
+	maxrate = 0;
+	while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+		/* Note: may be misaligned, make a local, aligned copy */
+		os_memcpy(&p, custom, sizeof(struct iw_param));
+		if (p.value > maxrate)
+			maxrate = p.value;
+		clen -= sizeof(struct iw_param);
+		custom += sizeof(struct iw_param);
+	}
+	res->maxrate = maxrate;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+				    struct wext_scan_data *res, char *custom,
+				    char *end)
+{
+	char *genie, *gpos, *gend;
+	u8 *tmp;
+
+	gpos = genie = custom;
+	gend = genie + iwe->u.data.length;
+	if (gend > end) {
+		wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+		return;
+	}
+
+	tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+	if (tmp == NULL)
+		return;
+	os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+	res->ie = tmp;
+	res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+				 struct wext_scan_data *res, char *custom,
+				 char *end)
+{
+	size_t clen;
+	u8 *tmp;
+
+	clen = iwe->u.data.length;
+	if (custom + clen > end)
+		return;
+
+	if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+		char *spos;
+		int bytes;
+		spos = custom + 7;
+		bytes = custom + clen - spos;
+		if (bytes & 1)
+			return;
+		bytes /= 2;
+		tmp = os_realloc(res->ie, res->ie_len + bytes);
+		if (tmp == NULL)
+			return;
+		hexstr2bin(spos, tmp + res->ie_len, bytes);
+		res->ie = tmp;
+		res->ie_len += bytes;
+	} else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+		char *spos;
+		int bytes;
+		spos = custom + 7;
+		bytes = custom + clen - spos;
+		if (bytes & 1)
+			return;
+		bytes /= 2;
+		tmp = os_realloc(res->ie, res->ie_len + bytes);
+		if (tmp == NULL)
+			return;
+		hexstr2bin(spos, tmp + res->ie_len, bytes);
+		res->ie = tmp;
+		res->ie_len += bytes;
+	} else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+		char *spos;
+		int bytes;
+		u8 bin[8];
+		spos = custom + 4;
+		bytes = custom + clen - spos;
+		if (bytes != 16) {
+			wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+			return;
+		}
+		bytes /= 2;
+		hexstr2bin(spos, bin, bytes);
+		res->res.tsf += WPA_GET_BE64(bin);
+	}
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_nl80211_data *drv, u16 cmd)
+{
+	return drv->we_version_compiled > 18 &&
+		(cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+		 cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_nl80211_add_scan_entry(struct wpa_scan_results *res,
+					   struct wext_scan_data *data)
+{
+	struct wpa_scan_res **tmp;
+	struct wpa_scan_res *r;
+	size_t extra_len;
+	u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+	/* Figure out whether we need to fake any IEs */
+	pos = data->ie;
+	end = pos + data->ie_len;
+	while (pos && pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_SSID)
+			ssid_ie = pos;
+		else if (pos[0] == WLAN_EID_SUPP_RATES)
+			rate_ie = pos;
+		else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+			rate_ie = pos;
+		pos += 2 + pos[1];
+	}
+
+	extra_len = 0;
+	if (ssid_ie == NULL)
+		extra_len += 2 + data->ssid_len;
+	if (rate_ie == NULL && data->maxrate)
+		extra_len += 3;
+
+	r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+	if (r == NULL)
+		return;
+	os_memcpy(r, &data->res, sizeof(*r));
+	r->ie_len = extra_len + data->ie_len;
+	pos = (u8 *) (r + 1);
+	if (ssid_ie == NULL) {
+		/*
+		 * Generate a fake SSID IE since the driver did not report
+		 * a full IE list.
+		 */
+		*pos++ = WLAN_EID_SSID;
+		*pos++ = data->ssid_len;
+		os_memcpy(pos, data->ssid, data->ssid_len);
+		pos += data->ssid_len;
+	}
+	if (rate_ie == NULL && data->maxrate) {
+		/*
+		 * Generate a fake Supported Rates IE since the driver did not
+		 * report a full IE list.
+		 */
+		*pos++ = WLAN_EID_SUPP_RATES;
+		*pos++ = 1;
+		*pos++ = data->maxrate;
+	}
+	if (data->ie)
+		os_memcpy(pos, data->ie, data->ie_len);
+
+	tmp = os_realloc(res->res,
+			 (res->num + 1) * sizeof(struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(r);
+		return;
+	}
+	tmp[res->num++] = r;
+	res->res = tmp;
+}
+				      
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	size_t ap_num = 0, len;
+	int first;
+	u8 *res_buf;
+	struct iw_event iwe_buf, *iwe = &iwe_buf;
+	char *pos, *end, *custom;
+	struct wpa_scan_results *res;
+	struct wext_scan_data data;
+
+	res_buf = wpa_driver_nl80211_giwscan(drv, &len);
+	if (res_buf == NULL)
+		return NULL;
+
+	ap_num = 0;
+	first = 1;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL) {
+		os_free(res_buf);
+		return NULL;
+	}
+
+	pos = (char *) res_buf;
+	end = (char *) res_buf + len;
+	os_memset(&data, 0, sizeof(data));
+
+	while (pos + IW_EV_LCP_LEN <= end) {
+		/* Event data may be unaligned, so make a local, aligned copy
+		 * before processing. */
+		os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+		if (iwe->len <= IW_EV_LCP_LEN)
+			break;
+
+		custom = pos + IW_EV_POINT_LEN;
+		if (wext_19_iw_point(drv, iwe->cmd)) {
+			/* WE-19 removed the pointer from struct iw_point */
+			char *dpos = (char *) &iwe_buf.u.data.length;
+			int dlen = dpos - (char *) &iwe_buf;
+			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+				  sizeof(struct iw_event) - dlen);
+		} else {
+			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+			custom += IW_EV_POINT_OFF;
+		}
+
+		switch (iwe->cmd) {
+		case SIOCGIWAP:
+			if (!first)
+				wpa_driver_nl80211_add_scan_entry(res, &data);
+			first = 0;
+			os_free(data.ie);
+			os_memset(&data, 0, sizeof(data));
+			os_memcpy(data.res.bssid,
+				  iwe->u.ap_addr.sa_data, ETH_ALEN);
+			break;
+		case SIOCGIWMODE:
+			wext_get_scan_mode(iwe, &data);
+			break;
+		case SIOCGIWESSID:
+			wext_get_scan_ssid(iwe, &data, custom, end);
+			break;
+		case SIOCGIWFREQ:
+			wext_get_scan_freq(iwe, &data);
+			break;
+		case IWEVQUAL:
+			wext_get_scan_qual(iwe, &data);
+			break;
+		case SIOCGIWENCODE:
+			wext_get_scan_encode(iwe, &data);
+			break;
+		case SIOCGIWRATE:
+			wext_get_scan_rate(iwe, &data, pos, end);
+			break;
+		case IWEVGENIE:
+			wext_get_scan_iwevgenie(iwe, &data, custom, end);
+			break;
+		case IWEVCUSTOM:
+			wext_get_scan_custom(iwe, &data, custom, end);
+			break;
+		}
+
+		pos += iwe->len;
+	}
+	os_free(res_buf);
+	res_buf = NULL;
+	if (!first)
+		wpa_driver_nl80211_add_scan_entry(res, &data);
+	os_free(data.ie);
+
+	wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+		   (unsigned long) len, (unsigned long) res->num);
+
+	return res;
+}
+
+
+static int wpa_driver_nl80211_get_range(void *priv)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iw_range *range;
+	struct iwreq iwr;
+	int minlen;
+	size_t buflen;
+
+	/*
+	 * Use larger buffer than struct iw_range in order to allow the
+	 * structure to grow in the future.
+	 */
+	buflen = sizeof(struct iw_range) + 500;
+	range = os_zalloc(buflen);
+	if (range == NULL)
+		return -1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = (caddr_t) range;
+	iwr.u.data.length = buflen;
+
+	minlen = ((char *) &range->enc_capa) - (char *) range +
+		sizeof(range->enc_capa);
+
+	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWRANGE]");
+		os_free(range);
+		return -1;
+	} else if (iwr.u.data.length >= minlen &&
+		   range->we_version_compiled >= 18) {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+			   "WE(source)=%d enc_capa=0x%x",
+			   range->we_version_compiled,
+			   range->we_version_source,
+			   range->enc_capa);
+		drv->has_capability = 1;
+		drv->we_version_compiled = range->we_version_compiled;
+		if (range->enc_capa & IW_ENC_CAPA_WPA) {
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+		}
+		if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+			drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+		}
+		drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+			WPA_DRIVER_CAPA_ENC_WEP104;
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+		if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+			drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x",
+			   drv->capa.key_mgmt, drv->capa.enc);
+	} else {
+		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+			   "assuming WPA is not supported");
+	}
+
+	os_free(range);
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_set_wpa(void *priv, int enabled)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+	return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+					      enabled);
+}
+
+
+static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
+				      const u8 *addr, int key_idx,
+				      int set_tx, const u8 *seq,
+				      size_t seq_len,
+				      const u8 *key, size_t key_len)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	int ret = -1, err;
+	struct nl_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+		   "seq_len=%lu key_len=%lu",
+		   __func__, alg, addr, key_idx, set_tx,
+		   (unsigned long) seq_len, (unsigned long) key_len);
+
+	msg = nlmsg_alloc();
+	if (msg == NULL)
+		return -1;
+
+	if (alg == WPA_ALG_NONE) {
+		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+			    NL80211_CMD_DEL_KEY, 0);
+	} else {
+		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+			    NL80211_CMD_NEW_KEY, 0);
+		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+		switch (alg) {
+		case WPA_ALG_WEP:
+			if (key_len == 5)
+				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+					    0x000FAC01);
+			else
+				NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+					    0x000FAC05);
+			break;
+		case WPA_ALG_TKIP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+			break;
+		case WPA_ALG_CCMP:
+			NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+			break;
+		default:
+			nlmsg_free(msg);
+			return -1;
+		}
+	}
+
+	if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
+		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	}
+	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	err = 0;
+	if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+	    (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
+		nlmsg_free(msg);
+		return -1;
+	}
+
+	if (set_tx && alg != WPA_ALG_NONE) {
+		nlmsg_free(msg);
+		msg = nlmsg_alloc();
+		if (msg == NULL)
+			return -1;
+
+		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+			    0, NL80211_CMD_SET_KEY, 0);
+		NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+		err = 0;
+		if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+		    (err = nl_wait_for_ack(drv->nl_handle)) < 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: set default key "
+				   "failed; err=%d", err);
+			nlmsg_free(msg);
+			return -1;
+		}
+	}
+
+	ret = 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_countermeasures(void *priv,
+					       int enabled)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	return wpa_driver_nl80211_set_auth_param(drv,
+					      IW_AUTH_TKIP_COUNTERMEASURES,
+					      enabled);
+}
+
+
+static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
+						int enabled)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	drv->use_crypt = enabled;
+	return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+					      enabled);
+}
+
+
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+				const u8 *addr, int cmd, int reason_code)
+{
+	struct iwreq iwr;
+	struct iw_mlme mlme;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_memset(&mlme, 0, sizeof(mlme));
+	mlme.cmd = cmd;
+	mlme.reason_code = reason_code;
+	mlme.addr.sa_family = ARPHRD_ETHER;
+	os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+	iwr.u.data.pointer = (caddr_t) &mlme;
+	iwr.u.data.length = sizeof(mlme);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+		perror("ioctl[SIOCSIWMLME]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+					  int reason_code)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
+					int reason_code)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+	return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC,
+				    reason_code);
+}
+
+
+static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie,
+				      size_t ie_len)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = (caddr_t) ie;
+	iwr.u.data.length = ie_len;
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWGENIE]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_cipher2wext(int cipher)
+{
+	switch (cipher) {
+	case CIPHER_NONE:
+		return IW_AUTH_CIPHER_NONE;
+	case CIPHER_WEP40:
+		return IW_AUTH_CIPHER_WEP40;
+	case CIPHER_TKIP:
+		return IW_AUTH_CIPHER_TKIP;
+	case CIPHER_CCMP:
+		return IW_AUTH_CIPHER_CCMP;
+	case CIPHER_WEP104:
+		return IW_AUTH_CIPHER_WEP104;
+	default:
+		return 0;
+	}
+}
+
+
+static int wpa_driver_nl80211_keymgmt2wext(int keymgmt)
+{
+	switch (keymgmt) {
+	case KEY_MGMT_802_1X:
+	case KEY_MGMT_802_1X_NO_WPA:
+		return IW_AUTH_KEY_MGMT_802_1X;
+	case KEY_MGMT_PSK:
+		return IW_AUTH_KEY_MGMT_PSK;
+	default:
+		return 0;
+	}
+}
+
+
+static int
+wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv,
+				  struct wpa_driver_associate_params *params)
+{
+	struct iwreq iwr;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+		   "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	/* Just changing mode, not actual keys */
+	iwr.u.encoding.flags = 0;
+	iwr.u.encoding.pointer = (caddr_t) NULL;
+	iwr.u.encoding.length = 0;
+
+	/*
+	 * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+	 * different things. Here they are used to indicate Open System vs.
+	 * Shared Key authentication algorithm. However, some drivers may use
+	 * them to select between open/restricted WEP encrypted (open = allow
+	 * both unencrypted and encrypted frames; restricted = only allow
+	 * encrypted frames).
+	 */
+
+	if (!drv->use_crypt) {
+		iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+	} else {
+		if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+			iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+		if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+			iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+	}
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+		perror("ioctl[SIOCSIWENCODE]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+	void *priv, struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	int ret = 0;
+	int allow_unencrypted_eapol;
+	int value;
+
+	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+	/*
+	 * If the driver did not support SIOCSIWAUTH, fallback to
+	 * SIOCSIWENCODE here.
+	 */
+	if (drv->auth_alg_fallback &&
+	    wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0)
+		ret = -1;
+
+	if (!params->bssid &&
+	    wpa_driver_nl80211_set_bssid(drv, NULL) < 0)
+		ret = -1;
+
+	if (wpa_driver_nl80211_set_mode(drv, params->mode) < 0)
+		ret = -1;
+	/* TODO: should consider getting wpa version and cipher/key_mgmt suites
+	 * from configuration, not from here, where only the selected suite is
+	 * available */
+	if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+	    < 0)
+		ret = -1;
+	if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+		value = IW_AUTH_WPA_VERSION_DISABLED;
+	else if (params->wpa_ie[0] == WLAN_EID_RSN)
+		value = IW_AUTH_WPA_VERSION_WPA2;
+	else
+		value = IW_AUTH_WPA_VERSION_WPA;
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_WPA_VERSION, value) < 0)
+		ret = -1;
+	value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite);
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+		ret = -1;
+	value = wpa_driver_nl80211_cipher2wext(params->group_suite);
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_CIPHER_GROUP, value) < 0)
+		ret = -1;
+	value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite);
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_KEY_MGMT, value) < 0)
+		ret = -1;
+	value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+		params->pairwise_suite != CIPHER_NONE ||
+		params->group_suite != CIPHER_NONE ||
+		params->wpa_ie_len;
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_PRIVACY_INVOKED, value) < 0)
+		ret = -1;
+
+	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
+	 * not using WPA. IEEE 802.1X specifies that these frames are not
+	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
+	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+	    params->key_mgmt_suite == KEY_MGMT_PSK)
+		allow_unencrypted_eapol = 0;
+	else
+		allow_unencrypted_eapol = 1;
+	
+	if (wpa_driver_nl80211_set_auth_param(drv,
+					   IW_AUTH_RX_UNENCRYPTED_EAPOL,
+					   allow_unencrypted_eapol) < 0)
+		ret = -1;
+	if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0)
+		ret = -1;
+	if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+		ret = -1;
+	if (params->bssid &&
+	    wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0)
+		ret = -1;
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	int algs = 0, res;
+
+	if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+		algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+	if (auth_alg & AUTH_ALG_SHARED_KEY)
+		algs |= IW_AUTH_ALG_SHARED_KEY;
+	if (auth_alg & AUTH_ALG_LEAP)
+		algs |= IW_AUTH_ALG_LEAP;
+	if (algs == 0) {
+		/* at least one algorithm should be set */
+		algs = IW_AUTH_ALG_OPEN_SYSTEM;
+	}
+
+	res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+					     algs);
+	drv->auth_alg_fallback = res == -2;
+	return res;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	int ret = -1, flags;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+		    0, NL80211_CMD_SET_INTERFACE, 0);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
+
+	if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+	    nl_wait_for_ack(drv->nl_handle) < 0)
+		goto try_again;
+
+	nlmsg_free(msg);
+	return 0;
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -1;
+
+try_again:
+	/* mac80211 doesn't allow mode changes while the device is up, so
+	 * take the device down, try to set the mode again, and bring the
+	 * device back up.
+	 */
+	if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
+		(void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+		/* Try to set the mode again while the interface is down */
+		if (nl_send_auto_complete(drv->nl_handle, msg) < 0 ||
+		    nl_wait_for_ack(drv->nl_handle) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to set interface %s "
+				   "mode", drv->ifname);
+		} else
+			ret = 0;
+
+		/* Ignore return value of get_ifflags to ensure that the device
+		 * is always up like it was before this function was called.
+		 */
+		(void) wpa_driver_nl80211_get_ifflags(drv, &flags);
+		(void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
+	}
+
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv,
+				 u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+	struct iwreq iwr;
+	struct iw_pmksa pmksa;
+	int ret = 0;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_memset(&pmksa, 0, sizeof(pmksa));
+	pmksa.cmd = cmd;
+	pmksa.bssid.sa_family = ARPHRD_ETHER;
+	if (bssid)
+		os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+	if (pmkid)
+		os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+	iwr.u.data.pointer = (caddr_t) &pmksa;
+	iwr.u.data.length = sizeof(pmksa);
+
+	if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+		if (errno != EOPNOTSUPP)
+			perror("ioctl[SIOCSIWPMKSA]");
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid,
+				     const u8 *pmkid)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid,
+		 			const u8 *pmkid)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_flush_pmkid(void *priv)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+				       struct wpa_driver_capa *capa)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	if (!drv->has_capability)
+		return -1;
+	os_memcpy(capa, &drv->capa, sizeof(*capa));
+	return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+	drv->operstate = state;
+	return wpa_driver_nl80211_send_oper_ifla(
+		drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+	.name = "nl80211",
+	.desc = "Linux nl80211/cfg80211",
+	.get_bssid = wpa_driver_nl80211_get_bssid,
+	.get_ssid = wpa_driver_nl80211_get_ssid,
+	.set_wpa = wpa_driver_nl80211_set_wpa,
+	.set_key = wpa_driver_nl80211_set_key,
+	.set_countermeasures = wpa_driver_nl80211_set_countermeasures,
+	.set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
+	.scan = wpa_driver_nl80211_scan,
+	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+	.deauthenticate = wpa_driver_nl80211_deauthenticate,
+	.disassociate = wpa_driver_nl80211_disassociate,
+	.associate = wpa_driver_nl80211_associate,
+	.set_auth_alg = wpa_driver_nl80211_set_auth_alg,
+	.init = wpa_driver_nl80211_init,
+	.deinit = wpa_driver_nl80211_deinit,
+	.add_pmkid = wpa_driver_nl80211_add_pmkid,
+	.remove_pmkid = wpa_driver_nl80211_remove_pmkid,
+	.flush_pmkid = wpa_driver_nl80211_flush_pmkid,
+	.get_capa = wpa_driver_nl80211_get_capa,
+	.set_operstate = wpa_driver_nl80211_set_operstate,
+};

Added: wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c (added)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ps3.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,186 @@
+/*
+ * WPA Supplicant - PS3 Linux wireless extension driver interface
+ * Copyright 2007, 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include "wireless_copy.h"
+#include "common.h"
+#include "wpa_common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+
+static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
+				struct wpa_driver_associate_params *params)
+{
+	int ret, i;
+	struct iwreq iwr;
+	char *buf, *str;
+
+	if (!params->psk && !params->passphrase) {
+		wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
+		return -EINVAL;
+	}
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	if (params->psk) {
+		/* includes null */
+		iwr.u.data.length = PMK_LEN * 2 + 1;
+		buf = os_malloc(iwr.u.data.length);
+		if (!buf)
+			return -ENOMEM;
+		str = buf;
+		for (i = 0; i < PMK_LEN; i++) {
+			str += snprintf(str, iwr.u.data.length - (str - buf),
+					"%02x", params->psk[i]);
+		}
+	} else if (params->passphrase) {
+		/* including quotations and null */
+		iwr.u.data.length = strlen(params->passphrase) + 3;
+		buf = os_malloc(iwr.u.data.length);
+		if (!buf)
+			return -ENOMEM;
+		buf[0] = '"';
+		os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
+		buf[iwr.u.data.length - 2] = '"';
+		buf[iwr.u.data.length - 1] = '\0';
+	} else
+		return -EINVAL;
+	iwr.u.data.pointer = (caddr_t) buf;
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
+	os_free(buf);
+
+	return ret;
+}
+
+static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
+				struct wpa_driver_associate_params *params)
+{
+	int ret, i;
+	struct iwreq iwr;
+
+	for (i = 0; i < 4; i++) {
+		os_memset(&iwr, 0, sizeof(iwr));
+		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+		iwr.u.encoding.flags = i + 1;
+		if (params->wep_key_len[i]) {
+			iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
+			iwr.u.encoding.length = params->wep_key_len[i];
+		} else
+			iwr.u.encoding.flags = IW_ENCODE_NOKEY |
+				IW_ENCODE_DISABLED;
+
+		if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+			perror("ioctl[SIOCSIWENCODE]");
+			ret = -1;
+		}
+	}
+	return ret;
+}
+
+static int wpa_driver_ps3_associate(void *priv,
+				    struct wpa_driver_associate_params *params)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	int ret, value;
+
+	wpa_printf(MSG_DEBUG, "%s: <-", __func__);
+
+	/* clear BSSID */
+	if (!params->bssid &&
+	    wpa_driver_wext_set_bssid(drv, NULL) < 0)
+		ret = -1;
+
+	if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+		ret = -1;
+
+	if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+		value = IW_AUTH_WPA_VERSION_DISABLED;
+	else if (params->wpa_ie[0] == WLAN_EID_RSN)
+		value = IW_AUTH_WPA_VERSION_WPA2;
+	else
+		value = IW_AUTH_WPA_VERSION_WPA;
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_WPA_VERSION, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_cipher2wext(params->group_suite);
+	if (wpa_driver_wext_set_auth_param(drv,
+					   IW_AUTH_CIPHER_GROUP, value) < 0)
+		ret = -1;
+	value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+	if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
+		ret = -1;
+
+	/* set selected BSSID */
+	if (params->bssid &&
+	    wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+		ret = -1;
+
+	switch (params->group_suite) {
+	case CIPHER_NONE:
+		ret = 0;
+		break;
+	case CIPHER_WEP40:
+	case CIPHER_WEP104:
+		ret = wpa_driver_ps3_set_wep_keys(drv, params);
+		break;
+	case CIPHER_TKIP:
+	case CIPHER_CCMP:
+		ret = wpa_driver_ps3_set_wpa_key(drv, params);
+		break;
+	}
+
+	/* start to associate */
+	ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
+
+	wpa_printf(MSG_DEBUG, "%s: ->", __func__);
+
+	return ret;
+}
+
+static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+	int ret;
+	wpa_printf(MSG_DEBUG, "%s:<-", __func__);
+
+	ret = wpa_driver_wext_get_capa(priv, capa);
+	if (ret) {
+		wpa_printf(MSG_INFO, "%s: base wext returns error %d",
+			   __func__, ret);
+		return ret;
+	}
+	/* PS3 hypervisor does association and 4way handshake by itself */
+	capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+	wpa_printf(MSG_DEBUG, "%s:->", __func__);
+	return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_ps3_ops = {
+	.name = "ps3",
+	.desc = "PLAYSTATION3 Linux wireless extension driver",
+	.get_bssid = wpa_driver_wext_get_bssid,
+	.get_ssid = wpa_driver_wext_get_ssid,
+	.scan = wpa_driver_wext_scan,
+	.get_scan_results2 = wpa_driver_wext_get_scan_results,
+	.associate = wpa_driver_ps3_associate, /* PS3 */
+	.init = wpa_driver_wext_init,
+	.deinit = wpa_driver_wext_deinit,
+	.get_capa = wpa_driver_ps3_get_capa, /* PS3 */
+};

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ralink.c Sat Jun 14 00:26:56 2008
@@ -57,7 +57,7 @@
 	if (buf == NULL)
 		return -1;
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.data.flags = oid;
 	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
 
@@ -84,7 +84,7 @@
 	UCHAR enabled = 0;
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.data.pointer = (UCHAR*) &enabled;
 	iwr.u.data.flags = RT_OID_NEW_DRIVER;
 
@@ -108,7 +108,7 @@
 	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
 		perror("ioctl[SIOCGIWAP]");
@@ -145,7 +145,7 @@
 	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.essid.pointer = (caddr_t) ssid;
 	iwr.u.essid.length = 32;
 
@@ -236,7 +236,7 @@
 	buf->SsidLength = ssid_len;
 	os_memcpy(buf->Ssid, ssid, ssid_len);
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
 	iwr.u.data.flags = OID_802_11_SSID;
 	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
@@ -611,8 +611,10 @@
 					   "receive ReqIEs !!!");
 				drv->assoc_req_ies =
 					os_malloc(iwe->u.data.length);
-				if (drv->assoc_req_ies == NULL)
+				if (drv->assoc_req_ies == NULL) {
+					os_free(buf);
 					return;
+				}
 
 				drv->assoc_req_ies_len = iwe->u.data.length;
 				os_memcpy(drv->assoc_req_ies, custom,
@@ -625,6 +627,7 @@
 				if (drv->assoc_resp_ies == NULL) {
 					os_free(drv->assoc_req_ies);
 					drv->assoc_req_ies = NULL;
+					os_free(buf);
 					return;
 				}
 
@@ -637,7 +640,7 @@
 					   "receive ASSOCINFO_EVENT !!!");
 
 				assoc_info_buf =
-					os_malloc(drv->assoc_req_ies_len +
+					os_zalloc(drv->assoc_req_ies_len +
 						  drv->assoc_resp_ies_len + 1);
 
 				if (assoc_info_buf == NULL) {
@@ -649,18 +652,26 @@
 					return;
 				}
 
-				os_memcpy(assoc_info_buf, drv->assoc_req_ies,
-					  drv->assoc_req_ies_len);
+				if (drv->assoc_req_ies) {
+					os_memcpy(assoc_info_buf,
+						  drv->assoc_req_ies,
+						  drv->assoc_req_ies_len);
+				}
 				info_pos = assoc_info_buf +
 					drv->assoc_req_ies_len;
-				os_memcpy(info_pos, drv->assoc_resp_ies,
-					  drv->assoc_resp_ies_len);
+				if (drv->assoc_resp_ies) {
+					os_memcpy(info_pos,
+						  drv->assoc_resp_ies,
+						  drv->assoc_resp_ies_len);
+				}
 				assoc_info_buf[drv->assoc_req_ies_len +
 					       drv->assoc_resp_ies_len] = '\0';
 				wpa_driver_ralink_event_wireless_custom(
 					drv, ctx, assoc_info_buf);
 				os_free(drv->assoc_req_ies);
+				drv->assoc_req_ies = NULL;
 				os_free(drv->assoc_resp_ies);
+				drv->assoc_resp_ies = NULL;
 				os_free(assoc_info_buf);
 			} else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
 			{
@@ -836,7 +847,7 @@
 	UINT we_version_compiled = 0;
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.data.pointer = (caddr_t) &we_version_compiled;
 	iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
 
@@ -898,7 +909,7 @@
 		return NULL;
 	}
 	/* do it */
-	os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 
 	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
 		perror(ifr.ifr_name);
@@ -912,7 +923,7 @@
 	drv->scanning_done = 1;
 	drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
 	drv->ctx = ctx;
-	os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
 	drv->ioctl_sock = s;
 	drv->g_driver_down = 0;
 
@@ -1034,7 +1045,7 @@
 	/* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
 
 	os_memset(&iwr, 0, sizeof(iwr));
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
 		perror("ioctl[SIOCSIWSCAN]");
@@ -1083,7 +1094,7 @@
 	wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
 
 	wsr->NumberOfItems = 0;
-	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	iwr.u.data.pointer = (void *) buf;
 	iwr.u.data.flags = OID_802_11_BSSID_LIST;
 

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sat Jun 14 00:26:56 2008
@@ -149,32 +149,6 @@
 #endif /* CONFIG_CLIENT_MLME */
 
 
-struct wpa_driver_wext_data {
-	void *ctx;
-	int event_sock;
-	int ioctl_sock;
-	int mlme_sock;
-	char ifname[IFNAMSIZ + 1];
-	int ifindex;
-	int ifindex2;
-	u8 *assoc_req_ies;
-	size_t assoc_req_ies_len;
-	u8 *assoc_resp_ies;
-	size_t assoc_resp_ies_len;
-	struct wpa_driver_capa capa;
-	int has_capability;
-	int we_version_compiled;
-
-	/* for set_auth_alg fallback */
-	int use_crypt;
-	int auth_alg_fallback;
-
-	int operstate;
-
-	char mlmedev[IFNAMSIZ + 1];
-
-	int scan_complete_events;
-};
 
 
 static int wpa_driver_wext_flush_pmkid(void *priv);
@@ -239,8 +213,8 @@
 }
 
 
-static int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
-					  int idx, u32 value)
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+				   int idx, u32 value)
 {
 	struct iwreq iwr;
 	int ret = 0;
@@ -251,9 +225,11 @@
 	iwr.u.param.value = value;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
-		perror("ioctl[SIOCSIWAUTH]");
-		fprintf(stderr, "WEXT auth param %d value 0x%x - ",
-			idx, value);
+		if (errno != EOPNOTSUPP) {
+			wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+				   "value 0x%x) failed: %s)",
+				   idx, value, strerror(errno));
+		}
 		ret = errno == EOPNOTSUPP ? -2 : -1;
 	}
 
@@ -655,9 +631,8 @@
 			wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
 				   MACSTR,
 				   MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
-			if (os_memcmp(iwe->u.ap_addr.sa_data,
-				      "\x00\x00\x00\x00\x00\x00", ETH_ALEN) ==
-			    0 ||
+			if (is_zero_ether_addr(
+				    (const u8 *) iwe->u.ap_addr.sa_data) ||
 			    os_memcmp(iwe->u.ap_addr.sa_data,
 				      "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
 			    0) {
@@ -760,7 +735,7 @@
 		   (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
 		   (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
 		   (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
-		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT" : "");
+		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 	/*
 	 * Some drivers send the association event before the operup event--in
 	 * this case, lifting operstate in wpa_driver_wext_set_operstate()
@@ -1318,8 +1293,15 @@
 		/*
 		 * Some drivers do not report frequency, but a channel.
 		 * Try to map this to frequency by assuming they are using
-		 * IEEE 802.11b/g.
+		 * IEEE 802.11b/g.  But don't overwrite a previously parsed
+		 * frequency if the driver sends both frequency and channel,
+		 * since the driver may be sending an A-band channel that we
+		 * don't handle here.
 		 */
+
+		if (res->res.freq)
+			return;
+
 		if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
 			res->res.freq = 2407 + 5 * iwe->u.freq.m;
 			return;
@@ -1975,7 +1957,7 @@
 }
 
 
-static int wpa_driver_wext_cipher2wext(int cipher)
+int wpa_driver_wext_cipher2wext(int cipher)
 {
 	switch (cipher) {
 	case CIPHER_NONE:
@@ -1994,7 +1976,7 @@
 }
 
 
-static int wpa_driver_wext_keymgmt2wext(int keymgmt)
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
 {
 	switch (keymgmt) {
 	case KEY_MGMT_802_1X:
@@ -2052,9 +2034,8 @@
 }
 
 
-static int
-wpa_driver_wext_associate(void *priv,
-			  struct wpa_driver_associate_params *params)
+int wpa_driver_wext_associate(void *priv,
+			      struct wpa_driver_associate_params *params)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	int ret = 0;
@@ -2170,17 +2151,54 @@
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
-	int ret = 0;
+	int ret = -1, flags;
+	unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
 
 	os_memset(&iwr, 0, sizeof(iwr));
 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+	iwr.u.mode = new_mode;
+	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+		ret = 0;
+		goto done;
+	}
+
+	if (errno != EBUSY) {
 		perror("ioctl[SIOCSIWMODE]");
-		ret = -1;
-	}
-
+		goto done;
+	}
+
+	/* mac80211 doesn't allow mode changes while the device is up, so if
+	 * the device isn't in the mode we're about to change to, take device
+	 * down, try to set the mode again, and bring it back up.
+	 */
+	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+		perror("ioctl[SIOCGIWMODE]");
+		goto done;
+	}
+
+	if (iwr.u.mode == new_mode) {
+		ret = 0;
+		goto done;
+	}
+
+	if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+		(void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+		/* Try to set the mode again while the interface is down */
+		iwr.u.mode = new_mode;
+		if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+			perror("ioctl[SIOCSIWMODE]");
+		else
+			ret = 0;
+
+		/* Ignore return value of get_ifflags to ensure that the device
+		 * is always up like it was before this function was called.
+		 */
+		(void) wpa_driver_wext_get_ifflags(drv, &flags);
+		(void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+	}
+
+done:
 	return ret;
 }
 
@@ -2237,7 +2255,7 @@
 }
 
 
-static int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	if (!drv->has_capability)

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.h Sat Jun 14 00:26:56 2008
@@ -15,7 +15,34 @@
 #ifndef DRIVER_WEXT_H
 #define DRIVER_WEXT_H
 
-struct wpa_driver_wext_data;
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+	void *ctx;
+	int event_sock;
+	int ioctl_sock;
+	int mlme_sock;
+	char ifname[IFNAMSIZ + 1];
+	int ifindex;
+	int ifindex2;
+	u8 *assoc_req_ies;
+	size_t assoc_req_ies_len;
+	u8 *assoc_resp_ies;
+	size_t assoc_resp_ies_len;
+	struct wpa_driver_capa capa;
+	int has_capability;
+	int we_version_compiled;
+
+	/* for set_auth_alg fallback */
+	int use_crypt;
+	int auth_alg_fallback;
+
+	int operstate;
+
+	char mlmedev[IFNAMSIZ + 1];
+
+	int scan_complete_events;
+};
 
 int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
 int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
@@ -43,4 +70,12 @@
 int wpa_driver_wext_set_operstate(void *priv, int state);
 int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
 
+int wpa_driver_wext_associate(void *priv,
+			      struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+				   int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
 #endif /* DRIVER_WEXT_H */

Modified: wpasupplicant/branches/upstream/current/src/drivers/drivers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/drivers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/drivers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/drivers.c Sat Jun 14 00:26:56 2008
@@ -18,6 +18,9 @@
 #ifdef CONFIG_DRIVER_WEXT
 extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
 #endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
+#endif /* CONFIG_DRIVER_NL80211 */
 #ifdef CONFIG_DRIVER_HOSTAP
 extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
 #endif /* CONFIG_DRIVER_HOSTAP */
@@ -61,6 +64,9 @@
 #ifdef CONFIG_DRIVER_OSX
 extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
 #endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_PS3
+extern struct wpa_driver_ops wpa_driver_ps3_ops; /* driver_ps3.c */
+#endif /* CONFIG_DRIVER_PS3 */
 #ifdef CONFIG_DRIVER_IPHONE
 extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
 #endif /* CONFIG_DRIVER_IPHONE */
@@ -71,6 +77,9 @@
 #ifdef CONFIG_DRIVER_WEXT
 	&wpa_driver_wext_ops,
 #endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+	&wpa_driver_nl80211_ops,
+#endif /* CONFIG_DRIVER_NL80211 */
 #ifdef CONFIG_DRIVER_HOSTAP
 	&wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
@@ -113,6 +122,9 @@
 #ifdef CONFIG_DRIVER_OSX
 	&wpa_driver_osx_ops,
 #endif /* CONFIG_DRIVER_OSX */
+#ifdef CONFIG_DRIVER_PS3
+	&wpa_driver_ps3_ops,
+#endif /* CONFIG_DRIVER_PS3 */
 #ifdef CONFIG_DRIVER_IPHONE
 	&wpa_driver_iphone_ops,
 #endif /* CONFIG_DRIVER_IPHONE */

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h Sat Jun 14 00:26:56 2008
@@ -75,6 +75,7 @@
 /* SMI Network Management Private Enterprise Code for vendor specific types */
 enum {
 	EAP_VENDOR_IETF = 0,
+	EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
 	EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
 };
 

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,304 @@
+/*
+ * EAP-FAST common helper functions (RFC 4851)
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "tls.h"
+#include "eap_defs.h"
+#include "eap_tlv_common.h"
+#include "eap_fast_common.h"
+
+
+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len)
+{
+	struct pac_tlv_hdr hdr;
+	hdr.type = host_to_be16(type);
+	hdr.len = host_to_be16(len);
+	wpabuf_put_data(buf, &hdr, sizeof(hdr));
+}
+
+
+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
+			     u16 len)
+{
+	eap_fast_put_tlv_hdr(buf, type, len);
+	wpabuf_put_data(buf, data, len);
+}
+
+
+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
+				 const struct wpabuf *data)
+{
+	eap_fast_put_tlv_hdr(buf, type, wpabuf_len(data));
+	wpabuf_put_buf(buf, data);
+}
+
+
+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
+{
+	struct wpabuf *e;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
+	e = wpabuf_alloc(sizeof(struct pac_tlv_hdr) + wpabuf_len(buf));
+	if (e == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
+			   "for TLV encapsulation");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	eap_fast_put_tlv_buf(e,
+			     EAP_TLV_TYPE_MANDATORY | EAP_TLV_EAP_PAYLOAD_TLV,
+			     buf);
+	wpabuf_free(buf);
+	return e;
+}
+
+
+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
+				   const u8 *client_random, u8 *master_secret)
+{
+#define TLS_RANDOM_LEN 32
+#define TLS_MASTER_SECRET_LEN 48
+	u8 seed[2 * TLS_RANDOM_LEN];
+
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
+		    client_random, TLS_RANDOM_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
+		    server_random, TLS_RANDOM_LEN);
+
+	/*
+	 * RFC 4851, Section 5.1:
+	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
+	 *                       server_random + client_random, 48)
+	 */
+	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
+	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
+	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
+		   "PAC to master secret label hash",
+		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
+			master_secret, TLS_MASTER_SECRET_LEN);
+}
+
+
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
+			 const char *label, size_t len)
+{
+	struct tls_keys keys;
+	u8 *rnd = NULL, *out;
+	int block_size;
+
+	block_size = tls_connection_get_keyblock_size(ssl_ctx, conn);
+	if (block_size < 0)
+		return NULL;
+
+	out = os_malloc(block_size + len);
+	if (out == NULL)
+		return NULL;
+
+	if (tls_connection_prf(ssl_ctx, conn, label, 1, out, block_size + len)
+	    == 0) {
+		os_memmove(out, out + block_size, len);
+		return out;
+	}
+
+	if (tls_connection_get_keys(ssl_ctx, conn, &keys))
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+
+	os_memcpy(rnd, keys.server_random, keys.server_random_len);
+	os_memcpy(rnd + keys.server_random_len, keys.client_random,
+		  keys.client_random_len);
+
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
+			"expansion", keys.master_key, keys.master_key_len);
+	if (tls_prf(keys.master_key, keys.master_key_len,
+		    label, rnd, keys.client_random_len +
+		    keys.server_random_len, out, block_size + len))
+		goto fail;
+	os_free(rnd);
+	os_memmove(out, out + block_size, len);
+	return out;
+
+fail:
+	os_free(rnd);
+	os_free(out);
+	return NULL;
+}
+
+
+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
+{
+	/*
+	 * RFC 4851, Section 5.4: EAP Master Session Key Generation
+	 * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
+	 */
+
+	sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+		   "Session Key Generating Function", (u8 *) "", 0,
+		   msk, EAP_FAST_KEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
+			msk, EAP_FAST_KEY_LEN);
+}
+
+
+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+{
+	/*
+	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
+	 * EMSK = T-PRF(S-IMCK[j],
+	 *        "Extended Session Key Generating Function", 64)
+	 */
+
+	sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+		   "Extended Session Key Generating Function", (u8 *) "", 0,
+		   emsk, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+			emsk, EAP_EMSK_LEN);
+}
+
+
+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+		       int tlv_type, u8 *pos, int len)
+{
+	switch (tlv_type) {
+	case EAP_TLV_EAP_PAYLOAD_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
+			    pos, len);
+		if (tlv->eap_payload_tlv) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "EAP-Payload TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->eap_payload_tlv = pos;
+		tlv->eap_payload_tlv_len = len;
+		break;
+	case EAP_TLV_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
+		if (tlv->result) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Result TLV in the message");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Result TLV");
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->result = WPA_GET_BE16(pos);
+		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->result != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
+				   tlv->result);
+			tlv->result = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
+			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
+			    pos, len);
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Intermediate-Result TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		if (tlv->iresult) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Intermediate-Result TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->iresult = WPA_GET_BE16(pos);
+		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
+		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
+				   "Result %d", tlv->iresult);
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
+			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
+			   "Success" : "Failure");
+		break;
+	case EAP_TLV_CRYPTO_BINDING_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
+			    pos, len);
+		if (tlv->crypto_binding) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Crypto-Binding TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
+		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Crypto-Binding TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->crypto_binding = (struct eap_tlv_crypto_binding_tlv *)
+			(pos - sizeof(struct eap_tlv_hdr));
+		break;
+	case EAP_TLV_REQUEST_ACTION_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
+			    pos, len);
+		if (tlv->request_action) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "Request-Action TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		if (len < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
+				   "Request-Action TLV");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			break;
+		}
+		tlv->request_action = WPA_GET_BE16(pos);
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
+			   tlv->request_action);
+		break;
+	case EAP_TLV_PAC_TLV:
+		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
+		if (tlv->pac) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
+				   "PAC TLV in the message");
+			tlv->iresult = EAP_TLV_RESULT_FAILURE;
+			return -2;
+		}
+		tlv->pac = pos;
+		tlv->pac_len = len;
+		break;
+	default:
+		/* Unknown TLV */
+		return -1;
+	}
+
+	return 0;
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_fast_common.h Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
 /*
  * EAP-FAST definitions (RFC 4851)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,6 +19,7 @@
 #define EAP_FAST_KEY_LEN 64
 #define EAP_FAST_SIMCK_LEN 40
 #define EAP_FAST_SKS_LEN 40
+#define EAP_FAST_CMK_LEN 20
 
 #define TLS_EXT_PAC_OPAQUE 35
 
@@ -82,4 +83,35 @@
 	u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
 };
 
+
+struct wpabuf;
+struct tls_connection;
+
+struct eap_fast_tlv_parse {
+	u8 *eap_payload_tlv;
+	size_t eap_payload_tlv_len;
+	struct eap_tlv_crypto_binding_tlv *crypto_binding;
+	size_t crypto_binding_len;
+	int iresult;
+	int result;
+	int request_action;
+	u8 *pac;
+	size_t pac_len;
+};
+
+void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
+void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
+		      u16 len);
+void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
+			  const struct wpabuf *data);
+struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
+void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
+				   const u8 *client_random, u8 *master_secret);
+u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
+			 const char *label, size_t len);
+void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
+void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
+int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
+		       int tlv_type, u8 *pos, int len);
+
 #endif /* EAP_FAST_H */

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,87 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+
+void peap_prfplus(int version, const u8 *key, size_t key_len,
+		  const char *label, const u8 *seed, size_t seed_len,
+		  u8 *buf, size_t buf_len)
+{
+	unsigned char counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label);
+	u8 extra[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (unsigned char *) label;
+	len[1] = label_len;
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	if (version == 0) {
+		/*
+		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
+		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
+		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
+		 * ...
+		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
+		 */
+
+		extra[0] = 0;
+		extra[1] = 0;
+
+		addr[3] = &counter;
+		len[3] = 1;
+		addr[4] = extra;
+		len[4] = 2;
+	} else {
+		/*
+		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
+		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
+		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
+		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
+		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
+		 *   ...
+		 */
+
+		extra[0] = buf_len & 0xff;
+
+		addr[3] = extra;
+		len[3] = 1;
+		addr[4] = &counter;
+		len[4] = 1;
+	}
+
+	pos = 0;
+	while (pos < buf_len) {
+		counter++;
+		plen = buf_len - pos;
+		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+		if (plen >= SHA1_MAC_LEN) {
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			pos += SHA1_MAC_LEN;
+		} else {
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		len[0] = SHA1_MAC_LEN;
+	}
+}

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.h Sat Jun 14 00:26:56 2008
@@ -1,0 +1,22 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_PEAP_COMMON_H
+#define EAP_PEAP_COMMON_H
+
+void peap_prfplus(int version, const u8 *key, size_t key_len,
+		  const char *label, const u8 *seed, size_t seed_len,
+		  u8 *buf, size_t buf_len);
+
+#endif /* EAP_PEAP_COMMON_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_tlv_common.h Sat Jun 14 00:26:56 2008
@@ -73,7 +73,7 @@
 } STRUCT_PACKED;
 
 /* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
-struct eap_tlv_crypto_binding__tlv {
+struct eap_tlv_crypto_binding_tlv {
 	be16 tlv_type;
 	be16 length;
 	u8 reserved;

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h Sat Jun 14 00:26:56 2008
@@ -350,6 +350,12 @@
 	 * fast_pac_format=binary option can be used to select binary format
 	 * for storing PAC entires in order to save some space (the default
 	 * text format uses about 2.5 times the size of minimal binary format).
+	 *
+	 * crypto_binding option can be used to control PEAPv0 cryptobinding
+	 * behavior:
+	 * 0 = do not use cryptobinding
+	 * 1 = use cryptobinding if server supports it (default)
+	 * 2 = require cryptobinding
 	 */
 	char *phase1;
 
@@ -409,6 +415,44 @@
 	 * using a smartcard.
 	 */
 	char *key_id;
+
+	/**
+	 * cert_id - Cert ID for OpenSSL engine
+	 *
+	 * This is used if the certificate operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *cert_id;
+
+	/**
+	 * ca_cert_id - CA Cert ID for OpenSSL engine
+	 *
+	 * This is used if the CA certificate for EAP-TLS is on a smartcard.
+	 */
+	char *ca_cert_id;
+
+	/**
+	 * key2_id - Key ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *key2_id;
+
+	/**
+	 * cert2_id - Cert ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if the certificate operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *cert2_id;
+
+	/**
+	 * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if the CA certificate for EAP-TLS is on a smartcard.
+	 */
+	char *ca_cert2_id;
 
 	/**
 	 * otp - One-time-password

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c Sat Jun 14 00:26:56 2008
@@ -19,7 +19,7 @@
 #include "eap_tls_common.h"
 #include "eap_config.h"
 #include "tls.h"
-#include "eap_tlv.h"
+#include "eap_common/eap_tlv_common.h"
 #include "sha1.h"
 #include "eap_fast_pac.h"
 
@@ -80,9 +80,6 @@
 				      u8 *master_secret)
 {
 	struct eap_fast_data *data = ctx;
-#define TLS_RANDOM_LEN 32
-#define TLS_MASTER_SECRET_LEN 48
-	u8 seed[2 * TLS_RANDOM_LEN];
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
 
@@ -101,10 +98,6 @@
 	}
 
 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
-		    client_random, TLS_RANDOM_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
-		    server_random, TLS_RANDOM_LEN);
 
 	if (data->current_pac == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "
@@ -113,19 +106,9 @@
 		return 0;
 	}
 
-	/*
-	 * RFC 4851, Section 5.1:
-	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
-	 *                       server_random + client_random, 48)
-	 */
-	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
-	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
-	sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
-		   "PAC to master secret label hash",
-		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
-			master_secret, TLS_MASTER_SECRET_LEN);
+	eap_fast_derive_master_secret(data->current_pac->pac_key,
+				      server_random, client_random,
+				      master_secret);
 
 	data->session_ticket_used = 1;
 
@@ -268,71 +251,10 @@
 
 static int eap_fast_derive_msk(struct eap_fast_data *data)
 {
-	/* Derive EAP Master Session Keys (section 5.4) */
-	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-		   "Session Key Generating Function", (u8 *) "", 0,
-		   data->key_data, EAP_FAST_KEY_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
-			data->key_data, EAP_FAST_KEY_LEN);
-
-	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-		   "Extended Session Key Generating Function",
-		   (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
-			data->emsk, EAP_EMSK_LEN);
-
+	eap_fast_derive_eap_msk(data->simck, data->key_data);
+	eap_fast_derive_eap_emsk(data->simck, data->emsk);
 	data->success = 1;
-
 	return 0;
-}
-
-
-static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-				char *label, size_t len)
-{
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-	int block_size;
-
-	block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
-	if (block_size < 0)
-		return NULL;
-
-	out = os_malloc(block_size + len);
-	if (out == NULL)
-		return NULL;
-
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
-			       block_size + len) == 0) {
-		os_memmove(out, out + block_size, len);
-		return out;
-	}
-
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
-			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, block_size + len))
-		goto fail;
-	os_free(rnd);
-	os_memmove(out, out + block_size, len);
-	return out;
-
-fail:
-	os_free(rnd);
-	os_free(out);
-	return NULL;
 }
 
 
@@ -345,7 +267,7 @@
 	 * Extra key material after TLS key_block: session_key_seed[40]
 	 */
 
-	sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
 				  EAP_FAST_SKS_LEN);
 	if (sks == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -371,7 +293,8 @@
 {
 	os_free(data->key_block_p);
 	data->key_block_p = (struct eap_fast_key_block_provisioning *)
-		eap_fast_derive_key(sm, &data->ssl, "key expansion",
+		eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+				    "key expansion",
 				    sizeof(*data->key_block_p));
 	if (data->key_block_p == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -435,12 +358,27 @@
 {
 	size_t i;
 
+	/* TODO: TNC with anonymous provisioning; need to require both
+	 * completed MSCHAPv2 and TNC */
+
 	if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "
 			   "during unauthenticated provisioning; reject phase2"
 			   " type %d", type);
 		return -1;
 	}
+
+#ifdef EAP_TNC
+	if (type == EAP_TYPE_TNC) {
+		data->phase2_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_type.method = EAP_TYPE_TNC;
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "
+			   "vendor %d method %d for TNC",
+			   data->phase2_type.vendor,
+			   data->phase2_type.method);
+		return 0;
+	}
+#endif /* EAP_TNC */
 
 	for (i = 0; i < data->num_phase2_types; i++) {
 		if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||
@@ -485,6 +423,17 @@
 	if (*pos == EAP_TYPE_IDENTITY) {
 		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
 		return 0;
+	}
+
+	if (data->phase2_priv && data->phase2_method &&
+	    *pos != data->phase2_type.method) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "
+			   "deinitialize previous method");
+		data->phase2_method->deinit(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+		data->phase2_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_type.method = EAP_TYPE_NONE;
 	}
 
 	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
@@ -596,32 +545,6 @@
 }
 
 
-static struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *msg;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP Payload TLV */
-	msg = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (msg == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(msg, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(msg, buf);
-	wpabuf_free(buf);
-	return msg;
-}
-
-
 static struct wpabuf * eap_fast_process_eap_payload_tlv(
 	struct eap_sm *sm, struct eap_fast_data *data,
 	struct eap_method_ret *ret, const struct eap_hdr *req,
@@ -661,7 +584,7 @@
 
 
 static int eap_fast_validate_crypto_binding(
-	struct eap_tlv_crypto_binding__tlv *_bind)
+	struct eap_tlv_crypto_binding_tlv *_bind)
 {
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
 		   "Received Version %d SubType %d",
@@ -687,8 +610,8 @@
 
 
 static void eap_fast_write_crypto_binding(
-	struct eap_tlv_crypto_binding__tlv *rbind,
-	struct eap_tlv_crypto_binding__tlv *_bind, const u8 *cmk)
+	struct eap_tlv_crypto_binding_tlv *rbind,
+	struct eap_tlv_crypto_binding_tlv *_bind, const u8 *cmk)
 {
 	rbind->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
 				       EAP_TLV_CRYPTO_BINDING_TLV);
@@ -699,7 +622,8 @@
 	rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
 	os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
 	inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
-	hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
+	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) rbind, sizeof(*rbind),
+		  rbind->compound_mac);
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
 		   "Received Version %d SubType %d",
@@ -773,8 +697,9 @@
 	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
 			data->simck, EAP_FAST_SIMCK_LEN);
-	os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, 20);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
+	os_memcpy(cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+			cmk, EAP_FAST_CMK_LEN);
 
 	return 0;
 }
@@ -807,17 +732,16 @@
 static struct wpabuf * eap_fast_process_crypto_binding(
 	struct eap_sm *sm, struct eap_fast_data *data,
 	struct eap_method_ret *ret,
-	struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len, int final)
+	struct eap_tlv_crypto_binding_tlv *_bind, size_t bind_len)
 {
 	struct wpabuf *resp;
 	u8 *pos;
-	struct eap_tlv_intermediate_result_tlv *rresult;
-	u8 cmk[20], cmac[20];
-	int res, req_tunnel_pac = 0;
+	u8 cmk[EAP_FAST_CMK_LEN], cmac[SHA1_MAC_LEN];
+	int res;
 	size_t len;
 
 	if (eap_fast_validate_crypto_binding(_bind) < 0)
-		return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
+		return NULL;
 
 	if (eap_fast_get_cmk(sm, data, cmk) < 0)
 		return NULL;
@@ -827,7 +751,8 @@
 	os_memset(_bind->compound_mac, 0, sizeof(cmac));
 	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
 		    "MAC calculation", (u8 *) _bind, bind_len);
-	hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
+	hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len,
+		  _bind->compound_mac);
 	res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
 	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
 		    cmac, sizeof(cmac));
@@ -835,9 +760,8 @@
 		    _bind->compound_mac, sizeof(cmac));
 	if (res != 0) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
-		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1);
 		os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
-		return resp;
+		return NULL;
 	}
 
 	/*
@@ -845,72 +769,24 @@
 	 * crypto binding to allow server to complete authentication.
 	 */
 
-	if (data->current_pac == NULL && data->provisioning &&
-	    !data->anon_provisioning) {
-		/*
-		 * Need to request Tunnel PAC when using authenticated
-		 * provisioning.
-		 */
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
-		req_tunnel_pac = 1;
-	}
-
-	len = sizeof(*rresult) + sizeof(struct eap_tlv_crypto_binding__tlv);
-	if (req_tunnel_pac)
-		len += sizeof(struct eap_tlv_hdr) +
-			sizeof(struct eap_tlv_request_action_tlv) +
-			sizeof(struct eap_tlv_pac_type_tlv);
+	len = sizeof(struct eap_tlv_crypto_binding_tlv);
 	resp = wpabuf_alloc(len);
 	if (resp == NULL)
 		return NULL;
-
-	/*
-	 * Both intermediate and final Result TLVs are identical, so ok to use
-	 * the same structure definition for them.
-	 */
-	rresult = wpabuf_put(resp, sizeof(*rresult));
-	rresult->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-					 (final ? EAP_TLV_RESULT_TLV :
-					  EAP_TLV_INTERMEDIATE_RESULT_TLV));
-	rresult->length = host_to_be16(2);
-	rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
 
 	if (!data->anon_provisioning && data->phase2_success &&
 	    eap_fast_derive_msk(data) < 0) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
 		ret->methodState = METHOD_DONE;
 		ret->decision = DECISION_FAIL;
-		rresult->status = host_to_be16(EAP_TLV_RESULT_FAILURE);
 		data->phase2_success = 0;
-	}
-
-	pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding__tlv));
-	eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding__tlv *)
+		wpabuf_free(resp);
+		return NULL;
+	}
+
+	pos = wpabuf_put(resp, sizeof(struct eap_tlv_crypto_binding_tlv));
+	eap_fast_write_crypto_binding((struct eap_tlv_crypto_binding_tlv *)
 				      pos, _bind, cmk);
-
-	if (req_tunnel_pac) {
-		u8 *pos2;
-		pos = wpabuf_put(resp, 0);
-		pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
-		wpabuf_put(resp, pos2 - pos);
-	}
-
-	if (final && data->phase2_success) {
-		if (data->anon_provisioning) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
-				   "provisioning completed successfully.");
-			ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_FAIL;
-		} else {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
-				   "completed successfully.");
-			if (data->provisioning)
-				ret->methodState = METHOD_MAY_CONT;
-			else
-				ret->methodState = METHOD_DONE;
-			ret->decision = DECISION_UNCOND_SUCC;
-		}
-	}
 
 	return resp;
 }
@@ -1128,7 +1004,7 @@
 	os_memset(&entry, 0, sizeof(entry));
 	if (eap_fast_process_pac_tlv(&entry, pac, pac_len) ||
 	    eap_fast_process_pac_info(&entry))
-		return eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+		return NULL;
 
 	eap_fast_add_pac(&data->pac, &data->current_pac, &entry);
 	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);
@@ -1169,94 +1045,6 @@
 }
 
 
-struct eap_fast_tlv_parse {
-	u8 *eap_payload_tlv;
-	size_t eap_payload_tlv_len;
-	u8 *pac;
-	size_t pac_len;
-	struct eap_tlv_crypto_binding__tlv *crypto_binding;
-	size_t crypto_binding_len;
-	int iresult;
-	int result;
-};
-
-
-static int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
-			      int tlv_type, u8 *pos, int len)
-{
-	switch (tlv_type) {
-	case EAP_TLV_EAP_PAYLOAD_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP Payload TLV",
-			    pos, len);
-		tlv->eap_payload_tlv = pos;
-		tlv->eap_payload_tlv_len = len;
-		break;
-	case EAP_TLV_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Result TLV");
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->result = WPA_GET_BE16(pos);
-		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->result != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
-				   tlv->result);
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
-			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
-			    pos, len);
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Intermediate Result TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->iresult = WPA_GET_BE16(pos);
-		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
-				   "Result %d", tlv->iresult);
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
-			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_CRYPTO_BINDING_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
-			    pos, len);
-		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
-		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Crypto-Binding TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->crypto_binding = (struct eap_tlv_crypto_binding__tlv *)
-			(pos - sizeof(struct eap_tlv_hdr));
-		break;
-	case EAP_TLV_PAC_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
-		tlv->pac = pos;
-		tlv->pac_len = len;
-		break;
-	default:
-		/* Unknown TLV */
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static int eap_fast_parse_decrypted(struct wpabuf *decrypted,
 				    struct eap_fast_tlv_parse *tlv,
 				    struct wpabuf **resp)
@@ -1328,6 +1116,24 @@
 }
 
 
+static struct wpabuf * eap_fast_pac_request(void)
+{
+	struct wpabuf *tmp;
+	u8 *pos, *pos2;
+
+	tmp = wpabuf_alloc(sizeof(struct eap_tlv_hdr) +
+			   sizeof(struct eap_tlv_request_action_tlv) +
+			   sizeof(struct eap_tlv_pac_type_tlv));
+	if (tmp == NULL)
+		return NULL;
+
+	pos = wpabuf_put(tmp, 0);
+	pos2 = eap_fast_write_pac_request(pos, PAC_TYPE_TUNNEL_PAC);
+	wpabuf_put(tmp, pos2 - pos);
+	return tmp;
+}
+
+
 static int eap_fast_process_decrypted(struct eap_sm *sm,
 				      struct eap_fast_data *data,
 				      struct eap_method_ret *ret,
@@ -1335,8 +1141,9 @@
 				      struct wpabuf *decrypted,
 				      struct wpabuf **out_data)
 {
-	struct wpabuf *resp = NULL;
+	struct wpabuf *resp = NULL, *tmp;
 	struct eap_fast_tlv_parse tlv;
+	int failed = 0;
 
 	if (eap_fast_parse_decrypted(decrypted, &tlv, &resp) < 0)
 		return 0;
@@ -1356,43 +1163,84 @@
 						 req->identifier, out_data);
 	}
 
+	if (tlv.crypto_binding) {
+		tmp = eap_fast_process_crypto_binding(sm, data, ret,
+						      tlv.crypto_binding,
+						      tlv.crypto_binding_len);
+		if (tmp == NULL)
+			failed = 1;
+		else
+			resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.iresult == EAP_TLV_RESULT_SUCCESS) {
+		tmp = eap_fast_tlv_result(failed ? EAP_TLV_RESULT_FAILURE :
+					  EAP_TLV_RESULT_SUCCESS, 1);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
 	if (tlv.eap_payload_tlv) {
-		resp = eap_fast_process_eap_payload_tlv(
+		tmp = eap_fast_process_eap_payload_tlv(
 			sm, data, ret, req, tlv.eap_payload_tlv,
 			tlv.eap_payload_tlv_len);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-	}
-
-	if (tlv.crypto_binding) {
-		int final = tlv.result == EAP_TLV_RESULT_SUCCESS;
-		resp = eap_fast_process_crypto_binding(sm, data, ret,
-						       tlv.crypto_binding,
-						       tlv.crypto_binding_len,
-						       final);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
+		resp = wpabuf_concat(resp, tmp);
 	}
 
 	if (tlv.pac && tlv.result != EAP_TLV_RESULT_SUCCESS) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
 			   "acknowledging success");
-		resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-	}
-
-	if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
-		resp = eap_fast_process_pac(sm, data, ret, tlv.pac,
-					    tlv.pac_len);
-		return eap_fast_encrypt_response(sm, data, resp,
-						 req->identifier, out_data);
-	}
-
-	wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
-		   "empty response packet");
-	return eap_fast_encrypt_response(sm, data, wpabuf_alloc(1),
-					 req->identifier, out_data);
+		failed = 1;
+	} else if (tlv.pac && tlv.result == EAP_TLV_RESULT_SUCCESS) {
+		tmp = eap_fast_process_pac(sm, data, ret, tlv.pac,
+					   tlv.pac_len);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (data->current_pac == NULL && data->provisioning &&
+	    !data->anon_provisioning) {
+		/*
+		 * Need to request Tunnel PAC when using authenticated
+		 * provisioning.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Request Tunnel PAC");
+		tmp = eap_fast_pac_request();
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (tlv.result == EAP_TLV_RESULT_SUCCESS && !failed) {
+		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_SUCCESS, 0);
+		resp = wpabuf_concat(resp, tmp);
+	} else if (failed) {
+		tmp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0);
+		resp = wpabuf_concat(resp, tmp);
+	}
+
+	if (resp && tlv.result == EAP_TLV_RESULT_SUCCESS && !failed &&
+	    tlv.crypto_binding && data->phase2_success) {
+		if (data->anon_provisioning) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Unauthenticated "
+				   "provisioning completed successfully.");
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+				   "completed successfully.");
+			if (data->provisioning)
+				ret->methodState = METHOD_MAY_CONT;
+			else
+				ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_UNCOND_SUCC;
+		}
+	}
+
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
+			   "empty response packet");
+		resp = wpabuf_alloc(1);
+	}
+
+	return eap_fast_encrypt_response(sm, data, resp, req->identifier,
+					 out_data);
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c Sat Jun 14 00:26:56 2008
@@ -15,11 +15,14 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha1.h"
 #include "eap_i.h"
 #include "eap_tls_common.h"
 #include "eap_config.h"
 #include "tls.h"
-#include "eap_tlv.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
+#include "tncc.h"
 
 
 /* Maximum supported PEAP version
@@ -60,6 +63,12 @@
 	u8 *key_data;
 
 	struct wpabuf *pending_phase2_req;
+	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+	int crypto_binding_used;
+	u8 ipmk[40];
+	u8 cmk[20];
+	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
+		  * is enabled. */
 };
 
 
@@ -96,6 +105,24 @@
 			   "receiving tunneled EAP-Success");
 	}
 
+	if (os_strstr(phase1, "crypto_binding=0")) {
+		data->crypto_binding = NO_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=1")) {
+		data->crypto_binding = OPTIONAL_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=2")) {
+		data->crypto_binding = REQUIRE_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
+	}
+
+#ifdef EAP_TNC
+	if (os_strstr(phase1, "tnc=soh")) {
+		data->soh = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH enabled");
+	}
+#endif /* EAP_TNC */
+
 	return 0;
 }
 
@@ -112,6 +139,7 @@
 	data->peap_version = EAP_PEAP_VERSION;
 	data->force_peap_version = -1;
 	data->peap_outer_success = 2;
+	data->crypto_binding = OPTIONAL_BINDING;
 
 	if (config && config->phase1 &&
 	    eap_peap_parse_phase1(data, config->phase1) < 0) {
@@ -154,6 +182,396 @@
 }
 
 
+/**
+ * eap_tlv_build_nak - Build EAP-TLV NAK message
+ * @id: EAP identifier for the header
+ * @nak_type: TLV type (EAP_TLV_*)
+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
+	wpabuf_put_be16(msg, 6); /* Length */
+	wpabuf_put_be32(msg, 0); /* Vendor-Id */
+	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
+
+	return msg;
+}
+
+
+static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
+			    u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
+	    data->phase2_method->isKeyAvailable == NULL ||
+	    data->phase2_method->getKey == NULL)
+		return 0;
+
+	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
+	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * Microsoft uses reverse order for MS-MPPE keys in
+		 * EAP-PEAP when compared to EAP-FAST derivation of
+		 * ISK. Swap the keys here to get the correct ISK for
+		 * EAP-PEAPv0 cryptobinding.
+		 */
+		u8 tmp[16];
+		os_memcpy(tmp, key, 16);
+		os_memcpy(key, key + 16, 16);
+		os_memcpy(key + 16, tmp, 16);
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+	u8 *tk;
+	u8 isk[32], imck[60];
+
+	/*
+	 * Tunnel key (TK) is the first 60 octets of the key generated by
+	 * phase 1 of PEAP (based on TLS).
+	 */
+	tk = data->key_data;
+	if (tk == NULL)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+	/*
+	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
+	 * TempKey = First 40 octets of TK
+	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+	 * in the end of the label just before ISK; is that just a typo?)
+	 */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
+		     isk, sizeof(isk), imck, sizeof(imck));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+			imck, sizeof(imck));
+
+	/* TODO: fast-connect: IPMK|CMK = TK */
+	os_memcpy(data->ipmk, imck, 40);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
+	os_memcpy(data->cmk, imck + 40, 20);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+	return 0;
+}
+
+
+static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
+				     struct eap_peap_data *data,
+				     struct wpabuf *buf)
+{
+	u8 *mac;
+	u8 eap_type = EAP_TYPE_PEAP;
+	const u8 *addr[2];
+	size_t len[2];
+	u16 tlv_type;
+	u8 binding_nonce[32];
+
+	/* FIX: should binding_nonce be copied from request? */
+	if (os_get_random(binding_nonce, 32))
+		return -1;
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	addr[0] = wpabuf_put(buf, 0);
+	len[0] = 60;
+	addr[1] = &eap_type;
+	len[1] = 1;
+
+	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+	if (data->peap_version >= 2)
+		tlv_type |= EAP_TLV_TYPE_MANDATORY;
+	wpabuf_put_be16(buf, tlv_type);
+	wpabuf_put_be16(buf, 56);
+
+	wpabuf_put_u8(buf, 0); /* Reserved */
+	wpabuf_put_u8(buf, data->peap_version); /* Version */
+	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
+	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
+	wpabuf_put_data(buf, binding_nonce, 32); /* Nonce */
+	mac = wpabuf_put(buf, 20); /* Compound_MAC */
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+		    addr[0], len[0]);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
+		    addr[1], len[1]);
+	hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
+	data->crypto_binding_used = 1;
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_build_result - Build EAP-TLV Result message
+ * @id: EAP identifier for the header
+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV Result message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
+					    struct eap_peap_data *data,
+					    int crypto_tlv_used,
+					    int id, u16 status)
+{
+	struct wpabuf *msg;
+	size_t len;
+
+	if (data->crypto_binding == NO_BINDING)
+		crypto_tlv_used = 0;
+
+	len = 6;
+	if (crypto_tlv_used)
+		len += 60; /* Cryptobinding TLV */
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
+	wpabuf_put_be16(msg, 2); /* Length */
+	wpabuf_put_be16(msg, status); /* Status */
+
+	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+					  struct eap_peap_data *data,
+					  const u8 *crypto_tlv,
+					  size_t crypto_tlv_len)
+{
+	u8 buf[61], mac[SHA1_MAC_LEN];
+	const u8 *pos;
+
+	if (eap_peap_derive_cmk(sm, data) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
+		return -1;
+	}
+
+	if (crypto_tlv_len != 4 + 56) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+			   "length %d", (int) crypto_tlv_len);
+		return -1;
+	}
+
+	pos = crypto_tlv;
+	pos += 4; /* TLV header */
+	if (pos[1] != data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+			   "mismatch (was %d; expected %d)",
+			   pos[1], data->peap_version);
+		return -1;
+	}
+
+	if (pos[3] != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+			   "SubType %d", pos[3]);
+		return -1;
+	}
+	pos += 4;
+	pos += 32; /* Nonce */
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	os_memcpy(buf, crypto_tlv, 60);
+	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+	buf[60] = EAP_TYPE_PEAP;
+	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+			   "cryptobinding TLV");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_process - Process a received EAP-TLV message and generate a response
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: EAP-TLV request to be processed. The caller must have validated that
+ * the buffer is large enough to contain full request (hdr->length bytes) and
+ * that the EAP type is EAP_TYPE_TLV.
+ * @resp: Buffer to return a pointer to the allocated response message. This
+ * field should be initialized to %NULL before the call. The value will be
+ * updated if a response message is generated. The caller is responsible for
+ * freeing the allocated message.
+ * @force_failure: Force negotiation to fail
+ * Returns: 0 on success, -1 on failure
+ */
+static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
+			   struct eap_method_ret *ret,
+			   const struct wpabuf *req, struct wpabuf **resp,
+			   int force_failure)
+{
+	size_t left, tlv_len;
+	const u8 *pos;
+	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+	size_t result_tlv_len = 0, crypto_tlv_len = 0;
+	int tlv_type, mandatory;
+
+	/* Parse TLVs */
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
+	if (pos == NULL)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		tlv_len = WPA_GET_BE16(pos);
+		pos += 2;
+		left -= 4;
+		if (tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+				   "(tlv_len=%lu left=%lu)",
+				   (unsigned long) tlv_len,
+				   (unsigned long) left);
+			return -1;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_RESULT_TLV:
+			result_tlv = pos;
+			result_tlv_len = tlv_len;
+			break;
+		case EAP_TLV_CRYPTO_BINDING_TLV:
+			crypto_tlv = pos;
+			crypto_tlv_len = tlv_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				/* NAK TLV and ignore all TLVs in this packet.
+				 */
+				*resp = eap_tlv_build_nak(eap_get_id(req),
+							  tlv_type);
+				return *resp == NULL ? -1 : 0;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		return -1;
+	}
+
+	/* Process supported TLVs */
+	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+			    crypto_tlv, crypto_tlv_len);
+		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+						   crypto_tlv_len + 4) < 0) {
+			if (result_tlv == NULL)
+				return -1;
+			force_failure = 1;
+		}
+	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+		return -1;
+	}
+
+	if (result_tlv) {
+		int status, resp_status;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+			    result_tlv, result_tlv_len);
+		if (result_tlv_len < 2) {
+			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+				   "(len=%lu)",
+				   (unsigned long) result_tlv_len);
+			return -1;
+		}
+		status = WPA_GET_BE16(result_tlv);
+		if (status == EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+				   "- EAP-TLV/Phase2 Completed");
+			if (force_failure) {
+				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
+					   " - force failed Phase 2");
+				resp_status = EAP_TLV_RESULT_FAILURE;
+				ret->decision = DECISION_FAIL;
+			} else {
+				resp_status = EAP_TLV_RESULT_SUCCESS;
+				ret->decision = DECISION_UNCOND_SUCC;
+			}
+		} else if (status == EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		} else {
+			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+				   "Status %d", status);
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		}
+		ret->methodState = METHOD_DONE;
+
+		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
+					     eap_get_id(req), resp_status);
+	}
+
+	return 0;
+}
+
+
 static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
 {
 	struct wpabuf *e;
@@ -206,7 +624,7 @@
 		break;
 	case EAP_TYPE_TLV:
 		os_memset(&iret, 0, sizeof(iret));
-		if (eap_tlv_process(sm, &iret, req, resp,
+		if (eap_tlv_process(sm, data, &iret, req, resp,
 				    data->phase2_eap_started &&
 				    !data->phase2_eap_success)) {
 			ret->methodState = METHOD_DONE;
@@ -220,6 +638,38 @@
 			data->phase2_success = 1;
 		}
 		break;
+	case EAP_TYPE_EXPANDED:
+#ifdef EAP_TNC
+		if (data->soh) {
+			const u8 *epos;
+			size_t eleft;
+
+			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
+						req, &eleft);
+			if (epos) {
+				struct wpabuf *buf;
+				wpa_printf(MSG_DEBUG,
+					   "EAP-PEAP: SoH EAP Extensions");
+				buf = tncc_process_soh_request(epos, eleft);
+				if (buf) {
+					*resp = eap_msg_alloc(
+						EAP_VENDOR_MICROSOFT, 0x21,
+						wpabuf_len(buf),
+						EAP_CODE_RESPONSE,
+						hdr->identifier);
+					if (*resp == NULL) {
+						ret->methodState = METHOD_DONE;
+						ret->decision = DECISION_FAIL;
+						return -1;
+					}
+					wpabuf_put_buf(*resp, buf);
+					wpabuf_free(buf);
+					break;
+				}
+			}
+		}
+#endif /* EAP_TNC */
+		/* fall through */
 	default:
 		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
 		    data->phase2_type.method == EAP_TYPE_NONE) {
@@ -256,9 +706,11 @@
 				data->phase2_type.method);
 			if (data->phase2_method) {
 				sm->init_phase2 = 1;
+				sm->mschapv2_full_key = 1;
 				data->phase2_priv =
 					data->phase2_method->init(sm);
 				sm->init_phase2 = 0;
+				sm->mschapv2_full_key = 0;
 			}
 		}
 		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
@@ -713,6 +1165,7 @@
 	struct eap_peap_data *data = priv;
 	wpabuf_free(data->pending_phase2_req);
 	data->pending_phase2_req = NULL;
+	data->crypto_binding_used = 0;
 }
 
 
@@ -777,7 +1230,23 @@
 		return NULL;
 
 	*len = EAP_TLS_KEY_LEN;
-	os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+	if (data->crypto_binding_used) {
+		u8 csk[128];
+		/*
+		 * Note: It looks like Microsoft implementation requires null
+		 * termination for this label while the one used for deriving
+		 * IPMK|CMK did not use null termination.
+		 */
+		peap_prfplus(data->peap_version, data->ipmk, 40,
+			     "Session Key Generating Function",
+			     (u8 *) "\00", 1, csk, sizeof(csk));
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+			    key, EAP_TLS_KEY_LEN);
+	} else
+		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
 
 	return key;
 }

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tls_common.c Sat Jun 14 00:26:56 2008
@@ -59,6 +59,8 @@
 	params->engine_id = config->engine_id;
 	params->pin = config->pin;
 	params->key_id = config->key_id;
+	params->cert_id = config->cert_id;
+	params->ca_cert_id = config->ca_cert_id;
 }
 
 
@@ -73,6 +75,11 @@
 	params->dh_file = (char *) config->dh_file2;
 	params->subject_match = (char *) config->subject_match2;
 	params->altsubject_match = (char *) config->altsubject_match2;
+	params->engine_id = config->engine_id;
+	params->pin = config->pin;
+	params->key_id = config->key2_id;
+	params->cert_id = config->cert2_id;
+	params->ca_cert_id = config->ca_cert2_id;
 }
 
 
@@ -820,6 +827,14 @@
 	buf_len = wpabuf_len(in_data);
 	if (data->tls_in_total > buf_len)
 		buf_len = data->tls_in_total;
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf_len += 500;
+	buf_len *= 3;
 	*in_decrypted = wpabuf_alloc(buf_len ? buf_len : 1);
 	if (*in_decrypted == NULL) {
 		eap_peer_tls_reset_input(data);

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_tnc.c Sat Jun 14 00:26:56 2008
@@ -21,8 +21,12 @@
 
 
 struct eap_tnc_data {
-	EapMethodState state;
+	enum { WAIT_START, MSG, WAIT_FRAG_ACK, DONE, FAIL } state;
 	struct tncc_data *tncc;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
 };
 
 
@@ -42,7 +46,8 @@
 	data = os_zalloc(sizeof(*data));
 	if (data == NULL)
 		return NULL;
-	data->state = METHOD_INIT;
+	data->state = WAIT_START;
+	data->fragment_size = 1300;
 	data->tncc = tncc_init();
 	if (data->tncc == NULL) {
 		os_free(data);
@@ -57,8 +62,140 @@
 {
 	struct eap_tnc_data *data = priv;
 
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
 	tncc_deinit(data->tncc);
 	os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data,
+					 struct eap_method_ret *ret, u8 id)
+{
+	struct wpabuf *resp;
+	u8 flags;
+	size_t send_len, plen;
+
+	ret->ignore = FALSE;
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	flags = EAP_TNC_VERSION;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, flags); /* Flags */
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(resp, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(resp, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		data->state = WAIT_FRAG_ACK;
+	}
+
+	return resp;
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+				const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+		data->state = FAIL;
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for "
+		   "%lu bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_tnc_process_fragment(struct eap_tnc_data *data,
+						struct eap_method_ret *ret,
+						u8 id, u8 flags,
+						u32 message_length,
+						const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+			   "fragmented packet");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+				   "message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return eap_tnc_build_frag_ack(id, EAP_CODE_RESPONSE);
 }
 
 
@@ -68,33 +205,93 @@
 {
 	struct eap_tnc_data *data = priv;
 	struct wpabuf *resp;
-	const u8 *pos;
+	const u8 *pos, *end;
 	u8 *rpos, *rpos1, *start;
 	size_t len, rlen;
 	size_t imc_len;
 	char *start_buf, *end_buf;
 	size_t start_len, end_len;
 	int tncs_done = 0;
+	u8 flags, id;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
 
 	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, reqData, &len);
-	if (pos == NULL || len == 0) {
+	if (pos == NULL) {
 		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (pos=%p len=%lu)",
 			   pos, (unsigned long) len);
 		ret->ignore = TRUE;
 		return NULL;
 	}
 
-	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload", pos, len);
-
-	if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+	id = eap_get_id(reqData);
+
+	end = pos + len;
+
+	if (len == 0)
+		flags = 0; /* fragment ack */
+	else
+		flags = *pos++;
+
+	if (len > 0 && (flags & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
 		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
-			   *pos & EAP_TNC_VERSION_MASK);
+			   flags & EAP_TNC_VERSION_MASK);
 		ret->ignore = TRUE;
 		return NULL;
 	}
 
-	if (data->state == METHOD_INIT) {
-		if (!(*pos & EAP_TNC_FLAGS_START)) {
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (len != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload in "
+				   "WAIT_FRAG_ACK state");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+		data->state = MSG;
+		return eap_tnc_build_msg(data, ret, id);
+	}
+
+	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+		
+	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+		return eap_tnc_process_fragment(data, ret, id, flags,
+						message_length, pos,
+						end - pos);
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	if (data->state == WAIT_START) {
+		if (!(flags & EAP_TNC_FLAGS_START)) {
 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
 				   "start flag in the first message");
 			ret->ignore = TRUE;
@@ -103,18 +300,20 @@
 
 		tncc_init_connection(data->tncc);
 
-		data->state = METHOD_MAY_CONT;
+		data->state = MSG;
 	} else {
 		enum tncc_process_res res;
 
-		if (*pos & EAP_TNC_FLAGS_START) {
+		if (flags & EAP_TNC_FLAGS_START) {
 			wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
 				   "flag again");
 			ret->ignore = TRUE;
 			return NULL;
 		}
 
-		res = tncc_process_if_tnccs(data->tncc, pos + 1, len - 1);
+		res = tncc_process_if_tnccs(data->tncc,
+					    wpabuf_head(data->in_buf),
+					    wpabuf_len(data->in_buf));
 		switch (res) {
 		case TNCCS_PROCESS_ERROR:
 			ret->ignore = TRUE;
@@ -142,10 +341,19 @@
 		}
 	}
 
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+
 	ret->ignore = FALSE;
-	ret->methodState = data->state;
+	ret->methodState = METHOD_MAY_CONT;
 	ret->decision = DECISION_UNCOND_SUCC;
 	ret->allowNotifications = TRUE;
+
+	if (data->out_buf) {
+		data->state = MSG;
+		return eap_tnc_build_msg(data, ret, id);
+	}
 
 	if (tncs_done) {
 		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
@@ -195,7 +403,9 @@
 
 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Response", start, rlen);
 
-	return resp;
+	data->out_buf = resp;
+	data->state = MSG;
+	return eap_tnc_build_msg(data, ret, id);
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c Sat Jun 14 00:26:56 2008
@@ -669,7 +669,7 @@
 
 	/* MS-CHAP-Challenge */
 	challenge = eap_ttls_implicit_challenge(
-		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN * 2 + 1);
+		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
 	if (challenge == NULL) {
 		wpabuf_free(msg);
 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
@@ -753,7 +753,8 @@
 			       identity, identity_len);
 
 	/* MS-CHAP-Challenge */
-	challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
+	challenge = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
 	if (challenge == NULL) {
 		wpabuf_free(msg);
 		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
@@ -901,7 +902,8 @@
 			       identity, identity_len);
 
 	/* CHAP-Challenge */
-	challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
+	challenge = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
 	if (challenge == NULL) {
 		wpabuf_free(msg);
 		wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
@@ -991,7 +993,7 @@
 		}
 	}
 
-	switch (data->phase2_type) {
+	switch (phase2_type) {
 	case EAP_TTLS_PHASE2_EAP:
 		res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
 		break;
@@ -1334,6 +1336,15 @@
 	}
 
 	if (parse->mschapv2 == NULL) {
+#ifdef EAP_TNC
+		if (data->phase2_success && parse->eapdata) {
+			/*
+			 * Allow EAP-TNC to be started after successfully
+			 * completed MSCHAPV2.
+			 */
+			return 1;
+		}
+#endif /* EAP_TNC */
 		wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
 			   "received for Phase2 MSCHAPV2");
 		return -1;
@@ -1435,9 +1446,7 @@
 	case EAP_TTLS_PHASE2_MSCHAPV2:
 		res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
 #ifdef EAP_TNC
-		if (res == 1 && parse->eapdata &&
-		    ret->methodState == METHOD_DONE &&
-		    ret->decision == DECISION_UNCOND_SUCC) {
+		if (res == 1 && parse->eapdata && data->phase2_success) {
 			/*
 			 * TNC may be required as the next
 			 * authentication method within the tunnel.

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c Sat Jun 14 00:26:56 2008
@@ -20,6 +20,8 @@
 #include "common.h"
 #include "base64.h"
 #include "tncc.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
 
 
 #ifdef UNICODE
@@ -37,7 +39,7 @@
 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
-"IF_TNCCS#https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
 #define IF_TNCCS_END "\n</TNCCS-Batch>"
 
 /* TNC IF-IMC */
@@ -1202,3 +1204,116 @@
 
 	os_free(tncc);
 }
+
+
+static struct wpabuf * tncc_build_soh(void)
+{
+	struct wpabuf *buf;
+	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
+	u8 correlation_id[24];
+	int ver = 2;
+
+	if (os_get_random(correlation_id, sizeof(correlation_id)))
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
+		    correlation_id, sizeof(correlation_id));
+
+	buf = wpabuf_alloc(200);
+	if (buf == NULL)
+		return NULL;
+
+	/* Vendor-Specific TLV (Microsoft) - SoH */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+	tlv_len = wpabuf_put(buf, 2); /* Length */
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+	wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
+	tlv_len2 = wpabuf_put(buf, 2); /* Length */
+
+	/* SoH Header */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
+	outer_len = wpabuf_put(buf, 2);
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+	wpabuf_put_be16(buf, ver); /* Inner Type */
+	inner_len = wpabuf_put(buf, 2);
+
+	if (ver == 2) {
+		/* SoH Mode Sub-Header */
+		/* Outer Type */
+		wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+		wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
+		wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+		/* Value: */
+		wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+		wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
+		wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
+	}
+
+	/* SSoH TLV */
+	/* System-Health-Id */
+	wpabuf_put_be16(buf, 0x0002); /* Type */
+	wpabuf_put_be16(buf, 4); /* Length */
+	wpabuf_put_be32(buf, 79616);
+	/* Vendor-Specific Attribute */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
+	ssoh_len = wpabuf_put(buf, 2);
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
+	/* TODO: MS-Machine-Inventory */
+	/* TODO: MS-Quarantine-State */
+	/* MS-Packet-Info */
+	wpabuf_put_u8(buf, 0x03);
+	wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
+	/* TODO: MS-MachineName */
+	/* MS-CorrelationId */
+	wpabuf_put_u8(buf, 0x06);
+	wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
+	end = wpabuf_put(buf, 0);
+	WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
+
+	/* TODO: SoHReportEntry TLV (zero or more) */
+
+	/* Update length fields */
+	end = wpabuf_put(buf, 0);
+	WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
+	WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
+	WPA_PUT_BE16(outer_len, end - outer_len - 2);
+	WPA_PUT_BE16(inner_len, end - inner_len - 2);
+
+	return buf;
+}
+
+
+struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len)
+{
+	const u8 *pos;
+
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
+
+	if (len < 12)
+		return NULL;
+
+	/* SoH Request */
+	pos = data;
+
+	/* TLV Type */
+	if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
+		return NULL;
+	pos += 2;
+
+	/* Length */
+	if (WPA_GET_BE16(pos) < 8)
+		return NULL;
+	pos += 2;
+
+	/* Vendor_Id */
+	if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
+		return NULL;
+	pos += 4;
+
+	/* TLV Type */
+	if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
+
+	return tncc_build_soh();
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h Sat Jun 14 00:26:56 2008
@@ -37,4 +37,6 @@
 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
 					    const u8 *msg, size_t len);
 
+struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len);
+
 #endif /* TNCC_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.c Sat Jun 14 00:26:56 2008
@@ -1154,6 +1154,7 @@
 	if (conf->eap_fast_a_id)
 		sm->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
 	sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	sm->tnc = conf->tnc;
 
 	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.h Sat Jun 14 00:26:56 2008
@@ -97,6 +97,7 @@
 	u8 *pac_opaque_encr_key;
 	char *eap_fast_a_id;
 	int eap_sim_aka_result_ind;
+	int tnc;
 };
 
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c Sat Jun 14 00:26:56 2008
@@ -31,6 +31,7 @@
 #define PAC_OPAQUE_TYPE_PAD 0
 #define PAC_OPAQUE_TYPE_KEY 1
 #define PAC_OPAQUE_TYPE_LIFETIME 2
+#define PAC_OPAQUE_TYPE_IDENTITY 3
 
 /* PAC-Key lifetime in seconds (hard limit) */
 #define PAC_KEY_LIFETIME (7 * 24 * 60 * 60)
@@ -62,7 +63,7 @@
 	struct eap_fast_key_block_provisioning *key_block_p;
 
 	u8 simck[EAP_FAST_SIMCK_LEN];
-	u8 cmk[20];
+	u8 cmk[EAP_FAST_CMK_LEN];
 	int simck_idx;
 
 	u8 pac_opaque_encr[16];
@@ -71,6 +72,10 @@
 	int anon_provisioning;
 	int send_new_pac; /* server triggered re-keying of Tunnel PAC */
 	struct wpabuf *pending_phase2_resp;
+	u8 *identity; /* from PAC-Opaque */
+	size_t identity_len;
+	int eap_seq;
+	int tnc_started;
 };
 
 
@@ -125,22 +130,17 @@
 				      u8 *master_secret)
 {
 	struct eap_fast_data *data = ctx;
-#define TLS_RANDOM_LEN 32
-#define TLS_MASTER_SECRET_LEN 48
-	u8 seed[2 * TLS_RANDOM_LEN];
 	const u8 *pac_opaque;
 	size_t pac_opaque_len;
 	u8 *buf, *pos, *end, *pac_key = NULL;
 	os_time_t lifetime = 0;
 	struct os_time now;
+	u8 *identity = NULL;
+	size_t identity_len = 0;
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");
 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket (PAC-Opaque)",
 		    ticket, len);
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: client_random",
-		    client_random, TLS_RANDOM_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
-		    server_random, TLS_RANDOM_LEN);
 
 	if (len < 4 || WPA_GET_BE16(ticket) != PAC_TYPE_PAC_OPAQUE) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Ignore invalid "
@@ -217,6 +217,10 @@
 			}
 			lifetime = WPA_GET_BE32(pos + 2);
 			break;
+		case PAC_OPAQUE_TYPE_IDENTITY:
+			identity = pos + 2;
+			identity_len = pos[1];
+			break;
 		}
 
 		pos += 2 + pos[1];
@@ -229,6 +233,17 @@
 		return -1;
 	}
 
+	if (identity) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: Identity from "
+				  "PAC-Opaque", identity, identity_len);
+		os_free(data->identity);
+		data->identity = os_malloc(identity_len);
+		if (data->identity) {
+			os_memcpy(data->identity, identity, identity_len);
+			data->identity_len = identity_len;
+		}
+	}
+
 	if (os_get_time(&now) < 0 || lifetime <= 0 || now.sec > lifetime) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: PAC-Key not valid anymore "
 			   "(lifetime=%ld now=%ld)", lifetime, now.sec);
@@ -239,72 +254,12 @@
 	if (lifetime - now.sec < PAC_KEY_REFRESH_TIME)
 		data->send_new_pac = 1;
 
-	/*
-	 * RFC 4851, Section 5.1:
-	 * master_secret = T-PRF(PAC-Key, "PAC to master secret label hash", 
-	 *                       server_random + client_random, 48)
-	 */
-	os_memcpy(seed, server_random, TLS_RANDOM_LEN);
-	os_memcpy(seed + TLS_RANDOM_LEN, client_random, TLS_RANDOM_LEN);
-	sha1_t_prf(pac_key, EAP_FAST_PAC_KEY_LEN,
-		   "PAC to master secret label hash",
-		   seed, sizeof(seed), master_secret, TLS_MASTER_SECRET_LEN);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: master_secret",
-			master_secret, TLS_MASTER_SECRET_LEN);
+	eap_fast_derive_master_secret(pac_key, server_random, client_random,
+				      master_secret);
 
 	os_free(buf);
 
 	return 1;
-}
-
-
-static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
-				char *label, size_t len)
-{
-	struct tls_keys keys;
-	u8 *rnd = NULL, *out;
-	int block_size;
-
-	block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
-	if (block_size < 0)
-		return NULL;
-
-	out = os_malloc(block_size + len);
-	if (out == NULL)
-		return NULL;
-
-	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
-			       block_size + len) == 0) {
-		os_memmove(out, out + block_size, len);
-		return out;
-	}
-
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		goto fail;
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	if (rnd == NULL)
-		goto fail;
-
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
-			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, block_size + len))
-		goto fail;
-	os_free(rnd);
-	os_memmove(out, out + block_size, len);
-	return out;
-
-fail:
-	os_free(rnd);
-	os_free(out);
-	return NULL;
 }
 
 
@@ -317,7 +272,7 @@
 	 * Extra key material after TLS key_block: session_key_seed[40]
 	 */
 
-	sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",
 				  EAP_FAST_SKS_LEN);
 	if (sks == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
@@ -343,7 +298,8 @@
 {
 	os_free(data->key_block_p);
 	data->key_block_p = (struct eap_fast_key_block_provisioning *)
-		eap_fast_derive_key(sm, &data->ssl, "key expansion",
+		eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,
+				    "key expansion",
 				    sizeof(*data->key_block_p));
 	if (data->key_block_p == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
@@ -428,8 +384,9 @@
 	os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
 			data->simck, EAP_FAST_SIMCK_LEN);
-	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, 20);
-	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", data->cmk, 20);
+	os_memcpy(data->cmk, imck + EAP_FAST_SIMCK_LEN, EAP_FAST_CMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]",
+			data->cmk, EAP_FAST_CMK_LEN);
 
 	return 0;
 }
@@ -517,6 +474,7 @@
 	os_free(data->srv_id);
 	os_free(data->key_block_p);
 	wpabuf_free(data->pending_phase2_resp);
+	os_free(data->identity);
 	os_free(data);
 }
 
@@ -525,11 +483,10 @@
 					    struct eap_fast_data *data, u8 id)
 {
 	struct wpabuf *req;
-	struct pac_tlv_hdr *a_id;
 	size_t srv_id_len = os_strlen(data->srv_id);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
-			    1 + sizeof(*a_id) + srv_id_len,
+			    1 + sizeof(struct pac_tlv_hdr) + srv_id_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-FAST: Failed to allocate memory for"
@@ -539,10 +496,9 @@
 	}
 
 	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->fast_version);
-	a_id = wpabuf_put(req, sizeof(*a_id));
-	a_id->type = host_to_be16(PAC_TYPE_A_ID);
-	a_id->len = host_to_be16(srv_id_len);
-	wpabuf_put_data(req, data->srv_id, srv_id_len);
+
+	/* RFC 4851, 4.1.1. Authority ID Data */
+	eap_fast_put_tlv(req, PAC_TYPE_A_ID, data->srv_id, srv_id_len);
 
 	eap_fast_state(data, PHASE1);
 
@@ -577,90 +533,6 @@
 }
 
 
-static struct wpabuf * eap_fast_build_req(struct eap_sm *sm,
-					  struct eap_fast_data *data, u8 id)
-{
-	int res;
-	struct wpabuf *req;
-
-	res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_FAST,
-					     data->fast_version, id, &req);
-
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-		if (eap_fast_phase1_done(sm, data) < 0) {
-			os_free(req);
-			return NULL;
-		}
-	}
-
-	if (res == 1)
-		return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
-						data->fast_version);
-	return req;
-}
-
-
-static struct wpabuf * eap_fast_encrypt(struct eap_sm *sm,
-					struct eap_fast_data *data,
-					u8 id, u8 *plain, size_t plain_len)
-{
-	int res;
-	struct wpabuf *buf;
-
-	/* TODO: add support for fragmentation, if needed. This will need to
-	 * add TLS Message Length field, if the frame is fragmented. */
-	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_FAST,
-			    1 + data->ssl.tls_out_limit,
-			    EAP_CODE_REQUEST, id);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, data->fast_version);
-
-	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-				     plain, plain_len, wpabuf_put(buf, 0),
-				     data->ssl.tls_out_limit);
-	if (res < 0) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
-			   "data");
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put(buf, res);
-	eap_update_len(buf);
-
-	return buf;
-}
-
-
-static struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf)
-{
-	struct wpabuf *e;
-	struct eap_tlv_hdr *tlv;
-
-	if (buf == NULL)
-		return NULL;
-
-	/* Encapsulate EAP packet in EAP-Payload TLV */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add EAP-Payload TLV");
-	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
-	if (e == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to allocate memory "
-			   "for TLV encapsulation");
-		wpabuf_free(buf);
-		return NULL;
-	}
-	tlv = wpabuf_put(e, sizeof(*tlv));
-	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
-				     EAP_TLV_EAP_PAYLOAD_TLV);
-	tlv->length = host_to_be16(wpabuf_len(buf));
-	wpabuf_put_buf(e, buf);
-	wpabuf_free(buf);
-	return e;
-}
-
-
 static struct wpabuf * eap_fast_build_phase2_req(struct eap_sm *sm,
 						 struct eap_fast_data *data,
 						 u8 id)
@@ -686,27 +558,40 @@
 {
 	struct wpabuf *buf;
 	struct eap_tlv_result_tlv *result;
-	struct eap_tlv_crypto_binding__tlv *binding;
-	int type;
-
-	buf = wpabuf_alloc(sizeof(*result) + sizeof(*binding));
+	struct eap_tlv_crypto_binding_tlv *binding;
+
+	buf = wpabuf_alloc(2 * sizeof(*result) + sizeof(*binding));
 	if (buf == NULL)
 		return NULL;
 
-	if (data->send_new_pac || data->anon_provisioning) {
-		type = EAP_TLV_INTERMEDIATE_RESULT_TLV;
+	if (data->send_new_pac || data->anon_provisioning ||
+	    data->phase2_method)
 		data->final_result = 0;
-	} else {
-		type = EAP_TLV_RESULT_TLV;
+	else
 		data->final_result = 1;
-	}
-
-	/* Result TLV */
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV (status=SUCCESS)");
-	result = wpabuf_put(buf, sizeof(*result));
-	result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | type);
-	result->length = host_to_be16(2);
-	result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+
+	if (!data->final_result || data->eap_seq > 1) {
+		/* Intermediate-Result */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Intermediate-Result TLV "
+			   "(status=SUCCESS)");
+		result = wpabuf_put(buf, sizeof(*result));
+		result->tlv_type = host_to_be16(
+			EAP_TLV_TYPE_MANDATORY |
+			EAP_TLV_INTERMEDIATE_RESULT_TLV);
+		result->length = host_to_be16(2);
+		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+	}
+
+	if (data->final_result) {
+		/* Result TLV */
+		wpa_printf(MSG_DEBUG, "EAP-FAST: Add Result TLV "
+			   "(status=SUCCESS)");
+		result = wpabuf_put(buf, sizeof(*result));
+		result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+						EAP_TLV_RESULT_TLV);
+		result->length = host_to_be16(2);
+		result->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
+	}
 
 	/* Crypto-Binding TLV */
 	binding = wpabuf_put(buf, sizeof(*binding));
@@ -737,7 +622,8 @@
 	 * Compound-MAC = HMAC-SHA1( CMK, Crypto-Binding TLV )
 	 */
 
-	hmac_sha1(data->cmk, 20, (u8 *) binding, sizeof(*binding),
+	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN,
+		  (u8 *) binding, sizeof(*binding),
 		  binding->compound_mac);
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Add Crypto-Binding TLV: Version %d "
@@ -756,45 +642,80 @@
 static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
 					  struct eap_fast_data *data)
 {
-	u8 pac_key[2 + EAP_FAST_PAC_KEY_LEN + 6];
-	u8 pac_opaque[8 + EAP_FAST_PAC_KEY_LEN + 8];
+	u8 pac_key[EAP_FAST_PAC_KEY_LEN];
+	u8 *pac_buf, *pac_opaque;
 	struct wpabuf *buf;
 	u8 *pos;
-	size_t buf_len, srv_id_len;
+	size_t buf_len, srv_id_len, pac_len;
 	struct eap_tlv_hdr *pac_tlv;
-	struct pac_tlv_hdr *hdr, *pac_info;
+	struct pac_tlv_hdr *pac_info;
 	struct eap_tlv_result_tlv *result;
 	struct os_time now;
 
+	if (os_get_random(pac_key, EAP_FAST_PAC_KEY_LEN) < 0 ||
+	    os_get_time(&now) < 0)
+		return NULL;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
+			pac_key, EAP_FAST_PAC_KEY_LEN);
+
+	pac_len = (2 + EAP_FAST_PAC_KEY_LEN) + (2 + 4) +
+		(2 + sm->identity_len) + 8;
+	pac_buf = os_malloc(pac_len);
+	if (pac_buf == NULL)
+		return NULL;
+
 	srv_id_len = os_strlen(data->srv_id);
 
-	pac_key[0] = PAC_OPAQUE_TYPE_KEY;
-	pac_key[1] = EAP_FAST_PAC_KEY_LEN;
-	if (os_get_random(pac_key + 2, EAP_FAST_PAC_KEY_LEN) < 0)
-		return NULL;
-	if (os_get_time(&now) < 0)
-		return NULL;
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Generated PAC-Key",
-			pac_key + 2, EAP_FAST_PAC_KEY_LEN);
-	pos = pac_key + 2 + EAP_FAST_PAC_KEY_LEN;
+	pos = pac_buf;
+	*pos++ = PAC_OPAQUE_TYPE_KEY;
+	*pos++ = EAP_FAST_PAC_KEY_LEN;
+	os_memcpy(pos, pac_key, EAP_FAST_PAC_KEY_LEN);
+	pos += EAP_FAST_PAC_KEY_LEN;
+
 	*pos++ = PAC_OPAQUE_TYPE_LIFETIME;
 	*pos++ = 4;
 	WPA_PUT_BE32(pos, now.sec + PAC_KEY_LIFETIME);
-
-	if (aes_wrap(data->pac_opaque_encr, sizeof(pac_key) / 8, pac_key,
-		     pac_opaque) < 0)
-		return NULL;
-
+	pos += 4;
+
+	if (sm->identity) {
+		*pos++ = PAC_OPAQUE_TYPE_IDENTITY;
+		*pos++ = sm->identity_len;
+		os_memcpy(pos, sm->identity, sm->identity_len);
+		pos += sm->identity_len;
+	}
+
+	pac_len = pos - pac_buf;
+	if (pac_len % 8) {
+		*pos++ = PAC_OPAQUE_TYPE_PAD;
+		pac_len++;
+	}
+
+	pac_opaque = os_malloc(pac_len + 8);
+	if (pac_opaque == NULL) {
+		os_free(pac_buf);
+		return NULL;
+	}
+	if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf,
+		     pac_opaque) < 0) {
+		os_free(pac_buf);
+		os_free(pac_opaque);
+		return NULL;
+	}
+	os_free(pac_buf);
+
+	pac_len += 8;
 	wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
-		    pac_opaque, sizeof(pac_opaque));
+		    pac_opaque, pac_len);
 
 	buf_len = sizeof(*pac_tlv) +
-		sizeof(*hdr) + EAP_FAST_PAC_KEY_LEN +
-		sizeof(*hdr) + sizeof(pac_opaque) +
+		sizeof(struct pac_tlv_hdr) + EAP_FAST_PAC_KEY_LEN +
+		sizeof(struct pac_tlv_hdr) + pac_len +
 		2 * srv_id_len + 100 + sizeof(*result);
 	buf = wpabuf_alloc(buf_len);
-	if (buf == NULL)
-		return NULL;
+	if (buf == NULL) {
+		os_free(pac_opaque);
+		return NULL;
+	}
 
 	/* PAC TLV */
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV");
@@ -803,45 +724,30 @@
 					 EAP_TLV_PAC_TLV);
 
 	/* PAC-Key */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	hdr->type = host_to_be16(PAC_TYPE_PAC_KEY);
-	hdr->len = host_to_be16(EAP_FAST_PAC_KEY_LEN);
-	wpabuf_put_data(buf, pac_key + 2, EAP_FAST_PAC_KEY_LEN);
+	eap_fast_put_tlv(buf, PAC_TYPE_PAC_KEY, pac_key, EAP_FAST_PAC_KEY_LEN);
 
 	/* PAC-Opaque */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	hdr->type = host_to_be16(PAC_TYPE_PAC_OPAQUE);
-	hdr->len = host_to_be16(sizeof(pac_opaque));
-	wpabuf_put_data(buf, pac_opaque, sizeof(pac_opaque));
+	eap_fast_put_tlv(buf, PAC_TYPE_PAC_OPAQUE, pac_opaque, pac_len);
+	os_free(pac_opaque);
 
 	/* PAC-Info */
 	pac_info = wpabuf_put(buf, sizeof(*pac_info));
 	pac_info->type = host_to_be16(PAC_TYPE_PAC_INFO);
 
 	/* PAC-Lifetime (inside PAC-Info) */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	hdr->type = host_to_be16(PAC_TYPE_CRED_LIFETIME);
-	hdr->len = host_to_be16(4);
+	eap_fast_put_tlv_hdr(buf, PAC_TYPE_CRED_LIFETIME, 4);
 	wpabuf_put_be32(buf, now.sec + PAC_KEY_LIFETIME);
 
 	/* A-ID (inside PAC-Info) */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	hdr->type = host_to_be16(PAC_TYPE_A_ID);
-	hdr->len = host_to_be16(srv_id_len);
-	wpabuf_put_data(buf, data->srv_id, srv_id_len);
+	eap_fast_put_tlv(buf, PAC_TYPE_A_ID, data->srv_id, srv_id_len);
 	
 	/* Note: headers may be misaligned after A-ID */
 
 	/* A-ID-Info (inside PAC-Info) */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_A_ID_INFO);
-	WPA_PUT_BE16((u8 *) &hdr->len, srv_id_len);
-	wpabuf_put_data(buf, data->srv_id, srv_id_len);
+	eap_fast_put_tlv(buf, PAC_TYPE_A_ID_INFO, data->srv_id, srv_id_len);
 
 	/* PAC-Type (inside PAC-Info) */
-	hdr = wpabuf_put(buf, sizeof(*hdr));
-	WPA_PUT_BE16((u8 *) &hdr->type, PAC_TYPE_PAC_TYPE);
-	WPA_PUT_BE16((u8 *) &hdr->len, 2);
+	eap_fast_put_tlv_hdr(buf, PAC_TYPE_PAC_TYPE, 2);
 	wpabuf_put_be16(buf, PAC_TYPE_TUNNEL_PAC);
 
 	/* Update PAC-Info and PAC TLV Length fields */
@@ -864,22 +770,45 @@
 static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
 	struct eap_fast_data *data = priv;
-	struct wpabuf *req;
+	struct wpabuf *req = NULL;
 	struct wpabuf *encr;
 
-	if (data->state == START)
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
+						data->fast_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+						data->fast_version, id);
+	}
+
+	switch (data->state) {
+	case START:
 		return eap_fast_build_start(sm, data, id);
-
-	if (data->state == PHASE1)
-		return eap_fast_build_req(sm, data, id);
-
-	switch (data->state) {
+	case PHASE1:
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			if (eap_fast_phase1_done(sm, data) < 0)
+				return NULL;
+		}
+		break;
 	case PHASE2_ID:
 	case PHASE2_METHOD:
 		req = eap_fast_build_phase2_req(sm, data, id);
 		break;
 	case CRYPTO_BINDING:
 		req = eap_fast_build_crypto_binding(sm, data);
+		if (data->phase2_method) {
+			/*
+			 * Include the start of the next EAP method in the
+			 * sequence in the same message with Crypto-Binding to
+			 * save a round-trip.
+			 */
+			struct wpabuf *eap;
+			eap = eap_fast_build_phase2_req(sm, data, id);
+			req = wpabuf_concat(req, eap);
+			eap_fast_state(data, PHASE2_METHOD);
+		}
 		break;
 	case REQUEST_PAC:
 		req = eap_fast_build_pac(sm, data);
@@ -890,16 +819,21 @@
 		return NULL;
 	}
 
-	if (req == NULL)
-		return NULL;
-
-	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
-			    req);
-	encr = eap_fast_encrypt(sm, data, id, wpabuf_mhead(req),
-				wpabuf_len(req));
-	wpabuf_free(req);
-
-	return encr;
+	if (req) {
+		wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 "
+				    "TLVs", req);
+		encr = eap_server_tls_encrypt(sm, &data->ssl,
+					      wpabuf_mhead(req),
+					      wpabuf_len(req));
+		wpabuf_free(req);
+
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = encr;
+	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
+					data->fast_version, id);
 }
 
 
@@ -971,6 +905,16 @@
 		left = in_len - sizeof(*hdr);
 		wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 type Nak'ed; "
 			    "allowed types", pos + 1, left - 1);
+#ifdef EAP_TNC
+		if (m && m->vendor == EAP_VENDOR_IETF &&
+		    m->method == EAP_TYPE_TNC) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Peer Nak'ed required "
+				   "TNC negotiation");
+			next_type = eap_fast_req_failure(sm, data);
+			eap_fast_phase2_init(sm, data, next_type);
+			return;
+		}
+#endif /* EAP_TNC */
 		eap_sm_process_nak(sm, pos + 1, left - 1);
 		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
 		    sm->user->methods[sm->user_eap_method_index].method !=
@@ -1033,9 +977,18 @@
 		wpa_printf(MSG_DEBUG, "EAP-FAST: try EAP type %d", next_type);
 		break;
 	case PHASE2_METHOD:
+	case CRYPTO_BINDING:
 		eap_fast_update_icmk(sm, data);
 		eap_fast_state(data, CRYPTO_BINDING);
+		data->eap_seq++;
 		next_type = EAP_TYPE_NONE;
+#ifdef EAP_TNC
+		if (sm->tnc && !data->tnc_started) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Initialize TNC");
+			next_type = EAP_TYPE_TNC;
+			data->tnc_started = 1;
+		}
+#endif /* EAP_TNC */
 		break;
 	case FAILURE:
 		break;
@@ -1082,144 +1035,6 @@
 			   "Phase 2 EAP header", hdr->code);
 		break;
 	}
-}
-
-
-struct eap_fast_tlv_parse {
-	u8 *eap_payload_tlv;
-	size_t eap_payload_tlv_len;
-	struct eap_tlv_crypto_binding__tlv *crypto_binding;
-	size_t crypto_binding_len;
-	int iresult;
-	int result;
-	int request_action;
-	u8 *pac;
-	size_t pac_len;
-};
-
-
-static int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
-			      int tlv_type, u8 *pos, int len)
-{
-	switch (tlv_type) {
-	case EAP_TLV_EAP_PAYLOAD_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: EAP-Payload TLV",
-			    pos, len);
-		if (tlv->eap_payload_tlv) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "EAP-Payload TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->eap_payload_tlv = pos;
-		tlv->eap_payload_tlv_len = len;
-		break;
-	case EAP_TLV_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Result TLV", pos, len);
-		if (tlv->result) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Result TLV in the message");
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Result TLV");
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->result = WPA_GET_BE16(pos);
-		if (tlv->result != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->result != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Result %d",
-				   tlv->result);
-			tlv->result = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Result: %s",
-			   tlv->result == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_INTERMEDIATE_RESULT_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Intermediate Result TLV",
-			    pos, len);
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Intermediate-Result TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		if (tlv->iresult) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Intermediate-Result TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->iresult = WPA_GET_BE16(pos);
-		if (tlv->iresult != EAP_TLV_RESULT_SUCCESS &&
-		    tlv->iresult != EAP_TLV_RESULT_FAILURE) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown Intermediate "
-				   "Result %d", tlv->iresult);
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-		}
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Intermediate Result: %s",
-			   tlv->iresult == EAP_TLV_RESULT_SUCCESS ?
-			   "Success" : "Failure");
-		break;
-	case EAP_TLV_CRYPTO_BINDING_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV",
-			    pos, len);
-		if (tlv->crypto_binding) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Crypto-Binding TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->crypto_binding_len = sizeof(struct eap_tlv_hdr) + len;
-		if (tlv->crypto_binding_len < sizeof(*tlv->crypto_binding)) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Crypto-Binding TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->crypto_binding = (struct eap_tlv_crypto_binding__tlv *)
-			(pos - sizeof(struct eap_tlv_hdr));
-		break;
-	case EAP_TLV_REQUEST_ACTION_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Request-Action TLV",
-			    pos, len);
-		if (tlv->request_action) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "Request-Action TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		if (len < 2) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: Too short "
-				   "Request-Action TLV");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			break;
-		}
-		tlv->request_action = WPA_GET_BE16(pos);
-		wpa_printf(MSG_DEBUG, "EAP-FAST: Request-Action: %d",
-			   tlv->request_action);
-		break;
-	case EAP_TLV_PAC_TLV:
-		wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: PAC TLV", pos, len);
-		if (tlv->pac) {
-			wpa_printf(MSG_DEBUG, "EAP-FAST: More than one "
-				   "PAC TLV in the message");
-			tlv->iresult = EAP_TLV_RESULT_FAILURE;
-			return -2;
-		}
-		tlv->pac = pos;
-		tlv->pac_len = len;
-		break;
-	default:
-		/* Unknown TLV */
-		return -1;
-	}
-
-	return 0;
 }
 
 
@@ -1271,10 +1086,10 @@
 
 
 static int eap_fast_validate_crypto_binding(
-	struct eap_fast_data *data, struct eap_tlv_crypto_binding__tlv *b,
+	struct eap_fast_data *data, struct eap_tlv_crypto_binding_tlv *b,
 	size_t bind_len)
 {
-	u8 cmac[20];
+	u8 cmac[SHA1_MAC_LEN];
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: "
 		   "Version %d Received Version %d SubType %d",
@@ -1311,7 +1126,8 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for "
 		    "Compound MAC calculation",
 		    (u8 *) b, bind_len);
-	hmac_sha1(data->cmk, 20, (u8 *) b, bind_len, b->compound_mac);
+	hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len,
+		  b->compound_mac);
 	if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) {
 		wpa_hexdump(MSG_MSGDUMP,
 			    "EAP-FAST: Calculated Compound MAC",
@@ -1388,11 +1204,6 @@
 		return;
 	}
 
-	if (tlv.eap_payload_tlv) {
-		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
-					    tlv.eap_payload_tlv_len);
-	}
-
 	if (check_crypto_binding) {
 		if (tlv.crypto_binding == NULL) {
 			wpa_printf(MSG_DEBUG, "EAP-FAST: No Crypto-Binding "
@@ -1424,7 +1235,11 @@
 		}
 
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Valid Crypto-Binding TLV "
-			   "received - authentication completed successfully");
+			   "received");
+		if (data->final_result) {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Authentication "
+				   "completed successfully");
+		}
 
 		if (data->anon_provisioning ||
 		    (tlv.request_action == EAP_TLV_ACTION_PROCESS_TLV &&
@@ -1437,19 +1252,29 @@
 			wpa_printf(MSG_DEBUG, "EAP-FAST: Server triggered "
 				   "re-keying of Tunnel PAC");
 			eap_fast_state(data, REQUEST_PAC);
-		} else
+		} else if (data->final_result)
 			eap_fast_state(data, SUCCESS);
+	}
+
+	if (tlv.eap_payload_tlv) {
+		eap_fast_process_phase2_eap(sm, data, tlv.eap_payload_tlv,
+					    tlv.eap_payload_tlv_len);
 	}
 }
 
 
 static void eap_fast_process_phase2(struct eap_sm *sm,
 				    struct eap_fast_data *data,
-				    const u8 *in_data, size_t in_len)
+				    struct wpabuf *in_buf)
 {
 	u8 *in_decrypted;
-	int len_decrypted, res;
+	int len_decrypted;
 	size_t buf_len;
+	u8 *in_data;
+	size_t in_len;
+
+	in_data = wpabuf_mhead(in_buf);
+	in_len = wpabuf_len(in_buf);
 
 	wpa_printf(MSG_DEBUG, "EAP-FAST: Received %lu bytes encrypted data for"
 		   " Phase 2", (unsigned long) in_len);
@@ -1465,20 +1290,17 @@
 		return;
 	}
 
-	/* FIX: get rid of const -> non-const typecast */
-	res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &in_data,
-					     &in_len);
-	if (res < 0 || res == 1)
-		return;
-
 	buf_len = in_len;
-	if (data->ssl.tls_in_total > buf_len)
-		buf_len = data->ssl.tls_in_total;
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf_len += 500;
+	buf_len *= 3;
 	in_decrypted = os_malloc(buf_len);
 	if (in_decrypted == NULL) {
-		os_free(data->ssl.tls_in);
-		data->ssl.tls_in = NULL;
-		data->ssl.tls_in_len = 0;
 		wpa_printf(MSG_WARNING, "EAP-FAST: Failed to allocate memory "
 			   "for decryption");
 		return;
@@ -1487,9 +1309,6 @@
 	len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
 					       in_data, in_len,
 					       in_decrypted, buf_len);
-	os_free(data->ssl.tls_in);
-	data->ssl.tls_in = NULL;
-	data->ssl.tls_in_len = 0;
 	if (len_decrypted < 0) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
 			   "data");
@@ -1515,105 +1334,125 @@
 }
 
 
-static void eap_fast_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
+static int eap_fast_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
 {
 	struct eap_fast_data *data = priv;
-	const u8 *pos;
-	u8 flags;
-	size_t left;
-	unsigned int tls_msg_len;
-	int peer_version;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_FAST, respData,
-			       &left);
-	if (pos == NULL || left < 1)
-		return;
-	flags = *pos++;
-	left--;
-	wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
-		   "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
-		   flags);
-	data->peer_version = peer_version = flags & EAP_PEAP_VERSION_MASK;
+
+	data->peer_version = peer_version;
+
 	if (data->force_version >= 0 && peer_version != data->force_version) {
 		wpa_printf(MSG_INFO, "EAP-FAST: peer did not select the forced"
 			   " version (forced=%d peer=%d) - reject",
 			   data->force_version, peer_version);
-		eap_fast_state(data, FAILURE);
-		return;
-	}
+		return -1;
+	}
+
 	if (peer_version < data->fast_version) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: peer ver=%d, own ver=%d; "
 			   "use version %d",
 			   peer_version, data->fast_version, peer_version);
 		data->fast_version = peer_version;
 	}
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
-		if (left < 4) {
-			wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
-				   "length");
-			eap_fast_state(data, FAILURE);
-			return;
-		}
-		tls_msg_len = WPA_GET_BE32(pos);
-		wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
-			   tls_msg_len);
-		if (data->ssl.tls_in_left == 0) {
-			data->ssl.tls_in_total = tls_msg_len;
-			data->ssl.tls_in_left = tls_msg_len;
-			os_free(data->ssl.tls_in);
-			data->ssl.tls_in = NULL;
-			data->ssl.tls_in_len = 0;
-		}
-		pos += 4;
-		left -= 4;
-	}
+
+	return 0;
+}
+
+
+static int eap_fast_process_phase1(struct eap_sm *sm,
+				   struct eap_fast_data *data)
+{
+	if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
+		wpa_printf(MSG_INFO, "EAP-FAST: TLS processing failed");
+		eap_fast_state(data, FAILURE);
+		return -1;
+	}
+
+	if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
+	    wpabuf_len(data->ssl.out_buf) > 0)
+		return 1;
+
+	/*
+	 * Phase 1 was completed with the received message (e.g., when using
+	 * abbreviated handshake), so Phase 2 can be started immediately
+	 * without having to send through an empty message to the peer.
+	 */
+
+	return eap_fast_phase1_done(sm, data);
+}
+
+
+static void eap_fast_process_phase2_start(struct eap_sm *sm,
+					  struct eap_fast_data *data)
+{
+	u8 next_type;
+
+	if (data->identity) {
+		os_free(sm->identity);
+		sm->identity = data->identity;
+		data->identity = NULL;
+		sm->identity_len = data->identity_len;
+		data->identity_len = 0;
+		sm->require_identity_match = 1;
+		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
+			wpa_hexdump_ascii(MSG_DEBUG, "EAP-FAST: "
+					  "Phase2 Identity not found "
+					  "in the user database",
+					  sm->identity, sm->identity_len);
+			next_type = eap_fast_req_failure(sm, data);
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-FAST: Identity already "
+				   "known - skip Phase 2 Identity Request");
+			next_type = sm->user->methods[0].method;
+			sm->user_eap_method_index = 1;
+		}
+
+		eap_fast_state(data, PHASE2_METHOD);
+	} else {
+		eap_fast_state(data, PHASE2_ID);
+		next_type = EAP_TYPE_IDENTITY;
+	}
+
+	eap_fast_phase2_init(sm, data, next_type);
+}
+
+
+static void eap_fast_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_fast_data *data = priv;
 
 	switch (data->state) {
 	case PHASE1:
-		if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
-		    0) {
-			wpa_printf(MSG_INFO, "EAP-FAST: TLS processing "
-				   "failed");
-			eap_fast_state(data, FAILURE);
-		}
-
-		if (!tls_connection_established(sm->ssl_ctx, data->ssl.conn) ||
-		    data->ssl.tls_out_len > 0)
-			break;
-
-		/*
-		 * Phase 1 was completed with the received message (e.g., when
-		 * using abbreviated handshake), so Phase 2 can be started
-		 * immediately without having to send through an empty message
-		 * to the peer.
-		 */
-
-		if (eap_fast_phase1_done(sm, data) < 0)
+		if (eap_fast_process_phase1(sm, data))
 			break;
 
 		/* fall through to PHASE2_START */
 	case PHASE2_START:
-		eap_fast_state(data, PHASE2_ID);
-		eap_fast_phase2_init(sm, data, EAP_TYPE_IDENTITY);
+		eap_fast_process_phase2_start(sm, data);
 		break;
 	case PHASE2_ID:
 	case PHASE2_METHOD:
 	case CRYPTO_BINDING:
 	case REQUEST_PAC:
-		eap_fast_process_phase2(sm, data, pos, left);
+		eap_fast_process_phase2(sm, data, data->ssl.in_buf);
 		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Unexpected state %d in %s",
 			   data->state, __func__);
 		break;
 	}
-
-	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
-		wpa_printf(MSG_INFO, "EAP-FAST: Locally detected fatal error "
-			   "in TLS processing");
+}
+
+
+static void eap_fast_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_fast_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_FAST, eap_fast_process_version,
+				   eap_fast_process_msg) < 0)
 		eap_fast_state(data, FAILURE);
-	}
 }
 
 
@@ -1632,20 +1471,11 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	/*
-	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
-	 * MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
-	 */
-
 	eapKeyData = os_malloc(EAP_FAST_KEY_LEN);
 	if (eapKeyData == NULL)
 		return NULL;
 
-	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-		   "Session Key Generating Function", (u8 *) "", 0,
-		   eapKeyData, EAP_FAST_KEY_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
-			eapKeyData, EAP_FAST_KEY_LEN);
+	eap_fast_derive_eap_msk(data->simck, eapKeyData);
 	*len = EAP_FAST_KEY_LEN;
 
 	return eapKeyData;
@@ -1660,22 +1490,11 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	/*
-	 * RFC 4851, Section 5.4: EAP Master Session Key Genreration
-	 * EMSK = T-PRF(S-IMCK[j],
-	 *        "Extended Session Key Generating Function", 64)
-	 */
-
 	eapKeyData = os_malloc(EAP_EMSK_LEN);
 	if (eapKeyData == NULL)
 		return NULL;
 
-	sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
-		   "Extended Session Key Generating Function",
-		   (u8 *) "", 0, eapKeyData, EAP_EMSK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
-			eapKeyData, EAP_EMSK_LEN);
-
+	eap_fast_derive_eap_emsk(data->simck, eapKeyData);
 	*len = EAP_EMSK_LEN;
 
 	return eapKeyData;

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_gtc.c Sat Jun 14 00:26:56 2008
@@ -134,14 +134,26 @@
 
 		wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Response user",
 				  pos, pos2 - pos);
-		os_free(sm->identity);
-		sm->identity_len = pos2 - pos;
-		sm->identity = os_malloc(sm->identity_len);
-		if (sm->identity == NULL) {
-			data->state = FAILURE;
-			return;
-		}
-		os_memcpy(sm->identity, pos, sm->identity_len);
+		if (sm->identity && sm->require_identity_match &&
+		    (pos2 - pos != (int) sm->identity_len ||
+		     os_memcmp(pos, sm->identity, sm->identity_len))) {
+			wpa_printf(MSG_DEBUG, "EAP-GTC: Phase 2 Identity did "
+				   "not match with required Identity");
+			wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Expected "
+					  "identity",
+					  sm->identity, sm->identity_len);
+			data->state = FAILURE;
+			return;
+		} else {
+			os_free(sm->identity);
+			sm->identity_len = pos2 - pos;
+			sm->identity = os_malloc(sm->identity_len);
+			if (sm->identity == NULL) {
+				data->state = FAILURE;
+				return;
+			}
+			os_memcpy(sm->identity, pos, sm->identity_len);
+		}
 
 		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
 			wpa_hexdump_ascii(MSG_DEBUG, "EAP-GTC: Phase2 "

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h Sat Jun 14 00:26:56 2008
@@ -150,12 +150,13 @@
 	void *eap_method_priv;
 	u8 *identity;
 	size_t identity_len;
+	/* Whether Phase 2 method should validate identity match */
+	int require_identity_match;
 	int lastId; /* Identifier used in the last EAP-Packet */
 	struct eap_user *user;
 	int user_eap_method_index;
 	int init_phase2;
 	void *ssl_ctx;
-	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
 	void *eap_sim_db_priv;
 	Boolean backend_auth;
 	Boolean update_user;
@@ -172,6 +173,7 @@
 	u8 *pac_opaque_encr_key;
 	char *eap_fast_a_id;
 	int eap_sim_aka_result_ind;
+	int tnc;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_ikev2.c Sat Jun 14 00:26:56 2008
@@ -416,6 +416,9 @@
 		else
 			eap_ikev2_state(data, FRAG_ACK);
 		return;
+	} else if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+		data->state = MSG;
 	}
 
 	if (data->in_buf == NULL) {

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c Sat Jun 14 00:26:56 2008
@@ -261,6 +261,13 @@
 	}
 #endif /* EAP_IKEV2 */
 
+#ifdef EAP_TNC
+	if (ret == 0) {
+		int eap_server_tnc_register(void);
+		ret = eap_server_tnc_register();
+	}
+#endif /* EAP_TNC */
+
 	return ret;
 }
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c Sat Jun 14 00:26:56 2008
@@ -15,10 +15,13 @@
 #include "includes.h"
 
 #include "common.h"
+#include "sha1.h"
 #include "eap_i.h"
 #include "eap_tls_common.h"
 #include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
 #include "tls.h"
+#include "tncs.h"
 
 
 /* Maximum supported PEAP version
@@ -36,15 +39,26 @@
 	struct eap_ssl_data ssl;
 	enum {
 		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,
-		PHASE2_METHOD,
+		PHASE2_METHOD, PHASE2_SOH,
 		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE
 	} state;
 
 	int peap_version;
+	int recv_version;
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
 	int force_version;
 	struct wpabuf *pending_phase2_resp;
+	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;
+	int crypto_binding_sent;
+	int crypto_binding_used;
+	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+	u8 binding_nonce[32];
+	u8 ipmk[40];
+	u8 cmk[20];
+	u8 *phase2_key;
+	size_t phase2_key_len;
+	struct wpabuf *soh_response;
 };
 
 
@@ -63,6 +77,8 @@
 		return "PHASE2_ID";
 	case PHASE2_METHOD:
 		return "PHASE2_METHOD";
+	case PHASE2_SOH:
+		return "PHASE2_SOH";
 	case PHASE2_TLV:
 		return "PHASE2_TLV";
 	case SUCCESS_REQ:
@@ -115,43 +131,37 @@
 }
 
 
-static EapType eap_peap_req_success(struct eap_sm *sm,
-				    struct eap_peap_data *data)
+static void eap_peap_req_success(struct eap_sm *sm,
+				 struct eap_peap_data *data)
 {
 	if (data->state == FAILURE || data->state == FAILURE_REQ) {
 		eap_peap_state(data, FAILURE);
-		return EAP_TYPE_NONE;
+		return;
 	}
 
 	if (data->peap_version == 0) {
-		sm->tlv_request = TLV_REQ_SUCCESS;
+		data->tlv_request = TLV_REQ_SUCCESS;
 		eap_peap_state(data, PHASE2_TLV);
-		return EAP_TYPE_TLV;
 	} else {
 		eap_peap_state(data, SUCCESS_REQ);
-		return EAP_TYPE_NONE;
-	}
-}
-
-
-static EapType eap_peap_req_failure(struct eap_sm *sm,
-				    struct eap_peap_data *data)
+	}
+}
+
+
+static void eap_peap_req_failure(struct eap_sm *sm,
+				 struct eap_peap_data *data)
 {
 	if (data->state == FAILURE || data->state == FAILURE_REQ ||
-	    data->state == SUCCESS_REQ ||
-	    (data->phase2_method &&
-	     data->phase2_method->method == EAP_TYPE_TLV)) {
+	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {
 		eap_peap_state(data, FAILURE);
-		return EAP_TYPE_NONE;
+		return;
 	}
 
 	if (data->peap_version == 0) {
-		sm->tlv_request = TLV_REQ_FAILURE;
+		data->tlv_request = TLV_REQ_FAILURE;
 		eap_peap_state(data, PHASE2_TLV);
-		return EAP_TYPE_TLV;
 	} else {
 		eap_peap_state(data, FAILURE_REQ);
-		return EAP_TYPE_NONE;
 	}
 }
 
@@ -172,6 +182,7 @@
 		data->peap_version = data->force_version;
 	}
 	data->state = START;
+	data->crypto_binding = OPTIONAL_BINDING;
 
 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
@@ -192,6 +203,8 @@
 		data->phase2_method->reset(sm, data->phase2_priv);
 	eap_server_tls_ssl_deinit(sm, &data->ssl);
 	wpabuf_free(data->pending_phase2_resp);
+	os_free(data->phase2_key);
+	wpabuf_free(data->soh_response);
 	os_free(data);
 }
 
@@ -218,64 +231,6 @@
 }
 
 
-static struct wpabuf * eap_peap_build_req(struct eap_sm *sm,
-					  struct eap_peap_data *data, u8 id)
-{
-	int res;
-	struct wpabuf *req;
-
-	res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_PEAP,
-					     data->peap_version, id, &req);
-
-	if (data->peap_version < 2 &&
-	    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, starting "
-			   "Phase2");
-		eap_peap_state(data, PHASE2_START);
-	}
-
-	if (res == 1)
-		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
-						data->peap_version);
-	return req;
-}
-
-
-static struct wpabuf * eap_peap_encrypt(struct eap_sm *sm,
-					struct eap_peap_data *data,
-					u8 id, const u8 *plain,
-					size_t plain_len)
-{
-	int res;
-	struct wpabuf *buf;
-
-	/* TODO: add support for fragmentation, if needed. This will need to
-	 * add TLS Message Length field, if the frame is fragmented. */
-	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP,
-			    1 + data->ssl.tls_out_limit,
-			    EAP_CODE_REQUEST, id);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, data->peap_version);
-
-	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-				     plain, plain_len, wpabuf_put(buf, 0),
-				     data->ssl.tls_out_limit);
-	if (res < 0) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
-			   "data");
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put(buf, res);
-	eap_update_len(buf);
-
-	return buf;
-}
-
-
 static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,
 						 struct eap_peap_data *data,
 						 u8 id)
@@ -284,6 +239,10 @@
 	const u8 *req;
 	size_t req_len;
 
+	if (data->phase2_method == NULL || data->phase2_priv == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");
+		return NULL;
+	}
 	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);
 	if (data->peap_version >= 2 && buf)
 		buf = eap_peapv2_tlv_eap_payload(buf);
@@ -301,7 +260,198 @@
 		req_len -= sizeof(struct eap_hdr);
 	}
 
-	encr_req = eap_peap_encrypt(sm, data, id, req, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+
+
+#ifdef EAP_TNC
+static struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,
+						 struct eap_peap_data *data,
+						 u8 id)
+{
+	struct wpabuf *buf1, *buf, *encr_req;
+	const u8 *req;
+	size_t req_len;
+
+	buf1 = tncs_build_soh_request();
+	if (buf1 == NULL)
+		return NULL;
+
+	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),
+			    EAP_CODE_REQUEST, id);
+	if (buf == NULL) {
+		wpabuf_free(buf1);
+		return NULL;
+	}
+	wpabuf_put_buf(buf, buf1);
+	wpabuf_free(buf1);
+
+	req = wpabuf_head(buf);
+	req_len = wpabuf_len(buf);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",
+			req, req_len);
+
+	req += sizeof(struct eap_hdr);
+	req_len -= sizeof(struct eap_hdr);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
+	wpabuf_free(buf);
+
+	return encr_req;
+}
+#endif /* EAP_TNC */
+
+
+static void eap_peap_get_isk(struct eap_peap_data *data,
+			     u8 *isk, size_t isk_len)
+{
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+	if (data->phase2_key == NULL)
+		return;
+
+	key_len = data->phase2_key_len;
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, data->phase2_key, key_len);
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+	u8 *tk;
+	u8 isk[32], imck[60];
+
+	/*
+	 * Tunnel key (TK) is the first 60 octets of the key generated by
+	 * phase 1 of PEAP (based on TLS).
+	 */
+	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",
+				       EAP_TLS_KEY_LEN);
+	if (tk == NULL)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	eap_peap_get_isk(data, isk, sizeof(isk));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+	/*
+	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
+	 * TempKey = First 40 octets of TK
+	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+	 * in the end of the label just before ISK; is that just a typo?)
+	 */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
+		     isk, sizeof(isk), imck, sizeof(imck));
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+			imck, sizeof(imck));
+
+	os_free(tk);
+
+	/* TODO: fast-connect: IPMK|CMK = TK */
+	os_memcpy(data->ipmk, imck, 40);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
+	os_memcpy(data->cmk, imck + 40, 20);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,
+						 struct eap_peap_data *data,
+						 u8 id)
+{
+	struct wpabuf *buf, *encr_req;
+	size_t len;
+
+	len = 6; /* Result TLV */
+	if (data->crypto_binding != NO_BINDING)
+		len += 60; /* Cryptobinding TLV */
+#ifdef EAP_TNC
+	if (data->soh_response)
+		len += wpabuf_len(data->soh_response);
+#endif /* EAP_TNC */
+
+	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+			    EAP_CODE_REQUEST, id);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, 0x80); /* Mandatory */
+	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);
+	/* Length */
+	wpabuf_put_be16(buf, 2);
+	/* Status */
+	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?
+			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);
+
+	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&
+	    data->crypto_binding != NO_BINDING) {
+		u8 *mac;
+		u8 eap_type = EAP_TYPE_PEAP;
+		const u8 *addr[2];
+		size_t len[2];
+		u16 tlv_type;
+
+#ifdef EAP_TNC
+		if (data->soh_response) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "
+				   "Response TLV");
+			wpabuf_put_buf(buf, data->soh_response);
+			wpabuf_free(data->soh_response);
+			data->soh_response = NULL;
+		}
+#endif /* EAP_TNC */
+
+		if (eap_peap_derive_cmk(sm, data) < 0 ||
+		    os_get_random(data->binding_nonce, 32)) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+
+		/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+		addr[0] = wpabuf_put(buf, 0);
+		len[0] = 60;
+		addr[1] = &eap_type;
+		len[1] = 1;
+
+		tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+		if (data->peap_version >= 2)
+			tlv_type |= EAP_TLV_TYPE_MANDATORY;
+		wpabuf_put_be16(buf, tlv_type);
+		wpabuf_put_be16(buf, 56);
+
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_u8(buf, data->peap_version); /* Version */
+		wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */
+		wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */
+		wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
+		mac = wpabuf_put(buf, 20); /* Compound_MAC */
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK",
+			    data->cmk, 20);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+			    addr[0], len[0]);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
+			    addr[1], len[1]);
+		hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",
+			    mac, SHA1_MAC_LEN);
+		data->crypto_binding_sent = 1;
+	}
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",
+			    buf);
+
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf),
+					  wpabuf_len(buf));
 	wpabuf_free(buf);
 
 	return encr_req;
@@ -328,7 +478,7 @@
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
 			(u8 *) hdr, req_len);
 
-	encr_req = eap_peap_encrypt(sm, data, id, (u8 *) hdr, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, (u8 *) hdr, req_len);
 	os_free(hdr);
 
 	return encr_req;
@@ -338,26 +488,67 @@
 static struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
 	struct eap_peap_data *data = priv;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_PEAP,
+						data->peap_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+						data->peap_version, id);
+	}
 
 	switch (data->state) {
 	case START:
 		return eap_peap_build_start(sm, data, id);
 	case PHASE1:
 	case PHASE1_ID2:
-		return eap_peap_build_req(sm, data, id);
+		if (data->peap_version < 2 &&
+		    tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, "
+				   "starting Phase2");
+			eap_peap_state(data, PHASE2_START);
+		}
+		break;
 	case PHASE2_ID:
 	case PHASE2_METHOD:
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_peap_build_phase2_req(sm, data, id);
+		break;
+#ifdef EAP_TNC
+	case PHASE2_SOH:
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_peap_build_phase2_soh(sm, data, id);
+		break;
+#endif /* EAP_TNC */
 	case PHASE2_TLV:
-		return eap_peap_build_phase2_req(sm, data, id);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_peap_build_phase2_tlv(sm, data, id);
+		break;
 	case SUCCESS_REQ:
-		return eap_peap_build_phase2_term(sm, data, id, 1);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+							       1);
+		break;
 	case FAILURE_REQ:
-		return eap_peap_build_phase2_term(sm, data, id, 0);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_peap_build_phase2_term(sm, data, id,
+							       0);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d",
 			   __func__, data->state);
 		return NULL;
 	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP,
+					data->peap_version, id);
 }
 
 
@@ -397,6 +588,306 @@
 }
 
 
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+					  struct eap_peap_data *data,
+					  const u8 *crypto_tlv,
+					  size_t crypto_tlv_len)
+{
+	u8 buf[61], mac[SHA1_MAC_LEN];
+	const u8 *pos;
+
+	if (crypto_tlv_len != 4 + 56) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+			   "length %d", (int) crypto_tlv_len);
+		return -1;
+	}
+
+	pos = crypto_tlv;
+	pos += 4; /* TLV header */
+	if (pos[1] != data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+			   "mismatch (was %d; expected %d)",
+			   pos[1], data->peap_version);
+		return -1;
+	}
+
+	if (pos[3] != 1) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+			   "SubType %d", pos[3]);
+		return -1;
+	}
+	pos += 4;
+	pos += 32; /* Nonce */
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	os_memcpy(buf, crypto_tlv, 60);
+	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+	buf[60] = EAP_TYPE_PEAP;
+	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+			   "cryptobinding TLV");
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data",
+			    buf, 61);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+	return 0;
+}
+
+
+static void eap_peap_process_phase2_tlv(struct eap_sm *sm,
+					struct eap_peap_data *data,
+					struct wpabuf *in_data)
+{
+	const u8 *pos;
+	size_t left;
+	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+	size_t result_tlv_len = 0, crypto_tlv_len = 0;
+	int tlv_type, mandatory, tlv_len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left);
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header");
+		return;
+	}
+
+	/* Parse TLVs */
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = pos[0] & 0x3f;
+		tlv_type = (tlv_type << 8) | pos[1];
+		tlv_len = ((int) pos[2] << 8) | pos[3];
+		pos += 4;
+		left -= 4;
+		if ((size_t) tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+				   "(tlv_len=%d left=%lu)", tlv_len,
+				   (unsigned long) left);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_RESULT_TLV:
+			result_tlv = pos;
+			result_tlv_len = tlv_len;
+			break;
+		case EAP_TLV_CRYPTO_BINDING_TLV:
+			crypto_tlv = pos;
+			crypto_tlv_len = tlv_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	/* Process supported TLVs */
+	if (crypto_tlv && data->crypto_binding_sent) {
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+			    crypto_tlv, crypto_tlv_len);
+		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+						   crypto_tlv_len + 4) < 0) {
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		data->crypto_binding_used = 1;
+	} else if (!crypto_tlv && data->crypto_binding_sent &&
+		   data->crypto_binding == REQUIRE_BINDING) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	if (result_tlv) {
+		int status;
+		const char *requested;
+
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV",
+			    result_tlv, result_tlv_len);
+		if (result_tlv_len < 2) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV "
+				   "(len=%lu)",
+				   (unsigned long) result_tlv_len);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" :
+			"Failure";
+		status = WPA_GET_BE16(result_tlv);
+		if (status == EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success "
+				   "- requested %s", requested);
+			if (data->tlv_request == TLV_REQ_SUCCESS)
+				eap_peap_state(data, SUCCESS);
+			else
+				eap_peap_state(data, FAILURE);
+			
+		} else if (status == EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure "
+				   "- requested %s", requested);
+			eap_peap_state(data, FAILURE);
+		} else {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result "
+				   "Status %d", status);
+			eap_peap_state(data, FAILURE);
+		}
+	}
+}
+
+
+#ifdef EAP_TNC
+static void eap_peap_process_phase2_soh(struct eap_sm *sm,
+					struct eap_peap_data *data,
+					struct wpabuf *in_data)
+{
+	const u8 *pos, *vpos;
+	size_t left;
+	const u8 *soh_tlv = NULL;
+	size_t soh_tlv_len = 0;
+	int tlv_type, mandatory, tlv_len, vtlv_len;
+	u8 next_type;
+	u32 vendor_id;
+
+	pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left);
+	if (pos == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP "
+			   "Extensions Method header - skip TNC");
+		goto auth_method;
+	}
+
+	/* Parse TLVs */
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = pos[0] & 0x3f;
+		tlv_type = (tlv_type << 8) | pos[1];
+		tlv_len = ((int) pos[2] << 8) | pos[3];
+		pos += 4;
+		left -= 4;
+		if ((size_t) tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun "
+				   "(tlv_len=%d left=%lu)", tlv_len,
+				   (unsigned long) left);
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_VENDOR_SPECIFIC_TLV:
+			if (tlv_len < 4) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short "
+					   "vendor specific TLV (len=%d)",
+					   (int) tlv_len);
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+
+			vendor_id = WPA_GET_BE32(pos);
+			if (vendor_id != EAP_VENDOR_MICROSOFT) {
+				if (mandatory) {
+					eap_peap_state(data, FAILURE);
+					return;
+				}
+				break;
+			}
+
+			vpos = pos + 4;
+			mandatory = !!(vpos[0] & 0x80);
+			tlv_type = vpos[0] & 0x3f;
+			tlv_type = (tlv_type << 8) | vpos[1];
+			vtlv_len = ((int) vpos[2] << 8) | vpos[3];
+			vpos += 4;
+			if (vpos + vtlv_len > pos + left) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV "
+					   "underrun");
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+
+			if (tlv_type == 1) {
+				soh_tlv = vpos;
+				soh_tlv_len = vtlv_len;
+				break;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV "
+				   "Type %d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				eap_peap_state(data, FAILURE);
+				return;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+	/* Process supported TLVs */
+	if (soh_tlv) {
+		int failure = 0;
+		wpabuf_free(data->soh_response);
+		data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len,
+						      &failure);
+		if (failure) {
+			eap_peap_state(data, FAILURE);
+			return;
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received");
+		eap_peap_state(data, FAILURE);
+		return;
+	}
+
+auth_method:
+	eap_peap_state(data, PHASE2_METHOD);
+	next_type = sm->user->methods[0].method;
+	sm->user_eap_method_index = 1;
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
+	eap_peap_phase2_init(sm, data, next_type);
+}
+#endif /* EAP_TNC */
+
+
 static void eap_peap_process_phase2_response(struct eap_sm *sm,
 					     struct eap_peap_data *data,
 					     struct wpabuf *in_data)
@@ -405,6 +896,18 @@
 	const struct eap_hdr *hdr;
 	const u8 *pos;
 	size_t left;
+
+	if (data->state == PHASE2_TLV) {
+		eap_peap_process_phase2_tlv(sm, data, in_data);
+		return;
+	}
+
+#ifdef EAP_TNC
+	if (data->state == PHASE2_SOH) {
+		eap_peap_process_phase2_soh(sm, data, in_data);
+		return;
+	}
+#endif /* EAP_TNC */
 
 	if (data->phase2_priv == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not "
@@ -428,7 +931,8 @@
 			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
 				   next_type);
 		} else {
-			next_type = eap_peap_req_failure(sm, data);
+			eap_peap_req_failure(sm, data);
+			next_type = EAP_TYPE_NONE;
 		}
 		eap_peap_phase2_init(sm, data, next_type);
 		return;
@@ -454,22 +958,64 @@
 
 	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed");
-		next_type = eap_peap_req_failure(sm, data);
+		eap_peap_req_failure(sm, data);
+		next_type = EAP_TYPE_NONE;
 		eap_peap_phase2_init(sm, data, next_type);
 		return;
+	}
+
+	os_free(data->phase2_key);
+	if (data->phase2_method->getKey) {
+		data->phase2_key = data->phase2_method->getKey(
+			sm, data->phase2_priv, &data->phase2_key_len);
+		if (data->phase2_key == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey "
+				   "failed");
+			eap_peap_req_failure(sm, data);
+			eap_peap_phase2_init(sm, data, EAP_TYPE_NONE);
+			return;
+		}
+
+		if (data->phase2_key_len == 32 &&
+		    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+		    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+			/*
+			 * Microsoft uses reverse order for MS-MPPE keys in
+			 * EAP-PEAP when compared to EAP-FAST derivation of
+			 * ISK. Swap the keys here to get the correct ISK for
+			 * EAP-PEAPv0 cryptobinding.
+			 */
+			u8 tmp[16];
+			os_memcpy(tmp, data->phase2_key, 16);
+			os_memcpy(data->phase2_key, data->phase2_key + 16, 16);
+			os_memcpy(data->phase2_key + 16, tmp, 16);
+		}
 	}
 
 	switch (data->state) {
 	case PHASE1_ID2:
 	case PHASE2_ID:
+	case PHASE2_SOH:
 		if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) {
 			wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 "
 					  "Identity not found in the user "
 					  "database",
 					  sm->identity, sm->identity_len);
-			next_type = eap_peap_req_failure(sm, data);
+			eap_peap_req_failure(sm, data);
+			next_type = EAP_TYPE_NONE;
 			break;
 		}
+
+#ifdef EAP_TNC
+		if (data->state != PHASE2_SOH && sm->tnc &&
+		    data->peap_version == 0) {
+			eap_peap_state(data, PHASE2_SOH);
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize "
+				   "TNC (NAP SOH)");
+			next_type = EAP_TYPE_NONE;
+			break;
+		}
+#endif /* EAP_TNC */
 
 		eap_peap_state(data, PHASE2_METHOD);
 		next_type = sm->user->methods[0].method;
@@ -477,15 +1023,8 @@
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
 		break;
 	case PHASE2_METHOD:
-		next_type = eap_peap_req_success(sm, data);
-		break;
-	case PHASE2_TLV:
-		if (sm->tlv_request == TLV_REQ_SUCCESS ||
-		    data->state == SUCCESS_REQ) {
-			eap_peap_state(data, SUCCESS);
-		} else {
-			eap_peap_state(data, FAILURE);
-		}
+		eap_peap_req_success(sm, data);
+		next_type = EAP_TYPE_NONE;
 		break;
 	case FAILURE:
 		break;
@@ -502,12 +1041,17 @@
 static void eap_peap_process_phase2(struct eap_sm *sm,
 				    struct eap_peap_data *data,
 				    const struct wpabuf *respData,
-				    const u8 *in_data, size_t in_len)
+				    struct wpabuf *in_buf)
 {
 	struct wpabuf *in_decrypted;
-	int len_decrypted, res;
+	int len_decrypted;
 	const struct eap_hdr *hdr;
 	size_t buf_len, len;
+	u8 *in_data;
+	size_t in_len;
+
+	in_data = wpabuf_mhead(in_buf);
+	in_len = wpabuf_len(in_buf);
 
 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
 		   " Phase 2", (unsigned long) in_len);
@@ -522,20 +1066,17 @@
 		return;
 	}
 
-	/* FIX: get rid of const -> non-const typecast */
-	res = eap_server_tls_data_reassemble(sm, &data->ssl, (u8 **) &in_data,
-					     &in_len);
-	if (res < 0 || res == 1)
-		return;
-
 	buf_len = in_len;
-	if (data->ssl.tls_in_total > buf_len)
-		buf_len = data->ssl.tls_in_total;
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf_len += 500;
+	buf_len *= 3;
 	in_decrypted = wpabuf_alloc(buf_len);
 	if (in_decrypted == NULL) {
-		os_free(data->ssl.tls_in);
-		data->ssl.tls_in = NULL;
-		data->ssl.tls_in_len = 0;
 		wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
 			   "for decryption");
 		return;
@@ -545,9 +1086,6 @@
 					       in_data, in_len,
 					       wpabuf_mhead(in_decrypted),
 					       buf_len);
-	os_free(data->ssl.tls_in);
-	data->ssl.tls_in = NULL;
-	data->ssl.tls_in_len = 0;
 	if (len_decrypted < 0) {
 		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
 			   "data");
@@ -677,7 +1215,6 @@
 {
 	struct wpabuf *buf, *buf2;
 	int res;
-	u8 *tls_out;
 
 	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 "
 		   "payload in the same message");
@@ -720,50 +1257,28 @@
 			buf);
 
 	/* Append TLS data into the pending buffer after the Server Finished */
-	tls_out = os_realloc(data->ssl.tls_out,
-			     data->ssl.tls_out_len + wpabuf_len(buf));
-	if (tls_out == NULL) {
+	if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(buf)) < 0) {
 		wpabuf_free(buf);
 		return -1;
 	}
-
-	os_memcpy(tls_out + data->ssl.tls_out_len, wpabuf_head(buf),
-		  wpabuf_len(buf));
-	data->ssl.tls_out = tls_out;
-	data->ssl.tls_out_len += wpabuf_len(buf);
-
+	wpabuf_put_buf(data->ssl.out_buf, buf);
 	wpabuf_free(buf);
 
 	return 0;
 }
 
 
-static void eap_peap_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
+static int eap_peap_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
 {
 	struct eap_peap_data *data = priv;
-	const u8 *pos;
-	u8 flags;
-	size_t left;
-	unsigned int tls_msg_len;
-	int peer_version;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData,
-			       &left);
-	if (pos == NULL || left < 1)
-		return;
-	flags = *pos++;
-	left--;
-	wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
-		   "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
-		   flags);
-	peer_version = flags & EAP_PEAP_VERSION_MASK;
+
+	data->recv_version = peer_version;
 	if (data->force_version >= 0 && peer_version != data->force_version) {
 		wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced"
 			   " version (forced=%d peer=%d) - reject",
 			   data->force_version, peer_version);
-		eap_peap_state(data, FAILURE);
-		return;
+		return -1;
 	}
 	if (peer_version < data->peap_version) {
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; "
@@ -771,33 +1286,19 @@
 			   peer_version, data->peap_version, peer_version);
 		data->peap_version = peer_version;
 	}
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
-		if (left < 4) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
-				   "length");
-			eap_peap_state(data, FAILURE);
-			return;
-		}
-		tls_msg_len = WPA_GET_BE32(pos);
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
-			   tls_msg_len);
-		if (data->ssl.tls_in_left == 0) {
-			data->ssl.tls_in_total = tls_msg_len;
-			data->ssl.tls_in_left = tls_msg_len;
-			os_free(data->ssl.tls_in);
-			data->ssl.tls_in = NULL;
-			data->ssl.tls_in_len = 0;
-		}
-		pos += 4;
-		left -= 4;
-	}
+
+	return 0;
+}
+
+
+static void eap_peap_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_peap_data *data = priv;
 
 	switch (data->state) {
 	case PHASE1:
-		if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
-		    0) {
-			wpa_printf(MSG_INFO, "EAP-PEAP: TLS processing "
-				   "failed");
+		if (eap_server_tls_phase1(sm, &data->ssl) < 0) {
 			eap_peap_state(data, FAILURE);
 			break;
 		}
@@ -817,8 +1318,9 @@
 	case PHASE1_ID2:
 	case PHASE2_ID:
 	case PHASE2_METHOD:
+	case PHASE2_SOH:
 	case PHASE2_TLV:
-		eap_peap_process_phase2(sm, data, respData, pos, left);
+		eap_peap_process_phase2(sm, data, respData, data->ssl.in_buf);
 		break;
 	case SUCCESS_REQ:
 		eap_peap_state(data, SUCCESS);
@@ -831,12 +1333,17 @@
 			   data->state, __func__);
 		break;
 	}
-
-	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
-		wpa_printf(MSG_INFO, "EAP-PEAP: Locally detected fatal error "
-			   "in TLS processing");
+}
+
+
+static void eap_peap_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_peap_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_PEAP, eap_peap_process_version,
+				   eap_peap_process_msg) < 0)
 		eap_peap_state(data, FAILURE);
-	}
 }
 
 
@@ -854,6 +1361,31 @@
 
 	if (data->state != SUCCESS)
 		return NULL;
+
+	if (data->crypto_binding_used) {
+		u8 csk[128];
+		/*
+		 * Note: It looks like Microsoft implementation requires null
+		 * termination for this label while the one used for deriving
+		 * IPMK|CMK did not use null termination.
+		 */
+		peap_prfplus(data->peap_version, data->ipmk, 40,
+			     "Session Key Generating Function",
+			     (u8 *) "\00", 1, csk, sizeof(csk));
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
+		if (eapKeyData) {
+			os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN);
+			*len = EAP_TLS_KEY_LEN;
+			wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+				    eapKeyData, EAP_TLS_KEY_LEN);
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive "
+				   "key");
+		}
+
+		return eapKeyData;
+	}
 
 	/* TODO: PEAPv1 - different label in some cases */
 	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -29,6 +29,32 @@
 };
 
 
+static const char * eap_tls_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case CONTINUE:
+		return "CONTINUE";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_tls_state(struct eap_tls_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: %s -> %s",
+		   eap_tls_state_txt(data->state),
+		   eap_tls_state_txt(state));
+	data->state = state;
+}
+
+
 static void * eap_tls_init(struct eap_sm *sm)
 {
 	struct eap_tls_data *data;
@@ -68,52 +94,48 @@
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-TLS: Failed to allocate memory for "
 			   "request");
-		data->state = FAILURE;
+		eap_tls_state(data, FAILURE);
 		return NULL;
 	}
 
 	wpabuf_put_u8(req, EAP_TLS_FLAGS_START);
 
-	data->state = CONTINUE;
+	eap_tls_state(data, CONTINUE);
 
 	return req;
 }
 
 
-static struct wpabuf * eap_tls_build_req(struct eap_sm *sm,
-					 struct eap_tls_data *data, u8 id)
-{
-	int res;
-	struct wpabuf *req;
-
-	res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TLS, 0,
-					     id, &req);
-
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-		wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
-		data->state = SUCCESS;
-	}
-
-	if (res == 1)
+static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_tls_data *data = priv;
+
+
+	if (data->ssl.state == FRAG_ACK) {
 		return eap_server_tls_build_ack(id, EAP_TYPE_TLS, 0);
-	return req;
-}
-
-
-static struct wpabuf * eap_tls_buildReq(struct eap_sm *sm, void *priv, u8 id)
-{
-	struct eap_tls_data *data = priv;
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0,
+						id);
+	}
 
 	switch (data->state) {
 	case START:
 		return eap_tls_build_start(sm, data, id);
 	case CONTINUE:
-		return eap_tls_build_req(sm, data, id);
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+			eap_tls_state(data, SUCCESS);
+		}
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TLS: %s - unexpected state %d",
 			   __func__, data->state);
 		return NULL;
 	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TLS, 0, id);
 }
 
 
@@ -133,57 +155,28 @@
 }
 
 
+static void eap_tls_process_msg(struct eap_sm *sm, void *priv,
+				const struct wpabuf *respData)
+{
+	struct eap_tls_data *data = priv;
+	if (data->state == SUCCESS && wpabuf_len(data->ssl.in_buf) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Client acknowledged final TLS "
+			   "handshake message");
+		return;
+	}
+	if (eap_server_tls_phase1(sm, &data->ssl) < 0)
+		eap_tls_state(data, FAILURE);
+}
+
+
 static void eap_tls_process(struct eap_sm *sm, void *priv,
 			    struct wpabuf *respData)
 {
 	struct eap_tls_data *data = priv;
-	const u8 *pos;
-	u8 flags;
-	size_t left;
-	unsigned int tls_msg_len;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLS, respData, &left);
-	if (pos == NULL || left < 1)
-		return; /* Should not happen - frame already validated */
-
-	flags = *pos++;
-	left--;
-	wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
-		   "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
-		   flags);
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
-		if (left < 4) {
-			wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
-				   "length");
-			data->state = FAILURE;
-			return;
-		}
-		tls_msg_len = WPA_GET_BE32(pos);
-		wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
-			   tls_msg_len);
-		if (data->ssl.tls_in_left == 0) {
-			data->ssl.tls_in_total = tls_msg_len;
-			data->ssl.tls_in_left = tls_msg_len;
-			os_free(data->ssl.tls_in);
-			data->ssl.tls_in = NULL;
-			data->ssl.tls_in_len = 0;
-		}
-		pos += 4;
-		left -= 4;
-	}
-
-	if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) < 0) {
-		wpa_printf(MSG_INFO, "EAP-TLS: TLS processing failed");
-		data->state = FAILURE;
-		return;
-	}
-
-	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
-		wpa_printf(MSG_INFO, "EAP-TLS: Locally detected fatal error "
-			   "in TLS processing");
-		data->state = FAILURE;
-		return;
-	}
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_TLS, NULL, eap_tls_process_msg) <
+	    0)
+		eap_tls_state(data, FAILURE);
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -58,8 +58,8 @@
 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 {
 	tls_connection_deinit(sm->ssl_ctx, data->conn);
-	os_free(data->tls_in);
-	os_free(data->tls_out);
+	os_free(data->in_buf);
+	os_free(data->out_buf);
 }
 
 
@@ -106,188 +106,305 @@
 }
 
 
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
-				   struct eap_ssl_data *data,
-				   u8 **in_data, size_t *in_len)
-{
-	u8 *buf;
-
-	if (data->tls_in_left > *in_len || data->tls_in) {
-		if (*in_len == 0) {
-			wpa_printf(MSG_INFO, "SSL: Empty fragment when trying "
-				   "to reassemble");
-			return -1;
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+					 int eap_type, int version, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	wpa_printf(MSG_DEBUG, "SSL: Generating Request");
+	if (data->out_buf == NULL) {
+		wpa_printf(MSG_ERROR, "SSL: out_buf NULL in %s", __func__);
+		return NULL;
+	}
+
+	flags = version;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->tls_out_limit) {
+		send_len = data->tls_out_limit - 1;
+		flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
 		}
-		if (data->tls_in_len + *in_len > 65536) {
-			/* Limit length to avoid rogue peers from causing large
-			 * memory allocations. */
-			os_free(data->tls_in);
-			data->tls_in = NULL;
-			data->tls_in_len = 0;
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		data->state = MSG;
+	} else {
+		wpa_printf(MSG_DEBUG, "SSL: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		data->state = WAIT_FRAG_ACK;
+	}
+
+	return req;
+}
+
+
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
+			    id);
+	if (req == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
+	wpabuf_put_u8(req, version); /* Flags */
+	return req;
+}
+
+
+static int eap_server_tls_process_cont(struct eap_ssl_data *data,
+				       const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "SSL: Fragment overflow");
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_server_tls_process_fragment(struct eap_ssl_data *data,
+					   u8 flags, u32 message_length,
+					   const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & EAP_TLS_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "SSL: No Message Length field in a "
+			   "fragmented packet");
+		return -1;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+
+		/* Limit length to avoid rogue peers from causing large
+		 * memory allocations. */
+		if (message_length > 65536) {
 			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
 				   " over 64 kB)");
 			return -1;
 		}
-		buf = os_realloc(data->tls_in, data->tls_in_len + *in_len);
-		if (buf == NULL) {
-			os_free(data->tls_in);
-			data->tls_in = NULL;
-			data->tls_in_len = 0;
-			wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
-				   "for TLS data");
+
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "SSL: No memory for message");
 			return -1;
 		}
-		os_memcpy(buf + data->tls_in_len, *in_data, *in_len);
-		data->tls_in = buf;
-		data->tls_in_len += *in_len;
-		if (*in_len > data->tls_in_left) {
-			wpa_printf(MSG_INFO, "SSL: more data than TLS message "
-				   "length indicated");
-			data->tls_in_left = 0;
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "SSL: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return 0;
+}
+
+
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+	u8 *next;
+	size_t next_len;
+
+	next = tls_connection_server_handshake(
+		sm->ssl_ctx, data->conn,
+		wpabuf_mhead(data->in_buf),
+		wpabuf_len(data->in_buf),
+		&next_len);
+	if (next == NULL) {
+		wpa_printf(MSG_INFO, "SSL: TLS processing failed");
+		return -1;
+	}
+	if (data->out_buf) {
+		/* This should not happen.. */
+		wpa_printf(MSG_INFO, "SSL: pending tls_out data when "
+			   "processing new message");
+		os_free(data->out_buf);
+		WPA_ASSERT(data->out_buf == NULL);
+	}
+	data->out_buf = wpabuf_alloc_ext_data(next, next_len);
+	if (data->out_buf == NULL) {
+		os_free(next);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int eap_server_tls_reassemble(struct eap_ssl_data *data, u8 flags,
+				     const u8 **pos, size_t *left)
+{
+	unsigned int tls_msg_len = 0;
+	const u8 *end = *pos + *left;
+
+	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+		if (*left < 4) {
+			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+				   "length");
 			return -1;
 		}
-		data->tls_in_left -= *in_len;
-		if (data->tls_in_left > 0) {
-			wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
-				   "data", (unsigned long) data->tls_in_left);
-			return 1;
-		}
-
-		*in_data = data->tls_in;
-		*in_len = data->tls_in_len;
-	} else
-		data->tls_in_left = 0;
-
-	return 0;
-}
-
-
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
-				  const u8 *in_data, size_t in_len)
-{
-	WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
-
-	if (data->tls_out_len == 0) {
-		u8 *_in_data = (u8 *) in_data; /* FIX: get rid of the typecast
-						*/
-		/* No more data to send out - expect to receive more data from
-		 * the peer. */
-		int res = eap_server_tls_data_reassemble(sm, data, &_in_data,
-							 &in_len);
-		if (res < 0 || res == 1) {
-			wpa_printf(MSG_DEBUG, "SSL: data reassembly failed");
-			return res;
-		}
-		/* Full TLS message reassembled - continue handshake processing
-		 */
-		if (data->tls_out) {
-			/* This should not happen.. */
-			wpa_printf(MSG_INFO, "SSL: eap_tls_process_helper - "
-				   "pending tls_out data even though "
-				   "tls_out_len = 0");
-			os_free(data->tls_out);
-			WPA_ASSERT(data->tls_out == NULL);
-		}
-		data->tls_out = tls_connection_server_handshake(
-			sm->ssl_ctx, data->conn, _in_data, in_len,
-			&data->tls_out_len);
-
-		/* Clear reassembled input data (if the buffer was needed). */
-		data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
-		os_free(data->tls_in);
-		data->tls_in = NULL;
-	}
-
-	if (data->tls_out == NULL) {
-		wpa_printf(MSG_DEBUG, "SSL: failed to generate output data");
-		data->tls_out_len = 0;
-		return -1;
-	}
-	if (data->tls_out_len == 0) {
-		/* TLS negotiation should now be complete since all other cases
-		 * needing more that should have been catched above based on
-		 * the TLS Message Length field. */
-		wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
-		os_free(data->tls_out);
-		data->tls_out = NULL;
-
-		if (tls_connection_get_read_alerts(sm->ssl_ctx, data->conn)) {
-			wpa_printf(MSG_DEBUG, "SSL: Remote end sent a fatal "
-				   "alert - abort handshake");
+		tls_msg_len = WPA_GET_BE32(*pos);
+		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
+			   tls_msg_len);
+		*pos += 4;
+		*left -= 4;
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, tls_msg_len);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (*left != 0) {
+			wpa_printf(MSG_DEBUG, "SSL: Unexpected payload in "
+				   "WAIT_FRAG_ACK state");
 			return -1;
 		}
-
+		wpa_printf(MSG_DEBUG, "SSL: Fragment acknowledged");
 		return 1;
 	}
 
-	wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
-		   "%lu bytes)",
-		   (unsigned long) data->tls_out_len - data->tls_out_pos,
-		   (unsigned long) data->tls_out_len);
+	if (data->in_buf &&
+	    eap_server_tls_process_cont(data, *pos, end - *pos) < 0)
+		return -1;
+		
+	if (flags & EAP_TLS_FLAGS_MORE_FRAGMENTS) {
+		if (eap_server_tls_process_fragment(data, flags, tls_msg_len,
+						    *pos, end - *pos) < 0)
+			return -1;
+
+		data->state = FRAG_ACK;
+		return 1;
+	}
+
+	if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "SSL: All fragments received");
+		data->state = MSG;
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&data->tmpbuf, *pos, end - *pos);
+		data->in_buf = &data->tmpbuf;
+	}
 
 	return 0;
 }
 
 
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
-				   struct eap_ssl_data *data,
-				   int eap_type, int peap_version, u8 id,
-				   struct wpabuf **out_data)
-{
-	size_t len;
-	u8 *flags;
-	struct wpabuf *req;
-	int incl_len;
-
-	incl_len = data->tls_out_pos == 0 &&
-		data->tls_out_len > data->tls_out_limit;
-	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
-			    1 + (incl_len ? 4 : 0) + data->tls_out_limit,
-			    EAP_CODE_REQUEST, id);
-	if (req == NULL) {
-		*out_data = NULL;
-		return -1;
-	}
-	flags = wpabuf_put(req, 1);
-	*flags = peap_version;
-	if (incl_len) {
-		*flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
-		wpabuf_put_be32(req, data->tls_out_len);
-	}
-
-	len = data->tls_out_len - data->tls_out_pos;
-	if (len > data->tls_out_limit) {
-		*flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
-		len = data->tls_out_limit;
-		wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
-			   "will follow", (unsigned long) len);
-	}
-	wpabuf_put_data(req, &data->tls_out[data->tls_out_pos], len);
-	data->tls_out_pos += len;
-
-	eap_update_len(req);
-	*out_data = req;
-
-	if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
-		data->tls_out_len = 0;
-		data->tls_out_pos = 0;
-		os_free(data->tls_out);
-		data->tls_out = NULL;
-	}
-
-	return 0;
-}
-
-
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int peap_version)
-{
-	struct wpabuf *req;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_REQUEST,
-			    id);
-	if (req == NULL)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "SSL: Building ACK");
-	wpabuf_put_u8(req, peap_version); /* Flags */
-	return req;
-}
+static void eap_server_tls_free_in_buf(struct eap_ssl_data *data)
+{
+	if (data->in_buf != &data->tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+				       struct eap_ssl_data *data,
+				       const u8 *plain, size_t plain_len)
+{
+	int res;
+	struct wpabuf *buf;
+	size_t buf_len;
+
+	/* reserve some extra room for encryption overhead */
+	buf_len = plain_len + 200;
+	buf = wpabuf_alloc(buf_len);
+	if (buf == NULL)
+		return NULL;
+	res = tls_connection_encrypt(sm->ssl_ctx, data->conn,
+				     plain, plain_len, wpabuf_put(buf, 0),
+				     buf_len);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 data");
+		wpabuf_free(buf);
+		return NULL;
+	}
+
+	wpabuf_put(buf, res);
+
+	return buf;
+}
+
+
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+			   struct wpabuf *respData, void *priv, int eap_type,
+			   int (*proc_version)(struct eap_sm *sm, void *priv,
+					       int peer_version),
+			   void (*proc_msg)(struct eap_sm *sm, void *priv,
+					    const struct wpabuf *respData))
+{
+	const u8 *pos;
+	u8 flags;
+	size_t left;
+	int ret, res = 0;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, respData, &left);
+	if (pos == NULL || left < 1)
+		return 0; /* Should not happen - frame already validated */
+	flags = *pos++;
+	left--;
+	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - Flags 0x%02x",
+		   (unsigned long) wpabuf_len(respData), flags);
+
+	if (proc_version &&
+	    proc_version(sm, priv, flags & EAP_TLS_VERSION_MASK) < 0)
+		return -1;
+
+	ret = eap_server_tls_reassemble(data, flags, &pos, &left);
+	if (ret < 0) {
+		res = -1;
+		goto done;
+	} else if (ret == 1)
+		return 0;
+
+	if (proc_msg)
+		proc_msg(sm, priv, respData);
+
+	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->conn) > 1) {
+		wpa_printf(MSG_INFO, "SSL: Locally detected fatal error in "
+			   "TLS processing");
+		res = -1;
+	}
+
+done:
+	eap_server_tls_free_in_buf(data);
+
+	return res;
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tls_common.h Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,18 +18,17 @@
 struct eap_ssl_data {
 	struct tls_connection *conn;
 
-	u8 *tls_out;
-	size_t tls_out_len;
-	size_t tls_out_pos;
 	size_t tls_out_limit;
-	u8 *tls_in;
-	size_t tls_in_len;
-	size_t tls_in_left;
-	size_t tls_in_total;
 
 	int phase2;
 
 	struct eap_sm *eap;
+
+	enum { MSG, FRAG_ACK, WAIT_FRAG_ACK } state;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	struct wpabuf tmpbuf;
 };
 
 
@@ -37,7 +36,7 @@
 #define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
 #define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
 #define EAP_TLS_FLAGS_START 0x20
-#define EAP_PEAP_VERSION_MASK 0x07
+#define EAP_TLS_VERSION_MASK 0x07
 
  /* could be up to 128 bytes, but only the first 64 bytes are used */
 #define EAP_TLS_KEY_LEN 64
@@ -48,16 +47,18 @@
 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 			       char *label, size_t len);
-int eap_server_tls_data_reassemble(struct eap_sm *sm,
-				   struct eap_ssl_data *data,
-				   u8 **in_data, size_t *in_len);
-int eap_server_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
-				  const u8 *in_data, size_t in_len);
-int eap_server_tls_buildReq_helper(struct eap_sm *sm,
-				   struct eap_ssl_data *data,
-				   int eap_type, int peap_version, u8 id,
-				   struct wpabuf **out_data);
-struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type,
-					 int peap_version);
+struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
+					 int eap_type, int version, u8 id);
+struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
+int eap_server_tls_phase1(struct eap_sm *sm, struct eap_ssl_data *data);
+struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
+				       struct eap_ssl_data *data,
+				       const u8 *plain, size_t plain_len);
+int eap_server_tls_process(struct eap_sm *sm, struct eap_ssl_data *data,
+			   struct wpabuf *respData, void *priv, int eap_type,
+			   int (*proc_version)(struct eap_sm *sm, void *priv,
+					       int peer_version),
+			   void (*proc_msg)(struct eap_sm *sm, void *priv,
+					    const struct wpabuf *respData));
 
 #endif /* EAP_TLS_COMMON_H */

Added: wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_tnc.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,540 @@
+/*
+ * EAP server method: EAP-TNC (Trusted Network Connect)
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "eap_i.h"
+#include "tncs.h"
+
+
+struct eap_tnc_data {
+	enum { START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE,
+	       FAIL } state;
+	enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
+	struct tncs_data *tncs;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	size_t out_used;
+	size_t fragment_size;
+};
+
+
+/* EAP-TNC Flags */
+#define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TNC_FLAGS_START 0x20
+#define EAP_TNC_VERSION_MASK 0x07
+
+#define EAP_TNC_VERSION 1
+
+
+static void * eap_tnc_init(struct eap_sm *sm)
+{
+	struct eap_tnc_data *data;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = START;
+	data->tncs = tncs_init();
+	if (data->tncs == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	data->fragment_size = 1300;
+
+	return data;
+}
+
+
+static void eap_tnc_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	tncs_deinit(data->tncs);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
+					   struct eap_tnc_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
+			    id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
+			   "request");
+		data->state = FAIL;
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
+
+	data->state = CONTINUE;
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
+				     struct eap_tnc_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 *rpos, *rpos1, *start;
+	size_t rlen;
+	char *start_buf, *end_buf;
+	size_t start_len, end_len;
+	size_t imv_len;
+
+	imv_len = tncs_total_send_len(data->tncs);
+
+	start_buf = tncs_if_tnccs_start(data->tncs);
+	if (start_buf == NULL)
+		return NULL;
+	start_len = os_strlen(start_buf);
+	end_buf = tncs_if_tnccs_end();
+	if (end_buf == NULL) {
+		os_free(start_buf);
+		return NULL;
+	}
+	end_len = os_strlen(end_buf);
+
+	rlen = 1 + start_len + imv_len + end_len;
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, rlen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		os_free(start_buf);
+		os_free(end_buf);
+		return NULL;
+	}
+
+	start = wpabuf_put(req, 0);
+	wpabuf_put_u8(req, EAP_TNC_VERSION);
+	wpabuf_put_data(req, start_buf, start_len);
+	os_free(start_buf);
+
+	rpos1 = wpabuf_put(req, 0);
+	rpos = tncs_copy_send_buf(data->tncs, rpos1);
+	wpabuf_put(req, rpos - rpos1);
+
+	wpabuf_put_data(req, end_buf, end_len);
+	os_free(end_buf);
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request", start, rlen);
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
+						    struct eap_tnc_data *data,
+						    u8 id)
+{
+	switch (data->recommendation) {
+	case ALLOW:
+		data->state = DONE;
+		break;
+	case ISOLATE:
+		data->state = FAIL;
+		/* TODO: support assignment to a different VLAN */
+		break;
+	case NO_ACCESS:
+		data->state = FAIL;
+		break;
+	case NO_RECOMMENDATION:
+		data->state = DONE;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
+		return NULL;
+	}
+
+	return eap_tnc_build(sm, data, id);
+}
+
+
+static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 0, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
+			   "for fragment ack");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
+
+	return msg;
+}
+
+
+static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request");
+
+	flags = EAP_TNC_VERSION;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (1 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 1;
+		flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
+		if (data->out_used == 0) {
+			flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
+			send_len -= 4;
+		}
+	}
+
+	plen = 1 + send_len;
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		plen += 4;
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL)
+		return NULL;
+
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
+		wpabuf_put_be32(req, wpabuf_len(data->out_buf));
+
+	wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
+			send_len);
+	data->out_used += send_len;
+
+	if (data->out_used == wpabuf_len(data->out_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		data->state = WAIT_FRAG_ACK;
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_tnc_data *data = priv;
+
+	switch (data->state) {
+	case START:
+		tncs_init_connection(data->tncs);
+		return eap_tnc_build_start(sm, data, id);
+	case CONTINUE:
+		if (data->out_buf == NULL) {
+			data->out_buf = eap_tnc_build(sm, data, id);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+					   "generate message");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		return eap_tnc_build_msg(data, id);
+	case RECOMMENDATION:
+		if (data->out_buf == NULL) {
+			data->out_buf = eap_tnc_build_recommendation(sm, data,
+								     id);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
+					   "generate recommendation message");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		return eap_tnc_build_msg(data, id);
+	case WAIT_FRAG_ACK:
+		return eap_tnc_build_msg(data, id);
+	case FRAG_ACK:
+		return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST);
+	case DONE:
+	case FAIL:
+		return NULL;
+	}
+
+	return NULL;
+}
+
+
+static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_tnc_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
+			       &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
+		return TRUE;
+	}
+
+	if (len == 0 && data->state != WAIT_FRAG_ACK) {
+		wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
+		return TRUE;
+	}
+
+	if (len == 0)
+		return FALSE; /* Fragment ACK does not include flags */
+
+	if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
+			   *pos & EAP_TNC_VERSION_MASK);
+		return TRUE;
+	}
+
+	if (*pos & EAP_TNC_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf)
+{
+	enum tncs_process_res res;
+
+	res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf),
+				    wpabuf_len(inbuf));
+	switch (res) {
+	case TNCCS_RECOMMENDATION_ALLOW:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
+		data->state = RECOMMENDATION;
+		data->recommendation = ALLOW;
+		break;
+	case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
+		data->state = RECOMMENDATION;
+		data->recommendation = NO_RECOMMENDATION;
+		break;
+	case TNCCS_RECOMMENDATION_ISOLATE:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
+		data->state = RECOMMENDATION;
+		data->recommendation = ISOLATE;
+		break;
+	case TNCCS_RECOMMENDATION_NO_ACCESS:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
+		data->state = RECOMMENDATION;
+		data->recommendation = NO_ACCESS;
+		break;
+	case TNCCS_PROCESS_ERROR:
+		wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
+		data->state = FAIL;
+		break;
+	default:
+		break;
+	}
+}
+
+
+static int eap_tnc_process_cont(struct eap_tnc_data *data,
+				const u8 *buf, size_t len)
+{
+	/* Process continuation of a pending message */
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
+		data->state = FAIL;
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_tnc_process_fragment(struct eap_tnc_data *data,
+				    u8 flags, u32 message_length,
+				    const u8 *buf, size_t len)
+{
+	/* Process a fragment that is not the last one of the message */
+	if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
+			   "fragmented packet");
+		return -1;
+	}
+
+	if (data->in_buf == NULL) {
+		/* First fragment of the message */
+		data->in_buf = wpabuf_alloc(message_length);
+		if (data->in_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
+				   "message");
+			return -1;
+		}
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return 0;
+}
+
+
+static void eap_tnc_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_tnc_data *data = priv;
+	const u8 *pos, *end;
+	size_t len;
+	u8 flags;
+	u32 message_length = 0;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
+	if (pos == NULL)
+		return; /* Should not happen; message already verified */
+
+	end = pos + len;
+
+	if (len == 1 && (data->state == DONE || data->state == FAIL)) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
+			   "message");
+		return;
+	}
+
+	if (len == 0) {
+		/* fragment ack */
+		flags = 0;
+	} else
+		flags = *pos++;
+
+	if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
+			data->state = FAIL;
+			return;
+		}
+		message_length = WPA_GET_BE32(pos);
+		pos += 4;
+
+		if (message_length < (u32) (end - pos)) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
+				   "Length (%d; %ld remaining in this msg)",
+				   message_length, (long) (end - pos));
+			data->state = FAIL;
+			return;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
+		   "Message Length %u", flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (len != 0) {
+			wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
+				   "in WAIT_FRAG_ACK state");
+			data->state = FAIL;
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
+		data->state = CONTINUE;
+		return;
+	}
+
+	if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
+		data->state = FAIL;
+		return;
+	}
+		
+	if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
+		if (eap_tnc_process_fragment(data, flags, message_length,
+					     pos, end - pos) < 0)
+			data->state = FAIL;
+		else
+			data->state = FRAG_ACK;
+		return;
+	} else if (data->state == FRAG_ACK) {
+		wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
+		data->state = CONTINUE;
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
+			  wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
+	tncs_process(data, data->in_buf);
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	return data->state == DONE;
+}
+
+
+static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_tnc_data *data = priv;
+	return data->state == DONE;
+}
+
+
+int eap_server_tnc_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tnc_init;
+	eap->reset = eap_tnc_reset;
+	eap->buildReq = eap_tnc_buildReq;
+	eap->check = eap_tnc_check;
+	eap->process = eap_tnc_process;
+	eap->isDone = eap_tnc_isDone;
+	eap->isSuccess = eap_tnc_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_ttls.c Sat Jun 14 00:26:56 2008
@@ -55,6 +55,7 @@
 	u8 mschapv2_ident;
 	int tls_ia_configured;
 	struct wpabuf *pending_phase2_eap_resp;
+	int tnc_started;
 };
 
 
@@ -444,62 +445,6 @@
 }
 
 
-static struct wpabuf * eap_ttls_build_req(struct eap_sm *sm,
-					  struct eap_ttls_data *data, u8 id)
-{
-	int res;
-	struct wpabuf *req;
-
-	res = eap_server_tls_buildReq_helper(sm, &data->ssl, EAP_TYPE_TTLS,
-					     data->ttls_version, id, &req);
-
-	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, starting "
-			   "Phase2");
-		eap_ttls_state(data, PHASE2_START);
-	}
-
-	if (res == 1)
-		return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
-						data->ttls_version);
-	return req;
-}
-
-
-static struct wpabuf * eap_ttls_encrypt(struct eap_sm *sm,
-					struct eap_ttls_data *data,
-					u8 id, u8 *plain, size_t plain_len)
-{
-	int res;
-	struct wpabuf *buf;
-
-	/* TODO: add support for fragmentation, if needed. This will need to
-	 * add TLS Message Length field, if the frame is fragmented. */
-	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-			    1 + data->ssl.tls_out_limit,
-			    EAP_CODE_REQUEST, id);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, data->ttls_version);
-
-	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
-				     plain, plain_len, wpabuf_put(buf, 0),
-				     data->ssl.tls_out_limit);
-	if (res < 0) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
-			   "data");
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put(buf, res);
-	eap_update_len(buf);
-
-	return buf;
-}
-
-
 static struct wpabuf * eap_ttls_build_phase2_eap_req(
 	struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
 {
@@ -527,7 +472,7 @@
 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/EAP: Encrypt encapsulated Phase "
 			"2 data", req, req_len);
 
-	encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
 	wpabuf_free(buf);
 
 	return encr_req;
@@ -535,7 +480,7 @@
 
 
 static struct wpabuf * eap_ttls_build_phase2_mschapv2(
-	struct eap_sm *sm, struct eap_ttls_data *data, u8 id)
+	struct eap_sm *sm, struct eap_ttls_data *data)
 {
 	struct wpabuf *encr_req;
 	u8 *req, *pos, *end;
@@ -569,7 +514,7 @@
 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Encrypting Phase 2 "
 			"data", req, req_len);
 
-	encr_req = eap_ttls_encrypt(sm, data, id, req, req_len);
+	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);
 	os_free(req);
 
 	return encr_req;
@@ -577,19 +522,15 @@
 
 
 static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, u8 id, int final)
+	struct eap_sm *sm, struct eap_ttls_data *data, int final)
 {
 	int len;
 	struct wpabuf *req;
 	const int max_len = 300;
 
-	len = 1 + max_len;
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, len,
-			    EAP_CODE_REQUEST, id);
+	req = wpabuf_alloc(max_len);
 	if (req == NULL)
 		return NULL;
-
-	wpabuf_put_u8(req, data->ttls_version);
 
 	len = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
 						    data->ssl.conn, final,
@@ -600,7 +541,6 @@
 		return NULL;
 	}
 	wpabuf_put(req, len);
-	eap_update_len(req);
 
 	return req;
 }
@@ -609,23 +549,51 @@
 static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
 	struct eap_ttls_data *data = priv;
+
+	if (data->ssl.state == FRAG_ACK) {
+		return eap_server_tls_build_ack(id, EAP_TYPE_TTLS,
+						data->ttls_version);
+	}
+
+	if (data->ssl.state == WAIT_FRAG_ACK) {
+		return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+						data->ttls_version, id);
+	}
 
 	switch (data->state) {
 	case START:
 		return eap_ttls_build_start(sm, data, id);
 	case PHASE1:
-		return eap_ttls_build_req(sm, data, id);
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase1 done, "
+				   "starting Phase2");
+			eap_ttls_state(data, PHASE2_START);
+		}
+		break;
 	case PHASE2_METHOD:
-		return eap_ttls_build_phase2_eap_req(sm, data, id);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_ttls_build_phase2_eap_req(sm, data,
+								  id);
+		break;
 	case PHASE2_MSCHAPV2_RESP:
-		return eap_ttls_build_phase2_mschapv2(sm, data, id);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_ttls_build_phase2_mschapv2(sm, data);
+		break;
 	case PHASE_FINISHED:
-		return eap_ttls_build_phase_finished(sm, data, id, 1);
+		wpabuf_free(data->ssl.out_buf);
+		data->ssl.out_used = 0;
+		data->ssl.out_buf = eap_ttls_build_phase_finished(sm, data, 1);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
 			   __func__, data->state);
 		return NULL;
 	}
+
+	return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_TTLS,
+					data->ttls_version, id);
 }
 
 
@@ -1147,12 +1115,17 @@
 
 static void eap_ttls_process_phase2(struct eap_sm *sm,
 				    struct eap_ttls_data *data,
-				    u8 *in_data, size_t in_len)
+				    struct wpabuf *in_buf)
 {
 	u8 *in_decrypted;
-	int len_decrypted, res;
+	int len_decrypted;
 	struct eap_ttls_avp parse;
 	size_t buf_len;
+	u8 *in_data;
+	size_t in_len;
+
+	in_data = wpabuf_mhead(in_buf);
+	in_len = wpabuf_len(in_buf);
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
 		   " Phase 2", (unsigned long) in_len);
@@ -1168,19 +1141,17 @@
 		return;
 	}
 
-	res = eap_server_tls_data_reassemble(sm, &data->ssl, &in_data,
-					     &in_len);
-	if (res < 0 || res == 1)
-		return;
-
 	buf_len = in_len;
-	if (data->ssl.tls_in_total > buf_len)
-		buf_len = data->ssl.tls_in_total;
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf_len += 500;
+	buf_len *= 3;
 	in_decrypted = os_malloc(buf_len);
 	if (in_decrypted == NULL) {
-		os_free(data->ssl.tls_in);
-		data->ssl.tls_in = NULL;
-		data->ssl.tls_in_len = 0;
 		wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory "
 			   "for decryption");
 		return;
@@ -1189,9 +1160,6 @@
 	len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
 					       in_data, in_len,
 					       in_decrypted, buf_len);
-	os_free(data->ssl.tls_in);
-	data->ssl.tls_in = NULL;
-	data->ssl.tls_in_len = 0;
 	if (len_decrypted < 0) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
 			   "data");
@@ -1243,6 +1211,15 @@
 			goto done;
 		}
 	}
+
+#ifdef EAP_TNC
+	if (data->tnc_started && parse.eap == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: TNC started but no EAP "
+			   "response from peer");
+		eap_ttls_state(data, FAILURE);
+		goto done;
+	}
+#endif /* EAP_TNC */
 
 	if (parse.eap) {
 		eap_ttls_process_phase2_eap(sm, data, parse.eap,
@@ -1276,26 +1253,29 @@
 }
 
 
-static void eap_ttls_process(struct eap_sm *sm, void *priv,
-			     struct wpabuf *respData)
+static void eap_ttls_start_tnc(struct eap_sm *sm, struct eap_ttls_data *data)
+{
+#ifdef EAP_TNC
+	if (!sm->tnc || data->state != SUCCESS || data->tnc_started)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Initialize TNC");
+	if (eap_ttls_phase2_eap_init(sm, data, EAP_TYPE_TNC)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize TNC");
+		eap_ttls_state(data, FAILURE);
+		return;
+	}
+
+	data->tnc_started = 1;
+	eap_ttls_state(data, PHASE2_METHOD);
+#endif /* EAP_TNC */
+}
+
+
+static int eap_ttls_process_version(struct eap_sm *sm, void *priv,
+				    int peer_version)
 {
 	struct eap_ttls_data *data = priv;
-	const u8 *pos;
-	u8 flags;
-	size_t left;
-	unsigned int tls_msg_len;
-	int peer_version;
-
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TTLS, respData,
-			       &left);
-	if (pos == NULL || left < 1)
-		return;
-	flags = *pos++;
-	left--;
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
-		   "Flags 0x%02x", (unsigned long) wpabuf_len(respData),
-		   flags);
-	peer_version = flags & EAP_PEAP_VERSION_MASK;
 	if (peer_version < data->ttls_version) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: peer ver=%d, own ver=%d; "
 			   "use version %d",
@@ -1307,50 +1287,34 @@
 		if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
 			wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
 				   "TLS/IA");
-			eap_ttls_state(data, FAILURE);
-			return;
+			return -1;
 		}
 		data->tls_ia_configured = 1;
 	}
 
-	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
-		if (left < 4) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
-				   "length");
-			eap_ttls_state(data, FAILURE);
-			return;
-		}
-		tls_msg_len = WPA_GET_BE32(pos);
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS Message Length: %d",
-			   tls_msg_len);
-		if (data->ssl.tls_in_left == 0) {
-			data->ssl.tls_in_total = tls_msg_len;
-			data->ssl.tls_in_left = tls_msg_len;
-			os_free(data->ssl.tls_in);
-			data->ssl.tls_in = NULL;
-			data->ssl.tls_in_len = 0;
-		}
-		pos += 4;
-		left -= 4;
-	}
+	return 0;
+}
+
+
+static void eap_ttls_process_msg(struct eap_sm *sm, void *priv,
+				 const struct wpabuf *respData)
+{
+	struct eap_ttls_data *data = priv;
 
 	switch (data->state) {
 	case PHASE1:
-		if (eap_server_tls_process_helper(sm, &data->ssl, pos, left) <
-		    0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: TLS processing "
-				   "failed");
+		if (eap_server_tls_phase1(sm, &data->ssl) < 0)
 			eap_ttls_state(data, FAILURE);
-		}
 		break;
 	case PHASE2_START:
 	case PHASE2_METHOD:
 	case PHASE_FINISHED:
-		/* FIX: get rid of const->non-const typecast */
-		eap_ttls_process_phase2(sm, data, (u8 *) pos, left);
+		eap_ttls_process_phase2(sm, data, data->ssl.in_buf);
+		eap_ttls_start_tnc(sm, data);
 		break;
 	case PHASE2_MSCHAPV2_RESP:
-		if (data->mschapv2_resp_ok && left == 0) {
+		if (data->mschapv2_resp_ok && wpabuf_len(data->ssl.in_buf) ==
+		    0) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged response");
 			eap_ttls_state(data, data->ttls_version > 0 ?
@@ -1363,21 +1327,28 @@
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Unexpected "
 				   "frame from peer (payload len %lu, "
 				   "expected empty frame)",
-				   (unsigned long) left);
+				   (unsigned long)
+				   wpabuf_len(data->ssl.in_buf));
 			eap_ttls_state(data, FAILURE);
 		}
+		eap_ttls_start_tnc(sm, data);
 		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected state %d in %s",
 			   data->state, __func__);
 		break;
 	}
-
-	if (tls_connection_get_write_alerts(sm->ssl_ctx, data->ssl.conn) > 1) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Locally detected fatal error "
-			   "in TLS processing");
-		eap_ttls_state(data, FAILURE);
-	}
+}
+
+
+static void eap_ttls_process(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	struct eap_ttls_data *data = priv;
+	if (eap_server_tls_process(sm, &data->ssl, respData, data,
+				   EAP_TYPE_TTLS, eap_ttls_process_version,
+				   eap_ttls_process_msg) < 0)
+		eap_ttls_state(data, FAILURE);
 }
 
 

Added: wpasupplicant/branches/upstream/current/src/eap_server/tncs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/tncs.c?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/tncs.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/tncs.c Sat Jun 14 00:26:56 2008
@@ -1,0 +1,1272 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+#include "base64.h"
+#include "tncs.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_defs.h"
+
+
+/* TODO: TNCS must be thread-safe; review the code and add locking etc. if
+ * needed.. */
+
+#define TNC_CONFIG_FILE "/etc/tnc_config"
+#define IF_TNCCS_START \
+"<?xml version=\"1.0\"?>\n" \
+"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
+"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
+"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
+"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
+#define IF_TNCCS_END "\n</TNCCS-Batch>"
+
+/* TNC IF-IMV */
+
+typedef unsigned long TNC_UInt32;
+typedef unsigned char *TNC_BufferReference;
+
+typedef TNC_UInt32 TNC_IMVID;
+typedef TNC_UInt32 TNC_ConnectionID;
+typedef TNC_UInt32 TNC_ConnectionState;
+typedef TNC_UInt32 TNC_RetryReason;
+typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
+typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
+typedef TNC_UInt32 TNC_MessageType;
+typedef TNC_MessageType *TNC_MessageTypeList;
+typedef TNC_UInt32 TNC_VendorID;
+typedef TNC_UInt32 TNC_Subtype;
+typedef TNC_UInt32 TNC_Version;
+typedef TNC_UInt32 TNC_Result;
+typedef TNC_UInt32 TNC_AttributeID;
+
+typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
+	TNC_IMVID imvID,
+	char *functionName,
+	void **pOutfunctionPointer);
+
+#define TNC_RESULT_SUCCESS 0
+#define TNC_RESULT_NOT_INITIALIZED 1
+#define TNC_RESULT_ALREADY_INITIALIZED 2
+#define TNC_RESULT_NO_COMMON_VERSION 3
+#define TNC_RESULT_CANT_RETRY 4
+#define TNC_RESULT_WONT_RETRY 5
+#define TNC_RESULT_INVALID_PARAMETER 6
+#define TNC_RESULT_CANT_RESPOND 7
+#define TNC_RESULT_ILLEGAL_OPERATION 8
+#define TNC_RESULT_OTHER 9
+#define TNC_RESULT_FATAL 10
+
+#define TNC_CONNECTION_STATE_CREATE 0
+#define TNC_CONNECTION_STATE_HANDSHAKE 1
+#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
+#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
+#define TNC_CONNECTION_STATE_ACCESS_NONE 4
+#define TNC_CONNECTION_STATE_DELETE 5
+
+#define TNC_IFIMV_VERSION_1 1
+
+#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
+#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
+
+/* TNCC-TNCS Message Types */
+#define TNC_TNCCS_RECOMMENDATION		0x00000001
+#define TNC_TNCCS_ERROR				0x00000002
+#define TNC_TNCCS_PREFERREDLANGUAGE		0x00000003
+#define TNC_TNCCS_REASONSTRINGS			0x00000004
+
+/* Possible TNC_IMV_Action_Recommendation values: */
+enum IMV_Action_Recommendation {
+	TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
+	TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
+	TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+	TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+/* Possible TNC_IMV_Evaluation_Result values: */
+enum IMV_Evaluation_Result {
+	TNC_IMV_EVALUATION_RESULT_COMPLIANT,
+	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
+	TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
+	TNC_IMV_EVALUATION_RESULT_ERROR,
+	TNC_IMV_EVALUATION_RESULT_DONT_KNOW
+};
+
+struct tnc_if_imv {
+	struct tnc_if_imv *next;
+	char *name;
+	char *path;
+	void *dlhandle; /* from dlopen() */
+	TNC_IMVID imvID;
+	TNC_MessageTypeList supported_types;
+	size_t num_supported_types;
+
+	/* Functions implemented by IMVs (with TNC_IMV_ prefix) */
+	TNC_Result (*Initialize)(
+		TNC_IMVID imvID,
+		TNC_Version minVersion,
+		TNC_Version maxVersion,
+		TNC_Version *pOutActualVersion);
+	TNC_Result (*NotifyConnectionChange)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID,
+		TNC_ConnectionState newState);
+	TNC_Result (*ReceiveMessage)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID,
+		TNC_BufferReference message,
+		TNC_UInt32 messageLength,
+		TNC_MessageType messageType);
+	TNC_Result (*SolicitRecommendation)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*BatchEnding)(
+		TNC_IMVID imvID,
+		TNC_ConnectionID connectionID);
+	TNC_Result (*Terminate)(TNC_IMVID imvID);
+	TNC_Result (*ProvideBindFunction)(
+		TNC_IMVID imvID,
+		TNC_TNCS_BindFunctionPointer bindFunction);
+};
+
+
+#define TNC_MAX_IMV_ID 10
+
+struct tncs_data {
+	struct tncs_data *next;
+	struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
+	TNC_ConnectionID connectionID;
+	unsigned int last_batchid;
+	enum IMV_Action_Recommendation recommendation;
+	int done;
+
+	struct conn_imv {
+		u8 *imv_send;
+		size_t imv_send_len;
+		enum IMV_Action_Recommendation recommendation;
+		int recommendation_set;
+	} imv_data[TNC_MAX_IMV_ID];
+
+	char *tncs_message;
+};
+
+
+struct tncs_global {
+	struct tnc_if_imv *imv;
+	TNC_ConnectionID next_conn_id;
+	struct tncs_data *connections;
+};
+
+static struct tncs_global *tncs_global_data = NULL;
+
+
+static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
+{
+	struct tnc_if_imv *imv;
+
+	if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
+		return NULL;
+	imv = tncs_global_data->imv;
+	while (imv) {
+		if (imv->imvID == imvID)
+			return imv;
+		imv = imv->next;
+	}
+	return NULL;
+}
+
+
+static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
+{
+	struct tncs_data *tncs;
+
+	if (tncs_global_data == NULL)
+		return NULL;
+
+	tncs = tncs_global_data->connections;
+	while (tncs) {
+		if (tncs->connectionID == connectionID)
+			return tncs;
+		tncs = tncs->next;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
+		   (unsigned long) connectionID);
+
+	return NULL;
+}
+
+
+/* TNCS functions that IMVs can call */
+TNC_Result TNC_TNCS_ReportMessageTypes(
+	TNC_IMVID imvID,
+	TNC_MessageTypeList supportedTypes,
+	TNC_UInt32 typeCount)
+{
+	TNC_UInt32 i;
+	struct tnc_if_imv *imv;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
+		   "typeCount=%lu)",
+		   (unsigned long) imvID, (unsigned long) typeCount);
+
+	for (i = 0; i < typeCount; i++) {
+		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
+			   i, supportedTypes[i]);
+	}
+
+	imv = tncs_get_imv(imvID);
+	if (imv == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+	os_free(imv->supported_types);
+	imv->supported_types =
+		os_malloc(typeCount * sizeof(TNC_MessageTypeList));
+	if (imv->supported_types == NULL)
+		return TNC_RESULT_FATAL;
+	os_memcpy(imv->supported_types, supportedTypes,
+		  typeCount * sizeof(TNC_MessageTypeList));
+	imv->num_supported_types = typeCount;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SendMessage(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_BufferReference message,
+	TNC_UInt32 messageLength,
+	TNC_MessageType messageType)
+{
+	struct tncs_data *tncs;
+	unsigned char *b64;
+	size_t b64len;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
+		   "connectionID=%lu messageType=%lu)",
+		   imvID, connectionID, messageType);
+	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
+			  message, messageLength);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs = tncs_get_conn(connectionID);
+	if (tncs == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	b64 = base64_encode(message, messageLength, &b64len);
+	if (b64 == NULL)
+		return TNC_RESULT_FATAL;
+
+	os_free(tncs->imv_data[imvID].imv_send);
+	tncs->imv_data[imvID].imv_send_len = 0;
+	tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
+	if (tncs->imv_data[imvID].imv_send == NULL) {
+		os_free(b64);
+		return TNC_RESULT_OTHER;
+	}
+
+	tncs->imv_data[imvID].imv_send_len =
+		os_snprintf((char *) tncs->imv_data[imvID].imv_send,
+			    b64len + 100,
+			    "<IMC-IMV-Message><Type>%08X</Type>"
+			    "<Base64>%s</Base64></IMC-IMV-Message>",
+			    (unsigned int) messageType, b64);
+
+	os_free(b64);
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_RequestHandshakeRetry(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_RetryReason reason)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_ProvideRecommendation(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_IMV_Action_Recommendation recommendation,
+	TNC_IMV_Evaluation_Result evaluation)
+{
+	struct tncs_data *tncs;
+
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
+		   "connectionID=%lu recommendation=%lu evaluation=%lu)",
+		   (unsigned long) imvID, (unsigned long) connectionID,
+		   (unsigned long) recommendation, (unsigned long) evaluation);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs = tncs_get_conn(connectionID);
+	if (tncs == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	tncs->imv_data[imvID].recommendation = recommendation;
+	tncs->imv_data[imvID].recommendation_set = 1;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_GetAttribute(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_AttributeID attribureID,
+	TNC_UInt32 bufferLength,
+	TNC_BufferReference buffer,
+	TNC_UInt32 *pOutValueLength)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_SetAttribute(
+	TNC_IMVID imvID,
+	TNC_ConnectionID connectionID,
+	TNC_AttributeID attribureID,
+	TNC_UInt32 bufferLength,
+	TNC_BufferReference buffer)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
+	/* TODO */
+	return TNC_RESULT_SUCCESS;
+}
+
+
+TNC_Result TNC_TNCS_BindFunction(
+	TNC_IMVID imvID,
+	char *functionName,
+	void **pOutFunctionPointer)
+{
+	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
+		   "functionName='%s')", (unsigned long) imvID, functionName);
+
+	if (tncs_get_imv(imvID) == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (pOutFunctionPointer == NULL)
+		return TNC_RESULT_INVALID_PARAMETER;
+
+	if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
+		*pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
+	else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
+		*pOutFunctionPointer = TNC_TNCS_SendMessage;
+	else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
+		 0)
+		*pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
+	else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
+		 0)
+		*pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
+	else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
+		*pOutFunctionPointer = TNC_TNCS_GetAttribute;
+	else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
+		*pOutFunctionPointer = TNC_TNCS_SetAttribute;
+	else
+		*pOutFunctionPointer = NULL;
+
+	return TNC_RESULT_SUCCESS;
+}
+
+
+static void * tncs_get_sym(void *handle, char *func)
+{
+	void *fptr;
+
+	fptr = dlsym(handle, func);
+
+	return fptr;
+}
+
+
+static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
+{
+	void *handle = imv->dlhandle;
+
+	/* Mandatory IMV functions */
+	imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
+	if (imv->Initialize == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_Initialize");
+		return -1;
+	}
+
+	imv->SolicitRecommendation = tncs_get_sym(
+		handle, "TNC_IMV_SolicitRecommendation");
+	if (imv->SolicitRecommendation == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_SolicitRecommendation");
+		return -1;
+	}
+
+	imv->ProvideBindFunction =
+		tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
+	if (imv->ProvideBindFunction == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: IMV does not export "
+			   "TNC_IMV_ProvideBindFunction");
+		return -1;
+	}
+
+	/* Optional IMV functions */
+	imv->NotifyConnectionChange =
+		tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
+	imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
+	imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
+	imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
+
+	return 0;
+}
+
+
+static int tncs_imv_initialize(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+	TNC_Version imv_ver;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
+		   imv->name);
+	res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
+			      TNC_IFIMV_VERSION_1, &imv_ver);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
+		   (unsigned long) res, (unsigned long) imv_ver);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_terminate(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+
+	if (imv->Terminate == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
+		   imv->name);
+	res = imv->Terminate(imv->imvID);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
+{
+	TNC_Result res;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
+		   "IMV '%s'", imv->name);
+	res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
+					     TNC_ConnectionID conn,
+					     TNC_ConnectionState state)
+{
+	TNC_Result res;
+
+	if (imv->NotifyConnectionChange == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
+		   " for IMV '%s'", (int) state, imv->name);
+	res = imv->NotifyConnectionChange(imv->imvID, conn, state);
+	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
+		   (unsigned long) res);
+
+	return res == TNC_RESULT_SUCCESS ? 0 : -1;
+}
+
+
+static int tncs_load_imv(struct tnc_if_imv *imv)
+{
+	if (imv->path == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
+		   imv->name, imv->path);
+	imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
+	if (imv->dlhandle == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
+			   imv->name, imv->path, dlerror());
+		return -1;
+	}
+
+	if (tncs_imv_resolve_funcs(imv) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
+		return -1;
+	}
+
+	if (tncs_imv_initialize(imv) < 0 ||
+	    tncs_imv_provide_bind_function(imv) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void tncs_free_imv(struct tnc_if_imv *imv)
+{
+	os_free(imv->name);
+	os_free(imv->path);
+	os_free(imv->supported_types);
+}
+
+static void tncs_unload_imv(struct tnc_if_imv *imv)
+{
+	tncs_imv_terminate(imv);
+
+	if (imv->dlhandle)
+		dlclose(imv->dlhandle);
+
+	tncs_free_imv(imv);
+}
+
+
+static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
+{
+	size_t i;
+	unsigned int vendor, subtype;
+
+	if (imv == NULL || imv->supported_types == NULL)
+		return 0;
+
+	vendor = type >> 8;
+	subtype = type & 0xff;
+
+	for (i = 0; i < imv->num_supported_types; i++) {
+		unsigned int svendor, ssubtype;
+		svendor = imv->supported_types[i] >> 8;
+		ssubtype = imv->supported_types[i] & 0xff;
+		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
+		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
+			      const u8 *msg, size_t len)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (imv->ReceiveMessage == NULL ||
+		    !tncs_supported_type(imv, type))
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
+			   imv->name);
+		res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
+					  (TNC_BufferReference) msg, len,
+					  type);
+		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+static void tncs_batch_ending(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (imv->BatchEnding == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
+			   imv->name);
+		res = imv->BatchEnding(imv->imvID, tncs->connectionID);
+		wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+static void tncs_solicit_recommendation(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	TNC_Result res;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		if (tncs->imv_data[imv->imvID].recommendation_set)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
+			   "IMV '%s'", imv->name);
+		res = imv->SolicitRecommendation(imv->imvID,
+						 tncs->connectionID);
+		wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
+			   (unsigned long) res);
+	}
+}
+
+
+void tncs_init_connection(struct tncs_data *tncs)
+{
+	struct tnc_if_imv *imv;
+	int i;
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		tncs_imv_notify_connection_change(
+			imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
+		tncs_imv_notify_connection_change(
+			imv, tncs->connectionID,
+			TNC_CONNECTION_STATE_HANDSHAKE);
+	}
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+		os_free(tncs->imv_data[i].imv_send);
+		tncs->imv_data[i].imv_send = NULL;
+		tncs->imv_data[i].imv_send_len = 0;
+	}
+}
+
+
+size_t tncs_total_send_len(struct tncs_data *tncs)
+{
+	int i;
+	size_t len = 0;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++)
+		len += tncs->imv_data[i].imv_send_len;
+	if (tncs->tncs_message)
+		len += os_strlen(tncs->tncs_message);
+	return len;
+}
+
+
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
+{
+	int i;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++) {
+		if (tncs->imv_data[i].imv_send == NULL)
+			continue;
+
+		os_memcpy(pos, tncs->imv_data[i].imv_send,
+			  tncs->imv_data[i].imv_send_len);
+		pos += tncs->imv_data[i].imv_send_len;
+		os_free(tncs->imv_data[i].imv_send);
+		tncs->imv_data[i].imv_send = NULL;
+		tncs->imv_data[i].imv_send_len = 0;
+	}
+
+	if (tncs->tncs_message) {
+		size_t len = os_strlen(tncs->tncs_message);
+		os_memcpy(pos, tncs->tncs_message, len);
+		pos += len;
+		os_free(tncs->tncs_message);
+		tncs->tncs_message = NULL;
+	}
+
+	return pos;
+}
+
+
+char * tncs_if_tnccs_start(struct tncs_data *tncs)
+{
+	char *buf = os_malloc(1000);
+	if (buf == NULL)
+		return NULL;
+	tncs->last_batchid++;
+	os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
+	return buf;
+}
+
+
+char * tncs_if_tnccs_end(void)
+{
+	char *buf = os_malloc(100);
+	if (buf == NULL)
+		return NULL;
+	os_snprintf(buf, 100, IF_TNCCS_END);
+	return buf;
+}
+
+
+static int tncs_get_type(char *start, unsigned int *type)
+{
+	char *pos = os_strstr(start, "<Type>");
+	if (pos == NULL)
+		return -1;
+	pos += 6;
+	*type = strtoul(pos, NULL, 16);
+	return 0;
+}
+
+
+static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
+{
+	char *pos, *pos2;
+	unsigned char *decoded;
+
+	pos = os_strstr(start, "<Base64>");
+	if (pos == NULL)
+		return NULL;
+
+	pos += 8;
+	pos2 = os_strstr(pos, "</Base64>");
+	if (pos2 == NULL)
+		return NULL;
+	*pos2 = '\0';
+
+	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
+				decoded_len);
+	*pos2 = '<';
+	if (decoded == NULL) {
+		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
+	}
+
+	return decoded;
+}
+
+
+static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
+{
+	enum IMV_Action_Recommendation rec;
+	struct tnc_if_imv *imv;
+	TNC_ConnectionState state;
+	char *txt;
+
+	wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
+
+	if (tncs->done)
+		return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+
+	tncs_solicit_recommendation(tncs);
+
+	/* Select the most restrictive recommendation */
+	rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		TNC_IMV_Action_Recommendation irec;
+		irec = tncs->imv_data[imv->imvID].recommendation;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
+		    rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
+		if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
+		    rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
+			rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
+	}
+
+	wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
+	tncs->recommendation = rec;
+	tncs->done = 1;
+
+	txt = NULL;
+	switch (rec) {
+	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+		txt = "allow";
+		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+		break;
+	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+		txt = "isolate";
+		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
+		break;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+		txt = "none";
+		state = TNC_CONNECTION_STATE_ACCESS_NONE;
+		break;
+	default:
+		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
+		break;
+	}
+
+	if (txt) {
+		os_free(tncs->tncs_message);
+		tncs->tncs_message = os_zalloc(200);
+		if (tncs->tncs_message) {
+			os_snprintf(tncs->tncs_message, 199,
+				    "<TNCC-TNCS-Message><Type>%08X</Type>"
+				    "<XML><TNCCS-Recommendation type=\"%s\">"
+				    "</TNCCS-Recommendation></XML>"
+				    "</TNCC-TNCS-Message>",
+				    TNC_TNCCS_RECOMMENDATION, txt);
+		}
+	}
+
+	for (imv = tncs->imv; imv; imv = imv->next) {
+		tncs_imv_notify_connection_change(imv, tncs->connectionID,
+						  state);
+	}
+
+	switch (rec) {
+	case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
+		return TNCCS_RECOMMENDATION_ALLOW;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
+		return TNCCS_RECOMMENDATION_NO_ACCESS;
+	case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
+		return TNCCS_RECOMMENDATION_ISOLATE;
+	case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
+		return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
+	default:
+		return TNCCS_PROCESS_ERROR;
+	}
+}
+
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+					    const u8 *msg, size_t len)
+{
+	char *buf, *start, *end, *pos, *pos2, *payload;
+	unsigned int batch_id;
+	unsigned char *decoded;
+	size_t decoded_len;
+
+	buf = os_malloc(len + 1);
+	if (buf == NULL)
+		return TNCCS_PROCESS_ERROR;
+
+	os_memcpy(buf, msg, len);
+	buf[len] = '\0';
+	start = os_strstr(buf, "<TNCCS-Batch ");
+	end = os_strstr(buf, "</TNCCS-Batch>");
+	if (start == NULL || end == NULL || start > end) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	start += 13;
+	while (*start == ' ')
+		start++;
+	*end = '\0';
+
+	pos = os_strstr(start, "BatchId=");
+	if (pos == NULL) {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+
+	pos += 8;
+	if (*pos == '"')
+		pos++;
+	batch_id = atoi(pos);
+	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
+		   batch_id);
+	if (batch_id != tncs->last_batchid + 1) {
+		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
+			   "%u (expected %u)",
+			   batch_id, tncs->last_batchid + 1);
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	tncs->last_batchid = batch_id;
+
+	while (*pos != '\0' && *pos != '>')
+		pos++;
+	if (*pos == '\0') {
+		os_free(buf);
+		return TNCCS_PROCESS_ERROR;
+	}
+	pos++;
+	payload = start;
+
+	/*
+	 * <IMC-IMV-Message>
+	 * <Type>01234567</Type>
+	 * <Base64>foo==</Base64>
+	 * </IMC-IMV-Message>
+	 */
+
+	while (*start) {
+		char *endpos;
+		unsigned int type;
+
+		pos = os_strstr(start, "<IMC-IMV-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 17;
+		end = os_strstr(start, "</IMC-IMV-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 18;
+
+		if (tncs_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
+
+		decoded = tncs_get_base64(start, &decoded_len);
+		if (decoded == NULL) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+
+		tncs_send_to_imvs(tncs, type, decoded, decoded_len);
+
+		os_free(decoded);
+
+		start = end;
+	}
+
+	/*
+	 * <TNCC-TNCS-Message>
+	 * <Type>01234567</Type>
+	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
+	 * <Base64>foo==</Base64>
+	 * </TNCC-TNCS-Message>
+	 */
+
+	start = payload;
+	while (*start) {
+		unsigned int type;
+		char *xml, *xmlend, *endpos;
+
+		pos = os_strstr(start, "<TNCC-TNCS-Message>");
+		if (pos == NULL)
+			break;
+		start = pos + 19;
+		end = os_strstr(start, "</TNCC-TNCS-Message>");
+		if (end == NULL)
+			break;
+		*end = '\0';
+		endpos = end;
+		end += 20;
+
+		if (tncs_get_type(start, &type) < 0) {
+			*endpos = '<';
+			start = end;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
+			   type);
+
+		/* Base64 OR XML */
+		decoded = NULL;
+		xml = NULL;
+		xmlend = NULL;
+		pos = os_strstr(start, "<XML>");
+		if (pos) {
+			pos += 5;
+			pos2 = os_strstr(pos, "</XML>");
+			if (pos2 == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+			xmlend = pos2;
+			xml = pos;
+		} else {
+			decoded = tncs_get_base64(start, &decoded_len);
+			if (decoded == NULL) {
+				*endpos = '<';
+				start = end;
+				continue;
+			}
+		}
+
+		if (decoded) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message Base64",
+					  decoded, decoded_len);
+			os_free(decoded);
+		}
+
+		if (xml) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "TNC: TNCC-TNCS-Message XML",
+					  (unsigned char *) xml,
+					  xmlend - xml);
+		}
+
+		start = end;
+	}
+
+	os_free(buf);
+
+	tncs_batch_ending(tncs);
+
+	if (tncs_total_send_len(tncs) == 0)
+		return tncs_derive_recommendation(tncs);
+
+	return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
+}
+
+
+static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
+					  int *error)
+{
+	struct tnc_if_imv *imv;
+	char *pos, *pos2;
+
+	if (id >= TNC_MAX_IMV_ID) {
+		wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
+		return NULL;
+	}
+
+	imv = os_zalloc(sizeof(*imv));
+	if (imv == NULL) {
+		*error = 1;
+		return NULL;
+	}
+
+	imv->imvID = id;
+
+	pos = start;
+	wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
+	if (pos + 1 >= end || *pos != '"') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no starting quotation mark)", start);
+		os_free(imv);
+		return NULL;
+	}
+
+	pos++;
+	pos2 = pos;
+	while (pos2 < end && *pos2 != '"')
+		pos2++;
+	if (pos2 >= end) {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no ending quotation mark)", start);
+		os_free(imv);
+		return NULL;
+	}
+	*pos2 = '\0';
+	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
+	imv->name = os_strdup(pos);
+
+	pos = pos2 + 1;
+	if (pos >= end || *pos != ' ') {
+		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
+			   "(no space after name)", start);
+		os_free(imv);
+		return NULL;
+	}
+
+	pos++;
+	wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
+	imv->path = os_strdup(pos);
+
+	return imv;
+}
+
+
+static int tncs_read_config(struct tncs_global *global)
+{
+	char *config, *end, *pos, *line_end;
+	size_t config_len;
+	struct tnc_if_imv *imv, *last;
+	int id = 0;
+
+	last = NULL;
+
+	config = os_readfile(TNC_CONFIG_FILE, &config_len);
+	if (config == NULL) {
+		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
+			   "file '%s'", TNC_CONFIG_FILE);
+		return -1;
+	}
+
+	end = config + config_len;
+	for (pos = config; pos < end; pos = line_end + 1) {
+		line_end = pos;
+		while (*line_end != '\n' && *line_end != '\r' &&
+		       line_end < end)
+			line_end++;
+		*line_end = '\0';
+
+		if (os_strncmp(pos, "IMV ", 4) == 0) {
+			int error = 0;
+
+			imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
+			if (error)
+				return -1;
+			if (imv) {
+				if (last == NULL)
+					global->imv = imv;
+				else
+					last->next = imv;
+				last = imv;
+			}
+		}
+	}
+
+	os_free(config);
+
+	return 0;
+}
+
+
+struct tncs_data * tncs_init(void)
+{
+	struct tncs_data *tncs;
+
+	if (tncs_global_data == NULL)
+		return NULL;
+
+	tncs = os_zalloc(sizeof(*tncs));
+	if (tncs == NULL)
+		return NULL;
+	tncs->imv = tncs_global_data->imv;
+	tncs->connectionID = tncs_global_data->next_conn_id++;
+	tncs->next = tncs_global_data->connections;
+	tncs_global_data->connections = tncs;
+
+	return tncs;
+}
+
+
+void tncs_deinit(struct tncs_data *tncs)
+{
+	int i;
+	struct tncs_data *prev, *conn;
+
+	if (tncs == NULL)
+		return;
+
+	for (i = 0; i < TNC_MAX_IMV_ID; i++)
+		os_free(tncs->imv_data[i].imv_send);
+
+	prev = NULL;
+	conn = tncs_global_data->connections;
+	while (conn) {
+		if (conn == tncs) {
+			if (prev)
+				prev->next = tncs->next;
+			else
+				tncs_global_data->connections = tncs->next;
+			break;
+		}
+		prev = conn;
+		conn = conn->next;
+	}
+
+	os_free(tncs->tncs_message);
+	os_free(tncs);
+}
+
+
+int tncs_global_init(void)
+{
+	struct tnc_if_imv *imv;
+
+	tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
+	if (tncs_global_data == NULL)
+		return -1;
+
+	if (tncs_read_config(tncs_global_data) < 0) {
+		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
+		goto failed;
+	}
+
+	for (imv = tncs_global_data->imv; imv; imv = imv->next) {
+		if (tncs_load_imv(imv)) {
+			wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
+				   imv->name);
+			goto failed;
+		}
+	}
+
+	return 0;
+
+failed:
+	tncs_global_deinit();
+	return -1;
+}
+
+
+void tncs_global_deinit(void)
+{
+	struct tnc_if_imv *imv, *prev;
+
+	if (tncs_global_data == NULL)
+		return;
+
+	imv = tncs_global_data->imv;
+	while (imv) {
+		tncs_unload_imv(imv);
+
+		prev = imv;
+		imv = imv->next;
+		os_free(prev);
+	}
+
+	os_free(tncs_global_data);
+}
+
+
+struct wpabuf * tncs_build_soh_request(void)
+{
+	struct wpabuf *buf;
+
+	/*
+	 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
+	 * Method)
+	 */
+
+	buf = wpabuf_alloc(8 + 4);
+	if (buf == NULL)
+		return NULL;
+
+	/* Vendor-Specific TLV (Microsoft) - SoH Request */
+	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
+	wpabuf_put_be16(buf, 8); /* Length */
+
+	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
+
+	wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
+	wpabuf_put_be16(buf, 0); /* Length */
+
+	return buf;
+}
+
+
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+				 int *failure)
+{
+	wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
+	*failure = 0;
+
+	/* TODO: return MS-SoH Response TLV */
+
+	return NULL;
+}

Added: wpasupplicant/branches/upstream/current/src/eap_server/tncs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/tncs.h?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/tncs.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/tncs.h Sat Jun 14 00:26:56 2008
@@ -1,0 +1,49 @@
+/*
+ * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TNCS_H
+#define TNCS_H
+
+struct tncs_data;
+
+struct tncs_data * tncs_init(void);
+void tncs_deinit(struct tncs_data *tncs);
+void tncs_init_connection(struct tncs_data *tncs);
+size_t tncs_total_send_len(struct tncs_data *tncs);
+u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos);
+char * tncs_if_tnccs_start(struct tncs_data *tncs);
+char * tncs_if_tnccs_end(void);
+
+enum tncs_process_res {
+	TNCCS_PROCESS_ERROR = -1,
+	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
+	TNCCS_RECOMMENDATION_ERROR,
+	TNCCS_RECOMMENDATION_ALLOW,
+	TNCCS_RECOMMENDATION_NONE,
+	TNCCS_RECOMMENDATION_ISOLATE,
+	TNCCS_RECOMMENDATION_NO_ACCESS,
+	TNCCS_RECOMMENDATION_NO_RECOMMENDATION
+};
+
+enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
+					    const u8 *msg, size_t len);
+
+int tncs_global_init(void);
+void tncs_global_deinit(void);
+
+struct wpabuf * tncs_build_soh_request(void);
+struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
+				 int *failure);
+
+#endif /* TNCS_H */

Modified: wpasupplicant/branches/upstream/current/src/radius/radius.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.c Sat Jun 14 00:26:56 2008
@@ -181,6 +181,8 @@
 	  RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
 	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+	  RADIUS_ATTR_TEXT },
 	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
 };
 #define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
@@ -803,6 +805,7 @@
 	ppos = plain = os_malloc(plen);
 	if (plain == NULL)
 		return NULL;
+	plain[0] = 0;
 
 	while (left > 0) {
 		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
@@ -827,7 +830,7 @@
 		left -= MD5_MAC_LEN;
 	}
 
-	if (plain[0] > plen - 1) {
+	if (plain[0] == 0 || plain[0] > plen - 1) {
 		printf("Failed to decrypt MPPE key\n");
 		os_free(plain);
 		return NULL;

Modified: wpasupplicant/branches/upstream/current/src/radius/radius.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius.h Sat Jun 14 00:26:56 2008
@@ -87,6 +87,7 @@
        RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
        RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
        RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
+       RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
        RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
 };
 

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sat Jun 14 00:26:56 2008
@@ -738,15 +738,16 @@
 		     struct hostapd_radius_server *oserv,
 		     int sock, int sock6, int auth)
 {
-	struct sockaddr_in serv;
+	struct sockaddr_in serv, claddr;
 #ifdef CONFIG_IPV6
-	struct sockaddr_in6 serv6;
+	struct sockaddr_in6 serv6, claddr6;
 #endif /* CONFIG_IPV6 */
-	struct sockaddr *addr;
-	socklen_t addrlen;
+	struct sockaddr *addr, *cl_addr;
+	socklen_t addrlen, claddrlen;
 	char abuf[50];
 	int sel_sock;
 	struct radius_msg_list *entry;
+	struct hostapd_radius_servers *conf = radius->conf;
 
 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_INFO,
@@ -816,10 +817,64 @@
 		return -1;
 	}
 
+	if (conf->force_client_addr) {
+		switch (conf->client_addr.af) {
+		case AF_INET:
+			os_memset(&claddr, 0, sizeof(claddr));
+			claddr.sin_family = AF_INET;
+			claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
+			claddr.sin_port = htons(0);
+			cl_addr = (struct sockaddr *) &claddr;
+			claddrlen = sizeof(claddr);
+			break;
+#ifdef CONFIG_IPV6
+		case AF_INET6:
+			os_memset(&claddr6, 0, sizeof(claddr6));
+			claddr6.sin6_family = AF_INET6;
+			os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
+				  sizeof(struct in6_addr));
+			claddr6.sin6_port = htons(0);
+			cl_addr = (struct sockaddr *) &claddr6;
+			claddrlen = sizeof(claddr6);
+			break;
+#endif /* CONFIG_IPV6 */
+		default:
+			return -1;
+		}
+
+		if (bind(sel_sock, cl_addr, claddrlen) < 0) {
+			perror("bind[radius]");
+			return -1;
+		}
+	}
+
 	if (connect(sel_sock, addr, addrlen) < 0) {
 		perror("connect[radius]");
 		return -1;
 	}
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	switch (nserv->addr.af) {
+	case AF_INET:
+		claddrlen = sizeof(claddr);
+		getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
+		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+			   inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
+		break;
+#ifdef CONFIG_IPV6
+	case AF_INET6: {
+		claddrlen = sizeof(claddr6);
+		getsockname(sel_sock, (struct sockaddr *) &claddr6,
+			    &claddrlen);
+		wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
+			   inet_ntop(AF_INET6, &claddr6.sin6_addr,
+				     abuf, sizeof(abuf)),
+			   ntohs(claddr6.sin6_port));
+		break;
+	}
+#endif /* CONFIG_IPV6 */
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 	if (auth)
 		radius->auth_sock = sel_sock;

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_client.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_client.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.h Sat Jun 14 00:26:56 2008
@@ -57,6 +57,9 @@
 	int acct_interim_interval;
 
 	int msg_dumps;
+
+	struct hostapd_ip_addr client_addr;
+	int force_client_addr;
 };
 
 

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.c Sat Jun 14 00:26:56 2008
@@ -87,6 +87,7 @@
 	u8 *pac_opaque_encr_key;
 	char *eap_fast_a_id;
 	int eap_sim_aka_result_ind;
+	int tnc;
 	int ipv6;
 	struct os_time start_time;
 	struct radius_server_counters counters;
@@ -311,6 +312,7 @@
 	eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
 	eap_conf.eap_fast_a_id = data->eap_fast_a_id;
 	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
+	eap_conf.tnc = data->tnc;
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
 	if (sess->eap == NULL) {
@@ -1016,6 +1018,7 @@
 		data->eap_fast_a_id = os_strdup(conf->eap_fast_a_id);
 	data->get_eap_user = conf->get_eap_user;
 	data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	data->tnc = conf->tnc;
 
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);

Modified: wpasupplicant/branches/upstream/current/src/radius/radius_server.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/radius/radius_server.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.h Sat Jun 14 00:26:56 2008
@@ -27,6 +27,7 @@
 	u8 *pac_opaque_encr_key;
 	char *eap_fast_a_id;
 	int eap_sim_aka_result_ind;
+	int tnc;
 	int ipv6;
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/peerkey.c Sat Jun 14 00:26:56 2008
@@ -867,8 +867,8 @@
 	if (peerkey->cipher == WPA_CIPHER_TKIP) {
 		/* Swap Tx/Rx keys for Michael MIC */
 		os_memcpy(key_buf, _key, 16);
-		os_memcpy(key_buf + 16, _key + 24, 8);
-		os_memcpy(key_buf + 24, _key + 16, 8);
+		os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
+		os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
 		_key = key_buf;
 		key_len = 32;
 	} else

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/preauth.c Sat Jun 14 00:26:56 2008
@@ -68,8 +68,7 @@
 	wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
 
 	if (sm->preauth_eapol == NULL ||
-	    os_memcmp(sm->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
-		      ETH_ALEN) == 0 ||
+	    is_zero_ether_addr(sm->preauth_bssid) ||
 	    os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
 		wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
 			   "unexpected source " MACSTR " - dropped",

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.c Sat Jun 14 00:26:56 2008
@@ -98,8 +98,7 @@
 			int ver, const u8 *dest, u16 proto,
 			u8 *msg, size_t msg_len, u8 *key_mic)
 {
-	if (os_memcmp(dest, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 &&
-	    os_memcmp(sm->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
 		/*
 		 * Association event was not yet received; try to fetch
 		 * BSSID from the driver.
@@ -451,7 +450,6 @@
 		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
 		wpa_cipher_txt(sm->pairwise_cipher),
 		wpa_cipher_txt(sm->group_cipher));
-	wpa_sm_cancel_scan(sm);
 	wpa_sm_cancel_auth_timeout(sm);
 	wpa_sm_set_state(sm, WPA_COMPLETED);
 
@@ -783,7 +781,6 @@
 	}
 
 	wpa_sm_disassociate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
-	wpa_sm_req_scan(sm, 0, 0);
 }
 
 
@@ -1791,7 +1788,6 @@
 
 		os_memset(sm->pmk, 0, sizeof(sm->pmk));
 		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
-		wpa_sm_req_scan(sm, 0, 0);
 	}
 }
 
@@ -1859,6 +1855,8 @@
  */
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
 {
+	int clear_ptk = 1;
+
 	if (sm == NULL)
 		return;
 
@@ -1871,15 +1869,25 @@
 		rsn_preauth_deinit(sm);
 
 #ifdef CONFIG_IEEE80211R
-	if ((sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	     sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) &&
-	    wpa_ft_is_completed(sm)) {
+	if (wpa_ft_is_completed(sm)) {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
 
 		/* Prepare for the next transition */
 		wpa_ft_prepare_auth_request(sm);
+
+		clear_ptk = 0;
 	}
 #endif /* CONFIG_IEEE80211R */
+
+	if (clear_ptk) {
+		/*
+		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
+		 * this is not part of a Fast BSS Transition.
+		 */
+		wpa_printf(MSG_DEBUG, "WPA: Clear old PTK");
+		sm->ptk_set = 0;
+		sm->tptk_set = 0;
+	}
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa.h Sat Jun 14 00:26:56 2008
@@ -36,8 +36,6 @@
 
 	void (*set_state)(void *ctx, wpa_states state);
 	wpa_states (*get_state)(void *ctx);
-	void (*req_scan)(void *ctx, int sec, int usec);
-	void (*cancel_scan)(void *ctx);
 	void (*deauthenticate)(void * ctx, int reason_code); 
 	void (*disassociate)(void *ctx, int reason_code);
 	int (*set_key)(void *ctx, wpa_alg alg,
@@ -280,7 +278,7 @@
 			    int ft_action, const u8 *target_ap);
 int wpa_ft_is_completed(struct wpa_sm *sm);
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
-				 size_t ies_len);
+				 size_t ies_len, const u8 *src_addr);
 int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap);
 
 #else /* CONFIG_IEEE80211R */
@@ -310,7 +308,8 @@
 }
 
 static inline int
-wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			     const u8 *src_addr)
 {
 	return -1;
 }

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c Sat Jun 14 00:26:56 2008
@@ -121,7 +121,7 @@
 			       const u8 *kck, const u8 *target_ap)
 {
 	size_t buf_len;
-	u8 *buf, *pos, *ftie_len;
+	u8 *buf, *pos, *ftie_len, *ftie_pos;
 	struct rsn_mdie *mdie;
 	struct rsn_ftie *ftie;
 	struct rsn_ie_hdr *rsnie;
@@ -226,6 +226,7 @@
 	mdie->ft_capab = 0; /* FIX: copy from the target AP's MDIE */
 
 	/* FTIE[SNonce, R0KH-ID] */
+	ftie_pos = pos;
 	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
 	ftie_len = pos++;
 	ftie = (struct rsn_ftie *) pos;
@@ -255,7 +256,7 @@
 		ftie->mic_control[1] = 3; /* Information element count */
 		if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
 			       ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
-			       ((u8 *) ftie) - 2, 2 + *ftie_len,
+			       ftie_pos, 2 + *ftie_len,
 			       (u8 *) rsnie, 2 + rsnie->len, NULL, 0,
 			       ftie->mic) < 0) {
 			wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
@@ -535,7 +536,7 @@
 	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
 		    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
 
-	bssid = ft_action ? sm->target_ap : sm->bssid;
+	bssid = target_ap;
 	wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
 			  bssid, sm->pmk_r1_name,
 			  (u8 *) &sm->ptk, sizeof(sm->ptk), ptk_name);
@@ -581,7 +582,7 @@
 
 
 int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
-				 size_t ies_len)
+				 size_t ies_len, const u8 *src_addr)
 {
 	struct wpa_ft_ies parse;
 	struct rsn_mdie *mdie;
@@ -664,7 +665,7 @@
 		return -1;
 	}
 
-	if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, sm->bssid, 6,
+	if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
 		       parse.mdie - 2, parse.mdie_len + 2,
 		       parse.ftie - 2, parse.ftie_len + 2,
 		       parse.rsn - 2, parse.rsn_len + 2, NULL, 0,

Modified: wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_i.h Sat Jun 14 00:26:56 2008
@@ -120,18 +120,6 @@
 	return sm->ctx->get_state(sm->ctx->ctx);
 }
 
-static inline void wpa_sm_req_scan(struct wpa_sm *sm, int sec, int usec)
-{
-	WPA_ASSERT(sm->ctx->req_scan);
-	sm->ctx->req_scan(sm->ctx->ctx, sec, usec);
-}
-
-static inline void wpa_sm_cancel_scan(struct wpa_sm *sm)
-{
-	WPA_ASSERT(sm->ctx->cancel_scan);
-	sm->ctx->cancel_scan(sm->ctx->ctx);
-}
-
 static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
 {
 	WPA_ASSERT(sm->ctx->deauthenticate);

Modified: wpasupplicant/branches/upstream/current/src/tls/libtommath.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/libtommath.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/libtommath.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/libtommath.c Sat Jun 14 00:26:56 2008
@@ -1,17 +1,14 @@
 /*
- * Minimal code for RSA support from LibTomMath 0.3.9
- * http://math.libtomcrypt.com/
- * http://math.libtomcrypt.com/files/ltm-0.39.tar.bz2
+ * Minimal code for RSA support from LibTomMath 0.41
+ * http://libtom.org/
+ * http://libtom.org/files/ltm-0.41.tar.bz2
  * This library was released in public domain by Tom St Denis.
  *
- * The combination in this file is not using many of the optimized algorithms
- * (e.g., Montgomery reduction) and is considerable slower than the LibTomMath
- * with its default of SC_RSA_1 settins. The main purpose of having this
- * version here is to make it easier to build bignum.c wrapper without having
- * to install and build an external library. However, it is likely worth the
- * effort to use the full library with SC_RSA_1 instead of this minimized copy.
- * Including the optimized algorithms may increase the size requirements by
- * 15 kB or so (measured with x86 build).
+ * The combination in this file may not use all of the optimized algorithms
+ * from LibTomMath and may be considerable slower than the LibTomMath with its
+ * default settings. The main purpose of having this version here is to make it
+ * easier to build bignum.c wrapper without having to install and build an
+ * external library.
  *
  * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
  * libtommath.c file instead of using the external LibTomMath library.
@@ -30,6 +27,32 @@
 #define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
 				 * would require other than mp_reduce */
 
+#ifdef LTM_FAST
+
+/* Use faster div at the cost of about 1 kB */
+#define BN_MP_MUL_D_C
+
+/* Include faster exptmod (Montgomery) at the cost of about 2.5 kB in code */
+#define BN_MP_EXPTMOD_FAST_C
+#define BN_MP_MONTGOMERY_SETUP_C
+#define BN_FAST_MP_MONTGOMERY_REDUCE_C
+#define BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+#define BN_MP_MUL_2_C
+
+/* Include faster sqr at the cost of about 0.5 kB in code */
+#define BN_FAST_S_MP_SQR_C
+
+#else /* LTM_FAST */
+
+#define BN_MP_DIV_SMALL
+#define BN_MP_INIT_MULTI_C
+#define BN_MP_CLEAR_MULTI_C
+#define BN_MP_ABS_C
+#endif /* LTM_FAST */
+
+/* Current uses do not require support for negative exponent in exptmod, so we
+ * can save about 1.5 kB in leaving out invmod. */
+#define LTM_NO_NEG_EXP
 
 /* from tommath.h */
 
@@ -110,8 +133,12 @@
 
 static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
 
+#ifdef BN_MP_INIT_MULTI_C
 static int mp_init_multi(mp_int *mp, ...);
+#endif
+#ifdef BN_MP_CLEAR_MULTI_C
 static void mp_clear_multi(mp_int *mp, ...);
+#endif
 static int mp_lshd(mp_int * a, int b);
 static void mp_set(mp_int * a, mp_digit b);
 static void mp_clamp(mp_int * a);
@@ -122,16 +149,20 @@
 static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
 static int mp_init_copy(mp_int * a, mp_int * b);
 static int mp_mul_2d(mp_int * a, int b, mp_int * c);
+#ifndef LTM_NO_NEG_EXP
 static int mp_div_2(mp_int * a, mp_int * b);
+static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+#endif /* LTM_NO_NEG_EXP */
 static int mp_copy(mp_int * a, mp_int * b);
 static int mp_count_bits(mp_int * a);
 static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
 static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
 static int mp_grow(mp_int * a, int size);
 static int mp_cmp_mag(mp_int * a, mp_int * b);
-static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+#ifdef BN_MP_ABS_C
 static int mp_abs(mp_int * a, mp_int * b);
-static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+#endif
 static int mp_sqr(mp_int * a, mp_int * b);
 static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
 static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
@@ -139,6 +170,15 @@
 static int mp_reduce_setup(mp_int * a, mp_int * b);
 static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
 static int mp_init_size(mp_int * a, int size);
+#ifdef BN_MP_EXPTMOD_FAST_C
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+#endif /* BN_MP_EXPTMOD_FAST_C */
+#ifdef BN_FAST_S_MP_SQR_C
+static int fast_s_mp_sqr (mp_int * a, mp_int * b);
+#endif /* BN_FAST_S_MP_SQR_C */
+#ifdef BN_MP_MUL_D_C
+static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
+#endif /* BN_MP_MUL_D_C */
 
 
 
@@ -546,6 +586,9 @@
 
   /* if exponent X is negative we have to recurse */
   if (X->sign == MP_NEG) {
+#ifdef LTM_NO_NEG_EXP
+        return MP_VAL;
+#else /* LTM_NO_NEG_EXP */
 #ifdef BN_MP_INVMOD_C
      mp_int tmpG, tmpX;
      int err;
@@ -578,6 +621,7 @@
      /* no invmod */
      return MP_VAL;
 #endif
+#endif /* LTM_NO_NEG_EXP */
   }
 
 /* modified diminished radix reduction */
@@ -668,6 +712,7 @@
 }
 
 
+#ifndef LTM_NO_NEG_EXP
 /* hac 14.61, pp608 */
 static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
 {
@@ -694,6 +739,7 @@
 #endif
   return MP_VAL;
 }
+#endif /* LTM_NO_NEG_EXP */
 
 
 /* get the size for an unsigned equivalent */
@@ -704,6 +750,7 @@
 }
 
 
+#ifndef LTM_NO_NEG_EXP
 /* hac 14.61, pp608 */
 static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
 {
@@ -857,6 +904,7 @@
 LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
   return res;
 }
+#endif /* LTM_NO_NEG_EXP */
 
 
 /* compare maginitude of two ints (unsigned) */
@@ -1233,6 +1281,7 @@
 }
 
 
+#ifdef BN_MP_ABS_C
 /* b = |a| 
  *
  * Simple function copies the input and fixes the sign to positive
@@ -1253,6 +1302,7 @@
 
   return MP_OKAY;
 }
+#endif
 
 
 /* set to a digit */
@@ -1264,6 +1314,7 @@
 }
 
 
+#ifndef LTM_NO_NEG_EXP
 /* b = a/2 */
 static int mp_div_2(mp_int * a, mp_int * b)
 {
@@ -1310,6 +1361,7 @@
   mp_clamp (b);
   return MP_OKAY;
 }
+#endif /* LTM_NO_NEG_EXP */
 
 
 /* shift left by a certain bit count */
@@ -1377,6 +1429,7 @@
 }
 
 
+#ifdef BN_MP_INIT_MULTI_C
 static int mp_init_multi(mp_int *mp, ...) 
 {
     mp_err res = MP_OKAY;      /* Assume ok until proven otherwise */
@@ -1412,8 +1465,10 @@
     va_end(args);
     return res;                /* Assumed ok, if error flagged above. */
 }
-
-
+#endif
+
+
+#ifdef BN_MP_CLEAR_MULTI_C
 static void mp_clear_multi(mp_int *mp, ...) 
 {
     mp_int* next_mp = mp;
@@ -1425,6 +1480,7 @@
     }
     va_end(args);
 }
+#endif
 
 
 /* shift left a certain amount of digits */
@@ -1531,6 +1587,8 @@
   return MP_OKAY;
 }
 
+
+#ifdef BN_MP_DIV_SMALL
 
 /* slower bit-bang division... also smaller */
 static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
@@ -1599,6 +1657,206 @@
    mp_clear_multi(&ta, &tb, &tq, &q, NULL);
    return res;
 }
+
+#else
+
+/* integer signed division. 
+ * c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ * HAC pp.598 Algorithm 14.20
+ *
+ * Note that the description in HAC is horribly 
+ * incomplete.  For example, it doesn't consider 
+ * the case where digits are removed from 'x' in 
+ * the inner loop.  It also doesn't consider the 
+ * case that y has fewer than three digits, etc..
+ *
+ * The overall algorithm is as described as 
+ * 14.20 from HAC but fixed to treat these cases.
+*/
+static int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+  mp_int  q, x, y, t1, t2;
+  int     res, n, t, i, norm, neg;
+
+  /* is divisor zero ? */
+  if (mp_iszero (b) == 1) {
+    return MP_VAL;
+  }
+
+  /* if a < b then q=0, r = a */
+  if (mp_cmp_mag (a, b) == MP_LT) {
+    if (d != NULL) {
+      res = mp_copy (a, d);
+    } else {
+      res = MP_OKAY;
+    }
+    if (c != NULL) {
+      mp_zero (c);
+    }
+    return res;
+  }
+
+  if ((res = mp_init_size (&q, a->used + 2)) != MP_OKAY) {
+    return res;
+  }
+  q.used = a->used + 2;
+
+  if ((res = mp_init (&t1)) != MP_OKAY) {
+    goto LBL_Q;
+  }
+
+  if ((res = mp_init (&t2)) != MP_OKAY) {
+    goto LBL_T1;
+  }
+
+  if ((res = mp_init_copy (&x, a)) != MP_OKAY) {
+    goto LBL_T2;
+  }
+
+  if ((res = mp_init_copy (&y, b)) != MP_OKAY) {
+    goto LBL_X;
+  }
+
+  /* fix the sign */
+  neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+  x.sign = y.sign = MP_ZPOS;
+
+  /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
+  norm = mp_count_bits(&y) % DIGIT_BIT;
+  if (norm < (int)(DIGIT_BIT-1)) {
+     norm = (DIGIT_BIT-1) - norm;
+     if ((res = mp_mul_2d (&x, norm, &x)) != MP_OKAY) {
+       goto LBL_Y;
+     }
+     if ((res = mp_mul_2d (&y, norm, &y)) != MP_OKAY) {
+       goto LBL_Y;
+     }
+  } else {
+     norm = 0;
+  }
+
+  /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
+  n = x.used - 1;
+  t = y.used - 1;
+
+  /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
+  if ((res = mp_lshd (&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+    goto LBL_Y;
+  }
+
+  while (mp_cmp (&x, &y) != MP_LT) {
+    ++(q.dp[n - t]);
+    if ((res = mp_sub (&x, &y, &x)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+  }
+
+  /* reset y by shifting it back down */
+  mp_rshd (&y, n - t);
+
+  /* step 3. for i from n down to (t + 1) */
+  for (i = n; i >= (t + 1); i--) {
+    if (i > x.used) {
+      continue;
+    }
+
+    /* step 3.1 if xi == yt then set q{i-t-1} to b-1, 
+     * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
+    if (x.dp[i] == y.dp[t]) {
+      q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+    } else {
+      mp_word tmp;
+      tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+      tmp |= ((mp_word) x.dp[i - 1]);
+      tmp /= ((mp_word) y.dp[t]);
+      if (tmp > (mp_word) MP_MASK)
+        tmp = MP_MASK;
+      q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+    }
+
+    /* while (q{i-t-1} * (yt * b + y{t-1})) > 
+             xi * b**2 + xi-1 * b + xi-2 
+     
+       do q{i-t-1} -= 1; 
+    */
+    q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+    do {
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+      /* find left hand */
+      mp_zero (&t1);
+      t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+      t1.dp[1] = y.dp[t];
+      t1.used = 2;
+      if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+
+      /* find right hand */
+      t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+      t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+      t2.dp[2] = x.dp[i];
+      t2.used = 3;
+    } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+    /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
+    if ((res = mp_mul_d (&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    if ((res = mp_sub (&x, &t1, &x)) != MP_OKAY) {
+      goto LBL_Y;
+    }
+
+    /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
+    if (x.sign == MP_NEG) {
+      if ((res = mp_copy (&y, &t1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+      if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+      if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+        goto LBL_Y;
+      }
+
+      q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+    }
+  }
+
+  /* now q is the quotient and x is the remainder 
+   * [which we have to normalize] 
+   */
+  
+  /* get sign before writing to c */
+  x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+  if (c != NULL) {
+    mp_clamp (&q);
+    mp_exch (&q, c);
+    c->sign = neg;
+  }
+
+  if (d != NULL) {
+    mp_div_2d (&x, norm, &x, NULL);
+    mp_exch (&x, d);
+  }
+
+  res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+  return res;
+}
+
+#endif
 
 
 #ifdef MP_LOW_MEM
@@ -2368,3 +2626,756 @@
   mp_clear (&t);
   return MP_OKAY;
 }
+
+
+#ifdef BN_MP_MONTGOMERY_SETUP_C
+/* setups the montgomery reduction stuff */
+static int
+mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+  mp_digit x, b;
+
+/* fast inversion mod 2**k
+ *
+ * Based on the fact that
+ *
+ * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
+ *                    =>  2*X*A - X*X*A*A = 1
+ *                    =>  2*(1) - (1)     = 1
+ */
+  b = n->dp[0];
+
+  if ((b & 1) == 0) {
+    return MP_VAL;
+  }
+
+  x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+  x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+  x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
+#endif
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+  x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+  x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
+#endif
+
+  /* rho = -1/m mod b */
+  *rho = (unsigned long)(((mp_word)1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+/* computes xR**-1 == x (mod N) via Montgomery Reduction
+ *
+ * This is an optimized implementation of montgomery_reduce
+ * which uses the comba method to quickly calculate the columns of the
+ * reduction.
+ *
+ * Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+  int     ix, res, olduse;
+  mp_word W[MP_WARRAY];
+
+  /* get old used count */
+  olduse = x->used;
+
+  /* grow a as required */
+  if (x->alloc < n->used + 1) {
+    if ((res = mp_grow (x, n->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* first we have to get the digits of the input into
+   * an array of double precision words W[...]
+   */
+  {
+    register mp_word *_W;
+    register mp_digit *tmpx;
+
+    /* alias for the W[] array */
+    _W   = W;
+
+    /* alias for the digits of  x*/
+    tmpx = x->dp;
+
+    /* copy the digits of a into W[0..a->used-1] */
+    for (ix = 0; ix < x->used; ix++) {
+      *_W++ = *tmpx++;
+    }
+
+    /* zero the high words of W[a->used..m->used*2] */
+    for (; ix < n->used * 2 + 1; ix++) {
+      *_W++ = 0;
+    }
+  }
+
+  /* now we proceed to zero successive digits
+   * from the least significant upwards
+   */
+  for (ix = 0; ix < n->used; ix++) {
+    /* mu = ai * m' mod b
+     *
+     * We avoid a double precision multiplication (which isn't required)
+     * by casting the value down to a mp_digit.  Note this requires
+     * that W[ix-1] have  the carry cleared (see after the inner loop)
+     */
+    register mp_digit mu;
+    mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+    /* a = a + mu * m * b**i
+     *
+     * This is computed in place and on the fly.  The multiplication
+     * by b**i is handled by offseting which columns the results
+     * are added to.
+     *
+     * Note the comba method normally doesn't handle carries in the
+     * inner loop In this case we fix the carry from the previous
+     * column since the Montgomery reduction requires digits of the
+     * result (so far) [see above] to work.  This is
+     * handled by fixing up one carry after the inner loop.  The
+     * carry fixups are done in order so after these loops the
+     * first m->used words of W[] have the carries fixed
+     */
+    {
+      register int iy;
+      register mp_digit *tmpn;
+      register mp_word *_W;
+
+      /* alias for the digits of the modulus */
+      tmpn = n->dp;
+
+      /* Alias for the columns set by an offset of ix */
+      _W = W + ix;
+
+      /* inner loop */
+      for (iy = 0; iy < n->used; iy++) {
+          *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+      }
+    }
+
+    /* now fix carry for next digit, W[ix+1] */
+    W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+  }
+
+  /* now we have to propagate the carries and
+   * shift the words downward [all those least
+   * significant digits we zeroed].
+   */
+  {
+    register mp_digit *tmpx;
+    register mp_word *_W, *_W1;
+
+    /* nox fix rest of carries */
+
+    /* alias for current word */
+    _W1 = W + ix;
+
+    /* alias for next word, where the carry goes */
+    _W = W + ++ix;
+
+    for (; ix <= n->used * 2 + 1; ix++) {
+      *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+    }
+
+    /* copy out, A = A/b**n
+     *
+     * The result is A/b**n but instead of converting from an
+     * array of mp_word to mp_digit than calling mp_rshd
+     * we just copy them in the right order
+     */
+
+    /* alias for destination word */
+    tmpx = x->dp;
+
+    /* alias for shifted double precision result */
+    _W = W + n->used;
+
+    for (ix = 0; ix < n->used + 1; ix++) {
+      *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+    }
+
+    /* zero oldused digits, if the input a was larger than
+     * m->used+1 we'll have to clear the digits
+     */
+    for (; ix < olduse; ix++) {
+      *tmpx++ = 0;
+    }
+  }
+
+  /* set the max used and clamp */
+  x->used = n->used + 1;
+  mp_clamp (x);
+
+  /* if A >= m then A = A - m */
+  if (mp_cmp_mag (x, n) != MP_LT) {
+    return s_mp_sub (x, n, x);
+  }
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_2_C
+/* b = a*2 */
+static int mp_mul_2(mp_int * a, mp_int * b)
+{
+  int     x, res, oldused;
+
+  /* grow to accomodate result */
+  if (b->alloc < a->used + 1) {
+    if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  oldused = b->used;
+  b->used = a->used;
+
+  {
+    register mp_digit r, rr, *tmpa, *tmpb;
+
+    /* alias for source */
+    tmpa = a->dp;
+    
+    /* alias for dest */
+    tmpb = b->dp;
+
+    /* carry */
+    r = 0;
+    for (x = 0; x < a->used; x++) {
+    
+      /* get what will be the *next* carry bit from the 
+       * MSB of the current digit 
+       */
+      rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+      
+      /* now shift up this digit, add in the carry [from the previous] */
+      *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+      
+      /* copy the carry that would be from the source 
+       * digit into the next iteration 
+       */
+      r = rr;
+    }
+
+    /* new leading digit? */
+    if (r != 0) {
+      /* add a MSB which is always 1 at this point */
+      *tmpb = 1;
+      ++(b->used);
+    }
+
+    /* now zero any excess digits on the destination 
+     * that we didn't write to 
+     */
+    tmpb = b->dp + b->used;
+    for (x = b->used; x < oldused; x++) {
+      *tmpb++ = 0;
+    }
+  }
+  b->sign = a->sign;
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+/*
+ * shifts with subtractions when the result is greater than b.
+ *
+ * The method is slightly modified to shift B unconditionally upto just under
+ * the leading bit of b.  This saves alot of multiple precision shifting.
+ */
+static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+  int     x, bits, res;
+
+  /* how many bits of last digit does b use */
+  bits = mp_count_bits (b) % DIGIT_BIT;
+
+  if (b->used > 1) {
+     if ((res = mp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+        return res;
+     }
+  } else {
+     mp_set(a, 1);
+     bits = 1;
+  }
+
+
+  /* now compute C = A * B mod b */
+  for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
+    if ((res = mp_mul_2 (a, a)) != MP_OKAY) {
+      return res;
+    }
+    if (mp_cmp_mag (a, b) != MP_LT) {
+      if ((res = s_mp_sub (a, b, a)) != MP_OKAY) {
+        return res;
+      }
+    }
+  }
+
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_EXPTMOD_FAST_C
+/* computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+ *
+ * Uses a left-to-right k-ary sliding window to compute the modular exponentiation.
+ * The value of k changes based on the size of the exponent.
+ *
+ * Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+ */
+
+static int mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+  mp_int  M[TAB_SIZE], res;
+  mp_digit buf, mp;
+  int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+  /* use a pointer to the reduction algorithm.  This allows us to use
+   * one of many reduction algorithms without modding the guts of
+   * the code with if statements everywhere.
+   */
+  int     (*redux)(mp_int*,mp_int*,mp_digit);
+
+  /* find window size */
+  x = mp_count_bits (X);
+  if (x <= 7) {
+    winsize = 2;
+  } else if (x <= 36) {
+    winsize = 3;
+  } else if (x <= 140) {
+    winsize = 4;
+  } else if (x <= 450) {
+    winsize = 5;
+  } else if (x <= 1303) {
+    winsize = 6;
+  } else if (x <= 3529) {
+    winsize = 7;
+  } else {
+    winsize = 8;
+  }
+
+#ifdef MP_LOW_MEM
+  if (winsize > 5) {
+     winsize = 5;
+  }
+#endif
+
+  /* init M array */
+  /* init first cell */
+  if ((err = mp_init(&M[1])) != MP_OKAY) {
+     return err;
+  }
+
+  /* now init the second half of the array */
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    if ((err = mp_init(&M[x])) != MP_OKAY) {
+      for (y = 1<<(winsize-1); y < x; y++) {
+        mp_clear (&M[y]);
+      }
+      mp_clear(&M[1]);
+      return err;
+    }
+  }
+
+  /* determine and setup reduction code */
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_SETUP_C     
+     /* now setup montgomery  */
+     if ((err = mp_montgomery_setup (P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+
+     /* automatically pick the comba one if available (saves quite a few calls/ifs) */
+#ifdef BN_FAST_MP_MONTGOMERY_REDUCE_C
+     if (((P->used * 2 + 1) < MP_WARRAY) &&
+          P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+        redux = fast_mp_montgomery_reduce;
+     } else 
+#endif
+     {
+#ifdef BN_MP_MONTGOMERY_REDUCE_C
+        /* use slower baseline Montgomery method */
+        redux = mp_montgomery_reduce;
+#else
+        err = MP_VAL;
+        goto LBL_M;
+#endif
+     }
+  } else if (redmode == 1) {
+#if defined(BN_MP_DR_SETUP_C) && defined(BN_MP_DR_REDUCE_C)
+     /* setup DR reduction for moduli of the form B**k - b */
+     mp_dr_setup(P, &mp);
+     redux = mp_dr_reduce;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  } else {
+#if defined(BN_MP_REDUCE_2K_SETUP_C) && defined(BN_MP_REDUCE_2K_C)
+     /* setup DR reduction for moduli of the form 2**k - b */
+     if ((err = mp_reduce_2k_setup(P, &mp)) != MP_OKAY) {
+        goto LBL_M;
+     }
+     redux = mp_reduce_2k;
+#else
+     err = MP_VAL;
+     goto LBL_M;
+#endif
+  }
+
+  /* setup result */
+  if ((err = mp_init (&res)) != MP_OKAY) {
+    goto LBL_M;
+  }
+
+  /* create M table
+   *
+
+   *
+   * The first half of the table is not computed though accept for M[0] and M[1]
+   */
+
+  if (redmode == 0) {
+#ifdef BN_MP_MONTGOMERY_CALC_NORMALIZATION_C
+     /* now we need R mod m */
+     if ((err = mp_montgomery_calc_normalization (&res, P)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+#else 
+     err = MP_VAL;
+     goto LBL_RES;
+#endif
+
+     /* now set M[1] to G * R mod m */
+     if ((err = mp_mulmod (G, &res, P, &M[1])) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  } else {
+     mp_set(&res, 1);
+     if ((err = mp_mod(G, P, &M[1])) != MP_OKAY) {
+        goto LBL_RES;
+     }
+  }
+
+  /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
+  if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+    goto LBL_RES;
+  }
+
+  for (x = 0; x < (winsize - 1); x++) {
+    if ((err = mp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* create upper table */
+  for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+    if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+      goto LBL_RES;
+    }
+    if ((err = redux (&M[x], P, mp)) != MP_OKAY) {
+      goto LBL_RES;
+    }
+  }
+
+  /* set initial mode and bit cnt */
+  mode   = 0;
+  bitcnt = 1;
+  buf    = 0;
+  digidx = X->used - 1;
+  bitcpy = 0;
+  bitbuf = 0;
+
+  for (;;) {
+    /* grab next digit as required */
+    if (--bitcnt == 0) {
+      /* if digidx == -1 we are out of digits so break */
+      if (digidx == -1) {
+        break;
+      }
+      /* read next digit and reset bitcnt */
+      buf    = X->dp[digidx--];
+      bitcnt = (int)DIGIT_BIT;
+    }
+
+    /* grab the next msb from the exponent */
+    y     = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+    buf <<= (mp_digit)1;
+
+    /* if the bit is zero and mode == 0 then we ignore it
+     * These represent the leading zero bits before the first 1 bit
+     * in the exponent.  Technically this opt is not required but it
+     * does lower the # of trivial squaring/reductions used
+     */
+    if (mode == 0 && y == 0) {
+      continue;
+    }
+
+    /* if the bit is zero and mode == 1 then we square */
+    if (mode == 1 && y == 0) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      continue;
+    }
+
+    /* else we add it to the window */
+    bitbuf |= (y << (winsize - ++bitcpy));
+    mode    = 2;
+
+    if (bitcpy == winsize) {
+      /* ok window is filled so square as required and multiply  */
+      /* square first */
+      for (x = 0; x < winsize; x++) {
+        if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+
+      /* then multiply */
+      if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* empty window and reset */
+      bitcpy = 0;
+      bitbuf = 0;
+      mode   = 1;
+    }
+  }
+
+  /* if bits remain then square/multiply */
+  if (mode == 2 && bitcpy > 0) {
+    /* square then multiply if the bit is set */
+    for (x = 0; x < bitcpy; x++) {
+      if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+      if ((err = redux (&res, P, mp)) != MP_OKAY) {
+        goto LBL_RES;
+      }
+
+      /* get next bit of the window */
+      bitbuf <<= 1;
+      if ((bitbuf & (1 << winsize)) != 0) {
+        /* then multiply */
+        if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+        if ((err = redux (&res, P, mp)) != MP_OKAY) {
+          goto LBL_RES;
+        }
+      }
+    }
+  }
+
+  if (redmode == 0) {
+     /* fixup result if Montgomery reduction is used
+      * recall that any value in a Montgomery system is
+      * actually multiplied by R mod n.  So we have
+      * to reduce one more time to cancel out the factor
+      * of R.
+      */
+     if ((err = redux(&res, P, mp)) != MP_OKAY) {
+       goto LBL_RES;
+     }
+  }
+
+  /* swap res with Y */
+  mp_exch (&res, Y);
+  err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_M:
+  mp_clear(&M[1]);
+  for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+    mp_clear (&M[x]);
+  }
+  return err;
+}
+#endif
+
+
+#ifdef BN_FAST_S_MP_SQR_C
+/* the jist of squaring...
+ * you do like mult except the offset of the tmpx [one that 
+ * starts closer to zero] can't equal the offset of tmpy.  
+ * So basically you set up iy like before then you min it with
+ * (ty-tx) so that it never happens.  You double all those 
+ * you add in the inner loop
+
+After that loop you do the squares and add them in.
+*/
+
+static int fast_s_mp_sqr (mp_int * a, mp_int * b)
+{
+  int       olduse, res, pa, ix, iz;
+  mp_digit   W[MP_WARRAY], *tmpx;
+  mp_word   W1;
+
+  /* grow the destination as required */
+  pa = a->used + a->used;
+  if (b->alloc < pa) {
+    if ((res = mp_grow (b, pa)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* number of output digits to produce */
+  W1 = 0;
+  for (ix = 0; ix < pa; ix++) { 
+      int      tx, ty, iy;
+      mp_word  _W;
+      mp_digit *tmpy;
+
+      /* clear counter */
+      _W = 0;
+
+      /* get offsets into the two bignums */
+      ty = MIN(a->used-1, ix);
+      tx = ix - ty;
+
+      /* setup temp aliases */
+      tmpx = a->dp + tx;
+      tmpy = a->dp + ty;
+
+      /* this is the number of times the loop will iterrate, essentially
+         while (tx++ < a->used && ty-- >= 0) { ... }
+       */
+      iy = MIN(a->used-tx, ty+1);
+
+      /* now for squaring tx can never equal ty 
+       * we halve the distance since they approach at a rate of 2x
+       * and we have to round because odd cases need to be executed
+       */
+      iy = MIN(iy, (ty-tx+1)>>1);
+
+      /* execute loop */
+      for (iz = 0; iz < iy; iz++) {
+         _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+      }
+
+      /* double the inner product and add carry */
+      _W = _W + _W + W1;
+
+      /* even columns have the square term in them */
+      if ((ix&1) == 0) {
+         _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+      }
+
+      /* store it */
+      W[ix] = (mp_digit)(_W & MP_MASK);
+
+      /* make next carry */
+      W1 = _W >> ((mp_word)DIGIT_BIT);
+  }
+
+  /* setup dest */
+  olduse  = b->used;
+  b->used = a->used+a->used;
+
+  {
+    mp_digit *tmpb;
+    tmpb = b->dp;
+    for (ix = 0; ix < pa; ix++) {
+      *tmpb++ = W[ix] & MP_MASK;
+    }
+
+    /* clear unused digits [that existed in the old copy of c] */
+    for (; ix < olduse; ix++) {
+      *tmpb++ = 0;
+    }
+  }
+  mp_clamp (b);
+  return MP_OKAY;
+}
+#endif
+
+
+#ifdef BN_MP_MUL_D_C
+/* multiply by a digit */
+static int
+mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
+{
+  mp_digit u, *tmpa, *tmpc;
+  mp_word  r;
+  int      ix, res, olduse;
+
+  /* make sure c is big enough to hold a*b */
+  if (c->alloc < a->used + 1) {
+    if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+      return res;
+    }
+  }
+
+  /* get the original destinations used count */
+  olduse = c->used;
+
+  /* set the sign */
+  c->sign = a->sign;
+
+  /* alias for a->dp [source] */
+  tmpa = a->dp;
+
+  /* alias for c->dp [dest] */
+  tmpc = c->dp;
+
+  /* zero carry */
+  u = 0;
+
+  /* compute columns */
+  for (ix = 0; ix < a->used; ix++) {
+    /* compute product and carry sum for this term */
+    r       = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+    /* mask off higher bits to get a single digit */
+    *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+    /* send carry into next iteration */
+    u       = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+  }
+
+  /* store final carry [if any] and increment ix offset  */
+  *tmpc++ = u;
+  ++ix;
+
+  /* now zero digits above the top */
+  while (ix++ < olduse) {
+     *tmpc++ = 0;
+  }
+
+  /* set used count */
+  c->used = a->used + 1;
+  mp_clamp(c);
+
+  return MP_OKAY;
+}
+#endif

Modified: wpasupplicant/branches/upstream/current/src/utils/base64.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/base64.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/base64.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/base64.c Sat Jun 14 00:26:56 2008
@@ -115,7 +115,7 @@
 			count++;
 	}
 
-	if (count % 4)
+	if (count == 0 || count % 4)
 		return NULL;
 
 	olen = count / 4 * 3;

Modified: wpasupplicant/branches/upstream/current/src/utils/common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/common.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/common.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/common.h Sat Jun 14 00:26:56 2008
@@ -428,6 +428,10 @@
 
 const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
 
+static inline int is_zero_ether_addr(const u8 *a)
+{
+	return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
+}
 
 #include "wpa_debug.h"
 

Modified: wpasupplicant/branches/upstream/current/src/utils/eloop.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop.c Sat Jun 14 00:26:56 2008
@@ -242,7 +242,10 @@
 	timeout = os_malloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	os_get_time(&timeout->time);
+	if (os_get_time(&timeout->time) < 0) {
+		os_free(timeout);
+		return -1;
+	}
 	timeout->time.sec += secs;
 	timeout->time.usec += usecs;
 	while (timeout->time.usec >= 1000000) {
@@ -309,6 +312,25 @@
 	}
 
 	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+
+		tmp = tmp->next;
+	}
+
+	return 0;
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/utils/eloop.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop.h Sat Jun 14 00:26:56 2008
@@ -207,6 +207,19 @@
 			 void *eloop_data, void *user_data);
 
 /**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data);
+
+/**
  * eloop_register_signal - Register handler for signals
  * @sig: Signal number (e.g., SIGHUP)
  * @handler: Callback function to be called when the signal is received

Modified: wpasupplicant/branches/upstream/current/src/utils/eloop_none.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop_none.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop_none.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop_none.c Sat Jun 14 00:26:56 2008
@@ -194,6 +194,26 @@
 	}
 
 	return removed;
+}
+
+
+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
+						void *timeout_ctx),
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+
+		tmp = tmp->next;
+	}
+
+	return 0;
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/utils/eloop_win.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/eloop_win.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop_win.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop_win.c Sat Jun 14 00:26:56 2008
@@ -317,6 +317,25 @@
 	}
 
 	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+
+		tmp = tmp->next;
+	}
+
+	return 0;
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.c Sat Jun 14 00:26:56 2008
@@ -1,6 +1,6 @@
 /*
  * Dynamic data buffer
- * Copyright (c) 2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2007-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -123,3 +123,40 @@
 	}
 	return tmp;
 }
+
+
+/**
+ * wpabuf_concat - Concatenate two buffers into a newly allocated one
+ * @a: First buffer
+ * @b: Second buffer
+ * Returns: wpabuf with concatenated a + b data or %NULL on failure
+ *
+ * Both buffers a and b will be freed regardless of the return value. Input
+ * buffers can be %NULL which is interpreted as an empty buffer.
+ */
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
+{
+	struct wpabuf *n = NULL;
+	size_t len = 0;
+
+	if (b == NULL)
+		return a;
+
+	if (a)
+		len += wpabuf_len(a);
+	if (b)
+		len += wpabuf_len(b);
+
+	n = wpabuf_alloc(len);
+	if (n) {
+		if (a)
+			wpabuf_put_buf(n, a);
+		if (b)
+			wpabuf_put_buf(n, b);
+	}
+
+	wpabuf_free(a);
+	wpabuf_free(b);
+
+	return n;
+}

Modified: wpasupplicant/branches/upstream/current/src/utils/wpabuf.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpabuf.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpabuf.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpabuf.h Sat Jun 14 00:26:56 2008
@@ -36,6 +36,7 @@
 struct wpabuf * wpabuf_dup(const struct wpabuf *src);
 void wpabuf_free(struct wpabuf *buf);
 void * wpabuf_put(struct wpabuf *buf, size_t len);
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
 
 
 /**

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sat Jun 14 00:26:56 2008
@@ -1,4 +1,21 @@
 ChangeLog for wpa_supplicant
+
+????-??-?? - v0.6.4
+	* added support for EAP Sequences in EAP-FAST Phase 2
+	* added support for using TNC with EAP-FAST
+	* added driver_ps3 for the PS3 Linux wireless driver
+	* added support for optional cryptobinding with PEAPv0
+	* fixed the OpenSSL patches (0.9.8g and 0.9.9) for EAP-FAST to
+	  allow fallback to full handshake if server rejects PAC-Opaque
+	* added fragmentation support for EAP-TNC
+	* added support for parsing PKCS #8 formatted private keys into the
+	  internal TLS implementation (both PKCS #1 RSA key and PKCS #8
+	  encapsulated RSA key can now be used)
+	* added option of using faster, but larger, routines in the internal
+	  LibTomMath (for internal TLS implementation) to speed up DH and RSA
+	  calculations (CONFIG_INTERNAL_LIBTOMMATH_FAST=y)
+	* fixed race condition between disassociation event and group key
+	  handshake to avoid getting stuck in incorrect state [Bug 261]
 
 2008-02-22 - v0.6.3
 	* removed 'nai' and 'eappsk' network configuration variables that were

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sat Jun 14 00:26:56 2008
@@ -127,6 +127,12 @@
 CONFIG_WIRELESS_EXTENSION=y
 endif
 
+ifdef CONFIG_DRIVER_NL80211
+CFLAGS += -DCONFIG_DRIVER_NL80211
+OBJS_d += ../src/drivers/driver_nl80211.o
+LIBS += -lnl
+endif
+
 ifdef CONFIG_DRIVER_PRISM54
 CFLAGS += -DCONFIG_DRIVER_PRISM54
 OBJS_d += ../src/drivers/driver_prism54.o
@@ -210,6 +216,12 @@
 LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
 endif
 
+ifdef CONFIG_DRIVER_PS3
+CFLAGS += -DCONFIG_DRIVER_PS3 -m64
+OBJS_d += ../src/drivers/driver_ps3.o
+LDFLAGS += -m64
+endif
+
 ifdef CONFIG_DRIVER_IPHONE
 CFLAGS += -DCONFIG_DRIVER_IPHONE
 OBJS_d += ../src/drivers/driver_iphone.o
@@ -264,11 +276,11 @@
 else
 CFLAGS += -DEAP_PEAP
 OBJS += ../src/eap_peer/eap_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
 OBJS_h += ../src/eap_server/eap_peap.o
 endif
 TLS_FUNCS=y
 CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_TLV=y
 endif
 
 ifdef CONFIG_EAP_TTLS
@@ -411,21 +423,16 @@
 NEED_FIPS186_2_PRF=y
 endif
 
-ifdef CONFIG_EAP_TLV
-# EAP-TLV
-CFLAGS += -DEAP_TLV
-OBJS += ../src/eap_peer/eap_tlv.o
-OBJS_h += ../src/eap_server/eap_tlv.o
-endif
-
 ifdef CONFIG_EAP_FAST
 # EAP-FAST
 ifeq ($(CONFIG_EAP_FAST), dyn)
 CFLAGS += -DEAP_FAST_DYNAMIC
 EAPDYN += ../src/eap_peer/eap_fast.so
+EAPDYN += ../src/eap_common/eap_fast_common.o
 else
 CFLAGS += -DEAP_FAST
 OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS += ../src/eap_common/eap_fast_common.o
 OBJS_h += ../src/eap_server/eap_fast.o
 endif
 TLS_FUNCS=y
@@ -621,6 +628,9 @@
 ifeq ($(CONFIG_CRYPTO), internal)
 ifdef CONFIG_INTERNAL_LIBTOMMATH
 CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
 else
 LIBS += -ltommath
 LIBS_p += -ltommath

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.c Sat Jun 14 00:26:56 2008
@@ -1296,6 +1296,11 @@
 	{ STR_KEYe(pin) },
 	{ STRe(engine_id) },
 	{ STRe(key_id) },
+	{ STRe(cert_id) },
+	{ STRe(ca_cert_id) },
+	{ STRe(key2_id) },
+	{ STRe(cert2_id) },
+	{ STRe(ca_cert2_id) },
 	{ INTe(engine) },
 	{ INT(eapol_flags) },
 #endif /* IEEE8021X_EAPOL */
@@ -1453,6 +1458,11 @@
 	os_free(eap->pin);
 	os_free(eap->engine_id);
 	os_free(eap->key_id);
+	os_free(eap->cert_id);
+	os_free(eap->ca_cert_id);
+	os_free(eap->key2_id);
+	os_free(eap->cert2_id);
+	os_free(eap->ca_cert2_id);
 	os_free(eap->otp);
 	os_free(eap->pending_req_otp);
 	os_free(eap->pac_file);

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c Sat Jun 14 00:26:56 2008
@@ -754,6 +754,11 @@
 	STR(pin);
 	STR(engine_id);
 	STR(key_id);
+	STR(cert_id);
+	STR(ca_cert_id);
+	STR(key2_id);
+	STR(cert2_id);
+	STR(ca_cert2_id);
 	INTe(engine);
 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
 #endif /* IEEE8021X_EAPOL */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c Sat Jun 14 00:26:56 2008
@@ -766,6 +766,11 @@
 	STR(pin);
 	STR(engine_id);
 	STR(key_id);
+	STR(cert_id);
+	STR(ca_cert_id);
+	STR(key2_id);
+	STR(cert2_id);
+	STR(ca_cert2_id);
 	INTe(engine);
 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
 #endif /* IEEE8021X_EAPOL */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c Sat Jun 14 00:26:56 2008
@@ -76,6 +76,7 @@
 }
 
 
+#ifdef IEEE8021X_EAPOL
 static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
 					     char *addr)
 {
@@ -95,6 +96,7 @@
 
 	return 0;
 }
+#endif /* IEEE8021X_EAPOL */
 
 
 #ifdef CONFIG_PEERKEY
@@ -328,9 +330,7 @@
 	}
 
 	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
-	ssid->bssid_set =
-		os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
-		
+	ssid->bssid_set = !is_zero_ether_addr(bssid);
 
 	return 0;
 }
@@ -1396,9 +1396,11 @@
 			wpa_s->reassociate = 1;
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
+#ifdef IEEE8021X_EAPOL
 	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
 		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
 			reply_len = -1;
+#endif /* IEEE8021X_EAPOL */
 #ifdef CONFIG_PEERKEY
 	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
 		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c Sat Jun 14 00:26:56 2008
@@ -21,10 +21,10 @@
 #include "ctrl_iface_dbus.h"
 #include "ctrl_iface_dbus_handlers.h"
 
-#define DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
+#define _DBUS_VERSION (DBUS_VERSION_MAJOR << 8 | DBUS_VERSION_MINOR)
 #define DBUS_VER(major, minor) ((major) << 8 | (minor))
 
-#if DBUS_VERSION < DBUS_VER(1,1)
+#if _DBUS_VERSION < DBUS_VER(1,1)
 #define dbus_watch_get_unix_fd dbus_watch_get_fd
 #endif
 
@@ -534,6 +534,9 @@
 			reply = wpas_dbus_iface_disconnect(message, wpa_s);
 		else if (!strcmp(method, "setAPScan"))
 			reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
+		else if (!strcmp(method, "setSmartcardModules"))
+			reply = wpas_dbus_iface_set_smartcard_modules(message,
+								      wpa_s);
 		else if (!strcmp(method, "state"))
 			reply = wpas_dbus_iface_get_state(message, wpa_s);
 		else if (!strcmp(method, "setBlobs"))

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.c Sat Jun 14 00:26:56 2008
@@ -22,6 +22,8 @@
 #include "eap_peer/eap_methods.h"
 #include "dbus_dict_helpers.h"
 #include "ieee802_11_defs.h"
+#include "wpas_glue.h"
+#include "eapol_supp/eapol_supp_sm.h"
 
 
 /**
@@ -1179,6 +1181,76 @@
 
 
 /**
+ * wpas_dbus_iface_set_smartcard_modules - Set smartcard related module paths
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ *          failure (0)
+ *
+ * Handler function for "setSmartcardModules" method call.
+ */
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
+{
+	DBusMessageIter iter, iter_dict;
+	char *opensc_engine_path = NULL;
+	char *pkcs11_engine_path = NULL;
+	char *pkcs11_module_path = NULL;
+	struct wpa_dbus_dict_entry entry;
+
+	if (!dbus_message_iter_init(message, &iter))
+		goto error;
+
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		goto error;
+
+	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+		if (!strcmp(entry.key, "opensc_engine_path") &&
+		    (entry.type == DBUS_TYPE_STRING)) {
+			opensc_engine_path = os_strdup(entry.str_value);
+			if (opensc_engine_path == NULL)
+				goto error;
+		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
+			   (entry.type == DBUS_TYPE_STRING)) {
+			pkcs11_engine_path = os_strdup(entry.str_value);
+			if (pkcs11_engine_path == NULL)
+				goto error;
+		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
+				 (entry.type == DBUS_TYPE_STRING)) {
+			pkcs11_module_path = os_strdup(entry.str_value);
+			if (pkcs11_module_path == NULL)
+				goto error;
+		} else {
+			wpa_dbus_dict_entry_clear(&entry);
+			goto error;
+		}
+		wpa_dbus_dict_entry_clear(&entry);
+	}
+
+#ifdef EAP_TLS_OPENSSL
+	os_free(wpa_s->conf->opensc_engine_path);
+	wpa_s->conf->opensc_engine_path = opensc_engine_path;
+	os_free(wpa_s->conf->pkcs11_engine_path);
+	wpa_s->conf->pkcs11_engine_path = pkcs11_engine_path;
+	os_free(wpa_s->conf->pkcs11_module_path);
+	wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
+#endif /* EAP_TLS_OPENSSL */
+
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_supplicant_init_eapol(wpa_s);
+
+	return wpas_dbus_new_success_reply(message);
+
+error:
+	os_free(opensc_engine_path);
+	os_free(pkcs11_engine_path);
+	os_free(pkcs11_module_path);
+	return wpas_dbus_new_invalid_opts_error(message, NULL);
+}
+
+/**
  * wpas_dbus_iface_get_state - Get interface state
  * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus_handlers.h Sat Jun 14 00:26:56 2008
@@ -68,6 +68,9 @@
 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
                                           struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_iface_set_smartcard_modules(
+	DBusMessage *message, struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
 					struct wpa_supplicant *wpa_s);
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_unix.c Sat Jun 14 00:26:56 2008
@@ -311,7 +311,7 @@
 			/* Group name not found - try to parse this as gid */
 			gid = strtol(gid_str, &endp, 10);
 			if (*gid_str == '\0' || *endp != '\0') {
-				wpa_printf(MSG_DEBUG, "CTRL: Invalid group "
+				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
 					   "'%s'", gid_str);
 				goto fail;
 			}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c Sat Jun 14 00:26:56 2008
@@ -674,7 +674,7 @@
 	/* Zero-length arrays are valid. */
 	if (entry->array_len == 0) {
 		free(entry->bytearray_value);
-		entry->strarray_value = NULL;
+		entry->bytearray_value = NULL;
 	}
 
 	success = TRUE;

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig Sat Jun 14 00:26:56 2008
@@ -307,6 +307,10 @@
 #LIBS += -L$(LTM_PATH)
 #LIBS_p += -L$(LTM_PATH)
 #endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
 
 # Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
 # This is only for Windows builds and requires WMI-related header files and

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.sgml Sat Jun 14 00:26:56 2008
@@ -72,17 +72,18 @@
    case of OTP request, it includes the challenge from the
    authentication server.</para>
 
-    <para>The reply to these requests can be given with 'identity',
-    'password', and 'otp' commands. &lt;id&gt; needs to be copied from the
-    the matching request. 'password' and 'otp' commands can be used
-    regardless of whether the request was for PASSWORD or OTP. The
-    main difference between these two commands is that values given
-    with 'password' are remembered as long as wpa_supplicant is
-    running whereas values given with 'otp' are used only once and
-    then forgotten, i.e., wpa_supplicant will ask frontend for a new
-    value for every use. This can be used to implement
-    one-time-password lists and generic token card -based
-    authentication.</para>
+    <para>The reply to these requests can be given with
+    <emphasis>identity</emphasis>, <emphasis>password</emphasis>, and
+    <emphasis>otp</emphasis> commands. &lt;id&gt; needs to be copied from
+    the matching request. <emphasis>password</emphasis> and
+    <emphasis>otp</emphasis> commands can be used regardless of whether
+    the request was for PASSWORD or OTP. The main difference between these
+    two commands is that values given with <emphasis>password</emphasis> are
+    remembered as long as wpa_supplicant is running whereas values given
+    with <emphasis>otp</emphasis> are used only once and then forgotten,
+    i.e., wpa_supplicant will ask frontend for a new value for every use.
+    This can be used to implement one-time-password lists and generic token
+    card -based authentication.</para>
 
     <para>Example request for password and a matching reply:</para>
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.sgml Sat Jun 14 00:26:56 2008
@@ -49,9 +49,9 @@
     <title>Example configuration</title>
 
     <para>The following steps are an example of how to configure
-    <command>wpa_priv</command> to allow users in the 'wpapriv' group
-    to communicate with <command>wpa_supplicant</command> with privilege
-    separation:</para>
+    <command>wpa_priv</command> to allow users in the
+    <emphasis>wpapriv</emphasis> group to communicate with
+    <command>wpa_supplicant</command> with privilege separation:</para>
 
     <para>Create user group (e.g., wpapriv) and assign users that
     should be able to use wpa_supplicant into that group.</para>
@@ -111,7 +111,7 @@
 	supported <command>wpa_supplicant</command> driver backends is to be
 	used. To get a list of supported driver types see wpa_supplicant help
 	(e.g, wpa_supplicant -h). The driver backend supported by most good
-	drivers is 'wext'.</para>
+	drivers is <emphasis>wext</emphasis>.</para>
 
 	<para>The &lt;ifname&gt; string specifies which network
 	interface is to be managed by <command>wpa_supplicant</command>

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml Sat Jun 14 00:26:56 2008
@@ -26,7 +26,7 @@
     <para>Changes to configuration file can be reloaded be sending
     SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP
     wpa_supplicant'). Similarly, reloading can be triggered with
-    the 'wpa_cli reconfigure' command.</para>
+    the <emphasis>wpa_cli reconfigure</emphasis> command.</para>
 
     <para>Configuration file can include one or more network blocks,
     e.g., one for each used SSID. wpa_supplicant will automatically
@@ -174,7 +174,7 @@
 
       <listitem>
 	<para>Authentication for wired Ethernet. This can be used with
-       'wired' interface (-Dwired on command line).</para>
+       <emphasis>wired</emphasis> interface (-Dwired on command line).</para>
 
 <blockquote><programlisting>
 ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=wheel

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml Sat Jun 14 00:26:56 2008
@@ -238,7 +238,11 @@
 
   <refsect1>
     <title>Available Drivers</title>
-    <para>The available drivers to specify with the -D option are:</para>
+    <para>A summary of available driver backends is below. Support for each
+    of the driver backends is chosen at wpa_supplicant compile time. For a
+    list of supported driver backends that may be used with the -D option on
+    your system, refer to the help output of wpa_supplicant
+    (<emphasis>wpa_supplicant -h</emphasis>).</para>
 
     <variablelist>
       <varlistentry>
@@ -530,9 +534,9 @@
 	snapshot/v0.2.x)</term>
 	<listitem>
 	  <para> (http://hostap.epitest.fi/) Driver needs to be set in
-	Managed mode ('iwconfig wlan0 mode managed').  Please note
-	that station firmware version needs to be 1.7.0 or newer to
-	work in WPA mode.</para>
+	  Managed mode (<emphasis>iwconfig wlan0 mode managed</emphasis>).
+	  Please note that station firmware version needs to be 1.7.0 or
+	  newer to work in WPA mode.</para>
 	</listitem>
       </varlistentry>
 
@@ -736,8 +740,8 @@
     <para>Add MODE="Managed" and WPA="y" to the network scheme in
     <filename>/etc/pcmcia/wireless.opts</filename>.</para>
 
-    <para>Add the following block to the end of 'start' action handler
-    in <filename>/etc/pcmcia/wireless</filename>:</para>
+    <para>Add the following block to the end of <emphasis>start</emphasis>
+    action handler in <filename>/etc/pcmcia/wireless</filename>:</para>
 
     <blockquote><programlisting>
 if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
@@ -746,8 +750,8 @@
     </programlisting></blockquote>
 
 
-    <para>Add the following block to the end of 'stop' action handler
-    (may need to be separated from other actions) in
+    <para>Add the following block to the end of <emphasis>stop</emphasis>
+    action handler (may need to be separated from other actions) in
     <filename>/etc/pcmcia/wireless</filename>:</para>
 
     <blockquote><programlisting>

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt Sat Jun 14 00:26:56 2008
@@ -91,6 +91,7 @@
 EAP-TTLS/EAP-PAX	-   -   -   -   -   -   -   -   -   -   +   -
 EAP-TTLS/EAP-SAKE	-   -   -   -   -   -   -   -   -   -   +   -
 EAP-TTLS/EAP-GPSK	-   -   -   -   -   -   -   -   -   -   +   -
+EAP-TTLS + TNC		-   -   -   -   -   +   -   -   -   -   +   -
 EAP-SIM			+   -   -   ?   -   +   -   ?   -   -   +   -
 EAP-AKA			-   -   -   -   -   +   -   -   -   -   +   -
 EAP-PSK			+7  -   -   -   -   +   -   -   -   -   +   -
@@ -110,8 +111,9 @@
 EAP-FAST/TLS(auth)	-   -   -   -   -   -   -   -   -   -   +   +
 EAP-FAST/SIM(auth)	-   -   -   -   -   -   -   -   -   -   +   -
 EAP-FAST/AKA(auth)	-   -   -   -   -   -   -   -   -   -   +   -
+EAP-FAST + TNC		-   -   -   -   -   -   -   -   -   -   +   -
 LEAP			+   -   +   +   +   +   F   +6  -   +   -   +
-EAP-TNC			+9  -   -   -   -   +   -   -   -   -   -   -
+EAP-TNC			+9  -   -   -   -   +   -   -   -   -   +   -
 EAP-IKEv2		+10 -   -   -   -   -   -   -   -   -   +   -
 
 1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sat Jun 14 00:26:56 2008
@@ -66,6 +66,8 @@
 
 	char *connect_info;
 	u8 own_addr[ETH_ALEN];
+	int cui_flag;
+	char *cui_str;
 };
 
 static struct eapol_test_data eapol_test;
@@ -162,6 +164,23 @@
 				 (u8 *) buf, os_strlen(buf))) {
 		printf("Could not add Connect-Info\n");
 		goto fail;
+	}
+
+	if (e->cui_flag) {
+		int l = 0;
+		if (e->cui_flag == 1) {
+			l = 1;
+			buf[0] = '\0';
+		} else if (e->cui_flag == 2) {
+			os_snprintf(buf, sizeof(buf), "%s", e->cui_str);
+			l = os_strlen(buf);
+		}
+		if (!radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 (u8 *) buf, l)) {
+			printf("Could not add Chargeable-User-Identity\n");
+			goto fail;
+		}
 	}
 
 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
@@ -616,7 +635,8 @@
 
 static void wpa_init_conf(struct eapol_test_data *e,
 			  struct wpa_supplicant *wpa_s, const char *authsrv,
-			  int port, const char *secret)
+			  int port, const char *secret,
+			  const char *cli_addr)
 {
 	struct hostapd_radius_server *as;
 	int res;
@@ -652,6 +672,16 @@
 	e->radius_conf->auth_server = as;
 	e->radius_conf->auth_servers = as;
 	e->radius_conf->msg_dumps = 1;
+	if (cli_addr) {
+		if (hostapd_parse_ip_addr(cli_addr,
+					  &e->radius_conf->client_addr) == 0)
+			e->radius_conf->force_client_addr = 1;
+		else {
+			wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+				   cli_addr);
+			assert(0);
+		}
+	}
 
 	e->radius = radius_client_init(wpa_s, e->radius_conf);
 	assert(e->radius != NULL);
@@ -846,9 +876,10 @@
 {
 	printf("usage:\n"
 	       "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
-	       "[-s<AS secret>] \\\n"
+	       "[-s<AS secret>]\\\n"
 	       "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
-	       "           [-M<client MAC address>]\n"
+	       "           [-M<client MAC address>] \\\n"
+	       "           [-I<CUI>] [-i] [-A<client IP>]\n"
 	       "eapol_test scard\n"
 	       "eapol_test sim <PIN> <num triplets> [debug]\n"
 	       "\n");
@@ -860,6 +891,8 @@
 	       "default 1812\n"
 	       "  -s<AS secret> = shared secret with the authentication "
 	       "server, default 'radius'\n"
+	       "  -A<client IP> = IP address of the client, default: select "
+	       "automatically\n"
 	       "  -r<count> = number of re-authentications\n"
 	       "  -W = wait for a control interface monitor before starting\n"
 	       "  -S = save configuration after authentiation\n"
@@ -869,7 +902,10 @@
 	       "CONNECT 11Mbps 802.11b)\n"
 	       "  -M<client MAC address> = Set own MAC address "
 	       "(Calling-Station-Id,\n"
-	       "                           default: 02:00:00:00:00:01)\n");
+	       "                           default: 02:00:00:00:00:01)\n"
+	       "  -I<CUI> = send Chargeable-User-Identity containing the "
+	       "value of CUI\n"
+	       "  -i = send NUL value in Chargeable-User-Identity\n");
 }
 
 
@@ -880,6 +916,7 @@
 	char *as_addr = "127.0.0.1";
 	int as_port = 1812;
 	char *as_secret = "radius";
+	char *cli_addr = NULL;
 	char *conf = NULL;
 	int timeout = 30;
 
@@ -896,18 +933,28 @@
 	wpa_debug_show_keys = 1;
 
 	for (;;) {
-		c = getopt(argc, argv, "a:c:C:M:np:r:s:St:W");
+		c = getopt(argc, argv, "a:A:c:C:iI:M:np:r:s:St:W");
 		if (c < 0)
 			break;
 		switch (c) {
 		case 'a':
 			as_addr = optarg;
 			break;
+		case 'A':
+			cli_addr = optarg;
+			break;
 		case 'c':
 			conf = optarg;
 			break;
 		case 'C':
 			eapol_test.connect_info = optarg;
+			break;
+		case 'i':
+			eapol_test.cui_flag = 1;
+			break;
+		case 'I':
+			eapol_test.cui_flag = 2;
+			eapol_test.cui_str = optarg;
 			break;
 		case 'M':
 			if (hwaddr_aton(optarg, eapol_test.own_addr)) {
@@ -979,7 +1026,8 @@
 		return -1;
 	}
 
-	wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret);
+	wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret,
+		      cli_addr);
 	wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
 	if (wpa_s.ctrl_iface == NULL) {
 		printf("Failed to initialize control interface '%s'.\n"

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sat Jun 14 00:26:56 2008
@@ -805,7 +805,7 @@
 	if (wpa_s->wpa_state >= WPA_ASSOCIATED)
 		wpa_supplicant_req_scan(wpa_s, 0, 100000);
 	bssid = wpa_s->bssid;
-	if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	if (is_zero_ether_addr(bssid))
 		bssid = wpa_s->pending_bssid;
 	wpa_blacklist_add(wpa_s, bssid);
 	wpa_sm_notify_disassoc(wpa_s->wpa);

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf?rev=1186&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/examples/openCryptoki.conf Sat Jun 14 00:26:56 2008
@@ -1,0 +1,41 @@
+# EAP-TLS using private key and certificates via OpenSSL PKCS#11 engine and
+# openCryptoki (e.g., with TPM token)
+
+# This example uses following PKCS#11 objects:
+# $ pkcs11-tool --module /usr/lib/opencryptoki/libopencryptoki.so  -O -l
+# Please enter User PIN:
+# Private Key Object; RSA
+#   label:      rsakey
+#   ID:         04
+#   Usage:      decrypt, sign, unwrap
+# Certificate Object, type = X.509 cert
+#   label:      ca
+#   ID:         01
+# Certificate Object, type = X.509 cert
+#   label:      cert
+#   ID:         04
+
+# Configure OpenSSL to load the PKCS#11 engine and openCryptoki module
+pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so
+pkcs11_module_path=/usr/lib/opencryptoki/libopencryptoki.so
+
+network={
+	ssid="test network"
+	key_mgmt=WPA-EAP
+	eap=TLS
+	identity="User"
+
+	# use OpenSSL PKCS#11 engine for this network
+	engine=1
+	engine_id="pkcs11"
+
+	# select the private key and certificates based on ID (see pkcs11-tool
+	# output above)
+	key_id="4"
+	cert_id="4"
+	ca_cert_id="1"
+
+	# set the PIN code; leave this out to configure the PIN to be requested
+	# interactively when needed (e.g., via wpa_gui or wpa_cli)
+	pin="123456"
+}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/main.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/main.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/main.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/main.c Sat Jun 14 00:26:56 2008
@@ -39,7 +39,7 @@
 	int i;
 	printf("%s\n\n%s\n"
 	       "usage:\n"
-	       "  wpa_supplicant [-BddhKLqqtuvwW] [-P<pid file>] "
+	       "  wpa_supplicant [-BddhKLqqtuvW] [-P<pid file>] "
 	       "[-g<global ctrl>] \\\n"
 	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
 	       "[-p<driver_param>] \\\n"

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sat Jun 14 00:26:56 2008
@@ -356,7 +356,7 @@
 
 static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
 {
-	if (wpa_s->mlme.associated == assoc)
+	if (wpa_s->mlme.associated == assoc && !assoc)
 		return;
 
 	wpa_s->mlme.associated = assoc;
@@ -1051,6 +1051,7 @@
 		data.ft_ies.ies = mgmt->u.auth.variable;
 		data.ft_ies.ies_len = len -
 			(mgmt->u.auth.variable - (u8 *) mgmt);
+		os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
 		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
 		ieee80211_auth_completed(wpa_s);
 		break;
@@ -1258,7 +1259,8 @@
 			return;
 		}
 		if (wpa_ft_validate_reassoc_resp(
-			    wpa_s->wpa, pos, len - (pos - (u8 *) mgmt)) < 0) {
+			    wpa_s->wpa, pos, len - (pos - (u8 *) mgmt),
+			    mgmt->sa) < 0) {
 			wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc"
 				   "Resp failed");
 			return;
@@ -2453,8 +2455,7 @@
 	wpa_s->mlme.freq = params->freq;
 	if (params->bssid) {
 		os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
-		if (os_memcmp(params->bssid, "\x00\x00\x00\x00\x00\x00",
-			      ETH_ALEN))
+		if (!is_zero_ether_addr(params->bssid))
 			wpa_s->mlme.bssid_set = 1;
 		bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
 		if (bss) {

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/preauth_test.c Sat Jun 14 00:26:56 2008
@@ -43,18 +43,6 @@
 };
 
 
-static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
-{
-	wpa_supplicant_req_scan(wpa_s, sec, usec);
-}
-
-
-static void _wpa_supplicant_cancel_scan(void *wpa_s)
-{
-	wpa_supplicant_cancel_scan(wpa_s);
-}
-
-
 static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
 {
 	wpa_supplicant_disassociate(wpa_s, reason_code);
@@ -253,8 +241,6 @@
 	ctx->ctx = wpa_s;
 	ctx->set_state = _wpa_supplicant_set_state;
 	ctx->get_state = _wpa_supplicant_get_state;
-	ctx->req_scan = _wpa_supplicant_req_scan;
-	ctx->cancel_scan = _wpa_supplicant_cancel_scan;
 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
 	ctx->disassociate = _wpa_supplicant_disassociate;
 	ctx->set_key = wpa_supplicant_set_key;

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c Sat Jun 14 00:26:56 2008
@@ -172,6 +172,28 @@
  */
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
 {
+	/* If there's at least one network that should be specifically scanned
+	 * then don't cancel the scan and reschedule.  Some drivers do
+	 * background scanning which generates frequent scan results, and that
+	 * causes the specific SSID scan to get continually pushed back and
+	 * never happen, which causes hidden APs to never get probe-scanned.
+	 */
+	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
+	    wpa_s->conf->ap_scan == 1) {
+		struct wpa_ssid *ssid = wpa_s->conf->ssid;
+
+		while (ssid) {
+			if (!ssid->disabled && ssid->scan_ssid)
+				break;
+			ssid = ssid->next;
+		}
+		if (ssid) {
+			wpa_msg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
+			        "ensure that specific SSID scans occur");
+			return;
+		}
+	}
+
 	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
 		sec, usec);
 	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/todo.txt Sat Jun 14 00:26:56 2008
@@ -59,7 +59,6 @@
   could very well be done before EAP has been started
 - try to work around race in receiving association event and first EAPOL
   message
-- helper function to do memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
 - add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
   clear memory; this would be used to clear temporary buffers containing
   private data (e.g., keys); the macro can be defined to NOP in order to save

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.h Sat Jun 14 00:26:56 2008
@@ -10,6 +10,7 @@
 ** destructor.
 *****************************************************************************/
 
+#include <stdlib.h>
 
 enum {
     AUTH_NONE = 0,

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/userdatarequest.ui.h Sat Jun 14 00:26:56 2008
@@ -9,6 +9,8 @@
 ** These will automatically be called by the form's constructor and
 ** destructor.
 *****************************************************************************/
+
+#include <stdlib.h>
 
 int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
 {

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpagui.ui.h Sat Jun 14 00:26:56 2008
@@ -16,6 +16,7 @@
 #include <unistd.h>
 #endif
 
+#include <stdlib.h>
 
 void WpaGui::init()
 {

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/wpamsg.h Sat Jun 14 00:26:56 2008
@@ -14,6 +14,7 @@
 
 class WpaMsg {
 public:
+    WpaMsg() {}
     WpaMsg(const QString &_msg, int _priority = 2)
 	: msg(_msg), priority(_priority)
     {

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sat Jun 14 00:26:56 2008
@@ -187,7 +187,7 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	const u8 *bssid = wpa_s->bssid;
-	if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+	if (is_zero_ether_addr(bssid))
 		bssid = wpa_s->pending_bssid;
 	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
 		MAC2STR(bssid));
@@ -1090,13 +1090,15 @@
 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 	} else {
 		/* Timeout for IEEE 802.11 authentication and association */
-		int timeout;
-		if (assoc_failed)
-			timeout = 5;
-		else if (wpa_s->conf->ap_scan == 1)
-			timeout = 10;
-		else
-			timeout = 60;
+		int timeout = 60;
+
+		if (assoc_failed) {
+			/* give IBSS a bit more time */
+ 			timeout = ssid->mode ? 10 : 5;
+		} else if (wpa_s->conf->ap_scan == 1) {
+			/* give IBSS a bit more time */
+ 			timeout = ssid->mode ? 20 : 10;
+		}
 		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
 	}
 
@@ -1131,8 +1133,7 @@
 				 int reason_code)
 {
 	u8 *addr = NULL;
-	if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
-	{
+	if (!is_zero_ether_addr(wpa_s->bssid)) {
 		if (wpa_s->use_client_mlme)
 			ieee80211_sta_disassociate(wpa_s, reason_code);
 		else
@@ -1160,8 +1161,7 @@
 {
 	u8 *addr = NULL;
 	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
-	if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
-	{
+	if (!is_zero_ether_addr(wpa_s->bssid)) {
 		if (wpa_s->use_client_mlme)
 			ieee80211_sta_deauthenticate(wpa_s, reason_code);
 		else

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sat Jun 14 00:26:56 2008
@@ -304,7 +304,7 @@
 #	MSCHAP (EAP-MSCHAPv2, EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
 #	EAP-PSK (128-bit PSK), EAP-PAX (128-bit PSK), and EAP-SAKE (256-bit
 #	PSK) is also configured using this field. For EAP-GPSK, this is a
-	variable length PSK.
+#	variable length PSK.
 # ca_cert: File path to CA certificate file (PEM/DER). This file can have one
 #	or more trusted CA certificates. If ca_cert and ca_path are not
 #	included, server certificate will not be verified. This is insecure and
@@ -387,6 +387,11 @@
 #	challenges (by default, it accepts 2 or 3)
 #	result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
 #	protected result indication.
+#	'crypto_binding' option can be used to control PEAPv0 cryptobinding
+#	behavior:
+#	 * 0 = do not use cryptobinding
+#	 * 1 = use cryptobinding if server supports it (default)
+#	 * 2 = require cryptobinding
 # phase2: Phase2 (inner authentication with TLS tunnel) parameters
 #	(string with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
 #	"autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS)

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c?rev=1186&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c Sat Jun 14 00:26:56 2008
@@ -143,13 +143,11 @@
 		return -1;
 	}
 
-	if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
-	{
+	if (is_zero_ether_addr(wpa_s->bssid)) {
 		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
 			   "EAPOL frame");
 		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
-		    os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) !=
-		    0) {
+		    !is_zero_ether_addr(bssid)) {
 			dst = bssid;
 			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
 				   " from the driver as the EAPOL destination",
@@ -271,7 +269,6 @@
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
 		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
 	} else {
-		wpa_supplicant_cancel_scan(wpa_s);
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
 		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
 	}
@@ -355,18 +352,6 @@
 }
 
 
-static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
-{
-	wpa_supplicant_req_scan(wpa_s, sec, usec);
-}
-
-
-static void _wpa_supplicant_cancel_scan(void *wpa_s)
-{
-	wpa_supplicant_cancel_scan(wpa_s);
-}
-
-
 static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
 {
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
@@ -399,12 +384,16 @@
 static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
 {
 	wpa_supplicant_disassociate(wpa_s, reason_code);
+	/* Schedule a scan to make sure we continue looking for networks */
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
 
 static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
 {
 	wpa_supplicant_deauthenticate(wpa_s, reason_code);
+	/* Schedule a scan to make sure we continue looking for networks */
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
 }
 
 
@@ -576,8 +565,6 @@
 	ctx->ctx = wpa_s;
 	ctx->set_state = _wpa_supplicant_set_state;
 	ctx->get_state = _wpa_supplicant_get_state;
-	ctx->req_scan = _wpa_supplicant_req_scan;
-	ctx->cancel_scan = _wpa_supplicant_cancel_scan;
 	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
 	ctx->disassociate = _wpa_supplicant_disassociate;
 	ctx->set_key = wpa_supplicant_set_key;
@@ -619,8 +606,10 @@
 		os_memset(&conf, 0, sizeof(conf));
 		conf.peerkey_enabled = ssid->peerkey;
 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
+#ifdef IEEE8021X_EAPOL
 		conf.eap_workaround = ssid->eap_workaround;
 		conf.eap_conf_ctx = &ssid->eap;
+#endif /* IEEE8021X_EAPOL */
 		conf.ssid = ssid->ssid;
 		conf.ssid_len = ssid->ssid_len;
 	}




More information about the Pkg-wpa-devel mailing list