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

kelmo-guest at users.alioth.debian.org kelmo-guest at users.alioth.debian.org
Sat Jan 10 08:43:04 UTC 2009


Author: kelmo-guest
Date: Sat Jan 10 08:43:01 2009
New Revision: 1303

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

Added:
    wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h
    wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c
    wpasupplicant/branches/upstream/current/src/wps/
    wpasupplicant/branches/upstream/current/src/wps/.gitignore
    wpasupplicant/branches/upstream/current/src/wps/Makefile
    wpasupplicant/branches/upstream/current/src/wps/wps.c
    wpasupplicant/branches/upstream/current/src/wps/wps.h
    wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c
    wpasupplicant/branches/upstream/current/src/wps/wps_attr_parse.c
    wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c
    wpasupplicant/branches/upstream/current/src/wps/wps_common.c
    wpasupplicant/branches/upstream/current/src/wps/wps_defs.h
    wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.c
    wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.h
    wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c
    wpasupplicant/branches/upstream/current/src/wps/wps_i.h
    wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.links
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.refs
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.nsi
    wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h
Removed:
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/setup-mingw-cross-compiling
Modified:
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.8i-tls-extensions.patch
    wpasupplicant/branches/upstream/current/patches/openssl-0.9.9-session-ticket.patch
    wpasupplicant/branches/upstream/current/src/Makefile
    wpasupplicant/branches/upstream/current/src/common/defs.h
    wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c
    wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h
    wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h
    wpasupplicant/branches/upstream/current/src/common/version.h
    wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h
    wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c
    wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
    wpasupplicant/branches/upstream/current/src/crypto/sha1.c
    wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c
    wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
    wpasupplicant/branches/upstream/current/src/drivers/driver.h
    wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_test.c
    wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c
    wpasupplicant/branches/upstream/current/src/drivers/ndis_events.c
    wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h
    wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.c
    wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c
    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_gpsk.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_methods.c
    wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.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_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_aka.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h
    wpasupplicant/branches/upstream/current/src/eap_server/eap_identity.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.c
    wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.h
    wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c
    wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.h
    wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet.h
    wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_winpcap.c
    wpasupplicant/branches/upstream/current/src/radius/radius_client.c
    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/wpa_ft.c
    wpasupplicant/branches/upstream/current/src/tls/bignum.c
    wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
    wpasupplicant/branches/upstream/current/src/utils/eloop_win.c
    wpasupplicant/branches/upstream/current/src/utils/includes.h
    wpasupplicant/branches/upstream/current/src/utils/ip_addr.c
    wpasupplicant/branches/upstream/current/src/utils/os_unix.c
    wpasupplicant/branches/upstream/current/src/utils/pcsc_funcs.c
    wpasupplicant/branches/upstream/current/src/utils/state_machine.h
    wpasupplicant/branches/upstream/current/src/utils/uuid.c
    wpasupplicant/branches/upstream/current/src/utils/uuid.h
    wpasupplicant/branches/upstream/current/src/utils/wpa_debug.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
    wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
    wpasupplicant/branches/upstream/current/wpa_supplicant/README
    wpasupplicant/branches/upstream/current/wpa_supplicant/README-Windows.txt
    wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/config.h
    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_named_pipe.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/code_structure.doxygen
    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
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.fast
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.full
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/kerneldoc2doxygen.pl
    wpasupplicant/branches/upstream/current/wpa_supplicant/doc/porting.doxygen
    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/main_winsvc.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/win_example.reg
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui/networkconfig.ui.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/wpa_supplicant_i.h
    wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c

Modified: wpasupplicant/branches/upstream/current/patches/openssl-0.9.8i-tls-extensions.patch
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/patches/openssl-0.9.8i-tls-extensions.patch?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/patches/openssl-0.9.8i-tls-extensions.patch (original)
+++ wpasupplicant/branches/upstream/current/patches/openssl-0.9.8i-tls-extensions.patch Sat Jan 10 08:43:01 2009
@@ -9,31 +9,33 @@
 command line.
 
 
-diff -upr openssl-0.9.8i.orig/ssl/s3_clnt.c openssl-0.9.8i/ssl/s3_clnt.c
+Index: openssl-0.9.8i/ssl/s3_clnt.c
+===================================================================
 --- openssl-0.9.8i.orig/ssl/s3_clnt.c	2008-06-16 19:56:41.000000000 +0300
-+++ openssl-0.9.8i/ssl/s3_clnt.c	2008-09-28 16:50:18.000000000 +0300
-@@ -759,6 +759,20 @@ int ssl3_get_server_hello(SSL *s)
++++ openssl-0.9.8i/ssl/s3_clnt.c	2008-11-23 20:39:40.000000000 +0200
+@@ -759,6 +759,21 @@
  		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);
++			{
++			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)
  	    {
-@@ -2701,11 +2715,8 @@ static int ssl3_check_finished(SSL *s)
+@@ -2701,11 +2716,8 @@
  	{
  	int ok;
  	long n;
@@ -47,10 +49,11 @@
  		return 1;
  	/* this function is called when we really expect a Certificate
  	 * message, so permit appropriate message length */
-diff -upr openssl-0.9.8i.orig/ssl/s3_srvr.c openssl-0.9.8i/ssl/s3_srvr.c
+Index: openssl-0.9.8i/ssl/s3_srvr.c
+===================================================================
 --- openssl-0.9.8i.orig/ssl/s3_srvr.c	2008-09-14 21:16:09.000000000 +0300
-+++ openssl-0.9.8i/ssl/s3_srvr.c	2008-09-28 16:50:18.000000000 +0300
-@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s)
++++ openssl-0.9.8i/ssl/s3_srvr.c	2008-11-23 20:37:40.000000000 +0200
+@@ -959,6 +959,59 @@
  			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
  			goto err;
  		}
@@ -66,20 +69,20 @@
 +		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;
@@ -105,12 +108,12 @@
 +
 +			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)
+@@ -1097,16 +1150,22 @@
  	unsigned char *buf;
  	unsigned char *p,*d;
  	int i,sl;
@@ -134,44 +137,51 @@
  		/* Do the message type and length last */
  		d=p= &(buf[4]);
  
-diff -upr openssl-0.9.8i.orig/ssl/ssl_err.c openssl-0.9.8i/ssl/ssl_err.c
+Index: openssl-0.9.8i/ssl/ssl_err.c
+===================================================================
 --- openssl-0.9.8i.orig/ssl/ssl_err.c	2008-08-13 22:44:44.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl_err.c	2008-09-28 16:50:18.000000000 +0300
-@@ -253,6 +253,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
++++ openssl-0.9.8i/ssl/ssl_err.c	2008-11-23 20:33:43.000000000 +0200
+@@ -253,6 +253,7 @@
  {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"},
++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
  {0,NULL}
  	};
  
-diff -upr openssl-0.9.8i.orig/ssl/ssl.h openssl-0.9.8i/ssl/ssl.h
+Index: openssl-0.9.8i/ssl/ssl.h
+===================================================================
 --- openssl-0.9.8i.orig/ssl/ssl.h	2008-08-13 22:44:44.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl.h	2008-09-28 16:50:18.000000000 +0300
-@@ -344,6 +344,7 @@ extern "C" {
++++ openssl-0.9.8i/ssl/ssl.h	2008-11-23 20:35:41.000000000 +0200
+@@ -344,6 +344,7 @@
   * '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;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
  
  /* used to hold info on the particular ciphers used */
  typedef struct ssl_cipher_st
-@@ -362,6 +363,8 @@ typedef struct ssl_cipher_st
+@@ -362,6 +363,9 @@
  
  DECLARE_STACK_OF(SSL_CIPHER)
  
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
 +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
  	{
-@@ -1034,6 +1037,14 @@ struct ssl_st
+@@ -1034,6 +1038,18 @@
  
  	/* RFC4507 session ticket expected to be received or sent */
  	int tlsext_ticket_expected;
 +
-+	/* TLS extensions */
-+	TLS_EXTENSION *tls_extension;
++	/* TLS Session Ticket extension override */
++	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++	/* TLS Session Ticket extension callback */
++	tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++	void *tls_session_ticket_ext_cb_arg;
 +
 +	/* TLS pre-shared secret session resumption */
 +	tls_session_secret_cb_fn tls_session_secret_cb;
@@ -180,12 +190,15 @@
  	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
  #define session_ctx initial_ctx
  #else
-@@ -1632,6 +1643,12 @@ void *SSL_COMP_get_compression_methods(v
+@@ -1632,6 +1648,15 @@
  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);
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg);
 +
 +/* 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);
@@ -193,112 +206,122 @@
  /* 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.
-@@ -1824,6 +1841,7 @@ void ERR_load_SSL_strings(void);
+@@ -1824,6 +1849,7 @@
  #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
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT		 213
  
  /* Reason codes. */
  #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
-diff -upr openssl-0.9.8i.orig/ssl/ssl_sess.c openssl-0.9.8i/ssl/ssl_sess.c
+Index: openssl-0.9.8i/ssl/ssl_sess.c
+===================================================================
 --- openssl-0.9.8i.orig/ssl/ssl_sess.c	2008-06-04 21:35:27.000000000 +0300
-+++ openssl-0.9.8i/ssl/ssl_sess.c	2008-09-28 16:50:18.000000000 +0300
-@@ -707,6 +707,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
++++ openssl-0.9.8i/ssl/ssl_sess.c	2008-11-23 20:32:24.000000000 +0200
+@@ -707,6 +707,61 @@
  	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, 
++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)
++	}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg)
 +	{
-+		if(s->tls_extension)
++	if (s == NULL) return(0);
++	s->tls_session_ticket_ext_cb = cb;
++	s->tls_session_ticket_ext_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++	{
++	if (s->version >= TLS1_VERSION)
 +		{
-+			OPENSSL_free(s->tls_extension);
-+			s->tls_extension = NULL;
++		if (s->tlsext_session_ticket)
++			{
++			OPENSSL_free(s->tlsext_session_ticket);
++			s->tlsext_session_ticket = NULL;
++			}
++
++		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++		if (!s->tlsext_session_ticket)
++			{
++			SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++			return 0;
++			}
++
++		if (ext_data)
++			{
++			s->tlsext_session_ticket->length = ext_len;
++			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++			}
++		else
++			{
++			s->tlsext_session_ticket->length = 0;
++			s->tlsext_session_ticket->data = NULL;
++			}
++
++		return 1;
 +		}
 +
-+		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;
 +	}
-+
-+	return 0;
-+}
 +#endif /* OPENSSL_NO_TLSEXT */
 +
  typedef struct timeout_param_st
  	{
  	SSL_CTX *ctx;
-diff -upr openssl-0.9.8i.orig/ssl/t1_lib.c openssl-0.9.8i/ssl/t1_lib.c
+Index: openssl-0.9.8i/ssl/t1_lib.c
+===================================================================
 --- openssl-0.9.8i.orig/ssl/t1_lib.c	2008-09-04 01:13:04.000000000 +0300
-+++ openssl-0.9.8i/ssl/t1_lib.c	2008-09-28 16:50:18.000000000 +0300
-@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
++++ openssl-0.9.8i/ssl/t1_lib.c	2008-11-23 20:31:20.000000000 +0200
+@@ -106,6 +106,12 @@
  
  void tls1_free(SSL *s)
  	{
 +#ifndef OPENSSL_NO_TLSEXT
-+	if(s->tls_extension)
-+	{
-+		OPENSSL_free(s->tls_extension);
-+	}
++	if (s->tlsext_session_ticket)
++		{
++		OPENSSL_free(s->tlsext_session_ticket);
++		}
 +#endif
  	ssl3_free(s);
  	}
  
-@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex
+@@ -175,8 +181,23 @@
  		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;
++		else if (s->session && s->tlsext_session_ticket &&
++			 s->tlsext_session_ticket->data)
++			{
++			ticklen = s->tlsext_session_ticket->length;
 +			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
 +			if (!s->session->tlsext_tick)
 +				return NULL;
-+			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			memcpy(s->session->tlsext_tick,
++			       s->tlsext_session_ticket->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)
++		if (ticklen == 0 && s->tlsext_session_ticket &&
++		    s->tlsext_session_ticket->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
+@@ -190,6 +211,7 @@
  			ret += ticklen;
  			}
  		}
@@ -306,39 +329,76 @@
  
  	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
  		{
-@@ -776,6 +799,8 @@ int tls1_process_ticket(SSL *s, unsigned
+@@ -407,6 +429,15 @@
+ 				}
+ 
+ 			}
++		else if (type == TLSEXT_TYPE_session_ticket)
++			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
++			}
+ 		else if (type == TLSEXT_TYPE_status_request
+ 						&& s->ctx->tlsext_status_cb)
+ 			{
+@@ -553,6 +584,12 @@
+ 			}
+ 		else if (type == TLSEXT_TYPE_session_ticket)
+ 			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
+ 			if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ 				|| (size > 0))
+ 				{
+@@ -776,6 +813,15 @@
  				s->tlsext_ticket_expected = 1;
  				return 0;	/* Cache miss */
  				}
 +			if (s->tls_session_secret_cb)
++				{
++				/* Indicate cache miss here and instead of
++				 * generating the session from ticket now,
++				 * trigger abbreviated handshake based on
++				 * external mechanism to calculate the master
++				 * secret later. */
 +				return 0;
++				}
  			return tls_decrypt_ticket(s, p, size, session_id, len,
  									ret);
  			}
-diff -upr openssl-0.9.8i.orig/ssl/tls1.h openssl-0.9.8i/ssl/tls1.h
+Index: openssl-0.9.8i/ssl/tls1.h
+===================================================================
 --- openssl-0.9.8i.orig/ssl/tls1.h	2008-04-30 19:11:33.000000000 +0300
-+++ openssl-0.9.8i/ssl/tls1.h	2008-09-28 16:50:18.000000000 +0300
-@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
++++ openssl-0.9.8i/ssl/tls1.h	2008-11-23 20:22:38.000000000 +0200
+@@ -398,6 +398,13 @@
  #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;
++struct tls_session_ticket_ext_st
++	{
 +	unsigned short length;
 +	void *data;
-+};
++	};
 +
  #ifdef  __cplusplus
  }
  #endif
-diff -upr openssl-0.9.8i.orig/util/ssleay.num openssl-0.9.8i/util/ssleay.num
+Index: openssl-0.9.8i/util/ssleay.num
+===================================================================
 --- openssl-0.9.8i.orig/util/ssleay.num	2008-06-05 13:57:21.000000000 +0300
-+++ openssl-0.9.8i/util/ssleay.num	2008-09-28 16:50:57.000000000 +0300
-@@ -242,3 +242,5 @@ SSL_set_SSL_CTX                         
++++ openssl-0.9.8i/util/ssleay.num	2008-11-23 20:22:05.000000000 +0200
+@@ -242,3 +242,5 @@
  SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
  SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
  SSL_CTX_set_client_cert_engine          293	EXIST::FUNCTION:ENGINE
-+SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
-+SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	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=1303&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 Jan 10 08:43:01 2009
@@ -3,6 +3,10 @@
 
 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).
+
+NOTE: This patch (without SSL_set_hello_extension() wrapper) was
+merged into the upstream OpenSSL 0.9.9 tree and as such, an external
+patch for EAP-FAST support is not needed anymore.
 
 
 

Modified: wpasupplicant/branches/upstream/current/src/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/Makefile?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/Makefile (original)
+++ wpasupplicant/branches/upstream/current/src/Makefile Sat Jan 10 08:43:01 2009
@@ -1,4 +1,4 @@
-SUBDIRS=common crypto drivers hlr_auc_gw eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils
+SUBDIRS=common crypto drivers hlr_auc_gw eapol_supp eap_common eap_peer eap_server l2_packet radius rsn_supp tls utils wps
 
 all:
 	@echo Nothing to be made.

Modified: wpasupplicant/branches/upstream/current/src/common/defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/defs.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/defs.h Sat Jan 10 08:43:01 2009
@@ -42,6 +42,7 @@
 #define WPA_KEY_MGMT_FT_PSK BIT(6)
 #define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
 #define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
+#define WPA_KEY_MGMT_WPS BIT(9)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
@@ -85,7 +86,8 @@
 typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
 	       KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE,
 	       KEY_MGMT_FT_802_1X, KEY_MGMT_FT_PSK,
-	       KEY_MGMT_802_1X_SHA256, KEY_MGMT_PSK_SHA256
+	       KEY_MGMT_802_1X_SHA256, KEY_MGMT_PSK_SHA256,
+	       KEY_MGMT_WPS
 } wpa_key_mgmt;
 
 /**

Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.c Sat Jan 10 08:43:01 2009
@@ -75,8 +75,28 @@
 				return -1;
 			}
 			break;
+		case 4:
+			/* Wi-Fi Protected Setup (WPS) IE */
+			elems->wps_ie = pos;
+			elems->wps_ie_len = elen;
+			break;
 		default:
 			wpa_printf(MSG_MSGDUMP, "Unknown Microsoft "
+				   "information element ignored "
+				   "(type=%d len=%lu)\n",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_BROADCOM:
+		switch (pos[3]) {
+		case VENDOR_HT_CAPAB_OUI_TYPE:
+			elems->vendor_ht_cap = pos;
+			elems->vendor_ht_cap_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_MSGDUMP, "Unknown Broadcom "
 				   "information element ignored "
 				   "(type=%d len=%lu)\n",
 				   pos[3], (unsigned long) elen);

Modified: wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_common.h Sat Jan 10 08:43:01 2009
@@ -45,6 +45,8 @@
 	u8 wme_len;
 	u8 *wme_tspec;
 	u8 wme_tspec_len;
+	u8 *wps_ie;
+	u8 wps_ie_len;
 	u8 *power_cap;
 	u8 power_cap_len;
 	u8 *supp_channels;
@@ -59,6 +61,8 @@
 	u8 ht_operation_len;
 	u8 *assoc_comeback;
 	u8 assoc_comeback_len;
+	u8 *vendor_ht_cap;
+	u8 vendor_ht_cap_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/ieee802_11_defs.h Sat Jan 10 08:43:01 2009
@@ -118,6 +118,7 @@
 #define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 27
 /* IEEE 802.11w */
 #define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
 /* IEEE 802.11i */
 #define WLAN_STATUS_INVALID_IE 40
 #define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
@@ -164,9 +165,6 @@
 #define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
 #define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
 #define WLAN_REASON_CIPHER_SUITE_REJECTED 24
-/* IEEE 802.11w */
-#define WLAN_REASON_INVALID_GROUP_MGMT_CIPHER 25
-#define WLAN_REASON_ROBUST_MGMT_FRAME_POLICY_VIOLATION 26
 
 
 /* Information Element IDs */
@@ -216,14 +214,14 @@
 #define WLAN_ACTION_BLOCK_ACK 3
 #define WLAN_ACTION_RADIO_MEASUREMENT 5
 #define WLAN_ACTION_FT 6
-#define WLAN_ACTION_PING 8
+#define WLAN_ACTION_SA_QUERY 8
 #define WLAN_ACTION_WMM 17
 
-/* Ping Action frame (IEEE 802.11w/D6.0, 7.4.9) */
-#define WLAN_PING_REQUEST 0
-#define WLAN_PING_RESPONSE 1
-
-#define WLAN_PING_TRANS_ID_LEN 16
+/* SA Query Action frame (IEEE 802.11w/D7.0, 7.4.9) */
+#define WLAN_SA_QUERY_REQUEST 0
+#define WLAN_SA_QUERY_RESPONSE 1
+
+#define WLAN_SA_QUERY_TR_ID_LEN 16
 
 
 #ifdef _MSC_VER
@@ -323,12 +321,12 @@
 				} STRUCT_PACKED ft_action_resp;
 				struct {
 					u8 action;
-					u8 trans_id[WLAN_PING_TRANS_ID_LEN];
-				} STRUCT_PACKED ping_req;
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_req;
 				struct {
 					u8 action; /* */
-					u8 trans_id[WLAN_PING_TRANS_ID_LEN];
-				} STRUCT_PACKED ping_resp;
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_resp;
 			} u;
 		} STRUCT_PACKED action;
 	} u;
@@ -344,10 +342,6 @@
 
 
 /* HT Capability element */
-
-#define MIMO_PWR_DONT_SEND_MIMO_SEQS            0
-#define MIMO_PWR_NEED2PRECEDE_MIMO_SEQS_BY_RTS  1
-#define MIMO_PWR_NO_LIMIT_ON_MIMO_SEQS          3
 
 enum {
 	MAX_RX_AMPDU_FACTOR_8KB = 0,
@@ -431,19 +425,25 @@
 	(((_var_) & (((u32)7) << (_shift_))) >> (_shift_))
 
 
-#define HT_CAP_INFO_ADVANCED_CODDING_CAP	((u16) BIT(0))
+#define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
 #define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
-#define HT_CAP_INFO_MIMO_PWR_SAVE_OFFSET	2
+#define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_SMPS_STATIC			((u16) 0)
+#define HT_CAP_INFO_SMPS_DYNAMIC		((u16) BIT(2))
+#define HT_CAP_INFO_SMPS_DISABLED		((u16) (BIT(2) | BIT(3)))
 #define HT_CAP_INFO_GREEN_FIELD			((u16) BIT(4))
 #define HT_CAP_INFO_SHORT_GI20MHZ		((u16) BIT(5))
 #define HT_CAP_INFO_SHORT_GI40MHZ		((u16) BIT(6))
 #define HT_CAP_INFO_TX_STBC			((u16) BIT(7))
-#define HT_CAP_INFO_RX_STBC_OFFSET		8
+#define HT_CAP_INFO_RX_STBC_MASK		((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_RX_STBC_1			((u16) BIT(8))
+#define HT_CAP_INFO_RX_STBC_12			((u16) BIT(9))
+#define HT_CAP_INFO_RX_STBC_123			((u16) (BIT(8) | BIT(9)))
 #define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
 #define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
 #define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
 #define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
-#define HT_CAP_INFO_STBC_CTRL_FRAME_SUPP	((u16) BIT(14))
+#define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
 #define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
 
 
@@ -493,10 +493,6 @@
 } STRUCT_PACKED;
 
 
-#define EXT_CHNL_OFF_NONE   0
-#define EXT_CHNL_OFF_ABOVE  1
-#define EXT_CHNL_OFF_BELOW  3
-
 #define REC_TRANS_CHNL_WIDTH_20     0
 #define REC_TRANS_CHNL_WIDTH_ANY    1
 
@@ -505,7 +501,9 @@
 #define OP_MODE_20MHZ_HT_STA_ASSOCED    2
 #define OP_MODE_MIXED                   3
 
-#define HT_INFO_HT_PARAM_EXT_CHNL_OFF_OFFSET		0
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
 #define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
 #define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
 #define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
@@ -578,4 +576,9 @@
 #define WME_TSPEC_DIRECTION_DOWNLINK 1
 #define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
 
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
 #endif /* IEEE802_11_DEFS_H */

Added: wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h (added)
+++ wpasupplicant/branches/upstream/current/src/common/nl80211_copy.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,818 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006, 2007, 2008 Johannes Berg <johannes at sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice at sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca at cozybit.com>
+ * Copyright 2008 Michael Buesch <mb at bu3sch.de>
+ * Copyright 2008 Luis R. Rodriguez <lrodriguez at atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen at atheros.com>
+ * Copyright 2008 Colin McCabe <colin at cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ *	to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ *	%NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ *	%NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or
+ *	%NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ *	or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ *	%NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ *	either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ *	on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ *	to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ *	%NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ *	be sent from userspace to request creation of a new virtual interface,
+ *	then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ *	%NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ *	userspace to request deletion of a virtual interface, then requires
+ *	attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ *	by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ *	%NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ *	%NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC and %NL80211_ATTR_KEY_CIPHER
+ *	attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ *	or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ *	%NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ *	%NL80211_BEACON_HEAD and %NL80211_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ *	parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ *	%NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ *	the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ *	or, if no MAC address given, all stations, on the interface identified
+ *	by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * 	destination %NL80211_ATTR_MAC on the interface identified by
+ * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
+ * 	destination %NL80211_ATTR_MAC on the interface identified by
+ * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ *	the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ *	or, if no MAC address given, all mesh paths, on the interface identified
+ *	by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ *	%NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ *	after being queried by the kernel. CRDA replies by sending a regulatory
+ *	domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ *	current alpha2 if it found a match. It also provides
+ * 	NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * 	regulatory rule is a nested set of attributes  given by
+ * 	%NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * 	%NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * 	%NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * 	to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * 	store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ *	interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ *      interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+	NL80211_CMD_UNSPEC,
+
+	NL80211_CMD_GET_WIPHY,		/* can dump */
+	NL80211_CMD_SET_WIPHY,
+	NL80211_CMD_NEW_WIPHY,
+	NL80211_CMD_DEL_WIPHY,
+
+	NL80211_CMD_GET_INTERFACE,	/* can dump */
+	NL80211_CMD_SET_INTERFACE,
+	NL80211_CMD_NEW_INTERFACE,
+	NL80211_CMD_DEL_INTERFACE,
+
+	NL80211_CMD_GET_KEY,
+	NL80211_CMD_SET_KEY,
+	NL80211_CMD_NEW_KEY,
+	NL80211_CMD_DEL_KEY,
+
+	NL80211_CMD_GET_BEACON,
+	NL80211_CMD_SET_BEACON,
+	NL80211_CMD_NEW_BEACON,
+	NL80211_CMD_DEL_BEACON,
+
+	NL80211_CMD_GET_STATION,
+	NL80211_CMD_SET_STATION,
+	NL80211_CMD_NEW_STATION,
+	NL80211_CMD_DEL_STATION,
+
+	NL80211_CMD_GET_MPATH,
+	NL80211_CMD_SET_MPATH,
+	NL80211_CMD_NEW_MPATH,
+	NL80211_CMD_DEL_MPATH,
+
+	NL80211_CMD_SET_BSS,
+
+	NL80211_CMD_SET_REG,
+	NL80211_CMD_REQ_SET_REG,
+
+	NL80211_CMD_GET_MESH_PARAMS,
+	NL80211_CMD_SET_MESH_PARAMS,
+
+	/* add new commands above here */
+
+	/* used to define NL80211_CMD_MAX below */
+	__NL80211_CMD_AFTER_LAST,
+	NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ *	/sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ *	if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *	NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ *		this attribute)
+ *	NL80211_CHAN_HT20 = HT20 only
+ *	NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ *	NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ *	16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ *	keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ *	section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ *	CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *	&enum nl80211_sta_flags.
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ *	IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ *	rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ *	to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ *	given for %NL80211_CMD_GET_STATION, nested attribute containing
+ *	info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ *	consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ *	&enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ *      &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * 	current regulatory domain should be set to or is already set to.
+ * 	For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * 	to query the CRDA to retrieve one regulatory domain. This attribute can
+ * 	also be used by userspace to query the kernel for the currently set
+ * 	regulatory domain. We chose an alpha2 as that is also used by the
+ * 	IEEE-802.11d country information element to identify a country.
+ * 	Users can also simply ask the wireless core to set regulatory domain
+ * 	to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ *	rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ *	(u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ *	rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ *	restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ *	association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ *	supported interface types, each a flag attribute with the number
+ *	of the interface mode.
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything inbetween, this is ABI! */
+	NL80211_ATTR_UNSPEC,
+
+	NL80211_ATTR_WIPHY,
+	NL80211_ATTR_WIPHY_NAME,
+
+	NL80211_ATTR_IFINDEX,
+	NL80211_ATTR_IFNAME,
+	NL80211_ATTR_IFTYPE,
+
+	NL80211_ATTR_MAC,
+
+	NL80211_ATTR_KEY_DATA,
+	NL80211_ATTR_KEY_IDX,
+	NL80211_ATTR_KEY_CIPHER,
+	NL80211_ATTR_KEY_SEQ,
+	NL80211_ATTR_KEY_DEFAULT,
+
+	NL80211_ATTR_BEACON_INTERVAL,
+	NL80211_ATTR_DTIM_PERIOD,
+	NL80211_ATTR_BEACON_HEAD,
+	NL80211_ATTR_BEACON_TAIL,
+
+	NL80211_ATTR_STA_AID,
+	NL80211_ATTR_STA_FLAGS,
+	NL80211_ATTR_STA_LISTEN_INTERVAL,
+	NL80211_ATTR_STA_SUPPORTED_RATES,
+	NL80211_ATTR_STA_VLAN,
+	NL80211_ATTR_STA_INFO,
+
+	NL80211_ATTR_WIPHY_BANDS,
+
+	NL80211_ATTR_MNTR_FLAGS,
+
+	NL80211_ATTR_MESH_ID,
+	NL80211_ATTR_STA_PLINK_ACTION,
+	NL80211_ATTR_MPATH_NEXT_HOP,
+	NL80211_ATTR_MPATH_INFO,
+
+	NL80211_ATTR_BSS_CTS_PROT,
+	NL80211_ATTR_BSS_SHORT_PREAMBLE,
+	NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+	NL80211_ATTR_HT_CAPABILITY,
+
+	NL80211_ATTR_SUPPORTED_IFTYPES,
+
+	NL80211_ATTR_REG_ALPHA2,
+	NL80211_ATTR_REG_RULES,
+
+	NL80211_ATTR_MESH_PARAMS,
+
+	NL80211_ATTR_BSS_BASIC_RATES,
+
+	NL80211_ATTR_WIPHY_TXQ_PARAMS,
+	NL80211_ATTR_WIPHY_FREQ,
+	NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+	NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+	/* add attributes here, update the policy in nl80211.c */
+
+	__NL80211_ATTR_AFTER_LAST,
+	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET
+
+#define NL80211_MAX_SUPP_RATES			32
+#define NL80211_MAX_SUPP_REG_RULES		32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY	0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY	16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY	24
+#define NL80211_HT_CAPABILITY_LEN		26
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+	NL80211_IFTYPE_UNSPECIFIED,
+	NL80211_IFTYPE_ADHOC,
+	NL80211_IFTYPE_STATION,
+	NL80211_IFTYPE_AP,
+	NL80211_IFTYPE_AP_VLAN,
+	NL80211_IFTYPE_WDS,
+	NL80211_IFTYPE_MONITOR,
+	NL80211_IFTYPE_MESH_POINT,
+
+	/* keep last */
+	__NL80211_IFTYPE_AFTER_LAST,
+	NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ *	with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ */
+enum nl80211_sta_flags {
+	__NL80211_STA_FLAG_INVALID,
+	NL80211_STA_FLAG_AUTHORIZED,
+	NL80211_STA_FLAG_SHORT_PREAMBLE,
+	NL80211_STA_FLAG_WME,
+	NL80211_STA_FLAG_MFP,
+
+	/* keep last */
+	__NL80211_STA_FLAG_AFTER_LAST,
+	NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+	__NL80211_RATE_INFO_INVALID,
+	NL80211_RATE_INFO_BITRATE,
+	NL80211_RATE_INFO_MCS,
+	NL80211_RATE_INFO_40_MHZ_WIDTH,
+	NL80211_RATE_INFO_SHORT_GI,
+
+	/* keep last */
+	__NL80211_RATE_INFO_AFTER_LAST,
+	NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * 	containing info as possible, see &enum nl80211_sta_info_txrate.
+ */
+enum nl80211_sta_info {
+	__NL80211_STA_INFO_INVALID,
+	NL80211_STA_INFO_INACTIVE_TIME,
+	NL80211_STA_INFO_RX_BYTES,
+	NL80211_STA_INFO_TX_BYTES,
+	NL80211_STA_INFO_LLID,
+	NL80211_STA_INFO_PLID,
+	NL80211_STA_INFO_PLINK_STATE,
+	NL80211_STA_INFO_SIGNAL,
+	NL80211_STA_INFO_TX_BITRATE,
+
+	/* keep last */
+	__NL80211_STA_INFO_AFTER_LAST,
+	NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+	NL80211_MPATH_FLAG_ACTIVE =	1<<0,
+	NL80211_MPATH_FLAG_RESOLVING =	1<<1,
+	NL80211_MPATH_FLAG_DSN_VALID =	1<<2,
+	NL80211_MPATH_FLAG_FIXED =	1<<3,
+	NL80211_MPATH_FLAG_RESOLVED =	1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_DSN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * 	&enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+	__NL80211_MPATH_INFO_INVALID,
+	NL80211_MPATH_INFO_FRAME_QLEN,
+	NL80211_MPATH_INFO_DSN,
+	NL80211_MPATH_INFO_METRIC,
+	NL80211_MPATH_INFO_EXPTIME,
+	NL80211_MPATH_INFO_FLAGS,
+	NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+	NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+	/* keep last */
+	__NL80211_MPATH_INFO_AFTER_LAST,
+	NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ *	an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ *	an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ *	defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ */
+enum nl80211_band_attr {
+	__NL80211_BAND_ATTR_INVALID,
+	NL80211_BAND_ATTR_FREQS,
+	NL80211_BAND_ATTR_RATES,
+
+	NL80211_BAND_ATTR_HT_MCS_SET,
+	NL80211_BAND_ATTR_HT_CAPA,
+	NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+	NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+	/* keep last */
+	__NL80211_BAND_ATTR_AFTER_LAST,
+	NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ *	regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ *	permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ *	on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ *	(100 * dBm).
+ */
+enum nl80211_frequency_attr {
+	__NL80211_FREQUENCY_ATTR_INVALID,
+	NL80211_FREQUENCY_ATTR_FREQ,
+	NL80211_FREQUENCY_ATTR_DISABLED,
+	NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+	NL80211_FREQUENCY_ATTR_NO_IBSS,
+	NL80211_FREQUENCY_ATTR_RADAR,
+	NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+	/* keep last */
+	__NL80211_FREQUENCY_ATTR_AFTER_LAST,
+	NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ *	in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+	__NL80211_BITRATE_ATTR_INVALID,
+	NL80211_BITRATE_ATTR_RATE,
+	NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+	/* keep last */
+	__NL80211_BITRATE_ATTR_AFTER_LAST,
+	NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * 	considerations for a given frequency range. These are the
+ * 	&enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * 	rule in KHz. This is not a center of frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * 	in KHz. This is not a center a frequency but an actual regulatory
+ * 	band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * 	frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * 	for a given frequency range. The value is in mBi (100 * dBi).
+ * 	If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * 	a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+	__NL80211_REG_RULE_ATTR_INVALID,
+	NL80211_ATTR_REG_RULE_FLAGS,
+
+	NL80211_ATTR_FREQ_RANGE_START,
+	NL80211_ATTR_FREQ_RANGE_END,
+	NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+	NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+	NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+	/* keep last */
+	__NL80211_REG_RULE_ATTR_AFTER_LAST,
+	NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+	NL80211_RRF_NO_OFDM		= 1<<0,
+	NL80211_RRF_NO_CCK		= 1<<1,
+	NL80211_RRF_NO_INDOOR		= 1<<2,
+	NL80211_RRF_NO_OUTDOOR		= 1<<3,
+	NL80211_RRF_DFS			= 1<<4,
+	NL80211_RRF_PTP_ONLY		= 1<<5,
+	NL80211_RRF_PTMP_ONLY		= 1<<6,
+	NL80211_RRF_PASSIVE_SCAN	= 1<<7,
+	NL80211_RRF_NO_IBSS		= 1<<8,
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ *	overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+	__NL80211_MNTR_FLAG_INVALID,
+	NL80211_MNTR_FLAG_FCSFAIL,
+	NL80211_MNTR_FLAG_PLCPFAIL,
+	NL80211_MNTR_FLAG_CONTROL,
+	NL80211_MNTR_FLAG_OTHER_BSS,
+	NL80211_MNTR_FLAG_COOK_FRAMES,
+
+	/* keep last */
+	__NL80211_MNTR_FLAG_AFTER_LAST,
+	NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+	__NL80211_MESHCONF_INVALID,
+	NL80211_MESHCONF_RETRY_TIMEOUT,
+	NL80211_MESHCONF_CONFIRM_TIMEOUT,
+	NL80211_MESHCONF_HOLDING_TIMEOUT,
+	NL80211_MESHCONF_MAX_PEER_LINKS,
+	NL80211_MESHCONF_MAX_RETRIES,
+	NL80211_MESHCONF_TTL,
+	NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+	NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+	NL80211_MESHCONF_PATH_REFRESH_TIME,
+	NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+	NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+	NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+
+	/* keep last */
+	__NL80211_MESHCONF_ATTR_AFTER_LAST,
+	NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ *	disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ *	2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+	__NL80211_TXQ_ATTR_INVALID,
+	NL80211_TXQ_ATTR_QUEUE,
+	NL80211_TXQ_ATTR_TXOP,
+	NL80211_TXQ_ATTR_CWMIN,
+	NL80211_TXQ_ATTR_CWMAX,
+	NL80211_TXQ_ATTR_AIFS,
+
+	/* keep last */
+	__NL80211_TXQ_ATTR_AFTER_LAST,
+	NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+	NL80211_TXQ_Q_VO,
+	NL80211_TXQ_Q_VI,
+	NL80211_TXQ_Q_BE,
+	NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+	NL80211_CHAN_NO_HT,
+	NL80211_CHAN_HT20,
+	NL80211_CHAN_HT40MINUS,
+	NL80211_CHAN_HT40PLUS
+};
+#endif /* __LINUX_NL80211_H */

Modified: wpasupplicant/branches/upstream/current/src/common/version.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/version.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/version.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/version.h Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define VERSION_STR "0.6.6"
+#define VERSION_STR "0.6.7"
 
 #endif /* VERSION_H */

Modified: wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h (original)
+++ wpasupplicant/branches/upstream/current/src/common/wpa_ctrl.h Sat Jan 10 08:43:01 2009
@@ -49,6 +49,28 @@
 /** New scan results available */
 #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
 
+/** WPS overlap detected in PBC mode */
+#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
+/** Available WPS AP with active PBC found in scan results */
+#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with recently selected PIN registrar found in scan results
+ */
+#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
+/** Available WPS AP found in scan results */
+#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
+/** A new credential received */
+#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
+/** M2D received */
+#define WPS_EVENT_M2D "WPS-M2D "
+/** WPS registration failed after M2/M2D */
+#define WPS_EVENT_FAIL "WPS-FAIL "
+/** WPS registration completed successfully */
+#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
+
+/* hostapd control interface - fixed message prefixes */
+#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
+#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
+
 
 /* wpa_supplicant/hostapd control interface access */
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/crypto_internal.c Sat Jan 10 08:43:01 2009
@@ -790,7 +790,7 @@
 }
 
 
-#ifdef EAP_FAST
+#if defined(EAP_FAST) || defined(CONFIG_WPS)
 
 int crypto_mod_exp(const u8 *base, size_t base_len,
 		   const u8 *power, size_t power_len,
@@ -827,7 +827,7 @@
 	return ret;
 }
 
-#endif /* EAP_FAST */
+#endif /* EAP_FAST || CONFIG_WPS */
 
 
 #endif /* CONFIG_TLS_INTERNAL */

Modified: wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/ms_funcs.c Sat Jan 10 08:43:01 2009
@@ -110,7 +110,7 @@
 /**
  * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @peer_hallenge: 16-octet PeerChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
  * @password: 0-to-256-unicode-char Password (IN; ASCII)
@@ -135,7 +135,7 @@
 /**
  * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
- * @peer_hallenge: 16-octet PeerChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
  * @password_hash: 16-octet PasswordHash (IN)
@@ -164,7 +164,7 @@
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
- * encoded as a 42-octet ASCII string (S=<hexdump of response>)
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
  */
 void generate_authenticator_response_pwhash(
 	const u8 *password_hash,
@@ -219,7 +219,7 @@
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
  * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
- * encoded as a 42-octet ASCII string (S=<hexdump of response>)
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
  */
 void generate_authenticator_response(const u8 *password, size_t password_len,
 				     const u8 *peer_challenge,
@@ -429,7 +429,7 @@
  * @new_password_len: Length of new_password
  * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
  * @old_password_len: Length of old_password
- * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
+ * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
  */
 void old_nt_password_hash_encrypted_with_new_nt_password_hash(
 	const u8 *new_password, size_t new_password_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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/sha1.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/sha1.c Sat Jan 10 08:43:01 2009
@@ -345,7 +345,7 @@
  * @passphrase: ASCII passphrase
  * @ssid: SSID
  * @ssid_len: SSID length in bytes
- * @interations: Number of iterations to run
+ * @iterations: Number of iterations to run
  * @buf: Buffer for the generated key
  * @buflen: Length of the buffer in bytes
  *

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c (original)
+++ wpasupplicant/branches/upstream/current/src/crypto/tls_openssl.c Sat Jan 10 08:43:01 2009
@@ -37,7 +37,7 @@
 #define OPENSSL_d2i_TYPE unsigned char **
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
 #ifdef SSL_OP_NO_TICKET
 /*
  * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
@@ -120,10 +120,12 @@
 				     DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
 = NULL; /* to be loaded from crypt32.dll */
 
+#ifdef CONFIG_MINGW32_LOAD_CERTENUM
 static PCCERT_CONTEXT WINAPI
 (*CertEnumCertificatesInStore)(HCERTSTORE hCertStore,
 			       PCCERT_CONTEXT pPrevCertContext)
 = NULL; /* to be loaded from crypt32.dll */
+#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
 
 static int mingw_load_crypto_func(void)
 {
@@ -151,6 +153,7 @@
 		return -1;
 	}
 
+#ifdef CONFIG_MINGW32_LOAD_CERTENUM
 	CertEnumCertificatesInStore = (void *) GetProcAddress(
 		dll, "CertEnumCertificatesInStore");
 	if (CertEnumCertificatesInStore == NULL) {
@@ -159,6 +162,7 @@
 			   "crypt32 library");
 		return -1;
 	}
+#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
 
 	return 0;
 }

Modified: wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/Apple80211.h Sat Jan 10 08:43:01 2009
@@ -105,11 +105,13 @@
  * channel: CFNumber(kCFNumberSInt32Type)
  * signal: CFNumber(kCFNumberSInt32Type)
  * appleIE: CFData
+ * WPSNOPINRequired: CFBoolean
  * noise: CFNumber(kCFNumberSInt32Type)
  * capability: CFNumber(kCFNumberSInt32Type)
  * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
  * appleIE_Version: CFNumber(kCFNumberSInt32Type)
  * appleIE_Robust: CFBoolean
+ * WPSConfigured: CFBoolean
  * scanWasDirected: CFBoolean
  * appleIE_Product: CFNumber(kCFNumberSInt32Type)
  * authModes: CFArray of CFNumber(kCFNumberSInt32Type)

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver.h (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver.h Sat Jan 10 08:43:01 2009
@@ -126,6 +126,23 @@
 };
 
 /**
+ * struct wpa_interface_info - Network interface information
+ * @next: Pointer to the next interface or NULL if this is the last one
+ * @ifname: Interface name that can be used with init() or init2()
+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
+ *	not available
+ * @drv_bame: struct wpa_driver_ops::name (note: unlike other strings, this one
+ *	is not an allocated copy, i.e., get_interfaces() caller will not free
+ *	this)
+ */
+struct wpa_interface_info {
+	struct wpa_interface_info *next;
+	char *ifname;
+	char *desc;
+	const char *drv_name;
+};
+
+/**
  * struct wpa_driver_associate_params - Association parameters
  * Data for struct wpa_driver_ops::associate().
  */
@@ -164,6 +181,8 @@
 	 * instead. The driver can determine which version is used by
 	 * looking at the first byte of the IE (0xdd for WPA, 0x30 for
 	 * WPA2/RSN).
+	 *
+	 * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
 	 */
 	const u8 *wpa_ie;
 	/**
@@ -922,13 +941,13 @@
 	 struct wpa_scan_results * (*get_scan_results2)(void *priv);
 
 	/**
-	 * * set_probe_req_ie - Set information element(s) for Probe Request
+	 * set_probe_req_ie - Set information element(s) for Probe Request
 	 * @priv: private driver interface data
 	 * @ies: Information elements to append or %NULL to remove extra IEs
 	 * @ies_len: Length of the IE buffer in octets
 	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*set_probe_req_ie)(void *, const u8 *ies, size_t ies_len);
+	int (*set_probe_req_ie)(void *priv, const u8 *ies, size_t ies_len);
 
  	/**
 	 * set_mode - Request driver to set the operating mode
@@ -943,6 +962,61 @@
 	 * Returns: 0 on success, -1 on failure
 	 */
 	int (*set_mode)(void *priv, int mode);
+
+	/**
+	 * set_country - Set country
+	 * @priv: Private driver interface data
+	 * @alpha2: country to which to switch to
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is for drivers which support some form
+	 * of setting a regulatory domain.
+	 */
+	int (*set_country)(void *priv, const char *alpha2);
+
+	/**
+	 * global_init - Global driver initialization
+	 * Returns: Pointer to private data (global), %NULL on failure
+	 *
+	 * This optional function is called to initialize the driver wrapper
+	 * for global data, i.e., data that applies to all interfaces. If this
+	 * function is implemented, global_deinit() will also need to be
+	 * implemented to free the private data. The driver will also likely
+	 * use init2() function instead of init() to get the pointer to global
+	 * data available to per-interface initializer.
+	 */
+	void * (*global_init)(void);
+
+	/**
+	 * global_deinit - Global driver deinitialization
+	 * @priv: private driver global data from global_init()
+	 *
+	 * Terminate any global driver related functionality and free the
+	 * global data structure.
+	 */
+	void (*global_deinit)(void *priv);
+
+	/**
+	 * init2 - Initialize driver interface (with global data)
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function can be used instead of init() if the driver wrapper
+	 * uses global data.
+	 */
+	void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+
+	/**
+	 * get_interfaces - Get information about available interfaces
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Allocated buffer of interface information (caller is
+	 * responsible for freeing the data structure) on success, NULL on
+	 * failure
+	 */
+	struct wpa_interface_info * (*get_interfaces)(void *global_priv);
 };
 
 /* Function to check whether a driver is for wired connections */
@@ -1239,8 +1313,11 @@
 
 const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
 #define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WPS_IE_VENDOR_TYPE 0x0050f204
 const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
 				  u32 vendor_type);
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type);
 int wpa_scan_get_max_rate(const struct wpa_scan_res *res);
 void wpa_scan_results_free(struct wpa_scan_results *res);
 void wpa_scan_sort_results(struct wpa_scan_results *res);

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_ndis.c Sat Jan 10 08:43:01 2009
@@ -25,7 +25,11 @@
 #else /* CONFIG_USE_NDISUIO */
 #include <Packet32.h>
 #endif /* CONFIG_USE_NDISUIO */
+#ifdef __MINGW32_VERSION
+#include <ddk/ntddndis.h>
+#else /* __MINGW32_VERSION */
 #include <ntddndis.h>
+#endif /* __MINGW32_VERSION */
 
 #ifdef _WIN32_WCE
 #include <winioctl.h>
@@ -489,7 +493,7 @@
 	char txt[50];
 
 	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
-	wpa_hexdump_key(MSG_MSGDUMP, txt, data, len);
+	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
 
 	buflen = sizeof(*o) + len;
 	reallen = buflen - sizeof(o->Data);
@@ -517,7 +521,7 @@
 	char txt[50];
 
 	os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
-	wpa_hexdump_key(MSG_MSGDUMP, txt, data, len);
+	wpa_hexdump_key(MSG_MSGDUMP, txt, (const u8 *) data, len);
 
 	buf = os_zalloc(sizeof(*o) + len);
 	if (buf == NULL)
@@ -615,8 +619,8 @@
 		return 0;
 	}
 
-	return ndis_get_oid(drv, OID_802_11_BSSID, bssid, ETH_ALEN) < 0 ?
-		-1 : 0;
+	return ndis_get_oid(drv, OID_802_11_BSSID, (char *) bssid, ETH_ALEN) <
+		0 ? -1 : 0;
 }
 
 
@@ -675,7 +679,7 @@
 	int i;
 	for (i = 0; i < 32; i++)
 		ssid[i] = rand() & 0xff;
-	return wpa_driver_ndis_set_ssid(drv, ssid, 32);
+	return wpa_driver_ndis_set_ssid(drv, (u8 *) ssid, 32);
 }
 
 
@@ -900,7 +904,7 @@
 	os_memcpy(wep->KeyMaterial, key, key_len);
 
 	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
-			(char *) wep, len);
+			(u8 *) wep, len);
 	res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
 
 	os_free(wep);
@@ -971,7 +975,7 @@
 	}
 
 	wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
-			(char *) nkey, len);
+			(u8 *) nkey, len);
 	res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
 	os_free(nkey);
 
@@ -1039,6 +1043,11 @@
 			auth_mode = Ndis802_11AuthModeWPA2PSK;
 		else
 			auth_mode = Ndis802_11AuthModeWPA2;
+#ifdef CONFIG_WPS
+	} else if (params->key_mgmt_suite == KEY_MGMT_WPS) {
+		auth_mode = Ndis802_11AuthModeOpen;
+		priv_mode = Ndis802_11PrivFilterAcceptAll;
+#endif /* CONFIG_WPS */
 	} else {
 		priv_mode = Ndis802_11PrivFilter8021xWEP;
 		if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
@@ -1084,7 +1093,8 @@
 	ndis_set_encr_status(drv, encr);
 
 	if (params->bssid) {
-		ndis_set_oid(drv, OID_802_11_BSSID, params->bssid, ETH_ALEN);
+		ndis_set_oid(drv, OID_802_11_BSSID, (char *) params->bssid,
+			     ETH_ALEN);
 		drv->oid_bssid_set = 1;
 	} else if (drv->oid_bssid_set) {
 		ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
@@ -1123,7 +1133,7 @@
 		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
 		entry = entry->next;
 	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (char *) p, len);
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (u8 *) p, len);
 	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
 	os_free(p);
 	return ret;
@@ -1229,7 +1239,7 @@
 	p.Length = 8;
 	p.BSSIDInfoCount = 0;
 	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-		    (char *) &p, 8);
+		    (u8 *) &p, 8);
 	ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
 
 	if (prev_authmode != Ndis802_11AuthModeWPA2)
@@ -1275,7 +1285,8 @@
 			len = sizeof(buf);
 		}
 	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: association information", buf, len);
+	wpa_hexdump(MSG_MSGDUMP, "NDIS: association information",
+		    (u8 *) buf, len);
 	if (len < sizeof(*ai)) {
 		wpa_printf(MSG_DEBUG, "NDIS: too short association "
 			   "information");
@@ -1296,14 +1307,14 @@
 	}
 
 	wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
-		    buf + ai->OffsetRequestIEs, ai->RequestIELength);
+		    (u8 *) buf + ai->OffsetRequestIEs, ai->RequestIELength);
 	wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
-		    buf + ai->OffsetResponseIEs, ai->ResponseIELength);
+		    (u8 *) buf + ai->OffsetResponseIEs, ai->ResponseIELength);
 
 	os_memset(&data, 0, sizeof(data));
-	data.assoc_info.req_ies = buf + ai->OffsetRequestIEs;
+	data.assoc_info.req_ies = (u8 *) buf + ai->OffsetRequestIEs;
 	data.assoc_info.req_ies_len = ai->RequestIELength;
-	data.assoc_info.resp_ies = buf + ai->OffsetResponseIEs;
+	data.assoc_info.resp_ies = (u8 *) buf + ai->OffsetResponseIEs;
 	data.assoc_info.resp_ies_len = ai->ResponseIELength;
 
 	blen = 65535;
@@ -1658,7 +1669,7 @@
 		return;
 	}
 
-	wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", buf, len);
+	wpa_hexdump(MSG_MSGDUMP, "OID_802_11_CAPABILITY", (u8 *) buf, len);
 	c = (NDIS_802_11_CAPABILITY *) buf;
 	if (len < sizeof(*c) || c->Version != 2) {
 		wpa_printf(MSG_DEBUG, "NDIS: unsupported "
@@ -2734,7 +2745,7 @@
 	}
 
 	if (ndis_get_oid(drv, OID_802_3_CURRENT_ADDRESS,
-			 drv->own_addr, ETH_ALEN) < 0) {
+			 (char *) drv->own_addr, ETH_ALEN) < 0) {
 		wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
 			   "failed");
 		wpa_driver_ndis_adapter_close(drv);
@@ -2830,6 +2841,240 @@
 #endif /* _WIN32_WCE */
 	os_free(drv->adapter_desc);
 	os_free(drv);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_ndis_get_interfaces(void *global_priv)
+{
+	struct wpa_interface_info *iface = NULL, *niface;
+
+#ifdef CONFIG_USE_NDISUIO
+	NDISUIO_QUERY_BINDING *b;
+	size_t blen = sizeof(*b) + 1024;
+	int i, error;
+	DWORD written;
+	char name[256], desc[256];
+	WCHAR *pos;
+	size_t j, len;
+	HANDLE ndisuio;
+
+	ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
+			     GENERIC_READ | GENERIC_WRITE, 0, NULL,
+			     OPEN_EXISTING,
+			     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+			     INVALID_HANDLE_VALUE);
+	if (ndisuio == INVALID_HANDLE_VALUE) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
+			   "NDISUIO: %d", (int) GetLastError());
+		return NULL;
+	}
+
+#ifndef _WIN32_WCE
+	if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
+			     NULL, 0, &written, NULL)) {
+		wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
+			   "%d", (int) GetLastError());
+		CloseHandle(ndisuio);
+		return NULL;
+	}
+#endif /* _WIN32_WCE */
+
+	b = os_malloc(blen);
+	if (b == NULL) {
+		CloseHandle(ndisuio);
+		return NULL;
+	}
+
+	for (i = 0; ; i++) {
+		os_memset(b, 0, blen);
+		b->BindingIndex = i;
+		if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+				     b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
+				     &written, NULL)) {
+			error = (int) GetLastError();
+			if (error == ERROR_NO_MORE_ITEMS)
+				break;
+			wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
+				   "failed: %d", error);
+			break;
+		}
+
+		pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+		len = b->DeviceNameLength;
+		if (len >= sizeof(name))
+			len = sizeof(name) - 1;
+		for (j = 0; j < len; j++)
+			name[j] = (char) pos[j];
+		name[len] = '\0';
+
+		pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+		len = b->DeviceDescrLength;
+		if (len >= sizeof(desc))
+			len = sizeof(desc) - 1;
+		for (j = 0; j < len; j++)
+			desc[j] = (char) pos[j];
+		desc[len] = '\0';
+
+		wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
+
+		niface = os_zalloc(sizeof(*niface));
+		if (niface == NULL)
+			break;
+		niface->drv_name = "ndis";
+		if (os_strncmp(name, "\\DEVICE\\", 8) == 0)
+			niface->ifname = os_strdup(name + 8);
+		else
+			niface->ifname = os_strdup(name);
+		if (niface->ifname == NULL) {
+			os_free(niface);
+			break;
+		}
+		niface->desc = os_strdup(desc);
+		niface->next = iface;
+		iface = niface;
+	}
+
+	os_free(b);
+	CloseHandle(ndisuio);
+#else /* CONFIG_USE_NDISUIO */
+	PTSTR _names;
+	char *names, *pos, *pos2;
+	ULONG len;
+	BOOLEAN res;
+	char *name[MAX_ADAPTERS];
+	char *desc[MAX_ADAPTERS];
+	int num_name, num_desc, i;
+
+	wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
+		   PacketGetVersion());
+
+	len = 8192;
+	_names = os_zalloc(len);
+	if (_names == NULL)
+		return NULL;
+
+	res = PacketGetAdapterNames(_names, &len);
+	if (!res && len > 8192) {
+		os_free(_names);
+		_names = os_zalloc(len);
+		if (_names == NULL)
+			return NULL;
+		res = PacketGetAdapterNames(_names, &len);
+	}
+
+	if (!res) {
+		wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
+			   "(PacketGetAdapterNames)");
+		os_free(_names);
+		return NULL;
+	}
+
+	names = (char *) _names;
+	if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
+		wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
+			   "UNICODE");
+		/* Convert to ASCII */
+		pos2 = pos = names;
+		while (pos2 < names + len) {
+			if (pos2[0] == '\0' && pos2[1] == '\0' &&
+			    pos2[2] == '\0' && pos2[3] == '\0') {
+				pos2 += 4;
+				break;
+			}
+			*pos++ = pos2[0];
+			pos2 += 2;
+		}
+		os_memcpy(pos + 2, names, pos - names);
+		pos += 2;
+	} else
+		pos = names;
+
+	num_name = 0;
+	while (pos < names + len) {
+		name[num_name] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return NULL;
+		}
+		pos++;
+		num_name++;
+		if (num_name >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
+			os_free(names);
+			return NULL;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter names found",
+				   num_name);
+			pos++;
+			break;
+		}
+	}
+
+	num_desc = 0;
+	while (pos < names + len) {
+		desc[num_desc] = pos;
+		while (*pos && pos < names + len)
+			pos++;
+		if (pos + 1 >= names + len) {
+			os_free(names);
+			return NULL;
+		}
+		pos++;
+		num_desc++;
+		if (num_desc >= MAX_ADAPTERS) {
+			wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
+				   "descriptions");
+			os_free(names);
+			return NULL;
+		}
+		if (*pos == '\0') {
+			wpa_printf(MSG_DEBUG, "NDIS: %d adapter descriptions "
+				   "found", num_name);
+			pos++;
+			break;
+		}
+	}
+
+	/*
+	 * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
+	 * descriptions. Fill in dummy descriptors to work around this.
+	 */
+	while (num_desc < num_name)
+		desc[num_desc++] = "dummy description";
+
+	if (num_name != num_desc) {
+		wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
+			   "description counts (%d != %d)",
+			   num_name, num_desc);
+		os_free(names);
+		return NULL;
+	}
+
+	for (i = 0; i < num_name; i++) {
+		niface = os_zalloc(sizeof(*niface));
+		if (niface == NULL)
+			break;
+		niface->drv_name = "ndis";
+		if (os_strncmp(name[i], "\\Device\\NPF_", 12) == 0)
+			niface->ifname = os_strdup(name[i] + 12);
+		else
+			niface->ifname = os_strdup(name[i]);
+		if (niface->ifname == NULL) {
+			os_free(niface);
+			break;
+		}
+		niface->desc = os_strdup(desc[i]);
+		niface->next = iface;
+		iface = niface;
+	}
+
+#endif /* CONFIG_USE_NDISUIO */
+
+	return iface;
 }
 
 
@@ -2872,5 +3117,10 @@
 	NULL /* send_ft_action */,
 	wpa_driver_ndis_get_scan_results,
 	NULL /* set_probe_req_ie */,
-	NULL /* set_mode */
+	NULL /* set_mode */,
+	NULL /* set_country */,
+	NULL /* global_init */,
+	NULL /* global_deinit */,
+	NULL /* init2 */,
+	wpa_driver_ndis_get_interfaces
 };

Modified: 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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_nl80211.c Sat Jan 10 08:43:01 2009
@@ -18,7 +18,7 @@
 #include <netlink/genl/genl.h>
 #include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
-#include <linux/nl80211.h>
+#include "nl80211_copy.h"
 #ifdef CONFIG_CLIENT_MLME
 #include <netpacket/packet.h>
 #include <linux/if_ether.h>
@@ -958,6 +958,41 @@
 }
 
 
+/**
+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
+ * @priv: driver_nl80211 private data
+ * @alpha2_arg: country to which to switch to
+ * Returns: 0 on success, -1 on failure
+ *
+ * This asks nl80211 to set the regulatory domain for given
+ * country ISO / IEC alpha2.
+ */
+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
+{
+	struct wpa_driver_nl80211_data *drv = priv;
+	char alpha2[3];
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		goto nla_put_failure;
+
+	alpha2[0] = alpha2_arg[0];
+	alpha2[1] = alpha2_arg[1];
+	alpha2[2] = '\0';
+
+	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+		    0, NL80211_CMD_REQ_SET_REG, 0);
+
+	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+	if (send_and_recv_msgs(drv, msg, NULL, NULL))
+		return -EINVAL;
+	return 0;
+nla_put_failure:
+	return -EINVAL;
+}
+
+
 #ifdef CONFIG_CLIENT_MLME
 
 static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv,
@@ -1211,13 +1246,13 @@
 
 
 /**
- * wpa_driver_nl80211_init - Initialize WE driver interface
+ * wpa_driver_nl80211_init - Initialize nl80211 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)
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
 {
 	int s;
 	struct sockaddr_nl local;
@@ -1351,13 +1386,13 @@
 
 
 /**
- * wpa_driver_nl80211_deinit - Deinitialize WE driver interface
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+ * @priv: Pointer to private nl80211 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)
+static void wpa_driver_nl80211_deinit(void *priv)
 {
 	struct wpa_driver_nl80211_data *drv = priv;
 	int flags;
@@ -1814,7 +1849,8 @@
  * @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)
+static 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;
@@ -2858,6 +2894,7 @@
 	.flush_pmkid = wpa_driver_nl80211_flush_pmkid,
 	.get_capa = wpa_driver_nl80211_get_capa,
 	.set_operstate = wpa_driver_nl80211_set_operstate,
+	.set_country = wpa_driver_nl80211_set_country,
 #ifdef CONFIG_CLIENT_MLME
 	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
 	.set_channel = wpa_driver_nl80211_set_channel,

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_privsep.c Sat Jan 10 08:43:01 2009
@@ -774,7 +774,12 @@
 	NULL /* send_ft_action */,
 	wpa_driver_privsep_get_scan_results2,
 	NULL /* set_probe_req_ie */,
-	wpa_driver_privsep_set_mode
+	wpa_driver_privsep_set_mode,
+	NULL /* set_country */,
+	NULL /* global_init */,
+	NULL /* global_deinit */,
+	NULL /* init2 */,
+	NULL /* get_interfaces */
 };
 
 

Modified: wpasupplicant/branches/upstream/current/src/drivers/driver_test.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/driver_test.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_test.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_test.c Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - testing driver interface
- * 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
@@ -12,10 +12,20 @@
  * See README and COPYING for more details.
  */
 
+/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */
+#include "build_config.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock2.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
 #include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
 #include <sys/un.h>
 #include <dirent.h>
 #include <sys/stat.h>
+#define DRIVER_TEST_UNIX
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "common.h"
 #include "driver.h"
@@ -25,12 +35,21 @@
 #include "ieee802_11_defs.h"
 
 
+struct wpa_driver_test_global {
+	int dummy;
+};
+
 struct wpa_driver_test_data {
+	struct wpa_driver_test_global *global;
 	void *ctx;
 	u8 own_addr[ETH_ALEN];
 	int test_socket;
+#ifdef DRIVER_TEST_UNIX
 	struct sockaddr_un hostapd_addr;
+#endif /* DRIVER_TEST_UNIX */
 	int hostapd_addr_set;
+	struct sockaddr_in hostapd_addr_udp;
+	int hostapd_addr_udp_set;
 	char *own_socket_path;
 	char *test_dir;
 	u8 bssid[ETH_ALEN];
@@ -44,6 +63,8 @@
 	size_t assoc_wpa_ie_len;
 	int use_mlme;
 	int associated;
+	u8 *probe_req_ie;
+	size_t probe_req_ie_len;
 };
 
 
@@ -51,6 +72,7 @@
 {
 	struct wpa_driver_test_data *drv = eloop_ctx;
 
+#ifdef DRIVER_TEST_UNIX
 	if (drv->associated && drv->hostapd_addr_set) {
 		struct stat st;
 		if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
@@ -60,6 +82,7 @@
 			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
 		}
 	}
+#endif /* DRIVER_TEST_UNIX */
 
 	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
 }
@@ -79,16 +102,34 @@
 }
 
 
+#ifdef DRIVER_TEST_UNIX
 static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
 				const char *path)
 {
 	struct dirent *dent;
 	DIR *dir;
 	struct sockaddr_un addr;
+	char cmd[512], *pos, *end;
+	int ret;
 
 	dir = opendir(path);
 	if (dir == NULL)
 		return;
+
+	end = cmd + sizeof(cmd);
+	pos = cmd;
+	ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
+			  MAC2STR(drv->own_addr));
+	if (ret >= 0 && ret < end - pos)
+		pos += ret;
+	if (drv->probe_req_ie) {
+		ret = os_snprintf(pos, end - pos, " ");
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
+					drv->probe_req_ie_len);
+	}
+	end[-1] = '\0';
 
 	while ((dent = readdir(dir))) {
 		if (os_strncmp(dent->d_name, "AP-", 3) != 0)
@@ -100,13 +141,14 @@
 		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
 			    path, dent->d_name);
 
-		if (sendto(drv->test_socket, "SCAN", 4, 0,
+		if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
 			   (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 			perror("sendto(test_socket)");
 		}
 	}
 	closedir(dir);
 }
+#endif /* DRIVER_TEST_UNIX */
 
 
 static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
@@ -116,6 +158,7 @@
 
 	drv->num_scanres = 0;
 
+#ifdef DRIVER_TEST_UNIX
 	if (drv->test_socket >= 0 && drv->test_dir)
 		wpa_driver_scan_dir(drv, drv->test_dir);
 
@@ -123,6 +166,14 @@
 	    sendto(drv->test_socket, "SCAN", 4, 0,
 		   (struct sockaddr *) &drv->hostapd_addr,
 		   sizeof(drv->hostapd_addr)) < 0) {
+		perror("sendto(test_socket)");
+	}
+#endif /* DRIVER_TEST_UNIX */
+
+	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+	    sendto(drv->test_socket, "SCAN", 4, 0,
+		   (struct sockaddr *) &drv->hostapd_addr_udp,
+		   sizeof(drv->hostapd_addr_udp)) < 0) {
 		perror("sendto(test_socket)");
 	}
 
@@ -213,6 +264,7 @@
 	} else
 		drv->assoc_wpa_ie_len = 0;
 
+#ifdef DRIVER_TEST_UNIX
 	if (drv->test_dir && params->bssid) {
 		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
 		drv->hostapd_addr.sun_family = AF_UNIX;
@@ -222,8 +274,10 @@
 			    drv->test_dir, MAC2STR(params->bssid));
 		drv->hostapd_addr_set = 1;
 	}
-
-	if (drv->test_socket >= 0 && drv->hostapd_addr_set) {
+#endif /* DRIVER_TEST_UNIX */
+
+	if (drv->test_socket >= 0 &&
+	    (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
 		char cmd[200], *pos, *end;
 		int ret;
 		end = cmd + sizeof(cmd);
@@ -240,12 +294,22 @@
 		pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
 					params->wpa_ie_len);
 		end[-1] = '\0';
-		if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+#ifdef DRIVER_TEST_UNIX
+		if (drv->hostapd_addr_set &&
+		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
 			   (struct sockaddr *) &drv->hostapd_addr,
 			   sizeof(drv->hostapd_addr)) < 0) {
 			perror("sendto(test_socket)");
 			return -1;
 		}
+#endif /* DRIVER_TEST_UNIX */
+		if (drv->hostapd_addr_udp_set &&
+		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+			   (struct sockaddr *) &drv->hostapd_addr_udp,
+			   sizeof(drv->hostapd_addr_udp)) < 0) {
+			perror("sendto(test_socket)");
+			return -1;
+		}
 
 		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
 		drv->ssid_len = params->ssid_len;
@@ -276,6 +340,7 @@
 
 static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
 {
+#ifdef DRIVER_TEST_UNIX
 	if (drv->test_socket >= 0 &&
 	    sendto(drv->test_socket, "DISASSOC", 8, 0,
 		   (struct sockaddr *) &drv->hostapd_addr,
@@ -283,6 +348,14 @@
 		perror("sendto(test_socket)");
 		return -1;
 	}
+#endif /* DRIVER_TEST_UNIX */
+	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+	    sendto(drv->test_socket, "DISASSOC", 8, 0,
+		   (struct sockaddr *) &drv->hostapd_addr_udp,
+		   sizeof(drv->hostapd_addr_udp)) < 0) {
+		perror("sendto(test_socket)");
+		return -1;
+	}
 	return 0;
 }
 
@@ -314,7 +387,7 @@
 
 
 static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
-				     struct sockaddr_un *from,
+				     struct sockaddr *from,
 				     socklen_t fromlen,
 				     const char *data)
 {
@@ -401,7 +474,7 @@
 
 
 static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
-				      struct sockaddr_un *from,
+				      struct sockaddr *from,
 				      socklen_t fromlen,
 				      const char *data)
 {
@@ -423,7 +496,7 @@
 
 
 static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
-				     struct sockaddr_un *from,
+				     struct sockaddr *from,
 				     socklen_t fromlen)
 {
 	drv->associated = 0;
@@ -432,7 +505,7 @@
 
 
 static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
-				  struct sockaddr_un *from,
+				  struct sockaddr *from,
 				  socklen_t fromlen,
 				  const u8 *data, size_t data_len)
 {
@@ -449,7 +522,7 @@
 
 
 static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
-				 struct sockaddr_un *from,
+				 struct sockaddr *from,
 				 socklen_t fromlen,
 				 const u8 *data, size_t data_len)
 {
@@ -467,7 +540,7 @@
 	struct wpa_driver_test_data *drv = eloop_ctx;
 	char *buf;
 	int res;
-	struct sockaddr_un from;
+	struct sockaddr_storage from;
 	socklen_t fromlen = sizeof(from);
 	const size_t buflen = 2000;
 
@@ -486,18 +559,22 @@
 	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
 
 	if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
-		wpa_driver_test_scanresp(drv, &from, fromlen, buf + 9);
+		wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
+					 fromlen, buf + 9);
 	} else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
-		wpa_driver_test_assocresp(drv, &from, fromlen, buf + 10);
+		wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
+					  fromlen, buf + 10);
 	} else if (os_strcmp(buf, "DISASSOC") == 0) {
-		wpa_driver_test_disassoc(drv, &from, fromlen);
+		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+					 fromlen);
 	} else if (os_strcmp(buf, "DEAUTH") == 0) {
-		wpa_driver_test_disassoc(drv, &from, fromlen);
+		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+					 fromlen);
 	} else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
-		wpa_driver_test_eapol(drv, &from, fromlen,
+		wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
 				      (const u8 *) buf + 6, res - 6);
 	} else if (os_strncmp(buf, "MLME ", 5) == 0) {
-		wpa_driver_test_mlme(drv, &from, fromlen,
+		wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
 				     (const u8 *) buf + 5, res - 5);
 	} else {
 		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
@@ -507,13 +584,15 @@
 }
 
 
-static void * wpa_driver_test_init(void *ctx, const char *ifname)
+static void * wpa_driver_test_init2(void *ctx, const char *ifname,
+				    void *global_priv)
 {
 	struct wpa_driver_test_data *drv;
 
 	drv = os_zalloc(sizeof(*drv));
 	if (drv == NULL)
 		return NULL;
+	drv->global = global_priv;
 	drv->ctx = ctx;
 	drv->test_socket = -1;
 
@@ -564,6 +643,7 @@
 	os_free(drv->test_dir);
 	for (i = 0; i < MAX_SCAN_RESULTS; i++)
 		os_free(drv->scanres[i]);
+	os_free(drv->probe_req_ie);
 	os_free(drv);
 }
 
@@ -571,6 +651,7 @@
 static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
 				  const char *dir)
 {
+#ifdef DRIVER_TEST_UNIX
 	static unsigned int counter = 0;
 	struct sockaddr_un addr;
 	size_t len;
@@ -617,22 +698,73 @@
 				 wpa_driver_test_receive_unix, drv, NULL);
 
 	return 0;
+#else /* DRIVER_TEST_UNIX */
+	return -1;
+#endif /* DRIVER_TEST_UNIX */
+}
+
+
+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
+				      char *dst)
+{
+	char *pos;
+
+	pos = os_strchr(dst, ':');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
+
+	drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
+	if (drv->test_socket < 0) {
+		perror("socket(PF_INET)");
+		return -1;
+	}
+
+	os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
+	drv->hostapd_addr_udp.sin_family = AF_INET;
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+	{
+		int a[4];
+		u8 *pos;
+		sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+		pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
+		*pos++ = a[0];
+		*pos++ = a[1];
+		*pos++ = a[2];
+		*pos++ = a[3];
+	}
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+	drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
+
+	drv->hostapd_addr_udp_set = 1;
+
+	eloop_register_read_sock(drv->test_socket,
+				 wpa_driver_test_receive_unix, drv, NULL);
+
+	return 0;
 }
 
 
 static int wpa_driver_test_set_param(void *priv, const char *param)
 {
 	struct wpa_driver_test_data *drv = priv;
-	const char *pos, *pos2;
-	size_t len;
+	const char *pos;
 
 	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
 	if (param == NULL)
 		return 0;
 
 	wpa_driver_test_close_test_socket(drv);
+
+#ifdef DRIVER_TEST_UNIX
 	pos = os_strstr(param, "test_socket=");
 	if (pos) {
+		const char *pos2;
+		size_t len;
+
 		pos += 12;
 		pos2 = os_strchr(pos, ' ');
 		if (pos2)
@@ -646,6 +778,7 @@
 		os_memcpy(drv->hostapd_addr.sun_path, pos, len);
 		drv->hostapd_addr_set = 1;
 	}
+#endif /* DRIVER_TEST_UNIX */
 
 	pos = os_strstr(param, "test_dir=");
 	if (pos) {
@@ -657,9 +790,24 @@
 		end = os_strchr(drv->test_dir, ' ');
 		if (end)
 			*end = '\0';
-		wpa_driver_test_attach(drv, drv->test_dir);
-	} else
-		wpa_driver_test_attach(drv, NULL);
+		if (wpa_driver_test_attach(drv, drv->test_dir))
+			return -1;
+	} else {
+		pos = os_strstr(param, "test_udp=");
+		if (pos) {
+			char *dst, *epos;
+			dst = os_strdup(pos + 9);
+			if (dst == NULL)
+				return -1;
+			epos = os_strchr(dst, ' ');
+			if (epos)
+				*epos = '\0';
+			if (wpa_driver_test_attach_udp(drv, dst))
+				return -1;
+			os_free(dst);
+		} else if (wpa_driver_test_attach(drv, NULL))
+			return -1;
+	}
 
 	if (os_strstr(param, "use_associnfo=1")) {
 		wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
@@ -689,10 +837,14 @@
 				      const u8 *data, size_t data_len)
 {
 	struct wpa_driver_test_data *drv = priv;
-	struct msghdr msg;
-	struct iovec io[3];
+	char *msg;
+	size_t msg_len;
 	struct l2_ethhdr eth;
-	struct sockaddr_un addr;
+	struct sockaddr *addr;
+	socklen_t alen;
+#ifdef DRIVER_TEST_UNIX
+	struct sockaddr_un addr_un;
+#endif /* DRIVER_TEST_UNIX */
 
 	wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
 
@@ -701,40 +853,55 @@
 	os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
 	eth.h_proto = host_to_be16(proto);
 
-	io[0].iov_base = "EAPOL ";
-	io[0].iov_len = 6;
-	io[1].iov_base = (u8 *) &eth;
-	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = (u8 *) data;
-	io[2].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
+	msg_len = 6 + sizeof(eth) + data_len;
+	msg = os_malloc(msg_len);
+	if (msg == NULL)
+		return -1;
+	os_memcpy(msg, "EAPOL ", 6);
+	os_memcpy(msg + 6, &eth, sizeof(eth));
+	os_memcpy(msg + 6 + sizeof(eth), data, data_len);
+
 	if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
 	    drv->test_dir == NULL) {
-		msg.msg_name = &drv->hostapd_addr;
-		msg.msg_namelen = sizeof(drv->hostapd_addr);
+		if (drv->hostapd_addr_udp_set) {
+			addr = (struct sockaddr *) &drv->hostapd_addr_udp;
+			alen = sizeof(drv->hostapd_addr_udp);
+		} else {
+#ifdef DRIVER_TEST_UNIX
+			addr = (struct sockaddr *) &drv->hostapd_addr;
+			alen = sizeof(drv->hostapd_addr);
+#else /* DRIVER_TEST_UNIX */
+			os_free(msg);
+			return -1;
+#endif /* DRIVER_TEST_UNIX */
+		}
 	} else {
+#ifdef DRIVER_TEST_UNIX
 		struct stat st;
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+		os_memset(&addr_un, 0, sizeof(addr_un));
+		addr_un.sun_family = AF_UNIX;
+		os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
 			    "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
-		if (stat(addr.sun_path, &st) < 0) {
-			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+		if (stat(addr_un.sun_path, &st) < 0) {
+			os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
 				    "%s/AP-" MACSTR,
 				    drv->test_dir, MAC2STR(dest));
 		}
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-	}
-
-	if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+		addr = (struct sockaddr *) &addr_un;
+		alen = sizeof(addr_un);
+#else /* DRIVER_TEST_UNIX */
+		os_free(msg);
+		return -1;
+#endif /* DRIVER_TEST_UNIX */
+	}
+
+	if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
 		perror("sendmsg(test_socket)");
+		os_free(msg);
 		return -1;
 	}
 
+	os_free(msg);
 	return 0;
 }
 
@@ -811,8 +978,8 @@
 }
 
 
-int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode, int chan,
-				int freq)
+static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode,
+				       int chan, int freq)
 {
 	wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
 		   __func__, phymode, chan, freq);
@@ -846,8 +1013,15 @@
 	msg.msg_iovlen = 2;
 	if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
 	    drv->test_dir == NULL) {
-		msg.msg_name = &drv->hostapd_addr;
-		msg.msg_namelen = sizeof(drv->hostapd_addr);
+		if (drv->hostapd_addr_udp_set) {
+			msg.msg_name = &drv->hostapd_addr_udp;
+			msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+		} else {
+#ifdef DRIVER_TEST_UNIX
+			msg.msg_name = &drv->hostapd_addr;
+			msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+		}
 	} else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
 	{
 		dir = opendir(drv->test_dir);
@@ -921,19 +1095,81 @@
 }
 
 
-int wpa_driver_test_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
+				    size_t ssid_len)
 {
 	wpa_printf(MSG_DEBUG, "%s", __func__);
 	return 0;
 }
 
 
-int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
+static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
 {
 	wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
 	return 0;
 }
 #endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies,
+					    size_t ies_len)
+{
+	struct wpa_driver_test_data *drv = priv;
+
+	os_free(drv->probe_req_ie);
+	if (ies) {
+		drv->probe_req_ie = os_malloc(ies_len);
+		if (drv->probe_req_ie == NULL) {
+			drv->probe_req_ie_len = 0;
+			return -1;
+		}
+		os_memcpy(drv->probe_req_ie, ies, ies_len);
+		drv->probe_req_ie_len = ies_len;
+	} else {
+		drv->probe_req_ie = NULL;
+		drv->probe_req_ie_len = 0;
+	}
+	return 0;
+}
+
+
+static void * wpa_driver_test_global_init(void)
+{
+	struct wpa_driver_test_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	return global;
+}
+
+
+static void wpa_driver_test_global_deinit(void *priv)
+{
+	struct wpa_driver_test_global *global = priv;
+	os_free(global);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+	/* struct wpa_driver_test_global *global = priv; */
+	struct wpa_interface_info *iface;
+
+	iface = os_zalloc(sizeof(*iface));
+	if (iface == NULL)
+		return iface;
+	iface->ifname = os_strdup("sta0");
+	iface->desc = os_strdup("test interface 0");
+	iface->drv_name = "test";
+	iface->next = os_zalloc(sizeof(*iface));
+	if (iface->next) {
+		iface->next->ifname = os_strdup("sta1");
+		iface->next->desc = os_strdup("test interface 1");
+		iface->next->drv_name = "test";
+	}
+
+	return iface;
+}
 
 
 const struct wpa_driver_ops wpa_driver_test_ops = {
@@ -943,7 +1179,7 @@
 	wpa_driver_test_get_ssid,
 	wpa_driver_test_set_wpa,
 	wpa_driver_test_set_key,
-	wpa_driver_test_init,
+	NULL /* init */,
 	wpa_driver_test_deinit,
 	wpa_driver_test_set_param,
 	NULL /* set_countermeasures */,
@@ -984,6 +1220,11 @@
 	NULL /* update_ft_ies */,
 	NULL /* send_ft_action */,
 	wpa_driver_test_get_scan_results2,
-	NULL /* set_probe_req_ie */,
-	NULL /* set_mode */
+	wpa_driver_test_set_probe_req_ie,
+	NULL /* set_mode */,
+	NULL /* set_country */,
+	wpa_driver_test_global_init,
+	wpa_driver_test_global_deinit,
+	wpa_driver_test_init2,
+	wpa_driver_test_get_interfaces
 };

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/driver_wext.c Sat Jan 10 08:43:01 2009
@@ -1726,13 +1726,11 @@
 	case WPA_ALG_PMK:
 		ext->alg = IW_ENCODE_ALG_PMK;
 		break;
-#ifdef WEXT_MFP_PENDING
 #ifdef CONFIG_IEEE80211W
 	case WPA_ALG_IGTK:
 		ext->alg = IW_ENCODE_ALG_AES_CMAC;
 		break;
 #endif /* CONFIG_IEEE80211W */
-#endif /* WEXT_MFP_PENDING */
 	default:
 		wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
 			   __FUNCTION__, alg);
@@ -2084,7 +2082,6 @@
 					   IW_AUTH_RX_UNENCRYPTED_EAPOL,
 					   allow_unencrypted_eapol) < 0)
 		ret = -1;
-#ifdef WEXT_MFP_PENDING
 #ifdef CONFIG_IEEE80211W
 	switch (params->mgmt_frame_protection) {
 	case NO_MGMT_FRAME_PROTECTION:
@@ -2100,7 +2097,6 @@
 	if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
 		ret = -1;
 #endif /* CONFIG_IEEE80211W */
-#endif /* WEXT_MFP_PENDING */
 	if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
 		ret = -1;
 	if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)

Modified: wpasupplicant/branches/upstream/current/src/drivers/ndis_events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/ndis_events.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/ndis_events.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/ndis_events.c Sat Jan 10 08:43:01 2009
@@ -281,7 +281,7 @@
 		SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
 		*pos++ = ch;
 	}
-	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", data, data_len);
+	wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
 
 	VariantClear(&vt);
 
@@ -752,7 +752,8 @@
 	}
 
 	hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
-			      &IID_IWbemLocator, (LPVOID *) &events->pLoc);
+			      &IID_IWbemLocator,
+			      (LPVOID *) (void *) &events->pLoc);
 	if (FAILED(hr)) {
 		wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
 			   "0x%x", (int) hr);

Modified: wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c (original)
+++ wpasupplicant/branches/upstream/current/src/drivers/scan_helpers.c Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Helper functions for scan result processing
- * 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
@@ -56,6 +56,37 @@
 	}
 
 	return NULL;
+}
+
+
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(res->ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (res + 1);
+	end = pos + res->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
 }
 
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_defs.h Sat Jan 10 08:43:01 2009
@@ -66,9 +66,9 @@
 	EAP_TYPE_PSK = 47 /* RFC 4764 */,
 	EAP_TYPE_SAKE = 48 /* RFC 4763 */,
 	EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
-	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */,
-	EAP_TYPE_GPSK = 255 /* EXPERIMENTAL - type not yet allocated
-			     * draft-ietf-emu-eap-gpsk-01.txt */
+	EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
+	EAP_TYPE_GPSK = 51 /* draft-ietf-emu-eap-gpsk-17.txt */,
+	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 } EapType;
 
 

Modified: 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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_peap_common.c Sat Jan 10 08:43:01 2009
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "sha1.h"
+#include "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,

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.c Sat Jan 10 08:43:01 2009
@@ -1,5 +1,5 @@
 /*
- * EAP peer/server: EAP-SIM/AKA shared routines
+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
  * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "eap_common/eap_defs.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "crypto.h"
 #include "aes_wrap.h"
 #include "wpabuf.h"
@@ -230,6 +231,272 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
 		    mac, EAP_SIM_MAC_LEN);
 }
+
+
+#ifdef EAP_AKA_PRIME
+static void prf_prime(const u8 *k, const char *seed1,
+		      const u8 *seed2, size_t seed2_len,
+		      const u8 *seed3, size_t seed3_len,
+		      u8 *res, size_t res_len)
+{
+	const u8 *addr[5];
+	size_t len[5];
+	u8 hash[SHA256_MAC_LEN];
+	u8 iter;
+
+	/*
+	 * PRF'(K,S) = T1 | T2 | T3 | T4 | ...
+	 * T1 = HMAC-SHA-256 (K, S | 0x01)
+	 * T2 = HMAC-SHA-256 (K, T1 | S | 0x02)
+	 * T3 = HMAC-SHA-256 (K, T2 | S | 0x03)
+	 * T4 = HMAC-SHA-256 (K, T3 | S | 0x04)
+	 * ...
+	 */
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (const u8 *) seed1;
+	len[1] = os_strlen(seed1);
+	addr[2] = seed2;
+	len[2] = seed2_len;
+	addr[3] = seed3;
+	len[3] = seed3_len;
+	addr[4] = &iter;
+	len[4] = 1;
+
+	iter = 0;
+	while (res_len) {
+		size_t hlen;
+		iter++;
+		hmac_sha256_vector(k, 32, 5, addr, len, hash);
+		len[0] = SHA256_MAC_LEN;
+		hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len;
+		os_memcpy(res, hash, hlen);
+		res += hlen;
+		res_len -= hlen;
+	}
+}
+
+
+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
+			       const u8 *ik, const u8 *ck, u8 *k_encr,
+			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk)
+{
+	u8 key[EAP_AKA_IK_LEN + EAP_AKA_CK_LEN];
+	u8 keys[EAP_SIM_K_ENCR_LEN + EAP_AKA_PRIME_K_AUT_LEN +
+		EAP_AKA_PRIME_K_RE_LEN + EAP_MSK_LEN + EAP_EMSK_LEN];
+	u8 *pos;
+
+	/*
+	 * MK = PRF'(IK'|CK',"EAP-AKA'"|Identity)
+	 * K_encr = MK[0..127]
+	 * K_aut  = MK[128..383]
+	 * K_re   = MK[384..639]
+	 * MSK    = MK[640..1151]
+	 * EMSK   = MK[1152..1663]
+	 */
+
+	os_memcpy(key, ik, EAP_AKA_IK_LEN);
+	os_memcpy(key + EAP_AKA_IK_LEN, ck, EAP_AKA_CK_LEN);
+
+	prf_prime(key, "EAP-AKA'", identity, identity_len, NULL, 0,
+		  keys, sizeof(keys));
+
+	pos = keys;
+	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_encr",
+			k_encr, EAP_SIM_K_ENCR_LEN);
+	pos += EAP_SIM_K_ENCR_LEN;
+
+	os_memcpy(k_aut, pos, EAP_AKA_PRIME_K_AUT_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	pos += EAP_AKA_PRIME_K_AUT_LEN;
+
+	os_memcpy(k_re, pos, EAP_AKA_PRIME_K_RE_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': K_re",
+			k_re, EAP_AKA_PRIME_K_RE_LEN);
+	pos += EAP_AKA_PRIME_K_RE_LEN;
+
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+				     const u8 *identity, size_t identity_len,
+				     const u8 *nonce_s, u8 *msk, u8 *emsk)
+{
+	u8 seed3[2 + EAP_SIM_NONCE_S_LEN];
+	u8 keys[EAP_MSK_LEN + EAP_EMSK_LEN];
+	u8 *pos;
+
+	/*
+	 * MK = PRF'(K_re,"EAP-AKA' re-auth"|Identity|counter|NONCE_S)
+	 * MSK  = MK[0..511]
+	 * EMSK = MK[512..1023]
+	 */
+
+	WPA_PUT_BE16(seed3, counter);
+	os_memcpy(seed3 + 2, nonce_s, EAP_SIM_NONCE_S_LEN);
+
+	prf_prime(k_re, "EAP-AKA' re-auth", identity, identity_len,
+		  seed3, sizeof(seed3),
+		  keys, sizeof(keys));
+
+	pos = keys;
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': MSK", msk, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': EMSK", emsk, EAP_EMSK_LEN);
+
+	os_memset(keys, 0, sizeof(keys));
+
+	return 0;
+}
+
+
+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+	u8 *tmp;
+
+	if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN ||
+	    mac < wpabuf_head_u8(req) ||
+	    mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN)
+		return -1;
+
+	tmp = os_malloc(wpabuf_len(req));
+	if (tmp == NULL)
+		return -1;
+
+	addr[0] = tmp;
+	len[0] = wpabuf_len(req);
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA-256-128 */
+	os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req));
+	os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg",
+		    tmp, wpabuf_len(req));
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC",
+		    hmac, EAP_SIM_MAC_LEN);
+	os_free(tmp);
+
+	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+}
+
+
+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
+			    u8 *mac, const u8 *extra, size_t extra_len)
+{
+	unsigned char hmac[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	addr[0] = msg;
+	len[0] = msg_len;
+	addr[1] = extra;
+	len[1] = extra_len;
+
+	/* HMAC-SHA-256-128 */
+	os_memset(mac, 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut",
+			k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac);
+	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC",
+		    mac, EAP_SIM_MAC_LEN);
+}
+
+
+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
+				      const u8 *network_name,
+				      size_t network_name_len)
+{
+	u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN];
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[5];
+	size_t len[5];
+	u8 fc;
+	u8 l0[2], l1[2];
+
+	/* 3GPP TS 33.402 V8.0.0
+	 * (CK', IK') = F(CK, IK, <access network identity>)
+	 */
+	/* TODO: CK', IK' generation should really be moved into the actual
+	 * AKA procedure with network name passed in there and option to use
+	 * AMF separation bit = 1 (3GPP TS 33.401). */
+
+	/* Change Request 33.402 CR 0033 to version 8.1.1 from
+	 * 3GPP TSG-SA WG3 Meeting #53 in September 2008:
+	 *
+	 * CK' || IK' = HMAC-SHA-256(Key, S)
+	 * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln
+	 * Key = CK || IK
+	 * FC = 0x20
+	 * P0 = access network identity (3GPP TS 24.302)
+	 * L0 = length of acceess network identity (2 octets, big endian)
+	 * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0
+	 * L1 = 0x00 0x06
+	 */
+
+	fc = 0x20;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)");
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN);
+	wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity",
+			  network_name, network_name_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6);
+
+	os_memcpy(key, ck, EAP_AKA_CK_LEN);
+	os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK",
+			key, sizeof(key));
+
+	addr[0] = &fc;
+	len[0] = 1;
+	addr[1] = network_name;
+	len[1] = network_name_len;
+	WPA_PUT_BE16(l0, network_name_len);
+	addr[2] = l0;
+	len[2] = 2;
+	addr[3] = sqn_ak;
+	len[3] = 6;
+	WPA_PUT_BE16(l1, 6);
+	addr[4] = l1;
+	len[4] = 2;
+
+	hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')",
+			hash, sizeof(hash));
+
+	os_memcpy(ck, hash, EAP_AKA_CK_LEN);
+	os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN);
+}
+#endif /* EAP_AKA_PRIME */
 
 
 int eap_sim_parse_attr(const u8 *start, const u8 *end,
@@ -357,8 +624,20 @@
 			break;
 		case EAP_SIM_AT_IDENTITY:
 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_IDENTITY");
-			attr->identity = apos + 2;
-			attr->identity_len = alen - 2;
+			plen = WPA_GET_BE16(apos);
+			apos += 2;
+			alen -= 2;
+			if (plen > alen) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid "
+					   "AT_IDENTITY (Actual Length %lu, "
+					   "remaining length %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+
+			attr->identity = apos;
+			attr->identity_len = plen;
 			break;
 		case EAP_SIM_AT_VERSION_LIST:
 			if (aka) {
@@ -554,7 +833,8 @@
 			}
 			apos += 2;
 			alen -= 2;
-			if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN) {
+			if (alen != 0 && alen != EAP_AKA_CHECKCODE_LEN &&
+			    alen != EAP_AKA_PRIME_CHECKCODE_LEN) {
 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
 					   "AT_CHECKCODE (len %lu)",
 					   (unsigned long) alen);
@@ -578,6 +858,62 @@
 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RESULT_IND");
 			attr->result_ind = 1;
 			break;
+#ifdef EAP_AKA_PRIME
+		case EAP_SIM_AT_KDF_INPUT:
+			if (aka != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
+					   "AT_KDF_INPUT");
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF_INPUT");
+			plen = WPA_GET_BE16(apos);
+			apos += 2;
+			alen -= 2;
+			if (plen > alen) {
+				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
+					   "AT_KDF_INPUT (Actual Length %lu, "
+					   "remaining length %lu)",
+					   (unsigned long) plen,
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->kdf_input = apos;
+			attr->kdf_input_len = plen;
+			break;
+		case EAP_SIM_AT_KDF:
+			if (aka != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Unexpected "
+					   "AT_KDF");
+				return -1;
+			}
+
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_KDF");
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA': Invalid "
+					   "AT_KDF (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) {
+				wpa_printf(MSG_DEBUG, "EAP-AKA': Too many "
+					   "AT_KDF attributes - ignore this");
+				continue;
+			}
+			attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos);
+			attr->kdf_count++;
+			break;
+		case EAP_SIM_AT_BIDDING:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_BIDDING");
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid "
+					   "AT_BIDDING (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->bidding = apos;
+			break;
+#endif /* EAP_AKA_PRIME */
 		default:
 			if (pos[0] < 128) {
 				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
@@ -641,6 +977,7 @@
 struct eap_sim_msg {
 	struct wpabuf *buf;
 	size_t mac, iv, encr; /* index from buf */
+	int type;
 };
 
 
@@ -654,6 +991,7 @@
 	if (msg == NULL)
 		return NULL;
 
+	msg->type = type;
 	msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN);
 	if (msg->buf == NULL) {
 		os_free(msg);
@@ -685,6 +1023,14 @@
 	eap = wpabuf_mhead(msg->buf);
 	eap->length = host_to_be16(wpabuf_len(msg->buf));
 
+#ifdef EAP_AKA_PRIME
+	if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) {
+		eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf),
+				       wpabuf_len(msg->buf),
+				       (u8 *) wpabuf_mhead(msg->buf) +
+				       msg->mac, extra, extra_len);
+	} else
+#endif /* EAP_AKA_PRIME */
 	if (k_aut && msg->mac) {
 		eap_sim_add_mac(k_aut, (u8 *) wpabuf_head(msg->buf),
 				wpabuf_len(msg->buf),

Modified: wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_sim_common.h Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
- * EAP peer/server: EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
+ * 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
@@ -70,6 +70,10 @@
 #define EAP_AKA_MIN_RES_LEN 4
 #define EAP_AKA_MAX_RES_LEN 16
 #define EAP_AKA_CHECKCODE_LEN 20
+
+#define EAP_AKA_PRIME_K_AUT_LEN 32
+#define EAP_AKA_PRIME_CHECKCODE_LEN 32
+#define EAP_AKA_PRIME_K_RE_LEN 32
 
 struct wpabuf;
 
@@ -89,6 +93,49 @@
 		       const u8 *mac, const u8 *extra, size_t extra_len);
 void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
 		     const u8 *extra, size_t extra_len);
+
+#ifdef EAP_AKA_PRIME
+void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
+			       const u8 *ik, const u8 *ck, u8 *k_encr,
+			       u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk);
+int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+				     const u8 *identity, size_t identity_len,
+				     const u8 *nonce_s, u8 *msk, u8 *emsk);
+int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len);
+void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
+			    u8 *mac, const u8 *extra, size_t extra_len);
+
+void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
+				      const u8 *network_name,
+				      size_t network_name_len);
+#else /* EAP_AKA_PRIME */
+static inline void eap_aka_prime_derive_keys(const u8 *identity,
+					     size_t identity_len,
+					     const u8 *ik, const u8 *ck,
+					     u8 *k_encr, u8 *k_aut, u8 *k_re,
+					     u8 *msk, u8 *emsk)
+{
+}
+
+static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
+						   const u8 *identity,
+						   size_t identity_len,
+						   const u8 *nonce_s, u8 *msk,
+						   u8 *emsk)
+{
+	return -1;
+}
+
+static inline int eap_sim_verify_mac_sha256(const u8 *k_aut,
+					    const struct wpabuf *req,
+					    const u8 *mac, const u8 *extra,
+					    size_t extra_len)
+{
+	return -1;
+}
+#endif /* EAP_AKA_PRIME */
 
 
 /* EAP-SIM/AKA Attributes (0..127 non-skippable) */
@@ -110,12 +157,15 @@
 #define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
 #define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
 #define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
+#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */
+#define EAP_SIM_AT_KDF 24 /* only AKA' */
 #define EAP_SIM_AT_IV 129
 #define EAP_SIM_AT_ENCR_DATA 130
 #define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
 #define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
 #define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
 #define EAP_SIM_AT_RESULT_IND 135
+#define EAP_SIM_AT_BIDDING 136
 
 /* AT_NOTIFICATION notification code values */
 #define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
@@ -124,6 +174,12 @@
 #define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
 #define EAP_SIM_SUCCESS 32768
 
+/* EAP-AKA' AT_KDF Key Derivation Function values */
+#define EAP_AKA_PRIME_KDF 1
+
+/* AT_BIDDING flags */
+#define EAP_AKA_BIDDING_FLAG_D 0x8000
+
 
 enum eap_sim_id_req {
 	NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
@@ -135,14 +191,20 @@
 	const u8 *next_pseudonym, *next_reauth_id;
 	const u8 *nonce_mt, *identity, *res, *auts;
 	const u8 *checkcode;
+	const u8 *kdf_input;
+	const u8 *bidding;
 	size_t num_chal, version_list_len, encr_data_len;
 	size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
 	size_t res_len_bits;
 	size_t checkcode_len;
+	size_t kdf_input_len;
 	enum eap_sim_id_req id_req;
 	int notification, counter, selected_version, client_error_code;
 	int counter_too_small;
 	int result_ind;
+#define EAP_AKA_PRIME_KDF_MAX 10
+	u16 kdf[EAP_AKA_PRIME_KDF_MAX];
+	size_t kdf_count;
 };
 
 int eap_sim_parse_attr(const u8 *start, const u8 *end,

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,39 @@
+/*
+ * EAP-WSC common routines for Wi-Fi Protected Setup
+ * Copyright (c) 2007, 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 "eap_defs.h"
+#include "eap_common.h"
+#include "wps/wps.h"
+#include "eap_wsc_common.h"
+
+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2, code, id);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "FRAG_ACK");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/FRAG_ACK");
+	wpabuf_put_u8(msg, WSC_FRAG_ACK); /* Op-Code */
+	wpabuf_put_u8(msg, 0); /* Flags */
+
+	return msg;
+}

Added: wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.h (added)
+++ wpasupplicant/branches/upstream/current/src/eap_common/eap_wsc_common.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,33 @@
+/*
+ * EAP-WSC definitions for Wi-Fi Protected Setup
+ * Copyright (c) 2007, 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_WSC_COMMON_H
+#define EAP_WSC_COMMON_H
+
+#define EAP_VENDOR_TYPE_WSC 1
+
+#define WSC_FLAGS_MF 0x01
+#define WSC_FLAGS_LF 0x02
+
+#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0"
+#define WSC_ID_REGISTRAR_LEN 30
+#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0"
+#define WSC_ID_ENROLLEE_LEN 29
+
+#define WSC_FRAGMENT_SIZE 1400
+
+
+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code);
+
+#endif /* EAP_WSC_COMMON_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap.c Sat Jan 10 08:43:01 2009
@@ -31,6 +31,7 @@
 #include "pcsc_funcs.h"
 #include "wpa_ctrl.h"
 #include "state_machine.h"
+#include "eap_common/eap_wsc_common.h"
 
 #define STATE_MACHINE_DATA struct eap_sm
 #define STATE_MACHINE_DEBUG_PREFIX "EAP"
@@ -105,7 +106,7 @@
  * @method: EAP type
  * Returns: 1 = allowed EAP method, 0 = not allowed
  */
-static int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
 {
 	struct eap_peer_config *config = eap_get_config(sm);
 	int i;
@@ -1177,8 +1178,7 @@
 	sm->eapol_cb = eapol_cb;
 	sm->msg_ctx = msg_ctx;
 	sm->ClientTimeout = 60;
-	if (conf->mac_addr)
-		os_memcpy(sm->mac_addr, conf->mac_addr, ETH_ALEN);
+	sm->wps = conf->wps;
 
 	os_memset(&tlsconf, 0, sizeof(tlsconf));
 	tlsconf.opensc_engine_path = conf->opensc_engine_path;
@@ -2043,3 +2043,29 @@
 	if (sm)
 		eap_deinit_prev_method(sm, "invalidate");
 }
+
+
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
+		return 0; /* Not using PBC */
+
+	return 1;
+}
+
+
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
+		return 0; /* Not using PIN */
+
+	return 1;
+}

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap.h Sat Jan 10 08:43:01 2009
@@ -246,11 +246,11 @@
 	 */
 	const char *pkcs11_module_path;
 	/**
-	 * mac_addr - MAC address of the peer
-	 *
-	 * This can be left %NULL if not available.
-	 */
-	const u8 *mac_addr;
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
 };
 
 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
@@ -283,6 +283,9 @@
 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
 void eap_invalidate_cached_session(struct eap_sm *sm);
 
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
+
 #endif /* IEEE8021X_EAPOL */
 
 #endif /* EAP_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_aka.c Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
- * EAP peer method: EAP-AKA (RFC 4187)
- * Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi>
+ * EAP peer method: EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
+ * 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 @@
 #include "pcsc_funcs.h"
 #include "eap_common/eap_sim_common.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "crypto.h"
 #include "eap_peer/eap_config.h"
 #ifdef CONFIG_USIM_SIMULATOR
@@ -31,8 +32,9 @@
 	size_t res_len;
 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
 	u8 mk[EAP_SIM_MK_LEN];
-	u8 k_aut[EAP_SIM_K_AUT_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
 	u8 emsk[EAP_EMSK_LEN];
 	u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
@@ -54,6 +56,10 @@
 	struct wpabuf *id_msgs;
 	int prev_id;
 	int result_ind, use_result_ind;
+	u8 eap_method;
+	u8 *network_name;
+	size_t network_name_len;
+	u16 kdf;
 };
 
 
@@ -96,6 +102,8 @@
 	if (data == NULL)
 		return NULL;
 
+	data->eap_method = EAP_TYPE_AKA;
+
 	eap_aka_state(data, CONTINUE);
 	data->prev_id = -1;
 
@@ -103,6 +111,18 @@
 
 	return data;
 }
+
+
+#ifdef EAP_AKA_PRIME
+static void * eap_aka_prime_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data = eap_aka_init(sm);
+	if (data == NULL)
+		return NULL;
+	data->eap_method = EAP_TYPE_AKA_PRIME;
+	return data;
+}
+#endif /* EAP_AKA_PRIME */
 
 
 static void eap_aka_deinit(struct eap_sm *sm, void *priv)
@@ -113,6 +133,7 @@
 		os_free(data->reauth_id);
 		os_free(data->last_eap_identity);
 		wpabuf_free(data->id_msgs);
+		os_free(data->network_name);
 		os_free(data);
 	}
 }
@@ -302,7 +323,7 @@
 {
 	const u8 *addr;
 	size_t len;
-	u8 hash[SHA1_MAC_LEN];
+	u8 hash[SHA256_MAC_LEN];
 
 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
 
@@ -315,14 +336,20 @@
 		return;
 	}
 
-	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
+	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
 	addr = wpabuf_head(data->id_msgs);
 	len = wpabuf_len(data->id_msgs);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
-	sha1_vector(1, &addr, &len, hash);
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+#endif /* EAP_AKA_PRIME */
+		sha1_vector(1, &addr, &len, hash);
 
 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
-			EAP_AKA_CHECKCODE_LEN);
+			data->eap_method == EAP_TYPE_AKA_PRIME ?
+			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
 }
 
 
@@ -331,7 +358,8 @@
 {
 	const u8 *addr;
 	size_t len;
-	u8 hash[SHA1_MAC_LEN];
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
 
 	if (checkcode == NULL)
 		return -1;
@@ -346,19 +374,27 @@
 		return 0;
 	}
 
-	if (checkcode_len != EAP_AKA_CHECKCODE_LEN) {
+	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
+		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
+
+	if (checkcode_len != hash_len) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from server "
 			   "indicates that AKA/Identity message were not "
 			   "used, but they were");
 		return -1;
 	}
 
-	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
+	/* Checkcode is SHA1/SHA256 hash over all EAP-AKA/Identity packets. */
 	addr = wpabuf_head(data->id_msgs);
 	len = wpabuf_len(data->id_msgs);
-	sha1_vector(1, &addr, &len, hash);
-
-	if (os_memcmp(hash, checkcode, EAP_AKA_CHECKCODE_LEN) != 0) {
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+#endif /* EAP_AKA_PRIME */
+		sha1_vector(1, &addr, &len, hash);
+
+	if (os_memcmp(hash, checkcode, hash_len) != 0) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
 		return -1;
 	}
@@ -376,7 +412,7 @@
 	data->num_id_req = 0;
 	data->num_notification = 0;
 
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_CLIENT_ERROR);
 	eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0);
 	return eap_sim_msg_finish(msg, NULL, NULL, 0);
@@ -394,7 +430,7 @@
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Authentication-Reject "
 		   "(id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT);
 	return eap_sim_msg_finish(msg, NULL, NULL, 0);
 }
@@ -410,7 +446,7 @@
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Synchronization-Failure "
 		   "(id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
 	wpa_printf(MSG_DEBUG, "   AT_AUTS");
 	eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
@@ -449,7 +485,7 @@
 		eap_aka_clear_identities(data, CLEAR_EAP_ID);
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_IDENTITY);
 
 	if (identity) {
@@ -469,7 +505,7 @@
 	struct eap_sim_msg *msg;
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_CHALLENGE);
 	wpa_printf(MSG_DEBUG, "   AT_RES");
 	eap_sim_msg_add(msg, EAP_SIM_AT_RES, data->res_len * 8,
@@ -494,7 +530,7 @@
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Reauthentication (id=%d)",
 		   id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
 	wpa_printf(MSG_DEBUG, "   AT_IV");
 	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
@@ -535,7 +571,7 @@
 	u8 *k_aut = (notification & 0x4000) == 0 ? data->k_aut : NULL;
 
 	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Notification (id=%d)", id);
-	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_NOTIFICATION);
 	if (k_aut && data->reauth) {
 		wpa_printf(MSG_DEBUG, "   AT_IV");
@@ -611,6 +647,101 @@
 }
 
 
+static int eap_aka_verify_mac(struct eap_aka_data *data,
+			      const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len)
+{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
+						 extra_len);
+	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
+}
+
+
+#ifdef EAP_AKA_PRIME
+static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data,
+						u8 id, u16 kdf)
+{
+	struct eap_sim_msg *msg;
+
+	data->kdf = kdf;
+	wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d) (KDF "
+		   "select)", id);
+	msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method,
+			       EAP_AKA_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_KDF");
+	eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0);
+	return eap_sim_msg_finish(msg, NULL, NULL, 0);
+}
+
+
+static struct wpabuf * eap_aka_prime_kdf_neg(struct eap_aka_data *data,
+					     u8 id, struct eap_sim_attrs *attr)
+{
+	size_t i;
+
+	for (i = 0; i < attr->kdf_count; i++) {
+		if (attr->kdf[i] == EAP_AKA_PRIME_KDF)
+			return eap_aka_prime_kdf_select(data, id,
+							EAP_AKA_PRIME_KDF);
+	}
+
+	/* No matching KDF found - fail authentication as if AUTN had been
+	 * incorrect */
+	return eap_aka_authentication_reject(data, id);
+}
+
+
+static int eap_aka_prime_kdf_valid(struct eap_aka_data *data,
+				   struct eap_sim_attrs *attr)
+{
+	size_t i, j;
+
+	if (attr->kdf_count == 0)
+		return 0;
+
+	/* The only allowed (and required) duplication of a KDF is the addition
+	 * of the selected KDF into the beginning of the list. */
+
+	if (data->kdf) {
+		if (attr->kdf[0] != data->kdf) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
+				   "accept the selected KDF");
+			return 0;
+		}
+
+		for (i = 1; i < attr->kdf_count; i++) {
+			if (attr->kdf[i] == data->kdf)
+				break;
+		}
+		if (i == attr->kdf_count &&
+		    attr->kdf_count < EAP_AKA_PRIME_KDF_MAX) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': The server did not "
+				   "duplicate the selected KDF");
+			return 0;
+		}
+
+		/* TODO: should check that the list is identical to the one
+		 * used in the previous Challenge message apart from the added
+		 * entry in the beginning. */
+	}
+
+	for (i = data->kdf ? 1 : 0; i < attr->kdf_count; i++) {
+		for (j = i + 1; j < attr->kdf_count; j++) {
+			if (attr->kdf[i] == attr->kdf[j]) {
+				wpa_printf(MSG_WARNING, "EAP-AKA': The server "
+					   "included a duplicated KDF");
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+#endif /* EAP_AKA_PRIME */
+
+
 static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm,
 						 struct eap_aka_data *data,
 						 u8 id,
@@ -632,6 +763,52 @@
 		return eap_aka_client_error(data, id,
 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
 	}
+
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		if (!attr->kdf_input || attr->kdf_input_len == 0) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': Challenge message "
+				   "did not include non-empty AT_KDF_INPUT");
+			/* Fail authentication as if AUTN had been incorrect */
+			return eap_aka_authentication_reject(data, id);
+		}
+		os_free(data->network_name);
+		data->network_name = os_malloc(attr->kdf_input_len);
+		if (data->network_name == NULL) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': No memory for "
+				   "storing Network Name");
+			return eap_aka_authentication_reject(data, id);
+		}
+		os_memcpy(data->network_name, attr->kdf_input,
+			  attr->kdf_input_len);
+		data->network_name_len = attr->kdf_input_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': Network Name "
+				  "(AT_KDF_INPUT)",
+				  data->network_name, data->network_name_len);
+		/* TODO: check Network Name per 3GPP.33.402 */
+
+		if (!eap_aka_prime_kdf_valid(data, attr))
+			return eap_aka_authentication_reject(data, id);
+
+		if (attr->kdf[0] != EAP_AKA_PRIME_KDF)
+			return eap_aka_prime_kdf_neg(data, id, attr);
+
+		data->kdf = EAP_AKA_PRIME_KDF;
+		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
+	}
+
+	if (data->eap_method == EAP_TYPE_AKA && attr->bidding) {
+		u16 flags = WPA_GET_BE16(attr->bidding);
+		if ((flags & EAP_AKA_BIDDING_FLAG_D) &&
+		    eap_allowed_method(sm, EAP_VENDOR_IETF,
+				       EAP_TYPE_AKA_PRIME)) {
+			wpa_printf(MSG_WARNING, "EAP-AKA: Bidding down from "
+				   "AKA' to AKA detected");
+			/* Fail authentication as if AUTN had been incorrect */
+			return eap_aka_authentication_reject(data, id);
+		}
+	}
+#endif /* EAP_AKA_PRIME */
 
 	data->reauth = 0;
 	if (!attr->mac || !attr->rand || !attr->autn) {
@@ -660,6 +837,16 @@
 		return eap_aka_client_error(data, id,
 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
 	}
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
+		 * needed 6-octet SQN ^AK for CK',IK' derivation */
+		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
+						 data->autn,
+						 data->network_name,
+						 data->network_name_len);
+	}
+#endif /* EAP_AKA_PRIME */
 	if (data->last_eap_identity) {
 		identity = data->last_eap_identity;
 		identity_len = data->last_eap_identity_len;
@@ -670,12 +857,17 @@
 		identity = eap_get_config_identity(sm, &identity_len);
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
 			  "derivation", identity, identity_len);
-	eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
-			  data->mk);
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
-	{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+					  data->ck, data->k_encr, data->k_aut,
+					  data->k_re, data->msk, data->emsk);
+	} else {
+		eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
+				  data->mk);
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+	}
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
 			   "used invalid AT_MAC");
 		return eap_aka_client_error(data, id,
@@ -763,8 +955,7 @@
 		return -1;
 	}
 
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
-	{
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
 			   "used invalid AT_MAC");
 		return -1;
@@ -842,8 +1033,7 @@
 	}
 
 	data->reauth = 1;
-	if (eap_sim_verify_mac(data->k_aut, reqData, attr->mac, (u8 *) "", 0))
-	{
+	if (eap_aka_verify_mac(data, reqData, attr->mac, (u8 *) "", 0)) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
 			   "did not have valid AT_MAC");
 		return eap_aka_client_error(data, id,
@@ -881,10 +1071,6 @@
 		wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
 			   "(%d <= %d)", eattr.counter, data->counter);
 		data->counter_too_small = eattr.counter;
-
-		eap_sim_derive_keys_reauth(eattr.counter, data->reauth_id,
-					   data->reauth_id_len, eattr.nonce_s,
-					   data->mk, NULL, NULL);
 
 		/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
 		 * reauth_id must not be used to start a new reauthentication.
@@ -908,10 +1094,18 @@
 	wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
 		    data->nonce_s, EAP_SIM_NONCE_S_LEN);
 
-	eap_sim_derive_keys_reauth(data->counter,
-				   data->reauth_id, data->reauth_id_len,
-				   data->nonce_s, data->mk, data->msk,
-				   data->emsk);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
+						 data->reauth_id,
+						 data->reauth_id_len,
+						 data->nonce_s,
+						 data->msk, data->emsk);
+	} else {
+		eap_sim_derive_keys_reauth(data->counter, data->reauth_id,
+					   data->reauth_id_len,
+					   data->nonce_s, data->mk,
+					   data->msk, data->emsk);
+	}
 	eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 	eap_aka_learn_ids(data, &eattr);
 
@@ -955,7 +1149,8 @@
 		return NULL;
 	}
 
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, reqData, &len);
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, reqData,
+			       &len);
 	if (pos == NULL || len < 1) {
 		ret->ignore = TRUE;
 		return NULL;
@@ -973,7 +1168,8 @@
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
 	pos += 2; /* Reserved */
 
-	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr, 1,
+	if (eap_sim_parse_attr(pos, wpabuf_head_u8(reqData) + len, &attr,
+			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
 			       0)) {
 		res = eap_aka_client_error(data, id,
 					   EAP_AKA_UNABLE_TO_PROCESS_PACKET);
@@ -1152,3 +1348,35 @@
 		eap_peer_method_free(eap);
 	return ret;
 }
+
+
+#ifdef EAP_AKA_PRIME
+int eap_peer_aka_prime_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
+				    "AKA'");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_prime_init;
+	eap->deinit = eap_aka_deinit;
+	eap->process = eap_aka_process;
+	eap->isKeyAvailable = eap_aka_isKeyAvailable;
+	eap->getKey = eap_aka_getKey;
+	eap->has_reauth_data = eap_aka_has_reauth_data;
+	eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
+	eap->init_for_reauth = eap_aka_init_for_reauth;
+	eap->get_identity = eap_aka_get_identity;
+	eap->get_emsk = eap_aka_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+
+	return ret;
+}
+#endif /* EAP_AKA_PRIME */

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_config.h Sat Jan 10 08:43:01 2009
@@ -83,10 +83,10 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 *
 	 * On Windows, trusted CA certificates can be loaded from the system
-	 * certificate store by setting this to cert_store://<name>, e.g.,
+	 * certificate store by setting this to cert_store://name, e.g.,
 	 * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
 	 * Note that when running wpa_supplicant as an application, the user
 	 * certificate store (My user account) is used, whereas computer store
@@ -115,7 +115,7 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *client_cert;
 
@@ -142,7 +142,7 @@
 	 * (Computer account) is used when running wpasvc as a service.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *private_key;
 
@@ -167,7 +167,7 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *dh_file;
 
@@ -215,7 +215,7 @@
 	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *ca_cert2;
 
@@ -242,7 +242,7 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *client_cert2;
 
@@ -255,7 +255,7 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *private_key2;
 
@@ -276,7 +276,7 @@
 	 * wpa_supplicant is run in the background.
 	 *
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	u8 *dh_file2;
 
@@ -344,7 +344,7 @@
 	 * 2 = allow authenticated provisioning,
 	 * 3 = allow both unauthenticated and authenticated provisioning
 	 *
-	 * fast_max_pac_list_len=<num> option can be used to set the maximum
+	 * fast_max_pac_list_len=num option can be used to set the maximum
 	 * number of PAC entries to store in a PAC list (default: 10).
 	 *
 	 * fast_pac_format=binary option can be used to select binary format
@@ -356,6 +356,9 @@
 	 * 0 = do not use cryptobinding (default)
 	 * 1 = use cryptobinding if server supports it
 	 * 2 = require cryptobinding
+	 *
+	 * EAP-WSC (WPS) uses following options: pin=Device_Password and
+	 * uuid=Device_UUID
 	 */
 	char *phase1;
 
@@ -575,7 +578,7 @@
 	 * to the file should be used since working directory may change when
 	 * wpa_supplicant is run in the background.
 	 * Alternatively, a named configuration blob can be used by setting
-	 * this to blob://<blob name>.
+	 * this to blob://blob_name.
 	 */
 	char *pac_file;
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_fast.c Sat Jan 10 08:43:01 2009
@@ -343,10 +343,8 @@
 		sm->peer_challenge = data->key_block_p->client_challenge;
 	}
 	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;
 	sm->auth_challenge = NULL;
 	sm->peer_challenge = NULL;
 
@@ -661,7 +659,18 @@
 
 	if (key_len > isk_len)
 		key_len = isk_len;
-	os_memcpy(isk, key, key_len);
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
 	os_free(key);
 
 	return 0;

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_gpsk.c Sat Jan 10 08:43:01 2009
@@ -130,8 +130,8 @@
 }
 
 
-const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
-				      const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data,
+					     const u8 *pos, const u8 *end)
 {
 	u16 alen;
 
@@ -161,8 +161,8 @@
 }
 
 
-const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
-					const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data,
+					       const u8 *pos, const u8 *end)
 {
 	if (pos == NULL)
 		return NULL;
@@ -219,10 +219,11 @@
 }
 
 
-const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
-					struct eap_gpsk_data *data,
-					const u8 **list, size_t *list_len,
-					const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm,
+					       struct eap_gpsk_data *data,
+					       const u8 **list,
+					       size_t *list_len,
+					       const u8 *pos, const u8 *end)
 {
 	if (pos == NULL)
 		return NULL;
@@ -374,8 +375,8 @@
 }
 
 
-const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data, const u8 *pos,
-				  const u8 *end)
+static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data,
+					 const u8 *pos, const u8 *end)
 {
 	if (end - pos < EAP_GPSK_RAND_LEN) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
@@ -413,8 +414,8 @@
 }
 
 
-const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
-				       const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data,
+					      const u8 *pos, const u8 *end)
 {
 	size_t len;
 
@@ -444,6 +445,7 @@
 				  data->id_server, data->id_server_len);
 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3",
 				  pos, len);
+		return NULL;
 	}
 
 	pos += len;
@@ -452,8 +454,8 @@
 }
 
 
-const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data, const u8 *pos,
-				    const u8 *end)
+static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data,
+					   const u8 *pos, const u8 *end)
 {
 	int vendor, specifier;
 	const struct eap_gpsk_csuite *csuite;
@@ -481,8 +483,8 @@
 }
 
 
-const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
-					  const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data,
+						 const u8 *pos, const u8 *end)
 {
 	u16 alen;
 
@@ -508,9 +510,9 @@
 }
 
 
-const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
-					const u8 *payload,
-					const u8 *pos, const u8 *end)
+static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data,
+					       const u8 *payload,
+					       const u8 *pos, const u8 *end)
 {
 	size_t miclen;
 	u8 mic[EAP_GPSK_MAX_MIC_LEN];

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_i.h Sat Jan 10 08:43:01 2009
@@ -328,12 +328,11 @@
 
 	/* Optional challenges generated in Phase 1 (EAP-FAST) */
 	u8 *peer_challenge, *auth_challenge;
-	int mschapv2_full_key; /* Request full MSCHAPv2 key */
 
 	int num_rounds;
 	int force_disabled;
 
-	u8 mac_addr[ETH_ALEN];
+	struct wps_context *wps;
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
@@ -349,5 +348,6 @@
 const struct wpa_config_blob *
 eap_get_config_blob(struct eap_sm *sm, const char *name);
 void eap_notify_pending(struct eap_sm *sm);
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method);
 
 #endif /* EAP_I_H */

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_methods.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_methods.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_methods.c Sat Jan 10 08:43:01 2009
@@ -427,6 +427,13 @@
 	}
 #endif /* EAP_AKA */
 
+#ifdef EAP_AKA_PRIME
+	if (ret == 0) {
+		int eap_peer_aka_prime_register(void);
+		ret = eap_peer_aka_prime_register();
+	}
+#endif /* EAP_AKA_PRIME */
+
 #ifdef EAP_FAST
 	if (ret == 0) {
 		int eap_peer_fast_register(void);
@@ -454,6 +461,13 @@
 		ret = eap_peer_gpsk_register();
 	}
 #endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+	if (ret == 0) {
+		int eap_peer_wsc_register(void);
+		ret = eap_peer_wsc_register();
+	}
+#endif /* EAP_WSC */
 
 #ifdef EAP_IKEV2
 	if (ret == 0) {

Modified: wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_mschapv2.c Sat Jan 10 08:43:01 2009
@@ -93,7 +93,6 @@
 	 */
 	u8 *peer_challenge;
 	u8 *auth_challenge;
-	int full_key;
 
 	int phase2;
 	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
@@ -114,10 +113,7 @@
 	if (data == NULL)
 		return NULL;
 
-	data->full_key = sm->mschapv2_full_key;
-
 	if (sm->peer_challenge) {
-		data->full_key = 1;
 		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
 		if (data->peer_challenge == NULL) {
 			eap_mschapv2_deinit(sm, data);
@@ -830,27 +826,17 @@
 	if (!data->master_key_valid || !data->success)
 		return NULL;
 
-	if (data->full_key) {
-		/* EAP-FAST needs both send and receive keys */
-		key_len = 2 * MSCHAPV2_KEY_LEN;
-	} else {
-		key_len = MSCHAPV2_KEY_LEN;
-	}
+	key_len = 2 * MSCHAPV2_KEY_LEN;
 
 	key = os_malloc(key_len);
 	if (key == NULL)
 		return NULL;
 
-	if (data->full_key) {
-		get_asymetric_start_key(data->master_key, key,
-					MSCHAPV2_KEY_LEN, 0, 0);
-		get_asymetric_start_key(data->master_key,
-					key + MSCHAPV2_KEY_LEN,
-					MSCHAPV2_KEY_LEN, 1, 0);
-	} else {
-		get_asymetric_start_key(data->master_key, key,
-					MSCHAPV2_KEY_LEN, 1, 0);
-	}
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
+	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
+	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				MSCHAPV2_KEY_LEN, 0, 0);
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
 			key, key_len);

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_peap.c Sat Jan 10 08:43:01 2009
@@ -60,6 +60,7 @@
 				 * EAP-Success and expect AS to send outer
 				 * (unencrypted) EAP-Success after this */
 	int resuming; /* starting a resumed session */
+	int reauth; /* reauthentication */
 	u8 *key_data;
 
 	struct wpabuf *pending_phase2_req;
@@ -118,9 +119,15 @@
 	}
 
 #ifdef EAP_TNC
-	if (os_strstr(phase1, "tnc=soh")) {
+	if (os_strstr(phase1, "tnc=soh2")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
+	} else if (os_strstr(phase1, "tnc=soh1")) {
 		data->soh = 1;
-		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH enabled");
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
+	} else if (os_strstr(phase1, "tnc=soh")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
 	}
 #endif /* EAP_TNC */
 
@@ -140,7 +147,7 @@
 	data->peap_version = EAP_PEAP_VERSION;
 	data->force_peap_version = -1;
 	data->peap_outer_success = 2;
-	data->crypto_binding = NO_BINDING;
+	data->crypto_binding = OPTIONAL_BINDING;
 
 	if (config && config->phase1 &&
 	    eap_peap_parse_phase1(data, config->phase1) < 0) {
@@ -231,21 +238,6 @@
 		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);
@@ -268,6 +260,18 @@
 	if (tk == NULL)
 		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	if (data->reauth &&
+	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+		/* Fast-connect: IPMK|CMK = TK */
+		os_memcpy(data->ipmk, tk, 40);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
+				data->ipmk, 40);
+		os_memcpy(data->cmk, tk + 40, 20);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
+				data->cmk, 20);
+		return 0;
+	}
 
 	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
 		return -1;
@@ -286,7 +290,6 @@
 	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);
@@ -656,7 +659,8 @@
 				struct wpabuf *buf;
 				wpa_printf(MSG_DEBUG,
 					   "EAP-PEAP: SoH EAP Extensions");
-				buf = tncc_process_soh_request(epos, eleft);
+				buf = tncc_process_soh_request(data->soh,
+							       epos, eleft);
 				if (buf) {
 					*resp = eap_msg_alloc(
 						EAP_VENDOR_MICROSOFT, 0x21,
@@ -712,11 +716,9 @@
 				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) {
@@ -1191,6 +1193,7 @@
 	data->phase2_eap_success = 0;
 	data->phase2_eap_started = 0;
 	data->resuming = 1;
+	data->reauth = 1;
 	sm->peap_done = FALSE;
 	return priv;
 }

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=1303&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 Jan 10 08:43:01 2009
@@ -501,6 +501,17 @@
 	length_included = data->tls_out_pos == 0 &&
 		(data->tls_out_len > data->tls_out_limit ||
 		 data->include_tls_length);
+	if (!length_included &&
+	    eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
+	    !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
+		/*
+		 * Windows Server 2008 NPS really wants to have the TLS Message
+		 * length included in phase 0 even for unfragmented frames or
+		 * it will get very confused with Compound MAC calculation and
+		 * Outer TLVs.
+		 */
+		length_included = 1;
+	}
 
 	*out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
 				  1 + length_included * 4 + len,
@@ -738,8 +749,21 @@
 		ret->ignore = TRUE;
 		return NULL;
 	}
-	*flags = *pos++;
-	left--;
+	if (left == 0) {
+		wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
+			   "octet included");
+		if (!sm->workaround) {
+			ret->ignore = TRUE;
+			return NULL;
+		}
+
+		wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
+			   "indicates ACK frame");
+		*flags = 0;
+	} else {
+		*flags = *pos++;
+		left--;
+	}
 	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
 		   "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
 		   *flags);

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_ttls.c Sat Jan 10 08:43:01 2009
@@ -558,10 +558,8 @@
 			EAP_VENDOR_IETF, 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) {

Added: wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/eap_wsc.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,452 @@
+/*
+ * EAP-WSC peer for Wi-Fi Protected Setup
+ * 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 "uuid.h"
+#include "eap_i.h"
+#include "eap_common/eap_wsc_common.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+
+
+struct eap_wsc_data {
+	enum { WAIT_START, MESG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	int registrar;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	enum wsc_op_code in_op_code, out_op_code;
+	size_t out_used;
+	size_t fragment_size;
+	struct wps_data *wps;
+	struct wps_context *wps_ctx;
+};
+
+
+static const char * eap_wsc_state_txt(int state)
+{
+	switch (state) {
+	case WAIT_START:
+		return "WAIT_START";
+	case MESG:
+		return "MESG";
+	case FRAG_ACK:
+		return "FRAG_ACK";
+	case WAIT_FRAG_ACK:
+		return "WAIT_FRAG_ACK";
+	case DONE:
+		return "DONE";
+	case FAIL:
+		return "FAIL";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_wsc_state(struct eap_wsc_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
+		   eap_wsc_state_txt(data->state),
+		   eap_wsc_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_wsc_init(struct eap_sm *sm)
+{
+	struct eap_wsc_data *data;
+	const u8 *identity;
+	size_t identity_len;
+	int registrar;
+	struct wps_config cfg;
+	const char *pos;
+	const char *phase1;
+	struct wps_context *wps;
+
+	wps = sm->wps;
+	if (wps == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: WPS context not available");
+		return NULL;
+	}
+
+	identity = eap_get_config_identity(sm, &identity_len);
+
+	if (identity && identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0)
+		registrar = 1; /* Supplicant is Registrar */
+	else if (identity && identity_len == WSC_ID_ENROLLEE_LEN &&
+	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0)
+		registrar = 0; /* Supplicant is Enrollee */
+	else {
+		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
+				  identity, identity_len);
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = registrar ? MESG : WAIT_START;
+	data->registrar = registrar;
+	data->wps_ctx = wps;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = wps;
+	cfg.registrar = registrar;
+
+	phase1 = eap_get_config_phase1(sm);
+	if (phase1 == NULL) {
+		wpa_printf(MSG_INFO, "EAP-WSC: phase1 configuration data not "
+			   "set");
+		os_free(data);
+		return NULL;
+	}
+
+	pos = os_strstr(phase1, "pin=");
+	if (pos) {
+		pos += 4;
+		cfg.pin = (const u8 *) pos;
+		while (*pos != '\0' && *pos != ' ')
+			pos++;
+		cfg.pin_len = pos - (const char *) cfg.pin;
+	} else {
+		pos = os_strstr(phase1, "pbc=1");
+		if (pos)
+			cfg.pbc = 1;
+	}
+
+	if (cfg.pin == NULL && !cfg.pbc) {
+		wpa_printf(MSG_INFO, "EAP-WSC: PIN or PBC not set in phase1 "
+			   "configuration data");
+		os_free(data);
+		return NULL;
+	}
+
+	data->wps = wps_init(&cfg);
+	if (data->wps == NULL) {
+		os_free(data);
+		return NULL;
+	}
+	data->fragment_size = WSC_FRAGMENT_SIZE;
+
+	if (registrar && cfg.pin) {
+		wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
+				      cfg.pin, cfg.pin_len);
+	}
+
+	return data;
+}
+
+
+static void eap_wsc_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	wps_deinit(data->wps);
+	os_free(data->wps_ctx->network_key);
+	data->wps_ctx->network_key = NULL;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_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-WSC: Generating Response");
+	ret->allowNotifications = TRUE;
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (2 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 2;
+		flags |= WSC_FLAGS_MF;
+		if (data->out_used == 0) {
+			flags |= WSC_FLAGS_LF;
+			send_len -= 2;
+		}
+	}
+	plen = 2 + send_len;
+	if (flags & WSC_FLAGS_LF)
+		plen += 2;
+	resp = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, data->out_op_code); /* Op-Code */
+	wpabuf_put_u8(resp, flags); /* Flags */
+	if (flags & WSC_FLAGS_LF)
+		wpabuf_put_be16(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-WSC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		if ((data->state == FAIL && data->out_op_code == WSC_ACK) ||
+		    data->out_op_code == WSC_NACK ||
+		    data->out_op_code == WSC_Done) {
+			eap_wsc_state(data, FAIL);
+			ret->methodState = METHOD_DONE;
+		} else
+			eap_wsc_state(data, MESG);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_wsc_state(data, WAIT_FRAG_ACK);
+	}
+
+	return resp;
+}
+
+
+static int eap_wsc_process_cont(struct eap_wsc_data *data,
+				const u8 *buf, size_t len, u8 op_code)
+{
+	/* Process continuation of a pending message */
+	if (op_code != data->in_op_code) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
+			   "fragment (expected %d)",
+			   op_code, data->in_op_code);
+		return -1;
+	}
+
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting "
+		   "for %lu bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_wsc_process_fragment(struct eap_wsc_data *data,
+						struct eap_method_ret *ret,
+						u8 id, u8 flags, u8 op_code,
+						u16 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 & WSC_FLAGS_LF)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: 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-WSC: No memory for "
+				   "message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		data->in_op_code = op_code;
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes in first "
+			   "fragment, waiting for %lu bytes more",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_tailroom(data->in_buf));
+	}
+
+	return eap_wsc_build_frag_ack(id, EAP_CODE_RESPONSE);
+}
+
+
+static struct wpabuf * eap_wsc_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_wsc_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 op_code, flags, id;
+	u16 message_length = 0;
+	enum wps_process_res res;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, reqData,
+			       &len);
+	if (pos == NULL || len < 2) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+
+	start = pos;
+	end = start + len;
+
+	op_code = *pos++;
+	flags = *pos++;
+	if (flags & WSC_FLAGS_LF) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		message_length = WPA_GET_BE16(pos);
+		pos += 2;
+
+		if (message_length < end - pos) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
+				   "Length");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
+		   "Flags 0x%x Message Length %d",
+		   op_code, flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (op_code != WSC_FRAG_ACK) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_FRAG_ACK state", op_code);
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
+		eap_wsc_state(data, MESG);
+		return eap_wsc_build_msg(data, ret, id);
+	}
+
+	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
+	    op_code != WSC_Done && op_code != WSC_Start) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->state == WAIT_START) {
+		if (op_code != WSC_Start) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_START state", op_code);
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Received start");
+		eap_wsc_state(data, MESG);
+		/* Start message has empty payload, skip processing */
+		goto send_msg;
+	} else if (op_code == WSC_Start) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->in_buf &&
+	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (flags & WSC_FLAGS_MF) {
+		return eap_wsc_process_fragment(data, ret, id, flags, op_code,
+						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;
+	}
+
+	res = wps_process_msg(data->wps, op_code, data->in_buf);
+	switch (res) {
+	case WPS_DONE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
+			   "successfully - wait for EAP failure");
+		eap_wsc_state(data, FAIL);
+		break;
+	case WPS_CONTINUE:
+		eap_wsc_state(data, MESG);
+		break;
+	case WPS_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
+		eap_wsc_state(data, FAIL);
+		break;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+
+send_msg:
+	if (data->out_buf == NULL) {
+		data->out_buf = wps_get_msg(data->wps, &data->out_op_code);
+		if (data->out_buf == NULL) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to receive "
+				   "message from WPS");
+			return NULL;
+		}
+		data->out_used = 0;
+	}
+
+	eap_wsc_state(data, MESG);
+	return eap_wsc_build_msg(data, ret, id);
+}
+
+
+int eap_peer_wsc_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+				    "WSC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_wsc_init;
+	eap->deinit = eap_wsc_deinit;
+	eap->process = eap_wsc_process;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.c Sat Jan 10 08:43:01 2009
@@ -1218,12 +1218,11 @@
 }
 
 
-static struct wpabuf * tncc_build_soh(void)
+static struct wpabuf * tncc_build_soh(int ver)
 {
 	struct wpabuf *buf;
 	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
 	u8 correlation_id[24];
-	int ver = 2;
 	/* TODO: get correct name */
 	char *machinename = "wpa_supplicant at w1.fi";
 
@@ -1332,7 +1331,7 @@
 }
 
 
-struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len)
+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
 {
 	const u8 *pos;
 
@@ -1365,5 +1364,5 @@
 
 	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
 
-	return tncc_build_soh();
-}
+	return tncc_build_soh(2);
+}

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_peer/tncc.h Sat Jan 10 08:43:01 2009
@@ -37,6 +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);
+struct wpabuf * tncc_process_soh_request(int ver, 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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.c Sat Jan 10 08:43:01 2009
@@ -792,10 +792,51 @@
 				   int eapSRTT, int eapRTTVAR,
 				   int methodTimeout)
 {
-	/* For now, retransmission is done in EAPOL state machines, so make
-	 * sure EAP state machine does not end up trying to retransmit packets.
+	int rto, i;
+
+	if (methodTimeout) {
+		/*
+		 * EAP method (either internal or through AAA server, provided
+		 * timeout hint. Use that as-is as a timeout for retransmitting
+		 * the EAP request if no response is received.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
+			   "(from EAP method hint)", methodTimeout);
+		return methodTimeout;
+	}
+
+	/*
+	 * RFC 3748 recommends algorithms described in RFC 2988 for estimation
+	 * of the retransmission timeout. This should be implemented once
+	 * round-trip time measurements are available. For nowm a simple
+	 * backoff mechanism is used instead if there are no EAP method
+	 * specific hints.
+	 *
+	 * SRTT = smoothed round-trip time
+	 * RTTVAR = round-trip time variation
+	 * RTO = retransmission timeout
 	 */
-	return 1;
+
+	/*
+	 * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
+	 * initial retransmission and then double the RTO to provide back off
+	 * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
+	 * modified RTOmax.
+	 */
+	rto = 3;
+	for (i = 0; i < retransCount; i++) {
+		rto *= 2;
+		if (rto >= 20) {
+			rto = 20;
+			break;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
+		   "(from dynamic back off; retransCount=%d)",
+		   rto, retransCount);
+
+	return rto;
 }
 
 
@@ -1051,9 +1092,28 @@
 	}
 
 	if ((sm->user == NULL || sm->update_user) && sm->identity) {
+		/*
+		 * Allow Identity method to be started once to allow identity
+		 * selection hint to be sent from the authentication server,
+		 * but prevent a loop of Identity requests by only allowing
+		 * this to happen once.
+		 */
+		int id_req = 0;
+		if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
+		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[0].method == EAP_TYPE_IDENTITY)
+			id_req = 1;
 		if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
 			wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
 				   "found from database -> FAILURE");
+			return DECISION_FAILURE;
+		}
+		if (id_req && sm->user &&
+		    sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
+			wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
+				   "identity request loop -> FAILURE");
+			sm->update_user = TRUE;
 			return DECISION_FAILURE;
 		}
 		sm->update_user = FALSE;
@@ -1139,7 +1199,7 @@
 		return NULL;
 	sm->eapol_ctx = eapol_ctx;
 	sm->eapol_cb = eapol_cb;
-	sm->MaxRetrans = 10;
+	sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
 	sm->ssl_ctx = conf->ssl_ctx;
 	sm->eap_sim_db_priv = conf->eap_sim_db_priv;
 	sm->backend_auth = conf->backend_auth;
@@ -1166,6 +1226,9 @@
 	sm->pac_key_refresh_time = conf->pac_key_refresh_time;
 	sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
 	sm->tnc = conf->tnc;
+	sm->wps = conf->wps;
+	if (conf->assoc_wps_ie)
+		sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
 
 	wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
 
@@ -1199,6 +1262,7 @@
 	wpabuf_free(sm->eap_if.aaaEapRespData);
 	os_free(sm->eap_if.aaaEapKeyData);
 	eap_user_free(sm->user);
+	wpabuf_free(sm->assoc_wps_ie);
 	os_free(sm);
 }
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap.h Sat Jan 10 08:43:01 2009
@@ -103,6 +103,8 @@
 	int pac_key_refresh_time;
 	int eap_sim_aka_result_ind;
 	int tnc;
+	struct wps_context *wps;
+	const struct wpabuf *assoc_wps_ie;
 };
 
 

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_aka.c Sat Jan 10 08:43:01 2009
@@ -1,5 +1,5 @@
 /*
- * hostapd / EAP-AKA (RFC 4187)
+ * hostapd / EAP-AKA (RFC 4187) and EAP-AKA' (draft-arkko-eap-aka-kdf)
  * Copyright (c) 2005-2008, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -19,14 +19,16 @@
 #include "eap_common/eap_sim_common.h"
 #include "eap_server/eap_sim_db.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "crypto.h"
 
 
 struct eap_aka_data {
 	u8 mk[EAP_SIM_MK_LEN];
 	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
-	u8 k_aut[EAP_SIM_K_AUT_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN]; /* EAP-AKA' only */
 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
 	u8 emsk[EAP_EMSK_LEN];
 	u8 rand[EAP_AKA_RAND_LEN];
@@ -49,6 +51,10 @@
 
 	struct wpabuf *id_msgs;
 	int pending_id;
+	u8 eap_method;
+	u8 *network_name;
+	size_t network_name_len;
+	u16 kdf;
 };
 
 
@@ -99,12 +105,50 @@
 	data = os_zalloc(sizeof(*data));
 	if (data == NULL)
 		return NULL;
+
+	data->eap_method = EAP_TYPE_AKA;
+
 	data->state = IDENTITY;
 	eap_aka_determine_identity(sm, data, 1, 0);
 	data->pending_id = -1;
 
 	return data;
 }
+
+
+#ifdef EAP_AKA_PRIME
+static void * eap_aka_prime_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data;
+	/* TODO: make ANID configurable; see 3GPP TS 24.302 */
+	char *network_name = "WLAN";
+
+	if (sm->eap_sim_db_priv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->eap_method = EAP_TYPE_AKA_PRIME;
+	data->network_name = os_malloc(os_strlen(network_name));
+	if (data->network_name == NULL) {
+		os_free(data);
+		return NULL;
+	}
+
+	data->network_name_len = os_strlen(network_name);
+	os_memcpy(data->network_name, network_name, data->network_name_len);
+
+	data->state = IDENTITY;
+	eap_aka_determine_identity(sm, data, 1, 0);
+	data->pending_id = -1;
+
+	return data;
+}
+#endif /* EAP_AKA_PRIME */
 
 
 static void eap_aka_reset(struct eap_sm *sm, void *priv)
@@ -113,6 +157,7 @@
 	os_free(data->next_pseudonym);
 	os_free(data->next_reauth_id);
 	wpabuf_free(data->id_msgs);
+	os_free(data->network_name);
 	os_free(data);
 }
 
@@ -141,7 +186,7 @@
 {
 	const u8 *addr;
 	size_t len;
-	u8 hash[SHA1_MAC_LEN];
+	u8 hash[SHA256_MAC_LEN];
 
 	wpa_printf(MSG_DEBUG, "   AT_CHECKCODE");
 
@@ -158,10 +203,14 @@
 	addr = wpabuf_head(data->id_msgs);
 	len = wpabuf_len(data->id_msgs);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-AKA: AT_CHECKCODE data", addr, len);
-	sha1_vector(1, &addr, &len, hash);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+		sha1_vector(1, &addr, &len, hash);
 
 	eap_sim_msg_add(msg, EAP_SIM_AT_CHECKCODE, 0, hash,
-			EAP_AKA_CHECKCODE_LEN);
+			data->eap_method == EAP_TYPE_AKA_PRIME ?
+			EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN);
 }
 
 
@@ -170,7 +219,8 @@
 {
 	const u8 *addr;
 	size_t len;
-	u8 hash[SHA1_MAC_LEN];
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
 
 	if (checkcode == NULL)
 		return -1;
@@ -185,7 +235,10 @@
 		return 0;
 	}
 
-	if (checkcode_len != EAP_AKA_CHECKCODE_LEN) {
+	hash_len = data->eap_method == EAP_TYPE_AKA_PRIME ?
+		EAP_AKA_PRIME_CHECKCODE_LEN : EAP_AKA_CHECKCODE_LEN;
+
+	if (checkcode_len != hash_len) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: Checkcode from peer indicates "
 			   "that AKA/Identity message were not used, but they "
 			   "were");
@@ -195,9 +248,12 @@
 	/* Checkcode is SHA1 hash over all EAP-AKA/Identity packets. */
 	addr = wpabuf_head(data->id_msgs);
 	len = wpabuf_len(data->id_msgs);
-	sha1_vector(1, &addr, &len, hash);
-
-	if (os_memcmp(hash, checkcode, EAP_AKA_CHECKCODE_LEN) != 0) {
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		sha256_vector(1, &addr, &len, hash);
+	else
+		sha1_vector(1, &addr, &len, hash);
+
+	if (os_memcmp(hash, checkcode, hash_len) != 0) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE");
 		return -1;
 	}
@@ -213,7 +269,7 @@
 	struct wpabuf *buf;
 
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_IDENTITY);
 	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
 				      sm->identity_len)) {
@@ -309,11 +365,23 @@
 	struct eap_sim_msg *msg;
 
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_CHALLENGE);
 	wpa_printf(MSG_DEBUG, "   AT_RAND");
 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
 	eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		if (data->kdf) {
+			/* Add the selected KDF into the beginning */
+			eap_sim_msg_add(msg, EAP_SIM_AT_KDF, data->kdf,
+					NULL, 0);
+		}
+		eap_sim_msg_add(msg, EAP_SIM_AT_KDF, EAP_AKA_PRIME_KDF,
+				NULL, 0);
+		eap_sim_msg_add(msg, EAP_SIM_AT_KDF_INPUT,
+				data->network_name_len,
+				data->network_name, data->network_name_len);
+	}
 
 	if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
 		eap_sim_msg_free(msg);
@@ -326,6 +394,35 @@
 		wpa_printf(MSG_DEBUG, "   AT_RESULT_IND");
 		eap_sim_msg_add(msg, EAP_SIM_AT_RESULT_IND, 0, NULL, 0);
 	}
+
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA) {
+		u16 flags = 0;
+		int i;
+		int aka_prime_preferred = 0;
+
+		i = 0;
+		while (sm->user && i < EAP_MAX_METHODS &&
+		       (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+			sm->user->methods[i].method != EAP_TYPE_NONE)) {
+			if (sm->user->methods[i].vendor == EAP_VENDOR_IETF) {
+				if (sm->user->methods[i].method ==
+				    EAP_TYPE_AKA)
+					break;
+				if (sm->user->methods[i].method ==
+				    EAP_TYPE_AKA_PRIME) {
+					aka_prime_preferred = 1;
+					break;
+				}
+			}
+			i++;
+		}
+
+		if (aka_prime_preferred)
+			flags |= EAP_AKA_BIDDING_FLAG_D;
+		eap_sim_msg_add(msg, EAP_SIM_AT_BIDDING, flags, NULL, 0);
+	}
+#endif /* EAP_AKA_PRIME */
 
 	wpa_printf(MSG_DEBUG, "   AT_MAC");
 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
@@ -345,13 +442,21 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
 			data->nonce_s, EAP_SIM_NONCE_S_LEN);
 
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
-	eap_sim_derive_keys_reauth(data->counter, sm->identity,
-				   sm->identity_len, data->nonce_s, data->mk,
-				   data->msk, data->emsk);
-
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys_reauth(data->k_re, data->counter,
+						 sm->identity,
+						 sm->identity_len,
+						 data->nonce_s,
+						 data->msk, data->emsk);
+	} else {
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+		eap_sim_derive_keys_reauth(data->counter, sm->identity,
+					   sm->identity_len, data->nonce_s,
+					   data->mk, data->msk, data->emsk);
+	}
+
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
 
 	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
@@ -379,7 +484,7 @@
 	struct eap_sim_msg *msg;
 
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
-	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, data->eap_method,
 			       EAP_AKA_SUBTYPE_NOTIFICATION);
 	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION (%d)", data->notification);
 	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
@@ -437,10 +542,12 @@
 static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
 			     struct wpabuf *respData)
 {
+	struct eap_aka_data *data = priv;
 	const u8 *pos;
 	size_t len;
 
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
+			       &len);
 	if (pos == NULL || len < 3) {
 		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
 		return TRUE;
@@ -523,14 +630,33 @@
 			data->reauth = eap_sim_db_get_reauth_entry(
 				sm->eap_sim_db_priv, sm->identity,
 				sm->identity_len);
+			if (data->reauth &&
+			    data->reauth->aka_prime !=
+			    (data->eap_method == EAP_TYPE_AKA_PRIME)) {
+				wpa_printf(MSG_DEBUG, "EAP-AKA: Reauth data "
+					   "was for different AKA version");
+				data->reauth = NULL;
+			}
 			if (data->reauth) {
 				wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
 					   "re-authentication");
 				identity = data->reauth->identity;
 				identity_len = data->reauth->identity_len;
 				data->counter = data->reauth->counter;
-				os_memcpy(data->mk, data->reauth->mk,
-					  EAP_SIM_MK_LEN);
+				if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+					os_memcpy(data->k_encr,
+						  data->reauth->k_encr,
+						  EAP_SIM_K_ENCR_LEN);
+					os_memcpy(data->k_aut,
+						  data->reauth->k_aut,
+						  EAP_AKA_PRIME_K_AUT_LEN);
+					os_memcpy(data->k_re,
+						  data->reauth->k_re,
+						  EAP_AKA_PRIME_K_RE_LEN);
+				} else {
+					os_memcpy(data->mk, data->reauth->mk,
+						  EAP_SIM_MK_LEN);
+				}
 			}
 		}
 	}
@@ -571,6 +697,17 @@
 		return;
 	}
 
+#ifdef EAP_AKA_PRIME
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		/* Note: AUTN = (SQN ^ AK) || AMF || MAC which gives us the
+		 * needed 6-octet SQN ^AK for CK',IK' derivation */
+		eap_aka_prime_derive_ck_ik_prime(data->ck, data->ik,
+						 data->autn,
+						 data->network_name,
+						 data->network_name_len);
+	}
+#endif /* EAP_AKA_PRIME */
+
 	data->reauth = NULL;
 	data->counter = 0; /* reset re-auth counter since this is full auth */
 
@@ -596,10 +733,16 @@
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
 			  sm->identity, identity_len);
 
-	eap_aka_derive_mk(sm->identity, identity_len, data->ik, data->ck,
-			  data->mk);
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
-			    data->emsk);
+	if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+		eap_aka_prime_derive_keys(identity, identity_len, data->ik,
+					  data->ck, data->k_encr, data->k_aut,
+					  data->k_re, data->msk, data->emsk);
+	} else {
+		eap_aka_derive_mk(sm->identity, identity_len, data->ik,
+				  data->ck, data->mk);
+		eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut,
+				    data->msk, data->emsk);
+	}
 
 	eap_aka_state(data, CHALLENGE);
 }
@@ -638,6 +781,18 @@
 }
 
 
+static int eap_aka_verify_mac(struct eap_aka_data *data,
+			      const struct wpabuf *req,
+			      const u8 *mac, const u8 *extra,
+			      size_t extra_len)
+{
+	if (data->eap_method == EAP_TYPE_AKA_PRIME)
+		return eap_sim_verify_mac_sha256(data->k_aut, req, mac, extra,
+						 extra_len);
+	return eap_sim_verify_mac(data->k_aut, req, mac, extra, extra_len);
+}
+
+
 static void eap_aka_process_challenge(struct eap_sm *sm,
 				      struct eap_aka_data *data,
 				      struct wpabuf *respData,
@@ -647,6 +802,31 @@
 	size_t identity_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
+
+#ifdef EAP_AKA_PRIME
+#if 0
+	/* KDF negotiation; to be enabled only after more than one KDF is
+	 * supported */
+	if (data->eap_method == EAP_TYPE_AKA_PRIME &&
+	    attr->kdf_count == 1 && attr->mac == NULL) {
+		if (attr->kdf[0] != EAP_AKA_PRIME_KDF) {
+			wpa_printf(MSG_WARNING, "EAP-AKA': Peer selected "
+				   "unknown KDF");
+			data->notification =
+				EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+			eap_aka_state(data, NOTIFICATION);
+			return;
+		}
+
+		data->kdf = attr->kdf[0];
+
+		/* Allow negotiation to continue with the selected KDF by
+		 * sending another Challenge message */
+		wpa_printf(MSG_DEBUG, "EAP-AKA': KDF %d selected", data->kdf);
+		return;
+	}
+#endif
+#endif /* EAP_AKA_PRIME */
 
 	if (attr->checkcode &&
 	    eap_aka_verify_checkcode(data, attr->checkcode,
@@ -658,7 +838,7 @@
 		return;
 	}
 	if (attr->mac == NULL ||
-	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, NULL, 0)) {
+	    eap_aka_verify_mac(data, respData, attr->mac, NULL, 0)) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
 			   "did not include valid AT_MAC");
 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
@@ -707,10 +887,23 @@
 		data->next_pseudonym = NULL;
 	}
 	if (data->next_reauth_id) {
-		eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-				      identity_len,
-				      data->next_reauth_id, data->counter + 1,
-				      data->mk);
+		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+#ifdef EAP_AKA_PRIME
+			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+						    identity,
+						    identity_len,
+						    data->next_reauth_id,
+						    data->counter + 1,
+						    data->k_encr, data->k_aut,
+						    data->k_re);
+#endif /* EAP_AKA_PRIME */
+		} else {
+			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+					      identity_len,
+					      data->next_reauth_id,
+					      data->counter + 1,
+					      data->mk);
+		}
 		data->next_reauth_id = NULL;
 	}
 }
@@ -763,7 +956,7 @@
 	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
 
 	if (attr->mac == NULL ||
-	    eap_sim_verify_mac(data->k_aut, respData, attr->mac, data->nonce_s,
+	    eap_aka_verify_mac(data, respData, attr->mac, data->nonce_s,
 			       EAP_SIM_NONCE_S_LEN)) {
 		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
 			   "did not include valid AT_MAC");
@@ -833,9 +1026,23 @@
 		data->next_pseudonym = NULL;
 	}
 	if (data->next_reauth_id) {
-		eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
-				      identity_len, data->next_reauth_id,
-				      data->counter + 1, data->mk);
+		if (data->eap_method == EAP_TYPE_AKA_PRIME) {
+#ifdef EAP_AKA_PRIME
+			eap_sim_db_add_reauth_prime(sm->eap_sim_db_priv,
+						    identity,
+						    identity_len,
+						    data->next_reauth_id,
+						    data->counter + 1,
+						    data->k_encr, data->k_aut,
+						    data->k_re);
+#endif /* EAP_AKA_PRIME */
+		} else {
+			eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+					      identity_len,
+					      data->next_reauth_id,
+					      data->counter + 1,
+					      data->mk);
+		}
 		data->next_reauth_id = NULL;
 	} else {
 		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
@@ -898,7 +1105,8 @@
 	size_t len;
 	struct eap_sim_attrs attr;
 
-	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA, respData, &len);
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, data->eap_method, respData,
+			       &len);
 	if (pos == NULL || len < 3)
 		return;
 
@@ -914,7 +1122,9 @@
 		return;
 	}
 
-	if (eap_sim_parse_attr(pos, end, &attr, 1, 0)) {
+	if (eap_sim_parse_attr(pos, end, &attr,
+			       data->eap_method == EAP_TYPE_AKA_PRIME ? 2 : 1,
+			       0)) {
 		wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
 		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
 		eap_aka_state(data, NOTIFICATION);
@@ -1031,3 +1241,34 @@
 		eap_server_method_free(eap);
 	return ret;
 }
+
+
+#ifdef EAP_AKA_PRIME
+int eap_server_aka_prime_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME,
+				      "AKA'");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_prime_init;
+	eap->reset = eap_aka_reset;
+	eap->buildReq = eap_aka_buildReq;
+	eap->check = eap_aka_check;
+	eap->process = eap_aka_process;
+	eap->isDone = eap_aka_isDone;
+	eap->getKey = eap_aka_getKey;
+	eap->isSuccess = eap_aka_isSuccess;
+	eap->get_emsk = eap_aka_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+
+	return ret;
+}
+#endif /* EAP_AKA_PRIME */

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_fast.c Sat Jan 10 08:43:01 2009
@@ -354,7 +354,18 @@
 
 	if (key_len > isk_len)
 		key_len = isk_len;
-	os_memcpy(isk, key, key_len);
+	if (key_len == 32 &&
+	    data->phase2_method->vendor == EAP_VENDOR_IETF &&
+	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {
+		/*
+		 * EAP-FAST uses reverse order for MS-MPPE keys when deriving
+		 * MSK from EAP-MSCHAPv2. Swap the keys here to get the correct
+		 * ISK for EAP-FAST cryptobinding.
+		 */
+		os_memcpy(isk, key + 16, 16);
+		os_memcpy(isk + 16, key, 16);
+	} else
+		os_memcpy(isk, key, key_len);
 	os_free(key);
 
 	return 0;

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_i.h Sat Jan 10 08:43:01 2009
@@ -181,6 +181,8 @@
 	int pac_key_refresh_time;
 	int eap_sim_aka_result_ind;
 	int tnc;
+	struct wps_context *wps;
+	struct wpabuf *assoc_wps_ie;
 };
 
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_identity.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_identity.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_identity.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_identity.c Sat Jan 10 08:43:01 2009
@@ -125,6 +125,8 @@
 		return; /* Should not happen - frame already validated */
 
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
+	if (sm->identity)
+		sm->update_user = TRUE;
 	os_free(sm->identity);
 	sm->identity = os_malloc(len ? len : 1);
 	if (sm->identity == 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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_methods.c Sat Jan 10 08:43:01 2009
@@ -68,7 +68,7 @@
  * EAP_SERVER_METHOD_INTERFACE_VERSION)
  * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
  * @method: EAP type number (EAP_TYPE_*)
- * name: Name of the method (e.g., "TLS")
+ * @name: Name of the method (e.g., "TLS")
  * Returns: Allocated EAP method structure or %NULL on failure
  *
  * The returned structure should be freed with eap_server_method_free() when it
@@ -212,6 +212,13 @@
 	}
 #endif /* EAP_AKA */
 
+#ifdef EAP_AKA_PRIME
+	if (ret == 0) {
+		int eap_server_aka_prime_register(void);
+		ret = eap_server_aka_prime_register();
+	}
+#endif /* EAP_AKA_PRIME */
+
 #ifdef EAP_PAX
 	if (ret == 0) {
 		int eap_server_pax_register(void);
@@ -253,6 +260,13 @@
 		ret = eap_server_fast_register();
 	}
 #endif /* EAP_FAST */
+
+#ifdef EAP_WSC
+	if (ret == 0) {
+		int eap_server_wsc_register(void);
+		ret = eap_server_wsc_register();
+	}
+#endif /* EAP_WSC */
 
 #ifdef EAP_IKEV2
 	if (ret == 0) {

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_mschapv2.c Sat Jan 10 08:43:01 2009
@@ -524,9 +524,10 @@
 	key = os_malloc(*len);
 	if (key == NULL)
 		return NULL;
-	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 0);
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 1);
 	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 0);
+				MSCHAPV2_KEY_LEN, 1, 1);
 	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
 
 	return key;

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_peap.c Sat Jan 10 08:43:01 2009
@@ -975,21 +975,6 @@
 			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) {

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.c (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.c Sat Jan 10 08:43:01 2009
@@ -942,27 +942,12 @@
 }
 
 
-/**
- * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
- * @priv: Private data pointer from eap_sim_db_init()
- * @identity: Identity of the user (may be permanent identity or pseudonym)
- * @identity_len: Length of identity
- * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
- * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
- * free it.
- * @mk: 16-byte MK from the previous full authentication
- * Returns: 0 on success, -1 on failure
- *
- * This function adds a new re-authentication entry for an EAP-SIM user.
- * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
- * anymore.
- */
-int eap_sim_db_add_reauth(void *priv, const u8 *identity,
-			  size_t identity_len, char *reauth_id, u16 counter,
-			  const u8 *mk)
-{
-	struct eap_sim_db_data *data = priv;
+static struct eap_sim_reauth *
+eap_sim_db_add_reauth_data(struct eap_sim_db_data *data, const u8 *identity,
+			   size_t identity_len, char *reauth_id, u16 counter)
+{
 	struct eap_sim_reauth *r;
+
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add reauth_id for identity",
 			  identity, identity_len);
 	wpa_printf(MSG_DEBUG, "EAP-SIM DB: reauth_id: %s", reauth_id);
@@ -980,7 +965,7 @@
 		r = os_zalloc(sizeof(*r));
 		if (r == NULL) {
 			os_free(reauth_id);
-			return -1;
+			return NULL;
 		}
 
 		r->next = data->reauths;
@@ -988,7 +973,7 @@
 		if (r->identity == NULL) {
 			os_free(r);
 			os_free(reauth_id);
-			return -1;
+			return NULL;
 		}
 		os_memcpy(r->identity, identity, identity_len);
 		r->identity_len = identity_len;
@@ -998,10 +983,86 @@
 	}
 
 	r->counter = counter;
+
+	return r;
+}
+
+
+/**
+ * eap_sim_db_add_reauth - EAP-SIM DB: Add new re-authentication entry
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: Identity of the user (may be permanent identity or pseudonym)
+ * @identity_len: Length of identity
+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
+ * free it.
+ * @counter: AT_COUNTER value for fast re-authentication
+ * @mk: 16-byte MK from the previous full authentication or %NULL
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new re-authentication entry for an EAP-SIM user.
+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
+ * anymore.
+ */
+int eap_sim_db_add_reauth(void *priv, const u8 *identity,
+			  size_t identity_len, char *reauth_id, u16 counter,
+			  const u8 *mk)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_reauth *r;
+
+	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
+				       counter);
+	if (r == NULL)
+		return -1;
+
 	os_memcpy(r->mk, mk, EAP_SIM_MK_LEN);
+	r->aka_prime = 0;
 
 	return 0;
 }
+
+
+#ifdef EAP_AKA_PRIME
+/**
+ * eap_sim_db_add_reauth_prime - EAP-AKA' DB: Add new re-authentication entry
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: Identity of the user (may be permanent identity or pseudonym)
+ * @identity_len: Length of identity
+ * @reauth_id: reauth_id for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_reauth_id(). Caller must not
+ * free it.
+ * @counter: AT_COUNTER value for fast re-authentication
+ * @k_encr: K_encr from the previous full authentication
+ * @k_aut: K_aut from the previous full authentication
+ * @k_re: 32-byte K_re from the previous full authentication
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new re-authentication entry for an EAP-AKA' user.
+ * EAP-SIM DB is responsible of freeing reauth_id buffer once it is not needed
+ * anymore.
+ */
+int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
+				size_t identity_len, char *reauth_id,
+				u16 counter, const u8 *k_encr, const u8 *k_aut,
+				const u8 *k_re)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_reauth *r;
+
+	r = eap_sim_db_add_reauth_data(data, identity, identity_len, reauth_id,
+				       counter);
+	if (r == NULL)
+		return -1;
+
+	r->aka_prime = 1;
+	os_memcpy(r->k_encr, k_encr, EAP_SIM_K_ENCR_LEN);
+	os_memcpy(r->k_aut, k_aut, EAP_AKA_PRIME_K_AUT_LEN);
+	os_memcpy(r->k_re, k_re, EAP_AKA_PRIME_K_RE_LEN);
+
+	return 0;
+}
+#endif /* EAP_AKA_PRIME */
 
 
 /**
@@ -1038,7 +1099,6 @@
  * @identity: Identity of the user (may be permanent identity, pseudonym, or
  * reauth_id)
  * @identity_len: Length of identity
- * @len: Buffer for length of the returned permanent identity
  * Returns: Pointer to the re-auth entry, or %NULL if not found
  */
 struct eap_sim_reauth *

Modified: wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.h (original)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_sim_db.h Sat Jan 10 08:43:01 2009
@@ -54,6 +54,10 @@
 int eap_sim_db_add_reauth(void *priv, const u8 *identity,
 			  size_t identity_len, char *reauth_id, u16 counter,
 			  const u8 *mk);
+int eap_sim_db_add_reauth_prime(void *priv, const u8 *identity,
+				size_t identity_len, char *reauth_id,
+				u16 counter, const u8 *k_encr, const u8 *k_aut,
+				const u8 *k_re);
 
 const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
 				    size_t identity_len, size_t *len);
@@ -64,7 +68,11 @@
 	size_t identity_len;
 	char *reauth_id;
 	u16 counter;
+	int aka_prime;
 	u8 mk[EAP_SIM_MK_LEN];
+	u8 k_encr[EAP_SIM_K_ENCR_LEN];
+	u8 k_aut[EAP_AKA_PRIME_K_AUT_LEN];
+	u8 k_re[EAP_AKA_PRIME_K_RE_LEN];
 };
 
 struct eap_sim_reauth *

Added: wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c (added)
+++ wpasupplicant/branches/upstream/current/src/eap_server/eap_wsc.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,467 @@
+/*
+ * EAP-WSC server for Wi-Fi Protected Setup
+ * 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 "eap_i.h"
+#include "eap_common/eap_wsc_common.h"
+#include "wps/wps.h"
+
+
+struct eap_wsc_data {
+	enum { START, MSG, FRAG_ACK, WAIT_FRAG_ACK, DONE, FAIL } state;
+	int registrar;
+	struct wpabuf *in_buf;
+	struct wpabuf *out_buf;
+	enum wsc_op_code in_op_code, out_op_code;
+	size_t out_used;
+	size_t fragment_size;
+	struct wps_data *wps;
+};
+
+
+static const char * eap_wsc_state_txt(int state)
+{
+	switch (state) {
+	case START:
+		return "START";
+	case MSG:
+		return "MSG";
+	case FRAG_ACK:
+		return "FRAG_ACK";
+	case WAIT_FRAG_ACK:
+		return "WAIT_FRAG_ACK";
+	case DONE:
+		return "DONE";
+	case FAIL:
+		return "FAIL";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_wsc_state(struct eap_wsc_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-WSC: %s -> %s",
+		   eap_wsc_state_txt(data->state),
+		   eap_wsc_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_wsc_init(struct eap_sm *sm)
+{
+	struct eap_wsc_data *data;
+	int registrar;
+	struct wps_config cfg;
+
+	if (sm->identity && sm->identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(sm->identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) ==
+	    0)
+		registrar = 0; /* Supplicant is Registrar */
+	else if (sm->identity && sm->identity_len == WSC_ID_ENROLLEE_LEN &&
+		 os_memcmp(sm->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN)
+		 == 0)
+		registrar = 1; /* Supplicant is Enrollee */
+	else {
+		wpa_hexdump_ascii(MSG_INFO, "EAP-WSC: Unexpected identity",
+				  sm->identity, sm->identity_len);
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = registrar ? START : MSG;
+	data->registrar = registrar;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	cfg.wps = sm->wps;
+	cfg.registrar = registrar;
+	if (registrar) {
+		if (sm->wps == NULL || sm->wps->registrar == NULL) {
+			wpa_printf(MSG_INFO, "EAP-WSC: WPS Registrar not "
+				   "initialized");
+			os_free(data);
+			return NULL;
+		}
+	} else {
+		if (sm->user == NULL || sm->user->password == NULL) {
+			wpa_printf(MSG_INFO, "EAP-WSC: No AP PIN (password) "
+				   "configured for Enrollee functionality");
+			os_free(data);
+			return NULL;
+		}
+		cfg.pin = sm->user->password;
+		cfg.pin_len = sm->user->password_len;
+	}
+	cfg.assoc_wps_ie = sm->assoc_wps_ie;
+	data->wps = wps_init(&cfg);
+	if (data->wps == NULL) {
+		os_free(data);
+		return NULL;
+	}
+	data->fragment_size = WSC_FRAGMENT_SIZE;
+
+	return data;
+}
+
+
+static void eap_wsc_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	wpabuf_free(data->in_buf);
+	wpabuf_free(data->out_buf);
+	wps_deinit(data->wps);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_wsc_build_start(struct eap_sm *sm,
+					   struct eap_wsc_data *data, u8 id)
+{
+	struct wpabuf *req;
+
+	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, 2,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "request");
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Send WSC/Start");
+	wpabuf_put_u8(req, WSC_Start); /* Op-Code */
+	wpabuf_put_u8(req, 0); /* Flags */
+
+	return req;
+}
+
+
+static struct wpabuf * eap_wsc_build_msg(struct eap_wsc_data *data, u8 id)
+{
+	struct wpabuf *req;
+	u8 flags;
+	size_t send_len, plen;
+
+	flags = 0;
+	send_len = wpabuf_len(data->out_buf) - data->out_used;
+	if (2 + send_len > data->fragment_size) {
+		send_len = data->fragment_size - 2;
+		flags |= WSC_FLAGS_MF;
+		if (data->out_used == 0) {
+			flags |= WSC_FLAGS_LF;
+			send_len -= 2;
+		}
+	}
+	plen = 2 + send_len;
+	if (flags & WSC_FLAGS_LF)
+		plen += 2;
+	req = eap_msg_alloc(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC, plen,
+			    EAP_CODE_REQUEST, id);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-WSC: Failed to allocate memory for "
+			   "request");
+		return NULL;
+	}
+
+	wpabuf_put_u8(req, data->out_op_code); /* Op-Code */
+	wpabuf_put_u8(req, flags); /* Flags */
+	if (flags & WSC_FLAGS_LF)
+		wpabuf_put_be16(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-WSC: Sending out %lu bytes "
+			   "(message sent completely)",
+			   (unsigned long) send_len);
+		wpabuf_free(data->out_buf);
+		data->out_buf = NULL;
+		data->out_used = 0;
+		eap_wsc_state(data, MSG);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Sending out %lu bytes "
+			   "(%lu more to send)", (unsigned long) send_len,
+			   (unsigned long) wpabuf_len(data->out_buf) -
+			   data->out_used);
+		eap_wsc_state(data, WAIT_FRAG_ACK);
+	}
+
+	return req;
+}
+
+
+static struct wpabuf * eap_wsc_buildReq(struct eap_sm *sm, void *priv, u8 id)
+{
+	struct eap_wsc_data *data = priv;
+
+	switch (data->state) {
+	case START:
+		return eap_wsc_build_start(sm, data, id);
+	case MSG:
+		if (data->out_buf == NULL) {
+			data->out_buf = wps_get_msg(data->wps,
+						    &data->out_op_code);
+			if (data->out_buf == NULL) {
+				wpa_printf(MSG_DEBUG, "EAP-WSC: Failed to "
+					   "receive message from WPS");
+				return NULL;
+			}
+			data->out_used = 0;
+		}
+		/* pass through */
+	case WAIT_FRAG_ACK:
+		return eap_wsc_build_msg(data, id);
+	case FRAG_ACK:
+		return eap_wsc_build_frag_ack(id, EAP_CODE_REQUEST);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected state %d in "
+			   "buildReq", data->state);
+		return NULL;
+	}
+}
+
+
+static Boolean eap_wsc_check(struct eap_sm *sm, void *priv,
+			     struct wpabuf *respData)
+{
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+			       respData, &len);
+	if (pos == NULL || len < 2) {
+		wpa_printf(MSG_INFO, "EAP-WSC: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static int eap_wsc_process_cont(struct eap_wsc_data *data,
+				const u8 *buf, size_t len, u8 op_code)
+{
+	/* Process continuation of a pending message */
+	if (op_code != data->in_op_code) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d in "
+			   "fragment (expected %d)",
+			   op_code, data->in_op_code);
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	if (len > wpabuf_tailroom(data->in_buf)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment overflow");
+		eap_wsc_state(data, FAIL);
+		return -1;
+	}
+
+	wpabuf_put_data(data->in_buf, buf, len);
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received %lu bytes, waiting for %lu "
+		   "bytes more", (unsigned long) len,
+		   (unsigned long) wpabuf_tailroom(data->in_buf));
+
+	return 0;
+}
+
+
+static int eap_wsc_process_fragment(struct eap_wsc_data *data,
+				    u8 flags, u8 op_code, u16 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 & WSC_FLAGS_LF)) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: 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-WSC: No memory for "
+				   "message");
+			return -1;
+		}
+		data->in_op_code = op_code;
+		wpabuf_put_data(data->in_buf, buf, len);
+		wpa_printf(MSG_DEBUG, "EAP-WSC: 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_wsc_process(struct eap_sm *sm, void *priv,
+			    struct wpabuf *respData)
+{
+	struct eap_wsc_data *data = priv;
+	const u8 *start, *pos, *end;
+	size_t len;
+	u8 op_code, flags;
+	u16 message_length = 0;
+	enum wps_process_res res;
+	struct wpabuf tmpbuf;
+
+	pos = eap_hdr_validate(EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+			       respData, &len);
+	if (pos == NULL || len < 2)
+		return; /* Should not happen; message already verified */
+
+	start = pos;
+	end = start + len;
+
+	op_code = *pos++;
+	flags = *pos++;
+	if (flags & WSC_FLAGS_LF) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Message underflow");
+			return;
+		}
+		message_length = WPA_GET_BE16(pos);
+		pos += 2;
+
+		if (message_length < end - pos) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
+				   "Length");
+			return;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-WSC: Received packet: Op-Code %d "
+		   "Flags 0x%x Message Length %d",
+		   op_code, flags, message_length);
+
+	if (data->state == WAIT_FRAG_ACK) {
+		if (op_code != WSC_FRAG_ACK) {
+			wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d "
+				   "in WAIT_FRAG_ACK state", op_code);
+			eap_wsc_state(data, FAIL);
+			return;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Fragment acknowledged");
+		eap_wsc_state(data, MSG);
+		return;
+	}
+
+	if (op_code != WSC_ACK && op_code != WSC_NACK && op_code != WSC_MSG &&
+	    op_code != WSC_Done) {
+		wpa_printf(MSG_DEBUG, "EAP-WSC: Unexpected Op-Code %d",
+			   op_code);
+		eap_wsc_state(data, FAIL);
+		return;
+	}
+
+	if (data->in_buf &&
+	    eap_wsc_process_cont(data, pos, end - pos, op_code) < 0) {
+		eap_wsc_state(data, FAIL);
+		return;
+	}
+
+	if (flags & WSC_FLAGS_MF) {
+		if (eap_wsc_process_fragment(data, flags, op_code,
+					     message_length, pos, end - pos) <
+		    0)
+			eap_wsc_state(data, FAIL);
+		else
+			eap_wsc_state(data, FRAG_ACK);
+		return;
+	}
+
+	if (data->in_buf == NULL) {
+		/* Wrap unfragmented messages as wpabuf without extra copy */
+		wpabuf_set(&tmpbuf, pos, end - pos);
+		data->in_buf = &tmpbuf;
+	}
+
+	res = wps_process_msg(data->wps, op_code, data->in_buf);
+	switch (res) {
+	case WPS_DONE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing completed "
+			   "successfully - report EAP failure");
+		eap_wsc_state(data, FAIL);
+		break;
+	case WPS_CONTINUE:
+		eap_wsc_state(data, MSG);
+		break;
+	case WPS_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-WSC: WPS processing failed");
+		eap_wsc_state(data, FAIL);
+		break;
+	}
+
+	if (data->in_buf != &tmpbuf)
+		wpabuf_free(data->in_buf);
+	data->in_buf = NULL;
+}
+
+
+static Boolean eap_wsc_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_wsc_data *data = priv;
+	return data->state == FAIL;
+}
+
+
+static Boolean eap_wsc_isSuccess(struct eap_sm *sm, void *priv)
+{
+	/* EAP-WSC will always result in EAP-Failure */
+	return FALSE;
+}
+
+
+static int eap_wsc_getTimeout(struct eap_sm *sm, void *priv)
+{
+	/* Recommended retransmit times: retransmit timeout 5 seconds,
+	 * per-message timeout 15 seconds, i.e., 3 tries. */
+	sm->MaxRetrans = 2; /* total 3 attempts */
+	return 5;
+}
+
+
+int eap_server_wsc_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_WFA, EAP_VENDOR_TYPE_WSC,
+				      "WSC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_wsc_init;
+	eap->reset = eap_wsc_reset;
+	eap->buildReq = eap_wsc_buildReq;
+	eap->check = eap_wsc_check;
+	eap->process = eap_wsc_process;
+	eap->isDone = eap_wsc_isDone;
+	eap->isSuccess = eap_wsc_isSuccess;
+	eap->getTimeout = eap_wsc_getTimeout;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}

Modified: wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c (original)
+++ wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.c Sat Jan 10 08:43:01 2009
@@ -1804,6 +1804,7 @@
 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
 #endif /* EAP_TLS_OPENSSL */
+	conf.wps = ctx->wps;
 
 	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
 	if (sm->eap == NULL) {

Modified: wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.h (original)
+++ wpasupplicant/branches/upstream/current/src/eapol_supp/eapol_supp_sm.h Sat Jan 10 08:43:01 2009
@@ -199,6 +199,13 @@
 	 */
 	const char *pkcs11_module_path;
 #endif /* EAP_TLS_OPENSSL */
+
+	/**
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
 
 	/**
 	 * eap_param_needed - Notify that EAP parameter is needed

Modified: wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet.h (original)
+++ wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet.h Sat Jan 10 08:43:01 2009
@@ -38,7 +38,7 @@
 struct l2_ethhdr {
 	u8 h_dest[ETH_ALEN];
 	u8 h_source[ETH_ALEN];
-	u16 h_proto;
+	be16 h_proto;
 } STRUCT_PACKED;
 
 #ifdef _MSC_VER

Modified: wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_winpcap.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_winpcap.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_winpcap.c (original)
+++ wpasupplicant/branches/upstream/current/src/l2_packet/l2_packet_winpcap.c Sat Jan 10 08:43:01 2009
@@ -336,5 +336,6 @@
 
 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
 {
-	SetEvent(l2->rx_notify);
-}
+	if (l2)
+		SetEvent(l2->rx_notify);
+}

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_client.c Sat Jan 10 08:43:01 2009
@@ -712,9 +712,9 @@
 }
 
 
-void radius_client_update_acct_msgs(struct radius_client_data *radius,
-				    u8 *shared_secret,
-				    size_t shared_secret_len)
+static void radius_client_update_acct_msgs(struct radius_client_data *radius,
+					   u8 *shared_secret,
+					   size_t shared_secret_len)
 {
 	struct radius_msg_list *entry;
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.c (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.c Sat Jan 10 08:43:01 2009
@@ -93,11 +93,14 @@
 	int pac_key_refresh_time;
 	int eap_sim_aka_result_ind;
 	int tnc;
+	struct wps_context *wps;
 	int ipv6;
 	struct os_time start_time;
 	struct radius_server_counters counters;
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);
+	char *eap_req_id_text;
+	size_t eap_req_id_text_len;
 };
 
 
@@ -323,6 +326,7 @@
 	eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
 	eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
 	eap_conf.tnc = data->tnc;
+	eap_conf.wps = data->wps;
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
 	if (sess->eap == NULL) {
@@ -1040,6 +1044,15 @@
 	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->wps = conf->wps;
+	if (conf->eap_req_id_text) {
+		data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
+		if (data->eap_req_id_text) {
+			os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
+				  conf->eap_req_id_text_len);
+			data->eap_req_id_text_len = conf->eap_req_id_text_len;
+		}
+	}
 
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);
@@ -1087,6 +1100,7 @@
 	os_free(data->pac_opaque_encr_key);
 	os_free(data->eap_fast_a_id);
 	os_free(data->eap_fast_a_id_info);
+	os_free(data->eap_req_id_text);
 	os_free(data);
 }
 
@@ -1214,9 +1228,19 @@
 }
 
 
+static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+	*len = data->eap_req_id_text_len;
+	return data->eap_req_id_text;
+}
+
+
 static struct eapol_callbacks radius_server_eapol_cb =
 {
 	.get_eap_user = radius_server_get_eap_user,
+	.get_eap_req_id_text = radius_server_get_eap_req_id_text,
 };
 
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/radius/radius_server.h (original)
+++ wpasupplicant/branches/upstream/current/src/radius/radius_server.h Sat Jan 10 08:43:01 2009
@@ -33,9 +33,12 @@
 	int pac_key_refresh_time;
 	int eap_sim_aka_result_ind;
 	int tnc;
+	struct wps_context *wps;
 	int ipv6;
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);
+	const char *eap_req_id_text;
+	size_t eap_req_id_text_len;
 };
 
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c (original)
+++ wpasupplicant/branches/upstream/current/src/rsn_supp/wpa_ft.c Sat Jan 10 08:43:01 2009
@@ -692,18 +692,24 @@
 	wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
 			igtk_elem, igtk_elem_len);
 
-	if (igtk_elem_len != 2 + 6 + 24) {
+	if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
 		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
 			   "length %lu", (unsigned long) igtk_elem_len);
 		return -1;
 	}
-	if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 8, igtk)) {
+	if (igtk_elem[8] != WPA_IGTK_LEN) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
+			   "%d", igtk_elem[8]);
+		return -1;
+	}
+
+	if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
 		wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
 			   "decrypt IGTK");
 		return -1;
 	}
 
-	/* KeyID[2] | PN[6] | Key[16+8] */
+	/* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
 
 	keyidx = WPA_GET_LE16(igtk_elem);
 

Modified: wpasupplicant/branches/upstream/current/src/tls/bignum.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/bignum.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/bignum.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/bignum.c Sat Jan 10 08:43:01 2009
@@ -97,7 +97,7 @@
 
 /**
  * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
- * @a: Bignum from bignum_init(); to be set to the given value
+ * @n: Bignum from bignum_init(); to be set to the given value
  * @buf: Buffer with unsigned binary value
  * @len: Length of buf in octets
  * Returns: 0 on success, -1 on failure

Modified: wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c (original)
+++ wpasupplicant/branches/upstream/current/src/tls/tlsv1_client.c Sat Jan 10 08:43:01 2009
@@ -124,6 +124,8 @@
  * @in_data: Input data from TLS peer
  * @in_len: Input data length
  * @out_len: Length of the output buffer.
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * @appl_data_len: Pointer to variable that is set to appl_data length
  * Returns: Pointer to output data, %NULL on failure
  */
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/eloop_win.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/eloop_win.c Sat Jan 10 08:43:01 2009
@@ -463,12 +463,11 @@
 	while (!eloop.terminate &&
 	       (eloop.timeout || eloop.reader_count > 0 ||
 		eloop.event_count > 0)) {
+		tv.sec = tv.usec = 0;
 		if (eloop.timeout) {
 			os_get_time(&now);
 			if (os_time_before(&now, &eloop.timeout->time))
 				os_time_sub(&eloop.timeout->time, &now, &tv);
-			else
-				tv.sec = tv.usec = 0;
 		}
 
 		count = 0;

Modified: wpasupplicant/branches/upstream/current/src/utils/includes.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/includes.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/includes.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/includes.h Sat Jan 10 08:43:01 2009
@@ -12,7 +12,7 @@
  * See README and COPYING for more details.
  *
  * This header file is included into all C files so that commonly used header
- * files can be selected with OS specific #ifdefs in one place instead of
+ * files can be selected with OS specific ifdef blocks in one place instead of
  * having to have OS/C library specific selection in many files.
  */
 

Modified: wpasupplicant/branches/upstream/current/src/utils/ip_addr.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/ip_addr.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/ip_addr.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/ip_addr.c Sat Jan 10 08:43:01 2009
@@ -53,8 +53,7 @@
 		break;
 #ifdef CONFIG_IPV6
 	case AF_INET6:
-		if (os_memcpy(&a->u.v6, &b->u.v6, sizeof(a->u.v6))
-		    != 0)
+		if (os_memcmp(&a->u.v6, &b->u.v6, sizeof(a->u.v6)) != 0)
 			return 1;
 		break;
 #endif /* CONFIG_IPV6 */

Modified: wpasupplicant/branches/upstream/current/src/utils/os_unix.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/os_unix.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/os_unix.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/os_unix.c Sat Jan 10 08:43:01 2009
@@ -78,9 +78,9 @@
 
 int os_daemonize(const char *pid_file)
 {
-#ifdef __unclinux
+#ifdef __uClinux__
 	return -1;
-#else /* __uclinux */
+#else /* __uClinux__ */
 	if (daemon(0, 0)) {
 		perror("daemon");
 		return -1;
@@ -95,7 +95,7 @@
 	}
 
 	return -0;
-#endif /* __uclinux */
+#endif /* __uClinux__ */
 }
 
 

Modified: wpasupplicant/branches/upstream/current/src/utils/pcsc_funcs.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/pcsc_funcs.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/pcsc_funcs.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/pcsc_funcs.c Sat Jan 10 08:43:01 2009
@@ -611,7 +611,7 @@
 /**
  * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
  * @scard: Pointer to private data from scard_init()
- * pin: PIN code as an ASCII string (e.g., "1234")
+ * @pin: PIN code as an ASCII string (e.g., "1234")
  * Returns: 0 on success, -1 on failure
  */
 int scard_set_pin(struct scard_data *scard, const char *pin)

Modified: wpasupplicant/branches/upstream/current/src/utils/state_machine.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/state_machine.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/state_machine.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/state_machine.h Sat Jan 10 08:43:01 2009
@@ -14,7 +14,7 @@
  * This file includes a set of pre-processor macros that can be used to
  * implement a state machine. In addition to including this header file, each
  * file implementing a state machine must define STATE_MACHINE_DATA to be the
- * data structure including state variables (enum <machine>_state,
+ * data structure including state variables (enum machine_state,
  * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
  * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
  * a group of state machines with shared data structure, STATE_MACHINE_ADDR
@@ -61,7 +61,7 @@
  * SM_ENTRY_M - State machine function entry point for state machine group
  * @machine: State machine name
  * @_state: State machine state
- * @data: State variable prefix (full variable: <prefix>_state)
+ * @data: State variable prefix (full variable: prefix_state)
  *
  * This macro is like SM_ENTRY, but for state machine groups that use a shared
  * data structure for more than one state machine. Both machine and prefix
@@ -80,7 +80,7 @@
  * SM_ENTRY_MA - State machine function entry point for state machine group
  * @machine: State machine name
  * @_state: State machine state
- * @data: State variable prefix (full variable: <prefix>_state)
+ * @data: State variable prefix (full variable: prefix_state)
  *
  * This macro is like SM_ENTRY_M, but a MAC address is included in debug
  * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to

Modified: wpasupplicant/branches/upstream/current/src/utils/uuid.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/uuid.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/uuid.c (original)
+++ wpasupplicant/branches/upstream/current/src/utils/uuid.c Sat Jan 10 08:43:01 2009
@@ -15,6 +15,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto.h"
+#include "sha1.h"
 #include "uuid.h"
 
 int uuid_str2bin(const char *str, u8 *bin)
@@ -65,3 +67,41 @@
 		return -1;
 	return 0;
 }
+
+
+int is_nil_uuid(const u8 *uuid)
+{
+	int i;
+	for (i = 0; i < UUID_LEN; i++)
+		if (uuid[i])
+			return 0;
+	return 1;
+}
+
+
+void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
+{
+	const u8 *addr[2];
+	size_t len[2];
+	u8 hash[SHA1_MAC_LEN];
+	u8 nsid[16] = {
+		0x52, 0x64, 0x80, 0xf8,
+		0xc9, 0x9b,
+		0x4b, 0xe5,
+		0xa6, 0x55,
+		0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
+	};
+
+	addr[0] = nsid;
+	len[0] = sizeof(nsid);
+	addr[1] = mac_addr;
+	len[1] = 6;
+	sha1_vector(2, addr, len, hash);
+	os_memcpy(uuid, hash, 16);
+
+	/* Version: 5 = named-based version using SHA-1 */
+	uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
+
+	/* Variant specified in RFC 4122 */
+	uuid[8] = 0x80 | (uuid[8] & 0x3f);
+}

Modified: wpasupplicant/branches/upstream/current/src/utils/uuid.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/uuid.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/uuid.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/uuid.h Sat Jan 10 08:43:01 2009
@@ -19,5 +19,7 @@
 
 int uuid_str2bin(const char *str, u8 *bin);
 int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
+int is_nil_uuid(const u8 *uuid);
+void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
 
 #endif /* UUID_H */

Modified: wpasupplicant/branches/upstream/current/src/utils/wpa_debug.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/utils/wpa_debug.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/src/utils/wpa_debug.h (original)
+++ wpasupplicant/branches/upstream/current/src/utils/wpa_debug.h Sat Jan 10 08:43:01 2009
@@ -43,7 +43,7 @@
 /**
  * wpa_debug_printf_timestamp - Print timestamp for debug output
  *
- * This function prints a timestamp in <seconds from 1970>.<microsoconds>
+ * This function prints a timestamp in seconds_from_1970.microsoconds
  * format if debug output has been configured to include timestamps in debug
  * messages.
  */

Added: wpasupplicant/branches/upstream/current/src/wps/.gitignore
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/.gitignore?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/.gitignore (added)
+++ wpasupplicant/branches/upstream/current/src/wps/.gitignore Sat Jan 10 08:43:01 2009
@@ -1,0 +1,1 @@
+*.d

Added: wpasupplicant/branches/upstream/current/src/wps/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/Makefile?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/Makefile (added)
+++ wpasupplicant/branches/upstream/current/src/wps/Makefile Sat Jan 10 08:43:01 2009
@@ -1,0 +1,6 @@
+all:
+	@echo Nothing to be made.
+
+clean:
+	for d in $(SUBDIRS); do make -C $$d clean; done
+	rm -f *~ *.o *.d

Added: wpasupplicant/branches/upstream/current/src/wps/wps.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,318 @@
+/*
+ * Wi-Fi Protected Setup
+ * 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 "wps_i.h"
+#include "wps_dev_attr.h"
+#include "ieee802_11_defs.h"
+
+
+/**
+ * wps_init - Initialize WPS Registration protocol data
+ * @cfg: WPS configuration
+ * Returns: Pointer to allocated data or %NULL on failure
+ *
+ * This function is used to initialize WPS data for a registration protocol
+ * instance (i.e., each run of registration protocol as a Registrar of
+ * Enrollee. The caller is responsible for freeing this data after the
+ * registration run has been completed by calling wps_deinit().
+ */
+struct wps_data * wps_init(const struct wps_config *cfg)
+{
+	struct wps_data *data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->wps = cfg->wps;
+	data->registrar = cfg->registrar;
+	if (cfg->registrar) {
+		os_memcpy(data->uuid_r, cfg->wps->uuid, WPS_UUID_LEN);
+	} else {
+		os_memcpy(data->mac_addr_e, cfg->wps->dev.mac_addr, ETH_ALEN);
+		os_memcpy(data->uuid_e, cfg->wps->uuid, WPS_UUID_LEN);
+	}
+	if (cfg->pin) {
+		data->dev_pw_id = DEV_PW_DEFAULT;
+		data->dev_password = os_malloc(cfg->pin_len);
+		if (data->dev_password == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memcpy(data->dev_password, cfg->pin, cfg->pin_len);
+		data->dev_password_len = cfg->pin_len;
+	}
+
+	data->pbc = cfg->pbc;
+	if (cfg->pbc) {
+		/* Use special PIN '00000000' for PBC */
+		data->dev_pw_id = DEV_PW_PUSHBUTTON;
+		os_free(data->dev_password);
+		data->dev_password = os_malloc(8);
+		if (data->dev_password == NULL) {
+			os_free(data);
+			return NULL;
+		}
+		os_memset(data->dev_password, '0', 8);
+		data->dev_password_len = 8;
+	}
+
+	data->state = data->registrar ? RECV_M1 : SEND_M1;
+
+	if (cfg->assoc_wps_ie) {
+		struct wps_parse_attr attr;
+		wpa_hexdump_buf(MSG_DEBUG, "WPS: WPS IE from (Re)AssocReq",
+				cfg->assoc_wps_ie);
+		if (wps_parse_msg(cfg->assoc_wps_ie, &attr) < 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to parse WPS IE "
+				   "from (Re)AssocReq");
+		} else if (attr.request_type == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: No Request Type attribute "
+				   "in (Re)AssocReq WPS IE");
+		} else {
+			wpa_printf(MSG_DEBUG, "WPS: Request Type (from WPS IE "
+				   "in (Re)AssocReq WPS IE): %d",
+				   *attr.request_type);
+			data->request_type = *attr.request_type;
+		}
+	}
+
+	return data;
+}
+
+
+/**
+ * wps_deinit - Deinitialize WPS Registration protocol data
+ * @data: WPS Registration protocol data from wps_init()
+ */
+void wps_deinit(struct wps_data *data)
+{
+	if (data->wps_pin_revealed) {
+		wpa_printf(MSG_DEBUG, "WPS: Full PIN information revealed and "
+			   "negotiation failed");
+		if (data->registrar)
+			wps_registrar_invalidate_pin(data->wps->registrar,
+						     data->uuid_e);
+	} else if (data->registrar)
+		wps_registrar_unlock_pin(data->wps->registrar, data->uuid_e);
+
+	wpabuf_free(data->dh_privkey);
+	wpabuf_free(data->dh_pubkey_e);
+	wpabuf_free(data->dh_pubkey_r);
+	wpabuf_free(data->last_msg);
+	os_free(data->dev_password);
+	os_free(data->new_psk);
+	wps_device_data_free(&data->peer_dev);
+	os_free(data);
+}
+
+
+/**
+ * wps_process_msg - Process a WPS message
+ * @wps: WPS Registration protocol data from wps_init()
+ * @op_code: Message OP Code
+ * @msg: Message data
+ * Returns: Processing result
+ *
+ * This function is used to process WPS messages with OP Codes WSC_ACK,
+ * WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
+ * responsible for reassembling the messages before calling this function.
+ * Response to this message is built by calling wps_get_msg().
+ */
+enum wps_process_res wps_process_msg(struct wps_data *wps,
+				     enum wsc_op_code op_code,
+				     const struct wpabuf *msg)
+{
+	if (wps->registrar)
+		return wps_registrar_process_msg(wps, op_code, msg);
+	else
+		return wps_enrollee_process_msg(wps, op_code, msg);
+}
+
+
+/**
+ * wps_get_msg - Build a WPS message
+ * @wps: WPS Registration protocol data from wps_init()
+ * @op_code: Buffer for returning message OP Code
+ * Returns: The generated WPS message or %NULL on failure
+ *
+ * This function is used to build a response to a message processed by calling
+ * wps_process_msg(). The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
+{
+	if (wps->registrar)
+		return wps_registrar_get_msg(wps, op_code);
+	else
+		return wps_enrollee_get_msg(wps, op_code);
+}
+
+
+/**
+ * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PBC Registrar is active, 0 if not
+ */
+int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	/*
+	 * In theory, this could also verify that attr.sel_reg_config_methods
+	 * includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
+	 * do not set Selected Registrar Config Methods attribute properly, so
+	 * it is safer to just use Device Password ID here.
+	 */
+
+	if (wps_parse_msg(msg, &attr) < 0 ||
+	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
+	    !attr.dev_password_id ||
+	    WPA_GET_BE16(attr.dev_password_id) != DEV_PW_PUSHBUTTON)
+		return 0;
+
+	return 1;
+}
+
+
+/**
+ * wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PIN
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PIN Registrar is active, 0 if not
+ */
+int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	/*
+	 * In theory, this could also verify that attr.sel_reg_config_methods
+	 * includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
+	 * but some deployed AP implementations do not set Selected Registrar
+	 * Config Methods attribute properly, so it is safer to just use
+	 * Device Password ID here.
+	 */
+
+	if (wps_parse_msg(msg, &attr) < 0 ||
+	    !attr.selected_registrar || *attr.selected_registrar == 0 ||
+	    !attr.dev_password_id ||
+	    WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
+		return 0;
+
+	return 1;
+}
+
+
+/**
+ * wps_get_uuid_e - Get UUID-E from WPS IE
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: Pointer to UUID-E or %NULL if not included
+ *
+ * The returned pointer is to the msg contents and it remains valid only as
+ * long as the msg buffer is valid.
+ */
+const u8 * wps_get_uuid_e(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return NULL;
+	return attr.uuid_e;
+}
+
+
+/**
+ * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
+ * @req_type: Value for Request Type attribute
+ * Returns: WPS IE or %NULL on failure
+ *
+ * The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
+{
+	struct wpabuf *ie;
+	u8 *len;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
+		   "Request");
+	ie = wpabuf_alloc(100);
+	if (ie == NULL)
+		return NULL;
+
+	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+	len = wpabuf_put(ie, 1);
+	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+
+	if (wps_build_version(ie) ||
+	    wps_build_req_type(ie, req_type)) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+
+	*len = wpabuf_len(ie) - 2;
+
+	return ie;
+}
+
+
+/**
+ * wps_build_probe_req_ie - Build WPS IE for Probe Request
+ * @pbc: Whether searching for PBC mode APs
+ * @dev: Device attributes
+ * @uuid: Own UUID
+ * @req_type: Value for Request Type attribute
+ * Returns: WPS IE or %NULL on failure
+ *
+ * The caller is responsible for freeing the buffer.
+ */
+struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+				       const u8 *uuid,
+				       enum wps_request_type req_type)
+{
+	struct wpabuf *ie;
+	u8 *len;
+	u16 methods;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
+
+	ie = wpabuf_alloc(200);
+	if (ie == NULL)
+		return NULL;
+
+	wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+	len = wpabuf_put(ie, 1);
+	wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+
+	if (pbc)
+		methods = WPS_CONFIG_PUSHBUTTON;
+	else
+		methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY |
+			WPS_CONFIG_KEYPAD;
+
+	if (wps_build_version(ie) ||
+	    wps_build_req_type(ie, req_type) ||
+	    wps_build_config_methods(ie, methods) ||
+	    wps_build_uuid_e(ie, uuid) ||
+	    wps_build_primary_dev_type(dev, ie) ||
+	    wps_build_rf_bands(dev, ie) ||
+	    wps_build_assoc_state(NULL, ie) ||
+	    wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
+	    wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON :
+				      DEV_PW_DEFAULT)) {
+		wpabuf_free(ie);
+		return NULL;
+	}
+
+	*len = wpabuf_len(ie) - 2;
+
+	return ie;
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,385 @@
+/*
+ * Wi-Fi Protected Setup
+ * 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 WPS_H
+#define WPS_H
+
+#include "wps_defs.h"
+
+/**
+ * enum wsc_op_code - EAP-WSC OP-Code values
+ */
+enum wsc_op_code {
+	WSC_Start = 0x01,
+	WSC_ACK = 0x02,
+	WSC_NACK = 0x03,
+	WSC_MSG = 0x04,
+	WSC_Done = 0x05,
+	WSC_FRAG_ACK = 0x06
+};
+
+struct wps_registrar;
+
+/**
+ * struct wps_credential - WPS Credential
+ * @ssid: SSID
+ * @ssid_len: Length of SSID
+ * @auth_type: Authentication Type (WPS_AUTH_OPEN, .. flags)
+ * @encr_type: Encryption Type (WPS_ENCR_NONE, .. flags)
+ * @key_idx: Key index
+ * @key: Key
+ * @key_len: Key length in octets
+ * @mac_addr: MAC address of the peer
+ */
+struct wps_credential {
+	u8 ssid[32];
+	size_t ssid_len;
+	u16 auth_type;
+	u16 encr_type;
+	u8 key_idx;
+	u8 key[64];
+	size_t key_len;
+	u8 mac_addr[ETH_ALEN];
+};
+
+/**
+ * struct wps_device_data - WPS Device Data
+ * @mac_addr: Device MAC address
+ * @device_name: Device Name (0..32 octets encoded in UTF-8)
+ * @manufacturer: Manufacturer (0..64 octets encoded in UTF-8)
+ * @model_name: Model Name (0..32 octets encoded in UTF-8)
+ * @model_number: Model Number (0..32 octets encoded in UTF-8)
+ * @serial_number: Serial Number (0..32 octets encoded in UTF-8)
+ * @categ: Primary Device Category
+ * @oui: Primary Device OUI
+ * @sub_categ: Primary Device Sub-Category
+ * @os_version: OS Version
+ * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
+ */
+struct wps_device_data {
+	u8 mac_addr[ETH_ALEN];
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u16 categ;
+	u32 oui;
+	u16 sub_categ;
+	u32 os_version;
+	u8 rf_bands;
+};
+
+/**
+ * struct wps_config - WPS configuration for a single registration protocol run
+ */
+struct wps_config {
+	/**
+	 * wps - Pointer to long term WPS context
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * registrar - Whether this end is a Registrar
+	 */
+	int registrar;
+
+	/**
+	 * pin - Enrollee Device Password (%NULL for Registrar or PBC)
+	 */
+	const u8 *pin;
+
+	/**
+	 * pin_len - Length on pin in octets
+	 */
+	size_t pin_len;
+
+	/**
+	 * pbc - Whether this is protocol run uses PBC
+	 */
+	int pbc;
+
+	/**
+	 * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
+	 */
+	const struct wpabuf *assoc_wps_ie;
+};
+
+struct wps_data * wps_init(const struct wps_config *cfg);
+
+void wps_deinit(struct wps_data *data);
+
+/**
+ * enum wps_process_res - WPS message processing result
+ */
+enum wps_process_res {
+	/**
+	 * WPS_DONE - Processing done
+	 */
+	WPS_DONE,
+
+	/**
+	 * WPS_CONTINUE - Processing continues
+	 */
+	WPS_CONTINUE,
+
+	/**
+	 * WPS_FAILURE - Processing failed
+	 */
+	WPS_FAILURE
+};
+enum wps_process_res wps_process_msg(struct wps_data *wps,
+				     enum wsc_op_code op_code,
+				     const struct wpabuf *msg);
+
+struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
+
+int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
+int wps_is_selected_pin_registrar(const struct wpabuf *msg);
+const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+
+struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
+struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev,
+				       const u8 *uuid,
+				       enum wps_request_type req_type);
+
+
+/**
+ * struct wps_registrar_config - WPS Registrar configuration
+ */
+struct wps_registrar_config {
+	/**
+	 * new_psk_cb - Callback for new PSK
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @mac_addr: MAC address of the Enrollee
+	 * @psk: The new PSK
+	 * @psk_len: The length of psk in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called when a new per-device PSK is provisioned.
+	 */
+	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
+			  size_t psk_len);
+
+	/**
+	 * set_ie_cb - Callback for WPS IE changes
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @beacon_ie: WPS IE for Beacon
+	 * @beacon_ie_len: WPS IE length for Beacon
+	 * @probe_resp_ie: WPS IE for Probe Response
+	 * @probe_resp_ie_len: WPS IE length for Probe Response
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called whenever the WPS IE in Beacon or Probe
+	 * Response frames needs to be changed (AP only).
+	 */
+	int (*set_ie_cb)(void *ctx, const u8 *beacon_ie, size_t beacon_ie_len,
+			 const u8 *probe_resp_ie, size_t probe_resp_ie_len);
+
+	/**
+	 * pin_needed_cb - Callback for requesting a PIN
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @uuid_e: UUID-E of the unknown Enrollee
+	 * @dev: Device Data from the unknown Enrollee
+	 *
+	 * This callback is called whenever an unknown Enrollee requests to use
+	 * PIN method and a matching PIN (Device Password) is not found in
+	 * Registrar data.
+	 */
+	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
+			      const struct wps_device_data *dev);
+
+	/**
+	 * cb_ctx: Higher layer context data for Registrar callbacks
+	 */
+	void *cb_ctx;
+};
+
+
+/**
+ * enum wps_event - WPS event types
+ */
+enum wps_event {
+	/**
+	 * WPS_EV_M2D - M2D received (Registrar did not know us)
+	 */
+	WPS_EV_M2D,
+
+	/**
+	 * WPS_EV_FAIL - Registration failed
+	 */
+	WPS_EV_FAIL,
+
+	/**
+	 * WPS_EV_SUCCESS - Registration succeeded
+	 */
+	WPS_EV_SUCCESS
+};
+
+/**
+ * union wps_event_data - WPS event data
+ */
+union wps_event_data {
+	/**
+	 * struct wps_event_m2d - M2D event data
+	 */
+	struct wps_event_m2d {
+		u16 config_methods;
+		const u8 *manufacturer;
+		size_t manufacturer_len;
+		const u8 *model_name;
+		size_t model_name_len;
+		const u8 *model_number;
+		size_t model_number_len;
+		const u8 *serial_number;
+		size_t serial_number_len;
+		const u8 *dev_name;
+		size_t dev_name_len;
+		const u8 *primary_dev_type; /* 8 octets */
+		u16 config_error;
+		u16 dev_password_id;
+	} m2d;
+
+	/**
+	 * struct wps_event_fail - Registration failure information
+	 * @msg: enum wps_msg_type
+	 */
+	struct wps_event_fail {
+		int msg;
+	} fail;
+};
+
+/**
+ * struct wps_context - Long term WPS context data
+ *
+ * This data is stored at the higher layer Authenticator or Supplicant data
+ * structures and it is maintained over multiple registration protocol runs.
+ */
+struct wps_context {
+	/**
+	 * ap - Whether the local end is an access point
+	 */
+	int ap;
+
+	/**
+	 * registrar - Pointer to WPS registrar data from wps_registrar_init()
+	 */
+	struct wps_registrar *registrar;
+
+	/**
+	 * wps_state - Current WPS state
+	 */
+	enum wps_state wps_state;
+
+	/**
+	 * ap_setup_locked - Whether AP setup is locked (only used at AP)
+	 */
+	int ap_setup_locked;
+
+	/**
+	 * uuid - Own UUID
+	 */
+	u8 uuid[16];
+
+	/**
+	 * ssid - SSID
+	 *
+	 * This SSID is used by the Registrar to fill in information for
+	 * Credentials. In addition, AP uses it when acting as an Enrollee to
+	 * notify Registrar of the current configuration.
+	 */
+	u8 ssid[32];
+
+	/**
+	 * ssid_len - Length of ssid in octets
+	 */
+	size_t ssid_len;
+
+	/**
+	 * dev - Own WPS device data
+	 */
+	struct wps_device_data dev;
+
+	/**
+	 * config_methods - Enabled configuration methods
+	 *
+	 * Bit field of WPS_CONFIG_*
+	 */
+	u16 config_methods;
+
+	/**
+	 * encr_types - Enabled encryption types (bit field of WPS_ENCR_*)
+	 */
+	u16 encr_types;
+
+	/**
+	 * auth_types - Authentication types (bit field of WPS_AUTH_*)
+	 */
+	u16 auth_types;
+
+	/**
+	 * network_key - The current Network Key (PSK) or %NULL to generate new
+	 *
+	 * If %NULL, Registrar will generate per-device PSK. In addition, AP
+	 * uses this when acting as an Enrollee to notify Registrar of the
+	 * current configuration.
+	 */
+	u8 *network_key;
+
+	/**
+	 * network_key_len - Length of network_key in octets
+	 */
+	size_t network_key_len;
+
+	/**
+	 * cred_cb - Callback to notify that new Credentials were received
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @cred: The received Credential
+	 * Return: 0 on success, -1 on failure
+	 */
+	int (*cred_cb)(void *ctx, const struct wps_credential *cred);
+
+	/**
+	 * event_cb - Event callback (state information about progress)
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @event: Event type
+	 * @data: Event data
+	 */
+	void (*event_cb)(void *ctx, enum wps_event event,
+			 union wps_event_data *data);
+
+	/**
+	 * cb_ctx: Higher layer context data for callbacks
+	 */
+	void *cb_ctx;
+};
+
+
+struct wps_registrar *
+wps_registrar_init(struct wps_context *wps,
+		   const struct wps_registrar_config *cfg);
+void wps_registrar_deinit(struct wps_registrar *reg);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
+			  const u8 *pin, size_t pin_len);
+int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_button_pushed(struct wps_registrar *reg);
+void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
+				const struct wpabuf *wps_data);
+
+unsigned int wps_pin_checksum(unsigned int pin);
+unsigned int wps_pin_valid(unsigned int pin);
+unsigned int wps_generate_pin(void);
+
+#endif /* WPS_H */

Added: wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_attr_build.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,253 @@
+/*
+ * Wi-Fi Protected Setup - attribute building
+ * 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 "dh_groups.h"
+#include "sha256.h"
+#include "aes_wrap.h"
+#include "wps_i.h"
+
+
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
+{
+	struct wpabuf *pubkey;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Public Key");
+	pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey);
+	if (pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
+			   "Diffie-Hellman handshake");
+		return -1;
+	}
+
+	wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
+	wpabuf_put_be16(msg, wpabuf_len(pubkey));
+	wpabuf_put_buf(msg, pubkey);
+
+	if (wps->registrar) {
+		wpabuf_free(wps->dh_pubkey_r);
+		wps->dh_pubkey_r = pubkey;
+	} else {
+		wpabuf_free(wps->dh_pubkey_e);
+		wps->dh_pubkey_e = pubkey;
+	}
+
+	return 0;
+}
+
+
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Request Type");
+	wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, type);
+	return 0;
+}
+
+
+int wps_build_config_methods(struct wpabuf *msg, u16 methods)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
+	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * UUID-E");
+	wpabuf_put_be16(msg, ATTR_UUID_E);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
+	return 0;
+}
+
+
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, id);
+	return 0;
+}
+
+
+int wps_build_config_error(struct wpabuf *msg, u16 err)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Configuration Error (%d)", err);
+	wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, err);
+	return 0;
+}
+
+
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "building authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Authenticator");
+	wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
+	wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
+	wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
+
+	return 0;
+}
+
+
+int wps_build_version(struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Version");
+	wpabuf_put_be16(msg, ATTR_VERSION);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_VERSION);
+	return 0;
+}
+
+
+int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Message Type (%d)", msg_type);
+	wpabuf_put_be16(msg, ATTR_MSG_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, msg_type);
+	return 0;
+}
+
+
+int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Enrollee Nonce");
+	wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Registrar Nonce");
+	wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
+	wpabuf_put_be16(msg, WPS_NONCE_LEN);
+	wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
+	return 0;
+}
+
+
+int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type Flags");
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_AUTH_TYPES);
+	return 0;
+}
+
+
+int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type Flags");
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_ENCR_TYPES);
+	return 0;
+}
+
+
+int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Connection Type Flags");
+	wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_CONN_ESS);
+	return 0;
+}
+
+
+int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Association State");
+	wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
+	return 0;
+}
+
+
+int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Key Wrap Authenticator");
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+		    wpabuf_len(msg), hash);
+
+	wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
+	wpabuf_put_be16(msg, WPS_KWA_LEN);
+	wpabuf_put_data(msg, hash, WPS_KWA_LEN);
+	return 0;
+}
+
+
+int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
+			    struct wpabuf *plain)
+{
+	size_t pad_len;
+	const size_t block_size = 16;
+	u8 *iv, *data;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Encrypted Settings");
+
+	/* PKCS#5 v2.0 pad */
+	pad_len = block_size - wpabuf_len(plain) % block_size;
+	os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
+
+	wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
+	wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
+
+	iv = wpabuf_put(msg, block_size);
+	if (os_get_random(iv, block_size) < 0)
+		return -1;
+
+	data = wpabuf_put(msg, 0);
+	wpabuf_put_buf(msg, plain);
+	if (aes_128_cbc_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
+		return -1;
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_attr_parse.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_attr_parse.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_attr_parse.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_attr_parse.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,429 @@
+/*
+ * Wi-Fi Protected Setup - attribute parsing
+ * 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 "wps_i.h"
+
+
+static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
+			const u8 *pos, u16 len)
+{
+	switch (type) {
+	case ATTR_VERSION:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
+				   len);
+			return -1;
+		}
+		attr->version = pos;
+		break;
+	case ATTR_MSG_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->msg_type = pos;
+		break;
+	case ATTR_ENROLLEE_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->enrollee_nonce = pos;
+		break;
+	case ATTR_REGISTRAR_NONCE:
+		if (len != WPS_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
+				   "length %u", len);
+			return -1;
+		}
+		attr->registrar_nonce = pos;
+		break;
+	case ATTR_UUID_E:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_e = pos;
+		break;
+	case ATTR_UUID_R:
+		if (len != WPS_UUID_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
+				   len);
+			return -1;
+		}
+		attr->uuid_r = pos;
+		break;
+	case ATTR_AUTH_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type Flags length %u", len);
+			return -1;
+		}
+		attr->auth_type_flags = pos;
+		break;
+	case ATTR_ENCR_TYPE_FLAGS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->encr_type_flags = pos;
+		break;
+	case ATTR_CONN_TYPE_FLAGS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
+				   "Flags length %u", len);
+			return -1;
+		}
+		attr->conn_type_flags = pos;
+		break;
+	case ATTR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
+				   "length %u", len);
+			return -1;
+		}
+		attr->config_methods = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
+				   "Registrar Config Methods length %u", len);
+			return -1;
+		}
+		attr->sel_reg_config_methods = pos;
+		break;
+	case ATTR_PRIMARY_DEV_TYPE:
+		if (len != sizeof(struct wps_dev_type)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->primary_dev_type = pos;
+		break;
+	case ATTR_RF_BANDS:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
+				   "%u", len);
+			return -1;
+		}
+		attr->rf_bands = pos;
+		break;
+	case ATTR_ASSOC_STATE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
+				   "length %u", len);
+			return -1;
+		}
+		attr->assoc_state = pos;
+		break;
+	case ATTR_CONFIG_ERROR:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
+				   "Error length %u", len);
+			return -1;
+		}
+		attr->config_error = pos;
+		break;
+	case ATTR_DEV_PASSWORD_ID:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
+				   "ID length %u", len);
+			return -1;
+		}
+		attr->dev_password_id = pos;
+		break;
+	case ATTR_OS_VERSION:
+		if (len != 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
+				   "%u", len);
+			return -1;
+		}
+		attr->os_version = pos;
+		break;
+	case ATTR_WPS_STATE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
+				   "Setup State length %u", len);
+			return -1;
+		}
+		attr->wps_state = pos;
+		break;
+	case ATTR_AUTHENTICATOR:
+		if (len != WPS_AUTHENTICATOR_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
+				   "length %u", len);
+			return -1;
+		}
+		attr->authenticator = pos;
+		break;
+	case ATTR_R_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash1 = pos;
+		break;
+	case ATTR_R_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->r_hash2 = pos;
+		break;
+	case ATTR_E_HASH1:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash1 = pos;
+		break;
+	case ATTR_E_HASH2:
+		if (len != WPS_HASH_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
+				   len);
+			return -1;
+		}
+		attr->e_hash2 = pos;
+		break;
+	case ATTR_R_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce1 = pos;
+		break;
+	case ATTR_R_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->r_snonce2 = pos;
+		break;
+	case ATTR_E_SNONCE1:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce1 = pos;
+		break;
+	case ATTR_E_SNONCE2:
+		if (len != WPS_SECRET_NONCE_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
+				   "%u", len);
+			return -1;
+		}
+		attr->e_snonce2 = pos;
+		break;
+	case ATTR_KEY_WRAP_AUTH:
+		if (len != WPS_KWA_LEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
+				   "Authenticator length %u", len);
+			return -1;
+		}
+		attr->key_wrap_auth = pos;
+		break;
+	case ATTR_AUTH_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->auth_type = pos;
+		break;
+	case ATTR_ENCR_TYPE:
+		if (len != 2) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
+				   "Type length %u", len);
+			return -1;
+		}
+		attr->encr_type = pos;
+		break;
+	case ATTR_NETWORK_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_idx = pos;
+		break;
+	case ATTR_NETWORK_KEY_INDEX:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
+				   "length %u", len);
+			return -1;
+		}
+		attr->network_key_idx = pos;
+		break;
+	case ATTR_MAC_ADDR:
+		if (len != ETH_ALEN) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
+				   "length %u", len);
+			return -1;
+		}
+		attr->mac_addr = pos;
+		break;
+	case ATTR_KEY_PROVIDED_AUTO:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
+				   "Automatically length %u", len);
+			return -1;
+		}
+		attr->key_prov_auto = pos;
+		break;
+	case ATTR_802_1X_ENABLED:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
+				   "length %u", len);
+			return -1;
+		}
+		attr->dot1x_enabled = pos;
+		break;
+	case ATTR_SELECTED_REGISTRAR:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
+				   " length %u", len);
+			return -1;
+		}
+		attr->selected_registrar = pos;
+		break;
+	case ATTR_REQUEST_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_type = pos;
+		break;
+	case ATTR_RESPONSE_TYPE:
+		if (len != 1) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
+				   "length %u", len);
+			return -1;
+		}
+		attr->request_type = pos;
+		break;
+	case ATTR_MANUFACTURER:
+		attr->manufacturer = pos;
+		attr->manufacturer_len = len;
+		break;
+	case ATTR_MODEL_NAME:
+		attr->model_name = pos;
+		attr->model_name_len = len;
+		break;
+	case ATTR_MODEL_NUMBER:
+		attr->model_number = pos;
+		attr->model_number_len = len;
+		break;
+	case ATTR_SERIAL_NUMBER:
+		attr->serial_number = pos;
+		attr->serial_number_len = len;
+		break;
+	case ATTR_DEV_NAME:
+		attr->dev_name = pos;
+		attr->dev_name_len = len;
+		break;
+	case ATTR_PUBLIC_KEY:
+		attr->public_key = pos;
+		attr->public_key_len = len;
+		break;
+	case ATTR_ENCR_SETTINGS:
+		attr->encr_settings = pos;
+		attr->encr_settings_len = len;
+		break;
+	case ATTR_CRED:
+		if (attr->num_cred >= MAX_CRED_COUNT) {
+			wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
+				   "attribute (max %d credentials)",
+				   MAX_CRED_COUNT);
+			break;
+		}
+		attr->cred[attr->num_cred] = pos;
+		attr->cred_len[attr->num_cred] = len;
+		attr->num_cred++;
+		break;
+	case ATTR_SSID:
+		attr->ssid = pos;
+		attr->ssid_len = len;
+		break;
+	case ATTR_NETWORK_KEY:
+		attr->network_key = pos;
+		attr->network_key_len = len;
+		break;
+	case ATTR_EAP_TYPE:
+		attr->eap_type = pos;
+		attr->eap_type_len = len;
+		break;
+	case ATTR_EAP_IDENTITY:
+		attr->eap_identity = pos;
+		attr->eap_identity_len = len;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
+			   "len=%u", type, len);
+		break;
+	}
+
+	return 0;
+}
+
+
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
+{
+	const u8 *pos, *end;
+	u16 type, len;
+
+	os_memset(attr, 0, sizeof(*attr));
+	pos = wpabuf_head(msg);
+	end = pos + wpabuf_len(msg);
+
+	while (pos < end) {
+		if (end - pos < 4) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
+				   "%lu bytes remaining",
+				   (unsigned long) (end - pos));
+			return -1;
+		}
+
+		type = WPA_GET_BE16(pos);
+		pos += 2;
+		len = WPA_GET_BE16(pos);
+		pos += 2;
+		wpa_printf(MSG_MSGDUMP, "WPS: attr type=0x%x len=%u",
+			   type, len);
+		if (len > end - pos) {
+			wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
+			return -1;
+		}
+
+		if (wps_set_attr(attr, type, pos, len) < 0)
+			return -1;
+
+		pos += len;
+	}
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_attr_process.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,302 @@
+/*
+ * Wi-Fi Protected Setup - attribute processing
+ * 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 "sha256.h"
+#include "wps_i.h"
+
+
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+
+	if (authenticator == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
+			   "included");
+		return -1;
+	}
+
+	if (wps->last_msg == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
+			   "validating authenticator");
+		return -1;
+	}
+
+	/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
+	 * (M_curr* is M_curr without the Authenticator attribute)
+	 */
+	addr[0] = wpabuf_head(wps->last_msg);
+	len[0] = wpabuf_len(wps->last_msg);
+	addr[1] = wpabuf_head(msg);
+	len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+	if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *head;
+	size_t len;
+
+	if (key_wrap_auth == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
+		return -1;
+	}
+
+	head = wpabuf_head(msg);
+	len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
+	if (head + len != key_wrap_auth - 4) {
+		wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
+			   "decrypted attribute");
+		return -1;
+	}
+
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
+	if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_idx(struct wps_credential *cred,
+					const u8 *idx)
+{
+	if (idx == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Index");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
+
+	return 0;
+}
+
+
+static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
+				 size_t ssid_len)
+{
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
+		return -1;
+	}
+
+	/* Remove zero-padding since some Registrar implementations seem to use
+	 * hardcoded 32-octet length for this attribute */
+	while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
+		ssid_len--;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
+	if (ssid_len <= sizeof(cred->ssid)) {
+		os_memcpy(cred->ssid, ssid, ssid_len);
+		cred->ssid_len = ssid_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_auth_type(struct wps_credential *cred,
+				      const u8 *auth_type)
+{
+	if (auth_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Authentication Type");
+		return -1;
+	}
+
+	cred->auth_type = WPA_GET_BE16(auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
+		   cred->auth_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_encr_type(struct wps_credential *cred,
+				      const u8 *encr_type)
+{
+	if (encr_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Encryption Type");
+		return -1;
+	}
+
+	cred->encr_type = WPA_GET_BE16(encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
+		   cred->encr_type);
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key_idx(struct wps_credential *cred,
+					    const u8 *key_idx)
+{
+	if (key_idx == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
+	cred->key_idx = *key_idx;
+
+	return 0;
+}
+
+
+static int wps_process_cred_network_key(struct wps_credential *cred,
+					const u8 *key, size_t key_len)
+{
+	if (key == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "Network Key");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
+	if (key_len <= sizeof(cred->key)) {
+		os_memcpy(cred->key, key, key_len);
+		cred->key_len = key_len;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_cred_mac_addr(struct wps_credential *cred,
+				     const u8 *mac_addr)
+{
+	if (mac_addr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
+			   "MAC Address");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
+	os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_type(struct wps_credential *cred,
+				     const u8 *eap_type, size_t eap_type_len)
+{
+	if (eap_type == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_eap_identity(struct wps_credential *cred,
+					 const u8 *identity,
+					 size_t identity_len)
+{
+	if (identity == NULL)
+		return 0; /* optional attribute */
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
+			  identity, identity_len);
+
+	return 0;
+}
+
+
+static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
+					  const u8 *key_prov_auto)
+{
+	if (key_prov_auto == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
+		   *key_prov_auto);
+
+	return 0;
+}
+
+
+static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
+					   const u8 *dot1x_enabled)
+{
+	if (dot1x_enabled == NULL)
+		return 0; /* optional attribute */
+
+	wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
+
+	return 0;
+}
+
+
+int wps_process_cred(struct wps_parse_attr *attr,
+		     struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Process Credential");
+
+	/* TODO: support multiple Network Keys */
+	if (wps_process_cred_network_idx(cred, attr->network_idx) ||
+	    wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr) ||
+	    wps_process_cred_eap_type(cred, attr->eap_type,
+				      attr->eap_type_len) ||
+	    wps_process_cred_eap_identity(cred, attr->eap_identity,
+					  attr->eap_identity_len) ||
+	    wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
+	    wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled))
+		return -1;
+
+	return 0;
+}
+
+
+int wps_process_ap_settings(struct wps_parse_attr *attr,
+			    struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
+	os_memset(cred, 0, sizeof(*cred));
+	/* TODO: optional attributes New Password and Device Password ID */
+	if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
+	    wps_process_cred_auth_type(cred, attr->auth_type) ||
+	    wps_process_cred_encr_type(cred, attr->encr_type) ||
+	    wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
+	    wps_process_cred_network_key(cred, attr->network_key,
+					 attr->network_key_len) ||
+	    wps_process_cred_mac_addr(cred, attr->mac_addr))
+		return -1;
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_common.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_common.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_common.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_common.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,322 @@
+/*
+ * Wi-Fi Protected Setup - common functionality
+ * 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 "dh_groups.h"
+#include "sha256.h"
+#include "aes_wrap.h"
+#include "crypto.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
+	     const char *label, u8 *res, size_t res_len)
+{
+	u8 i_buf[4], key_bits[4];
+	const u8 *addr[4];
+	size_t len[4];
+	int i, iter;
+	u8 hash[SHA256_MAC_LEN], *opos;
+	size_t left;
+
+	WPA_PUT_BE32(key_bits, res_len * 8);
+
+	addr[0] = i_buf;
+	len[0] = sizeof(i_buf);
+	addr[1] = label_prefix;
+	len[1] = label_prefix_len;
+	addr[2] = (const u8 *) label;
+	len[2] = os_strlen(label);
+	addr[3] = key_bits;
+	len[3] = sizeof(key_bits);
+
+	iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
+	opos = res;
+	left = res_len;
+
+	for (i = 1; i <= iter; i++) {
+		WPA_PUT_BE32(i_buf, i);
+		hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash);
+		if (i < iter) {
+			os_memcpy(opos, hash, SHA256_MAC_LEN);
+			opos += SHA256_MAC_LEN;
+			left -= SHA256_MAC_LEN;
+		} else
+			os_memcpy(opos, hash, left);
+	}
+}
+
+
+int wps_derive_keys(struct wps_data *wps)
+{
+	struct wpabuf *pubkey, *dh_shared;
+	u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
+	const u8 *addr[3];
+	size_t len[3];
+	u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
+
+	if (wps->dh_privkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
+		return -1;
+	}
+
+	pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
+	if (pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
+		return -1;
+	}
+
+	dh_shared = dh_derive_shared(pubkey, wps->dh_privkey,
+				     dh_groups_get(WPS_DH_GROUP));
+	if (dh_shared == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
+		return -1;
+	}
+
+	/* Own DH private key is not needed anymore */
+	wpabuf_free(wps->dh_privkey);
+	wps->dh_privkey = NULL;
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
+
+	/* DHKey = SHA-256(g^AB mod p) */
+	addr[0] = wpabuf_head(dh_shared);
+	len[0] = wpabuf_len(dh_shared);
+	sha256_vector(1, addr, len, dhkey);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
+	wpabuf_free(dh_shared);
+
+	/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
+	addr[0] = wps->nonce_e;
+	len[0] = WPS_NONCE_LEN;
+	addr[1] = wps->mac_addr_e;
+	len[1] = ETH_ALEN;
+	addr[2] = wps->nonce_r;
+	len[2] = WPS_NONCE_LEN;
+	hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
+
+	wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
+		keys, sizeof(keys));
+	os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
+	os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
+	os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
+		  WPS_EMSK_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
+			wps->authkey, WPS_AUTHKEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
+			wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
+
+	return 0;
+}
+
+
+int wps_derive_mgmt_keys(struct wps_data *wps)
+{
+	u8 nonces[2 * WPS_NONCE_LEN];
+	u8 keys[WPS_MGMTAUTHKEY_LEN + WPS_MGMTENCKEY_LEN];
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[2];
+	size_t len[2];
+	const char *auth_label = "WFA-WLAN-Management-MgmtAuthKey";
+	const char *enc_label = "WFA-WLAN-Management-MgmtEncKey";
+
+	/* MgmtAuthKey || MgmtEncKey =
+	 * kdf(EMSK, N1 || N2 || "WFA-WLAN-Management-Keys", 384) */
+	os_memcpy(nonces, wps->nonce_e, WPS_NONCE_LEN);
+	os_memcpy(nonces + WPS_NONCE_LEN, wps->nonce_r, WPS_NONCE_LEN);
+	wps_kdf(wps->emsk, nonces, sizeof(nonces), "WFA-WLAN-Management-Keys",
+		keys, sizeof(keys));
+	os_memcpy(wps->mgmt_auth_key, keys, WPS_MGMTAUTHKEY_LEN);
+	os_memcpy(wps->mgmt_enc_key, keys + WPS_MGMTAUTHKEY_LEN,
+		  WPS_MGMTENCKEY_LEN);
+
+	addr[0] = nonces;
+	len[0] = sizeof(nonces);
+
+	/* MgmtEncKeyID = first 128 bits of
+	 * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtAuthKey") */
+	addr[1] = (const u8 *) auth_label;
+	len[1] = os_strlen(auth_label);
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(wps->mgmt_auth_key_id, hash, WPS_MGMT_KEY_ID_LEN);
+
+	/* MgmtEncKeyID = first 128 bits of
+	 * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtEncKey") */
+	addr[1] = (const u8 *) enc_label;
+	len[1] = os_strlen(enc_label);
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(wps->mgmt_enc_key_id, hash, WPS_MGMT_KEY_ID_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtAuthKey",
+			wps->mgmt_auth_key, WPS_MGMTAUTHKEY_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: MgmtAuthKeyID",
+		    wps->mgmt_auth_key_id, WPS_MGMT_KEY_ID_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtEncKey",
+			wps->mgmt_enc_key, WPS_MGMTENCKEY_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: MgmtEncKeyID",
+		    wps->mgmt_enc_key_id, WPS_MGMT_KEY_ID_LEN);
+
+	return 0;
+}
+
+
+void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+		    size_t dev_passwd_len)
+{
+	u8 hash[SHA256_MAC_LEN];
+
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
+		    (dev_passwd_len + 1) / 2, hash);
+	os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
+	hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
+		    dev_passwd + (dev_passwd_len + 1) / 2,
+		    dev_passwd_len / 2, hash);
+	os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
+			      dev_passwd, dev_passwd_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
+}
+
+
+struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
+					  size_t encr_len)
+{
+	struct wpabuf *decrypted;
+	const size_t block_size = 16;
+	size_t i;
+	u8 pad;
+	const u8 *pos;
+
+	/* AES-128-CBC */
+	if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
+	{
+		wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
+		return NULL;
+	}
+
+	decrypted = wpabuf_alloc(encr_len - block_size);
+	if (decrypted == NULL)
+		return NULL;
+
+	wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
+	wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
+	if (aes_128_cbc_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
+				wpabuf_len(decrypted))) {
+		wpabuf_free(decrypted);
+		return NULL;
+	}
+
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
+			    decrypted);
+
+	pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
+	pad = *pos;
+	if (pad > wpabuf_len(decrypted)) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
+		wpabuf_free(decrypted);
+		return NULL;
+	}
+	for (i = 0; i < pad; i++) {
+		if (*pos-- != pad) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
+				   "string");
+			wpabuf_free(decrypted);
+			return NULL;
+		}
+	}
+	decrypted->used -= pad;
+
+	return decrypted;
+}
+
+
+/**
+ * wps_pin_checksum - Compute PIN checksum
+ * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
+ * Returns: Checksum digit
+ */
+unsigned int wps_pin_checksum(unsigned int pin)
+{
+	unsigned int accum = 0;
+	while (pin) {
+		accum += 3 * (pin % 10);
+		pin /= 10;
+		accum += pin % 10;
+		pin /= 10;
+	}
+
+	return (10 - accum % 10) % 10;
+}
+
+
+/**
+ * wps_pin_valid - Check whether a PIN has a valid checksum
+ * @pin: Eight digit PIN (i.e., including the checksum digit)
+ * Returns: 1 if checksum digit is valid, or 0 if not
+ */
+unsigned int wps_pin_valid(unsigned int pin)
+{
+	return wps_pin_checksum(pin / 10) == (pin % 10);
+}
+
+
+/**
+ * wps_generate_pin - Generate a random PIN
+ * Returns: Eight digit PIN (i.e., including the checksum digit)
+ */
+unsigned int wps_generate_pin(void)
+{
+	unsigned int val;
+
+	/* Generate seven random digits for the PIN */
+	if (os_get_random((unsigned char *) &val, sizeof(val)) < 0) {
+		struct os_time now;
+		os_get_time(&now);
+		val = os_random() ^ now.sec ^ now.usec;
+	}
+	val %= 10000000;
+
+	/* Append checksum digit */
+	return val * 10 + wps_pin_checksum(val);
+}
+
+
+void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg)
+{
+	union wps_event_data data;
+
+	if (wps->event_cb == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.fail.msg = msg;
+	wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, &data);
+}
+
+
+void wps_success_event(struct wps_context *wps)
+{
+	if (wps->event_cb == NULL)
+		return;
+
+	wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_defs.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_defs.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_defs.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_defs.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,297 @@
+/*
+ * Wi-Fi Protected Setup - message definitions
+ * 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 WPS_DEFS_H
+#define WPS_DEFS_H
+
+#define WPS_VERSION 0x10
+
+/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
+#define WPS_DH_GROUP 5
+
+#define WPS_UUID_LEN 16
+#define WPS_NONCE_LEN 16
+#define WPS_AUTHENTICATOR_LEN 8
+#define WPS_AUTHKEY_LEN 32
+#define WPS_KEYWRAPKEY_LEN 16
+#define WPS_EMSK_LEN 32
+#define WPS_PSK_LEN 16
+#define WPS_SECRET_NONCE_LEN 16
+#define WPS_HASH_LEN 32
+#define WPS_KWA_LEN 8
+#define WPS_MGMTAUTHKEY_LEN 32
+#define WPS_MGMTENCKEY_LEN 16
+#define WPS_MGMT_KEY_ID_LEN 16
+
+/* Attribute Types */
+enum wps_attribute {
+	ATTR_AP_CHANNEL = 0x1001,
+	ATTR_ASSOC_STATE = 0x1002,
+	ATTR_AUTH_TYPE = 0x1003,
+	ATTR_AUTH_TYPE_FLAGS = 0x1004,
+	ATTR_AUTHENTICATOR = 0x1005,
+	ATTR_CONFIG_METHODS = 0x1008,
+	ATTR_CONFIG_ERROR = 0x1009,
+	ATTR_CONFIRM_URL4 = 0x100a,
+	ATTR_CONFIRM_URL6 = 0x100b,
+	ATTR_CONN_TYPE = 0x100c,
+	ATTR_CONN_TYPE_FLAGS = 0x100d,
+	ATTR_CRED = 0x100e,
+	ATTR_ENCR_TYPE = 0x100f,
+	ATTR_ENCR_TYPE_FLAGS = 0x1010,
+	ATTR_DEV_NAME = 0x1011,
+	ATTR_DEV_PASSWORD_ID = 0x1012,
+	ATTR_E_HASH1 = 0x1014,
+	ATTR_E_HASH2 = 0x1015,
+	ATTR_E_SNONCE1 = 0x1016,
+	ATTR_E_SNONCE2 = 0x1017,
+	ATTR_ENCR_SETTINGS = 0x1018,
+	ATTR_ENROLLEE_NONCE = 0x101a,
+	ATTR_FEATURE_ID = 0x101b,
+	ATTR_IDENTITY = 0x101c,
+	ATTR_IDENTITY_PROOF = 0x101d,
+	ATTR_KEY_WRAP_AUTH = 0x101e,
+	ATTR_KEY_ID = 0x101f,
+	ATTR_MAC_ADDR = 0x1020,
+	ATTR_MANUFACTURER = 0x1021,
+	ATTR_MSG_TYPE = 0x1022,
+	ATTR_MODEL_NAME = 0x1023,
+	ATTR_MODEL_NUMBER = 0x1024,
+	ATTR_NETWORK_INDEX = 0x1026,
+	ATTR_NETWORK_KEY = 0x1027,
+	ATTR_NETWORK_KEY_INDEX = 0x1028,
+	ATTR_NEW_DEVICE_NAME = 0x1029,
+	ATTR_NEW_PASSWORD = 0x102a,
+	ATTR_OOB_DEVICE_PASSWORD = 0x102c,
+	ATTR_OS_VERSION = 0x102d,
+	ATTR_POWER_LEVEL = 0x102f,
+	ATTR_PSK_CURRENT = 0x1030,
+	ATTR_PSK_MAX = 0x1031,
+	ATTR_PUBLIC_KEY = 0x1032,
+	ATTR_RADIO_ENABLE = 0x1033,
+	ATTR_REBOOT = 0x1034,
+	ATTR_REGISTRAR_CURRENT = 0x1035,
+	ATTR_REGISTRAR_ESTABLISHED = 0x1036,
+	ATTR_REGISTRAR_LIST = 0x1037,
+	ATTR_REGISTRAR_MAX = 0x1038,
+	ATTR_REGISTRAR_NONCE = 0x1039,
+	ATTR_REQUEST_TYPE = 0x103a,
+	ATTR_RESPONSE_TYPE = 0x103b,
+	ATTR_RF_BANDS = 0x103c,
+	ATTR_R_HASH1 = 0x103d,
+	ATTR_R_HASH2 = 0x103e,
+	ATTR_R_SNONCE1 = 0x103f,
+	ATTR_R_SNONCE2 = 0x1040,
+	ATTR_SELECTED_REGISTRAR = 0x1041,
+	ATTR_SERIAL_NUMBER = 0x1042,
+	ATTR_WPS_STATE = 0x1044,
+	ATTR_SSID = 0x1045,
+	ATTR_TOTAL_NETWORKS = 0x1046,
+	ATTR_UUID_E = 0x1047,
+	ATTR_UUID_R = 0x1048,
+	ATTR_VENDOR_EXT = 0x1049,
+	ATTR_VERSION = 0x104a,
+	ATTR_X509_CERT_REQ = 0x104b,
+	ATTR_X509_CERT = 0x104c,
+	ATTR_EAP_IDENTITY = 0x104d,
+	ATTR_MSG_COUNTER = 0x104e,
+	ATTR_PUBKEY_HASH = 0x104f,
+	ATTR_REKEY_KEY = 0x1050,
+	ATTR_KEY_LIFETIME = 0x1051,
+	ATTR_PERMITTED_CFG_METHODS = 0x1052,
+	ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,
+	ATTR_PRIMARY_DEV_TYPE = 0x1054,
+	ATTR_SECONDARY_DEV_TYP_ELIST = 0x1055,
+	ATTR_PORTABLE_DEV = 0x1056,
+	ATTR_AP_SETUP_LOCKED = 0x1057,
+	ATTR_APPLICATION_EXT = 0x1058,
+	ATTR_EAP_TYPE = 0x1059,
+	ATTR_IV = 0x1060,
+	ATTR_KEY_PROVIDED_AUTO = 0x1061,
+	ATTR_802_1X_ENABLED = 0x1062,
+	ATTR_APPSESSIONKEY = 0x1063,
+	ATTR_WEPTRANSMITKEY = 0x1064
+};
+
+/* Device Password ID */
+enum wps_dev_password_id {
+	DEV_PW_DEFAULT = 0x0000,
+	DEV_PW_USER_SPECIFIED = 0x0001,
+	DEV_PW_MACHINE_SPECIFIED = 0x0002,
+	DEV_PW_REKEY = 0x0003,
+	DEV_PW_PUSHBUTTON = 0x0004,
+	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+};
+
+/* Message Type */
+enum wps_msg_type {
+	WPS_Beacon = 0x01,
+	WPS_ProbeRequest = 0x02,
+	WPS_ProbeResponse = 0x03,
+	WPS_M1 = 0x04,
+	WPS_M2 = 0x05,
+	WPS_M2D = 0x06,
+	WPS_M3 = 0x07,
+	WPS_M4 = 0x08,
+	WPS_M5 = 0x09,
+	WPS_M6 = 0x0a,
+	WPS_M7 = 0x0b,
+	WPS_M8 = 0x0c,
+	WPS_WSC_ACK = 0x0d,
+	WPS_WSC_NACK = 0x0e,
+	WPS_WSC_DONE = 0x0f
+};
+
+/* Authentication Type Flags */
+#define WPS_AUTH_OPEN 0x0001
+#define WPS_AUTH_WPAPSK 0x0002
+#define WPS_AUTH_SHARED 0x0004
+#define WPS_AUTH_WPA 0x0008
+#define WPS_AUTH_WPA2 0x0010
+#define WPS_AUTH_WPA2PSK 0x0020
+#define WPS_AUTH_TYPES (WPS_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \
+			WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)
+
+/* Encryption Type Flags */
+#define WPS_ENCR_NONE 0x0001
+#define WPS_ENCR_WEP 0x0002
+#define WPS_ENCR_TKIP 0x0004
+#define WPS_ENCR_AES 0x0008
+#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
+			WPS_ENCR_AES)
+
+/* Configuration Error */
+enum wps_config_error {
+	WPS_CFG_NO_ERROR = 0,
+	WPS_CFG_OOB_IFACE_READ_ERROR = 1,
+	WPS_CFG_DECRYPTION_CRC_FAILURE = 2,
+	WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,
+	WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,
+	WPS_CFG_SIGNAL_TOO_WEAK = 5,
+	WPS_CFG_NETWORK_AUTH_FAILURE = 6,
+	WPS_CFG_NETWORK_ASSOC_FAILURE = 7,
+	WPS_CFG_NO_DHCP_RESPONSE = 8,
+	WPS_CFG_FAILED_DHCP_CONFIG = 9,
+	WPS_CFG_IP_ADDR_CONFLICT = 10,
+	WPS_CFG_NO_CONN_TO_REGISTRAR = 11,
+	WPS_CFG_MULTIPLE_PBC_DETECTED = 12,
+	WPS_CFG_ROGUE_SUSPECTED = 13,
+	WPS_CFG_DEVICE_BUSY = 14,
+	WPS_CFG_SETUP_LOCKED = 15,
+	WPS_CFG_MSG_TIMEOUT = 16,
+	WPS_CFG_REG_SESS_TIMEOUT = 17,
+	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
+};
+
+/* RF Bands */
+#define WPS_RF_24GHZ 0x01
+#define WPS_RF_50GHZ 0x02
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+
+/* Connection Type Flags */
+#define WPS_CONN_ESS 0x01
+#define WPS_CONN_IBSS 0x02
+
+/* Wi-Fi Protected Setup State */
+enum wps_state {
+	WPS_STATE_NOT_CONFIGURED = 1,
+	WPS_STATE_CONFIGURED = 2
+};
+
+/* Association State */
+enum wps_assoc_state {
+	WPS_ASSOC_NOT_ASSOC = 0,
+	WPS_ASSOC_CONN_SUCCESS = 1,
+	WPS_ASSOC_CFG_FAILURE = 2,
+	WPS_ASSOC_FAILURE = 3,
+	WPS_ASSOC_IP_FAILURE = 4
+};
+
+
+/* Primary Device Type */
+struct wps_dev_type {
+	u8 categ_id[2];
+	u8 oui[4];
+	u8 sub_categ_id[2];
+};
+
+#define WPS_DEV_OUI_WFA 0x0050f204
+
+enum wps_dev_categ {
+	WPS_DEV_COMPUTER = 1,
+	WPS_DEV_INPUT = 2,
+	WPS_DEV_PRINTER = 3,
+	WPS_DEV_CAMERA = 4,
+	WPS_DEV_STORAGE = 5,
+	WPS_DEV_NETWORK_INFRA = 6,
+	WPS_DEV_DISPLAY = 7,
+	WPS_DEV_MULTIMEDIA = 8,
+	WPS_DEV_GAMING = 9,
+	WPS_DEV_PHONE = 10
+};
+
+enum wps_dev_subcateg {
+	WPS_DEV_COMPUTER_PC = 1,
+	WPS_DEV_COMPUTER_SERVER = 2,
+	WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+	WPS_DEV_PRINTER_PRINTER = 1,
+	WPS_DEV_PRINTER_SCANNER = 2,
+	WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+	WPS_DEV_STORAGE_NAS = 1,
+	WPS_DEV_NETWORK_INFRA_AP = 1,
+	WPS_DEV_NETWORK_INFRA_ROUTER = 2,
+	WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+	WPS_DEV_DISPLAY_TV = 1,
+	WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
+	WPS_DEV_DISPLAY_PROJECTOR = 3,
+	WPS_DEV_MULTIMEDIA_DAR = 1,
+	WPS_DEV_MULTIMEDIA_PVR = 2,
+	WPS_DEV_MULTIMEDIA_MCX = 3,
+	WPS_DEV_GAMING_XBOX = 1,
+	WPS_DEV_GAMING_XBOX360 = 2,
+	WPS_DEV_GAMING_PLAYSTATION = 3,
+	WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+};
+
+
+/* Request Type */
+enum wps_request_type {
+	WPS_REQ_ENROLLEE_INFO = 0,
+	WPS_REQ_ENROLLEE = 1,
+	WPS_REQ_REGISTRAR = 2,
+	WPS_REQ_WLAN_MANAGER_REGISTRAR = 3
+};
+
+/* Response Type */
+enum wps_response_type {
+	WPS_RESP_ENROLLEE_INFO = 0,
+	WPS_RESP_ENROLLEE = 1,
+	WPS_RESP_REGISTRAR = 2,
+	WPS_RESP_AP = 3
+};
+
+/* Walk Time for push button configuration (in seconds) */
+#define WPS_PBC_WALK_TIME 120
+
+#endif /* WPS_DEFS_H */

Added: wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,390 @@
+/*
+ * Wi-Fi Protected Setup - device attributes
+ * 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 "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+static int wps_build_manufacturer(struct wps_device_data *dev,
+				  struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Manufacturer");
+	wpabuf_put_be16(msg, ATTR_MANUFACTURER);
+	len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a null character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, '\0');
+	} else {
+		wpabuf_put_be16(msg, len);
+		wpabuf_put_data(msg, dev->manufacturer, len);
+	}
+	return 0;
+}
+
+
+static int wps_build_model_name(struct wps_device_data *dev,
+				struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Model Name");
+	wpabuf_put_be16(msg, ATTR_MODEL_NAME);
+	len = dev->model_name ? os_strlen(dev->model_name) : 0;
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a null character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, '\0');
+	} else {
+		wpabuf_put_be16(msg, len);
+		wpabuf_put_data(msg, dev->model_name, len);
+	}
+	return 0;
+}
+
+
+static int wps_build_model_number(struct wps_device_data *dev,
+				  struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Model Number");
+	wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
+	len = dev->model_number ? os_strlen(dev->model_number) : 0;
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a null character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, '\0');
+	} else {
+		wpabuf_put_be16(msg, len);
+		wpabuf_put_data(msg, dev->model_number, len);
+	}
+	return 0;
+}
+
+
+static int wps_build_serial_number(struct wps_device_data *dev,
+				   struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Serial Number");
+	wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
+	len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a null character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, '\0');
+	} else {
+		wpabuf_put_be16(msg, len);
+		wpabuf_put_data(msg, dev->serial_number, len);
+	}
+	return 0;
+}
+
+
+int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	struct wps_dev_type *d;
+	wpa_printf(MSG_DEBUG, "WPS:  * Primary Device Type");
+	wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
+	wpabuf_put_be16(msg, sizeof(*d));
+	d = wpabuf_put(msg, sizeof(*d));
+	WPA_PUT_BE16(d->categ_id, dev->categ);
+	WPA_PUT_BE32(d->oui, dev->oui);
+	WPA_PUT_BE16(d->sub_categ_id, dev->sub_categ);
+	return 0;
+}
+
+
+static int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	size_t len;
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Name");
+	wpabuf_put_be16(msg, ATTR_DEV_NAME);
+	len = dev->device_name ? os_strlen(dev->device_name) : 0;
+	if (len == 0) {
+		/*
+		 * Some deployed WPS implementations fail to parse zero-length
+		 * attributes. As a workaround, send a null character if the
+		 * device attribute string is empty.
+		 */
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, '\0');
+	} else {
+		wpabuf_put_be16(msg, len);
+		wpabuf_put_data(msg, dev->device_name, len);
+	}
+	return 0;
+}
+
+
+int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	if (wps_build_manufacturer(dev, msg) ||
+	    wps_build_model_name(dev, msg) ||
+	    wps_build_model_number(dev, msg) ||
+	    wps_build_serial_number(dev, msg) ||
+	    wps_build_primary_dev_type(dev, msg) ||
+	    wps_build_dev_name(dev, msg))
+		return -1;
+	return 0;
+}
+
+
+int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * OS Version");
+	wpabuf_put_be16(msg, ATTR_OS_VERSION);
+	wpabuf_put_be16(msg, 4);
+	wpabuf_put_be32(msg, 0x80000000 | dev->os_version);
+	return 0;
+}
+
+
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * RF Bands (%x)", dev->rf_bands);
+	wpabuf_put_be16(msg, ATTR_RF_BANDS);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, dev->rf_bands);
+	return 0;
+}
+
+
+static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
+				    size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
+
+	os_free(dev->manufacturer);
+	dev->manufacturer = os_malloc(str_len + 1);
+	if (dev->manufacturer == NULL)
+		return -1;
+	os_memcpy(dev->manufacturer, str, str_len);
+	dev->manufacturer[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
+				  size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Model Name received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
+
+	os_free(dev->model_name);
+	dev->model_name = os_malloc(str_len + 1);
+	if (dev->model_name == NULL)
+		return -1;
+	os_memcpy(dev->model_name, str, str_len);
+	dev->model_name[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
+				    size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Model Number received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
+
+	os_free(dev->model_number);
+	dev->model_number = os_malloc(str_len + 1);
+	if (dev->model_number == NULL)
+		return -1;
+	os_memcpy(dev->model_number, str, str_len);
+	dev->model_number[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_serial_number(struct wps_device_data *dev,
+				     const u8 *str, size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Serial Number received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
+
+	os_free(dev->serial_number);
+	dev->serial_number = os_malloc(str_len + 1);
+	if (dev->serial_number == NULL)
+		return -1;
+	os_memcpy(dev->serial_number, str, str_len);
+	dev->serial_number[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
+				size_t str_len)
+{
+	if (str == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Name received");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
+
+	os_free(dev->device_name);
+	dev->device_name = os_malloc(str_len + 1);
+	if (dev->device_name == NULL)
+		return -1;
+	os_memcpy(dev->device_name, str, str_len);
+	dev->device_name[str_len] = '\0';
+
+	return 0;
+}
+
+
+static int wps_process_primary_dev_type(struct wps_device_data *dev,
+					const u8 *dev_type)
+{
+	struct wps_dev_type *d;
+
+	if (dev_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
+		return -1;
+	}
+
+	d = (struct wps_dev_type *) dev_type;
+	dev->categ = WPA_GET_BE16(d->categ_id);
+	dev->oui = WPA_GET_BE32(d->oui);
+	dev->sub_categ = WPA_GET_BE16(d->sub_categ_id);
+
+	wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: category %d "
+		   "OUI %08x sub-category %d",
+		   dev->categ, dev->oui, dev->sub_categ);
+
+	return 0;
+}
+
+
+int wps_process_device_attrs(struct wps_device_data *dev,
+			     struct wps_parse_attr *attr)
+{
+	if (wps_process_manufacturer(dev, attr->manufacturer,
+				     attr->manufacturer_len) ||
+	    wps_process_model_name(dev, attr->model_name,
+				   attr->model_name_len) ||
+	    wps_process_model_number(dev, attr->model_number,
+				     attr->model_number_len) ||
+	    wps_process_serial_number(dev, attr->serial_number,
+				      attr->serial_number_len) ||
+	    wps_process_primary_dev_type(dev, attr->primary_dev_type) ||
+	    wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len))
+		return -1;
+	return 0;
+}
+
+
+int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
+{
+	if (ver == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No OS Version received");
+		return -1;
+	}
+
+	dev->os_version = WPA_GET_BE32(ver);
+	wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version);
+
+	return 0;
+}
+
+
+int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
+{
+	if (bands == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No RF Bands received");
+		return -1;
+	}
+
+	dev->rf_bands = *bands;
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands);
+
+	return 0;
+}
+
+
+void wps_device_data_dup(struct wps_device_data *dst,
+			 const struct wps_device_data *src)
+{
+	if (src->device_name)
+		dst->device_name = os_strdup(src->device_name);
+	if (src->manufacturer)
+		dst->manufacturer = os_strdup(src->manufacturer);
+	if (src->model_name)
+		dst->model_name = os_strdup(src->model_name);
+	if (src->model_number)
+		dst->model_number = os_strdup(src->model_number);
+	if (src->serial_number)
+		dst->serial_number = os_strdup(src->serial_number);
+	dst->categ = src->categ;
+	dst->oui = src->oui;
+	dst->sub_categ = src->sub_categ;
+	dst->os_version = src->os_version;
+	dst->rf_bands = src->rf_bands;
+}
+
+
+void wps_device_data_free(struct wps_device_data *dev)
+{
+	os_free(dev->device_name);
+	dev->device_name = NULL;
+	os_free(dev->manufacturer);
+	dev->manufacturer = NULL;
+	os_free(dev->model_name);
+	dev->model_name = NULL;
+	os_free(dev->model_number);
+	dev->model_number = NULL;
+	os_free(dev->serial_number);
+	dev->serial_number = NULL;
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_dev_attr.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,33 @@
+/*
+ * Wi-Fi Protected Setup - device attributes
+ * 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 WPS_DEV_ATTR_H
+#define WPS_DEV_ATTR_H
+
+struct wps_parse_attr;
+
+int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
+int wps_build_primary_dev_type(struct wps_device_data *dev,
+			       struct wpabuf *msg);
+int wps_process_device_attrs(struct wps_device_data *dev,
+			     struct wps_parse_attr *attr);
+int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
+int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
+void wps_device_data_dup(struct wps_device_data *dst,
+			 const struct wps_device_data *src);
+void wps_device_data_free(struct wps_device_data *dev);
+
+#endif /* WPS_DEV_ATTR_H */

Added: wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_enrollee.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,1137 @@
+/*
+ * Wi-Fi Protected Setup - Enrollee
+ * 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 "sha256.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, wps->mac_addr_e, ETH_ALEN);
+	return 0;
+}
+
+
+static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State");
+	wpabuf_put_be16(msg, ATTR_WPS_STATE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, WPS_STATE_CONFIGURED);
+	return 0;
+}
+
+
+static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 *hash;
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-S2",
+		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
+
+	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
+			   "E-Hash derivation");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash1");
+	wpabuf_put_be16(msg, ATTR_E_HASH1);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = wps->snonce;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * E-Hash2");
+	wpabuf_put_be16(msg, ATTR_E_HASH2);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
+static int wps_build_e_snonce1(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce1");
+	wpabuf_put_be16(msg, ATTR_E_SNONCE1);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_e_snonce2(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * E-SNonce2");
+	wpabuf_put_be16(msg, ATTR_E_SNONCE2);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
+			WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static struct wpabuf * wps_build_m1(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+	u16 methods;
+
+	if (os_get_random(wps->nonce_e, WPS_NONCE_LEN) < 0)
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
+		    wps->nonce_e, WPS_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M1");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+	if (wps->pbc)
+		methods |= WPS_CONFIG_PUSHBUTTON;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M1) ||
+	    wps_build_uuid_e(msg, wps->uuid_e) ||
+	    wps_build_mac_addr(wps, msg) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_public_key(wps, msg) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods(msg, methods) ||
+	    wps_build_wps_state(wps, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_dev_password_id(msg, wps->dev_pw_id) ||
+	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
+	    wps_build_os_version(&wps->wps->dev, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M2;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m3(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M3");
+
+	if (wps->dev_password == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password available");
+		return NULL;
+	}
+	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M3) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_hash(wps, msg) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M4;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m5(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M5");
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M5) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_snonce1(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    wps_build_encr_settings(wps, msg, plain) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_M6;
+	return msg;
+}
+
+
+static int wps_build_cred_ssid(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, wps->wps->ssid_len);
+	wpabuf_put_data(msg, wps->wps->ssid, wps->wps->ssid_len);
+	return 0;
+}
+
+
+static int wps_build_cred_auth_type(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type");
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, wps->wps->auth_types);
+	return 0;
+}
+
+
+static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type");
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, wps->wps->encr_types);
+	return 0;
+}
+
+
+static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
+	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+	wpabuf_put_be16(msg, wps->wps->network_key_len);
+	wpabuf_put_data(msg, wps->wps->network_key, wps->wps->network_key_len);
+	return 0;
+}
+
+
+static int wps_build_cred_mac_addr(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address (AP BSSID)");
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, wps->wps->dev.mac_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static struct wpabuf * wps_build_m7(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
+
+	plain = wpabuf_alloc(500);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M7) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_e_snonce2(wps, plain) ||
+	    (wps->wps->ap &&
+	     (wps_build_cred_ssid(wps, plain) ||
+	      wps_build_cred_mac_addr(wps, plain) ||
+	      wps_build_cred_auth_type(wps, plain) ||
+	      wps_build_cred_encr_type(wps, plain) ||
+	      wps_build_cred_network_key(wps, plain))) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    wps_build_encr_settings(wps, msg, plain) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_M8;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_done(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_Done");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_DONE) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (wps->wps->ap)
+		wps->state = RECV_ACK;
+	else {
+		wps_success_event(wps->wps);
+		wps->state = WPS_FINISHED;
+	}
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_config_error(msg, wps->config_error)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
+				     enum wsc_op_code *op_code)
+{
+	struct wpabuf *msg;
+
+	switch (wps->state) {
+	case SEND_M1:
+		msg = wps_build_m1(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M3:
+		msg = wps_build_m3(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M5:
+		msg = wps_build_m5(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M7:
+		msg = wps_build_m7(wps);
+		*op_code = WSC_MSG;
+		break;
+	case RECEIVED_M2D:
+		if (wps->wps->ap) {
+			msg = wps_build_wsc_nack(wps);
+			*op_code = WSC_NACK;
+			break;
+		}
+		msg = wps_build_wsc_ack(wps);
+		*op_code = WSC_ACK;
+		if (msg) {
+			/* Another M2/M2D may be received */
+			wps->state = RECV_M2;
+		}
+		break;
+	case SEND_WSC_NACK:
+		msg = wps_build_wsc_nack(wps);
+		*op_code = WSC_NACK;
+		break;
+	case WPS_MSG_DONE:
+		msg = wps_build_wsc_done(wps);
+		*op_code = WSC_Done;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
+			   "a message", wps->state);
+		msg = NULL;
+		break;
+	}
+
+	if (*op_code == WSC_MSG && msg) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return msg;
+}
+
+
+static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
+{
+	if (r_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
+		return -1;
+	}
+
+	os_memcpy(wps->nonce_r, r_nonce, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
+		    wps->nonce_r, WPS_NONCE_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
+{
+	if (e_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
+		return -1;
+	}
+
+	if (os_memcmp(wps->nonce_e, e_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce received");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_uuid_r(struct wps_data *wps, const u8 *uuid_r)
+{
+	if (uuid_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-R received");
+		return -1;
+	}
+
+	os_memcpy(wps->uuid_r, uuid_r, WPS_UUID_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
+			      size_t pk_len)
+{
+	if (pk == NULL || pk_len == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
+		return -1;
+	}
+
+	wpabuf_free(wps->dh_pubkey_r);
+	wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
+	if (wps->dh_pubkey_r == NULL)
+		return -1;
+
+	if (wps_derive_keys(wps) < 0)
+		return -1;
+
+	if (wps->request_type == WPS_REQ_WLAN_MANAGER_REGISTRAR &&
+	    wps_derive_mgmt_keys(wps) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static int wps_process_r_hash1(struct wps_data *wps, const u8 *r_hash1)
+{
+	if (r_hash1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-Hash1 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash1, r_hash1, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", wps->peer_hash1, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_r_hash2(struct wps_data *wps, const u8 *r_hash2)
+{
+	if (r_hash2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-Hash2 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash2, r_hash2, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", wps->peer_hash2, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (r_snonce1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce1 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce1", r_snonce1,
+			WPS_SECRET_NONCE_LEN);
+
+	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = r_snonce1;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the first "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (r_snonce2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2,
+			WPS_SECRET_NONCE_LEN);
+
+	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = r_snonce2;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
+			      size_t cred_len)
+{
+	struct wps_parse_attr attr;
+	struct wpabuf msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received Credential");
+	os_memset(&wps->cred, 0, sizeof(wps->cred));
+	wpabuf_set(&msg, cred, cred_len);
+	if (wps_parse_msg(&msg, &attr) < 0 ||
+	    wps_process_cred(&attr, &wps->cred))
+		return -1;
+
+	if (wps->wps->cred_cb)
+		wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+
+	return 0;
+}
+
+
+static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
+			     size_t cred_len[], size_t num_cred)
+{
+	size_t i;
+
+	if (wps->wps->ap)
+		return 0;
+
+	if (num_cred == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Credential attributes "
+			   "received");
+		return -1;
+	}
+
+	for (i = 0; i < num_cred; i++) {
+		if (wps_process_cred_e(wps, cred[i], cred_len[i]))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_ap_settings_e(struct wps_data *wps,
+				     struct wps_parse_attr *attr)
+{
+	struct wps_credential cred;
+
+	if (!wps->wps->ap)
+		return 0;
+
+	if (wps_process_ap_settings(attr, &cred) < 0)
+		return -1;
+
+	wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
+		   "Registrar");
+
+	if (wps->wps->cred_cb)
+		wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+
+	return 0;
+}
+
+
+static enum wps_process_res wps_process_m2(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M2");
+
+	if (wps->state != RECV_M2) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M2", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_uuid_r(wps, attr->uuid_r) ||
+	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->wps->ap && wps->wps->ap_setup_locked) {
+		wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
+			   "registration of a new Registrar");
+		wps->config_error = WPS_CFG_SETUP_LOCKED;
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wps->state = SEND_M3;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m2d(struct wps_data *wps,
+					    struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M2D");
+
+	if (wps->state != RECV_M2) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M2D", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer",
+			  attr->manufacturer, attr->manufacturer_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name",
+			  attr->model_name, attr->model_name_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number",
+			  attr->model_number, attr->model_number_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number",
+			  attr->serial_number, attr->serial_number_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name",
+			  attr->dev_name, attr->dev_name_len);
+
+	if (wps->wps->event_cb) {
+		union wps_event_data data;
+		struct wps_event_m2d *m2d = &data.m2d;
+		os_memset(&data, 0, sizeof(data));
+		if (attr->config_methods)
+			m2d->config_methods =
+				WPA_GET_BE16(attr->config_methods);
+		m2d->manufacturer = attr->manufacturer;
+		m2d->manufacturer_len = attr->manufacturer_len;
+		m2d->model_name = attr->model_name;
+		m2d->model_name_len = attr->model_name_len;
+		m2d->model_number = attr->model_number;
+		m2d->model_number_len = attr->model_number_len;
+		m2d->serial_number = attr->serial_number;
+		m2d->serial_number_len = attr->serial_number_len;
+		m2d->dev_name = attr->dev_name;
+		m2d->dev_name_len = attr->dev_name_len;
+		m2d->primary_dev_type = attr->primary_dev_type;
+		if (attr->config_error)
+			m2d->config_error =
+				WPA_GET_BE16(attr->config_error);
+		if (attr->dev_password_id)
+			m2d->dev_password_id =
+				WPA_GET_BE16(attr->dev_password_id);
+		wps->wps->event_cb(wps->wps->cb_ctx, WPS_EV_M2D, &data);
+	}
+
+	wps->state = RECEIVED_M2D;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m4(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M4");
+
+	if (wps->state != RECV_M4) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M4", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg) ||
+	    wps_process_r_hash1(wps, attr->r_hash1) ||
+	    wps_process_r_hash2(wps, attr->r_hash2)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_r_snonce1(wps, eattr.r_snonce1)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M5;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m6(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M6");
+
+	if (wps->state != RECV_M6) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M6", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_r_snonce2(wps, eattr.r_snonce2)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M7;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m8(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M8");
+
+	if (wps->state != RECV_M8) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M8", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_creds(wps, eattr.cred, eattr.cred_len,
+			      eattr.num_cred) ||
+	    wps_process_ap_settings_e(wps, &eattr)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = WPS_MSG_DONE;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	enum wps_process_res ret = WPS_CONTINUE;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	switch (*attr.msg_type) {
+	case WPS_M2:
+		ret = wps_process_m2(wps, msg, &attr);
+		break;
+	case WPS_M2D:
+		ret = wps_process_m2d(wps, &attr);
+		break;
+	case WPS_M4:
+		ret = wps_process_m4(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M4);
+		break;
+	case WPS_M6:
+		ret = wps_process_m6(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M6);
+		break;
+	case WPS_M8:
+		ret = wps_process_m8(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M8);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (ret == WPS_CONTINUE) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return ret;
+}
+
+
+static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_ACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (wps->state == RECV_ACK && wps->wps->ap) {
+		wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
+			   "completed successfully");
+		wps_success_event(wps->wps);
+		wps->state = WPS_FINISHED;
+		return WPS_DONE;
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_NACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		wpa_hexdump(MSG_DEBUG, "WPS: Received Registrar Nonce",
+			    attr.registrar_nonce, WPS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Expected Registrar Nonce",
+			    wps->nonce_r, WPS_NONCE_LEN);
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		wpa_hexdump(MSG_DEBUG, "WPS: Received Enrollee Nonce",
+			    attr.enrollee_nonce, WPS_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Expected Enrollee Nonce",
+			    wps->nonce_e, WPS_NONCE_LEN);
+		return WPS_FAILURE;
+	}
+
+	if (attr.config_error == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
+			   "in WSC_NACK");
+		return WPS_FAILURE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Registrar terminated negotiation with "
+		   "Configuration Error %d", WPA_GET_BE16(attr.config_error));
+
+	switch (wps->state) {
+	case RECV_M4:
+		wps_fail_event(wps->wps, WPS_M3);
+		break;
+	case RECV_M6:
+		wps_fail_event(wps->wps, WPS_M5);
+		break;
+	case RECV_M8:
+		wps_fail_event(wps->wps, WPS_M7);
+		break;
+	default:
+		break;
+	}
+
+	/* Followed by NACK if Enrollee is Supplicant or EAP-Failure if
+	 * Enrollee is Authenticator */
+	wps->state = SEND_WSC_NACK;
+
+	return WPS_FAILURE;
+}
+
+
+enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
+					      enum wsc_op_code op_code,
+					      const struct wpabuf *msg)
+{
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
+		   "op_code=%d)",
+		   (unsigned long) wpabuf_len(msg), op_code);
+
+	switch (op_code) {
+	case WSC_MSG:
+		return wps_process_wsc_msg(wps, msg);
+	case WSC_ACK:
+		return wps_process_wsc_ack(wps, msg);
+	case WSC_NACK:
+		return wps_process_wsc_nack(wps, msg);
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
+		return WPS_FAILURE;
+	}
+}

Added: wpasupplicant/branches/upstream/current/src/wps/wps_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_i.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_i.h (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_i.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,238 @@
+/*
+ * Wi-Fi Protected Setup - internal definitions
+ * 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 WPS_I_H
+#define WPS_I_H
+
+#include "wps.h"
+
+/**
+ * struct wps_data - WPS registration protocol data
+ *
+ * This data is stored at the EAP-WSC server/peer method and it is kept for a
+ * single registration protocol run.
+ */
+struct wps_data {
+	/**
+	 * wps - Pointer to long term WPS context
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * registrar - Whether this end is a Registrar
+	 */
+	int registrar;
+
+	enum {
+		/* Enrollee states */
+		SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,
+		RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,
+		SEND_WSC_NACK,
+
+		/* Registrar states */
+		RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,
+		RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK
+	} state;
+
+	u8 uuid_e[WPS_UUID_LEN];
+	u8 uuid_r[WPS_UUID_LEN];
+	u8 mac_addr_e[ETH_ALEN];
+	u8 nonce_e[WPS_NONCE_LEN];
+	u8 nonce_r[WPS_NONCE_LEN];
+	u8 psk1[WPS_PSK_LEN];
+	u8 psk2[WPS_PSK_LEN];
+	u8 snonce[2 * WPS_SECRET_NONCE_LEN];
+	u8 peer_hash1[WPS_HASH_LEN];
+	u8 peer_hash2[WPS_HASH_LEN];
+
+	struct wpabuf *dh_privkey;
+	struct wpabuf *dh_pubkey_e;
+	struct wpabuf *dh_pubkey_r;
+	u8 authkey[WPS_AUTHKEY_LEN];
+	u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
+	u8 emsk[WPS_EMSK_LEN];
+	u8 mgmt_auth_key[WPS_MGMTAUTHKEY_LEN];
+	u8 mgmt_auth_key_id[WPS_MGMT_KEY_ID_LEN];
+	u8 mgmt_enc_key[WPS_MGMTENCKEY_LEN];
+	u8 mgmt_enc_key_id[WPS_MGMT_KEY_ID_LEN];
+
+	struct wpabuf *last_msg;
+
+	u8 *dev_password;
+	size_t dev_password_len;
+	u16 dev_pw_id;
+	int pbc;
+
+	/**
+	 * request_type - Request Type attribute from (Re)AssocReq
+	 */
+	u8 request_type;
+
+	/**
+	 * encr_type - Available encryption types
+	 */
+	u16 encr_type;
+
+	/**
+	 * auth_type - Available authentication types
+	 */
+	u16 auth_type;
+
+	u8 *new_psk;
+	size_t new_psk_len;
+
+	int wps_pin_revealed;
+	struct wps_credential cred;
+
+	struct wps_device_data peer_dev;
+
+	/**
+	 * config_error - Configuration Error value to be used in NACK
+	 */
+	u16 config_error;
+};
+
+
+struct wps_parse_attr {
+	/* fixed length fields */
+	const u8 *version; /* 1 octet */
+	const u8 *msg_type; /* 1 octet */
+	const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
+	const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
+	const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
+	const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
+	const u8 *auth_type_flags; /* 2 octets */
+	const u8 *encr_type_flags; /* 2 octets */
+	const u8 *conn_type_flags; /* 1 octet */
+	const u8 *config_methods; /* 2 octets */
+	const u8 *sel_reg_config_methods; /* 2 octets */
+	const u8 *primary_dev_type; /* 8 octets */
+	const u8 *rf_bands; /* 1 octet */
+	const u8 *assoc_state; /* 2 octets */
+	const u8 *config_error; /* 2 octets */
+	const u8 *dev_password_id; /* 2 octets */
+	const u8 *os_version; /* 4 octets */
+	const u8 *wps_state; /* 1 octet */
+	const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
+	const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
+	const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
+	const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
+	const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
+	const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
+	const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
+	const u8 *auth_type; /* 2 octets */
+	const u8 *encr_type; /* 2 octets */
+	const u8 *network_idx; /* 1 octet */
+	const u8 *network_key_idx; /* 1 octet */
+	const u8 *mac_addr; /* ETH_ALEN (6) octets */
+	const u8 *key_prov_auto; /* 1 octet (Bool) */
+	const u8 *dot1x_enabled; /* 1 octet (Bool) */
+	const u8 *selected_registrar; /* 1 octet (Bool) */
+	const u8 *request_type; /* 1 octet */
+	const u8 *response_type; /* 1 octet */
+
+	/* variable length fields */
+	const u8 *manufacturer;
+	size_t manufacturer_len;
+	const u8 *model_name;
+	size_t model_name_len;
+	const u8 *model_number;
+	size_t model_number_len;
+	const u8 *serial_number;
+	size_t serial_number_len;
+	const u8 *dev_name;
+	size_t dev_name_len;
+	const u8 *public_key;
+	size_t public_key_len;
+	const u8 *encr_settings;
+	size_t encr_settings_len;
+	const u8 *ssid; /* <= 32 octets */
+	size_t ssid_len;
+	const u8 *network_key; /* <= 64 octets */
+	size_t network_key_len;
+	const u8 *eap_type; /* <= 8 octets */
+	size_t eap_type_len;
+	const u8 *eap_identity; /* <= 64 octets */
+	size_t eap_identity_len;
+
+	/* attributes that can occur multiple times */
+#define MAX_CRED_COUNT 10
+	const u8 *cred[MAX_CRED_COUNT];
+	size_t cred_len[MAX_CRED_COUNT];
+	size_t num_cred;
+};
+
+/* wps_common.c */
+void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
+	     const char *label, u8 *res, size_t res_len);
+int wps_derive_keys(struct wps_data *wps);
+int wps_derive_mgmt_keys(struct wps_data *wps);
+void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
+		    size_t dev_passwd_len);
+struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
+					  size_t encr_len);
+void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg);
+void wps_success_event(struct wps_context *wps);
+
+/* wps_attr_parse.c */
+int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
+
+/* wps_attr_build.c */
+int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
+int wps_build_config_methods(struct wpabuf *msg, u16 methods);
+int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
+int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
+int wps_build_config_error(struct wpabuf *msg, u16 err);
+int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
+			    struct wpabuf *plain);
+int wps_build_version(struct wpabuf *msg);
+int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
+int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
+int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
+
+/* wps_attr_process.c */
+int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
+			      const struct wpabuf *msg);
+int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
+			      const u8 *key_wrap_auth);
+int wps_process_cred(struct wps_parse_attr *attr,
+		     struct wps_credential *cred);
+int wps_process_ap_settings(struct wps_parse_attr *attr,
+			    struct wps_credential *cred);
+
+/* wps_enrollee.c */
+struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
+				     enum wsc_op_code *op_code);
+enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
+					      enum wsc_op_code op_code,
+					      const struct wpabuf *msg);
+
+/* wps_registrar.c */
+struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
+				      enum wsc_op_code *op_code);
+enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
+					       enum wsc_op_code op_code,
+					       const struct wpabuf *msg);
+
+#endif /* WPS_I_H */

Added: wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c (added)
+++ wpasupplicant/branches/upstream/current/src/wps/wps_registrar.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,2179 @@
+/*
+ * Wi-Fi Protected Setup - Registrar
+ * 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 "sha256.h"
+#include "base64.h"
+#include "ieee802_11_defs.h"
+#include "eloop.h"
+#include "wps_i.h"
+#include "wps_dev_attr.h"
+
+
+struct wps_uuid_pin {
+	struct wps_uuid_pin *next;
+	u8 uuid[WPS_UUID_LEN];
+	int wildcard_uuid;
+	u8 *pin;
+	size_t pin_len;
+	int locked;
+};
+
+
+static void wps_free_pin(struct wps_uuid_pin *pin)
+{
+	os_free(pin->pin);
+	os_free(pin);
+}
+
+
+static void wps_free_pins(struct wps_uuid_pin *pins)
+{
+	struct wps_uuid_pin *pin, *prev;
+
+	pin = pins;
+	while (pin) {
+		prev = pin;
+		pin = pin->next;
+		wps_free_pin(prev);
+	}
+}
+
+
+struct wps_pbc_session {
+	struct wps_pbc_session *next;
+	u8 addr[ETH_ALEN];
+	u8 uuid_e[WPS_UUID_LEN];
+	struct os_time timestamp;
+};
+
+
+static void wps_free_pbc_sessions(struct wps_pbc_session *pbc)
+{
+	struct wps_pbc_session *prev;
+
+	while (pbc) {
+		prev = pbc;
+		pbc = pbc->next;
+		os_free(prev);
+	}
+}
+
+
+struct wps_registrar {
+	struct wps_context *wps;
+
+	int pbc;
+	int selected_registrar;
+
+	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
+			  size_t psk_len);
+	int (*set_ie_cb)(void *ctx, const u8 *beacon_ie, size_t beacon_ie_len,
+			 const u8 *probe_resp_ie, size_t probe_resp_ie_len);
+	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
+			      const struct wps_device_data *dev);
+	void *cb_ctx;
+
+	struct wps_uuid_pin *pins;
+	struct wps_pbc_session *pbc_sessions;
+};
+
+
+static int wps_set_ie(struct wps_registrar *reg);
+static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx);
+
+
+static void wps_registrar_add_pbc_session(struct wps_registrar *reg,
+					  const u8 *addr, const u8 *uuid_e)
+{
+	struct wps_pbc_session *pbc, *prev = NULL;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	pbc = reg->pbc_sessions;
+	while (pbc) {
+		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
+		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+			if (prev)
+				prev->next = pbc->next;
+			else
+				reg->pbc_sessions = pbc->next;
+			break;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+
+	if (!pbc) {
+		pbc = os_zalloc(sizeof(*pbc));
+		if (pbc == NULL)
+			return;
+		os_memcpy(pbc->addr, addr, ETH_ALEN);
+		if (uuid_e)
+			os_memcpy(pbc->uuid_e, uuid_e, WPS_UUID_LEN);
+	}
+
+	pbc->next = reg->pbc_sessions;
+	reg->pbc_sessions = pbc;
+	pbc->timestamp = now;
+
+	/* remove entries that have timed out */
+	prev = pbc;
+	pbc = pbc->next;
+
+	while (pbc) {
+		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME) {
+			prev->next = NULL;
+			wps_free_pbc_sessions(pbc);
+			break;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+}
+
+
+static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
+					     const u8 *addr, const u8 *uuid_e)
+{
+	struct wps_pbc_session *pbc, *prev = NULL;
+
+	pbc = reg->pbc_sessions;
+	while (pbc) {
+		if (os_memcmp(pbc->addr, addr, ETH_ALEN) == 0 &&
+		    os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+			if (prev)
+				prev->next = pbc->next;
+			else
+				reg->pbc_sessions = pbc->next;
+			os_free(pbc);
+			break;
+		}
+		prev = pbc;
+		pbc = pbc->next;
+	}
+}
+
+
+static int wps_registrar_pbc_overlap(struct wps_registrar *reg,
+				     const u8 *addr, const u8 *uuid_e)
+{
+	int count = 0;
+	struct wps_pbc_session *pbc;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	for (pbc = reg->pbc_sessions; pbc; pbc = pbc->next) {
+		if (now.sec > pbc->timestamp.sec + WPS_PBC_WALK_TIME)
+			break;
+		if (addr == NULL || os_memcmp(addr, pbc->addr, ETH_ALEN) ||
+		    uuid_e == NULL ||
+		    os_memcmp(uuid_e, pbc->uuid_e, WPS_UUID_LEN))
+			count++;
+	}
+
+	if (addr || uuid_e)
+		count++;
+
+	return count > 1 ? 1 : 0;
+}
+
+
+static int wps_build_wps_state(struct wps_context *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Wi-Fi Protected Setup State (%d)",
+		   wps->wps_state);
+	wpabuf_put_be16(msg, ATTR_WPS_STATE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, wps->wps_state);
+	return 0;
+}
+
+
+static int wps_build_ap_setup_locked(struct wps_context *wps,
+				     struct wpabuf *msg)
+{
+	if (wps->ap_setup_locked) {
+		wpa_printf(MSG_DEBUG, "WPS:  * AP Setup Locked");
+		wpabuf_put_be16(msg, ATTR_AP_SETUP_LOCKED);
+		wpabuf_put_be16(msg, 1);
+		wpabuf_put_u8(msg, 1);
+	}
+	return 0;
+}
+
+
+static int wps_build_selected_registrar(struct wps_registrar *reg,
+					struct wpabuf *msg)
+{
+	if (!reg->selected_registrar)
+		return 0;
+	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar");
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, 1);
+	return 0;
+}
+
+
+static int wps_build_sel_reg_dev_password_id(struct wps_registrar *reg,
+					     struct wpabuf *msg)
+{
+	u16 id = reg->pbc ? DEV_PW_PUSHBUTTON : DEV_PW_DEFAULT;
+	if (!reg->selected_registrar)
+		return 0;
+	wpa_printf(MSG_DEBUG, "WPS:  * Device Password ID (%d)", id);
+	wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, id);
+	return 0;
+}
+
+
+static int wps_build_sel_reg_config_methods(struct wps_registrar *reg,
+					    struct wpabuf *msg)
+{
+	u16 methods;
+	if (!reg->selected_registrar)
+		return 0;
+	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+	if (reg->pbc)
+		methods |= WPS_CONFIG_PUSHBUTTON;
+	wpa_printf(MSG_DEBUG, "WPS:  * Selected Registrar Config Methods (%x)",
+		   methods);
+	wpabuf_put_be16(msg, ATTR_SELECTED_REGISTRAR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+static int wps_build_probe_config_methods(struct wps_registrar *reg,
+					  struct wpabuf *msg)
+{
+	u16 methods;
+	methods = 0;
+	wpa_printf(MSG_DEBUG, "WPS:  * Config Methods (%x)", methods);
+	wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, methods);
+	return 0;
+}
+
+
+static int wps_build_config_methods_r(struct wps_registrar *reg,
+				      struct wpabuf *msg)
+{
+	u16 methods;
+	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
+	if (reg->pbc)
+		methods |= WPS_CONFIG_PUSHBUTTON;
+	return wps_build_config_methods(msg, methods);
+}
+
+
+static int wps_build_resp_type(struct wps_registrar *reg, struct wpabuf *msg)
+{
+	u8 resp = reg->wps->ap ? WPS_RESP_AP : WPS_RESP_REGISTRAR;
+	wpa_printf(MSG_DEBUG, "WPS:  * Response Type (%d)", resp);
+	wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, resp);
+	return 0;
+}
+
+
+/**
+ * wps_registrar_init - Initialize WPS Registrar data
+ * @wps: Pointer to longterm WPS context
+ * @cfg: Registrar configuration
+ * Returns: Pointer to allocated Registrar data or %NULL on failure
+ *
+ * This function is used to initialize WPS Registrar functionality. It can be
+ * used for a single Registrar run (e.g., when run in a supplicant) or multiple
+ * runs (e.g., when run as an internal Registrar in an AP). Caller is
+ * responsible for freeing the returned data with wps_registrar_deinit() when
+ * Registrar functionality is not needed anymore.
+ */
+struct wps_registrar *
+wps_registrar_init(struct wps_context *wps,
+		   const struct wps_registrar_config *cfg)
+{
+	struct wps_registrar *reg = os_zalloc(sizeof(*reg));
+	if (reg == NULL)
+		return NULL;
+
+	reg->wps = wps;
+	reg->new_psk_cb = cfg->new_psk_cb;
+	reg->set_ie_cb = cfg->set_ie_cb;
+	reg->pin_needed_cb = cfg->pin_needed_cb;
+	reg->cb_ctx = cfg->cb_ctx;
+
+	if (wps_set_ie(reg)) {
+		wps_registrar_deinit(reg);
+		return NULL;
+	}
+
+	return reg;
+}
+
+
+/**
+ * wps_registrar_deinit - Deinitialize WPS Registrar data
+ * @reg: Registrar data from wps_registrar_init()
+ */
+void wps_registrar_deinit(struct wps_registrar *reg)
+{
+	if (reg == NULL)
+		return;
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	wps_free_pins(reg->pins);
+	wps_free_pbc_sessions(reg->pbc_sessions);
+	os_free(reg);
+}
+
+
+/**
+ * wps_registrar_add_pin - Configure a new PIN for Registrar
+ * @reg: Registrar data from wps_registrar_init()
+ * @uuid: UUID-E or %NULL for wildcard (any UUID)
+ * @pin: PIN (Device Password)
+ * @pin_len: Length of pin in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
+			  const u8 *pin, size_t pin_len)
+{
+	struct wps_uuid_pin *p;
+
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	if (uuid == NULL)
+		p->wildcard_uuid = 1;
+	else
+		os_memcpy(p->uuid, uuid, WPS_UUID_LEN);
+	p->pin = os_malloc(pin_len);
+	if (p->pin == NULL) {
+		os_free(p);
+		return -1;
+	}
+	os_memcpy(p->pin, pin, pin_len);
+	p->pin_len = pin_len;
+
+	p->next = reg->pins;
+	reg->pins = p;
+
+	wpa_printf(MSG_DEBUG, "WPS: A new PIN configured");
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
+	reg->selected_registrar = 1;
+	reg->pbc = 0;
+	wps_set_ie(reg);
+
+	return 0;
+}
+
+
+/**
+ * wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
+ * @reg: Registrar data from wps_registrar_init()
+ * @uuid: UUID-E
+ * Returns: 0 on success, -1 on failure (e.g., PIN not found)
+ */
+int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
+{
+	struct wps_uuid_pin *pin, *prev;
+
+	prev = NULL;
+	pin = reg->pins;
+	while (pin) {
+		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
+			if (prev == NULL)
+				reg->pins = pin->next;
+			else
+				prev->next = pin->next;
+			wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
+				    pin->uuid, WPS_UUID_LEN);
+			wps_free_pin(pin);
+			return 0;
+		}
+		prev = pin;
+		pin = pin->next;
+	}
+
+	return -1;
+}
+
+
+static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
+					const u8 *uuid, size_t *pin_len)
+{
+	struct wps_uuid_pin *pin;
+
+	pin = reg->pins;
+	while (pin) {
+		if (!pin->wildcard_uuid &&
+		    os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0)
+			break;
+		pin = pin->next;
+	}
+
+	if (!pin) {
+		/* Check for wildcard UUIDs since none of the UUID-specific
+		 * PINs matched */
+		pin = reg->pins;
+		while (pin) {
+			if (pin->wildcard_uuid == 1) {
+				wpa_printf(MSG_DEBUG, "WPS: Found a wildcard "
+					   "PIN. Assigned it for this UUID-E");
+				pin->wildcard_uuid = 2;
+				os_memcpy(pin->uuid, uuid, WPS_UUID_LEN);
+				break;
+			}
+			pin = pin->next;
+		}
+	}
+
+	if (!pin)
+		return NULL;
+
+	/*
+	 * Lock the PIN to avoid attacks based on concurrent re-use of the PIN
+	 * that could otherwise avoid PIN invalidations.
+	 */
+	if (pin->locked) {
+		wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
+			   "allow concurrent re-use");
+		return NULL;
+	}
+	*pin_len = pin->pin_len;
+	pin->locked = 1;
+	return pin->pin;
+}
+
+
+/**
+ * wps_registrar_unlock_pin - Unlock a PIN for a specific UUID-E
+ * @reg: Registrar data from wps_registrar_init()
+ * @uuid: UUID-E
+ * Returns: 0 on success, -1 on failure
+ *
+ * PINs are locked to enforce only one concurrent use. This function unlocks a
+ * PIN to allow it to be used again. If the specified PIN was configured using
+ * a wildcard UUID, it will be removed instead of allowing multiple uses.
+ */
+int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
+{
+	struct wps_uuid_pin *pin;
+
+	pin = reg->pins;
+	while (pin) {
+		if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
+			if (pin->wildcard_uuid == 2) {
+				wpa_printf(MSG_DEBUG, "WPS: Invalidating used "
+					   "wildcard PIN");
+				return wps_registrar_invalidate_pin(reg, uuid);
+			}
+			pin->locked = 0;
+			return 0;
+		}
+		pin = pin->next;
+	}
+
+	return -1;
+}
+
+
+static void wps_registrar_stop_pbc(struct wps_registrar *reg)
+{
+	reg->selected_registrar = 0;
+	reg->pbc = 0;
+	wps_set_ie(reg);
+}
+
+
+static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wps_registrar *reg = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
+	wps_registrar_stop_pbc(reg);
+}
+
+
+/**
+ * wps_registrar_button_pushed - Notify Registrar that AP button was pushed
+ * @reg: Registrar data from wps_registrar_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called on an AP when a push button is pushed to activate
+ * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
+ * or when a PBC registration is completed.
+ */
+int wps_registrar_button_pushed(struct wps_registrar *reg)
+{
+	if (wps_registrar_pbc_overlap(reg, NULL, NULL)) {
+		wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
+			   "mode");
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
+	reg->selected_registrar = 1;
+	reg->pbc = 1;
+	wps_set_ie(reg);
+
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wps_registrar_pbc_timeout,
+			       reg, NULL);
+	return 0;
+}
+
+
+static void wps_registrar_pbc_completed(struct wps_registrar *reg)
+{
+	wpa_printf(MSG_DEBUG, "WPS: PBC completed - stopping PBC mode");
+	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
+	wps_registrar_stop_pbc(reg);
+}
+
+
+/**
+ * wps_registrar_probe_req_rx - Notify Registrar of Probe Request
+ * @reg: Registrar data from wps_registrar_init()
+ * @addr: MAC address of the Probe Request sender
+ * @wps_data: WPS IE contents
+ *
+ * This function is called on an AP when a Probe Request with WPS IE is
+ * received. This is used to track PBC mode use and to detect possible overlap
+ * situation with other WPS APs.
+ */
+void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
+				const struct wpabuf *wps_data)
+{
+	struct wps_parse_attr attr;
+	u16 methods;
+
+	wpa_hexdump_buf(MSG_MSGDUMP,
+			"WPS: Probe Request with WPS data received",
+			wps_data);
+
+	if (wps_parse_msg(wps_data, &attr) < 0 ||
+	    attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported ProbeReq WPS IE "
+			   "version 0x%x", attr.version ? *attr.version : 0);
+		return;
+	}
+
+	if (attr.config_methods == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in "
+			   "Probe Request");
+		return;
+	}
+
+	methods = WPA_GET_BE16(attr.config_methods);
+	if (!(methods & WPS_CONFIG_PUSHBUTTON))
+		return; /* Not PBC */
+
+	wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
+		   MACSTR, MAC2STR(addr));
+
+	wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+}
+
+
+static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr,
+			  const u8 *psk, size_t psk_len)
+{
+	if (reg->new_psk_cb == NULL)
+		return 0;
+
+	return reg->new_psk_cb(reg->cb_ctx, mac_addr, psk, psk_len);
+}
+
+
+static void wps_cb_pin_needed(struct wps_registrar *reg, const u8 *uuid_e,
+			      const struct wps_device_data *dev)
+{
+	if (reg->pin_needed_cb == NULL)
+		return;
+
+	reg->pin_needed_cb(reg->cb_ctx, uuid_e, dev);
+}
+
+
+static int wps_cb_set_ie(struct wps_registrar *reg,
+			 const struct wpabuf *beacon_ie,
+			 const struct wpabuf *probe_resp_ie)
+{
+	if (reg->set_ie_cb == NULL)
+		return 0;
+
+	return reg->set_ie_cb(reg->cb_ctx, wpabuf_head(beacon_ie),
+			      wpabuf_len(beacon_ie),
+			      wpabuf_head(probe_resp_ie),
+			      wpabuf_len(probe_resp_ie));
+}
+
+
+/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
+static struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
+{
+	struct wpabuf *ie;
+	const u8 *pos, *end;
+
+	ie = wpabuf_alloc(wpabuf_len(data) + 100);
+	if (ie == NULL) {
+		wpabuf_free(data);
+		return NULL;
+	}
+
+	pos = wpabuf_head(data);
+	end = pos + wpabuf_len(data);
+
+	while (end > pos) {
+		size_t frag_len = end - pos;
+		if (frag_len > 251)
+			frag_len = 251;
+		wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
+		wpabuf_put_u8(ie, 4 + frag_len);
+		wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
+		wpabuf_put_data(ie, pos, frag_len);
+		pos += frag_len;
+	}
+
+	wpabuf_free(data);
+
+	return ie;
+}
+
+
+static int wps_set_ie(struct wps_registrar *reg)
+{
+	struct wpabuf *beacon;
+	struct wpabuf *probe;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs");
+
+	beacon = wpabuf_alloc(300);
+	if (beacon == NULL)
+		return -1;
+	probe = wpabuf_alloc(400);
+	if (probe == NULL) {
+		wpabuf_free(beacon);
+		return -1;
+	}
+
+	if (wps_build_version(beacon) ||
+	    wps_build_wps_state(reg->wps, beacon) ||
+	    wps_build_ap_setup_locked(reg->wps, beacon) ||
+	    wps_build_selected_registrar(reg, beacon) ||
+	    wps_build_sel_reg_dev_password_id(reg, beacon) ||
+	    wps_build_sel_reg_config_methods(reg, beacon) ||
+	    wps_build_version(probe) ||
+	    wps_build_wps_state(reg->wps, probe) ||
+	    wps_build_ap_setup_locked(reg->wps, probe) ||
+	    wps_build_selected_registrar(reg, probe) ||
+	    wps_build_sel_reg_dev_password_id(reg, probe) ||
+	    wps_build_sel_reg_config_methods(reg, probe) ||
+	    wps_build_resp_type(reg, probe) ||
+	    wps_build_uuid_e(probe, reg->wps->uuid) ||
+	    wps_build_device_attrs(&reg->wps->dev, probe) ||
+	    wps_build_probe_config_methods(reg, probe) ||
+	    wps_build_rf_bands(&reg->wps->dev, probe)) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+
+	beacon = wps_ie_encapsulate(beacon);
+	probe = wps_ie_encapsulate(probe);
+
+	if (!beacon || !probe) {
+		wpabuf_free(beacon);
+		wpabuf_free(probe);
+		return -1;
+	}
+
+	ret = wps_cb_set_ie(reg, beacon, probe);
+	wpabuf_free(beacon);
+	wpabuf_free(probe);
+
+	return ret;
+}
+
+
+static int wps_get_dev_password(struct wps_data *wps)
+{
+	const u8 *pin;
+	size_t pin_len = 0;
+
+	os_free(wps->dev_password);
+	wps->dev_password = NULL;
+
+	if (wps->pbc) {
+		wpa_printf(MSG_DEBUG, "WPS: Use default PIN for PBC");
+		pin = (const u8 *) "00000000";
+		pin_len = 8;
+	} else {
+		pin = wps_registrar_get_pin(wps->wps->registrar, wps->uuid_e,
+					    &pin_len);
+	}
+	if (pin == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password available for "
+			   "the Enrollee");
+		wps_cb_pin_needed(wps->wps->registrar, wps->uuid_e,
+				  &wps->peer_dev);
+		return -1;
+	}
+
+	wps->dev_password = os_malloc(pin_len);
+	if (wps->dev_password == NULL)
+		return -1;
+	os_memcpy(wps->dev_password, pin, pin_len);
+	wps->dev_password_len = pin_len;
+
+	return 0;
+}
+
+
+static int wps_build_uuid_r(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * UUID-R");
+	wpabuf_put_be16(msg, ATTR_UUID_R);
+	wpabuf_put_be16(msg, WPS_UUID_LEN);
+	wpabuf_put_data(msg, wps->uuid_r, WPS_UUID_LEN);
+	return 0;
+}
+
+
+static int wps_build_r_hash(struct wps_data *wps, struct wpabuf *msg)
+{
+	u8 *hash;
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (os_get_random(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "WPS: R-S1", wps->snonce, WPS_SECRET_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-S2",
+		    wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN);
+
+	if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for "
+			   "R-Hash derivation");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash1");
+	wpabuf_put_be16(msg, ATTR_R_HASH1);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* R-Hash1 = HMAC_AuthKey(R-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = wps->snonce;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash1", hash, SHA256_MAC_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS:  * R-Hash2");
+	wpabuf_put_be16(msg, ATTR_R_HASH2);
+	wpabuf_put_be16(msg, SHA256_MAC_LEN);
+	hash = wpabuf_put(msg, SHA256_MAC_LEN);
+	/* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+	wpa_hexdump(MSG_DEBUG, "WPS: R-Hash2", hash, SHA256_MAC_LEN);
+
+	return 0;
+}
+
+
+static int wps_build_r_snonce1(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce1");
+	wpabuf_put_be16(msg, ATTR_R_SNONCE1);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce, WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_r_snonce2(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * R-SNonce2");
+	wpabuf_put_be16(msg, ATTR_R_SNONCE2);
+	wpabuf_put_be16(msg, WPS_SECRET_NONCE_LEN);
+	wpabuf_put_data(msg, wps->snonce + WPS_SECRET_NONCE_LEN,
+			WPS_SECRET_NONCE_LEN);
+	return 0;
+}
+
+
+static int wps_build_cred_network_idx(struct wpabuf *msg,
+				      struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Index");
+	wpabuf_put_be16(msg, ATTR_NETWORK_INDEX);
+	wpabuf_put_be16(msg, 1);
+	wpabuf_put_u8(msg, 0);
+	return 0;
+}
+
+
+static int wps_build_cred_ssid(struct wpabuf *msg,
+			       struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, cred->ssid_len);
+	wpabuf_put_data(msg, cred->ssid, cred->ssid_len);
+	return 0;
+}
+
+
+static int wps_build_cred_auth_type(struct wpabuf *msg,
+				    struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Authentication Type (0x%x)",
+		   cred->auth_type);
+	wpabuf_put_be16(msg, ATTR_AUTH_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, cred->auth_type);
+	return 0;
+}
+
+
+static int wps_build_cred_encr_type(struct wpabuf *msg,
+				    struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Encryption Type (0x%x)",
+		   cred->encr_type);
+	wpabuf_put_be16(msg, ATTR_ENCR_TYPE);
+	wpabuf_put_be16(msg, 2);
+	wpabuf_put_be16(msg, cred->encr_type);
+	return 0;
+}
+
+
+static int wps_build_cred_network_key(struct wpabuf *msg,
+				      struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * Network Key");
+	wpabuf_put_be16(msg, ATTR_NETWORK_KEY);
+	wpabuf_put_be16(msg, cred->key_len);
+	wpabuf_put_data(msg, cred->key, cred->key_len);
+	return 0;
+}
+
+
+static int wps_build_cred_mac_addr(struct wpabuf *msg,
+				   struct wps_credential *cred)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * MAC Address");
+	wpabuf_put_be16(msg, ATTR_MAC_ADDR);
+	wpabuf_put_be16(msg, ETH_ALEN);
+	wpabuf_put_data(msg, cred->mac_addr, ETH_ALEN);
+	return 0;
+}
+
+
+static int wps_build_credential(struct wpabuf *msg,
+				struct wps_credential *cred)
+{
+	if (wps_build_cred_network_idx(msg, cred) ||
+	    wps_build_cred_ssid(msg, cred) ||
+	    wps_build_cred_auth_type(msg, cred) ||
+	    wps_build_cred_encr_type(msg, cred) ||
+	    wps_build_cred_network_key(msg, cred) ||
+	    wps_build_cred_mac_addr(msg, cred))
+		return -1;
+	return 0;
+}
+
+
+static int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
+{
+	struct wpabuf *cred;
+
+	wpa_printf(MSG_DEBUG, "WPS:  * Credential");
+	os_memset(&wps->cred, 0, sizeof(wps->cred));
+
+	os_memcpy(wps->cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
+	wps->cred.ssid_len = wps->wps->ssid_len;
+
+	/* Select the best authentication and encryption type */
+	if (wps->auth_type & WPS_AUTH_WPA2PSK)
+		wps->auth_type = WPS_AUTH_WPA2PSK;
+	else if (wps->auth_type & WPS_AUTH_WPAPSK)
+		wps->auth_type = WPS_AUTH_WPAPSK;
+	else if (wps->auth_type & WPS_AUTH_OPEN)
+		wps->auth_type = WPS_AUTH_OPEN;
+	else if (wps->auth_type & WPS_AUTH_SHARED)
+		wps->auth_type = WPS_AUTH_SHARED;
+	else {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported auth_type 0x%x",
+			   wps->auth_type);
+		return -1;
+	}
+	wps->cred.auth_type = wps->auth_type;
+
+	if (wps->auth_type == WPS_AUTH_WPA2PSK ||
+	    wps->auth_type == WPS_AUTH_WPAPSK) {
+		if (wps->encr_type & WPS_ENCR_AES)
+			wps->encr_type = WPS_ENCR_AES;
+		else if (wps->encr_type & WPS_ENCR_TKIP)
+			wps->encr_type = WPS_ENCR_TKIP;
+		else {
+			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
+				   "type for WPA/WPA2");
+			return -1;
+		}
+	} else {
+		if (wps->encr_type & WPS_ENCR_WEP)
+			wps->encr_type = WPS_ENCR_WEP;
+		else if (wps->encr_type & WPS_ENCR_NONE)
+			wps->encr_type = WPS_ENCR_NONE;
+		else {
+			wpa_printf(MSG_DEBUG, "WPS: No suitable encryption "
+				   "type for non-WPA/WPA2 mode");
+			return -1;
+		}
+	}
+	wps->cred.encr_type = wps->encr_type;
+	os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
+
+	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap) {
+		u8 r[16];
+		/* Generate a random passphrase */
+		if (os_get_random(r, sizeof(r)) < 0)
+			return -1;
+		os_free(wps->new_psk);
+		wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len);
+		if (wps->new_psk == NULL)
+			return -1;
+		wps->new_psk_len--; /* remove newline */
+		while (wps->new_psk_len &&
+		       wps->new_psk[wps->new_psk_len - 1] == '=')
+			wps->new_psk_len--;
+		wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Generated passphrase",
+				      wps->new_psk, wps->new_psk_len);
+		os_memcpy(wps->cred.key, wps->new_psk, wps->new_psk_len);
+		wps->cred.key_len = wps->new_psk_len;
+	} else if (wps->wps->network_key) {
+		os_memcpy(wps->cred.key, wps->wps->network_key,
+			  wps->wps->network_key_len);
+		wps->cred.key_len = wps->wps->network_key_len;
+	} else if (wps->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+		char hex[65];
+		/* Generate a random per-device PSK */
+		os_free(wps->new_psk);
+		wps->new_psk_len = 32;
+		wps->new_psk = os_malloc(wps->new_psk_len);
+		if (wps->new_psk == NULL)
+			return -1;
+		if (os_get_random(wps->new_psk, wps->new_psk_len) < 0) {
+			os_free(wps->new_psk);
+			wps->new_psk = NULL;
+			return -1;
+		}
+		wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK",
+				wps->new_psk, wps->new_psk_len);
+		wpa_snprintf_hex(hex, sizeof(hex), wps->new_psk,
+				 wps->new_psk_len);
+		os_memcpy(wps->cred.key, hex, wps->new_psk_len * 2);
+		wps->cred.key_len = wps->new_psk_len * 2;
+	}
+
+	cred = wpabuf_alloc(200);
+	if (cred == NULL)
+		return -1;
+
+	if (wps_build_credential(cred, &wps->cred)) {
+		wpabuf_free(cred);
+		return -1;
+	}
+
+	wpabuf_put_be16(msg, ATTR_CRED);
+	wpabuf_put_be16(msg, wpabuf_len(cred));
+	wpabuf_put_buf(msg, cred);
+	wpabuf_free(cred);
+
+	return 0;
+}
+
+
+static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *msg)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * AP Settings");
+
+	if (wps_build_credential(msg, &wps->cred))
+		return -1;
+
+	return 0;
+}
+
+
+static struct wpabuf * wps_build_m2(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	if (os_get_random(wps->nonce_r, WPS_NONCE_LEN) < 0)
+		return NULL;
+	wpa_hexdump(MSG_DEBUG, "WPS: Registrar Nonce",
+		    wps->nonce_r, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-R", wps->uuid_r, WPS_UUID_LEN);
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M2");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M2) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_uuid_r(wps, msg) ||
+	    wps_build_public_key(wps, msg) ||
+	    wps_derive_keys(wps) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_config_error(msg, WPS_CFG_NO_ERROR) ||
+	    wps_build_dev_password_id(msg, DEV_PW_DEFAULT) ||
+	    wps_build_os_version(&wps->wps->dev, msg) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M3;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m2d(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+	u16 err = WPS_CFG_NO_ERROR;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps->wps->ap && wps->wps->ap_setup_locked)
+		err = WPS_CFG_SETUP_LOCKED;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M2D) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_uuid_r(wps, msg) ||
+	    wps_build_auth_type_flags(wps, msg) ||
+	    wps_build_encr_type_flags(wps, msg) ||
+	    wps_build_conn_type_flags(wps, msg) ||
+	    wps_build_config_methods_r(wps->wps->registrar, msg) ||
+	    wps_build_device_attrs(&wps->wps->dev, msg) ||
+	    wps_build_rf_bands(&wps->wps->dev, msg) ||
+	    wps_build_assoc_state(wps, msg) ||
+	    wps_build_config_error(msg, err) ||
+	    wps_build_os_version(&wps->wps->dev, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wps->state = RECV_M2D_ACK;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m4(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M4");
+
+	wps_derive_psk(wps, wps->dev_password, wps->dev_password_len);
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M4) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_r_hash(wps, msg) ||
+	    wps_build_r_snonce1(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    wps_build_encr_settings(wps, msg, plain) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_M5;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m6(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M6");
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M6) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_r_snonce2(wps, plain) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    wps_build_encr_settings(wps, msg, plain) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->wps_pin_revealed = 1;
+	wps->state = RECV_M7;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_m8(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message M8");
+
+	plain = wpabuf_alloc(500);
+	if (plain == NULL)
+		return NULL;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL) {
+		wpabuf_free(plain);
+		return NULL;
+	}
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_M8) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    (wps->wps->ap && wps_build_cred(wps, plain)) ||
+	    (!wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
+	    wps_build_key_wrap_auth(wps, plain) ||
+	    wps_build_encr_settings(wps, msg, plain) ||
+	    wps_build_authenticator(wps, msg)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+	wpabuf_free(plain);
+
+	wps->state = RECV_DONE;
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_ACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
+{
+	struct wpabuf *msg;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	if (wps_build_version(msg) ||
+	    wps_build_msg_type(msg, WPS_WSC_NACK) ||
+	    wps_build_enrollee_nonce(wps, msg) ||
+	    wps_build_registrar_nonce(wps, msg) ||
+	    wps_build_config_error(msg, wps->config_error)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
+				      enum wsc_op_code *op_code)
+{
+	struct wpabuf *msg;
+
+	switch (wps->state) {
+	case SEND_M2:
+		if (wps_get_dev_password(wps) < 0)
+			msg = wps_build_m2d(wps);
+		else
+			msg = wps_build_m2(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M2D:
+		msg = wps_build_m2d(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M4:
+		msg = wps_build_m4(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M6:
+		msg = wps_build_m6(wps);
+		*op_code = WSC_MSG;
+		break;
+	case SEND_M8:
+		msg = wps_build_m8(wps);
+		*op_code = WSC_MSG;
+		break;
+	case RECV_DONE:
+		msg = wps_build_wsc_ack(wps);
+		*op_code = WSC_ACK;
+		break;
+	case SEND_WSC_NACK:
+		msg = wps_build_wsc_nack(wps);
+		*op_code = WSC_NACK;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported state %d for building "
+			   "a message", wps->state);
+		msg = NULL;
+		break;
+	}
+
+	if (*op_code == WSC_MSG && msg) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return msg;
+}
+
+
+static int wps_process_enrollee_nonce(struct wps_data *wps, const u8 *e_nonce)
+{
+	if (e_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Enrollee Nonce received");
+		return -1;
+	}
+
+	os_memcpy(wps->nonce_e, e_nonce, WPS_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: Enrollee Nonce",
+		    wps->nonce_e, WPS_NONCE_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_registrar_nonce(struct wps_data *wps, const u8 *r_nonce)
+{
+	if (r_nonce == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Registrar Nonce received");
+		return -1;
+	}
+
+	if (os_memcmp(wps->nonce_r, r_nonce, WPS_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce received");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_uuid_e(struct wps_data *wps, const u8 *uuid_e)
+{
+	if (uuid_e == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No UUID-E received");
+		return -1;
+	}
+
+	os_memcpy(wps->uuid_e, uuid_e, WPS_UUID_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: UUID-E", wps->uuid_e, WPS_UUID_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_dev_password_id(struct wps_data *wps, const u8 *pw_id)
+{
+	if (pw_id == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Device Password ID received");
+		return -1;
+	}
+
+	wps->dev_pw_id = WPA_GET_BE16(pw_id);
+	wpa_printf(MSG_DEBUG, "WPS: Device Password ID %d", wps->dev_pw_id);
+
+	return 0;
+}
+
+
+static int wps_process_e_hash1(struct wps_data *wps, const u8 *e_hash1)
+{
+	if (e_hash1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-Hash1 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash1, e_hash1, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", wps->peer_hash1, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_e_hash2(struct wps_data *wps, const u8 *e_hash2)
+{
+	if (e_hash2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-Hash2 received");
+		return -1;
+	}
+
+	os_memcpy(wps->peer_hash2, e_hash2, WPS_HASH_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", wps->peer_hash2, WPS_HASH_LEN);
+
+	return 0;
+}
+
+
+static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (e_snonce1 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce1 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce1", e_snonce1,
+			WPS_SECRET_NONCE_LEN);
+
+	/* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */
+	addr[0] = e_snonce1;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk1;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does "
+			   "not match with the pre-committed value");
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the first "
+		   "half of the device password");
+
+	return 0;
+}
+
+
+static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2)
+{
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+
+	if (e_snonce2 == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No E-SNonce2 received");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: E-SNonce2", e_snonce2,
+			WPS_SECRET_NONCE_LEN);
+
+	/* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */
+	addr[0] = e_snonce2;
+	len[0] = WPS_SECRET_NONCE_LEN;
+	addr[1] = wps->psk2;
+	len[1] = WPS_PSK_LEN;
+	addr[2] = wpabuf_head(wps->dh_pubkey_e);
+	len[2] = wpabuf_len(wps->dh_pubkey_e);
+	addr[3] = wpabuf_head(wps->dh_pubkey_r);
+	len[3] = wpabuf_len(wps->dh_pubkey_r);
+	hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash);
+
+	if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does "
+			   "not match with the pre-committed value");
+		wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e);
+		wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee proved knowledge of the second "
+		   "half of the device password");
+	wps->wps_pin_revealed = 0;
+	wps_registrar_unlock_pin(wps->wps->registrar, wps->uuid_e);
+
+	return 0;
+}
+
+
+static int wps_process_mac_addr(struct wps_data *wps, const u8 *mac_addr)
+{
+	if (mac_addr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No MAC Address received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee MAC Address " MACSTR,
+		   MAC2STR(mac_addr));
+	os_memcpy(wps->mac_addr_e, mac_addr, ETH_ALEN);
+	os_memcpy(wps->peer_dev.mac_addr, mac_addr, ETH_ALEN);
+
+	return 0;
+}
+
+
+static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
+			      size_t pk_len)
+{
+	if (pk == NULL || pk_len == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No Public Key received");
+		return -1;
+	}
+
+	wpabuf_free(wps->dh_pubkey_e);
+	wps->dh_pubkey_e = wpabuf_alloc_copy(pk, pk_len);
+	if (wps->dh_pubkey_e == NULL)
+		return -1;
+
+	return 0;
+}
+
+
+static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
+{
+	u16 auth_types;
+
+	if (auth == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Authentication Type flags "
+			   "received");
+		return -1;
+	}
+
+	auth_types = WPA_GET_BE16(auth);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Authentication Type flags 0x%x",
+		   auth_types);
+	wps->auth_type = wps->wps->auth_types & auth_types;
+	if (wps->auth_type == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
+			   "authentication types (own 0x%x Enrollee 0x%x)",
+			   wps->wps->auth_types, auth_types);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
+{
+	u16 encr_types;
+
+	if (encr == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Encryption Type flags "
+			   "received");
+		return -1;
+	}
+
+	encr_types = WPA_GET_BE16(encr);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Encryption Type flags 0x%x",
+		   encr_types);
+	wps->encr_type = wps->wps->encr_types & encr_types;
+	if (wps->encr_type == 0) {
+		wpa_printf(MSG_DEBUG, "WPS: No match in supported "
+			   "encryption types");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wps_process_conn_type_flags(struct wps_data *wps, const u8 *conn)
+{
+	if (conn == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Connection Type flags "
+			   "received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Connection Type flags 0x%x",
+		   *conn);
+
+	return 0;
+}
+
+
+static int wps_process_config_methods(struct wps_data *wps, const u8 *methods)
+{
+	u16 m;
+
+	if (methods == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Config Methods received");
+		return -1;
+	}
+
+	m = WPA_GET_BE16(methods);
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Config Methods 0x%x", m);
+
+	return 0;
+}
+
+
+static int wps_process_wps_state(struct wps_data *wps, const u8 *state)
+{
+	if (state == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Wi-Fi Protected Setup State "
+			   "received");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Wi-Fi Protected Setup State %d",
+		   *state);
+
+	return 0;
+}
+
+
+static int wps_process_assoc_state(struct wps_data *wps, const u8 *assoc)
+{
+	u16 a;
+
+	if (assoc == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Association State received");
+		return -1;
+	}
+
+	a = WPA_GET_BE16(assoc);
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Association State %d", a);
+
+	return 0;
+}
+
+
+static int wps_process_config_error(struct wps_data *wps, const u8 *err)
+{
+	u16 e;
+
+	if (err == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error received");
+		return -1;
+	}
+
+	e = WPA_GET_BE16(err);
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee Configuration Error %d", e);
+
+	return 0;
+}
+
+
+static enum wps_process_res wps_process_m1(struct wps_data *wps,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M1");
+
+	if (wps->state != RECV_M1) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M1", wps->state);
+		return WPS_FAILURE;
+	}
+
+	if (wps_process_uuid_e(wps, attr->uuid_e) ||
+	    wps_process_mac_addr(wps, attr->mac_addr) ||
+	    wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
+	    wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
+	    wps_process_auth_type_flags(wps, attr->auth_type_flags) ||
+	    wps_process_encr_type_flags(wps, attr->encr_type_flags) ||
+	    wps_process_conn_type_flags(wps, attr->conn_type_flags) ||
+	    wps_process_config_methods(wps, attr->config_methods) ||
+	    wps_process_wps_state(wps, attr->wps_state) ||
+	    wps_process_device_attrs(&wps->peer_dev, attr) ||
+	    wps_process_rf_bands(&wps->peer_dev, attr->rf_bands) ||
+	    wps_process_assoc_state(wps, attr->assoc_state) ||
+	    wps_process_dev_password_id(wps, attr->dev_password_id) ||
+	    wps_process_config_error(wps, attr->config_error) ||
+	    wps_process_os_version(&wps->peer_dev, attr->os_version))
+		return WPS_FAILURE;
+
+	if (wps->dev_pw_id != DEV_PW_DEFAULT &&
+	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
+	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
+	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
+	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
+	     !wps->wps->registrar->pbc)) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
+			   wps->dev_pw_id);
+		wps->state = SEND_M2D;
+		return WPS_CONTINUE;
+	}
+
+	if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
+		if (wps_registrar_pbc_overlap(wps->wps->registrar,
+					      wps->mac_addr_e, wps->uuid_e)) {
+			wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
+				   "negotiation");
+			wps->state = SEND_M2D;
+			return WPS_CONTINUE;
+		}
+		wps_registrar_add_pbc_session(wps->wps->registrar,
+					      wps->mac_addr_e, wps->uuid_e);
+		wps->pbc = 1;
+	}
+
+	wps->state = SEND_M2;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m3(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received M3");
+
+	if (wps->state != RECV_M3) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M3", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg) ||
+	    wps_process_e_hash1(wps, attr->e_hash1) ||
+	    wps_process_e_hash2(wps, attr->e_hash2)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wps->state = SEND_M4;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_m5(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M5");
+
+	if (wps->state != RECV_M5) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M5", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_e_snonce1(wps, eattr.e_snonce1)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M6;
+	return WPS_CONTINUE;
+}
+
+
+static int wps_process_ap_settings_r(struct wps_data *wps,
+				     struct wps_parse_attr *attr)
+{
+	if (wps->wps->ap)
+		return 0;
+
+	/* AP Settings Attributes in M7 when Enrollee is an AP */
+	if (wps_process_ap_settings(attr, &wps->cred) < 0)
+		return -1;
+
+	wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
+
+	/*
+	 * TODO: Provide access to AP settings and allow changes before sending
+	 * out M8. For now, just copy the settings unchanged into M8.
+	 */
+
+	return 0;
+}
+
+
+static enum wps_process_res wps_process_m7(struct wps_data *wps,
+					   const struct wpabuf *msg,
+					   struct wps_parse_attr *attr)
+{
+	struct wpabuf *decrypted;
+	struct wps_parse_attr eattr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received M7");
+
+	if (wps->state != RECV_M7) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving M7", wps->state);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
+	    wps_process_authenticator(wps, attr->authenticator, msg)) {
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	decrypted = wps_decrypt_encr_settings(wps, attr->encr_settings,
+					      attr->encr_settings_len);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to decrypted Encrypted "
+			   "Settings attribute");
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
+		   "attribute");
+	if (wps_parse_msg(decrypted, &eattr) < 0 ||
+	    wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
+	    wps_process_e_snonce2(wps, eattr.e_snonce2) ||
+	    wps_process_ap_settings_r(wps, &eattr)) {
+		wpabuf_free(decrypted);
+		wps->state = SEND_WSC_NACK;
+		return WPS_CONTINUE;
+	}
+
+	wpabuf_free(decrypted);
+
+	wps->state = SEND_M8;
+	return WPS_CONTINUE;
+}
+
+
+static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	enum wps_process_res ret = WPS_CONTINUE;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_MSG");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_M1 &&
+	    (attr.registrar_nonce == NULL ||
+	     os_memcmp(wps->nonce_r, attr.registrar_nonce,
+		       WPS_NONCE_LEN != 0))) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	switch (*attr.msg_type) {
+	case WPS_M1:
+		ret = wps_process_m1(wps, &attr);
+		break;
+	case WPS_M3:
+		ret = wps_process_m3(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M3);
+		break;
+	case WPS_M5:
+		ret = wps_process_m5(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M5);
+		break;
+	case WPS_M7:
+		ret = wps_process_m7(wps, msg, &attr);
+		if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
+			wps_fail_event(wps->wps, WPS_M7);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (ret == WPS_CONTINUE) {
+		/* Save a copy of the last message for Authenticator derivation
+		 */
+		wpabuf_free(wps->last_msg);
+		wps->last_msg = wpabuf_dup(msg);
+	}
+
+	return ret;
+}
+
+
+static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps,
+						const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_ACK");
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_ACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (wps->state == RECV_M2D_ACK) {
+		/* TODO: support for multiple registrars and sending of
+		 * multiple M2/M2D messages */
+
+		wpa_printf(MSG_DEBUG, "WPS: No more registrars available - "
+			   "terminate negotiation");
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+	int old_state;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_NACK");
+
+	old_state = wps->state;
+	wps->state = SEND_WSC_NACK;
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_NACK) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.config_error == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Configuration Error attribute "
+			   "in WSC_NACK");
+		return WPS_FAILURE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Enrollee terminated negotiation with "
+		   "Configuration Error %d", WPA_GET_BE16(attr.config_error));
+
+	switch (old_state) {
+	case RECV_M3:
+		wps_fail_event(wps->wps, WPS_M2);
+		break;
+	case RECV_M5:
+		wps_fail_event(wps->wps, WPS_M4);
+		break;
+	case RECV_M7:
+		wps_fail_event(wps->wps, WPS_M6);
+		break;
+	case RECV_DONE:
+		wps_fail_event(wps->wps, WPS_M8);
+		break;
+	default:
+		break;
+	}
+
+	return WPS_FAILURE;
+}
+
+
+static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
+						 const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	wpa_printf(MSG_DEBUG, "WPS: Received WSC_Done");
+
+	if (wps->state != RECV_DONE) {
+		wpa_printf(MSG_DEBUG, "WPS: Unexpected state (%d) for "
+			   "receiving WSC_Done", wps->state);
+		return WPS_FAILURE;
+	}
+
+	if (wps_parse_msg(msg, &attr) < 0)
+		return WPS_FAILURE;
+
+	if (attr.version == NULL || *attr.version != WPS_VERSION) {
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
+			   attr.version ? *attr.version : 0);
+		return WPS_FAILURE;
+	}
+
+	if (attr.msg_type == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute");
+		return WPS_FAILURE;
+	}
+
+	if (*attr.msg_type != WPS_WSC_DONE) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type %d",
+			   *attr.msg_type);
+		return WPS_FAILURE;
+	}
+
+	if (attr.registrar_nonce == NULL ||
+	    os_memcmp(wps->nonce_r, attr.registrar_nonce, WPS_NONCE_LEN != 0))
+	{
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in registrar nonce");
+		return WPS_FAILURE;
+	}
+
+	if (attr.enrollee_nonce == NULL ||
+	    os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) {
+		wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce");
+		return WPS_FAILURE;
+	}
+
+	wpa_printf(MSG_DEBUG, "WPS: Negotiation completed successfully");
+
+	if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->new_psk &&
+	    wps->wps->ap) {
+		struct wps_credential cred;
+
+		wpa_printf(MSG_DEBUG, "WPS: Moving to Configured state based "
+			   "on first Enrollee connection");
+
+		os_memset(&cred, 0, sizeof(cred));
+		os_memcpy(cred.ssid, wps->wps->ssid, wps->wps->ssid_len);
+		cred.ssid_len = wps->wps->ssid_len;
+		cred.auth_type = WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK;
+		cred.encr_type = WPS_ENCR_TKIP | WPS_ENCR_AES;
+		os_memcpy(cred.key, wps->new_psk, wps->new_psk_len);
+		cred.key_len = wps->new_psk_len;
+
+		wps->wps->wps_state = WPS_STATE_CONFIGURED;
+		wpa_hexdump_ascii_key(MSG_DEBUG,
+				      "WPS: Generated random passphrase",
+				      wps->new_psk, wps->new_psk_len);
+		if (wps->wps->cred_cb)
+			wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+
+		os_free(wps->new_psk);
+		wps->new_psk = NULL;
+	}
+
+	if (!wps->wps->ap) {
+		wpa_printf(MSG_DEBUG, "WPS: Update local configuration based "
+			   "on the modified AP configuration");
+		if (wps->wps->cred_cb)
+			wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+	}
+
+	if (wps->new_psk) {
+		if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
+				   wps->new_psk, wps->new_psk_len)) {
+			wpa_printf(MSG_DEBUG, "WPS: Failed to configure the "
+				   "new PSK");
+		}
+		os_free(wps->new_psk);
+		wps->new_psk = NULL;
+	}
+
+	if (wps->pbc) {
+		wps_registrar_remove_pbc_session(wps->wps->registrar,
+						 wps->mac_addr_e, wps->uuid_e);
+		wps_registrar_pbc_completed(wps->wps->registrar);
+	}
+
+	wps_success_event(wps->wps);
+
+	return WPS_DONE;
+}
+
+
+enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
+					       enum wsc_op_code op_code,
+					       const struct wpabuf *msg)
+{
+	enum wps_process_res ret;
+
+	wpa_printf(MSG_DEBUG, "WPS: Processing received message (len=%lu "
+		   "op_code=%d)",
+		   (unsigned long) wpabuf_len(msg), op_code);
+
+	switch (op_code) {
+	case WSC_MSG:
+		return wps_process_wsc_msg(wps, msg);
+	case WSC_ACK:
+		return wps_process_wsc_ack(wps, msg);
+	case WSC_NACK:
+		return wps_process_wsc_nack(wps, msg);
+	case WSC_Done:
+		ret = wps_process_wsc_done(wps, msg);
+		if (ret == WPS_FAILURE) {
+			wps->state = SEND_WSC_NACK;
+			wps_fail_event(wps->wps, WPS_WSC_DONE);
+		}
+		return ret;
+	default:
+		wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
+		return WPS_FAILURE;
+	}
+}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ChangeLog Sat Jan 10 08:43:01 2009
@@ -1,4 +1,26 @@
 ChangeLog for wpa_supplicant
+
+2009-01-06 - v0.6.7
+	* added support for Wi-Fi Protected Setup (WPS)
+	  (wpa_supplicant can now be configured to act as a WPS Enrollee to
+	  enroll credentials for a network using PIN and PBC methods; in
+	  addition, wpa_supplicant can act as a wireless WPS Registrar to
+	  configure an AP); WPS support can be enabled by adding CONFIG_WPS=y
+	  into .config and setting the runtime configuration variables in
+	  wpa_supplicant.conf (see WPS section in the example configuration
+	  file); new wpa_cli commands wps_pin, wps_pbc, and wps_reg are used to
+	  manage WPS negotiation; see README-WPS for more details
+	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+	* added support for using driver_test over UDP socket
+	* fixed PEAPv0 Cryptobinding interoperability issue with Windows Server
+	  2008 NPS; optional cryptobinding is now enabled (again) by default
+	* fixed PSK editing in wpa_gui
+	* changed EAP-GPSK to use the IANA assigned EAP method type 51
+	* added a Windows installer that includes WinPcap and all the needed
+	  DLLs; in addition, it set up the registry automatically so that user
+	  will only need start wpa_gui to get prompted to start the wpasvc
+	  servide and add a new interface if needed through wpa_gui dialog
+	* updated management frame protection to use IEEE 802.11w/D7.0
 
 2008-11-23 - v0.6.6
 	* added Milenage SIM/USIM emulator for EAP-SIM/EAP-AKA

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/Makefile Sat Jan 10 08:43:01 2009
@@ -427,6 +427,16 @@
 CONFIG_EAP_SIM_COMMON=y
 endif
 
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+CFLAGS += -DEAP_AKA_PRIME
+endif
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_EAP_SIM_COMMON
 OBJS += ../src/eap_common/eap_sim_common.o
 OBJS_h += ../src/eap_server/eap_sim_db.o
@@ -491,6 +501,32 @@
 CFLAGS += -DEAP_GPSK_SHA256
 endif
 NEED_SHA256=y
+endif
+
+ifdef CONFIG_WPS
+# EAP-WSC
+ifeq ($(CONFIG_EAP_WSC), dyn)
+CFLAGS += -DCONFIG_WPS -DEAP_WSC_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_wsc.so
+else
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.o
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+OBJS_h += ../src/eap_server/eap_wsc.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
 endif
 
 ifdef CONFIG_EAP_IKEV2
@@ -1080,6 +1116,10 @@
 	$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
 		-Deap_peer_sake_register=eap_peer_method_dynamic_init
 
+eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
+	$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+		-Deap_peer_wsc_register=eap_peer_method_dynamic_init
+
 eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
 	$(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
 		-Deap_peer_ikev2_register=eap_peer_method_dynamic_init
@@ -1184,16 +1224,10 @@
 	cp doc/latex/refman.pdf wpa_supplicant-devel.pdf
 
 docs-fast: docs-pics
-	doxygen doc/doxygen.fast
+	(cd ..; doxygen wpa_supplicant/doc/doxygen.fast; cd wpa_supplicant)
 
 clean-docs:
 	rm -rf doc/latex doc/html
 	rm -f doc/wpa_supplicant.{eps,png} wpa_supplicant-devel.pdf
 
-wpa_supplicant-sparse: .config $(OBJS)
-	@echo Sparse run completed
-
-run-sparse:
-	CC="sparse -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -D__INT_MAX__=2147483647 -D__SHRT_MAX__=32767 -D__LONG_MAX__=2147483647 -D__SCHAR_MAX__=127 -Wbitwise" $(MAKE) wpa_supplicant-sparse
-
 -include $(OBJS:%.o=%.d)

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/README
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/README?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/README (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/README Sat Jan 10 08:43:01 2009
@@ -1,7 +1,7 @@
 WPA Supplicant
 ==============
 
-Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi> and contributors
+Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi> and contributors
 All Rights Reserved.
 
 This program is dual-licensed under both the GPL version 2 and BSD

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/README-WPS Sat Jan 10 08:43:01 2009
@@ -1,0 +1,165 @@
+wpa_supplicant and Wi-Fi Protected Setup (WPS)
+==============================================
+
+This document describes how the WPS implementation in wpa_supplicant
+can be configured and how an external component on the client (e.g.,
+management GUI) is used to enable WPS enrollment and registrar
+registration.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+  addition of new devices); this may be either in the AP ("internal
+  Registrar") or in an external device, e.g., a laptop, ("external
+  Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+wpa_supplicant implementation
+-----------------------------
+
+wpa_supplicant includes an optional WPS component that can be used as
+an Enrollee to enroll new network credential or as a Registrar to
+configure an AP. The current version of wpa_supplicant does not
+support operation as an external WLAN Management Registrar for adding
+new client devices or configuring the AP over UPnP.
+
+
+wpa_supplicant configuration
+----------------------------
+
+WPS is an optional component that needs to be enabled in
+wpa_supplicant build configuration (.config). Here is an example
+configuration that includes WPS support and Linux wireless extensions
+-based driver interface:
+
+CONFIG_DRIVER_WEXT=y
+CONFIG_EAP=y
+CONFIG_WPS=y
+
+
+WPS needs the Universally Unique IDentifier (UUID; see RFC 4122) for
+the device. This is configured in the runtime configuration for
+wpa_supplicant (if not set, UUID will be generated based on local MAC
+address):
+
+# example UUID for WPS
+uuid=12345678-9abc-def0-1234-56789abcdef0
+
+The network configuration blocks needed for WPS are added
+automatically based on control interface commands, so they do not need
+to be added explicitly in the configuration file.
+
+WPS registration will generate new network blocks for the acquired
+credentials. If these are to be stored for future use (after
+restarting wpa_supplicant), wpa_supplicant will need to be configured
+to allow configuration file updates:
+
+update_config=1
+
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. wpa_supplicant uses the control interface as an input channel
+for these events.
+
+If the client device has a display, a random PIN has to be generated
+for each WPS registration session. wpa_supplicant can do this with a
+control interface request, e.g., by calling wpa_cli:
+
+wpa_cli wps_pin any
+
+This will return the generated 8-digit PIN which will then need to be
+entered at the Registrar to complete WPS registration. At that point,
+the client will be enrolled with credentials needed to connect to the
+AP to access the network.
+
+
+If the client device does not have a display that could show the
+random PIN, a hardcoded PIN that is printed on a label can be
+used. wpa_supplicant is notified this with a control interface
+request, e.g., by calling wpa_cli:
+
+wpa_cli wps_pin any 12345670
+
+This starts the WPS negotiation in the same way as above with the
+generated PIN.
+
+
+If the client design wants to support optional WPS PBC mode, this can
+be enabled by either a physical button in the client device or a
+virtual button in the user interface. The PBC operation requires that
+a button is also pressed at the AP/Registrar at about the same time (2
+minute window). wpa_supplicant is notified of the local button event
+over the control interface, e.g., by calling wpa_cli:
+
+wpa_cli wps_pbc
+
+At this point, the AP/Registrar has two minutes to complete WPS
+negotiation which will generate a new WPA PSK in the same way as the
+PIN method described above.
+
+
+If the client wants to operation in the Registrar role to configure an
+AP, wpa_supplicant is notified over the control interface, e.g., with
+wpa_cli:
+
+wpa_cli wps_reg <AP BSSID> <AP PIN>
+(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
+
+
+Scanning
+--------
+
+Scan results ('wpa_cli scan_results' or 'wpa_cli bss <idx>') include a
+flags field that is used to indicate whether the BSS support WPS. If
+the AP support WPS, but has not recently activated a Registrar, [WPS]
+flag will be included. If PIN method has been recently selected,
+[WPS-PIN] is shown instead. Similarly, [WPS-PBC] is shown if PBC mode
+is in progress. GUI programs can use these as triggers for suggesting
+a guided WPS configuration to the user. In addition, control interface
+monitor events WPS-AP-AVAILABLE{,-PBC,-PIN} can be used to find out if
+there are WPS enabled APs in scan results without having to go through
+all the details in the GUI. These notification could be used, e.g., to
+suggest possible WPS connection to the user.
+
+
+wpa_gui
+-------
+
+wpa_gui-qt4 directory contains a sample GUI that shows an example of
+how WPS support can be integrated into the GUI. Its main window has a
+WPS tab that guides user through WPS registration with automatic AP
+selection. In addition, it shows how WPS can be started manually by
+selecting an AP from scan results.

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/README-Windows.txt
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/README-Windows.txt?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/README-Windows.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/README-Windows.txt Sat Jan 10 08:43:01 2009
@@ -1,8 +1,7 @@
 wpa_supplicant for Windows
 ==========================
 
-Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi> and
-contributors
+Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi> and contributors
 All Rights Reserved.
 
 This program is dual-licensed under both the GPL version 2 and BSD

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.c Sat Jan 10 08:43:01 2009
@@ -60,14 +60,19 @@
 static char * wpa_config_parse_string(const char *value, size_t *len)
 {
 	if (*value == '"') {
-		char *pos;
+		const char *pos;
+		char *str;
 		value++;
 		pos = os_strrchr(value, '"');
 		if (pos == NULL || pos[1] != '\0')
 			return NULL;
-		*pos = '\0';
-		*len = os_strlen(value);
-		return os_strdup(value);
+		*len = pos - value;
+		str = os_malloc(*len + 1);
+		if (str == NULL)
+			return NULL;
+		os_memcpy(str, value, *len);
+		str[*len] = '\0';
+		return str;
 	} else {
 		u8 *str;
 		size_t tlen, hlen = os_strlen(value);
@@ -515,6 +520,10 @@
 		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
 			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+		else if (os_strcmp(start, "WPS") == 0)
+			val |= WPA_KEY_MGMT_WPS;
+#endif /* CONFIG_WPS */
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -620,6 +629,12 @@
 		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
 				   pos == buf ? "" : " ");
 #endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WPS
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		pos += os_snprintf(pos, end - pos, "%sWPS",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_WPS */
 
 	return buf;
 }
@@ -1034,8 +1049,8 @@
 				   "password.", line);
 			return -1;
 		}
-		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
-				  (u8 *) tmp, res_len);
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+				      (u8 *) tmp, res_len);
 
 		os_free(ssid->eap.password);
 		ssid->eap.password = (u8 *) tmp;
@@ -1306,7 +1321,7 @@
 	{ FUNC(eap) },
 	{ STR_LENe(identity) },
 	{ STR_LENe(anonymous_identity) },
-	{ FUNC(password) },
+	{ FUNC_KEY(password) },
 	{ STRe(ca_cert) },
 	{ STRe(ca_path) },
 	{ STRe(client_cert) },
@@ -1567,6 +1582,12 @@
 	os_free(config->pkcs11_module_path);
 #endif /* EAP_TLS_OPENSSL */
 	os_free(config->driver_param);
+	os_free(config->device_name);
+	os_free(config->manufacturer);
+	os_free(config->model_name);
+	os_free(config->model_number);
+	os_free(config->serial_number);
+	os_free(config->device_type);
 	os_free(config->pssid);
 	os_free(config);
 }

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/config.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/config.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config.h Sat Jan 10 08:43:01 2009
@@ -154,7 +154,7 @@
 	 * ctrl_interface_group - Control interface group (DEPRECATED)
 	 *
 	 * This variable is only used for backwards compatibility. Group for
-	 * UNIX domain sockets should now be specified using GROUP=<group> in
+	 * UNIX domain sockets should now be specified using GROUP=group in
 	 * ctrl_interface variable.
 	 */
 	char *ctrl_interface_group;
@@ -247,6 +247,71 @@
 	 * blobs - Configuration blobs
 	 */
 	struct wpa_config_blob *blobs;
+
+	/**
+	 * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS
+	 */
+	u8 uuid[16];
+
+	/**
+	 * device_name - Device Name (WPS)
+	 * User-friendly description of device; up to 32 octets encoded in
+	 * UTF-8
+	 */
+	char *device_name;
+
+	/**
+	 * manufacturer - Manufacturer (WPS)
+	 * The manufacturer of the device (up to 64 ASCII characters)
+	 */
+	char *manufacturer;
+
+	/**
+	 * model_name - Model Name (WPS)
+	 * Model of the device (up to 32 ASCII characters)
+	 */
+	char *model_name;
+
+	/**
+	 * model_number - Model Number (WPS)
+	 * Additional device description (up to 32 ASCII characters)
+	 */
+	char *model_number;
+
+	/**
+	 * serial_number - Serial Number (WPS)
+	 * Serial number of the device (up to 32 characters)
+	 */
+	char *serial_number;
+
+	/**
+	 * device_type - Primary Device Type (WPS)
+	 * Used format: categ-OUI-subcateg
+	 * categ = Category as an integer value
+	 * OUI = OUI and type octet as a 4-octet hex-encoded value;
+	 *	0050F204 for default WPS OUI
+	 * subcateg = OUI-specific Sub Category as an integer value
+	 * Examples:
+	 *   1-0050F204-1 (Computer / PC)
+	 *   1-0050F204-2 (Computer / Server)
+	 *   5-0050F204-1 (Storage / NAS)
+	 *   6-0050F204-1 (Network Infrastructure / AP)
+	 */
+	char *device_type;
+
+	/**
+	 * os_version - OS Version (WPS)
+	 * 4-octet operating system version number
+	 */
+	u8 os_version[4];
+
+	/**
+	 * country - Country code
+	 *
+	 * This is the ISO/IEC alpha2 country code for which we are operating
+	 * in
+	 */
+	char country[2];
 };
 
 

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_file.c Sat Jan 10 08:43:01 2009
@@ -21,6 +21,7 @@
 #include "common.h"
 #include "config.h"
 #include "base64.h"
+#include "uuid.h"
 #include "eap_peer/eap_methods.h"
 
 
@@ -269,147 +270,97 @@
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 
 
-#ifdef CONFIG_CTRL_IFACE
-static int wpa_config_process_ctrl_interface(struct wpa_config *config,
-					     char *pos)
-{
-	os_free(config->ctrl_interface);
-	config->ctrl_interface = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "ctrl_interface='%s'", config->ctrl_interface);
+struct global_parse_data {
+	char *name;
+	int (*parser)(const struct global_parse_data *data,
+		      struct wpa_config *config, int line, const char *value);
+	void *param1, *param2, *param3;
+};
+
+
+static int wpa_config_parse_int(const struct global_parse_data *data,
+				struct wpa_config *config, int line,
+				const char *pos)
+{
+	int *dst;
+	dst = (int *) (((u8 *) config) + (long) data->param1);
+	*dst = atoi(pos);
+	wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
+
+	if (data->param2 && *dst < (long) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+			   "min_value=%ld)", line, data->name, *dst,
+			   (long) data->param2);
+		*dst = (long) data->param2;
+		return -1;
+	}
+
+	if (data->param3 && *dst > (long) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+			   "max_value=%ld)", line, data->name, *dst,
+			   (long) data->param3);
+		*dst = (long) data->param3;
+		return -1;
+	}
+
 	return 0;
 }
 
 
-static int wpa_config_process_ctrl_interface_group(struct wpa_config *config,
-						   char *pos)
-{
-	os_free(config->ctrl_interface_group);
-	config->ctrl_interface_group = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "ctrl_interface_group='%s' (DEPRECATED)",
-		   config->ctrl_interface_group);
+static int wpa_config_parse_str(const struct global_parse_data *data,
+				struct wpa_config *config, int line,
+				const char *pos)
+{
+	size_t len;
+	char **dst, *tmp;
+
+	len = os_strlen(pos);
+	if (data->param2 && len < (size_t) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+			   "min_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param2);
+		return -1;
+	}
+
+	if (data->param3 && len > (size_t) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+			   "max_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param3);
+		return -1;
+	}
+
+	tmp = os_strdup(pos);
+	if (tmp == NULL)
+		return -1;
+
+	dst = (char **) (((u8 *) config) + (long) data->param1);
+	os_free(*dst);
+	*dst = tmp;
+	wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
+
 	return 0;
 }
-#endif /* CONFIG_CTRL_IFACE */
-
-
-static int wpa_config_process_eapol_version(struct wpa_config *config,
-					    int line, char *pos)
-{
-	config->eapol_version = atoi(pos);
-	if (config->eapol_version < 1 || config->eapol_version > 2) {
-		wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL version (%d): "
-			   "'%s'.", line, config->eapol_version, pos);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "eapol_version=%d", config->eapol_version);
+
+
+static int wpa_config_process_country(const struct global_parse_data *data,
+				      struct wpa_config *config, int line,
+				      const char *pos)
+{
+	if (!pos[0] || !pos[1]) {
+		wpa_printf(MSG_DEBUG, "Invalid country set");
+		return -1;
+	}
+	config->country[0] = pos[0];
+	config->country[1] = pos[1];
+	wpa_printf(MSG_DEBUG, "country='%c%c'",
+		   config->country[0], config->country[1]);
 	return 0;
 }
 
 
-static int wpa_config_process_ap_scan(struct wpa_config *config, char *pos)
-{
-	config->ap_scan = atoi(pos);
-	wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
-	return 0;
-}
-
-
-static int wpa_config_process_fast_reauth(struct wpa_config *config, char *pos)
-{
-	config->fast_reauth = atoi(pos);
-	wpa_printf(MSG_DEBUG, "fast_reauth=%d", config->fast_reauth);
-	return 0;
-}
-
-
-#ifdef EAP_TLS_OPENSSL
-
-static int wpa_config_process_opensc_engine_path(struct wpa_config *config,
-						 char *pos)
-{
-	os_free(config->opensc_engine_path);
-	config->opensc_engine_path = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "opensc_engine_path='%s'",
-		   config->opensc_engine_path);
-	return 0;
-}
-
-
-static int wpa_config_process_pkcs11_engine_path(struct wpa_config *config,
-						 char *pos)
-{
-	os_free(config->pkcs11_engine_path);
-	config->pkcs11_engine_path = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "pkcs11_engine_path='%s'",
-		   config->pkcs11_engine_path);
-	return 0;
-}
-
-
-static int wpa_config_process_pkcs11_module_path(struct wpa_config *config,
-						 char *pos)
-{
-	os_free(config->pkcs11_module_path);
-	config->pkcs11_module_path = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "pkcs11_module_path='%s'",
-		   config->pkcs11_module_path);
-	return 0;
-}
-
-#endif /* EAP_TLS_OPENSSL */
-
-
-static int wpa_config_process_driver_param(struct wpa_config *config,
-					   char *pos)
-{
-	os_free(config->driver_param);
-	config->driver_param = os_strdup(pos);
-	wpa_printf(MSG_DEBUG, "driver_param='%s'", config->driver_param);
-	return 0;
-}
-
-
-static int wpa_config_process_pmk_lifetime(struct wpa_config *config,
-					   char *pos)
-{
-	config->dot11RSNAConfigPMKLifetime = atoi(pos);
-	wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKLifetime=%d",
-		   config->dot11RSNAConfigPMKLifetime);
-	return 0;
-}
-
-
-static int wpa_config_process_pmk_reauth_threshold(struct wpa_config *config,
-						   char *pos)
-{
-	config->dot11RSNAConfigPMKReauthThreshold = atoi(pos);
-	wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKReauthThreshold=%d",
-		   config->dot11RSNAConfigPMKReauthThreshold);
-	return 0;
-}
-
-
-static int wpa_config_process_sa_timeout(struct wpa_config *config, char *pos)
-{
-	config->dot11RSNAConfigSATimeout = atoi(pos);
-	wpa_printf(MSG_DEBUG, "dot11RSNAConfigSATimeout=%d",
-		   config->dot11RSNAConfigSATimeout);
-	return 0;
-}
-
-
-#ifndef CONFIG_NO_CONFIG_WRITE
-static int wpa_config_process_update_config(struct wpa_config *config,
-					    char *pos)
-{
-	config->update_config = atoi(pos);
-	wpa_printf(MSG_DEBUG, "update_config=%d", config->update_config);
-	return 0;
-}
-#endif /* CONFIG_NO_CONFIG_WRITE */
-
-
-static int wpa_config_process_load_dynamic_eap(int line, char *so)
+static int wpa_config_process_load_dynamic_eap(
+	const struct global_parse_data *data, struct wpa_config *config,
+	int line, const char *so)
 {
 	int ret;
 	wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
@@ -427,61 +378,125 @@
 }
 
 
+#ifdef CONFIG_WPS
+
+static int wpa_config_process_uuid(const struct global_parse_data *data,
+				   struct wpa_config *config, int line,
+				   const char *pos)
+{
+	char buf[40];
+	if (uuid_str2bin(pos, config->uuid)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
+		return -1;
+	}
+	uuid_bin2str(config->uuid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "uuid=%s", buf);
+	return 0;
+}
+
+
+static int wpa_config_process_os_version(const struct global_parse_data *data,
+					 struct wpa_config *config, int line,
+					 const char *pos)
+{
+	if (hexstr2bin(pos, config->os_version, 4)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "os_version=%08x",
+		   WPA_GET_BE32(config->os_version));
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_config structure */
+#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
+
+#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
+#define _INT(f) #f, wpa_config_parse_int, OFFSET(f)
+#define INT(f) _INT(f), NULL, NULL
+#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
+#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL
+#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+
+static const struct global_parse_data global_fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+	{ STR(ctrl_interface) },
+	{ STR(ctrl_interface_group) } /* deprecated */,
+#endif /* CONFIG_CTRL_IFACE */
+	{ INT_RANGE(eapol_version, 1, 2) },
+	{ INT(ap_scan) },
+	{ INT(fast_reauth) },
+#ifdef EAP_TLS_OPENSSL
+	{ STR(opensc_engine_path) },
+	{ STR(pkcs11_engine_path) },
+	{ STR(pkcs11_module_path) },
+#endif /* EAP_TLS_OPENSSL */
+	{ STR(driver_param) },
+	{ INT(dot11RSNAConfigPMKLifetime) },
+	{ INT(dot11RSNAConfigPMKReauthThreshold) },
+	{ INT(dot11RSNAConfigSATimeout) },
+#ifndef CONFIG_NO_CONFIG_WRITE
+	{ INT(update_config) },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	{ FUNC_NO_VAR(load_dynamic_eap) },
+#ifdef CONFIG_WPS
+	{ FUNC(uuid) },
+	{ STR_RANGE(device_name, 0, 32) },
+	{ STR_RANGE(manufacturer, 0, 64) },
+	{ STR_RANGE(model_name, 0, 32) },
+	{ STR_RANGE(model_number, 0, 32) },
+	{ STR_RANGE(serial_number, 0, 32) },
+	{ STR(device_type) },
+	{ FUNC(os_version) },
+#endif /* CONFIG_WPS */
+	{ FUNC(country) }
+};
+
+#undef FUNC
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _STR
+#undef STR
+#undef STR_RANGE
+#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+
+
 static int wpa_config_process_global(struct wpa_config *config, char *pos,
 				     int line)
 {
-#ifdef CONFIG_CTRL_IFACE
-	if (os_strncmp(pos, "ctrl_interface=", 15) == 0)
-		return wpa_config_process_ctrl_interface(config, pos + 15);
-
-	if (os_strncmp(pos, "ctrl_interface_group=", 21) == 0)
-		return wpa_config_process_ctrl_interface_group(config,
-							       pos + 21);
-#endif /* CONFIG_CTRL_IFACE */
-
-	if (os_strncmp(pos, "eapol_version=", 14) == 0)
-		return wpa_config_process_eapol_version(config, line,
-							pos + 14);
-
-	if (os_strncmp(pos, "ap_scan=", 8) == 0)
-		return wpa_config_process_ap_scan(config, pos + 8);
-
-	if (os_strncmp(pos, "fast_reauth=", 12) == 0)
-		return wpa_config_process_fast_reauth(config, pos + 12);
-
-#ifdef EAP_TLS_OPENSSL
-	if (os_strncmp(pos, "opensc_engine_path=", 19) == 0)
-		return wpa_config_process_opensc_engine_path(config, pos + 19);
-
-	if (os_strncmp(pos, "pkcs11_engine_path=", 19) == 0)
-		return wpa_config_process_pkcs11_engine_path(config, pos + 19);
-
-	if (os_strncmp(pos, "pkcs11_module_path=", 19) == 0)
-		return wpa_config_process_pkcs11_module_path(config, pos + 19);
-#endif /* EAP_TLS_OPENSSL */
-
-	if (os_strncmp(pos, "driver_param=", 13) == 0)
-		return wpa_config_process_driver_param(config, pos + 13);
-
-	if (os_strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27) == 0)
-		return wpa_config_process_pmk_lifetime(config, pos + 27);
-
-	if (os_strncmp(pos, "dot11RSNAConfigPMKReauthThreshold=", 34) == 0)
-		return wpa_config_process_pmk_reauth_threshold(config,
-							       pos + 34);
-
-	if (os_strncmp(pos, "dot11RSNAConfigSATimeout=", 25) == 0)
-		return wpa_config_process_sa_timeout(config, pos + 25);
-
-#ifndef CONFIG_NO_CONFIG_WRITE
-	if (os_strncmp(pos, "update_config=", 14) == 0)
-		return wpa_config_process_update_config(config, pos + 14);
-#endif /* CONFIG_NO_CONFIG_WRITE */
-
-	if (os_strncmp(pos, "load_dynamic_eap=", 17) == 0)
-		return wpa_config_process_load_dynamic_eap(line, pos + 17);
-
-	return -1;
+	size_t i;
+	int ret = 0;
+
+	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+		const struct global_parse_data *field = &global_fields[i];
+		size_t flen = os_strlen(field->name);
+		if (os_strncmp(pos, field->name, flen) != 0 ||
+		    pos[flen] != '=')
+			continue;
+
+		if (field->parser(field, config, line, pos + flen + 1)) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to "
+				   "parse '%s'.", line, pos);
+			ret = -1;
+		}
+		break;
+	}
+	if (i == NUM_GLOBAL_FIELDS) {
+		wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
+			   line, pos);
+		ret = -1;
+	}
+
+	return ret;
 }
 
 
@@ -845,6 +860,32 @@
 			config->dot11RSNAConfigSATimeout);
 	if (config->update_config)
 		fprintf(f, "update_config=%d\n", config->update_config);
+#ifdef CONFIG_WPS
+	if (!is_nil_uuid(config->uuid)) {
+		char buf[40];
+		uuid_bin2str(config->uuid, buf, sizeof(buf));
+		fprintf(f, "uuid=%s\n", buf);
+	}
+	if (config->device_name)
+		fprintf(f, "device_name=%s\n", config->device_name);
+	if (config->manufacturer)
+		fprintf(f, "manufacturer=%s\n", config->manufacturer);
+	if (config->model_name)
+		fprintf(f, "model_name=%s\n", config->model_name);
+	if (config->model_number)
+		fprintf(f, "model_number=%s\n", config->model_number);
+	if (config->serial_number)
+		fprintf(f, "serial_number=%s\n", config->serial_number);
+	if (config->device_type)
+		fprintf(f, "device_type=%s\n", config->device_type);
+	if (WPA_GET_BE32(config->os_version))
+		fprintf(f, "os_version=%08x\n",
+			WPA_GET_BE32(config->os_version));
+#endif /* CONFIG_WPS */
+	if (config->country[0] && config->country[1]) {
+		fprintf(f, "country=%c%c\n",
+			config->country[0], config->country[1]);
+	}
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -871,6 +912,8 @@
 	wpa_config_write_global(f, config);
 
 	for (ssid = config->ssid; ssid; ssid = ssid->next) {
+		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+			continue; /* do not save temporary WPS networks */
 		fprintf(f, "\nnetwork={\n");
 		wpa_config_write_network(f, ssid);
 		fprintf(f, "}\n");

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/config_winreg.c Sat Jan 10 08:43:01 2009
@@ -11,12 +11,13 @@
  *
  * See README and COPYING for more details.
  *
- * This file implements a configuration backend for Windows registry.. All the
+ * This file implements a configuration backend for Windows registry. All the
  * configuration information is stored in the registry and the format for
  * network configuration fields is same as described in the sample
  * configuration file, wpa_supplicant.conf.
  *
- * Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs
+ * Configuration data is in
+ * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
  * key. Each configuration profile has its own key under this. In terms of text
  * files, each profile would map to a separate text file with possibly multiple
  * networks. Under each profile, there is a networks key that lists all
@@ -24,14 +25,18 @@
  * network block in the configuration file. In addition, blobs subkey has
  * possible blobs as values.
  *
- * HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
- *    ssid="example"
- *    key_mgmt=WPA-PSK
+ * Example network configuration block:
+ * \verbatim
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+   ssid="example"
+   key_mgmt=WPA-PSK
+\endverbatim
  */
 
 #include "includes.h"
 
 #include "common.h"
+#include "uuid.h"
 #include "config.h"
 
 #ifndef WPA_KEY_ROOT
@@ -161,6 +166,45 @@
 }
 
 
+#ifdef CONFIG_WPS
+static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
+{
+	char *str;
+	int ret = 0;
+
+	str = wpa_config_read_reg_string(hk, TEXT("uuid"));
+	if (str == NULL)
+		return 0;
+
+	if (uuid_str2bin(str, config->uuid))
+		ret = -1;
+
+	os_free(str);
+
+	return ret;
+}
+
+
+static int wpa_config_read_global_os_version(struct wpa_config *config,
+					     HKEY hk)
+{
+	char *str;
+	int ret = 0;
+
+	str = wpa_config_read_reg_string(hk, TEXT("os_version"));
+	if (str == NULL)
+		return 0;
+
+	if (hexstr2bin(str, config->os_version, 4))
+		ret = -1;
+
+	os_free(str);
+
+	return ret;
+}
+#endif /* CONFIG_WPS */
+
+
 static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
 {
 	int errors = 0;
@@ -169,12 +213,13 @@
 	wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
 				  &config->fast_reauth);
 	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
-				  &config->dot11RSNAConfigPMKLifetime);
+				  (int *) &config->dot11RSNAConfigPMKLifetime);
 	wpa_config_read_reg_dword(hk,
 				  TEXT("dot11RSNAConfigPMKReauthThreshold"),
+				  (int *)
 				  &config->dot11RSNAConfigPMKReauthThreshold);
 	wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
-				  &config->dot11RSNAConfigSATimeout);
+				  (int *) &config->dot11RSNAConfigSATimeout);
 	wpa_config_read_reg_dword(hk, TEXT("update_config"),
 				  &config->update_config);
 
@@ -190,6 +235,23 @@
 
 	config->ctrl_interface = wpa_config_read_reg_string(
 		hk, TEXT("ctrl_interface"));
+
+#ifdef CONFIG_WPS
+	if (wpa_config_read_global_uuid(config, hk))
+		errors++;
+	config->device_name = wpa_config_read_reg_string(
+		hk, TEXT("device_name"));
+	config->manufacturer = wpa_config_read_reg_string(
+		hk, TEXT("manufacturer"));
+	config->model_name = wpa_config_read_reg_string(
+		hk, TEXT("model_name"));
+	config->serial_number = wpa_config_read_reg_string(
+		hk, TEXT("serial_number"));
+	config->device_type = wpa_config_read_reg_string(
+		hk, TEXT("device_type"));
+	if (wpa_config_read_global_os_version(config, hk))
+		errors++;
+#endif /* CONFIG_WPS */
 
 	return errors ? -1 : 0;
 }
@@ -492,6 +554,26 @@
 	wpa_config_write_reg_dword(hk, TEXT("update_config"),
 				   config->update_config,
 				   0);
+#ifdef CONFIG_WPS
+	if (!is_nil_uuid(config->uuid)) {
+		char buf[40];
+		uuid_bin2str(config->uuid, buf, sizeof(buf));
+		wpa_config_write_reg_string(hk, "uuid", buf);
+	}
+	wpa_config_write_reg_string(hk, "device_name", config->device_name);
+	wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
+	wpa_config_write_reg_string(hk, "model_name", config->model_name);
+	wpa_config_write_reg_string(hk, "model_number", config->model_number);
+	wpa_config_write_reg_string(hk, "serial_number",
+				    config->serial_number);
+	wpa_config_write_reg_string(hk, "device_type", config->device_type);
+	if (WPA_GET_BE32(config->os_version)) {
+		char vbuf[10];
+		os_snprintf(vbuf, sizeof(vbuf), "%08x",
+			    WPA_GET_BE32(config->os_version));
+		wpa_config_write_reg_string(hk, "os_version", vbuf);
+	}
+#endif /* CONFIG_WPS */
 
 	return 0;
 }
@@ -874,6 +956,8 @@
 
 	wpa_config_delete_subkeys(hk, TEXT("networks"));
 	for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+			continue; /* do not save temporary WPS networks */
 		if (wpa_config_write_network(hk, ssid, id))
 			errors++;
 	}

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface.c Sat Jan 10 08:43:01 2009
@@ -27,8 +27,11 @@
 #include "wpa_ctrl.h"
 #include "eap_peer/eap.h"
 #include "ieee802_11_defs.h"
-
-
+#include "wps_supplicant.h"
+#include "wps/wps.h"
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+					    char *buf, int len);
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
 						  char *buf, int len);
 
@@ -137,6 +140,91 @@
 	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap);
 }
 #endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_WPS
+static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN];
+
+	if (cmd == NULL || os_strcmp(cmd, "any") == 0)
+		return wpas_wps_start_pbc(wpa_s, NULL);
+
+	if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+	return wpas_wps_start_pbc(wpa_s, bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
+					     char *cmd, char *buf,
+					     size_t buflen)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+	char *pin;
+	int ret;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin)
+		*pin++ = '\0';
+
+	if (os_strcmp(cmd, "any") == 0)
+		_bssid = NULL;
+	else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+	if (pin) {
+		ret = wpas_wps_start_pin(wpa_s, _bssid, pin);
+		if (ret < 0)
+			return -1;
+		ret = os_snprintf(buf, buflen, "%s", pin);
+		if (ret < 0 || (size_t) ret >= buflen)
+			return -1;
+		return ret;
+	}
+
+	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL);
+	if (ret < 0)
+		return -1;
+
+	/* Return the generated PIN */
+	ret = os_snprintf(buf, buflen, "%08d", ret);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+	char *pin;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	if (os_strcmp(cmd, "any") == 0)
+		_bssid = NULL;
+	else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+	return wpas_wps_start_reg(wpa_s, _bssid, pin);
+}
+#endif /* CONFIG_WPS */
 
 
 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
@@ -528,6 +616,34 @@
 	return pos;
 }
 
+static char * wpa_supplicant_wps_ie_txt(char *pos, char *end,
+					const struct wpa_scan_res *res)
+{
+#ifdef CONFIG_WPS
+	struct wpabuf *wps_ie;
+	int ret;
+	const char *txt;
+
+	wps_ie = wpa_scan_get_vendor_ie_multi(res, WPS_IE_VENDOR_TYPE);
+	if (wps_ie == NULL)
+		return pos;
+
+	if (wps_is_selected_pbc_registrar(wps_ie))
+		txt = "[WPS-PBC]";
+	else if (wps_is_selected_pin_registrar(wps_ie))
+		txt = "[WPS-PIN]";
+	else
+		txt = "[WPS]";
+
+	ret = os_snprintf(pos, end - pos, "%s", txt);
+	if (ret >= 0 && ret < end - pos)
+		pos += ret;
+	wpabuf_free(wps_ie);
+#endif /* CONFIG_WPS */
+
+	return pos;
+}
+
 
 /* Format one result on one text line into a buffer. */
 static int wpa_supplicant_ctrl_iface_scan_result(
@@ -551,6 +667,7 @@
 	ie2 = wpa_scan_get_ie(res, WLAN_EID_RSN);
 	if (ie2)
 		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+	pos = wpa_supplicant_wps_ie_txt(pos, end, res);
 	if (!ie && !ie2 && res->caps & IEEE80211_CAP_PRIVACY) {
 		ret = os_snprintf(pos, end - pos, "[WEP]");
 		if (ret < 0 || ret >= end - pos)
@@ -1314,6 +1431,7 @@
 	ie2 = wpa_scan_get_ie(bss, WLAN_EID_RSN);
 	if (ie2)
 		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+	pos = wpa_supplicant_wps_ie_txt(pos, end, bss);
 	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
 		ret = os_snprintf(pos, end - pos, "[WEP]");
 		if (ret < 0 || ret >= end - pos)
@@ -1432,6 +1550,21 @@
 		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
 			reply_len = -1;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
+							      reply,
+							      reply_size);
+	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
+			reply_len = -1;
+#endif /* CONFIG_WPS */
 	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
 	{
 		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -1492,6 +1625,9 @@
 	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
 		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
 			reply_len = -1;
+	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+		reply_len = wpa_supplicant_global_iface_list(
+			wpa_s->global, reply, reply_size);
 	} else if (os_strcmp(buf, "INTERFACES") == 0) {
 		reply_len = wpa_supplicant_global_iface_interfaces(
 			wpa_s->global, reply, reply_size);
@@ -1607,6 +1743,63 @@
 }
 
 
+static void wpa_free_iface_info(struct wpa_interface_info *iface)
+{
+	struct wpa_interface_info *prev;
+
+	while (iface) {
+		prev = iface;
+		iface = iface->next;
+
+		os_free(prev->ifname);
+		os_free(prev->desc);
+		os_free(prev);
+	}
+}
+
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+					    char *buf, int len)
+{
+	int i, res;
+	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
+	char *pos, *end;
+
+	for (i = 0; wpa_supplicant_drivers[i]; i++) {
+		struct wpa_driver_ops *drv = wpa_supplicant_drivers[i];
+		if (drv->get_interfaces == NULL)
+			continue;
+		tmp = drv->get_interfaces(global->drv_priv);
+		if (tmp == NULL)
+			continue;
+
+		if (last == NULL)
+			iface = last = tmp;
+		else
+			last->next = tmp;
+		while (last->next)
+			last = last->next;
+	}
+
+	pos = buf;
+	end = buf + len;
+	for (tmp = iface; tmp; tmp = tmp->next) {
+		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
+				  tmp->drv_name, tmp->ifname,
+				  tmp->desc ? tmp->desc : "");
+		if (res < 0 || res >= end - pos) {
+			*pos = '\0';
+			break;
+		}
+		pos += res;
+	}
+
+	wpa_free_iface_info(iface);
+
+	return pos - buf;
+}
+
+
 static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
 						  char *buf, int len)
 {
@@ -1659,6 +1852,9 @@
 	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
 		if (wpa_supplicant_global_iface_remove(global, buf + 17))
 			reply_len = -1;
+	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+		reply_len = wpa_supplicant_global_iface_list(
+			global, reply, reply_size);
 	} else if (os_strcmp(buf, "INTERFACES") == 0) {
 		reply_len = wpa_supplicant_global_iface_interfaces(
 			global, reply, reply_size);

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_dbus.c Sat Jan 10 08:43:01 2009
@@ -920,7 +920,6 @@
 
 /**
  * wpas_dbus_register_new_iface - Register a new interface with dbus
- * @global: Global %wpa_supplicant data
  * @wpa_s: %wpa_supplicant interface description structure to register
  * Returns: 0 on success, -1 on error
  *

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=1303&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 Jan 10 08:43:01 2009
@@ -153,7 +153,7 @@
 	 * Try to get the wpa_supplicant record for this iface, return
 	 * an error if we already control it.
 	 */
-	if (wpa_supplicant_get_iface(global, iface.ifname) != 0) {
+	if (wpa_supplicant_get_iface(global, iface.ifname) != NULL) {
 		reply = dbus_message_new_error(message,
 					       WPAS_ERROR_EXISTS_ERROR,
 					       "wpa_supplicant already "
@@ -415,6 +415,14 @@
 	ie = wpa_scan_get_ie(res, WLAN_EID_RSN);
 	if (ie) {
 		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+						     (const char *) ie,
+						     ie[1] + 2))
+			goto error;
+	}
+
+	ie = wpa_scan_get_vendor_ie(res, WPS_IE_VENDOR_TYPE);
+	if (ie) {
+		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
 						     (const char *) ie,
 						     ie[1] + 2))
 			goto error;
@@ -1279,7 +1287,7 @@
 /**
  * wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
  * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
+ * @wpa_s: %wpa_supplicant data structure
  * Returns: A dbus message containing a UINT32 indicating success (1) or
  *          failure (0)
  *
@@ -1362,7 +1370,7 @@
 /**
  * wpas_dbus_iface_remove_blob - Remove named binary blobs
  * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
+ * @wpa_s: %wpa_supplicant data structure
  * Returns: A dbus message containing a UINT32 indicating success (1) or
  *          failure (0)
  *

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_named_pipe.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_named_pipe.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_named_pipe.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/ctrl_iface_named_pipe.c Sat Jan 10 08:43:01 2009
@@ -412,7 +412,8 @@
 		return -1;
 	if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
 		    t_sddl, SDDL_REVISION_1,
-		    (PSECURITY_DESCRIPTOR *) &priv->attr.lpSecurityDescriptor,
+		    (PSECURITY_DESCRIPTOR *) (void *)
+		    &priv->attr.lpSecurityDescriptor,
 		    NULL)) {
 		os_free(t_sddl);
 		wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/dbus_dict_helpers.c Sat Jan 10 08:43:01 2009
@@ -21,7 +21,7 @@
 
 /**
  * Start a dict in a dbus message.  Should be paired with a call to
- * {@link wpa_dbus_dict_close_write}.
+ * wpa_dbus_dict_close_write().
  *
  * @param iter A valid dbus message iterator
  * @param iter_dict (out) A dict iterator to pass to further dict functions
@@ -50,12 +50,12 @@
 
 /**
  * End a dict element in a dbus message.  Should be paired with
- * a call to {@link wpa_dbus_dict_open_write}.
+ * a call to wpa_dbus_dict_open_write().
  *
  * @param iter valid dbus message iterator, same as passed to
  *    wpa_dbus_dict_open_write()
  * @param iter_dict a dbus dict iterator returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @return TRUE on success, FALSE on failure
  *
  */
@@ -209,7 +209,7 @@
  * Add a string entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The string value
  * @return TRUE on success, FALSE on failure
@@ -229,7 +229,7 @@
  * Add a byte entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The byte value
  * @return TRUE on success, FALSE on failure
@@ -249,7 +249,7 @@
  * Add a boolean entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The boolean value
  * @return TRUE on success, FALSE on failure
@@ -269,7 +269,7 @@
  * Add a 16-bit signed integer entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 16-bit signed integer value
  * @return TRUE on success, FALSE on failure
@@ -290,7 +290,7 @@
  * Add a 16-bit unsigned integer entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 16-bit unsigned integer value
  * @return TRUE on success, FALSE on failure
@@ -311,7 +311,7 @@
  * Add a 32-bit signed integer to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 32-bit signed integer value
  * @return TRUE on success, FALSE on failure
@@ -332,7 +332,7 @@
  * Add a 32-bit unsigned integer entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 32-bit unsigned integer value
  * @return TRUE on success, FALSE on failure
@@ -353,7 +353,7 @@
  * Add a 64-bit integer entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 64-bit integer value
  * @return TRUE on success, FALSE on failure
@@ -374,7 +374,7 @@
  * Add a 64-bit unsigned integer entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The 64-bit unsigned integer value
  * @return TRUE on success, FALSE on failure
@@ -395,7 +395,7 @@
  * Add a double-precision floating point entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The double-precision floating point value
  * @return TRUE on success, FALSE on failure
@@ -416,7 +416,7 @@
  * Add a DBus object path entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The DBus object path value
  * @return TRUE on success, FALSE on failure
@@ -437,7 +437,7 @@
  * Add a byte array entry to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_write}
+ *    wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param value The byte array
  * @param value_len The length of the byte array, in bytes
@@ -462,14 +462,14 @@
  * Begin a string array entry in the dict
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *                  {@link nmu_dbus_dict_open_write}
+ *                  wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param iter_dict_entry A private DBusMessageIter provided by the caller to
- *                        be passed to {@link wpa_dbus_dict_end_string_array}
+ *                        be passed to wpa_dbus_dict_end_string_array()
  * @param iter_dict_val A private DBusMessageIter provided by the caller to
- *                      be passed to {@link wpa_dbus_dict_end_string_array}
+ *                      be passed to wpa_dbus_dict_end_string_array()
  * @param iter_array On return, the DBusMessageIter to be passed to
- *                   {@link wpa_dbus_dict_string_array_add_element}
+ *                   wpa_dbus_dict_string_array_add_element()
  * @return TRUE on success, FALSE on failure
  *
  */
@@ -506,7 +506,7 @@
  * Add a single string element to a string array dict entry
  *
  * @param iter_array A valid DBusMessageIter returned from
- *                   {@link wpa_dbus_dict_begin_string_array}'s
+ *                   wpa_dbus_dict_begin_string_array()'s
  *                   iter_array parameter
  * @param elem The string element to be added to the dict entry's string array
  * @return TRUE on success, FALSE on failure
@@ -527,13 +527,13 @@
  * End a string array dict entry
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *                  {@link nmu_dbus_dict_open_write}
+ *                  wpa_dbus_dict_open_write()
  * @param iter_dict_entry A private DBusMessageIter returned from
- *                        {@link wpa_dbus_dict_end_string_array}
+ *                        wpa_dbus_dict_end_string_array()
  * @param iter_dict_val A private DBusMessageIter returned from
- *                      {@link wpa_dbus_dict_end_string_array}
+ *                      wpa_dbus_dict_end_string_array()
  * @param iter_array A DBusMessageIter returned from
- *                   {@link wpa_dbus_dict_end_string_array}
+ *                   wpa_dbus_dict_end_string_array()
  * @return TRUE on success, FALSE on failure
  *
  */
@@ -560,7 +560,7 @@
  * Convenience function to add an entire string array to the dict.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *                  {@link nmu_dbus_dict_open_write}
+ *                  wpa_dbus_dict_open_write()
  * @param key The key of the dict item
  * @param items The array of strings
  * @param num_items The number of strings in the array
@@ -608,7 +608,7 @@
  *
  * @param iter A valid DBusMessageIter pointing to the start of the dict
  * @param iter_dict (out) A DBusMessageIter to be passed to
- *    {@link wpa_dbus_dict_read_next_entry}
+ *    wpa_dbus_dict_read_next_entry()
  * @return TRUE on success, FALSE on failure
  *
  */
@@ -868,14 +868,14 @@
 /**
  * Read the current key/value entry from the dict.  Entries are dynamically
  * allocated when needed and must be freed after use with the
- * {@link wpa_dbus_dict_entry_clear} function.
+ * wpa_dbus_dict_entry_clear() function.
  *
  * The returned entry object will be filled with the type and value of the next
  * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
  * occurred.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_read}
+ *    wpa_dbus_dict_open_read()
  * @param entry A valid dict entry object into which the dict key and value
  *    will be placed
  * @return TRUE on success, FALSE on failure
@@ -927,7 +927,7 @@
  * Return whether or not there are additional dictionary entries.
  *
  * @param iter_dict A valid DBusMessageIter returned from
- *    {@link wpa_dbus_dict_open_read}
+ *    wpa_dbus_dict_open_read()
  * @return TRUE if more dict entries exists, FALSE if no more dict entries
  * exist
  */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/defconfig Sat Jan 10 08:43:01 2009
@@ -156,6 +156,10 @@
 # EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
 #CONFIG_EAP_AKA=y
 
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
 # Enable USIM simulator (Milenage) for EAP-AKA
 #CONFIG_USIM_SIMULATOR=y
 
@@ -169,6 +173,9 @@
 
 # EAP-TNC and related Trusted Network Connect support (experimental)
 #CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/code_structure.doxygen
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/code_structure.doxygen?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/code_structure.doxygen (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/code_structure.doxygen Sat Jan 10 08:43:01 2009
@@ -148,7 +148,7 @@
 	TLS library wrapper for GnuTLS
 
 
-\section crypto_func Cryptographic functions
+\section tls_func TLS library
 
 asn1.c and asn1.h
 	ASN.1 DER parsing

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.links
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.links?rev=1303&op=file
==============================================================================
    (empty)

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.refs
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.refs?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.refs (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/manpage.refs Sat Jan 10 08:43:01 2009
@@ -1,0 +1,4 @@
+{
+  '' => '',
+  '' => ''
+}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_background.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_BACKGROUND" "8" "23 November 2008" "" ""
+.TH "WPA_BACKGROUND" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_cli.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_CLI" "8" "23 November 2008" "" ""
+.TH "WPA_CLI" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_cli \- WPA command line client

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_gui.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_GUI" "8" "23 November 2008" "" ""
+.TH "WPA_GUI" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_gui \- WPA Graphical User Interface

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_passphrase.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PASSPHRASE" "8" "23 November 2008" "" ""
+.TH "WPA_PASSPHRASE" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_priv.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_PRIV" "8" "23 November 2008" "" ""
+.TH "WPA_PRIV" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_priv \- wpa_supplicant privilege separation helper

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.8 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT" "8" "23 November 2008" "" ""
+.TH "WPA_SUPPLICANT" "8" "06 January 2009" "" ""
 
 .SH NAME
 wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
@@ -52,7 +52,7 @@
 .PP
 Before wpa_supplicant can do its work, the network interface
 must be available.  That means that the physical device must be
-present and enabled, and the driver for the device must have be
+present and enabled, and the driver for the device must be
 loaded. The daemon will exit immediately if the device is not already
 available.
 .PP

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 Sat Jan 10 08:43:01 2009
@@ -3,7 +3,7 @@
 .\" <http://shell.ipoline.com/~elmert/comp/docbook2X/> 
 .\" Please send any bug reports, improvements, comments, patches, 
 .\" etc. to Steve Cheng <steve at ggi-project.org>.
-.TH "WPA_SUPPLICANT.CONF" "5" "23 November 2008" "" ""
+.TH "WPA_SUPPLICANT.CONF" "5" "06 January 2009" "" ""
 
 .SH NAME
 wpa_supplicant.conf \- configuration file for wpa_supplicant

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=1303&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 Jan 10 08:43:01 2009
@@ -66,7 +66,7 @@
 
     <para>Before wpa_supplicant can do its work, the network interface
     must be available.  That means that the physical device must be
-    present and enabled, and the driver for the device must have be
+    present and enabled, and the driver for the device must be
     loaded. The daemon will exit immediately if the device is not already
     available.</para>
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.fast
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.fast?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.fast (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.fast Sat Jan 10 08:43:01 2009
@@ -1,14 +1,13 @@
-# Doxyfile 1.4.1
+# Doxyfile 1.4.4
 
 #---------------------------------------------------------------------------
 # Project related configuration options
 #---------------------------------------------------------------------------
 PROJECT_NAME           = wpa_supplicant
 PROJECT_NUMBER         = 0.6.x
-OUTPUT_DIRECTORY       = doc
+OUTPUT_DIRECTORY       = wpa_supplicant/doc
 CREATE_SUBDIRS         = NO
 OUTPUT_LANGUAGE        = English
-USE_WINDOWS_ENCODING   = NO
 BRIEF_MEMBER_DESC      = YES
 REPEAT_BRIEF           = YES
 ABBREVIATE_BRIEF       = "The $name class" \
@@ -33,6 +32,7 @@
 DETAILS_AT_TOP         = NO
 INHERIT_DOCS           = YES
 DISTRIBUTE_GROUP_DOC   = NO
+SEPARATE_MEMBER_PAGES  = NO
 TAB_SIZE               = 8
 ALIASES                = 
 OPTIMIZE_OUTPUT_FOR_C  = YES
@@ -65,14 +65,14 @@
 ENABLED_SECTIONS       = 
 MAX_INITIALIZER_LINES  = 30
 SHOW_USED_FILES        = YES
-SHOW_DIRECTORIES       = NO
+SHOW_DIRECTORIES       = YES
 FILE_VERSION_FILTER    = 
 #---------------------------------------------------------------------------
 # configuration options related to warning and progress messages
 #---------------------------------------------------------------------------
 QUIET                  = NO
 WARNINGS               = YES
-WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_UNDOCUMENTED   = NO
 WARN_IF_DOC_ERROR      = YES
 WARN_NO_PARAMDOC       = YES
 WARN_FORMAT            = "$file:$line: $text"
@@ -80,25 +80,27 @@
 #---------------------------------------------------------------------------
 # configuration options related to the input files
 #---------------------------------------------------------------------------
-INPUT                  = . \
-	../src/crypto \
-	../src/utils \
-	../src/eap_peer \
-	../src/eap_common \
-	../src/l2_packet \
-	../src/rsn_supp \
-	../src/drivers/driver.h \
-	../src/drivers/drivers.c \
-	../src/tls
-FILE_PATTERNS          = *.c *.h *.doxygen
+INPUT                  = wpa_supplicant \
+	src/common \
+	src/crypto \
+	src/drivers \
+	src/eap_common \
+	src/eapol_supp \
+	src/eap_peer \
+	src/l2_packet \
+	src/rsn_supp \
+	src/tls \
+	src/utils \
+	src/wps
+FILE_PATTERNS          = *.c *.h *.cpp *.m *.doxygen
 RECURSIVE              = YES
-EXCLUDE                = 
+EXCLUDE                = wpa_supplicant/wpa_gui
 EXCLUDE_SYMLINKS       = NO
-EXCLUDE_PATTERNS       = 
+EXCLUDE_PATTERNS       = */.moc/* */.ui/*
 EXAMPLE_PATH           = 
 EXAMPLE_PATTERNS       = *
 EXAMPLE_RECURSIVE      = NO
-IMAGE_PATH             = doc
+IMAGE_PATH             = wpa_supplicant/doc
 INPUT_FILTER           = kerneldoc2doxygen.pl
 FILTER_PATTERNS        = 
 FILTER_SOURCE_FILES    = YES
@@ -196,7 +198,7 @@
 SEARCH_INCLUDES        = YES
 INCLUDE_PATH           = 
 INCLUDE_FILE_PATTERNS  = 
-PREDEFINED             = IEEE8021X_EAPOL
+PREDEFINED             = IEEE8021X_EAPOL CONFIG_CTRL_IFACE
 EXPAND_AS_DEFINED      = 
 SKIP_FUNCTION_MACROS   = YES
 #---------------------------------------------------------------------------
@@ -226,8 +228,6 @@
 DOT_IMAGE_FORMAT       = png
 DOT_PATH               = 
 DOTFILE_DIRS           = 
-MAX_DOT_GRAPH_WIDTH    = 1024
-MAX_DOT_GRAPH_HEIGHT   = 1024
 MAX_DOT_GRAPH_DEPTH    = 1000
 DOT_TRANSPARENT        = NO
 DOT_MULTI_TARGETS      = NO

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.full
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.full?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.full (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/doxygen.full Sat Jan 10 08:43:01 2009
@@ -1,4 +1,4 @@
-# Doxyfile 1.4.1
+# Doxyfile 1.4.4
 
 #---------------------------------------------------------------------------
 # Project related configuration options
@@ -8,7 +8,6 @@
 OUTPUT_DIRECTORY       = wpa_supplicant/doc
 CREATE_SUBDIRS         = NO
 OUTPUT_LANGUAGE        = English
-USE_WINDOWS_ENCODING   = NO
 BRIEF_MEMBER_DESC      = YES
 REPEAT_BRIEF           = YES
 ABBREVIATE_BRIEF       = "The $name class" \
@@ -24,7 +23,7 @@
                          the
 ALWAYS_DETAILED_SEC    = NO
 INLINE_INHERITED_MEMB  = NO
-FULL_PATH_NAMES        = NO
+FULL_PATH_NAMES        = YES
 STRIP_FROM_PATH        =
 STRIP_FROM_INC_PATH    = 
 SHORT_NAMES            = NO
@@ -33,6 +32,7 @@
 DETAILS_AT_TOP         = NO
 INHERIT_DOCS           = YES
 DISTRIBUTE_GROUP_DOC   = NO
+SEPARATE_MEMBER_PAGES  = NO
 TAB_SIZE               = 8
 ALIASES                = 
 OPTIMIZE_OUTPUT_FOR_C  = YES
@@ -72,7 +72,7 @@
 #---------------------------------------------------------------------------
 QUIET                  = NO
 WARNINGS               = YES
-WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_UNDOCUMENTED   = NO
 WARN_IF_DOC_ERROR      = YES
 WARN_NO_PARAMDOC       = YES
 WARN_FORMAT            = "$file:$line: $text"
@@ -90,16 +90,17 @@
 	src/l2_packet \
 	src/rsn_supp \
 	src/tls \
-	src/utils
+	src/utils \
+	src/wps
 FILE_PATTERNS          = *.c *.h *.cpp *.m *.doxygen
 RECURSIVE              = YES
-EXCLUDE                = 
+EXCLUDE                = wpa_supplicant/wpa_gui
 EXCLUDE_SYMLINKS       = NO
-EXCLUDE_PATTERNS       = 
+EXCLUDE_PATTERNS       = */.moc/* */.ui/*
 EXAMPLE_PATH           = 
 EXAMPLE_PATTERNS       = *
 EXAMPLE_RECURSIVE      = NO
-IMAGE_PATH             = doc
+IMAGE_PATH             = wpa_supplicant/doc
 INPUT_FILTER           = kerneldoc2doxygen.pl
 FILTER_PATTERNS        = 
 FILTER_SOURCE_FILES    = YES
@@ -227,8 +228,6 @@
 DOT_IMAGE_FORMAT       = png
 DOT_PATH               = 
 DOTFILE_DIRS           = 
-MAX_DOT_GRAPH_WIDTH    = 1024
-MAX_DOT_GRAPH_HEIGHT   = 1024
 MAX_DOT_GRAPH_DEPTH    = 1000
 DOT_TRANSPARENT        = NO
 DOT_MULTI_TARGETS      = NO

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/kerneldoc2doxygen.pl
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/kerneldoc2doxygen.pl?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/kerneldoc2doxygen.pl (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/kerneldoc2doxygen.pl Sat Jan 10 08:43:01 2009
@@ -20,7 +20,7 @@
 #
 ##########################################################################
 # Copyright (C) 2003 Jonathan Foster <jon at jon-foster.co.uk>
-# Copyright (C) 2005 Jouni Malinen <j at w1.fi>
+# Copyright (C) 2005-2008 Jouni Malinen <j at w1.fi>
 # (modified for kerneldoc format used in wpa_supplicant)
 #
 # This program is free software; you can redistribute it and/or modify
@@ -69,6 +69,11 @@
 #
 sub fixcomment {
     $t = $_[0];
+
+    # wpa_supplicant -> %wpa_supplicant except for struct wpa_supplicant
+    $t =~ s/struct wpa_supplicant/struct STRUCTwpa_supplicant/sg;
+    $t =~ s/ wpa_supplicant/ \%wpa_supplicant/sg;
+    $t =~ s/struct STRUCTwpa_supplicant/struct wpa_supplicant/sg;
 
     # " * func: foo" --> "\brief foo\n"
     # " * struct bar: foo" --> "\brief foo\n"

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/doc/porting.doxygen
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/doc/porting.doxygen?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/doc/porting.doxygen (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/doc/porting.doxygen Sat Jan 10 08:43:01 2009
@@ -19,9 +19,9 @@
 %wpa_supplicant is mostly using ANSI C functions that are available on
 most targets. However, couple of additional functions that are common
 on modern UNIX systems are used. Number of these are listed with
-prototypes in common.h (the #ifdef CONFIG_ANSI_C_EXTRA block). These
-functions may need to be implemented or at least defined as macros to
-native functions in the target OS or C library.
+prototypes in common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
+block). These functions may need to be implemented or at least defined
+as macros to native functions in the target OS or C library.
 
 Many of the common ANSI C functions are used through a wrapper
 definitions in os.h to allow these to be replaced easily with a

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eap_testing.txt Sat Jan 10 08:43:01 2009
@@ -94,20 +94,21 @@
 EAP-TTLS + TNC		-   -   -   -   -   +   -   -   -   -   +   -
 EAP-SIM			+   -   -   ?   -   +   -   ?   -   -   +   -
 EAP-AKA			-   -   -   -   -   +   -   -   -   -   +   -
+EAP-AKA'		-   -   -   -   -   -   -   -   -   -   +   -
 EAP-PSK			+7  -   -   -   -   +   -   -   -   -   +   -
 EAP-PAX			-   -   -   -   -   +   -   -   -   -   +   -
 EAP-SAKE		-   -   -   -   -   -   -   -   -   -   +   -
 EAP-GPSK		-   -   -   -   -   -   -   -   -   -   +   -
-EAP-FAST/MSCHAPv2(prov)	-   -   -   +   -   -   -   -   -   +   +   +
-EAP-FAST/GTC(auth)	-   -   -   +   -   -   -   -   -   +   +   +
-EAP-FAST/MSCHAPv2(aprov)-   -   -   -   -   -   -   -   -   -   +   +
-EAP-FAST/GTC(aprov)	-   -   -   -   -   -   -   -   -   -   +   +
-EAP-FAST/MD5(aprov)	-   -   -   -   -   -   -   -   -   -   +   -
+EAP-FAST/MSCHAPv2(prov)	-   -   -   +   -   +   -   -   -   +   +   +
+EAP-FAST/GTC(auth)	-   -   -   +   -   +   -   -   -   +   +   +
+EAP-FAST/MSCHAPv2(aprov)-   -   -   -   -   +   -   -   -   -   +   +
+EAP-FAST/GTC(aprov)	-   -   -   -   -   +   -   -   -   -   +   +
+EAP-FAST/MD5(aprov)	-   -   -   -   -   +   -   -   -   -   +   -
 EAP-FAST/TLS(aprov)	-   -   -   -   -   -   -   -   -   -   +   +
 EAP-FAST/SIM(aprov)	-   -   -   -   -   -   -   -   -   -   +   -
 EAP-FAST/AKA(aprov)	-   -   -   -   -   -   -   -   -   -   +   -
-EAP-FAST/MSCHAPv2(auth)	-   -   -   -   -   -   -   -   -   -   +   +
-EAP-FAST/MD5(auth)	-   -   -   -   -   -   -   -   -   -   +   -
+EAP-FAST/MSCHAPv2(auth)	-   -   -   -   -   +   -   -   -   -   +   +
+EAP-FAST/MD5(auth)	-   -   -   -   -   +   -   -   -   -   +   -
 EAP-FAST/TLS(auth)	-   -   -   -   -   -   -   -   -   -   +   +
 EAP-FAST/SIM(auth)	-   -   -   -   -   -   -   -   -   -   +   -
 EAP-FAST/AKA(auth)	-   -   -   -   -   -   -   -   -   -   +   -

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/eapol_test.c Sat Jan 10 08:43:01 2009
@@ -38,6 +38,13 @@
 struct wpa_driver_ops *wpa_supplicant_drivers[] = { NULL };
 
 
+struct extra_radius_attr {
+	u8 type;
+	char syntax;
+	char *data;
+	struct extra_radius_attr *next;
+};
+
 struct eapol_test_data {
 	struct wpa_supplicant *wpa_s;
 
@@ -66,8 +73,7 @@
 
 	char *connect_info;
 	u8 own_addr[ETH_ALEN];
-	int cui_flag;
-	char *cui_str;
+	struct extra_radius_attr *extra_attrs;
 };
 
 static struct eapol_test_data eapol_test;
@@ -84,6 +90,69 @@
 			   MAC2STR(addr), txt);
 	else
 		wpa_printf(MSG_DEBUG, "%s", txt);
+}
+
+
+static int add_extra_attr(struct radius_msg *msg,
+			  struct extra_radius_attr *attr)
+{
+	size_t len;
+	char *pos;
+	u32 val;
+	char buf[128];
+
+	switch (attr->syntax) {
+	case 's':
+		os_snprintf(buf, sizeof(buf), "%s", attr->data);
+		len = os_strlen(buf);
+		break;
+	case 'n':
+		buf[0] = '\0';
+		len = 1;
+		break;
+	case 'x':
+		pos = attr->data;
+		if (pos[0] == '0' && pos[1] == 'x')
+			pos += 2;
+		len = os_strlen(pos);
+		if ((len & 1) || (len / 2) > sizeof(buf)) {
+			printf("Invalid extra attribute hexstring\n");
+			return -1;
+		}
+		len /= 2;
+		if (hexstr2bin(pos, (u8 *) buf, len) < 0) {
+			printf("Invalid extra attribute hexstring\n");
+			return -1;
+		}
+		break;
+	case 'd':
+		val = htonl(atoi(attr->data));
+		os_memcpy(buf, &val, 4);
+		len = 4;
+		break;
+	default:
+		printf("Incorrect extra attribute syntax specification\n");
+		return -1;
+	}
+
+	if (!radius_msg_add_attr(msg, attr->type, (u8 *) buf, len)) {
+		printf("Could not add attribute %d\n", attr->type);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int add_extra_attrs(struct radius_msg *msg,
+			   struct extra_radius_attr *attrs)
+{
+	struct extra_radius_attr *p;
+	for (p = attrs; p; p = p->next) {
+		if (add_extra_attr(msg, p) < 0)
+			return -1;
+	}
+	return 0;
 }
 
 
@@ -166,22 +235,8 @@
 		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 (add_extra_attrs(msg, e->extra_attrs) < 0)
+		goto fail;
 
 	if (eap && !radius_msg_add_eap(msg, eap, len)) {
 		printf("Could not add EAP-Message\n");
@@ -365,6 +420,8 @@
 static void test_eapol_clean(struct eapol_test_data *e,
 			     struct wpa_supplicant *wpa_s)
 {
+	struct extra_radius_attr *p, *prev;
+
 	radius_client_deinit(e->radius);
 	os_free(e->last_eap_radius);
 	if (e->last_recv_radius) {
@@ -387,6 +444,13 @@
 		wpa_s->ctrl_iface = NULL;
 	}
 	wpa_config_free(wpa_s->conf);
+
+	p = e->extra_attrs;
+	while (p) {
+		prev = p;
+		p = p->next;
+		os_free(prev);
+	}
 }
 
 
@@ -560,6 +624,16 @@
 				keys->recv_len;
 			os_memcpy(e->authenticator_pmk, keys->recv,
 				  e->authenticator_pmk_len);
+			if (e->authenticator_pmk_len == 16 && keys->send &&
+			    keys->send_len == 16) {
+				/* MS-CHAP-v2 derives 16 octet keys */
+				wpa_printf(MSG_DEBUG, "Use MS-MPPE-Send-Key "
+					   "to extend PMK to 32 octets");
+				os_memcpy(e->authenticator_pmk +
+					  e->authenticator_pmk_len,
+					  keys->send, keys->send_len);
+				e->authenticator_pmk_len += keys->send_len;
+			}
 		}
 
 		os_free(keys->send);
@@ -879,7 +953,8 @@
 	       "[-s<AS secret>]\\\n"
 	       "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
 	       "           [-M<client MAC address>] \\\n"
-	       "           [-I<CUI>] [-i] [-A<client IP>]\n"
+	       "           [-N<attr spec>] \\\n"
+	       "           [-A<client IP>]\n"
 	       "eapol_test scard\n"
 	       "eapol_test sim <PIN> <num triplets> [debug]\n"
 	       "\n");
@@ -895,7 +970,7 @@
 	       "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"
+	       "  -S = save configuration after authentication\n"
 	       "  -n = no MPPE keys expected\n"
 	       "  -t<timeout> = sets timeout in seconds (default: 30 s)\n"
 	       "  -C<Connect-Info> = RADIUS Connect-Info (default: "
@@ -903,9 +978,18 @@
 	       "  -M<client MAC address> = Set own MAC address "
 	       "(Calling-Station-Id,\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");
+	       "  -N<attr spec> = send arbitrary attribute specified by:\n"
+	       "                  attr_id:syntax:value or attr_id\n"
+	       "                  attr_id - number id of the attribute\n"
+	       "                  syntax - one of: s, d, x\n"
+	       "                     s = string\n"
+	       "                     d = integer\n"
+	       "                     x = octet string\n"
+	       "                  value - attribute value.\n"
+	       "       When only attr_id is specified, NULL will be used as "
+	       "value.\n"
+	       "       Multiple attributes can be specified by using the "
+	       "option several times.\n");
 }
 
 
@@ -919,6 +1003,8 @@
 	char *cli_addr = NULL;
 	char *conf = NULL;
 	int timeout = 30;
+	char *pos;
+	struct extra_radius_attr *p = NULL, *p1;
 
 	if (os_program_init())
 		return -1;
@@ -933,7 +1019,7 @@
 	wpa_debug_show_keys = 1;
 
 	for (;;) {
-		c = getopt(argc, argv, "a:A:c:C:iI:M:np:r:s:St:W");
+		c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -948,13 +1034,6 @@
 			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)) {
@@ -982,6 +1061,34 @@
 			break;
 		case 'W':
 			wait_for_monitor++;
+			break;
+		case 'N':
+			p1 = os_zalloc(sizeof(p1));
+			if (p1 == NULL)
+				break;
+			if (!p)
+				eapol_test.extra_attrs = p1;
+			else
+				p->next = p1;
+			p = p1;
+
+			p->type = atoi(optarg);
+			pos = os_strchr(optarg, ':');
+			if (pos == NULL) {
+				p->syntax = 'n';
+				p->data = NULL;
+				break;
+			}
+
+			pos++;
+			if (pos[0] == '\0' || pos[1] != ':') {
+				printf("Incorrect format of attribute "
+				       "specification\n");
+				break;
+			}
+
+			p->syntax = pos[0];
+			p->data = pos + 2;
 			break;
 		default:
 			usage();

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/events.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/events.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/events.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/events.c Sat Jan 10 08:43:01 2009
@@ -31,6 +31,7 @@
 #include "ieee802_11_defs.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
+#include "wps_supplicant.h"
 
 
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -275,6 +276,11 @@
 	struct wpa_ie_data ie;
 	int proto_match = 0;
 	const u8 *rsn_ie, *wpa_ie;
+	int ret;
+
+	ret = wpas_wps_ssid_bss_match(ssid, bss);
+	if (ret >= 0)
+		return ret;
 
 	rsn_ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
 	while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
@@ -409,13 +415,22 @@
 		}
 
 		for (ssid = group; ssid; ssid = ssid->pnext) {
+			int check_ssid = 1;
+
 			if (ssid->disabled) {
 				wpa_printf(MSG_DEBUG, "   skip - disabled");
 				continue;
 			}
 
-			if (ssid_len != ssid->ssid_len ||
-			    os_memcmp(ssid_, ssid->ssid, ssid_len) != 0) {
+#ifdef CONFIG_WPS
+			if (ssid->ssid_len == 0 &&
+			    wpas_wps_ssid_wildcard_ok(ssid, bss))
+				check_ssid = 0;
+#endif /* CONFIG_WPS */
+
+			if (check_ssid &&
+			    (ssid_len != ssid->ssid_len ||
+			     os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
 				wpa_printf(MSG_DEBUG, "   skip - "
 					   "SSID mismatch");
 				continue;
@@ -485,12 +500,26 @@
 		}
 
 		for (ssid = group; ssid; ssid = ssid->pnext) {
+			int check_ssid = ssid->ssid_len != 0;
+
 			if (ssid->disabled) {
 				wpa_printf(MSG_DEBUG, "   skip - disabled");
 				continue;
 			}
 
-			if (ssid->ssid_len != 0 &&
+#ifdef CONFIG_WPS
+			if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+				/* Only allow wildcard SSID match if an AP
+				 * advertises active WPS operation that matches
+				 * with our mode. */
+				check_ssid = 1;
+				if (ssid->ssid_len == 0 &&
+				    wpas_wps_ssid_wildcard_ok(ssid, bss))
+					check_ssid = 0;
+			}
+#endif /* CONFIG_WPS */
+
+			if (check_ssid &&
 			    (ssid_len != ssid->ssid_len ||
 			     os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
 				wpa_printf(MSG_DEBUG, "   skip - "
@@ -507,6 +536,7 @@
 			}
 			
 			if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+			    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
 			    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
 			{
 				wpa_printf(MSG_DEBUG, "   skip - "
@@ -596,9 +626,11 @@
 	} else {
 		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
 		wpa_supplicant_dbus_notify_scan_results(wpa_s);
-	}
-
-	if (wpa_s->conf->ap_scan == 2 || wpa_s->disconnected)
+		wpas_wps_notify_scan_results(wpa_s);
+	}
+
+	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)) ||
+	    wpa_s->disconnected)
 		return;
 
 	while (selected == NULL) {
@@ -619,6 +651,13 @@
 	}
 
 	if (selected) {
+		if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
+			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
+				"PBC session overlap");
+			timeout = 10;
+			goto req_scan;
+		}
+
 		/* Do not trigger new association unless the BSSID has changed
 		 * or if reassociation is requested. If we are in process of
 		 * associating with the selected BSSID, do not trigger new

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/main.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/main.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/main.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/main.c Sat Jan 10 08:43:01 2009
@@ -19,19 +19,6 @@
 
 #include "common.h"
 #include "wpa_supplicant_i.h"
-
-
-extern const char *wpa_supplicant_version;
-extern const char *wpa_supplicant_license;
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern const char *wpa_supplicant_full_license1;
-extern const char *wpa_supplicant_full_license2;
-extern const char *wpa_supplicant_full_license3;
-extern const char *wpa_supplicant_full_license4;
-extern const char *wpa_supplicant_full_license5;
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-extern struct wpa_driver_ops *wpa_supplicant_drivers[];
 
 
 static void usage(void)

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/main_winsvc.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/main_winsvc.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/main_winsvc.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/main_winsvc.c Sat Jan 10 08:43:01 2009
@@ -12,7 +12,7 @@
  * See README and COPYING for more details.
  *
  * The root of wpa_supplicant configuration in registry is
- * HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global
+ * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
  * parameters and a 'interfaces' subkey with all the interface configuration
  * (adapter to confname mapping). Each such mapping is a subkey that has
  * 'adapter' and 'config' values.
@@ -70,9 +70,10 @@
 	HKEY hk;
 #define TBUFLEN 255
 	TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
-	DWORD buflen;
+	DWORD buflen, val;
 	LONG ret;
 	struct wpa_interface iface;
+	int skip_on_error = 0;
 
 	ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
 	if (ret != ERROR_SUCCESS) {
@@ -116,10 +117,21 @@
 		iface.confname = (char *) config;
 	}
 
+	buflen = sizeof(val);
+	ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
+			      (LPBYTE) &val, &buflen);
+	if (ret == ERROR_SUCCESS && buflen == sizeof(val))
+		skip_on_error = val;
+
 	RegCloseKey(hk);
 
-	if (wpa_supplicant_add_iface(global, &iface) == NULL)
-		return -1;
+	if (wpa_supplicant_add_iface(global, &iface) == NULL) {
+		if (skip_on_error)
+			wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
+				   "initialization failure", iface.ifname);
+		else
+			return -1;
+	}
 
 	return 0;
 }

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/mlme.c Sat Jan 10 08:43:01 2009
@@ -1738,9 +1738,9 @@
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-PING.response */
-static int ieee80211_sta_send_ping_resp(struct wpa_supplicant *wpa_s,
-					const u8 *addr, const u8 *trans_id)
+/* MLME-SAQuery.response */
+static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *addr, const u8 *trans_id)
 {
 	struct ieee80211_mgmt *mgmt;
 	int res;
@@ -1749,7 +1749,7 @@
 	mgmt = os_zalloc(sizeof(*mgmt));
 	if (mgmt == NULL) {
 		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-			   "ping action frame");
+			   "SA Query action frame");
 		return -1;
 	}
 
@@ -1759,11 +1759,11 @@
 	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
 					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_PING;
-	mgmt->u.action.u.ping_resp.action = WLAN_PING_RESPONSE;
-	os_memcpy(mgmt->u.action.u.ping_resp.trans_id, trans_id,
-		  WLAN_PING_TRANS_ID_LEN);
-	len += 1 + sizeof(mgmt->u.action.u.ping_resp);
+	mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
+	mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE;
+	os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	len += 1 + sizeof(mgmt->u.action.u.sa_query_resp);
 
 	res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len);
 	os_free(mgmt);
@@ -1772,36 +1772,36 @@
 }
 
 
-static void ieee80211_rx_mgmt_ping_action(
+static void ieee80211_rx_mgmt_sa_query_action(
 	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
 	struct ieee80211_rx_status *rx_status)
 {
-	if (len < 24 + 1 + sizeof(mgmt->u.action.u.ping_req)) {
-		wpa_printf(MSG_DEBUG, "MLME: Too short Ping Action frame");
-		return;
-	}
-
-	if (mgmt->u.action.u.ping_req.action != WLAN_PING_REQUEST) {
-		wpa_printf(MSG_DEBUG, "MLME: Unexpected Ping Action %d",
-			   mgmt->u.action.u.ping_req.action);
+	if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) {
+		wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame");
+		return;
+	}
+
+	if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) {
+		wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d",
+			   mgmt->u.action.u.sa_query_req.action);
 		return;
 	}
 
 	if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore ping from unknown source "
-			   MACSTR, MAC2STR(mgmt->sa));
+		wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown "
+			   "source " MACSTR, MAC2STR(mgmt->sa));
 		return;
 	}
 
 	if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore ping request during "
+		wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during "
 			   "association process");
 		return;
 	}
 
-	wpa_printf(MSG_DEBUG, "MLME: Replying to ping request");
-	ieee80211_sta_send_ping_resp(wpa_s, mgmt->sa,
-				     mgmt->u.action.u.ping_req.trans_id);
+	wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request");
+	ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u.
+					 sa_query_req.trans_id);
 }
 
 #endif /* CONFIG_IEEE80211W */
@@ -1824,8 +1824,8 @@
 		break;
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_IEEE80211W
-	case WLAN_ACTION_PING:
-		ieee80211_rx_mgmt_ping_action(wpa_s, mgmt, len, rx_status);
+	case WLAN_ACTION_SA_QUERY:
+		ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
 		break;
 #endif /* CONFIG_IEEE80211W */
 	default:

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/scan.c Sat Jan 10 08:43:01 2009
@@ -19,7 +19,7 @@
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "mlme.h"
-#include "uuid.h"
+#include "wps_supplicant.h"
 
 
 static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -41,13 +41,42 @@
 }
 
 
+#ifdef CONFIG_WPS
+static int wpas_wps_in_use(struct wpa_config *conf,
+			   enum wps_request_type *req_type)
+{
+	struct wpa_ssid *ssid;
+	int wps = 0;
+
+	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+			continue;
+
+		wps = 1;
+		*req_type = wpas_wps_get_req_type(ssid);
+		if (!ssid->eap.phase1)
+			continue;
+
+		if (os_strstr(ssid->eap.phase1, "pbc=1"))
+			return 2;
+	}
+
+	return wps;
+}
+#endif /* CONFIG_WPS */
+
 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
 	int enabled, scan_req = 0, ret;
+	struct wpabuf *wps_ie = NULL;
 	const u8 *extra_ie = NULL;
 	size_t extra_ie_len = 0;
+	int wps = 0;
+#ifdef CONFIG_WPS
+	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
+#endif /* CONFIG_WPS */
 
 	if (wpa_s->disconnected && !wpa_s->scan_req)
 		return;
@@ -134,8 +163,12 @@
 	} else
 		wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
 
+#ifdef CONFIG_WPS
+	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
+#endif /* CONFIG_WPS */
+
 	if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1 &&
-	    !wpa_s->use_client_mlme) {
+	    !wpa_s->use_client_mlme && wps != 2) {
 		wpa_s->scan_res_tried++;
 		wpa_s->scan_req = scan_req;
 		wpa_printf(MSG_DEBUG, "Trying to get current scan results "
@@ -144,6 +177,17 @@
 		wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
 		return;
 	}
+
+#ifdef CONFIG_WPS
+	if (wps) {
+		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+						wpa_s->wps->uuid, req_type);
+		if (wps_ie) {
+			extra_ie = wpabuf_head(wps_ie);
+			extra_ie_len = wpabuf_len(wps_ie);
+		}
+	}
+#endif /* CONFIG_WPS */
 
 	if (wpa_s->use_client_mlme) {
 		ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len);
@@ -154,6 +198,8 @@
 		ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL,
 				   ssid ? ssid->ssid_len : 0);
 	}
+
+	wpabuf_free(wps_ie);
 
 	if (ret) {
 		wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/win_example.reg
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/win_example.reg?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/win_example.reg (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/win_example.reg Sat Jan 10 08:43:01 2009
@@ -11,6 +11,13 @@
 [HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test]
 "ap_scan"=dword:00000002
 "update_config"=dword:00000001
+"uuid"="12345678-9abc-def0-1234-56789abcdef0"
+"device_name"="Wireless Client"
+"manufacturer"="Company"
+"model_name"="cmodel"
+"serial_number"="12345"
+"device_type"="1-0050F204-1"
+"os_version"="01020300"
 
 [HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\blobs]
 "testblob"=hex:01,02,03,04,05
@@ -31,4 +38,5 @@
 "adapter"="{A7627643-C310-49E5-BD89-7E77709C04AB}"
 "config"="test"
 "ctrl_interface"=""
+"skip_on_error"=dword:00000000
 

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_cli.c Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2004-2009, 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
@@ -31,7 +31,7 @@
 
 static const char *wpa_cli_version =
 "wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2008, Jouni Malinen <j at w1.fi> and contributors";
+"Copyright (c) 2004-2009, Jouni Malinen <j at w1.fi> and contributors";
 
 
 static const char *wpa_cli_license =
@@ -86,55 +86,6 @@
 "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
 "\n";
 
-static const char *commands_help =
-"commands:\n"
-"  status [verbose] = get current WPA/EAPOL/EAP status\n"
-"  mib = get MIB variables (dot1x, dot11)\n"
-"  help = show this usage help\n"
-"  interface [ifname] = show interfaces/select interface\n"
-"  level <debug level> = change debug level\n"
-"  license = show full wpa_cli license\n"
-"  logoff = IEEE 802.1X EAPOL state machine logoff\n"
-"  logon = IEEE 802.1X EAPOL state machine logon\n"
-"  set = set variables (shows list of variables when run without arguments)\n"
-"  pmksa = show PMKSA cache\n"
-"  reassociate = force reassociation\n"
-"  reconfigure = force wpa_supplicant to re-read its configuration file\n"
-"  preauthenticate <BSSID> = force preauthentication\n"
-"  identity <network id> <identity> = configure identity for an SSID\n"
-"  password <network id> <password> = configure password for an SSID\n"
-"  new_password <network id> <password> = change password for an SSID\n"
-"  pin <network id> <pin> = configure pin for an SSID\n"
-"  otp <network id> <password> = configure one-time-password for an SSID\n"
-"  passphrase <network id> <passphrase> = configure private key passphrase\n"
-"    for an SSID\n"
-"  bssid <network id> <BSSID> = set preferred BSSID for an SSID\n"
-"  list_networks = list configured networks\n"
-"  select_network <network id> = select a network (disable others)\n"
-"  enable_network <network id> = enable a network\n"
-"  disable_network <network id> = disable a network\n"
-"  add_network = add a network\n"
-"  remove_network <network id> = remove a network\n"
-"  set_network <network id> <variable> <value> = set network variables "
-"(shows\n"
-"    list of variables when run without arguments)\n"
-"  get_network <network id> <variable> = get network variables\n"
-"  save_config = save the current configuration\n"
-"  disconnect = disconnect and wait for reassociate/reconnect command before\n "
-"    connecting\n"
-"  reconnect = like reassociate, but only takes effect if already "
-"disconnected\n"
-"  scan = request new BSS scan\n"
-"  scan_results = get latest scan results\n"
-"  bss <<idx> | <bssid>> = get detailed scan result info\n"
-"  get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
-"get capabilies\n"
-"  ap_scan <value> = set ap_scan parameter\n"
-"  stkstart <addr> = request STK negotiation with <addr>\n"
-"  ft_ds <addr> = request over-the-DS FT with <addr>\n"
-"  terminate = terminate wpa_supplicant\n"
-"  quit = exit wpa_cli\n";
-
 static struct wpa_ctrl *ctrl_conn;
 static int wpa_cli_quit = 0;
 static int wpa_cli_attached = 0;
@@ -144,6 +95,9 @@
 static char *ctrl_ifname = NULL;
 static const char *pid_file = NULL;
 static const char *action_file = NULL;
+
+
+static void print_help();
 
 
 static void usage(void)
@@ -158,9 +112,8 @@
 	       "       wpa_supplicant\n"
 	       "  -B = run a daemon in the background\n"
 	       "  default path: /var/run/wpa_supplicant\n"
-	       "  default interface: first interface found in socket path\n"
-	       "%s",
-	       commands_help);
+	       "  default interface: first interface found in socket path\n");
+	print_help();
 }
 
 
@@ -274,7 +227,7 @@
 
 static int wpa_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	printf("%s", commands_help);
+	print_help();
 	return 0;
 }
 
@@ -432,6 +385,80 @@
 	res = os_snprintf(cmd, sizeof(cmd), "FT_DS %s", argv[0]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long FT_DS command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc == 0) {
+		/* Any BSSID */
+		return wpa_ctrl_command(ctrl, "WPS_PBC");
+	}
+
+	/* Specific BSSID */
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_PBC %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_PBC command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc == 0) {
+		printf("Invalid WPS_PIN command: need one or two arguments:\n"
+		       "- BSSID: use 'any' to select any\n"
+		       "- PIN: optional, used only with devices that have no "
+		       "display\n");
+		return -1;
+	}
+
+	if (argc == 1) {
+		/* Use dynamically generated PIN (returned as reply) */
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s", argv[0]);
+		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+			printf("Too long WPS_PIN command.\n");
+			return -1;
+		}
+		return wpa_ctrl_command(ctrl, cmd);
+	}
+
+	/* Use hardcoded PIN from a label */
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_PIN %s %s", argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_PIN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_wps_reg(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 2) {
+		printf("Invalid WPS_REG command: need two arguments:\n"
+		       "- BSSID: use 'any' to select any\n"
+		       "- AP PIN\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_REG %s %s", argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_REG command.\n");
 		return -1;
 	}
 	return wpa_ctrl_command(ctrl, cmd);
@@ -1042,57 +1069,228 @@
 }
 
 
+static int wpa_cli_cmd_interface_list(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "INTERFACE_LIST");
+}
+
+
+enum wpa_cli_cmd_flags {
+	cli_cmd_flag_none		= 0x00,
+	cli_cmd_flag_sensitive		= 0x01
+};
+
 struct wpa_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+	enum wpa_cli_cmd_flags flags;
+	const char *usage;
 };
 
 static struct wpa_cli_cmd wpa_cli_commands[] = {
-	{ "status", wpa_cli_cmd_status },
-	{ "ping", wpa_cli_cmd_ping },
-	{ "mib", wpa_cli_cmd_mib },
-	{ "help", wpa_cli_cmd_help },
-	{ "interface", wpa_cli_cmd_interface },
-	{ "level", wpa_cli_cmd_level },
-	{ "license", wpa_cli_cmd_license },
-	{ "quit", wpa_cli_cmd_quit },
-	{ "set", wpa_cli_cmd_set },
-	{ "logon", wpa_cli_cmd_logon },
-	{ "logoff", wpa_cli_cmd_logoff },
-	{ "pmksa", wpa_cli_cmd_pmksa },
-	{ "reassociate", wpa_cli_cmd_reassociate },
-	{ "preauthenticate", wpa_cli_cmd_preauthenticate },
-	{ "identity", wpa_cli_cmd_identity },
-	{ "password", wpa_cli_cmd_password },
-	{ "new_password", wpa_cli_cmd_new_password },
-	{ "pin", wpa_cli_cmd_pin },
-	{ "otp", wpa_cli_cmd_otp },
-	{ "passphrase", wpa_cli_cmd_passphrase },
-	{ "bssid", wpa_cli_cmd_bssid },
-	{ "list_networks", wpa_cli_cmd_list_networks },
-	{ "select_network", wpa_cli_cmd_select_network },
-	{ "enable_network", wpa_cli_cmd_enable_network },
-	{ "disable_network", wpa_cli_cmd_disable_network },
-	{ "add_network", wpa_cli_cmd_add_network },
-	{ "remove_network", wpa_cli_cmd_remove_network },
-	{ "set_network", wpa_cli_cmd_set_network },
-	{ "get_network", wpa_cli_cmd_get_network },
-	{ "save_config", wpa_cli_cmd_save_config },
-	{ "disconnect", wpa_cli_cmd_disconnect },
-	{ "reconnect", wpa_cli_cmd_reconnect },
-	{ "scan", wpa_cli_cmd_scan },
-	{ "scan_results", wpa_cli_cmd_scan_results },
-	{ "bss", wpa_cli_cmd_bss },
-	{ "get_capability", wpa_cli_cmd_get_capability },
-	{ "reconfigure", wpa_cli_cmd_reconfigure },
-	{ "terminate", wpa_cli_cmd_terminate },
-	{ "interface_add", wpa_cli_cmd_interface_add },
-	{ "interface_remove", wpa_cli_cmd_interface_remove },
-	{ "ap_scan", wpa_cli_cmd_ap_scan },
-	{ "stkstart", wpa_cli_cmd_stkstart },
-	{ "ft_ds", wpa_cli_cmd_ft_ds },
-	{ NULL, NULL }
+	{ "status", wpa_cli_cmd_status,
+	  cli_cmd_flag_none,
+	  "[verbose] = get current WPA/EAPOL/EAP status" },
+	{ "ping", wpa_cli_cmd_ping,
+	  cli_cmd_flag_none,
+	  "= pings wpa_supplicant" },
+	{ "mib", wpa_cli_cmd_mib,
+	  cli_cmd_flag_none,
+	  "= get MIB variables (dot1x, dot11)" },
+	{ "help", wpa_cli_cmd_help,
+	  cli_cmd_flag_none,
+	  "= show this usage help" },
+	{ "interface", wpa_cli_cmd_interface,
+	  cli_cmd_flag_none,
+	  "[ifname] = show interfaces/select interface" },
+	{ "level", wpa_cli_cmd_level,
+	  cli_cmd_flag_none,
+	  "<debug level> = change debug level" },
+	{ "license", wpa_cli_cmd_license,
+	  cli_cmd_flag_none,
+	  "= show full wpa_cli license" },
+	{ "quit", wpa_cli_cmd_quit,
+	  cli_cmd_flag_none,
+	  "= exit wpa_cli" },
+	{ "set", wpa_cli_cmd_set,
+	  cli_cmd_flag_none,
+	  "= set variables (shows list of variables when run without "
+	  "arguments)" },
+	{ "logon", wpa_cli_cmd_logon,
+	  cli_cmd_flag_none,
+	  "= IEEE 802.1X EAPOL state machine logon" },
+	{ "logoff", wpa_cli_cmd_logoff,
+	  cli_cmd_flag_none,
+	  "= IEEE 802.1X EAPOL state machine logoff" },
+	{ "pmksa", wpa_cli_cmd_pmksa,
+	  cli_cmd_flag_none,
+	  "= show PMKSA cache" },
+	{ "reassociate", wpa_cli_cmd_reassociate,
+	  cli_cmd_flag_none,
+	  "= force reassociation" },
+	{ "preauthenticate", wpa_cli_cmd_preauthenticate,
+	  cli_cmd_flag_none,
+	  "<BSSID> = force preauthentication" },
+	{ "identity", wpa_cli_cmd_identity,
+	  cli_cmd_flag_none,
+	  "<network id> <identity> = configure identity for an SSID" },
+	{ "password", wpa_cli_cmd_password,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = configure password for an SSID" },
+	{ "new_password", wpa_cli_cmd_new_password,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = change password for an SSID" },
+	{ "pin", wpa_cli_cmd_pin,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <pin> = configure pin for an SSID" },
+	{ "otp", wpa_cli_cmd_otp,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <password> = configure one-time-password for an SSID"
+	},
+	{ "passphrase", wpa_cli_cmd_passphrase,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <passphrase> = configure private key passphrase\n"
+	  "  for an SSID" },
+	{ "bssid", wpa_cli_cmd_bssid,
+	  cli_cmd_flag_none,
+	  "<network id> <BSSID> = set preferred BSSID for an SSID" },
+	{ "list_networks", wpa_cli_cmd_list_networks,
+	  cli_cmd_flag_none,
+	  "= list configured networks" },
+	{ "select_network", wpa_cli_cmd_select_network,
+	  cli_cmd_flag_none,
+	  "<network id> = select a network (disable others)" },
+	{ "enable_network", wpa_cli_cmd_enable_network,
+	  cli_cmd_flag_none,
+	  "<network id> = enable a network" },
+	{ "disable_network", wpa_cli_cmd_disable_network,
+	  cli_cmd_flag_none,
+	  "<network id> = disable a network" },
+	{ "add_network", wpa_cli_cmd_add_network,
+	  cli_cmd_flag_none,
+	  "= add a network" },
+	{ "remove_network", wpa_cli_cmd_remove_network,
+	  cli_cmd_flag_none,
+	  "<network id> = remove a network" },
+	{ "set_network", wpa_cli_cmd_set_network,
+	  cli_cmd_flag_sensitive,
+	  "<network id> <variable> <value> = set network variables (shows\n"
+	  "  list of variables when run without arguments)" },
+	{ "get_network", wpa_cli_cmd_get_network,
+	  cli_cmd_flag_none,
+	  "<network id> <variable> = get network variables" },
+	{ "save_config", wpa_cli_cmd_save_config,
+	  cli_cmd_flag_none,
+	  "= save the current configuration" },
+	{ "disconnect", wpa_cli_cmd_disconnect,
+	  cli_cmd_flag_none,
+	  "= disconnect and wait for reassociate/reconnect command before\n"
+	  "  connecting" },
+	{ "reconnect", wpa_cli_cmd_reconnect,
+	  cli_cmd_flag_none,
+	  "= like reassociate, but only takes effect if already disconnected"
+	},
+	{ "scan", wpa_cli_cmd_scan,
+	  cli_cmd_flag_none,
+	  "= request new BSS scan" },
+	{ "scan_results", wpa_cli_cmd_scan_results,
+	  cli_cmd_flag_none,
+	  "= get latest scan results" },
+	{ "bss", wpa_cli_cmd_bss,
+	  cli_cmd_flag_none,
+	  "<<idx> | <bssid>> = get detailed scan result info" },
+	{ "get_capability", wpa_cli_cmd_get_capability,
+	  cli_cmd_flag_none,
+	  "<eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies" },
+	{ "reconfigure", wpa_cli_cmd_reconfigure,
+	  cli_cmd_flag_none,
+	  "= force wpa_supplicant to re-read its configuration file" },
+	{ "terminate", wpa_cli_cmd_terminate,
+	  cli_cmd_flag_none,
+	  "= terminate wpa_supplicant" },
+	{ "interface_add", wpa_cli_cmd_interface_add,
+	  cli_cmd_flag_none,
+	  "<ifname> <confname> <driver> <ctrl_interface> <driver_param>\n"
+	  "  <bridge_name> = adds new interface, all parameters but <ifname>\n"
+	  "  are optional" },
+	{ "interface_remove", wpa_cli_cmd_interface_remove,
+	  cli_cmd_flag_none,
+	  "<ifname> = removes the interface" },
+	{ "interface_list", wpa_cli_cmd_interface_list,
+	  cli_cmd_flag_none,
+	  "= list available interfaces" },
+	{ "ap_scan", wpa_cli_cmd_ap_scan,
+	  cli_cmd_flag_none,
+	  "<value> = set ap_scan parameter" },
+	{ "stkstart", wpa_cli_cmd_stkstart,
+	  cli_cmd_flag_none,
+	  "<addr> = request STK negotiation with <addr>" },
+	{ "ft_ds", wpa_cli_cmd_ft_ds,
+	  cli_cmd_flag_none,
+	  "<addr> = request over-the-DS FT with <addr>" },
+	{ "wps_pbc", wpa_cli_cmd_wps_pbc,
+	  cli_cmd_flag_none,
+	  "[BSSID] = start Wi-Fi Protected Setup: Push Button Configuration" },
+	{ "wps_pin", wpa_cli_cmd_wps_pin,
+	  cli_cmd_flag_sensitive,
+	  "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
+	  "hardcoded)" },
+	{ "wps_reg", wpa_cli_cmd_wps_reg,
+	  cli_cmd_flag_sensitive,
+	  "<BSSID> <AP PIN> = start WPS Registrar to configure an AP" },
+	{ NULL, NULL, cli_cmd_flag_none, NULL }
 };
+
+
+/*
+ * Prints command usage, lines are padded with the specified string.
+ */
+static void print_cmd_help(struct wpa_cli_cmd *cmd, const char *pad)
+{
+	char c;
+	size_t n;
+
+	printf("%s%s ", pad, cmd->cmd);
+	for (n = 0; (c = cmd->usage[n]); n++) {
+		printf("%c", c);
+		if (c == '\n')
+			printf("%s", pad);
+	}
+	printf("\n");
+}
+
+
+static void print_help(void)
+{
+	int n;
+	printf("commands:\n");
+	for (n = 0; wpa_cli_commands[n].cmd; n++)
+		print_cmd_help(&wpa_cli_commands[n], "  ");
+}
+
+
+#ifdef CONFIG_READLINE
+static int cmd_has_sensitive_data(const char *cmd)
+{
+	const char *c, *delim;
+	int n;
+	size_t len;
+
+	delim = os_strchr(cmd, ' ');
+	if (delim)
+		len = delim - cmd;
+	else
+		len = os_strlen(cmd);
+
+	for (n = 0; (c = wpa_cli_commands[n].cmd); n++) {
+		if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c))
+			return (wpa_cli_commands[n].flags &
+				cli_cmd_flag_sensitive);
+	}
+	return 0;
+}
+#endif /* CONFIG_READLINE */
 
 
 static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1430,24 +1628,20 @@
 		 * passwords. */
 		HIST_ENTRY *h;
 		history_set_pos(0);
-		h = next_history();
-		while (h) {
+		while ((h = current_history())) {
 			char *p = h->line;
 			while (*p == ' ' || *p == '\t')
 				p++;
-			if (os_strncasecmp(p, "pa", 2) == 0 ||
-			    os_strncasecmp(p, "o", 1) == 0 ||
-			    os_strncasecmp(p, "n", 1)) {
+			if (cmd_has_sensitive_data(p)) {
 				h = remove_history(where_history());
 				if (h) {
 					os_free(h->line);
 					os_free(h->data);
 					os_free(h);
-				}
-				h = current_history();
-			} else {
-				h = next_history();
-			}
+				} else
+					next_history();
+			} else
+				next_history();
 		}
 		write_history(hfile);
 		os_free(hfile);

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.cpp?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.cpp (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.cpp Sat Jan 10 08:43:01 2009
@@ -1,0 +1,245 @@
+/*
+ * wpa_gui - AddInterface class
+ * 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 <cstdio>
+#include "wpa_ctrl.h"
+
+#include <QMessageBox>
+
+#include "wpagui.h"
+#include "addinterface.h"
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <windows.h>
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent)
+	: QDialog(parent), wpagui(_wpagui)
+{
+	setWindowTitle("Select network interface to add");
+	resize(400, 200);
+	vboxLayout = new QVBoxLayout(this);
+
+	interfaceWidget = new QTreeWidget(this);
+	interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+	interfaceWidget->setUniformRowHeights(true);
+	interfaceWidget->setSortingEnabled(true);
+	interfaceWidget->setColumnCount(3);
+	interfaceWidget->headerItem()->setText(0, "driver");
+	interfaceWidget->headerItem()->setText(1, "interface");
+	interfaceWidget->headerItem()->setText(2, "description");
+	interfaceWidget->setItemsExpandable(FALSE);
+	interfaceWidget->setRootIsDecorated(FALSE);
+	vboxLayout->addWidget(interfaceWidget);
+
+	connect(interfaceWidget,
+		SIGNAL(itemActivated(QTreeWidgetItem *, int)), this,
+		SLOT(interfaceSelected(QTreeWidgetItem *)));
+
+	addInterfaces();
+}
+
+
+void AddInterface::addInterfaces()
+{
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	struct wpa_ctrl *ctrl;
+	int ret;
+	char buf[2048];
+	size_t len;
+
+	ctrl = wpa_ctrl_open(NULL);
+	if (ctrl == NULL)
+		return;
+
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL);
+	if (ret < 0) {
+		wpa_ctrl_close(ctrl);
+		return;
+	}
+	buf[len] = '\0';
+
+	wpa_ctrl_close(ctrl);
+
+	QString ifaces(buf);
+	QStringList lines = ifaces.split(QRegExp("\\n"));
+	for (QStringList::Iterator it = lines.begin();
+	     it != lines.end(); it++) {
+		QStringList arg = (*it).split(QChar('\t'));
+		if (arg.size() < 3)
+			continue;
+		QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget);
+		if (!item)
+			break;
+
+		item->setText(0, arg[0]);
+		item->setText(1, arg[1]);
+		item->setText(2, arg[2]);
+	}
+
+	interfaceWidget->resizeColumnToContents(0);
+	interfaceWidget->resizeColumnToContents(1);
+	interfaceWidget->resizeColumnToContents(2);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+bool AddInterface::addRegistryInterface(const QString &ifname)
+{
+	HKEY hk, ihk;
+	LONG ret;
+	int id, tmp;
+	TCHAR name[10];
+	DWORD val, i;
+
+	ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"),
+			   0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY,
+			   &hk);
+	if (ret != ERROR_SUCCESS)
+		return false;
+
+	id = -1;
+
+	for (i = 0; ; i++) {
+		TCHAR name[255];
+		DWORD namelen;
+
+		namelen = 255;
+		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
+				   NULL);
+
+		if (ret == ERROR_NO_MORE_ITEMS)
+			break;
+
+		if (ret != ERROR_SUCCESS)
+			break;
+
+		if (namelen >= 255)
+			namelen = 255 - 1;
+		name[namelen] = '\0';
+
+#ifdef UNICODE
+		QString s((QChar *) name, namelen);
+#else /* UNICODE */
+		QString s(name);
+#endif /* UNICODE */
+		tmp = s.toInt();
+		if (tmp > id)
+			id = tmp;
+	}
+
+	id += 1;
+
+#ifdef UNICODE
+	wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+	os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+	ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk,
+			     NULL);
+	RegCloseKey(hk);
+	if (ret != ERROR_SUCCESS)
+		return false;
+
+#ifdef UNICODE
+	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
+		      (LPBYTE) ifname.unicode(),
+		      (ifname.length() + 1) * sizeof(TCHAR));
+
+#else /* UNICODE */
+	RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
+		      (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1);
+#endif /* UNICODE */
+	RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ,
+		      (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR));
+	RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ,
+		      (LPBYTE) TEXT(""), 1 * sizeof(TCHAR));
+	val = 1;
+	RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val,
+		      sizeof(val));
+
+	RegCloseKey(ihk);
+	return true;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void AddInterface::interfaceSelected(QTreeWidgetItem *sel)
+{
+	if (!sel)
+		return;
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	struct wpa_ctrl *ctrl;
+	int ret;
+	char buf[20], cmd[256];
+	size_t len;
+
+	/*
+	 * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
+	 * <driver_param>TAB<bridge_name>
+	 */
+	snprintf(cmd, sizeof(cmd),
+		 "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+		 sel->text(1).toAscii().constData(),
+		 "default",
+		 sel->text(0).toAscii().constData(),
+		 "yes", "", "");
+	cmd[sizeof(cmd) - 1] = '\0';
+
+	ctrl = wpa_ctrl_open(NULL);
+	if (ctrl == NULL)
+		return;
+
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
+	wpa_ctrl_close(ctrl);
+
+	if (ret < 0) {
+		QMessageBox::warning(this, "wpa_gui",
+				     "Add interface command could not be "
+				     "completed.");
+		return;
+	}
+
+	buf[len] = '\0';
+	if (buf[0] != 'O' || buf[1] != 'K') {
+		QMessageBox::warning(this, "wpa_gui",
+				     "Failed to add the interface.");
+		return;
+	}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+	if (!addRegistryInterface(sel->text(1))) {
+		QMessageBox::information(this, "wpa_gui",
+					 "Failed to add the interface into "
+					 "registry.");
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	wpagui->selectAdapter(sel->text(1));
+	close();
+}

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.h (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/addinterface.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,45 @@
+/*
+ * wpa_gui - AddInterface class
+ * 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 ADDINTERFACE_H
+#define ADDINTERFACE_H
+
+#include <QObject>
+
+#include <QtGui/QDialog>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QVBoxLayout>
+
+class WpaGui;
+
+class AddInterface : public QDialog
+{
+	Q_OBJECT
+
+public:
+	AddInterface(WpaGui *_wpagui, QWidget *parent = 0);
+
+public slots:
+	virtual void interfaceSelected(QTreeWidgetItem *sel);
+
+private:
+	void addInterfaces();
+	bool addRegistryInterface(const QString &ifname);
+
+	QVBoxLayout *vboxLayout;
+	QTreeWidget *interfaceWidget;
+	WpaGui *wpagui;
+};
+
+#endif /* ADDINTERFACE_H */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp Sat Jan 10 08:43:01 2009
@@ -44,6 +44,7 @@
 	connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork()));
 	connect(eapSelect, SIGNAL(activated(int)), this,
 		SLOT(eapChanged(int)));
+	connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps()));
 
 	wpagui = NULL;
 	new_network = false;
@@ -98,6 +99,10 @@
 	wepEnabled(auth == AUTH_NONE && encr == 1);
 
 	getEapCapa();
+
+	if (flags.indexOf("[WPS") >= 0)
+		useWpsButton->setEnabled(true);
+	bssid = sel->text(1);
 }
 
 
@@ -273,7 +278,7 @@
 		setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
 	}
 	if (pskEdit->isEnabled() &&
-	    strcmp(passwordEdit->text().toAscii().constData(),
+	    strcmp(pskEdit->text().toAscii().constData(),
 		   WPA_GUI_KEY_DATA) != 0)
 		setNetworkParam(id, "psk",
 				pskEdit->text().toAscii().constData(),
@@ -646,7 +651,7 @@
 		if (strncmp(reply, "\"auth=", 6))
 			break;
 		if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) {
-			val = "GTC(auth) + MSCHAPv2(prov)";
+			val = (char *) "GTC(auth) + MSCHAPv2(prov)";
 			break;
 		}
 		val = reply + 2;
@@ -806,3 +811,13 @@
 	QStringList types = res.split(QChar(' '));
 	eapSelect->insertItems(-1, types);
 }
+
+
+void NetworkConfig::useWps()
+{
+	if (wpagui == NULL)
+		return;
+	wpagui->setBssFromScan(bssid);
+	wpagui->wpsDialog();
+	close();
+}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.h Sat Jan 10 08:43:01 2009
@@ -43,6 +43,7 @@
 	virtual void writeWepKey(int network_id, QLineEdit *edit, int id);
 	virtual void removeNetwork();
 	virtual void eapChanged(int sel);
+	virtual void useWps();
 
 protected slots:
 	virtual void languageChange();
@@ -51,6 +52,7 @@
 	WpaGui *wpagui;
 	int edit_network_id;
 	bool new_network;
+	QString bssid;
 
 	virtual void wepEnabled(bool enabled);
 	virtual void getEapCapa();

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.ui?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.ui (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/networkconfig.ui Sat Jan 10 08:43:01 2009
@@ -349,14 +349,14 @@
      </layout>
     </widget>
    </item>
-   <item row="1" column="1" >
+   <item row="1" column="2" >
     <widget class="QPushButton" name="addButton" >
      <property name="text" >
       <string>Add</string>
      </property>
     </widget>
    </item>
-   <item row="1" column="2" >
+   <item row="1" column="3" >
     <widget class="QPushButton" name="removeButton" >
      <property name="enabled" >
       <bool>false</bool>
@@ -378,6 +378,16 @@
       </size>
      </property>
     </spacer>
+   </item>
+   <item row="1" column="1" >
+    <widget class="QPushButton" name="useWpsButton" >
+     <property name="enabled" >
+      <bool>false</bool>
+     </property>
+     <property name="text" >
+      <string>WPS</string>
+     </property>
+    </widget>
    </item>
   </layout>
  </widget>

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro Sat Jan 10 08:43:01 2009
@@ -15,6 +15,13 @@
   DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
   SOURCES += ../../src/utils/os_win32.c
   RESOURCES += icons_png.qrc
+} else:win32-x-g++ {
+  # cross compilation to win32
+  LIBS += -lws2_32 -static -mwindows
+  DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+  DEFINES += _X86_
+  SOURCES += ../../src/utils/os_win32.c
+  RESOURCES += icons_png.qrc
 } else {
   DEFINES += CONFIG_CTRL_IFACE_UNIX
   SOURCES += ../../src/utils/os_unix.c
@@ -27,7 +34,8 @@
 	eventhistory.h \
 	scanresults.h \
 	userdatarequest.h \
-	networkconfig.h
+	networkconfig.h \
+	addinterface.h
 
 SOURCES	+= main.cpp \
 	wpagui.cpp \
@@ -35,6 +43,7 @@
 	scanresults.cpp \
 	userdatarequest.cpp \
 	networkconfig.cpp \
+	addinterface.cpp \
 	../../src/common/wpa_ctrl.c
 
 RESOURCES += icons.qrc

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.cpp Sat Jan 10 08:43:01 2009
@@ -17,6 +17,10 @@
 #include <unistd.h>
 #endif
 
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <windows.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
 #include <cstdio>
 #include <QMessageBox>
 #include <QCloseEvent>
@@ -42,12 +46,37 @@
 {
 	setupUi(this);
 
+#ifdef CONFIG_NATIVE_WINDOWS
+	fileStopServiceAction = new QAction(this);
+	fileStopServiceAction->setObjectName("Stop Service");
+	fileStopServiceAction->setIconText("Stop Service");
+	fileMenu->insertAction(actionWPS, fileStopServiceAction);
+
+	fileStartServiceAction = new QAction(this);
+	fileStartServiceAction->setObjectName("Start Service");
+	fileStartServiceAction->setIconText("Start Service");
+	fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
+
+	connect(fileStartServiceAction, SIGNAL(triggered()), this,
+		SLOT(startService()));
+	connect(fileStopServiceAction, SIGNAL(triggered()), this,
+		SLOT(stopService()));
+
+	addInterfaceAction = new QAction(this);
+	addInterfaceAction->setIconText("Add Interface");
+	fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
+
+	connect(addInterfaceAction, SIGNAL(triggered()), this,
+		SLOT(addInterface()));
+#endif /* CONFIG_NATIVE_WINDOWS */
+
 	(void) statusBar();
 
 	connect(fileEventHistoryAction, SIGNAL(triggered()), this,
 		SLOT(eventHistory()));
 	connect(fileSaveConfigAction, SIGNAL(triggered()), this,
 		SLOT(saveConfig()));
+	connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog()));
 	connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
 	connect(networkAddAction, SIGNAL(triggered()), this,
 		SLOT(addNetwork()));
@@ -86,9 +115,17 @@
 	connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
 	connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
 		this, SLOT(editListedNetwork()));
+	connect(wpaguiTab, SIGNAL(currentChanged(int)), this,
+		SLOT(tabChanged(int)));
+	connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc()));
+	connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin()));
+	connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this,
+		SLOT(wpsApPinChanged(const QString &)));
+	connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin()));
 
 	eh = NULL;
 	scanres = NULL;
+	add_iface = NULL;
 	udr = NULL;
 	tray_icon = NULL;
 	startInTray = false;
@@ -105,6 +142,7 @@
 	else
 		show();
 
+	connectedToService = false;
 	textStatus->setText("connecting to wpa_supplicant");
 	timer = new QTimer(this);
 	connect(timer, SIGNAL(timeout()), SLOT(ping()));
@@ -146,6 +184,12 @@
 		scanres->close();
 		delete scanres;
 		scanres = NULL;
+	}
+
+	if (add_iface) {
+		add_iface->close();
+		delete add_iface;
+		add_iface = NULL;
 	}
 
 	if (udr) {
@@ -250,6 +294,7 @@
 			ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
 					       &len, NULL);
 			if (ret >= 0) {
+				connectedToService = true;
 				buf[len] = '\0';
 				pos = strchr(buf, '\n');
 				if (pos)
@@ -261,8 +306,22 @@
 #endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
 	}
 
-	if (ctrl_iface == NULL)
+	if (ctrl_iface == NULL) {
+#ifdef CONFIG_NATIVE_WINDOWS
+		static bool first = true;
+		if (first && !serviceRunning()) {
+			first = false;
+			if (QMessageBox::warning(
+				    this, qAppName(),
+				    "wpa_supplicant service is not running.\n"
+				    "Do you want to start it?",
+				    QMessageBox::Yes | QMessageBox::No) ==
+			    QMessageBox::Yes)
+				startService();
+		}
+#endif /* CONFIG_NATIVE_WINDOWS */
 		return -1;
+	}
 
 #ifdef CONFIG_CTRL_IFACE_UNIX
 	flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
@@ -340,6 +399,16 @@
 		}
 	}
 
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
+			     NULL) >= 0) {
+		buf[len] = '\0';
+
+		QString res(buf);
+		QStringList types = res.split(QChar(' '));
+		actionWPS->setEnabled(types.contains("WSC"));
+	}
+
 	return 0;
 }
 
@@ -385,6 +454,21 @@
 		textSsid->clear();
 		textBssid->clear();
 		textIpAddress->clear();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+		static bool first = true;
+		if (first && connectedToService &&
+		    (ctrl_iface == NULL || *ctrl_iface == '\0')) {
+			first = false;
+			if (QMessageBox::information(
+				    this, qAppName(),
+				    "No network interfaces in use.\n"
+				    "Would you like to add one?",
+				    QMessageBox::Yes | QMessageBox::No) ==
+			    QMessageBox::Yes)
+				addInterface();
+		}
+#endif /* CONFIG_NATIVE_WINDOWS */
 		return;
 	}
 
@@ -599,6 +683,7 @@
 	char reply[10];
 	size_t reply_len = sizeof(reply);
 	ctrlRequest("DISCONNECT", reply, &reply_len);
+	stopWpsRun(false);
 }
 
 
@@ -679,6 +764,14 @@
 		updateStatus();
 		updateNetworks();
 	}
+
+#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
+	/* Use less frequent pings and status updates when the main window is
+	 * hidden (running in taskbar). */
+	int interval = isHidden() ? 5000 : 1000;
+	if (timer->interval() != interval)
+		timer->setInterval(interval);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
 }
 
 
@@ -738,6 +831,49 @@
 		showTrayMessage(QSystemTrayIcon::Information, 3,
 				"Connection to network established.");
 		QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
+		stopWpsRun(true);
+	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
+		showTrayMessage(QSystemTrayIcon::Information, 3,
+				"Wi-Fi Protected Setup (WPS) AP\n"
+				"in active PBC mode found.");
+		wpsStatusText->setText("WPS AP in active PBC mode found");
+		wpaguiTab->setCurrentWidget(wpsTab);
+		wpsInstructions->setText("Press the PBC button on the screen "
+					 "to start registration");
+	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
+		showTrayMessage(QSystemTrayIcon::Information, 3,
+				"Wi-Fi Protected Setup (WPS) AP\n"
+				" in active PIN mode found.");
+		wpsStatusText->setText("WPS AP with recently selected "
+				       "registrar");
+		wpaguiTab->setCurrentWidget(wpsTab);
+	} else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
+		showTrayMessage(QSystemTrayIcon::Information, 3,
+				"Wi-Fi Protected Setup (WPS)\n"
+				"AP detected.");
+		wpsStatusText->setText("WPS AP detected");
+		wpaguiTab->setCurrentWidget(wpsTab);
+	} else if (str_match(pos, WPS_EVENT_OVERLAP)) {
+		showTrayMessage(QSystemTrayIcon::Information, 3,
+				"Wi-Fi Protected Setup (WPS)\n"
+				"PBC mode overlap detected.");
+		wpsStatusText->setText("PBC mode overlap detected");
+		wpsInstructions->setText("More than one AP is currently in "
+					 "active WPS PBC mode. Wait couple of "
+					 "minutes and try again");
+		wpaguiTab->setCurrentWidget(wpsTab);
+	} else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
+		wpsStatusText->setText("Network configuration received");
+		wpaguiTab->setCurrentWidget(wpsTab);
+	} else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
+		if (strstr(pos, "(WSC)"))
+			wpsStatusText->setText("Registration started");
+	} else if (str_match(pos, WPS_EVENT_M2D)) {
+		wpsStatusText->setText("Registrar does not yet know PIN");
+	} else if (str_match(pos, WPS_EVENT_FAIL)) {
+		wpsStatusText->setText("Registration failed");
+	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+		wpsStatusText->setText("Registration succeeded");
 	}
 }
 
@@ -804,6 +940,7 @@
 	cmd.prepend("SELECT_NETWORK ");
 	ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
 	triggerUpdate();
+	stopWpsRun(false);
 }
 
 
@@ -1275,3 +1412,254 @@
 
 	event->accept();
 }
+
+
+void WpaGui::wpsDialog()
+{
+	wpaguiTab->setCurrentWidget(wpsTab);
+}
+
+
+void WpaGui::tabChanged(int index)
+{
+	if (index != 2)
+		return;
+
+	if (wpsRunning)
+		return;
+
+	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+	if (bssFromScan.isEmpty())
+		wpsApPinButton->setEnabled(false);
+}
+
+
+void WpaGui::wpsPbc()
+{
+	char reply[20];
+	size_t reply_len = sizeof(reply);
+
+	if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
+		return;
+
+	wpsPinEdit->setEnabled(false);
+	if (wpsStatusText->text().compare("WPS AP in active PBC mode found")) {
+		wpsInstructions->setText("Press the push button on the AP to "
+					 "start the PBC mode.");
+	} else {
+		wpsInstructions->setText("If you have not yet done so, press "
+					 "the push button on the AP to start "
+					 "the PBC mode.");
+	}
+	wpsStatusText->setText("Waiting for Registrar");
+	wpsRunning = true;
+}
+
+
+void WpaGui::wpsGeneratePin()
+{
+	char reply[20];
+	size_t reply_len = sizeof(reply) - 1;
+
+	if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
+		return;
+
+	reply[reply_len] = '\0';
+
+	wpsPinEdit->setText(reply);
+	wpsPinEdit->setEnabled(true);
+	wpsInstructions->setText("Enter the generated PIN into the Registrar "
+				 "(either the internal one in the AP or an "
+				 "external one).");
+	wpsStatusText->setText("Waiting for Registrar");
+	wpsRunning = true;
+}
+
+
+void WpaGui::setBssFromScan(const QString &bssid)
+{
+	bssFromScan = bssid;
+	wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+	wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
+	wpsStatusText->setText("WPS AP selected from scan results");
+	wpsInstructions->setText("If you want to use an AP device PIN, e.g., "
+				 "from a label in the device, enter the eight "
+				 "digit AP PIN and click Use AP PIN button.");
+}
+
+
+void WpaGui::wpsApPinChanged(const QString &text)
+{
+	wpsApPinButton->setEnabled(text.length() == 8);
+}
+
+
+void WpaGui::wpsApPin()
+{
+	char reply[20];
+	size_t reply_len = sizeof(reply);
+
+	QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
+	if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
+		return;
+
+	wpsStatusText->setText("Waiting for AP/Enrollee");
+	wpsRunning = true;
+}
+
+
+void WpaGui::stopWpsRun(bool success)
+{
+	if (wpsRunning)
+		wpsStatusText->setText(success ? "Connected to the network" :
+				       "Stopped");
+	else
+		wpsStatusText->setText("");
+	wpsPinEdit->setEnabled(false);
+	wpsInstructions->setText("");
+	wpsRunning = false;
+	bssFromScan = "";
+	wpsApPinEdit->setEnabled(false);
+	wpsApPinButton->setEnabled(false);
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+
+class ErrorMsg : public QMessageBox {
+public:
+	ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
+	void showMsg(QString msg);
+private:
+	DWORD err;
+};
+
+ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
+	QMessageBox(parent), err(last_err)
+{
+	setWindowTitle("wpa_gui error");
+	setIcon(QMessageBox::Warning);
+}
+
+void ErrorMsg::showMsg(QString msg)
+{
+	LPTSTR buf;
+
+	setText(msg);
+	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			  FORMAT_MESSAGE_FROM_SYSTEM,
+			  NULL, err, 0, (LPTSTR) (void *) &buf,
+			  0, NULL) > 0) {
+		QString msg = QString::fromWCharArray(buf);
+		setInformativeText(QString("[%1] %2").arg(err).arg(msg));
+		LocalFree(buf);
+	} else {
+		setInformativeText(QString("[%1]").arg(err));
+	}
+
+	exec();
+}
+
+
+void WpaGui::startService()
+{
+	SC_HANDLE svc, scm;
+
+	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+	if (!scm) {
+		ErrorMsg(this).showMsg("OpenSCManager failed");
+		return;
+	}
+
+	svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
+	if (!svc) {
+		ErrorMsg(this).showMsg("OpenService failed");
+		CloseServiceHandle(scm);
+		return;
+	}
+
+	if (!StartService(svc, 0, NULL)) {
+		ErrorMsg(this).showMsg("Failed to start wpa_supplicant "
+				       "service");
+	}
+
+	CloseServiceHandle(svc);
+	CloseServiceHandle(scm);
+}
+
+
+void WpaGui::stopService()
+{
+	SC_HANDLE svc, scm;
+	SERVICE_STATUS status;
+
+	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+	if (!scm) {
+		ErrorMsg(this).showMsg("OpenSCManager failed");
+		return;
+	}
+
+	svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
+	if (!svc) {
+		ErrorMsg(this).showMsg("OpenService failed");
+		CloseServiceHandle(scm);
+		return;
+	}
+
+	if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
+		ErrorMsg(this).showMsg("Failed to stop wpa_supplicant "
+				       "service");
+	}
+
+	CloseServiceHandle(svc);
+	CloseServiceHandle(scm);
+}
+
+
+bool WpaGui::serviceRunning()
+{
+	SC_HANDLE svc, scm;
+	SERVICE_STATUS status;
+	bool running = false;
+
+	scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+	if (!scm) {
+		printf("OpenSCManager failed: %d\n", (int) GetLastError());
+		return false;
+	}
+
+	svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
+	if (!svc) {
+		printf("OpenService failed: %d\n\n", (int) GetLastError());
+		CloseServiceHandle(scm);
+		return false;
+	}
+
+	if (QueryServiceStatus(svc, &status)) {
+		if (status.dwCurrentState != SERVICE_STOPPED)
+			running = true;
+	}
+
+	CloseServiceHandle(svc);
+	CloseServiceHandle(scm);
+
+	return running;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void WpaGui::addInterface()
+{
+	if (add_iface) {
+		add_iface->close();
+		delete add_iface;
+	}
+	add_iface = new AddInterface(this, this);
+	add_iface->show();
+	add_iface->exec();
+}

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.h Sat Jan 10 08:43:01 2009
@@ -18,6 +18,7 @@
 #include <QSystemTrayIcon>
 #include <QObject>
 #include "ui_wpagui.h"
+#include "addinterface.h"
 
 class UserDataRequest;
 
@@ -38,6 +39,7 @@
 	virtual void enableNetwork(const QString &sel);
 	virtual void disableNetwork(const QString &sel);
 	virtual int getNetworkDisabled(const QString &sel);
+	void setBssFromScan(const QString &bssid);
 
 public slots:
 	virtual void parse_argv();
@@ -71,6 +73,17 @@
 	virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
 				     int sec, const QString &msg);
 	virtual void showTrayStatus();
+	virtual void wpsDialog();
+	virtual void tabChanged(int index);
+	virtual void wpsPbc();
+	virtual void wpsGeneratePin();
+	virtual void wpsApPinChanged(const QString &text);
+	virtual void wpsApPin();
+#ifdef CONFIG_NATIVE_WINDOWS
+	virtual void startService();
+	virtual void stopService();
+#endif /* CONFIG_NATIVE_WINDOWS */
+	virtual void addInterface();
 
 protected slots:
 	virtual void languageChange();
@@ -105,6 +118,24 @@
 	bool startInTray;
 
 	int openCtrlConnection(const char *ifname);
+
+	bool wpsRunning;
+
+	QString bssFromScan;
+
+	void stopWpsRun(bool success);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+	QAction *fileStartServiceAction;
+	QAction *fileStopServiceAction;
+
+	bool serviceRunning();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	QAction *addInterfaceAction;
+	AddInterface *add_iface;
+
+	bool connectedToService;
 };
 
 #endif /* WPAGUI_H */

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_gui-qt4/wpagui.ui Sat Jan 10 08:43:01 2009
@@ -289,6 +289,89 @@
         </item>
        </layout>
       </widget>
+      <widget class="QWidget" name="wpsTab" >
+       <attribute name="title" >
+        <string>WPS</string>
+       </attribute>
+       <layout class="QGridLayout" name="gridLayout" >
+        <item row="0" column="0" >
+         <widget class="QLabel" name="label_2" >
+          <property name="text" >
+           <string>Status:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" colspan="3" >
+         <widget class="QLabel" name="wpsStatusText" >
+          <property name="text" >
+           <string/>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0" colspan="2" >
+         <widget class="QPushButton" name="wpsPbcButton" >
+          <property name="text" >
+           <string>PBC - push button</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0" colspan="2" >
+         <widget class="QPushButton" name="wpsPinButton" >
+          <property name="text" >
+           <string>Generate PIN</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="2" >
+         <widget class="QLabel" name="label" >
+          <property name="text" >
+           <string>PIN:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="3" >
+         <widget class="QLineEdit" name="wpsPinEdit" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="readOnly" >
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0" colspan="2" >
+         <widget class="QPushButton" name="wpsApPinButton" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="text" >
+           <string>Use AP PIN</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="2" >
+         <widget class="QLabel" name="label_3" >
+          <property name="text" >
+           <string>AP PIN:</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="3" >
+         <widget class="QLineEdit" name="wpsApPinEdit" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="0" colspan="4" >
+         <widget class="QTextEdit" name="wpsInstructions" >
+          <property name="readOnly" >
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
      </widget>
     </item>
    </layout>
@@ -308,6 +391,7 @@
     </property>
     <addaction name="fileEventHistoryAction" />
     <addaction name="fileSaveConfigAction" />
+    <addaction name="actionWPS" />
     <addaction name="separator" />
     <addaction name="fileExitAction" />
    </widget>
@@ -408,6 +492,14 @@
     <string>&amp;About</string>
    </property>
   </action>
+  <action name="actionWPS" >
+   <property name="enabled" >
+    <bool>false</bool>
+   </property>
+   <property name="text" >
+    <string>&amp;Wi-Fi Protected Setup</string>
+   </property>
+  </action>
  </widget>
  <layoutdefault spacing="6" margin="11" />
  <pixmapfunction></pixmapfunction>

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=1303&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 Jan 10 08:43:01 2009
@@ -179,7 +179,7 @@
 	setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
     }
     if (pskEdit->isEnabled() &&
-	strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
+	strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
 	setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
     if (eapSelect->isEnabled())
 	setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.c Sat Jan 10 08:43:01 2009
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant
- * Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2003-2009, 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
@@ -38,10 +38,11 @@
 #include "ieee802_11_defs.h"
 #include "blacklist.h"
 #include "wpas_glue.h"
+#include "wps_supplicant.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2008, Jouni Malinen <j at w1.fi> and contributors";
+"Copyright (c) 2003-2009, Jouni Malinen <j at w1.fi> and contributors";
 
 const char *wpa_supplicant_license =
 "This program is free software. You can distribute it and/or modify it\n"
@@ -107,8 +108,6 @@
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-extern struct wpa_driver_ops *wpa_supplicant_drivers[];
-
 extern int wpa_debug_level;
 extern int wpa_debug_show_keys;
 extern int wpa_debug_timestamp;
@@ -251,10 +250,9 @@
 	struct eapol_config eapol_conf;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
-		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
-	}
+	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
 		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
@@ -282,7 +280,8 @@
 	eapol_conf.workaround = ssid->eap_workaround;
 	eapol_conf.eap_disabled =
 		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
-		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 }
@@ -302,7 +301,9 @@
 {
 	int i;
 
-	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
+	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
 	else
 		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
@@ -382,6 +383,8 @@
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
 
 	ieee80211_sta_deinit(wpa_s);
+
+	wpas_wps_deinit(wpa_s);
 }
 
 
@@ -635,6 +638,8 @@
 		return KEY_MGMT_802_1X_SHA256;
 	case WPA_KEY_MGMT_PSK_SHA256:
 		return KEY_MGMT_PSK_SHA256;
+	case WPA_KEY_MGMT_WPS:
+		return KEY_MGMT_WPS;
 	case WPA_KEY_MGMT_PSK:
 	default:
 		return KEY_MGMT_PSK;
@@ -927,6 +932,17 @@
 			wpa_ft_prepare_auth_request(wpa_s->wpa);
 		}
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+		   wpa_s->conf->ap_scan == 2 &&
+		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		/* Use ap_scan==1 style network selection to find the network
+		 */
+		wpa_s->scan_req = 2;
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return;
+#endif /* CONFIG_WPS */
 	} else {
 		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
 			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
@@ -1001,6 +1017,18 @@
 				   "results)");
 			return;
 		}
+#ifdef CONFIG_WPS
+	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+		if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+			wpa_ie_len = wpabuf_len(wps_ie);
+			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
+		} else
+			wpa_ie_len = 0;
+		wpabuf_free(wps_ie);
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+#endif /* CONFIG_WPS */
 	} else {
 		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
 		wpa_ie_len = 0;
@@ -1019,6 +1047,8 @@
 			wep_keys_set = 1;
 		}
 	}
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
+		use_crypt = 0;
 
 #ifdef IEEE8021X_EAPOL
 	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
@@ -1089,6 +1119,18 @@
 	case IEEE80211W_REQUIRED:
 		params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED;
 		break;
+	}
+	if (ssid->ieee80211w != NO_IEEE80211W && bss) {
+		const u8 *rsn = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+		struct wpa_ie_data ie;
+		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
+		    ie.capabilities &
+		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+			wpa_printf(MSG_DEBUG, "WPA: Selected AP supports MFP: "
+				   "require MFP");
+			params.mgmt_frame_protection =
+				MGMT_FRAME_PROTECTION_REQUIRED;
+		}
 	}
 #endif /* CONFIG_IEEE80211W */
 
@@ -1397,6 +1439,14 @@
 		    (!entry->bssid_set ||
 		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
 			return entry;
+#ifdef CONFIG_WPS
+		if (!entry->disabled &&
+		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    (entry->ssid == NULL || entry->ssid_len == 0) &&
+		    (!entry->bssid_set ||
+		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+			return entry;
+#endif /* CONFIG_WPS */
 		entry = entry->next;
 	}
 
@@ -1458,7 +1508,8 @@
 		wpa_supplicant_req_auth_timeout(
 			wpa_s,
 			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
-			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
 			70 : 10, 0);
 	}
 	wpa_s->eapol_received++;
@@ -1769,7 +1820,16 @@
 	if (wpa_supplicant_driver_init(wpa_s) < 0)
 		return -1;
 
+	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
+	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
+		wpa_printf(MSG_DEBUG, "Failed to set country");
+		return -1;
+	}
+
 	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+	if (wpas_wps_init(wpa_s))
+		return -1;
 
 	if (wpa_supplicant_init_eapol(wpa_s) < 0)
 		return -1;
@@ -1950,7 +2010,7 @@
 struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
 {
 	struct wpa_global *global;
-	int ret;
+	int ret, i;
 
 	if (params == NULL)
 		return NULL;
@@ -2005,6 +2065,30 @@
 		}
 	}
 
+	for (i = 0; wpa_supplicant_drivers[i]; i++)
+		global->drv_count++;
+	if (global->drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+	if (global->drv_priv == NULL) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+	for (i = 0; wpa_supplicant_drivers[i]; i++) {
+		if (!wpa_supplicant_drivers[i]->global_init)
+			continue;
+		global->drv_priv[i] = wpa_supplicant_drivers[i]->global_init();
+		if (global->drv_priv[i] == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize driver "
+				   "'%s'", wpa_supplicant_drivers[i]->name);
+			wpa_supplicant_deinit(global);
+			return NULL;
+		}
+	}
+
 	return global;
 }
 
@@ -2051,6 +2135,8 @@
  */
 void wpa_supplicant_deinit(struct wpa_global *global)
 {
+	int i;
+
 	if (global == NULL)
 		return;
 
@@ -2064,6 +2150,13 @@
 
 	eap_peer_unregister_methods();
 
+	for (i = 0; wpa_supplicant_drivers[i]; i++) {
+		if (!global->drv_priv[i])
+			continue;
+		wpa_supplicant_drivers[i]->global_deinit(global->drv_priv[i]);
+	}
+	os_free(global->drv_priv);
+
 	eloop_destroy();
 
 	if (global->params.pid_file) {

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.conf Sat Jan 10 08:43:01 2009
@@ -135,12 +135,61 @@
 # in most cases.
 #driver_param="field=value"
 
+# Country code
+# The ISO/IEC alpha2 country code for the country in which this device is
+# currently operating.
+#country=US
+
 # Maximum lifetime for PMKSA in seconds; default 43200
 #dot11RSNAConfigPMKLifetime=43200
 # Threshold for reauthentication (percentage of PMK lifetime); default 70
 #dot11RSNAConfigPMKReauthThreshold=70
 # Timeout for security association negotiation in seconds; default 60
 #dot11RSNAConfigSATimeout=60
+
+# Wi-Fi Protected Setup (WPS) parameters
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless Client
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=cmodel
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=1-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
 
 # network block
 #
@@ -397,6 +446,8 @@
 #	 * 0 = do not use cryptobinding (default)
 #	 * 1 = use cryptobinding if server supports it
 #	 * 2 = require cryptobinding
+#	EAP-WSC (WPS) uses following options: pin=<Device Password> or
+#	pbc=1.
 # 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)

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.nsi
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.nsi?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.nsi (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant.nsi Sat Jan 10 08:43:01 2009
@@ -1,0 +1,108 @@
+!define PRODUCT_NAME "wpa_supplicant"
+!define PRODUCT_VERSION "@WPAVER@"
+!define PRODUCT_PUBLISHER "Jouni Malinen"
+
+Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
+outfile "../wpa_supplicant- at WPAVER@.exe"
+
+installDir "$PROGRAMFILES\wpa_supplicant"
+
+Page Directory
+Page InstFiles
+
+section -Prerequisites
+	SetOutPath $INSTDIR\Prerequisites
+	MessageBox MB_YESNO "Install WinPcap?" /SD IDYES IDNO endWinPcap
+		File "/opt/Qt-Win/files/WinPcap_4_0_2.exe"
+		ExecWait "$INSTDIR\Prerequisites\WinPcap_4_0_2.exe"
+		Goto endWinPcap
+	endWinPcap:
+sectionEnd
+
+
+section
+	setOutPath $INSTDIR
+
+	File wpa_gui.exe
+	File wpa_cli.exe
+	File COPYING
+	File README
+	File README-Windows.txt
+	File win_example.reg
+	File win_if_list.exe
+	File wpa_passphrase.exe
+	File wpa_supplicant.conf
+	File wpa_supplicant.exe
+	File wpasvc.exe
+
+	File /opt/Qt-Win/files/mingwm10.dll
+	File /opt/Qt-Win/files/QtCore4.dll
+	File /opt/Qt-Win/files/QtGui4.dll
+
+	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_level" 0
+	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_show_keys" 0
+	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_timestamp" 0
+	WriteRegDWORD HKLM "Software\wpa_supplicant" "debug_use_file" 0
+
+	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "ap_scan" 2
+	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default" "update_config" 1
+	WriteRegDWORD HKLM "Software\wpa_supplicant\configs\default\networks" "dummy" 1
+	DeleteRegValue HKLM "Software\wpa_supplicant\configs\default\networks" "dummy"
+
+	WriteRegDWORD HKLM "Software\wpa_supplicant\interfaces" "dummy" 1
+	DeleteRegValue HKLM "Software\wpa_supplicant\interfaces" "dummy"
+
+	writeUninstaller "$INSTDIR\uninstall.exe"
+
+	WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
+		"DisplayName" "wpa_supplicant"
+WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant" \
+		"UninstallString" "$INSTDIR\uninstall.exe"
+
+	CreateDirectory "$SMPROGRAMS\wpa_supplicant"
+	CreateShortCut "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk" "$INSTDIR\wpa_gui.exe"
+	CreateShortCut "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk" "$INSTDIR\uninstall.exe"
+
+	ExecWait "$INSTDIR\wpasvc.exe reg"
+sectionEnd
+
+
+Function un.onInit
+	MessageBox MB_YESNO "This will uninstall wpa_supplicant. Continue?" IDYES NoAbort
+	Abort
+  NoAbort:
+FunctionEnd
+
+section "uninstall"
+	DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\wpa_supplicant"
+	delete "$INSTDIR\uninstall.exe"
+
+	ExecWait "$INSTDIR\wpasvc.exe unreg"
+
+	DeleteRegKey HKLM "Software\wpa_supplicant"
+
+	delete "$INSTDIR\wpa_gui.exe"
+	delete "$INSTDIR\wpa_cli.exe"
+	delete "$INSTDIR\COPYING"
+	delete "$INSTDIR\README"
+	delete "$INSTDIR\README-Windows.txt"
+	delete "$INSTDIR\win_example.reg"
+	delete "$INSTDIR\win_if_list.exe"
+	delete "$INSTDIR\wpa_passphrase.exe"
+	delete "$INSTDIR\wpa_supplicant.conf"
+	delete "$INSTDIR\wpa_supplicant.exe"
+	delete "$INSTDIR\wpasvc.exe"
+
+	delete "$INSTDIR\mingwm10.dll"
+	delete "$INSTDIR\QtCore4.dll"
+	delete "$INSTDIR\QtGui4.dll"
+
+	delete "$INSTDIR\Prerequisites\WinPcap_4_0_2.exe"
+	rmdir "$INSTDIR\Prerequisites"
+
+	rmdir "$INSTDIR"
+
+	delete "$SMPROGRAMS\wpa_supplicant\wpa_gui.lnk"
+	delete "$SMPROGRAMS\wpa_supplicant\Uninstall.lnk"
+	rmdir "$SMPROGRAMS\wpa_supplicant"
+sectionEnd

Modified: wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h?rev=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpa_supplicant_i.h Sat Jan 10 08:43:01 2009
@@ -17,6 +17,19 @@
 
 #include "drivers/driver.h"
 
+extern const char *wpa_supplicant_version;
+extern const char *wpa_supplicant_license;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern const char *wpa_supplicant_full_license1;
+extern const char *wpa_supplicant_full_license2;
+extern const char *wpa_supplicant_full_license3;
+extern const char *wpa_supplicant_full_license4;
+extern const char *wpa_supplicant_full_license5;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+extern struct wpa_driver_ops *wpa_supplicant_drivers[];
+
+
 struct wpa_scan_result;
 struct wpa_sm;
 struct wpa_supplicant;
@@ -156,6 +169,8 @@
 	struct wpa_params params;
 	struct ctrl_iface_global_priv *ctrl_iface;
 	struct ctrl_iface_dbus_priv *dbus_ctrl_iface;
+	void **drv_priv;
+	size_t drv_count;
 };
 
 
@@ -338,6 +353,8 @@
 	int pending_mic_error_report;
 	int pending_mic_error_pairwise;
 	int mic_errors_seen; /* Michael MIC errors with the current PTK */
+
+	struct wps_context *wps;
 };
 
 
@@ -394,6 +411,8 @@
 static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
 				  const char *ifname)
 {
+	if (wpa_s->driver->init2)
+		return wpa_s->driver->init2(wpa_s, ifname, wpa_s->global);
 	if (wpa_s->driver->init) {
 		return wpa_s->driver->init(wpa_s, ifname);
 	}
@@ -674,6 +693,14 @@
 	return -1;
 }
 
+static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
+				      const char *alpha2)
+{
+	if (wpa_s->driver->set_country)
+		return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2);
+	return 0;
+}
+
 static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
 				    const u8 *data, size_t data_len)
 {

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=1303&op=diff
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c (original)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wpas_glue.c Sat Jan 10 08:43:01 2009
@@ -27,6 +27,7 @@
 #include "ieee802_11_defs.h"
 #include "wpa_ctrl.h"
 #include "wpas_glue.h"
+#include "wps_supplicant.h"
 
 
 #ifndef CONFIG_NO_CONFIG_BLOBS
@@ -228,6 +229,9 @@
 	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
 		   success ? "" : "un");
 
+	if (wpas_wps_eapol_cb(wpa_s) > 0)
+		return;
+
 	if (!success) {
 		/*
 		 * Make sure we do not get stuck here waiting for long EAPOL
@@ -554,6 +558,7 @@
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
 #endif /* EAP_TLS_OPENSSL */
+	ctx->wps = wpa_s->wps;
 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
 	ctx->cb = wpa_supplicant_eapol_cb;
 	ctx->cb_ctx = wpa_s;

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.c Sat Jan 10 08:43:01 2009
@@ -1,0 +1,692 @@
+/*
+ * wpa_supplicant / WPS integration
+ * 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 "ieee802_11_defs.h"
+#include "wpa_common.h"
+#include "config.h"
+#include "eap_peer/eap.h"
+#include "wpa_supplicant_i.h"
+#include "eloop.h"
+#include "uuid.h"
+#include "wpa_ctrl.h"
+#include "eap_common/eap_wsc_common.h"
+#include "wps_supplicant.h"
+
+
+static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
+static void wpas_clear_wps(struct wpa_supplicant *wpa_s);
+
+
+int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid &&
+	    !(wpa_s->current_ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		wpa_printf(MSG_DEBUG, "WPS: Network configuration replaced - "
+			   "try to associate with the received credential");
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_wps_cred(void *ctx,
+				   const struct wps_credential *cred)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED);
+
+	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
+			   "on the received credential");
+		os_free(ssid->eap.identity);
+		ssid->eap.identity = NULL;
+		ssid->eap.identity_len = 0;
+		os_free(ssid->eap.phase1);
+		ssid->eap.phase1 = NULL;
+		os_free(ssid->eap.eap_methods);
+		ssid->eap.eap_methods = NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
+			   "received credential");
+		ssid = wpa_config_add_network(wpa_s->conf);
+		if (ssid == NULL)
+			return -1;
+	}
+
+	wpa_config_set_network_defaults(ssid);
+
+	os_free(ssid->ssid);
+	ssid->ssid = os_malloc(cred->ssid_len);
+	if (ssid->ssid) {
+		os_memcpy(ssid->ssid, cred->ssid, cred->ssid_len);
+		ssid->ssid_len = cred->ssid_len;
+	}
+
+	switch (cred->encr_type) {
+	case WPS_ENCR_NONE:
+		ssid->pairwise_cipher = ssid->group_cipher = WPA_CIPHER_NONE;
+		break;
+	case WPS_ENCR_WEP:
+		ssid->pairwise_cipher = ssid->group_cipher =
+			WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104;
+		if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
+		    cred->key_idx < NUM_WEP_KEYS) {
+			os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
+				  cred->key_len);
+			ssid->wep_key_len[cred->key_idx] = cred->key_len;
+			ssid->wep_tx_keyidx = cred->key_idx;
+		}
+		break;
+	case WPS_ENCR_TKIP:
+		ssid->pairwise_cipher = WPA_CIPHER_TKIP;
+		ssid->group_cipher = WPA_CIPHER_TKIP;
+		break;
+	case WPS_ENCR_AES:
+		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+		ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
+		break;
+	}
+
+	switch (cred->auth_type) {
+	case WPS_AUTH_OPEN:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+		ssid->proto = 0;
+		break;
+	case WPS_AUTH_SHARED:
+		ssid->auth_alg = WPA_AUTH_ALG_SHARED;
+		ssid->key_mgmt = WPA_KEY_MGMT_NONE;
+		ssid->proto = 0;
+		break;
+	case WPS_AUTH_WPAPSK:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+		ssid->proto = WPA_PROTO_WPA;
+		break;
+	case WPS_AUTH_WPA:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		ssid->proto = WPA_PROTO_WPA;
+		break;
+	case WPS_AUTH_WPA2:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		ssid->proto = WPA_PROTO_RSN;
+		break;
+	case WPS_AUTH_WPA2PSK:
+		ssid->auth_alg = WPA_AUTH_ALG_OPEN;
+		ssid->key_mgmt = WPA_KEY_MGMT_PSK;
+		ssid->proto = WPA_PROTO_RSN;
+		break;
+	}
+
+	if (ssid->key_mgmt == WPA_KEY_MGMT_PSK) {
+		if (cred->key_len == 2 * PMK_LEN) {
+			if (hexstr2bin((const char *) cred->key, ssid->psk,
+				       PMK_LEN)) {
+				wpa_printf(MSG_ERROR, "WPS: Invalid Network "
+					   "Key");
+				return -1;
+			}
+			ssid->psk_set = 1;
+		} else if (cred->key_len >= 8 && cred->key_len < 2 * PMK_LEN) {
+			os_free(ssid->passphrase);
+			ssid->passphrase = os_malloc(cred->key_len + 1);
+			if (ssid->passphrase == NULL)
+				return -1;
+			os_memcpy(ssid->passphrase, cred->key, cred->key_len);
+			ssid->passphrase[cred->key_len] = '\0';
+			wpa_config_update_psk(ssid);
+		} else {
+			wpa_printf(MSG_ERROR, "WPS: Invalid Network Key "
+				   "length %lu",
+				   (unsigned long) cred->key_len);
+			return -1;
+		}
+	}
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->conf->update_config &&
+	    wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+		wpa_printf(MSG_DEBUG, "WPS: Failed to update configuration");
+		return -1;
+	}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+	return 0;
+}
+
+
+static void wpa_supplicant_wps_event_m2d(struct wpa_supplicant *wpa_s,
+					 struct wps_event_m2d *m2d)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_M2D
+		"dev_password_id=%d config_error=%d",
+		m2d->dev_password_id, m2d->config_error);
+}
+
+
+static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
+					  struct wps_event_fail *fail)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_FAIL "msg=%d", fail->msg);
+	wpas_clear_wps(wpa_s);
+}
+
+
+static void wpa_supplicant_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_SUCCESS);
+}
+
+
+static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
+				     union wps_event_data *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	switch (event) {
+	case WPS_EV_M2D:
+		wpa_supplicant_wps_event_m2d(wpa_s, &data->m2d);
+		break;
+	case WPS_EV_FAIL:
+		wpa_supplicant_wps_event_fail(wpa_s, &data->fail);
+		break;
+	case WPS_EV_SUCCESS:
+		wpa_supplicant_wps_event_success(wpa_s);
+		break;
+	}
+}
+
+
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
+{
+	if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
+	    eap_is_wps_pin_enrollee(&ssid->eap))
+		return WPS_REQ_ENROLLEE;
+	else
+		return WPS_REQ_REGISTRAR;
+}
+
+
+static void wpas_clear_wps(struct wpa_supplicant *wpa_s)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+
+	/* Remove any existing WPS network from configuration */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+			if (ssid == wpa_s->current_ssid)
+				wpa_s->current_ssid = NULL;
+			id = ssid->id;
+		} else
+			id = -1;
+		ssid = ssid->next;
+		if (id >= 0)
+			wpa_config_remove_network(wpa_s->conf, id);
+	}
+}
+
+
+static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_printf(MSG_DEBUG, "WPS: Requested operation timed out");
+	wpas_clear_wps(wpa_s);
+}
+
+
+static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
+					      int registrar, const u8 *bssid)
+{
+	struct wpa_ssid *ssid;
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return NULL;
+	wpa_config_set_network_defaults(ssid);
+	if (wpa_config_set(ssid, "key_mgmt", "WPS", 0) < 0 ||
+	    wpa_config_set(ssid, "eap", "WSC", 0) < 0 ||
+	    wpa_config_set(ssid, "identity", registrar ?
+			   "\"" WSC_ID_REGISTRAR "\"" :
+			   "\"" WSC_ID_ENROLLEE "\"", 0) < 0) {
+		wpa_config_remove_network(wpa_s->conf, ssid->id);
+		return NULL;
+	}
+
+	if (bssid) {
+		size_t i;
+		struct wpa_scan_res *res;
+
+		os_memcpy(ssid->bssid, bssid, ETH_ALEN);
+		ssid->bssid_set = 1;
+
+		/* Try to get SSID from scan results */
+		if (wpa_s->scan_res == NULL &&
+		    wpa_supplicant_get_scan_results(wpa_s) < 0)
+			return ssid; /* Could not find any scan results */
+
+		for (i = 0; i < wpa_s->scan_res->num; i++) {
+			const u8 *ie;
+
+			res = wpa_s->scan_res->res[i];
+			if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0)
+				continue;
+
+			ie = wpa_scan_get_ie(res, WLAN_EID_SSID);
+			if (ie == NULL)
+				break;
+			os_free(ssid->ssid);
+			ssid->ssid = os_malloc(ie[1]);
+			if (ssid->ssid == NULL)
+				break;
+			os_memcpy(ssid->ssid, ie + 2, ie[1]);
+			ssid->ssid_len = ie[1];
+			break;
+		}
+	}
+
+	return ssid;
+}
+
+
+static void wpas_wps_reassoc(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *selected)
+{
+	struct wpa_ssid *ssid;
+
+	/* Mark all other networks disabled and trigger reassociation */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		ssid->disabled = ssid != selected;
+		ssid = ssid->next;
+	}
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_ssid *ssid;
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	if (ssid == NULL)
+		return -1;
+	wpa_config_set(ssid, "phase1", "\"pbc=1\"", 0);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpas_wps_reassoc(wpa_s, ssid);
+	return 0;
+}
+
+
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin)
+{
+	struct wpa_ssid *ssid;
+	char val[30];
+	unsigned int rpin = 0;
+
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 0, bssid);
+	if (ssid == NULL)
+		return -1;
+	if (pin)
+		os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
+	else {
+		rpin = wps_generate_pin();
+		os_snprintf(val, sizeof(val), "\"pin=%08d\"", rpin);
+	}
+	wpa_config_set(ssid, "phase1", val, 0);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpas_wps_reassoc(wpa_s, ssid);
+	return rpin;
+}
+
+
+int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin)
+{
+	struct wpa_ssid *ssid;
+	char val[30];
+
+	if (!pin)
+		return -1;
+	wpas_clear_wps(wpa_s);
+	ssid = wpas_wps_add_network(wpa_s, 1, bssid);
+	if (ssid == NULL)
+		return -1;
+	os_snprintf(val, sizeof(val), "\"pin=%s\"", pin);
+	wpa_config_set(ssid, "phase1", val, 0);
+	eloop_register_timeout(WPS_PBC_WALK_TIME, 0, wpas_wps_timeout,
+			       wpa_s, NULL);
+	wpas_wps_reassoc(wpa_s, ssid);
+	return 0;
+}
+
+
+static int wpas_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+			       size_t psk_len)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Received new WPA/WPA2-PSK from WPS for "
+		   "STA " MACSTR, MAC2STR(mac_addr));
+	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+	/* TODO */
+
+	return 0;
+}
+
+
+static void wpas_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+				   const struct wps_device_data *dev)
+{
+	char uuid[40], txt[400];
+	int len;
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_printf(MSG_DEBUG, "WPS: PIN needed for UUID-E %s", uuid);
+	len = os_snprintf(txt, sizeof(txt), "WPS-EVENT-PIN-NEEDED %s " MACSTR
+			  " [%s|%s|%s|%s|%s|%d-%08X-%d]",
+			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			  dev->manufacturer, dev->model_name,
+			  dev->model_number, dev->serial_number,
+			  dev->categ, dev->oui, dev->sub_categ);
+	if (len > 0 && len < (int) sizeof(txt))
+		wpa_printf(MSG_INFO, "%s", txt);
+}
+
+
+int wpas_wps_init(struct wpa_supplicant *wpa_s)
+{
+	struct wps_context *wps;
+	struct wps_registrar_config rcfg;
+
+	wps = os_zalloc(sizeof(*wps));
+	if (wps == NULL)
+		return -1;
+
+	wps->cred_cb = wpa_supplicant_wps_cred;
+	wps->event_cb = wpa_supplicant_wps_event;
+	wps->cb_ctx = wpa_s;
+
+	wps->dev.device_name = wpa_s->conf->device_name;
+	wps->dev.manufacturer = wpa_s->conf->manufacturer;
+	wps->dev.model_name = wpa_s->conf->model_name;
+	wps->dev.model_number = wpa_s->conf->model_number;
+	wps->dev.serial_number = wpa_s->conf->serial_number;
+	if (wpa_s->conf->device_type) {
+		char *pos;
+		u8 oui[4];
+		/* <categ>-<OUI>-<subcateg> */
+		wps->dev.categ = atoi(wpa_s->conf->device_type);
+		pos = os_strchr(wpa_s->conf->device_type, '-');
+		if (pos == NULL) {
+			wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+			os_free(wps);
+			return -1;
+		}
+		pos++;
+		if (hexstr2bin(pos, oui, 4)) {
+			wpa_printf(MSG_ERROR, "WPS: Invalid device_type OUI");
+			os_free(wps);
+			return -1;
+		}
+		wps->dev.oui = WPA_GET_BE32(oui);
+		pos = os_strchr(pos, '-');
+		if (pos == NULL) {
+			wpa_printf(MSG_ERROR, "WPS: Invalid device_type");
+			os_free(wps);
+			return -1;
+		}
+		pos++;
+		wps->dev.sub_categ = atoi(pos);
+	}
+	wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
+	wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
+	os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
+	if (is_nil_uuid(wpa_s->conf->uuid)) {
+		uuid_gen_mac_addr(wpa_s->own_addr, wps->uuid);
+		wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC address",
+			    wps->uuid, WPS_UUID_LEN);
+	} else
+		os_memcpy(wps->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
+
+	wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
+	wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+
+	os_memset(&rcfg, 0, sizeof(rcfg));
+	rcfg.new_psk_cb = wpas_wps_new_psk_cb;
+	rcfg.pin_needed_cb = wpas_wps_pin_needed_cb;
+	rcfg.cb_ctx = wpa_s;
+
+	wps->registrar = wps_registrar_init(wps, &rcfg);
+	if (wps->registrar == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to initialize WPS Registrar");
+		os_free(wps);
+		return -1;
+	}
+
+	wpa_s->wps = wps;
+
+	return 0;
+}
+
+
+void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+
+	if (wpa_s->wps == NULL)
+		return;
+
+	wps_registrar_deinit(wpa_s->wps->registrar);
+	os_free(wpa_s->wps->network_key);
+	os_free(wpa_s->wps);
+	wpa_s->wps = NULL;
+}
+
+
+int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss)
+{
+	struct wpabuf *wps_ie;
+
+	if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+		return -1;
+
+	wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+		if (!wps_ie) {
+			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
+			return 0;
+		}
+
+		if (!wps_is_selected_pbc_registrar(wps_ie)) {
+			wpa_printf(MSG_DEBUG, "   skip - WPS AP "
+				   "without active PBC Registrar");
+			wpabuf_free(wps_ie);
+			return 0;
+		}
+
+		/* TODO: overlap detection */
+		wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
+			   "(Active PBC)");
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+		if (!wps_ie) {
+			wpa_printf(MSG_DEBUG, "   skip - non-WPS AP");
+			return 0;
+		}
+
+		if (!wps_is_selected_pin_registrar(wps_ie)) {
+			wpa_printf(MSG_DEBUG, "   skip - WPS AP "
+				   "without active PIN Registrar");
+			wpabuf_free(wps_ie);
+			return 0;
+		}
+		wpa_printf(MSG_DEBUG, "   selected based on WPS IE "
+			   "(Active PIN)");
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	if (wps_ie) {
+		wpa_printf(MSG_DEBUG, "   selected based on WPS IE");
+		wpabuf_free(wps_ie);
+		return 1;
+	}
+
+	return -1;
+}
+
+
+int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+			      struct wpa_scan_res *bss)
+{
+	struct wpabuf *wps_ie = NULL;
+	int ret = 0;
+
+	if (eap_is_wps_pbc_enrollee(&ssid->eap)) {
+		wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (wps_ie && wps_is_selected_pbc_registrar(wps_ie)) {
+			/* allow wildcard SSID for WPS PBC */
+			ret = 1;
+		}
+	} else if (eap_is_wps_pin_enrollee(&ssid->eap)) {
+		wps_ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (wps_ie && wps_is_selected_pin_registrar(wps_ie)) {
+			/* allow wildcard SSID for WPS PIN */
+			ret = 1;
+		}
+	}
+
+	if (!ret && ssid->bssid_set &&
+	    os_memcmp(ssid->bssid, bss->bssid, ETH_ALEN) == 0) {
+		/* allow wildcard SSID due to hardcoded BSSID match */
+		ret = 1;
+	}
+
+	wpabuf_free(wps_ie);
+
+	return ret;
+}
+
+
+int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+			      struct wpa_scan_res *selected,
+			      struct wpa_ssid *ssid)
+{
+	const u8 *sel_uuid, *uuid;
+	size_t i;
+	struct wpabuf *wps_ie;
+	int ret = 0;
+
+	if (!eap_is_wps_pbc_enrollee(&ssid->eap))
+		return 0;
+
+	/* Make sure that only one AP is in active PBC mode */
+	wps_ie = wpa_scan_get_vendor_ie_multi(selected, WPS_IE_VENDOR_TYPE);
+	if (wps_ie)
+		sel_uuid = wps_get_uuid_e(wps_ie);
+	else
+		sel_uuid = NULL;
+
+	for (i = 0; i < wpa_s->scan_res->num; i++) {
+		struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
+		struct wpabuf *ie;
+		if (bss == selected)
+			continue;
+		ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (!ie)
+			continue;
+		if (!wps_is_selected_pbc_registrar(ie)) {
+			wpabuf_free(ie);
+			continue;
+		}
+		uuid = wps_get_uuid_e(ie);
+		if (sel_uuid == NULL || uuid == NULL ||
+		    os_memcmp(sel_uuid, uuid, 16) != 0) {
+			ret = 1; /* PBC overlap */
+			wpabuf_free(ie);
+			break;
+		}
+
+		/* TODO: verify that this is reasonable dual-band situation */
+
+		wpabuf_free(ie);
+	}
+
+	wpabuf_free(wps_ie);
+
+	return ret;
+}
+
+
+void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+	size_t i;
+
+	if (wpa_s->disconnected || wpa_s->wpa_state >= WPA_ASSOCIATED)
+		return;
+
+	for (i = 0; i < wpa_s->scan_res->num; i++) {
+		struct wpa_scan_res *bss = wpa_s->scan_res->res[i];
+		struct wpabuf *ie;
+		ie = wpa_scan_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+		if (!ie)
+			continue;
+		if (wps_is_selected_pbc_registrar(ie))
+			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PBC);
+		else if (wps_is_selected_pin_registrar(ie))
+			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE_PIN);
+		else
+			wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_AP_AVAILABLE);
+		wpabuf_free(ie);
+		break;
+	}
+}
+
+
+int wpas_wps_searching(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && !ssid->disabled)
+			return 1;
+	}
+
+	return 0;
+}

Added: wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h
URL: http://svn.debian.org/wsvn/wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h?rev=1303&op=file
==============================================================================
--- wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h (added)
+++ wpasupplicant/branches/upstream/current/wpa_supplicant/wps_supplicant.h Sat Jan 10 08:43:01 2009
@@ -1,0 +1,91 @@
+/*
+ * wpa_supplicant / WPS integration
+ * 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 WPS_SUPPLICANT_H
+#define WPS_SUPPLICANT_H
+
+#ifdef CONFIG_WPS
+
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+
+int wpas_wps_init(struct wpa_supplicant *wpa_s);
+void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
+int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin);
+int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin);
+int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid, struct wpa_scan_res *bss);
+int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+			      struct wpa_scan_res *selected,
+			      struct wpa_ssid *ssid);
+void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
+int wpas_wps_searching(struct wpa_supplicant *wpa_s);
+
+#else /* CONFIG_WPS */
+
+static inline int wpas_wps_init(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_wps_ssid_bss_match(struct wpa_ssid *ssid,
+					  struct wpa_scan_res *bss)
+{
+	return -1;
+}
+
+static inline int wpas_wps_ssid_wildcard_ok(struct wpa_ssid *ssid,
+					    struct wpa_scan_res *bss)
+{
+	return 0;
+}
+
+static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+					    struct wpa_scan_res *selected,
+					    struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_SUPPLICANT_H */




More information about the Pkg-wpa-devel mailing list