[Midnightbsd-cvs] src: contrib/hostapd: update to 0.5.8

laffer1 at midnightbsd.org laffer1 at midnightbsd.org
Mon Nov 24 22:48:00 EST 2008


Log Message:
-----------
update to 0.5.8

Modified Files:
--------------
    src/contrib/hostapd:
        COPYING (r1.1.1.1 -> r1.2)
        ChangeLog (r1.2 -> r1.3)
        FREEBSD-Xlist (r1.2 -> r1.3)
        FREEBSD-upgrade (r1.2 -> r1.3)
        Makefile (r1.2 -> r1.3)
        README (r1.2 -> r1.3)
        accounting.c (r1.2 -> r1.3)
        accounting.h (r1.1.1.1 -> r1.2)
        aes.c (r1.2 -> r1.3)
        aes_wrap.c (r1.2 -> r1.3)
        aes_wrap.h (r1.2 -> r1.3)
        ap.h (r1.1.1.1 -> r1.2)
        common.c (r1.2 -> r1.3)
        common.h (r1.2 -> r1.3)
        config.c (r1.2 -> r1.3)
        config.h (r1.2 -> r1.3)
        config_types.h (r1.1 -> r1.2)
        crypto.c (r1.2 -> r1.3)
        crypto.h (r1.2 -> r1.3)
        ctrl_iface.c (r1.2 -> r1.3)
        ctrl_iface.h (r1.1.1.1 -> r1.2)
        defconfig (r1.2 -> r1.3)
        defs.h (r1.2 -> r1.3)
        driver.h (r1.2 -> r1.3)
        driver_test.c (r1.2 -> r1.3)
        driver_wired.c (r1.2 -> r1.3)
        eap.c (r1.2 -> r1.3)
        eap.h (r1.2 -> r1.3)
        eap_defs.h (r1.2 -> r1.3)
        eap_gtc.c (r1.1.1.1 -> r1.2)
        eap_i.h (r1.2 -> r1.3)
        eap_identity.c (r1.2 -> r1.3)
        eap_md5.c (r1.2 -> r1.3)
        eap_mschapv2.c (r1.1.1.1 -> r1.2)
        eap_pax.c (r1.1 -> r1.2)
        eap_pax_common.c (r1.1 -> r1.2)
        eap_pax_common.h (r1.1 -> r1.2)
        eap_peap.c (r1.2 -> r1.3)
        eap_psk.c (r1.1 -> r1.2)
        eap_psk_common.c (r1.1 -> r1.2)
        eap_psk_common.h (r1.1 -> r1.2)
        eap_sim.c (r1.2 -> r1.3)
        eap_sim_common.c (r1.2 -> r1.3)
        eap_sim_common.h (r1.2 -> r1.3)
        eap_sim_db.c (r1.2 -> r1.3)
        eap_sim_db.h (r1.1.1.1 -> r1.2)
        eap_tls.c (r1.2 -> r1.3)
        eap_tls_common.c (r1.2 -> r1.3)
        eap_tls_common.h (r1.1.1.1 -> r1.2)
        eap_tlv.c (r1.1.1.1 -> r1.2)
        eap_ttls.c (r1.2 -> r1.3)
        eap_ttls.h (r1.2 -> r1.3)
        eapol_sm.c (r1.2 -> r1.3)
        eapol_sm.h (r1.2 -> r1.3)
        eloop.c (r1.2 -> r1.3)
        eloop.h (r1.2 -> r1.3)
        hostap_common.h (r1.2 -> r1.3)
        hostapd.8 (r1.1 -> r1.2)
        hostapd.c (r1.2 -> r1.3)
        hostapd.conf (r1.2 -> r1.3)
        hostapd.eap_user (r1.2 -> r1.3)
        hostapd.h (r1.2 -> r1.3)
        hostapd_cli.1 (r1.1 -> r1.2)
        hostapd_cli.c (r1.2 -> r1.3)
        iapp.c (r1.2 -> r1.3)
        iapp.h (r1.1.1.1 -> r1.2)
        ieee802_11.c (r1.2 -> r1.3)
        ieee802_11.h (r1.1.1.1 -> r1.2)
        ieee802_11_auth.c (r1.2 -> r1.3)
        ieee802_11_auth.h (r1.1.1.1 -> r1.2)
        ieee802_1x.c (r1.2 -> r1.3)
        ieee802_1x.h (r1.2 -> r1.3)
        l2_packet.h (r1.2 -> r1.3)
        md5.c (r1.2 -> r1.3)
        md5.h (r1.2 -> r1.3)
        ms_funcs.c (r1.2 -> r1.3)
        ms_funcs.h (r1.2 -> r1.3)
        radius.c (r1.2 -> r1.3)
        radius.h (r1.2 -> r1.3)
        radius_client.c (r1.2 -> r1.3)
        radius_client.h (r1.2 -> r1.3)
        radius_server.c (r1.2 -> r1.3)
        radius_server.h (r1.2 -> r1.3)
        rc4.c (r1.2 -> r1.3)
        rc4.h (r1.2 -> r1.3)
        sha1.c (r1.2 -> r1.3)
        sha1.h (r1.2 -> r1.3)
        sta_info.c (r1.2 -> r1.3)
        sta_info.h (r1.2 -> r1.3)
        tls.h (r1.2 -> r1.3)
        tls_none.c (r1.2 -> r1.3)
        tls_openssl.c (r1.2 -> r1.3)
        version.h (r1.2 -> r1.3)
        wpa.c (r1.2 -> r1.3)
        wpa.h (r1.2 -> r1.3)
        wpa_ctrl.c (r1.1 -> r1.2)
        wpa_ctrl.h (r1.1 -> r1.2)

Added Files:
-----------
    src/contrib/hostapd:
        aes.h (r1.1)
        ap_list.c (r1.1)
        ap_list.h (r1.1)
        beacon.c (r1.1)
        beacon.h (r1.1)
        build_config.h (r1.1)
        des.c (r1.1)
        eap_aka.c (r1.1)
        eap_gpsk.c (r1.1)
        eap_gpsk_common.c (r1.1)
        eap_gpsk_common.h (r1.1)
        eap_methods.c (r1.1)
        eap_methods.h (r1.1)
        eap_sake.c (r1.1)
        eap_sake_common.c (r1.1)
        eap_sake_common.h (r1.1)
        eap_vendor_test.c (r1.1)
        eloop_none.c (r1.1)
        eloop_win.c (r1.1)
        hlr_auc_gw.c (r1.1)
        hw_features.c (r1.1)
        hw_features.h (r1.1)
        ieee802_11h.c (r1.1)
        ieee802_11h.h (r1.1)
        includes.h (r1.1)
        l2_packet_none.c (r1.1)
        md4.c (r1.1)
        milenage.c (r1.1)
        milenage.h (r1.1)
        mlme.c (r1.1)
        mlme.h (r1.1)
        os.h (r1.1)
        os_internal.c (r1.1)
        os_none.c (r1.1)
        os_unix.c (r1.1)
        pmksa_cache.c (r1.1)
        pmksa_cache.h (r1.1)
        preauth.c (r1.1)
        preauth.h (r1.1)
        reconfig.c (r1.1)
        sha256.c (r1.1)
        sha256.h (r1.1)
        state_machine.h (r1.1)
        tls_gnutls.c (r1.1)
        vlan_init.c (r1.1)
        vlan_init.h (r1.1)
        wme.c (r1.1)
        wme.h (r1.1)
        wpa_common.h (r1.1)
    src/contrib/hostapd/doc:
        code_structure.doxygen (r1.1)
        ctrl_iface.doxygen (r1.1)
        doxygen.fast (r1.1)
        doxygen.full (r1.1)
        driver_wrapper.doxygen (r1.1)
        eap.doxygen (r1.1)
        hostapd.fig (r1.1)
        kerneldoc2doxygen.pl (r1.1)
        mainpage.doxygen (r1.1)
        porting.doxygen (r1.1)

-------------- next part --------------
Index: sta_info.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/sta_info.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/sta_info.c -L contrib/hostapd/sta_info.c -u -r1.2 -r1.3
--- contrib/hostapd/sta_info.c
+++ contrib/hostapd/sta_info.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Station table
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / Station table
+ * Copyright (c) 2002-2006, 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
@@ -13,12 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "sta_info.h"
@@ -29,10 +23,17 @@
 #include "radius.h"
 #include "eapol_sm.h"
 #include "wpa.h"
+#include "preauth.h"
 #include "radius_client.h"
 #include "driver.h"
-#include "hostap_common.h"
-
+#include "beacon.h"
+#include "hw_features.h"
+#include "mlme.h"
+#include "vlan_init.h"
+
+static int ap_sta_in_other_bss(struct hostapd_data *hapd,
+			       struct sta_info *sta, u32 flags);
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
 		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -61,7 +62,7 @@
 }
 
 
-static void ap_sta_list_del(hostapd *hapd, struct sta_info *sta)
+static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct sta_info *tmp;
 
@@ -81,14 +82,14 @@
 }
 
 
-void ap_sta_hash_add(hostapd *hapd, struct sta_info *sta)
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
 	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
 }
 
 
-static void ap_sta_hash_del(hostapd *hapd, struct sta_info *sta)
+static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct sta_info *s;
 
@@ -109,10 +110,14 @@
 }
 
 
-void ap_free_sta(hostapd *hapd, struct sta_info *sta)
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
+	int set_beacon = 0;
+
 	accounting_sta_stop(hapd, sta);
-	if (!(sta->flags & WLAN_STA_PREAUTH))
+
+	if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
+	    !(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_sta_remove(hapd, sta->addr);
 
 	ap_sta_hash_del(hapd, sta);
@@ -122,23 +127,50 @@
 		hapd->sta_aid[sta->aid - 1] = NULL;
 
 	hapd->num_sta--;
+	if (sta->nonerp_set) {
+		sta->nonerp_set = 0;
+		hapd->iface->num_sta_non_erp--;
+		if (hapd->iface->num_sta_non_erp == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 0;
+		hapd->iface->num_sta_no_short_slot_time--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_slot_time == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 0;
+		hapd->iface->num_sta_no_short_preamble--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 0)
+			set_beacon++;
+	}
+
+	if (set_beacon)
+		ieee802_11_set_beacons(hapd->iface);
+
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
 
 	ieee802_1x_free_station(sta);
-	wpa_free_station(sta);
+	wpa_auth_sta_deinit(sta->wpa_sm);
+	rsn_preauth_free_station(hapd, sta);
 	radius_client_flush_auth(hapd->radius, sta->addr);
 
 	if (sta->last_assoc_req)
 		free(sta->last_assoc_req);
 
 	free(sta->challenge);
-	free(sta->wpa_ie);
 
 	free(sta);
 }
 
 
-void hostapd_free_stas(hostapd *hapd)
+void hostapd_free_stas(struct hostapd_data *hapd)
 {
 	struct sta_info *sta, *prev;
 
@@ -146,6 +178,10 @@
 
 	while (sta) {
 		prev = sta;
+		if (sta->flags & WLAN_STA_AUTH) {
+			mlme_deauthenticate_indication(
+				hapd, sta, WLAN_REASON_UNSPECIFIED);
+		}
 		sta = sta->next;
 		printf("Removing station " MACSTR "\n", MAC2STR(prev->addr));
 		ap_free_sta(hapd, prev);
@@ -155,7 +191,7 @@
 
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 	unsigned long next_time = 0;
 
@@ -179,13 +215,14 @@
 			printf("  Could not get station info from kernel "
 			       "driver for " MACSTR ".\n",
 			       MAC2STR(sta->addr));
-		} else if (inactive_sec < AP_MAX_INACTIVITY &&
+		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
 			   sta->flags & WLAN_STA_ASSOC) {
 			/* station activity detected; reset timeout state */
 			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
 				      "  Station has been active\n");
 			sta->timeout_next = STA_NULLFUNC;
-			next_time = AP_MAX_INACTIVITY - inactive_sec;
+			next_time = hapd->conf->ap_max_inactivity -
+				inactive_sec;
 		}
 	}
 
@@ -197,7 +234,7 @@
 		/* data nullfunc frame poll did not produce TX errors; assume
 		 * station ACKed it */
 		sta->timeout_next = STA_NULLFUNC;
-		next_time = AP_MAX_INACTIVITY;
+		next_time = hapd->conf->ap_max_inactivity;
 	}
 
 	if (next_time) {
@@ -216,6 +253,7 @@
 			      "  Polling STA with data frame\n");
 		sta->flags |= WLAN_STA_PENDING_POLL;
 
+#ifndef CONFIG_NATIVE_WINDOWS
 		/* FIX: WLAN_FC_STYPE_NULLFUNC would be more appropriate, but
 		 * it is apparently not retried so TX Exc events are not
 		 * received for it */
@@ -230,6 +268,7 @@
 
 		if (hostapd_send_mgmt_frame(hapd, &hdr, sizeof(hdr), 0) < 0)
 			perror("ap_handle_timer: send");
+#endif /* CONFIG_NATIVE_WINDOWS */
 	} else if (sta->timeout_next != STA_REMOVE) {
 		int deauth = sta->timeout_next == STA_DEAUTH;
 
@@ -255,7 +294,7 @@
 		break;
 	case STA_DISASSOC:
 		sta->flags &= ~WLAN_STA_ASSOC;
-		ieee802_1x_set_port_enabled(hapd, sta, 0);
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 		if (!sta->acct_terminate_cause)
 			sta->acct_terminate_cause =
 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@@ -267,6 +306,8 @@
 		sta->timeout_next = STA_DEAUTH;
 		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
 				       hapd, sta);
+		mlme_disassociate_indication(
+			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
 		break;
 	case STA_DEAUTH:
 	case STA_REMOVE:
@@ -276,31 +317,38 @@
 		if (!sta->acct_terminate_cause)
 			sta->acct_terminate_cause =
 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
+		mlme_deauthenticate_indication(
+			hapd, sta,
+			WLAN_REASON_PREV_AUTH_NOT_VALID);
 		ap_free_sta(hapd, sta);
 		break;
 	}
 }
 
 
-void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
+	u8 addr[ETH_ALEN];
 
 	if (!(sta->flags & WLAN_STA_AUTH))
 		return;
 
-	hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	mlme_deauthenticate_indication(hapd, sta,
+				       WLAN_REASON_PREV_AUTH_NOT_VALID);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
 		       "session timeout");
 	sta->acct_terminate_cause =
 		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
+	memcpy(addr, sta->addr, ETH_ALEN);
 	ap_free_sta(hapd, sta);
+	hostapd_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
 
 
-void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta,
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout)
 {
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -312,7 +360,7 @@
 }
 
 
-void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta)
+void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
 }
@@ -327,29 +375,211 @@
 		return sta;
 
 	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "  New STA\n");
-	if (hapd->num_sta >= MAX_STA_COUNT) {
+	if (hapd->num_sta >= hapd->conf->max_num_sta) {
 		/* FIX: might try to remove some old STAs first? */
 		printf("  no more room for new STAs (%d/%d)\n",
-		       hapd->num_sta, MAX_STA_COUNT);
+		       hapd->num_sta, hapd->conf->max_num_sta);
 		return NULL;
 	}
 
-	sta = (struct sta_info *) malloc(sizeof(struct sta_info));
+	sta = wpa_zalloc(sizeof(struct sta_info));
 	if (sta == NULL) {
 		printf("  malloc failed\n");
 		return NULL;
 	}
-	memset(sta, 0, sizeof(struct sta_info));
 	sta->acct_interim_interval = hapd->conf->radius->acct_interim_interval;
 
 	/* initialize STA info data */
-	eloop_register_timeout(AP_MAX_INACTIVITY, 0, ap_handle_timer,
-			       hapd, sta);
+	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+			       ap_handle_timer, hapd, sta);
 	memcpy(sta->addr, addr, ETH_ALEN);
 	sta->next = hapd->sta_list;
 	hapd->sta_list = sta;
 	hapd->num_sta++;
 	ap_sta_hash_add(hapd, sta);
+	sta->ssid = &hapd->conf->ssid;
 
 	return sta;
 }
+
+
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Removing STA " MACSTR
+		      " from kernel driver\n", MAC2STR(sta->addr));
+	if (hostapd_sta_remove(hapd, sta->addr) &&
+	    sta->flags & WLAN_STA_ASSOC) {
+		printf("Could not remove station " MACSTR " from kernel "
+		       "driver.\n", MAC2STR(sta->addr));
+		return -1;
+	}
+	return 0;
+}
+
+
+static int ap_sta_in_other_bss(struct hostapd_data *hapd,
+			       struct sta_info *sta, u32 flags)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	size_t i;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		struct sta_info *sta2;
+		/* bss should always be set during operation, but it may be
+		 * NULL during reconfiguration. Assume the STA is not
+		 * associated to another BSS in that case to avoid NULL pointer
+		 * dereferences. */
+		if (bss == hapd || bss == NULL)
+			continue;
+		sta2 = ap_get_sta(bss, sta->addr);
+		if (sta2 && ((sta2->flags & flags) == flags))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason)
+{
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: disassociate STA " MACSTR
+		      "\n", hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_ASSOC;
+	if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
+		ap_sta_remove(hapd, sta);
+	sta->timeout_next = STA_DEAUTH;
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	mlme_disassociate_indication(hapd, sta, reason);
+}
+
+
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason)
+{
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "%s: deauthenticate STA " MACSTR
+		      "\n", hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC))
+		ap_sta_remove(hapd, sta);
+	sta->timeout_next = STA_REMOVE;
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	mlme_deauthenticate_indication(hapd, sta, reason);
+}
+
+
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid)
+{
+	const char *iface;
+	struct hostapd_vlan *vlan = NULL;
+
+	/*
+	 * Do not proceed furthur if the vlan id remains same. We do not want
+	 * duplicate dynamic vlan entries.
+	 */
+	if (sta->vlan_id == old_vlanid)
+		return 0;
+
+	/*
+	 * During 1x reauth, if the vlan id changes, then remove the old id and
+	 * proceed furthur to add the new one.
+	 */
+	if (old_vlanid > 0)
+		vlan_remove_dynamic(hapd, old_vlanid);
+
+	iface = hapd->conf->iface;
+	if (sta->ssid->vlan[0])
+		iface = sta->ssid->vlan;
+
+	if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+		sta->vlan_id = 0;
+	else if (sta->vlan_id > 0) {
+		vlan = hapd->conf->vlan;
+		while (vlan) {
+			if (vlan->vlan_id == sta->vlan_id ||
+			    vlan->vlan_id == VLAN_ID_WILDCARD) {
+				iface = vlan->ifname;
+				break;
+			}
+			vlan = vlan->next;
+		}
+	}
+
+	if (sta->vlan_id > 0 && vlan == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
+			       "binding station to (vlan_id=%d)",
+			       sta->vlan_id);
+		return -1;
+	} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
+		vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
+		if (vlan == NULL) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not add "
+				       "dynamic VLAN interface for vlan_id=%d",
+				       sta->vlan_id);
+			return -1;
+		}
+
+		iface = vlan->ifname;
+		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not "
+				       "configure encryption for dynamic VLAN "
+				       "interface for vlan_id=%d",
+				       sta->vlan_id);
+		}
+
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
+			       "interface '%s'", iface);
+	} else if (vlan && vlan->vlan_id == sta->vlan_id) {
+		if (sta->vlan_id > 0) {
+			vlan->dynamic_vlan++;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "updated existing "
+				       "dynamic VLAN interface '%s'", iface);
+		}
+
+		/*
+		 * Update encryption configuration for statically generated
+		 * VLAN interface. This is only used for static WEP
+		 * configuration for the case where hostapd did not yet know
+		 * which keys are to be used when the interface was added.
+		 */
+		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not "
+				       "configure encryption for VLAN "
+				       "interface for vlan_id=%d",
+				       sta->vlan_id);
+		}
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
+		       "'%s'", iface);
+
+	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
+		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
+
+	return hostapd_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+}
Index: hostapd.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostapd.h -L contrib/hostapd/hostapd.h -u -r1.2 -r1.3
--- contrib/hostapd/hostapd.h
+++ contrib/hostapd/hostapd.h
@@ -1,3 +1,18 @@
+/*
+ * hostapd / Initialization and configuration
+ * Host AP kernel driver
+ * Copyright (c) 2002-2006, 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 HOSTAPD_H
 #define HOSTAPD_H
 
@@ -28,11 +43,17 @@
 
 #include "config.h"
 
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#define MAX_VLAN_ID 4094
+
 struct ieee8023_hdr {
 	u8 dest[6];
 	u8 src[6];
 	u16 ethertype;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 
 struct ieee80211_hdr {
@@ -44,7 +65,11 @@
 	u16 seq_ctrl;
 	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
 	 */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
 
 #define IEEE80211_DA_FROMDS addr1
 #define IEEE80211_BSSID_FROMDS addr2
@@ -61,21 +86,36 @@
 
 extern unsigned char rfc1042_header[6];
 
-typedef struct hostapd_data hostapd;
-
 struct hostap_sta_driver_data {
 	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+	unsigned long current_tx_rate;
+	unsigned long inactive_msec;
+	unsigned long flags;
+	unsigned long num_ps_buf_frames;
+	unsigned long tx_retry_failed;
+	unsigned long tx_retry_count;
+	int last_rssi;
+	int last_ack_rssi;
 };
 
 struct driver_ops;
 struct wpa_ctrl_dst;
 struct radius_server_data;
 
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+struct full_dynamic_vlan;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+/**
+ * struct hostapd_data - hostapd per-BSS data structure
+ */
 struct hostapd_data {
-	struct hostapd_config *conf;
-	char *config_fname;
+	struct hostapd_iface *iface;
+	struct hostapd_config *iconf;
+	struct hostapd_bss_config *conf;
+	int interface_added; /* virtual interface added for this BSS */
 
-	u8 own_addr[6];
+	u8 own_addr[ETH_ALEN];
 
 	int num_sta; /* number of entries in sta_list */
 	struct sta_info *sta_list; /* STA info list head */
@@ -93,6 +133,7 @@
 	u8 default_wep_key_idx;
 
 	struct radius_client_data *radius;
+	int radius_client_reconfigured;
 	u32 acct_session_id_hi, acct_session_id_lo;
 
 	struct iapp_data *iapp;
@@ -106,16 +147,8 @@
 	struct hostapd_cached_radius_acl *acl_cache;
 	struct hostapd_acl_query_data *acl_queries;
 
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
 	struct wpa_authenticator *wpa_auth;
 
-#define PMKID_HASH_SIZE 128
-#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
-	struct rsn_pmksa_cache *pmkid[PMKID_HASH_SIZE];
-	struct rsn_pmksa_cache *pmksa;
-	int pmksa_count;
-
 	struct rsn_preauth_interface *preauth_iface;
 	time_t michael_mic_failure;
 	int michael_mic_failures;
@@ -127,23 +160,96 @@
 	void *ssl_ctx;
 	void *eap_sim_db_priv;
 	struct radius_server_data *radius_srv;
+
+	int parameter_set_count;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	struct full_dynamic_vlan *full_dynamic_vlan;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
+
+/**
+ * hostapd_iface_cb - Generic callback type for per-iface asynchronous requests
+ * @iface: the interface the event occured on.
+ * @status: 0 if the request succeeded; -1 if the request failed.
+ */
+typedef void (*hostapd_iface_cb)(struct hostapd_iface *iface, int status);
+
+
+struct hostapd_config_change;
+
+/**
+ * struct hostapd_iface - hostapd per-interface data structure
+ */
+struct hostapd_iface {
+	char *config_fname;
+	struct hostapd_config *conf;
+
+	hostapd_iface_cb setup_cb;
+
+	size_t num_bss;
+	struct hostapd_data **bss;
+
+	int num_ap; /* number of entries in ap_list */
+	struct ap_info *ap_list; /* AP info list head */
+	struct ap_info *ap_hash[STA_HASH_SIZE];
+	struct ap_info *ap_iter_list;
+
+	struct hostapd_hw_modes *hw_features;
+	int num_hw_features;
+	struct hostapd_hw_modes *current_mode;
+	/* Rates that are currently used (i.e., filtered copy of
+	 * current_mode->channels */
+	int num_rates;
+	struct hostapd_rate_data *current_rates;
+	hostapd_iface_cb hw_mode_sel_cb;
+
+	u16 hw_flags;
+
+	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+	 * in 802.11g BSS) */
+	int num_sta_non_erp;
+
+	/* Number of associated stations that do not support Short Slot Time */
+	int num_sta_no_short_slot_time;
+
+	/* Number of associated stations that do not support Short Preamble */
+	int num_sta_no_short_preamble;
+
+	int olbc; /* Overlapping Legacy BSS Condition */
+
+	int dfs_enable;
+	u8 pwr_const;
+	unsigned int tx_power;
+	unsigned int sta_max_power;
+
+	unsigned int channel_switch;
+
+	struct hostapd_config_change *change;
+	hostapd_iface_cb reload_iface_cb;
+	hostapd_iface_cb config_reload_cb;
 };
 
-void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta, int reassoc);
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc);
 void hostapd_logger(struct hostapd_data *hapd, const u8 *addr,
 		    unsigned int module, int level, const char *fmt,
-		    ...) __attribute__ ((format (printf, 5, 6)));
+		    ...) PRINTF_FORMAT(5, 6);
 
 
+#ifndef _MSC_VER
 #define HOSTAPD_DEBUG(level, args...) \
 do { \
 	if (hapd->conf == NULL || hapd->conf->debug >= (level)) \
 		printf(args); \
 } while (0)
+#endif /* _MSC_VER */
 
 #define HOSTAPD_DEBUG_COND(level) (hapd->conf->debug >= (level))
 
 const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
 			    size_t buflen);
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
 
 #endif /* HOSTAPD_H */
--- /dev/null
+++ contrib/hostapd/eap_gpsk.c
@@ -0,0 +1,646 @@
+/*
+ * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt) server
+ * Copyright (c) 2006-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 "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_gpsk_common.h"
+
+
+struct eap_gpsk_data {
+	enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
+	u8 rand_server[EAP_GPSK_RAND_LEN];
+	u8 rand_client[EAP_GPSK_RAND_LEN];
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 sk[EAP_GPSK_MAX_SK_LEN];
+	size_t sk_len;
+	u8 pk[EAP_GPSK_MAX_PK_LEN];
+	size_t pk_len;
+	u8 *id_client;
+	size_t id_client_len;
+	u8 *id_server;
+	size_t id_server_len;
+#define MAX_NUM_CSUITES 2
+	struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
+	size_t csuite_count;
+	int vendor; /* CSuite/Vendor */
+	int specifier; /* CSuite/Specifier */
+};
+
+
+static const char * eap_gpsk_state_txt(int state)
+{
+	switch (state) {
+	case GPSK_1:
+		return "GPSK-1";
+	case GPSK_3:
+		return "GPSK-3";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
+		   eap_gpsk_state_txt(data->state),
+		   eap_gpsk_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_gpsk_init(struct eap_sm *sm)
+{
+	struct eap_gpsk_data *data;
+
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = GPSK_1;
+
+	/* TODO: add support for configuring ID_Server */
+	data->id_server = (u8 *) strdup("hostapd");
+	if (data->id_server)
+		data->id_server_len = strlen((char *) data->id_server);
+
+	data->csuite_count = 0;
+	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+					   EAP_GPSK_CIPHER_AES)) {
+		WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+			     EAP_GPSK_VENDOR_IETF);
+		WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+			     EAP_GPSK_CIPHER_AES);
+		data->csuite_count++;
+	}
+	if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+					   EAP_GPSK_CIPHER_SHA256)) {
+		WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+			     EAP_GPSK_VENDOR_IETF);
+		WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+			     EAP_GPSK_CIPHER_SHA256);
+		data->csuite_count++;
+	}
+
+	return data;
+}
+
+
+static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	free(data->id_server);
+	free(data->id_client);
+	free(data);
+}
+
+
+static u8 * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
+				  struct eap_gpsk_data *data,
+				  int id, size_t *reqDataLen)
+{
+	u8 *pos;
+	size_t len;
+	struct eap_hdr *req;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
+
+	if (hostapd_get_rand(data->rand_server, EAP_GPSK_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
+		    data->rand_server, EAP_GPSK_RAND_LEN);
+
+	len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+		data->csuite_count * sizeof(struct eap_gpsk_csuite);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqDataLen,
+			    len, EAP_CODE_REQUEST, id, &pos);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+			   "for request/GPSK-1");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	*pos++ = EAP_GPSK_OPCODE_GPSK_1;
+
+	WPA_PUT_BE16(pos, data->id_server_len);
+	pos += 2;
+	if (data->id_server)
+		memcpy(pos, data->id_server, data->id_server_len);
+	pos += data->id_server_len;
+
+	memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+
+	WPA_PUT_BE16(pos, data->csuite_count * sizeof(struct eap_gpsk_csuite));
+	pos += 2;
+	memcpy(pos, data->csuite_list,
+	       data->csuite_count * sizeof(struct eap_gpsk_csuite));
+
+	return (u8 *) req;
+}
+
+
+static u8 * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
+				  struct eap_gpsk_data *data,
+				  int id, size_t *reqDataLen)
+{
+	u8 *pos, *start;
+	size_t len, miclen;
+	struct eap_gpsk_csuite *csuite;
+	struct eap_hdr *req;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	len = 1 + 2 * EAP_GPSK_RAND_LEN + sizeof(struct eap_gpsk_csuite) + 2 +
+		miclen;
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqDataLen,
+			    len, EAP_CODE_REQUEST, id, &pos);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+			   "for request/GPSK-3");
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	*pos++ = EAP_GPSK_OPCODE_GPSK_3;
+	start = pos;
+
+	memcpy(pos, data->rand_client, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	csuite = (struct eap_gpsk_csuite *) pos;
+	WPA_PUT_BE24(csuite->vendor, data->vendor);
+	WPA_PUT_BE24(csuite->specifier, data->specifier);
+	pos += sizeof(*csuite);
+
+	/* no PD_Payload_2 */
+	WPA_PUT_BE16(pos, 0);
+	pos += 2;
+
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, start, pos - start, pos) < 0)
+	{
+		free(req);
+		eap_gpsk_state(data, FAILURE);
+		return NULL;
+	}
+
+	return (u8 *) req;
+}
+
+
+static u8 * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, int id,
+			      size_t *reqDataLen)
+{
+	struct eap_gpsk_data *data = priv;
+
+	switch (data->state) {
+	case GPSK_1:
+		return eap_gpsk_build_gpsk_1(sm, data, id, reqDataLen);
+	case GPSK_3:
+		return eap_gpsk_build_gpsk_3(sm, data, id, reqDataLen);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
+			      u8 *respData, size_t respDataLen)
+{
+	struct eap_gpsk_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
+		return TRUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
+
+	if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
+		return FALSE;
+
+	if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
+		   *pos, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
+				    struct eap_gpsk_data *data,
+				    u8 *respData, size_t respDataLen,
+				    const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	u16 alen;
+	const struct eap_gpsk_csuite *csuite;
+	size_t i, miclen;
+	u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+	if (data->state != GPSK_1)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Client length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Client");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	free(data->id_client);
+	data->id_client = malloc(alen);
+	if (data->id_client == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
+			   "%d-octet ID_Client", alen);
+		return;
+	}
+	memcpy(data->id_client, pos, alen);
+	data->id_client_len = alen;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client",
+			  data->id_client, data->id_client_len);
+	pos += alen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Server length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "ID_Server");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (alen != data->id_server_len ||
+	    memcmp(pos, data->id_server, alen) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
+			   "GPSK-2 did not match");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += alen;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "RAND_Client");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	memcpy(data->rand_client, pos, EAP_GPSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client",
+		    data->rand_client, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+
+	if (end - pos < EAP_GPSK_RAND_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "RAND_Server");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
+			   "GPSK-2 did not match");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
+			    data->rand_server, EAP_GPSK_RAND_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
+			    pos, EAP_GPSK_RAND_LEN);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += EAP_GPSK_RAND_LEN;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_List length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_List");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
+	    memcmp(pos, data->csuite_list, alen) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
+			   "GPSK-2 did not match");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += alen;
+
+	if (end - pos < (int) sizeof(*csuite)) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "CSuite_Sel");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	csuite = (const struct eap_gpsk_csuite *) pos;
+	for (i = 0; i < data->csuite_count; i++) {
+		if (memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) ==
+		    0)
+			break;
+	}
+	if (i == data->csuite_count) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
+			   "ciphersuite %d:%d",
+			   WPA_GET_BE24(csuite->vendor),
+			   WPA_GET_BE24(csuite->specifier));
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	data->vendor = WPA_GET_BE24(csuite->vendor);
+	data->specifier = WPA_GET_BE24(csuite->specifier);
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
+		   data->vendor, data->specifier);
+	pos += sizeof(*csuite);	
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1 length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+	pos += alen;
+
+	if (sm->user == NULL || sm->user->password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
+			   "for the user");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+
+	if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
+				 data->vendor, data->specifier,
+				 data->rand_client, data->rand_server,
+				 data->id_client, data->id_client_len,
+				 data->id_server, data->id_server_len,
+				 data->msk, data->emsk,
+				 data->sk, &data->sk_len,
+				 data->pk, &data->pk_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	if (end - pos < (int) miclen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+			   "(left=%d miclen=%d)", end - pos, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, payload, pos - payload, mic)
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (memcmp(mic, pos, miclen) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += miclen;
+
+	if (pos != end) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
+			   "data in the end of GPSK-2", end - pos);
+	}
+
+	eap_gpsk_state(data, GPSK_3);
+}
+
+
+static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
+				    struct eap_gpsk_data *data,
+				    u8 *respData, size_t respDataLen,
+				    const u8 *payload, size_t payloadlen)
+{
+	const u8 *pos, *end;
+	u16 alen;
+	size_t miclen;
+	u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+	if (data->state != GPSK_3)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
+
+	pos = payload;
+	end = payload + payloadlen;
+
+	if (end - pos < 2) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1 length");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	alen = WPA_GET_BE16(pos);
+	pos += 2;
+	if (end - pos < alen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+			   "PD_Payload_1");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+	pos += alen;
+
+	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+	if (end - pos < (int) miclen) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+			   "(left=%d miclen=%d)", end - pos, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+				 data->specifier, payload, pos - payload, mic)
+	    < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	if (memcmp(mic, pos, miclen) != 0) {
+		wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+		wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	pos += miclen;
+
+	if (pos != end) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
+			   "data in the end of GPSK-4", end - pos);
+	}
+
+	eap_gpsk_state(data, SUCCESS);
+}
+
+
+static void eap_gpsk_process(struct eap_sm *sm, void *priv,
+			     u8 *respData, size_t respDataLen)
+{
+	struct eap_gpsk_data *data = priv;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1)
+		return;
+
+	switch (*pos) {
+	case EAP_GPSK_OPCODE_GPSK_2:
+		eap_gpsk_process_gpsk_2(sm, data, respData, respDataLen,
+					pos + 1, len - 1);
+		break;
+	case EAP_GPSK_OPCODE_GPSK_4:
+		eap_gpsk_process_gpsk_4(sm, data, respData, respDataLen,
+					pos + 1, len - 1);
+		break;
+	}
+}
+
+
+static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_gpsk_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_gpsk_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gpsk_init;
+	eap->reset = eap_gpsk_reset;
+	eap->buildReq = eap_gpsk_buildReq;
+	eap->check = eap_gpsk_check;
+	eap->process = eap_gpsk_process;
+	eap->isDone = eap_gpsk_isDone;
+	eap->getKey = eap_gpsk_getKey;
+	eap->isSuccess = eap_gpsk_isSuccess;
+	eap->get_emsk = eap_gpsk_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: iapp.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/iapp.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/iapp.h -L contrib/hostapd/iapp.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/iapp.h
+++ contrib/hostapd/iapp.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2005, 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 IAPP_H
 #define IAPP_H
 
@@ -8,6 +22,8 @@
 void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
 struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
 void iapp_deinit(struct iapp_data *iapp);
+int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
+		  struct hostapd_bss_config *oldbss);
 
 #else /* CONFIG_IAPP */
 
@@ -26,6 +42,13 @@
 {
 }
 
+static inline int
+iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
+	      struct hostapd_bss_config *oldbss)
+{
+	return 0;
+}
+
 #endif /* CONFIG_IAPP */
 
 #endif /* IAPP_H */
--- /dev/null
+++ contrib/hostapd/build_config.h
@@ -0,0 +1,50 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, 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.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define EAP_TLS_FUNCS
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define _CRT_SECURE_NO_DEPRECATE
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */
Index: radius.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius.c -L contrib/hostapd/radius.c -u -r1.2 -r1.3
--- contrib/hostapd/radius.c
+++ contrib/hostapd/radius.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RADIUS client
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2005, 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
@@ -13,18 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/time.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
 
 #include "common.h"
 #include "radius.h"
@@ -36,12 +24,12 @@
 {
 	struct radius_msg *msg;
 
-	msg = (struct radius_msg *) malloc(sizeof(*msg));
+	msg = os_malloc(sizeof(*msg));
 	if (msg == NULL)
 		return NULL;
 
 	if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
-		free(msg);
+		os_free(msg);
 		return NULL;
 	}
 
@@ -56,20 +44,19 @@
 	if (msg == NULL || init_len < sizeof(struct radius_hdr))
 		return -1;
 
-	memset(msg, 0, sizeof(*msg));
-	msg->buf = (unsigned char *) malloc(init_len);
+	os_memset(msg, 0, sizeof(*msg));
+	msg->buf = wpa_zalloc(init_len);
 	if (msg->buf == NULL)
 		return -1;
-	memset(msg->buf, 0, init_len);
 
 	msg->buf_size = init_len;
 	msg->hdr = (struct radius_hdr *) msg->buf;
 	msg->buf_used = sizeof(*msg->hdr);
 
-	msg->attrs = (struct radius_attr_hdr **)
-		malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
+	msg->attrs =
+		os_malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
 	if (msg->attrs == NULL) {
-		free(msg->buf);
+		os_free(msg->buf);
 		msg->buf = NULL;
 		msg->hdr = NULL;
 		return -1;
@@ -92,14 +79,14 @@
 void radius_msg_free(struct radius_msg *msg)
 {
 	if (msg->buf != NULL) {
-		free(msg->buf);
+		os_free(msg->buf);
 		msg->buf = NULL;
 		msg->hdr = NULL;
 	}
 	msg->buf_size = msg->buf_used = 0;
 
 	if (msg->attrs != NULL) {
-		free(msg->attrs);
+		os_free(msg->attrs);
 		msg->attrs = NULL;
 	}
 	msg->attr_size = msg->attr_used = 0;
@@ -178,10 +165,15 @@
 	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
+	  RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
 	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
 	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
 	  RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
+	  RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
@@ -191,7 +183,7 @@
 
 static struct radius_attr_type *radius_get_attr_type(u8 type)
 {
-	int i;
+	size_t i;
 
 	for (i = 0; i < RADIUS_ATTRS; i++) {
 		if (type == radius_attrs[i].type)
@@ -202,6 +194,15 @@
 }
 
 
+static void print_char(char c)
+{
+	if (c >= 32 && c < 127)
+		printf("%c", c);
+	else
+		printf("<%02x>", c);
+}
+
+
 static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
 {
 	struct radius_attr_type *attr;
@@ -257,11 +258,9 @@
 		break;
 
 	case RADIUS_ATTR_INT32:
-		if (len == 4) {
-			u32 *val = (u32 *) pos;
-			printf("      Value: %u\n",
-			       (unsigned int) ntohl(*val));
-		} else
+		if (len == 4)
+			printf("      Value: %u\n", WPA_GET_BE32(pos));
+		else
 			printf("      Invalid INT32 length %d\n", len);
 		break;
 
@@ -273,7 +272,7 @@
 
 void radius_msg_dump(struct radius_msg *msg)
 {
-	int i;
+	size_t i;
 
 	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
 	       msg->hdr->code, radius_code_string(msg->hdr->code),
@@ -291,7 +290,7 @@
 		u8 auth[MD5_MAC_LEN];
 		struct radius_attr_hdr *attr;
 
-		memset(auth, 0, MD5_MAC_LEN);
+		os_memset(auth, 0, MD5_MAC_LEN);
 		attr = radius_msg_add_attr(msg,
 					   RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
 					   auth, MD5_MAC_LEN);
@@ -323,7 +322,7 @@
 	const u8 *addr[4];
 	size_t len[4];
 
-	memset(auth, 0, MD5_MAC_LEN);
+	os_memset(auth, 0, MD5_MAC_LEN);
 	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
 				   auth, MD5_MAC_LEN);
 	if (attr == NULL) {
@@ -331,8 +330,8 @@
 		return -1;
 	}
 	msg->hdr->length = htons(msg->buf_used);
-	memcpy(msg->hdr->authenticator, req_authenticator,
-	       sizeof(msg->hdr->authenticator));
+	os_memcpy(msg->hdr->authenticator, req_authenticator,
+		  sizeof(msg->hdr->authenticator));
 	hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
 		 (u8 *) (attr + 1));
 
@@ -363,7 +362,7 @@
 	size_t len[2];
 
 	msg->hdr->length = htons(msg->buf_used);
-	memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
+	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
 	addr[0] = msg->buf;
 	len[0] = msg->buf_used;
 	addr[1] = secret;
@@ -384,9 +383,7 @@
 		struct radius_attr_hdr **nattrs;
 		int nlen = msg->attr_size * 2;
 
-		nattrs = (struct radius_attr_hdr **)
-			realloc(msg->attrs, nlen * sizeof(*msg->attrs));
-
+		nattrs = os_realloc(msg->attrs, nlen * sizeof(*msg->attrs));
 		if (nattrs == NULL)
 			return -1;
 
@@ -417,12 +414,12 @@
 	if (msg->buf_size < buf_needed) {
 		/* allocate more space for message buffer */
 		unsigned char *nbuf;
-		int nlen = msg->buf_size;
-		int diff, i;
+		size_t i, nlen = msg->buf_size;
+		int diff;
 
 		while (nlen < buf_needed)
 			nlen *= 2;
-		nbuf = (unsigned char *) realloc(msg->buf, nlen);
+		nbuf = os_realloc(msg->buf, nlen);
 		if (nbuf == NULL)
 			return NULL;
 		diff = nbuf - msg->buf;
@@ -432,7 +429,7 @@
 		for (i = 0; i < msg->attr_used; i++)
 			msg->attrs[i] = (struct radius_attr_hdr *)
 				(((u8 *) msg->attrs[i]) + diff);
-		memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
+		os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
 		msg->buf_size = nlen;
 	}
 
@@ -440,7 +437,7 @@
 	attr->type = type;
 	attr->length = sizeof(*attr) + data_len;
 	if (data_len > 0)
-		memcpy(attr + 1, data, data_len);
+		os_memcpy(attr + 1, data, data_len);
 
 	msg->buf_used += sizeof(*attr) + data_len;
 
@@ -475,23 +472,23 @@
 		       (unsigned long) len - msg_len);
 	}
 
-	msg = (struct radius_msg *) malloc(sizeof(*msg));
+	msg = os_malloc(sizeof(*msg));
 	if (msg == NULL)
 		return NULL;
 
 	if (radius_msg_initialize(msg, msg_len)) {
-		free(msg);
+		os_free(msg);
 		return NULL;
 	}
 
-	memcpy(msg->buf, data, msg_len);
+	os_memcpy(msg->buf, data, msg_len);
 	msg->buf_size = msg->buf_used = msg_len;
 
 	/* parse attributes */
 	pos = (unsigned char *) (msg->hdr + 1);
 	end = msg->buf + msg->buf_used;
 	while (pos < end) {
-		if (end - pos < sizeof(*attr))
+		if ((size_t) (end - pos) < sizeof(*attr))
 			goto fail;
 
 		attr = (struct radius_attr_hdr *) pos;
@@ -511,7 +508,7 @@
 
  fail:
 	radius_msg_free(msg);
-	free(msg);
+	os_free(msg);
 	return NULL;
 }
 
@@ -543,8 +540,7 @@
 u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
 {
 	u8 *eap, *pos;
-	size_t len;
-	int i;
+	size_t len, i;
 
 	if (msg == NULL)
 		return NULL;
@@ -559,7 +555,7 @@
 	if (len == 0)
 		return NULL;
 
-	eap = malloc(len);
+	eap = os_malloc(len);
 	if (eap == NULL)
 		return NULL;
 
@@ -568,7 +564,7 @@
 		if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE) {
 			struct radius_attr_hdr *attr = msg->attrs[i];
 			int flen = attr->length - sizeof(*attr);
-			memcpy(pos, attr + 1, flen);
+			os_memcpy(pos, attr + 1, flen);
 			pos += flen;
 		}
 	}
@@ -586,7 +582,7 @@
 	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
 	u8 orig_authenticator[16];
 	struct radius_attr_hdr *attr = NULL;
-	int i;
+	size_t i;
 
 	for (i = 0; i < msg->attr_used; i++) {
 		if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
@@ -604,22 +600,22 @@
 		return 1;
 	}
 
-	memcpy(orig, attr + 1, MD5_MAC_LEN);
-	memset(attr + 1, 0, MD5_MAC_LEN);
+	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+	os_memset(attr + 1, 0, MD5_MAC_LEN);
 	if (req_auth) {
-		memcpy(orig_authenticator, msg->hdr->authenticator,
-		       sizeof(orig_authenticator));
-		memcpy(msg->hdr->authenticator, req_auth,
-		       sizeof(msg->hdr->authenticator));
+		os_memcpy(orig_authenticator, msg->hdr->authenticator,
+			  sizeof(orig_authenticator));
+		os_memcpy(msg->hdr->authenticator, req_auth,
+			  sizeof(msg->hdr->authenticator));
 	}
 	hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
-	memcpy(attr + 1, orig, MD5_MAC_LEN);
+	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
 	if (req_auth) {
-		memcpy(msg->hdr->authenticator, orig_authenticator,
-		       sizeof(orig_authenticator));
+		os_memcpy(msg->hdr->authenticator, orig_authenticator,
+			  sizeof(orig_authenticator));
 	}
 
-	if (memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+	if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
 		printf("Invalid Message-Authenticator!\n");
 		return 1;
 	}
@@ -656,13 +652,12 @@
 	addr[3] = secret;
 	len[3] = secret_len;
 	md5_vector(4, addr, len, hash);
-	if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+	if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
 		printf("Response Authenticator invalid!\n");
 		return 1;
 	}
 
 	return 0;
-
 }
 
 
@@ -670,7 +665,7 @@
 			 u8 type)
 {
 	struct radius_attr_hdr *attr = NULL;
-	int i;
+	size_t i;
 
 	for (i = 0; i < src->attr_used; i++) {
 		if (src->attrs[i]->type == type) {
@@ -695,15 +690,15 @@
  * Use one-way MD5 hash calculated from current timestamp and some data given
  * by the caller. */
 void radius_msg_make_authenticator(struct radius_msg *msg,
-				   u8 *data, size_t len)
+				   const u8 *data, size_t len)
 {
-	struct timeval tv;
+	struct os_time tv;
 	long int l;
 	const u8 *addr[3];
 	size_t elen[3];
 
-	gettimeofday(&tv, NULL);
-	l = random();
+	os_get_time(&tv);
+	l = os_random();
 	addr[0] = (u8 *) &tv;
 	elen[0] = sizeof(tv);
 	addr[1] = data;
@@ -717,21 +712,21 @@
 /* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
  * Returns the Attribute payload and sets alen to indicate the length of the
  * payload if a vendor attribute with subtype is found, otherwise returns NULL.
- * The returned payload is allocated with malloc() and caller must free it.
+ * The returned payload is allocated with os_malloc() and caller must free it
+ * by calling os_free().
  */
 static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
 				      u8 subtype, size_t *alen)
 {
 	u8 *data, *pos;
-	int i;
-	size_t len;
+	size_t i, len;
 
 	if (msg == NULL)
 		return NULL;
 
 	for (i = 0; i < msg->attr_used; i++) {
 		struct radius_attr_hdr *attr = msg->attrs[i];
-		int left;
+		size_t left;
 		u32 vendor_id;
 		struct radius_attr_vendor *vhdr;
 
@@ -744,7 +739,7 @@
 
 		pos = (u8 *) (attr + 1);
 
-		memcpy(&vendor_id, pos, 4);
+		os_memcpy(&vendor_id, pos, 4);
 		pos += 4;
 		left -= 4;
 
@@ -765,10 +760,10 @@
 			}
 
 			len = vhdr->vendor_length - sizeof(*vhdr);
-			data = malloc(len);
+			data = os_malloc(len);
 			if (data == NULL)
 				return NULL;
-			memcpy(data, pos + sizeof(*vhdr), len);
+			os_memcpy(data, pos + sizeof(*vhdr), len);
 			if (alen)
 				*alen = len;
 			return data;
@@ -804,7 +799,7 @@
 	}
 
 	plen = left;
-	ppos = plain = malloc(plen);
+	ppos = plain = os_malloc(plen);
 	if (plain == NULL)
 		return NULL;
 
@@ -833,19 +828,19 @@
 
 	if (plain[0] > plen - 1) {
 		printf("Failed to decrypt MPPE key\n");
-		free(plain);
+		os_free(plain);
 		return NULL;
 	}
 
-	res = malloc(plain[0]);
+	res = os_malloc(plain[0]);
 	if (res == NULL) {
-		free(plain);
+		os_free(plain);
 		return NULL;
 	}
-	memcpy(res, plain + 1, plain[0]);
+	os_memcpy(res, plain + 1, plain[0]);
 	if (reslen)
 		*reslen = plain[0];
-	free(plain);
+	os_free(plain);
 	return res;
 }
 
@@ -867,9 +862,9 @@
 	if (len & 0x0f) {
 		len = (len & 0xf0) + 16;
 	}
-	memset(ebuf, 0, len);
+	os_memset(ebuf, 0, len);
 	ebuf[0] = key_len;
-	memcpy(ebuf + 1, key, key_len);
+	os_memcpy(ebuf + 1, key, key_len);
 
 	*elen = len;
 
@@ -910,12 +905,10 @@
 	if (msg == NULL || sent_msg == NULL)
 		return NULL;
 
-	keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+	keys = wpa_zalloc(sizeof(*keys));
 	if (keys == NULL)
 		return NULL;
 
-	memset(keys, 0, sizeof(*keys));
-
 	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
 					 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
 					 &keylen);
@@ -924,7 +917,7 @@
 					    sent_msg->hdr->authenticator,
 					    secret, secret_len,
 					    &keys->send_len);
-		free(key);
+		os_free(key);
 	}
 
 	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
@@ -935,7 +928,7 @@
 					    sent_msg->hdr->authenticator,
 					    secret, secret_len,
 					    &keys->recv_len);
-		free(key);
+		os_free(key);
 	}
 
 	return keys;
@@ -953,21 +946,20 @@
 	if (msg == NULL || sent_msg == NULL)
 		return NULL;
 
-	keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+	keys = wpa_zalloc(sizeof(*keys));
 	if (keys == NULL)
 		return NULL;
 
-	memset(keys, 0, sizeof(*keys));
-
 	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
 					 RADIUS_CISCO_AV_PAIR, &keylen);
-	if (key && keylen == 51 && memcmp(key, "leap:session-key=", 17) == 0) {
+	if (key && keylen == 51 &&
+	    os_memcmp(key, "leap:session-key=", 17) == 0) {
 		keys->recv = decrypt_ms_key(key + 17, keylen - 17,
 					    sent_msg->hdr->authenticator,
 					    secret, secret_len,
 					    &keys->recv_len);
-		free(key);
 	}
+	os_free(key);
 
 	return keys;
 }
@@ -991,17 +983,17 @@
 	hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
 
 	/* MS-MPPE-Send-Key */
-	buf = malloc(hlen + send_key_len + 16);
+	buf = os_malloc(hlen + send_key_len + 16);
 	if (buf == NULL) {
 		return 0;
 	}
 	pos = buf;
-	memcpy(pos, &vendor_id, sizeof(vendor_id));
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
 	pos += sizeof(vendor_id);
 	vhdr = (struct radius_attr_vendor *) pos;
 	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
 	pos = (u8 *) (vhdr + 1);
-	salt = random() | 0x8000;
+	salt = os_random() | 0x8000;
 	*pos++ = salt >> 8;
 	*pos++ = salt;
 	encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
@@ -1010,18 +1002,18 @@
 
 	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
 				   buf, hlen + elen);
-	free(buf);
+	os_free(buf);
 	if (attr == NULL) {
 		return 0;
 	}
 
 	/* MS-MPPE-Recv-Key */
-	buf = malloc(hlen + send_key_len + 16);
+	buf = os_malloc(hlen + send_key_len + 16);
 	if (buf == NULL) {
 		return 0;
 	}
 	pos = buf;
-	memcpy(pos, &vendor_id, sizeof(vendor_id));
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
 	pos += sizeof(vendor_id);
 	vhdr = (struct radius_attr_vendor *) pos;
 	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
@@ -1035,7 +1027,7 @@
 
 	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
 				   buf, hlen + elen);
-	free(buf);
+	os_free(buf);
 	if (attr == NULL) {
 		return 0;
 	}
@@ -1052,8 +1044,8 @@
 				  u8 *secret, size_t secret_len)
 {
 	u8 buf[128];
-	int padlen, i, pos;
-	size_t buf_len;
+	int padlen, i;
+	size_t buf_len, pos;
 	const u8 *addr[2];
 	size_t len[2];
 	u8 hash[16];
@@ -1061,13 +1053,13 @@
 	if (data_len > 128)
 		return NULL;
 
-	memcpy(buf, data, data_len);
+	os_memcpy(buf, data, data_len);
 	buf_len = data_len;
 
 	padlen = data_len % 16;
 	if (padlen) {
 		padlen = 16 - padlen;
-		memset(buf + data_len, 0, padlen);
+		os_memset(buf + data_len, 0, padlen);
 		buf_len += padlen;
 	}
 
@@ -1101,9 +1093,8 @@
 
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
 {
-	int i;
 	struct radius_attr_hdr *attr = NULL;
-	size_t dlen;
+	size_t i, dlen;
 
 	for (i = 0; i < msg->attr_used; i++) {
 		if (msg->attrs[i]->type == type) {
@@ -1117,7 +1108,7 @@
 
 	dlen = attr->length - sizeof(*attr);
 	if (buf)
-		memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+		os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
 	return dlen;
 }
 
@@ -1125,7 +1116,7 @@
 int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
 			    size_t *len, const u8 *start)
 {
-	int i;
+	size_t i;
 	struct radius_attr_hdr *attr = NULL;
 
 	for (i = 0; i < msg->attr_used; i++) {
@@ -1147,7 +1138,8 @@
 
 int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
 {
-	int i, count;
+	size_t i;
+	int count;
 
 	for (count = 0, i = 0; i < msg->attr_used; i++) {
 		if (msg->attrs[i]->type == type &&
@@ -1158,3 +1150,80 @@
 
 	return count;
 }
+
+
+struct radius_tunnel_attrs {
+	int tag_used;
+	int type; /* Tunnel-Type */
+	int medium_type; /* Tunnel-Medium-Type */
+	int vlanid;
+};
+
+
+/**
+ * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * @msg: RADIUS message
+ * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ */
+int radius_msg_get_vlanid(struct radius_msg *msg)
+{
+	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
+	size_t i;
+	struct radius_attr_hdr *attr = NULL;
+	const u8 *data;
+	char buf[10];
+	size_t dlen;
+
+	os_memset(&tunnel, 0, sizeof(tunnel));
+
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = msg->attrs[i];
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (attr->length < 3)
+			continue;
+		if (data[0] >= RADIUS_TUNNEL_TAGS)
+			tun = &tunnel[0];
+		else
+			tun = &tunnel[data[0]];
+
+		switch (attr->type) {
+		case RADIUS_ATTR_TUNNEL_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->type = (data[1] << 16) | (data[2] << 8) | data[3];
+			break;
+		case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->medium_type =
+				(data[1] << 16) | (data[2] << 8) | data[3];
+			break;
+		case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
+			if (data[0] < RADIUS_TUNNEL_TAGS) {
+				data++;
+				dlen--;
+			}
+			if (dlen >= sizeof(buf))
+				break;
+			os_memcpy(buf, data, dlen);
+			buf[dlen] = '\0';
+			tun->tag_used++;
+			tun->vlanid = atoi(buf);
+			break;
+		}
+	}
+
+	for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
+		tun = &tunnel[i];
+		if (tun->tag_used &&
+		    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
+		    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
+		    tun->vlanid > 0)
+			return tun->vlanid;
+	}
+
+	return -1;
+}
--- /dev/null
+++ contrib/hostapd/eap_sake_common.h
@@ -0,0 +1,104 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006, 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_SAKE_COMMON_H
+#define EAP_SAKE_COMMON_H
+
+#define EAP_SAKE_VERSION 2
+
+#define EAP_SAKE_SUBTYPE_CHALLENGE 1
+#define EAP_SAKE_SUBTYPE_CONFIRM 2
+#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3
+#define EAP_SAKE_SUBTYPE_IDENTITY 4
+
+#define EAP_SAKE_AT_RAND_S 1
+#define EAP_SAKE_AT_RAND_P 2
+#define EAP_SAKE_AT_MIC_S 3
+#define EAP_SAKE_AT_MIC_P 4
+#define EAP_SAKE_AT_SERVERID 5
+#define EAP_SAKE_AT_PEERID 6
+#define EAP_SAKE_AT_SPI_S 7
+#define EAP_SAKE_AT_SPI_P 8
+#define EAP_SAKE_AT_ANY_ID_REQ 9
+#define EAP_SAKE_AT_PERM_ID_REQ 10
+#define EAP_SAKE_AT_ENCR_DATA 128
+#define EAP_SAKE_AT_IV 129
+#define EAP_SAKE_AT_PADDING 130
+#define EAP_SAKE_AT_NEXT_TMPID 131
+#define EAP_SAKE_AT_MSK_LIFE 132
+
+#define EAP_SAKE_RAND_LEN 16
+#define EAP_SAKE_MIC_LEN 16
+#define EAP_SAKE_ROOT_SECRET_LEN 16
+#define EAP_SAKE_SMS_LEN 16
+#define EAP_SAKE_TEK_AUTH_LEN 16
+#define EAP_SAKE_TEK_CIPHER_LEN 16
+#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_sake_hdr {
+	u8 code;
+	u8 identifier;
+	u16 length;
+	u8 type; /* EAP_TYPE_SAKE */
+	u8 version; /* EAP_SAKE_VERSION */
+	u8 session_id;
+	u8 subtype;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+struct eap_sake_parse_attr {
+	const u8 *rand_s;
+	const u8 *rand_p;
+	const u8 *mic_s;
+	const u8 *mic_p;
+	const u8 *serverid;
+	size_t serverid_len;
+	const u8 *peerid;
+	size_t peerid_len;
+	const u8 *spi_s;
+	size_t spi_s_len;
+	const u8 *spi_p;
+	size_t spi_p_len;
+	const u8 *any_id_req;
+	const u8 *perm_id_req;
+	const u8 *encr_data;
+	size_t encr_data_len;
+	const u8 *iv;
+	size_t iv_len;
+	const u8 *next_tmpid;
+	size_t next_tmpid_len;
+	const u8 *msk_life;
+};
+
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+			      struct eap_sake_parse_attr *attr);
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+			  const u8 *rand_s, const u8 *rand_p,
+			  u8 *tek, u8 *msk, u8 *emsk);
+int eap_sake_compute_mic(const u8 *tek_auth,
+			 const u8 *rand_s, const u8 *rand_p,
+			 const u8 *serverid, size_t serverid_len,
+			 const u8 *peerid, size_t peerid_len,
+			 int peer, const u8 *eap, size_t eap_len,
+			 const u8 *mic_pos, u8 *mic);
+
+#endif /* EAP_SAKE_COMMON_H */
Index: ieee802_11_auth.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_11_auth.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ieee802_11_auth.c -L contrib/hostapd/ieee802_11_auth.c -u -r1.2 -r1.3
--- contrib/hostapd/ieee802_11_auth.c
+++ contrib/hostapd/ieee802_11_auth.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / IEEE 802.11 authentication (ACL)
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2006, 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
@@ -13,14 +12,9 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
 
 #include "hostapd.h"
 #include "ieee802_11.h"
@@ -28,7 +22,6 @@
 #include "radius.h"
 #include "radius_client.h"
 #include "eloop.h"
-#include "hostap_common.h"
 
 #define RADIUS_ACL_TIMEOUT 30
 
@@ -40,6 +33,7 @@
 	struct hostapd_cached_radius_acl *next;
 	u32 session_timeout;
 	u32 acct_interim_interval;
+	int vlan_id;
 };
 
 
@@ -65,9 +59,9 @@
 }
 
 
-static int hostapd_acl_cache_get(struct hostapd_data *hapd, u8 *addr,
+static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 				 u32 *session_timeout,
-				 u32 *acct_interim_interval)
+				 u32 *acct_interim_interval, int *vlan_id)
 {
 	struct hostapd_cached_radius_acl *entry;
 	time_t now;
@@ -82,6 +76,8 @@
 			if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 				*session_timeout = entry->session_timeout;
 			*acct_interim_interval = entry->acct_interim_interval;
+			if (vlan_id)
+				*vlan_id = entry->vlan_id;
 			return entry->accepted;
 		}
 
@@ -101,7 +97,7 @@
 }
 
 
-static int hostapd_radius_acl_query(hostapd *hapd, u8 *addr,
+static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
 				    struct hostapd_acl_query_data *query)
 {
 	struct radius_msg *msg;
@@ -154,7 +150,7 @@
 	}
 
 	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		 MAC2STR(hapd->own_addr), hapd->conf->ssid);
+		 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
 				 (u8 *) buf, strlen(buf))) {
 		printf("Could not add Called-Station-Id\n");
@@ -192,11 +188,14 @@
 }
 
 
-int hostapd_allowed_address(hostapd *hapd, u8 *addr, u8 *msg, size_t len,
-			    u32 *session_timeout, u32 *acct_interim_interval)
+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+			    const u8 *msg, size_t len, u32 *session_timeout,
+			    u32 *acct_interim_interval, int *vlan_id)
 {
 	*session_timeout = 0;
 	*acct_interim_interval = 0;
+	if (vlan_id)
+		*vlan_id = 0;
 
 	if (hostapd_maclist_found(hapd->conf->accept_mac,
 				  hapd->conf->num_accept_mac, addr))
@@ -216,7 +215,8 @@
 
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
-						acct_interim_interval);
+						acct_interim_interval,
+						vlan_id);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			return res;
@@ -237,12 +237,11 @@
 			return HOSTAPD_ACL_REJECT;
 
 		/* No entry in the cache - query external RADIUS server */
-		query = malloc(sizeof(*query));
+		query = wpa_zalloc(sizeof(*query));
 		if (query == NULL) {
 			printf("malloc for query data failed\n");
 			return HOSTAPD_ACL_REJECT;
 		}
-		memset(query, 0, sizeof(*query));
 		time(&query->timestamp);
 		memcpy(query->addr, addr, ETH_ALEN);
 		if (hostapd_radius_acl_query(hapd, addr, query)) {
@@ -272,7 +271,7 @@
 }
 
 
-static void hostapd_acl_expire_cache(hostapd *hapd, time_t now)
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd, time_t now)
 {
 	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
 
@@ -301,7 +300,7 @@
 }
 
 
-static void hostapd_acl_expire_queries(hostapd *hapd, time_t now)
+static void hostapd_acl_expire_queries(struct hostapd_data *hapd, time_t now)
 {
 	struct hostapd_acl_query_data *prev, *entry, *tmp;
 
@@ -332,7 +331,7 @@
 
 static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	time_t now;
 
 	time(&now);
@@ -382,12 +381,11 @@
 	}
 
 	/* Insert Accept/Reject info into ACL cache */
-	cache = malloc(sizeof(*cache));
+	cache = wpa_zalloc(sizeof(*cache));
 	if (cache == NULL) {
 		printf("Failed to add ACL cache entry\n");
 		goto done;
 	}
-	memset(cache, 0, sizeof(*cache));
 	time(&cache->timestamp);
 	memcpy(cache->addr, query->addr, sizeof(cache->addr));
 	if (msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
@@ -408,6 +406,8 @@
 				      MAC2STR(query->addr));
 			cache->acct_interim_interval = 0;
 		}
+
+		cache->vlan_id = radius_msg_get_vlanid(msg);
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
 	cache->next = hapd->acl_cache;
@@ -417,7 +417,7 @@
 	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Re-sending authentication frame "
 		      "after successful RADIUS ACL query\n");
 	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
-			WLAN_FC_STYPE_AUTH);
+			WLAN_FC_STYPE_AUTH, NULL);
 
  done:
 	if (prev == NULL)
@@ -431,7 +431,7 @@
 }
 
 
-int hostapd_acl_init(hostapd *hapd)
+int hostapd_acl_init(struct hostapd_data *hapd)
 {
 	if (radius_client_register(hapd->radius, RADIUS_AUTH,
 				   hostapd_acl_recv_radius, hapd))
@@ -443,10 +443,12 @@
 }
 
 
-void hostapd_acl_deinit(hostapd *hapd)
+void hostapd_acl_deinit(struct hostapd_data *hapd)
 {
 	struct hostapd_acl_query_data *query, *prev;
 
+	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
+
 	hostapd_acl_cache_free(hapd->acl_cache);
 
 	query = hapd->acl_queries;
@@ -456,3 +458,16 @@
 		hostapd_acl_query_free(prev);
 	}
 }
+
+
+int hostapd_acl_reconfig(struct hostapd_data *hapd,
+			 struct hostapd_config *oldconf)
+{
+	if (!hapd->radius_client_reconfigured)
+		return 0;
+
+	hostapd_acl_deinit(hapd);
+	return hostapd_acl_init(hapd);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
Index: ctrl_iface.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ctrl_iface.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/ctrl_iface.h -L contrib/hostapd/ctrl_iface.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/ctrl_iface.h
+++ contrib/hostapd/ctrl_iface.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, 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 CTRL_IFACE_H
 #define CTRL_IFACE_H
 
Index: defs.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/defs.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/defs.h -L contrib/hostapd/defs.h -u -r1.2 -r1.3
--- contrib/hostapd/defs.h
+++ contrib/hostapd/defs.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Common definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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
@@ -24,7 +24,8 @@
 typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 
 
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP,
+	       WPA_ALG_IGTK, WPA_ALG_DHV } wpa_alg;
 typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
 	       CIPHER_WEP104 } wpa_cipher;
 typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
@@ -128,4 +129,12 @@
 	WPA_COMPLETED
 } wpa_states;
 
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
 #endif /* DEFS_H */
--- /dev/null
+++ contrib/hostapd/sha256.c
@@ -0,0 +1,379 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2006, 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 "crypto.h"
+
+
+/**
+ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (32 bytes)
+ */
+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+			const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[32];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = SHA256(key) */
+        if (key_len > 64) {
+		sha256_vector(1, &key, &key_len, tk);
+		key = tk;
+		key_len = 32;
+        }
+
+	/* the HMAC_SHA256 transform looks like:
+	 *
+	 * SHA256(K XOR opad, SHA256(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	memset(k_pad, 0, sizeof(k_pad));
+	memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	sha256_vector(1 + num_elem, _addr, _len, mac);
+
+	memset(k_pad, 0, sizeof(k_pad));
+	memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = SHA256_MAC_LEN;
+	sha256_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (20 bytes)
+ */
+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		 size_t data_len, u8 *mac)
+{
+	hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5A.3)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+		const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	u16 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[3];
+	size_t len[3];
+	u8 counter_le[2];
+
+	addr[0] = counter_le;
+	len[0] = 2;
+	addr[1] = (u8 *) label;
+	len[1] = strlen(label) + 1;
+	addr[2] = data;
+	len[2] = data_len;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		WPA_PUT_LE16(counter_le, counter);
+		if (plen >= SHA256_MAC_LEN) {
+			hmac_sha256_vector(key, key_len, 3, addr, len,
+					   &buf[pos]);
+			pos += SHA256_MAC_LEN;
+		} else {
+			hmac_sha256_vector(key, key_len, 3, addr, len, hash);
+			memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+}
+
+
+#ifdef INTERNAL_SHA256
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[64];
+};
+
+static void sha256_init(struct sha256_state *md);
+static int sha256_process(struct sha256_state *md, const unsigned char *in,
+			  unsigned long inlen);
+static int sha256_done(struct sha256_state *md, unsigned char *out);
+
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		 u8 *mac)
+{
+	struct sha256_state ctx;
+	size_t i;
+
+	sha256_init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		sha256_process(&ctx, addr[i], len[i]);
+	sha256_done(&ctx, mac);
+}
+
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+
+/* Various logical functions */
+#define RORc(x, y) \
+( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
+   ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y)) 
+#define S(x, n)         RORc((x), (n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md, unsigned char *buf)
+{
+	u32 S[8], W[64], t0, t1;
+	u32 t;
+	int i;
+
+	/* copy state into S */
+	for (i = 0; i < 8; i++) {
+		S[i] = md->state[i];
+	}
+
+	/* copy the state into 512-bits into W[0..15] */
+	for (i = 0; i < 16; i++)
+		W[i] = WPA_GET_BE32(buf + (4 * i));
+
+	/* fill W[16..63] */
+	for (i = 16; i < 64; i++) {
+		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+			W[i - 16];
+	}        
+
+	/* Compress */
+#define RND(a,b,c,d,e,f,g,h,i)                          \
+	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
+	t1 = Sigma0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+	for (i = 0; i < 64; ++i) {
+		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; 
+		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+	}
+
+	/* feedback */
+	for (i = 0; i < 8; i++) {
+		md->state[i] = md->state[i] + S[i];
+	}
+	return 0;
+}
+
+
+/* Initialize the hash state */
+static void sha256_init(struct sha256_state *md)
+{
+	md->curlen = 0;
+	md->length = 0;
+	md->state[0] = 0x6A09E667UL;
+	md->state[1] = 0xBB67AE85UL;
+	md->state[2] = 0x3C6EF372UL;
+	md->state[3] = 0xA54FF53AUL;
+	md->state[4] = 0x510E527FUL;
+	md->state[5] = 0x9B05688CUL;
+	md->state[6] = 0x1F83D9ABUL;
+	md->state[7] = 0x5BE0CD19UL;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+static int sha256_process(struct sha256_state *md, const unsigned char *in,
+			  unsigned long inlen)
+{
+	unsigned long n;
+#define block_size 64
+
+	if (md->curlen > sizeof(md->buf))
+		return -1;
+
+	while (inlen > 0) {
+		if (md->curlen == 0 && inlen >= block_size) {
+			if (sha256_compress(md, (unsigned char *) in) < 0)
+				return -1;
+			md->length += block_size * 8;
+			in += block_size;
+			inlen -= block_size;
+		} else {
+			n = MIN(inlen, (block_size - md->curlen));
+			memcpy(md->buf + md->curlen, in, n);
+			md->curlen += n;
+			in += n;
+			inlen -= n;
+			if (md->curlen == block_size) {
+				if (sha256_compress(md, md->buf) < 0)
+					return -1;
+				md->length += 8 * block_size;
+				md->curlen = 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (32 bytes)
+   @return CRYPT_OK if successful
+*/
+static int sha256_done(struct sha256_state *md, unsigned char *out)
+{
+	int i;
+
+	if (md->curlen >= sizeof(md->buf))
+		return -1;
+
+	/* increase the length of the message */
+	md->length += md->curlen * 8;
+
+	/* append the '1' bit */
+	md->buf[md->curlen++] = (unsigned char) 0x80;
+
+	/* if the length is currently above 56 bytes we append zeros
+	 * then compress.  Then we can fall back to padding zeros and length
+	 * encoding like normal.
+	 */
+	if (md->curlen > 56) {
+		while (md->curlen < 64) {
+			md->buf[md->curlen++] = (unsigned char) 0;
+		}
+		sha256_compress(md, md->buf);
+		md->curlen = 0;
+	}
+
+	/* pad upto 56 bytes of zeroes */
+	while (md->curlen < 56) {
+		md->buf[md->curlen++] = (unsigned char) 0;
+	}
+
+	/* store length */
+	WPA_PUT_BE64(md->buf + 56, md->length);
+	sha256_compress(md, md->buf);
+
+	/* copy output */
+	for (i = 0; i < 8; i++)
+		WPA_PUT_BE32(out + (4 * i), md->state[i]);
+
+	return 0;
+}
+
+/* ===== end - public domain SHA256 implementation ===== */
+
+#endif /* INTERNAL_SHA256 */
Index: common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/common.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/common.h -L contrib/hostapd/common.h -u -r1.2 -r1.3
--- contrib/hostapd/common.h
+++ contrib/hostapd/common.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2006, 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
@@ -15,12 +15,14 @@
 #ifndef COMMON_H
 #define COMMON_H
 
+#include "os.h"
+
 #ifdef __linux__
 #include <endian.h>
 #include <byteswap.h>
 #endif /* __linux__ */
 
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
 #include <sys/types.h>
 #include <sys/endian.h>
 #define __BYTE_ORDER	_BYTE_ORDER
@@ -29,51 +31,22 @@
 #define bswap_16 bswap16
 #define bswap_32 bswap32
 #define bswap_64 bswap64
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-
-static inline int daemon(int nochdir, int noclose)
-{
-	printf("Windows - daemon() not supported yet\n");
-	return -1;
-}
-
-static inline void sleep(int seconds)
-{
-	Sleep(seconds * 1000);
-}
-
-static inline void usleep(unsigned long usec)
-{
-	Sleep(usec / 1000);
-}
-
-#ifndef timersub
-#define timersub(a, b, res) do { \
-	(res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
-	(res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
-	if ((res)->tv_usec < 0) { \
-		(res)->tv_sec--; \
-		(res)->tv_usec += 1000000; \
-	} \
-} while (0)
-#endif
-
-struct timezone {
-	int  tz_minuteswest;
-	int  tz_dsttime;
-};
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+	* defined(__DragonFly__) */
 
-int gettimeofday(struct timeval *tv, struct timezone *tz);
+#ifdef CONFIG_TI_COMPILER
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#ifdef __big_endian__
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif /* CONFIG_TI_COMPILER */
 
-static inline long int random(void)
-{
-	return rand();
-}
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
 
-typedef int gid_t;
 typedef int socklen_t;
 
 #ifndef MSG_DONTWAIT
@@ -84,6 +57,10 @@
 
 #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
 
+#ifdef _MSC_VER
+#define inline __inline
+#endif /* _MSC_VER */
+
 static inline unsigned short wpa_swap_16(unsigned short v)
 {
 	return ((v & 0xff) << 8) | (v >> 8);
@@ -105,6 +82,18 @@
 
 #else /* __CYGWIN__ */
 
+#ifndef __BYTE_ORDER
+#ifndef __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#if defined(sparc)
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+#endif /* __BYTE_ORDER */
+
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define le_to_host16(n) (n)
 #define host_to_le16(n) (n)
@@ -113,6 +102,10 @@
 #define le_to_host32(n) (n)
 #define be_to_host32(n) bswap_32(n)
 #define host_to_be32(n) bswap_32(n)
+#define le_to_host64(n) (n)
+#define host_to_le64(n) (n)
+#define be_to_host64(n) bswap_64(n)
+#define host_to_be64(n) bswap_64(n)
 #elif __BYTE_ORDER == __BIG_ENDIAN
 #define le_to_host16(n) bswap_16(n)
 #define host_to_le16(n) bswap_16(n)
@@ -121,6 +114,10 @@
 #define le_to_host32(n) bswap_32(n)
 #define be_to_host32(n) (n)
 #define host_to_be32(n) (n)
+#define le_to_host64(n) bswap_64(n)
+#define host_to_le64(n) bswap_64(n)
+#define be_to_host64(n) (n)
+#define host_to_be64(n) (n)
 #ifndef WORDS_BIGENDIAN
 #define WORDS_BIGENDIAN
 #endif
@@ -145,12 +142,88 @@
 		(a)[0] = ((u16) (val)) & 0xff;	\
 	} while (0)
 
+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+			 ((u32) (a)[2]))
+#define WPA_PUT_BE24(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u32) (val)) >> 16);	\
+		(a)[1] = (u8) (((u32) (val)) >> 8);	\
+		(a)[2] = (u8) (((u32) (val)) & 0xff);	\
+	} while (0)
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define WPA_PUT_BE32(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u32) (val)) >> 24);	\
+		(a)[1] = (u8) (((u32) (val)) >> 16);	\
+		(a)[2] = (u8) (((u32) (val)) >> 8);	\
+		(a)[3] = (u8) (((u32) (val)) & 0xff);	\
+	} while (0)
+
+#define WPA_PUT_BE64(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u64) (val)) >> 56);	\
+		(a)[1] = (u8) (((u64) (val)) >> 48);	\
+		(a)[2] = (u8) (((u64) (val)) >> 40);	\
+		(a)[3] = (u8) (((u64) (val)) >> 32);	\
+		(a)[4] = (u8) (((u64) (val)) >> 24);	\
+		(a)[5] = (u8) (((u64) (val)) >> 16);	\
+		(a)[6] = (u8) (((u64) (val)) >> 8);	\
+		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
+	} while (0)
+
 
 #ifndef ETH_ALEN
 #define ETH_ALEN 6
 #endif
 
+#ifdef _MSC_VER
+typedef UINT64 u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef INT64 s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* _MSC_VER */
+
+#ifdef __vxworks
+typedef unsigned long long u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef long long s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* __vxworks */
+
+#ifdef CONFIG_TI_COMPILER
+#ifdef _LLONG_AVAILABLE
+typedef unsigned long long u64;
+#else
+/*
+ * TODO: 64-bit variable not available. Using long as a workaround to test the
+ * build, but this will likely not work for all operations.
+ */
+typedef unsigned long u64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#define WPA_TYPES_DEFINED
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef WPA_TYPES_DEFINED
+#ifdef CONFIG_USE_INTTYPES_H
+#include <inttypes.h>
+#else
 #include <stdint.h>
+#endif
 typedef uint64_t u64;
 typedef uint32_t u32;
 typedef uint16_t u16;
@@ -159,19 +232,27 @@
 typedef int32_t s32;
 typedef int16_t s16;
 typedef int8_t s8;
+#define WPA_TYPES_DEFINED
+#endif /* !WPA_TYPES_DEFINED */
 
-int hostapd_get_rand(u8 *buf, size_t len);
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len);
+#define hostapd_get_rand os_get_random
 int hwaddr_aton(const char *txt, u8 *addr);
 int hexstr2bin(const char *hex, u8 *buf, size_t len);
-char * rel2abs_path(const char *rel_path);
 void inc_byte_array(u8 *counter, size_t len);
-void print_char(char c);
-void fprint_char(FILE *f, char c);
+void wpa_get_ntp_timestamp(u8 *buf);
+
+
+#ifdef __GNUC__
+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#endif
 
 
 /* Debugging function - conditional printf and hex dump. Driver wrappers can
- *  use these for debugging purposes. */
+ * use these for debugging purposes. */
 
 enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
 
@@ -179,13 +260,18 @@
 
 #define wpa_debug_print_timestamp() do { } while (0)
 #define wpa_printf(args...) do { } while (0)
-#define wpa_hexdump(args...) do { } while (0)
-#define wpa_hexdump_key(args...) do { } while (0)
-#define wpa_hexdump_ascii(args...) do { } while (0)
-#define wpa_hexdump_ascii_key(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
+#define wpa_debug_open_file() do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
 
 #else /* CONFIG_NO_STDOUT_DEBUG */
 
+int wpa_debug_open_file(void);
+void wpa_debug_close_file(void);
+
 /**
  * wpa_debug_printf_timestamp - Print timestamp for debug output
  *
@@ -207,7 +293,7 @@
  * Note: New line '\n' is added to the end of the text when printing to stdout.
  */
 void wpa_printf(int level, char *fmt, ...)
-__attribute__ ((format (printf, 2, 3)));
+PRINTF_FORMAT(2, 3);
 
 /**
  * wpa_hexdump - conditional hex dump
@@ -273,6 +359,42 @@
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_register_cb(f) do { } while (0)
+#else /* CONFIG_NO_WPA_MSG */
+/**
+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. This function is like wpa_printf(), but it also sends the
+ * same message to all attached ctrl_iface monitors.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_msg(void *ctx, int level, char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+				size_t len);
+
+/**
+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages
+ * @func: Callback function (%NULL to unregister)
+ */
+void wpa_msg_register_cb(wpa_msg_cb_func func);
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+			       size_t len);
+
+
 #ifdef EAPOL_TEST
 #define WPA_ASSERT(a)						       \
 	do {							       \
@@ -287,4 +409,84 @@
 #define WPA_ASSERT(a) do { } while (0)
 #endif
 
+
+#ifdef _MSC_VER
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#undef close
+#define close closesocket
+#endif /* _MSC_VER */
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+/* snprintf - used in number of places; sprintf() is _not_ a good replacement
+ * due to possible buffer overflow; see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for portable implementation of
+ * snprintf. */
+int snprintf(char *str, size_t size, const char *format, ...);
+
+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
+
+/* getopt - only used in main.c */
+int getopt(int argc, char *const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+
+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
+#ifndef __socklen_t_defined
+typedef int socklen_t;
+#endif
+#endif
+
+/* inline - define as __inline or just define it to be empty, if needed */
+#ifdef CONFIG_NO_INLINE
+#define inline
+#else
+#define inline __inline
+#endif
+
+#ifndef __func__
+#define __func__ "__func__ not defined"
+#endif
+
+#ifndef bswap_16
+#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
+#endif
+
+#ifndef bswap_32
+#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
+		     (((u32) (a) << 8) & 0xff0000) | \
+     		     (((u32) (a) >> 8) & 0xff00) | \
+     		     (((u32) (a) >> 24) & 0xff))
+#endif
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#ifdef _WIN32_WCE
+void perror(const char *s);
+#endif /* _WIN32_WCE */
+
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+#define wpa_zalloc(s) os_zalloc((s))
+
+#ifdef CONFIG_NATIVE_WINDOWS
+void wpa_unicode2ascii_inplace(TCHAR *str);
+TCHAR * wpa_strdup_tchar(const char *str);
+#else /* CONFIG_NATIVE_WINDOWS */
+#define wpa_unicode2ascii_inplace(s) do { } while (0)
+#define wpa_strdup_tchar(s) strdup((s))
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len);
+
+typedef u32 __be32;
+typedef u64 __be64;
+
 #endif /* COMMON_H */
--- /dev/null
+++ contrib/hostapd/milenage.h
@@ -0,0 +1,26 @@
+/*
+ * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006 <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 MILENAGE_H
+#define MILENAGE_H
+
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len);
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn);
+void gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
+		  u8 *kc);
+
+#endif /* MILENAGE_H */
--- /dev/null
+++ contrib/hostapd/vlan_init.c
@@ -0,0 +1,835 @@
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "driver.h"
+#include "vlan_init.h"
+
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+typedef __uint64_t __u64;
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#include <linux/if_bridge.h>
+
+#include "priv_netlink.h"
+#include "eloop.h"
+
+
+struct full_dynamic_vlan {
+	int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+
+static int ifconfig_helper(const char *if_name, int up)
+{
+	int fd;
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+		perror("ioctl[SIOCGIFFLAGS]");
+		close(fd);
+		return -1;
+	}
+
+	if (up)
+		ifr.ifr_flags |= IFF_UP;
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+		perror("ioctl[SIOCSIFFLAGS]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int ifconfig_up(const char *if_name)
+{
+	return ifconfig_helper(if_name, 1);
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+	return ifconfig_helper(if_name, 0);
+}
+
+
+/*
+ * These are only available in recent linux headers (without the leading
+ * underscore).
+ */
+#define _GET_VLAN_REALDEV_NAME_CMD	8
+#define _GET_VLAN_VID_CMD		9
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS      		256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+	int fd;
+	struct ifreq ifr;
+	unsigned long args[2];
+	int if_index;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	if_index = if_nametoindex(if_name);
+
+	if (if_index == 0) {
+		printf("Failure determining interface index for '%s'\n",
+		       if_name);
+		close(fd);
+		return -1;
+	}
+
+	args[0] = BRCTL_DEL_IF;
+	args[1] = if_index;
+
+	strncpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) args;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+		/* No error if interface already removed. */
+		perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add interface 'if_name' to the bridge 'br_name'
+
+	returns -1 on error
+	returns 1 if the interface is already part of the bridge
+	returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+	int fd;
+	struct ifreq ifr;
+	unsigned long args[2];
+	int if_index;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	if_index = if_nametoindex(if_name);
+
+	if (if_index == 0) {
+		printf("Failure determining interface index for '%s'\n",
+		       if_name);
+		close(fd);
+		return -1;
+	}
+
+	args[0] = BRCTL_ADD_IF;
+	args[1] = if_index;
+
+	strncpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) args;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		if (errno == EBUSY) {
+			/* The interface is already added. */
+			close(fd);
+			return 1;
+		}
+
+		perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+	int fd;
+	unsigned long arg[2];
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	arg[0] = BRCTL_DEL_BRIDGE;
+	arg[1] = (unsigned long) br_name;
+
+	if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+		/* No error if bridge already removed. */
+		perror("ioctl[BRCTL_DEL_BRIDGE]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add a bridge with the name 'br_name'.
+
+	returns -1 on error
+	returns 1 if the bridge already exists
+	returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+	int fd;
+	unsigned long arg[2];
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	arg[0] = BRCTL_ADD_BRIDGE;
+	arg[1] = (unsigned long) br_name;
+
+	if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+ 		if (errno == EEXIST) {
+			/* The bridge is already added. */
+			close(fd);
+			return 1;
+		} else {
+			perror("ioctl[BRCTL_ADD_BRIDGE]");
+			close(fd);
+			return -1;
+		}
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+	int fd;
+	int i;
+	int port_cnt = 0;
+	unsigned long arg[4];
+	int ifindices[MAX_BR_PORTS];
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	arg[0] = BRCTL_GET_PORT_LIST;
+	arg[1] = (unsigned long) ifindices;
+	arg[2] = MAX_BR_PORTS;
+	arg[3] = 0;
+
+	memset(ifindices, 0, sizeof(ifindices));
+	strncpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) arg;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
+		close(fd);
+		return -1;
+	}
+
+	for (i = 1; i < MAX_BR_PORTS; i++) {
+		if (ifindices[i] > 0) {
+			port_cnt++;
+		}
+	}
+
+	close(fd);
+	return port_cnt;
+}
+
+
+static int vlan_rem(const char *if_name)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	if ((strlen(if_name) + 1) > sizeof(if_request.device1)) {
+		fprintf(stderr, "Interface name to long.\n");
+		return -1;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	memset(&if_request, 0, sizeof(if_request));
+
+	strcpy(if_request.device1, if_name);
+	if_request.cmd = DEL_VLAN_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add a vlan interface with VLAN ID 'vid' and tagged interface
+	'if_name'.
+
+	returns -1 on error
+	returns 1 if the interface already exists
+	returns 0 otherwise
+*/
+static int vlan_add(const char *if_name, int vid)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	ifconfig_up(if_name);
+
+	if ((strlen(if_name) + 1) > sizeof(if_request.device1)) {
+		fprintf(stderr, "Interface name to long.\n");
+		return -1;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	memset(&if_request, 0, sizeof(if_request));
+
+	/* Determine if a suitable vlan device already exists. */
+
+	snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+		 vid);
+
+	if_request.cmd = _GET_VLAN_VID_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
+
+		if (if_request.u.VID == vid) {
+			if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
+
+			if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0
+			    && strncmp(if_request.u.device2, if_name,
+				       sizeof(if_request.u.device2)) == 0) {
+				close(fd);
+				return 1;
+			}
+		}
+	}
+
+	/* A suitable vlan device does not already exist, add one. */
+
+	memset(&if_request, 0, sizeof(if_request));
+	strcpy(if_request.device1, if_name);
+	if_request.u.VID = vid;
+	if_request.cmd = ADD_VLAN_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int vlan_set_name_type(unsigned int name_type)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		perror("socket[AF_INET,SOCK_STREAM]");
+		return -1;
+	}
+
+	memset(&if_request, 0, sizeof(if_request));
+
+	if_request.u.name_type = name_type;
+	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+{
+	char vlan_ifname[IFNAMSIZ];
+	char br_name[IFNAMSIZ];
+	struct hostapd_vlan *vlan = hapd->conf->vlan;
+	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+
+	while (vlan) {
+		if (strcmp(ifname, vlan->ifname) == 0) {
+
+			snprintf(br_name, sizeof(br_name), "brvlan%d",
+				 vlan->vlan_id);
+
+			if (!br_addbr(br_name))
+				vlan->clean |= DVLAN_CLEAN_BR;
+
+			ifconfig_up(br_name);
+
+			if (tagged_interface) {
+
+				if (!vlan_add(tagged_interface, vlan->vlan_id))
+					vlan->clean |= DVLAN_CLEAN_VLAN;
+
+				snprintf(vlan_ifname, sizeof(vlan_ifname),
+					 "vlan%d", vlan->vlan_id);
+
+				if (!br_addif(br_name, vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+
+				ifconfig_up(vlan_ifname);
+			}
+
+			if (!br_addif(br_name, ifname))
+				vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+
+			ifconfig_up(ifname);
+
+			break;
+		}
+		vlan = vlan->next;
+	}
+}
+
+
+static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
+{
+	char vlan_ifname[IFNAMSIZ];
+	char br_name[IFNAMSIZ];
+	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int numports;
+
+	first = prev = vlan;
+
+	while (vlan) {
+		if (strcmp(ifname, vlan->ifname) == 0) {
+			snprintf(br_name, sizeof(br_name), "brvlan%d",
+				 vlan->vlan_id);
+
+			if (tagged_interface) {
+				snprintf(vlan_ifname, sizeof(vlan_ifname),
+					 "vlan%d", vlan->vlan_id);
+
+				numports = br_getnumports(br_name);
+				if (numports == 1) {
+					br_delif(br_name, vlan_ifname);
+
+					vlan_rem(vlan_ifname);
+
+					ifconfig_down(br_name);
+					br_delbr(br_name);
+				}
+			}
+
+			if (vlan == first) {
+				hapd->conf->vlan = vlan->next;
+			} else {
+				prev->next = vlan->next;
+			}
+			free(vlan);
+
+			break;
+		}
+		prev = vlan;
+		vlan = vlan->next;
+	}
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+		  struct hostapd_data *hapd)
+{
+	struct ifinfomsg *ifi;
+	int attrlen, nlmsg_len, rta_len;
+	struct rtattr *attr;
+
+	if (len < sizeof(*ifi))
+		return;
+
+	ifi = NLMSG_DATA(h);
+
+	nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+	attrlen = h->nlmsg_len - nlmsg_len;
+	if (attrlen < 0)
+		return;
+
+	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		char ifname[IFNAMSIZ + 1];
+
+		if (attr->rta_type == IFLA_IFNAME) {
+			int n = attr->rta_len - rta_len;
+			if (n < 0)
+				break;
+
+			memset(ifname, 0, sizeof(ifname));
+
+			if ((size_t) n > sizeof(ifname))
+				n = sizeof(ifname);
+			memcpy(ifname, ((char *) attr) + rta_len, n);
+
+			if (del)
+				vlan_dellink(ifname, hapd);
+			else
+				vlan_newlink(ifname, hapd);
+		}
+
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	char buf[8192];
+	int left;
+	struct sockaddr_nl from;
+	socklen_t fromlen;
+	struct nlmsghdr *h;
+	struct hostapd_data *hapd = eloop_ctx;
+
+	fromlen = sizeof(from);
+	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+			(struct sockaddr *) &from, &fromlen);
+	if (left < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			perror("recvfrom(netlink)");
+		return;
+	}
+
+	h = (struct nlmsghdr *) buf;
+	while (left >= (int) sizeof(*h)) {
+		int len, plen;
+
+		len = h->nlmsg_len;
+		plen = len - sizeof(*h);
+		if (len > left || plen < 0) {
+			printf("Malformed netlink message: "
+			       "len=%d left=%d plen=%d", len, left, plen);
+			break;
+		}
+
+		switch (h->nlmsg_type) {
+		case RTM_NEWLINK:
+			vlan_read_ifnames(h, plen, 0, hapd);
+			break;
+		case RTM_DELLINK:
+			vlan_read_ifnames(h, plen, 1, hapd);
+			break;
+		}
+
+		len = NLMSG_ALIGN(len);
+		left -= len;
+		h = (struct nlmsghdr *) ((char *) h + len);
+	}
+
+	if (left > 0) {
+		printf("%d extra bytes in the end of netlink message",
+		       left);
+	}
+}
+
+
+static struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+	struct sockaddr_nl local;
+	struct full_dynamic_vlan *priv;
+
+	priv = malloc(sizeof(*priv));
+
+	if (priv == NULL)
+		return NULL;
+
+	memset(priv, 0, sizeof(*priv));
+
+	vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+
+	priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (priv->s < 0) {
+		perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+		free(priv);
+		return NULL;
+	}
+
+	memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+	local.nl_groups = RTMGRP_LINK;
+	if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+		perror("bind(netlink)");
+		close(priv->s);
+		free(priv);
+		return NULL;
+	}
+
+	if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+	{
+		close(priv->s);
+		free(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+	if (priv == NULL)
+		return;
+	eloop_unregister_read_sock(priv->s);
+	close(priv->s);
+	free(priv);
+}
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+			      struct hostapd_ssid *mssid, const char *dyn_vlan)
+{
+        int i;
+
+        if (dyn_vlan == NULL)
+		return 0;
+
+	/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
+	 * functions for setting up dynamic broadcast keys. */
+	for (i = 0; i < 4; i++) {
+		if (mssid->wep.key[i] &&
+		    hostapd_set_encryption(dyn_vlan, hapd, "WEP", NULL,
+					   i, mssid->wep.key[i],
+					   mssid->wep.len[i],
+					   i == mssid->wep.idx)) {
+			printf("VLAN: Could not set WEP encryption for "
+			       "dynamic VLAN.\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int vlan_dynamic_add(struct hostapd_data *hapd,
+			    struct hostapd_vlan *vlan)
+{
+	while (vlan) {
+		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
+		    hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
+		{
+			if (errno != EEXIST) {
+				printf("Could not add VLAN iface: %s: %s\n",
+				       vlan->ifname, strerror(errno));
+				return -1;
+			}
+		}
+
+		vlan = vlan->next;
+	}
+
+	return 0;
+}
+
+
+static void vlan_dynamic_remove(struct hostapd_data *hapd,
+				struct hostapd_vlan *vlan)
+{
+	struct hostapd_vlan *next;
+
+	while (vlan) {
+		next = vlan->next;
+
+		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
+		    hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
+				      NULL)) {
+			printf("Could not remove VLAN iface: %s: %s\n",
+			       vlan->ifname, strerror(errno));
+		}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		if (vlan->clean)
+			vlan_dellink(vlan->ifname, hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+		vlan = next;
+	}
+}
+
+
+int vlan_init(struct hostapd_data *hapd)
+{
+	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
+		return -1;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+        return 0;
+}
+
+
+void vlan_deinit(struct hostapd_data *hapd)
+{
+	vlan_dynamic_remove(hapd, hapd->conf->vlan);
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+}
+
+
+int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
+		  struct hostapd_bss_config *oldbss)
+{
+	vlan_dynamic_remove(hapd, oldbss->vlan);
+	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
+		return -1;
+
+	return 0;
+}
+
+
+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+				       struct hostapd_vlan *vlan,
+				       int vlan_id)
+{
+	struct hostapd_vlan *n;
+	char *ifname, *pos;
+
+	if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
+	    vlan->vlan_id != VLAN_ID_WILDCARD)
+		return NULL;
+
+	ifname = strdup(vlan->ifname);
+	if (ifname == NULL)
+		return NULL;
+	pos = strchr(ifname, '#');
+	if (pos == NULL) {
+		free(ifname);
+		return NULL;
+	}
+	*pos++ = '\0';
+
+	n = malloc(sizeof(*n));
+	if (n == NULL) {
+		free(ifname);
+		return NULL;
+	}
+
+	memset(n, 0, sizeof(*n));
+	n->vlan_id = vlan_id;
+	n->dynamic_vlan = 1;
+
+	snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id, pos);
+	free(ifname);
+
+	if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
+		free(n);
+		return NULL;
+	}
+
+	n->next = hapd->conf->vlan;
+	hapd->conf->vlan = n;
+
+	return n;
+}
+
+
+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
+{
+	struct hostapd_vlan *vlan;
+
+	if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+		return 1;
+
+	vlan = hapd->conf->vlan;
+	while (vlan) {
+		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
+			vlan->dynamic_vlan--;
+			break;
+		}
+		vlan = vlan->next;
+	}
+
+	if (vlan == NULL)
+		return 1;
+
+	if (vlan->dynamic_vlan == 0)
+		hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
+
+	return 0;
+}
Index: eloop.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eloop.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eloop.h -L contrib/hostapd/eloop.h -u -r1.2 -r1.3
--- contrib/hostapd/eloop.h
+++ contrib/hostapd/eloop.h
@@ -1,6 +1,6 @@
 /*
  * Event loop
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2006, 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
@@ -23,18 +23,67 @@
 #ifndef ELOOP_H
 #define ELOOP_H
 
-/* Magic number for eloop_cancel_timeout() */
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
 #define ELOOP_ALL_CTX (void *) -1
 
 /**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+	EVENT_TYPE_READ = 0,
+	EVENT_TYPE_WRITE,
+	EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @eloop_ctx: Registered callback context data (global user_data from
+ * eloop_init() call)
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *eloop_ctx,
+				     void *signal_ctx);
+
+/**
  * eloop_init() - Initialize global event loop data
  * @user_data: Pointer to global data passed as eloop_ctx to signal handlers
+ * Returns: 0 on success, -1 on failure
  *
  * This function must be called before any other eloop_* function. user_data
  * can be used to configure a global (to the process) pointer that will be
  * passed as eloop_ctx parameter to signal handlers.
  */
-void eloop_init(void *user_data);
+int eloop_init(void *user_data);
 
 /**
  * eloop_register_read_sock - Register handler for read events
@@ -46,11 +95,11 @@
  *
  * Register a read socket notifier for the given file descriptor. The handler
  * function will be called whenever data is available for reading from the
- * socket.
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
  */
-int eloop_register_read_sock(int sock,
-			     void (*handler)(int sock, void *eloop_ctx,
-					     void *sock_ctx),
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
 			     void *eloop_data, void *user_data);
 
 /**
@@ -63,6 +112,71 @@
 void eloop_unregister_read_sock(int sock);
 
 /**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+			eloop_sock_handler handler,
+			void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targetted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+			 eloop_event_handler handler,
+			 void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
  * eloop_register_timeout - Register timeout
  * @secs: Number of seconds to the timeout
  * @usecs: Number of microseconds to the timeout
@@ -75,7 +189,7 @@
  * given time.
  */
 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   eloop_timeout_handler handler,
 			   void *eloop_data, void *user_data);
 
 /**
@@ -89,7 +203,7 @@
  * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
  * cancelling all timeouts regardless of eloop_data/user_data.
  */
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+int eloop_cancel_timeout(eloop_timeout_handler handler,
 			 void *eloop_data, void *user_data);
 
 /**
@@ -100,20 +214,67 @@
  * Returns: 0 on success, -1 on failure
  *
  * Register a callback function that will be called when a signal is received.
- * The calback function is actually called only after the system signal handler
- * has returned. This means that the normal limits for sighandlers (i.e., only
- * "safe functions" allowed) do not apply for the registered callback.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
  *
  * Signals are 'global' events and there is no local eloop_data pointer like
  * with other handlers. The global user_data pointer registered with
  * eloop_init() will be used as eloop_ctx for signal handlers.
  */
-int eloop_register_signal(int sig,
-			  void (*handler)(int sig, void *eloop_ctx,
-					  void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
 			  void *user_data);
 
 /**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data);
+
+/**
  * eloop_run - Start the event loop
  *
  * Start the event loop and continue running as long as there are any
@@ -133,7 +294,7 @@
 /**
  * eloop_destroy - Free any resources allocated for the event loop
  *
- * After calling eloop_destoy(), other eloop_* functions must not be called
+ * After calling eloop_destroy(), other eloop_* functions must not be called
  * before re-running eloop_init().
  */
 void eloop_destroy(void);
@@ -149,4 +310,18 @@
  */
 int eloop_terminated(void);
 
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+/**
+ * eloop_get_user_data - Get global user data
+ * Returns: user_data pointer that was registered with eloop_init()
+ */
+void * eloop_get_user_data(void);
+
 #endif /* ELOOP_H */
Index: FREEBSD-upgrade
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/FREEBSD-upgrade,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/FREEBSD-upgrade -L contrib/hostapd/FREEBSD-upgrade -u -r1.2 -r1.3
--- contrib/hostapd/FREEBSD-upgrade
+++ contrib/hostapd/FREEBSD-upgrade
@@ -1,4 +1,4 @@
-$FreeBSD: src/contrib/hostapd/FREEBSD-upgrade,v 1.1.2.1 2006/03/24 01:42:33 sam Exp $
+$FreeBSD: src/contrib/hostapd/FREEBSD-upgrade,v 1.3 2007/07/09 16:24:41 sam Exp $
 
 WPA/802.1x Authenticator
 	originals can be found at: http://hostap.epitest.fi/releases/
@@ -6,12 +6,12 @@
 
 For the import files and directories were pruned by:
 
-	tar -X FREEBSD-Xlist -zxf hostapd-0.4.8.tar.gz
+	tar -X FREEBSD-Xlist -zxf hostapd-0.5.8.tar.gz
 
 then imported by:
 
-	cvs import -m 'Import of hostapd 0.4.8' \
-		src/contrib/hostapd MALINEN v0_4_8
+	cvs import -m 'Import of hostapd 0.5.8' \
+		src/contrib/hostapd MALINEN v0_5_8
 
 To make local changes to hostapd, simply patch and commit to the
 main branch (aka HEAD).  Never make local changes on the vendor
@@ -21,4 +21,4 @@
 the next vendor release.
 
 sam at FreeBSD.org
-6-March-2006
+7-July-2007
Index: eap_pax_common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_pax_common.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_pax_common.h -L contrib/hostapd/eap_pax_common.h -u -r1.1 -r1.2
--- contrib/hostapd/eap_pax_common.h
+++ contrib/hostapd/eap_pax_common.h
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005-2006, 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
@@ -15,6 +15,10 @@
 #ifndef EAP_PAX_COMMON_H
 #define EAP_PAX_COMMON_H
 
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
 struct eap_pax_hdr {
 	u8 code;
 	u8 identifier;
@@ -26,7 +30,11 @@
 	u8 dh_group_id;
 	u8 public_key_id;
 	/* Followed by variable length payload and ICV */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
 
 
 /* op_code: */
@@ -45,22 +53,31 @@
 /* flags: */
 #define EAP_PAX_FLAGS_MF			0x01
 #define EAP_PAX_FLAGS_CE			0x02
+#define EAP_PAX_FLAGS_AI			0x04
 
 /* mac_id: */
 #define EAP_PAX_MAC_HMAC_SHA1_128		0x01
-#define EAP_PAX_MAC_AES_CBC_MAC_128		0x02
+#define EAP_PAX_HMAC_SHA256_128			0x02
 
 /* dh_group_id: */
 #define EAP_PAX_DH_GROUP_NONE			0x00
-#define EAP_PAX_DH_GROUP_3072_MODP		0x01
+#define EAP_PAX_DH_GROUP_2048_MODP		0x01
+#define EAP_PAX_DH_GROUP_3072_MODP		0x02
+#define EAP_PAX_DH_GROUP_NIST_ECC_P_256		0x03
 
 /* public_key_id: */
 #define EAP_PAX_PUBLIC_KEY_NONE			0x00
-#define EAP_PAX_PUBLIC_KEY_RSA_OAEP_2048	0x01
+#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP		0x01
+#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5	0x02
+#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC	0x03
+
+/* ADE type: */
+#define EAP_PAX_ADE_VENDOR_SPECIFIC		0x01
+#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING	0x02
+#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING	0x03
 
 
 #define EAP_PAX_RAND_LEN 32
-#define EAP_PAX_MSK_LEN 64
 #define EAP_PAX_MAC_LEN 16
 #define EAP_PAX_ICV_LEN 16
 #define EAP_PAX_AK_LEN 16
Index: eap_pax_common.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_pax_common.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_pax_common.c -L contrib/hostapd/eap_pax_common.c -u -r1.1 -r1.2
--- contrib/hostapd/eap_pax_common.c
+++ contrib/hostapd/eap_pax_common.c
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "sha1.h"
@@ -33,7 +31,7 @@
  * @output: Buffer for the derived key
  * Returns: 0 on success, -1 failed
  *
- * draft-clancy-eap-pax-04.txt, chap. 2.5: PAX-KDF-W(X, Y, Z)
+ * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
  */
 int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
 		const char *identifier,
@@ -50,12 +48,12 @@
 	if (identifier == NULL || num_blocks >= 255)
 		return -1;
 
-	/* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
 	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
 		return -1;
 
 	addr[0] = (const u8 *) identifier;
-	len[0] = strlen(identifier);
+	len[0] = os_strlen(identifier);
 	addr[1] = entropy;
 	len[1] = entropy_len;
 	addr[2] = &counter;
@@ -66,7 +64,7 @@
 	for (counter = 1; counter <= (u8) num_blocks; counter++) {
 		size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
 		hmac_sha1_vector(key, key_len, 3, addr, len, mac);
-		memcpy(pos, mac, clen);
+		os_memcpy(pos, mac, clen);
 		pos += clen;
 		left -= clen;
 	}
@@ -102,7 +100,7 @@
 	size_t len[3];
 	size_t count;
 
-	/* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+	/* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
 	if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
 		return -1;
 
@@ -115,7 +113,7 @@
 
 	count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
 	hmac_sha1_vector(key, key_len, count, addr, len, hash);
-	memcpy(mac, hash, EAP_PAX_MAC_LEN);
+	os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
 
 	return 0;
 }
Index: ap.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ap.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/ap.h -L contrib/hostapd/ap.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/ap.h
+++ contrib/hostapd/ap.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Station table data structures
+ * Copyright (c) 2002-2004, 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 AP_H
 #define AP_H
 
@@ -9,16 +23,13 @@
 #define WLAN_STA_PERM BIT(4)
 #define WLAN_STA_AUTHORIZED BIT(5)
 #define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-#define WLAN_STA_PREAUTH BIT(7)
-
-#define WLAN_RATE_1M BIT(0)
-#define WLAN_RATE_2M BIT(1)
-#define WLAN_RATE_5M5 BIT(2)
-#define WLAN_RATE_11M BIT(3)
-#define WLAN_RATE_COUNT 4
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_NONERP BIT(31)
 
-/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
- * but some pre-standard IEEE 802.11g products use longer elements. */
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs). */
 #define WLAN_SUPP_RATES_MAX 32
 
 
@@ -31,7 +42,14 @@
 	u16 capability;
 	u16 listen_interval; /* or beacon_int for APs */
 	u8 supported_rates[WLAN_SUPP_RATES_MAX];
-	u8 tx_supp_rates;
+	int supported_rates_len;
+
+	unsigned int nonerp_set:1;
+	unsigned int no_short_slot_time_set:1;
+	unsigned int no_short_preamble_set:1;
+
+	u16 auth_alg;
+	u8 previous_ap[6];
 
 	enum {
 		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
@@ -57,26 +75,15 @@
 
 	u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
 
-	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
 	struct wpa_state_machine *wpa_sm;
-	enum {
-		WPA_VERSION_NO_WPA = 0 /* WPA not used */,
-		WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
-		WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
-	} wpa;
-	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
-	struct rsn_pmksa_cache *pmksa;
 	struct rsn_preauth_interface *preauth_iface;
-	u8 req_replay_counter[8 /* WPA_REPLAY_COUNTER_LEN */];
-	int req_replay_counter_used;
-	u32 dot11RSNAStatsTKIPLocalMICFailures;
-	u32 dot11RSNAStatsTKIPRemoteMICFailures;
-};
 
+	struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
+	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+
+	int vlan_id;
+};
 
-#define MAX_STA_COUNT 1024
 
 /* Maximum number of AIDs to use for STAs; must be 2007 or lower
  * (8802.11 limitation) */
@@ -95,5 +102,10 @@
 #define AP_MAX_INACTIVITY (5 * 60)
 #define AP_DISASSOC_DELAY (1)
 #define AP_DEAUTH_DELAY (1)
+/* Number of seconds to keep STA entry with Authenticated flag after it has
+ * been disassociated. */
+#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
+/* Number of seconds to keep STA entry after it has been deauthenticated. */
+#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
 
 #endif /* AP_H */
--- /dev/null
+++ contrib/hostapd/tls_gnutls.c
@@ -0,0 +1,1370 @@
+/*
+ * WPA Supplicant / SSL/TLS interface functions for openssl
+ * Copyright (c) 2004-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 <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#ifdef PKCS12_FUNCS
+#include <gnutls/pkcs12.h>
+#endif /* PKCS12_FUNCS */
+
+#ifdef CONFIG_GNUTLS_EXTRA
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+#define GNUTLS_IA
+#include <gnutls/extra.h>
+#if LIBGNUTLS_VERSION_NUMBER == 0x010302
+/* This function is not included in the current gnutls/extra.h even though it
+ * should be, so define it here as a workaround for the time being. */
+int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
+#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* CONFIG_GNUTLS_EXTRA */
+
+#include "common.h"
+#include "tls.h"
+
+
+#define TLS_RANDOM_SIZE 32
+#define TLS_MASTER_SIZE 48
+
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x010302
+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
+ * use of internal structures to get the master_secret and
+ * {server,client}_random.
+ */
+#define GNUTLS_INTERNAL_STRUCTURE_HACK
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+/*
+ * It looks like gnutls does not provide access to client/server_random and
+ * master_key. This is somewhat unfortunate since these are needed for key
+ * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
+ * hack that copies the gnutls_session_int definition from gnutls_int.h so that
+ * we can get the needed information.
+ */
+
+typedef u8 uint8;
+typedef unsigned char opaque;
+typedef struct {
+    uint8 suite[2];
+} cipher_suite_st;
+
+typedef struct {
+	gnutls_connection_end_t entity;
+	gnutls_kx_algorithm_t kx_algorithm;
+	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t read_mac_algorithm;
+	gnutls_compression_method_t read_compression_algorithm;
+	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t write_mac_algorithm;
+	gnutls_compression_method_t write_compression_algorithm;
+	cipher_suite_st current_cipher_suite;
+	opaque master_secret[TLS_MASTER_SIZE];
+	opaque client_random[TLS_RANDOM_SIZE];
+	opaque server_random[TLS_RANDOM_SIZE];
+	/* followed by stuff we are not interested in */
+} security_parameters_st;
+
+struct gnutls_session_int {
+	security_parameters_st security_parameters;
+	/* followed by things we are not interested in */
+};
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+static int tls_gnutls_ref_count = 0;
+
+struct tls_global {
+	/* Data for session resumption */
+	void *session_data;
+	size_t session_data_size;
+
+	int server;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+};
+
+struct tls_connection {
+	gnutls_session session;
+	char *subject_match, *altsubject_match;
+	int read_alerts, write_alerts, failed;
+
+	u8 *pre_shared_secret;
+	size_t pre_shared_secret_len;
+	int established;
+	int verify_peer;
+
+	u8 *push_buf, *pull_buf, *pull_buf_offset;
+	size_t push_buf_len, pull_buf_len;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+
+	int tls_ia;
+	int final_phase_finished;
+
+#ifdef GNUTLS_IA
+	gnutls_ia_server_credentials_t iacred_srv;
+	gnutls_ia_client_credentials_t iacred_cli;
+
+	/* Session keys generated in the current phase for inner secret
+	 * permutation before generating/verifying PhaseFinished. */
+	u8 *session_keys;
+	size_t session_keys_len;
+
+	u8 inner_secret[TLS_MASTER_SIZE];
+#endif /* GNUTLS_IA */
+};
+
+
+static void tls_log_func(int level, const char *msg)
+{
+	char *s, *pos;
+	if (level == 6 || level == 7) {
+		/* These levels seem to be mostly I/O debug and msg dumps */
+		return;
+	}
+
+	s = os_strdup(msg);
+	if (s == NULL)
+		return;
+
+	pos = s;
+	while (*pos != '\0') {
+		if (*pos == '\n') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
+		   "gnutls<%d> %s", level, s);
+	os_free(s);
+}
+
+
+extern int wpa_debug_show_keys;
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	/* Because of the horrible hack to get master_secret and client/server
+	 * random, we need to make sure that the gnutls version is something
+	 * that is expected to have same structure definition for the session
+	 * data.. */
+	const char *ver;
+	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
+				 "1.3.2",
+				 NULL };
+	int i;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
+		os_free(global);
+		return NULL;
+	}
+	tls_gnutls_ref_count++;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	ver = gnutls_check_version(NULL);
+	if (ver == NULL) {
+		tls_deinit(global);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
+	for (i = 0; ok_ver[i]; i++) {
+		if (strcmp(ok_ver[i], ver) == 0)
+			break;
+	}
+	if (ok_ver[i] == NULL) {
+		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
+			   "to be tested and enabled in tls_gnutls.c", ver);
+		tls_deinit(global);
+		return NULL;
+	}
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	gnutls_global_set_log_function(tls_log_func);
+	if (wpa_debug_show_keys)
+		gnutls_global_set_log_level(11);
+	return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	if (global) {
+		if (global->params_set)
+			gnutls_certificate_free_credentials(global->xcred);
+		os_free(global->session_data);
+		os_free(global);
+	}
+
+	tls_gnutls_ref_count--;
+	if (tls_gnutls_ref_count == 0)
+		gnutls_global_deinit();
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	return 0;
+}
+
+
+static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+	u8 *end;
+	if (conn->pull_buf == NULL) {
+		errno = EWOULDBLOCK;
+		return -1;
+	}
+
+	end = conn->pull_buf + conn->pull_buf_len;
+	if ((size_t) (end - conn->pull_buf_offset) < len)
+		len = end - conn->pull_buf_offset;
+	os_memcpy(buf, conn->pull_buf_offset, len);
+	conn->pull_buf_offset += len;
+	if (conn->pull_buf_offset == end) {
+		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+		os_free(conn->pull_buf);
+		conn->pull_buf = conn->pull_buf_offset = NULL;
+		conn->pull_buf_len = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf",
+			   __func__, end - conn->pull_buf_offset);
+	}
+	return len;
+}
+
+
+static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+	u8 *nbuf;
+
+	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
+	if (nbuf == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	os_memcpy(nbuf + conn->push_buf_len, buf, len);
+	conn->push_buf = nbuf;
+	conn->push_buf_len += len;
+
+	return len;
+}
+
+
+static int tls_gnutls_init_session(struct tls_global *global,
+				   struct tls_connection *conn)
+{
+	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
+	const int protos[2] = { GNUTLS_TLS1, 0 };
+	int ret;
+
+	ret = gnutls_init(&conn->session,
+			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
+			   "connection: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_set_default_priority(conn->session);
+	if (ret < 0)
+		goto fail;
+
+	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
+	if (ret < 0)
+		goto fail;
+
+	ret = gnutls_protocol_set_priority(conn->session, protos);
+	if (ret < 0)
+		goto fail;
+
+	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
+	gnutls_transport_set_push_function(conn->session, tls_push_func);
+	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
+		   gnutls_strerror(ret));
+	gnutls_deinit(conn->session);
+	return -1;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	struct tls_connection *conn;
+	int ret;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	if (tls_gnutls_init_session(global, conn)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	if (global->params_set) {
+		ret = gnutls_credentials_set(conn->session,
+					     GNUTLS_CRD_CERTIFICATE,
+					     global->xcred);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "Failed to configure "
+				   "credentials: %s", gnutls_strerror(ret));
+			os_free(conn);
+			return NULL;
+		}
+	}
+
+	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+
+#ifdef GNUTLS_IA
+	if (conn->iacred_srv)
+		gnutls_ia_free_server_credentials(conn->iacred_srv);
+	if (conn->iacred_cli)
+		gnutls_ia_free_client_credentials(conn->iacred_cli);
+	if (conn->session_keys) {
+		os_memset(conn->session_keys, 0, conn->session_keys_len);
+		os_free(conn->session_keys);
+	}
+#endif /* GNUTLS_IA */
+
+	gnutls_certificate_free_credentials(conn->xcred);
+	gnutls_deinit(conn->session);
+	os_free(conn->pre_shared_secret);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	os_free(conn->push_buf);
+	os_free(conn->pull_buf);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	struct tls_global *global = ssl_ctx;
+	int ret;
+
+	if (conn == NULL)
+		return -1;
+
+	/* Shutdown previous TLS connection without notifying the peer
+	 * because the connection was already terminated in practice
+	 * and "close notify" shutdown alert would confuse AS. */
+	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+	os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	conn->established = 0;
+	conn->final_phase_finished = 0;
+#ifdef GNUTLS_IA
+	if (conn->session_keys) {
+		os_memset(conn->session_keys, 0, conn->session_keys_len);
+		os_free(conn->session_keys);
+	}
+	conn->session_keys_len = 0;
+#endif /* GNUTLS_IA */
+
+	gnutls_deinit(conn->session);
+	if (tls_gnutls_init_session(global, conn)) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
+			   "for session resumption use");
+		return -1;
+	}
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->params_set ? conn->xcred :
+				     global->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
+			   "for session resumption: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (global->session_data) {
+		ret = gnutls_session_set_data(conn->session,
+					      global->session_data,
+					      global->session_data_size);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
+				   "data: %s", gnutls_strerror(ret));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+#if 0
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	GENERAL_NAME *gen;
+	char *field, *tmp;
+	void *ext;
+	int i, found = 0;
+	size_t len;
+
+	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		gen = sk_GENERAL_NAME_value(ext, i);
+		switch (gen->type) {
+		case GEN_EMAIL:
+			field = "EMAIL";
+			break;
+		case GEN_DNS:
+			field = "DNS";
+			break;
+		case GEN_URI:
+			field = "URI";
+			break;
+		default:
+			field = NULL;
+			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
+				   "unsupported type=%d", gen->type);
+			break;
+		}
+
+		if (!field)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
+			   field, gen->d.ia5->data);
+		len = os_strlen(field) + 1 +
+			strlen((char *) gen->d.ia5->data) + 1;
+		tmp = os_malloc(len);
+		if (tmp == NULL)
+			continue;
+		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+		if (strstr(tmp, match))
+			found++;
+		os_free(tmp);
+	}
+
+	return found;
+}
+#endif
+
+
+#if 0
+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	char buf[256];
+	X509 *err_cert;
+	int err, depth;
+	SSL *ssl;
+	struct tls_connection *conn;
+	char *match, *altmatch;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	err = X509_STORE_CTX_get_error(x509_ctx);
+	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+					 SSL_get_ex_data_X509_STORE_CTX_idx());
+	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+
+	conn = SSL_get_app_data(ssl);
+	match = conn ? conn->subject_match : NULL;
+	altmatch = conn ? conn->altsubject_match : NULL;
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'", err,
+			   X509_verify_cert_error_string(err), depth, buf);
+	} else {
+		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
+			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
+			   preverify_ok, err,
+			   X509_verify_cert_error_string(err), depth, buf);
+		if (depth == 0 && match && strstr(buf, match) == NULL) {
+			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+				   "match with '%s'", buf, match);
+			preverify_ok = 0;
+		} else if (depth == 0 && altmatch &&
+			   !tls_match_altsubject(err_cert, altmatch)) {
+			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+				   "'%s' not found", altmatch);
+			preverify_ok = 0;
+		}
+	}
+
+	return preverify_ok;
+}
+#endif
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+
+	if (conn == NULL || params == NULL)
+		return -1;
+
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (params->subject_match) {
+		conn->subject_match = os_strdup(params->subject_match);
+		if (conn->subject_match == NULL)
+			return -1;
+	}
+
+	os_free(conn->altsubject_match);
+	conn->altsubject_match = NULL;
+	if (params->altsubject_match) {
+		conn->altsubject_match = os_strdup(params->altsubject_match);
+		if (conn->altsubject_match == NULL)
+			return -1;
+	}
+
+	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
+	 * to force peer validation(?) */
+
+	if (params->ca_cert) {
+		conn->verify_peer = 1;
+		ret = gnutls_certificate_set_x509_trust_file(
+			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				conn->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				return -1;
+			}
+		}
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			conn->xcred, params->client_cert, params->private_key,
+			GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				conn->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				return ret;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
+			params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			return -1;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			return -1;
+		}
+	}
+
+	conn->tls_ia = params->tls_ia;
+	conn->params_set = 1;
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
+			   gnutls_strerror(ret));
+	}
+
+#ifdef GNUTLS_IA
+	if (conn->iacred_cli)
+		gnutls_ia_free_client_credentials(conn->iacred_cli);
+
+	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
+			   gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
+				     conn->iacred_cli);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
+			   gnutls_strerror(ret));
+		gnutls_ia_free_client_credentials(conn->iacred_cli);
+		conn->iacred_cli = NULL;
+		return -1;
+	}
+#endif /* GNUTLS_IE */
+
+	return ret;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	struct tls_global *global = tls_ctx;
+	int ret;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+
+	if (global->params_set) {
+		gnutls_certificate_free_credentials(global->xcred);
+		global->params_set = 0;
+	}
+
+	ret = gnutls_certificate_allocate_credentials(&global->xcred);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
+			   "%s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (params->ca_cert) {
+		ret = gnutls_certificate_set_x509_trust_file(
+			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				global->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			global->xcred, params->client_cert,
+			params->private_key, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				global->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			global->xcred, params->private_key,
+			GNUTLS_X509_FMT_DER, params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			goto fail;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			goto fail;
+		}
+	}
+
+	global->params_set = 1;
+
+	return 0;
+
+fail:
+	gnutls_certificate_free_credentials(global->xcred);
+	return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	if (conn == NULL || conn->session == NULL)
+		return -1;
+
+	conn->verify_peer = verify_peer;
+	gnutls_certificate_server_set_request(conn->session,
+					      verify_peer ? GNUTLS_CERT_REQUIRE
+					      : GNUTLS_CERT_REQUEST);
+
+	return 0;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	security_parameters_st *sec;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	if (conn == NULL || conn->session == NULL || keys == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	sec = &conn->session->security_parameters;
+	keys->master_key = sec->master_secret;
+	keys->master_key_len = TLS_MASTER_SIZE;
+	keys->client_random = sec->client_random;
+	keys->server_random = sec->server_random;
+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+	keys->client_random =
+		(u8 *) gnutls_session_get_client_random(conn->session);
+	keys->server_random =
+		(u8 *) gnutls_session_get_server_random(conn->session);
+	/* No access to master_secret */
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+#ifdef GNUTLS_IA
+	gnutls_ia_extract_inner_secret(conn->session,
+				       (char *) conn->inner_secret);
+	keys->inner_secret = conn->inner_secret;
+	keys->inner_secret_len = TLS_MASTER_SIZE;
+#endif /* GNUTLS_IA */
+
+	keys->client_random_len = TLS_RANDOM_SIZE;
+	keys->server_random_len = TLS_RANDOM_SIZE;
+
+	return 0;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+	if (conn == NULL || conn->session == NULL)
+		return -1;
+
+	return gnutls_prf(conn->session, os_strlen(label), label,
+			  server_random_first, 0, NULL, out_len, (char *) out);
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+	return -1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
+static int tls_connection_verify_peer(struct tls_connection *conn)
+{
+	unsigned int status, num_certs, i;
+	struct os_time now;
+	const gnutls_datum_t *certs;
+	gnutls_x509_crt_t cert;
+
+	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
+			   "certificate chain");
+		return -1;
+	}
+
+	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
+			   "known issuer");
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_REVOKED) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
+		return -1;
+	}
+
+	os_get_time(&now);
+
+	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
+	if (certs == NULL) {
+		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
+			   "received");
+		return -1;
+	}
+
+	for (i = 0; i < num_certs; i++) {
+		char *buf;
+		size_t len;
+		if (gnutls_x509_crt_init(&cert) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
+				   "failed");
+			return -1;
+		}
+
+		if (gnutls_x509_crt_import(cert, &certs[i],
+					   GNUTLS_X509_FMT_DER) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
+				   "certificate %d/%d", i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			return -1;
+		}
+
+		gnutls_x509_crt_get_dn(cert, NULL, &len);
+		len++;
+		buf = os_malloc(len + 1);
+		if (buf) {
+			buf[0] = buf[len] = '\0';
+			gnutls_x509_crt_get_dn(cert, buf, &len);
+		}
+		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
+			   i + 1, num_certs, buf);
+
+		if (i == 0) {
+			/* TODO: validate subject_match and altsubject_match */
+		}
+
+		os_free(buf);
+
+		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+				   "not valid at this time",
+				   i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			return -1;
+		}
+
+		gnutls_x509_crt_deinit(cert);
+	}
+
+	return 0;
+}
+
+
+u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
+			      const u8 *in_data, size_t in_len,
+			      size_t *out_len, u8 **appl_data,
+			      size_t *appl_data_len)
+{
+	struct tls_global *global = ssl_ctx;
+	u8 *out_data;
+	int ret;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (in_data && in_len) {
+		if (conn->pull_buf) {
+			wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
+				   "pull_buf", __func__, conn->pull_buf_len);
+			os_free(conn->pull_buf);
+		}
+		conn->pull_buf = os_malloc(in_len);
+		if (conn->pull_buf == NULL)
+			return NULL;
+		os_memcpy(conn->pull_buf, in_data, in_len);
+		conn->pull_buf_offset = conn->pull_buf;
+		conn->pull_buf_len = in_len;
+	}
+
+	ret = gnutls_handshake(conn->session);
+	if (ret < 0) {
+		switch (ret) {
+		case GNUTLS_E_AGAIN:
+			if (global->server && conn->established &&
+			    conn->push_buf == NULL) {
+				/* Need to return something to trigger
+				 * completion of EAP-TLS. */
+				conn->push_buf = os_malloc(1);
+			}
+			break;
+		case GNUTLS_E_FATAL_ALERT_RECEIVED:
+			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
+				   __func__, gnutls_alert_get_name(
+					   gnutls_alert_get(conn->session)));
+			conn->read_alerts++;
+			/* continue */
+		default:
+			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
+				   "-> %s", __func__, gnutls_strerror(ret));
+			conn->failed++;
+		}
+	} else {
+		size_t size;
+
+		if (conn->verify_peer && tls_connection_verify_peer(conn)) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
+				   "failed validation");
+			conn->failed++;
+			return NULL;
+		}
+
+		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
+			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
+			conn->failed++;
+			return NULL;
+		}
+
+		if (conn->tls_ia)
+			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
+		else {
+			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
+				   "successfully");
+		}
+		conn->established = 1;
+		if (conn->push_buf == NULL) {
+			/* Need to return something to get final TLS ACK. */
+			conn->push_buf = os_malloc(1);
+		}
+
+		gnutls_session_get_data(conn->session, NULL, &size);
+		if (global->session_data == NULL ||
+		    global->session_data_size < size) {
+			os_free(global->session_data);
+			global->session_data = os_malloc(size);
+		}
+		if (global->session_data) {
+			global->session_data_size = size;
+			gnutls_session_get_data(conn->session,
+						global->session_data,
+						&global->session_data_size);
+		}
+	}
+
+	out_data = conn->push_buf;
+	*out_len = conn->push_buf_len;
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return out_data;
+}
+
+
+u8 * tls_connection_server_handshake(void *ssl_ctx,
+				     struct tls_connection *conn,
+				     const u8 *in_data, size_t in_len,
+				     size_t *out_len)
+{
+	return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
+					out_len, NULL, NULL);
+}
+
+
+int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
+			   const u8 *in_data, size_t in_len,
+			   u8 *out_data, size_t out_len)
+{
+	ssize_t res;
+
+#ifdef GNUTLS_IA
+	if (conn->tls_ia)
+		res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
+	else
+#endif /* GNUTLS_IA */
+	res = gnutls_record_send(conn->session, in_data, in_len);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
+			   __func__, gnutls_strerror(res));
+		return -1;
+	}
+	if (conn->push_buf == NULL)
+		return -1;
+	if (conn->push_buf_len < out_len)
+		out_len = conn->push_buf_len;
+	os_memcpy(out_data, conn->push_buf, out_len);
+	os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return out_len;
+}
+
+
+int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
+			   const u8 *in_data, size_t in_len,
+			   u8 *out_data, size_t out_len)
+{
+	ssize_t res;
+
+	if (conn->pull_buf) {
+		wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
+			   "pull_buf", __func__, conn->pull_buf_len);
+		os_free(conn->pull_buf);
+	}
+	conn->pull_buf = os_malloc(in_len);
+	if (conn->pull_buf == NULL)
+		return -1;
+	os_memcpy(conn->pull_buf, in_data, in_len);
+	conn->pull_buf_offset = conn->pull_buf;
+	conn->pull_buf_len = in_len;
+
+#ifdef GNUTLS_IA
+	if (conn->tls_ia) {
+		res = gnutls_ia_recv(conn->session, (char *) out_data,
+				     out_len);
+		if (out_len >= 12 &&
+		    (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
+		     res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
+			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
+			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
+				   __func__, final ? "Final" : "Intermediate");
+
+			res = gnutls_ia_permute_inner_secret(
+				conn->session, conn->session_keys_len,
+				(char *) conn->session_keys);
+			if (conn->session_keys) {
+				os_memset(conn->session_keys, 0,
+					  conn->session_keys_len);
+				os_free(conn->session_keys);
+			}
+			conn->session_keys = NULL;
+			conn->session_keys_len = 0;
+			if (res) {
+				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
+					   "inner secret: %s",
+					   __func__, gnutls_strerror(res));
+				return -1;
+			}
+
+			res = gnutls_ia_verify_endphase(conn->session,
+							(char *) out_data);
+			if (res == 0) {
+				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
+					   "checksum", __func__);
+			} else {
+				wpa_printf(MSG_INFO, "%s: Endphase "
+					   "verification failed: %s",
+					   __func__, gnutls_strerror(res));
+				return -1;
+			}
+
+			if (final)
+				conn->final_phase_finished = 1;
+
+			return 0;
+		}
+
+		if (res < 0) {
+			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+				   "(%s)", __func__, res,
+				   gnutls_strerror(res));
+		}
+		return res;
+	}
+#endif /* GNUTLS_IA */
+
+	res = gnutls_record_recv(conn->session, out_data, out_len);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+			   "(%s)", __func__, res, gnutls_strerror(res));
+	}
+
+	return res;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return 0;
+	return gnutls_session_is_resumed(conn->session);
+}
+
+
+int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
+				  const u8 *key, size_t key_len)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	/* TODO */
+	buf[0] = '\0';
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	/* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
+	return 0;
+}
+
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	/* TODO */
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	unsigned int capa = 0;
+
+#ifdef GNUTLS_IA
+	capa |= TLS_CAPABILITY_IA;
+#endif /* GNUTLS_IA */
+
+	return capa;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+			  int tls_ia)
+{
+#ifdef GNUTLS_IA
+	int ret;
+
+	if (conn == NULL)
+		return -1;
+
+	conn->tls_ia = tls_ia;
+	if (!tls_ia)
+		return 0;
+
+	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
+			   gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
+				     conn->iacred_srv);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
+			   gnutls_strerror(ret));
+		gnutls_ia_free_server_credentials(conn->iacred_srv);
+		conn->iacred_srv = NULL;
+		return -1;
+	}
+
+	return 0;
+#else /* GNUTLS_IA */
+	return -1;
+#endif /* GNUTLS_IA */
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+					  struct tls_connection *conn,
+					  int final,
+					  u8 *out_data, size_t out_len)
+{
+#ifdef GNUTLS_IA
+	int ret;
+
+	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
+		return -1;
+
+	ret = gnutls_ia_permute_inner_secret(conn->session,
+					     conn->session_keys_len,
+					     (char *) conn->session_keys);
+	if (conn->session_keys) {
+		os_memset(conn->session_keys, 0, conn->session_keys_len);
+		os_free(conn->session_keys);
+	}
+	conn->session_keys = NULL;
+	conn->session_keys_len = 0;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
+			   __func__, gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_ia_endphase_send(conn->session, final);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
+			   __func__, gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (conn->push_buf == NULL)
+		return -1;
+	if (conn->push_buf_len < out_len)
+		out_len = conn->push_buf_len;
+	os_memcpy(out_data, conn->push_buf, out_len);
+	os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return out_len;
+#else /* GNUTLS_IA */
+	return -1;
+#endif /* GNUTLS_IA */
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+					   struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+
+	return conn->final_phase_finished;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const u8 *key, size_t key_len)
+{
+#ifdef GNUTLS_IA
+	if (conn == NULL || !conn->tls_ia)
+		return -1;
+
+	if (conn->session_keys) {
+		os_memset(conn->session_keys, 0, conn->session_keys_len);
+		os_free(conn->session_keys);
+	}
+	conn->session_keys_len = 0;
+
+	if (key) {
+		conn->session_keys = os_malloc(key_len);
+		if (conn->session_keys == NULL)
+			return -1;
+		os_memcpy(conn->session_keys, key, key_len);
+		conn->session_keys_len = key_len;
+	} else {
+		conn->session_keys = NULL;
+		conn->session_keys_len = 0;
+	}
+
+	return 0;
+#else /* GNUTLS_IA */
+	return -1;
+#endif /* GNUTLS_IA */
+}
Index: common.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/common.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/common.c -L contrib/hostapd/common.c -u -r1.2 -r1.3
--- contrib/hostapd/common.c
+++ contrib/hostapd/common.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2006, 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,70 +12,20 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#include <wincrypt.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
 
 #include "common.h"
 
 
+#ifdef CONFIG_DEBUG_FILE
+static FILE *out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+int wpa_debug_use_file = 0;
 int wpa_debug_level = MSG_INFO;
 int wpa_debug_show_keys = 0;
 int wpa_debug_timestamp = 0;
 
 
-int hostapd_get_rand(u8 *buf, size_t len)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
-	HCRYPTPROV prov;
-	BOOL ret;
-
-	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
-				 CRYPT_VERIFYCONTEXT))
-		return -1;
-
-	ret = CryptGenRandom(prov, len, buf);
-	CryptReleaseContext(prov, 0);
-
-	return ret ? 0 : -1;
-#else /* CONFIG_NATIVE_WINDOWS */
-	FILE *f;
-	size_t rc;
-
-	f = fopen("/dev/urandom", "r");
-	if (f == NULL) {
-		printf("Could not open /dev/urandom.\n");
-		return -1;
-	}
-
-	rc = fread(buf, 1, len, f);
-	fclose(f);
-
-	return rc != len ? -1 : 0;
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
-{
-	size_t i;
-	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
-	for (i = 0; i < len; i++)
-		printf(" %02x", buf[i]);
-	printf("\n");
-}
-
-
 static int hex2num(char c)
 {
 	if (c >= '0' && c <= '9')
@@ -139,7 +89,8 @@
  */
 int hexstr2bin(const char *hex, u8 *buf, size_t len)
 {
-	int i, a;
+	size_t i;
+	int a;
 	const char *ipos = hex;
 	u8 *opos = buf;
 
@@ -154,45 +105,6 @@
 }
 
 
-char * rel2abs_path(const char *rel_path)
-{
-	char *buf = NULL, *cwd, *ret;
-	size_t len = 128, cwd_len, rel_len, ret_len;
-
-	if (rel_path[0] == '/')
-		return strdup(rel_path);
-
-	for (;;) {
-		buf = malloc(len);
-		if (buf == NULL)
-			return NULL;
-		cwd = getcwd(buf, len);
-		if (cwd == NULL) {
-			free(buf);
-			if (errno != ERANGE) {
-				return NULL;
-			}
-			len *= 2;
-		} else {
-			break;
-		}
-	}
-
-	cwd_len = strlen(cwd);
-	rel_len = strlen(rel_path);
-	ret_len = cwd_len + 1 + rel_len + 1;
-	ret = malloc(ret_len);
-	if (ret) {
-		memcpy(ret, cwd, cwd_len);
-		ret[cwd_len] = '/';
-		memcpy(ret + cwd_len + 1, rel_path, rel_len);
-		ret[ret_len - 1] = '\0';
-	}
-	free(buf);
-	return ret;
-}
-
-
 /**
  * inc_byte_array - Increment arbitrary length byte array by one
  * @counter: Pointer to byte array
@@ -214,40 +126,40 @@
 }
 
 
-void print_char(char c)
+void wpa_get_ntp_timestamp(u8 *buf)
 {
-	if (c >= 32 && c < 127)
-		printf("%c", c);
-	else
-		printf("<%02x>", c);
-}
-
+	struct os_time now;
+	u32 sec, usec;
 
-void fprint_char(FILE *f, char c)
-{
-	if (c >= 32 && c < 127)
-		fprintf(f, "%c", c);
-	else
-		fprintf(f, "<%02x>", c);
+	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+	os_get_time(&now);
+	sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */
+	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+	usec = now.usec;
+	usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9));
+	os_memcpy(buf, (u8 *) &sec, 4);
+	os_memcpy(buf + 4, (u8 *) &usec, 4);
 }
 
 
+
 #ifndef CONFIG_NO_STDOUT_DEBUG
 
 void wpa_debug_print_timestamp(void)
 {
-	struct timeval tv;
-	char buf[16];
+	struct os_time tv;
 
 	if (!wpa_debug_timestamp)
 		return;
 
-	gettimeofday(&tv, NULL);
-	if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
-		     localtime((const time_t *) &tv.tv_sec)) <= 0) {
-		snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
-	}
-	printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
+	os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+			(unsigned int) tv.usec);
+	} else
+#endif /* CONFIG_DEBUG_FILE */
+	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
 }
 
 
@@ -269,8 +181,17 @@
 	va_start(ap, fmt);
 	if (level >= wpa_debug_level) {
 		wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+		if (out_file) {
+			vfprintf(out_file, fmt, ap);
+			fprintf(out_file, "\n");
+		} else {
+#endif /* CONFIG_DEBUG_FILE */
 		vprintf(fmt, ap);
 		printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+		}
+#endif /* CONFIG_DEBUG_FILE */
 	}
 	va_end(ap);
 }
@@ -283,6 +204,21 @@
 	if (level < wpa_debug_level)
 		return;
 	wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		fprintf(out_file, "%s - hexdump(len=%lu):",
+			title, (unsigned long) len);
+		if (buf == NULL) {
+			fprintf(out_file, " [NULL]");
+		} else if (show) {
+			for (i = 0; i < len; i++)
+				fprintf(out_file, " %02x", buf[i]);
+		} else {
+			fprintf(out_file, " [REMOVED]");
+		}
+		fprintf(out_file, "\n");
+	} else {
+#endif /* CONFIG_DEBUG_FILE */
 	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
 	if (buf == NULL) {
 		printf(" [NULL]");
@@ -293,6 +229,9 @@
 		printf(" [REMOVED]");
 	}
 	printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+	}
+#endif /* CONFIG_DEBUG_FILE */
 }
 
 void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
@@ -310,13 +249,51 @@
 static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
 			       size_t len, int show)
 {
-	int i, llen;
+	size_t i, llen;
 	const u8 *pos = buf;
-	const int line_len = 16;
+	const size_t line_len = 16;
 
 	if (level < wpa_debug_level)
 		return;
 	wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		if (!show) {
+			fprintf(out_file,
+				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+				title, (unsigned long) len);
+			return;
+		}
+		if (buf == NULL) {
+			fprintf(out_file,
+				"%s - hexdump_ascii(len=%lu): [NULL]\n",
+				title, (unsigned long) len);
+			return;
+		}
+		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
+			title, (unsigned long) len);
+		while (len) {
+			llen = len > line_len ? line_len : len;
+			fprintf(out_file, "    ");
+			for (i = 0; i < llen; i++)
+				fprintf(out_file, " %02x", pos[i]);
+			for (i = llen; i < line_len; i++)
+				fprintf(out_file, "   ");
+			fprintf(out_file, "   ");
+			for (i = 0; i < llen; i++) {
+				if (isprint(pos[i]))
+					fprintf(out_file, "%c", pos[i]);
+				else
+					fprintf(out_file, "_");
+			}
+			for (i = llen; i < line_len; i++)
+				fprintf(out_file, " ");
+			fprintf(out_file, "\n");
+			pos += llen;
+			len -= llen;
+		}
+	} else {
+#endif /* CONFIG_DEBUG_FILE */
 	if (!show) {
 		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 		       title, (unsigned long) len);
@@ -348,6 +325,9 @@
 		pos += llen;
 		len -= llen;
 	}
+#ifdef CONFIG_DEBUG_FILE
+	}
+#endif /* CONFIG_DEBUG_FILE */
 }
 
 
@@ -363,26 +343,261 @@
 	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
 }
 
+
+int wpa_debug_open_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+	static int count = 0;
+	char fname[64];
+	if (!wpa_debug_use_file)
+		return 0;
+#ifdef _WIN32
+	os_snprintf(fname, sizeof(fname), "\\Temp\\wpa_supplicant-log-%d.txt",
+		    count++);
+#else /* _WIN32 */
+	os_snprintf(fname, sizeof(fname), "/tmp/wpa_supplicant-log-%d.txt",
+		    count++);
+#endif /* _WIN32 */
+	out_file = fopen(fname, "w");
+	return out_file == NULL ? -1 : 0;
+#else /* CONFIG_DEBUG_FILE */
+	return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+void wpa_debug_close_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+	if (!wpa_debug_use_file)
+		return;
+	fclose(out_file);
+	out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
-#ifdef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_NO_WPA_MSG
+static wpa_msg_cb_func wpa_msg_cb = NULL;
+
+void wpa_msg_register_cb(wpa_msg_cb_func func)
+{
+	wpa_msg_cb = func;
+}
 
-#define EPOCHFILETIME (116444736000000000ULL)
 
-int gettimeofday(struct timeval *tv, struct timezone *tz)
+void wpa_msg(void *ctx, int level, char *fmt, ...)
 {
-	FILETIME ft;
-	LARGE_INTEGER li;
-	ULONGLONG t;
-
-	GetSystemTimeAsFileTime(&ft);
-	li.LowPart = ft.dwLowDateTime;
-	li.HighPart = ft.dwHighDateTime;
-	t = (li.QuadPart - EPOCHFILETIME) / 10;
-	tv->tv_sec = (long) (t / 1000000);
-	tv->tv_usec = (long) (t % 1000000);
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
 
-	return 0;
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
+			   "buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_printf(level, "%s", buf);
+	if (wpa_msg_cb)
+		wpa_msg_cb(ctx, level, buf, len);
+	os_free(buf);
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+				    size_t len, int uppercase)
+{
+	size_t i;
+	char *pos = buf, *end = buf + buf_size;
+	int ret;
+	if (buf_size == 0)
+		return 0;
+	for (i = 0; i < len; i++) {
+		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+				  data[i]);
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+	end[-1] = '\0';
+	return pos - buf;
+}
+
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
+
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+			       size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+		   s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+	static int optchr = 1;
+	char *cp;
+
+	if (optchr == 1) {
+		if (optind >= argc) {
+			/* all arguments processed */
+			return EOF;
+		}
+
+		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+			/* no option characters */
+			return EOF;
+		}
+	}
+
+	if (os_strcmp(argv[optind], "--") == 0) {
+		/* no more options */
+		optind++;
+		return EOF;
+	}
+
+	optopt = argv[optind][optchr];
+	cp = os_strchr(optstring, optopt);
+	if (cp == NULL || optopt == ':') {
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		return '?';
+	}
+
+	if (cp[1] == ':') {
+		/* Argument required */
+		optchr = 1;
+		if (argv[optind][optchr + 1]) {
+			/* No space between option and argument */
+			optarg = &argv[optind++][optchr + 1];
+		} else if (++optind >= argc) {
+			/* option requires an argument */
+			return '?';
+		} else {
+			/* Argument in the next argv */
+			optarg = argv[optind++];
+		}
+	} else {
+		/* No argument */
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		optarg = NULL;
+	}
+	return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+	char *dst = (char *) str;
+	while (*str)
+		*dst++ = (char) *str++;
+	*dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+	TCHAR *buf;
+	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+	if (buf == NULL)
+		return NULL;
+	wsprintf(buf, L"%S", str);
+	return buf;
+#else /* UNICODE */
+	return os_strdup(str);
+#endif /* UNICODE */
 }
 #endif /* CONFIG_NATIVE_WINDOWS */
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
+{
+	static char ssid_txt[33];
+	char *pos;
+
+	if (ssid_len > 32)
+		ssid_len = 32;
+	os_memcpy(ssid_txt, ssid, ssid_len);
+	ssid_txt[ssid_len] = '\0';
+	for (pos = ssid_txt; *pos != '\0'; pos++) {
+		if ((u8) *pos < 32 || (u8) *pos >= 127)
+			*pos = '_';
+	}
+	return ssid_txt;
+}
--- /dev/null
+++ contrib/hostapd/state_machine.h
@@ -0,0 +1,144 @@
+/*
+ * wpa_supplicant/hostapd - State machine definitions
+ * Copyright (c) 2002-2005, 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.
+ *
+ * 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,
+ * 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
+ * needs to be defined to point to the MAC address used in debug output.
+ * SM_ENTRY_M macro can be used to define similar group of state machines
+ * without this additional debug info.
+ */
+
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+/**
+ * SM_STATE - Declaration of a state machine function
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used to declare a state machine function. It is used in place
+ * of a C function definition to declare functions to be run when the state is
+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
+ */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
+	int global)
+
+/**
+ * SM_ENTRY - State machine function entry point
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used inside each state machine function declared with
+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
+ * after declaration of possible local variables. This macro prints debug
+ * information about state transition and update the state machine state.
+ */
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
+		   " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+/**
+ * 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)
+ *
+ * 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
+ * parameters are set to "sub-state machine" name. prefix is used to allow more
+ * than one state variable to be stored in the same data structure.
+ */
+#define SM_ENTRY_M(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
+		   #machine " entering state " #_state); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * 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)
+ *
+ * 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
+ * be included in debug.
+ */
+#define SM_ENTRY_MA(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
+		   #machine " entering state " #_state, \
+		   MAC2STR(STATE_MACHINE_ADDR)); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTER - Enter a new state machine state
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro expands to a function call to a state machine function defined
+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to
+ * move the state machine to a new state.
+ */
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+
+/**
+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is like SM_ENTER, but this is used when entering a new state
+ * based on a global (not specific to any particular state) rule. A separate
+ * macro is used to avoid unwanted debug message floods when the same global
+ * rule is forcing a state machine to remain in on state.
+ */
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+/**
+ * SM_STEP - Declaration of a state machine step function
+ * @machine: State machine name
+ *
+ * This macro is used to declare a state machine step function. It is used in
+ * place of a C function definition to declare a function that is used to move
+ * state machine to a new state based on state variables. This function uses
+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
+ */
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
+
+/**
+ * SM_STEP_RUN - Call the state machine step function
+ * @machine: State machine name
+ *
+ * This macro expands to a function call to a state machine step function
+ * defined with SM_STEP macro.
+ */
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+#endif /* STATE_MACHINE_H */
Index: sta_info.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/sta_info.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/sta_info.h -L contrib/hostapd/sta_info.h -u -r1.2 -r1.3
--- contrib/hostapd/sta_info.h
+++ contrib/hostapd/sta_info.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2004, 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 STA_INFO_H
 #define STA_INFO_H
 
@@ -6,14 +20,21 @@
 			      void *ctx),
 		    void *ctx);
 struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
-void ap_sta_hash_add(hostapd *hapd, struct sta_info *sta);
-void ap_free_sta(hostapd *hapd, struct sta_info *sta);
-void ap_free_sta(hostapd *hapd, struct sta_info *sta);
-void hostapd_free_stas(hostapd *hapd);
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_free_stas(struct hostapd_data *hapd);
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
-void ap_sta_session_timeout(hostapd *hapd, struct sta_info *sta,
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
 			    u32 session_timeout);
-void ap_sta_no_session_timeout(hostapd *hapd, struct sta_info *sta);
+void ap_sta_no_session_timeout(struct hostapd_data *hapd,
+			       struct sta_info *sta);
 struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason);
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason);
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid);
 
 #endif /* STA_INFO_H */
Index: md5.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/md5.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/md5.c -L contrib/hostapd/md5.c -u -r1.2 -r1.3
--- contrib/hostapd/md5.c
+++ contrib/hostapd/md5.c
@@ -1,6 +1,6 @@
 /*
  * MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "md5.h"
@@ -35,9 +33,8 @@
 {
 	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
 	u8 tk[16];
-	int i;
 	const u8 *_addr[6];
-	size_t _len[6];
+	size_t i, _len[6];
 
 	if (num_elem > 5) {
 		/*
@@ -64,8 +61,8 @@
 	 * and text is the data being protected */
 
 	/* start out by storing key in ipad */
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 
 	/* XOR key with ipad values */
 	for (i = 0; i < 64; i++)
@@ -80,8 +77,8 @@
 	}
 	md5_vector(1 + num_elem, _addr, _len, mac);
 
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 	/* XOR key with opad values */
 	for (i = 0; i < 64; i++)
 		k_pad[i] ^= 0x5c;
@@ -110,7 +107,7 @@
 }
 
 
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_MD5
 
 struct MD5Context {
 	u32 buf[4];
@@ -118,12 +115,15 @@
 	u8 in[64];
 };
 
+#ifndef CONFIG_CRYPTO_INTERNAL
 static void MD5Init(struct MD5Context *context);
 static void MD5Update(struct MD5Context *context, unsigned char const *buf,
-		      unsigned len);
+			  unsigned len);
 static void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
 static void MD5Transform(u32 buf[4], u32 const in[16]);
 
+
 typedef struct MD5Context MD5_CTX;
 
 
@@ -137,7 +137,7 @@
 void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 	MD5_CTX ctx;
-	int i;
+	size_t i;
 
 	MD5Init(&ctx);
 	for (i = 0; i < num_elem; i++)
@@ -186,7 +186,7 @@
  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
  * initialization constants.
  */
-static void MD5Init(struct MD5Context *ctx)
+void MD5Init(struct MD5Context *ctx)
 {
     ctx->buf[0] = 0x67452301;
     ctx->buf[1] = 0xefcdab89;
@@ -201,8 +201,7 @@
  * Update context to reflect the concatenation of another buffer full
  * of bytes.
  */
-static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
-		      unsigned len)
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
 {
     u32 t;
 
@@ -222,10 +221,10 @@
 
 	t = 64 - t;
 	if (len < t) {
-	    memcpy(p, buf, len);
+	    os_memcpy(p, buf, len);
 	    return;
 	}
-	memcpy(p, buf, t);
+	os_memcpy(p, buf, t);
 	byteReverse(ctx->in, 16);
 	MD5Transform(ctx->buf, (u32 *) ctx->in);
 	buf += t;
@@ -234,7 +233,7 @@
     /* Process data in 64-byte chunks */
 
     while (len >= 64) {
-	memcpy(ctx->in, buf, 64);
+	os_memcpy(ctx->in, buf, 64);
 	byteReverse(ctx->in, 16);
 	MD5Transform(ctx->buf, (u32 *) ctx->in);
 	buf += 64;
@@ -243,14 +242,14 @@
 
     /* Handle any remaining bytes of data. */
 
-    memcpy(ctx->in, buf, len);
+    os_memcpy(ctx->in, buf, len);
 }
 
 /*
  * Final wrapup - pad to 64-byte boundary with the bit pattern
  * 1 0* (64-bit count of bits processed, MSB-first)
  */
-static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
 {
     unsigned count;
     unsigned char *p;
@@ -269,15 +268,15 @@
     /* Pad out to 56 mod 64 */
     if (count < 8) {
 	/* Two lots of padding:  Pad the first block to 64 bytes */
-	memset(p, 0, count);
+	os_memset(p, 0, count);
 	byteReverse(ctx->in, 16);
 	MD5Transform(ctx->buf, (u32 *) ctx->in);
 
 	/* Now fill the next block with 56 bytes */
-	memset(ctx->in, 0, 56);
+	os_memset(ctx->in, 0, 56);
     } else {
 	/* Pad block to 56 bytes */
-	memset(p, 0, count - 8);
+	os_memset(p, 0, count - 8);
     }
     byteReverse(ctx->in, 14);
 
@@ -287,8 +286,8 @@
 
     MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
-    memcpy(digest, ctx->buf, 16);
-    memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+    os_memcpy(digest, ctx->buf, 16);
+    os_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
@@ -392,4 +391,4 @@
 }
 /* ===== end - public domain MD5 implementation ===== */
 
-#endif /* !EAP_TLS_FUNCS */
+#endif /* INTERNAL_MD5 */
--- /dev/null
+++ contrib/hostapd/mlme.h
@@ -0,0 +1,40 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 MLME_H
+#define MLME_H
+
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta);
+
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code);
+
+void mlme_associate_indication(struct hostapd_data *hapd,
+			       struct sta_info *sta);
+
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta);
+
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code);
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr);
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* MLME_H */
Index: driver_wired.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/driver_wired.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/driver_wired.c -L contrib/hostapd/driver_wired.c -u -r1.2 -r1.3
--- contrib/hostapd/driver_wired.c
+++ contrib/hostapd/driver_wired.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Kernel driver communication
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / Kernel driver communication for wired (Ethernet) drivers
+ * Copyright (c) 2002-2005, Jouni Malinen <j at w1.fi>
  * Copyright (c) 2004, Gunter Burchardt <tira at isx.de>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -14,16 +13,8 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
+#include "includes.h"
 #include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
 
 #ifdef USE_KERNEL_HEADERS
 #include <asm/types.h>
@@ -105,7 +96,8 @@
 }
 
 
-static void handle_data(struct hostapd_data *hapd, char *buf, size_t len)
+static void handle_data(struct hostapd_data *hapd, unsigned char *buf,
+			size_t len)
 {
 	struct ieee8023_hdr *hdr;
 	u8 *pos, *sa;
@@ -306,8 +298,9 @@
 }
 
 
-static int wired_send_eapol(void *priv, u8 *addr,
-			    u8 *data, size_t data_len, int encrypt)
+static int wired_send_eapol(void *priv, const u8 *addr,
+			    const u8 *data, size_t data_len, int encrypt,
+			    const u8 *own_addr)
 {
 	struct wired_driver_data *drv = priv;
 	u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP;
@@ -317,17 +310,16 @@
 	int res;
 
 	len = sizeof(*hdr) + data_len;
-	hdr = malloc(len);
+	hdr = wpa_zalloc(len);
 	if (hdr == NULL) {
 		printf("malloc() failed for wired_send_eapol(len=%lu)\n",
 		       (unsigned long) len);
 		return -1;
 	}
 
-	memset(hdr, 0, len);
 	memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
 	       ETH_ALEN);
-	memcpy(hdr->src, drv->hapd->own_addr, ETH_ALEN);
+	memcpy(hdr->src, own_addr, ETH_ALEN);
 	hdr->ethertype = htons(ETH_P_PAE);
 
 	pos = (u8 *) (hdr + 1);
@@ -350,19 +342,20 @@
 {
 	struct wired_driver_data *drv;
 
-	drv = malloc(sizeof(struct wired_driver_data));
+	drv = wpa_zalloc(sizeof(struct wired_driver_data));
 	if (drv == NULL) {
 		printf("Could not allocate memory for wired driver data\n");
 		return -1;
 	}
 
-	memset(drv, 0, sizeof(*drv));
 	drv->ops = wired_driver_ops;
 	drv->hapd = hapd;
 	drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
 
-	if (wired_init_sockets(drv))
+	if (wired_init_sockets(drv)) {
+		free(drv);
 		return -1;
+	}
 
 	hapd->driver = &drv->ops;
 	return 0;
Index: radius_client.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius_client.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius_client.h -L contrib/hostapd/radius_client.h -u -r1.2 -r1.3
--- contrib/hostapd/radius_client.h
+++ contrib/hostapd/radius_client.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / RADIUS client
+ * Copyright (c) 2002-2005, 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 RADIUS_CLIENT_H
 #define RADIUS_CLIENT_H
 
@@ -73,15 +87,19 @@
 			   void *data);
 int radius_client_send(struct radius_client_data *radius,
 		       struct radius_msg *msg,
-		       RadiusType msg_type, u8 *addr);
+		       RadiusType msg_type, const u8 *addr);
 u8 radius_client_get_id(struct radius_client_data *radius);
 
-void radius_client_flush(struct radius_client_data *radius);
+void radius_client_flush(struct radius_client_data *radius, int only_auth);
 struct radius_client_data *
 radius_client_init(void *ctx, struct hostapd_radius_servers *conf);
 void radius_client_deinit(struct radius_client_data *radius);
 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr);
 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
 			  size_t buflen);
+struct radius_client_data *
+radius_client_reconfig(struct radius_client_data *old, void *ctx,
+		       struct hostapd_radius_servers *oldconf,
+		       struct hostapd_radius_servers *newconf);
 
 #endif /* RADIUS_CLIENT_H */
--- /dev/null
+++ contrib/hostapd/os.h
@@ -0,0 +1,485 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions
+ * Copyright (c) 2005-2006, 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 OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+	os_time_t sec;
+	os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+	((a)->sec < (b)->sec || \
+	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+	(res)->sec = (a)->sec - (b)->sec; \
+	(res)->usec = (a)->usec - (b)->usec; \
+	if ((res)->usec < 0) { \
+		(res)->sec--; \
+		(res)->usec += 1000000; \
+	} \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t);
+
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */
--- /dev/null
+++ contrib/hostapd/os_internal.c
@@ -0,0 +1,441 @@
+/*
+ * wpa_supplicant/hostapd / Internal implementation of OS specific functions
+ * Copyright (c) 2005-2006, 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.
+ *
+ * This file is an example of operating system specific  wrapper functions.
+ * This version implements many of the functions internally, so it can be used
+ * to fill in missing functions from the target system C libraries.
+ *
+ * Some of the functions are using standard C library calls in order to keep
+ * this file in working condition to allow the functions to be tested on a
+ * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
+ * this file to work correctly. Note that these implementations are only
+ * examples and are not optimized for speed.
+ */
+
+#include "includes.h"
+
+#undef OS_REJECT_C_LIB_FUNCTIONS
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		sleep(sec);
+	if (usec)
+		usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	os_memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	*t = (os_time_t) mktime(&tm);
+	return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	if (daemon(0, 0)) {
+		perror("daemon");
+		return -1;
+	}
+
+	if (pid_file) {
+		FILE *f = fopen(pid_file, "w");
+		if (f) {
+			fprintf(f, "%u\n", getpid());
+			fclose(f);
+		}
+	}
+
+	return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+	if (pid_file)
+		unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "rb");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+	return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	char *buf = NULL, *cwd, *ret;
+	size_t len = 128, cwd_len, rel_len, ret_len;
+
+	if (rel_path[0] == '/')
+		return os_strdup(rel_path);
+
+	for (;;) {
+		buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		cwd = getcwd(buf, len);
+		if (cwd == NULL) {
+			os_free(buf);
+			if (errno != ERANGE) {
+				return NULL;
+			}
+			len *= 2;
+		} else {
+			break;
+		}
+	}
+
+	cwd_len = strlen(cwd);
+	rel_len = strlen(rel_path);
+	ret_len = cwd_len + 1 + rel_len + 1;
+	ret = os_malloc(ret_len);
+	if (ret) {
+		os_memcpy(ret, cwd, cwd_len);
+		ret[cwd_len] = '/';
+		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+		ret[ret_len - 1] = '\0';
+	}
+	os_free(buf);
+	return ret;
+}
+
+
+int os_program_init(void)
+{
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+	unsetenv(name);
+	return 0;
+#else
+	return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	fseek(f, 0, SEEK_END);
+	*len = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	buf = os_malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	fread(buf, 1, *len, f);
+	fclose(f);
+
+	return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	void *n = os_malloc(size);
+	if (n)
+		os_memset(n, 0, size);
+	return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+	free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+	char *d = dest;
+	const char *s = src;
+	while (n--)
+		*d++ = *s++;
+	return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+	if (dest < src)
+		os_memcpy(dest, src, n);
+	else {
+		/* overlapping areas */
+		char *d = (char *) dest + n;
+		const char *s = (const char *) src + n;
+		while (n--)
+			*--d = *--s;
+	}
+	return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+	char *p = s;
+	while (n--)
+		*p++ = c;
+	return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+	const unsigned char *p1 = s1, *p2 = s2;
+
+	if (n == 0)
+		return 0;
+
+	while (*p1 == *p2) {
+		p1++;
+		p2++;
+		n--;
+		if (n == 0)
+			return 0;
+	}
+
+	return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+	char *res;
+	size_t len;
+	if (s == NULL)
+		return NULL;
+	len = os_strlen(s);
+	res = os_malloc(len + 1);
+	if (res)
+		os_memcpy(res, s, len + 1);
+	return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+	const char *p = s;
+	while (*p)
+		p++;
+	return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+	while (*s) {
+		if (*s == c)
+			return (char *) s;
+		s++;
+	}
+	return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+	const char *p = s;
+	while (*p)
+		p++;
+	p--;
+	while (p >= s) {
+		if (*p == c)
+			return (char *) p;
+		p--;
+	}
+	return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+	while (*s1 == *s2) {
+		if (*s1 == '\0')
+			break;
+		s1++;
+		s2++;
+	}
+
+	return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+	if (n == 0)
+		return 0;
+
+	while (*s1 == *s2) {
+		if (*s1 == '\0')
+			break;
+		s1++;
+		s2++;
+		n--;
+		if (n == 0)
+			return 0;
+	}
+
+	return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+	char *d = dest;
+
+	while (n--) {
+		*d = *src;
+		if (*src == '\0')
+			break;
+		d++;
+		src++;
+	}
+
+	return dest;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+	size_t len = os_strlen(needle);
+	while (*haystack) {
+		if (os_strncmp(haystack, needle, len) == 0)
+			return (char *) haystack;
+		haystack++;
+	}
+
+	return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+	va_list ap;
+	int ret;
+
+	/* See http://www.ijs.si/software/snprintf/ for portable
+	 * implementation of snprintf.
+	 */
+
+	va_start(ap, format);
+	ret = vsnprintf(str, size, format, ap);
+	va_end(ap);
+	if (size > 0)
+		str[size - 1] = '\0';
+	return ret;
+}
Index: eap_defs.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_defs.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_defs.h -L contrib/hostapd/eap_defs.h -u -r1.2 -r1.3
--- contrib/hostapd/eap_defs.h
+++ contrib/hostapd/eap_defs.h
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant/hostapd / Shared EAP definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: Shared EAP definitions
+ * Copyright (c) 2004-2006, 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
@@ -17,12 +17,20 @@
 
 /* RFC 3748 - Extensible Authentication Protocol (EAP) */
 
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
 struct eap_hdr {
 	u8 code;
 	u8 identifier;
 	u16 length; /* including code and identifier; network byte order */
 	/* followed by length-4 octets of data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
 
 enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
        EAP_CODE_FAILURE = 4 };
@@ -40,17 +48,28 @@
 	EAP_TYPE_GTC = 6, /* RFC 3748 */
 	EAP_TYPE_TLS = 13 /* RFC 2716 */,
 	EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
-	EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
+	EAP_TYPE_SIM = 18 /* RFC 4186 */,
 	EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
-	EAP_TYPE_AKA = 23 /* draft-arkko-pppext-eap-aka-12.txt */,
+	EAP_TYPE_AKA = 23 /* RFC 4187 */,
 	EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
 	EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
 	EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
-	EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
-	EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
-	EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
-	EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
-			    * draft-bersani-eap-psk-09 */
+	EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-05.txt */,
+	EAP_TYPE_PAX = 46 /* RFC 4746 */,
+	EAP_TYPE_PSK = 47 /* RFC 4764 */,
+	EAP_TYPE_SAKE = 48 /* RFC 4763 */,
+	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */,
+	EAP_TYPE_GPSK = 255 /* EXPERIMENTAL - type not yet allocated
+			     * draft-ietf-emu-eap-gpsk-01.txt */
 } EapType;
 
+
+/* SMI Network Management Private Enterprise Code for vendor specific types */
+enum {
+	EAP_VENDOR_IETF = 0
+};
+
+#define EAP_MSK_LEN 64
+#define EAP_EMSK_LEN 64
+
 #endif /* EAP_DEFS_H */
--- /dev/null
+++ contrib/hostapd/ieee802_11h.h
@@ -0,0 +1,27 @@
+/*
+ * hostapd / IEEE 802.11h
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * 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 IEEE802_11H_H
+#define IEEE802_11H_H
+
+#define SPECT_LOOSE_BINDING	1
+#define SPECT_STRICT_BINDING	2
+
+#define CHAN_SWITCH_MODE_NOISY	0
+#define CHAN_SWITCH_MODE_QUIET	1
+
+int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len);
+
+#endif /* IEEE802_11H_H */
Index: eap_sim.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_sim.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_sim.c -L contrib/hostapd/eap_sim.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_sim.c
+++ contrib/hostapd/eap_sim.c
@@ -1,6 +1,6 @@
 /*
- * hostapd / EAP-SIM (draft-haverinen-pppext-eap-sim-15.txt)
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / EAP-SIM (RFC 4186)
+ * Copyright (c) 2005-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -25,38 +22,23 @@
 #include "eap_sim_db.h"
 
 
-#define EAP_SIM_VERSION 1
-
-/* EAP-SIM Subtypes */
-#define EAP_SIM_SUBTYPE_START 10
-#define EAP_SIM_SUBTYPE_CHALLENGE 11
-#define EAP_SIM_SUBTYPE_NOTIFICATION 12
-#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
-#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
-
-/* AT_CLIENT_ERROR_CODE error codes */
-#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
-#define EAP_SIM_UNSUPPORTED_VERSION 1
-#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
-#define EAP_SIM_RAND_NOT_FRESH 3
-
-#define KC_LEN 8
-#define SRES_LEN 4
-#define EAP_SIM_MAX_FAST_REAUTHS 1000
-
-#define EAP_SIM_MAX_CHAL 3
-
 struct eap_sim_data {
 	u8 mk[EAP_SIM_MK_LEN];
 	u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
+	u8 nonce_s[EAP_SIM_NONCE_S_LEN];
 	u8 k_aut[EAP_SIM_K_AUT_LEN];
 	u8 k_encr[EAP_SIM_K_ENCR_LEN];
 	u8 msk[EAP_SIM_KEYING_DATA_LEN];
-	u8 kc[EAP_SIM_MAX_CHAL][KC_LEN];
-	u8 sres[EAP_SIM_MAX_CHAL][SRES_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+	u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
 	u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
 	int num_chal;
-	enum { START, CHALLENGE, SUCCESS, FAILURE } state;
+	enum { START, CHALLENGE, REAUTH, SUCCESS, FAILURE } state;
+	char *next_pseudonym;
+	char *next_reauth_id;
+	u16 counter;
+	struct eap_sim_reauth *reauth;
 };
 
 
@@ -67,6 +49,8 @@
 		return "START";
 	case CHALLENGE:
 		return "CHALLENGE";
+	case REAUTH:
+		return "REAUTH";
 	case SUCCESS:
 		return "SUCCESS";
 	case FAILURE:
@@ -79,7 +63,7 @@
 
 static void eap_sim_state(struct eap_sim_data *data, int state)
 {
-	wpa_printf(MSG_DEBUG, "EAP-SIM %s -> %s",
+	wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
 		   eap_sim_state_txt(data->state),
 		   eap_sim_state_txt(state));
 	data->state = state;
@@ -95,10 +79,9 @@
 		return NULL;
 	}
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = START;
 
 	return data;
@@ -108,6 +91,8 @@
 static void eap_sim_reset(struct eap_sm *sm, void *priv)
 {
 	struct eap_sim_data *data = priv;
+	free(data->next_pseudonym);
+	free(data->next_reauth_id);
 	free(data);
 }
 
@@ -118,12 +103,15 @@
 	struct eap_sim_msg *msg;
 	u8 ver[2];
 
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
 			       EAP_SIM_SUBTYPE_START);
 	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
 				      sm->identity_len)) {
+		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
 		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
 	}
+	wpa_printf(MSG_DEBUG, "   AT_VERSION_LIST");
 	ver[0] = 0;
 	ver[1] = EAP_SIM_VERSION;
 	eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
@@ -132,22 +120,128 @@
 }
 
 
+static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
+			      struct eap_sim_msg *msg, u16 counter,
+			      const u8 *nonce_s)
+{
+	free(data->next_pseudonym);
+	data->next_pseudonym =
+		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
+	free(data->next_reauth_id);
+	if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+		data->next_reauth_id =
+			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
+			   "count exceeded - force full authentication");
+		data->next_reauth_id = NULL;
+	}
+
+	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+	    counter == 0 && nonce_s == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter > 0) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+	}
+
+	if (nonce_s) {
+		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
+		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+				EAP_SIM_NONCE_S_LEN);
+	}
+
+	if (data->next_pseudonym) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
+			   data->next_pseudonym);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+				strlen(data->next_pseudonym),
+				(u8 *) data->next_pseudonym,
+				strlen(data->next_pseudonym));
+	}
+
+	if (data->next_reauth_id) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
+			   data->next_reauth_id);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+				strlen(data->next_reauth_id),
+				(u8 *) data->next_reauth_id,
+				strlen(data->next_reauth_id));
+	}
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static u8 * eap_sim_build_challenge(struct eap_sm *sm,
 				    struct eap_sim_data *data,
 				    int id, size_t *reqDataLen)
 {
 	struct eap_sim_msg *msg;
 
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
 	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
 			       EAP_SIM_SUBTYPE_CHALLENGE);
+	wpa_printf(MSG_DEBUG, "   AT_RAND");
 	eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
 			data->num_chal * GSM_RAND_LEN);
+
+	if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
 	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
 	return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
 				  EAP_SIM_NONCE_MT_LEN);
 }
 
 
+static u8 * eap_sim_build_reauth(struct eap_sm *sm,
+				 struct eap_sim_data *data,
+				 int id, size_t *reqDataLen)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
+
+	if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+		return NULL;
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: 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_SIM,
+			       EAP_SIM_SUBTYPE_REAUTHENTICATION);
+
+	if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
 static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
 			     size_t *reqDataLen)
 {
@@ -158,6 +252,8 @@
 		return eap_sim_build_start(sm, data, id, reqDataLen);
 	case CHALLENGE:
 		return eap_sim_build_challenge(sm, data, id, reqDataLen);
+	case REAUTH:
+		return eap_sim_build_reauth(sm, data, id, reqDataLen);
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
 			   "buildReq", data->state);
@@ -173,12 +269,11 @@
 	struct eap_sim_data *data = priv;
 	struct eap_hdr *resp;
 	u8 *pos, subtype;
-	size_t len;
 
 	resp = (struct eap_hdr *) respData;
 	pos = (u8 *) (resp + 1);
 	if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	    (ntohs(resp->length)) > respDataLen) {
 		wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
 		return TRUE;
 	}
@@ -202,6 +297,13 @@
 			return TRUE;
 		}
 		break;
+	case REAUTH:
+		if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
+			wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
 	default:
 		wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
 			   "processing a response", data->state);
@@ -218,43 +320,15 @@
 }
 
 
-static void eap_sim_derive_mk(struct eap_sim_data *data,
-			      const u8 *identity, size_t identity_len,
-			      const u8 *nonce_mt, int selected_version,
-			      int num_chal, const u8 *kc)
-{
-	u8 sel_ver[2], ver_list[2];
-	const unsigned char *addr[5];
-	size_t len[5];
-
-	addr[0] = identity;
-	addr[1] = kc;
-	addr[2] = nonce_mt;
-	addr[3] = ver_list;
-	addr[4] = sel_ver;
-
-	len[0] = identity_len;
-	len[1] = num_chal * KC_LEN;
-	len[2] = EAP_SIM_NONCE_MT_LEN;
-	len[3] = sizeof(ver_list);
-	len[4] = sizeof(sel_ver);
-
-	ver_list[0] = 0;
-	ver_list[1] = EAP_SIM_VERSION;
-	sel_ver[0] = selected_version >> 8;
-	sel_ver[1] = selected_version & 0xff;
-
-	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
-	sha1_vector(5, addr, len, data->mk);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
-}
-
-
 static void eap_sim_process_start(struct eap_sm *sm,
 				  struct eap_sim_data *data,
 				  u8 *respData, size_t respDataLen,
 				  struct eap_sim_attrs *attr)
 {
+	const u8 *identity;
+	size_t identity_len;
+	u8 ver_list[2];
+
 	wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
 
 	if (attr->nonce_mt == NULL || attr->selected_version < 0) {
@@ -281,8 +355,35 @@
 		}
 	}
 
-	if (sm->identity == NULL || sm->identity_len < 1 ||
-	    sm->identity[0] != '1') {
+	identity = NULL;
+	identity_len = 0;
+
+	if (sm->identity && sm->identity_len > 0 &&
+	    sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	} else {
+		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
+						    sm->identity,
+						    sm->identity_len,
+						    &identity_len);
+		if (identity == NULL) {
+			data->reauth = eap_sim_db_get_reauth_entry(
+				sm->eap_sim_db_priv, sm->identity,
+				sm->identity_len);
+			if (data->reauth) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
+					   "re-authentication");
+				identity = data->reauth->identity;
+				identity_len = data->reauth->identity_len;
+				data->counter = data->reauth->counter;
+				memcpy(data->mk, data->reauth->mk,
+				       EAP_SIM_MK_LEN);
+			}
+		}
+	}
+
+	if (identity == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
 			   " user name");
 		eap_sim_state(data, FAILURE);
@@ -290,12 +391,26 @@
 	}
 
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
-			  sm->identity, sm->identity_len);
+			  identity, identity_len);
+
+	if (data->reauth) {
+		eap_sim_state(data, REAUTH);
+		return;
+	}
+
+	data->counter = 0; /* reset re-auth counter since this is full auth */
+	data->reauth = NULL;
 
 	data->num_chal = eap_sim_db_get_gsm_triplets(
-		sm->eap_sim_db_priv, sm->identity, sm->identity_len,
+		sm->eap_sim_db_priv, identity, identity_len,
 		EAP_SIM_MAX_CHAL,
-		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres);
+		(u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
+	if (data->num_chal == EAP_SIM_DB_PENDING) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
+			   "not yet available - pending request");
+		sm->method_pending = METHOD_PENDING_WAIT;
+		return;
+	}
 	if (data->num_chal < 2) {
 		wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
 			   "authentication triplets for the peer");
@@ -303,11 +418,16 @@
 		return;
 	}
 
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
+			  sm->identity, sm->identity_len);
+
 	memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
-	eap_sim_derive_mk(data, sm->identity, sm->identity_len, attr->nonce_mt,
-			  attr->selected_version, data->num_chal,
-			  (u8 *) data->kc);
-	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+	WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
+	eap_sim_derive_mk(sm->identity, sm->identity_len, attr->nonce_mt,
+			  attr->selected_version, ver_list, sizeof(ver_list),
+			  data->num_chal, (const u8 *) data->kc, data->mk);
+	eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+			    data->emsk);
 
 	eap_sim_state(data, CHALLENGE);
 }
@@ -318,9 +438,13 @@
 				      u8 *respData, size_t respDataLen,
 				      struct eap_sim_attrs *attr)
 {
+	const u8 *identity;
+	size_t identity_len;
+
 	if (attr->mac == NULL ||
 	    eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
-			       (u8 *) data->sres, data->num_chal * SRES_LEN)) {
+			       (u8 *) data->sres,
+			       data->num_chal * EAP_SIM_SRES_LEN)) {
 		wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
 			   "did not include valid AT_MAC");
 		eap_sim_state(data, FAILURE);
@@ -330,6 +454,113 @@
 	wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
 		   "correct AT_MAC");
 	eap_sim_state(data, SUCCESS);
+
+	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
+					    sm->identity_len, &identity_len);
+	if (identity == NULL) {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	}
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+					 identity_len,
+					 data->next_pseudonym);
+		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);
+		data->next_reauth_id = NULL;
+	}
+}
+
+
+static void eap_sim_process_reauth(struct eap_sm *sm,
+				   struct eap_sim_data *data,
+				   u8 *respData, size_t respDataLen,
+				   struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted = NULL;
+	const u8 *identity, *id2;
+	size_t identity_len, id2_len;
+
+	if (attr->mac == NULL ||
+	    eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
+			       data->nonce_s, EAP_SIM_NONCE_S_LEN)) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+			   "did not include valid AT_MAC");
+		goto fail;
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+			   "message did not include encrypted data");
+		goto fail;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+			   "data from reauthentication message");
+		goto fail;
+	}
+
+	if (eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+			   "used incorrect counter %u, expected %u",
+			   eattr.counter, data->counter);
+		goto fail;
+	}
+	free(decrypted);
+	decrypted = NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
+		   "the correct AT_MAC");
+	eap_sim_state(data, SUCCESS);
+
+	if (data->reauth) {
+		identity = data->reauth->identity;
+		identity_len = data->reauth->identity_len;
+	} else {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	}
+
+	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
+				       identity_len, &id2_len);
+	if (id2) {
+		identity = id2;
+		identity_len = id2_len;
+	}
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+					 identity_len, data->next_pseudonym);
+		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);
+		data->next_reauth_id = NULL;
+	} else {
+		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+		data->reauth = NULL;
+	}
+
+	return;
+
+fail:
+	eap_sim_state(data, FAILURE);
+	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+	data->reauth = NULL;
+	free(decrypted);
 }
 
 
@@ -377,6 +608,9 @@
 	case CHALLENGE:
 		eap_sim_process_challenge(sm, data, respData, len, &attr);
 		break;
+	case REAUTH:
+		eap_sim_process_reauth(sm, data, respData, len, &attr);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
 			   "process", data->state);
@@ -409,6 +643,23 @@
 }
 
 
+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+	return key;
+}
+
+
 static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
 {
 	struct eap_sim_data *data = priv;
@@ -416,16 +667,28 @@
 }
 
 
-const struct eap_method eap_method_sim =
+int eap_server_sim_register(void)
 {
-	.method = EAP_TYPE_SIM,
-	.name = "SIM",
-	.init = eap_sim_init,
-	.reset = eap_sim_reset,
-	.buildReq = eap_sim_buildReq,
-	.check = eap_sim_check,
-	.process = eap_sim_process,
-	.isDone = eap_sim_isDone,
-	.getKey = eap_sim_getKey,
-	.isSuccess = eap_sim_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sim_init;
+	eap->reset = eap_sim_reset;
+	eap->buildReq = eap_sim_buildReq;
+	eap->check = eap_sim_check;
+	eap->process = eap_sim_process;
+	eap->isDone = eap_sim_isDone;
+	eap->getKey = eap_sim_getKey;
+	eap->isSuccess = eap_sim_isSuccess;
+	eap->get_emsk = eap_sim_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
--- /dev/null
+++ contrib/hostapd/eap_methods.c
@@ -0,0 +1,273 @@
+/*
+ * hostapd / EAP method registration
+ * Copyright (c) 2004-2006, 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 "hostapd.h"
+#include "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods;
+
+
+/**
+ * eap_sm_get_eap_methods - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == method)
+			return m;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_get_type(const char *name, int *vendor)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (strcmp(m->name, name) == 0) {
+			*vendor = m->vendor;
+			return m->method;
+		}
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_server_method_alloc - Allocate EAP server method structure
+ * @version: Version of the EAP server method interface (set to
+ * 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")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_server_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+					    EapType method, const char *name)
+{
+	struct eap_method *eap;
+	eap = wpa_zalloc(sizeof(*eap));
+	if (eap == NULL)
+		return NULL;
+	eap->version = version;
+	eap->vendor = vendor;
+	eap->method = method;
+	eap->name = name;
+	return eap;
+}
+
+
+/**
+ * eap_server_method_free - Free EAP server method structure
+ * @method: Method structure allocated with eap_server_method_alloc()
+ */
+void eap_server_method_free(struct eap_method *method)
+{
+	free(method);
+}
+
+
+/**
+ * eap_server_method_register - Register an EAP server method
+ * @method: EAP method to register
+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
+ * has already been registered
+ *
+ * Each EAP server method needs to call this function to register itself as a
+ * supported EAP method.
+ */
+int eap_server_method_register(struct eap_method *method)
+{
+	struct eap_method *m, *last = NULL;
+
+	if (method == NULL || method->name == NULL ||
+	    method->version != EAP_SERVER_METHOD_INTERFACE_VERSION)
+		return -1;
+
+	for (m = eap_methods; m; m = m->next) {
+		if ((m->vendor == method->vendor &&
+		     m->method == method->method) ||
+		    strcmp(m->name, method->name) == 0)
+			return -2;
+		last = m;
+	}
+
+	if (last)
+		last->next = method;
+	else
+		eap_methods = method;
+
+	return 0;
+}
+
+
+/**
+ * eap_server_register_methods - Register statically linked EAP server methods
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called at program initialization to register all EAP server
+ * methods that were linked in statically.
+ */
+int eap_server_register_methods(void)
+{
+	int ret = 0;
+
+	if (ret == 0) {
+		int eap_server_identity_register(void);
+		ret = eap_server_identity_register();
+	}
+
+#ifdef EAP_MD5
+	if (ret == 0) {
+		int eap_server_md5_register(void);
+		ret = eap_server_md5_register();
+	}
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+	if (ret == 0) {
+		int eap_server_tls_register(void);
+		ret = eap_server_tls_register();
+	}
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+	if (ret == 0) {
+		int eap_server_mschapv2_register(void);
+		ret = eap_server_mschapv2_register();
+	}
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+	if (ret == 0) {
+		int eap_server_peap_register(void);
+		ret = eap_server_peap_register();
+	}
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TLV
+	if (ret == 0) {
+		int eap_server_tlv_register(void);
+		ret = eap_server_tlv_register();
+	}
+#endif /* EAP_TLV */
+
+#ifdef EAP_GTC
+	if (ret == 0) {
+		int eap_server_gtc_register(void);
+		ret = eap_server_gtc_register();
+	}
+#endif /* EAP_GTC */
+
+#ifdef EAP_TTLS
+	if (ret == 0) {
+		int eap_server_ttls_register(void);
+		ret = eap_server_ttls_register();
+	}
+#endif /* EAP_TTLS */
+
+#ifdef EAP_SIM
+	if (ret == 0) {
+		int eap_server_sim_register(void);
+		ret = eap_server_sim_register();
+	}
+#endif /* EAP_SIM */
+
+#ifdef EAP_AKA
+	if (ret == 0) {
+		int eap_server_aka_register(void);
+		ret = eap_server_aka_register();
+	}
+#endif /* EAP_AKA */
+
+#ifdef EAP_PAX
+	if (ret == 0) {
+		int eap_server_pax_register(void);
+		ret = eap_server_pax_register();
+	}
+#endif /* EAP_PAX */
+
+#ifdef EAP_PSK
+	if (ret == 0) {
+		int eap_server_psk_register(void);
+		ret = eap_server_psk_register();
+	}
+#endif /* EAP_PSK */
+
+#ifdef EAP_SAKE
+	if (ret == 0) {
+		int eap_server_sake_register(void);
+		ret = eap_server_sake_register();
+	}
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+	if (ret == 0) {
+		int eap_server_gpsk_register(void);
+		ret = eap_server_gpsk_register();
+	}
+#endif /* EAP_GPSK */
+
+#ifdef EAP_VENDOR_TEST
+	if (ret == 0) {
+		int eap_server_vendor_test_register(void);
+		ret = eap_server_vendor_test_register();
+	}
+#endif /* EAP_VENDOR_TEST */
+
+	return ret;
+}
+
+
+/**
+ * eap_server_unregister_methods - Unregister EAP server methods
+ *
+ * This function is called at program termination to unregister all EAP server
+ * methods.
+ */
+void eap_server_unregister_methods(void)
+{
+	struct eap_method *m;
+
+	while (eap_methods) {
+		m = eap_methods;
+		eap_methods = eap_methods->next;
+
+		if (m->free)
+			m->free(m);
+		else
+			eap_server_method_free(m);
+	}
+}
Index: wpa_ctrl.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/wpa_ctrl.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/wpa_ctrl.h -L contrib/hostapd/wpa_ctrl.h -u -r1.1 -r1.2
--- contrib/hostapd/wpa_ctrl.h
+++ contrib/hostapd/wpa_ctrl.h
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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
@@ -147,7 +147,7 @@
 /**
  * wpa_ctrl_pending - Check whether there are pending event messages
  * @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: Non-zero if there are pending messages
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
  *
  * This function will check whether there are any pending control interface
  * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
Index: eap_sim_db.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_sim_db.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_sim_db.c -L contrib/hostapd/eap_sim_db.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_sim_db.c
+++ contrib/hostapd/eap_sim_db.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2005-2006, 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
@@ -10,106 +10,555 @@
  * license.
  *
  * See README and COPYING for more details.
+ *
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface that is using an external program as an SS7 gateway to
+ * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
+ * implementation of such a gateway program. This eap_sim_db.c takes care of
+ * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
+ * gateway implementations for HLR/AuC access. Alternatively, it can also be
+ * completely replaced if the in-memory database of pseudonyms/re-auth
+ * identities is not suitable for some cases.
  */
 
-/* This is an example implementation of the EAP-SIM database/authentication
- * gateway interface that is expected to be replaced with an implementation of
- * SS7 gateway to GSM authentication center (HLR/AuC) or a local
- * implementation of SIM triplet generator.
- *
- * The example implementation here reads triplets from a text file in
- * IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex strings. This
- * is used to simulate an HLR/AuC. As such, it is not very useful for real life
- * authentication, but it is useful both as an example implementation and for
- * EAP-SIM testing.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
+#include <sys/un.h>
 
 #include "common.h"
 #include "eap_sim_common.h"
 #include "eap_sim_db.h"
+#include "eloop.h"
 
+struct eap_sim_pseudonym {
+	struct eap_sim_pseudonym *next;
+	u8 *identity;
+	size_t identity_len;
+	char *pseudonym;
+};
 
-/* TODO: add an alternative callback based version of the interface. This is
- * needed to work better with the single threaded design of hostapd. For this,
- * the EAP data has to be stored somewhere and eap_sim_db is given a context
- * pointer for this and a callback function. The callback function will re-send
- * the EAP data through normal operations which will eventually end up calling
- * eap_sim_db_get_gsm_triplets() again for the same user. This time, eap_sim_db
- * should have the triplets available immediately. */
-
+struct eap_sim_db_pending {
+	struct eap_sim_db_pending *next;
+	u8 imsi[20];
+	size_t imsi_len;
+	enum { PENDING, SUCCESS, FAILURE } state;
+	void *cb_session_ctx;
+	struct os_time timestamp;
+	int aka;
+	union {
+		struct {
+			u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+			u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
+			u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+			int num_chal;
+		} sim;
+		struct {
+			u8 rand[EAP_AKA_RAND_LEN];
+			u8 autn[EAP_AKA_AUTN_LEN];
+			u8 ik[EAP_AKA_IK_LEN];
+			u8 ck[EAP_AKA_CK_LEN];
+			u8 res[EAP_AKA_RES_MAX_LEN];
+			size_t res_len;
+		} aka;
+	} u;
+};
 
 struct eap_sim_db_data {
+	int sock;
 	char *fname;
+	char *local_sock;
+	void (*get_complete_cb)(void *ctx, void *session_ctx);
+	void *ctx;
+	struct eap_sim_pseudonym *pseudonyms;
+	struct eap_sim_reauth *reauths;
+	struct eap_sim_db_pending *pending;
 };
 
-#define KC_LEN 8
-#define SRES_LEN 4
-#define RAND_LEN 16
+
+static struct eap_sim_db_pending *
+eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
+		       size_t imsi_len, int aka)
+{
+	struct eap_sim_db_pending *entry, *prev = NULL;
+
+	entry = data->pending;
+	while (entry) {
+		if (entry->aka == aka && entry->imsi_len == imsi_len &&
+		    memcmp(entry->imsi, imsi, imsi_len) == 0) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				data->pending = entry->next;
+			break;
+		}
+		prev = entry;
+		entry = entry->next;
+	}
+	return entry;
+}
+
+
+static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
+				   struct eap_sim_db_pending *entry)
+{
+	entry->next = data->pending;
+	data->pending = entry;
+}
+
+
+static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
+				     const char *imsi, char *buf)
+{
+	char *start, *end, *pos;
+	struct eap_sim_db_pending *entry;
+	int num_chal;
+
+	/*
+	 * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
+	 * SIM-RESP-AUTH <IMSI> FAILURE
+	 * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
+	 */
+
+	entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 0);
+	if (entry == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+			   "received message found");
+		return;
+	}
+
+	start = buf;
+	if (strncmp(start, "FAILURE", 7) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+			   "failure");
+		entry->state = FAILURE;
+		eap_sim_db_add_pending(data, entry);
+		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+		return;
+	}
+
+	num_chal = 0;
+	while (num_chal < EAP_SIM_MAX_CHAL) {
+		end = strchr(start, ' ');
+		if (end)
+			*end = '\0';
+
+		pos = strchr(start, ':');
+		if (pos == NULL)
+			goto parse_fail;
+		*pos = '\0';
+		if (hexstr2bin(start, entry->u.sim.kc[num_chal],
+			       EAP_SIM_KC_LEN))
+			goto parse_fail;
+
+		start = pos + 1;
+		pos = strchr(start, ':');
+		if (pos == NULL)
+			goto parse_fail;
+		*pos = '\0';
+		if (hexstr2bin(start, entry->u.sim.sres[num_chal],
+			       EAP_SIM_SRES_LEN))
+			goto parse_fail;
+
+		start = pos + 1;
+		if (hexstr2bin(start, entry->u.sim.rand[num_chal],
+			       GSM_RAND_LEN))
+			goto parse_fail;
+
+		num_chal++;
+		if (end == NULL)
+			break;
+		else
+			start = end + 1;
+	}
+	entry->u.sim.num_chal = num_chal;
+
+	entry->state = SUCCESS;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+		   "successfully - callback");
+	eap_sim_db_add_pending(data, entry);
+	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+	free(entry);
+}
+
+
+static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
+				     const char *imsi, char *buf)
+{
+	char *start, *end;
+	struct eap_sim_db_pending *entry;
+
+	/*
+	 * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+	 * AKA-RESP-AUTH <IMSI> FAILURE
+	 * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
+	 */
+
+	entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 1);
+	if (entry == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+			   "received message found");
+		return;
+	}
+
+	start = buf;
+	if (strncmp(start, "FAILURE", 7) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+			   "failure");
+		entry->state = FAILURE;
+		eap_sim_db_add_pending(data, entry);
+		data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+		return;
+	}
+
+	end = strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = strchr(start, ' ');
+	if (end == NULL)
+		goto parse_fail;
+	*end = '\0';
+	if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
+		goto parse_fail;
+
+	start = end + 1;
+	end = strchr(start, ' ');
+	if (end)
+		*end = '\0';
+	else {
+		end = start;
+		while (*end)
+			end++;
+	}
+	entry->u.aka.res_len = (end - start) / 2;
+	if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
+		entry->u.aka.res_len = 0;
+		goto parse_fail;
+	}
+	if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
+		goto parse_fail;
+
+	entry->state = SUCCESS;
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+		   "successfully - callback");
+	eap_sim_db_add_pending(data, entry);
+	data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+	free(entry);
+}
+
+
+static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct eap_sim_db_data *data = eloop_ctx;
+	char buf[1000], *pos, *cmd, *imsi;
+	int res;
+
+	res = recv(sock, buf, sizeof(buf), 0);
+	if (res < 0)
+		return;
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
+			      "external source", (u8 *) buf, res);
+	if (res == 0)
+		return;
+	if (res >= (int) sizeof(buf))
+		res = sizeof(buf) - 1;
+	buf[res] = '\0';
+
+	if (data->get_complete_cb == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
+			   "registered");
+		return;
+	}
+
+	/* <cmd> <IMSI> ... */
+
+	cmd = buf;
+	pos = strchr(cmd, ' ');
+	if (pos == NULL)
+		goto parse_fail;
+	*pos = '\0';
+	imsi = pos + 1;
+	pos = strchr(imsi, ' ');
+	if (pos == NULL)
+		goto parse_fail;
+	*pos = '\0';
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
+		   cmd, imsi);
+
+	if (strcmp(cmd, "SIM-RESP-AUTH") == 0)
+		eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
+	else if (strcmp(cmd, "AKA-RESP-AUTH") == 0)
+		eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
+	else
+		wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
+			   "'%s'", cmd);
+	return;
+
+parse_fail:
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+}
+
+
+static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
+{
+	struct sockaddr_un addr;
+	static int counter = 0;
+
+	if (strncmp(data->fname, "unix:", 5) != 0)
+		return -1;
+
+	data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (data->sock < 0) {
+		perror("socket(eap_sim_db)");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path),
+		 "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
+	data->local_sock = strdup(addr.sun_path);
+	if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind(eap_sim_db)");
+		close(data->sock);
+		data->sock = -1;
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", data->fname + 5);
+	if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("connect(eap_sim_db)");
+		wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
+				  (u8 *) addr.sun_path, strlen(addr.sun_path));
+		close(data->sock);
+		data->sock = -1;
+		return -1;
+	}
+
+	eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
+
+	return 0;
+}
+
+
+static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
+{
+	if (data->sock >= 0) {
+		eloop_unregister_read_sock(data->sock);
+		close(data->sock);
+		data->sock = -1;
+	}
+	if (data->local_sock) {
+		unlink(data->local_sock);
+		free(data->local_sock);
+		data->local_sock = NULL;
+	}
+}
 
 
-/* Initialize EAP-SIM database/authentication gateway interface.
- * Returns pointer to a private data structure. */
-void * eap_sim_db_init(const char *config)
+/**
+ * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
+ * @config: Configuration data (e.g., file name)
+ * @get_complete_cb: Callback function for reporting availability of triplets
+ * @ctx: Context pointer for get_complete_cb
+ * Returns: Pointer to a private data structure or %NULL on failure
+ */
+void * eap_sim_db_init(const char *config,
+		       void (*get_complete_cb)(void *ctx, void *session_ctx),
+		       void *ctx)
 {
 	struct eap_sim_db_data *data;
 
-	data = malloc(sizeof(*data));
-	if (data == NULL) {
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
 		return NULL;
-	}
 
-	memset(data, 0, sizeof(*data));
+	data->sock = -1;
+	data->get_complete_cb = get_complete_cb;
+	data->ctx = ctx;
 	data->fname = strdup(config);
-	if (data->fname == NULL) {
-		free(data);
-		return NULL;
+	if (data->fname == NULL)
+		goto fail;
+
+	if (strncmp(data->fname, "unix:", 5) == 0) {
+		if (eap_sim_db_open_socket(data))
+			goto fail;
 	}
 
 	return data;
+
+fail:
+	eap_sim_db_close_socket(data);
+	free(data->fname);
+	free(data);
+	return NULL;
 }
 
-/* Deinitialize EAP-SIM database/authentication gateway interface.
- * priv is the pointer from eap_sim_db_init(). */
+
+static void eap_sim_db_free_pseudonym(struct eap_sim_pseudonym *p)
+{
+	free(p->identity);
+	free(p->pseudonym);
+	free(p);
+}
+
+
+static void eap_sim_db_free_reauth(struct eap_sim_reauth *r)
+{
+	free(r->identity);
+	free(r->reauth_id);
+	free(r);
+}
+
+
+/**
+ * eap_sim_db_deinit - Deinitialize EAP-SIM DB/authentication gw interface
+ * @priv: Private data pointer from eap_sim_db_init()
+ */
 void eap_sim_db_deinit(void *priv)
 {
 	struct eap_sim_db_data *data = priv;
+	struct eap_sim_pseudonym *p, *prev;
+	struct eap_sim_reauth *r, *prevr;
+	struct eap_sim_db_pending *pending, *prev_pending;
+
+	eap_sim_db_close_socket(data);
 	free(data->fname);
+
+	p = data->pseudonyms;
+	while (p) {
+		prev = p;
+		p = p->next;
+		eap_sim_db_free_pseudonym(prev);
+	}
+
+	r = data->reauths;
+	while (r) {
+		prevr = r;
+		r = r->next;
+		eap_sim_db_free_reauth(prevr);
+	}
+
+	pending = data->pending;
+	while (pending) {
+		prev_pending = pending;
+		pending = pending->next;
+		free(prev_pending);
+	}
+
 	free(data);
 }
 
 
-/* Get GSM triplets for user name identity (identity_len bytes). In most cases,
- * the user name is '1' | IMSI, i.e., 1 followed by the IMSI in ASCII format.
- * The identity may also include NAI realm (@realm).
- * priv is the pointer from eap_sim_db_init().
- * Returns the number of triplets received (has to be less than or equal to
- * max_chal) or -1 on error (e.g., user not found). rand, kc, and sres are
- * pointers to data areas for the triplets. */
+static int eap_sim_db_send(struct eap_sim_db_data *data, const char *msg,
+			   size_t len)
+{
+	int _errno = 0;
+
+	if (send(data->sock, msg, len, 0) < 0) {
+		_errno = errno;
+		perror("send[EAP-SIM DB UNIX]");
+	}
+
+	if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
+	    _errno == ECONNREFUSED) {
+		/* Try to reconnect */
+		eap_sim_db_close_socket(data);
+		if (eap_sim_db_open_socket(data) < 0)
+			return -1;
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Reconnected to the "
+			   "external server");
+		if (send(data->sock, msg, len, 0) < 0) {
+			perror("send[EAP-SIM DB UNIX]");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void eap_sim_db_expire_pending(struct eap_sim_db_data *data)
+{
+	/* TODO: add limit for maximum length for pending list; remove latest
+	 * (i.e., last) entry from the list if the limit is reached; could also
+	 * use timeout to expire pending entries */
+}
+
+
+/**
+ * eap_sim_db_get_gsm_triplets - Get GSM triplets
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: User name identity
+ * @identity_len: Length of identity in bytes
+ * @max_chal: Maximum number of triplets
+ * @_rand: Buffer for RAND values
+ * @kc: Buffer for Kc values
+ * @sres: Buffer for SRES values
+ * @cb_session_ctx: Session callback context for get_complete_cb()
+ * Returns: Number of triplets received (has to be less than or equal to
+ * max_chal), -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not found), or
+ * -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this case, the
+ * callback function registered with eap_sim_db_init() will be called once the
+ * results become available.
+ *
+ * In most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
+ * ASCII format.
+ *
+ * When using an external server for GSM triplets, this function can always
+ * start a request and return EAP_SIM_DB_PENDING immediately if authentication
+ * triplets are not available. Once the triplets are received, callback
+ * function registered with eap_sim_db_init() is called to notify EAP state
+ * machine to reprocess the message. This eap_sim_db_get_gsm_triplets()
+ * function will then be called again and the newly received triplets will then
+ * be given to the caller.
+ */
 int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
 				size_t identity_len, int max_chal,
-				u8 *rand, u8 *kc, u8 *sres)
+				u8 *_rand, u8 *kc, u8 *sres,
+				void *cb_session_ctx)
 {
 	struct eap_sim_db_data *data = priv;
-	FILE *f;
-	int count, i;
-	char buf[80], *pos, *next;
+	struct eap_sim_db_pending *entry;
+	int len, ret;
+	size_t i;
+	char msg[40];
 
-	f = fopen(data->fname, "r");
-	if (f == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet "
-			   "file '%s'", data->fname);
-		return -1;
-	}
-
-	if (identity_len < 2 || identity[0] != '1') {
+	if (identity_len < 2 || identity[0] != EAP_SIM_PERMANENT_PREFIX ||
+	    identity_len + 1 > sizeof(entry->imsi)) {
 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 				  identity, identity_len);
-		fclose(f);
-		return -1;
+		return EAP_SIM_DB_FAILURE;
 	}
 	identity++;
 	identity_len--;
@@ -119,90 +568,560 @@
 			break;
 		}
 	}
-	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: get triplets for IMSI",
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get GSM triplets for IMSI",
 			  identity, identity_len);
 
-	count = 0;
-	while (count < max_chal && fgets(buf, sizeof(buf), f)) {
-		/* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */
-		buf[sizeof(buf) - 1] = '\0';
-		pos = buf;
-		while (*pos != '\0' && *pos != '\n')
-			pos++;
-		if (*pos == '\n')
-			*pos = '\0';
-		if (pos - buf < 60 || pos[0] == '#')
-			continue;
+	entry = eap_sim_db_get_pending(data, identity, identity_len, 0);
+	if (entry) {
+		int num_chal;
+		if (entry->state == FAILURE) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+				   "failure");
+			free(entry);
+			return EAP_SIM_DB_FAILURE;
+		}
 
-		pos = strchr(buf, ':');
-		if (pos == NULL)
-			continue;
-		*pos++ = '\0';
-		if (strlen(buf) != identity_len ||
-		    memcmp(buf, identity, identity_len) != 0)
-			continue;
+		if (entry->state == PENDING) {
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+				   "still pending");
+			eap_sim_db_add_pending(data, entry);
+			return EAP_SIM_DB_PENDING;
+		}
 
-		next = strchr(pos, ':');
-		if (next == NULL)
-			continue;
-		*next++ = '\0';
-		if (hexstr2bin(pos, &kc[count * KC_LEN], KC_LEN) < 0)
-			continue;
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending entry -> "
+			   "%d challenges", entry->u.sim.num_chal);
+		num_chal = entry->u.sim.num_chal;
+		if (num_chal > max_chal)
+			num_chal = max_chal;
+		memcpy(_rand, entry->u.sim.rand, num_chal * GSM_RAND_LEN);
+		memcpy(sres, entry->u.sim.sres, num_chal * EAP_SIM_SRES_LEN);
+		memcpy(kc, entry->u.sim.kc, num_chal * EAP_SIM_KC_LEN);
+		free(entry);
+		return num_chal;
+	}
+
+	if (data->sock < 0) {
+		if (eap_sim_db_open_socket(data) < 0)
+			return EAP_SIM_DB_FAILURE;
+	}
 
-		pos = next;
-		next = strchr(pos, ':');
-		if (next == NULL)
-			continue;
-		*next++ = '\0';
-		if (hexstr2bin(pos, &sres[count * SRES_LEN], SRES_LEN) < 0)
-			continue;
+	len = snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
+	if (len < 0 || len + identity_len >= sizeof(msg))
+		return EAP_SIM_DB_FAILURE;
+	memcpy(msg + len, identity, identity_len);
+	len += identity_len;
+	ret = snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
+	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+		return EAP_SIM_DB_FAILURE;
+	len += ret;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting SIM authentication "
+		    "data for IMSI", identity, identity_len);
+	if (eap_sim_db_send(data, msg, len) < 0)
+		return EAP_SIM_DB_FAILURE;
+
+	entry = wpa_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return EAP_SIM_DB_FAILURE;
+
+	os_get_time(&entry->timestamp);
+	memcpy(entry->imsi, identity, identity_len);
+	entry->imsi_len = identity_len;
+	entry->cb_session_ctx = cb_session_ctx;
+	entry->state = PENDING;
+	eap_sim_db_add_pending(data, entry);
+	eap_sim_db_expire_pending(data);
 
-		if (hexstr2bin(next, &rand[count * RAND_LEN], RAND_LEN) < 0)
-			continue;
+	return EAP_SIM_DB_PENDING;
+}
 
-		count++;
+
+static struct eap_sim_pseudonym *
+eap_sim_db_get_pseudonym(struct eap_sim_db_data *data, const u8 *identity,
+			 size_t identity_len)
+{
+	char *pseudonym;
+	size_t len;
+	struct eap_sim_pseudonym *p;
+
+	if (identity_len == 0 ||
+	    (identity[0] != EAP_SIM_PSEUDONYM_PREFIX &&
+	     identity[0] != EAP_AKA_PSEUDONYM_PREFIX))
+		return NULL;
+
+	/* Remove possible realm from identity */
+	len = 0;
+	while (len < identity_len) {
+		if (identity[len] == '@')
+			break;
+		len++;
 	}
 
-	fclose(f);
+	pseudonym = malloc(len + 1);
+	if (pseudonym == NULL)
+		return NULL;
+	memcpy(pseudonym, identity, len);
+	pseudonym[len] = '\0';
 
-	if (count == 0) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: no triplets found");
-		count = -1;
+	p = data->pseudonyms;
+	while (p) {
+		if (strcmp(p->pseudonym, pseudonym) == 0)
+			break;
+		p = p->next;
 	}
 
-	return count;
+	free(pseudonym);
+
+	return p;
 }
 
 
-/* Verify whether the given user identity (identity_len bytes) is known. In
- * most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
- * ASCII format.
- * priv is the pointer from eap_sim_db_init().
- * Returns 0 if the user is found and GSM triplets would be available for it or
- * -1 on error (e.g., user not found or no triplets available). */
+static struct eap_sim_pseudonym *
+eap_sim_db_get_pseudonym_id(struct eap_sim_db_data *data, const u8 *identity,
+			    size_t identity_len)
+{
+	struct eap_sim_pseudonym *p;
+
+	if (identity_len == 0 ||
+	    (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
+	     identity[0] != EAP_AKA_PERMANENT_PREFIX))
+		return NULL;
+
+	p = data->pseudonyms;
+	while (p) {
+		if (identity_len == p->identity_len &&
+		    memcmp(p->identity, identity, identity_len) == 0)
+			break;
+		p = p->next;
+	}
+
+	return p;
+}
+
+
+static struct eap_sim_reauth *
+eap_sim_db_get_reauth(struct eap_sim_db_data *data, const u8 *identity,
+		      size_t identity_len)
+{
+	char *reauth_id;
+	size_t len;
+	struct eap_sim_reauth *r;
+
+	if (identity_len == 0 ||
+	    (identity[0] != EAP_SIM_REAUTH_ID_PREFIX &&
+	     identity[0] != EAP_AKA_REAUTH_ID_PREFIX))
+		return NULL;
+
+	/* Remove possible realm from identity */
+	len = 0;
+	while (len < identity_len) {
+		if (identity[len] == '@')
+			break;
+		len++;
+	}
+
+	reauth_id = malloc(len + 1);
+	if (reauth_id == NULL)
+		return NULL;
+	memcpy(reauth_id, identity, len);
+	reauth_id[len] = '\0';
+
+	r = data->reauths;
+	while (r) {
+		if (strcmp(r->reauth_id, reauth_id) == 0)
+			break;
+		r = r->next;
+	}
+
+	free(reauth_id);
+
+	return r;
+}
+
+
+static struct eap_sim_reauth *
+eap_sim_db_get_reauth_id(struct eap_sim_db_data *data, const u8 *identity,
+			 size_t identity_len)
+{
+	struct eap_sim_pseudonym *p;
+	struct eap_sim_reauth *r;
+
+	if (identity_len == 0)
+		return NULL;
+
+	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
+	if (p == NULL)
+		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
+	if (p) {
+		identity = p->identity;
+		identity_len = p->identity_len;
+	}
+
+	r = data->reauths;
+	while (r) {
+		if (identity_len == r->identity_len &&
+		    memcmp(r->identity, identity, identity_len) == 0)
+			break;
+		r = r->next;
+	}
+
+	return r;
+}
+
+
+/**
+ * eap_sim_db_identity_known - Verify whether the given identity is known
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: User name identity
+ * @identity_len: Length of identity in bytes 
+ * Returns: 0 if the user is found or -1 on failure
+ *
+ * In most cases, the user name is ['0','1'] | IMSI, i.e., 1 followed by the
+ * IMSI in ASCII format, ['2','3'] | pseudonym, or ['4','5'] | reauth_id.
+ */
 int eap_sim_db_identity_known(void *priv, const u8 *identity,
 			      size_t identity_len)
 {
 	struct eap_sim_db_data *data = priv;
-	FILE *f;
-	char buf[80], *pos;
-	int i;
 
-	if (identity_len < 1 || identity[0] != '1') {
+	if (identity == NULL || identity_len < 2)
+		return -1;
+
+	if (identity[0] == EAP_SIM_PSEUDONYM_PREFIX ||
+	    identity[0] == EAP_AKA_PSEUDONYM_PREFIX) {
+		struct eap_sim_pseudonym *p =
+			eap_sim_db_get_pseudonym(data, identity, identity_len);
+		return p ? 0 : -1;
+	}
+
+	if (identity[0] == EAP_SIM_REAUTH_ID_PREFIX ||
+	    identity[0] == EAP_AKA_REAUTH_ID_PREFIX) {
+		struct eap_sim_reauth *r =
+			eap_sim_db_get_reauth(data, identity, identity_len);
+		return r ? 0 : -1;
+	}
+
+	if (identity[0] != EAP_SIM_PERMANENT_PREFIX &&
+	    identity[0] != EAP_AKA_PERMANENT_PREFIX) {
+		/* Unknown identity prefix */
+		return -1;
+	}
+
+	/* TODO: Should consider asking HLR/AuC gateway whether this permanent
+	 * identity is known. If it is, EAP-SIM/AKA can skip identity request.
+	 * In case of EAP-AKA, this would reduce number of needed round-trips.
+	 * Ideally, this would be done with one wait, i.e., just request
+	 * authentication data and store it for the next use. This would then
+	 * need to use similar pending-request functionality as the normal
+	 * request for authentication data at later phase.
+	 */
+	return -1;
+}
+
+
+static char * eap_sim_db_get_next(struct eap_sim_db_data *data, char prefix)
+{
+	char *id, *pos, *end;
+	u8 buf[10];
+
+	if (hostapd_get_rand(buf, sizeof(buf)))
+		return NULL;
+	id = malloc(sizeof(buf) * 2 + 2);
+	if (id == NULL)
+		return NULL;
+
+	pos = id;
+	end = id + sizeof(buf) * 2 + 2;
+	*pos++ = prefix;
+	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+	
+	return id;
+}
+
+
+/**
+ * eap_sim_db_get_next_pseudonym - EAP-SIM DB: Get next pseudonym
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @aka: Using EAP-AKA instead of EAP-SIM
+ * Returns: Next pseudonym (allocated string) or %NULL on failure
+ *
+ * This function is used to generate a pseudonym for EAP-SIM. The returned
+ * pseudonym is not added to database at this point; it will need to be added
+ * with eap_sim_db_add_pseudonym() once the authentication has been completed
+ * successfully. Caller is responsible for freeing the returned buffer.
+ */
+char * eap_sim_db_get_next_pseudonym(void *priv, int aka)
+{
+	struct eap_sim_db_data *data = priv;
+	return eap_sim_db_get_next(data, aka ? EAP_AKA_PSEUDONYM_PREFIX :
+				   EAP_SIM_PSEUDONYM_PREFIX);
+}
+
+
+/**
+ * eap_sim_db_get_next_reauth_id - EAP-SIM DB: Get next reauth_id
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @aka: Using EAP-AKA instead of EAP-SIM
+ * Returns: Next reauth_id (allocated string) or %NULL on failure
+ *
+ * This function is used to generate a fast re-authentication identity for
+ * EAP-SIM. The returned reauth_id is not added to database at this point; it
+ * will need to be added with eap_sim_db_add_reauth() once the authentication
+ * has been completed successfully. Caller is responsible for freeing the
+ * returned buffer.
+ */
+char * eap_sim_db_get_next_reauth_id(void *priv, int aka)
+{
+	struct eap_sim_db_data *data = priv;
+	return eap_sim_db_get_next(data, aka ? EAP_AKA_REAUTH_ID_PREFIX :
+				   EAP_SIM_REAUTH_ID_PREFIX);
+}
+
+
+/**
+ * eap_sim_db_add_pseudonym - EAP-SIM DB: Add new pseudonym
+ * @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
+ * @pseudonym: Pseudonym for this user. This needs to be an allocated buffer,
+ * e.g., return value from eap_sim_db_get_next_pseudonym(). Caller must not
+ * free it.
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds a new pseudonym for EAP-SIM user. EAP-SIM DB is
+ * responsible of freeing pseudonym buffer once it is not needed anymore.
+ */
+int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
+			     size_t identity_len, char *pseudonym)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_pseudonym *p;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Add pseudonym for identity",
+			  identity, identity_len);
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pseudonym: %s", pseudonym);
+
+	/* TODO: could store last two pseudonyms */
+	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
+	if (p == NULL)
+		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
+
+	if (p) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
+			   "pseudonym: %s", p->pseudonym);
+		free(p->pseudonym);
+		p->pseudonym = pseudonym;
+		return 0;
+	}
+
+	p = wpa_zalloc(sizeof(*p));
+	if (p == NULL) {
+		free(pseudonym);
 		return -1;
 	}
 
-	f = fopen(data->fname, "r");
-	if (f == NULL) {
-		wpa_printf(MSG_DEBUG, "EAP-SIM DB: could not open triplet "
-			   "file '%s'", data->fname);
+	p->next = data->pseudonyms;
+	p->identity = malloc(identity_len);
+	if (p->identity == NULL) {
+		free(p);
+		free(pseudonym);
 		return -1;
 	}
+	memcpy(p->identity, identity, identity_len);
+	p->identity_len = identity_len;
+	p->pseudonym = pseudonym;
+	data->pseudonyms = p;
 
-	if (identity_len < 2 || identity[0] != '1') {
+	wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new pseudonym entry");
+	return 0;
+}
+
+
+/**
+ * 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;
+	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);
+
+	r = eap_sim_db_get_reauth(data, identity, identity_len);
+	if (r == NULL)
+		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+
+	if (r) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Replacing previous "
+			   "reauth_id: %s", r->reauth_id);
+		free(r->reauth_id);
+		r->reauth_id = reauth_id;
+	} else {
+		r = wpa_zalloc(sizeof(*r));
+		if (r == NULL) {
+			free(reauth_id);
+			return -1;
+		}
+
+		r->next = data->reauths;
+		r->identity = malloc(identity_len);
+		if (r->identity == NULL) {
+			free(r);
+			free(reauth_id);
+			return -1;
+		}
+		memcpy(r->identity, identity, identity_len);
+		r->identity_len = identity_len;
+		r->reauth_id = reauth_id;
+		data->reauths = r;
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Added new reauth entry");
+	}
+
+	r->counter = counter;
+	memcpy(r->mk, mk, EAP_SIM_MK_LEN);
+
+	return 0;
+}
+
+
+/**
+ * eap_sim_db_get_permanent - EAP-SIM DB: Get permanent identity
+ * @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
+ * @len: Buffer for length of the returned permanent identity
+ * Returns: Pointer to the permanent identity, or %NULL if not found
+ */
+const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
+				    size_t identity_len, size_t *len)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_pseudonym *p;
+
+	if (identity == NULL)
+		return NULL;
+
+	p = eap_sim_db_get_pseudonym(data, identity, identity_len);
+	if (p == NULL)
+		p = eap_sim_db_get_pseudonym_id(data, identity, identity_len);
+	if (p == NULL)
+		return NULL;
+
+	*len = p->identity_len;
+	return p->identity;
+}
+
+
+/**
+ * eap_sim_db_get_reauth_entry - EAP-SIM DB: Get re-authentication entry
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @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 *
+eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
+			    size_t identity_len)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_reauth *r;
+
+	if (identity == NULL)
+		return NULL;
+	r = eap_sim_db_get_reauth(data, identity, identity_len);
+	if (r == NULL)
+		r = eap_sim_db_get_reauth_id(data, identity, identity_len);
+	return r;
+}
+
+
+/**
+ * eap_sim_db_remove_reauth - EAP-SIM DB: Remove re-authentication entry
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @reauth: Pointer to re-authentication entry from
+ * eap_sim_db_get_reauth_entry()
+ */
+void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_reauth *r, *prev = NULL;
+	r = data->reauths;
+	while (r) {
+		if (r == reauth) {
+			if (prev)
+				prev->next = r->next;
+			else
+				data->reauths = r->next;
+			eap_sim_db_free_reauth(r);
+			return;
+		}
+		prev = r;
+		r = r->next;
+	}
+}
+
+
+/**
+ * eap_sim_db_get_aka_auth - Get AKA authentication values
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: User name identity
+ * @identity_len: Length of identity in bytes
+ * @_rand: Buffer for RAND value
+ * @autn: Buffer for AUTN value
+ * @ik: Buffer for IK value
+ * @ck: Buffer for CK value
+ * @res: Buffer for RES value
+ * @res_len: Buffer for RES length
+ * @cb_session_ctx: Session callback context for get_complete_cb()
+ * Returns: 0 on success, -1 (EAP_SIM_DB_FAILURE) on error (e.g., user not
+ * found), or -2 (EAP_SIM_DB_PENDING) if results are not yet available. In this
+ * case, the callback function registered with eap_sim_db_init() will be
+ * called once the results become available.
+ *
+ * In most cases, the user name is '0' | IMSI, i.e., 0 followed by the IMSI in
+ * ASCII format.
+ *
+ * When using an external server for AKA authentication, this function can
+ * always start a request and return EAP_SIM_DB_PENDING immediately if
+ * authentication triplets are not available. Once the authentication data are
+ * received, callback function registered with eap_sim_db_init() is called to
+ * notify EAP state machine to reprocess the message. This
+ * eap_sim_db_get_aka_auth() function will then be called again and the newly
+ * received triplets will then be given to the caller.
+ */
+int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
+			    size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
+			    u8 *ck, u8 *res, size_t *res_len,
+			    void *cb_session_ctx)
+{
+	struct eap_sim_db_data *data = priv;
+	struct eap_sim_db_pending *entry;
+	int len;
+	size_t i;
+	char msg[40];
+
+	if (identity_len < 2 || identity == NULL ||
+	    identity[0] != EAP_AKA_PERMANENT_PREFIX ||
+	    identity_len + 1 > sizeof(entry->imsi)) {
 		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
 				  identity, identity_len);
-		return -1;
+		return EAP_SIM_DB_FAILURE;
 	}
 	identity++;
 	identity_len--;
@@ -212,32 +1131,123 @@
 			break;
 		}
 	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: Get AKA auth for IMSI",
+			  identity, identity_len);
 
-	while (fgets(buf, sizeof(buf), f)) {
-		/* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */
-		buf[sizeof(buf) - 1] = '\0';
-		pos = buf;
-		while (*pos != '\0' && *pos != '\n')
-			pos++;
-		if (*pos == '\n')
-			*pos = '\0';
-		if (pos - buf < 60 || pos[0] == '#')
-			continue;
+	entry = eap_sim_db_get_pending(data, identity, identity_len, 1);
+	if (entry) {
+		if (entry->state == FAILURE) {
+			free(entry);
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failure");
+			return EAP_SIM_DB_FAILURE;
+		}
 
-		pos = strchr(buf, ':');
-		if (pos == NULL)
-			continue;
-		*pos++ = '\0';
-		if (strlen(buf) != identity_len ||
-		    memcmp(buf, identity, identity_len) != 0)
-			continue;
+		if (entry->state == PENDING) {
+			eap_sim_db_add_pending(data, entry);
+			wpa_printf(MSG_DEBUG, "EAP-SIM DB: Pending");
+			return EAP_SIM_DB_PENDING;
+		}
 
-		fclose(f);
+		wpa_printf(MSG_DEBUG, "EAP-SIM DB: Returning successfully "
+			   "received authentication data");
+		memcpy(_rand, entry->u.aka.rand, EAP_AKA_RAND_LEN);
+		memcpy(autn, entry->u.aka.autn, EAP_AKA_AUTN_LEN);
+		memcpy(ik, entry->u.aka.ik, EAP_AKA_IK_LEN);
+		memcpy(ck, entry->u.aka.ck, EAP_AKA_CK_LEN);
+		memcpy(res, entry->u.aka.res, EAP_AKA_RES_MAX_LEN);
+		*res_len = entry->u.aka.res_len;
+		free(entry);
 		return 0;
 	}
 
-	/* IMSI not found */
+	if (data->sock < 0) {
+		if (eap_sim_db_open_socket(data) < 0)
+			return EAP_SIM_DB_FAILURE;
+	}
 
-	fclose(f);
-	return -1;
+	len = snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
+	if (len < 0 || len + identity_len >= sizeof(msg))
+		return EAP_SIM_DB_FAILURE;
+	memcpy(msg + len, identity, identity_len);
+	len += identity_len;
+
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: requesting AKA authentication "
+		    "data for IMSI", identity, identity_len);
+	if (eap_sim_db_send(data, msg, len) < 0)
+		return EAP_SIM_DB_FAILURE;
+
+	entry = wpa_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return EAP_SIM_DB_FAILURE;
+
+	os_get_time(&entry->timestamp);
+	entry->aka = 1;
+	memcpy(entry->imsi, identity, identity_len);
+	entry->imsi_len = identity_len;
+	entry->cb_session_ctx = cb_session_ctx;
+	entry->state = PENDING;
+	eap_sim_db_add_pending(data, entry);
+	eap_sim_db_expire_pending(data);
+
+	return EAP_SIM_DB_PENDING;
+}
+
+
+/**
+ * eap_sim_db_resynchronize - Resynchronize AKA AUTN
+ * @priv: Private data pointer from eap_sim_db_init()
+ * @identity: User name identity
+ * @identity_len: Length of identity in bytes
+ * @auts: AUTS value from the peer
+ * @_rand: RAND value used in the rejected message
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when the peer reports synchronization failure in the
+ * AUTN value by sending AUTS. The AUTS and RAND values should be sent to
+ * HLR/AuC to allow it to resynchronize with the peer. After this,
+ * eap_sim_db_get_aka_auth() will be called again to to fetch updated
+ * RAND/AUTN values for the next challenge.
+ */
+int eap_sim_db_resynchronize(void *priv, const u8 *identity,
+			     size_t identity_len, const u8 *auts,
+			     const u8 *_rand)
+{
+	struct eap_sim_db_data *data = priv;
+
+	if (identity_len < 2 || identity[0] != EAP_AKA_PERMANENT_PREFIX ||
+	    identity_len > 20) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM DB: unexpected identity",
+				  identity, identity_len);
+		return -1;
+	}
+
+	if (data->sock >= 0) {
+		char msg[100];
+		int len, ret;
+
+		len = snprintf(msg, sizeof(msg), "AKA-AUTS ");
+		if (len < 0 || len + identity_len - 1 >= sizeof(msg))
+			return -1;
+		memcpy(msg + len, identity + 1, identity_len - 1);
+		len += identity_len - 1;
+
+		ret = snprintf(msg + len, sizeof(msg) - len, " ");
+		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+			return -1;
+		len += ret;
+		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
+					auts, EAP_AKA_AUTS_LEN);
+		ret = snprintf(msg + len, sizeof(msg) - len, " ");
+		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+			return -1;
+		len += ret;
+		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
+					_rand, EAP_AKA_RAND_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM DB: reporting AKA AUTS for "
+			    "IMSI", identity + 1, identity_len - 1);
+		if (eap_sim_db_send(data, msg, len) < 0)
+			return -1;
+	}
+
+	return 0;
 }
--- /dev/null
+++ contrib/hostapd/os_unix.c
@@ -0,0 +1,212 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions for UNIX/POSIX systems
+ * Copyright (c) 2005-2006, 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 "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		sleep(sec);
+	if (usec)
+		usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	*t = (os_time_t) mktime(&tm);
+	return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	if (daemon(0, 0)) {
+		perror("daemon");
+		return -1;
+	}
+
+	if (pid_file) {
+		FILE *f = fopen(pid_file, "w");
+		if (f) {
+			fprintf(f, "%u\n", getpid());
+			fclose(f);
+		}
+	}
+
+	return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+	if (pid_file)
+		unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "rb");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+	return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	char *buf = NULL, *cwd, *ret;
+	size_t len = 128, cwd_len, rel_len, ret_len;
+	int last_errno;
+
+	if (rel_path[0] == '/')
+		return strdup(rel_path);
+
+	for (;;) {
+		buf = malloc(len);
+		if (buf == NULL)
+			return NULL;
+		cwd = getcwd(buf, len);
+		if (cwd == NULL) {
+			last_errno = errno;
+			free(buf);
+			if (last_errno != ERANGE)
+				return NULL;
+			len *= 2;
+			if (len > 2000)
+				return NULL;
+		} else {
+			buf[len - 1] = '\0';
+			break;
+		}
+	}
+
+	cwd_len = strlen(cwd);
+	rel_len = strlen(rel_path);
+	ret_len = cwd_len + 1 + rel_len + 1;
+	ret = malloc(ret_len);
+	if (ret) {
+		memcpy(ret, cwd, cwd_len);
+		ret[cwd_len] = '/';
+		memcpy(ret + cwd_len + 1, rel_path, rel_len);
+		ret[ret_len - 1] = '\0';
+	}
+	free(buf);
+	return ret;
+}
+
+
+int os_program_init(void)
+{
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+	unsetenv(name);
+	return 0;
+#else
+	return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	fseek(f, 0, SEEK_END);
+	*len = ftell(f);
+	fseek(f, 0, SEEK_SET);
+
+	buf = malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	fread(buf, 1, *len, f);
+	fclose(f);
+
+	return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	return calloc(1, size);
+}
Index: eap_psk_common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_psk_common.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_psk_common.h -L contrib/hostapd/eap_psk_common.h -u -r1.1 -r1.2
--- contrib/hostapd/eap_psk_common.h
+++ contrib/hostapd/eap_psk_common.h
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, 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,7 +19,6 @@
 #define EAP_PSK_RAND_LEN 16
 #define EAP_PSK_MAC_LEN 16
 #define EAP_PSK_TEK_LEN 16
-#define EAP_PSK_MSK_LEN 64
 #define EAP_PSK_PSK_LEN 16
 #define EAP_PSK_AK_LEN 16
 #define EAP_PSK_KDK_LEN 16
@@ -29,6 +28,13 @@
 #define EAP_PSK_R_FLAG_DONE_FAILURE 3
 #define EAP_PSK_E_FLAG 0x20
 
+#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6)
+#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
 /* Shared prefix for all EAP-PSK frames */
 struct eap_psk_hdr {
 	u8 code;
@@ -36,7 +42,7 @@
 	u16 length; /* including code, identifier, and length */
 	u8 type; /* EAP_TYPE_PSK */
 	u8 flags;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 /* EAP-PSK First Message (AS -> Supplicant) */
 struct eap_psk_hdr_1 {
@@ -47,7 +53,7 @@
 	u8 flags;
 	u8 rand_s[EAP_PSK_RAND_LEN];
 	/* Followed by variable length ID_S */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 /* EAP-PSK Second Message (Supplicant -> AS) */
 struct eap_psk_hdr_2 {
@@ -60,7 +66,7 @@
 	u8 rand_p[EAP_PSK_RAND_LEN];
 	u8 mac_p[EAP_PSK_MAC_LEN];
 	/* Followed by variable length ID_P */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 /* EAP-PSK Third Message (AS -> Supplicant) */
 struct eap_psk_hdr_3 {
@@ -72,7 +78,7 @@
 	u8 rand_s[EAP_PSK_RAND_LEN];
 	u8 mac_s[EAP_PSK_MAC_LEN];
 	/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 /* EAP-PSK Fourth Message (Supplicant -> AS) */
 struct eap_psk_hdr_4 {
@@ -83,10 +89,15 @@
 	u8 flags;
 	u8 rand_s[EAP_PSK_RAND_LEN];
 	/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
 
 
 void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk);
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+			 u8 *emsk);
 
 #endif /* EAP_PSK_COMMON_H */
Index: README
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/README,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/README -L contrib/hostapd/README -u -r1.2 -r1.3
--- contrib/hostapd/README
+++ contrib/hostapd/README
@@ -2,8 +2,7 @@
 	  Authenticator and RADIUS authentication server
 ================================================================
 
-Copyright (c) 2002-2006, Jouni Malinen <jkmaline at cc.hut.fi> and
-contributors
+Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi> and contributors
 All Rights Reserved.
 
 This program is dual-licensed under both the GPL version 2 and BSD
@@ -27,13 +26,13 @@
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 (this copy of the license is in COPYING file)
 
 
-Alternatively, this software may be distributed under the terms of BSD
-license:
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -92,9 +91,9 @@
 
 	madwifi driver for cards based on Atheros chip set (ar521x)
 	(http://sourceforge.net/projects/madwifi/)
-	Please note that you will need to modify the hostapd Makefile
-	to use correct path for madwifi driver root directory
-	(CFLAGS += -I../head line in Makefile).
+	Please note that you will need to add the correct path for
+	madwifi driver root directory in .config (see defconfig file for
+	an example: CFLAGS += -I<path>)
 
 	Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
 	(http://www.prism54.org/)
@@ -158,14 +157,6 @@
 device that is also used with IEEE 802.11 management frames. The
 frames to the Supplicant are sent using the same device.
 
-hostapd includes a minimal colocated Authentication Server for testing
-purposes. It only requests the identity of the Supplicant and
-authorizes any host that is able to send a valid EAP Response
-frame. This can be used for quick testing since it does not require an
-external Authentication Server, but it should not be used for any real
-authentication purposes since no keys are required and anyone can
-authenticate.
-
 The normal configuration of the Authenticator would use an external
 Authentication Server. hostapd supports RADIUS encapsulation of EAP
 packets, so the Authentication Server should be a RADIUS server, like
Index: driver.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/driver.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/driver.h -L contrib/hostapd/driver.h -u -r1.2 -r1.3
--- contrib/hostapd/driver.h
+++ contrib/hostapd/driver.h
@@ -1,6 +1,10 @@
 #ifndef DRIVER_H
 #define DRIVER_H
 
+enum hostapd_driver_if_type {
+	HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
+};
+
 struct driver_ops {
 	const char *name;		/* as appears in the config file */
 
@@ -12,6 +16,7 @@
 
 	/**
 	 * set_8021x - enable/disable IEEE 802.1X support
+	 * @ifname: Interface name (for multi-SSID/VLAN support)
 	 * @priv: driver private data
 	 * @enabled: 1 = enable, 0 = disable
 	 *
@@ -20,7 +25,7 @@
 	 * Configure the kernel driver to enable/disable 802.1X support.
 	 * This may be an empty function if 802.1X support is always enabled.
 	 */
-	int (*set_ieee8021x)(void *priv, int enabled);
+	int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
 
 	/**
 	 * set_privacy - enable/disable privacy
@@ -31,32 +36,111 @@
 	 *
 	 * Configure privacy.
 	 */
-	int (*set_privacy)(void *priv, int enabled);
+	int (*set_privacy)(const char *ifname, void *priv, int enabled);
 
-	int (*set_encryption)(void *priv, const char *alg, u8 *addr,
-			      int idx, u8 *key, size_t key_len);
-	int (*get_seqnum)(void *priv, u8 *addr, int idx, u8 *seq);
+	int (*set_encryption)(const char *ifname, void *priv, const char *alg,
+			      const u8 *addr, int idx,
+			      const u8 *key, size_t key_len, int txkey);
+	int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+			  int idx, u8 *seq);
+	int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
+			       int idx, u8 *seq);
 	int (*flush)(void *priv);
-	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+	int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
+				size_t elem_len);
 
 	int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
-			     u8 *addr);
-	int (*send_eapol)(void *priv, u8 *addr, u8 *data, size_t data_len,
-			  int encrypt);
-	int (*set_sta_authorized)(void *driver, u8 *addr, int authorized);
-	int (*sta_deauth)(void *priv, u8 *addr, int reason);
-	int (*sta_disassoc)(void *priv, u8 *addr, int reason);
-	int (*sta_remove)(void *priv, u8 *addr);
-	int (*get_ssid)(void *priv, u8 *buf, int len);
-	int (*set_ssid)(void *priv, u8 *buf, int len);
+			     const u8 *addr);
+	int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
+			  size_t data_len, int encrypt, const u8 *own_addr);
+	int (*sta_deauth)(void *priv, const u8 *addr, int reason);
+	int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
+	int (*sta_remove)(void *priv, const u8 *addr);
+	int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
+	int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
+			int len);
 	int (*set_countermeasures)(void *priv, int enabled);
 	int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
 			       int flags);
-	int (*set_assoc_ap)(void *priv, u8 *addr);
-	int (*sta_add)(void *priv, u8 *addr, u16 aid, u16 capability,
-		       u8 tx_supp_rates);
-	int (*get_inact_sec)(void *priv, u8 *addr);
-	int (*sta_clear_stats)(void *priv, u8 *addr);
+	int (*set_assoc_ap)(void *priv, const u8 *addr);
+	int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
+		       u16 capability, u8 *supp_rates, size_t supp_rates_len,
+		       int flags);
+	int (*get_inact_sec)(void *priv, const u8 *addr);
+	int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+	int (*set_freq)(void *priv, int mode, int freq);
+	int (*set_rts)(void *priv, int rts);
+	int (*get_rts)(void *priv, int *rts);
+	int (*set_frag)(void *priv, int frag);
+	int (*get_frag)(void *priv, int *frag);
+	int (*set_retry)(void *priv, int short_retry, int long_retry);
+	int (*get_retry)(void *priv, int *short_retry, int *long_retry);
+
+	int (*sta_set_flags)(void *priv, const u8 *addr,
+			     int flags_or, int flags_and);
+	int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
+			     int mode);
+	int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
+				unsigned char power_level,
+				unsigned char antenna_max);
+	int (*set_regulatory_domain)(void *priv, unsigned int rd);
+	int (*set_country)(void *priv, const char *country);
+	int (*set_ieee80211d)(void *priv, int enabled);
+	int (*set_beacon)(const char *ifname, void *priv,
+			  u8 *head, size_t head_len,
+			  u8 *tail, size_t tail_len);
+
+	/* Configure internal bridge:
+	 * 0 = disabled, i.e., client separation is enabled (no bridging of
+	 *     packets between associated STAs
+	 * 1 = enabled, i.e., bridge packets between associated STAs (default)
+	 */
+	int (*set_internal_bridge)(void *priv, int value);
+	int (*set_beacon_int)(void *priv, int value);
+	int (*set_dtim_period)(const char *ifname, void *priv, int value);
+	/* Configure broadcast SSID mode:
+	 * 0 = include SSID in Beacon frames and reply to Probe Request frames
+	 *     that use broadcast SSID
+	 * 1 = hide SSID from Beacon frames and ignore Probe Request frames for
+	 *     broadcast SSID
+	 */
+	int (*set_broadcast_ssid)(void *priv, int value);
+	int (*set_cts_protect)(void *priv, int value);
+	int (*set_key_tx_rx_threshold)(void *priv, int value);
+	int (*set_preamble)(void *priv, int value);
+	int (*set_short_slot_time)(void *priv, int value);
+	int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+				   int cw_max, int burst_time);
+	int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
+	int (*bss_remove)(void *priv, const char *ifname);
+	int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
+	int (*passive_scan)(void *priv, int now, int our_mode_only,
+			    int interval, int _listen, int *channel,
+			    int *last_rx);
+	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+							 u16 *num_modes,
+							 u16 *flags);
+	int (*if_add)(const char *iface, void *priv,
+		      enum hostapd_driver_if_type type, char *ifname,
+		      const u8 *addr);
+	int (*if_update)(void *priv, enum hostapd_driver_if_type type,
+			 char *ifname, const u8 *addr);
+	int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
+			 const char *ifname, const u8 *addr);
+	int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+			    int vlan_id);
+	/**
+	 * commit - Optional commit changes handler
+	 * @priv: driver private data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional handler function can be registered if the driver
+	 * interface implementation needs to commit changes (e.g., by setting
+	 * network interface up) at the end of initial configuration. If set,
+	 * this handler will be called after initial setup has been completed.
+	 */
+	int (*commit)(void *priv);
 };
 
 static inline int
@@ -94,11 +178,12 @@
 }
 
 static inline int
-hostapd_set_ieee8021x(struct hostapd_data *hapd, int enabled)
+hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
+		      int enabled)
 {
 	if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
 		return 0;
-	return hapd->driver->set_ieee8021x(hapd->driver, enabled);
+	return hapd->driver->set_ieee8021x(ifname, hapd->driver, enabled);
 }
 
 static inline int
@@ -106,25 +191,38 @@
 {
 	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
 		return 0;
-	return hapd->driver->set_privacy(hapd->driver, enabled);
+	return hapd->driver->set_privacy(hapd->conf->iface, hapd->driver,
+					 enabled);
 }
 
 static inline int
-hostapd_set_encryption(struct hostapd_data *hapd, const char *alg, u8 *addr,
-		       int idx, u8 *key, size_t key_len)
+hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
+		       const char *alg, const u8 *addr, int idx,
+		       u8 *key, size_t key_len, int txkey)
 {
 	if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
 		return 0;
-	return hapd->driver->set_encryption(hapd->driver, alg, addr, idx, key,
-					    key_len);
+	return hapd->driver->set_encryption(ifname, hapd->driver, alg, addr,
+					    idx, key, key_len, txkey);
 }
 
 static inline int
-hostapd_get_seqnum(struct hostapd_data *hapd, u8 *addr, int idx, u8 *seq)
+hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+		   const u8 *addr, int idx, u8 *seq)
 {
 	if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
 		return 0;
-	return hapd->driver->get_seqnum(hapd->driver, addr, idx, seq);
+	return hapd->driver->get_seqnum(ifname, hapd->driver, addr, idx, seq);
+}
+
+static inline int
+hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
+			const u8 *addr, int idx, u8 *seq)
+{
+	if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
+		return -1;
+	return hapd->driver->get_seqnum_igtk(ifname, hapd->driver, addr, idx,
+					     seq);
 }
 
 static inline int
@@ -141,12 +239,13 @@
 {
 	if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
 		return 0;
-	return hapd->driver->set_generic_elem(hapd->driver, elem, elem_len);
+	return hapd->driver->set_generic_elem(hapd->conf->iface, hapd->driver,
+					      elem, elem_len);
 }
 
 static inline int
 hostapd_read_sta_data(struct hostapd_data *hapd,
-		      struct hostap_sta_driver_data *data, u8 *addr)
+		      struct hostap_sta_driver_data *data, const u8 *addr)
 {
 	if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
 		return -1;
@@ -154,26 +253,17 @@
 }
 
 static inline int
-hostapd_send_eapol(struct hostapd_data *hapd, u8 *addr, u8 *data,
+hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data,
 		   size_t data_len, int encrypt)
 {
 	if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
 		return 0;
 	return hapd->driver->send_eapol(hapd->driver, addr, data, data_len,
-					encrypt);
-}
-
-static inline int
-hostapd_set_sta_authorized(struct hostapd_data *hapd, u8 *addr, int authorized)
-{
-	if (hapd->driver == NULL || hapd->driver->set_sta_authorized == NULL)
-		return 0;
-	return hapd->driver->set_sta_authorized(hapd->driver, addr,
-						authorized);
+					encrypt, hapd->own_addr);
 }
 
 static inline int
-hostapd_sta_deauth(struct hostapd_data *hapd, u8 *addr, int reason)
+hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason)
 {
 	if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
 		return 0;
@@ -181,7 +271,7 @@
 }
 
 static inline int
-hostapd_sta_disassoc(struct hostapd_data *hapd, u8 *addr, int reason)
+hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason)
 {
 	if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
 		return 0;
@@ -189,7 +279,7 @@
 }
 
 static inline int
-hostapd_sta_remove(struct hostapd_data *hapd, u8 *addr)
+hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
 {
 	if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
 		return 0;
@@ -201,15 +291,17 @@
 {
 	if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
 		return 0;
-	return hapd->driver->get_ssid(hapd->driver, buf, len);
+	return hapd->driver->get_ssid(hapd->conf->iface, hapd->driver, buf,
+				      len);
 }
 
 static inline int
-hostapd_set_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
 {
 	if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
 		return 0;
-	return hapd->driver->set_ssid(hapd->driver, buf, len);
+	return hapd->driver->set_ssid(hapd->conf->iface, hapd->driver, buf,
+				      len);
 }
 
 static inline int
@@ -222,14 +314,14 @@
 }
 
 static inline int
-hostapd_set_assoc_ap(struct hostapd_data *hapd, u8 *addr)
+hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
 {
 	if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
 		return 0;
 	return hapd->driver->set_assoc_ap(hapd->driver, addr);
 }
 
-static inline int 
+static inline int
 hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
 {
 	if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
@@ -238,34 +330,327 @@
 }
 
 static inline int
-hostapd_sta_add(struct hostapd_data *hapd, u8 *addr, u16 aid, u16 capability,
-		u8 tx_supp_rates)
+hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
+		u16 aid, u16 capability, u8 *supp_rates, size_t supp_rates_len,
+		int flags)
 {
 	if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
 		return 0;
-	return hapd->driver->sta_add(hapd->driver, addr, aid, capability,
-				     tx_supp_rates);
+	return hapd->driver->sta_add(ifname, hapd->driver, addr, aid,
+				     capability, supp_rates, supp_rates_len,
+				     flags);
 }
 
 static inline int
-hostapd_get_inact_sec(struct hostapd_data *hapd, u8 *addr)
+hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
 {
 	if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
 		return 0;
 	return hapd->driver->get_inact_sec(hapd->driver, addr);
 }
 
+static inline int
+hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
+{
+	if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
+		return 0;
+	return hapd->driver->set_freq(hapd->driver, mode, freq);
+}
+
+static inline int
+hostapd_set_rts(struct hostapd_data *hapd, int rts)
+{
+	if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
+		return 0;
+	return hapd->driver->set_rts(hapd->driver, rts);
+}
+
+static inline int
+hostapd_get_rts(struct hostapd_data *hapd, int *rts)
+{
+	if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
+		return 0;
+	return hapd->driver->get_rts(hapd->driver, rts);
+}
+
+static inline int
+hostapd_set_frag(struct hostapd_data *hapd, int frag)
+{
+	if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
+		return 0;
+	return hapd->driver->set_frag(hapd->driver, frag);
+}
+
+static inline int
+hostapd_get_frag(struct hostapd_data *hapd, int *frag)
+{
+	if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
+		return 0;
+	return hapd->driver->get_frag(hapd->driver, frag);
+}
+
+static inline int
+hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
+{
+	if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
+		return 0;
+	return hapd->driver->set_retry(hapd->driver, short_retry, long_retry);
+}
+
+static inline int
+hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
+{
+	if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
+		return 0;
+	return hapd->driver->get_retry(hapd->driver, short_retry, long_retry);
+}
+
+static inline int
+hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+		      int flags_or, int flags_and)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+		return 0;
+	return hapd->driver->sta_set_flags(hapd->driver, addr, flags_or,
+					   flags_and);
+}
+
+static inline int
+hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
+		      int *basic_rates, int mode)
+{
+	if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
+		return 0;
+	return hapd->driver->set_rate_sets(hapd->driver, supp_rates,
+					   basic_rates, mode);
+}
+
+static inline int
+hostapd_set_channel_flag(struct hostapd_data *hapd, int mode, int chan,
+			 int flag, unsigned char power_level,
+			 unsigned char antenna_max)
+{
+	if (hapd->driver == NULL || hapd->driver->set_channel_flag == NULL)
+		return 0;
+	return hapd->driver->set_channel_flag(hapd->driver, mode, chan, flag,
+					      power_level, antenna_max);
+}
+
+static inline int
+hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_regulatory_domain == NULL)
+		return 0;
+	return hapd->driver->set_regulatory_domain(hapd->driver, rd);
+}
+
+static inline int
+hostapd_set_country(struct hostapd_data *hapd, const char *country)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_country == NULL)
+		return 0;
+	return hapd->driver->set_country(hapd->driver, country);
+}
+
+static inline int
+hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_ieee80211d == NULL)
+		return 0;
+	return hapd->driver->set_ieee80211d(hapd->driver, enabled);
+}
 
 void driver_register(const char *name, const struct driver_ops *ops);
 void driver_unregister(const char *name);
 const struct driver_ops *driver_lookup(const char *name);
 
 static inline int
-hostapd_sta_clear_stats(struct hostapd_data *hapd, u8 *addr)
+hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
 {
 	if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
 		return 0;
 	return hapd->driver->sta_clear_stats(hapd->driver, addr);
 }
 
+static inline int
+hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
+		   u8 *head, size_t head_len,
+		   u8 *tail, size_t tail_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+		return 0;
+	return hapd->driver->set_beacon(ifname, hapd->driver, head, head_len,
+					tail, tail_len);
+}
+
+static inline int
+hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
+		return 0;
+	return hapd->driver->set_internal_bridge(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
+		return 0;
+	return hapd->driver->set_beacon_int(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
+		return 0;
+	return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->driver,
+					     value);
+}
+
+static inline int
+hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
+		return 0;
+	return hapd->driver->set_broadcast_ssid(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
+		return 0;
+	return hapd->driver->set_cts_protect(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_key_tx_rx_threshold == NULL)
+		return 0;
+	return hapd->driver->set_key_tx_rx_threshold(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_preamble(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
+		return 0;
+	return hapd->driver->set_preamble(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
+{
+	if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
+		return 0;
+	return hapd->driver->set_short_slot_time(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+			    int cw_min, int cw_max, int burst_time)
+{
+	if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
+		return 0;
+	return hapd->driver->set_tx_queue_params(hapd->driver, queue, aifs,
+						 cw_min, cw_max, burst_time);
+}
+
+static inline int
+hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
+{
+	if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
+		return 0;
+	return hapd->driver->bss_add(hapd->driver, ifname, bssid);
+}
+
+static inline int
+hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
+{
+	if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
+		return 0;
+	return hapd->driver->bss_remove(hapd->driver, ifname);
+}
+
+static inline int
+hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
+		       const u8 *mask)
+{
+	if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
+		return 1;
+	return hapd->driver->valid_bss_mask(hapd->driver, addr, mask);
+}
+
+static inline int
+hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+	       char *ifname, const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+		return -1;
+	return hapd->driver->if_add(hapd->conf->iface, hapd->driver, type,
+				    ifname, addr);
+}
+
+static inline int
+hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+		  char *ifname, const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->if_update == NULL)
+		return -1;
+	return hapd->driver->if_update(hapd->driver, type, ifname, addr);
+}
+
+static inline int
+hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+		  char *ifname, const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+		return -1;
+	return hapd->driver->if_remove(hapd->driver, type, ifname, addr);
+}
+
+static inline int
+hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
+		     int interval, int _listen, int *channel,
+		     int *last_rx)
+{
+	if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
+		return -1;
+	return hapd->driver->passive_scan(hapd->driver, now, our_mode_only,
+					  interval, _listen, channel, last_rx);
+}
+
+static inline struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+			    u16 *flags)
+{
+	if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
+		return NULL;
+	return hapd->driver->get_hw_feature_data(hapd->driver, num_modes,
+						 flags);
+}
+
+static inline int
+hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
+		     const u8 *addr, int vlan_id)
+{
+	if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+		return 0;
+	return hapd->driver->set_sta_vlan(hapd->driver, addr, ifname, vlan_id);
+}
+
+static inline int
+hostapd_driver_commit(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->commit == NULL)
+		return 0;
+	return hapd->driver->commit(hapd->driver);
+}
+
 #endif /* DRIVER_H */
--- /dev/null
+++ contrib/hostapd/preauth.c
@@ -0,0 +1,276 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2006, 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"
+
+#ifdef CONFIG_RSN_PREAUTH
+
+#include "hostapd.h"
+#include "l2_packet.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "wpa_common.h"
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "preauth.h"
+
+#ifndef ETH_P_PREAUTH
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+#endif /* ETH_P_PREAUTH */
+
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_preauth_interface {
+	struct rsn_preauth_interface *next;
+	struct hostapd_data *hapd;
+	struct l2_packet_data *l2;
+	char *ifname;
+	int ifindex;
+};
+
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+				const u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface = ctx;
+	struct hostapd_data *hapd = piface->hapd;
+	struct ieee802_1x_hdr *hdr;
+	struct sta_info *sta;
+	struct l2_ethhdr *ethhdr;
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: receive pre-auth packet "
+		      "from interface '%s'\n", piface->ifname);
+	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: too short pre-auth "
+			      "packet (len=%lu)\n", (unsigned long) len);
+		return;
+	}
+
+	ethhdr = (struct l2_ethhdr *) buf;
+	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
+
+	if (memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for "
+			      "foreign address " MACSTR "\n",
+			      MAC2STR(ethhdr->h_dest));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, ethhdr->h_source);
+	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for "
+			      "already association STA " MACSTR "\n",
+			      MAC2STR(sta->addr));
+		return;
+	}
+	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
+		sta = ap_sta_add(hapd, ethhdr->h_source);
+		if (sta == NULL)
+			return;
+		sta->flags = WLAN_STA_PREAUTH;
+
+		ieee802_1x_new_station(hapd, sta);
+		if (sta->eapol_sm == NULL) {
+			ap_free_sta(hapd, sta);
+			sta = NULL;
+		} else {
+			sta->eapol_sm->radius_identifier = -1;
+			sta->eapol_sm->portValid = TRUE;
+			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
+		}
+	}
+	if (sta == NULL)
+		return;
+	sta->preauth_iface = piface;
+	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
+			   len - sizeof(*ethhdr));
+}
+
+
+static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
+{
+	struct rsn_preauth_interface *piface;
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN pre-auth interface '%s'\n",
+		      ifname);
+
+	piface = wpa_zalloc(sizeof(*piface));
+	if (piface == NULL)
+		return -1;
+	piface->hapd = hapd;
+
+	piface->ifname = strdup(ifname);
+	if (piface->ifname == NULL) {
+		goto fail1;
+	}
+
+	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
+				    rsn_preauth_receive, piface, 1);
+	if (piface->l2 == NULL) {
+		printf("Failed to open register layer 2 access to "
+		       "ETH_P_PREAUTH\n");
+		goto fail2;
+	}
+
+	piface->next = hapd->preauth_iface;
+	hapd->preauth_iface = piface;
+	return 0;
+
+fail2:
+	free(piface->ifname);
+fail1:
+	free(piface);
+	return -1;
+}
+
+
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+	struct rsn_preauth_interface *piface, *prev;
+
+	piface = hapd->preauth_iface;
+	hapd->preauth_iface = NULL;
+	while (piface) {
+		prev = piface;
+		piface = piface->next;
+		l2_packet_deinit(prev->l2);
+		free(prev->ifname);
+		free(prev);
+	}
+}
+
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	char *tmp, *start, *end;
+
+	if (hapd->conf->rsn_preauth_interfaces == NULL)
+		return 0;
+
+	tmp = strdup(hapd->conf->rsn_preauth_interfaces);
+	if (tmp == NULL)
+		return -1;
+	start = tmp;
+	for (;;) {
+		while (*start == ' ')
+			start++;
+		if (*start == '\0')
+			break;
+		end = strchr(start, ' ');
+		if (end)
+			*end = '\0';
+
+		if (rsn_preauth_iface_add(hapd, start)) {
+			rsn_preauth_iface_deinit(hapd);
+			return -1;
+		}
+
+		if (end)
+			start = end + 1;
+		else
+			break;
+	}
+	free(tmp);
+	return 0;
+}
+
+
+static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
+		   MACSTR, MAC2STR(sta->addr));
+	ap_free_sta(hapd, sta);
+}
+
+
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success)
+{
+	u8 *key;
+	size_t len;
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
+		       success ? "succeeded" : "failed");
+
+	key = ieee802_1x_get_key_crypt(sta->eapol_sm, &len);
+	if (success && key) {
+		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
+					       sta->addr,
+					       dot11RSNAConfigPMKLifetime,
+					       sta->eapol_sm) == 0) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "added PMKSA cache entry (pre-auth)");
+		} else {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "failed to add PMKSA cache entry "
+				       "(pre-auth)");
+		}
+	}
+
+	/*
+	 * Finish STA entry removal from timeout in order to avoid freeing
+	 * STA data before the caller has finished processing.
+	 */
+	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
+}
+
+
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface;
+	struct l2_ethhdr *ethhdr;
+
+	piface = hapd->preauth_iface;
+	while (piface) {
+		if (piface == sta->preauth_iface)
+			break;
+		piface = piface->next;
+	}
+
+	if (piface == NULL) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: Could not find "
+			      "pre-authentication interface for " MACSTR "\n",
+			      MAC2STR(sta->addr));
+		return;
+	}
+
+	ethhdr = malloc(sizeof(*ethhdr) + len);
+	if (ethhdr == NULL)
+		return;
+
+	memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
+	memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
+	ethhdr->h_proto = htons(ETH_P_PREAUTH);
+	memcpy(ethhdr + 1, buf, len);
+
+	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
+			   sizeof(*ethhdr) + len) < 0) {
+		printf("Failed to send preauth packet using l2_packet_send\n");
+	}
+	free(ethhdr);
+}
+
+
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
+}
+
+#endif /* CONFIG_RSN_PREAUTH */
Index: ieee802_11.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_11.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ieee802_11.c -L contrib/hostapd/ieee802_11.c -u -r1.2 -r1.3
--- contrib/hostapd/ieee802_11.c
+++ contrib/hostapd/ieee802_11.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / IEEE 802.11 Management
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2006, 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
@@ -13,18 +12,17 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/socket.h>
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
 #include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <time.h>
 
 #include "eloop.h"
 #include "hostapd.h"
 #include "ieee802_11.h"
+#include "beacon.h"
+#include "hw_features.h"
 #include "radius.h"
 #include "radius_client.h"
 #include "ieee802_11_auth.h"
@@ -33,39 +31,206 @@
 #include "rc4.h"
 #include "ieee802_1x.h"
 #include "wpa.h"
+#include "wme.h"
+#include "ap_list.h"
 #include "accounting.h"
 #include "driver.h"
-#include "hostap_common.h"
+#include "ieee802_11h.h"
+#include "mlme.h"
 
 
-static u8 * hostapd_eid_supp_rates(hostapd *hapd, u8 *eid)
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
 {
 	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
 
 	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = 4; /* len */
-	*pos++ = 0x82; /* 1 Mbps, base set */
-	*pos++ = 0x84; /* 2 Mbps, base set */
-	*pos++ = 0x0b; /* 5.5 Mbps */
-	*pos++ = 0x16; /* 11 Mbps */
+	num = hapd->iface->num_rates;
+	if (num > 8) {
+		/* rest of the rates are encoded in Extended supported
+		 * rates element */
+		num = 8;
+	}
+
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
+	     i++) {
+		count++;
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
+
+	num = hapd->iface->num_rates;
+	if (num <= 8)
+		return eid;
+	num -= 8;
+
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
+	     i++) {
+		count++;
+		if (count <= 8)
+			continue; /* already in SuppRates IE */
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
 
 	return pos;
 }
 
 
-static u16 hostapd_own_capab_info(hostapd *hapd)
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe)
 {
 	int capab = WLAN_CAPABILITY_ESS;
-	if (hapd->conf->wpa ||
-	    (hapd->conf->ieee802_1x &&
-	     (hapd->conf->default_wep_key_len ||
-	      hapd->conf->individual_wep_key_len)))
+	int privacy;
+
+	if (hapd->iface->num_sta_no_short_preamble == 0 &&
+	    hapd->iconf->preamble == SHORT_PREAMBLE)
+		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+	privacy = hapd->conf->ssid.wep.keys_set;
+
+	if (hapd->conf->ieee802_1x &&
+	    (hapd->conf->default_wep_key_len ||
+	     hapd->conf->individual_wep_key_len))
+		privacy = 1;
+
+	if (hapd->conf->wpa)
+		privacy = 1;
+
+	if (sta) {
+		int policy, def_klen;
+		if (probe && sta->ssid_probe) {
+			policy = sta->ssid_probe->security_policy;
+			def_klen = sta->ssid_probe->wep.default_len;
+		} else {
+			policy = sta->ssid->security_policy;
+			def_klen = sta->ssid->wep.default_len;
+		}
+		privacy = policy != SECURITY_PLAINTEXT;
+		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
+			privacy = 0;
+	}
+
+	if (privacy)
 		capab |= WLAN_CAPABILITY_PRIVACY;
+
+	if (hapd->iface && hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    hapd->iface->num_sta_no_short_slot_time == 0)
+		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+	if (hapd->iface->dfs_enable) 
+		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
+
 	return capab;
 }
 
 
-static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+				* 00:50:F2 */
+
+static int ieee802_11_parse_vendor_specific(struct hostapd_data *hapd,
+					    u8 *pos, size_t elen,
+					    struct ieee802_11_elems *elems,
+					    int show_errors)
+{
+	unsigned int oui;
+
+	/* first 3 bytes in vendor specific information element are the IEEE
+	 * OUI of the vendor. The following byte is used a vendor specific
+	 * sub-type. */
+	if (elen < 4) {
+		if (show_errors) {
+			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS, "short vendor "
+				      "specific information element ignored "
+				      "(len=%lu)\n", (unsigned long) elen);
+		}
+		return -1;
+	}
+
+	oui = (pos[0] << 16) | (pos[1] << 8) | pos[2];
+	switch (oui) {
+	case OUI_MICROSOFT:
+		/* Microsoft/Wi-Fi information elements are further typed and
+		 * subtyped */
+		switch (pos[3]) {
+		case 1:
+			/* Microsoft OUI (00:50:F2) with OUI Type 1:
+			 * real WPA information element */
+			elems->wpa_ie = pos;
+			elems->wpa_ie_len = elen;
+			break;
+		case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
+			if (elen < 5) {
+				HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+					      "short WME information element "
+					      "ignored (len=%lu)\n",
+					      (unsigned long) elen);
+				return -1;
+			}
+			switch (pos[4]) {
+			case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
+			case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
+				elems->wme = pos;
+				elems->wme_len = elen;
+				break;
+			case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
+				elems->wme_tspec = pos;
+				elems->wme_tspec_len = elen;
+				break;
+			default:
+				HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+					      "unknown WME information element"
+					      " ignored (subtype=%d "
+					      "len=%lu)\n",
+					      pos[4], (unsigned long) elen);
+				return -1;
+			}
+			break;
+		default:
+			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+				      "Unknown Microsoft information element "
+				      "ignored (type=%d len=%lu)\n",
+				      pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	default:
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+			      "unknown vendor specific information element "
+			      "ignored (vendor OUI %02x:%02x:%02x len=%lu)\n",
+			      pos[0], pos[1], pos[2], (unsigned long) elen);
+		return -1;
+	}
+
+	return 0;
+}
+
 
 ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
 				size_t len,
@@ -92,8 +257,7 @@
 					      "failed (id=%d elen=%d "
 					      "left=%lu)\n",
 					      id, elen, (unsigned long) left);
-				if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL))
-					hostapd_hexdump("IEs", start, len);
+				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
 			}
 			return ParseFailed;
 		}
@@ -131,30 +295,32 @@
 			elems->challenge = pos;
 			elems->challenge_len = elen;
 			break;
-		case WLAN_EID_GENERIC:
-			if (elen > 4 && memcmp(pos, WPA_OUI_TYPE, 4) == 0) {
-				elems->wpa_ie = pos;
-				elems->wpa_ie_len = elen;
-			} else if (show_errors) {
-				HOSTAPD_DEBUG(HOSTAPD_DEBUG_EXCESSIVE,
-					      "IEEE 802.11 element parse "
-					      "ignored unknown generic element"
-					      " (id=%d elen=%d OUI:type="
-					      "%02x-%02x-%02x:%d)\n",
-					      id, elen,
-					      elen >= 1 ? pos[0] : 0,
-					      elen >= 2 ? pos[1] : 0,
-					      elen >= 3 ? pos[2] : 0,
-					      elen >= 4 ? pos[3] : 0);
-				unknown++;
-			} else {
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (ieee802_11_parse_vendor_specific(hapd, pos, elen,
+							     elems,
+							     show_errors))
 				unknown++;
-			}
 			break;
 		case WLAN_EID_RSN:
 			elems->rsn_ie = pos;
 			elems->rsn_ie_len = elen;
 			break;
+		case WLAN_EID_PWR_CAPABILITY:
+			elems->power_cap = pos;
+			elems->power_cap_len = elen;
+			break;
+		case WLAN_EID_SUPPORTED_CHANNELS:
+			elems->supp_channels = pos;
+			elems->supp_channels_len = elen;
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -177,7 +343,7 @@
 }
 
 
-static void ieee802_11_print_ssid(const u8 *ssid, u8 len)
+void ieee802_11_print_ssid(const u8 *ssid, u8 len)
 {
 	int i;
 	for (i = 0; i < len; i++) {
@@ -189,9 +355,31 @@
 }
 
 
+void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason)
+{
+	struct ieee80211_mgmt mgmt;
+	char buf[30];
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "deauthenticate - reason %d", reason);
+	snprintf(buf, sizeof(buf), "SEND-DEAUTHENTICATE %d", reason);
+	memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_DEAUTH);
+	memcpy(mgmt.da, addr, ETH_ALEN);
+	memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+	memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+	mgmt.u.deauth.reason_code = host_to_le16(reason);
+	if (hostapd_send_mgmt_frame(hapd, &mgmt, IEEE80211_HDRLEN +
+				    sizeof(mgmt.u.deauth), 0) < 0)
+		perror("ieee802_11_send_deauth: send");
+}
+
+
 static void ieee802_11_sta_authenticate(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	struct ieee80211_mgmt mgmt;
 
 	if (hapd->assoc_ap_state == WAIT_BEACON)
@@ -227,7 +415,7 @@
 
 static void ieee802_11_sta_associate(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	u8 buf[256];
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf;
 	u8 *p;
@@ -261,6 +449,7 @@
 	p += hapd->assoc_ap_ssid_len;
 
 	p = hostapd_eid_supp_rates(hapd, p);
+	p = hostapd_eid_ext_supp_rates(hapd, p);
 
 	if (hostapd_send_mgmt_frame(hapd, mgmt, p - (u8 *) mgmt, 0) < 0)
 		perror("ieee802_11_sta_associate: send");
@@ -270,7 +459,7 @@
 }
 
 
-static u16 auth_shared_key(hostapd *hapd, struct sta_info *sta,
+static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
 			   u16 auth_transaction, u8 *challenge, int iswep)
 {
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -284,10 +473,9 @@
 			u8 key[8];
 			time_t now;
 			int r;
-			sta->challenge = malloc(WLAN_AUTH_CHALLENGE_LEN);
-			if (!sta->challenge)
+			sta->challenge = wpa_zalloc(WLAN_AUTH_CHALLENGE_LEN);
+			if (sta->challenge == NULL)
 				return WLAN_STATUS_UNSPECIFIED_FAILURE;
-			memset(sta->challenge, 0, WLAN_AUTH_CHALLENGE_LEN);
 
 			now = time(NULL);
 			r = random();
@@ -320,7 +508,7 @@
 	 * authentication reply. */
 #else
 	sta->flags |= WLAN_STA_AUTH;
-	wpa_sm_event(hapd, sta, WPA_AUTH);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
 #endif
 	free(sta->challenge);
 	sta->challenge = NULL;
@@ -329,7 +517,8 @@
 }
 
 
-static void send_auth_reply(hostapd *hapd, struct ieee80211_mgmt *mgmt,
+static void send_auth_reply(struct hostapd_data *hapd,
+			    struct ieee80211_mgmt *mgmt,
 			    u16 auth_alg, u16 auth_transaction, u16 resp,
 			    u8 *challenge)
 {
@@ -372,7 +561,8 @@
 }
 
 
-static void handle_auth(hostapd *hapd, struct ieee80211_mgmt *mgmt, size_t len)
+static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+			size_t len)
 {
 	u16 auth_alg, auth_transaction, status_code;
 	u16 resp = WLAN_STATUS_SUCCESS;
@@ -381,6 +571,7 @@
 	u16 fc;
 	u8 *challenge = NULL;
 	u32 session_timeout, acct_interim_interval;
+	int vlan_id = 0;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		printf("handle_auth - too short payload (len=%lu)\n",
@@ -454,7 +645,7 @@
 
 	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
 				      &session_timeout,
-				      &acct_interim_interval);
+				      &acct_interim_interval, &vlan_id);
 	if (res == HOSTAPD_ACL_REJECT) {
 		printf("Station " MACSTR " not allowed to authenticate.\n",
 		       MAC2STR(mgmt->sa));
@@ -476,6 +667,22 @@
 		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 		goto fail;
 	}
+
+	if (vlan_id > 0) {
+		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       sta->vlan_id) == NULL) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
+				       "%d received from RADIUS server",
+				       vlan_id);
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		sta->vlan_id = vlan_id;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+	}
+
 	sta->flags &= ~WLAN_STA_PREAUTH;
 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
@@ -497,12 +704,16 @@
 		 * authentication reply. */
 #else
 		sta->flags |= WLAN_STA_AUTH;
-		wpa_sm_event(hapd, sta, WPA_AUTH);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+		sta->auth_alg = WLAN_AUTH_OPEN;
+		mlme_authenticate_indication(hapd, sta);
 #endif
 		break;
 	case WLAN_AUTH_SHARED_KEY:
 		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
 				       fc & WLAN_FC_ISWEP);
+		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
+		mlme_authenticate_indication(hapd, sta);
 		break;
 	}
 
@@ -512,8 +723,8 @@
 }
 
 
-static void handle_assoc(hostapd *hapd, struct ieee80211_mgmt *mgmt,
-			 size_t len, int reassoc)
+static void handle_assoc(struct hostapd_data *hapd,
+			 struct ieee80211_mgmt *mgmt, size_t len, int reassoc)
 {
 	u16 capab_info, listen_interval;
 	u16 resp = WLAN_STATUS_SUCCESS;
@@ -572,6 +783,11 @@
 		goto fail;
 	}
 
+	if (reassoc) {
+		memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
+		       ETH_ALEN);
+	}
+
 	sta->capability = capab_info;
 
 	/* followed by SSID and Supported rates */
@@ -583,8 +799,8 @@
 		goto fail;
 	}
 
-	if (elems.ssid_len != hapd->conf->ssid_len ||
-	    memcmp(elems.ssid, hapd->conf->ssid, elems.ssid_len) != 0) {
+	if (elems.ssid_len != hapd->conf->ssid.ssid_len ||
+	    memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) != 0) {
 		printf("Station " MACSTR " tried to associate with "
 		       "unknown SSID '", MAC2STR(sta->addr));
 		ieee802_11_print_ssid(elems.ssid, elems.ssid_len);
@@ -593,32 +809,56 @@
 		goto fail;
 	}
 
-	if (elems.supp_rates) {
-		if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
-			printf("STA " MACSTR ": Invalid supported rates "
-			       "element length %d\n", MAC2STR(sta->addr),
+	sta->flags &= ~WLAN_STA_WME;
+	if (elems.wme && hapd->conf->wme_enabled) {
+		if (hostapd_eid_wme_valid(hapd, elems.wme, elems.wme_len))
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "invalid WME element in association "
+				       "request");
+		else
+			sta->flags |= WLAN_STA_WME;
+	}
+
+	if (!elems.supp_rates) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "No supported rates element in AssocReq");
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	if (elems.supp_rates_len > sizeof(sta->supported_rates)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Invalid supported rates element length %d",
 			       elems.supp_rates_len);
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
+	memcpy(sta->supported_rates, elems.supp_rates, elems.supp_rates_len);
+	sta->supported_rates_len = elems.supp_rates_len;
+
+	if (elems.ext_supp_rates) {
+		if (elems.supp_rates_len + elems.ext_supp_rates_len >
+		    sizeof(sta->supported_rates)) {
+			hostapd_logger(hapd, mgmt->sa,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Invalid supported rates element length"
+				       " %d+%d", elems.supp_rates_len,
+				       elems.ext_supp_rates_len);
 			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
 			goto fail;
 		}
 
-		memset(sta->supported_rates, 0, sizeof(sta->supported_rates));
-		memcpy(sta->supported_rates, elems.supp_rates,
-		       elems.supp_rates_len);
-
-		sta->tx_supp_rates = 0;
-		for (i = 0; i < elems.supp_rates_len; i++) {
-			if ((sta->supported_rates[i] & 0x7f) == 2)
-				sta->tx_supp_rates |= WLAN_RATE_1M;
-			if ((sta->supported_rates[i] & 0x7f) == 4)
-				sta->tx_supp_rates |= WLAN_RATE_2M;
-			if ((sta->supported_rates[i] & 0x7f) == 11)
-				sta->tx_supp_rates |= WLAN_RATE_5M5;
-			if ((sta->supported_rates[i] & 0x7f) == 22)
-				sta->tx_supp_rates |= WLAN_RATE_11M;
-		}
-	} else
-		sta->tx_supp_rates = 0xff;
+		memcpy(sta->supported_rates + elems.supp_rates_len,
+		       elems.ext_supp_rates, elems.ext_supp_rates_len);
+		sta->supported_rates_len += elems.ext_supp_rates_len;
+	}
 
 	if ((hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) && elems.rsn_ie) {
 		wpa_ie = elems.rsn_ie;
@@ -642,28 +882,87 @@
 		int res;
 		wpa_ie -= 2;
 		wpa_ie_len += 2;
-		res = wpa_validate_wpa_ie(hapd, sta, wpa_ie, wpa_ie_len,
-					  elems.rsn_ie ?
-					  HOSTAPD_WPA_VERSION_WPA2 :
-					  HOSTAPD_WPA_VERSION_WPA);
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			printf("Failed to initialize WPA state machine\n");
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  wpa_ie, wpa_ie_len);
 		if (res == WPA_INVALID_GROUP)
 			resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
 		else if (res == WPA_INVALID_PAIRWISE)
 			resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
 		else if (res == WPA_INVALID_AKMP)
 			resp = WLAN_STATUS_AKMP_NOT_VALID;
+		else if (res == WPA_ALLOC_FAIL)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+		else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */
+		else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE; /* FIX */
+#endif /* CONFIG_IEEE80211W */
 		else if (res != WPA_IE_OK)
 			resp = WLAN_STATUS_INVALID_IE;
 		if (resp != WLAN_STATUS_SUCCESS)
 			goto fail;
-		free(sta->wpa_ie);
-		sta->wpa_ie = malloc(wpa_ie_len);
-		if (sta->wpa_ie == NULL) {
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (hapd->iface->dfs_enable &&
+	    hapd->iconf->ieee80211h == SPECT_STRICT_BINDING) {
+		if (hostapd_check_power_cap(hapd, elems.power_cap,
+					    elems.power_cap_len)) {
+			resp = WLAN_STATUS_PWR_CAPABILITY_NOT_VALID;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Power capabilities of the station not "
+				       "acceptable");
 			goto fail;
 		}
-		sta->wpa_ie_len = wpa_ie_len;
-		memcpy(sta->wpa_ie, wpa_ie, wpa_ie_len);
+	}
+
+	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		sta->flags |= WLAN_STA_NONERP;
+	for (i = 0; i < sta->supported_rates_len; i++) {
+		if ((sta->supported_rates[i] & 0x7f) > 22) {
+			sta->flags &= ~WLAN_STA_NONERP;
+			break;
+		}
+	}
+	if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
+		sta->nonerp_set = 1;
+		hapd->iface->num_sta_non_erp++;
+		if (hapd->iface->num_sta_non_erp == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
+	    !sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 1;
+		hapd->iface->num_sta_no_short_slot_time++;
+		if (hapd->iface->current_mode->mode ==
+		    HOSTAPD_MODE_IEEE80211G &&
+		    hapd->iface->num_sta_no_short_slot_time == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+	else
+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    !sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 1;
+		hapd->iface->num_sta_no_short_preamble++;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 1)
+			ieee802_11_set_beacons(hapd->iface);
 	}
 
 	/* get a unique AID */
@@ -723,12 +1022,16 @@
 		u8 *p;
 		send_len += sizeof(mgmt->u.assoc_resp);
 		mgmt->u.assoc_resp.capab_info =
-			host_to_le16(hostapd_own_capab_info(hapd));
+			host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
 		mgmt->u.assoc_resp.status_code = host_to_le16(resp);
 		mgmt->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
 						      | BIT(14) | BIT(15));
 		/* Supported rates */
 		p = hostapd_eid_supp_rates(hapd, mgmt->u.assoc_resp.variable);
+		/* Extended supported rates */
+		p = hostapd_eid_ext_supp_rates(hapd, p);
+		if (sta->flags & WLAN_STA_WME)
+			p = hostapd_eid_wme(hapd, p);
 		send_len += p - mgmt->u.assoc_resp.variable;
 
 		/* Request TX callback */
@@ -740,8 +1043,8 @@
 }
 
 
-static void handle_assoc_resp(hostapd *hapd, struct ieee80211_mgmt *mgmt,
-			      size_t len)
+static void handle_assoc_resp(struct hostapd_data *hapd,
+			      struct ieee80211_mgmt *mgmt, size_t len)
 {
 	u16 status_code, aid;
 
@@ -791,8 +1094,8 @@
 }
 
 
-static void handle_disassoc(hostapd *hapd, struct ieee80211_mgmt *mgmt,
-			    size_t len)
+static void handle_disassoc(struct hostapd_data *hapd,
+			    struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct sta_info *sta;
 
@@ -828,11 +1131,11 @@
 	}
 
 	sta->flags &= ~WLAN_STA_ASSOC;
-	wpa_sm_event(hapd, sta, WPA_DISASSOC);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "disassociated");
 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-	ieee802_1x_set_port_enabled(hapd, sta, 0);
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 	/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
 	 * authenticated. */
 	accounting_sta_stop(hapd, sta);
@@ -846,11 +1149,14 @@
 		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
 				       hapd, sta);
 	}
+
+	mlme_disassociate_indication(
+		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
 }
 
 
-static void handle_deauth(hostapd *hapd, struct ieee80211_mgmt *mgmt,
-			  size_t len)
+static void handle_deauth(struct hostapd_data *hapd,
+			  struct ieee80211_mgmt *mgmt, size_t len)
 {
 	struct sta_info *sta;
 
@@ -885,17 +1191,20 @@
 	}
 
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_sm_event(hapd, sta, WPA_DEAUTH);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+	mlme_deauthenticate_indication(
+		hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-	ieee802_1x_set_port_enabled(hapd, sta, 0);
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 	ap_free_sta(hapd, sta);
 }
 
 
-static void handle_beacon(hostapd *hapd, struct ieee80211_mgmt *mgmt,
-			  size_t len)
+static void handle_beacon(struct hostapd_data *hapd,
+			  struct ieee80211_mgmt *mgmt, size_t len,
+			  struct hostapd_frame_info *fi)
 {
 	struct ieee802_11_elems elems;
 
@@ -921,6 +1230,8 @@
 		ieee802_11_sta_authenticate(hapd, NULL);
 	}
 
+	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
+
 	if (!HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_EXCESSIVE))
 		return;
 
@@ -936,17 +1247,79 @@
 }
 
 
-void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype)
+static void handle_action(struct hostapd_data *hapd,
+			  struct ieee80211_mgmt *mgmt, size_t len)
+{
+	if (len < IEEE80211_HDRLEN + 1) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "handle_action - too short payload (len=%lu)",
+			       (unsigned long) len);
+		return;
+	}
+
+	switch (mgmt->u.action.category) {
+	case WME_ACTION_CATEGORY:
+		hostapd_wme_action(hapd, mgmt, len);
+		return;
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "handle_action - unknown action category %d",
+		       mgmt->u.action.category);
+	if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
+	    !(mgmt->sa[0] & 0x01)) {
+		/*
+		 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
+		 * Return the Action frame to the source without change
+		 * except that MSB of the Category set to 1.
+		 */
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
+			   "frame back to sender");
+		os_memcpy(mgmt->da, mgmt->sa, ETH_ALEN);
+		os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+		mgmt->u.action.category |= 0x80;
+
+		hostapd_send_mgmt_frame(hapd, mgmt, len, 0);
+	}
+}
+
+
+/**
+ * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
+ * @hapd: hostapd BSS data structure (the BSS to which the management frame was
+ * sent to)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ *
+ * Process all incoming IEEE 802.11 management frames. This will be called for
+ * each frame received from the kernel driver through wlan#ap interface. In
+ * addition, it can be called to re-inserted pending frames (e.g., when using
+ * external RADIUS server as an MAC ACL).
+ */
+void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len, u16 stype,
+		     struct hostapd_frame_info *fi)
 {
 	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) buf;
+	int broadcast;
 
 	if (stype == WLAN_FC_STYPE_BEACON) {
 		HOSTAPD_DEBUG(HOSTAPD_DEBUG_EXCESSIVE, "mgmt::beacon\n");
-		handle_beacon(hapd, mgmt, len);
+		handle_beacon(hapd, mgmt, len, fi);
 		return;
 	}
 
-	if (memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0 &&
+	if (fi && fi->passive_scan)
+		return;
+
+	broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
+		mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
+		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
+
+	if (!broadcast && memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0 &&
 	    (hapd->assoc_ap_state == DO_NOT_ASSOC ||
 	     memcmp(mgmt->bssid, hapd->conf->assoc_ap_addr, ETH_ALEN) != 0)) {
 		printf("MGMT: BSSID=" MACSTR " not our address\n",
@@ -956,13 +1329,16 @@
 
 
 	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
-		printf("mgmt::probe_req\n");
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS, "mgmt::probe_req\n");
+		handle_probe_req(hapd, mgmt, len);
 		return;
 	}
 
 	if (memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
-		printf("MGMT: DA=" MACSTR " not our address\n",
-		       MAC2STR(mgmt->da));
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "MGMT: DA=" MACSTR " not our address",
+			       MAC2STR(mgmt->da));
 		return;
 	}
 
@@ -991,14 +1367,21 @@
 		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::deauth\n");
 		handle_deauth(hapd, mgmt, len);
 		break;
+	case WLAN_FC_STYPE_ACTION:
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::action\n");
+		handle_action(hapd, mgmt, len);
+		break;
 	default:
-		printf("unknown mgmt frame subtype %d\n", stype);
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "unknown mgmt frame subtype %d", stype);
 		break;
 	}
 }
 
 
-static void handle_auth_cb(hostapd *hapd, struct ieee80211_mgmt *mgmt,
+static void handle_auth_cb(struct hostapd_data *hapd,
+			   struct ieee80211_mgmt *mgmt,
 			   size_t len, int ok)
 {
 	u16 auth_alg, auth_transaction, status_code;
@@ -1038,7 +1421,8 @@
 }
 
 
-static void handle_assoc_cb(hostapd *hapd, struct ieee80211_mgmt *mgmt,
+static void handle_assoc_cb(struct hostapd_data *hapd,
+			    struct ieee80211_mgmt *mgmt,
 			    size_t len, int reassoc, int ok)
 {
 	u16 status;
@@ -1089,12 +1473,39 @@
 		new_assoc = 0;
 	sta->flags |= WLAN_STA_ASSOC;
 
-	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
-			    sta->tx_supp_rates)) {
-		printf("Could not add station to kernel driver.\n");
+	if (reassoc)
+		mlme_reassociate_indication(hapd, sta);
+	else
+		mlme_associate_indication(hapd, sta);
+
+	if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid,
+			    sta->capability, sta->supported_rates,
+			    sta->supported_rates_len, 0)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "Could not add STA to kernel driver");
+	}
+
+	if (sta->eapol_sm == NULL) {
+		/*
+		 * This STA does not use RADIUS server for EAP authentication,
+		 * so bind it to the selected VLAN interface now, since the
+		 * interface selection is not going to change anymore.
+		 */
+		ap_sta_bind_vlan(hapd, sta, 0);
+	} else if (sta->vlan_id) {
+		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
+		ap_sta_bind_vlan(hapd, sta, 0);
+	}
+	if (sta->flags & WLAN_STA_SHORT_PREAMBLE) {
+		hostapd_sta_set_flags(hapd, sta->addr,
+				      WLAN_STA_SHORT_PREAMBLE, ~0);
+	} else {
+		hostapd_sta_set_flags(hapd, sta->addr,
+				      0, ~WLAN_STA_SHORT_PREAMBLE);
 	}
 
-	wpa_sm_event(hapd, sta, WPA_ASSOC);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
 
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
@@ -1128,6 +1539,9 @@
 			      "mgmt::reassoc_resp cb\n");
 		handle_assoc_cb(hapd, mgmt, len, 1, ok);
 		break;
+	case WLAN_FC_STYPE_PROBE_RESP:
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "mgmt::proberesp cb\n");
+		break;
 	default:
 		printf("unknown mgmt cb frame subtype %d\n", stype);
 		break;
@@ -1153,11 +1567,10 @@
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
 
-	if (hapd->wpa_auth)
-		hapd->wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
+	wpa_auth_countermeasures_start(hapd->wpa_auth);
 	hapd->tkip_countermeasures = 1;
 	hostapd_set_countermeasures(hapd, 1);
-	wpa_gtk_rekey(hapd);
+	wpa_gtk_rekey(hapd->wpa_auth);
 	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
 	eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
 			       hapd, NULL);
@@ -1171,7 +1584,7 @@
 }
 
 
-void ieee80211_michael_mic_failure(struct hostapd_data *hapd, u8 *addr,
+void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
 				   int local)
 {
 	time_t now;
@@ -1179,11 +1592,12 @@
 	if (addr && local) {
 		struct sta_info *sta = ap_get_sta(hapd, addr);
 		if (sta != NULL) {
-			sta->dot11RSNAStatsTKIPLocalMICFailures++;
+			wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
 			hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_INFO,
 				       "Michael MIC failure detected in "
 				       "received frame");
+			mlme_michaelmicfailure_indication(hapd, addr);
 		} else {
 			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
 				      "MLME-MICHAELMICFAILURE.indication "
@@ -1218,3 +1632,5 @@
 	/* TODO */
 	return 0;
 }
+
+#endif /* CONFIG_NATIVE_WINDOWS */
Index: ieee802_11_auth.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_11_auth.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/ieee802_11_auth.h -L contrib/hostapd/ieee802_11_auth.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/ieee802_11_auth.h
+++ contrib/hostapd/ieee802_11_auth.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2005, 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 IEEE802_11_AUTH_H
 #define IEEE802_11_AUTH_H
 
@@ -8,9 +22,12 @@
 	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
 };
 
-int hostapd_allowed_address(hostapd *hapd, u8 *addr, u8 *msg, size_t len,
-			    u32 *session_timeout, u32 *acct_interim_interval);
-int hostapd_acl_init(hostapd *hapd);
-void hostapd_acl_deinit(hostapd *hapd);
+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+			    const u8 *msg, size_t len, u32 *session_timeout,
+			    u32 *acct_interim_interval, int *vlan_id);
+int hostapd_acl_init(struct hostapd_data *hapd);
+void hostapd_acl_deinit(struct hostapd_data *hapd);
+int hostapd_acl_reconfig(struct hostapd_data *hapd,
+			 struct hostapd_config *oldconf);
 
 #endif /* IEEE802_11_AUTH_H */
Index: accounting.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/accounting.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/accounting.c -L contrib/hostapd/accounting.c -u -r1.2 -r1.3
--- contrib/hostapd/accounting.c
+++ contrib/hostapd/accounting.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Accounting
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, 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
@@ -13,18 +12,8 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <signal.h>
+#include "includes.h"
 #include <assert.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-
 
 #include "hostapd.h"
 #include "radius.h"
@@ -40,7 +29,13 @@
  * input/output octets and updates Acct-{Input,Output}-Gigawords. */
 #define ACCT_DEFAULT_UPDATE_INTERVAL 300
 
-static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
+/* from ieee802_1x.c */
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+
+static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
+					  struct sta_info *sta,
 					  int status_type)
 {
 	struct radius_msg *msg;
@@ -131,7 +126,7 @@
 	}
 
 	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		 MAC2STR(hapd->own_addr), hapd->conf->ssid);
+		 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
 				 (u8 *) buf, strlen(buf))) {
 		printf("Could not add Called-Station-Id\n");
@@ -154,7 +149,10 @@
 			goto fail;
 		}
 
-		snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+		snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+			 radius_sta_rate(hapd, sta) / 2,
+			 (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+			 radius_mode_txt(hapd));
 		if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
 					 (u8 *) buf, strlen(buf))) {
 			printf("Could not add Connect-Info\n");
@@ -211,7 +209,7 @@
 
 static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
 {
-	hostapd *hapd = eloop_ctx;
+	struct hostapd_data *hapd = eloop_ctx;
 	struct sta_info *sta = timeout_ctx;
 	int interval;
 
@@ -229,11 +227,11 @@
 }
 
 
-void accounting_sta_start(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct radius_msg *msg;
 	int interval;
-	
+
 	if (sta->acct_session_started)
 		return;
 
@@ -260,7 +258,8 @@
 }
 
 
-void accounting_sta_report(hostapd *hapd, struct sta_info *sta, int stop)
+void accounting_sta_report(struct hostapd_data *hapd, struct sta_info *sta,
+			   int stop)
 {
 	struct radius_msg *msg;
 	int cause = sta->acct_terminate_cause;
@@ -360,14 +359,14 @@
 }
 
 
-void accounting_sta_interim(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	if (sta->acct_session_started)
 		accounting_sta_report(hapd, sta, 0);
 }
 
 
-void accounting_sta_stop(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	if (sta->acct_session_started) {
 		accounting_sta_report(hapd, sta, 1);
@@ -435,7 +434,7 @@
 }
 
 
-int accounting_init(hostapd *hapd)
+int accounting_init(struct hostapd_data *hapd)
 {
 	/* Acct-Session-Id should be unique over reboots. If reliable clock is
 	 * not available, this could be replaced with reboot counter, etc. */
@@ -451,7 +450,18 @@
 }
 
 
-void accounting_deinit(hostapd *hapd)
+void accounting_deinit(struct hostapd_data *hapd)
 {
 	accounting_report_state(hapd, 0);
 }
+
+
+int accounting_reconfig(struct hostapd_data *hapd,
+			struct hostapd_config *oldconf)
+{
+	if (!hapd->radius_client_reconfigured)
+		return 0;
+
+	accounting_deinit(hapd);
+	return accounting_init(hapd);
+}
Index: hostapd_cli.1
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd_cli.1,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/hostapd_cli.1 -L contrib/hostapd/hostapd_cli.1 -u -r1.1 -r1.2
--- contrib/hostapd/hostapd_cli.1
+++ contrib/hostapd/hostapd_cli.1
@@ -77,7 +77,7 @@
 .SH SEE ALSO
 .BR hostapd (8).
 .SH AUTHOR
-hostapd_cli was written by Jouni Malinen <jkmaline at cc.hut.fi>. 
+hostapd_cli was written by Jouni Malinen <j at w1.fi>. 
 .PP
 This manual page was written by Faidon Liambotis <faidon at cube.gr>,
 for the Debian project (but may be used by others).
Index: eap_tls_common.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_tls_common.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_tls_common.c -L contrib/hostapd/eap_tls_common.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_tls_common.c
+++ contrib/hostapd/eap_tls_common.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLS/PEAP/TTLS common functions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -71,31 +68,42 @@
 			char *label, size_t len)
 {
 	struct tls_keys keys;
-	u8 *random;
-	u8 *out;
+	u8 *rnd = NULL, *out;
 
-	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-		return NULL;
 	out = malloc(len);
-	random = malloc(keys.client_random_len + keys.server_random_len);
-	if (out == NULL || random == NULL) {
-		free(out);
-		free(random);
+	if (out == NULL)
 		return NULL;
-	}
-	memcpy(random, keys.client_random, keys.client_random_len);
-	memcpy(random + keys.client_random_len, keys.server_random,
+
+	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
+	    0)
+		return out;
+
+	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+		goto fail;
+
+	if (keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.master_key == NULL)
+		goto fail;
+
+	rnd = malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+	memcpy(rnd, keys.client_random, keys.client_random_len);
+	memcpy(rnd + keys.client_random_len, keys.server_random,
 	       keys.server_random_len);
 
 	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, random, keys.client_random_len +
-		    keys.server_random_len, out, len)) {
-		free(random);
-		free(out);
-		return NULL;
-	}
-	free(random);
+		    label, rnd, keys.client_random_len +
+		    keys.server_random_len, out, len))
+		goto fail;
+
+	free(rnd);
 	return out;
+
+fail:
+	free(out);
+	free(rnd);
+	return NULL;
 }
 
 
@@ -105,6 +113,16 @@
 	u8 *buf;
 
 	if (data->tls_in_left > *in_len || data->tls_in) {
+		if (data->tls_in_len + *in_len > 65536) {
+			/* Limit length to avoid rogue peers from causing large
+			 * memory allocations. */
+			free(data->tls_in);
+			data->tls_in = NULL;
+			data->tls_in_len = 0;
+			wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
+				   " over 64 kB)");
+			return -1;
+		}
 		buf = realloc(data->tls_in, data->tls_in_len + *in_len);
 		if (buf == NULL) {
 			free(data->tls_in);
--- /dev/null
+++ contrib/hostapd/beacon.c
@@ -0,0 +1,419 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * 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"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "wpa.h"
+#include "wme.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "sta_info.h"
+#include "ieee802_11h.h"
+
+
+static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
+{
+	u8 erp = 0;
+
+	if (hapd->iface == NULL || hapd->iface->current_mode == NULL ||
+	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return 0;
+
+	switch (hapd->iconf->cts_protection_type) {
+	case CTS_PROTECTION_FORCE_ENABLED:
+		erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
+		break;
+	case CTS_PROTECTION_FORCE_DISABLED:
+		erp = 0;
+		break;
+	case CTS_PROTECTION_AUTOMATIC:
+		if (hapd->iface->olbc)
+			erp |= ERP_INFO_USE_PROTECTION;
+		/* continue */
+	case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
+		if (hapd->iface->num_sta_non_erp > 0) {
+			erp |= ERP_INFO_NON_ERP_PRESENT |
+				ERP_INFO_USE_PROTECTION;
+		}
+		break;
+	}
+	if (hapd->iface->num_sta_no_short_preamble > 0)
+		erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
+
+	return erp;
+}
+
+
+static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
+{
+	*eid++ = WLAN_EID_DS_PARAMS;
+	*eid++ = 1;
+	*eid++ = hapd->iconf->channel;
+	return eid;
+}
+
+
+static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->iface == NULL || hapd->iface->current_mode == NULL ||
+	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return eid;
+
+	/* Set NonERP_present and use_protection bits if there
+	 * are any associated NonERP stations. */
+	/* TODO: use_protection bit can be set to zero even if
+	 * there are NonERP stations present. This optimization
+	 * might be useful if NonERP stations are "quiet".
+	 * See 802.11g/D6 E-1 for recommended practice.
+	 * In addition, Non ERP present might be set, if AP detects Non ERP
+	 * operation on other APs. */
+
+	/* Add ERP Information element */
+	*eid++ = WLAN_EID_ERP_INFO;
+	*eid++ = 1;
+	*eid++ = ieee802_11_erp_info(hapd);
+
+	return eid;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+				int max_len)
+{
+	int left;
+	u8 *pos = eid;
+
+	if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
+	    max_len < 6)
+		return eid;
+
+	*pos++ = WLAN_EID_COUNTRY;
+	pos++; /* length will be set later */
+	memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+	pos += 3;
+	left = max_len - 3;
+
+	if ((pos - eid) & 1) {
+		if (left < 1)
+			return eid;
+		*pos++ = 0; /* pad for 16-bit alignment */
+		left--;
+	}
+
+	eid[1] = (pos - eid) - 2;
+
+	return pos;
+}
+
+
+static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
+
+{
+	if (!hapd->iface->dfs_enable)
+		return eid;
+	*eid++ = WLAN_EID_PWR_CONSTRAINT;
+	*eid++ = 1;
+	*eid++ = hapd->iface->pwr_const;
+	return eid;
+}
+
+
+static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
+
+{
+	if (!hapd->iface->dfs_enable)
+		return eid;
+	*eid++ = WLAN_EID_TPC_REPORT;
+	*eid++ = 2;
+	*eid++ = hapd->iface->tx_power; /* TX POWER */
+	*eid++ = 0; /* Link Margin */
+	return eid;
+}
+
+static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
+
+{
+	if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
+		return eid;
+	*eid++ = WLAN_EID_CHANNEL_SWITCH;
+	*eid++ = 3;
+	*eid++ = CHAN_SWITCH_MODE_QUIET;
+	*eid++ = hapd->iface->channel_switch; /* New channel */
+	/* 0 - very soon; 1 - before next TBTT; num - after num beacons */
+	*eid++ = 0;
+	return eid;
+}
+
+
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
+			    struct sta_info *sta)
+{
+	const u8 *ie;
+	size_t ielen;
+
+	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+	if (ie == NULL || ielen > len)
+		return eid;
+
+	memcpy(eid, ie, ielen);
+	return eid + ielen;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+		      size_t len)
+{
+	struct ieee80211_mgmt *resp;
+	struct ieee802_11_elems elems;
+	char *ssid;
+	u8 *pos, *epos;
+	size_t ssid_len;
+	struct sta_info *sta = NULL;
+
+	if (!hapd->iconf->send_probe_response)
+		return;
+
+	if (ieee802_11_parse_elems(hapd, mgmt->u.probe_req.variable,
+				   len - (IEEE80211_HDRLEN +
+					  sizeof(mgmt->u.probe_req)), &elems,
+				   0)
+	    == ParseFailed) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+			      "Could not parse ProbeReq from " MACSTR "\n",
+			      MAC2STR(mgmt->sa));
+		return;
+	}
+
+	ssid = NULL;
+	ssid_len = 0;
+
+	if ((!elems.ssid || !elems.supp_rates)) {
+		printf("STA " MACSTR " sent probe request without SSID or "
+		       "supported rates element\n", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+			      "Probe Request from " MACSTR " for broadcast "
+			      "SSID ignored\n", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+
+	if (elems.ssid_len == 0 ||
+	    (elems.ssid_len == hapd->conf->ssid.ssid_len &&
+	     memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) {
+		ssid = hapd->conf->ssid.ssid;
+		ssid_len = hapd->conf->ssid.ssid_len;
+		if (sta)
+			sta->ssid_probe = &hapd->conf->ssid;
+	}
+
+	if (!ssid) {
+		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS)) {
+			printf("Probe Request from " MACSTR " for foreign "
+			       "SSID '", MAC2STR(mgmt->sa));
+			ieee802_11_print_ssid(elems.ssid, elems.ssid_len);
+			printf("'\n");
+		}
+		return;
+	}
+
+	/* TODO: verify that supp_rates contains at least one matching rate
+	 * with AP configuration */
+#define MAX_PROBERESP_LEN 512
+	resp = wpa_zalloc(MAX_PROBERESP_LEN);
+	if (resp == NULL)
+		return;
+	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_PROBE_RESP);
+	memcpy(resp->da, mgmt->sa, ETH_ALEN);
+	memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+	memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+	resp->u.probe_resp.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	resp->u.probe_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+	pos = resp->u.probe_resp.variable;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = ssid_len;
+	memcpy(pos, ssid, ssid_len);
+	pos += ssid_len;
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+	pos = hostapd_eid_power_constraint(hapd, pos);
+	pos = hostapd_eid_tpc_report(hapd, pos);
+
+	/* ERP Information element */
+	pos = hostapd_eid_erp_info(hapd, pos);
+
+	/* Extended supported rates */
+	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+	pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+
+	/* Wi-Fi Wireless Multimedia Extensions */
+	if (hapd->conf->wme_enabled)
+		pos = hostapd_eid_wme(hapd, pos);
+
+	if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
+		perror("handle_probe_req: send");
+
+	free(resp);
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS, "STA " MACSTR
+		      " sent probe request for %s SSID\n",
+		      MAC2STR(mgmt->sa), elems.ssid_len == 0 ? "broadcast" :
+		      "our");
+}
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *head;
+	u8 *pos, *tail, *tailpos;
+	int preamble;
+	u16 capab_info;
+	size_t head_len, tail_len;
+	int cts_protection = ((ieee802_11_erp_info(hapd) &
+			      ERP_INFO_USE_PROTECTION) ? 1 : 0);
+
+#define BEACON_HEAD_BUF_SIZE 256
+#define BEACON_TAIL_BUF_SIZE 256
+	head = wpa_zalloc(BEACON_HEAD_BUF_SIZE);
+	tailpos = tail = malloc(BEACON_TAIL_BUF_SIZE);
+	if (head == NULL || tail == NULL) {
+		printf("Failed to set beacon data\n");
+		free(head);
+		free(tail);
+		return;
+	}
+
+	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_BEACON);
+	head->duration = host_to_le16(0);
+	memset(head->da, 0xff, ETH_ALEN);
+
+	memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+	memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+	head->u.beacon.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+	head->u.beacon.capab_info = host_to_le16(capab_info);
+	pos = &head->u.beacon.variable[0];
+
+	/* SSID */
+	*pos++ = WLAN_EID_SSID;
+	if (hapd->conf->ignore_broadcast_ssid == 2) {
+		/* clear the data, but keep the correct length of the SSID */
+		*pos++ = hapd->conf->ssid.ssid_len;
+		memset(pos, 0, hapd->conf->ssid.ssid_len);
+		pos += hapd->conf->ssid.ssid_len;
+	} else if (hapd->conf->ignore_broadcast_ssid) {
+		*pos++ = 0; /* empty SSID */
+	} else {
+		*pos++ = hapd->conf->ssid.ssid_len;
+		memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+		pos += hapd->conf->ssid.ssid_len;
+	}
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	head_len = pos - (u8 *) head;
+
+	tailpos = hostapd_eid_country(hapd, tailpos,
+				      tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
+	tailpos = hostapd_eid_power_constraint(hapd, tailpos);
+	tailpos = hostapd_eid_channel_switch(hapd, tailpos);
+	tailpos = hostapd_eid_tpc_report(hapd, tailpos);
+
+	/* ERP Information element */
+	tailpos = hostapd_eid_erp_info(hapd, tailpos);
+
+	/* Extended supported rates */
+	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
+
+	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
+				  tailpos, NULL);
+
+	/* Wi-Fi Wireless Multimedia Extensions */
+	if (hapd->conf->wme_enabled)
+		tailpos = hostapd_eid_wme(hapd, tailpos);
+
+	tail_len = tailpos > tail ? tailpos - tail : 0;
+
+	if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
+			       tail, tail_len))
+		printf("Failed to set beacon head/tail\n");
+
+	free(tail);
+	free(head);
+
+	if (hostapd_set_cts_protect(hapd, cts_protection))
+		printf("Failed to set CTS protect in kernel driver\n");
+
+	if (hapd->iface && hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    hostapd_set_short_slot_time(hapd,
+					hapd->iface->num_sta_no_short_slot_time
+					> 0 ? 0 : 1))
+		printf("Failed to set Short Slot Time option in kernel "
+		       "driver\n");
+
+	if (hapd->iface && hapd->iface->num_sta_no_short_preamble == 0 &&
+	    hapd->iconf->preamble == SHORT_PREAMBLE)
+		preamble = SHORT_PREAMBLE;
+	else
+		preamble = LONG_PREAMBLE;
+	if (hostapd_set_preamble(hapd, preamble))
+		printf("Could not set preamble for kernel driver\n");
+}
+
+
+void ieee802_11_set_beacons(struct hostapd_iface *iface)
+{
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++)
+		ieee802_11_set_beacon(iface->bss[i]);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
Index: crypto.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/crypto.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/crypto.c -L contrib/hostapd/crypto.c -u -r1.2 -r1.3
--- contrib/hostapd/crypto.c
+++ contrib/hostapd/crypto.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2005, 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,9 +12,8 @@
  * See README and COPYING for more details.
  */
 
-#include <string.h>
-#include <sys/types.h>
-
+#include "includes.h"
+#include <openssl/opensslv.h>
 #include <openssl/md4.h>
 #include <openssl/md5.h>
 #include <openssl/sha.h>
@@ -36,7 +35,7 @@
 void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 	MD4_CTX ctx;
-	int i;
+	size_t i;
 
 	MD4_Init(&ctx);
 	for (i = 0; i < num_elem; i++)
@@ -70,7 +69,7 @@
 void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 	MD5_CTX ctx;
-	int i;
+	size_t i;
 
 	MD5_Init(&ctx);
 	for (i = 0; i < num_elem; i++)
@@ -82,7 +81,7 @@
 void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 	SHA_CTX ctx;
-	int i;
+	size_t i;
 
 	SHA1_Init(&ctx);
 	for (i = 0; i < num_elem; i++)
@@ -91,24 +90,78 @@
 }
 
 
-void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u8 *state, const u8 data[64])
 {
 	SHA_CTX context;
-	memset(&context, 0, sizeof(context));
-	memcpy(&context.h0, state, 5 * 4);
+	os_memset(&context, 0, sizeof(context));
+	os_memcpy(&context.h0, state, 5 * 4);
 	SHA1_Transform(&context, data);
-	memcpy(state, &context.h0, 5 * 4);
+	os_memcpy(state, &context.h0, 5 * 4);
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len > sizeof(xkey))
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	os_memset(xkey + seed_len, 0, 64 - seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			sha1_transform((u8 *) _t, xkey);
+			_t[0] = host_to_be32(_t[0]);
+			_t[1] = host_to_be32(_t[1]);
+			_t[2] = host_to_be32(_t[2]);
+			_t[3] = host_to_be32(_t[3]);
+			_t[4] = host_to_be32(_t[4]);
+			os_memcpy(xpos, _t, 20);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += 20;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
 }
 
 
 void * aes_encrypt_init(const u8 *key, size_t len)
 {
 	AES_KEY *ak;
-	ak = malloc(sizeof(*ak));
+	ak = os_malloc(sizeof(*ak));
 	if (ak == NULL)
 		return NULL;
 	if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
-		free(ak);
+		os_free(ak);
 		return NULL;
 	}
 	return ak;
@@ -123,18 +176,18 @@
 
 void aes_encrypt_deinit(void *ctx)
 {
-	free(ctx);
+	os_free(ctx);
 }
 
 
 void * aes_decrypt_init(const u8 *key, size_t len)
 {
 	AES_KEY *ak;
-	ak = malloc(sizeof(*ak));
+	ak = os_malloc(sizeof(*ak));
 	if (ak == NULL)
 		return NULL;
 	if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
-		free(ak);
+		os_free(ak);
 		return NULL;
 	}
 	return ak;
@@ -149,6 +202,6 @@
 
 void aes_decrypt_deinit(void *ctx)
 {
-	free(ctx);
+	os_free(ctx);
 }
 #endif /* EAP_TLS_FUNCS */
Index: eap_sim_db.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_sim_db.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_sim_db.h -L contrib/hostapd/eap_sim_db.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/eap_sim_db.h
+++ contrib/hostapd/eap_sim_db.h
@@ -1,39 +1,94 @@
+/*
+ * hostapd / EAP-SIM database/authenticator gateway
+ * Copyright (c) 2005-2006, 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_SIM_DB_H
 #define EAP_SIM_DB_H
 
 #ifdef EAP_SIM
 
-/* Initialize EAP-SIM database/authentication gateway interface.
- * Returns pointer to a private data structure. */
-void * eap_sim_db_init(const char *config);
+#include "eap_sim_common.h"
+
+/* Identity prefixes */
+#define EAP_SIM_PERMANENT_PREFIX '1'
+#define EAP_SIM_PSEUDONYM_PREFIX '3'
+#define EAP_SIM_REAUTH_ID_PREFIX '5'
+#define EAP_AKA_PERMANENT_PREFIX '0'
+#define EAP_AKA_PSEUDONYM_PREFIX '2'
+#define EAP_AKA_REAUTH_ID_PREFIX '4'
+
+void * eap_sim_db_init(const char *config,
+		       void (*get_complete_cb)(void *ctx, void *session_ctx),
+		       void *ctx);
 
-/* Deinitialize EAP-SIM database/authentication gateway interface.
- * priv is the pointer from eap_sim_db_init(). */
 void eap_sim_db_deinit(void *priv);
 
-/* Get GSM triplets for user name identity (identity_len bytes). In most cases,
- * the user name is '1' | IMSI, i.e., 1 followed by the IMSI in ASCII format.
- * priv is the pointer from eap_sim_db_init().
- * Returns the number of triplets received (has to be less than or equal to
- * max_chal) or -1 on error (e.g., user not found). rand, kc, and sres are
- * pointers to data areas for the triplets. */
 int eap_sim_db_get_gsm_triplets(void *priv, const u8 *identity,
 				size_t identity_len, int max_chal,
-				u8 *rand, u8 *kc, u8 *sres);
+				u8 *_rand, u8 *kc, u8 *sres,
+				void *cb_session_ctx);
+
+#define EAP_SIM_DB_FAILURE -1
+#define EAP_SIM_DB_PENDING -2
 
-/* Verify whether the given user identity (identity_len bytes) is known. In
- * most cases, the user name is '1' | IMSI, i.e., 1 followed by the IMSI in
- * ASCII format.
- * priv is the pointer from eap_sim_db_init().
- * Returns 0 if the user is found and GSM triplets would be available for it or
- * -1 on error (e.g., user not found or no triplets available). */
 int eap_sim_db_identity_known(void *priv, const u8 *identity,
 			      size_t identity_len);
 
+char * eap_sim_db_get_next_pseudonym(void *priv, int aka);
+
+char * eap_sim_db_get_next_reauth_id(void *priv, int aka);
+
+int eap_sim_db_add_pseudonym(void *priv, const u8 *identity,
+			     size_t identity_len, char *pseudonym);
+
+int eap_sim_db_add_reauth(void *priv, const u8 *identity,
+			  size_t identity_len, char *reauth_id, u16 counter,
+			  const u8 *mk);
+
+const u8 * eap_sim_db_get_permanent(void *priv, const u8 *identity,
+				    size_t identity_len, size_t *len);
+
+struct eap_sim_reauth {
+	struct eap_sim_reauth *next;
+	u8 *identity;
+	size_t identity_len;
+	char *reauth_id;
+	u16 counter;
+	u8 mk[EAP_SIM_MK_LEN];
+};
+
+struct eap_sim_reauth *
+eap_sim_db_get_reauth_entry(void *priv, const u8 *identity,
+			    size_t identity_len);
+
+void eap_sim_db_remove_reauth(void *priv, struct eap_sim_reauth *reauth);
+
+int eap_sim_db_get_aka_auth(void *priv, const u8 *identity,
+			    size_t identity_len, u8 *_rand, u8 *autn, u8 *ik,
+			    u8 *ck, u8 *res, size_t *res_len,
+			    void *cb_session_ctx);
+
+int eap_sim_db_resynchronize(void *priv, const u8 *identity,
+			     size_t identity_len, const u8 *auts,
+			     const u8 *_rand);
+
 #else /* EAP_SIM */
-static inline void * eap_sim_db_init(const char *config)
+static inline void *
+eap_sim_db_init(const char *config,
+		void (*get_complete_cb)(void *ctx, void *session_ctx),
+		void *ctx)
 {
-	return NULL;
+	return (void *) 1;
 }
 
 static inline void eap_sim_db_deinit(void *priv)
--- /dev/null
+++ contrib/hostapd/ieee802_11h.c
@@ -0,0 +1,34 @@
+/*
+ * hostapd / IEEE 802.11h
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * 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 "hostapd.h"
+
+
+int hostapd_check_power_cap(struct hostapd_data *hapd, u8 *power, u8 len)
+{
+	unsigned int max_pwr;
+
+	if (len < 2) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+			      "Too short power capability IE\n");
+		return -1;
+	}
+	max_pwr = power[1];
+	if (max_pwr > hapd->iface->sta_max_power)
+		return -1;
+	return 0;
+}
Index: Makefile
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/Makefile,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/Makefile -L contrib/hostapd/Makefile -u -r1.2 -r1.3
--- contrib/hostapd/Makefile
+++ contrib/hostapd/Makefile
@@ -1,6 +1,5 @@
 CC=gcc
 DIR_WPA_SUPPLICANT=.
-DIR_HOSTAP=.
 
 ifndef CFLAGS
 CFLAGS = -MMD -O2 -Wall -g
@@ -11,18 +10,41 @@
 CFLAGS += -DHOSTAPD_DUMP_STATE
 
 # Include directories for CVS version
-CFLAGS += -I. -I$(DIR_HOSTAP) -I../utils -I$(DIR_WPA_SUPPLICANT)
+CFLAGS += -I. -I../utils -I$(DIR_WPA_SUPPLICANT)
 
 # Uncomment following line and set the path to your kernel tree include
 # directory if your C library does not include all header files.
 # CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
 
-OBJS =	hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.o \
+-include .config
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS =	hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.o md4.o \
 	common.o ieee802_11.o config.o ieee802_11_auth.o accounting.o \
 	sta_info.o radius_client.o sha1.o wpa.o aes_wrap.o ctrl_iface.o \
-	driver_conf.o
+	driver_conf.o os_$(CONFIG_OS).o preauth.o pmksa_cache.o beacon.o \
+	hw_features.o wme.o ap_list.o reconfig.o \
+	mlme.o vlan_init.o ieee802_11h.o
 
--include .config
+HOBJS=hlr_auc_gw.o common.o os_$(CONFIG_OS).o milenage.o aes_wrap.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
 
 ifdef CONFIG_IAPP
 CFLAGS += -DCONFIG_IAPP
@@ -34,6 +56,15 @@
 CONFIG_L2_PACKET=y
 endif
 
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
 ifdef CONFIG_DRIVER_HOSTAP
 CFLAGS += -DCONFIG_DRIVER_HOSTAP
 OBJS += driver.o
@@ -55,6 +86,11 @@
 OBJS += driver_prism54.o
 endif
 
+ifdef CONFIG_DRIVER_DEVICESCAPE
+CFLAGS += -DCONFIG_DRIVER_DEVICESCAPE
+OBJS += driver_devicescape.o
+endif
+
 ifdef CONFIG_DRIVER_BSD
 CFLAGS += -DCONFIG_DRIVER_BSD
 OBJS += driver_bsd.o
@@ -70,7 +106,6 @@
 
 ifdef CONFIG_L2_PACKET
 ifdef CONFIG_DNET_PCAP
-CFLAGS += -DUSE_DNET_PCAP
 ifdef CONFIG_L2_FREEBSD
 LIBS += -lpcap
 OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet_freebsd.o
@@ -122,9 +157,21 @@
 
 ifdef CONFIG_EAP_SIM
 CFLAGS += -DEAP_SIM
-OBJS += eap_sim.o $(DIR_WPA_SUPPLICANT)/eap_sim_common.o
-# Example EAP-SIM interface for GSM authentication. This can be replaced with
-# another file implementating the interface specified in eap_sim_db.h.
+OBJS += eap_sim.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_AKA
+OBJS += eap_aka.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += $(DIR_WPA_SUPPLICANT)/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
 OBJS += eap_sim_db.o
 endif
 
@@ -138,6 +185,25 @@
 OBJS += eap_psk.o $(DIR_WPA_SUPPLICANT)/eap_psk_common.o
 endif
 
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SAKE
+OBJS += eap_sake.o $(DIR_WPA_SUPPLICANT)/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_GPSK
+OBJS += eap_gpsk.o $(DIR_WPA_SUPPLICANT)/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+NEED_SHA256=y
+endif
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += eap_vendor_test.o
+endif
+
 ifdef CONFIG_EAP_TLV
 CFLAGS += -DEAP_TLV
 OBJS += eap_tlv.o
@@ -145,15 +211,34 @@
 
 ifdef CONFIG_EAP
 CFLAGS += -DEAP_SERVER
-OBJS += eap.o eap_identity.o
+OBJS += eap.o eap_methods.o eap_identity.o
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
 endif
 
 ifdef TLS_FUNCS
 # Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
 CFLAGS += -DEAP_TLS_FUNCS
-OBJS += eap_tls_common.o $(DIR_WPA_SUPPLICANT)/tls_openssl.o
+OBJS += eap_tls_common.o
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += $(DIR_WPA_SUPPLICANT)/tls_openssl.o
 LIBS += -lssl -lcrypto
 LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += $(DIR_WPA_SUPPLICANT)/tls_gnutls.o
+LIBS += -lgnutls -lgcrypt -lgpg-error
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+ifdef CONFIG_GNUTLS_EXTRA
+CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+NEED_CRYPTO=y
 else
 OBJS += $(DIR_WPA_SUPPLICANT)/tls_none.o
 endif
@@ -163,10 +248,60 @@
 endif
 
 ifdef MS_FUNCS
+OBJS += $(DIR_WPA_SUPPLICANT)/ms_funcs.o
+NEED_CRYPTO=y
+endif
+
+ifdef NEED_CRYPTO
 ifndef TLS_FUNCS
+ifeq ($(CONFIG_TLS), openssl)
 LIBS += -lcrypto
+LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += $(DIR_WPA_SUPPLICANT)/crypto.o
+OBJS_p += $(DIR_WPA_SUPPLICANT)/crypto.o
+HOBJS += $(DIR_WPA_SUPPLICANT)/crypto.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+OBJS_p += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+HOBJS += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
+endif
+else
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+
+ifdef CONFIG_INTERNAL_AES
+CFLAGS += -DINTERNAL_AES
+endif
+ifdef CONFIG_INTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA1
+endif
+ifdef CONFIG_INTERNAL_SHA256
+CFLAGS += -DINTERNAL_SHA256
 endif
-OBJS += $(DIR_WPA_SUPPLICANT)/ms_funcs.o $(DIR_WPA_SUPPLICANT)/crypto.o
+ifdef CONFIG_INTERNAL_MD5
+CFLAGS += -DINTERNAL_MD5
+endif
+ifdef CONFIG_INTERNAL_MD4
+CFLAGS += -DINTERNAL_MD4
+endif
+
+ifdef NEED_SHA256
+OBJS += sha256.o
 endif
 
 ifdef CONFIG_RADIUS_SERVER
@@ -178,6 +313,12 @@
 CFLAGS += -DCONFIG_IPV6
 endif
 
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
 ALL=hostapd hostapd_cli
 
 all: verify_config $(ALL)
@@ -201,10 +342,7 @@
 	rm -f driver_conf.c
 	echo '/* THIS FILE AUTOMATICALLY GENERATED, DO NOT EDIT! */' \
 							> driver_conf.c
-	echo '#include <stdlib.h>'			>> driver_conf.c
-	echo '#include <stdio.h>'			>> driver_conf.c
-	echo '#include <sys/types.h>'			>> driver_conf.c
-	echo '#include <netinet/in.h>'			>> driver_conf.c
+	echo '#include "includes.h"'			>> driver_conf.c
 	echo '#include "hostapd.h"'			>> driver_conf.c
 	echo '#include "driver.h"'			>> driver_conf.c
 ifdef CONFIG_DRIVER_HOSTAP
@@ -219,6 +357,9 @@
 ifdef CONFIG_DRIVER_PRISM54
 	echo "void prism54_driver_register(void);"	>> driver_conf.c
 endif
+ifdef CONFIG_DRIVER_DEVICESCAPE
+	echo "void devicescape_driver_register(void);"	>> driver_conf.c
+endif
 ifdef CONFIG_DRIVER_BSD
 	echo "void bsd_driver_register(void);"		>> driver_conf.c
 endif
@@ -238,6 +379,9 @@
 ifdef CONFIG_DRIVER_PRISM54
 	echo "prism54_driver_register();"		>> driver_conf.c
 endif
+ifdef CONFIG_DRIVER_DEVICESCAPE
+	echo "devicescape_driver_register();"		>> driver_conf.c
+endif
 ifdef CONFIG_DRIVER_BSD
 	echo "bsd_driver_register();"			>> driver_conf.c
 endif
@@ -249,7 +393,48 @@
 hostapd_cli: hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
 	$(CC) -o hostapd_cli hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
 
+NOBJS = nt_password_hash.o $(DIR_WPA_SUPPLICANT)/ms_funcs.o sha1.o rc4.o md5.o
+NOBJS += $(DIR_WPA_SUPPLICANT)/crypto.o os_$(CONFIG_OS).o
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+nt_password_hash: $(NOBJS)
+	$(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
+
+hlr_auc_gw: $(HOBJS)
+	$(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+
 clean:
-	rm -f core *~ *.o hostapd hostapd_cli *.d driver_conf.c
+	rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+	rm -f *.d driver_conf.c
+
+%.eps: %.fig
+	fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+	fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+		> $*.png
+
+docs-pics: doc/hostapd.png doc/hostapd.eps
+
+docs: docs-pics
+	doxygen doc/doxygen.full
+	$(MAKE) -C doc/latex
+	cp doc/latex/refman.pdf hostapd-devel.pdf
+
+docs-fast: docs-pics
+	doxygen doc/doxygen.fast
+
+clean-docs:
+	rm -rf doc/latex doc/html
+	rm -f doc/hosta.d{eps,png} hostapd-devel.pdf
+
+TEST_SRC_MILENAGE = milenage.c aes_wrap.c common.c os_$(CONFIG_OS).c
+test-milenage: $(TEST_SRC_MILENAGE)
+	$(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
+		-DTEST_MAIN_MILENAGE -I. -I../wpa_supplicant -DINTERNAL_AES
+	./test-milenage
+	rm test-milenage
 
 -include $(OBJS:%.o=%.d)
Index: aes.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/aes.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/aes.c -L contrib/hostapd/aes.c -u -r1.2 -r1.3
--- contrib/hostapd/aes.c
+++ contrib/hostapd/aes.c
@@ -9,7 +9,7 @@
  *   cost of reduced throughput (quite small difference on Pentium 4,
  *   10-25% when using -O1 or -O2 optimization)
  *
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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
@@ -21,6 +21,8 @@
  * See README and COPYING for more details.
  */
 
+#include "includes.h"
+
 /*
  * rijndael-alg-fst.c
  *
@@ -1060,7 +1062,7 @@
 	u32 *rk;
 	if (len != 16)
 		return NULL;
-	rk = malloc(4 * 44);
+	rk = os_malloc(4 * 44);
 	if (rk == NULL)
 		return NULL;
 	rijndaelKeySetupEnc(rk, key);
@@ -1076,7 +1078,7 @@
 
 void aes_encrypt_deinit(void *ctx)
 {
-	free(ctx);
+	os_free(ctx);
 }
 
 
@@ -1085,7 +1087,7 @@
 	u32 *rk;
 	if (len != 16)
 		return NULL;
-	rk = malloc(4 * 44);
+	rk = os_malloc(4 * 44);
 	if (rk == NULL)
 		return NULL;
 	rijndaelKeySetupDec(rk, key);
@@ -1101,5 +1103,5 @@
 
 void aes_decrypt_deinit(void *ctx)
 {
-	free(ctx);
+	os_free(ctx);
 }
Index: eap_ttls.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_ttls.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_ttls.h -L contrib/hostapd/eap_ttls.h -u -r1.2 -r1.3
--- contrib/hostapd/eap_ttls.h
+++ contrib/hostapd/eap_ttls.h
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
+ * Copyright (c) 2004-2005, 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
@@ -36,11 +36,11 @@
 
 #define AVP_PAD(start, pos) \
 do { \
-	int pad; \
-	pad = (4 - (((pos) - (start)) & 3)) & 3; \
-	memset((pos), 0, pad); \
-	pos += pad; \
-} while(0)
+	int __pad; \
+	__pad = (4 - (((pos) - (start)) & 3)) & 3; \
+	os_memset((pos), 0, __pad); \
+	pos += __pad; \
+} while (0)
 
 
 /* RFC 2865 */
Index: radius_server.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius_server.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius_server.h -L contrib/hostapd/radius_server.h -u -r1.2 -r1.3
--- contrib/hostapd/radius_server.h
+++ contrib/hostapd/radius_server.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / RADIUS authentication server
+ * Copyright (c) 2005, 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 RADIUS_SERVER_H
 #define RADIUS_SERVER_H
 
@@ -23,6 +37,8 @@
 int radius_server_get_mib(struct radius_server_data *data, char *buf,
 			  size_t buflen);
 
+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx);
+
 #else /* RADIUS_SERVER */
 
 static inline struct radius_server_data *
@@ -41,6 +57,11 @@
 	return 0;
 }
 
+static inline void
+radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
+{
+}
+
 #endif /* RADIUS_SERVER */
 
 #endif /* RADIUS_SERVER_H */
--- /dev/null
+++ contrib/hostapd/wme.h
@@ -0,0 +1,146 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 WME_H
+#define WME_H
+
+#ifdef __linux__
+#include <endian.h>
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#include <sys/types.h>
+#include <sys/endian.h>
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+	* defined(__DragonFly__) */
+
+#define WME_OUI_TYPE 2
+#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WME_VERSION 1
+
+#define WME_ACTION_CATEGORY 17
+#define WME_ACTION_CODE_SETUP_REQUEST 0
+#define WME_ACTION_CODE_SETUP_RESPONSE 1
+#define WME_ACTION_CODE_TEARDOWN 2
+
+#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0
+#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1
+#define WME_SETUP_RESPONSE_STATUS_REFUSED 3
+
+#define WME_TSPEC_DIRECTION_UPLINK 0
+#define WME_TSPEC_DIRECTION_DOWNLINK 1
+#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+extern inline u16 tsinfo(int tag1d, int contention_based, int direction)
+{
+	return (tag1d << 11) | (contention_based << 7) | (direction << 5) |
+	  (tag1d << 1);
+}
+
+
+struct wme_information_element {
+	/* required fields for WME version 1 */
+	u8 oui[3];
+	u8 oui_type;
+	u8 oui_subtype;
+	u8 version;
+	u8 acInfo;
+
+} __attribute__ ((packed));
+
+struct wme_ac_parameter {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+	/* byte 1 */
+	u8 	aifsn:4,
+		acm:1,
+	 	aci:2,
+	 	reserved:1;
+
+	/* byte 2 */
+	u8 	eCWmin:4,
+	 	eCWmax:4;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+	/* byte 1 */
+	u8 	reserved:1,
+	 	aci:2,
+	 	acm:1,
+	 	aifsn:4;
+
+	/* byte 2 */
+	u8 	eCWmax:4,
+	 	eCWmin:4;
+#else
+#error	"Please fix <endian.h>"
+#endif
+
+	/* bytes 3 & 4 */
+	u16 txopLimit;
+} __attribute__ ((packed));
+
+struct wme_parameter_element {
+	/* required fields for WME version 1 */
+	u8 oui[3];
+	u8 oui_type;
+	u8 oui_subtype;
+	u8 version;
+	u8 acInfo;
+	u8 reserved;
+	struct wme_ac_parameter ac[4];
+
+} __attribute__ ((packed));
+
+struct wme_tspec_info_element {
+	u8 eid;
+	u8 length;
+	u8 oui[3];
+	u8 oui_type;
+	u8 oui_subtype;
+	u8 version;
+	u16 ts_info;
+	u16 nominal_msdu_size;
+	u16 maximum_msdu_size;
+	u32 minimum_service_interval;
+	u32 maximum_service_interval;
+	u32 inactivity_interval;
+	u32 start_time;
+	u32 minimum_data_rate;
+	u32 mean_data_rate;
+	u32 maximum_burst_size;
+	u32 minimum_phy_rate;
+	u32 peak_data_rate;
+	u32 delay_bound;
+	u16 surplus_bandwidth_allowance;
+	u16 medium_time;
+} __attribute__ ((packed));
+
+
+/* Access Categories */
+enum {
+	WME_AC_BK = 1,
+	WME_AC_BE = 0,
+	WME_AC_VI = 2,
+	WME_AC_VO = 3
+};
+
+
+u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid);
+int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len);
+int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+			size_t len);
+
+#endif /* WME_H */
Index: eap_identity.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_identity.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_identity.c -L contrib/hostapd/eap_identity.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_identity.c
+++ contrib/hostapd/eap_identity.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-Identity
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -32,10 +29,9 @@
 {
 	struct eap_identity_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = CONTINUE;
 
 	return data;
@@ -61,7 +57,7 @@
 
 
 static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
-			     size_t *reqDataLen)
+				  size_t *reqDataLen)
 {
 	struct eap_identity_data *data = priv;
 	struct eap_hdr *req;
@@ -76,8 +72,8 @@
 		req_data = NULL;
 		req_data_len = 0;
 	}
-	*reqDataLen = sizeof(*req) + 1 + req_data_len;
-	req = malloc(*reqDataLen);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, reqDataLen,
+			    req_data_len, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
 			   "memory for request");
@@ -85,11 +81,6 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	pos = (u8 *) (req + 1);
-	*pos++ = EAP_TYPE_IDENTITY;
 	if (req_data)
 		memcpy(pos, req_data, req_data_len);
 
@@ -100,14 +91,12 @@
 static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
 			     u8 *respData, size_t respDataLen)
 {
-	struct eap_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	size_t len;
 
-	resp = (struct eap_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_IDENTITY ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+			       respData, respDataLen, &len);
+	if (pos == NULL) {
 		wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
 		return TRUE;
 	}
@@ -120,9 +109,8 @@
 			    u8 *respData, size_t respDataLen)
 {
 	struct eap_identity_data *data = priv;
-	struct eap_hdr *resp;
-	u8 *pos;
-	int len;
+	const u8 *pos;
+	size_t len;
 
 	if (data->pick_up) {
 		if (eap_identity_check(sm, data, respData, respDataLen)) {
@@ -134,15 +122,11 @@
 		data->pick_up = 0;
 	}
 
-	resp = (struct eap_hdr *) respData;
-	len = ntohs(resp->length);
-	pos = (u8 *) (resp + 1);
-	pos++;
-	len -= sizeof(*resp) + 1;
-	if (len < 0) {
-		data->state = FAILURE;
-		return;
-	}
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+			       respData, respDataLen, &len);
+	if (pos == NULL)
+		return; /* Should not happen - frame already validated */
+
 	wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
 	free(sm->identity);
 	sm->identity = malloc(len);
@@ -170,16 +154,28 @@
 }
 
 
-const struct eap_method eap_method_identity =
+int eap_server_identity_register(void)
 {
-	.method = EAP_TYPE_IDENTITY,
-	.name = "Identity",
-	.init = eap_identity_init,
-	.initPickUp = eap_identity_initPickUp,
-	.reset = eap_identity_reset,
-	.buildReq = eap_identity_buildReq,
-	.check = eap_identity_check,
-	.process = eap_identity_process,
-	.isDone = eap_identity_isDone,
-	.isSuccess = eap_identity_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+				      "Identity");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_identity_init;
+	eap->initPickUp = eap_identity_initPickUp;
+	eap->reset = eap_identity_reset;
+	eap->buildReq = eap_identity_buildReq;
+	eap->check = eap_identity_check;
+	eap->process = eap_identity_process;
+	eap->isDone = eap_identity_isDone;
+	eap->isSuccess = eap_identity_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
--- /dev/null
+++ contrib/hostapd/l2_packet_none.c
@@ -0,0 +1,123 @@
+/*
+ * WPA Supplicant - Layer2 packet handling example with dummy functions
+ * Copyright (c) 2003-2005, 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.
+ *
+ * This file can be used as a starting point for layer2 packet implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+	char ifname[17];
+	u8 own_addr[ETH_ALEN];
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len);
+	void *rx_callback_ctx;
+	int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+		     * buffers */
+	int fd;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+	os_memcpy(addr, l2->own_addr, ETH_ALEN);
+	return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len)
+{
+	if (l2 == NULL)
+		return -1;
+
+	/*
+	 * TODO: Send frame (may need different implementation depending on
+	 * whether l2->l2_hdr is set).
+	 */
+
+	return 0;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	u8 buf[2300];
+	int res;
+
+	/* TODO: receive frame (e.g., recv() using sock */
+	buf[0] = 0;
+	res = 0;
+
+	l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */,
+			buf, res);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr)
+{
+	struct l2_packet_data *l2;
+
+	l2 = os_zalloc(sizeof(struct l2_packet_data));
+	if (l2 == NULL)
+		return NULL;
+	os_strncpy(l2->ifname, ifname, sizeof(l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	/*
+	 * TODO: open connection for receiving frames
+	 */
+	l2->fd = -1;
+	eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+	return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	if (l2->fd >= 0) {
+		eloop_unregister_read_sock(l2->fd);
+		/* TODO: close connection */
+	}
+		
+	os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	/* TODO: get interface IP address */
+	return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+	/* This function can be left empty */
+}
Index: eap_tls.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_tls.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_tls.c -L contrib/hostapd/eap_tls.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_tls.c
+++ contrib/hostapd/eap_tls.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -37,10 +34,9 @@
 {
 	struct eap_tls_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = START;
 
 	if (eap_tls_ssl_init(sm, &data->ssl, 1)) {
@@ -134,12 +130,11 @@
 {
 	struct eap_hdr *resp;
 	u8 *pos;
-	size_t len;
 
 	resp = (struct eap_hdr *) respData;
 	pos = (u8 *) (resp + 1);
 	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_TLS ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	    (ntohs(resp->length)) > respDataLen) {
 		wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
 		return TRUE;
 	}
@@ -231,6 +226,38 @@
 }
 
 
+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *eapKeyData, *emsk;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = eap_tls_derive_key(sm, &data->ssl,
+					"client EAP encryption",
+					EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+	if (eapKeyData) {
+		emsk = malloc(EAP_EMSK_LEN);
+		if (emsk)
+			memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+			       EAP_EMSK_LEN);
+		free(eapKeyData);
+	} else
+		emsk = NULL;
+
+	if (emsk) {
+		*len = EAP_EMSK_LEN;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived EMSK",
+			    emsk, EAP_EMSK_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive EMSK");
+	}
+
+	return emsk;
+}
+
+
 static Boolean eap_tls_isSuccess(struct eap_sm *sm, void *priv)
 {
 	struct eap_tls_data *data = priv;
@@ -238,16 +265,28 @@
 }
 
 
-const struct eap_method eap_method_tls =
+int eap_server_tls_register(void)
 {
-	.method = EAP_TYPE_TLS,
-	.name = "TLS",
-	.init = eap_tls_init,
-	.reset = eap_tls_reset,
-	.buildReq = eap_tls_buildReq,
-	.check = eap_tls_check,
-	.process = eap_tls_process,
-	.isDone = eap_tls_isDone,
-	.getKey = eap_tls_getKey,
-	.isSuccess = eap_tls_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tls_init;
+	eap->reset = eap_tls_reset;
+	eap->buildReq = eap_tls_buildReq;
+	eap->check = eap_tls_check;
+	eap->process = eap_tls_process;
+	eap->isDone = eap_tls_isDone;
+	eap->getKey = eap_tls_getKey;
+	eap->isSuccess = eap_tls_isSuccess;
+	eap->get_emsk = eap_tls_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: eap_ttls.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_ttls.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_ttls.c -L contrib/hostapd/eap_ttls.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_ttls.c
+++ contrib/hostapd/eap_ttls.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TTLS (draft-ietf-pppext-eap-ttls-05.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -23,11 +20,20 @@
 #include "eap_tls_common.h"
 #include "ms_funcs.h"
 #include "md5.h"
+#include "sha1.h"
 #include "crypto.h"
 #include "tls.h"
 #include "eap_ttls.h"
 
-#define EAP_TTLS_VERSION 0
+
+/* Maximum supported PEAP version
+ * 0 = draft-ietf-pppext-eap-ttls-03.txt / draft-funk-eap-ttls-v0-00.txt
+ * 1 = draft-funk-eap-ttls-v1-00.txt
+ */
+#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
+
+
+#define MSCHAPV2_KEY_LEN 16
 
 
 static void eap_ttls_reset(struct eap_sm *sm, void *priv);
@@ -37,15 +43,17 @@
 	struct eap_ssl_data ssl;
 	enum {
 		START, PHASE1, PHASE2_START, PHASE2_METHOD,
-		PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
+		PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
 	} state;
 
 	int ttls_version;
+	int force_version;
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
 	int mschapv2_resp_ok;
 	u8 mschapv2_auth_response[20];
 	u8 mschapv2_ident;
+	int tls_ia_configured;
 };
 
 
@@ -62,6 +70,8 @@
 		return "PHASE2_METHOD";
 	case PHASE2_MSCHAPV2_RESP:
 		return "PHASE2_MSCHAPV2_RESP";
+	case PHASE_FINISHED:
+		return "PHASE_FINISHED";
 	case SUCCESS:
 		return "SUCCESS";
 	case FAILURE:
@@ -173,11 +183,16 @@
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
 			   "length=%d", (int) avp_code, avp_flags,
 			   (int) avp_length);
-		if (avp_length > left) {
+		if ((int) avp_length > left) {
 			wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
 				   "(len=%d, left=%d) - dropped",
 				   (int) avp_length, left);
-			return -1;
+			goto fail;
+		}
+		if (avp_length < sizeof(*avp)) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length "
+				   "%d", avp_length);
+			goto fail;
 		}
 		dpos = (u8 *) (avp + 1);
 		dlen = avp_length - sizeof(*avp);
@@ -185,7 +200,7 @@
 			if (dlen < 4) {
 				wpa_printf(MSG_WARNING, "EAP-TTLS: vendor AVP "
 					   "underflow");
-				return -1;
+				goto fail;
 			}
 			vendor_id = be_to_host32(* (u32 *) dpos);
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
@@ -204,7 +219,7 @@
 					wpa_printf(MSG_WARNING, "EAP-TTLS: "
 						   "failed to allocate memory "
 						   "for Phase 2 EAP data");
-					return -1;
+					goto fail;
 				}
 				memcpy(parse->eap, dpos, dlen);
 				parse->eap_len = dlen;
@@ -215,9 +230,7 @@
 					wpa_printf(MSG_WARNING, "EAP-TTLS: "
 						   "failed to allocate memory "
 						   "for Phase 2 EAP data");
-					free(parse->eap);
-					parse->eap = NULL;
-					return -1;
+					goto fail;
 				}
 				memcpy(neweap + parse->eap_len, dpos, dlen);
 				parse->eap = neweap;
@@ -281,7 +294,7 @@
 			wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported "
 				   "mandatory AVP code %d vendor_id %d - "
 				   "dropped", (int) avp_code, (int) vendor_id);
-			return -1;
+			goto fail;
 		} else {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported "
 				   "AVP code %d vendor_id %d",
@@ -294,6 +307,65 @@
 	}
 
 	return 0;
+
+fail:
+	free(parse->eap);
+	parse->eap = NULL;
+	return -1;
+}
+
+
+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
+					struct eap_ttls_data *data, size_t len)
+{
+	struct tls_keys keys;
+	u8 *challenge, *rnd;
+
+	if (data->ttls_version == 0) {
+		return eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
+					  len);
+	}
+
+	memset(&keys, 0, sizeof(keys));
+	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
+	    keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.inner_secret == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
+			   "client random, or server random to derive "
+			   "implicit challenge");
+		return NULL;
+	}
+
+	rnd = malloc(keys.client_random_len + keys.server_random_len);
+	challenge = malloc(len);
+	if (rnd == NULL || challenge == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
+			   "challenge derivation");
+		free(rnd);
+		free(challenge);
+		return NULL;
+	}
+	memcpy(rnd, keys.server_random, keys.server_random_len);
+	memcpy(rnd + keys.server_random_len, keys.client_random,
+	       keys.client_random_len);
+
+	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
+		    "inner application challenge", rnd,
+		    keys.client_random_len + keys.server_random_len,
+		    challenge, len)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
+			   "challenge");
+		free(rnd);
+		free(challenge);
+		return NULL;
+	}
+
+	free(rnd);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
+			challenge, len);
+
+	return challenge;
 }
 
 
@@ -301,13 +373,31 @@
 {
 	struct eap_ttls_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->ttls_version = EAP_TTLS_VERSION;
+	data->force_version = -1;
+	if (sm->user && sm->user->force_version >= 0) {
+		data->force_version = sm->user->force_version;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
+			   data->force_version);
+		data->ttls_version = data->force_version;
+	}
 	data->state = START;
 
+	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
+	    data->ttls_version > 0) {
+		if (data->force_version > 0) {
+			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
+				   "TLS library does not support TLS/IA.",
+				   data->force_version);
+			eap_ttls_reset(sm, data);
+			return NULL;
+		}
+		data->ttls_version = 0;
+	}
+
 	if (eap_tls_ssl_init(sm, &data->ssl, 0)) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
 		eap_ttls_reset(sm, data);
@@ -456,23 +546,24 @@
 					   int id, size_t *reqDataLen)
 {
 	u8 *req, *encr_req, *pos, *end;
+	int ret;
 	size_t req_len;
-	int i;
 
 	pos = req = malloc(100);
 	if (req == NULL)
 		return NULL;
-	end = req + 200;
+	end = req + 100;
 
 	if (data->mschapv2_resp_ok) {
 		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_SUCCESS,
 				       RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
 		*pos++ = data->mschapv2_ident;
-		pos += snprintf((char *) pos, end - pos, "S=");
-		for (i = 0; i < sizeof(data->mschapv2_auth_response); i++) {
-			pos += snprintf((char *) pos, end - pos, "%02X",
-					data->mschapv2_auth_response[i]);
-		}
+		ret = snprintf((char *) pos, end - pos, "S=");
+		if (ret >= 0 && ret < end - pos)
+			pos += ret;
+		pos += wpa_snprintf_hex_uppercase(
+			(char *) pos, end - pos, data->mschapv2_auth_response,
+			sizeof(data->mschapv2_auth_response));
 	} else {
 		pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_ERROR,
 				       RADIUS_VENDOR_ID_MICROSOFT, 1, 6);
@@ -492,6 +583,43 @@
 }
 
 
+static u8 * eap_ttls_build_phase_finished(struct eap_sm *sm,
+					  struct eap_ttls_data *data,
+					  int id, int final,
+					  size_t *reqDataLen)
+{
+	int len;
+	struct eap_hdr *req;
+	u8 *pos;
+	const int max_len = 300;
+
+	len = sizeof(struct eap_hdr) + 2 + max_len;
+	req = malloc(len);
+	if (req == NULL)
+		return NULL;
+
+	req->code = EAP_CODE_REQUEST;
+	req->identifier = id;
+
+	pos = (u8 *) (req + 1);
+	*pos++ = EAP_TYPE_TTLS;
+	*pos++ = data->ttls_version;
+
+	len = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
+						    data->ssl.conn,
+						    final, pos, max_len);
+	if (len < 0) {
+		free(req);
+		return NULL;
+	}
+
+	*reqDataLen = sizeof(struct eap_hdr) + 2 + len;
+	req->length = host_to_be16(*reqDataLen);
+
+	return (u8 *) req;
+}
+
+
 static u8 * eap_ttls_buildReq(struct eap_sm *sm, void *priv, int id,
 			      size_t *reqDataLen)
 {
@@ -507,6 +635,9 @@
 	case PHASE2_MSCHAPV2_RESP:
 		return eap_ttls_build_phase2_mschapv2(sm, data, id,
 						      reqDataLen);
+	case PHASE_FINISHED:
+		return eap_ttls_build_phase_finished(sm, data, id, 1,
+						     reqDataLen);
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
 			   __func__, data->state);
@@ -520,12 +651,11 @@
 {
 	struct eap_hdr *resp;
 	u8 *pos;
-	size_t len;
 
 	resp = (struct eap_hdr *) respData;
 	pos = (u8 *) (resp + 1);
 	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_TTLS ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	    (ntohs(resp->length)) > respDataLen) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
 		return TRUE;
 	}
@@ -534,6 +664,37 @@
 }
 
 
+static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
+					    struct eap_ttls_data *data,
+					    const u8 *key, size_t key_len)
+{
+	u8 *buf;
+	size_t buf_len;
+	int ret;
+
+	if (key) {
+		buf_len = 2 + key_len;
+		buf = malloc(buf_len);
+		if (buf == NULL)
+			return -1;
+		WPA_PUT_BE16(buf, key_len);
+		memcpy(buf + 2, key, key_len);
+	} else {
+		buf = NULL;
+		buf_len = 0;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
+			"secret permutation", buf, buf_len);
+	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
+						     data->ssl.conn,
+						     buf, buf_len);
+	free(buf);
+
+	return ret;
+}
+
+
 static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
 					struct eap_ttls_data *data,
 					const u8 *user_password,
@@ -541,9 +702,9 @@
 {
 	/* TODO: add support for verifying that the user entry accepts
 	 * EAP-TTLS/PAP. */
-	if (!sm->user || !sm->user->password) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No user password "
-			   "configured");
+	if (!sm->user || !sm->user->password || sm->user->password_hash) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: No plaintext user "
+			   "password configured");
 		eap_ttls_state(data, FAILURE);
 		return;
 	}
@@ -557,7 +718,8 @@
 	}
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
-	eap_ttls_state(data, SUCCESS);
+	eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
+		       SUCCESS);
 }
 
 
@@ -585,15 +747,15 @@
 
 	/* TODO: add support for verifying that the user entry accepts
 	 * EAP-TTLS/CHAP. */
-	if (!sm->user || !sm->user->password) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No user password "
-			   "configured");
+	if (!sm->user || !sm->user->password || sm->user->password_hash) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: No plaintext user "
+			   "password configured");
 		eap_ttls_state(data, FAILURE);
 		return;
 	}
 
-	chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
-				  EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
+	chal = eap_ttls_implicit_challenge(sm, data,
+					   EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
 	if (chal == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Failed to generate "
 			   "challenge from TLS data");
@@ -621,7 +783,8 @@
 
 	if (memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
-		eap_ttls_state(data, SUCCESS);
+		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
+			       SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
 		eap_ttls_state(data, FAILURE);
@@ -656,8 +819,8 @@
 		return;
 	}
 
-	chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
-				  EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
+	chal = eap_ttls_implicit_challenge(sm, data,
+					   EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
 	if (chal == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Failed to generate "
 			   "challenge from TLS data");
@@ -674,12 +837,16 @@
 	}
 	free(chal);
 
-	nt_challenge_response(challenge, sm->user->password,
-			      sm->user->password_len, nt_response);
+	if (sm->user->password_hash)
+		challenge_response(challenge, sm->user->password, nt_response);
+	else
+		nt_challenge_response(challenge, sm->user->password,
+				      sm->user->password_len, nt_response);
 
 	if (memcmp(nt_response, response + 2 + 24, 24) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
-		eap_ttls_state(data, SUCCESS);
+		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
+			       SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
 		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -697,10 +864,9 @@
 					     size_t challenge_len,
 					     u8 *response, size_t response_len)
 {
-	u8 *chal, *username, nt_response[24], *pos, *rx_resp, *peer_challenge,
+	u8 *chal, *username, nt_response[24], *rx_resp, *peer_challenge,
 		*auth_challenge;
-	size_t username_len;
-	int i;
+	size_t username_len, i;
 
 	if (challenge == NULL || response == NULL ||
 	    challenge_len != EAP_TTLS_MSCHAPV2_CHALLENGE_LEN ||
@@ -727,7 +893,6 @@
 	 * (if present). */
 	username = sm->identity;
 	username_len = sm->identity_len;
-	pos = username;
 	for (i = 0; i < username_len; i++) {
 		if (username[i] == '\\') {
 			username_len -= i + 1;
@@ -736,8 +901,8 @@
 		}
 	}
 
-	chal = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
-				  EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
+	chal = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
 	if (chal == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Failed to generate "
 			   "challenge from TLS data");
@@ -764,25 +929,62 @@
 	wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAPV2: peer_challenge",
 		    peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
 
-	generate_nt_response(auth_challenge, peer_challenge,
-			     username, username_len,
-			     sm->user->password, sm->user->password_len,
-			     nt_response);
+	if (sm->user->password_hash) {
+		generate_nt_response_pwhash(auth_challenge, peer_challenge,
+					    username, username_len,
+					    sm->user->password,
+					    nt_response);
+	} else {
+		generate_nt_response(auth_challenge, peer_challenge,
+				     username, username_len,
+				     sm->user->password,
+				     sm->user->password_len,
+				     nt_response);
+	}
 
 	rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8;
 	if (memcmp(nt_response, rx_resp, 24) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
 			   "NT-Response");
 		data->mschapv2_resp_ok = 1;
+		if (data->ttls_version > 0) {
+			const u8 *pw_hash;
+			u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
+			u8 session_key[2 * MSCHAPV2_KEY_LEN];
+
+			if (sm->user->password_hash)
+				pw_hash = sm->user->password;
+			else {
+				nt_password_hash(sm->user->password,
+						 sm->user->password_len,
+						 pw_hash_buf);
+				pw_hash = pw_hash_buf;
+			}
+			hash_nt_password_hash(pw_hash, pw_hash_hash);
+			get_master_key(pw_hash_hash, nt_response, master_key);
+			get_asymetric_start_key(master_key, session_key,
+						MSCHAPV2_KEY_LEN, 0, 0);
+			get_asymetric_start_key(master_key,
+						session_key + MSCHAPV2_KEY_LEN,
+						MSCHAPV2_KEY_LEN, 1, 0);
+			eap_ttls_ia_permute_inner_secret(sm, data,
+							 session_key,
+							 sizeof(session_key));
+		}
 
-		generate_authenticator_response(sm->user->password,
-						sm->user->password_len,
-						peer_challenge,
-						auth_challenge,
-						username, username_len,
-						nt_response,
-						data->mschapv2_auth_response);
-
+		if (sm->user->password_hash) {
+			generate_authenticator_response_pwhash(
+				sm->user->password,
+				peer_challenge, auth_challenge,
+				username, username_len, nt_response,
+				data->mschapv2_auth_response);
+		} else {
+			generate_authenticator_response(
+				sm->user->password, sm->user->password_len,
+				peer_challenge, auth_challenge,
+				username, username_len, nt_response,
+				data->mschapv2_auth_response);
+		}
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Invalid "
 			   "NT-Response");
@@ -798,14 +1000,16 @@
 
 
 static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
-				    struct eap_ttls_data *data, u8 eap_type)
+				    struct eap_ttls_data *data,
+				    EapType eap_type)
 {
 	if (data->phase2_priv && data->phase2_method) {
 		data->phase2_method->reset(sm, data->phase2_priv);
 		data->phase2_method = NULL;
 		data->phase2_priv = NULL;
 	}
-	data->phase2_method = eap_sm_get_eap_methods(eap_type);
+	data->phase2_method = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+						     eap_type);
 	if (!data->phase2_method)
 		return -1;
 
@@ -824,6 +1028,8 @@
 	struct eap_hdr *hdr;
 	u8 *pos;
 	size_t left;
+	const struct eap_method *m = data->phase2_method;
+	void *priv = data->phase2_priv;
 
 	if (data->phase2_priv == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: %s - Phase2 not "
@@ -833,17 +1039,17 @@
 
 	hdr = (struct eap_hdr *) in_data;
 	pos = (u8 *) (hdr + 1);
-	left = in_len - sizeof(*hdr);
 
 	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = in_len - sizeof(*hdr);
 		wpa_hexdump(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 type Nak'ed; "
 			    "allowed types", pos + 1, left - 1);
 		eap_sm_process_nak(sm, pos + 1, left - 1);
 		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index] !=
+		    sm->user->methods[sm->user_eap_method_index].method !=
 		    EAP_TYPE_NONE) {
-			next_type =
-				sm->user->methods[sm->user_eap_method_index++];
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d",
 				   next_type);
 			eap_ttls_phase2_eap_init(sm, data, next_type);
@@ -853,19 +1059,18 @@
 		return;
 	}
 
-	if (data->phase2_method->check(sm, data->phase2_priv, in_data,
-				       in_len)) {
+	if (m->check(sm, priv, in_data, in_len)) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 check() asked to "
 			   "ignore the packet");
 		return;
 	}
 
-	data->phase2_method->process(sm, data->phase2_priv, in_data, in_len);
+	m->process(sm, priv, in_data, in_len);
 
-	if (!data->phase2_method->isDone(sm, data->phase2_priv))
+	if (!m->isDone(sm, priv))
 		return;
 
-	if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) {
+	if (!m->isSuccess(sm, priv)) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/EAP: Phase2 method failed");
 		eap_ttls_state(data, FAILURE);
 		return;
@@ -883,12 +1088,22 @@
 		}
 
 		eap_ttls_state(data, PHASE2_METHOD);
-		next_type = sm->user->methods[0];
+		next_type = sm->user->methods[0].method;
 		sm->user_eap_method_index = 1;
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
 		break;
 	case PHASE2_METHOD:
-		eap_ttls_state(data, SUCCESS);
+		if (data->ttls_version > 0) {
+			if (m->getKey) {
+				u8 *key;
+				size_t key_len;
+				key = m->getKey(sm, priv, &key_len);
+				eap_ttls_ia_permute_inner_secret(sm, data,
+								 key, key_len);
+			}
+			eap_ttls_state(data, PHASE_FINISHED);
+		} else
+			eap_ttls_state(data, SUCCESS);
 		break;
 	case FAILURE:
 		break;
@@ -956,8 +1171,9 @@
 				    u8 *in_data, size_t in_len)
 {
 	u8 *in_decrypted;
-	int buf_len, len_decrypted, res;
+	int len_decrypted, res;
 	struct eap_ttls_avp parse;
+	size_t buf_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
 		   " Phase 2", (unsigned long) in_len);
@@ -993,6 +1209,23 @@
 		return;
 	}
 
+	if (data->state == PHASE_FINISHED) {
+		if (len_decrypted == 0 &&
+		    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
+							   data->ssl.conn)) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
+				   "received");
+			eap_ttls_state(data, SUCCESS);
+		} else {
+			wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
+				   "FinalPhaseFinished");
+			eap_ttls_state(data, FAILURE);
+		}
+
+		free(in_decrypted);
+		return;
+	}
+
 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
 			in_decrypted, len_decrypted);
 
@@ -1075,8 +1308,18 @@
 			   "use version %d",
 			   peer_version, data->ttls_version, peer_version);
 		data->ttls_version = peer_version;
-			   
 	}
+
+	if (data->ttls_version > 0 && !data->tls_ia_configured) {
+		if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
+			wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
+				   "TLS/IA");
+			eap_ttls_state(data, FAILURE);
+			return;
+		}
+		data->tls_ia_configured = 1;
+	}
+
 	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
 		if (left < 4) {
 			wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
@@ -1109,13 +1352,15 @@
 		break;
 	case PHASE2_START:
 	case PHASE2_METHOD:
+	case PHASE_FINISHED:
 		eap_ttls_process_phase2(sm, data, resp, pos, left);
 		break;
 	case PHASE2_MSCHAPV2_RESP:
 		if (data->mschapv2_resp_ok && left == 0) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged response");
-			eap_ttls_state(data, SUCCESS);
+			eap_ttls_state(data, data->ttls_version > 0 ?
+				       PHASE_FINISHED : SUCCESS);
 		} else if (!data->mschapv2_resp_ok) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged error");
@@ -1148,6 +1393,54 @@
 }
 
 
+static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
+				   struct eap_ttls_data *data)
+{
+	struct tls_keys keys;
+	u8 *rnd, *key;
+
+	memset(&keys, 0, sizeof(keys));
+	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
+	    keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.inner_secret == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
+			   "client random, or server random to derive keying "
+			   "material");
+		return NULL;
+	}
+
+	rnd = malloc(keys.client_random_len + keys.server_random_len);
+	key = malloc(EAP_TLS_KEY_LEN);
+	if (rnd == NULL || key == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
+		free(rnd);
+		free(key);
+		return NULL;
+	}
+	memcpy(rnd, keys.client_random, keys.client_random_len);
+	memcpy(rnd + keys.client_random_len, keys.server_random,
+	       keys.server_random_len);
+
+	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
+		    "ttls v1 keying material", rnd, keys.client_random_len +
+		    keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
+		free(rnd);
+		free(key);
+		return NULL;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
+		    rnd, keys.client_random_len + keys.server_random_len);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
+			keys.inner_secret, keys.inner_secret_len);
+
+	free(rnd);
+
+	return key;
+}
+
+
 static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_ttls_data *data = priv;
@@ -1156,13 +1449,18 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	eapKeyData = eap_tls_derive_key(sm, &data->ssl,
-					"ttls keying material",
-					EAP_TLS_KEY_LEN);
+	if (data->ttls_version == 0) {
+		eapKeyData = eap_tls_derive_key(sm, &data->ssl,
+						"ttls keying material",
+						EAP_TLS_KEY_LEN);
+	} else {
+		eapKeyData = eap_ttls_v1_derive_key(sm, data);
+	}
+
 	if (eapKeyData) {
 		*len = EAP_TLS_KEY_LEN;
-		wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived key",
-			    eapKeyData, EAP_TLS_KEY_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
+				eapKeyData, EAP_TLS_KEY_LEN);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
 	}
@@ -1178,16 +1476,27 @@
 }
 
 
-const struct eap_method eap_method_ttls =
+int eap_server_ttls_register(void)
 {
-	.method = EAP_TYPE_TTLS,
-	.name = "TTLS",
-	.init = eap_ttls_init,
-	.reset = eap_ttls_reset,
-	.buildReq = eap_ttls_buildReq,
-	.check = eap_ttls_check,
-	.process = eap_ttls_process,
-	.isDone = eap_ttls_isDone,
-	.getKey = eap_ttls_getKey,
-	.isSuccess = eap_ttls_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_ttls_init;
+	eap->reset = eap_ttls_reset;
+	eap->buildReq = eap_ttls_buildReq;
+	eap->check = eap_ttls_check;
+	eap->process = eap_ttls_process;
+	eap->isDone = eap_ttls_isDone;
+	eap->getKey = eap_ttls_getKey;
+	eap->isSuccess = eap_ttls_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: ChangeLog
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ChangeLog,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ChangeLog -L contrib/hostapd/ChangeLog -u -r1.2 -r1.3
--- contrib/hostapd/ChangeLog
+++ contrib/hostapd/ChangeLog
@@ -1,9 +1,136 @@
 ChangeLog for hostapd
 
-2006-02-08 - v0.4.8
+2007-05-28 - v0.5.8
+	* updated driver_devicescape.c to build with the current
+	  wireless-dev.git tree and net/d80211 changes
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-03.txt)
+	* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+	  in Success Request [Bug 203]
+	* added support for sending EAP-AKA Notifications in error cases
+	* RADIUS server: added support for processing duplicate messages
+	  (retransmissions from RADIUS client) by replying with the previous
+	  reply
+
+2006-12-31 - v0.5.7
+	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+	* updated EAP-PSK to use the IANA-allocated EAP type 47
+	* fixed EAP-PSK bit ordering of the Flags field
+	* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+	  by reading wpa_psk_file [Bug 181]
+	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
+	* fixed IPv6 connection to RADIUS accounting server
+
+2006-11-24 - v0.5.6
+	* added support for configuring and controlling multiple BSSes per
+	  radio interface (bss=<ifname> in hostapd.conf); this is only
+	  available with Devicescape and test driver interfaces
+	* fixed PMKSA cache update in the end of successful RSN
+	  pre-authentication
+	* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+	  for each STA based on RADIUS Access-Accept attributes); this requires
+	  VLAN support from the kernel driver/802.11 stack and this is
+	  currently only available with Devicescape and test driver interfaces
+	* driver_madwifi: fixed configuration of unencrypted modes (plaintext
+	  and IEEE 802.1X without WEP)
+	* removed STAKey handshake since PeerKey handshake has replaced it in
+	  IEEE 802.11ma and there are no known deployments of STAKey
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-01.txt)
+	* added preliminary implementation of IEEE 802.11w/D1.0 (management
+	  frame protection)
+	  (Note: this requires driver support to work properly.)
+	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+	* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+	* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+	  parameters from a text file to make it possible to implement proper
+	  GSM/UMTS authentication server for multiple SIM/USIM cards using
+	  EAP-SIM/EAP-AKA
+	* fixed session timeout processing with drivers that do not use
+	  ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+	* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+	  hostapd (e.g., to initialize wired network authentication based on an
+	  external signal)
+	* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+	  using WPA2 even if PMKSA caching is not used
+	* added -P<pid file> argument for hostapd to write the current process
+	  id into a file
+	* added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+	* fixed nt_password_hash build [Bug 144]
+	* added PeerKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS) to replace STAKey handshake
+	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+	  draft-clancy-emu-eap-shared-secret-00.txt)
+	* fixed a segmentation fault when RSN pre-authentication was completed
+	  successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+	* do not build nt_password_hash and hlr_auc_gw by default to avoid
+	  requiring a TLS library for a successful build; these programs can be
+	  build with 'make nt_password_hash' and 'make hlr_auc_gw'
+	* added a new configuration option, eapol_version, that can be used to
+	  set EAPOL version to 1 (default is 2) to work around broken client
+	  implementations that drop EAPOL frames which use version number 2
+	  [Bug 89]
+	* added support for EAP-SAKE (no EAP method number allocated yet, so
+	  this is using the same experimental type 255 as EAP-PSK)
+	* fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
 	* fixed stdarg use in hostapd_logger(): if both stdout and syslog
 	  logging was enabled, hostapd could trigger a segmentation fault in
 	  vsyslog on some CPU -- C library combinations
+	* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+	  program to make it easier to use for implementing real SS7 gateway;
+	  eap_sim_db is not anymore used as a file name for GSM authentication
+	  triplets; instead, it is path to UNIX domain socket that will be used
+	  to communicate with the external gateway program (e.g., hlr_auc_gw)
+	* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+	  local information (GSM authentication triplets from a text file and
+	  hardcoded AKA authentication data); this can be used to test EAP-SIM
+	  and EAP-AKA
+	* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+	  to make it possible to test EAP-AKA with real USIM cards (this is
+	  disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+	  to enable this)
+	* driver_madwifi: added support for getting station RSN IE from
+	  madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+	  broken with earlier change (r1357) in the driver
+	* changed EAP method registration to use a dynamic list of methods
+	  instead of a static list generated at build time
+	* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+	  [Bug 125]
+	* added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+	* driver_test: added better support for multiple APs and STAs by using
+	  a directory with sockets that include MAC address for each device in
+	  the name (test_socket=DIR:/tmp/test)
+	* added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+	* added experimental STAKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS); note: this is disabled by default in both
+	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+	  and stakey=1)
+	* added support for EAP methods to use callbacks to external programs
+	  by buffering a pending request and processing it after the EAP method
+	  is ready to continue
+	* improved EAP-SIM database interface to allow external request to GSM
+	  HLR/AuC without blocking hostapd process
+	* added support for using EAP-SIM pseudonyms and fast re-authentication
+	* added support for EAP-AKA in the integrated EAP authenticator
+	* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+	  user database to allow EAP-SIM/AKA selection without extra roundtrip
+	  for EAP-Nak negotiation
+	* added support for storing EAP user password as NtPasswordHash instead
+	  of plaintext password when using MSCHAP or MSCHAPv2 for
+	  authentication (hash:<16-octet hex value>); added nt_password_hash
+	  tool for hashing password to generate NtPasswordHash
 
 2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
 	* driver_wired: fixed EAPOL sending to optionally use PAE group address
--- /dev/null
+++ contrib/hostapd/wme.c
@@ -0,0 +1,260 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "ieee802_11.h"
+#include "wme.h"
+#include "sta_info.h"
+#include "driver.h"
+
+
+/* TODO: maintain separate sequence and fragment numbers for each AC
+ * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
+ * if only WME stations are receiving a certain group */
+
+
+static u8 wme_oui[3] = { 0x00, 0x50, 0xf2 };
+
+
+/* Add WME Parameter Element to Beacon and Probe Response frames. */
+u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	struct wme_parameter_element *wme =
+		(struct wme_parameter_element *) (pos + 2);
+	int e;
+
+	if (!hapd->conf->wme_enabled)
+		return eid;
+	eid[0] = WLAN_EID_VENDOR_SPECIFIC;
+	wme->oui[0] = 0x00;
+	wme->oui[1] = 0x50;
+	wme->oui[2] = 0xf2;
+	wme->oui_type = WME_OUI_TYPE;
+	wme->oui_subtype = WME_OUI_SUBTYPE_PARAMETER_ELEMENT;
+	wme->version = WME_VERSION;
+	wme->acInfo = hapd->parameter_set_count & 0xf;
+
+	/* fill in a parameter set record for each AC */
+	for (e = 0; e < 4; e++) {
+		struct wme_ac_parameter *ac = &wme->ac[e];
+		struct hostapd_wme_ac_params *acp =
+			&hapd->iconf->wme_ac_params[e];
+
+		ac->aifsn = acp->aifs;
+		ac->acm = acp->admission_control_mandatory;
+		ac->aci = e;
+		ac->reserved = 0;
+		ac->eCWmin = acp->cwmin;
+		ac->eCWmax = acp->cwmax;
+		ac->txopLimit = host_to_le16(acp->txopLimit);
+	}
+
+	pos = (u8 *) (wme + 1);
+	eid[1] = pos - eid - 2; /* element length */
+
+	return pos;
+}
+
+
+/* This function is called when a station sends an association request with
+ * WME info element. The function returns zero on success or non-zero on any
+ * error in WME element. eid does not include Element ID and Length octets. */
+int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+	struct wme_information_element *wme;
+
+	wpa_hexdump(MSG_MSGDUMP, "WME IE", eid, len);
+
+	if (len < sizeof(struct wme_information_element)) {
+		printf("Too short WME IE (len=%lu)\n", (unsigned long) len);
+		return -1;
+	}
+
+	wme = (struct wme_information_element *) eid;
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Validating WME IE: OUI "
+		      "%02x:%02x:%02x  OUI type %d  OUI sub-type %d  "
+		      "version %d\n",
+		      wme->oui[0], wme->oui[1], wme->oui[2], wme->oui_type,
+		      wme->oui_subtype, wme->version);
+	if (memcmp(wme->oui, wme_oui, sizeof(wme_oui)) != 0 ||
+	    wme->oui_type != WME_OUI_TYPE ||
+	    wme->oui_subtype != WME_OUI_SUBTYPE_INFORMATION_ELEMENT ||
+	    wme->version != WME_VERSION) {
+		printf("Unsupported WME IE OUI/Type/Subtype/Version\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/* This function is called when a station sends an ACK frame for an AssocResp
+ * frame (status=success) and the matching AssocReq contained a WME element.
+ */
+int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	/* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
+	if (sta->flags & WLAN_STA_WME)
+		hostapd_sta_set_flags(hapd, sta->addr, WLAN_STA_WME, ~0);
+	else
+		hostapd_sta_set_flags(hapd, sta->addr, 0, ~WLAN_STA_WME);
+
+	return 0;
+}
+
+
+static void wme_send_action(struct hostapd_data *hapd, const u8 *addr,
+			    const struct wme_tspec_info_element *tspec,
+			    u8 action_code, u8 dialogue_token, u8 status_code)
+{
+	u8 buf[256];
+	struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
+	struct wme_tspec_info_element *t =
+		(struct wme_tspec_info_element *)
+		m->u.action.u.wme_action.variable;
+	int len;
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "action response - reason %d", status_code);
+	memset(buf, 0, sizeof(buf));
+	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					WLAN_FC_STYPE_ACTION);
+	memcpy(m->da, addr, ETH_ALEN);
+	memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+	memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+	m->u.action.category = WME_ACTION_CATEGORY;
+	m->u.action.u.wme_action.action_code = action_code;
+	m->u.action.u.wme_action.dialog_token = dialogue_token;
+	m->u.action.u.wme_action.status_code = status_code;
+	memcpy(t, tspec, sizeof(struct wme_tspec_info_element));
+	len = ((u8 *) (t + 1)) - buf;
+
+	if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0)
+		perror("wme_send_action: send");
+}
+
+
+/* given frame data payload size in bytes, and data_rate in bits per second
+ * returns time to complete frame exchange */
+/* FIX: should not use floating point types */
+static double wme_frame_exchange_time(int bytes, int data_rate, int encryption,
+				      int cts_protection)
+{
+	/* TODO: account for MAC/PHY headers correctly */
+	/* TODO: account for encryption headers */
+	/* TODO: account for WDS headers */
+	/* TODO: account for CTS protection */
+	/* TODO: account for SIFS + ACK at minimum PHY rate */
+	return (bytes + 400) * 8.0 / data_rate;
+}
+
+
+static void wme_setup_request(struct hostapd_data *hapd,
+			      struct ieee80211_mgmt *mgmt,
+			      struct wme_tspec_info_element *tspec, size_t len)
+{
+	/* FIX: should not use floating point types */
+	double medium_time, pps;
+
+	/* TODO: account for airtime and answer no to tspec setup requests
+	 * when none left!! */
+
+	pps = (tspec->mean_data_rate / 8.0) / tspec->nominal_msdu_size;
+	medium_time = (tspec->surplus_bandwidth_allowance / 8) * pps *
+		wme_frame_exchange_time(tspec->nominal_msdu_size,
+					tspec->minimum_phy_rate, 0, 0);
+	tspec->medium_time = medium_time * 1000000.0 / 32.0;
+
+	wme_send_action(hapd, mgmt->sa, tspec, WME_ACTION_CODE_SETUP_RESPONSE,
+			mgmt->u.action.u.wme_action.dialog_token,
+			WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED);
+}
+
+
+void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+			size_t len)
+{
+	int action_code;
+	int left = len - IEEE80211_HDRLEN - 4;
+	u8 *pos = ((u8 *) mgmt) + IEEE80211_HDRLEN + 4;
+	struct ieee802_11_elems elems;
+	struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
+
+	/* check that the request comes from a valid station */
+	if (!sta ||
+	    (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WME)) !=
+	    (WLAN_STA_ASSOC | WLAN_STA_WME)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "wme action received is not from associated wme"
+			       " station");
+		/* TODO: respond with action frame refused status code */
+		return;
+	}
+
+	/* extract the tspec info element */
+	if (ieee802_11_parse_elems(hapd, pos, left, &elems, 1) == ParseFailed)
+	{
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wme_action - could not parse wme "
+			       "action");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	if (!elems.wme_tspec ||
+	    elems.wme_tspec_len != (sizeof(struct wme_tspec_info_element) - 2))
+	{
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wme_action - missing or wrong length "
+			       "tspec");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	/* TODO: check the request is for an AC with ACM set, if not, refuse
+	 * request */
+
+	action_code = mgmt->u.action.u.wme_action.action_code;
+	switch (action_code) {
+	case WME_ACTION_CODE_SETUP_REQUEST:
+		wme_setup_request(hapd, mgmt, (struct wme_tspec_info_element *)
+				  elems.wme_tspec, len);
+		return;
+#if 0
+	/* TODO: needed for client implementation */
+	case WME_ACTION_CODE_SETUP_RESPONSE:
+		wme_setup_request(hapd, mgmt, len);
+		return;
+	/* TODO: handle station teardown requests */
+	case WME_ACTION_CODE_TEARDOWN:
+		wme_teardown(hapd, mgmt, len);
+		return;
+#endif
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "hostapd_wme_action - unknown action code %d",
+		       action_code);
+}
--- /dev/null
+++ contrib/hostapd/os_none.c
@@ -0,0 +1,220 @@
+/*
+ * wpa_supplicant/hostapd / Empty OS specific functions
+ * Copyright (c) 2005-2006, 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.
+ *
+ * This file can be used as a starting point when adding a new OS target. The
+ * functions here do not really work as-is since they are just empty or only
+ * return an error value. os_internal.c can be used as another starting point
+ * or reference since it has example implementation of many of these functions.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	return -1;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	return -1;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+	return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	return -1;
+}
+
+
+unsigned long os_random(void)
+{
+	return 0;
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	return NULL; /* strdup(rel_path) can be used here */
+}
+
+
+int os_program_init(void)
+{
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+	return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	return NULL;
+}
+
+
+void * os_zalloc(size_t size)
+{
+	return NULL;
+}
+
+
+#ifdef OS_NO_C_LIB_DEFINES
+void * os_malloc(size_t size)
+{
+	return NULL;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	return NULL;
+}
+
+
+void os_free(void *ptr)
+{
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+	return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+	return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+	return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+	return 0;
+}
+
+
+char * os_strdup(const char *s)
+{
+	return NULL;
+}
+
+
+size_t os_strlen(const char *s)
+{
+	return 0;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+	/*
+	 * Ignoring case is not required for main functionality, so just use
+	 * the case sensitive version of the function.
+	 */
+	return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+	return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+	return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+	return 0;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+	return 0;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+	return dest;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+	return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+	return 0;
+}
+#endif /* OS_NO_C_LIB_DEFINES */
Index: sha1.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/sha1.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/sha1.h -L contrib/hostapd/sha1.h -u -r1.2 -r1.3
--- contrib/hostapd/sha1.h
+++ contrib/hostapd/sha1.h
@@ -1,6 +1,6 @@
 /*
  * SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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
@@ -30,4 +30,12 @@
 void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
 		 int iterations, u8 *buf, size_t buflen);
 
+#ifdef CONFIG_CRYPTO_INTERNAL
+struct SHA1Context;
+
+void SHA1Init(struct SHA1Context *context);
+void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+
 #endif /* SHA1_H */
--- /dev/null
+++ contrib/hostapd/eap_sake.c
@@ -0,0 +1,547 @@
+/*
+ * hostapd / EAP-SAKE (RFC 4763) server
+ * Copyright (c) 2006, 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 "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_sake_common.h"
+
+
+struct eap_sake_data {
+	enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
+	u8 rand_s[EAP_SAKE_RAND_LEN];
+	u8 rand_p[EAP_SAKE_RAND_LEN];
+	struct {
+		u8 auth[EAP_SAKE_TEK_AUTH_LEN];
+		u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
+	} tek;
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 session_id;
+	u8 *peerid;
+	size_t peerid_len;
+	u8 *serverid;
+	size_t serverid_len;
+};
+
+
+static const char * eap_sake_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_sake_state(struct eap_sake_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
+		   eap_sake_state_txt(data->state),
+		   eap_sake_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_sake_init(struct eap_sm *sm)
+{
+	struct eap_sake_data *data;
+
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = CHALLENGE;
+
+	if (hostapd_get_rand(&data->session_id, 1)) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+		os_free(data);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
+		   data->session_id);
+
+	/* TODO: add support for configuring SERVERID */
+	data->serverid = (u8 *) strdup("hostapd");
+	if (data->serverid)
+		data->serverid_len = strlen((char *) data->serverid);
+
+	return data;
+}
+
+
+static void eap_sake_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	os_free(data->serverid);
+	os_free(data->peerid);
+	os_free(data);
+}
+
+
+static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload,
+			       int id, size_t *length, u8 subtype)
+{
+	struct eap_sake_hdr *req;
+	u8 *msg;
+
+	*length += sizeof(struct eap_sake_hdr);
+
+	msg = wpa_zalloc(*length);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
+			   "request");
+		return NULL;
+	}
+
+	req = (struct eap_sake_hdr *) msg;
+	req->code = EAP_CODE_REQUEST;
+	req->identifier = id;
+	req->length = htons((u16) *length);
+	req->type = EAP_TYPE_SAKE;
+	req->version = EAP_SAKE_VERSION;
+	req->session_id = data->session_id;
+	req->subtype = subtype;
+	*payload = (u8 *) (req + 1);
+
+	return msg;
+}
+
+
+static u8 * eap_sake_build_identity(struct eap_sm *sm,
+				    struct eap_sake_data *data,
+				    int id, size_t *reqDataLen)
+{
+	u8 *msg, *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
+
+	*reqDataLen = 4;
+	if (data->serverid)
+		*reqDataLen += 2 + data->serverid_len;
+	msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+				 EAP_SAKE_SUBTYPE_IDENTITY);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
+	*pos++ = EAP_SAKE_AT_PERM_ID_REQ;
+	*pos++ = 4;
+	*pos++ = 0;
+	*pos++ = 0;
+
+	if (data->serverid) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+		*pos++ = EAP_SAKE_AT_SERVERID;
+		*pos++ = 2 + data->serverid_len;
+		os_memcpy(pos, data->serverid, data->serverid_len);
+	}
+
+	return msg;
+}
+
+
+static u8 * eap_sake_build_challenge(struct eap_sm *sm,
+				     struct eap_sake_data *data,
+				     int id, size_t *reqDataLen)
+{
+	u8 *msg, *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
+
+	if (hostapd_get_rand(data->rand_s, EAP_SAKE_RAND_LEN)) {
+		wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+		data->state = FAILURE;
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
+		    data->rand_s, EAP_SAKE_RAND_LEN);
+
+	*reqDataLen = 2 + EAP_SAKE_RAND_LEN;
+	if (data->serverid)
+		*reqDataLen += 2 + data->serverid_len;
+	msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+				 EAP_SAKE_SUBTYPE_CHALLENGE);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
+	*pos++ = EAP_SAKE_AT_RAND_S;
+	*pos++ = 2 + EAP_SAKE_RAND_LEN;
+	os_memcpy(pos, data->rand_s, EAP_SAKE_RAND_LEN);
+	pos += EAP_SAKE_RAND_LEN;
+
+	if (data->serverid) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+		*pos++ = EAP_SAKE_AT_SERVERID;
+		*pos++ = 2 + data->serverid_len;
+		os_memcpy(pos, data->serverid, data->serverid_len);
+	}
+
+	return msg;
+}
+
+
+static u8 * eap_sake_build_confirm(struct eap_sm *sm,
+				   struct eap_sake_data *data,
+				   int id, size_t *reqDataLen)
+{
+	u8 *msg, *pos;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
+
+	*reqDataLen = 2 + EAP_SAKE_MIC_LEN;
+	msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+				 EAP_SAKE_SUBTYPE_CONFIRM);
+	if (msg == NULL) {
+		data->state = FAILURE;
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
+	*pos++ = EAP_SAKE_AT_MIC_S;
+	*pos++ = 2 + EAP_SAKE_MIC_LEN;
+	if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+				 data->serverid, data->serverid_len,
+				 data->peerid, data->peerid_len, 0,
+				 msg, *reqDataLen, pos, pos)) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+		data->state = FAILURE;
+		os_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static u8 * eap_sake_buildReq(struct eap_sm *sm, void *priv, int id,
+			      size_t *reqDataLen)
+{
+	struct eap_sake_data *data = priv;
+
+	switch (data->state) {
+	case IDENTITY:
+		return eap_sake_build_identity(sm, data, id, reqDataLen);
+	case CHALLENGE:
+		return eap_sake_build_challenge(sm, data, id, reqDataLen);
+	case CONFIRM:
+		return eap_sake_build_confirm(sm, data, id, reqDataLen);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
+			   data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
+			      u8 *respData, size_t respDataLen)
+{
+	struct eap_sake_data *data = priv;
+	struct eap_sake_hdr *resp;
+	size_t len;
+	u8 version, session_id, subtype;
+
+	resp = (struct eap_sake_hdr *) respData;
+	if (respDataLen < sizeof(*resp) ||
+	    resp->type != EAP_TYPE_SAKE ||
+	    (len = ntohs(resp->length)) > respDataLen ||
+	    len < sizeof(*resp)) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
+		return TRUE;
+	}
+	version = resp->version;
+	session_id = resp->session_id;
+	subtype = resp->subtype;
+
+	if (version != EAP_SAKE_VERSION) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
+		return TRUE;
+	}
+
+	if (session_id != data->session_id) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
+			   session_id, data->session_id);
+		return TRUE;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
+
+	if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
+		return FALSE;
+
+	if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
+		return FALSE;
+
+	if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
+		return FALSE;
+
+	if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
+		return FALSE;
+
+	wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
+		   subtype, data->state);
+
+	return TRUE;
+}
+
+
+static void eap_sake_process_identity(struct eap_sm *sm,
+				      struct eap_sake_data *data,
+				      u8 *respData, size_t respDataLen,
+				      u8 *payload, size_t payloadlen)
+{
+	if (data->state != IDENTITY)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
+	/* TODO: update identity and select new user data */
+	eap_sake_state(data, CHALLENGE);
+}
+
+
+static void eap_sake_process_challenge(struct eap_sm *sm,
+				       struct eap_sake_data *data,
+				       u8 *respData, size_t respDataLen,
+				       u8 *payload, size_t payloadlen)
+{
+	struct eap_sake_parse_attr attr;
+	u8 mic_p[EAP_SAKE_MIC_LEN];
+
+	if (data->state != CHALLENGE)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
+
+	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+		return;
+
+	if (!attr.rand_p || !attr.mic_p) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
+			   "include AT_RAND_P or AT_MIC_P");
+		return;
+	}
+
+	os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
+
+	os_free(data->peerid);
+	data->peerid = NULL;
+	data->peerid_len = 0;
+	if (attr.peerid) {
+		data->peerid = os_malloc(attr.peerid_len);
+		if (data->peerid == NULL)
+			return;
+		os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
+		data->peerid_len = attr.peerid_len;
+	}
+
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
+			   "%d-byte key not configured",
+			   2 * EAP_SAKE_ROOT_SECRET_LEN);
+		data->state = FAILURE;
+		return;
+	}
+	eap_sake_derive_keys(sm->user->password,
+			     sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
+			     data->rand_s, data->rand_p,
+			     (u8 *) &data->tek, data->msk, data->emsk);
+
+	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+			     data->serverid, data->serverid_len,
+			     data->peerid, data->peerid_len, 1,
+			     respData, respDataLen, attr.mic_p, mic_p);
+	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+		eap_sake_state(data, FAILURE);
+		return;
+	}
+
+	eap_sake_state(data, CONFIRM);
+}
+
+
+static void eap_sake_process_confirm(struct eap_sm *sm,
+				     struct eap_sake_data *data,
+				     u8 *respData, size_t respDataLen,
+				     u8 *payload, size_t payloadlen)
+{
+	struct eap_sake_parse_attr attr;
+	u8 mic_p[EAP_SAKE_MIC_LEN];
+
+	if (data->state != CONFIRM)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
+
+	if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+		return;
+
+	if (!attr.mic_p) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
+			   "include AT_MIC_P");
+		return;
+	}
+
+	eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+			     data->serverid, data->serverid_len,
+			     data->peerid, data->peerid_len, 1,
+			     respData, respDataLen, attr.mic_p, mic_p);
+	if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+		wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+		eap_sake_state(data, FAILURE);
+	} else
+		eap_sake_state(data, SUCCESS);
+}
+
+
+static void eap_sake_process_auth_reject(struct eap_sm *sm,
+					 struct eap_sake_data *data,
+					 u8 *respData, size_t respDataLen,
+					 u8 *payload, size_t payloadlen)
+{
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
+	eap_sake_state(data, FAILURE);
+}
+
+
+static void eap_sake_process(struct eap_sm *sm, void *priv,
+			     u8 *respData, size_t respDataLen)
+{
+	struct eap_sake_data *data = priv;
+	struct eap_sake_hdr *resp;
+	u8 subtype, *pos, *end;
+
+	resp = (struct eap_sake_hdr *) respData;
+	subtype = resp->subtype;
+	pos = (u8 *) (resp + 1);
+	end = respData + ntohs(resp->length);
+
+	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
+		    pos, end - pos);
+
+	switch (subtype) {
+	case EAP_SAKE_SUBTYPE_IDENTITY:
+		eap_sake_process_identity(sm, data, respData, respDataLen, pos,
+					  end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CHALLENGE:
+		eap_sake_process_challenge(sm, data, respData, respDataLen,
+					   pos, end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_CONFIRM:
+		eap_sake_process_confirm(sm, data, respData, respDataLen, pos,
+					 end - pos);
+		break;
+	case EAP_SAKE_SUBTYPE_AUTH_REJECT:
+		eap_sake_process_auth_reject(sm, data, respData, respDataLen,
+					     pos, end - pos);
+		break;
+	}
+}
+
+
+static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+
+	return key;
+}
+
+
+static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_sake_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_sake_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_sake_init;
+	eap->reset = eap_sake_reset;
+	eap->buildReq = eap_sake_buildReq;
+	eap->check = eap_sake_check;
+	eap->process = eap_sake_process;
+	eap->isDone = eap_sake_isDone;
+	eap->getKey = eap_sake_getKey;
+	eap->isSuccess = eap_sake_isSuccess;
+	eap->get_emsk = eap_sake_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: hostap_common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostap_common.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostap_common.h -L contrib/hostapd/hostap_common.h -u -r1.2 -r1.3
--- contrib/hostapd/hostap_common.h
+++ contrib/hostapd/hostap_common.h
@@ -1,361 +1,20 @@
+/*
+ * hostapd / Kernel driver communication with Linux Host AP driver
+ * Copyright (c) 2002-2006, 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 HOSTAP_COMMON_H
 #define HOSTAP_COMMON_H
 
-#define BIT(x) (1 << (x))
-
-#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
-
-#ifndef ETH_P_PAE
-#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
-#endif /* ETH_P_PAE */
-
-#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
-
-
-
-/* IEEE 802.11 defines */
-
-#define WLAN_FC_PVER (BIT(1) | BIT(0))
-#define WLAN_FC_TODS BIT(8)
-#define WLAN_FC_FROMDS BIT(9)
-#define WLAN_FC_MOREFRAG BIT(10)
-#define WLAN_FC_RETRY BIT(11)
-#define WLAN_FC_PWRMGT BIT(12)
-#define WLAN_FC_MOREDATA BIT(13)
-#define WLAN_FC_ISWEP BIT(14)
-#define WLAN_FC_ORDER BIT(15)
-
-#define WLAN_FC_GET_TYPE(fc) (((fc) & (BIT(3) | BIT(2))) >> 2)
-#define WLAN_FC_GET_STYPE(fc) \
-	(((fc) & (BIT(7) | BIT(6) | BIT(5) | BIT(4))) >> 4)
-
-#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
-#define WLAN_GET_SEQ_SEQ(seq) \
-	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
-
-#define WLAN_FC_TYPE_MGMT 0
-#define WLAN_FC_TYPE_CTRL 1
-#define WLAN_FC_TYPE_DATA 2
-
-/* management */
-#define WLAN_FC_STYPE_ASSOC_REQ 0
-#define WLAN_FC_STYPE_ASSOC_RESP 1
-#define WLAN_FC_STYPE_REASSOC_REQ 2
-#define WLAN_FC_STYPE_REASSOC_RESP 3
-#define WLAN_FC_STYPE_PROBE_REQ 4
-#define WLAN_FC_STYPE_PROBE_RESP 5
-#define WLAN_FC_STYPE_BEACON 8
-#define WLAN_FC_STYPE_ATIM 9
-#define WLAN_FC_STYPE_DISASSOC 10
-#define WLAN_FC_STYPE_AUTH 11
-#define WLAN_FC_STYPE_DEAUTH 12
-
-/* control */
-#define WLAN_FC_STYPE_PSPOLL 10
-#define WLAN_FC_STYPE_RTS 11
-#define WLAN_FC_STYPE_CTS 12
-#define WLAN_FC_STYPE_ACK 13
-#define WLAN_FC_STYPE_CFEND 14
-#define WLAN_FC_STYPE_CFENDACK 15
-
-/* data */
-#define WLAN_FC_STYPE_DATA 0
-#define WLAN_FC_STYPE_DATA_CFACK 1
-#define WLAN_FC_STYPE_DATA_CFPOLL 2
-#define WLAN_FC_STYPE_DATA_CFACKPOLL 3
-#define WLAN_FC_STYPE_NULLFUNC 4
-#define WLAN_FC_STYPE_CFACK 5
-#define WLAN_FC_STYPE_CFPOLL 6
-#define WLAN_FC_STYPE_CFACKPOLL 7
-
-/* Authentication algorithms */
-#define WLAN_AUTH_OPEN 0
-#define WLAN_AUTH_SHARED_KEY 1
-
-#define WLAN_AUTH_CHALLENGE_LEN 128
-
-#define WLAN_CAPABILITY_ESS BIT(0)
-#define WLAN_CAPABILITY_IBSS BIT(1)
-#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
-#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
-#define WLAN_CAPABILITY_PRIVACY BIT(4)
-
-/* Status codes */
-#define WLAN_STATUS_SUCCESS 0
-#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
-#define WLAN_STATUS_CAPS_UNSUPPORTED 10
-#define WLAN_STATUS_REASSOC_NO_ASSOC 11
-#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
-#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
-#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
-#define WLAN_STATUS_CHALLENGE_FAIL 15
-#define WLAN_STATUS_AUTH_TIMEOUT 16
-#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
-#define WLAN_STATUS_ASSOC_DENIED_RATES 18
-/* 802.11b */
-#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
-#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
-#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
-/* IEEE 802.11i */
-#define WLAN_STATUS_INVALID_IE 40
-#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
-#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
-#define WLAN_STATUS_AKMP_NOT_VALID 43
-#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
-#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
-#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
-
-/* Reason codes */
-#define WLAN_REASON_UNSPECIFIED 1
-#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
-#define WLAN_REASON_DEAUTH_LEAVING 3
-#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
-#define WLAN_REASON_DISASSOC_AP_BUSY 5
-#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
-#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
-#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
-#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
-/* IEEE 802.11i */
-#define WLAN_REASON_INVALID_IE 13
-#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
-#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
-#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
-#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
-#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
-#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
-#define WLAN_REASON_AKMP_NOT_VALID 20
-#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
-#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
-#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
-#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
-
-
-/* Information Element IDs */
-#define WLAN_EID_SSID 0
-#define WLAN_EID_SUPP_RATES 1
-#define WLAN_EID_FH_PARAMS 2
-#define WLAN_EID_DS_PARAMS 3
-#define WLAN_EID_CF_PARAMS 4
-#define WLAN_EID_TIM 5
-#define WLAN_EID_IBSS_PARAMS 6
-#define WLAN_EID_CHALLENGE 16
-#define WLAN_EID_RSN 48
-#define WLAN_EID_GENERIC 221
-
-
-/* HFA384X Configuration RIDs */
-#define HFA384X_RID_CNFPORTTYPE 0xFC00
-#define HFA384X_RID_CNFOWNMACADDR 0xFC01
-#define HFA384X_RID_CNFDESIREDSSID 0xFC02
-#define HFA384X_RID_CNFOWNCHANNEL 0xFC03
-#define HFA384X_RID_CNFOWNSSID 0xFC04
-#define HFA384X_RID_CNFOWNATIMWINDOW 0xFC05
-#define HFA384X_RID_CNFSYSTEMSCALE 0xFC06
-#define HFA384X_RID_CNFMAXDATALEN 0xFC07
-#define HFA384X_RID_CNFWDSADDRESS 0xFC08
-#define HFA384X_RID_CNFPMENABLED 0xFC09
-#define HFA384X_RID_CNFPMEPS 0xFC0A
-#define HFA384X_RID_CNFMULTICASTRECEIVE 0xFC0B
-#define HFA384X_RID_CNFMAXSLEEPDURATION 0xFC0C
-#define HFA384X_RID_CNFPMHOLDOVERDURATION 0xFC0D
-#define HFA384X_RID_CNFOWNNAME 0xFC0E
-#define HFA384X_RID_CNFOWNDTIMPERIOD 0xFC10
-#define HFA384X_RID_CNFWDSADDRESS1 0xFC11 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS2 0xFC12 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS3 0xFC13 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS4 0xFC14 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS5 0xFC15 /* AP f/w only */
-#define HFA384X_RID_CNFWDSADDRESS6 0xFC16 /* AP f/w only */
-#define HFA384X_RID_CNFMULTICASTPMBUFFERING 0xFC17 /* AP f/w only */
-#define HFA384X_RID_UNKNOWN1 0xFC20
-#define HFA384X_RID_UNKNOWN2 0xFC21
-#define HFA384X_RID_CNFWEPDEFAULTKEYID 0xFC23
-#define HFA384X_RID_CNFDEFAULTKEY0 0xFC24
-#define HFA384X_RID_CNFDEFAULTKEY1 0xFC25
-#define HFA384X_RID_CNFDEFAULTKEY2 0xFC26
-#define HFA384X_RID_CNFDEFAULTKEY3 0xFC27
-#define HFA384X_RID_CNFWEPFLAGS 0xFC28
-#define HFA384X_RID_CNFWEPKEYMAPPINGTABLE 0xFC29
-#define HFA384X_RID_CNFAUTHENTICATION 0xFC2A
-#define HFA384X_RID_CNFMAXASSOCSTA 0xFC2B /* AP f/w only */
-#define HFA384X_RID_CNFTXCONTROL 0xFC2C
-#define HFA384X_RID_CNFROAMINGMODE 0xFC2D
-#define HFA384X_RID_CNFHOSTAUTHENTICATION 0xFC2E /* AP f/w only */
-#define HFA384X_RID_CNFRCVCRCERROR 0xFC30
-#define HFA384X_RID_CNFMMLIFE 0xFC31
-#define HFA384X_RID_CNFALTRETRYCOUNT 0xFC32
-#define HFA384X_RID_CNFBEACONINT 0xFC33
-#define HFA384X_RID_CNFAPPCFINFO 0xFC34 /* AP f/w only */
-#define HFA384X_RID_CNFSTAPCFINFO 0xFC35
-#define HFA384X_RID_CNFPRIORITYQUSAGE 0xFC37
-#define HFA384X_RID_CNFTIMCTRL 0xFC40
-#define HFA384X_RID_UNKNOWN3 0xFC41 /* added in STA f/w 0.7.x */
-#define HFA384X_RID_CNFTHIRTY2TALLY 0xFC42 /* added in STA f/w 0.8.0 */
-#define HFA384X_RID_CNFENHSECURITY 0xFC43 /* AP f/w or STA f/w >= 1.6.3 */
-#define HFA384X_RID_CNFDBMADJUST 0xFC46 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_GENERICELEMENT 0xFC48 /* added in STA f/w 1.7.0;
-					   * write only */
-#define HFA384X_RID_PROPAGATIONDELAY 0xFC49 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_GROUPADDRESSES 0xFC80
-#define HFA384X_RID_CREATEIBSS 0xFC81
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD 0xFC82
-#define HFA384X_RID_RTSTHRESHOLD 0xFC83
-#define HFA384X_RID_TXRATECONTROL 0xFC84
-#define HFA384X_RID_PROMISCUOUSMODE 0xFC85
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD0 0xFC90 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD1 0xFC91 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD2 0xFC92 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD3 0xFC93 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD4 0xFC94 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD5 0xFC95 /* AP f/w only */
-#define HFA384X_RID_FRAGMENTATIONTHRESHOLD6 0xFC96 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD0 0xFC97 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD1 0xFC98 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD2 0xFC99 /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD3 0xFC9A /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD4 0xFC9B /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD5 0xFC9C /* AP f/w only */
-#define HFA384X_RID_RTSTHRESHOLD6 0xFC9D /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL0 0xFC9E /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL1 0xFC9F /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL2 0xFCA0 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL3 0xFCA1 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL4 0xFCA2 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL5 0xFCA3 /* AP f/w only */
-#define HFA384X_RID_TXRATECONTROL6 0xFCA4 /* AP f/w only */
-#define HFA384X_RID_CNFSHORTPREAMBLE 0xFCB0
-#define HFA384X_RID_CNFEXCLUDELONGPREAMBLE 0xFCB1
-#define HFA384X_RID_CNFAUTHENTICATIONRSPTO 0xFCB2
-#define HFA384X_RID_CNFBASICRATES 0xFCB3
-#define HFA384X_RID_CNFSUPPORTEDRATES 0xFCB4
-#define HFA384X_RID_CNFFALLBACKCTRL 0xFCB5 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYDISABLE 0xFCB6 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_WEPKEYMAPINDEX 0xFCB7 /* ? */
-#define HFA384X_RID_BROADCASTKEYID 0xFCB8 /* ? */
-#define HFA384X_RID_ENTSECFLAGEYID 0xFCB9 /* ? */
-#define HFA384X_RID_CNFPASSIVESCANCTRL 0xFCBA /* added in STA f/w 1.5.0 */
-#define HFA384X_RID_SSNHANDLINGMODE 0xFCBB /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCONTROL 0xFCBC /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_MDCCOUNTRY 0xFCBD /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_TXPOWERMAX 0xFCBE /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_CNFLFOENABLED 0xFCBF /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_CAPINFO 0xFCC0 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_LISTENINTERVAL 0xFCC1 /* added in STA f/w 1.7.0 */
-#define HFA384X_RID_SW_ANT_DIV 0xFCC2 /* added in STA f/w 1.7.0; Prism3 */
-#define HFA384X_RID_LED_CTRL 0xFCC4 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_HFODELAY 0xFCC5 /* added in STA f/w 1.7.6 */
-#define HFA384X_RID_DISALLOWEDBSSID 0xFCC6 /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_TICKTIME 0xFCE0
-#define HFA384X_RID_SCANREQUEST 0xFCE1
-#define HFA384X_RID_JOINREQUEST 0xFCE2
-#define HFA384X_RID_AUTHENTICATESTATION 0xFCE3 /* AP f/w only */
-#define HFA384X_RID_CHANNELINFOREQUEST 0xFCE4 /* AP f/w only */
-#define HFA384X_RID_HOSTSCAN 0xFCE5 /* added in STA f/w 1.3.1 */
-
-/* HFA384X Information RIDs */
-#define HFA384X_RID_MAXLOADTIME 0xFD00
-#define HFA384X_RID_DOWNLOADBUFFER 0xFD01
-#define HFA384X_RID_PRIID 0xFD02
-#define HFA384X_RID_PRISUPRANGE 0xFD03
-#define HFA384X_RID_CFIACTRANGES 0xFD04
-#define HFA384X_RID_NICSERNUM 0xFD0A
-#define HFA384X_RID_NICID 0xFD0B
-#define HFA384X_RID_MFISUPRANGE 0xFD0C
-#define HFA384X_RID_CFISUPRANGE 0xFD0D
-#define HFA384X_RID_CHANNELLIST 0xFD10
-#define HFA384X_RID_REGULATORYDOMAINS 0xFD11
-#define HFA384X_RID_TEMPTYPE 0xFD12
-#define HFA384X_RID_CIS 0xFD13
-#define HFA384X_RID_STAID 0xFD20
-#define HFA384X_RID_STASUPRANGE 0xFD21
-#define HFA384X_RID_MFIACTRANGES 0xFD22
-#define HFA384X_RID_CFIACTRANGES2 0xFD23
-#define HFA384X_RID_PRODUCTNAME 0xFD24 /* added in STA f/w 1.3.1;
-					* only Prism2.5(?) */
-#define HFA384X_RID_PORTSTATUS 0xFD40
-#define HFA384X_RID_CURRENTSSID 0xFD41
-#define HFA384X_RID_CURRENTBSSID 0xFD42
-#define HFA384X_RID_COMMSQUALITY 0xFD43
-#define HFA384X_RID_CURRENTTXRATE 0xFD44
-#define HFA384X_RID_CURRENTBEACONINTERVAL 0xFD45
-#define HFA384X_RID_CURRENTSCALETHRESHOLDS 0xFD46
-#define HFA384X_RID_PROTOCOLRSPTIME 0xFD47
-#define HFA384X_RID_SHORTRETRYLIMIT 0xFD48
-#define HFA384X_RID_LONGRETRYLIMIT 0xFD49
-#define HFA384X_RID_MAXTRANSMITLIFETIME 0xFD4A
-#define HFA384X_RID_MAXRECEIVELIFETIME 0xFD4B
-#define HFA384X_RID_CFPOLLABLE 0xFD4C
-#define HFA384X_RID_AUTHENTICATIONALGORITHMS 0xFD4D
-#define HFA384X_RID_PRIVACYOPTIONIMPLEMENTED 0xFD4F
-#define HFA384X_RID_DBMCOMMSQUALITY 0xFD51 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_CURRENTTXRATE1 0xFD80 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE2 0xFD81 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE3 0xFD82 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE4 0xFD83 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE5 0xFD84 /* AP f/w only */
-#define HFA384X_RID_CURRENTTXRATE6 0xFD85 /* AP f/w only */
-#define HFA384X_RID_OWNMACADDR 0xFD86 /* AP f/w only */
-#define HFA384X_RID_SCANRESULTSTABLE 0xFD88 /* added in STA f/w 0.8.3 */
-#define HFA384X_RID_HOSTSCANRESULTS 0xFD89 /* added in STA f/w 1.3.1 */
-#define HFA384X_RID_AUTHENTICATIONUSED 0xFD8A /* added in STA f/w 1.3.4 */
-#define HFA384X_RID_CNFFAASWITCHCTRL 0xFD8B /* added in STA f/w 1.6.3 */
-#define HFA384X_RID_ASSOCIATIONFAILURE 0xFD8D /* added in STA f/w 1.8.0 */
-#define HFA384X_RID_PHYTYPE 0xFDC0
-#define HFA384X_RID_CURRENTCHANNEL 0xFDC1
-#define HFA384X_RID_CURRENTPOWERSTATE 0xFDC2
-#define HFA384X_RID_CCAMODE 0xFDC3
-#define HFA384X_RID_SUPPORTEDDATARATES 0xFDC6
-#define HFA384X_RID_LFO_VOLT_REG_TEST_RES 0xFDC7 /* added in STA f/w 1.7.1 */
-#define HFA384X_RID_BUILDSEQ 0xFFFE
-#define HFA384X_RID_FWID 0xFFFF
-
-
-struct hfa384x_comp_ident
-{
-	u16 id;
-	u16 variant;
-	u16 major;
-	u16 minor;
-} __attribute__ ((packed));
-
-#define HFA384X_COMP_ID_PRI 0x15
-#define HFA384X_COMP_ID_STA 0x1f
-#define HFA384X_COMP_ID_FW_AP 0x14b
-
-struct hfa384x_sup_range
-{
-	u16 role;
-	u16 id;
-	u16 variant;
-	u16 bottom;
-	u16 top;
-} __attribute__ ((packed));
-
-
-struct hfa384x_build_id
-{
-	u16 pri_seq;
-	u16 sec_seq;
-} __attribute__ ((packed));
-
-/* FD01 - Download Buffer */
-struct hfa384x_rid_download_buffer
-{
-	u16 page;
-	u16 offset;
-	u16 length;
-} __attribute__ ((packed));
-
-/* BSS connection quality (RID FD43 range, RID FD51 dBm-normalized) */
-struct hfa384x_comms_quality {
-	u16 comm_qual; /* 0 .. 92 */
-	u16 signal_level; /* 27 .. 154 */
-	u16 noise_level; /* 27 .. 154 */
-} __attribute__ ((packed));
-
-
 /* netdevice private ioctls (used, e.g., with iwpriv from user space) */
 
 /* New wireless extensions API - SET/GET convention (even ioctl numbers are
@@ -554,5 +213,4 @@
 #define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
 #define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
 
-
 #endif /* HOSTAP_COMMON_H */
Index: eap.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap.c -L contrib/hostapd/eap.c -u -r1.2 -r1.3
--- contrib/hostapd/eap.c
+++ contrib/hostapd/eap.c
@@ -1,6 +1,6 @@
 /*
- * hostapd / EAP Standalone Authenticator state machine
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / EAP Standalone Authenticator state machine (RFC 4137)
+ * Copyright (c) 2004-2006, 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
@@ -11,106 +11,25 @@
  *
  * See README and COPYING for more details.
  *
- * $FreeBSD: src/contrib/hostapd/eap.c,v 1.2.2.1 2006/03/24 01:42:33 sam Exp $
+ * $FreeBSD: src/contrib/hostapd/eap.c,v 1.4 2007/07/09 16:20:41 sam Exp $
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/socket.h>
+#include "includes.h"
 
 #include "hostapd.h"
-#include "eloop.h"
 #include "sta_info.h"
 #include "eap_i.h"
+#include "state_machine.h"
 
-#define EAP_MAX_AUTH_ROUNDS 50
-
-extern const struct eap_method eap_method_identity;
-#ifdef EAP_MD5
-extern const struct eap_method eap_method_md5;
-#endif /* EAP_MD5 */
-#ifdef EAP_TLS
-extern const struct eap_method eap_method_tls;
-#endif /* EAP_TLS */
-#ifdef EAP_MSCHAPv2
-extern const struct eap_method eap_method_mschapv2;
-#endif /* EAP_MSCHAPv2 */
-#ifdef EAP_PEAP
-extern const struct eap_method eap_method_peap;
-#endif /* EAP_PEAP */
-#ifdef EAP_TLV
-extern const struct eap_method eap_method_tlv;
-#endif /* EAP_TLV */
-#ifdef EAP_GTC
-extern const struct eap_method eap_method_gtc;
-#endif /* EAP_GTC */
-#ifdef EAP_TTLS
-extern const struct eap_method eap_method_ttls;
-#endif /* EAP_TTLS */
-#ifdef EAP_SIM
-extern const struct eap_method eap_method_sim;
-#endif /* EAP_SIM */
-#ifdef EAP_PAX
-extern const struct eap_method eap_method_pax;
-#endif /* EAP_PAX */
-#ifdef EAP_PSK
-extern const struct eap_method eap_method_psk;
-#endif /* EAP_PSK */
-
-static const struct eap_method *eap_methods[] =
-{
-	&eap_method_identity,
-#ifdef EAP_MD5
-	&eap_method_md5,
-#endif /* EAP_MD5 */
-#ifdef EAP_TLS
-	&eap_method_tls,
-#endif /* EAP_TLS */
-#ifdef EAP_MSCHAPv2
-	&eap_method_mschapv2,
-#endif /* EAP_MSCHAPv2 */
-#ifdef EAP_PEAP
-	&eap_method_peap,
-#endif /* EAP_PEAP */
-#ifdef EAP_TTLS
-	&eap_method_ttls,
-#endif /* EAP_TTLS */
-#ifdef EAP_TLV
-	&eap_method_tlv,
-#endif /* EAP_TLV */
-#ifdef EAP_GTC
-	&eap_method_gtc,
-#endif /* EAP_GTC */
-#ifdef EAP_SIM
-	&eap_method_sim,
-#endif /* EAP_SIM */
-#ifdef EAP_PAX
-	&eap_method_pax,
-#endif /* EAP_PAX */
-#ifdef EAP_PSK
-	&eap_method_psk,
-#endif /* EAP_PSK */
-};
-#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
-
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
 
-const struct eap_method * eap_sm_get_eap_methods(int method)
-{
-	int i;
-	for (i = 0; i < NUM_EAP_METHODS; i++) {
-		if (eap_methods[i]->method == method)
-			return eap_methods[i];
-	}
-	return NULL;
-}
+#define EAP_MAX_AUTH_ROUNDS 50
 
 static void eap_user_free(struct eap_user *user);
 
 
-/* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
+/* EAP state machines are described in RFC 4137 */
 
 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
 				   int eapSRTT, int eapRTTVAR,
@@ -120,34 +39,11 @@
 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
 static int eap_sm_nextId(struct eap_sm *sm, int id);
 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
 
 
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
-	int global)
-
-#define SM_ENTRY(machine, state) \
-if (!global || sm->machine ## _state != machine ## _ ## state) { \
-	sm->changed = TRUE; \
-	wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
-} \
-sm->machine ## _state = machine ## _ ## state;
-
-#define SM_ENTER(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 0)
-#define SM_ENTER_GLOBAL(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 1)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct eap_sm *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-
 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
 {
 	return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
@@ -179,6 +75,19 @@
 }
 
 
+/**
+ * eap_user_get - Fetch user information from the database
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @identity: Identity (User-Name) of the user
+ * @identity_len: Length of identity in bytes
+ * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function is used to fetch user information for EAP. The user will be
+ * selected based on the specified identity. sm->user and
+ * sm->user_eap_method_index are updated for the new user when a matching user
+ * is found. sm->user can be used to get user information (e.g., password).
+ */
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
 		 int phase2)
 {
@@ -191,10 +100,9 @@
 	eap_user_free(sm->user);
 	sm->user = NULL;
 
-	user = malloc(sizeof(*user));
+	user = wpa_zalloc(sizeof(*user));
 	if (user == NULL)
 	    return -1;
-	memset(user, 0, sizeof(*user));
 
 	if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
 				       identity_len, phase2, user) != 0) {
@@ -230,9 +138,11 @@
 	/* eapKeyAvailable = FALSE */
 	eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
 
-	/* This is not defined in draft-ietf-eap-statemachine-05.txt, but
-	 * method state needs to be reseted here so that it does not remain in
-	 * success state when re-authentication starts. */
+	/*
+	 * This is not defined in RFC 4137, but method state needs to be
+	 * reseted here so that it does not remain in success state when
+	 * re-authentication starts.
+	 */
 	if (sm->m && sm->eap_method_priv) {
 		sm->m->reset(sm, sm->eap_method_priv);
 		sm->eap_method_priv = NULL;
@@ -249,6 +159,7 @@
 		}
 	}
 	sm->num_rounds = 0;
+	sm->method_pending = METHOD_PENDING_NONE;
 }
 
 
@@ -262,7 +173,8 @@
 			sm->m->reset(sm, sm->eap_method_priv);
 			sm->eap_method_priv = NULL;
 		}
-		sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+		sm->m = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+					       sm->currentMethod);
 		if (sm->m && sm->m->initPickUp) {
 			sm->eap_method_priv = sm->m->initPickUp(sm);
 			if (sm->eap_method_priv == NULL) {
@@ -399,14 +311,21 @@
 
 SM_STATE(EAP, PROPOSE_METHOD)
 {
+	int vendor;
+	EapType type;
+
 	SM_ENTRY(EAP, PROPOSE_METHOD);
 
-	sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
+	type = eap_sm_Policy_getNextMethod(sm, &vendor);
+	if (vendor == EAP_VENDOR_IETF)
+		sm->currentMethod = type;
+	else
+		sm->currentMethod = EAP_TYPE_EXPANDED;
 	if (sm->m && sm->eap_method_priv) {
 		sm->m->reset(sm, sm->eap_method_priv);
 		sm->eap_method_priv = NULL;
 	}
-	sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+	sm->m = eap_sm_get_eap_methods(vendor, type);
 	if (sm->m) {
 		sm->eap_method_priv = sm->m->init(sm);
 		if (sm->eap_method_priv == NULL) {
@@ -536,7 +455,9 @@
 				SM_ENTER(EAP, SELECT_ACTION);
 			else if (sm->rxResp &&
 				 (sm->respMethod == EAP_TYPE_NAK ||
-				  sm->respMethod == EAP_TYPE_EXPANDED_NAK))
+				  (sm->respMethod == EAP_TYPE_EXPANDED &&
+				   sm->respVendor == EAP_VENDOR_IETF &&
+				   sm->respVendorMethod == EAP_TYPE_NAK)))
 				SM_ENTER(EAP, NAK);
 			else
 				SM_ENTER(EAP, PICK_UP_METHOD);
@@ -570,14 +491,25 @@
 	case EAP_RECEIVED:
 		if (sm->rxResp && (sm->respId == sm->currentId) &&
 		    (sm->respMethod == EAP_TYPE_NAK ||
-		     sm->respMethod == EAP_TYPE_EXPANDED_NAK)
+		     (sm->respMethod == EAP_TYPE_EXPANDED &&
+		      sm->respVendor == EAP_VENDOR_IETF &&
+		      sm->respVendorMethod == EAP_TYPE_NAK))
 		    && (sm->methodState == METHOD_PROPOSED))
 			SM_ENTER(EAP, NAK);
 		else if (sm->rxResp && (sm->respId == sm->currentId) &&
-			 (sm->respMethod == sm->currentMethod))
+			 ((sm->respMethod == sm->currentMethod) ||
+			  (sm->respMethod == EAP_TYPE_EXPANDED &&
+			   sm->respVendor == EAP_VENDOR_IETF &&
+			   sm->respVendorMethod == sm->currentMethod)))
 			SM_ENTER(EAP, INTEGRITY_CHECK);
-		else
+		else {
+			wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
+				   "rxResp=%d respId=%d currentId=%d "
+				   "respMethod=%d currentMethod=%d",
+				   sm->rxResp, sm->respId, sm->currentId,
+				   sm->respMethod, sm->currentMethod);
 			SM_ENTER(EAP, DISCARD);
+		}
 		break;
 	case EAP_DISCARD:
 		SM_ENTER(EAP, IDLE);
@@ -595,13 +527,48 @@
 		SM_ENTER(EAP, SEND_REQUEST);
 		break;
 	case EAP_METHOD_RESPONSE:
+		/*
+		 * Note: Mechanism to allow EAP methods to wait while going
+		 * through pending processing is an extension to RFC 4137
+		 * which only defines the transits to SELECT_ACTION and
+		 * METHOD_REQUEST from this METHOD_RESPONSE state.
+		 */
 		if (sm->methodState == METHOD_END)
 			SM_ENTER(EAP, SELECT_ACTION);
-		else
+		else if (sm->method_pending == METHOD_PENDING_WAIT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+				   "processing - wait before proceeding to "
+				   "METHOD_REQUEST state");
+		} else if (sm->method_pending == METHOD_PENDING_CONT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+				   "pending processing - reprocess pending "
+				   "EAP message");
+			sm->method_pending = METHOD_PENDING_NONE;
+			SM_ENTER(EAP, METHOD_RESPONSE);
+		} else
 			SM_ENTER(EAP, METHOD_REQUEST);
 		break;
 	case EAP_PROPOSE_METHOD:
-		SM_ENTER(EAP, METHOD_REQUEST);
+		/*
+		 * Note: Mechanism to allow EAP methods to wait while going
+		 * through pending processing is an extension to RFC 4137
+		 * which only defines the transit to METHOD_REQUEST from this
+		 * PROPOSE_METHOD state.
+		 */
+		if (sm->method_pending == METHOD_PENDING_WAIT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+				   "processing - wait before proceeding to "
+				   "METHOD_REQUEST state");
+			if (sm->user_eap_method_index > 0)
+				sm->user_eap_method_index--;
+		} else if (sm->method_pending == METHOD_PENDING_CONT) {
+			wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+				   "pending processing - reprocess pending "
+				   "EAP message");
+			sm->method_pending = METHOD_PENDING_NONE;
+			SM_ENTER(EAP, PROPOSE_METHOD);
+		} else
+			SM_ENTER(EAP, METHOD_REQUEST);
 		break;
 	case EAP_NAK:
 		SM_ENTER(EAP, SELECT_ACTION);
@@ -644,6 +611,8 @@
 	sm->rxResp = FALSE;
 	sm->respId = -1;
 	sm->respMethod = EAP_TYPE_NONE;
+	sm->respVendor = EAP_VENDOR_IETF;
+	sm->respVendorMethod = EAP_TYPE_NONE;
 
 	if (resp == NULL || len < sizeof(*hdr))
 		return;
@@ -662,11 +631,26 @@
 	if (hdr->code == EAP_CODE_RESPONSE)
 		sm->rxResp = TRUE;
 
-	if (len > sizeof(*hdr))
-		sm->respMethod = *((u8 *) (hdr + 1));
+	if (plen > sizeof(*hdr)) {
+		u8 *pos = (u8 *) (hdr + 1);
+		sm->respMethod = *pos++;
+		if (sm->respMethod == EAP_TYPE_EXPANDED) {
+			if (plen < sizeof(*hdr) + 8) {
+				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+					   "expanded EAP-Packet (plen=%lu)",
+					   (unsigned long) plen);
+				return;
+			}
+			sm->respVendor = WPA_GET_BE24(pos);
+			pos += 3;
+			sm->respVendorMethod = WPA_GET_BE32(pos);
+		}
+	}
 
 	wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
-		   "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
+		   "respMethod=%u respVendor=%u respVendorMethod=%u",
+		   sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
+		   sm->respVendorMethod);
 }
 
 
@@ -707,7 +691,7 @@
 static int eap_sm_nextId(struct eap_sm *sm, int id)
 {
 	if (id < 0) {
-		/* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
+		/* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
 		 * random number */
 		id = rand() & 0xff;
 		if (id != sm->lastId)
@@ -717,22 +701,40 @@
 }
 
 
+/**
+ * eap_sm_process_nak - Process EAP-Response/Nak
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @nak_list: Nak list (allowed methods) from the supplicant
+ * @len: Length of nak_list in bytes
+ *
+ * This function is called when EAP-Response/Nak is received from the
+ * supplicant. This can happen for both phase 1 and phase 2 authentications.
+ */
 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
 {
-	int i, j;
+	int i;
+	size_t j;
+
+	if (sm->user == NULL)
+		return;
 
 	wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
 		   "index %d)", sm->user_eap_method_index);
 
 	wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
-		    sm->user->methods, EAP_MAX_METHODS);
+		    (u8 *) sm->user->methods,
+		    EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
 	wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
 		    nak_list, len);
 
 	i = sm->user_eap_method_index;
-	while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
+	while (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)
+			goto not_found;
 		for (j = 0; j < len; j++) {
-			if (nak_list[j] == sm->user->methods[i]) {
+			if (nak_list[j] == sm->user->methods[i].method) {
 				break;
 			}
 		}
@@ -743,14 +745,19 @@
 			continue;
 		}
 
+	not_found:
 		/* not found - remove from the list */
 		memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
-			EAP_MAX_METHODS - i - 1);
-		sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
+			(EAP_MAX_METHODS - i - 1) *
+			sizeof(sm->user->methods[0]));
+		sm->user->methods[EAP_MAX_METHODS - 1].vendor =
+			EAP_VENDOR_IETF;
+		sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
 	}
 
 	wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
-		    sm->user->methods, EAP_MAX_METHODS);
+		    (u8 *) sm->user->methods, EAP_MAX_METHODS *
+		    sizeof(sm->user->methods[0]));
 }
 
 
@@ -770,9 +777,10 @@
 }
 
 
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
 {
 	EapType next;
+	int idx = sm->user_eap_method_index;
 
 	/* In theory, there should be no problems with starting
 	 * re-authentication with something else than EAP-Request/Identity and
@@ -782,16 +790,21 @@
 	 * Re-auth sets currentId == -1, so that can be used here to select
 	 * whether Identity needs to be requested again. */
 	if (sm->identity == NULL || sm->currentId == -1) {
+		*vendor = EAP_VENDOR_IETF;
 		next = EAP_TYPE_IDENTITY;
 		sm->update_user = TRUE;
-	} else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		   sm->user->methods[sm->user_eap_method_index] !=
-		   EAP_TYPE_NONE) {
-		next = sm->user->methods[sm->user_eap_method_index++];
+	} else if (sm->user && idx < EAP_MAX_METHODS &&
+		   (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
+		    sm->user->methods[idx].method != EAP_TYPE_NONE)) {
+		*vendor = sm->user->methods[idx].vendor;
+		next = sm->user->methods[idx].method;
+		sm->user_eap_method_index++;
 	} else {
+		*vendor = EAP_VENDOR_IETF;
 		next = EAP_TYPE_NONE;
 	}
-	wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
+	wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
+		   *vendor, next);
 	return next;
 }
 
@@ -824,7 +837,10 @@
 	}
 
 	if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-	    sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
+	    (sm->user->methods[sm->user_eap_method_index].vendor !=
+	     EAP_VENDOR_IETF ||
+	     sm->user->methods[sm->user_eap_method_index].method !=
+	     EAP_TYPE_NONE)) {
 		wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
 			   "available -> CONTINUE");
 		return DECISION_CONTINUE;
@@ -848,6 +864,15 @@
 }
 
 
+/**
+ * eap_sm_step - Step EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
 int eap_sm_step(struct eap_sm *sm)
 {
 	int res = 0;
@@ -861,17 +886,14 @@
 }
 
 
-u8 eap_get_type(const char *name)
-{
-	int i;
-	for (i = 0; i < NUM_EAP_METHODS; i++) {
-		if (strcmp(eap_methods[i]->name, name) == 0)
-			return eap_methods[i]->method;
-	}
-	return EAP_TYPE_NONE;
-}
-
-
+/**
+ * eap_set_eapRespData - Set EAP response (eapRespData)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @eapRespData: EAP-Response payload from the supplicant
+ * @eapRespDataLen: Length of eapRespData in bytes
+ *
+ * This function is called when an EAP-Response is received from a supplicant.
+ */
 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
 			 size_t eapRespDataLen)
 {
@@ -898,21 +920,29 @@
 }
 
 
+/**
+ * eap_sm_init - Allocate and initialize EAP state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine.
+ */
 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
-			    struct eap_config *eap_conf)
+			    struct eap_config *conf)
 {
 	struct eap_sm *sm;
 
-	sm = malloc(sizeof(*sm));
+	sm = wpa_zalloc(sizeof(*sm));
 	if (sm == NULL)
 		return NULL;
-	memset(sm, 0, sizeof(*sm));
 	sm->eapol_ctx = eapol_ctx;
 	sm->eapol_cb = eapol_cb;
 	sm->MaxRetrans = 10;
-	sm->ssl_ctx = eap_conf->ssl_ctx;
-	sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
-	sm->backend_auth = eap_conf->backend_auth;
+	sm->ssl_ctx = conf->ssl_ctx;
+	sm->eap_sim_db_priv = conf->eap_sim_db_priv;
+	sm->backend_auth = conf->backend_auth;
 
 	wpa_printf(MSG_DEBUG, "EAP: State machine created");
 
@@ -920,6 +950,13 @@
 }
 
 
+/**
+ * eap_sm_deinit - Deinitialize and free an EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
 void eap_sm_deinit(struct eap_sm *sm)
 {
 	if (sm == NULL)
@@ -937,6 +974,13 @@
 }
 
 
+/**
+ * eap_sm_notify_cached - Notify EAP state machine of cached PMK
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when PMKSA caching is used to skip EAP
+ * authentication.
+ */
 void eap_sm_notify_cached(struct eap_sm *sm)
 {
 	if (sm == NULL)
@@ -944,3 +988,153 @@
 
 	sm->EAP_state = EAP_SUCCESS;
 }
+
+
+/**
+ * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when data for a pending EAP-Request is received.
+ */
+void eap_sm_pending_cb(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
+	if (sm->method_pending == METHOD_PENDING_WAIT)
+		sm->method_pending = METHOD_PENDING_CONT;
+}
+
+
+/**
+ * eap_sm_method_pending - Query whether EAP method is waiting for pending data
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if method is waiting for pending data or 0 if not
+ */
+int eap_sm_method_pending(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->method_pending == METHOD_PENDING_WAIT;
+}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @vendor: Expected EAP Vendor-Id (0 = IETF)
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @msglen: Length of msg
+ * @plen: Pointer to variable to contain the returned payload length
+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure
+ *
+ * This is a helper function for EAP method implementations. This is usually
+ * called in the beginning of struct eap_method::process() function to verify
+ * that the received EAP request packet has a valid header. This function is
+ * able to process both legacy and expanded EAP headers and in most cases, the
+ * caller can just use the returned payload pointer (into *plen) for processing
+ * the payload regardless of whether the packet used the expanded EAP header or
+ * not.
+ */
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const u8 *msg, size_t msglen, size_t *plen)
+{
+	const struct eap_hdr *hdr;
+	const u8 *pos;
+	size_t len;
+
+	hdr = (const struct eap_hdr *) msg;
+
+	if (msglen < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+		return NULL;
+	}
+
+	len = be_to_host16(hdr->length);
+	if (len < sizeof(*hdr) + 1 || len > msglen) {
+		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+		return NULL;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+
+	if (*pos == EAP_TYPE_EXPANDED) {
+		int exp_vendor;
+		u32 exp_type;
+		if (len < sizeof(*hdr) + 8) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
+				   "length");
+			return NULL;
+		}
+		pos++;
+		exp_vendor = WPA_GET_BE24(pos);
+		pos += 3;
+		exp_type = WPA_GET_BE32(pos);
+		pos += 4;
+		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
+				   "type");
+			return NULL;
+		}
+
+		*plen = len - sizeof(*hdr) - 8;
+		return pos;
+	} else {
+		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+			return NULL;
+		}
+		*plen = len - sizeof(*hdr) - 1;
+		return pos + 1;
+	}
+}
+
+
+/**
+ * eap_msg_alloc - Allocate a buffer for an EAP message
+ * @vendor: Vendor-Id (0 = IETF)
+ * @type: EAP type
+ * @len: Buffer for returning message length
+ * @payload_len: Payload length in bytes (data after Type)
+ * @code: Message Code (EAP_CODE_*)
+ * @identifier: Identifier
+ * @payload: Pointer to payload pointer that will be set to point to the
+ * beginning of the payload or %NULL if payload pointer is not needed
+ * Returns: Pointer to the allocated message buffer or %NULL on error
+ *
+ * This function can be used to allocate a buffer for an EAP message and fill
+ * in the EAP header. This function is automatically using expanded EAP header
+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
+ * not need to separately select which header type to use when using this
+ * function to allocate the message buffers.
+ */
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+			       size_t payload_len, u8 code, u8 identifier,
+			       u8 **payload)
+{
+	struct eap_hdr *hdr;
+	u8 *pos;
+
+	*len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
+		payload_len;
+	hdr = malloc(*len);
+	if (hdr) {
+		hdr->code = code;
+		hdr->identifier = identifier;
+		hdr->length = host_to_be16(*len);
+		pos = (u8 *) (hdr + 1);
+		if (vendor == EAP_VENDOR_IETF) {
+			*pos++ = type;
+		} else {
+			*pos++ = EAP_TYPE_EXPANDED;
+			WPA_PUT_BE24(pos, vendor);
+			pos += 3;
+			WPA_PUT_BE32(pos, type);
+			pos += 4;
+		}
+		if (payload)
+			*payload = pos;
+	}
+
+	return hdr;
+}
Index: hostapd.eap_user
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd.eap_user,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostapd.eap_user -L contrib/hostapd/hostapd.eap_user -u -r1.2 -r1.3
--- contrib/hostapd/hostapd.eap_user
+++ contrib/hostapd/hostapd.eap_user
@@ -1,15 +1,24 @@
 # hostapd user database for integrated EAP authenticator
+
 # Each line must contain an identity, EAP method(s), and an optional password
 # separated with whitespace (space or tab). The identity and password must be
-# double quoted ("user"). [2] flag in the end of the line can be used to mark
-# users for tunneled phase 2 authentication (e.g., within EAP-PEAP). In these
-# cases, an anonymous identity can be used in the unencrypted phase 1 and the
-# real user identity is transmitted only within the encrypted tunnel in phase
-# 2. If non-anonymous access is needed, two user entries is needed, one for
-# phase 1 and another with the same username for phase 2.
+# double quoted ("user"). Password can alternatively be stored as
+# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
+# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
+# that the plaintext password does not need to be included in the user file.
+# Password hash is stored as hash:<16-octets of hex data> without quotation
+# marks.
+
+# [2] flag in the end of the line can be used to mark users for tunneled phase
+# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
+# identity can be used in the unencrypted phase 1 and the real user identity
+# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
+# access is needed, two user entries is needed, one for phase 1 and another
+# with the same username for phase 2.
 #
-# EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-SIM do not use password option.
-# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, and EAP-PSK require a password.
+# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-SIM, and EAP-AKA do not use password option.
+# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
+# password.
 # EAP-PEAP and EAP-TTLS require Phase 2 configuration.
 #
 # * can be used as a wildcard to match any user identity. The main purposes for
@@ -18,6 +27,11 @@
 # first matching entry is selected, so * should be used as the last phase 1
 # user entry.
 #
+# "prefix"* can be used to match the given prefix and anything after this. The
+# main purpose for this is to be able to avoid EAP method negotiation when the
+# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
+# is only allowed for phase 1 identities.
+#
 # Multiple methods can be configured to make the authenticator try them one by
 # one until the peer accepts one. The method names are separated with a
 # comma (,).
@@ -37,9 +51,19 @@
 "pax.user at example.com"	PAX	0123456789abcdef0123456789abcdef
 "psk user"	PSK	"unknown"
 "psk.user at example.com"	PSK	0123456789abcdef0123456789abcdef
+"sake.user at example.com"	SAKE	0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
 "ttls"		TTLS
 "not anonymous"	PEAP
-*		PEAP,TTLS,TLS,SIM
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
+"0"*		AKA,TTLS,TLS,PEAP,SIM
+"1"*		SIM,TTLS,TLS,PEAP,AKA
+"2"*		AKA,TTLS,TLS,PEAP,SIM
+"3"*		SIM,TTLS,TLS,PEAP,AKA
+"4"*		AKA,TTLS,TLS,PEAP,SIM
+"5"*		SIM,TTLS,TLS,PEAP,AKA
+
+# Wildcard for all other identities
+*		PEAP,TTLS,TLS,SIM,AKA
 
 # Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
 "t-md5"		MD5	"password"	[2]
@@ -47,3 +71,4 @@
 "t-gtc"		GTC	"password"	[2]
 "not anonymous"	MSCHAPV2	"password"	[2]
 "user"		MD5,GTC,MSCHAPV2	"password"	[2]
+"test user"	MSCHAPV2	hash:000102030405060708090a0b0c0d0e0f	[2]
Index: eap_mschapv2.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_mschapv2.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_mschapv2.c -L contrib/hostapd/eap_mschapv2.c -u -r1.1.1.1 -r1.2
--- contrib/hostapd/eap_mschapv2.c
+++ contrib/hostapd/eap_mschapv2.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -24,16 +21,12 @@
 
 
 struct eap_mschapv2_hdr {
-	u8 code;
-	u8 identifier;
-	u16 length; /* including code, identifier, and length */
-	u8 type; /* EAP_TYPE_MSCHAPV2 */
 	u8 op_code; /* MSCHAPV2_OP_* */
 	u8 mschapv2_id; /* must be changed for challenges, but not for
 			 * success/failure */
 	u8 ms_length[2]; /* Note: misaligned; length - 5 */
 	/* followed by data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 #define MSCHAPV2_OP_CHALLENGE 1
 #define MSCHAPV2_OP_RESPONSE 2
@@ -51,6 +44,7 @@
 #define ERROR_CHANGING_PASSWORD 709
 
 #define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
 
 
 #define CHALLENGE_LEN 16
@@ -60,6 +54,8 @@
 	u8 auth_response[20];
 	enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
 	u8 resp_mschapv2_id;
+	u8 master_key[16];
+	int master_key_valid;
 };
 
 
@@ -67,10 +63,9 @@
 {
 	struct eap_mschapv2_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = CHALLENGE;
 
 	return data;
@@ -88,9 +83,11 @@
 					 struct eap_mschapv2_data *data,
 					 int id, size_t *reqDataLen)
 {
-	struct eap_mschapv2_hdr *req;
+	struct eap_hdr *req;
+	struct eap_mschapv2_hdr *ms;
 	u8 *pos;
 	char *name = "hostapd"; /* TODO: make this configurable */
+	size_t ms_len;
 
 	if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
 		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
@@ -99,8 +96,9 @@
 		return NULL;
 	}
 
-	*reqDataLen = sizeof(*req) + 1 + CHALLENGE_LEN + strlen(name);
-	req = malloc(*reqDataLen);
+	ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + strlen(name);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+			    ms_len, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 			   " for request");
@@ -108,15 +106,12 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	req->type = EAP_TYPE_MSCHAPV2;
-	req->op_code = MSCHAPV2_OP_CHALLENGE;
-	req->mschapv2_id = id;
-	req->ms_length[0] = (*reqDataLen - 5) >> 8;
-	req->ms_length[1] = (*reqDataLen - 5) & 0xff;
-	pos = (u8 *) (req + 1);
+	ms = (struct eap_mschapv2_hdr *) pos;
+	ms->op_code = MSCHAPV2_OP_CHALLENGE;
+	ms->mschapv2_id = id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	pos = (u8 *) (ms + 1);
 	*pos++ = CHALLENGE_LEN;
 	memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos,
@@ -132,15 +127,16 @@
 					   struct eap_mschapv2_data *data,
 					   int id, size_t *reqDataLen)
 {
-	struct eap_mschapv2_hdr *req;
-	u8 *pos, *msg, *end;
+	struct eap_hdr *req;
+	struct eap_mschapv2_hdr *ms;
+	u8 *pos, *msg;
 	char *message = "OK";
-	size_t msg_len;
-	int i;
+	size_t ms_len;
 
-	msg_len = 2 + 2 * sizeof(data->auth_response) + 3 + strlen(message);
-	*reqDataLen = sizeof(*req) + msg_len;
-	req = malloc(*reqDataLen + 1);
+	ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
+		strlen(message);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+			    ms_len, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 			   " for request");
@@ -148,27 +144,25 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	req->type = EAP_TYPE_MSCHAPV2;
-	req->op_code = MSCHAPV2_OP_SUCCESS;
-	req->mschapv2_id = data->resp_mschapv2_id;
-	req->ms_length[0] = (*reqDataLen - 5) >> 8;
-	req->ms_length[1] = (*reqDataLen - 5) & 0xff;
-
-	msg = pos = (u8 *) (req + 1);
-	end = ((u8 *) req) + *reqDataLen + 1;
-
-	pos += snprintf((char *) pos, end - pos, "S=");
-	for (i = 0; i < sizeof(data->auth_response); i++) {
-		pos += snprintf((char *) pos, end - pos, "%02X",
-				data->auth_response[i]);
-	}
-	pos += snprintf((char *) pos, end - pos, " M=%s", message);
+	ms = (struct eap_mschapv2_hdr *) pos;
+	ms->op_code = MSCHAPV2_OP_SUCCESS;
+	ms->mschapv2_id = data->resp_mschapv2_id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	msg = pos = (u8 *) (ms + 1);
+	*pos++ = 'S';
+	*pos++ = '=';
+	pos += wpa_snprintf_hex_uppercase((char *) pos,
+					  sizeof(data->auth_response) * 2 + 1,
+					  data->auth_response,
+					  sizeof(data->auth_response));
+	*pos++ = ' ';
+	*pos++ = 'M';
+	*pos++ = '=';
+	memcpy(pos, message, strlen(message));
 
 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
-			  msg, msg_len);
+			  msg, ms_len - sizeof(*ms));
 
 	return (u8 *) req;
 }
@@ -178,15 +172,16 @@
 					   struct eap_mschapv2_data *data,
 					   int id, size_t *reqDataLen)
 {
-	struct eap_mschapv2_hdr *req;
+	struct eap_hdr *req;
+	struct eap_mschapv2_hdr *ms;
 	u8 *pos;
 	char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
 		"M=FAILED";
-	size_t msg_len;
+	size_t ms_len;
 
-	msg_len = strlen(message);
-	*reqDataLen = sizeof(*req) + msg_len;
-	req = malloc(*reqDataLen + 1);
+	ms_len = sizeof(*ms) + strlen(message);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+			    ms_len, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
 			   " for request");
@@ -194,20 +189,15 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	req->type = EAP_TYPE_MSCHAPV2;
-	req->op_code = MSCHAPV2_OP_FAILURE;
-	req->mschapv2_id = data->resp_mschapv2_id;
-	req->ms_length[0] = (*reqDataLen - 5) >> 8;
-	req->ms_length[1] = (*reqDataLen - 5) & 0xff;
+	ms = (struct eap_mschapv2_hdr *) pos;
+	ms->op_code = MSCHAPV2_OP_FAILURE;
+	ms->mschapv2_id = data->resp_mschapv2_id;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
 
-	pos = (u8 *) (req + 1);
-	memcpy(pos, message, msg_len);
+	memcpy((u8 *) (ms + 1), message, strlen(message));
 
 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
-			  (u8 *) message, msg_len);
+			  (u8 *) message, strlen(message));
 
 	return (u8 *) req;
 }
@@ -241,17 +231,17 @@
 {
 	struct eap_mschapv2_data *data = priv;
 	struct eap_mschapv2_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	size_t len;
 
-	resp = (struct eap_mschapv2_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	if (respDataLen < 6 || resp->type != EAP_TYPE_MSCHAPV2 ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1) {
 		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
 		return TRUE;
 	}
 
+	resp = (struct eap_mschapv2_hdr *) pos;
 	if (data->state == CHALLENGE &&
 	    resp->op_code != MSCHAPV2_OP_RESPONSE) {
 		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
@@ -283,18 +273,23 @@
 					  u8 *respData, size_t respDataLen)
 {
 	struct eap_mschapv2_hdr *resp;
-	u8 *pos;
-	u8 *peer_challenge, *nt_response, flags, *name;
-	size_t name_len;
+	const u8 *pos, *end, *peer_challenge, *nt_response, *name;
+	u8 flags;
+	size_t len, name_len, i;
 	u8 expected[24];
-	int i;
-	u8 *username, *user;
+	const u8 *username, *user;
 	size_t username_len, user_len;
 
-	resp = (struct eap_mschapv2_hdr *) respData;
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
+
+	end = pos + len;
+	resp = (struct eap_mschapv2_hdr *) pos;
 	pos = (u8 *) (resp + 1);
 
-	if (respDataLen < sizeof(resp) + 1 + 49 ||
+	if (len < sizeof(*resp) + 1 + 49 ||
 	    resp->op_code != MSCHAPV2_OP_RESPONSE ||
 	    pos[0] != 49) {
 		wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
@@ -310,7 +305,7 @@
 	pos += 24;
 	flags = *pos++;
 	name = pos;
-	name_len = respData + respDataLen - name;
+	name_len = end - name;
 
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
 		    peer_challenge, 16);
@@ -355,26 +350,55 @@
 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
 			  username, username_len);
 
-	generate_nt_response(data->auth_challenge, peer_challenge,
-			     username, username_len,
-			     sm->user->password, sm->user->password_len,
-			     expected);
+	if (sm->user->password_hash) {
+		generate_nt_response_pwhash(data->auth_challenge,
+					    peer_challenge,
+					    username, username_len,
+					    sm->user->password,
+					    expected);
+	} else {
+		generate_nt_response(data->auth_challenge, peer_challenge,
+				     username, username_len,
+				     sm->user->password,
+				     sm->user->password_len,
+				     expected);
+	}
 
 	if (memcmp(nt_response, expected, 24) == 0) {
+		const u8 *pw_hash;
+		u8 pw_hash_buf[16], pw_hash_hash[16];
+
 		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
 		data->state = SUCCESS_REQ;
 
-
 		/* Authenticator response is not really needed yet, but
 		 * calculate it here so that peer_challenge and username need
 		 * not be saved. */
-		generate_authenticator_response(sm->user->password,
-						sm->user->password_len,
-						peer_challenge,
-						data->auth_challenge,
-						username, username_len,
-						nt_response,
-						data->auth_response);
+		if (sm->user->password_hash) {
+			pw_hash = sm->user->password;
+			generate_authenticator_response_pwhash(
+				sm->user->password, peer_challenge,
+				data->auth_challenge, username, username_len,
+				nt_response, data->auth_response);
+		} else {
+			nt_password_hash(sm->user->password,
+					 sm->user->password_len,
+					 pw_hash_buf);
+			pw_hash = pw_hash_buf;
+			generate_authenticator_response(sm->user->password,
+							sm->user->password_len,
+							peer_challenge,
+							data->auth_challenge,
+							username, username_len,
+							nt_response,
+							data->auth_response);
+		}
+
+		hash_nt_password_hash(pw_hash, pw_hash_hash);
+		get_master_key(pw_hash_hash, nt_response, data->master_key);
+		data->master_key_valid = 1;
+		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
+				data->master_key, MSCHAPV2_KEY_LEN);
 	} else {
 		wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
 			    expected, 24);
@@ -389,8 +413,15 @@
 					      u8 *respData, size_t respDataLen)
 {
 	struct eap_mschapv2_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
 
-	resp = (struct eap_mschapv2_hdr *) respData;
+	resp = (struct eap_mschapv2_hdr *) pos;
 
 	if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
 		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
@@ -409,8 +440,15 @@
 					      u8 *respData, size_t respDataLen)
 {
 	struct eap_mschapv2_hdr *resp;
+	const u8 *pos;
+	size_t len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1)
+		return; /* Should not happen - frame already validated */
 
-	resp = (struct eap_mschapv2_hdr *) respData;
+	resp = (struct eap_mschapv2_hdr *) pos;
 
 	if (resp->op_code == MSCHAPV2_OP_FAILURE) {
 		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
@@ -462,6 +500,27 @@
 }
 
 
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_mschapv2_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS || !data->master_key_valid)
+		return NULL;
+
+	*len = 2 * MSCHAPV2_KEY_LEN;
+	key = malloc(*len);
+	if (key == NULL)
+		return NULL;
+	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);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
+
+	return key;
+}
+
+
 static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
 {
 	struct eap_mschapv2_data *data = priv;
@@ -469,15 +528,28 @@
 }
 
 
-const struct eap_method eap_method_mschapv2 =
+int eap_server_mschapv2_register(void)
 {
-	.method = EAP_TYPE_MSCHAPV2,
-	.name = "MSCHAPV2",
-	.init = eap_mschapv2_init,
-	.reset = eap_mschapv2_reset,
-	.buildReq = eap_mschapv2_buildReq,
-	.check = eap_mschapv2_check,
-	.process = eap_mschapv2_process,
-	.isDone = eap_mschapv2_isDone,
-	.isSuccess = eap_mschapv2_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+				      "MSCHAPV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_mschapv2_init;
+	eap->reset = eap_mschapv2_reset;
+	eap->buildReq = eap_mschapv2_buildReq;
+	eap->check = eap_mschapv2_check;
+	eap->process = eap_mschapv2_process;
+	eap->isDone = eap_mschapv2_isDone;
+	eap->getKey = eap_mschapv2_getKey;
+	eap->isSuccess = eap_mschapv2_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
--- /dev/null
+++ contrib/hostapd/wpa_common.h
@@ -0,0 +1,58 @@
+/*
+ * WPA definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2005, 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 WPA_COMMON_H
+#define WPA_COMMON_H
+
+#define WPA_REPLAY_COUNTER_LEN 8
+#define WPA_NONCE_LEN 32
+#define WPA_KEY_RSC_LEN 8
+
+
+/* IEEE Std 802.1X-2004 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_hdr {
+	u8 version;
+	u8 type;
+	u16 length;
+	/* followed by length octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAPOL_VERSION 2
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+       IEEE802_1X_TYPE_EAPOL_START = 1,
+       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+       IEEE802_1X_TYPE_EAPOL_KEY = 3,
+       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
+       EAPOL_KEY_TYPE_WPA = 254 };
+
+#ifdef CONFIG_IEEE80211W
+#define WPA_DGTK_LEN 16
+#define WPA_DHV_LEN 16
+#define WPA_IGTK_LEN 16
+#endif /* CONFIG_IEEE80211W */
+
+#endif /* WPA_COMMON_H */
--- /dev/null
+++ contrib/hostapd/preauth.h
@@ -0,0 +1,58 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2005, 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 PREAUTH_H
+#define PREAUTH_H
+
+#ifdef CONFIG_RSN_PREAUTH
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd);
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success);
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len);
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_RSN_PREAUTH */
+
+static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void rsn_preauth_finished(struct hostapd_data *hapd,
+					struct sta_info *sta,
+					int success)
+{
+}
+
+static inline void rsn_preauth_send(struct hostapd_data *hapd,
+				    struct sta_info *sta,
+				    u8 *buf, size_t len)
+{
+}
+
+static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
+					    struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_RSN_PREAUTH */
+
+#endif /* PREAUTH_H */
Index: defconfig
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/defconfig,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/defconfig -L contrib/hostapd/defconfig -u -r1.2 -r1.3
--- contrib/hostapd/defconfig
+++ contrib/hostapd/defconfig
@@ -22,6 +22,15 @@
 # Driver interface for Prism54 driver
 #CONFIG_DRIVER_PRISM54=y
 
+# Driver interface for drivers using Devicescape IEEE 802.11 stack
+#CONFIG_DRIVER_DEVICESCAPE=y
+# Currently, driver_devicescape.c build requires some additional parameters
+# to be able to include some of the kernel header files. Following lines can
+# be used to set these (WIRELESS_DEV must point to the root directory of the
+# wireless-dev.git tree).
+#WIRELESS_DEV=/usr/src/wireless-dev
+#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
+
 # Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
 #CONFIG_DRIVER_BSD=y
 #CFLAGS += -I/usr/local/include
@@ -33,6 +42,15 @@
 # WPA2/IEEE 802.11i RSN pre-authentication
 CONFIG_RSN_PREAUTH=y
 
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
 # Integrated EAP server
 CONFIG_EAP=y
 
@@ -57,12 +75,23 @@
 # EAP-SIM for the integrated EAP server
 #CONFIG_EAP_SIM=y
 
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
 # EAP-PAX for the integrated EAP server
 #CONFIG_EAP_PAX=y
 
 # EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
 #CONFIG_EAP_PSK=y
 
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
 # PKCS#12 (PFX) support (used to read private key and certificate file from
 # a file that usually has extension .p12 or .pfx)
 CONFIG_PKCS12=y
Index: ms_funcs.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ms_funcs.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ms_funcs.h -L contrib/hostapd/ms_funcs.h -u -r1.2 -r1.3
--- contrib/hostapd/ms_funcs.h
+++ contrib/hostapd/ms_funcs.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2005, 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,11 +19,21 @@
 			  const u8 *username, size_t username_len,
 			  const u8 *password, size_t password_len,
 			  u8 *response);
+void generate_nt_response_pwhash(const u8 *auth_challenge,
+				 const u8 *peer_challenge,
+				 const u8 *username, size_t username_len,
+				 const u8 *password_hash,
+				 u8 *response);
 void generate_authenticator_response(const u8 *password, size_t password_len,
 				     const u8 *peer_challenge,
 				     const u8 *auth_challenge,
 				     const u8 *username, size_t username_len,
 				     const u8 *nt_response, u8 *response);
+void generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response);
 void nt_challenge_response(const u8 *challenge, const u8 *password,
 			   size_t password_len, u8 *response);
 
@@ -46,5 +56,4 @@
 	const u8 *old_password, size_t old_password_len,
 	u8 *encrypted_password_hash);
 
-
 #endif /* MS_FUNCS_H */
--- /dev/null
+++ contrib/hostapd/includes.h
@@ -0,0 +1,57 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, 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.
+ *
+ * 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
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+/* Include possible build time configuration before including anything else */
+#include "build_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#ifndef CONFIG_TI_COMPILER
+#include <signal.h>
+#include <sys/types.h>
+#endif /* CONFIG_TI_COMPILER */
+#include <errno.h>
+#endif /* _WIN32_WCE */
+#include <ctype.h>
+#include <time.h>
+
+#ifndef CONFIG_TI_COMPILER
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_TI_COMPILER
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef __vxworks
+#include <sys/uio.h>
+#include <sys/time.h>
+#endif /* __vxworks */
+#endif /* CONFIG_TI_COMPILER */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#endif /* INCLUDES_H */
Index: hostapd_cli.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd_cli.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostapd_cli.c -L contrib/hostapd/hostapd_cli.c -u -r1.2 -r1.3
--- contrib/hostapd/hostapd_cli.c
+++ contrib/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,11 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
+#include "includes.h"
 #include <dirent.h>
 
 #include "wpa_ctrl.h"
@@ -25,7 +21,7 @@
 
 static const char *hostapd_cli_version =
 "hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi> and contributors";
+"Copyright (c) 2004-2007, Jouni Malinen <j at w1.fi> and contributors";
 
 
 static const char *hostapd_cli_license =
@@ -47,7 +43,7 @@
 "\n"
 "You should have received a copy of the GNU General Public License\n"
 "along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n"
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n"
 "\n"
 "Alternatively, this software may be distributed under the terms of the\n"
 "BSD license.\n"
@@ -83,8 +79,9 @@
 static const char *commands_help =
 "Commands:\n"
 "   mib                  get MIB variables (dot1x, dot11, radius)\n"
-"   sta <addr>           get MIB vatiables for one station\n"
+"   sta <addr>           get MIB variables for one station\n"
 "   all_sta              get MIB variables for all stations\n"
+"   new_sta <addr>       add a new station\n"
 "   help                 show this usage help\n"
 "   interface [ifname]   show interfaces/select interface\n"
 "   level <debug level>  change debug level\n"
@@ -218,6 +215,20 @@
 }
 
 
+static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'new_sta' command - exactly one argument, STA "
+		       "address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
 				char *addr, size_t addr_len)
 {
@@ -365,6 +376,7 @@
 	{ "mib", hostapd_cli_cmd_mib },
 	{ "sta", hostapd_cli_cmd_sta },
 	{ "all_sta", hostapd_cli_cmd_all_sta },
+	{ "new_sta", hostapd_cli_cmd_new_sta },
 	{ "help", hostapd_cli_cmd_help },
 	{ "interface", hostapd_cli_cmd_interface },
 	{ "level", hostapd_cli_cmd_level },
@@ -525,6 +537,7 @@
 			printf("%s\n", hostapd_cli_version);
 			return 0;
 		case 'i':
+			free(ctrl_ifname);
 			ctrl_ifname = strdup(optarg);
 			break;
 		case 'p':
Index: md5.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/md5.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/md5.h -L contrib/hostapd/md5.h -u -r1.2 -r1.3
--- contrib/hostapd/md5.h
+++ contrib/hostapd/md5.h
@@ -1,6 +1,6 @@
 /*
  * MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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
@@ -22,4 +22,13 @@
 void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
 	      u8 *mac);
 
+#ifdef CONFIG_CRYPTO_INTERNAL
+struct MD5Context;
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+
 #endif /* MD5_H */
--- /dev/null
+++ contrib/hostapd/pmksa_cache.h
@@ -0,0 +1,54 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2006, 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 PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+	struct rsn_pmksa_cache_entry *next, *hnext;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	os_time_t expiration;
+	int akmp; /* WPA_KEY_MGMT_* */
+	u8 spa[ETH_ALEN];
+
+	u8 *identity;
+	size_t identity_len;
+	struct radius_class_data radius_class;
+	u8 eap_type_authsrv;
+	int vlan_id;
+};
+
+struct rsn_pmksa_cache;
+
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx), void *ctx);
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *spa, const u8 *pmkid);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, int session_timeout,
+		struct eapol_state_machine *eapol);
+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+			       struct eapol_state_machine *eapol);
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid);
+
+#endif /* PMKSA_CACHE_H */
Index: eap_gtc.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_gtc.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_gtc.c -L contrib/hostapd/eap_gtc.c -u -r1.1.1.1 -r1.2
--- contrib/hostapd/eap_gtc.c
+++ contrib/hostapd/eap_gtc.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-GTC (RFC 3748)
- * Copyright (c) 2004, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -31,10 +28,9 @@
 {
 	struct eap_gtc_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = CONTINUE;
 
 	return data;
@@ -58,8 +54,8 @@
 	size_t msg_len;
 
 	msg_len = strlen(msg);
-	*reqDataLen = sizeof(*req) + 1 + msg_len;
-	req = malloc(*reqDataLen);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqDataLen,
+			    msg_len, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
 			   "request");
@@ -67,11 +63,6 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	pos = (u8 *) (req + 1);
-	*pos++ = EAP_TYPE_GTC;
 	memcpy(pos, msg, msg_len);
 
 	data->state = CONTINUE;
@@ -83,14 +74,12 @@
 static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
 			     u8 *respData, size_t respDataLen)
 {
-	struct eap_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	size_t len;
 
-	resp = (struct eap_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_GTC ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1) {
 		wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
 		return TRUE;
 	}
@@ -103,20 +92,22 @@
 			    u8 *respData, size_t respDataLen)
 {
 	struct eap_gtc_data *data = priv;
-	struct eap_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	size_t rlen;
 
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_hash) {
+		wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
+			   "configured");
 		data->state = FAILURE;
 		return;
 	}
 
-	resp = (struct eap_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	pos++;
-	rlen = ntohs(resp->length) - sizeof(*resp) - 1;
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+			       respData, respDataLen, &rlen);
+	if (pos == NULL || rlen < 1)
+		return; /* Should not happen - frame already validated */
+
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
 
 	if (rlen != sm->user->password_len ||
@@ -144,15 +135,26 @@
 }
 
 
-const struct eap_method eap_method_gtc =
+int eap_server_gtc_register(void)
 {
-	.method = EAP_TYPE_GTC,
-	.name = "GTC",
-	.init = eap_gtc_init,
-	.reset = eap_gtc_reset,
-	.buildReq = eap_gtc_buildReq,
-	.check = eap_gtc_check,
-	.process = eap_gtc_process,
-	.isDone = eap_gtc_isDone,
-	.isSuccess = eap_gtc_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gtc_init;
+	eap->reset = eap_gtc_reset;
+	eap->buildReq = eap_gtc_buildReq;
+	eap->check = eap_gtc_check;
+	eap->process = eap_gtc_process;
+	eap->isDone = eap_gtc_isDone;
+	eap->isSuccess = eap_gtc_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
--- /dev/null
+++ contrib/hostapd/des.c
@@ -0,0 +1,476 @@
+/*
+ * DES and 3DES-EDE ciphers
+ *
+ * Modifications to LibTomCrypt implementation:
+ * Copyright (c) 2006, 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 "crypto.h"
+
+
+#ifdef INTERNAL_DES
+
+/*
+ * This implementation is based on a DES implementation included in
+ * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
+ * coding style.
+ */
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis at gmail.com, http://libtomcrypt.com
+ */
+
+/**
+  DES code submitted by Dobes Vandermeer
+*/
+
+#define ROLc(x, y) \
+	((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
+	  (((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+	   (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) \
+	(((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+	   (unsigned long) ((y) & 31)) | \
+	  ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
+	 0xFFFFFFFFUL)
+
+
+static const u32 bytebit[8] =
+{
+	0200, 0100, 040, 020, 010, 04, 02, 01 
+};
+
+static const u32 bigbyte[24] =
+{
+	0x800000UL,  0x400000UL,  0x200000UL,  0x100000UL,
+	0x80000UL,   0x40000UL,   0x20000UL,   0x10000UL,
+	0x8000UL,    0x4000UL,    0x2000UL,    0x1000UL,
+	0x800UL,     0x400UL,     0x200UL,     0x100UL,
+	0x80UL,      0x40UL,      0x20UL,      0x10UL,
+	0x8UL,       0x4UL,       0x2UL,       0x1L 
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const u8 pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,  0, 57, 49, 41, 33, 25, 17,  
+	 9,  1, 58, 50, 42, 34, 26, 18, 10,  2, 59, 51, 43, 35, 
+	62, 54, 46, 38, 30, 22, 14,  6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28, 20, 12,  4, 27, 19, 11,  3 
+};
+
+static const u8 totrot[16] = {
+	1,   2,  4,  6,
+	8,  10, 12, 14, 
+	15, 17, 19, 21, 
+	23, 25, 27, 28
+};
+
+static const u8 pc2[48] = {
+	13, 16, 10, 23,  0,  4,      2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7,     15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54,     29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52,     45, 41, 49, 35, 28, 31
+};
+
+
+static const u32 SP1[64] =
+{
+	0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+	0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+	0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+	0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+	0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+	0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+	0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+	0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+	0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+	0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+	0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+	0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+	0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+	0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+	0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const u32 SP2[64] =
+{
+	0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+	0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+	0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+	0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+	0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+	0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+	0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+	0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+	0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+	0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+	0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+	0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+	0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+	0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+	0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+	0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const u32 SP3[64] =
+{
+	0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+	0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+	0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+	0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+	0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+	0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+	0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+	0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+	0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+	0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+	0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+	0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+	0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+	0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+	0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+	0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const u32 SP4[64] =
+{
+	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+	0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+	0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+	0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+	0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+	0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+	0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+	0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+	0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+	0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+	0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+	0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+	0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+	0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+	0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+	0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const u32 SP5[64] =
+{
+	0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+	0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+	0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+	0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+	0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+	0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+	0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+	0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+	0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+	0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+	0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+	0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+	0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+	0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+	0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+	0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const u32 SP6[64] =
+{
+	0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+	0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+	0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+	0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+	0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+	0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+	0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+	0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+	0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+	0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+	0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+	0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+	0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+	0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+	0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+	0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const u32 SP7[64] =
+{
+	0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+	0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+	0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+	0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+	0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+	0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+	0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+	0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+	0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+	0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+	0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+	0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+	0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+	0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+	0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+	0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const u32 SP8[64] =
+{
+	0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+	0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+	0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+	0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+	0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+	0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+	0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+	0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+	0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+	0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+	0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+	0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+	0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+	0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+	0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+	0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
+};
+
+
+static void cookey(const u32 *raw1, u32 *keyout)
+{
+	u32 *cook;
+	const u32 *raw0;
+	u32 dough[32];
+	int i;
+
+	cook = dough;
+	for (i = 0; i < 16; i++, raw1++) {
+		raw0 = raw1++;
+		*cook    = (*raw0 & 0x00fc0000L) << 6;
+		*cook   |= (*raw0 & 0x00000fc0L) << 10;
+		*cook   |= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook    = (*raw0 & 0x0003f000L) << 12;
+		*cook   |= (*raw0 & 0x0000003fL) << 16;
+		*cook   |= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+	}
+
+	os_memcpy(keyout, dough, sizeof(dough));
+}
+
+
+static void deskey(const u8 *key, int decrypt, u32 *keyout)
+{
+	u32 i, j, l, m, n, kn[32];
+	u8 pc1m[56], pcr[56];
+
+	for (j = 0; j < 56; j++) {
+		l = (u32) pc1[j];
+		m = l & 7;
+		pc1m[j] = (u8)
+			((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
+	}
+
+	for (i = 0; i < 16; i++) {
+		if (decrypt)
+			m = (15 - i) << 1;
+		else
+			m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for (j = 0; j < 28; j++) {
+			l = j + (u32) totrot[i];
+			if (l < 28)
+				pcr[j] = pc1m[l];
+			else
+				pcr[j] = pc1m[l - 28];
+		}
+		for (/* j = 28 */; j < 56; j++) {
+			l = j + (u32) totrot[i];
+			if (l < 56)
+				pcr[j] = pc1m[l];
+			else
+				pcr[j] = pc1m[l - 28];
+		}
+		for (j = 0; j < 24; j++) {
+			if ((int) pcr[(int) pc2[j]] != 0)
+				kn[m] |= bigbyte[j];
+			if ((int) pcr[(int) pc2[j + 24]] != 0)
+				kn[n] |= bigbyte[j];
+		}
+	}
+
+	cookey(kn, keyout);
+}
+
+
+static void desfunc(u32 *block, const u32 *keys)
+{
+	u32 work, right, leftt;
+	int cur_round;
+
+	leftt = block[0];
+	right = block[1];
+
+	work = ((leftt >> 4)  ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+
+	work = ((right >> 2)  ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+
+	work = ((right >> 8)  ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+
+	right = ROLc(right, 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+
+	leftt ^= work;
+	right ^= work;
+	leftt = ROLc(leftt, 1);
+
+	for (cur_round = 0; cur_round < 8; cur_round++) {
+		work  = RORc(right, 4) ^ *keys++;
+		leftt ^= SP7[work        & 0x3fL]
+			^ SP5[(work >>  8) & 0x3fL]
+			^ SP3[(work >> 16) & 0x3fL]
+			^ SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		leftt ^= SP8[ work        & 0x3fL]
+			^  SP6[(work >>  8) & 0x3fL]
+			^  SP4[(work >> 16) & 0x3fL]
+			^  SP2[(work >> 24) & 0x3fL];
+
+		work = RORc(leftt, 4) ^ *keys++;
+		right ^= SP7[ work        & 0x3fL]
+			^  SP5[(work >>  8) & 0x3fL]
+			^  SP3[(work >> 16) & 0x3fL]
+			^  SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		right ^= SP8[ work        & 0x3fL]
+			^  SP6[(work >>  8) & 0x3fL]
+			^  SP4[(work >> 16) & 0x3fL]
+			^  SP2[(work >> 24) & 0x3fL];
+	}
+
+	right = RORc(right, 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = RORc(leftt, 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	/* -- */
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+
+	block[0] = right;
+	block[1] = leftt;
+}
+
+
+/* wpa_supplicant/hostapd specific wrapper */
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	u32 ek[32], work[2];
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	deskey(pkey, 0, ek);
+
+	work[0] = WPA_GET_BE32(clear);
+	work[1] = WPA_GET_BE32(clear + 4);
+	desfunc(work, ek);
+	WPA_PUT_BE32(cypher, work[0]);
+	WPA_PUT_BE32(cypher + 4, work[1]);
+}
+
+
+struct des3_key_s {
+	u32 ek[3][32];
+	u32 dk[3][32];
+};
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
+{
+	deskey(key, 0, dkey->ek[0]);
+	deskey(key + 8, 1, dkey->ek[1]);
+	deskey(key + 16, 0, dkey->ek[2]);
+
+	deskey(key, 1, dkey->dk[2]);
+	deskey(key + 8, 0, dkey->dk[1]);
+	deskey(key + 16, 1, dkey->dk[0]);
+}
+
+
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
+{
+	u32 work[2];
+
+	work[0] = WPA_GET_BE32(plain);
+	work[1] = WPA_GET_BE32(plain + 4);
+	desfunc(work, key->ek[0]);
+	desfunc(work, key->ek[1]);
+	desfunc(work, key->ek[2]);
+	WPA_PUT_BE32(crypt, work[0]);
+	WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
+{
+	u32 work[2];
+
+	work[0] = WPA_GET_BE32(crypt);
+	work[1] = WPA_GET_BE32(crypt + 4);
+	desfunc(work, key->dk[0]);
+	desfunc(work, key->dk[1]);
+	desfunc(work, key->dk[2]);
+	WPA_PUT_BE32(plain, work[0]);
+	WPA_PUT_BE32(plain + 4, work[1]);
+}
+
+#endif /* INTERNAL_DES */
Index: wpa_ctrl.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/wpa_ctrl.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/wpa_ctrl.c -L contrib/hostapd/wpa_ctrl.c -u -r1.1 -r1.2
--- contrib/hostapd/wpa_ctrl.c
+++ contrib/hostapd/wpa_ctrl.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,22 +12,21 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/socket.h>
-#include <netinet/in.h>
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
 #include <sys/un.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #include "wpa_ctrl.h"
-#ifdef CONFIG_NATIVE_WINDOWS
 #include "common.h"
-#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+#define CTRL_IFACE_SOCKET
+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
 
 
 /**
@@ -40,84 +39,121 @@
  * the arguments for most of the control interface library functions.
  */
 struct wpa_ctrl {
-	int s;
 #ifdef CONFIG_CTRL_IFACE_UDP
+	int s;
 	struct sockaddr_in local;
 	struct sockaddr_in dest;
-#else /* CONFIG_CTRL_IFACE_UDP */
+	char *cookie;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+	int s;
 	struct sockaddr_un local;
 	struct sockaddr_un dest;
-#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	HANDLE pipe;
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
 };
 
 
+#ifdef CONFIG_CTRL_IFACE_UNIX
+
 struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
 {
 	struct wpa_ctrl *ctrl;
-#ifndef CONFIG_CTRL_IFACE_UDP
 	static int counter = 0;
-#endif /* CONFIG_CTRL_IFACE_UDP */
 
-	ctrl = malloc(sizeof(*ctrl));
+	ctrl = os_malloc(sizeof(*ctrl));
 	if (ctrl == NULL)
 		return NULL;
-	memset(ctrl, 0, sizeof(*ctrl));
+	os_memset(ctrl, 0, sizeof(*ctrl));
 
-#ifdef CONFIG_CTRL_IFACE_UDP
-	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (ctrl->s < 0) {
-		perror("socket");
-		free(ctrl);
+		os_free(ctrl);
 		return NULL;
 	}
 
-	ctrl->local.sin_family = AF_INET;
-	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+	ctrl->local.sun_family = AF_UNIX;
+	os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+		    "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
-		 sizeof(ctrl->local)) < 0) {
+		    sizeof(ctrl->local)) < 0) {
 		close(ctrl->s);
-		free(ctrl);
+		os_free(ctrl);
 		return NULL;
 	}
 
-	ctrl->dest.sin_family = AF_INET;
-	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
-	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+	ctrl->dest.sun_family = AF_UNIX;
+	os_snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
+		    ctrl_path);
 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
 		    sizeof(ctrl->dest)) < 0) {
-		perror("connect");
 		close(ctrl->s);
-		free(ctrl);
+		unlink(ctrl->local.sun_path);
+		os_free(ctrl);
 		return NULL;
 	}
-#else /* CONFIG_CTRL_IFACE_UDP */
-	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	unlink(ctrl->local.sun_path);
+	close(ctrl->s);
+	os_free(ctrl);
+}
+
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	char buf[128];
+	size_t len;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (ctrl->s < 0) {
-		free(ctrl);
+		perror("socket");
+		os_free(ctrl);
 		return NULL;
 	}
 
-	ctrl->local.sun_family = AF_UNIX;
-	snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
-		 "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
+	ctrl->local.sin_family = AF_INET;
+	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
 	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
-		    sizeof(ctrl->local)) < 0) {
+		 sizeof(ctrl->local)) < 0) {
 		close(ctrl->s);
-		free(ctrl);
+		os_free(ctrl);
 		return NULL;
 	}
 
-	ctrl->dest.sun_family = AF_UNIX;
-	snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
-		 ctrl_path);
+	ctrl->dest.sin_family = AF_INET;
+	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
 	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
 		    sizeof(ctrl->dest)) < 0) {
+		perror("connect");
 		close(ctrl->s);
-		unlink(ctrl->local.sun_path);
-		free(ctrl);
+		os_free(ctrl);
 		return NULL;
 	}
-#endif /* CONFIG_CTRL_IFACE_UDP */
+
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->cookie = strdup(buf);
+	}
 
 	return ctrl;
 }
@@ -125,14 +161,15 @@
 
 void wpa_ctrl_close(struct wpa_ctrl *ctrl)
 {
-#ifndef CONFIG_CTRL_IFACE_UDP
-	unlink(ctrl->local.sun_path);
-#endif /* CONFIG_CTRL_IFACE_UDP */
 	close(ctrl->s);
-	free(ctrl);
+	os_free(ctrl->cookie);
+	os_free(ctrl);
 }
 
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
 
+#ifdef CTRL_IFACE_SOCKET
 int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
 		     char *reply, size_t *reply_len,
 		     void (*msg_cb)(char *msg, size_t len))
@@ -140,9 +177,35 @@
 	struct timeval tv;
 	int res;
 	fd_set rfds;
+	const char *_cmd;
+	char *cmd_buf = NULL;
+	size_t _cmd_len;
 
-	if (send(ctrl->s, cmd, cmd_len, 0) < 0)
+#ifdef CONFIG_CTRL_IFACE_UDP
+	if (ctrl->cookie) {
+		char *pos;
+		_cmd_len = strlen(ctrl->cookie) + 1 + cmd_len;
+		cmd_buf = os_malloc(_cmd_len );
+		if (cmd_buf == NULL)
+			return -1;
+		_cmd = cmd_buf;
+		pos = cmd_buf;
+		strcpy(pos, ctrl->cookie);
+		pos += strlen(ctrl->cookie);
+		*pos++ = ' ';
+		memcpy(pos, cmd, cmd_len);
+	} else
+#endif /* CONFIG_CTRL_IFACE_UDP */
+	{
+		_cmd = cmd;
+		_cmd_len = cmd_len;
+	}
+
+	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+		os_free(cmd_buf);
 		return -1;
+	}
+	os_free(cmd_buf);
 
 	for (;;) {
 		tv.tv_sec = 2;
@@ -177,6 +240,7 @@
 	}
 	return 0;
 }
+#endif /* CTRL_IFACE_SOCKET */
 
 
 static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
@@ -189,7 +253,7 @@
 			       buf, &len, NULL);
 	if (ret < 0)
 		return ret;
-	if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
+	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
 		return 0;
 	return -1;
 }
@@ -207,6 +271,8 @@
 }
 
 
+#ifdef CTRL_IFACE_SOCKET
+
 int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
 {
 	int res;
@@ -222,13 +288,12 @@
 int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
 {
 	struct timeval tv;
-	int res;
 	fd_set rfds;
 	tv.tv_sec = 0;
 	tv.tv_usec = 0;
 	FD_ZERO(&rfds);
 	FD_SET(ctrl->s, &rfds);
-	res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
 	return FD_ISSET(ctrl->s, &rfds);
 }
 
@@ -237,3 +302,124 @@
 {
 	return ctrl->s;
 }
+
+#endif /* CTRL_IFACE_SOCKET */
+
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	DWORD mode;
+	TCHAR name[256];
+	int i;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef UNICODE
+	if (ctrl_path == NULL)
+		_snwprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		_snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+			   ctrl_path);
+#else /* UNICODE */
+	if (ctrl_path == NULL)
+		os_snprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+			    ctrl_path);
+#endif /* UNICODE */
+
+	for (i = 0; i < 10; i++) {
+		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
+					NULL, OPEN_EXISTING, 0, NULL);
+		/*
+		 * Current named pipe server side in wpa_supplicant is
+		 * re-opening the pipe for new clients only after the previous
+		 * one is taken into use. This leaves a small window for race
+		 * conditions when two connections are being opened at almost
+		 * the same time. Retry if that was the case.
+		 */
+		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
+		    GetLastError() != ERROR_PIPE_BUSY)
+			break;
+		WaitNamedPipe(name, 1000);
+	}
+	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	mode = PIPE_READMODE_MESSAGE;
+	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
+		CloseHandle(ctrl->pipe);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	CloseHandle(ctrl->pipe);
+	os_free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	DWORD written;
+	DWORD readlen = *reply_len;
+
+	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
+		return -1;
+
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
+		return -1;
+	*reply_len = readlen;
+
+	return 0;
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	DWORD len = *reply_len;
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
+		return -1;
+	*reply_len = len;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	DWORD left;
+
+	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
+		return -1;
+	return left ? 1 : 0;
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return -1;
+}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#endif /* CONFIG_CTRL_IFACE */
Index: tls.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/tls.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/tls.h -L contrib/hostapd/tls.h -u -r1.2 -r1.3
--- contrib/hostapd/tls.h
+++ contrib/hostapd/tls.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / SSL/TLS interface definition
- * Copyright (c) 2004-2006, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j at w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,21 +18,14 @@
 struct tls_connection;
 
 struct tls_keys {
-	const u8 *master_key;
+	const u8 *master_key; /* TLS master secret */
 	size_t master_key_len;
 	const u8 *client_random;
 	size_t client_random_len;
 	const u8 *server_random;
 	size_t server_random_len;
-
-	/*
-	 * If TLS library does not provide access to master_key, but only to
-	 * EAP key block, this pointer can be set to point to the result of
-	 * PRF(master_secret, "client EAP encryption",
-	 * client_random + server_random).
-	 */
-	const u8 *eap_tls_prf;
-	size_t eap_tls_prf_len;
+	const u8 *inner_secret; /* TLS/IA inner secret */
+	size_t inner_secret_len;
 };
 
 struct tls_config {
@@ -71,8 +64,10 @@
  * @ppin: pointer to the pin variable in the configuration
  * (this is OpenSSL specific for now)
  * @key_id: the private key's key id (this is OpenSSL specific for now)
+ * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
  *
- * TLS connection parameters to be configured with tls_connection_set_params().
+ * TLS connection parameters to be configured with tls_connection_set_params()
+ * and tls_global_set_params().
  *
  * Certificates and private key can be configured either as a reference name
  * (file path or reference to certificate store) or by providing the same data
@@ -96,6 +91,7 @@
 	const char *dh_file;
 	const u8 *dh_blob;
 	size_t dh_blob_len;
+	int tls_ia;
 
 	/* OpenSSL specific variables */
 	int engine;
@@ -134,7 +130,6 @@
 /**
  * tls_get_errors - Process pending errors
  * @tls_ctx: TLS context data from tls_init()
- *
  * Returns: Number of found error, 0 if no errors detected.
  *
  * Process all pending TLS errors.
@@ -144,7 +139,6 @@
 /**
  * tls_connection_init - Initialize a new TLS connection
  * @tls_ctx: TLS context data from tls_init()
- *
  * Returns: Connection context data, conn for other function calls
  */
 struct tls_connection * tls_connection_init(void *tls_ctx);
@@ -162,16 +156,14 @@
  * tls_connection_established - Has the TLS connection been completed?
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: 1 if TLS connection has been completed, 0 if not.
  */
 int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 
 /**
- * tls_connection_shutdown - Shutdown TLS connection data.
+ * tls_connection_shutdown - Shutdown TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: 0 on success, -1 on failure
  *
  * Shutdown current TLS connection without releasing all resources. New
@@ -185,12 +177,12 @@
 	TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
 	TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
 };
+
 /**
  * tls_connection_set_params - Set TLS connection parameters
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @params: Connection parameters
- *
  * Returns: 0 on success, -1 on failure,
  * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
  * PKCS#11 engine failure, or
@@ -201,21 +193,23 @@
 			      const struct tls_connection_params *params);
 
 /**
- * tls_global_ca_cert - Set trusted CA certificate for all TLS connections
+ * tls_global_set_params - Set TLS parameters for all TLS connection
  * @tls_ctx: TLS context data from tls_init()
- * @ca_cert: File name for CA certificate in PEM or DER format
- * %NULL to allow all subjects
- *
- * Returns: 0 on success, -1 on failure
+ * @params: Global TLS parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
  */
-int tls_global_ca_cert(void *tls_ctx, const char *ca_cert);
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params);
 
 /**
  * tls_global_set_verify - Set global certificate verification options
  * @tls_ctx: TLS context data from tls_init()
  * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
  * 2 = verify CRL for all certificates
- *
  * Returns: 0 on success, -1 on failure
  */
 int tls_global_set_verify(void *tls_ctx, int check_crl);
@@ -225,55 +219,73 @@
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @verify_peer: 1 = verify peer certificate
- *
  * Returns: 0 on success, -1 on failure
  */
 int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
 			      int verify_peer);
 
 /**
- * tls_global_client_cert - Set client certificate for all TLS connections
+ * tls_connection_set_ia - Set TLS/IA parameters
  * @tls_ctx: TLS context data from tls_init()
- * @client_cert: File name for client certificate in PEM or DER format
- *
+ * @conn: Connection context data from tls_connection_init()
+ * @tls_ia: 1 = enable TLS/IA
  * Returns: 0 on success, -1 on failure
- */
-int tls_global_client_cert(void *tls_ctx, const char *client_cert);
-
-/**
- * tls_global_private_key - Set private key for all TLS connections
- * @tls_ctx: TLS context data from tls_init()
- * @private_key: File name for client private key in PEM or DER format
- * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
- * passphrase is used.
  *
- * Returns: 0 on success, -1 on failure
+ * This function is used to configure TLS/IA in server mode where
+ * tls_connection_set_params() is not used.
  */
-int tls_global_private_key(void *tls_ctx, const char *private_key,
-			   const char *private_key_passwd);
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+			  int tls_ia);
 
 /**
  * tls_connection_get_keys - Get master key and random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @keys: Structure of key/random data (filled on success)
- *
  * Returns: 0 on success, -1 on failure
  */
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys);
 
 /**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf() function
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len);
+
+/**
  * tls_connection_handshake - Process TLS handshake (client side)
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @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
  *
- * Caller is responsible for freeing returned output data.
+ * Caller is responsible for freeing returned output data. If the final
+ * handshake message includes application data, this is decrypted and
+ * appl_data (if not %NULL) is set to point this data. Caller is responsible
+ * for freeing appl_data.
  *
  * This function is used during TLS handshake. The first call is done with
  * in_data == %NULL and the library is expected to return ClientHello packet.
@@ -291,7 +303,8 @@
  */
 u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
 			      const u8 *in_data, size_t in_len,
-			      size_t *out_len);
+			      size_t *out_len, u8 **appl_data,
+			      size_t *appl_data_len);
 
 /**
  * tls_connection_server_handshake - Process TLS handshake (server side)
@@ -300,7 +313,6 @@
  * @in_data: Input data from TLS peer
  * @in_len: Input data length
  * @out_len: Length of the output buffer.
- *
  * Returns: pointer to output data, %NULL on failure
  *
  * Caller is responsible for freeing returned output data.
@@ -318,7 +330,6 @@
  * @in_len: Input buffer length
  * @out_data: Pointer to output buffer (encrypted TLS data)
  * @out_len: Maximum out_data length 
- *
  * Returns: Number of bytes written to out_data, -1 on failure
  *
  * This function is used after TLS handshake has been completed successfully to
@@ -336,7 +347,6 @@
  * @in_len: Input buffer length
  * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
  * @out_len: Maximum out_data length
- *
  * Returns: Number of bytes written to out_data, -1 on failure
  *
  * This function is used after TLS handshake has been completed successfully to
@@ -350,7 +360,6 @@
  * tls_connection_resumed - Was session resumption used
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: 1 if current session used session resumption, 0 if not
  */
 int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
@@ -361,23 +370,29 @@
  * @conn: Connection context data from tls_connection_init()
  * @key: TLS pre-master-secret
  * @key_len: length of key in bytes
- *
  * Returns: 0 on success, -1 on failure
  */
 int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
 				  const u8 *key, size_t key_len);
 
+enum {
+	TLS_CIPHER_NONE,
+	TLS_CIPHER_RC4_SHA /* 0x0005 */,
+	TLS_CIPHER_AES128_SHA /* 0x002f */,
+	TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
+	TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+};
+
 /**
- * tls_connection_set_anon_dh - Configure TLS connection to use anonymous DH
+ * tls_connection_set_cipher_list - Configure acceptable cipher suites
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
  * Returns: 0 on success, -1 on failure
- *
- * TODO: consider changing this to more generic routine for configuring allowed
- * ciphers
  */
-int tls_connection_set_anon_dh(void *tls_ctx, struct tls_connection *conn);
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers);
 
 /**
  * tls_get_cipher - Get current cipher name
@@ -385,7 +400,6 @@
  * @conn: Connection context data from tls_connection_init()
  * @buf: Buffer for the cipher name
  * @buflen: buf size
- *
  * Returns: 0 on success, -1 on failure
  *
  * Get the name of the currently used cipher.
@@ -397,7 +411,6 @@
  * tls_connection_enable_workaround - Enable TLS workaround options
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: 0 on success, -1 on failure
  *
  * This function is used to enable connection-specific workaround options for
@@ -411,9 +424,8 @@
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
  * @ext_type: Extension type
- * @data: Extension payload (NULL to remove extension)
+ * @data: Extension payload (%NULL to remove extension)
  * @data_len: Extension payload length
- *
  * Returns: 0 on success, -1 on failure
  */
 int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
@@ -433,7 +445,6 @@
  * tls_connection_get_read_alerts - Get connection read alert status
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: Number of times a fatal read (remote end reported error) has
  * happened during this connection.
  */
@@ -443,7 +454,6 @@
  * tls_connection_get_write_alerts - Get connection write alert status
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
- *
  * Returns: Number of times a fatal write (locally detected error) has happened
  * during this connection.
  */
@@ -460,4 +470,52 @@
 int tls_connection_get_keyblock_size(void *tls_ctx,
 				     struct tls_connection *conn);
 
+#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
+/**
+ * tls_capabilities - Get supported TLS capabilities
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
+ */
+unsigned int tls_capabilities(void *tls_ctx);
+
+/**
+ * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
+ * @out_data: Pointer to output buffer (encrypted TLS/IA data)
+ * @out_len: Maximum out_data length 
+ * Returns: Number of bytes written to out_data on success, -1 on failure
+ *
+ * This function is used to send the TLS/IA end phase message, e.g., when the
+ * EAP server completes EAP-TTLSv1.
+ */
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+					  struct tls_connection *conn,
+					  int final,
+					  u8 *out_data, size_t out_len);
+
+/**
+ * tls_connection_ia_final_phase_finished - Has final phase been completed
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
+ * on failure
+ */
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+					   struct tls_connection *conn);
+
+/**
+ * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @key: Session key material (session_key vectors with 2-octet length), or
+ * %NULL if no session key was generating in the current phase
+ * @key_len: Length of session key material
+ * Returns: 0 on success, -1 on failure
+ */
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const u8 *key, size_t key_len);
+
 #endif /* TLS_H */
--- /dev/null
+++ contrib/hostapd/eap_sake_common.c
@@ -0,0 +1,380 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006, Jouni Malinen <j at w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "eap_defs.h"
+#include "eap_sake_common.h"
+
+
+static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
+				   const u8 *pos)
+{
+	size_t i;
+
+	switch (pos[0]) {
+	case EAP_SAKE_AT_RAND_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
+		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->rand_s = pos + 2;
+		break;
+	case EAP_SAKE_AT_RAND_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
+		if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->rand_p = pos + 2;
+		break;
+	case EAP_SAKE_AT_MIC_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
+		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->mic_s = pos + 2;
+		break;
+	case EAP_SAKE_AT_MIC_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
+		if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
+				   "invalid length %d", pos[1]);
+			return -1;
+		}
+		attr->mic_p = pos + 2;
+		break;
+	case EAP_SAKE_AT_SERVERID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
+		attr->serverid = pos + 2;
+		attr->serverid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_PEERID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
+		attr->peerid = pos + 2;
+		attr->peerid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_SPI_S:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
+		attr->spi_s = pos + 2;
+		attr->spi_s_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_SPI_P:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
+		attr->spi_p = pos + 2;
+		attr->spi_p_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_ANY_ID_REQ:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
+		if (pos[1] != 4) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
+				   " length %d", pos[1]);
+			return -1;
+		}
+		attr->any_id_req = pos + 2;
+		break;
+	case EAP_SAKE_AT_PERM_ID_REQ:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
+		if (pos[1] != 4) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+				   "AT_PERM_ID_REQ length %d", pos[1]);
+			return -1;
+		}
+		attr->perm_id_req = pos + 2;
+		break;
+	case EAP_SAKE_AT_ENCR_DATA:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
+		attr->encr_data = pos + 2;
+		attr->encr_data_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_IV:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+		attr->iv = pos + 2;
+		attr->iv_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_PADDING:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
+		for (i = 2; i < pos[1]; i++) {
+			if (pos[i]) {
+				wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
+					   "with non-zero pad byte");
+				return -1;
+			}
+		}
+		break;
+	case EAP_SAKE_AT_NEXT_TMPID:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
+		attr->next_tmpid = pos + 2;
+		attr->next_tmpid_len = pos[1] - 2;
+		break;
+	case EAP_SAKE_AT_MSK_LIFE:
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+		if (pos[1] != 6) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+				   "AT_MSK_LIFE length %d", pos[1]);
+			return -1;
+		}
+		attr->msk_life = pos + 2;
+		break;
+	default:
+		if (pos[0] < 128) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
+				   " attribute %d", pos[0]);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
+			   "attribute %d", pos[0]);
+		break;
+	}
+
+	if (attr->iv && !attr->encr_data) {
+		wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_sake_parse_attributes - Parse EAP-SAKE attributes
+ * @buf: Packet payload (starting with the first attribute)
+ * @len: Payload length
+ * @attr: Structure to be filled with found attributes
+ * Returns: 0 on success or -1 on failure
+ */
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+			      struct eap_sake_parse_attr *attr)
+{
+	const u8 *pos = buf, *end = buf + len;
+
+	os_memset(attr, 0, sizeof(*attr));
+	while (pos < end) {
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
+			return -1;
+		}
+
+		if (pos[1] < 2) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
+				   "length (%d)", pos[1]);
+			return -1;
+		}
+
+		if (pos + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
+			return -1;
+		}
+
+		if (eap_sake_parse_add_attr(attr, pos))
+			return -1;
+
+		pos += pos[1];
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @data: Extra data (start) to bind into the key
+ * @data_len: Length of the data
+ * @data2: Extra data (end) to bind into the key
+ * @data2_len: Length of the data2
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
+ */
+static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+			 const u8 *data, size_t data_len,
+			 const u8 *data2, size_t data2_len,
+			 u8 *buf, size_t buf_len)
+{
+	u8 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label) + 1;
+	const unsigned char *addr[4];
+	size_t len[4];
+
+	addr[0] = (u8 *) label; /* Label | Y */
+	len[0] = label_len;
+	addr[1] = data; /* Msg[start] */
+	len[1] = data_len;
+	addr[2] = data2; /* Msg[end] */
+	len[2] = data2_len;
+	addr[3] = &counter; /* Length */
+	len[3] = 1;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		if (plen >= SHA1_MAC_LEN) {
+			hmac_sha1_vector(key, key_len, 4, addr, len,
+					 &buf[pos]);
+			pos += SHA1_MAC_LEN;
+		} else {
+			hmac_sha1_vector(key, key_len, 4, addr, len,
+					 hash);
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+}
+
+
+/**
+ * eap_sake_derive_keys - Derive EAP-SAKE keys
+ * @root_secret_a: 16-byte Root-Secret-A
+ * @root_secret_b: 16-byte Root-Secret-B
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ *
+ * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
+ */
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+			  const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
+			  u8 *emsk)
+{
+	u8 sms_a[EAP_SAKE_SMS_LEN];
+	u8 sms_b[EAP_SAKE_SMS_LEN];
+	u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
+			root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
+	eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+		     "SAKE Master Secret A",
+		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+		     sms_a, EAP_SAKE_SMS_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
+	eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+		     tek, EAP_SAKE_TEK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
+			tek, EAP_SAKE_TEK_AUTH_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
+			tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
+			root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
+	eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+		     "SAKE Master Secret B",
+		     rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+		     sms_b, EAP_SAKE_SMS_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
+	eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+		     rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+		     key_buf, sizeof(key_buf));
+	os_memcpy(msk, key_buf, EAP_MSK_LEN);
+	os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+/**
+ * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
+ * @tek_auth: 16-byte TEK-Auth
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @serverid: SERVERID
+ * @serverid_len: SERVERID length
+ * @peerid: PEERID
+ * @peerid_len: PEERID length
+ * @peer: MIC calculation for 0 = Server, 1 = Peer message
+ * @eap: EAP packet
+ * @eap_len: EAP packet length
+ * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
+ * @mic: Buffer for the computed 16-byte MIC
+ */
+int eap_sake_compute_mic(const u8 *tek_auth,
+			 const u8 *rand_s, const u8 *rand_p,
+			 const u8 *serverid, size_t serverid_len,
+			 const u8 *peerid, size_t peerid_len,
+			 int peer, const u8 *eap, size_t eap_len,
+			 const u8 *mic_pos, u8 *mic)
+{
+	u8 _rand[2 * EAP_SAKE_RAND_LEN];
+	u8 *tmp, *pos;
+	size_t tmplen;
+
+	tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
+	tmp = os_malloc(tmplen);
+	if (tmp == NULL)
+		return -1;
+	pos = tmp;
+	if (peer) {
+		if (peerid) {
+			os_memcpy(pos, peerid, peerid_len);
+			pos += peerid_len;
+		}
+		*pos++ = 0x00;
+		if (serverid) {
+			os_memcpy(pos, serverid, serverid_len);
+			pos += serverid_len;
+		}
+		*pos++ = 0x00;
+
+		os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
+		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
+			  EAP_SAKE_RAND_LEN);
+	} else {
+		if (serverid) {
+			os_memcpy(pos, serverid, serverid_len);
+			pos += serverid_len;
+		}
+		*pos++ = 0x00;
+		if (peerid) {
+			os_memcpy(pos, peerid, peerid_len);
+			pos += peerid_len;
+		}
+		*pos++ = 0x00;
+
+		os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
+		os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
+			  EAP_SAKE_RAND_LEN);
+	}
+
+	os_memcpy(pos, eap, eap_len);
+	os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
+
+	eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+		     peer ? "Peer MIC" : "Server MIC",
+		     _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+		     mic, EAP_SAKE_MIC_LEN);
+
+	os_free(tmp);
+
+	return 0;
+}
Index: ms_funcs.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ms_funcs.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ms_funcs.c -L contrib/hostapd/ms_funcs.c -u -r1.2 -r1.3
--- contrib/hostapd/ms_funcs.c
+++ contrib/hostapd/ms_funcs.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "sha1.h"
@@ -26,7 +24,7 @@
 /**
  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
  * @peer_challenge: 16-octet PeerChallenge (IN)
- * @auth_challenge: 16-octet AuthChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
  * @challenge: 8-octet Challenge (OUT)
@@ -47,41 +45,41 @@
 	len[2] = username_len;
 
 	sha1_vector(3, addr, len, hash);
-	memcpy(challenge, hash, 8);
+	os_memcpy(challenge, hash, 8);
 }
 
 
 /**
  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (OUT)
  */
 void nt_password_hash(const u8 *password, size_t password_len,
 		      u8 *password_hash)
 {
-	u8 *buf;
-	int i;
-	size_t len;
+	u8 buf[512], *pos;
+	size_t i, len;
 
-	/* Convert password into unicode */
-	buf = malloc(password_len * 2);
-	if (buf == NULL)
+	if (password_len > 256)
 		return;
-	memset(buf, 0, password_len * 2);
-	for (i = 0; i < password_len; i++)
+
+	/* Convert password into unicode */
+	for (i = 0; i < password_len; i++) {
 		buf[2 * i] = password[i];
+		buf[2 * i + 1] = 0;
+	}
 
 	len = password_len * 2;
-	md4_vector(1, (const u8 **) &buf, &len, password_hash);
-	free(buf);
+	pos = buf;
+	md4_vector(1, (const u8 **) &pos, &len, password_hash);
 }
 
 
 /**
  * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
  * @password_hash: 16-octet PasswordHash (IN)
- * @password_hash_hash: 16-octet PaswordHashHash (OUT)
+ * @password_hash_hash: 16-octet PasswordHashHash (OUT)
  */
 void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
 {
@@ -104,7 +102,7 @@
 	des_encrypt(challenge, password_hash + 7, response + 8);
 	zpwd[0] = password_hash[14];
 	zpwd[1] = password_hash[15];
-	memset(zpwd + 2, 0, 5);
+	os_memset(zpwd + 2, 0, 5);
 	des_encrypt(challenge, zpwd, response + 16);
 }
 
@@ -115,7 +113,7 @@
  * @peer_hallenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  */
@@ -135,21 +133,44 @@
 
 
 /**
- * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN)
- * @password_len: Length of password
+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_hallenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void generate_nt_response_pwhash(const u8 *auth_challenge,
+				 const u8 *peer_challenge,
+				 const u8 *username, size_t username_len,
+				 const u8 *password_hash,
+				 u8 *response)
+{
+	u8 challenge[8];
+
+	challenge_hash(peer_challenge, auth_challenge, username, username_len,
+		       challenge);
+	challenge_response(challenge, password_hash, response);
+}
+
+
+/**
+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password_hash: 16-octet PasswordHash (IN)
  * @nt_response: 24-octet NT-Response (IN)
  * @peer_challenge: 16-octet PeerChallenge (IN)
  * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
- * @response: 42-octet AuthenticatorResponse (OUT)
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * 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,
-				     const u8 *auth_challenge,
-				     const u8 *username, size_t username_len,
-				     const u8 *nt_response, u8 *response)
+void generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response)
 {
 	static const u8 magic1[39] = {
 		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
@@ -165,7 +186,7 @@
 		0x6E
 	};
 
-	u8 password_hash[16], password_hash_hash[16], challenge[8];
+	u8 password_hash_hash[16], challenge[8];
 	const unsigned char *addr1[3];
 	const size_t len1[3] = { 16, 24, sizeof(magic1) };
 	const unsigned char *addr2[3];
@@ -179,7 +200,6 @@
 	addr2[1] = challenge;
 	addr2[2] = magic2;
 
-	nt_password_hash(password, password_len, password_hash);
 	hash_nt_password_hash(password_hash, password_hash_hash);
 	sha1_vector(3, addr1, len1, response);
 
@@ -190,9 +210,36 @@
 
 
 /**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password_len: Length of password
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @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>)
+ */
+void generate_authenticator_response(const u8 *password, size_t password_len,
+				     const u8 *peer_challenge,
+				     const u8 *auth_challenge,
+				     const u8 *username, size_t username_len,
+				     const u8 *nt_response, u8 *response)
+{
+	u8 password_hash[16];
+	nt_password_hash(password, password_len, password_hash);
+	generate_authenticator_response_pwhash(password_hash,
+					       peer_challenge, auth_challenge,
+					       username, username_len,
+					       nt_response, response);
+}
+
+
+/**
  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
  * @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  */
@@ -228,7 +275,7 @@
 	addr[2] = magic1;
 
 	sha1_vector(3, addr, len, hash);
-	memcpy(master_key, hash, 16);
+	os_memcpy(master_key, hash, 16);
 }
 
 
@@ -236,7 +283,7 @@
  * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
  * @master_key: 16-octet MasterKey (IN)
  * @session_key: 8-to-16 octet SessionKey (OUT)
- * @session_key_len: SessionKeyLength (Length of session_key)
+ * @session_key_len: SessionKeyLength (Length of session_key) (IN)
  * @is_send: IsSend (IN, BOOLEAN)
  * @is_server: IsServer (IN, BOOLEAN)
  */
@@ -296,15 +343,15 @@
 
 	if (session_key_len > SHA1_MAC_LEN)
 		session_key_len = SHA1_MAC_LEN;
-	memcpy(session_key, digest, session_key_len);
+	os_memcpy(session_key, digest, session_key_len);
 }
 
 
 #define PWBLOCK_LEN 516
 
 /**
- * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN)
+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (IN)
  * @pw_block: 516-byte PwBlock (OUT)
@@ -319,10 +366,15 @@
 	if (password_len > 256)
 		return;
 
-	memset(pw_block, 0, PWBLOCK_LEN);
+	os_memset(pw_block, 0, PWBLOCK_LEN);
 	offset = (256 - password_len) * 2;
+	os_get_random(pw_block, offset);
 	for (i = 0; i < password_len; i++)
 		pw_block[offset + i * 2] = password[i];
+	/*
+	 * PasswordLength is 4 octets, but since the maximum password length is
+	 * 256, only first two (in little endian byte order) can be non-zero.
+	 */
 	pos = &pw_block[2 * 256];
 	WPA_PUT_LE16(pos, password_len * 2);
 	rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
@@ -331,9 +383,9 @@
 
 /**
  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
  * @old_password_len: Length of old_password
  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
  */
@@ -367,9 +419,9 @@
 
 /**
  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
  * @old_password_len: Length of old_password
  * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
  */
@@ -386,112 +438,3 @@
 					      new_password_hash,
 					      encrypted_password_hash);
 }
-
-
-#ifdef TEST_MAIN_MS_FUNCS
-
-#include "rc4.c"
-
-int main(int argc, char *argv[])
-{
-	/* Test vector from RFC2759 example */
-	u8 *username = "User";
-	u8 *password = "clientPass";
-	u8 auth_challenge[] = {
-		0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
-		0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
-	};
-	u8 peer_challenge[] = {
-		0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
-		0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
-	};
-	u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
-	u8 password_hash[] = {
-		0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
-		0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
-	};
-	u8 nt_response[] = {
-		0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
-		0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
-		0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
-	};
-	u8 password_hash_hash[] = {
-		0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
-		0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
-	};
-	u8 authenticator_response[] = {
-		0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
-		0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
-		0x93, 0x2C, 0xDA, 0x56
-	};
-	u8 master_key[] = {
-		0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
-		0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
-	};
-	u8 send_start_key[] = {
-		0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
-		0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
-	};
-	u8 buf[32];
-
-	int errors = 0;
-
-	printf("Testing ms_funcs.c\n");
-
-	challenge_hash(peer_challenge, auth_challenge,
-		       username, strlen(username),
-		       buf);
-	if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
-		printf("challenge_hash failed\n");
-		errors++;
-	}
-
-	nt_password_hash(password, strlen(password), buf);
-	if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
-		printf("nt_password_hash failed\n");
-		errors++;
-	}
-
-	generate_nt_response(auth_challenge, peer_challenge,
-			     username, strlen(username),
-			     password, strlen(password),
-			     buf);
-	if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
-		printf("generate_nt_response failed\n");
-		errors++;
-	}
-
-	hash_nt_password_hash(password_hash, buf);
-	if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
-		printf("hash_nt_password_hash failed\n");
-		errors++;
-	}
-
-	generate_authenticator_response(password, strlen(password),
-					peer_challenge, auth_challenge,
-					username, strlen(username),
-					nt_response, buf);
-	if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
-	    != 0) {
-		printf("generate_authenticator_response failed\n");
-		errors++;
-	}
-
-	get_master_key(password_hash_hash, nt_response, buf);
-	if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
-		printf("get_master_key failed\n");
-		errors++;
-	}
-
-	get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
-	if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
-		printf("get_asymetric_start_key failed\n");
-		errors++;
-	}
-
-	if (errors)
-		printf("FAILED! %d errors\n", errors);
-
-	return errors;
-}
-#endif /* TEST_MAIN_MS_FUNCS */
Index: hostapd.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostapd.c -L contrib/hostapd/hostapd.c -u -r1.2 -r1.3
--- contrib/hostapd/hostapd.c
+++ contrib/hostapd/hostapd.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-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
@@ -13,43 +12,41 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
 #include <syslog.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "eloop.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "ieee802_11.h"
+#include "beacon.h"
+#include "hw_features.h"
 #include "accounting.h"
 #include "eapol_sm.h"
 #include "iapp.h"
 #include "ap.h"
 #include "ieee802_11_auth.h"
+#include "ap_list.h"
 #include "sta_info.h"
 #include "driver.h"
 #include "radius_client.h"
 #include "radius_server.h"
 #include "wpa.h"
+#include "preauth.h"
+#include "wme.h"
+#include "vlan_init.h"
 #include "ctrl_iface.h"
 #include "tls.h"
 #include "eap_sim_db.h"
+#include "eap.h"
 #include "version.h"
-#include "hostap_common.h"
 
 
 struct hapd_interfaces {
-	int count;
-	hostapd **hapd;
+	size_t count;
+	struct hostapd_iface **iface;
 };
 
 unsigned char rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
@@ -103,6 +100,9 @@
 	case HOSTAPD_MODULE_IAPP:
 		module_str = "IAPP";
 		break;
+	case HOSTAPD_MODULE_MLME:
+		module_str = "MLME";
+		break;
 	default:
 		module_str = NULL;
 		break;
@@ -132,6 +132,7 @@
 		printf("\n");
 	}
 
+#ifndef CONFIG_NATIVE_WINDOWS
 	if ((conf_syslog & module) && level >= conf_syslog_level) {
 		int priority;
 		switch (level) {
@@ -156,6 +157,7 @@
 		vsyslog(priority, format, ap);
 		va_end(ap);
 	}
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 	free(format);
 }
@@ -183,7 +185,32 @@
 }
 
 
-static void hostapd_deauth_all_stas(hostapd *hapd)
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
+{
+	if (a == NULL && b == NULL)
+		return 0;
+	if (a == NULL || b == NULL)
+		return 1;
+
+	switch (a->af) {
+	case AF_INET:
+		if (a->u.v4.s_addr != b->u.v4.s_addr)
+			return 1;
+		break;
+#ifdef CONFIG_IPV6
+	case AF_INET6:
+		if (memcpy(&a->u.v6, &b->u.v6, sizeof(a->u.v6))
+		    != 0)
+			return 1;
+		break;
+#endif /* CONFIG_IPV6 */
+	}
+
+	return 0;
+}
+
+
+static void hostapd_deauth_all_stas(struct hostapd_data *hapd)
 {
 #if 0
 	u8 addr[ETH_ALEN];
@@ -199,8 +226,51 @@
 }
 
 
-/* This function will be called whenever a station associates with the AP */
-void hostapd_new_assoc_sta(hostapd *hapd, struct sta_info *sta, int reassoc)
+/**
+ * hostapd_prune_associations - Remove extraneous associations
+ * @hapd: Pointer to BSS data for the most recent association
+ * @sta: Pointer to the associated STA data
+ *
+ * This function looks through all radios and BSS's for previous
+ * (stale) associations of STA. If any are found they are removed.
+ */
+static void hostapd_prune_associations(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	struct sta_info *osta;
+	struct hostapd_data *ohapd;
+	size_t i, j;
+	struct hapd_interfaces *interfaces = eloop_get_user_data();
+
+	for (i = 0; i < interfaces->count; i++) {
+		for (j = 0; j < interfaces->iface[i]->num_bss; j++) {
+			ohapd = interfaces->iface[i]->bss[j];
+			if (ohapd == hapd)
+				continue;
+			osta = ap_get_sta(ohapd, sta->addr);
+			if (!osta)
+				continue;
+
+			ap_sta_disassociate(ohapd, osta,
+					    WLAN_REASON_UNSPECIFIED);
+		}
+	}
+}
+
+
+/**
+ * hostapd_new_assoc_sta - Notify that a new station associated with the AP
+ * @hapd: Pointer to BSS data
+ * @sta: Pointer to the associated STA data
+ * @reassoc: 1 to indicate this was a re-association; 0 = first association
+ *
+ * This function will be called whenever a station associates with the AP. It
+ * can be called for ieee802_11.c for drivers that export MLME to hostapd and
+ * from driver_*.c for drivers that take care of management frames (IEEE 802.11
+ * authentication and association) internally.
+ */
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc)
 {
 	if (hapd->tkip_countermeasures) {
 		hostapd_sta_deauth(hapd, sta->addr,
@@ -208,6 +278,8 @@
 		return;
 	}
 
+	hostapd_prune_associations(hapd, sta);
+
 	/* IEEE 802.11F (IAPP) */
 	if (hapd->conf->ieee802_11f)
 		iapp_new_station(hapd->iapp, sta);
@@ -218,13 +290,34 @@
 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
 		accounting_sta_start(hapd, sta);
 
+	hostapd_wme_sta_config(hapd, sta);
+
 	/* Start IEEE 802.1X authentication process for new stations */
 	ieee802_1x_new_station(hapd, sta);
 	if (reassoc)
-		wpa_sm_event(hapd, sta, WPA_REAUTH);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
 	else
-		wpa_new_station(hapd, sta);
+		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
+				 struct sta_info *sta, void *ctx)
+{
+	if (eapol_sm_eap_pending_cb(sta->eapol_sm, ctx) == 0)
+		return 1;
+	return 0;
+}
+
+
+static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0)
+		radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
 }
+#endif /* EAP_SERVER */
 
 
 static void handle_term(int sig, void *eloop_ctx, void *signal_ctx)
@@ -234,17 +327,39 @@
 }
 
 
+static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+				  struct wpa_auth_config *wconf)
+{
+	wconf->wpa = conf->wpa;
+	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
+	wconf->wpa_pairwise = conf->wpa_pairwise;
+	wconf->wpa_group = conf->wpa_group;
+	wconf->wpa_group_rekey = conf->wpa_group_rekey;
+	wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
+	wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
+	wconf->rsn_preauth = conf->rsn_preauth;
+	wconf->eapol_version = conf->eapol_version;
+	wconf->peerkey = conf->peerkey;
+	wconf->wme_enabled = conf->wme_enabled;
+#ifdef CONFIG_IEEE80211W
+	wconf->ieee80211w = conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
 static void handle_reload(int sig, void *eloop_ctx, void *signal_ctx)
 {
 	struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
 	struct hostapd_config *newconf;
-	int i;
+	size_t i;
+	struct wpa_auth_config wpa_auth_conf;
 
 	printf("Signal %d received - reloading configuration\n", sig);
 
 	for (i = 0; i < hapds->count; i++) {
-		hostapd *hapd = hapds->hapd[i];
-		newconf = hostapd_config_read(hapd->config_fname);
+		struct hostapd_data *hapd = hapds->iface[i]->bss[0];
+		newconf = hostapd_config_read(hapds->iface[i]->config_fname);
 		if (newconf == NULL) {
 			printf("Failed to read new configuration file - "
 			       "continuing with old.\n");
@@ -253,15 +368,26 @@
 		/* TODO: update dynamic data based on changed configuration
 		 * items (e.g., open/close sockets, remove stations added to
 		 * deny list, etc.) */
-		radius_client_flush(hapd->radius);
-		hostapd_config_free(hapd->conf);
-		hapd->conf = newconf;
+		radius_client_flush(hapd->radius, 0);
+		hostapd_config_free(hapd->iconf);
+
+		hostapd_wpa_auth_conf(&newconf->bss[0], &wpa_auth_conf);
+		wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
+
+		hapd->iconf = newconf;
+		hapd->conf = &newconf->bss[0];
+		hapds->iface[i]->conf = newconf;
+
+		if (hostapd_setup_wpa_psk(hapd->conf)) {
+			wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
+				   "after reloading configuration");
+		}
 	}
 }
 
 
 #ifdef HOSTAPD_DUMP_STATE
-static void hostapd_dump_state(hostapd *hapd)
+static void hostapd_dump_state(struct hostapd_data *hapd)
 {
 	FILE *f;
 	time_t now;
@@ -284,12 +410,18 @@
 
 	time(&now);
 	fprintf(f, "hostapd state dump - %s", ctime(&now));
+	fprintf(f, "num_sta=%d num_sta_non_erp=%d "
+		"num_sta_no_short_slot_time=%d\n"
+		"num_sta_no_short_preamble=%d\n",
+		hapd->num_sta, hapd->iface->num_sta_non_erp,
+		hapd->iface->num_sta_no_short_slot_time,
+		hapd->iface->num_sta_no_short_preamble);
 
 	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
 		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
 
 		fprintf(f,
-			"  AID=%d flags=0x%x %s%s%s%s%s%s\n"
+			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s\n"
 			"  capability=0x%x listen_interval=%d\n",
 			sta->aid,
 			sta->flags,
@@ -300,18 +432,19 @@
 			(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
 			(sta->flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" :
 			 ""),
+			(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+			 ""),
+			(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
+			 "[SHORT_PREAMBLE]" : ""),
+			(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
 			sta->capability,
 			sta->listen_interval);
 
 		fprintf(f, "  supported_rates=");
-		for (i = 0; i < sizeof(sta->supported_rates); i++)
-			if (sta->supported_rates[i] != 0)
-				fprintf(f, "%02x ", sta->supported_rates[i]);
-		fprintf(f, "%s%s%s%s\n",
-			(sta->tx_supp_rates & WLAN_RATE_1M ? "[1M]" : ""),
-			(sta->tx_supp_rates & WLAN_RATE_2M ? "[2M]" : ""),
-			(sta->tx_supp_rates & WLAN_RATE_5M5 ? "[5.5M]" : ""),
-			(sta->tx_supp_rates & WLAN_RATE_11M ? "[11M]" : ""));
+		for (i = 0; i < sta->supported_rates_len; i++)
+			fprintf(f, "%02x ", sta->supported_rates[i]);
+		fprintf(f, "\n");
 
 		fprintf(f,
 			"  timeout_next=%s\n",
@@ -350,16 +483,92 @@
 {
 #ifdef HOSTAPD_DUMP_STATE
 	struct hapd_interfaces *hapds = (struct hapd_interfaces *) eloop_ctx;
-	int i;
+	size_t i, j;
 
 	for (i = 0; i < hapds->count; i++) {
-		hostapd *hapd = hapds->hapd[i];
-		hostapd_dump_state(hapd);
+		struct hostapd_iface *hapd_iface = hapds->iface[i];
+		for (j = 0; j < hapd_iface->num_bss; j++)
+			hostapd_dump_state(hapd_iface->bss[j]);
 	}
 #endif /* HOSTAPD_DUMP_STATE */
 }
+#endif /* CONFIG_NATIVE_WINDOWS */
 
+static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
+					      char *ifname)
+{
+	int i;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (hostapd_set_encryption(ifname, hapd, "none", NULL, i, NULL,
+					   0, i == 0 ? 1 : 0)) {
+			printf("Failed to clear default encryption keys "
+			       "(ifname=%s keyidx=%d)\n", ifname, i);
+		}
+	}
+}
+
+
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
+{
+	hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
+	return 0;
+}
+
+
+static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
+{
+	int errors = 0, idx;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+	idx = ssid->wep.idx;
+	if (ssid->wep.default_len &&
+	    hostapd_set_encryption(hapd->conf->iface,
+				   hapd, "WEP", NULL, idx,
+			 	   ssid->wep.key[idx],
+			 	   ssid->wep.len[idx],
+				   idx == ssid->wep.idx)) {
+		printf("Could not set WEP encryption.\n");
+		errors++;
+	}
+
+	if (ssid->dyn_vlan_keys) {
+		size_t i;
+		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+			const char *ifname;
+			struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
+			if (key == NULL)
+				continue;
+			ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+							    i);
+			if (ifname == NULL)
+				continue;
+
+			idx = key->idx;
+			if (hostapd_set_encryption(ifname, hapd, "WEP", NULL,
+						   idx, key->key[idx],
+						   key->len[idx],
+						   idx == key->idx)) {
+				printf("Could not set dynamic VLAN WEP "
+				       "encryption.\n");
+				errors++;
+			}
+		}
+	}
 
+	return errors;
+}
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
 static void hostapd_cleanup(struct hostapd_data *hapd)
 {
 	hostapd_ctrl_iface_deinit(hapd);
@@ -367,9 +576,27 @@
 	free(hapd->default_wep_key);
 	hapd->default_wep_key = NULL;
 	iapp_deinit(hapd->iapp);
+	hapd->iapp = NULL;
 	accounting_deinit(hapd);
-	wpa_deinit(hapd);
+	rsn_preauth_iface_deinit(hapd);
+	if (hapd->wpa_auth) {
+		wpa_deinit(hapd->wpa_auth);
+		hapd->wpa_auth = NULL;
+
+		if (hostapd_set_privacy(hapd, 0)) {
+			wpa_printf(MSG_DEBUG, "Could not disable "
+				   "PrivacyInvoked for interface %s",
+				   hapd->conf->iface);
+		}
+
+		if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
+			wpa_printf(MSG_DEBUG, "Could not remove generic "
+				   "information element from interface %s",
+				   hapd->conf->iface);
+		}
+	}
 	ieee802_1x_deinit(hapd);
+	vlan_deinit(hapd);
 	hostapd_acl_deinit(hapd);
 	radius_client_deinit(hapd->radius);
 	hapd->radius = NULL;
@@ -378,14 +605,6 @@
 
 	hostapd_wireless_event_deinit(hapd);
 
-	if (hapd->driver)
-		hostapd_driver_deinit(hapd);
-
-	hostapd_config_free(hapd->conf);
-	hapd->conf = NULL;
-
-	free(hapd->config_fname);
-
 #ifdef EAP_TLS_FUNCS
 	if (hapd->ssl_ctx) {
 		tls_deinit(hapd->ssl_ctx);
@@ -393,39 +612,447 @@
 	}
 #endif /* EAP_TLS_FUNCS */
 
-	if (hapd->eap_sim_db_priv)
+#ifdef EAP_SERVER
+	if (hapd->eap_sim_db_priv) {
 		eap_sim_db_deinit(hapd->eap_sim_db_priv);
+		hapd->eap_sim_db_priv = NULL;
+	}
+#endif /* EAP_SERVER */
+
+	if (hapd->interface_added &&
+	    hostapd_bss_remove(hapd, hapd->conf->iface)) {
+		printf("Failed to remove BSS interface %s\n",
+		       hapd->conf->iface);
+	}
 }
 
 
-static int hostapd_flush_old_stations(hostapd *hapd)
+/**
+ * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called before per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
+{
+}
+
+
+/**
+ * hostapd_cleanup_iface - Complete per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called after per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+{
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = NULL;
+	free(iface->current_rates);
+	iface->current_rates = NULL;
+	ap_list_deinit(iface);
+	hostapd_config_free(iface->conf);
+	iface->conf = NULL;
+
+	free(iface->config_fname);
+	free(iface->bss);
+	free(iface);
+}
+
+
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
+{
+	int i;
+
+	hostapd_broadcast_wep_set(hapd);
+
+	if (hapd->conf->ssid.wep.default_len)
+		return 0;
+
+	for (i = 0; i < 4; i++) {
+		if (hapd->conf->ssid.wep.key[i] &&
+		    hostapd_set_encryption(iface, hapd, "WEP", NULL,
+					   i, hapd->conf->ssid.wep.key[i],
+					   hapd->conf->ssid.wep.len[i],
+					   i == hapd->conf->ssid.wep.idx)) {
+			printf("Could not set WEP encryption.\n");
+			return -1;
+		}
+		if (hapd->conf->ssid.wep.key[i] &&
+		    i == hapd->conf->ssid.wep.idx)
+			hostapd_set_privacy(hapd, 1);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd)
 {
 	int ret = 0;
 
-	printf("Flushing old station entries\n");
+	wpa_printf(MSG_DEBUG, "Flushing old station entries");
 	if (hostapd_flush(hapd)) {
 		printf("Could not connect to kernel driver.\n");
 		ret = -1;
 	}
-	printf("Deauthenticate all stations\n");
+	wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
 	hostapd_deauth_all_stas(hapd);
 
 	return ret;
 }
 
 
-static int hostapd_setup_interface(struct hostapd_data *hapd)
+static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
+				    logger_level level, const char *txt)
 {
-	struct hostapd_config *conf = hapd->conf;
-	u8 ssid[HOSTAPD_SSID_LEN + 1];
-	int ssid_len, set_ssid;
-	int ret = 0;
+	struct hostapd_data *hapd = ctx;
+	int hlevel;
 
-	if (hostapd_driver_init(hapd)) {
-		printf("%s driver initialization failed.\n",
-			hapd->driver ? hapd->driver->name : "Unknown");
-		hapd->driver = NULL;
+	switch (level) {
+	case LOGGER_WARNING:
+		hlevel = HOSTAPD_LEVEL_WARNING;
+		break;
+	case LOGGER_INFO:
+		hlevel = HOSTAPD_LEVEL_INFO;
+		break;
+	case LOGGER_DEBUG:
+	default:
+		hlevel = HOSTAPD_LEVEL_DEBUG;
+		break;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
+}
+
+
+static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
+					u16 reason)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
+		   "STA " MACSTR " reason %d",
+		   __func__, MAC2STR(addr), reason);
+
+	sta = ap_get_sta(hapd, addr);
+	hostapd_sta_deauth(hapd, addr, reason);
+	if (sta == NULL)
+		return;
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+	sta->timeout_next = STA_REMOVE;
+}
+
+
+static void hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	ieee80211_michael_mic_failure(hapd, addr, 0);
+}
+
+
+static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
+				       wpa_eapol_variable var, int value)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return;
+	switch (var) {
+	case WPA_EAPOL_portEnabled:
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_portValid:
+		ieee802_1x_notify_port_valid(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_authorized:
+		ieee802_1x_set_sta_authorized(hapd, sta, value);
+		break;
+	case WPA_EAPOL_portControl_Auto:
+		if (sta->eapol_sm)
+			sta->eapol_sm->portControl = Auto;
+		break;
+	case WPA_EAPOL_keyRun:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyAvailable:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyAvailable = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyDone:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_inc_EapolFramesTx:
+		if (sta->eapol_sm)
+			sta->eapol_sm->dot1xAuthEapolFramesTx++;
+		break;
+	}
+}
+
+
+static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
+				      wpa_eapol_variable var)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL || sta->eapol_sm == NULL)
+		return -1;
+	switch (var) {
+	case WPA_EAPOL_keyRun:
+		return sta->eapol_sm->keyRun;
+	case WPA_EAPOL_keyAvailable:
+		return sta->eapol_sm->keyAvailable;
+	default:
+		return -1;
+	}
+}
+
+
+static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
+					   const u8 *prev_psk)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_get_psk(hapd->conf, addr, prev_psk);
+}
+
+
+static int hostapd_wpa_auth_get_pmk(void *ctx, const u8 *addr, u8 *pmk,
+				    size_t *len)
+{
+	struct hostapd_data *hapd = ctx;
+	u8 *key;
+	size_t keylen;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
 		return -1;
+
+	key = ieee802_1x_get_key_crypt(sta->eapol_sm, &keylen);
+	if (key == NULL)
+		return -1;
+
+	if (keylen > *len)
+		keylen = WPA_PMK_LEN;
+	memcpy(pmk, key, keylen);
+	*len = keylen;
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, const char *alg,
+				    const u8 *addr, int idx, u8 *key,
+				    size_t key_len)
+{
+	struct hostapd_data *hapd = ctx;
+	const char *ifname = hapd->conf->iface;
+
+	if (vlan_id > 0) {
+		ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+		if (ifname == NULL)
+			return -1;
+	}
+
+	return hostapd_set_encryption(ifname, hapd, alg, addr, idx,
+				      key, key_len, 1);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
+				       u8 *seq)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum_igtk(void *ctx, const u8 *addr, int idx,
+					    u8 *seq)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_get_seqnum_igtk(hapd->conf->iface, hapd, addr, idx,
+				       seq);
+}
+
+
+static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+				       const u8 *data, size_t data_len,
+				       int encrypt)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_send_eapol(hapd, addr, data, data_len, encrypt);
+}
+
+
+static int hostapd_wpa_auth_for_each_sta(
+	void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
+	void *cb_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
+			return 1;
+	}
+	return 0;
+}
+
+
+/**
+ * hostapd_validate_bssid_configuration - Validate BSSID configuration
+ * @iface: Pointer to interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to validate that the configured BSSIDs are valid.
+ */
+static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
+{
+	u8 mask[ETH_ALEN] = { 0 };
+	struct hostapd_data *hapd = iface->bss[0];
+	unsigned int i = iface->conf->num_bss, bits = 0, j;
+	int res;
+
+	/* Generate BSSID mask that is large enough to cover the BSSIDs. */
+
+	/* Determine the bits necessary to cover the number of BSSIDs. */
+	for (i--; i; i >>= 1)
+		bits++;
+
+	/* Determine the bits necessary to any configured BSSIDs,
+	   if they are higher than the number of BSSIDs. */
+	for (j = 0; j < iface->conf->num_bss; j++) {
+		if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0)
+			continue;
+
+		for (i = 0; i < ETH_ALEN; i++) {
+			mask[i] |=
+				iface->conf->bss[j].bssid[i] ^
+				hapd->own_addr[i];
+		}
+	}
+
+	for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
+		;
+	j = 0;
+	if (i < ETH_ALEN) {
+		j = (5 - i) * 8;
+
+		while (mask[i] != 0) {
+			mask[i] >>= 1;
+			j++;
+		}
+	}
+
+	if (bits < j)
+		bits = j;
+
+	if (bits > 40)
+		return -1;
+
+	memset(mask, 0xff, ETH_ALEN);
+	j = bits / 8;
+	for (i = 5; i > 5 - j; i--)
+		mask[i] = 0;
+	j = bits % 8;
+	while (j--)
+		mask[i] <<= 1;
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "BSS count %lu, BSSID mask "
+		      MACSTR " (%d bits)\n",
+		      (unsigned long) iface->conf->num_bss, MAC2STR(mask),
+		      bits);
+
+	res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
+	if (res == 0)
+		return 0;
+
+	if (res < 0) {
+		printf("Driver did not accept BSSID mask " MACSTR " for start "
+		       "address " MACSTR ".\n",
+		       MAC2STR(mask), MAC2STR(hapd->own_addr));
+		return -1;
+	}
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
+			printf("Invalid BSSID mask " MACSTR " for start "
+			       "address " MACSTR ".\n"
+			       "Start address must be the first address in the"
+			       " block (i.e., addr AND mask == addr).\n",
+			       MAC2STR(mask), MAC2STR(hapd->own_addr));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int mac_in_conf(struct hostapd_config *conf, const void *a)
+{
+	size_t i;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+ * hostapd_setup_bss - Per-BSS setup (initialization)
+ * @hapd: Pointer to BSS data
+ * @first: Whether this BSS is the first BSS of an interface
+ *
+ * This function is used to initialize all per-BSS data structures and
+ * resources. This gets called in a loop for each BSS when an interface is
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+	int ssid_len, set_ssid;
+
+	if (!first) {
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+			/* Allocate the next available BSSID. */
+			do {
+				inc_byte_array(hapd->own_addr, ETH_ALEN);
+			} while (mac_in_conf(hapd->iconf, hapd->own_addr));
+		} else {
+			/* Allocate the configured BSSID. */
+			memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+
+			if (hostapd_mac_comp(hapd->own_addr,
+					     hapd->iface->bss[0]->own_addr) ==
+			    0) {
+				printf("BSS '%s' may not have BSSID "
+				       "set to the MAC address of the radio\n",
+				       hapd->conf->iface);
+				return -1;
+			}
+		}
+
+		hapd->interface_added = 1;
+		if (hostapd_bss_add(hapd->iface->bss[0], hapd->conf->iface,
+				    hapd->own_addr)) {
+			printf("Failed to add BSS (BSSID=" MACSTR ")\n",
+			       MAC2STR(hapd->own_addr));
+			return -1;
+		}
 	}
 
 	/*
@@ -438,37 +1065,51 @@
 		printf("Could not read SSID from system\n");
 		return -1;
 	}
-	if (conf->ssid_set) {
+	if (conf->ssid.ssid_set) {
 		/*
 		 * If SSID is specified in the config file and it differs
 		 * from what is being used then force installation of the
 		 * new SSID.
 		 */
-		set_ssid = (conf->ssid_len != ssid_len ||
-			    memcmp(conf->ssid, ssid, ssid_len) != 0);
+		set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
+			    memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
 	} else {
 		/*
 		 * No SSID in the config file; just use the one we got
 		 * from the system.
 		 */
 		set_ssid = 0;
-		conf->ssid_len = ssid_len;
-		memcpy(conf->ssid, ssid, conf->ssid_len);
-		conf->ssid[conf->ssid_len] = '\0';
+		conf->ssid.ssid_len = ssid_len;
+		memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
+		conf->ssid.ssid[conf->ssid.ssid_len] = '\0';
 	}
 
 	printf("Using interface %s with hwaddr " MACSTR " and ssid '%s'\n",
-	       hapd->conf->iface, MAC2STR(hapd->own_addr), hapd->conf->ssid);
+	       hapd->conf->iface, MAC2STR(hapd->own_addr),
+	       hapd->conf->ssid.ssid);
 
 	if (hostapd_setup_wpa_psk(conf)) {
 		printf("WPA-PSK setup failed.\n");
 		return -1;
 	}
 
+	/* Set flag for whether SSID is broadcast in beacons */
+	if (hostapd_set_broadcast_ssid(hapd,
+				       !!hapd->conf->ignore_broadcast_ssid)) {
+		printf("Could not set broadcast SSID flag for kernel "
+		       "driver\n");
+		return -1;
+	}
+
+	if (hostapd_set_dtim_period(hapd, hapd->conf->dtim_period)) {
+		printf("Could not set DTIM period for kernel driver\n");
+		return -1;
+	}
+
 	/* Set SSID for the kernel driver (to be used in beacon and probe
 	 * response frames) */
-	if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid,
-					 conf->ssid_len)) {
+	if (set_ssid && hostapd_set_ssid(hapd, (u8 *) conf->ssid.ssid,
+					 conf->ssid.ssid_len)) {
 		printf("Could not set SSID for kernel driver\n");
 		return -1;
 	}
@@ -480,21 +1121,7 @@
 		printf("RADIUS client initialization failed.\n");
 		return -1;
 	}
-	if (conf->radius_server_clients) {
-		struct radius_server_conf srv;
-		memset(&srv, 0, sizeof(srv));
-		srv.client_file = conf->radius_server_clients;
-		srv.auth_port = conf->radius_server_auth_port;
-		srv.hostapd_conf = conf;
-		srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
-		srv.ssl_ctx = hapd->ssl_ctx;
-		srv.ipv6 = conf->radius_server_ipv6;
-		hapd->radius_srv = radius_server_init(&srv);
-		if (hapd->radius_srv == NULL) {
-			printf("RADIUS server initialization failed.\n");
-			return -1;
-		}
-	}
+
 	if (hostapd_acl_init(hapd)) {
 		printf("ACL initialization failed.\n");
 		return -1;
@@ -504,9 +1131,51 @@
 		return -1;
 	}
 
-	if (hapd->conf->wpa && wpa_init(hapd)) {
-		printf("WPA initialization failed.\n");
-		return -1;
+	if (hapd->conf->wpa) {
+		struct wpa_auth_config _conf;
+		struct wpa_auth_callbacks cb;
+		const u8 *wpa_ie;
+		size_t wpa_ie_len;
+
+		hostapd_wpa_auth_conf(hapd->conf, &_conf);
+		memset(&cb, 0, sizeof(cb));
+		cb.ctx = hapd;
+		cb.logger = hostapd_wpa_auth_logger;
+		cb.disconnect = hostapd_wpa_auth_disconnect;
+		cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+		cb.set_eapol = hostapd_wpa_auth_set_eapol;
+		cb.get_eapol = hostapd_wpa_auth_get_eapol;
+		cb.get_psk = hostapd_wpa_auth_get_psk;
+		cb.get_pmk = hostapd_wpa_auth_get_pmk;
+		cb.set_key = hostapd_wpa_auth_set_key;
+		cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
+		cb.get_seqnum_igtk = hostapd_wpa_auth_get_seqnum_igtk;
+		cb.send_eapol = hostapd_wpa_auth_send_eapol;
+		cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
+		hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+		if (hapd->wpa_auth == NULL) {
+			printf("WPA initialization failed.\n");
+			return -1;
+		}
+
+		if (hostapd_set_privacy(hapd, 1)) {
+			wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
+				   "for interface %s", hapd->conf->iface);
+			return -1;
+		}
+
+		wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+		if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
+			wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+				   "the kernel driver.");
+			return -1;
+		}
+
+		if (rsn_preauth_iface_init(hapd)) {
+			printf("Initialization of RSN pre-authentication "
+			       "failed.\n");
+			return -1;
+		}
 	}
 
 	if (accounting_init(hapd)) {
@@ -520,21 +1189,308 @@
 		return -1;
 	}
 
-	if (hostapd_wireless_event_init(hapd) < 0)
+	if (hostapd_ctrl_iface_init(hapd)) {
+		printf("Failed to setup control interface\n");
 		return -1;
+	}
 
-	if (hostapd_flush_old_stations(hapd))
+	ieee802_11_set_beacon(hapd);
+
+	if (vlan_init(hapd)) {
+		printf("VLAN initialization failed.\n");
 		return -1;
+	}
 
-	if (hostapd_ctrl_iface_init(hapd)) {
-		printf("Failed to setup control interface\n");
-		ret = -1;
+	return 0;
+}
+
+
+/**
+ * setup_interface2 - Setup (initialize) an interface (part 2)
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success; -1 on failure.
+ *
+ * Flushes old stations, sets the channel, DFS parameters, encryption,
+ * beacons, and WDS links based on the configuration.
+ */
+static int setup_interface2(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int freq;
+	size_t j;
+	int ret = 0;
+	u8 *prev_addr;
+
+	hostapd_flush_old_stations(hapd);
+	hostapd_set_privacy(hapd, 0);
+
+	if (hapd->iconf->channel) {
+		freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+		printf("Mode: %s  Channel: %d  Frequency: %d MHz\n",
+		       hostapd_hw_mode_txt(hapd->iconf->hw_mode),
+		       hapd->iconf->channel, freq);
+
+		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq)) {
+			printf("Could not set channel for kernel driver\n");
+			return -1;
+		}
+	}
+
+	hostapd_broadcast_wep_clear(hapd);
+	if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+		return -1;
+
+	hostapd_set_beacon_int(hapd, hapd->iconf->beacon_int);
+	ieee802_11_set_beacon(hapd);
+
+	if (hapd->iconf->rts_threshold > -1 &&
+	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+		printf("Could not set RTS threshold for kernel driver\n");
+		return -1;
+	}
+
+	if (hapd->iconf->fragm_threshold > -1 &&
+	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+		printf("Could not set fragmentation threshold for kernel "
+		       "driver\n");
+		return -1;
+	}
+
+	prev_addr = hapd->own_addr;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		if (j)
+			memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+		if (hostapd_setup_bss(hapd, j == 0))
+			return -1;
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+			prev_addr = hapd->own_addr;
+	}
+
+	ap_list_init(iface);
+
+	if (hostapd_driver_commit(hapd) < 0) {
+		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
+			   "configuration", __func__);
+		return -1;
 	}
 
 	return ret;
 }
 
 
+static void setup_interface_start(void *eloop_data, void *user_ctx);
+static void setup_interface2_handler(void *eloop_data, void *user_ctx);
+
+/**
+ * setup_interface_finalize - Finish setup interface & call the callback
+ * @iface: Pointer to interface data.
+ * @status: Status of the setup interface (0 on success; -1 on failure).
+ * Returns: 0 on success; -1 on failure (e.g., was not in progress).
+ */
+static int setup_interface_finalize(struct hostapd_iface *iface, int status)
+{
+	hostapd_iface_cb cb;
+
+	if (!iface->setup_cb)
+		return -1;
+	
+	eloop_cancel_timeout(setup_interface_start, iface, NULL);
+	eloop_cancel_timeout(setup_interface2_handler, iface, NULL);
+	hostapd_select_hw_mode_stop(iface);
+
+	cb = iface->setup_cb;
+
+	iface->setup_cb = NULL;
+
+	cb(iface, status);
+
+	return 0;
+}
+
+
+/**
+ * setup_interface2_wrapper - Wrapper for setup_interface2()
+ * @iface: Pointer to interface data.
+ * @status: Status of the hw mode select.
+ *
+ * Wrapper for setup_interface2() to calls finalize function upon completion.
+ */
+static void setup_interface2_wrapper(struct hostapd_iface *iface, int status)
+{
+	int ret = status;
+	if (ret)
+		printf("Could not select hw_mode and channel. (%d)\n", ret);
+	else
+		ret = setup_interface2(iface);
+
+	setup_interface_finalize(iface, ret);
+}
+
+
+/**
+ * setup_interface2_handler - Used for immediate call of setup_interface2
+ * @eloop_data: Stores the struct hostapd_iface * for the interface.
+ * @user_ctx: Unused.
+ */
+static void setup_interface2_handler(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = eloop_data;
+
+	setup_interface2_wrapper(iface, 0);
+}
+
+
+/**
+ * setup_interface1 - Setup (initialize) an interface (part 1)
+ * @iface: Pointer to interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initializes the driver interface, validates the configuration,
+ * and sets driver parameters based on the configuration.
+ * Schedules setup_interface2() to be called immediately or after
+ * hardware mode setup takes place. 
+ */
+static int setup_interface1(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_bss_config *conf = hapd->conf;
+	size_t i;
+	char country[4];
+
+	/*
+	 * Initialize the driver interface and make sure that all BSSes get
+	 * configured with a pointer to this driver interface.
+	 */
+	if (hostapd_driver_init(hapd)) {
+		printf("%s driver initialization failed.\n",
+			hapd->driver ? hapd->driver->name : "Unknown");
+		hapd->driver = NULL;
+		return -1;
+	}
+	for (i = 0; i < iface->num_bss; i++)
+		iface->bss[i]->driver = hapd->driver;
+
+	if (hostapd_validate_bssid_configuration(iface))
+		return -1;
+
+	memcpy(country, hapd->iconf->country, 3);
+	country[3] = '\0';
+	if (hostapd_set_country(hapd, country) < 0) {
+		printf("Failed to set country code\n");
+		return -1;
+	}
+
+	if (hapd->iconf->ieee80211d || hapd->iconf->ieee80211h) {
+		if (hostapd_set_ieee80211d(hapd, 1) < 0) {
+			printf("Failed to set ieee80211d (%d)\n",
+			       hapd->iconf->ieee80211d);
+			return -1;
+		}
+	}
+
+	if (hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
+	    hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets)) {
+		printf("Failed to set bridge_packets for kernel driver\n");
+		return -1;
+	}
+
+	if (conf->radius_server_clients) {
+		struct radius_server_conf srv;
+		memset(&srv, 0, sizeof(srv));
+		srv.client_file = conf->radius_server_clients;
+		srv.auth_port = conf->radius_server_auth_port;
+		srv.hostapd_conf = conf;
+		srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
+		srv.ssl_ctx = hapd->ssl_ctx;
+		srv.ipv6 = conf->radius_server_ipv6;
+		hapd->radius_srv = radius_server_init(&srv);
+		if (hapd->radius_srv == NULL) {
+			printf("RADIUS server initialization failed.\n");
+			return -1;
+		}
+	}
+
+	/* TODO: merge with hostapd_driver_init() ? */
+	if (hostapd_wireless_event_init(hapd) < 0)
+		return -1;
+
+	if (hostapd_get_hw_features(iface)) {
+		/* Not all drivers support this yet, so continue without hw
+		 * feature data. */
+	} else {
+		return hostapd_select_hw_mode_start(iface,
+						    setup_interface2_wrapper);
+	}
+
+	eloop_register_timeout(0, 0, setup_interface2_handler, iface, NULL);
+	return 0;
+}
+
+
+/**
+ * setup_interface_start - Handler to start setup interface
+ * @eloop_data: Stores the struct hostapd_iface * for the interface.
+ * @user_ctx: Unused.
+ *
+ * An eloop handler is used so that all errors can be processed by the
+ * callback without introducing stack recursion.
+ */
+static void setup_interface_start(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = eloop_data;
+
+	int ret;
+
+	ret = setup_interface1(iface);
+	if (ret)
+		setup_interface_finalize(iface, ret);
+}
+
+
+/**
+ * hostapd_setup_interface_start - Start the setup of an interface
+ * @iface: Pointer to interface data.
+ * @cb: The function to callback when done.
+ * Returns:  0 if it starts successfully; cb will be called when done.
+ *          -1 on failure; cb will not be called.
+ *
+ * Initializes the driver interface, validates the configuration,
+ * and sets driver parameters based on the configuration.
+ * Flushes old stations, sets the channel, DFS parameters, encryption,
+ * beacons, and WDS links based on the configuration.
+ */
+int hostapd_setup_interface_start(struct hostapd_iface *iface,
+				  hostapd_iface_cb cb)
+{
+	if (iface->setup_cb) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Interface setup already in progress.\n",
+			   iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	iface->setup_cb = cb;
+
+	eloop_register_timeout(0, 0, setup_interface_start, iface, NULL);
+
+	return 0;
+}
+
+
+/**
+ * hostapd_setup_interace_stop - Stops the setup of an interface
+ * @iface: Pointer to interface data
+ * Returns:  0 if successfully stopped;
+ *          -1 on failure (i.e., was not in progress)
+ */
+int hostapd_setup_interface_stop(struct hostapd_iface *iface)
+{
+	return setup_interface_finalize(iface, -1);
+}
+
+
 struct driver {
 	struct driver *next;
 	char *name;
@@ -620,7 +1576,7 @@
 		"hostapd v" VERSION_STR "\n"
 		"User space daemon for IEEE 802.11 AP management,\n"
 		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
-		"Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi> "
+		"Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi> "
 		"and contributors\n");
 }
 
@@ -630,12 +1586,14 @@
 	show_version();
 	fprintf(stderr,
 		"\n"
-		"usage: hostapd [-hdBKt] <configuration file(s)>\n"
+		"usage: hostapd [-hdBKtv] [-P <PID file>] "
+		"<configuration file(s)>\n"
 		"\n"
 		"options:\n"
 		"   -h   show this usage\n"
 		"   -d   show more debug messages (-dd for even more)\n"
 		"   -B   run daemon in the background\n"
+		"   -P   PID file\n"
 		"   -K   include key data in debug messages\n"
 		"   -t   include timestamps in some debug messages\n"
 		"   -v   show hostapd version\n");
@@ -644,27 +1602,31 @@
 }
 
 
-static hostapd * hostapd_init(const char *config_file)
+/**
+ * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
+ * @hapd_iface: Pointer to interface data
+ * @conf: Pointer to per-interface configuration
+ * @bss: Pointer to per-BSS configuration for this BSS
+ * Returns: Pointer to allocated BSS data
+ *
+ * This function is used to allocate per-BSS data structure. This data will be
+ * freed after hostapd_cleanup() is called for it during interface
+ * deinitialization.
+ */
+static struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss)
 {
-	hostapd *hapd;
+	struct hostapd_data *hapd;
 
-	hapd = malloc(sizeof(*hapd));
-	if (hapd == NULL) {
-		printf("Could not allocate memory for hostapd data\n");
-		goto fail;
-	}
-	memset(hapd, 0, sizeof(*hapd));
-
-	hapd->config_fname = strdup(config_file);
-	if (hapd->config_fname == NULL) {
-		printf("Could not allocate memory for config_fname\n");
-		goto fail;
-	}
+	hapd = wpa_zalloc(sizeof(*hapd));
+	if (hapd == NULL)
+		return NULL;
 
-	hapd->conf = hostapd_config_read(hapd->config_fname);
-	if (hapd->conf == NULL) {
-		goto fail;
-	}
+	hapd->iconf = conf;
+	hapd->conf = bss;
+	hapd->iface = hapd_iface;
 
 	if (hapd->conf->individual_wep_key_len > 0) {
 		/* use key0 in individual key and key1 in broadcast key */
@@ -674,29 +1636,25 @@
 #ifdef EAP_TLS_FUNCS
 	if (hapd->conf->eap_server &&
 	    (hapd->conf->ca_cert || hapd->conf->server_cert)) {
+		struct tls_connection_params params;
+
 		hapd->ssl_ctx = tls_init(NULL);
 		if (hapd->ssl_ctx == NULL) {
 			printf("Failed to initialize TLS\n");
 			goto fail;
 		}
-		if (tls_global_ca_cert(hapd->ssl_ctx, hapd->conf->ca_cert)) {
-			printf("Failed to load CA certificate (%s)\n",
-				hapd->conf->ca_cert);
-			goto fail;
-		}
-		if (tls_global_client_cert(hapd->ssl_ctx,
-					   hapd->conf->server_cert)) {
-			printf("Failed to load server certificate (%s)\n",
-				hapd->conf->server_cert);
-			goto fail;
-		}
-		if (tls_global_private_key(hapd->ssl_ctx,
-					   hapd->conf->private_key,
-					   hapd->conf->private_key_passwd)) {
-			printf("Failed to load private key (%s)\n",
-			       hapd->conf->private_key);
+
+		memset(&params, 0, sizeof(params));
+		params.ca_cert = hapd->conf->ca_cert;
+		params.client_cert = hapd->conf->server_cert;
+		params.private_key = hapd->conf->private_key;
+		params.private_key_passwd = hapd->conf->private_key_passwd;
+
+		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
+			printf("Failed to set TLS parameters\n");
 			goto fail;
 		}
+
 		if (tls_global_set_verify(hapd->ssl_ctx,
 					  hapd->conf->check_crl)) {
 			printf("Failed to enable check_crl\n");
@@ -705,47 +1663,135 @@
 	}
 #endif /* EAP_TLS_FUNCS */
 
+#ifdef EAP_SERVER
 	if (hapd->conf->eap_sim_db) {
 		hapd->eap_sim_db_priv =
-			eap_sim_db_init(hapd->conf->eap_sim_db);
+			eap_sim_db_init(hapd->conf->eap_sim_db,
+					hostapd_sim_db_cb, hapd);
 		if (hapd->eap_sim_db_priv == NULL) {
 			printf("Failed to initialize EAP-SIM database "
 			       "interface\n");
 			goto fail;
 		}
 	}
+#endif /* EAP_SERVER */
 
 	if (hapd->conf->assoc_ap)
 		hapd->assoc_ap_state = WAIT_BEACON;
 
 	/* FIX: need to fix this const vs. not */
-	hapd->driver = (struct driver_ops *) hapd->conf->driver;
+	hapd->driver = (struct driver_ops *) hapd->iconf->driver;
 
 	return hapd;
 
+#if defined(EAP_TLS_FUNCS) || defined(EAP_SERVER)
 fail:
-	if (hapd) {
-		if (hapd->ssl_ctx)
-			tls_deinit(hapd->ssl_ctx);
-		if (hapd->conf)
-			hostapd_config_free(hapd->conf);
-		free(hapd->config_fname);
-		free(hapd);
+#endif
+	/* TODO: cleanup allocated resources(?) */
+	free(hapd);
+	return NULL;
+}
+
+
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+static struct hostapd_iface * hostapd_init(const char *config_file)
+{
+	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_config *conf = NULL;
+	struct hostapd_data *hapd;
+	size_t i;
+
+	hapd_iface = wpa_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL)
+		goto fail;
+
+	hapd_iface->config_fname = strdup(config_file);
+	if (hapd_iface->config_fname == NULL)
+		goto fail;
+
+	conf = hostapd_config_read(hapd_iface->config_fname);
+	if (conf == NULL)
+		goto fail;
+	hapd_iface->conf = conf;
+
+	hapd_iface->num_bss = conf->num_bss;
+	hapd_iface->bss = wpa_zalloc(conf->num_bss *
+				     sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		goto fail;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd == NULL)
+			goto fail;
+	}
+
+	return hapd_iface;
+
+fail:
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		for (i = 0; hapd_iface->bss && i < hapd_iface->num_bss; i++) {
+			hapd = hapd_iface->bss[i];
+			if (hapd && hapd->ssl_ctx)
+				tls_deinit(hapd->ssl_ctx);
+		}
+
+		free(hapd_iface->config_fname);
+		free(hapd_iface->bss);
+		free(hapd_iface);
 	}
 	return NULL;
 }
 
 
+/**
+ * register_drivers - Register driver interfaces
+ *
+ * This function is generated by Makefile (into driver_conf.c) to call all
+ * configured driver interfaces to register them to core hostapd.
+ */
 void register_drivers(void);
 
+
+/**
+ * setup_interface_done - Callback when an interface is done being setup.
+ * @iface: Pointer to interface data.
+ * @status: Status of the interface setup (0 on success; -1 on failure).
+ */
+static void setup_interface_done(struct hostapd_iface *iface, int status)
+{
+	if (status) {
+		wpa_printf(MSG_DEBUG, "%s: Unable to setup interface.",
+			   iface->bss[0]->conf->iface);
+		eloop_terminate();
+	} else
+		wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+			   iface->bss[0]->conf->iface);
+}
+
+
 int main(int argc, char *argv[])
 {
 	struct hapd_interfaces interfaces;
-	int ret = 1, i, j;
+	int ret = 1, k;
+	size_t i, j;
 	int c, debug = 0, daemonize = 0;
+	const char *pid_file = NULL;
 
 	for (;;) {
-		c = getopt(argc, argv, "BdhKtv");
+		c = getopt(argc, argv, "BdhKP:tv");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -754,6 +1800,8 @@
 			break;
 		case 'd':
 			debug++;
+			if (wpa_debug_level > 0)
+				wpa_debug_level--;
 			break;
 		case 'B':
 			daemonize++;
@@ -761,6 +1809,9 @@
 		case 'K':
 			wpa_debug_show_keys++;
 			break;
+		case 'P':
+			pid_file = optarg;
+			break;
 		case 't':
 			wpa_debug_timestamp++;
 			break;
@@ -780,67 +1831,106 @@
 
 	register_drivers();		/* NB: generated by Makefile */
 
+	if (eap_server_register_methods()) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		return -1;
+	}
+
 	interfaces.count = argc - optind;
 
-	interfaces.hapd = malloc(interfaces.count * sizeof(hostapd *));
-	if (interfaces.hapd == NULL) {
+	interfaces.iface = malloc(interfaces.count *
+				  sizeof(struct hostapd_iface *));
+	if (interfaces.iface == NULL) {
 		printf("malloc failed\n");
 		exit(1);
 	}
 
-	eloop_init(&interfaces);
+	if (eloop_init(&interfaces)) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+#ifndef CONFIG_NATIVE_WINDOWS
 	eloop_register_signal(SIGHUP, handle_reload, NULL);
-	eloop_register_signal(SIGINT, handle_term, NULL);
-	eloop_register_signal(SIGTERM, handle_term, NULL);
 	eloop_register_signal(SIGUSR1, handle_dump_state, NULL);
+#endif /* CONFIG_NATIVE_WINDOWS */
+	eloop_register_signal_terminate(handle_term, NULL);
 
+	/* Initialize interfaces */
 	for (i = 0; i < interfaces.count; i++) {
 		printf("Configuration file: %s\n", argv[optind + i]);
-		interfaces.hapd[i] = hostapd_init(argv[optind + i]);
-		if (!interfaces.hapd[i])
+		interfaces.iface[i] = hostapd_init(argv[optind + i]);
+		if (!interfaces.iface[i])
 			goto out;
-		for (j = 0; j < debug; j++) {
-			if (interfaces.hapd[i]->conf->logger_stdout_level > 0)
-				interfaces.hapd[i]->conf->
+		for (k = 0; k < debug; k++) {
+			if (interfaces.iface[i]->bss[0]->conf->
+			    logger_stdout_level > 0)
+				interfaces.iface[i]->bss[0]->conf->
 					logger_stdout_level--;
-			interfaces.hapd[i]->conf->debug++;
+			interfaces.iface[i]->bss[0]->conf->debug++;
 		}
-		if (hostapd_setup_interface(interfaces.hapd[i]))
+
+		ret = hostapd_setup_interface_start(interfaces.iface[i],
+						    setup_interface_done);
+		if (ret)
 			goto out;
-		wpa_debug_level -= interfaces.hapd[0]->conf->debug;
 	}
 
-	if (daemonize && daemon(0, 0)) {
+	if (daemonize && os_daemonize(pid_file)) {
 		perror("daemon");
 		goto out;
 	}
 
+#ifndef CONFIG_NATIVE_WINDOWS
 	openlog("hostapd", 0, LOG_DAEMON);
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 	eloop_run();
 
+	/* Disconnect associated stations from all interfaces and BSSes */
 	for (i = 0; i < interfaces.count; i++) {
-		hostapd_free_stas(interfaces.hapd[i]);
-		hostapd_flush_old_stations(interfaces.hapd[i]);
+		for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
+			struct hostapd_data *hapd =
+				interfaces.iface[i]->bss[j];
+			hostapd_free_stas(hapd);
+			hostapd_flush_old_stations(hapd);
+		}
 	}
 
 	ret = 0;
 
  out:
+	/* Deinitialize all interfaces */
 	for (i = 0; i < interfaces.count; i++) {
-		if (!interfaces.hapd[i])
+		if (!interfaces.iface[i])
 			continue;
-
-		hostapd_cleanup(interfaces.hapd[i]);
-		free(interfaces.hapd[i]);
+		hostapd_setup_interface_stop(interfaces.iface[i]);
+		hostapd_cleanup_iface_pre(interfaces.iface[i]);
+		for (j = 0; j < interfaces.iface[i]->num_bss; j++) {
+			struct hostapd_data *hapd =
+				interfaces.iface[i]->bss[j];
+			hostapd_cleanup(hapd);
+			if (j == interfaces.iface[i]->num_bss - 1 &&
+			    hapd->driver)
+				hostapd_driver_deinit(hapd);
+		}
+		for (j = 0; j < interfaces.iface[i]->num_bss; j++)
+			free(interfaces.iface[i]->bss[j]);
+		hostapd_cleanup_iface(interfaces.iface[i]);
 	}
-	free(interfaces.hapd);
+	free(interfaces.iface);
 
 	eloop_destroy();
 
+#ifndef CONFIG_NATIVE_WINDOWS
 	closelog();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	eap_server_unregister_methods();
 
 	driver_unregister_all();
 
+	os_daemonize_terminate(pid_file);
+
 	return ret;
 }
Index: radius_server.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius_server.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius_server.c -L contrib/hostapd/radius_server.c -u -r1.2 -r1.3
--- contrib/hostapd/radius_server.c
+++ contrib/hostapd/radius_server.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / RADIUS authentication server
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2005-2006, 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,13 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
+#include "includes.h"
 #include <net/if.h>
 
 #include "common.h"
@@ -37,6 +31,19 @@
 struct radius_client;
 struct radius_server_data;
 
+struct radius_server_counters {
+	u32 access_requests;
+	u32 invalid_requests;
+	u32 dup_access_requests;
+	u32 access_accepts;
+	u32 access_rejects;
+	u32 access_challenges;
+	u32 malformed_access_requests;
+	u32 bad_authenticators;
+	u32 packets_dropped;
+	u32 unknown_types;
+};
+
 struct radius_session {
 	struct radius_session *next;
 	struct radius_client *client;
@@ -47,6 +54,15 @@
 	size_t eapKeyDataLen, eapReqDataLen;
 	Boolean eapSuccess, eapRestart, eapFail, eapResp, eapReq, eapNoReq;
 	Boolean portEnabled, eapTimeout;
+
+	struct radius_msg *last_msg;
+	char *last_from_addr;
+	int last_from_port;
+	struct sockaddr_storage last_from;
+	socklen_t last_fromlen;
+	u8 last_identifier;
+	struct radius_msg *last_reply;
+	u8 last_authenticator[16];
 };
 
 struct radius_client {
@@ -60,18 +76,20 @@
 	char *shared_secret;
 	int shared_secret_len;
 	struct radius_session *sessions;
+	struct radius_server_counters counters;
 };
 
 struct radius_server_data {
 	int auth_sock;
 	struct radius_client *clients;
-	struct radius_server_session *sessions;
 	unsigned int next_sess_id;
 	void *hostapd_conf;
 	int num_sess;
 	void *eap_sim_db_priv;
 	void *ssl_ctx;
 	int ipv6;
+	struct os_time start_time;
+	struct radius_server_counters counters;
 };
 
 
@@ -153,17 +171,31 @@
 	free(sess->eapKeyData);
 	free(sess->eapReqData);
 	eap_sm_deinit(sess->eap);
+	if (sess->last_msg) {
+		radius_msg_free(sess->last_msg);
+		free(sess->last_msg);
+	}
+	free(sess->last_from_addr);
+	if (sess->last_reply) {
+		radius_msg_free(sess->last_reply);
+		free(sess->last_reply);
+	}
 	free(sess);
 	data->num_sess--;
 }
 
 
+static void radius_server_session_remove_timeout(void *eloop_ctx,
+						 void *timeout_ctx);
+
 static void radius_server_session_remove(struct radius_server_data *data,
 					 struct radius_session *sess)
 {
 	struct radius_client *client = sess->client;
 	struct radius_session *session, *prev;
 
+	eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
+
 	prev = NULL;
 	session = client->sessions;
 	while (session) {
@@ -182,6 +214,16 @@
 }
 
 
+static void radius_server_session_remove_timeout(void *eloop_ctx,
+						 void *timeout_ctx)
+{
+	struct radius_server_data *data = eloop_ctx;
+	struct radius_session *sess = timeout_ctx;
+	RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
+	radius_server_session_remove(data, sess);
+}
+
+
 static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct radius_server_data *data = eloop_ctx;
@@ -204,11 +246,10 @@
 		return NULL;
 	}
 
-	sess = malloc(sizeof(*sess));
-	if (sess == NULL) {
+	sess = wpa_zalloc(sizeof(*sess));
+	if (sess == NULL)
 		return NULL;
-	}
-	memset(sess, 0, sizeof(*sess));
+
 	sess->server = data;
 	sess->client = client;
 	sess->sess_id = data->next_sess_id++;
@@ -303,6 +344,7 @@
 
 	msg = radius_msg_new(code, request->hdr->identifier);
 	if (msg == NULL) {
+		RADIUS_DEBUG("Failed to allocate reply message");
 		return NULL;
 	}
 
@@ -383,6 +425,8 @@
 		radius_msg_dump(msg);
 	}
 
+	data->counters.access_rejects++;
+	client->counters.access_rejects++;
 	if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,
 		   (struct sockaddr *) from, sizeof(*from)) < 0) {
 		perror("sendto[RADIUS SRV]");
@@ -400,28 +444,31 @@
 				 struct radius_msg *msg,
 				 struct sockaddr *from, socklen_t fromlen,
 				 struct radius_client *client,
-				 const char *from_addr, int from_port)
+				 const char *from_addr, int from_port,
+				 struct radius_session *force_sess)
 {
 	u8 *eap = NULL;
 	size_t eap_len;
-	int res, state_included;
+	int res, state_included = 0;
 	u8 statebuf[4], resp_id;
 	unsigned int state;
 	struct radius_session *sess;
 	struct radius_msg *reply;
 	struct eap_hdr *hdr;
 
-	/* TODO: Implement duplicate packet processing */
-
-	res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
-				  sizeof(statebuf));
-	state_included = res >= 0;
-	if (res == sizeof(statebuf)) {
-		state = (statebuf[0] << 24) | (statebuf[1] << 16) |
-			(statebuf[2] << 8) | statebuf[3];
-		sess = radius_server_get_session(client, state);
-	} else {
-		sess = NULL;
+	if (force_sess)
+		sess = force_sess;
+	else {
+		res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
+					  sizeof(statebuf));
+		state_included = res >= 0;
+		if (res == sizeof(statebuf)) {
+			state = (statebuf[0] << 24) | (statebuf[1] << 16) |
+				(statebuf[2] << 8) | statebuf[3];
+			sess = radius_server_get_session(client, state);
+		} else {
+			sess = NULL;
+		}
 	}
 
 	if (sess) {
@@ -441,10 +488,35 @@
 		}
 	}
 
+	if (sess->last_from_port == from_port &&
+	    sess->last_identifier == msg->hdr->identifier &&
+	    os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) ==
+	    0) {
+		RADIUS_DEBUG("Duplicate message from %s", from_addr);
+		data->counters.dup_access_requests++;
+		client->counters.dup_access_requests++;
+
+		if (sess->last_reply) {
+			res = sendto(data->auth_sock, sess->last_reply->buf,
+				     sess->last_reply->buf_used, 0,
+				     (struct sockaddr *) from, fromlen);
+			if (res < 0) {
+				perror("sendto[RADIUS SRV]");
+			}
+			return 0;
+		}
+
+		RADIUS_DEBUG("No previous reply available for duplicate "
+			     "message");
+		return -1;
+	}
+		      
 	eap = radius_msg_get_eap(msg, &eap_len);
 	if (eap == NULL) {
 		RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
 			     from_addr);
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
 		return -1;
 	}
 
@@ -475,18 +547,31 @@
 	} else if (sess->eapFail) {
 		RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
 			     "set - generate EAP-Failure");
-		hdr = malloc(sizeof(*hdr));
+		hdr = wpa_zalloc(sizeof(*hdr));
 		if (hdr) {
-			memset(hdr, 0, sizeof(*hdr));
 			hdr->identifier = resp_id;
 			hdr->length = htons(sizeof(*hdr));
 			sess->eapReqData = (u8 *) hdr;
 			sess->eapReqDataLen = sizeof(*hdr);
 		}
+	} else if (eap_sm_method_pending(sess->eap)) {
+		if (sess->last_msg) {
+			radius_msg_free(sess->last_msg);
+			free(sess->last_msg);
+		}
+		sess->last_msg = msg;
+		sess->last_from_port = from_port;
+		free(sess->last_from_addr);
+		sess->last_from_addr = strdup(from_addr);
+		sess->last_fromlen = fromlen;
+		memcpy(&sess->last_from, from, fromlen);
+		return -2;
 	} else {
 		RADIUS_DEBUG("No EAP data from the state machine - ignore this"
 			     " Access-Request silently (assuming it was a "
 			     "duplicate)");
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
 		return -1;
 	}
 
@@ -502,18 +587,47 @@
 			radius_msg_dump(reply);
 		}
 
+		switch (reply->hdr->code) {
+		case RADIUS_CODE_ACCESS_ACCEPT:
+			data->counters.access_accepts++;
+			client->counters.access_accepts++;
+			break;
+		case RADIUS_CODE_ACCESS_REJECT:
+			data->counters.access_rejects++;
+			client->counters.access_rejects++;
+			break;
+		case RADIUS_CODE_ACCESS_CHALLENGE:
+			data->counters.access_challenges++;
+			client->counters.access_challenges++;
+			break;
+		}
 		res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
 			     (struct sockaddr *) from, fromlen);
 		if (res < 0) {
 			perror("sendto[RADIUS SRV]");
 		}
-		radius_msg_free(reply);
-		free(reply);
+		if (sess->last_reply) {
+			radius_msg_free(sess->last_reply);
+			free(sess->last_reply);
+		}
+		sess->last_reply = reply;
+		sess->last_from_port = from_port;
+		sess->last_identifier = msg->hdr->identifier;
+		os_memcpy(sess->last_authenticator, msg->hdr->authenticator,
+			  16);
+	} else {
+		data->counters.packets_dropped++;
+		client->counters.packets_dropped++;
 	}
 
 	if (sess->eapSuccess || sess->eapFail) {
-		RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
-		radius_server_session_remove(data, sess);
+		RADIUS_DEBUG("Removing completed session 0x%x after timeout",
+			     sess->sess_id);
+		eloop_cancel_timeout(radius_server_session_remove_timeout,
+				     data, sess);
+		eloop_register_timeout(10, 0,
+				       radius_server_session_remove_timeout,
+				       data, sess);
 	}
 
 	return 0;
@@ -576,12 +690,15 @@
 
 	if (client == NULL) {
 		RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
+		data->counters.invalid_requests++;
 		goto fail;
 	}
 
 	msg = radius_msg_parse(buf, len);
 	if (msg == NULL) {
 		RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
+		data->counters.malformed_access_requests++;
+		client->counters.malformed_access_requests++;
 		goto fail;
 	}
 
@@ -594,17 +711,26 @@
 
 	if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
 		RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
+		data->counters.unknown_types++;
+		client->counters.unknown_types++;
 		goto fail;
 	}
 
+	data->counters.access_requests++;
+	client->counters.access_requests++;
+
 	if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
 				       client->shared_secret_len, NULL)) {
 		RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
+		data->counters.bad_authenticators++;
+		client->counters.bad_authenticators++;
 		goto fail;
 	}
 
-	radius_server_request(data, msg, (struct sockaddr *) &from, fromlen,
-			      client, abuf, from_port);
+	if (radius_server_request(data, msg, (struct sockaddr *) &from,
+				  fromlen, client, abuf, from_port, NULL) ==
+	    -2)
+		return; /* msg was stored with the session */
 
 fail:
 	if (msg) {
@@ -796,12 +922,11 @@
 			break;
 		}
 
-		entry = malloc(sizeof(*entry));
+		entry = wpa_zalloc(sizeof(*entry));
 		if (entry == NULL) {
 			failed = 1;
 			break;
 		}
-		memset(entry, 0, sizeof(*entry));
 		entry->shared_secret = strdup(pos);
 		if (entry->shared_secret == NULL) {
 			failed = 1;
@@ -864,11 +989,11 @@
 	}
 #endif /* CONFIG_IPV6 */
 
-	data = malloc(sizeof(*data));
-	if (data == NULL) {
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
 		return NULL;
-	}
-	memset(data, 0, sizeof(*data));
+
+	os_get_time(&data->start_time);
 	data->hostapd_conf = conf->hostapd_conf;
 	data->eap_sim_db_priv = conf->eap_sim_db_priv;
 	data->ssl_ctx = conf->ssl_ctx;
@@ -924,8 +1049,113 @@
 int radius_server_get_mib(struct radius_server_data *data, char *buf,
 			  size_t buflen)
 {
-	/* TODO: add support for RADIUS authentication server MIB */
-	return 0;
+	int ret, uptime;
+	unsigned int idx;
+	char *end, *pos;
+	struct os_time now;
+	struct radius_client *cli;
+
+	/* RFC 2619 - RADIUS Authentication Server MIB */
+
+	if (data == NULL || buflen == 0)
+		return 0;
+
+	pos = buf;
+	end = buf + buflen;
+
+	os_get_time(&now);
+	uptime = (now.sec - data->start_time.sec) * 100 +
+		((now.usec - data->start_time.usec) / 10000) % 100;
+	ret = snprintf(pos, end - pos,
+		       "RADIUS-AUTH-SERVER-MIB\n"
+		       "radiusAuthServIdent=hostapd\n"
+		       "radiusAuthServUpTime=%d\n"
+		       "radiusAuthServResetTime=0\n"
+		       "radiusAuthServConfigReset=4\n",
+		       uptime);
+	if (ret < 0 || ret >= end - pos) {
+		*pos = '\0';
+		return pos - buf;
+	}
+	pos += ret;
+
+	ret = snprintf(pos, end - pos,
+		       "radiusAuthServTotalAccessRequests=%u\n"
+		       "radiusAuthServTotalInvalidRequests=%u\n"
+		       "radiusAuthServTotalDupAccessRequests=%u\n"
+		       "radiusAuthServTotalAccessAccepts=%u\n"
+		       "radiusAuthServTotalAccessRejects=%u\n"
+		       "radiusAuthServTotalAccessChallenges=%u\n"
+		       "radiusAuthServTotalMalformedAccessRequests=%u\n"
+		       "radiusAuthServTotalBadAuthenticators=%u\n"
+		       "radiusAuthServTotalPacketsDropped=%u\n"
+		       "radiusAuthServTotalUnknownTypes=%u\n",
+		       data->counters.access_requests,
+		       data->counters.invalid_requests,
+		       data->counters.dup_access_requests,
+		       data->counters.access_accepts,
+		       data->counters.access_rejects,
+		       data->counters.access_challenges,
+		       data->counters.malformed_access_requests,
+		       data->counters.bad_authenticators,
+		       data->counters.packets_dropped,
+		       data->counters.unknown_types);
+	if (ret < 0 || ret >= end - pos) {
+		*pos = '\0';
+		return pos - buf;
+	}
+	pos += ret;
+
+	for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
+		char abuf[50], mbuf[50];
+#ifdef CONFIG_IPV6
+		if (data->ipv6) {
+			if (inet_ntop(AF_INET6, &cli->addr6, abuf,
+				      sizeof(abuf)) == NULL)
+				abuf[0] = '\0';
+			if (inet_ntop(AF_INET6, &cli->mask6, abuf,
+				      sizeof(mbuf)) == NULL)
+				mbuf[0] = '\0';
+		}
+#endif /* CONFIG_IPV6 */
+		if (!data->ipv6) {
+			snprintf(abuf, sizeof(abuf), "%s",
+				 inet_ntoa(cli->addr));
+			snprintf(mbuf, sizeof(mbuf), "%s",
+				 inet_ntoa(cli->mask));
+		}
+
+		ret = snprintf(pos, end - pos,
+			       "radiusAuthClientIndex=%u\n"
+			       "radiusAuthClientAddress=%s/%s\n"
+			       "radiusAuthServAccessRequests=%u\n"
+			       "radiusAuthServDupAccessRequests=%u\n"
+			       "radiusAuthServAccessAccepts=%u\n"
+			       "radiusAuthServAccessRejects=%u\n"
+			       "radiusAuthServAccessChallenges=%u\n"
+			       "radiusAuthServMalformedAccessRequests=%u\n"
+			       "radiusAuthServBadAuthenticators=%u\n"
+			       "radiusAuthServPacketsDropped=%u\n"
+			       "radiusAuthServUnknownTypes=%u\n",
+			       idx,
+			       abuf, mbuf,
+			       cli->counters.access_requests,
+			       cli->counters.dup_access_requests,
+			       cli->counters.access_accepts,
+			       cli->counters.access_rejects,
+			       cli->counters.access_challenges,
+			       cli->counters.malformed_access_requests,
+			       cli->counters.bad_authenticators,
+			       cli->counters.packets_dropped,
+			       cli->counters.unknown_types);
+		if (ret < 0 || ret >= end - pos) {
+			*pos = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+
+	return pos - buf;
 }
 
 
@@ -1039,6 +1269,7 @@
 {
 	struct radius_session *sess = ctx;
 	const struct hostapd_eap_user *eap_user;
+	int i, count;
 
 	eap_user = hostapd_get_eap_user(sess->server->hostapd_conf, identity,
 					identity_len, phase2);
@@ -1046,9 +1277,13 @@
 		return -1;
 
 	memset(user, 0, sizeof(*user));
-	memcpy(user->methods, eap_user->methods,
-	       EAP_USER_MAX_METHODS > EAP_MAX_METHODS ?
-	       EAP_USER_MAX_METHODS : EAP_MAX_METHODS);
+	count = EAP_USER_MAX_METHODS;
+	if (count > EAP_MAX_METHODS)
+		count = EAP_MAX_METHODS;
+	for (i = 0; i < count; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
 
 	if (eap_user->password) {
 		user->password = malloc(eap_user->password_len);
@@ -1057,6 +1292,7 @@
 		memcpy(user->password, eap_user->password,
 		       eap_user->password_len);
 		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
 	}
 	user->force_version = eap_user->force_version;
 
@@ -1072,3 +1308,45 @@
 	.set_eapKeyData = radius_server_set_eapKeyData,
 	.get_eap_user = radius_server_get_eap_user,
 };
+
+
+void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
+{
+	struct radius_client *cli;
+	struct radius_session *s, *sess = NULL;
+	struct radius_msg *msg;
+
+	if (data == NULL)
+		return;
+
+	for (cli = data->clients; cli; cli = cli->next) {
+		for (s = cli->sessions; s; s = s->next) {
+			if (s->eap == ctx && s->last_msg) {
+				sess = s;
+				break;
+			}
+			if (sess)
+				break;
+		}
+		if (sess)
+			break;
+	}
+
+	if (sess == NULL) {
+		RADIUS_DEBUG("No session matched callback ctx");
+		return;
+	}
+
+	msg = sess->last_msg;
+	sess->last_msg = NULL;
+	eap_sm_pending_cb(sess->eap);
+	if (radius_server_request(data, msg,
+				  (struct sockaddr *) &sess->last_from,
+				  sess->last_fromlen, cli,
+				  sess->last_from_addr,
+				  sess->last_from_port, sess) == -2)
+		return; /* msg was stored with the session */
+
+	radius_msg_free(msg);
+	free(msg);
+}
Index: radius.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius.h -L contrib/hostapd/radius.h -u -r1.2 -r1.3
--- contrib/hostapd/radius.h
+++ contrib/hostapd/radius.h
@@ -1,15 +1,33 @@
+/*
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2005, 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 RADIUS_H
 #define RADIUS_H
 
 /* RFC 2865 - RADIUS */
 
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
 struct radius_hdr {
 	u8 code;
 	u8 identifier;
 	u16 length; /* including this header */
 	u8 authenticator[16];
 	/* followed by length-20 octets of attributes */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 enum { RADIUS_CODE_ACCESS_REQUEST = 1,
        RADIUS_CODE_ACCESS_ACCEPT = 2,
@@ -26,7 +44,7 @@
 	u8 type;
 	u8 length; /* including this header */
 	/* followed by length-2 octets of attribute value */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 #define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
 
@@ -60,9 +78,12 @@
        RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
        RADIUS_ATTR_EVENT_TIMESTAMP = 55,
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
+       RADIUS_ATTR_TUNNEL_TYPE = 64,
+       RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
        RADIUS_ATTR_CONNECT_INFO = 77,
        RADIUS_ATTR_EAP_MESSAGE = 79,
        RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
+       RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
        RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
        RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
 };
@@ -107,11 +128,25 @@
 #define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
 #define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
 
+#define RADIUS_TUNNEL_TAGS 32
+
+/* Tunnel-Type */
+#define RADIUS_TUNNEL_TYPE_PPTP 1
+#define RADIUS_TUNNEL_TYPE_L2TP 3
+#define RADIUS_TUNNEL_TYPE_IPIP 7
+#define RADIUS_TUNNEL_TYPE_GRE 10
+#define RADIUS_TUNNEL_TYPE_VLAN 13
+
+/* Tunnel-Medium-Type */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2
+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6
+
 
 struct radius_attr_vendor {
 	u8 vendor_type;
 	u8 vendor_length;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 #define RADIUS_VENDOR_ID_CISCO 9
 #define RADIUS_CISCO_AV_PAIR 1
@@ -123,6 +158,10 @@
        RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
 };
 
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
 struct radius_ms_mppe_keys {
 	u8 *send;
 	size_t send_len;
@@ -182,7 +221,7 @@
 int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
 			 u8 type);
 void radius_msg_make_authenticator(struct radius_msg *msg,
-				   u8 *data, size_t len);
+				   const u8 *data, size_t len);
 struct radius_ms_mppe_keys *
 radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
 		       u8 *secret, size_t secret_len);
@@ -199,6 +238,7 @@
 				  u8 *data, size_t data_len,
 				  u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+int radius_msg_get_vlanid(struct radius_msg *msg);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
 					    u32 value)
--- /dev/null
+++ contrib/hostapd/hw_features.h
@@ -0,0 +1,61 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 HW_FEATURES_H
+#define HW_FEATURES_H
+
+#define HOSTAPD_CHAN_W_SCAN 0x00000001
+#define HOSTAPD_CHAN_W_ACTIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_W_IBSS 0x00000004
+
+struct hostapd_channel_data {
+	short chan; /* channel number (IEEE 802.11) */
+	short freq; /* frequency in MHz */
+	int flag; /* flag for hostapd use (HOSTAPD_CHAN_*) */
+};
+
+#define HOSTAPD_RATE_ERP 0x00000001
+#define HOSTAPD_RATE_BASIC 0x00000002
+#define HOSTAPD_RATE_PREAMBLE2 0x00000004
+#define HOSTAPD_RATE_SUPPORTED 0x00000010
+#define HOSTAPD_RATE_OFDM 0x00000020
+#define HOSTAPD_RATE_CCK 0x00000040
+#define HOSTAPD_RATE_MANDATORY 0x00000100
+
+struct hostapd_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* HOSTAPD_RATE_ flags */
+};
+
+struct hostapd_hw_modes {
+	int mode;
+	int num_channels;
+	struct hostapd_channel_data *channels;
+	int num_rates;
+	struct hostapd_rate_data *rates;
+};
+
+
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features);
+int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
+				 hostapd_iface_cb cb);
+int hostapd_select_hw_mode_stop(struct hostapd_iface *iface);
+const char * hostapd_hw_mode_txt(int mode);
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+
+#endif /* HW_FEATURES_H */
Index: ctrl_iface.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ctrl_iface.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ctrl_iface.c -L contrib/hostapd/ctrl_iface.c -u -r1.2 -r1.3
--- contrib/hostapd/ctrl_iface.c
+++ contrib/hostapd/ctrl_iface.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / UNIX domain socket -based control interface
- * Copyright (c) 2004, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, 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
@@ -13,17 +12,12 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
 #include <sys/un.h>
-#include <sys/uio.h>
 #include <sys/stat.h>
-#include <errno.h>
-#include <netinet/in.h>
 
 #include "hostapd.h"
 #include "eloop.h"
@@ -35,6 +29,7 @@
 #include "ieee802_11.h"
 #include "ctrl_iface.h"
 #include "sta_info.h"
+#include "accounting.h"
 
 
 struct wpa_ctrl_dst {
@@ -52,10 +47,9 @@
 {
 	struct wpa_ctrl_dst *dst;
 
-	dst = malloc(sizeof(*dst));
+	dst = wpa_zalloc(sizeof(*dst));
 	if (dst == NULL)
 		return -1;
-	memset(dst, 0, sizeof(*dst));
 	memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
 	dst->addrlen = fromlen;
 	dst->debug_level = MSG_INFO;
@@ -122,20 +116,26 @@
 				      struct sta_info *sta,
 				      char *buf, size_t buflen)
 {
-	int len, res;
+	int len, res, ret;
 
 	if (sta == NULL) {
-		return snprintf(buf, buflen, "FAIL\n");
+		ret = snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
 	}
 
 	len = 0;
-	len += snprintf(buf + len, buflen - len, MACSTR "\n",
-			MAC2STR(sta->addr));
+	ret = snprintf(buf + len, buflen - len, MACSTR "\n",
+		       MAC2STR(sta->addr));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
 	if (res >= 0)
 		len += res;
-	res = wpa_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
 	if (res >= 0)
 		len += res;
 	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
@@ -158,9 +158,14 @@
 				  char *buf, size_t buflen)
 {
 	u8 addr[ETH_ALEN];
+	int ret;
 
-	if (hwaddr_aton(txtaddr, addr))
-		return snprintf(buf, buflen, "FAIL\n");
+	if (hwaddr_aton(txtaddr, addr)) {
+		ret = snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}
 	return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
 					  buf, buflen);
 }
@@ -172,14 +177,46 @@
 {
 	u8 addr[ETH_ALEN];
 	struct sta_info *sta;
+	int ret;
 
 	if (hwaddr_aton(txtaddr, addr) ||
-	    (sta = ap_get_sta(hapd, addr)) == NULL)
-		return snprintf(buf, buflen, "FAIL\n");
+	    (sta = ap_get_sta(hapd, addr)) == NULL) {
+		ret = snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}		
 	return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
 }
 
 
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+				      const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+		   "notification", MAC2STR(addr));
+	sta = ap_sta_add(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	hostapd_new_assoc_sta(hapd, sta, 0);
+	accounting_sta_get_id(hapd, sta);
+	return 0;
+}
+
+
 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
 				       void *sock_ctx)
 {
@@ -217,7 +254,7 @@
 	} else if (strcmp(buf, "MIB") == 0) {
 		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
 		if (reply_len >= 0) {
-			res = wpa_get_mib(hapd, reply + reply_len,
+			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
 					  reply_size - reply_len);
 			if (res < 0)
 				reply_len = -1;
@@ -260,6 +297,9 @@
 		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
 						    buf + 6))
 			reply_len = -1;
+	} else if (strncmp(buf, "NEW_STA ", 8) == 0) {
+		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+			reply_len = -1;
 	} else {
 		memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -290,6 +330,7 @@
 
 	snprintf(buf, len, "%s/%s",
 		 hapd->conf->ctrl_interface, hapd->conf->iface);
+	buf[len - 1] = '\0';
 	return buf;
 }
 
@@ -454,3 +495,5 @@
 		dst = next;
 	}
 }
+
+#endif /* CONFIG_NATIVE_WINDOWS */
Index: eapol_sm.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eapol_sm.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eapol_sm.c -L contrib/hostapd/eapol_sm.c -u -r1.2 -r1.3
--- contrib/hostapd/eapol_sm.c
+++ contrib/hostapd/eapol_sm.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / IEEE 802.1X Authenticator - EAPOL state machine
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / IEEE 802.1X Authenticator - EAPOL state machine
+ * Copyright (c) 2002-2005, 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,23 +11,24 @@
  *
  * See README and COPYING for more details.
  *
- * $FreeBSD: src/contrib/hostapd/eapol_sm.c,v 1.3.2.1 2006/03/24 01:42:33 sam Exp $
+ * $FreeBSD: src/contrib/hostapd/eapol_sm.c,v 1.5 2007/07/09 16:20:41 sam Exp $
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/socket.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "ieee802_1x.h"
 #include "eapol_sm.h"
 #include "eloop.h"
 #include "wpa.h"
+#include "preauth.h"
 #include "sta_info.h"
 #include "eap.h"
+#include "state_machine.h"
+
+#define STATE_MACHINE_DATA struct eapol_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
+#define STATE_MACHINE_ADDR sm->addr
 
 static struct eapol_callbacks eapol_cb;
 
@@ -49,25 +49,6 @@
 #define processKey() do { } while (0)
 
 
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_state_machine \
-*sm)
-
-#define SM_ENTRY(machine, _state, _data) \
-sm->_data.state = machine ## _ ## _state; \
-if (sm->hapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \
-	printf("IEEE 802.1X: " MACSTR " " #machine " entering state " #_state \
-		"\n", MAC2STR(sm->addr));
-
-#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-
 static void eapol_sm_step_run(struct eapol_state_machine *sm);
 static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
 
@@ -117,8 +98,8 @@
 
 SM_STATE(AUTH_PAE, INITIALIZE)
 {
-	SM_ENTRY(AUTH_PAE, INITIALIZE, auth_pae);
-	sm->auth_pae.portMode = Auto;
+	SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
+	sm->portMode = Auto;
 
 	sm->currentId = 255;
 }
@@ -126,21 +107,21 @@
 
 SM_STATE(AUTH_PAE, DISCONNECTED)
 {
-	int from_initialize = sm->auth_pae.state == AUTH_PAE_INITIALIZE;
+	int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
 
-	if (sm->auth_pae.eapolLogoff) {
-		if (sm->auth_pae.state == AUTH_PAE_CONNECTING)
-			sm->auth_pae.authEapLogoffsWhileConnecting++;
-		else if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED)
-			sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
+	if (sm->eapolLogoff) {
+		if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
+			sm->authEapLogoffsWhileConnecting++;
+		else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
+			sm->authAuthEapLogoffWhileAuthenticated++;
 	}
 
-	SM_ENTRY(AUTH_PAE, DISCONNECTED, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
 
 	sm->authPortStatus = Unauthorized;
 	setPortUnauthorized();
-	sm->auth_pae.reAuthCount = 0;
-	sm->auth_pae.eapolLogoff = FALSE;
+	sm->reAuthCount = 0;
+	sm->eapolLogoff = FALSE;
 	if (!from_initialize) {
 		if (sm->flags & EAPOL_SM_PREAUTH)
 			rsn_preauth_finished(sm->hapd, sm->sta, 0);
@@ -152,48 +133,58 @@
 
 SM_STATE(AUTH_PAE, RESTART)
 {
-	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED) {
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
 		if (sm->reAuthenticate)
-			sm->auth_pae.authAuthReauthsWhileAuthenticated++;
-		if (sm->auth_pae.eapolStart)
-			sm->auth_pae.authAuthEapStartsWhileAuthenticated++;
-		if (sm->auth_pae.eapolLogoff)
-			sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
+			sm->authAuthReauthsWhileAuthenticated++;
+		if (sm->eapolStart)
+			sm->authAuthEapStartsWhileAuthenticated++;
+		if (sm->eapolLogoff)
+			sm->authAuthEapLogoffWhileAuthenticated++;
 	}
 
-	SM_ENTRY(AUTH_PAE, RESTART, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
 
-	sm->auth_pae.eapRestart = TRUE;
+	sm->eapRestart = TRUE;
 	ieee802_1x_request_identity(sm->hapd, sm->sta);
 }
 
 
 SM_STATE(AUTH_PAE, CONNECTING)
 {
-	if (sm->auth_pae.state != AUTH_PAE_CONNECTING)
-		sm->auth_pae.authEntersConnecting++;
+	if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
+		sm->authEntersConnecting++;
 
-	SM_ENTRY(AUTH_PAE, CONNECTING, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
 
 	sm->reAuthenticate = FALSE;
-	sm->auth_pae.reAuthCount++;
+	sm->reAuthCount++;
 }
 
 
 SM_STATE(AUTH_PAE, HELD)
 {
-	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authFail)
-		sm->auth_pae.authAuthFailWhileAuthenticating++;
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
+		sm->authAuthFailWhileAuthenticating++;
 
-	SM_ENTRY(AUTH_PAE, HELD, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
 
 	sm->authPortStatus = Unauthorized;
 	setPortUnauthorized();
-	sm->quietWhile = sm->auth_pae.quietPeriod;
-	sm->auth_pae.eapolLogoff = FALSE;
+	sm->quietWhile = sm->quietPeriod;
+	sm->eapolLogoff = FALSE;
 
 	hostapd_logger(sm->hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_WARNING, "authentication failed");
+		       HOSTAPD_LEVEL_WARNING, "authentication failed - "
+		       "EAP type: %d (%s)",
+		       sm->eap_type_authsrv,
+		       eap_type_text(sm->eap_type_authsrv));
+	if (sm->eap_type_authsrv != sm->eap_type_supp) {
+		hostapd_logger(sm->hapd, sm->addr,
+			       HOSTAPD_MODULE_IEEE8021X, HOSTAPD_LEVEL_INFO,
+			       "Supplicant used different EAP type: %d (%s)",
+			       sm->eap_type_supp,
+			       eap_type_text(sm->eap_type_supp));
+	}
 	if (sm->flags & EAPOL_SM_PREAUTH)
 		rsn_preauth_finished(sm->hapd, sm->sta, 0);
 	else
@@ -203,16 +194,24 @@
 
 SM_STATE(AUTH_PAE, AUTHENTICATED)
 {
-	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
-		sm->auth_pae.authAuthSuccessesWhileAuthenticating++;
+	char *extra = "";
+
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
+		sm->authAuthSuccessesWhileAuthenticating++;
 							
-	SM_ENTRY(AUTH_PAE, AUTHENTICATED, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
 
 	sm->authPortStatus = Authorized;
 	setPortAuthorized();
-	sm->auth_pae.reAuthCount = 0;
+	sm->reAuthCount = 0;
+	if (sm->flags & EAPOL_SM_PREAUTH)
+		extra = " (pre-authentication)";
+	else if (wpa_auth_sta_get_pmksa(sm->sta->wpa_sm))
+		extra = " (PMKSA cache)";
 	hostapd_logger(sm->hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
-		       HOSTAPD_LEVEL_INFO, "authenticated");
+		       HOSTAPD_LEVEL_INFO, "authenticated - EAP type: %d (%s)"
+		       "%s", sm->eap_type_authsrv,
+		       eap_type_text(sm->eap_type_authsrv), extra);
 	if (sm->flags & EAPOL_SM_PREAUTH)
 		rsn_preauth_finished(sm->hapd, sm->sta, 1);
 	else
@@ -222,14 +221,14 @@
 
 SM_STATE(AUTH_PAE, AUTHENTICATING)
 {
-	if (sm->auth_pae.state == AUTH_PAE_CONNECTING && sm->rx_identity) {
-		sm->auth_pae.authEntersAuthenticating++;
+	if (sm->auth_pae_state == AUTH_PAE_CONNECTING && sm->rx_identity) {
+		sm->authEntersAuthenticating++;
 		sm->rx_identity = FALSE;
 	}
 
-	SM_ENTRY(AUTH_PAE, AUTHENTICATING, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
 
-	sm->auth_pae.eapolStart = FALSE;
+	sm->eapolStart = FALSE;
 	sm->authSuccess = FALSE;
 	sm->authFail = FALSE;
 	sm->authTimeout = FALSE;
@@ -241,16 +240,16 @@
 
 SM_STATE(AUTH_PAE, ABORTING)
 {
-	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING) {
+	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
 		if (sm->authTimeout)
-			sm->auth_pae.authAuthTimeoutsWhileAuthenticating++;
-		if (sm->auth_pae.eapolStart)
-			sm->auth_pae.authAuthEapStartsWhileAuthenticating++;
-		if (sm->auth_pae.eapolLogoff)
-			sm->auth_pae.authAuthEapLogoffWhileAuthenticating++;
+			sm->authAuthTimeoutsWhileAuthenticating++;
+		if (sm->eapolStart)
+			sm->authAuthEapStartsWhileAuthenticating++;
+		if (sm->eapolLogoff)
+			sm->authAuthEapLogoffWhileAuthenticating++;
 	}
 
-	SM_ENTRY(AUTH_PAE, ABORTING, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
 
 	sm->authAbort = TRUE;
 	sm->keyRun = FALSE;
@@ -260,44 +259,43 @@
 
 SM_STATE(AUTH_PAE, FORCE_AUTH)
 {
-	SM_ENTRY(AUTH_PAE, FORCE_AUTH, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
 
 	sm->authPortStatus = Authorized;
 	setPortAuthorized();
-	sm->auth_pae.portMode = ForceAuthorized;
-	sm->auth_pae.eapolStart = FALSE;
+	sm->portMode = ForceAuthorized;
+	sm->eapolStart = FALSE;
 	txCannedSuccess();
 }
 
 
 SM_STATE(AUTH_PAE, FORCE_UNAUTH)
 {
-	SM_ENTRY(AUTH_PAE, FORCE_UNAUTH, auth_pae);
+	SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
 
 	sm->authPortStatus = Unauthorized;
 	setPortUnauthorized();
-	sm->auth_pae.portMode = ForceUnauthorized;
-	sm->auth_pae.eapolStart = FALSE;
+	sm->portMode = ForceUnauthorized;
+	sm->eapolStart = FALSE;
 	txCannedFail();
 }
 
 
 SM_STEP(AUTH_PAE)
 {
-	if ((sm->portControl == Auto &&
-	     sm->auth_pae.portMode != sm->portControl) ||
+	if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
 	    sm->initialize || !sm->portEnabled)
 		SM_ENTER(AUTH_PAE, INITIALIZE);
 	else if (sm->portControl == ForceAuthorized &&
-		 sm->auth_pae.portMode != sm->portControl &&
+		 sm->portMode != sm->portControl &&
 		 !(sm->initialize || !sm->portEnabled))
 		SM_ENTER(AUTH_PAE, FORCE_AUTH);
 	else if (sm->portControl == ForceUnauthorized &&
-		 sm->auth_pae.portMode != sm->portControl &&
+		 sm->portMode != sm->portControl &&
 		 !(sm->initialize || !sm->portEnabled))
 		SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
 	else {
-		switch (sm->auth_pae.state) {
+		switch (sm->auth_pae_state) {
 		case AUTH_PAE_INITIALIZE:
 			SM_ENTER(AUTH_PAE, DISCONNECTED);
 			break;
@@ -305,7 +303,7 @@
 			SM_ENTER(AUTH_PAE, RESTART);
 			break;
 		case AUTH_PAE_RESTART:
-			if (!sm->auth_pae.eapRestart)
+			if (!sm->eapRestart)
 				SM_ENTER(AUTH_PAE, CONNECTING);
 			break;
 		case AUTH_PAE_HELD:
@@ -313,19 +311,17 @@
 				SM_ENTER(AUTH_PAE, RESTART);
 			break;
 		case AUTH_PAE_CONNECTING:
-			if (sm->auth_pae.eapolLogoff ||
-			    sm->auth_pae.reAuthCount > sm->auth_pae.reAuthMax)
+			if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
 				SM_ENTER(AUTH_PAE, DISCONNECTED);
-			else if ((sm->be_auth.eapReq &&
-				  sm->auth_pae.reAuthCount <=
-				  sm->auth_pae.reAuthMax) ||
+			else if ((sm->eapReq &&
+				  sm->reAuthCount <= sm->reAuthMax) ||
 				 sm->eapSuccess || sm->eapFail)
 				SM_ENTER(AUTH_PAE, AUTHENTICATING);
 			break;
 		case AUTH_PAE_AUTHENTICATED:
-			if (sm->auth_pae.eapolStart || sm->reAuthenticate)
+			if (sm->eapolStart || sm->reAuthenticate)
 				SM_ENTER(AUTH_PAE, RESTART);
-			else if (sm->auth_pae.eapolLogoff || !sm->portValid)
+			else if (sm->eapolLogoff || !sm->portValid)
 				SM_ENTER(AUTH_PAE, DISCONNECTED);
 			break;
 		case AUTH_PAE_AUTHENTICATING:
@@ -334,22 +330,22 @@
 			else if (sm->authFail ||
 				 (sm->keyDone && !sm->portValid))
 				SM_ENTER(AUTH_PAE, HELD);
-			else if (sm->auth_pae.eapolStart ||
-				 sm->auth_pae.eapolLogoff || sm->authTimeout)
+			else if (sm->eapolStart || sm->eapolLogoff ||
+				 sm->authTimeout)
 				SM_ENTER(AUTH_PAE, ABORTING);
 			break;
 		case AUTH_PAE_ABORTING:
-			if (sm->auth_pae.eapolLogoff && !sm->authAbort)
+			if (sm->eapolLogoff && !sm->authAbort)
 				SM_ENTER(AUTH_PAE, DISCONNECTED);
-			else if (!sm->auth_pae.eapolLogoff && !sm->authAbort)
+			else if (!sm->eapolLogoff && !sm->authAbort)
 				SM_ENTER(AUTH_PAE, RESTART);
 			break;
 		case AUTH_PAE_FORCE_AUTH:
-			if (sm->auth_pae.eapolStart)
+			if (sm->eapolStart)
 				SM_ENTER(AUTH_PAE, FORCE_AUTH);
 			break;
 		case AUTH_PAE_FORCE_UNAUTH:
-			if (sm->auth_pae.eapolStart)
+			if (sm->eapolStart)
 				SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
 			break;
 		}
@@ -362,21 +358,21 @@
 
 SM_STATE(BE_AUTH, INITIALIZE)
 {
-	SM_ENTRY(BE_AUTH, INITIALIZE, be_auth);
+	SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
 
 	abortAuth();
-	sm->be_auth.eapNoReq = FALSE;
+	sm->eapNoReq = FALSE;
 	sm->authAbort = FALSE;
 }
 
 
 SM_STATE(BE_AUTH, REQUEST)
 {
-	SM_ENTRY(BE_AUTH, REQUEST, be_auth);
+	SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
 
 	txReq();
-	sm->be_auth.eapReq = FALSE;
-	sm->be_auth.backendOtherRequestsToSupplicant++;
+	sm->eapReq = FALSE;
+	sm->backendOtherRequestsToSupplicant++;
 
 	/*
 	 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
@@ -395,21 +391,21 @@
 
 SM_STATE(BE_AUTH, RESPONSE)
 {
-	SM_ENTRY(BE_AUTH, RESPONSE, be_auth);
+	SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
 
 	sm->authTimeout = FALSE;
 	sm->eapolEap = FALSE;
-	sm->be_auth.eapNoReq = FALSE;
-	sm->aWhile = sm->be_auth.serverTimeout;
-	sm->be_auth.eapResp = TRUE;
+	sm->eapNoReq = FALSE;
+	sm->aWhile = sm->serverTimeout;
+	sm->eapResp = TRUE;
 	sendRespToServer();
-	sm->be_auth.backendResponses++;
+	sm->backendResponses++;
 }
 
 
 SM_STATE(BE_AUTH, SUCCESS)
 {
-	SM_ENTRY(BE_AUTH, SUCCESS, be_auth);
+	SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
 
 	txReq();
 	sm->authSuccess = TRUE;
@@ -419,7 +415,7 @@
 
 SM_STATE(BE_AUTH, FAIL)
 {
-	SM_ENTRY(BE_AUTH, FAIL, be_auth);
+	SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
 
 	/* Note: IEEE 802.1X-REV-d11 has unconditional txReq() here.
 	 * txCannelFail() is used as a workaround for the case where
@@ -435,7 +431,7 @@
 
 SM_STATE(BE_AUTH, TIMEOUT)
 {
-	SM_ENTRY(BE_AUTH, TIMEOUT, be_auth);
+	SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
 
 	sm->authTimeout = TRUE;
 }
@@ -443,7 +439,7 @@
 
 SM_STATE(BE_AUTH, IDLE)
 {
-	SM_ENTRY(BE_AUTH, IDLE, be_auth);
+	SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
 
 	sm->authStart = FALSE;
 }
@@ -451,9 +447,9 @@
 
 SM_STATE(BE_AUTH, IGNORE)
 {
-	SM_ENTRY(BE_AUTH, IGNORE, be_auth);
+	SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
 
-	sm->be_auth.eapNoReq = FALSE;
+	sm->eapNoReq = FALSE;
 }
 
 
@@ -464,31 +460,31 @@
 		return;
 	}
 
-	switch (sm->be_auth.state) {
+	switch (sm->be_auth_state) {
 	case BE_AUTH_INITIALIZE:
 		SM_ENTER(BE_AUTH, IDLE);
 		break;
 	case BE_AUTH_REQUEST:
 		if (sm->eapolEap)
 			SM_ENTER(BE_AUTH, RESPONSE);
-		else if (sm->be_auth.eapReq)
+		else if (sm->eapReq)
 			SM_ENTER(BE_AUTH, REQUEST);
 		else if (sm->eapTimeout)
 			SM_ENTER(BE_AUTH, TIMEOUT);
 		break;
 	case BE_AUTH_RESPONSE:
-		if (sm->be_auth.eapNoReq)
+		if (sm->eapNoReq)
 			SM_ENTER(BE_AUTH, IGNORE);
-		if (sm->be_auth.eapReq) {
-			sm->be_auth.backendAccessChallenges++;
+		if (sm->eapReq) {
+			sm->backendAccessChallenges++;
 			SM_ENTER(BE_AUTH, REQUEST);
 		} else if (sm->aWhile == 0)
 			SM_ENTER(BE_AUTH, TIMEOUT);
 		else if (sm->eapFail) {
-			sm->be_auth.backendAuthFails++;
+			sm->backendAuthFails++;
 			SM_ENTER(BE_AUTH, FAIL);
 		} else if (sm->eapSuccess) {
-			sm->be_auth.backendAuthSuccesses++;
+			sm->backendAuthSuccesses++;
 			SM_ENTER(BE_AUTH, SUCCESS);
 		}
 		break;
@@ -504,7 +500,7 @@
 	case BE_AUTH_IDLE:
 		if (sm->eapFail && sm->authStart)
 			SM_ENTER(BE_AUTH, FAIL);
-		else if (sm->be_auth.eapReq && sm->authStart)
+		else if (sm->eapReq && sm->authStart)
 			SM_ENTER(BE_AUTH, REQUEST);
 		else if (sm->eapSuccess && sm->authStart)
 			SM_ENTER(BE_AUTH, SUCCESS);
@@ -512,7 +508,7 @@
 	case BE_AUTH_IGNORE:
 		if (sm->eapolEap)
 			SM_ENTER(BE_AUTH, RESPONSE);
-		else if (sm->be_auth.eapReq)
+		else if (sm->eapReq)
 			SM_ENTER(BE_AUTH, REQUEST);
 		else if (sm->eapTimeout)
 			SM_ENTER(BE_AUTH, TIMEOUT);
@@ -526,31 +522,30 @@
 
 SM_STATE(REAUTH_TIMER, INITIALIZE)
 {
-	SM_ENTRY(REAUTH_TIMER, INITIALIZE, reauth_timer);
+	SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
 
-	sm->reAuthWhen = sm->reauth_timer.reAuthPeriod;
+	sm->reAuthWhen = sm->reAuthPeriod;
 }
 
 
 SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
 {
-	SM_ENTRY(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
+	SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
 
 	sm->reAuthenticate = TRUE;
-	wpa_sm_event(sm->hapd, sm->sta, WPA_REAUTH_EAPOL);
+	wpa_auth_sm_event(sm->sta->wpa_sm, WPA_REAUTH_EAPOL);
 }
 
 
 SM_STEP(REAUTH_TIMER)
 {
 	if (sm->portControl != Auto || sm->initialize ||
-	    sm->authPortStatus == Unauthorized ||
-	    !sm->reauth_timer.reAuthEnabled) {
+	    sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
 		SM_ENTER(REAUTH_TIMER, INITIALIZE);
 		return;
 	}
 
-	switch (sm->reauth_timer.state) {
+	switch (sm->reauth_timer_state) {
 	case REAUTH_TIMER_INITIALIZE:
 		if (sm->reAuthWhen == 0)
 			SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
@@ -567,13 +562,13 @@
 
 SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
 {
-	SM_ENTRY(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
+	SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
 }
 
 
 SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
 {
-	SM_ENTRY(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
+	SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
 
 	txKey();
 	sm->keyAvailable = FALSE;
@@ -588,10 +583,10 @@
 		return;
 	}
 
-	switch (sm->auth_key_tx.state) {
+	switch (sm->auth_key_tx_state) {
 	case AUTH_KEY_TX_NO_KEY_TRANSMIT:
 		if (sm->keyTxEnabled && sm->keyAvailable && sm->keyRun &&
-		    !sm->sta->wpa)
+		    !wpa_auth_sta_wpa_version(sm->sta->wpa_sm))
 			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
 		break;
 	case AUTH_KEY_TX_KEY_TRANSMIT:
@@ -609,16 +604,16 @@
 
 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
 {
-	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE, key_rx);
+	SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
 }
 
 
 SM_STATE(KEY_RX, KEY_RECEIVE)
 {
-	SM_ENTRY(KEY_RX, KEY_RECEIVE, key_rx);
+	SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
 
 	processKey();
-	sm->key_rx.rxKey = FALSE;
+	sm->rxKey = FALSE;
 }
 
 
@@ -629,13 +624,13 @@
 		return;
 	}
 
-	switch (sm->key_rx.state) {
+	switch (sm->key_rx_state) {
 	case KEY_RX_NO_KEY_RECEIVE:
-		if (sm->key_rx.rxKey)
+		if (sm->rxKey)
 			SM_ENTER(KEY_RX, KEY_RECEIVE);
 		break;
 	case KEY_RX_KEY_RECEIVE:
-		if (sm->key_rx.rxKey)
+		if (sm->rxKey)
 			SM_ENTER(KEY_RX, KEY_RECEIVE);
 		break;
 	}
@@ -647,16 +642,15 @@
 
 SM_STATE(CTRL_DIR, FORCE_BOTH)
 {
-	SM_ENTRY(CTRL_DIR, FORCE_BOTH, ctrl_dir);
-	sm->ctrl_dir.operControlledDirections = Both;
+	SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
+	sm->operControlledDirections = Both;
 }
 
 
 SM_STATE(CTRL_DIR, IN_OR_BOTH)
 {
-	SM_ENTRY(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
-	sm->ctrl_dir.operControlledDirections =
-		sm->ctrl_dir.adminControlledDirections;
+	SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
+	sm->operControlledDirections = sm->adminControlledDirections;
 }
 
 
@@ -667,16 +661,16 @@
 		return;
 	}
 
-	switch (sm->ctrl_dir.state) {
+	switch (sm->ctrl_dir_state) {
 	case CTRL_DIR_FORCE_BOTH:
-		if (sm->portEnabled && sm->ctrl_dir.operEdge)
+		if (sm->portEnabled && sm->operEdge)
 			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
 		break;
 	case CTRL_DIR_IN_OR_BOTH:
-		if (sm->ctrl_dir.operControlledDirections !=
-		    sm->ctrl_dir.adminControlledDirections)
+		if (sm->operControlledDirections !=
+		    sm->adminControlledDirections)
 			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
-		if (!sm->portEnabled || !sm->ctrl_dir.operEdge)
+		if (!sm->portEnabled || !sm->operEdge)
 			SM_ENTER(CTRL_DIR, FORCE_BOTH);
 		break;
 	}
@@ -685,16 +679,15 @@
 
 
 struct eapol_state_machine *
-eapol_sm_alloc(hostapd *hapd, struct sta_info *sta)
+eapol_sm_alloc(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct eapol_state_machine *sm;
 
-	sm = (struct eapol_state_machine *) malloc(sizeof(*sm));
+	sm = wpa_zalloc(sizeof(*sm));
 	if (sm == NULL) {
 		printf("IEEE 802.1X port state allocation failed\n");
 		return NULL;
 	}
-	memset(sm, 0, sizeof(*sm));
 	sm->radius_identifier = -1;
 	memcpy(sm->addr, sta->addr, ETH_ALEN);
 	if (sta->flags & WLAN_STA_PREAUTH)
@@ -704,23 +697,22 @@
 	sm->sta = sta;
 
 	/* Set default values for state machine constants */
-	sm->auth_pae.state = AUTH_PAE_INITIALIZE;
-	sm->auth_pae.quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
-	sm->auth_pae.reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
+	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
+	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
+	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
 
-	sm->be_auth.state = BE_AUTH_INITIALIZE;
-	sm->be_auth.serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
+	sm->be_auth_state = BE_AUTH_INITIALIZE;
+	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
 
-	sm->reauth_timer.state = REAUTH_TIMER_INITIALIZE;
-	sm->reauth_timer.reAuthPeriod = hapd->conf->eap_reauth_period;
-	sm->reauth_timer.reAuthEnabled = hapd->conf->eap_reauth_period > 0 ?
-		TRUE : FALSE;
+	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
+	sm->reAuthPeriod = hapd->conf->eap_reauth_period;
+	sm->reAuthEnabled = hapd->conf->eap_reauth_period > 0 ? TRUE : FALSE;
 
-	sm->auth_key_tx.state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
+	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
 
-	sm->key_rx.state = KEY_RX_NO_KEY_RECEIVE;
+	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
 
-	sm->ctrl_dir.state = CTRL_DIR_IN_OR_BOTH;
+	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
 
 	sm->portEnabled = FALSE;
 	sm->portControl = Auto;
@@ -781,8 +773,8 @@
 {
 	struct hostapd_data *hapd = sm->hapd;
 	u8 addr[ETH_ALEN];
-	int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx,
-		prev_key_rx, prev_ctrl_dir;
+	unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
+		prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
 	int max_steps = 100;
 
 	memcpy(addr, sm->sta->addr, ETH_ALEN);
@@ -794,12 +786,12 @@
 	 * eloop callback.
 	 */
 restart:
-	prev_auth_pae = sm->auth_pae.state;
-	prev_be_auth = sm->be_auth.state;
-	prev_reauth_timer = sm->reauth_timer.state;
-	prev_auth_key_tx = sm->auth_key_tx.state;
-	prev_key_rx = sm->key_rx.state;
-	prev_ctrl_dir = sm->ctrl_dir.state;
+	prev_auth_pae = sm->auth_pae_state;
+	prev_be_auth = sm->be_auth_state;
+	prev_reauth_timer = sm->reauth_timer_state;
+	prev_auth_key_tx = sm->auth_key_tx_state;
+	prev_key_rx = sm->key_rx_state;
+	prev_ctrl_dir = sm->ctrl_dir_state;
 
 	SM_STEP_RUN(AUTH_PAE);
 	if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
@@ -813,12 +805,12 @@
 	if (sm->initializing || eapol_sm_sta_entry_alive(hapd, addr))
 		SM_STEP_RUN(CTRL_DIR);
 
-	if (prev_auth_pae != sm->auth_pae.state ||
-	    prev_be_auth != sm->be_auth.state ||
-	    prev_reauth_timer != sm->reauth_timer.state ||
-	    prev_auth_key_tx != sm->auth_key_tx.state ||
-	    prev_key_rx != sm->key_rx.state ||
-	    prev_ctrl_dir != sm->ctrl_dir.state) {
+	if (prev_auth_pae != sm->auth_pae_state ||
+	    prev_be_auth != sm->be_auth_state ||
+	    prev_reauth_timer != sm->reauth_timer_state ||
+	    prev_auth_key_tx != sm->auth_key_tx_state ||
+	    prev_key_rx != sm->key_rx_state ||
+	    prev_ctrl_dir != sm->ctrl_dir_state) {
 		if (--max_steps > 0)
 			goto restart;
 		/* Re-run from eloop timeout */
@@ -837,7 +829,7 @@
 	}
 
 	if (eapol_sm_sta_entry_alive(hapd, addr))
-		wpa_sm_notify(sm->hapd, sm->sta);
+		wpa_auth_sm_notify(sm->sta->wpa_sm);
 }
 
 
@@ -1024,22 +1016,21 @@
 		"%s    authAuthReauthsWhileAuthenticated=%d\n"
 		"%s    authAuthEapStartsWhileAuthenticated=%d\n"
 		"%s    authAuthEapLogoffWhileAuthenticated=%d\n",
-		prefix, prefix, auth_pae_state_txt(sm->auth_pae.state), prefix,
-		_SB(sm->auth_pae.eapolLogoff), _SB(sm->auth_pae.eapolStart),
-		_SB(sm->auth_pae.eapRestart), prefix,
-		port_type_txt(sm->auth_pae.portMode), sm->auth_pae.reAuthCount,
-		prefix, sm->auth_pae.quietPeriod, sm->auth_pae.reAuthMax,
-		prefix, sm->auth_pae.authEntersConnecting,
-		prefix, sm->auth_pae.authEapLogoffsWhileConnecting,
-		prefix, sm->auth_pae.authEntersAuthenticating,
-		prefix, sm->auth_pae.authAuthSuccessesWhileAuthenticating,
-		prefix, sm->auth_pae.authAuthTimeoutsWhileAuthenticating,
-		prefix, sm->auth_pae.authAuthFailWhileAuthenticating,
-		prefix, sm->auth_pae.authAuthEapStartsWhileAuthenticating,
-		prefix, sm->auth_pae.authAuthEapLogoffWhileAuthenticating,
-		prefix, sm->auth_pae.authAuthReauthsWhileAuthenticated,
-		prefix, sm->auth_pae.authAuthEapStartsWhileAuthenticated,
-		prefix, sm->auth_pae.authAuthEapLogoffWhileAuthenticated);
+		prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
+		_SB(sm->eapolLogoff), _SB(sm->eapolStart), _SB(sm->eapRestart),
+		prefix, port_type_txt(sm->portMode), sm->reAuthCount,
+		prefix, sm->quietPeriod, sm->reAuthMax,
+		prefix, sm->authEntersConnecting,
+		prefix, sm->authEapLogoffsWhileConnecting,
+		prefix, sm->authEntersAuthenticating,
+		prefix, sm->authAuthSuccessesWhileAuthenticating,
+		prefix, sm->authAuthTimeoutsWhileAuthenticating,
+		prefix, sm->authAuthFailWhileAuthenticating,
+		prefix, sm->authAuthEapStartsWhileAuthenticating,
+		prefix, sm->authAuthEapLogoffWhileAuthenticating,
+		prefix, sm->authAuthReauthsWhileAuthenticated,
+		prefix, sm->authAuthEapStartsWhileAuthenticated,
+		prefix, sm->authAuthEapLogoffWhileAuthenticated);
 
 	fprintf(f, "%s  Backend Authentication:\n"
 		"%s    state=%s\n"
@@ -1051,42 +1042,39 @@
 		"%s    backendAuthSuccesses=%d\n"
 		"%s    backendAuthFails=%d\n",
 		prefix, prefix,
-		be_auth_state_txt(sm->be_auth.state),
-		prefix, _SB(sm->be_auth.eapNoReq), _SB(sm->be_auth.eapReq),
-		_SB(sm->be_auth.eapResp),
-		prefix, sm->be_auth.serverTimeout,
-		prefix, sm->be_auth.backendResponses,
-		prefix, sm->be_auth.backendAccessChallenges,
-		prefix, sm->be_auth.backendOtherRequestsToSupplicant,
-		prefix, sm->be_auth.backendAuthSuccesses,
-		prefix, sm->be_auth.backendAuthFails);
+		be_auth_state_txt(sm->be_auth_state),
+		prefix, _SB(sm->eapNoReq), _SB(sm->eapReq), _SB(sm->eapResp),
+		prefix, sm->serverTimeout,
+		prefix, sm->backendResponses,
+		prefix, sm->backendAccessChallenges,
+		prefix, sm->backendOtherRequestsToSupplicant,
+		prefix, sm->backendAuthSuccesses,
+		prefix, sm->backendAuthFails);
 
 	fprintf(f, "%s  Reauthentication Timer:\n"
 		"%s    state=%s\n"
 		"%s    reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
-		reauth_timer_state_txt(sm->reauth_timer.state), prefix,
-		sm->reauth_timer.reAuthPeriod,
-		_SB(sm->reauth_timer.reAuthEnabled));
+		reauth_timer_state_txt(sm->reauth_timer_state), prefix,
+		sm->reAuthPeriod, _SB(sm->reAuthEnabled));
 
 	fprintf(f, "%s  Authenticator Key Transmit:\n"
 		"%s    state=%s\n", prefix, prefix,
-		auth_key_tx_state_txt(sm->auth_key_tx.state));
+		auth_key_tx_state_txt(sm->auth_key_tx_state));
 
 	fprintf(f, "%s  Key Receive:\n"
 		"%s    state=%s\n"
 		"%s    rxKey=%s\n", prefix, prefix,
-		key_rx_state_txt(sm->key_rx.state),
-		prefix, _SB(sm->key_rx.rxKey));
+		key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
 
 	fprintf(f, "%s  Controlled Directions:\n"
 		"%s    state=%s\n"
 		"%s    adminControlledDirections=%s "
 		"operControlledDirections=%s\n"
 		"%s    operEdge=%s\n", prefix, prefix,
-		ctrl_dir_state_txt(sm->ctrl_dir.state),
-		prefix, ctrl_dir_txt(sm->ctrl_dir.adminControlledDirections),
-		ctrl_dir_txt(sm->ctrl_dir.operControlledDirections),
-		prefix, _SB(sm->ctrl_dir.operEdge));
+		ctrl_dir_state_txt(sm->ctrl_dir_state),
+		prefix, ctrl_dir_txt(sm->adminControlledDirections),
+		ctrl_dir_txt(sm->operControlledDirections),
+		prefix, _SB(sm->operEdge));
 #undef _SB
 }
 #endif /* HOSTAPD_DUMP_STATE */
@@ -1101,15 +1089,15 @@
 	case EAPOL_eapSuccess:
 		return sm->eapSuccess;
 	case EAPOL_eapRestart:
-		return sm->auth_pae.eapRestart;
+		return sm->eapRestart;
 	case EAPOL_eapFail:
 		return sm->eapFail;
 	case EAPOL_eapResp:
-		return sm->be_auth.eapResp;
+		return sm->eapResp;
 	case EAPOL_eapReq:
-		return sm->be_auth.eapReq;
+		return sm->eapReq;
 	case EAPOL_eapNoReq:
-		return sm->be_auth.eapNoReq;
+		return sm->eapNoReq;
 	case EAPOL_portEnabled:
 		return sm->portEnabled;
 	case EAPOL_eapTimeout:
@@ -1130,19 +1118,19 @@
 		sm->eapSuccess = value;
 		break;
 	case EAPOL_eapRestart:
-		sm->auth_pae.eapRestart = value;
+		sm->eapRestart = value;
 		break;
 	case EAPOL_eapFail:
 		sm->eapFail = value;
 		break;
 	case EAPOL_eapResp:
-		sm->be_auth.eapResp = value;
+		sm->eapResp = value;
 		break;
 	case EAPOL_eapReq:
-		sm->be_auth.eapReq = value;
+		sm->eapReq = value;
 		break;
 	case EAPOL_eapNoReq:
-		sm->be_auth.eapNoReq = value;
+		sm->eapNoReq = value;
 		break;
 	case EAPOL_portEnabled:
 		sm->portEnabled = value;
@@ -1216,6 +1204,7 @@
 {
 	struct eapol_state_machine *sm = ctx;
 	const struct hostapd_eap_user *eap_user;
+	int i, count;
 
 	eap_user = hostapd_get_eap_user(sm->hapd->conf, identity,
 					identity_len, phase2);
@@ -1224,9 +1213,13 @@
 
 	memset(user, 0, sizeof(*user));
 	user->phase2 = phase2;
-	memcpy(user->methods, eap_user->methods,
-	       EAP_USER_MAX_METHODS > EAP_MAX_METHODS ?
-	       EAP_USER_MAX_METHODS : EAP_MAX_METHODS);
+	count = EAP_USER_MAX_METHODS;
+	if (count > EAP_MAX_METHODS)
+		count = EAP_MAX_METHODS;
+	for (i = 0; i < count; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
 
 	if (eap_user->password) {
 		user->password = malloc(eap_user->password_len);
@@ -1259,3 +1252,15 @@
 	.get_eap_user = eapol_sm_get_eap_user,
 	.get_eap_req_id_text = eapol_sm_get_eap_req_id_text,
 };
+
+
+int eapol_sm_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
+{
+	if (sm == NULL || ctx != sm->eap)
+		return -1;
+
+	eap_sm_pending_cb(sm->eap);
+	eapol_sm_step(sm);
+
+	return 0;
+}
Index: COPYING
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/COPYING,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/COPYING -L contrib/hostapd/COPYING -u -r1.1.1.1 -r1.2
--- contrib/hostapd/COPYING
+++ contrib/hostapd/COPYING
@@ -2,7 +2,7 @@
 		       Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -305,7 +305,7 @@
 
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
 
 Also add information on how to contact you by electronic and paper mail.
Index: crypto.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/crypto.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/crypto.h -L contrib/hostapd/crypto.h -u -r1.2 -r1.3
--- contrib/hostapd/crypto.h
+++ contrib/hostapd/crypto.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2005, 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,16 +56,28 @@
 		 u8 *mac);
 
 /**
- * sha1_transform - Perform one SHA-1 transform step
- * @state: SHA-1 state
- * @data: Input data for the SHA-1 transform
- *
- * This function is used to implement random number generation specified in
- * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
- * similar to SHA-1, but has different message padding and as such, access to
- * just part of the SHA-1 is needed.
+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
+ * @seed: Seed/key for the PRF
+ * @seed_len: Seed length in bytes
+ * @x: Buffer for PRF output
+ * @xlen: Output length in bytes
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function implements random number generation specified in NIST FIPS
+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
+ * SHA-1, but has different message padding.
+ */
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen);
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
  */
-void sha1_transform(u8 *state, const u8 data[64]);
+void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		   u8 *mac);
 
 /**
  * des_encrypt - Encrypt one block with DES
@@ -120,4 +132,282 @@
 void aes_decrypt_deinit(void *ctx);
 
 
+enum crypto_hash_alg {
+	CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
+	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+};
+
+struct crypto_hash;
+
+/**
+ * crypto_hash_init - Initialize hash/HMAC function
+ * @alg: Hash algorithm
+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
+ * @key_len: Length of the key in bytes
+ * Returns: Pointer to hash context to use with other hash functions or %NULL
+ * on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len);
+
+/**
+ * crypto_hash_update - Add data to hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @data: Data buffer to add
+ * @len: Length of the buffer
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
+
+/**
+ * crypto_hash_finish - Complete hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
+ * context
+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
+ * hash context; on return, this is set to the actual length of the hash value
+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
+ * or -2 on other failures (including failed crypto_hash_update() operations)
+ *
+ * This function calculates the hash value and frees the context buffer that
+ * was used for hash calculation.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
+
+
+enum crypto_cipher_alg {
+	CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
+	CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
+};
+
+struct crypto_cipher;
+
+/**
+ * crypto_cipher_init - Initialize block/stream cipher function
+ * @alg: Cipher algorithm
+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
+ * @key: Cipher key
+ * @key_len: Length of key in bytes
+ * Returns: Pointer to cipher context to use with other cipher functions or
+ * %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len);
+
+/**
+ * crypto_cipher_encrypt - Cipher encrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @plain: Plaintext to cipher
+ * @crypt: Resulting ciphertext
+ * @len: Length of the plaintext
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Cipher decrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @crypt: Ciphertext to decrypt
+ * @plain: Resulting plaintext
+ * @len: Length of the cipher text
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Free cipher context
+ * @ctx: Context pointer from crypto_cipher_init()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_cipher_deinit(struct crypto_cipher *ctx);
+
+
+struct crypto_public_key;
+struct crypto_private_key;
+
+/**
+ * crypto_public_key_import - Import an RSA public key
+ * @key: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library supports X.509
+ * parsing. In that case, crypto_public_key_from_cert() is used to import the
+ * public key from a certificate.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+
+/**
+ * crypto_private_key_import - Import an RSA private key
+ * @key: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the private key or %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len);
+
+/**
+ * crypto_public_key_from_cert - Import an RSA public key from a certificate
+ * @buf: DER encoded X.509 certificate
+ * @len: Certificate buffer length in bytes
+ * Returns: Pointer to public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library does not support
+ * X.509 parsing. In that case, internal code will be used to parse the
+ * certificate and public key is imported using crypto_public_key_import().
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len);
+
+/**
+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
+ * @key: Public key
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
+ * @key: Private key from crypto_private_key_import()
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted (signed) data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen);
+
+/**
+ * crypto_public_key_free - Free public key
+ * @key: Public key
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_public_key_free(struct crypto_public_key *key);
+
+/**
+ * crypto_private_key_free - Free private key
+ * @key: Private key from crypto_private_key_import()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_private_key_free(struct crypto_private_key *key);
+
+/**
+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
+ * @key: Public key
+ * @crypt: Encrypted signature data (using the private key)
+ * @crypt_len: Encrypted signature data length
+ * @plain: Buffer for plaintext (at least crypt_len bytes)
+ * @plain_len: Plaintext length (max buffer size on input, real len on output);
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+				    const u8 *crypt, size_t crypt_len,
+				    u8 *plain, size_t *plain_len);
+
+/**
+ * crypto_global_init - Initialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_global_init(void);
+
+/**
+ * crypto_global_deinit - Deinitialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_global_deinit(void);
+
+/**
+ * crypto_mod_exp - Modular exponentiation of large integers
+ * @base: Base integer (big endian byte array)
+ * @base_len: Length of base integer in bytes
+ * @power: Power integer (big endian byte array)
+ * @power_len: Length of power integer in bytes
+ * @modulus: Modulus integer (big endian byte array)
+ * @modulus_len: Length of modulus integer in bytes
+ * @result: Buffer for the result
+ * @result_len: Result length (max buffer size on input, real len on output)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function calculates result = base ^ power mod modulus. modules_len is
+ * used as the maximum size of modulus buffer. It is set to the used size on
+ * success.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len);
+
 #endif /* CRYPTO_H */
Index: hostapd.8
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd.8,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/hostapd.8 -L contrib/hostapd/hostapd.8 -u -r1.1 -r1.2
--- contrib/hostapd/hostapd.8
+++ contrib/hostapd/hostapd.8
@@ -3,7 +3,7 @@
 hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
 .SH SYNOPSIS
 .B hostapd
-[-hdBKt] <configuration file(s)>
+[-hdBKtv] [-P <PID file>] <configuration file(s)>
 .SH DESCRIPTION
 This manual page documents briefly the
 .B hostapd
@@ -39,6 +39,9 @@
 .B \-B
 Run daemon in the background.
 .TP
+.B \-P <PID file>
+Path to PID file.
+.TP
 .B \-K
 Include key data in debug messages.
 .TP
@@ -50,7 +53,7 @@
 .SH SEE ALSO
 .BR hostapd_cli (1).
 .SH AUTHOR
-hostapd was written by Jouni Malinen <jkmaline at cc.hut.fi>. 
+hostapd was written by Jouni Malinen <j at w1.fi>. 
 .PP
 This manual page was written by Faidon Liambotis <faidon at cube.gr>,
 for the Debian project (but may be used by others).
Index: eap_i.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_i.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_i.h -L contrib/hostapd/eap_i.h -u -r1.2 -r1.3
--- contrib/hostapd/eap_i.h
+++ contrib/hostapd/eap_i.h
@@ -1,11 +1,32 @@
+/*
+ * hostapd / EAP Authenticator state machine internal structures (RFC 4137)
+ * Copyright (c) 2004-2005, 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_I_H
 #define EAP_I_H
 
 #include "eap.h"
 
-/* draft-ietf-eap-statemachine-05.pdf - EAP Standalone Authenticator */
+/* RFC 4137 - EAP Standalone Authenticator */
 
+/**
+ * struct eap_method - EAP method interface
+ * This structure defines the EAP method interface. Each method will need to
+ * register its own EAP type, EAP name, and set of function pointers for method
+ * specific operations. This interface is based on section 5.4 of RFC 4137.
+ */
 struct eap_method {
+	int vendor;
 	EapType method;
 	const char *name;
 
@@ -25,8 +46,58 @@
 	/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
 	 * but it is useful in implementing Policy.getDecision() */
 	Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * free - Free EAP method data
+	 * @method: Pointer to the method data registered with
+	 * eap_server_method_register().
+	 *
+	 * This function will be called when the EAP method is being
+	 * unregistered. If the EAP method allocated resources during
+	 * registration (e.g., allocated struct eap_method), they should be
+	 * freed in this function. No other method functions will be called
+	 * after this call. If this function is not defined (i.e., function
+	 * pointer is %NULL), a default handler is used to release the method
+	 * data with free(method). This is suitable for most cases.
+	 */
+	void (*free)(struct eap_method *method);
+
+#define EAP_SERVER_METHOD_INTERFACE_VERSION 1
+	/**
+	 * version - Version of the EAP server method interface
+	 *
+	 * The EAP server method implementation should set this variable to
+	 * EAP_SERVER_METHOD_INTERFACE_VERSION. This is used to verify that the
+	 * EAP method is using supported API version when using dynamically
+	 * loadable EAP methods.
+	 */
+	int version;
+
+	/**
+	 * next - Pointer to the next EAP method
+	 *
+	 * This variable is used internally in the EAP method registration code
+	 * to create a linked list of registered EAP methods.
+	 */
+	struct eap_method *next;
+
+	/**
+	 * get_emsk - Get EAP method specific keying extended material (EMSK)
+	 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @len: Pointer to a variable to store EMSK length
+	 * Returns: EMSK or %NULL if not available
+	 *
+	 * This function can be used to get the extended keying material from
+	 * the EAP method. The key may already be stored in the method-specific
+	 * private data or this function may derive the key.
+	 */
+	u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
 };
 
+/**
+ * struct eap_sm - EAP server state machine data
+ */
 struct eap_sm {
 	enum {
 		EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
@@ -77,6 +148,8 @@
 	Boolean rxResp;
 	int respId;
 	EapType respMethod;
+	int respVendor;
+	u32 respVendorMethod;
 	Boolean ignore;
 	enum {
 		DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE
@@ -102,11 +175,18 @@
 	Boolean update_user;
 
 	int num_rounds;
+	enum {
+		METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
+	} method_pending;
 };
 
-const struct eap_method * eap_sm_get_eap_methods(int method);
 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
 		 int phase2);
 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len);
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const u8 *msg, size_t msglen, size_t *plen);
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+			       size_t payload_len, u8 code, u8 identifier,
+			       u8 **payload);
 
 #endif /* EAP_I_H */
Index: eloop.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eloop.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eloop.c -L contrib/hostapd/eloop.c -u -r1.2 -r1.3
--- contrib/hostapd/eloop.c
+++ contrib/hostapd/eloop.c
@@ -1,6 +1,6 @@
 /*
  * Event loop based on select() loop
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2005, 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,19 +12,9 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
+#include "includes.h"
 
-#ifdef CONFIG_NATIVE_WINDOWS
 #include "common.h"
-#endif /* CONFIG_NATIVE_WINDOWS */
-
 #include "eloop.h"
 
 
@@ -32,29 +22,38 @@
 	int sock;
 	void *eloop_data;
 	void *user_data;
-	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+	eloop_sock_handler handler;
 };
 
 struct eloop_timeout {
-	struct timeval time;
+	struct os_time time;
 	void *eloop_data;
 	void *user_data;
-	void (*handler)(void *eloop_ctx, void *sock_ctx);
+	eloop_timeout_handler handler;
 	struct eloop_timeout *next;
 };
 
 struct eloop_signal {
 	int sig;
 	void *user_data;
-	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+	eloop_signal_handler handler;
 	int signaled;
 };
 
+struct eloop_sock_table {
+	int count;
+	struct eloop_sock *table;
+	int changed;
+};
+
 struct eloop_data {
 	void *user_data;
 
-	int max_sock, reader_count;
-	struct eloop_sock *readers;
+	int max_sock;
+
+	struct eloop_sock_table readers;
+	struct eloop_sock_table writers;
+	struct eloop_sock_table exceptions;
 
 	struct eloop_timeout *timeout;
 
@@ -64,81 +63,181 @@
 	int pending_terminate;
 
 	int terminate;
+	int reader_table_changed;
 };
 
 static struct eloop_data eloop;
 
 
-void eloop_init(void *user_data)
+int eloop_init(void *user_data)
 {
-	memset(&eloop, 0, sizeof(eloop));
+	os_memset(&eloop, 0, sizeof(eloop));
 	eloop.user_data = user_data;
+	return 0;
 }
 
 
-int eloop_register_read_sock(int sock,
-			     void (*handler)(int sock, void *eloop_ctx,
-					     void *sock_ctx),
-			     void *eloop_data, void *user_data)
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+                                     int sock, eloop_sock_handler handler,
+                                     void *eloop_data, void *user_data)
 {
 	struct eloop_sock *tmp;
 
+	if (table == NULL)
+		return -1;
+
 	tmp = (struct eloop_sock *)
-		realloc(eloop.readers,
-			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
+		os_realloc(table->table,
+			   (table->count + 1) * sizeof(struct eloop_sock));
 	if (tmp == NULL)
 		return -1;
 
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	eloop.reader_count++;
-	eloop.readers = tmp;
+	tmp[table->count].sock = sock;
+	tmp[table->count].eloop_data = eloop_data;
+	tmp[table->count].user_data = user_data;
+	tmp[table->count].handler = handler;
+	table->count++;
+	table->table = tmp;
 	if (sock > eloop.max_sock)
 		eloop.max_sock = sock;
+	table->changed = 1;
 
 	return 0;
 }
 
 
-void eloop_unregister_read_sock(int sock)
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+                                         int sock)
 {
 	int i;
 
-	if (eloop.readers == NULL || eloop.reader_count == 0)
+	if (table == NULL || table->table == NULL || table->count == 0)
 		return;
 
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
+	for (i = 0; i < table->count; i++) {
+		if (table->table[i].sock == sock)
 			break;
 	}
-	if (i == eloop.reader_count)
+	if (i == table->count)
 		return;
-	if (i != eloop.reader_count - 1) {
-		memmove(&eloop.readers[i], &eloop.readers[i + 1],
-			(eloop.reader_count - i - 1) *
-			sizeof(struct eloop_sock));
+	if (i != table->count - 1) {
+		os_memmove(&table->table[i], &table->table[i + 1],
+			   (table->count - i - 1) *
+			   sizeof(struct eloop_sock));
+	}
+	table->count--;
+	table->changed = 1;
+}
+
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+				     fd_set *fds)
+{
+	int i;
+
+	FD_ZERO(fds);
+
+	if (table->table == NULL)
+		return;
+
+	for (i = 0; i < table->count; i++)
+		FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+				      fd_set *fds)
+{
+	int i;
+
+	if (table == NULL || table->table == NULL)
+		return;
+
+	table->changed = 0;
+	for (i = 0; i < table->count; i++) {
+		if (FD_ISSET(table->table[i].sock, fds)) {
+			table->table[i].handler(table->table[i].sock,
+						table->table[i].eloop_data,
+						table->table[i].user_data);
+			if (table->changed)
+				break;
+		}
+	}
+}
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+	if (table)
+		os_free(table->table);
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data)
+{
+	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+				   eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+	switch (type) {
+	case EVENT_TYPE_READ:
+		return &eloop.readers;
+	case EVENT_TYPE_WRITE:
+		return &eloop.writers;
+	case EVENT_TYPE_EXCEPTION:
+		return &eloop.exceptions;
 	}
-	eloop.reader_count--;
+
+	return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+			eloop_sock_handler handler,
+			void *eloop_data, void *user_data)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	return eloop_sock_table_add_sock(table, sock, handler,
+					 eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	eloop_sock_table_remove_sock(table, sock);
 }
 
 
 int eloop_register_timeout(unsigned int secs, unsigned int usecs,
-			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   eloop_timeout_handler handler,
 			   void *eloop_data, void *user_data)
 {
 	struct eloop_timeout *timeout, *tmp, *prev;
 
-	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+	timeout = os_malloc(sizeof(*timeout));
 	if (timeout == NULL)
 		return -1;
-	gettimeofday(&timeout->time, NULL);
-	timeout->time.tv_sec += secs;
-	timeout->time.tv_usec += usecs;
-	while (timeout->time.tv_usec >= 1000000) {
-		timeout->time.tv_sec++;
-		timeout->time.tv_usec -= 1000000;
+	os_get_time(&timeout->time);
+	timeout->time.sec += secs;
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
 	}
 	timeout->eloop_data = eloop_data;
 	timeout->user_data = user_data;
@@ -153,7 +252,7 @@
 	prev = NULL;
 	tmp = eloop.timeout;
 	while (tmp != NULL) {
-		if (timercmp(&timeout->time, &tmp->time, <))
+		if (os_time_before(&timeout->time, &tmp->time))
 			break;
 		prev = tmp;
 		tmp = tmp->next;
@@ -171,7 +270,7 @@
 }
 
 
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+int eloop_cancel_timeout(eloop_timeout_handler handler,
 			 void *eloop_data, void *user_data)
 {
 	struct eloop_timeout *timeout, *prev, *next;
@@ -191,7 +290,7 @@
 				eloop.timeout = next;
 			else
 				prev->next = next;
-			free(timeout);
+			os_free(timeout);
 			removed++;
 		} else
 			prev = timeout;
@@ -266,17 +365,15 @@
 }
 
 
-int eloop_register_signal(int sig,
-			  void (*handler)(int sig, void *eloop_ctx,
-					  void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
 			  void *user_data)
 {
 	struct eloop_signal *tmp;
 
 	tmp = (struct eloop_signal *)
-		realloc(eloop.signals,
-			(eloop.signal_count + 1) *
-			sizeof(struct eloop_signal));
+		os_realloc(eloop.signals,
+			   (eloop.signal_count + 1) *
+			   sizeof(struct eloop_signal));
 	if (tmp == NULL)
 		return -1;
 
@@ -292,41 +389,67 @@
 }
 
 
-void eloop_run(void)
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data)
 {
-	fd_set *rfds;
-	int i, res;
-	struct timeval tv, now;
+	int ret = eloop_register_signal(SIGINT, handler, user_data);
+	if (ret == 0)
+		ret = eloop_register_signal(SIGTERM, handler, user_data);
+	return ret;
+}
+
 
-	rfds = malloc(sizeof(*rfds));
-	if (rfds == NULL) {
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+	return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+	fd_set *rfds, *wfds, *efds;
+	int res;
+	struct timeval _tv;
+	struct os_time tv, now;
+
+	rfds = os_malloc(sizeof(*rfds));
+	wfds = os_malloc(sizeof(*wfds));
+	efds = os_malloc(sizeof(*efds));
+	if (rfds == NULL || wfds == NULL || efds == NULL) {
 		printf("eloop_run - malloc failed\n");
-		return;
+		goto out;
 	}
 
 	while (!eloop.terminate &&
-		(eloop.timeout || eloop.reader_count > 0)) {
+	       (eloop.timeout || eloop.readers.count > 0 ||
+		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
 		if (eloop.timeout) {
-			gettimeofday(&now, NULL);
-			if (timercmp(&now, &eloop.timeout->time, <))
-				timersub(&eloop.timeout->time, &now, &tv);
+			os_get_time(&now);
+			if (os_time_before(&now, &eloop.timeout->time))
+				os_time_sub(&eloop.timeout->time, &now, &tv);
 			else
-				tv.tv_sec = tv.tv_usec = 0;
+				tv.sec = tv.usec = 0;
 #if 0
 			printf("next timeout in %lu.%06lu sec\n",
-			       tv.tv_sec, tv.tv_usec);
+			       tv.sec, tv.usec);
 #endif
+			_tv.tv_sec = tv.sec;
+			_tv.tv_usec = tv.usec;
 		}
 
-		FD_ZERO(rfds);
-		for (i = 0; i < eloop.reader_count; i++)
-			FD_SET(eloop.readers[i].sock, rfds);
-		res = select(eloop.max_sock + 1, rfds, NULL, NULL,
-			     eloop.timeout ? &tv : NULL);
-		if (res < 0 && errno != EINTR) {
+		eloop_sock_table_set_fds(&eloop.readers, rfds);
+		eloop_sock_table_set_fds(&eloop.writers, wfds);
+		eloop_sock_table_set_fds(&eloop.exceptions, efds);
+		res = select(eloop.max_sock + 1, rfds, wfds, efds,
+			     eloop.timeout ? &_tv : NULL);
+		if (res < 0 && errno != EINTR && errno != 0) {
 			perror("select");
-			free(rfds);
-			return;
+			goto out;
 		}
 		eloop_process_pending_signals();
 
@@ -334,13 +457,13 @@
 		if (eloop.timeout) {
 			struct eloop_timeout *tmp;
 
-			gettimeofday(&now, NULL);
-			if (!timercmp(&now, &eloop.timeout->time, <)) {
+			os_get_time(&now);
+			if (!os_time_before(&now, &eloop.timeout->time)) {
 				tmp = eloop.timeout;
 				eloop.timeout = eloop.timeout->next;
 				tmp->handler(tmp->eloop_data,
 					     tmp->user_data);
-				free(tmp);
+				os_free(tmp);
 			}
 
 		}
@@ -348,17 +471,15 @@
 		if (res <= 0)
 			continue;
 
-		for (i = 0; i < eloop.reader_count; i++) {
-			if (FD_ISSET(eloop.readers[i].sock, rfds)) {
-				eloop.readers[i].handler(
-					eloop.readers[i].sock,
-					eloop.readers[i].eloop_data,
-					eloop.readers[i].user_data);
-			}
-		}
+		eloop_sock_table_dispatch(&eloop.readers, rfds);
+		eloop_sock_table_dispatch(&eloop.writers, wfds);
+		eloop_sock_table_dispatch(&eloop.exceptions, efds);
 	}
 
-	free(rfds);
+out:
+	os_free(rfds);
+	os_free(wfds);
+	os_free(efds);
 }
 
 
@@ -376,10 +497,12 @@
 	while (timeout != NULL) {
 		prev = timeout;
 		timeout = timeout->next;
-		free(prev);
+		os_free(prev);
 	}
-	free(eloop.readers);
-	free(eloop.signals);
+	eloop_sock_table_destroy(&eloop.readers);
+	eloop_sock_table_destroy(&eloop.writers);
+	eloop_sock_table_destroy(&eloop.exceptions);
+	os_free(eloop.signals);
 }
 
 
@@ -387,3 +510,22 @@
 {
 	return eloop.terminate;
 }
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+	fd_set rfds;
+
+	if (sock < 0)
+		return;
+
+	FD_ZERO(&rfds);
+	FD_SET(sock, &rfds);
+	select(sock + 1, &rfds, NULL, NULL, NULL);
+}
+
+
+void * eloop_get_user_data(void)
+{
+	return eloop.user_data;
+}
--- /dev/null
+++ contrib/hostapd/hw_features.c
@@ -0,0 +1,429 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "config.h"
+#include "ieee802_11.h"
+#include "eloop.h"
+
+
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features)
+{
+	size_t i;
+
+	if (hw_features == NULL)
+		return;
+
+	for (i = 0; i < num_hw_features; i++) {
+		free(hw_features[i].channels);
+		free(hw_features[i].rates);
+	}
+
+	free(hw_features);
+}
+
+
+int hostapd_get_hw_features(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int ret = 0, i, j;
+	u16 num_modes, flags;
+	struct hostapd_hw_modes *modes;
+
+	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
+	if (modes == NULL) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Fetching hardware channel/rate support not "
+			       "supported.");
+		return -1;
+	}
+
+	iface->hw_flags = flags;
+
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = modes;
+	iface->num_hw_features = num_modes;
+
+	for (i = 0; i < num_modes; i++) {
+		struct hostapd_hw_modes *feature = &modes[i];
+		/* set flag for channels we can use in current regulatory
+		 * domain */
+		for (j = 0; j < feature->num_channels; j++) {
+			/* TODO: add regulatory domain lookup */
+			unsigned char power_level = 0;
+			unsigned char antenna_max = 0;
+
+			if ((feature->mode == HOSTAPD_MODE_IEEE80211G ||
+			     feature->mode == HOSTAPD_MODE_IEEE80211B) &&
+			    feature->channels[j].chan >= 1 &&
+			    feature->channels[j].chan <= 11) {
+				power_level = 20;
+				feature->channels[j].flag |=
+					HOSTAPD_CHAN_W_SCAN;
+			} else
+				feature->channels[j].flag &=
+					~HOSTAPD_CHAN_W_SCAN;
+
+			hostapd_set_channel_flag(hapd, feature->mode,
+						 feature->channels[j].chan,
+						 feature->channels[j].flag,
+						 power_level,
+						 antenna_max);
+		}
+	}
+
+	return ret;
+}
+
+
+static int hostapd_prepare_rates(struct hostapd_data *hapd,
+				 struct hostapd_hw_modes *mode)
+{
+	int i, num_basic_rates = 0;
+	int basic_rates_a[] = { 60, 120, 240, -1 };
+	int basic_rates_b[] = { 10, 20, -1 };
+	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
+	int *basic_rates;
+
+	if (hapd->iconf->basic_rates)
+		basic_rates = hapd->iconf->basic_rates;
+	else switch (mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		basic_rates = basic_rates_a;
+		break;
+	case HOSTAPD_MODE_IEEE80211B:
+		basic_rates = basic_rates_b;
+		break;
+	case HOSTAPD_MODE_IEEE80211G:
+		basic_rates = basic_rates_g;
+		break;
+	default:
+		return -1;
+	}
+
+	if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
+				  basic_rates, mode->mode)) {
+		printf("Failed to update rate sets in kernel module\n");
+	}
+
+	free(hapd->iface->current_rates);
+	hapd->iface->num_rates = 0;
+
+	hapd->iface->current_rates =
+		malloc(mode->num_rates * sizeof(struct hostapd_rate_data));
+	if (!hapd->iface->current_rates) {
+		printf("Failed to allocate memory for rate table.\n");
+		return -1;
+	}
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct hostapd_rate_data *rate;
+
+		if (hapd->iconf->supported_rates &&
+		    !hostapd_rate_found(hapd->iconf->supported_rates,
+					mode->rates[i].rate))
+			continue;
+
+		rate = &hapd->iface->current_rates[hapd->iface->num_rates];
+		memcpy(rate, &mode->rates[i],
+		       sizeof(struct hostapd_rate_data));
+		if (hostapd_rate_found(basic_rates, rate->rate)) {
+			rate->flags |= HOSTAPD_RATE_BASIC;
+			num_basic_rates++;
+		} else
+			rate->flags &= ~HOSTAPD_RATE_BASIC;
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+			      "RATE[%d] rate=%d flags=0x%x\n",
+			      hapd->iface->num_rates, rate->rate, rate->flags);
+		hapd->iface->num_rates++;
+	}
+
+	if (hapd->iface->num_rates == 0 || num_basic_rates == 0) {
+		printf("No rates remaining in supported/basic rate sets "
+		       "(%d,%d).\n", hapd->iface->num_rates, num_basic_rates);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void select_hw_mode_start(void *eloop_data, void *user_ctx);
+static void select_hw_mode2_handler(void *eloop_data, void *user_ctx);
+
+/**
+ * select_hw_mode_finalize - Finish select HW mode & call the callback
+ * @iface: Pointer to interface data.
+ * @status: Status of the select HW mode (0 on success; -1 on failure).
+ * Returns: 0 on success; -1 on failure (e.g., was not in progress).
+ */
+static int select_hw_mode_finalize(struct hostapd_iface *iface, int status)
+{
+	hostapd_iface_cb cb;
+
+	if (!iface->hw_mode_sel_cb)
+		return -1;
+
+	eloop_cancel_timeout(select_hw_mode_start, iface, NULL);
+	eloop_cancel_timeout(select_hw_mode2_handler, iface, NULL);
+
+	cb = iface->hw_mode_sel_cb;
+
+	iface->hw_mode_sel_cb = NULL;
+
+	cb(iface, status);
+
+	return 0;
+}
+
+
+/**
+ * select_hw_mode2 - Select the hardware mode (part 2)
+ * @iface: Pointer to interface data.
+ * @status: Status of auto chanel selection.
+ *
+ * Setup the rates and passive scanning based on the configuration.
+ */
+static void select_hw_mode2(struct hostapd_iface *iface, int status)
+{
+	int ret = status;
+	if (ret)
+		goto fail;
+
+	if (iface->current_mode == NULL) {
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured channel");
+		ret = -1;
+		goto fail;
+	}
+
+	if (hostapd_prepare_rates(iface->bss[0], iface->current_mode)) {
+		printf("Failed to prepare rates table.\n");
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+					   HOSTAPD_LEVEL_WARNING,
+					   "Failed to prepare rates table.");
+		ret = -1;
+		goto fail;
+	}
+
+	ret = hostapd_passive_scan(iface->bss[0], 0,
+				   iface->conf->passive_scan_mode,
+				   iface->conf->passive_scan_interval,
+				   iface->conf->passive_scan_listen,
+				   NULL, NULL);
+	if (ret) {
+		printf("Could not set passive scanning: %s\n", strerror(ret));
+		ret = 0;
+	}
+
+fail:
+	select_hw_mode_finalize(iface, ret);
+}
+
+
+/**
+ * select_hw_mode2_handler - Calls select_hw_mode2 when auto chan isn't used
+ * @eloop_data: Stores the struct hostapd_iface * for the interface.
+ * @user_ctx: Unused.
+ */
+static void select_hw_mode2_handler(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = eloop_data;
+
+	select_hw_mode2(iface, 0);
+}
+
+
+/**
+ * select_hw_mode1 - Select the hardware mode (part 1)
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success; -1 on failure.
+ *
+ * Setup the hardware mode and channel based on the configuration.
+ * Schedules select_hw_mode2() to be called immediately or after automatic
+ * channel selection takes place.
+ */
+static int select_hw_mode1(struct hostapd_iface *iface)
+{
+	int i, j, ok;
+
+	if (iface->num_hw_features < 1)
+		return -1;
+
+	iface->current_mode = NULL;
+	for (i = 0; i < iface->num_hw_features; i++) {
+		struct hostapd_hw_modes *mode = &iface->hw_features[i];
+		if (mode->mode == (int) iface->conf->hw_mode) {
+			iface->current_mode = mode;
+			break;
+		}
+	}
+
+	if (iface->current_mode == NULL) {
+		printf("Hardware does not support configured mode\n");
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured mode "
+			       "(%d)", (int) iface->conf->hw_mode);
+		return -1;
+	}
+
+	ok = 0;
+	for (j = 0; j < iface->current_mode->num_channels; j++) {
+		struct hostapd_channel_data *chan =
+			&iface->current_mode->channels[j];
+		if ((chan->flag & HOSTAPD_CHAN_W_SCAN) &&
+		    (chan->chan == iface->conf->channel)) {
+			ok = 1;
+			break;
+		}
+	}
+	if (ok == 0 && iface->conf->channel != 0) {
+		hostapd_logger(iface->bss[0], NULL,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Configured channel (%d) not found from the "
+			       "channel list of current mode (%d) %s",
+			       iface->conf->channel,
+			       iface->current_mode->mode,
+			       hostapd_hw_mode_txt(iface->current_mode->mode));
+		iface->current_mode = NULL;
+	}
+
+	/*
+	 * Calls select_hw_mode2() via a handler, so that the function is
+	 * always executed from eloop.
+	 */
+	eloop_register_timeout(0, 0, select_hw_mode2_handler, iface, NULL);
+	return 0;
+}
+
+
+/**
+ * select_hw_mode_start - Handler to start select HW mode
+ * @eloop_data: Stores the struct hostapd_iface * for the interface.
+ * @user_ctx: Unused.
+ *
+ * An eloop handler is used so that all errors can be processed by the
+ * callback without introducing stack recursion.
+ */
+static void select_hw_mode_start(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = (struct hostapd_iface *)eloop_data;
+
+	int ret;
+
+	ret = select_hw_mode1(iface);
+	if (ret)
+		select_hw_mode_finalize(iface, ret);
+}
+
+
+/**
+ * hostapd_select_hw_mode_start - Start selection of the hardware mode
+ * @iface: Pointer to interface data.
+ * @cb: The function to callback when done.
+ * Returns:  0 if it starts successfully; cb will be called when done.
+ *          -1 on failure; cb will not be called.
+ *
+ * Sets up the hardware mode, channel, rates, and passive scanning
+ * based on the configuration.
+ */
+int hostapd_select_hw_mode_start(struct hostapd_iface *iface,
+				 hostapd_iface_cb cb)
+{
+	if (iface->hw_mode_sel_cb) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Hardware mode select already in progress.",
+			   iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	iface->hw_mode_sel_cb = cb;
+
+	eloop_register_timeout(0, 0, select_hw_mode_start, iface, NULL);
+
+	return 0;
+}
+
+
+/**
+ * hostapd_auto_chan_select_stop - Stops automatic channel selection
+ * @iface: Pointer to interface data.
+ * Returns:  0 if successfully stopped;
+ *          -1 on failure (i.e., was not in progress)
+ */
+int hostapd_select_hw_mode_stop(struct hostapd_iface *iface)
+{
+	return select_hw_mode_finalize(iface, -1);
+}
+
+
+const char * hostapd_hw_mode_txt(int mode)
+{
+	switch (mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		return "IEEE 802.11a";
+	case HOSTAPD_MODE_IEEE80211B:
+		return "IEEE 802.11b";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "IEEE 802.11g";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->chan == chan)
+			return ch->freq;
+	}
+
+	return 0;
+}
+
+
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->freq == freq)
+			return ch->chan;
+	}
+
+	return 0;
+}
--- /dev/null
+++ contrib/hostapd/beacon.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 BEACON_H
+#define BEACON_H
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+		      size_t len);
+void ieee802_11_set_beacon(struct hostapd_data *hapd);
+void ieee802_11_set_beacons(struct hostapd_iface *iface);
+
+#endif /* BEACON_H */
Index: ieee802_11.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_11.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/ieee802_11.h -L contrib/hostapd/ieee802_11.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/ieee802_11.h
+++ contrib/hostapd/ieee802_11.h
@@ -1,6 +1,177 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2006, 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 IEEE802_11_H
 #define IEEE802_11_H
 
+/* IEEE 802.11 defines */
+
+#define WLAN_FC_PVER (BIT(1) | BIT(0))
+#define WLAN_FC_TODS BIT(8)
+#define WLAN_FC_FROMDS BIT(9)
+#define WLAN_FC_MOREFRAG BIT(10)
+#define WLAN_FC_RETRY BIT(11)
+#define WLAN_FC_PWRMGT BIT(12)
+#define WLAN_FC_MOREDATA BIT(13)
+#define WLAN_FC_ISWEP BIT(14)
+#define WLAN_FC_ORDER BIT(15)
+
+#define WLAN_FC_GET_TYPE(fc) (((fc) & (BIT(3) | BIT(2))) >> 2)
+#define WLAN_FC_GET_STYPE(fc) \
+	(((fc) & (BIT(7) | BIT(6) | BIT(5) | BIT(4))) >> 4)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+#define WLAN_GET_SEQ_SEQ(seq) \
+	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_TYPE_CTRL 1
+#define WLAN_FC_TYPE_DATA 2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_ASSOC_RESP 1
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+#define WLAN_FC_STYPE_REASSOC_RESP 3
+#define WLAN_FC_STYPE_PROBE_REQ 4
+#define WLAN_FC_STYPE_PROBE_RESP 5
+#define WLAN_FC_STYPE_BEACON 8
+#define WLAN_FC_STYPE_ATIM 9
+#define WLAN_FC_STYPE_DISASSOC 10
+#define WLAN_FC_STYPE_AUTH 11
+#define WLAN_FC_STYPE_DEAUTH 12
+#define WLAN_FC_STYPE_ACTION 13
+
+/* control */
+#define WLAN_FC_STYPE_PSPOLL 10
+#define WLAN_FC_STYPE_RTS 11
+#define WLAN_FC_STYPE_CTS 12
+#define WLAN_FC_STYPE_ACK 13
+#define WLAN_FC_STYPE_CFEND 14
+#define WLAN_FC_STYPE_CFENDACK 15
+
+/* data */
+#define WLAN_FC_STYPE_DATA 0
+#define WLAN_FC_STYPE_DATA_CFACK 1
+#define WLAN_FC_STYPE_DATA_CFPOLL 2
+#define WLAN_FC_STYPE_DATA_CFACKPOLL 3
+#define WLAN_FC_STYPE_NULLFUNC 4
+#define WLAN_FC_STYPE_CFACK 5
+#define WLAN_FC_STYPE_CFPOLL 6
+#define WLAN_FC_STYPE_CFACKPOLL 7
+#define WLAN_FC_STYPE_QOS_DATA 8
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS BIT(0)
+#define WLAN_CAPABILITY_IBSS BIT(1)
+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
+#define WLAN_CAPABILITY_PRIVACY BIT(4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
+#define WLAN_CAPABILITY_PBCC BIT(6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+/* IEEE 802.11i */
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_GENERIC 221
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
 
 struct ieee80211_mgmt {
 	u16 frame_control;
@@ -44,6 +215,18 @@
 			u16 reason_code;
 		} __attribute__ ((packed)) disassoc;
 		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} __attribute__ ((packed)) probe_req;
+		struct {
+			u8 timestamp[8];
+			u16 beacon_int;
+			u16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		} __attribute__ ((packed)) probe_resp;
+		struct {
 			u8 timestamp[8];
 			u16 beacon_int;
 			u16 capab_info;
@@ -51,10 +234,33 @@
 			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
 			u8 variable[0];
 		} __attribute__ ((packed)) beacon;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				} __attribute__ ((packed)) wme_action;
+				struct{
+					u8 action_code;
+					u8 element_id;
+					u8 length;
+					u8 switch_mode;
+					u8 new_chan;
+					u8 switch_count;
+				} __attribute__ ((packed)) chan_switch;
+			} u;
+		} __attribute__ ((packed)) action;
 	} u;
 } __attribute__ ((packed));
 
 
+#define ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define ERP_INFO_USE_PROTECTION BIT(1)
+#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
 /* Parsed Information Elements */
 struct ieee802_11_elems {
 	u8 *ssid;
@@ -73,27 +279,55 @@
 	u8 ibss_params_len;
 	u8 *challenge;
 	u8 challenge_len;
+	u8 *erp_info;
+	u8 erp_info_len;
+	u8 *ext_supp_rates;
+	u8 ext_supp_rates_len;
 	u8 *wpa_ie;
 	u8 wpa_ie_len;
 	u8 *rsn_ie;
 	u8 rsn_ie_len;
+	u8 *wme;
+	u8 wme_len;
+	u8 *wme_tspec;
+	u8 wme_tspec_len;
+	u8 *power_cap;
+	u8 power_cap_len;
+	u8 *supp_channels;
+	u8 supp_channels_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
 
 
+struct hostapd_frame_info {
+	u32 phytype;
+	u32 channel;
+	u32 datarate;
+	u32 ssi_signal;
+
+	unsigned int passive_scan:1;
+};
+
+
+void ieee802_11_send_deauth(struct hostapd_data *hapd, u8 *addr, u16 reason);
 void ieee802_11_mgmt(struct hostapd_data *hapd, u8 *buf, size_t len,
-		     u16 stype);
+		     u16 stype, struct hostapd_frame_info *fi);
 void ieee802_11_mgmt_cb(struct hostapd_data *hapd, u8 *buf, size_t len,
 			u16 stype, int ok);
 ParseRes ieee802_11_parse_elems(struct hostapd_data *hapd, u8 *start,
 				size_t len,
 				struct ieee802_11_elems *elems,
 				int show_errors);
-void ieee80211_michael_mic_failure(struct hostapd_data *hapd, u8 *addr,
+void ieee802_11_print_ssid(const u8 *ssid, u8 len);
+void ieee80211_michael_mic_failure(struct hostapd_data *hapd, const u8 *addr,
 				   int local);
 int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
 int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   char *buf, size_t buflen);
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe);
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
 
 #endif /* IEEE802_11_H */
Index: driver_test.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/driver_test.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/driver_test.c -L contrib/hostapd/driver_test.c -u -r1.2 -r1.3
--- contrib/hostapd/driver_test.c
+++ contrib/hostapd/driver_test.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Driver interface for development testing
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / Driver interface for development testing
+ * Copyright (c) 2004-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
@@ -13,18 +12,10 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
+#include "includes.h"
 #include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
 #include <sys/un.h>
-#include <sys/uio.h>
+#include <dirent.h>
 
 #include "hostapd.h"
 #include "driver.h"
@@ -37,7 +28,8 @@
 #include "accounting.h"
 #include "radius.h"
 #include "l2_packet.h"
-#include "hostap_common.h"
+#include "ieee802_11.h"
+#include "hw_features.h"
 
 
 struct test_client_socket {
@@ -45,6 +37,18 @@
 	u8 addr[ETH_ALEN];
 	struct sockaddr_un un;
 	socklen_t unlen;
+	struct test_driver_bss *bss;
+};
+
+struct test_driver_bss {
+	struct test_driver_bss *next;
+	char ifname[IFNAMSIZ + 1];
+	u8 bssid[ETH_ALEN];
+	u8 *ie;
+	size_t ielen;
+	u8 ssid[32];
+	size_t ssid_len;
+	int privacy;
 };
 
 struct test_driver_data {
@@ -52,13 +56,40 @@
 	struct hostapd_data *hapd;
 	struct test_client_socket *cli;
 	int test_socket;
-	u8 *ie;
-	size_t ielen;
+	struct test_driver_bss *bss;
+	char *socket_dir;
+	char *own_socket_path;
 };
 
 static const struct driver_ops test_driver_ops;
 
 
+static void test_driver_free_bss(struct test_driver_bss *bss)
+{
+	free(bss->ie);
+	free(bss);
+}
+
+
+static void test_driver_free_priv(struct test_driver_data *drv)
+{
+	struct test_driver_bss *bss, *prev;
+
+	if (drv == NULL)
+		return;
+
+	bss = drv->bss;
+	while (bss) {
+		prev = bss;
+		bss = bss->next;
+		test_driver_free_bss(prev);
+	}
+	free(drv->own_socket_path);
+	free(drv->socket_dir);
+	free(drv);
+}
+
+
 static struct test_client_socket *
 test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
 		    socklen_t fromlen)
@@ -67,7 +98,8 @@
 
 	while (cli) {
 		if (cli->unlen == fromlen &&
-		    strncmp(cli->un.sun_path, from->sun_path, fromlen) == 0)
+		    strncmp(cli->un.sun_path, from->sun_path,
+			    fromlen - sizeof(cli->un.sun_family)) == 0)
 			return cli;
 		cli = cli->next;
 	}
@@ -76,8 +108,9 @@
 }
 
 
-static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
-				  size_t data_len, int encrypt)
+static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
+				  size_t data_len, int encrypt,
+				  const u8 *own_addr)
 {
 	struct test_driver_data *drv = priv;
 	struct test_client_socket *cli;
@@ -95,18 +128,21 @@
 		cli = cli->next;
 	}
 
-	if (!cli)
+	if (!cli) {
+		wpa_printf(MSG_DEBUG, "%s: no destination client entry",
+			   __func__);
 		return -1;
+	}
 
 	memcpy(eth.h_dest, addr, ETH_ALEN);
-	memcpy(eth.h_source, drv->hapd->own_addr, ETH_ALEN);
+	memcpy(eth.h_source, own_addr, ETH_ALEN);
 	eth.h_proto = htons(ETH_P_EAPOL);
 
 	io[0].iov_base = "EAPOL ";
 	io[0].iov_len = 6;
 	io[1].iov_base = ð
 	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = data;
+	io[2].iov_base = (u8 *) data;
 	io[2].iov_len = data_len;
 
 	memset(&msg, 0, sizeof(msg));
@@ -118,42 +154,168 @@
 }
 
 
+static int test_driver_send_mgmt_frame(void *priv, const void *buf,
+				       size_t len, int flags)
+{
+	struct test_driver_data *drv = priv;
+	struct msghdr msg;
+	struct iovec io[2];
+	const u8 *dest;
+	int ret = 0, broadcast = 0;
+	char desttxt[30];
+	struct sockaddr_un addr;
+	struct dirent *dent;
+	DIR *dir;
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	if (drv->test_socket < 0 || len < 10 || drv->socket_dir == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%d "
+			   "socket_dir=%p)",
+			   __func__, drv->test_socket, len, drv->socket_dir);
+		return -1;
+	}
+
+	dest = buf;
+	dest += 4;
+	broadcast = memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
+
+	io[0].iov_base = "MLME ";
+	io[0].iov_len = 5;
+	io[1].iov_base = (void *) buf;
+	io[1].iov_len = len;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+	dir = opendir(drv->socket_dir);
+	if (dir == NULL) {
+		perror("test_driver: opendir");
+		return -1;
+	}
+	while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		/* Skip the file if it is not a socket. Also accept
+		 * DT_UNKNOWN (0) in case the C library or underlying file
+		 * system does not support d_type. */
+		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+			continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+
+		memset(&addr, 0, sizeof(addr));
+		addr.sun_family = AF_UNIX;
+		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+			 drv->socket_dir, dent->d_name);
+
+		if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
+			continue;
+		if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
+			   __func__, dent->d_name);
+
+		msg.msg_name = &addr;
+		msg.msg_namelen = sizeof(addr);
+		ret = sendmsg(drv->test_socket, &msg, 0);
+		if (ret < 0)
+			perror("driver_test: sendmsg");
+	}
+	closedir(dir);
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+	ieee802_11_mgmt_cb(drv->hapd, (u8 *) buf, len, WLAN_FC_GET_STYPE(fc),
+			   ret >= 0);
+
+	return ret;
+}
+
+
 static void test_driver_scan(struct test_driver_data *drv,
 			     struct sockaddr_un *from, socklen_t fromlen)
 {
 	char buf[512], *pos, *end;
-	int i;
-
-	pos = buf;
-	end = buf + sizeof(buf);
+	int ret;
+	struct test_driver_bss *bss;
 
 	wpa_printf(MSG_DEBUG, "test_driver: SCAN");
 
-	/* reply: SCANRESP BSSID SSID IEs */
-	pos += snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-			MAC2STR(drv->hapd->own_addr));
-	for (i = 0; i < drv->hapd->conf->ssid_len; i++) {
-		pos += snprintf(pos, end - pos, "%02x",
-				drv->hapd->conf->ssid[i]);
-	}
-	pos += snprintf(pos, end - pos, " ");
-	for (i = 0; i < drv->ielen; i++) {
-		pos += snprintf(pos, end - pos, "%02x",
-				drv->ie[i]);
+	for (bss = drv->bss; bss; bss = bss->next) {
+		pos = buf;
+		end = buf + sizeof(buf);
+
+		/* reply: SCANRESP BSSID SSID IEs */
+		ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+			       MAC2STR(bss->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos,
+					bss->ssid, bss->ssid_len);
+		ret = snprintf(pos, end - pos, " ");
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
+
+		if (bss->privacy) {
+			ret = snprintf(pos, end - pos, " PRIVACY");
+			if (ret < 0 || ret >= end - pos)
+				return;
+			pos += ret;
+		}
+
+		sendto(drv->test_socket, buf, pos - buf, 0,
+		       (struct sockaddr *) from, fromlen);
 	}
+}
 
-	sendto(drv->test_socket, buf, pos - buf, 0,
-	       (struct sockaddr *) from, fromlen);
+
+static struct hostapd_data * test_driver_get_hapd(struct test_driver_data *drv,
+						  struct test_driver_bss *bss)
+{
+	struct hostapd_iface *iface = drv->hapd->iface;
+	struct hostapd_data *hapd = NULL;
+	size_t i;
+
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: bss == NULL", __func__);
+		return NULL;
+	}
+
+	for (i = 0; i < iface->num_bss; i++) {
+		hapd = iface->bss[i];
+		if (memcmp(hapd->own_addr, bss->bssid, ETH_ALEN) == 0)
+			break;
+	}
+	if (i == iface->num_bss) {
+		wpa_printf(MSG_DEBUG, "%s: no matching interface entry found "
+			   "for BSSID " MACSTR, __func__, MAC2STR(bss->bssid));
+		return NULL;
+	}
+
+	return hapd;
 }
 
 
-static int test_driver_new_sta(struct test_driver_data *drv, const u8 *addr,
+static int test_driver_new_sta(struct test_driver_data *drv,
+			       struct test_driver_bss *bss, const u8 *addr,
 			       const u8 *ie, size_t ielen)
 {
-	struct hostapd_data *hapd = drv->hapd;
+	struct hostapd_data *hapd;
 	struct sta_info *sta;
 	int new_assoc, res;
 
+	hapd = test_driver_get_hapd(drv, bss);
+	if (hapd == NULL)
+		return -1;
+
 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
 		HOSTAPD_LEVEL_INFO, "associated");
 
@@ -172,30 +334,26 @@
 			printf("test_driver: no IE from STA\n");
 			return -1;
 		}
-		res = wpa_validate_wpa_ie(hapd, sta, ie, ielen,
-					  ie[0] == WLAN_EID_RSN ?
-					  HOSTAPD_WPA_VERSION_WPA2 :
-					  HOSTAPD_WPA_VERSION_WPA);
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			printf("test_driver: Failed to initialize WPA state "
+			       "machine\n");
+			return -1;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  ie, ielen);
 		if (res != WPA_IE_OK) {
 			printf("WPA/RSN information element rejected? "
 			       "(res %u)\n", res);
 			return -1;
 		}
-		free(sta->wpa_ie);
-		sta->wpa_ie = malloc(ielen);
-		if (sta->wpa_ie == NULL)
-			return -1;
-		memcpy(sta->wpa_ie, ie, ielen);
-		sta->wpa_ie_len = ielen;
-	} else {
-		free(sta->wpa_ie);
-		sta->wpa_ie = NULL;
-		sta->wpa_ie_len = 0;
 	}
 
 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
-	sta->flags |= WLAN_STA_ASSOC;
-	wpa_sm_event(hapd, sta, WPA_ASSOC);
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+	wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
 
 	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
 
@@ -210,17 +368,17 @@
 			      char *data)
 {
 	struct test_client_socket *cli;
-	u8 ie[256];
-	size_t ielen;
+	u8 ie[256], ssid[32];
+	size_t ielen, ssid_len = 0;
 	char *pos, *pos2, cmd[50];
+	struct test_driver_bss *bss;
 
 	/* data: STA-addr SSID(hex) IEs(hex) */
 
-	cli = malloc(sizeof(*cli));
+	cli = wpa_zalloc(sizeof(*cli));
 	if (cli == NULL)
 		return;
 
-	memset(cli, 0, sizeof(*cli));
 	if (hwaddr_aton(data, cli->addr)) {
 		printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
 		       data);
@@ -233,7 +391,14 @@
 	pos2 = strchr(pos, ' ');
 	ielen = 0;
 	if (pos2) {
-		/* TODO: verify SSID */
+		ssid_len = (pos2 - pos) / 2;
+		if (hexstr2bin(pos, ssid, ssid_len) < 0) {
+			wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
+			free(cli);
+			return;
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
+				  ssid, ssid_len);
 
 		pos = pos2 + 1;
 		ielen = strlen(pos) / 2;
@@ -243,19 +408,33 @@
 			ielen = 0;
 	}
 
+	for (bss = drv->bss; bss; bss = bss->next) {
+		if (bss->ssid_len == ssid_len &&
+		    memcmp(bss->ssid, ssid, ssid_len) == 0)
+			break;
+	}
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
+			   "configured BSSes", __func__);
+		free(cli);
+		return;
+	}
+
+	cli->bss = bss;
 	memcpy(&cli->un, from, sizeof(cli->un));
 	cli->unlen = fromlen;
 	cli->next = drv->cli;
 	drv->cli = cli;
 	wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
-			  cli->un.sun_path, cli->unlen);
+			  (const u8 *) cli->un.sun_path,
+			  cli->unlen - sizeof(cli->un.sun_family));
 
 	snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
-		 MAC2STR(drv->hapd->own_addr));
+		 MAC2STR(bss->bssid));
 	sendto(drv->test_socket, cmd, strlen(cmd), 0,
 	       (struct sockaddr *) from, fromlen);
 
-	if (test_driver_new_sta(drv, cli->addr, ie, ielen) < 0) {
+	if (test_driver_new_sta(drv, bss, cli->addr, ie, ielen) < 0) {
 		wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
 	}
 }
@@ -277,10 +456,10 @@
 	sta = ap_get_sta(drv->hapd, cli->addr);
 	if (sta != NULL) {
 		sta->flags &= ~WLAN_STA_ASSOC;
-		wpa_sm_event(drv->hapd, sta, WPA_DISASSOC);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 		sta->acct_terminate_cause =
 			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-		ieee802_1x_set_port_enabled(drv->hapd, sta, 0);
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 		ap_free_sta(drv->hapd, sta);
 	}
 }
@@ -292,20 +471,64 @@
 {
 	struct test_client_socket *cli;
 	if (datalen > 14) {
+		u8 *proto = data + 2 * ETH_ALEN;
 		/* Skip Ethernet header */
+		wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
+			   MACSTR " proto=%04x",
+			   MAC2STR(data), MAC2STR(data + ETH_ALEN),
+			   (proto[0] << 8) | proto[1]);
 		data += 14;
 		datalen -= 14;
 	}
 	cli = test_driver_get_cli(drv, from, fromlen);
-	if (cli)
-		ieee802_1x_receive(drv->hapd, cli->addr, data, datalen);
-	else {
+	if (cli) {
+		struct hostapd_data *hapd;
+		hapd = test_driver_get_hapd(drv, cli->bss);
+		if (hapd == NULL)
+			return;
+		ieee802_1x_receive(hapd, cli->addr, data, datalen);
+	} else {
 		wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
 			   "client");
 	}
 }
 
 
+static void test_driver_mlme(struct test_driver_data *drv,
+			     struct sockaddr_un *from, socklen_t fromlen,
+			     u8 *data, size_t datalen)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	hdr = (struct ieee80211_hdr *) data;
+
+	if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
+		struct test_client_socket *cli;
+		cli = wpa_zalloc(sizeof(*cli));
+		if (cli == NULL)
+			return;
+		wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
+			   MAC2STR(hdr->addr2));
+		memcpy(cli->addr, hdr->addr2, ETH_ALEN);
+		memcpy(&cli->un, from, sizeof(cli->un));
+		cli->unlen = fromlen;
+		cli->next = drv->cli;
+		drv->cli = cli;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
+		    data, datalen);
+	fc = le_to_host16(hdr->frame_control);
+	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
+		wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
+			   __func__);
+		return;
+	}
+	ieee802_11_mgmt(drv->hapd, data, datalen, WLAN_FC_GET_STYPE(fc), NULL);
+}
+
+
 static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
 {
 	struct test_driver_data *drv = eloop_ctx;
@@ -331,7 +554,10 @@
 	} else if (strcmp(buf, "DISASSOC") == 0) {
 		test_driver_disassoc(drv, &from, fromlen);
 	} else if (strncmp(buf, "EAPOL ", 6) == 0) {
-		test_driver_eapol(drv, &from, fromlen, buf + 6, res - 6);
+		test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
+				  res - 6);
+	} else if (strncmp(buf, "MLME ", 5) == 0) {
+		test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
 	} else {
 		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
 				  (u8 *) buf, res);
@@ -339,25 +565,40 @@
 }
 
 
-static int test_driver_set_generic_elem(void *priv,
+static int test_driver_set_generic_elem(const char *ifname, void *priv,
 					const u8 *elem, size_t elem_len)
 {
 	struct test_driver_data *drv = priv;
+	struct test_driver_bss *bss;
 
-	free(drv->ie);
-	drv->ie = malloc(elem_len);
-	if (drv->ie) {
-		memcpy(drv->ie, elem, elem_len);
-		drv->ielen = elem_len;
-		return 0;
-	} else {
-		drv->ielen = 0;
-		return -1;
+	for (bss = drv->bss; bss; bss = bss->next) {
+		if (strcmp(bss->ifname, ifname) != 0)
+			continue;
+
+		free(bss->ie);
+
+		if (elem == NULL) {
+			bss->ie = NULL;
+			bss->ielen = 0;
+			return 0;
+		}
+
+		bss->ie = malloc(elem_len);
+		if (bss->ie) {
+			memcpy(bss->ie, elem, elem_len);
+			bss->ielen = elem_len;
+			return 0;
+		} else {
+			bss->ielen = 0;
+			return -1;
+		}
 	}
+
+	return -1;
 }
 
 
-static int test_driver_sta_deauth(void *priv, u8 *addr, int reason)
+static int test_driver_sta_deauth(void *priv, const u8 *addr, int reason)
 {
 	struct test_driver_data *drv = priv;
 	struct test_client_socket *cli;
@@ -380,7 +621,7 @@
 }
 
 
-static int test_driver_sta_disassoc(void *priv, u8 *addr, int reason)
+static int test_driver_sta_disassoc(void *priv, const u8 *addr, int reason)
 {
 	struct test_driver_data *drv = priv;
 	struct test_client_socket *cli;
@@ -403,51 +644,346 @@
 }
 
 
+static struct hostapd_hw_modes *
+test_driver_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+	struct hostapd_hw_modes *modes;
+
+	*num_modes = 3;
+	*flags = 0;
+	modes = wpa_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+	if (modes == NULL)
+		return NULL;
+	modes[0].mode = HOSTAPD_MODE_IEEE80211G;
+	modes[0].num_channels = 1;
+	modes[0].num_rates = 1;
+	modes[0].channels = wpa_zalloc(sizeof(struct hostapd_channel_data));
+	modes[0].rates = wpa_zalloc(sizeof(struct hostapd_rate_data));
+	if (modes[0].channels == NULL || modes[0].rates == NULL) {
+		hostapd_free_hw_features(modes, *num_modes);
+		return NULL;
+	}
+	modes[0].channels[0].chan = 1;
+	modes[0].channels[0].freq = 2412;
+	modes[0].channels[0].flag = HOSTAPD_CHAN_W_SCAN |
+		HOSTAPD_CHAN_W_ACTIVE_SCAN;
+	modes[0].rates[0].rate = 10;
+	modes[0].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+		HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY;
+
+	modes[1].mode = HOSTAPD_MODE_IEEE80211B;
+	modes[1].num_channels = 1;
+	modes[1].num_rates = 1;
+	modes[1].channels = wpa_zalloc(sizeof(struct hostapd_channel_data));
+	modes[1].rates = wpa_zalloc(sizeof(struct hostapd_rate_data));
+	if (modes[1].channels == NULL || modes[1].rates == NULL) {
+		hostapd_free_hw_features(modes, *num_modes);
+		return NULL;
+	}
+	modes[1].channels[0].chan = 1;
+	modes[1].channels[0].freq = 2412;
+	modes[1].channels[0].flag = HOSTAPD_CHAN_W_SCAN |
+		HOSTAPD_CHAN_W_ACTIVE_SCAN;
+	modes[1].rates[0].rate = 10;
+	modes[1].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+		HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY;
+
+	modes[2].mode = HOSTAPD_MODE_IEEE80211A;
+	modes[2].num_channels = 1;
+	modes[2].num_rates = 1;
+	modes[2].channels = wpa_zalloc(sizeof(struct hostapd_channel_data));
+	modes[2].rates = wpa_zalloc(sizeof(struct hostapd_rate_data));
+	if (modes[2].channels == NULL || modes[2].rates == NULL) {
+		hostapd_free_hw_features(modes, *num_modes);
+		return NULL;
+	}
+	modes[2].channels[0].chan = 60;
+	modes[2].channels[0].freq = 5300;
+	modes[2].channels[0].flag = HOSTAPD_CHAN_W_SCAN |
+		HOSTAPD_CHAN_W_ACTIVE_SCAN;
+	modes[2].rates[0].rate = 60;
+	modes[2].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+		HOSTAPD_RATE_MANDATORY;
+
+	return modes;
+}
+
+
+static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid)
+{
+	struct test_driver_data *drv = priv;
+	struct test_driver_bss *bss;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
+		   __func__, ifname, MAC2STR(bssid));
+
+	bss = wpa_zalloc(sizeof(*bss));
+	if (bss == NULL)
+		return -1;
+
+	strncpy(bss->ifname, ifname, IFNAMSIZ);
+	memcpy(bss->bssid, bssid, ETH_ALEN);
+
+	bss->next = drv->bss;
+	drv->bss = bss;
+
+	return 0;
+}
+
+
+static int test_driver_bss_remove(void *priv, const char *ifname)
+{
+	struct test_driver_data *drv = priv;
+	struct test_driver_bss *bss, *prev;
+	struct test_client_socket *cli, *prev_c;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+
+	for (prev = NULL, bss = drv->bss; bss; prev = bss, bss = bss->next) {
+		if (strcmp(bss->ifname, ifname) != 0)
+			continue;
+
+		if (prev)
+			prev->next = bss->next;
+		else
+			drv->bss = bss->next;
+
+		for (prev_c = NULL, cli = drv->cli; cli;
+		     prev_c = cli, cli = cli->next) {
+			if (cli->bss != bss)
+				continue;
+			if (prev_c)
+				prev_c->next = cli->next;
+			else
+				drv->cli = cli->next;
+			free(cli);
+			break;
+		}
+
+		test_driver_free_bss(bss);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static int test_driver_if_add(const char *iface, void *priv,
+			      enum hostapd_driver_if_type type, char *ifname,
+			      const u8 *addr)
+{
+	wpa_printf(MSG_DEBUG, "%s(iface=%s type=%d ifname=%s)",
+		   __func__, iface, type, ifname);
+	return 0;
+}
+
+
+static int test_driver_if_update(void *priv, enum hostapd_driver_if_type type,
+				 char *ifname, const u8 *addr)
+{
+	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+	return 0;
+}
+
+
+static int test_driver_if_remove(void *priv, enum hostapd_driver_if_type type,
+				 const char *ifname, const u8 *addr)
+{
+	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+	return 0;
+}
+
+
+static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
+				      const u8 *mask)
+{
+	return 0;
+}
+
+
+static int test_driver_set_ssid(const char *ifname, void *priv, const u8 *buf,
+				int len)
+{
+	struct test_driver_data *drv = priv;
+	struct test_driver_bss *bss;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+	wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
+
+	for (bss = drv->bss; bss; bss = bss->next) {
+		if (strcmp(bss->ifname, ifname) != 0)
+			continue;
+
+		if (len < 0 || (size_t) len > sizeof(bss->ssid))
+			return -1;
+
+		memcpy(bss->ssid, buf, len);
+		bss->ssid_len = len;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static int test_driver_set_privacy(const char *ifname, void *priv, int enabled)
+{
+	struct test_driver_data *drv = priv;
+	struct test_driver_bss *bss;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s enabled=%d)",
+		   __func__, ifname, enabled);
+
+	for (bss = drv->bss; bss; bss = bss->next) {
+		if (strcmp(bss->ifname, ifname) != 0)
+			continue;
+
+		bss->privacy = enabled;
+
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static int test_driver_set_encryption(const char *iface, void *priv,
+				      const char *alg, const u8 *addr, int idx,
+				      const u8 *key, size_t key_len, int txkey)
+{
+	wpa_printf(MSG_DEBUG, "%s(iface=%s alg=%s idx=%d txkey=%d)",
+		   __func__, iface, alg, idx, txkey);
+	if (addr)
+		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
+	if (key)
+		wpa_hexdump_key(MSG_DEBUG, "   key", key, key_len);
+	return 0;
+}
+
+
+static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
+				    const char *ifname, int vlan_id)
+{
+	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
+		   __func__, MAC2STR(addr), ifname, vlan_id);
+	return 0;
+}
+
+
+static int test_driver_sta_add(const char *ifname, void *priv, const u8 *addr,
+			       u16 aid, u16 capability, u8 *supp_rates,
+			       size_t supp_rates_len, int flags)
+{
+	struct test_driver_data *drv = priv;
+	struct test_client_socket *cli;
+	struct test_driver_bss *bss;
+
+	wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
+		   "capability=0x%x flags=0x%x",
+		   __func__, ifname, MAC2STR(addr), aid, capability, flags);
+	wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
+		    supp_rates, supp_rates_len);
+
+	cli = drv->cli;
+	while (cli) {
+		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+			break;
+		cli = cli->next;
+	}
+	if (!cli) {
+		wpa_printf(MSG_DEBUG, "%s: no matching client entry",
+			   __func__);
+		return -1;
+	}
+
+	for (bss = drv->bss; bss; bss = bss->next) {
+		if (strcmp(ifname, bss->ifname) == 0)
+			break;
+	}
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: No matching interface found from "
+			   "configured BSSes", __func__);
+		return -1;
+	}
+
+	cli->bss = bss;
+
+	return 0;
+}
+
+
 static int test_driver_init(struct hostapd_data *hapd)
 {
 	struct test_driver_data *drv;
 	struct sockaddr_un addr;
 
-	drv = malloc(sizeof(struct test_driver_data));
+	drv = wpa_zalloc(sizeof(struct test_driver_data));
 	if (drv == NULL) {
 		printf("Could not allocate memory for test driver data\n");
 		return -1;
 	}
+	drv->bss = wpa_zalloc(sizeof(*drv->bss));
+	if (drv->bss == NULL) {
+		printf("Could not allocate memory for test driver BSS data\n");
+		free(drv);
+		return -1;
+	}
 
-	memset(drv, 0, sizeof(*drv));
 	drv->ops = test_driver_ops;
 	drv->hapd = hapd;
 
 	/* Generate a MAC address to help testing with multiple APs */
 	hapd->own_addr[0] = 0x02; /* locally administered */
-	sha1_prf(hapd->conf->iface, strlen(hapd->conf->iface),
+	sha1_prf((const u8 *) hapd->conf->iface, strlen(hapd->conf->iface),
 		 "hostapd test bssid generation",
-		 hapd->conf->ssid, hapd->conf->ssid_len,
+		 (const u8 *) hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len,
 		 hapd->own_addr + 1, ETH_ALEN - 1);
 
+	strncpy(drv->bss->ifname, hapd->conf->iface, IFNAMSIZ);
+	memcpy(drv->bss->bssid, hapd->own_addr, ETH_ALEN);
+
 	if (hapd->conf->test_socket) {
 		if (strlen(hapd->conf->test_socket) >= sizeof(addr.sun_path)) {
 			printf("Too long test_socket path\n");
-			free(drv);
+			test_driver_free_priv(drv);
 			return -1;
 		}
+		if (strncmp(hapd->conf->test_socket, "DIR:", 4) == 0) {
+			size_t len = strlen(hapd->conf->test_socket) + 30;
+			drv->socket_dir = strdup(hapd->conf->test_socket + 4);
+			drv->own_socket_path = malloc(len);
+			if (drv->own_socket_path) {
+				snprintf(drv->own_socket_path, len,
+					 "%s/AP-" MACSTR,
+					 hapd->conf->test_socket + 4,
+					 MAC2STR(hapd->own_addr));
+			}
+		} else {
+			drv->own_socket_path = strdup(hapd->conf->test_socket);
+		}
+		if (drv->own_socket_path == NULL) {
+			test_driver_free_priv(drv);
+			return -1;
+		}
+
 		drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
 		if (drv->test_socket < 0) {
 			perror("socket(PF_UNIX)");
-			free(drv);
+			test_driver_free_priv(drv);
 			return -1;
 		}
 
 		memset(&addr, 0, sizeof(addr));
 		addr.sun_family = AF_UNIX;
-		strncpy(addr.sun_path, hapd->conf->test_socket,
+		strncpy(addr.sun_path, drv->own_socket_path,
 			sizeof(addr.sun_path));
 		if (bind(drv->test_socket, (struct sockaddr *) &addr,
 			 sizeof(addr)) < 0) {
 			perror("bind(PF_UNIX)");
 			close(drv->test_socket);
-			unlink(hapd->conf->test_socket);
-			free(drv);
+			unlink(drv->own_socket_path);
+			test_driver_free_priv(drv);
 			return -1;
 		}
 		eloop_register_read_sock(drv->test_socket,
@@ -475,13 +1011,18 @@
 	if (drv->test_socket >= 0) {
 		eloop_unregister_read_sock(drv->test_socket);
 		close(drv->test_socket);
-		unlink(drv->hapd->conf->test_socket);
+		unlink(drv->own_socket_path);
 	}
 
 	drv->hapd->driver = NULL;
 
-	free(drv->ie);
-	free(drv);
+	/* There should be only one BSS remaining at this point. */
+	if (drv->bss == NULL)
+		wpa_printf(MSG_ERROR, "%s: drv->bss == NULL", __func__);
+	else if (drv->bss->next)
+		wpa_printf(MSG_ERROR, "%s: drv->bss->next != NULL", __func__);
+
+	test_driver_free_priv(drv);
 }
 
 
@@ -490,9 +1031,22 @@
 	.init = test_driver_init,
 	.deinit = test_driver_deinit,
 	.send_eapol = test_driver_send_eapol,
+	.send_mgmt_frame = test_driver_send_mgmt_frame,
 	.set_generic_elem = test_driver_set_generic_elem,
 	.sta_deauth = test_driver_sta_deauth,
 	.sta_disassoc = test_driver_sta_disassoc,
+	.get_hw_feature_data = test_driver_get_hw_feature_data,
+	.bss_add = test_driver_bss_add,
+	.bss_remove = test_driver_bss_remove,
+	.if_add = test_driver_if_add,
+	.if_update = test_driver_if_update,
+	.if_remove = test_driver_if_remove,
+	.valid_bss_mask = test_driver_valid_bss_mask,
+	.set_ssid = test_driver_set_ssid,
+	.set_privacy = test_driver_set_privacy,
+	.set_encryption = test_driver_set_encryption,
+	.set_sta_vlan = test_driver_set_sta_vlan,
+	.sta_add = test_driver_sta_add,
 };
 
 
Index: radius_client.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/radius_client.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/radius_client.c -L contrib/hostapd/radius_client.c -u -r1.2 -r1.3
--- contrib/hostapd/radius_client.c
+++ contrib/hostapd/radius_client.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RADIUS client
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / RADIUS client
+ * Copyright (c) 2002-2005, 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
@@ -13,19 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <errno.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
 
 #include "hostapd.h"
 #include "radius.h"
@@ -60,11 +47,11 @@
 			    * for the same STA. */
 	struct radius_msg *msg;
 	RadiusType msg_type;
-	time_t first_try;
-	time_t next_try;
+	os_time_t first_try;
+	os_time_t next_try;
 	int attempts;
 	int next_wait;
-	struct timeval last_attempt;
+	struct os_time last_attempt;
 
 	u8 *shared_secret;
 	size_t shared_secret_len;
@@ -110,8 +97,8 @@
 static void radius_client_msg_free(struct radius_msg_list *req)
 {
 	radius_msg_free(req->msg);
-	free(req->msg);
-	free(req);
+	os_free(req->msg);
+	os_free(req);
 }
 
 
@@ -135,9 +122,8 @@
 		num = &radius->num_auth_handlers;
 	}
 
-	newh = (struct radius_rx_handler *)
-		realloc(*handlers,
-			(*num + 1) * sizeof(struct radius_rx_handler));
+	newh = os_realloc(*handlers,
+			  (*num + 1) * sizeof(struct radius_rx_handler));
 	if (newh == NULL)
 		return -1;
 
@@ -173,7 +159,8 @@
 
 
 static int radius_client_retransmit(struct radius_client_data *radius,
-				    struct radius_msg_list *entry, time_t now)
+				    struct radius_msg_list *entry,
+				    os_time_t now)
 {
 	struct hostapd_radius_servers *conf = radius->conf;
 	int s;
@@ -203,7 +190,7 @@
 		       HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
 		       entry->msg->hdr->identifier);
 
-	gettimeofday(&entry->last_attempt, NULL);
+	os_get_time(&entry->last_attempt);
 	if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
 		radius_client_handle_send_error(radius, s, entry->msg_type);
 
@@ -225,7 +212,8 @@
 {
 	struct radius_client_data *radius = eloop_ctx;
 	struct hostapd_radius_servers *conf = radius->conf;
-	time_t now, first;
+	struct os_time now;
+	os_time_t first;
 	struct radius_msg_list *entry, *prev, *tmp;
 	int auth_failover = 0, acct_failover = 0;
 	char abuf[50];
@@ -234,13 +222,13 @@
 	if (!entry)
 		return;
 
-	time(&now);
+	os_get_time(&now);
 	first = 0;
 
 	prev = NULL;
 	while (entry) {
-		if (now >= entry->next_try &&
-		    radius_client_retransmit(radius, entry, now)) {
+		if (now.sec >= entry->next_try &&
+		    radius_client_retransmit(radius, entry, now.sec)) {
 			if (prev)
 				prev->next = entry->next;
 			else
@@ -269,14 +257,14 @@
 	}
 
 	if (radius->msgs) {
-		if (first < now)
-			first = now;
-		eloop_register_timeout(first - now, 0,
+		if (first < now.sec)
+			first = now.sec;
+		eloop_register_timeout(first - now.sec, 0,
 				       radius_client_timer, radius, NULL);
 		hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 			       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
 			       "retransmit in %ld seconds",
-			       (long int) (first - now));
+			       (long int) (first - now.sec));
 	}
 
 	if (auth_failover && conf->num_auth_servers > 1) {
@@ -332,7 +320,8 @@
 
 static void radius_client_update_timeout(struct radius_client_data *radius)
 {
-	time_t now, first;
+	struct os_time now;
+	os_time_t first;
 	struct radius_msg_list *entry;
 
 	eloop_cancel_timeout(radius_client_timer, radius, NULL);
@@ -347,21 +336,21 @@
 			first = entry->next_try;
 	}
 
-	time(&now);
-	if (first < now)
-		first = now;
-	eloop_register_timeout(first - now, 0, radius_client_timer, radius,
+	os_get_time(&now);
+	if (first < now.sec)
+		first = now.sec;
+	eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
 			       NULL);
 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
-		       " %ld seconds\n", (long int) (first - now));
+		       " %ld seconds\n", (long int) (first - now.sec));
 }
 
 
 static void radius_client_list_add(struct radius_client_data *radius,
 				   struct radius_msg *msg,
 				   RadiusType msg_type, u8 *shared_secret,
-				   size_t shared_secret_len, u8 *addr)
+				   size_t shared_secret_len, const u8 *addr)
 {
 	struct radius_msg_list *entry, *prev;
 
@@ -369,29 +358,28 @@
 		/* No point in adding entries to retransmit queue since event
 		 * loop has already been terminated. */
 		radius_msg_free(msg);
-		free(msg);
+		os_free(msg);
 		return;
 	}
 
-	entry = malloc(sizeof(*entry));
+	entry = wpa_zalloc(sizeof(*entry));
 	if (entry == NULL) {
 		printf("Failed to add RADIUS packet into retransmit list\n");
 		radius_msg_free(msg);
-		free(msg);
+		os_free(msg);
 		return;
 	}
 
-	memset(entry, 0, sizeof(*entry));
 	if (addr)
-		memcpy(entry->addr, addr, ETH_ALEN);
+		os_memcpy(entry->addr, addr, ETH_ALEN);
 	entry->msg = msg;
 	entry->msg_type = msg_type;
 	entry->shared_secret = shared_secret;
 	entry->shared_secret_len = shared_secret_len;
-	time(&entry->first_try);
+	os_get_time(&entry->last_attempt);
+	entry->first_try = entry->last_attempt.sec;
 	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
 	entry->attempts = 1;
-	gettimeofday(&entry->last_attempt, NULL);
 	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
 	entry->next = radius->msgs;
 	radius->msgs = entry;
@@ -415,7 +403,7 @@
 
 
 static void radius_client_list_del(struct radius_client_data *radius,
-				   RadiusType msg_type, u8 *addr)
+				   RadiusType msg_type, const u8 *addr)
 {
 	struct radius_msg_list *entry, *prev, *tmp;
 
@@ -426,7 +414,7 @@
 	prev = NULL;
 	while (entry) {
 		if (entry->msg_type == msg_type &&
-		    memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
 			if (prev)
 				prev->next = entry->next;
 			else
@@ -448,7 +436,8 @@
 
 
 int radius_client_send(struct radius_client_data *radius,
-		       struct radius_msg *msg, RadiusType msg_type, u8 *addr)
+		       struct radius_msg *msg, RadiusType msg_type,
+		       const u8 *addr)
 {
 	struct hostapd_radius_servers *conf = radius->conf;
 	u8 *shared_secret;
@@ -499,13 +488,13 @@
 	struct radius_client_data *radius = eloop_ctx;
 	struct hostapd_radius_servers *conf = radius->conf;
 	RadiusType msg_type = (RadiusType) sock_ctx;
-	int len, i, roundtrip;
+	int len, roundtrip;
 	unsigned char buf[3000];
 	struct radius_msg *msg;
 	struct radius_rx_handler *handlers;
-	size_t num_handlers;
+	size_t num_handlers, i;
 	struct radius_msg_list *req, *prev_req;
-	struct timeval tv;
+	struct os_time now;
 	struct hostapd_radius_server *rconf;
 	int invalid_authenticator = 0;
 
@@ -584,9 +573,9 @@
 		goto fail;
 	}
 
-	gettimeofday(&tv, NULL);
-	roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
-		(tv.tv_usec - req->last_attempt.tv_usec) / 10000;
+	os_get_time(&now);
+	roundtrip = (now.sec - req->last_attempt.sec) * 100 +
+		(now.usec - req->last_attempt.usec) / 10000;
 	hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_DEBUG,
 		       "Received RADIUS packet matched with a pending "
@@ -609,7 +598,7 @@
 		switch (res) {
 		case RADIUS_RX_PROCESSED:
 			radius_msg_free(msg);
-			free(msg);
+			os_free(msg);
 			/* continue */
 		case RADIUS_RX_QUEUED:
 			radius_client_msg_free(req);
@@ -637,13 +626,13 @@
 
  fail:
 	radius_msg_free(msg);
-	free(msg);
+	os_free(msg);
 }
 
 
 u8 radius_client_get_id(struct radius_client_data *radius)
 {
-	struct radius_msg_list *entry, *prev, *remove;
+	struct radius_msg_list *entry, *prev, *_remove;
 	u8 id = radius->next_radius_identifier++;
 
 	/* remove entries with matching id from retransmit list to avoid
@@ -661,36 +650,69 @@
 				prev->next = entry->next;
 			else
 				radius->msgs = entry->next;
-			remove = entry;
-		} else
-			remove = NULL;
-		prev = entry;
+			_remove = entry;
+		} else {
+			_remove = NULL;
+			prev = entry;
+		}
 		entry = entry->next;
 
-		if (remove)
-			radius_client_msg_free(remove);
+		if (_remove)
+			radius_client_msg_free(_remove);
 	}
 
 	return id;
 }
 
 
-void radius_client_flush(struct radius_client_data *radius)
+void radius_client_flush(struct radius_client_data *radius, int only_auth)
 {
-	struct radius_msg_list *entry, *prev;
+	struct radius_msg_list *entry, *prev, *tmp;
 
 	if (!radius)
 		return;
 
-	eloop_cancel_timeout(radius_client_timer, radius, NULL);
-
+	prev = NULL;
 	entry = radius->msgs;
-	radius->msgs = NULL;
-	radius->num_msgs = 0;
+
 	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		radius_client_msg_free(prev);
+		if (!only_auth || entry->msg_type == RADIUS_AUTH) {
+			if (prev)
+				prev->next = entry->next;
+			else
+				radius->msgs = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			radius_client_msg_free(tmp);
+			radius->num_msgs--;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+
+	if (radius->msgs == NULL)
+		eloop_cancel_timeout(radius_client_timer, radius, NULL);
+}
+
+
+void radius_client_update_acct_msgs(struct radius_client_data *radius,
+				    u8 *shared_secret,
+				    size_t shared_secret_len)
+{
+	struct radius_msg_list *entry;
+
+	if (!radius)
+		return;
+
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if (entry->msg_type == RADIUS_ACCT) {
+			entry->shared_secret = shared_secret;
+			entry->shared_secret_len = shared_secret_len;
+			radius_msg_finish_acct(entry->msg, shared_secret,
+					       shared_secret_len);
+		}
 	}
 }
 
@@ -709,6 +731,7 @@
 	socklen_t addrlen;
 	char abuf[50];
 	int sel_sock;
+	struct radius_msg_list *entry;
 
 	hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
 		       HOSTAPD_LEVEL_INFO,
@@ -718,37 +741,43 @@
 		       nserv->port);
 
 	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
-	    memcmp(nserv->shared_secret, oserv->shared_secret,
-		   nserv->shared_secret_len) != 0) {
-		/* Pending RADIUS packets used different shared
-		 * secret, so they would need to be modified. Could
-		 * update all message authenticators and
-		 * User-Passwords, etc. and retry with new server. For
-		 * now, just drop all pending packets. */
-		radius_client_flush(radius);
-	} else {
-		/* Reset retry counters for the new server */
-		struct radius_msg_list *entry;
-		entry = radius->msgs;
-		while (entry) {
-			entry->next_try = entry->first_try +
-				RADIUS_CLIENT_FIRST_WAIT;
-			entry->attempts = 0;
-			entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
-			entry = entry->next;
-		}
-		if (radius->msgs) {
-			eloop_cancel_timeout(radius_client_timer, radius,
-					     NULL);
-			eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
-					       radius_client_timer, radius,
-					       NULL);
+	    os_memcmp(nserv->shared_secret, oserv->shared_secret,
+		      nserv->shared_secret_len) != 0) {
+		/* Pending RADIUS packets used different shared secret, so
+		 * they need to be modified. Update accounting message
+		 * authenticators here. Authentication messages are removed
+		 * since they would require more changes and the new RADIUS
+		 * server may not be prepared to receive them anyway due to
+		 * missing state information. Client will likely retry
+		 * authentication, so this should not be an issue. */
+		if (auth)
+			radius_client_flush(radius, 1);
+		else {
+			radius_client_update_acct_msgs(
+				radius, nserv->shared_secret,
+				nserv->shared_secret_len);
 		}
 	}
 
+	/* Reset retry counters for the new server */
+	for (entry = radius->msgs; entry; entry = entry->next) {
+		if ((auth && entry->msg_type != RADIUS_AUTH) ||
+		    (!auth && entry->msg_type != RADIUS_ACCT))
+			continue;
+		entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+		entry->attempts = 0;
+		entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+	}
+
+	if (radius->msgs) {
+		eloop_cancel_timeout(radius_client_timer, radius, NULL);
+		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
+				       radius_client_timer, radius, NULL);
+	}
+
 	switch (nserv->addr.af) {
 	case AF_INET:
-		memset(&serv, 0, sizeof(serv));
+		os_memset(&serv, 0, sizeof(serv));
 		serv.sin_family = AF_INET;
 		serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
 		serv.sin_port = htons(nserv->port);
@@ -758,10 +787,10 @@
 		break;
 #ifdef CONFIG_IPV6
 	case AF_INET6:
-		memset(&serv6, 0, sizeof(serv6));
+		os_memset(&serv6, 0, sizeof(serv6));
 		serv6.sin6_family = AF_INET6;
-		memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
-		       sizeof(struct in6_addr));
+		os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
+			  sizeof(struct in6_addr));
 		serv6.sin6_port = htons(nserv->port);
 		addr = (struct sockaddr *) &serv6;
 		addrlen = sizeof(serv6);
@@ -878,6 +907,17 @@
 	else
 		ok++;
 
+#ifdef CONFIG_IPV6
+	radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (radius->acct_serv_sock6 < 0)
+		perror("socket[PF_INET6,SOCK_DGRAM]");
+	else
+		ok++;
+#endif /* CONFIG_IPV6 */
+
+	if (ok == 0)
+		return -1;
+
 	radius_change_server(radius, conf->acct_server, NULL,
 			     radius->acct_serv_sock, radius->acct_serv_sock6,
 			     0);
@@ -911,11 +951,10 @@
 {
 	struct radius_client_data *radius;
 
-	radius = malloc(sizeof(struct radius_client_data));
+	radius = wpa_zalloc(sizeof(struct radius_client_data));
 	if (radius == NULL)
 		return NULL;
 
-	memset(radius, 0, sizeof(struct radius_client_data));
 	radius->ctx = ctx;
 	radius->conf = conf;
 	radius->auth_serv_sock = radius->acct_serv_sock =
@@ -946,12 +985,17 @@
 	if (!radius)
 		return;
 
+	if (radius->auth_serv_sock >= 0)
+		eloop_unregister_read_sock(radius->auth_serv_sock);
+	if (radius->acct_serv_sock >= 0)
+		eloop_unregister_read_sock(radius->acct_serv_sock);
+
 	eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
 
-	radius_client_flush(radius);
-	free(radius->auth_handlers);
-	free(radius->acct_handlers);
-	free(radius);
+	radius_client_flush(radius, 0);
+	os_free(radius->auth_handlers);
+	os_free(radius->acct_handlers);
+	os_free(radius);
 }
 
 
@@ -963,7 +1007,7 @@
 	entry = radius->msgs;
 	while (entry) {
 		if (entry->msg_type == RADIUS_AUTH &&
-		    memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+		    os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
 			hostapd_logger(radius->ctx, addr,
 				       HOSTAPD_MODULE_RADIUS,
 				       HOSTAPD_LEVEL_DEBUG,
@@ -1003,37 +1047,37 @@
 		}
 	}
 
-	return snprintf(buf, buflen,
-			"radiusAuthServerIndex=%d\n"
-			"radiusAuthServerAddress=%s\n"
-			"radiusAuthClientServerPortNumber=%d\n"
-			"radiusAuthClientRoundTripTime=%d\n"
-			"radiusAuthClientAccessRequests=%u\n"
-			"radiusAuthClientAccessRetransmissions=%u\n"
-			"radiusAuthClientAccessAccepts=%u\n"
-			"radiusAuthClientAccessRejects=%u\n"
-			"radiusAuthClientAccessChallenges=%u\n"
-			"radiusAuthClientMalformedAccessResponses=%u\n"
-			"radiusAuthClientBadAuthenticators=%u\n"
-			"radiusAuthClientPendingRequests=%u\n"
-			"radiusAuthClientTimeouts=%u\n"
-			"radiusAuthClientUnknownTypes=%u\n"
-			"radiusAuthClientPacketsDropped=%u\n",
-			serv->index,
-			hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
-			serv->port,
-			serv->round_trip_time,
-			serv->requests,
-			serv->retransmissions,
-			serv->access_accepts,
-			serv->access_rejects,
-			serv->access_challenges,
-			serv->malformed_responses,
-			serv->bad_authenticators,
-			pending,
-			serv->timeouts,
-			serv->unknown_types,
-			serv->packets_dropped);
+	return os_snprintf(buf, buflen,
+			   "radiusAuthServerIndex=%d\n"
+			   "radiusAuthServerAddress=%s\n"
+			   "radiusAuthClientServerPortNumber=%d\n"
+			   "radiusAuthClientRoundTripTime=%d\n"
+			   "radiusAuthClientAccessRequests=%u\n"
+			   "radiusAuthClientAccessRetransmissions=%u\n"
+			   "radiusAuthClientAccessAccepts=%u\n"
+			   "radiusAuthClientAccessRejects=%u\n"
+			   "radiusAuthClientAccessChallenges=%u\n"
+			   "radiusAuthClientMalformedAccessResponses=%u\n"
+			   "radiusAuthClientBadAuthenticators=%u\n"
+			   "radiusAuthClientPendingRequests=%u\n"
+			   "radiusAuthClientTimeouts=%u\n"
+			   "radiusAuthClientUnknownTypes=%u\n"
+			   "radiusAuthClientPacketsDropped=%u\n",
+			   serv->index,
+			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+			   serv->port,
+			   serv->round_trip_time,
+			   serv->requests,
+			   serv->retransmissions,
+			   serv->access_accepts,
+			   serv->access_rejects,
+			   serv->access_challenges,
+			   serv->malformed_responses,
+			   serv->bad_authenticators,
+			   pending,
+			   serv->timeouts,
+			   serv->unknown_types,
+			   serv->packets_dropped);
 }
 
 
@@ -1053,33 +1097,33 @@
 		}
 	}
 
-	return snprintf(buf, buflen,
-			"radiusAccServerIndex=%d\n"
-			"radiusAccServerAddress=%s\n"
-			"radiusAccClientServerPortNumber=%d\n"
-			"radiusAccClientRoundTripTime=%d\n"
-			"radiusAccClientRequests=%u\n"
-			"radiusAccClientRetransmissions=%u\n"
-			"radiusAccClientResponses=%u\n"
-			"radiusAccClientMalformedResponses=%u\n"
-			"radiusAccClientBadAuthenticators=%u\n"
-			"radiusAccClientPendingRequests=%u\n"
-			"radiusAccClientTimeouts=%u\n"
-			"radiusAccClientUnknownTypes=%u\n"
-			"radiusAccClientPacketsDropped=%u\n",
-			serv->index,
-			hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
-			serv->port,
-			serv->round_trip_time,
-			serv->requests,
-			serv->retransmissions,
-			serv->responses,
-			serv->malformed_responses,
-			serv->bad_authenticators,
-			pending,
-			serv->timeouts,
-			serv->unknown_types,
-			serv->packets_dropped);
+	return os_snprintf(buf, buflen,
+			   "radiusAccServerIndex=%d\n"
+			   "radiusAccServerAddress=%s\n"
+			   "radiusAccClientServerPortNumber=%d\n"
+			   "radiusAccClientRoundTripTime=%d\n"
+			   "radiusAccClientRequests=%u\n"
+			   "radiusAccClientRetransmissions=%u\n"
+			   "radiusAccClientResponses=%u\n"
+			   "radiusAccClientMalformedResponses=%u\n"
+			   "radiusAccClientBadAuthenticators=%u\n"
+			   "radiusAccClientPendingRequests=%u\n"
+			   "radiusAccClientTimeouts=%u\n"
+			   "radiusAccClientUnknownTypes=%u\n"
+			   "radiusAccClientPacketsDropped=%u\n",
+			   serv->index,
+			   hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+			   serv->port,
+			   serv->round_trip_time,
+			   serv->requests,
+			   serv->retransmissions,
+			   serv->responses,
+			   serv->malformed_responses,
+			   serv->bad_authenticators,
+			   pending,
+			   serv->timeouts,
+			   serv->unknown_types,
+			   serv->packets_dropped);
 }
 
 
@@ -1113,3 +1157,48 @@
 
 	return count;
 }
+
+
+static int radius_servers_diff(struct hostapd_radius_server *nserv,
+			       struct hostapd_radius_server *oserv,
+			       int num)
+{
+	int i;
+
+	for (i = 0; i < num; i++) {
+		if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
+		    nserv[i].port != oserv[i].port ||
+		    nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
+		    memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
+			   nserv[i].shared_secret_len) != 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+struct radius_client_data *
+radius_client_reconfig(struct radius_client_data *old, void *ctx,
+		       struct hostapd_radius_servers *oldconf,
+		       struct hostapd_radius_servers *newconf)
+{
+	radius_client_flush(old, 0);
+
+	if (newconf->retry_primary_interval !=
+	    oldconf->retry_primary_interval ||
+	    newconf->num_auth_servers != oldconf->num_auth_servers ||
+	    newconf->num_acct_servers != oldconf->num_acct_servers ||
+	    radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
+				newconf->num_auth_servers) ||
+	    radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
+				newconf->num_acct_servers)) {
+		hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Reconfiguring RADIUS client");
+		radius_client_deinit(old);
+		return radius_client_init(ctx, newconf);
+	}
+
+	return old;
+}
Index: eap.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap.h -L contrib/hostapd/eap.h -u -r1.2 -r1.3
--- contrib/hostapd/eap.h
+++ contrib/hostapd/eap.h
@@ -1,18 +1,38 @@
-/* $FreeBSD: src/contrib/hostapd/eap.h,v 1.2.2.1 2006/03/24 01:42:33 sam Exp $ */
+/* $FreeBSD: src/contrib/hostapd/eap.h,v 1.4 2007/07/09 16:20:41 sam Exp $ */
+
+/*
+ * hostapd / EAP Standalone Authenticator state machine (RFC 4137)
+ * Copyright (c) 2004-2005, 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_H
 #define EAP_H
 
 #include "defs.h"
 #include "eap_defs.h"
+#include "eap_methods.h"
 
 struct eap_sm;
 
 #define EAP_MAX_METHODS 8
 struct eap_user {
-	u8 methods[EAP_MAX_METHODS];
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_MAX_METHODS];
 	u8 *password;
 	size_t password_len;
+	int password_hash; /* whether password is hashed with
+			    * nt_password_hash() */
 	int phase2;
 	int force_version;
 };
@@ -48,10 +68,11 @@
 			    struct eap_config *eap_conf);
 void eap_sm_deinit(struct eap_sm *sm);
 int eap_sm_step(struct eap_sm *sm);
-u8 eap_get_type(const char *name);
 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
 			 size_t eapRespDataLen);
 void eap_sm_notify_cached(struct eap_sm *sm);
+void eap_sm_pending_cb(struct eap_sm *sm);
+int eap_sm_method_pending(struct eap_sm *sm);
 
 #else /* EAP_SERVER */
 
@@ -71,10 +92,6 @@
 	return 0;
 }
 
-static inline u8 eap_get_type(const char *name)
-{
-	return EAP_TYPE_NONE;
-}
 
 static inline void eap_set_eapRespData(struct eap_sm *sm,
 				       const u8 *eapRespData,
@@ -86,6 +103,15 @@
 {
 }
 
+static inline void eap_sm_pending_cb(struct eap_sm *sm)
+{
+}
+
+static inline int eap_sm_method_pending(struct eap_sm *sm)
+{
+	return 0;
+}
+
 #endif /* EAP_SERVER */
 
 #endif /* EAP_H */
--- /dev/null
+++ contrib/hostapd/mlme.c
@@ -0,0 +1,176 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003-2006, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "wpa.h"
+#include "mlme.h"
+
+
+static const char * mlme_auth_alg_str(int alg)
+{
+	switch (alg) {
+	case WLAN_AUTH_OPEN:
+		return "OPEN_SYSTEM";
+	case WLAN_AUTH_SHARED_KEY:
+		return "SHARED_KEY";
+	}
+
+	return "unknown";
+}
+
+
+/**
+ * mlme_authenticate_indication - Report the establishment of an authentication
+ * relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * authentication relationship with a specific peer MAC entity that
+ * resulted from an authentication procedure that was initiated by
+ * that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
+ */
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
+		       MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_deauthenticate_indication - Report the invalidation of an
+ * authentication relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Deauthentication frame
+ *
+ * MLME calls this function as a result of the invalidation of an
+ * authentication relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_associate_indication - Report the establishment of an association with
+ * a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * association with a specific peer MAC entity that resulted from an
+ * association procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-ASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_reassociate_indication - Report the establishment of an reassociation
+ * with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * reassociation with a specific peer MAC entity that resulted from a
+ * reassociation procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ *
+ * sta->previous_ap contains the "Current AP" information from ReassocReq.
+ */
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-REASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_disassociate_indication - Report disassociation with a specific peer
+ * MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Disassociation frame
+ *
+ * MLME calls this function as a result of the invalidation of an association
+ * relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr)
+{
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-MichaelMICFailure.indication(" MACSTR ")",
+		       MAC2STR(addr));
+}
+
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DELETEKEYS.request(" MACSTR ")",
+		       MAC2STR(sta->addr));
+
+	if (sta->wpa_sm)
+		wpa_remove_ptk(sta->wpa_sm);
+}
Index: rc4.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/rc4.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/rc4.c -L contrib/hostapd/rc4.c -u -r1.2 -r1.3
--- contrib/hostapd/rc4.c
+++ contrib/hostapd/rc4.c
@@ -1,6 +1,6 @@
 /*
  * RC4 stream cipher
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2005, 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,7 +12,8 @@
  * See README and COPYING for more details.
  */
 
-#include <stdio.h>
+#include "includes.h"
+
 #include "common.h"
 #include "rc4.h"
 
@@ -35,7 +36,7 @@
 {
 	u32 i, j, k;
 	u8 S[256], *pos;
-	int kpos;
+	size_t kpos;
 
 	/* Setup RC4 state */
 	for (i = 0; i < 256; i++)
--- /dev/null
+++ contrib/hostapd/hlr_auc_gw.c
@@ -0,0 +1,588 @@
+/*
+ * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+ * Copyright (c) 2005-2006, 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.
+ *
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface to HLR/AuC. It is expected to be replaced with an
+ * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
+ * a local implementation of SIM triplet and AKA authentication data generator.
+ *
+ * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
+ * to and external program, e.g., this hlr_auc_gw. This interface uses simple
+ * text-based format:
+ *
+ * EAP-SIM / GSM triplet query/response:
+ * SIM-REQ-AUTH <IMSI> <max_chal>
+ * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
+ * SIM-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS query/response:
+ * AKA-REQ-AUTH <IMSI>
+ * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+ * AKA-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS AUTS (re-synchronization):
+ * AKA-AUTS <IMSI> <AUTS> <RAND>
+ *
+ * IMSI and max_chal are sent as an ASCII string,
+ * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
+ *
+ * The example implementation here reads GSM authentication triplets from a
+ * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
+ * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
+ * for real life authentication, but it is useful both as an example
+ * implementation and for EAP-SIM testing.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "common.h"
+#include "milenage.h"
+
+static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
+static const char *socket_path;
+static const char *default_gsm_triplet_file = "hostapd.sim_db";
+static const char *gsm_triplet_file;
+static int serv_sock = -1;
+
+/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
+struct milenage_parameters {
+	struct milenage_parameters *next;
+	char imsi[20];
+	u8 ki[16];
+	u8 opc[16];
+	u8 amf[2];
+	u8 sqn[6];
+};
+
+static struct milenage_parameters *milenage_db = NULL;
+
+#define EAP_SIM_MAX_CHAL 3
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+
+
+static int open_socket(const char *path)
+{
+	struct sockaddr_un addr;
+	int s;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	strncpy(addr.sun_path, path, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("bind(PF_UNIX)");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+
+
+static int read_milenage(const char *fname)
+{
+	FILE *f;
+	char buf[200], *pos, *pos2;
+	struct milenage_parameters *m = NULL;
+	int line, ret = 0;
+
+	if (fname == NULL)
+		return -1;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open Milenage data file '%s'\n", fname);
+		return -1;
+	}
+
+	line = 0;
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		/* Parse IMSI Ki OPc AMF SQN */
+		buf[sizeof(buf) - 1] = '\0';
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		pos = buf;
+		if (*pos == '\0')
+			continue;
+
+		m = os_zalloc(sizeof(*m));
+		if (m == NULL) {
+			ret = -1;
+			break;
+		}
+
+		/* IMSI */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) >= sizeof(m->imsi)) {
+			printf("%s:%d - Too long IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		strncpy(m->imsi, pos, sizeof(m->imsi));
+		pos = pos2 + 1;
+
+		/* Ki */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
+			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* OPc */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
+			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* AMF */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* SQN */
+		pos2 = strchr(pos, ' ');
+		if (pos2)
+			*pos2 = '\0';
+		if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
+			printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		m->next = milenage_db;
+		milenage_db = m;
+		m = NULL;
+	}
+	free(m);
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static struct milenage_parameters * get_milenage(const char *imsi)
+{
+	struct milenage_parameters *m = milenage_db;
+
+	while (m) {
+		if (strcmp(m->imsi, imsi) == 0)
+			break;
+		m = m->next;
+	}
+
+	return m;
+}
+
+
+static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	FILE *f;
+	int count, max_chal, ret;
+	char buf[80], *pos;
+	char reply[1000], *rpos, *rend;
+	struct milenage_parameters *m;
+
+	reply[0] = '\0';
+
+	pos = strchr(imsi, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		max_chal = atoi(pos);
+		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+			max_chal = EAP_SIM_MAX_CHAL;
+	} else
+		max_chal = EAP_SIM_MAX_CHAL;
+
+	rend = &reply[sizeof(reply)];
+	rpos = reply;
+	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
+	if (ret < 0 || ret >= rend - rpos)
+		return;
+	rpos += ret;
+
+	m = get_milenage(imsi);
+	if (m) {
+		u8 _rand[16], sres[4], kc[8];
+		for (count = 0; count < max_chal; count++) {
+			os_get_random(_rand, 16);
+			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+			*rpos++ = ' ';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
+		}
+		*rpos = '\0';
+		goto send;
+	}
+
+	/* TODO: could read triplet file into memory during startup and then
+	 * have pointer for IMSI to allow more than three first entries to be
+	 * used. */
+	f = fopen(gsm_triplet_file, "r");
+	if (f == NULL) {
+		printf("Could not open GSM triplet file '%s'\n",
+		       gsm_triplet_file);
+		ret = snprintf(rpos, rend - rpos, " FAILURE");
+		if (ret < 0 || ret >= rend - rpos)
+			return;
+		rpos += ret;
+		goto send;
+	}
+
+	count = 0;
+	while (count < max_chal && fgets(buf, sizeof(buf), f)) {
+		/* Parse IMSI:Kc:SRES:RAND and match IMSI with identity. */
+		buf[sizeof(buf) - 1] = '\0';
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		if (pos - buf < 60 || pos[0] == '#')
+			continue;
+
+		pos = strchr(buf, ':');
+		if (pos == NULL)
+			continue;
+		*pos++ = '\0';
+		if (strcmp(buf, imsi) != 0)
+			continue;
+
+		ret = snprintf(rpos, rend - rpos, " %s", pos);
+		if (ret < 0 || ret >= rend - rpos) {
+			fclose(f);
+			return;
+		}
+		rpos += ret;
+		count++;
+	}
+
+	fclose(f);
+
+	if (count == 0) {
+		printf("No GSM triplets found for %s\n", imsi);
+		ret = snprintf(rpos, rend - rpos, " FAILURE");
+		if (ret < 0 || ret >= rend - rpos)
+			return;
+		rpos += ret;
+	}
+
+send:
+	printf("Send: %s\n", reply);
+	if (sendto(s, reply, rpos - reply, 0,
+		   (struct sockaddr *) from, fromlen) < 0)
+		perror("send");
+}
+
+
+static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
+	char reply[1000], *pos, *end;
+	u8 _rand[EAP_AKA_RAND_LEN];
+	u8 autn[EAP_AKA_AUTN_LEN];
+	u8 ik[EAP_AKA_IK_LEN];
+	u8 ck[EAP_AKA_CK_LEN];
+	u8 res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	int ret;
+	struct milenage_parameters *m;
+
+	m = get_milenage(imsi);
+	if (m) {
+		os_get_random(_rand, EAP_AKA_RAND_LEN);
+		res_len = EAP_AKA_RES_MAX_LEN;
+		inc_byte_array(m->sqn, 6);
+		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+		       m->sqn[0], m->sqn[1], m->sqn[2],
+		       m->sqn[3], m->sqn[4], m->sqn[5]);
+		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
+				  autn, ik, ck, res, &res_len);
+	} else {
+		printf("Unknown IMSI: %s\n", imsi);
+#ifdef AKA_USE_FIXED_TEST_VALUES
+		printf("Using fixed test values for AKA\n");
+		memset(_rand, '0', EAP_AKA_RAND_LEN);
+		memset(autn, '1', EAP_AKA_AUTN_LEN);
+		memset(ik, '3', EAP_AKA_IK_LEN);
+		memset(ck, '4', EAP_AKA_CK_LEN);
+		memset(res, '2', EAP_AKA_RES_MAX_LEN);
+		res_len = EAP_AKA_RES_MAX_LEN;
+#else /* AKA_USE_FIXED_TEST_VALUES */
+		return;
+#endif /* AKA_USE_FIXED_TEST_VALUES */
+	}
+
+	pos = reply;
+	end = &reply[sizeof(reply)];
+	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+
+	printf("Send: %s\n", reply);
+
+	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
+		   fromlen) < 0)
+		perror("send");
+}
+
+
+static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
+		     char *imsi)
+{
+	char *auts, *rand;
+	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
+	struct milenage_parameters *m;
+
+	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
+
+	auts = strchr(imsi, ' ');
+	if (auts == NULL)
+		return;
+	*auts++ = '\0';
+
+	rand = strchr(auts, ' ');
+	if (rand == NULL)
+		return;
+	*rand++ = '\0';
+
+	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, rand);
+	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
+	    hexstr2bin(rand, _rand, EAP_AKA_RAND_LEN)) {
+		printf("Could not parse AUTS/RAND\n");
+		return;
+	}
+
+	m = get_milenage(imsi);
+	if (m == NULL) {
+		printf("Unknown IMSI: %s\n", imsi);
+		return;
+	}
+
+	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
+		printf("AKA-AUTS: Incorrect MAC-S\n");
+	} else {
+		memcpy(m->sqn, sqn, 6);
+		printf("AKA-AUTS: Re-synchronized: "
+		       "SQN=%02x%02x%02x%02x%02x%02x\n",
+		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+	}
+}
+
+
+static int process(int s)
+{
+	char buf[1000];
+	struct sockaddr_un from;
+	socklen_t fromlen;
+	ssize_t res;
+
+	fromlen = sizeof(from);
+	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+		       &fromlen);
+	if (res < 0) {
+		perror("recvfrom");
+		return -1;
+	}
+
+	if (res == 0)
+		return 0;
+
+	if ((size_t) res >= sizeof(buf))
+		res = sizeof(buf) - 1;
+	buf[res] = '\0';
+
+	printf("Received: %s\n", buf);
+
+	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
+		sim_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
+		aka_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
+		aka_auts(s, &from, fromlen, buf + 9);
+	else
+		printf("Unknown request: %s\n", buf);
+
+	return 0;
+}
+
+
+static void cleanup(void)
+{
+	struct milenage_parameters *m, *prev;
+
+	m = milenage_db;
+	while (m) {
+		prev = m;
+		m = m->next;
+		free(prev);
+	}
+
+	close(serv_sock);
+	unlink(socket_path);
+}
+
+
+static void handle_term(int sig)
+{
+	printf("Signal %d - terminate\n", sig);
+	exit(0);
+}
+
+
+static void usage(void)
+{
+	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
+	       "database/authenticator\n"
+	       "Copyright (c) 2005-2006, Jouni Malinen <j at w1.fi>\n"
+	       "\n"
+	       "usage:\n"
+	       "hlr_auc_gw [-h] [-s<socket path>] [-g<triplet file>] "
+	       "[-m<milenage file>]\n"
+	       "\n"
+	       "options:\n"
+	       "  -h = show this usage help\n"
+	       "  -s<socket path> = path for UNIX domain socket\n"
+	       "                    (default: %s)\n"
+	       "  -g<triplet file> = path for GSM authentication triplets\n"
+	       "                     (default: %s)\n"
+	       "  -m<milenage file> = path for Milenage keys\n",
+	       default_socket_path, default_gsm_triplet_file);
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c;
+	char *milenage_file = NULL;
+
+	socket_path = default_socket_path;
+	gsm_triplet_file = default_gsm_triplet_file;
+
+	for (;;) {
+		c = getopt(argc, argv, "g:hm:s:");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'g':
+			gsm_triplet_file = optarg;
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'm':
+			milenage_file = optarg;
+			break;
+		case 's':
+			socket_path = optarg;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	if (milenage_file && read_milenage(milenage_file) < 0)
+		return -1;
+
+	serv_sock = open_socket(socket_path);
+	if (serv_sock < 0)
+		return -1;
+
+	printf("Listening for requests on %s\n", socket_path);
+
+	atexit(cleanup);
+	signal(SIGTERM, handle_term);
+	signal(SIGINT, handle_term);
+
+	for (;;)
+		process(serv_sock);
+
+	return 0;
+}
Index: eap_tlv.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_tlv.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_tlv.c -L contrib/hostapd/eap_tlv.c -u -r1.1.1.1 -r1.2
--- contrib/hostapd/eap_tlv.c
+++ contrib/hostapd/eap_tlv.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -45,10 +42,9 @@
 {
 	struct eap_tlv_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = CONTINUE;
 
 	return data;
@@ -103,12 +99,11 @@
 {
 	struct eap_hdr *resp;
 	u8 *pos;
-	size_t len;
 
 	resp = (struct eap_hdr *) respData;
 	pos = (u8 *) (resp + 1);
 	if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_TLV ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	    (ntohs(resp->length)) > respDataLen) {
 		wpa_printf(MSG_INFO, "EAP-TLV: Invalid frame");
 		return TRUE;
 	}
@@ -123,14 +118,12 @@
 	struct eap_tlv_data *data = priv;
 	struct eap_hdr *resp;
 	u8 *pos;
-	int len;
 	size_t left;
 	u8 *result_tlv = NULL;
 	size_t result_tlv_len = 0;
 	int tlv_type, mandatory, tlv_len;
 
 	resp = (struct eap_hdr *) respData;
-	len = ntohs(resp->length);
 	pos = (u8 *) (resp + 1);
 
 	/* Parse TLVs */
@@ -145,7 +138,7 @@
 		tlv_len = ((int) pos[2] << 8) | pos[3];
 		pos += 4;
 		left -= 4;
-		if (tlv_len > left) {
+		if ((size_t) tlv_len > left) {
 			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
 				   "(tlv_len=%d left=%lu)", tlv_len,
 				   (unsigned long) left);
@@ -234,15 +227,26 @@
 }
 
 
-const struct eap_method eap_method_tlv =
+int eap_server_tlv_register(void)
 {
-	.method = EAP_TYPE_TLV,
-	.name = "TLV",
-	.init = eap_tlv_init,
-	.reset = eap_tlv_reset,
-	.buildReq = eap_tlv_buildReq,
-	.check = eap_tlv_check,
-	.process = eap_tlv_process,
-	.isDone = eap_tlv_isDone,
-	.isSuccess = eap_tlv_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_TLV, "TLV");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tlv_init;
+	eap->reset = eap_tlv_reset;
+	eap->buildReq = eap_tlv_buildReq;
+	eap->check = eap_tlv_check;
+	eap->process = eap_tlv_process;
+	eap->isDone = eap_tlv_isDone;
+	eap->isSuccess = eap_tlv_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: config.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/config.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/config.h -L contrib/hostapd/config.h -u -r1.2 -r1.3
--- contrib/hostapd/config.h
+++ contrib/hostapd/config.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2006, 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 CONFIG_H
 #define CONFIG_H
 
@@ -7,6 +21,68 @@
 
 struct hostapd_radius_servers;
 
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+	u8 idx;
+	u8 *key[NUM_WEP_KEYS];
+	size_t len[NUM_WEP_KEYS];
+	int keys_set;
+	size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+	SECURITY_PLAINTEXT = 0,
+	SECURITY_STATIC_WEP = 1,
+	SECURITY_IEEE_802_1X = 2,
+	SECURITY_WPA_PSK = 3,
+	SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+	char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+	size_t ssid_len;
+	int ssid_set;
+
+	char vlan[IFNAMSIZ + 1];
+	secpolicy security_policy;
+
+	struct hostapd_wpa_psk *wpa_psk;
+	char *wpa_passphrase;
+	char *wpa_psk_file;
+
+	struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+	int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+	struct hostapd_wep_keys **dyn_vlan_keys;
+	size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+	struct hostapd_vlan *next;
+	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+	char ifname[IFNAMSIZ + 1];
+	int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 	0x1
+#define DVLAN_CLEAN_VLAN	0x2
+#define DVLAN_CLEAN_VLAN_PORT	0x4
+#define DVLAN_CLEAN_WLAN_PORT	0x8
+	int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
 #define PMK_LEN 32
 struct hostapd_wpa_psk {
 	struct hostapd_wpa_psk *next;
@@ -20,19 +96,46 @@
 	struct hostapd_eap_user *next;
 	u8 *identity;
 	size_t identity_len;
-	u8 methods[EAP_USER_MAX_METHODS];
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_USER_MAX_METHODS];
 	u8 *password;
 	size_t password_len;
 	int phase2;
 	int force_version;
+	unsigned int wildcard_prefix:1;
+	unsigned int password_hash:1; /* whether password is hashed with
+				       * nt_password_hash() */
 };
 
-struct hostapd_config {
+
+#define NUM_TX_QUEUES 8
+
+struct hostapd_tx_queue_params {
+	int aifs;
+	int cwmin;
+	int cwmax;
+	int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+	int configured;
+};
+
+struct hostapd_wme_ac_params {
+	int cwmin;
+	int cwmax;
+	int aifs;
+	int txopLimit; /* in units of 32us */
+	int admission_control_mandatory;
+};
+
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
 	char iface[IFNAMSIZ + 1];
 	char bridge[IFNAMSIZ + 1];
 
-	const struct driver_ops *driver;
-
 	enum {
 		HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
 		HOSTAPD_LEVEL_DEBUG = 1,
@@ -47,6 +150,7 @@
 #define HOSTAPD_MODULE_WPA BIT(3)
 #define HOSTAPD_MODULE_DRIVER BIT(4)
 #define HOSTAPD_MODULE_IAPP BIT(5)
+#define HOSTAPD_MODULE_MLME BIT(6)
 	unsigned int logger_syslog; /* module bitfield */
 	unsigned int logger_stdout; /* module bitfield */
 
@@ -56,7 +160,12 @@
 	       HOSTAPD_DEBUG_EXCESSIVE = 4 } debug; /* debug verbosity level */
 	char *dump_log_name; /* file name for state dump (SIGUSR1) */
 
+	int max_num_sta; /* maximum number of STAs in station table */
+
+	int dtim_period;
+
 	int ieee802_1x; /* use IEEE 802.1X */
+	int eapol_version;
 	int eap_server; /* Use internal EAP server instead of external
 			 * RADIUS server */
 	struct hostapd_eap_user *eap_user;
@@ -65,19 +174,17 @@
 	char *nas_identifier;
 	struct hostapd_radius_servers *radius;
 
-#define HOSTAPD_SSID_LEN 32
-	char ssid[HOSTAPD_SSID_LEN + 1];
-	size_t ssid_len;
-	int ssid_set;
+	struct hostapd_ssid ssid;
+
 	char *eap_req_id_text; /* optional displayable message sent with
 				* EAP Request-Identity */
 	size_t eap_req_id_text_len;
 	int eapol_key_index_workaround;
-	int eapol_version;
 
 	size_t default_wep_key_len;
 	int individual_wep_key_len;
 	int wep_rekeying_period;
+	int broadcast_key_idx_min, broadcast_key_idx_max;
 	int eap_reauth_period;
 
 	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
@@ -105,9 +212,6 @@
 #define HOSTAPD_WPA_VERSION_WPA BIT(0)
 #define HOSTAPD_WPA_VERSION_WPA2 BIT(1)
 	int wpa;
-	struct hostapd_wpa_psk *wpa_psk;
-	char *wpa_passphrase;
-	char *wpa_psk_file;
 #define WPA_KEY_MGMT_IEEE8021X BIT(0)
 #define WPA_KEY_MGMT_PSK BIT(1)
 	int wpa_key_mgmt;
@@ -116,6 +220,14 @@
 #define WPA_CIPHER_WEP104 BIT(2)
 #define WPA_CIPHER_TKIP BIT(3)
 #define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+	enum {
+		NO_IEEE80211W = 0,
+		IEEE80211W_OPTIONAL = 1,
+		IEEE80211W_REQUIRED = 2
+	} ieee80211w;
+#endif /* CONFIG_IEEE80211W */
 	int wpa_pairwise;
 	int wpa_group;
 	int wpa_group_rekey;
@@ -123,6 +235,7 @@
 	int wpa_gmk_rekey;
 	int rsn_preauth;
 	char *rsn_preauth_interfaces;
+	int peerkey;
 
 	char *ctrl_interface; /* directory for UNIX domain sockets */
 	gid_t ctrl_interface_gid;
@@ -144,17 +257,106 @@
 				 * address instead of individual address
 				 * (for driver_wired.c).
 				 */
+
+	int ap_max_inactivity;
+	int ignore_broadcast_ssid;
+
+	int wme_enabled;
+
+	struct hostapd_vlan *vlan, *vlan_tail;
+
+	macaddr bssid;
+};
+
+
+typedef enum {
+	HOSTAPD_MODE_IEEE80211B,
+	HOSTAPD_MODE_IEEE80211G,
+	HOSTAPD_MODE_IEEE80211A,
+	NUM_HOSTAPD_MODES
+} hostapd_hw_mode;
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+	struct hostapd_bss_config *bss, *last_bss;
+	struct hostapd_radius_servers *radius;
+	size_t num_bss;
+
+	u16 beacon_int;
+	int rts_threshold;
+	int fragm_threshold;
+	u8 send_probe_response;
+	u8 channel;
+	hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+	enum {
+		LONG_PREAMBLE = 0,
+		SHORT_PREAMBLE = 1
+	} preamble;
+	enum {
+		CTS_PROTECTION_AUTOMATIC = 0,
+		CTS_PROTECTION_FORCE_ENABLED = 1,
+		CTS_PROTECTION_FORCE_DISABLED = 2,
+		CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
+	} cts_protection_type;
+
+	int *supported_rates;
+	int *basic_rates;
+
+	const struct driver_ops *driver;
+
+	int passive_scan_interval; /* seconds, 0 = disabled */
+	int passive_scan_listen; /* usec */
+	int passive_scan_mode;
+	int ap_table_max_size;
+	int ap_table_expiration_time;
+
+	char country[3]; /* first two octets: country code as described in
+			  * ISO/IEC 3166-1. Third octet:
+			  * ' ' (ascii 32): all environments
+			  * 'O': Outdoor environemnt only
+			  * 'I': Indoor environment only
+			  */
+
+	int ieee80211d;
+	unsigned int ieee80211h; /* Enable/Disable 80211h */
+
+	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+	/*
+	 * WME AC parameters, in same order as 802.1D, i.e.
+	 * 0 = BE (best effort)
+	 * 1 = BK (background)
+	 * 2 = VI (video)
+	 * 3 = VO (voice)
+	 */
+	struct hostapd_wme_ac_params wme_ac_params[4];
+
+	enum {
+		INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
+		INTERNAL_BRIDGE_DISABLED = 0,
+		INTERNAL_BRIDGE_ENABLED = 1
+	} bridge_packets;
 };
 
 
+int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_mac_comp_empty(const void *a);
 struct hostapd_config * hostapd_config_read(const char *fname);
 void hostapd_config_free(struct hostapd_config *conf);
-int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr);
-const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
-			   const u8 *prev_psk);
-int hostapd_setup_wpa_psk(struct hostapd_config *conf);
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+			struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+					int vlan_id);
 const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
 		     size_t identity_len, int phase2);
 
 #endif /* CONFIG_H */
Index: eap_psk_common.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_psk_common.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_psk_common.c -L contrib/hostapd/eap_psk_common.c -u -r1.1 -r1.2
--- contrib/hostapd/eap_psk_common.c
+++ contrib/hostapd/eap_psk_common.c
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, 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,12 +12,11 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "aes_wrap.h"
+#include "eap_defs.h"
 #include "eap_psk_common.h"
 
 #define aes_block_size 16
@@ -25,9 +24,9 @@
 
 void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
 {
-	memset(ak, 0, aes_block_size);
+	os_memset(ak, 0, aes_block_size);
 	aes_128_encrypt_block(psk, ak, ak);
-	memcpy(kdk, ak, aes_block_size);
+	os_memcpy(kdk, ak, aes_block_size);
 	ak[aes_block_size - 1] ^= 0x01;
 	kdk[aes_block_size - 1] ^= 0x02;
 	aes_128_encrypt_block(psk, ak, ak);
@@ -35,7 +34,8 @@
 }
 
 
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+			 u8 *emsk)
 {
 	u8 hash[aes_block_size];
 	u8 counter = 1;
@@ -48,10 +48,17 @@
 	hash[aes_block_size - 1] ^= counter;
 	counter++;
 
-	for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
+	for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) {
 		hash[aes_block_size - 1] ^= counter;
 		aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
 		hash[aes_block_size - 1] ^= counter;
 		counter++;
 	}
+
+	for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) {
+		hash[aes_block_size - 1] ^= counter;
+		aes_128_encrypt_block(kdk, hash, &emsk[i * aes_block_size]);
+		hash[aes_block_size - 1] ^= counter;
+		counter++;
+	}
 }
--- /dev/null
+++ contrib/hostapd/eap_gpsk_common.c
@@ -0,0 +1,441 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-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 "aes_wrap.h"
+#include "crypto.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "eap_gpsk_common.h"
+
+
+/**
+ * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: 1 if ciphersuite is support, or 0 if not
+ */
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
+{
+	if (vendor == EAP_GPSK_VENDOR_IETF &&
+	    specifier == EAP_GPSK_CIPHER_AES)
+		return 1;
+#ifdef EAP_GPSK_SHA256
+	if (vendor == EAP_GPSK_VENDOR_IETF &&
+	    specifier == EAP_GPSK_CIPHER_SHA256)
+		return 1;
+#endif /* EAP_GPSK_SHA256 */
+	return 0;
+}
+
+
+static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
+			 const u8 *data /* Z */, size_t data_len,
+			 u8 *buf, size_t len /* X */)
+{
+	u8 *opos;
+	size_t i, n, hashlen, left, clen;
+	u8 ibuf[2], hash[SHA1_MAC_LEN];
+	const u8 *addr[3];
+	size_t vlen[3];
+
+	hashlen = SHA1_MAC_LEN;
+	/* M_i = Hash-Function (i || Y || Z); */
+	addr[0] = ibuf;
+	vlen[0] = sizeof(ibuf);
+	addr[1] = psk;
+	vlen[1] = psk_len;
+	addr[2] = data;
+	vlen[2] = data_len;
+
+	opos = buf;
+	left = len;
+	n = (len + hashlen - 1) / hashlen;
+	for (i = 1; i <= n; i++) {
+		WPA_PUT_BE16(ibuf, i);
+		sha1_vector(3, addr, vlen, hash);
+		clen = left > hashlen ? hashlen : left;
+		os_memcpy(opos, hash, clen);
+		opos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+
+
+static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
+				    const u8 *seed, size_t seed_len,
+				    u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+				    u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_AES 16
+#define EAP_GPSK_PK_LEN_AES 16
+	u8 zero_string[1], mk[32], *pos, *data;
+	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
+		   EAP_GPSK_PK_LEN_AES];
+	size_t data_len;
+
+	/*
+	 * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+	 *            (= seed)
+	 * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
+	 * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+	 * MSK = GKDF-160 (MK, inputString)[0..63]
+	 * EMSK = GKDF-160 (MK, inputString)[64..127]
+	 * SK = GKDF-160 (MK, inputString)[128..143]
+	 * PK = GKDF-160 (MK, inputString)[144..159]
+	 * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+	 *               inputString)
+	 * Hash-Function = SHA-1 (see [RFC3174])
+	 * hashlen = 20 octets (160 bits)
+	 */
+
+	os_memset(zero_string, 0, sizeof(zero_string));
+
+	data_len = 2 + psk_len + 6 + seed_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	WPA_PUT_BE16(pos, psk_len);
+	pos += 2;
+	os_memcpy(pos, psk, psk_len);
+	pos += psk_len;
+	WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+	pos += 3;
+	WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_AES); /* CSuite/Specifier */
+	pos += 3;
+	os_memcpy(pos, seed, seed_len); /* inputString */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (AES)",
+			data, data_len);
+
+	if (eap_gpsk_gkdf(zero_string, sizeof(zero_string), data, data_len,
+			  mk, sizeof(mk)) < 0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+	if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
+			  kdf_out, sizeof(kdf_out)) < 0)
+		return -1;
+
+	pos = kdf_out;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	pos += EAP_EMSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, EAP_GPSK_SK_LEN_AES);
+	os_memcpy(sk, pos, EAP_GPSK_SK_LEN_AES);
+	*sk_len = EAP_GPSK_SK_LEN_AES;
+	pos += EAP_GPSK_SK_LEN_AES;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, EAP_GPSK_PK_LEN_AES);
+	os_memcpy(pk, pos, EAP_GPSK_PK_LEN_AES);
+	*pk_len = EAP_GPSK_PK_LEN_AES;
+
+	return 0;
+}
+
+
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, size_t psk_len,
+				const u8 *data /* Z */, size_t data_len,
+				u8 *buf, size_t len /* X */)
+{
+	u8 *opos;
+	size_t i, n, hashlen, left, clen;
+	u8 ibuf[2], hash[SHA256_MAC_LEN];
+	const u8 *addr[3];
+	size_t vlen[3];
+
+	hashlen = SHA256_MAC_LEN;
+	/* M_i = Hash-Function (i || Y || Z); */
+	addr[0] = ibuf;
+	vlen[0] = sizeof(ibuf);
+	addr[1] = psk;
+	vlen[1] = psk_len;
+	addr[2] = data;
+	vlen[2] = data_len;
+
+	opos = buf;
+	left = len;
+	n = (len + hashlen - 1) / hashlen;
+	for (i = 1; i <= n; i++) {
+		WPA_PUT_BE16(ibuf, i);
+		sha256_vector(3, addr, vlen, hash);
+		clen = left > hashlen ? hashlen : left;
+		os_memcpy(opos, hash, clen);
+		opos += clen;
+		left -= clen;
+	}
+
+	return 0;
+}
+
+
+static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
+				       const u8 *seed, size_t seed_len,
+				       u8 *msk, u8 *emsk,
+				       u8 *sk, size_t *sk_len,
+				       u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
+#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
+	u8 mk[SHA256_MAC_LEN], zero_string[1], *pos, *data;
+	u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
+		   EAP_GPSK_PK_LEN_SHA256];
+	size_t data_len;
+
+	/*
+	 * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+	 *            (= seed)
+	 * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
+	 * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+	 * MSK = GKDF-192 (MK, inputString)[0..63]
+	 * EMSK = GKDF-192 (MK, inputString)[64..127]
+	 * SK = GKDF-192 (MK, inputString)[128..159]
+	 * PK = GKDF-192 (MK, inputString)[160..191]
+	 * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+	 *               inputString)
+	 * Hash-Function = SHA256 (see [RFC4634])
+	 * hashlen = 32 octets (256 bits)
+	 */
+
+	os_memset(zero_string, 0, sizeof(zero_string));
+
+	data_len = 2 + psk_len + 6 + seed_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	WPA_PUT_BE16(pos, psk_len);
+	pos += 2;
+	os_memcpy(pos, psk, psk_len);
+	pos += psk_len;
+	WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+	pos += 3;
+	WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_SHA256); /* CSuite/Specifier */
+	pos += 3;
+	os_memcpy(pos, seed, seed_len); /* inputString */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (SHA256)",
+			data, data_len);
+
+	if (eap_gpsk_gkdf_sha256(zero_string, sizeof(zero_string),
+				 data, data_len, mk, sizeof(mk)) < 0) {
+		os_free(data);
+		return -1;
+	}
+	os_free(data);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+	if (eap_gpsk_gkdf_sha256(mk, sizeof(mk), seed, seed_len,
+				 kdf_out, sizeof(kdf_out)) < 0)
+		return -1;
+
+	pos = kdf_out;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+	os_memcpy(msk, pos, EAP_MSK_LEN);
+	pos += EAP_MSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
+	pos += EAP_EMSK_LEN;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK",
+			pos, EAP_GPSK_SK_LEN_SHA256);
+	os_memcpy(sk, pos, EAP_GPSK_SK_LEN_SHA256);
+	*sk_len = EAP_GPSK_SK_LEN_AES;
+	pos += EAP_GPSK_SK_LEN_AES;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK",
+			pos, EAP_GPSK_PK_LEN_SHA256);
+	os_memcpy(pk, pos, EAP_GPSK_PK_LEN_SHA256);
+	*pk_len = EAP_GPSK_PK_LEN_SHA256;
+
+	return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+/**
+ * eap_gpsk_derive_keys - Derive EAP-GPSK keys
+ * @psk: Pre-shared key (at least 16 bytes if AES is used)
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_client: 32-byte RAND_Client
+ * @rand_server: 32-byte RAND_Server
+ * @id_client: ID_Client
+ * @id_client_len: Length of ID_Client
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
+ * @sk_len: Buffer for returning length of SK
+ * @pk: Buffer for SK (at least EAP_GPSK_MAX_PK_LEN bytes)
+ * @pk_len: Buffer for returning length of PK
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+			 int specifier,
+			 const u8 *rand_client, const u8 *rand_server,
+			 const u8 *id_client, size_t id_client_len,
+			 const u8 *id_server, size_t id_server_len,
+			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+			 u8 *pk, size_t *pk_len)
+{
+	u8 *seed, *pos;
+	size_t seed_len;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
+		   vendor, specifier);
+
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return -1;
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+	/* Seed = RAND_Client || ID_Client || RAND_Server || ID_Server */
+	seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_client_len;
+	seed = os_malloc(seed_len);
+	if (seed == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+			   "for key derivation");
+		return -1;
+	}
+
+	pos = seed;
+	os_memcpy(pos, rand_client, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	os_memcpy(pos, id_client, id_client_len);
+	pos += id_client_len;
+	os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+	pos += EAP_GPSK_RAND_LEN;
+	os_memcpy(pos, id_server, id_server_len);
+	pos += id_server_len;
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+					       msk, emsk, sk, sk_len,
+					       pk, pk_len);
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+						  msk, emsk, sk, sk_len,
+						  pk, pk_len);
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+			   "key derivation", vendor, specifier);
+		ret = -1;
+		break;
+	}
+
+	os_free(seed);
+
+	return ret;
+}
+
+
+/**
+ * eap_gpsk_mic_len - Get the length of the MIC
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: MIC length in bytes
+ */
+size_t eap_gpsk_mic_len(int vendor, int specifier)
+{
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return 0;
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		return 16;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		return 32;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		return 0;
+	}
+}
+
+
+static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
+				    const u8 *data, size_t len, u8 *mic)
+{
+	if (sk_len != 16) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %d for "
+			   "AES-CMAC MIC", sk_len);
+		return -1;
+	}
+
+	return omac1_aes_128(sk, data, len, mic);
+}
+
+
+/**
+ * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
+ * @sk: Session key SK from eap_gpsk_derive_keys()
+ * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @data: Input data to MIC
+ * @len: Input data length in bytes
+ * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+			 int specifier, const u8 *data, size_t len, u8 *mic)
+{
+	int ret;
+
+	if (vendor != EAP_GPSK_VENDOR_IETF)
+		return -1;
+
+	switch (specifier) {
+	case EAP_GPSK_CIPHER_AES:
+		ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
+		break;
+#ifdef EAP_GPSK_SHA256
+	case EAP_GPSK_CIPHER_SHA256:
+		hmac_sha256(sk, sk_len, data, len, mic);
+		ret = 0;
+		break;
+#endif /* EAP_GPSK_SHA256 */
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+			   "MIC computation", vendor, specifier);
+		ret = -1;
+		break;
+	}
+
+	return ret;
+}
Index: wpa.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/wpa.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/wpa.c -L contrib/hostapd/wpa.c -u -r1.2 -r1.3
--- contrib/hostapd/wpa.c
+++ contrib/hostapd/wpa.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / WPA Authenticator
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * Copyright (c) 2004-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
@@ -12,43 +11,197 @@
  *
  * See README and COPYING for more details.
  *
- * $FreeBSD: src/contrib/hostapd/wpa.c,v 1.3.2.1 2006/03/24 01:42:34 sam Exp $
+ * $FreeBSD: src/contrib/hostapd/wpa.c,v 1.5 2007/07/09 16:20:41 sam Exp $
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
 
 #include "hostapd.h"
 #include "eapol_sm.h"
 #include "wpa.h"
-#include "driver.h"
+#include "wme.h"
 #include "sha1.h"
 #include "md5.h"
 #include "rc4.h"
 #include "aes_wrap.h"
-#include "ieee802_1x.h"
-#include "ieee802_11.h"
+#include "crypto.h"
 #include "eloop.h"
-#include "sta_info.h"
-#include "l2_packet.h"
-#include "accounting.h"
-#include "hostap_common.h"
+#include "ieee802_11.h"
+#include "pmksa_cache.h"
+#include "state_machine.h"
+
+#define STATE_MACHINE_DATA struct wpa_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "WPA"
+#define STATE_MACHINE_ADDR sm->addr
+
+
+#define RSN_NUM_REPLAY_COUNTERS_1 0
+#define RSN_NUM_REPLAY_COUNTERS_2 1
+#define RSN_NUM_REPLAY_COUNTERS_4 2
+#define RSN_NUM_REPLAY_COUNTERS_16 3
+
+
+struct wpa_group;
+
+struct wpa_stsl_negotiation {
+	struct wpa_stsl_negotiation *next;
+	u8 initiator[ETH_ALEN];
+	u8 peer[ETH_ALEN];
+};
+
+
+struct wpa_state_machine {
+	struct wpa_authenticator *wpa_auth;
+	struct wpa_group *group;
+
+	u8 addr[ETH_ALEN];
+
+	enum {
+		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
+		WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
+		WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
+		WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
+		WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
+	} wpa_ptk_state;
+
+	enum {
+		WPA_PTK_GROUP_IDLE = 0,
+		WPA_PTK_GROUP_REKEYNEGOTIATING,
+		WPA_PTK_GROUP_REKEYESTABLISHED,
+		WPA_PTK_GROUP_KEYERROR
+	} wpa_ptk_group_state;
+
+	Boolean Init;
+	Boolean DeauthenticationRequest;
+	Boolean AuthenticationRequest;
+	Boolean ReAuthenticationRequest;
+	Boolean Disconnect;
+	int TimeoutCtr;
+	int GTimeoutCtr;
+	Boolean TimeoutEvt;
+	Boolean EAPOLKeyReceived;
+	Boolean EAPOLKeyPairwise;
+	Boolean EAPOLKeyRequest;
+	Boolean MICVerified;
+	Boolean GUpdateStationKeys;
+	u8 ANonce[WPA_NONCE_LEN];
+	u8 SNonce[WPA_NONCE_LEN];
+	u8 PMK[WPA_PMK_LEN];
+	struct wpa_ptk PTK;
+	Boolean PTK_valid;
+	Boolean pairwise_set;
+	int keycount;
+	Boolean Pair;
+	u8 key_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	Boolean key_replay_counter_valid;
+	Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
+	Boolean PTKRequest; /* not in IEEE 802.11i state machine */
+	Boolean has_GTK;
+
+	u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
+	size_t last_rx_eapol_key_len;
+
+	unsigned int changed:1;
+	unsigned int in_step_loop:1;
+	unsigned int pending_deinit:1;
+	unsigned int started:1;
+	unsigned int sta_counted:1;
+	unsigned int mgmt_frame_prot:1;
+
+	u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int req_replay_counter_used;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	enum {
+		WPA_VERSION_NO_WPA = 0 /* WPA not used */,
+		WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
+		WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
+	} wpa;
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	u32 dot11RSNAStatsTKIPLocalMICFailures;
+	u32 dot11RSNAStatsTKIPRemoteMICFailures;
+};
+
+
+/* per group key state machine data */
+struct wpa_group {
+	struct wpa_group *next;
+	int vlan_id;
+
+	Boolean GInit;
+	int GNoStations;
+	int GKeyDoneStations;
+	Boolean GTKReKey;
+	int GTK_len;
+	int GN, GM;
+	Boolean GTKAuthenticator;
+	u8 Counter[WPA_NONCE_LEN];
+
+	enum {
+		WPA_GROUP_GTK_INIT = 0,
+		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+	} wpa_group_state;
+
+	u8 GMK[WPA_GMK_LEN];
+	u8 GTK[2][WPA_GTK_MAX_LEN];
+	u8 GNonce[WPA_NONCE_LEN];
+	Boolean changed;
+#ifdef CONFIG_IEEE80211W
+	u8 DGTK[WPA_DGTK_LEN];
+	u8 IGTK[2][WPA_IGTK_LEN];
+#endif /* CONFIG_IEEE80211W */
+};
+
+
+/* per authenticator data */
+struct wpa_authenticator {
+	struct wpa_group *group;
+
+	unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
+	u8 dot11RSNAAuthenticationSuiteSelected[4];
+	u8 dot11RSNAPairwiseCipherSelected[4];
+	u8 dot11RSNAGroupCipherSelected[4];
+	u8 dot11RSNAPMKIDUsed[PMKID_LEN];
+	u8 dot11RSNAAuthenticationSuiteRequested[4]; /* FIX: update */
+	u8 dot11RSNAPairwiseCipherRequested[4]; /* FIX: update */
+	u8 dot11RSNAGroupCipherRequested[4]; /* FIX: update */
+	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
+	unsigned int dot11RSNA4WayHandshakeFailures;
+
+	struct wpa_stsl_negotiation *stsl_negotiations;
+
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	u8 addr[ETH_ALEN];
+
+	struct rsn_pmksa_cache *pmksa;
+};
 
 
 static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpa_sm_step(struct wpa_state_machine *sm);
 static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
 static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
-static void wpa_group_sm_step(struct hostapd_data *hapd);
-static void pmksa_cache_free(struct hostapd_data *hapd);
-static struct rsn_pmksa_cache * pmksa_cache_get(struct hostapd_data *hapd,
-						u8 *spa, u8 *pmkid);
-
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group);
+static int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+			   struct wpa_stsl_negotiation *neg);
+static void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+			     struct wpa_state_machine *sm, int key_info,
+			     const u8 *key_rsc, const u8 *nonce,
+			     const u8 *kde, size_t kde_len,
+			     int keyidx, int encr, int force_version);
 
 /* Default timeouts are 100 ms, but this seems to be a bit too fast for most
  * WPA Supplicants, so use a bit longer timeout. */
@@ -61,7 +214,6 @@
 static const int dot11RSNAConfigPMKLifetime = 43200;
 static const int dot11RSNAConfigPMKReauthThreshold = 70;
 static const int dot11RSNAConfigSATimeout = 60;
-static const int pmksa_cache_max_entries = 1024;
 
 
 static const int WPA_SELECTOR_LEN = 4;
@@ -75,6 +227,9 @@
 static const u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
 static const u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
 static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
+#ifdef CONFIG_IEEE80211W
+static const u8 RSN_CIPHER_SUITE_AES_128_CMAC[] = { 0x00, 0x0f, 0xac, 6 };
+#endif /* CONFIG_IEEE80211W */
 
 static const int RSN_SELECTOR_LEN = 4;
 static const u16 RSN_VERSION = 1;
@@ -88,12 +243,50 @@
 static const u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
 
 /* EAPOL-Key Key Data Encapsulation
- * GroupKey and STAKey require encryption, otherwise, encryption is optional.
+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
  */
 static const u8 RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 };
+#if 0
 static const u8 RSN_KEY_DATA_STAKEY[] = { 0x00, 0x0f, 0xac, 2 };
+#endif
 static const u8 RSN_KEY_DATA_MAC_ADDR[] = { 0x00, 0x0f, 0xac, 3 };
 static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
+#ifdef CONFIG_PEERKEY
+static const u8 RSN_KEY_DATA_SMK[] = { 0x00, 0x0f, 0xac, 5 };
+static const u8 RSN_KEY_DATA_NONCE[] = { 0x00, 0x0f, 0xac, 6 };
+static const u8 RSN_KEY_DATA_LIFETIME[] = { 0x00, 0x0f, 0xac, 7 };
+static const u8 RSN_KEY_DATA_ERROR[] = { 0x00, 0x0f, 0xac, 8 };
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+/* FIX: IEEE 802.11w/D1.0 is using subtypes 5 and 6 for these, but they were
+ * already taken by 802.11ma (PeerKey). Need to update the values here once
+ * IEEE 802.11w fixes these. */
+static const u8 RSN_KEY_DATA_DHV[] = { 0x00, 0x0f, 0xac, 9 };
+static const u8 RSN_KEY_DATA_IGTK[] = { 0x00, 0x0f, 0xac, 10 };
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_PEERKEY
+enum {
+	STK_MUI_4WAY_STA_AP = 1,
+	STK_MUI_4WAY_STAT_STA = 2,
+	STK_MUI_GTK = 3,
+	STK_MUI_SMK = 4
+};
+
+enum {
+	STK_ERR_STA_NR = 1,
+	STK_ERR_STA_NRSN = 2,
+	STK_ERR_CPHR_NS = 3,
+	STK_ERR_NO_STSL = 4
+};
+#endif /* CONFIG_PEERKEY */
+
+#define GENERIC_INFO_ELEM 0xdd
+#define RSN_INFO_ELEM 0x30
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
 
 /* WPA IE version 1
  * 00-50-f2:1 (OUI:OUI type)
@@ -115,7 +308,7 @@
 	u8 oui[3];
 	u8 oui_type;
 	u16 version;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
 
 
 /* RSN IE version 1
@@ -131,16 +324,171 @@
  * RSN Capabilities (2 octets, little endian) (default: 0)
  * PMKID Count (2 octets) (default: 0)
  * PMKID List (16 * n octets)
+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
  */
 
 struct rsn_ie_hdr {
 	u8 elem_id; /* WLAN_EID_RSN */
 	u8 len;
 	u16 version;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+
+struct rsn_error_kde {
+	u16 mui;
+	u16 error_type;
+} STRUCT_PACKED;
+
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_dhv_kde {
+	u8 dhv[WPA_DHV_LEN];
+} STRUCT_PACKED;
+
+struct wpa_igtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 igtk[WPA_IGTK_LEN];
+} STRUCT_PACKED;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+static inline void wpa_auth_mic_failure_report(
+	struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	if (wpa_auth->cb.mic_failure_report)
+		wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
+static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, wpa_eapol_variable var,
+				      int value)
+{
+	if (wpa_auth->cb.set_eapol)
+		wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+}
+
+
+static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
+				     const u8 *addr, wpa_eapol_variable var)
+{
+	if (wpa_auth->cb.get_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+}
+
+
+static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
+					  const u8 *addr, const u8 *prev_psk)
+{
+	if (wpa_auth->cb.get_psk == NULL)
+		return NULL;
+	return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
+}
+
+
+static inline int wpa_auth_get_pmk(struct wpa_authenticator *wpa_auth,
+				   const u8 *addr, u8 *pmk, size_t *len)
+{
+	if (wpa_auth->cb.get_pmk == NULL)
+		return -1;
+	return wpa_auth->cb.get_pmk(wpa_auth->cb.ctx, addr, pmk, len);
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+				   int vlan_id,
+				   const char *alg, const u8 *addr, int idx,
+				   u8 *key, size_t key_len)
+{
+	if (wpa_auth->cb.set_key == NULL)
+		return -1;
+	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+				    key, key_len);
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
+					   const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum_igtk == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int
+wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		    const u8 *data, size_t data_len, int encrypt)
+{
+	if (wpa_auth->cb.send_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
+				       encrypt);
+}
+
+
+static inline int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+					int (*cb)(struct wpa_state_machine *sm,
+						  void *ctx),
+					void *cb_ctx)
+{
+	if (wpa_auth->cb.for_each_sta == NULL)
+		return 0;
+	return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+static void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			    logger_level level, const char *txt)
+{
+	if (wpa_auth->cb.logger == NULL)
+		return;
+	wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+}
+
+
+static void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth,
+			     const u8 *addr, logger_level level,
+			     const char *fmt, ...)
+{
+	char *format;
+	int maxlen;
+	va_list ap;
+
+	if (wpa_auth->cb.logger == NULL)
+		return;
+
+	maxlen = strlen(fmt) + 100;
+	format = malloc(maxlen);
+	if (!format)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(format, maxlen, fmt, ap);
+	va_end(ap);
+
+	wpa_auth_logger(wpa_auth, addr, level, format);
+
+	free(format);
+}
 
 
-static int wpa_write_wpa_ie(struct hostapd_data *hapd, u8 *buf, size_t len)
+static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
 	struct wpa_ie_hdr *hdr;
 	int num_suites;
@@ -152,16 +500,17 @@
 	hdr->version = host_to_le16(WPA_VERSION);
 	pos = (u8 *) (hdr + 1);
 
-	if (hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
+	if (conf->wpa_group == WPA_CIPHER_CCMP) {
 		memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
+	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
 		memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_WEP104) {
+	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
 		memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_WEP40) {
+	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
 		memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN);
 	} else {
-		printf("Invalid group cipher (%d).\n", hapd->conf->wpa_group);
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
 		return -1;
 	}
 	pos += WPA_SELECTOR_LEN;
@@ -170,25 +519,25 @@
 	count = pos;
 	pos += 2;
 
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+	if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
 		memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
 		pos += WPA_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+	if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
 		memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
 		pos += WPA_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_NONE) {
+	if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
 		memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN);
 		pos += WPA_SELECTOR_LEN;
 		num_suites++;
 	}
 
 	if (num_suites == 0) {
-		printf("Invalid pairwise cipher (%d).\n",
-		       hapd->conf->wpa_pairwise);
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->wpa_pairwise);
 		return -1;
 	}
 	*count++ = num_suites & 0xff;
@@ -198,12 +547,12 @@
 	count = pos;
 	pos += 2;
 
-	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
 		memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN);
 		pos += WPA_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
 		memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X,
 		       WPA_SELECTOR_LEN);
 		pos += WPA_SELECTOR_LEN;
@@ -211,8 +560,8 @@
 	}
 
 	if (num_suites == 0) {
-		printf("Invalid key management type (%d).\n",
-		       hapd->conf->wpa_key_mgmt);
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
 		return -1;
 	}
 	*count++ = num_suites & 0xff;
@@ -226,11 +575,12 @@
 }
 
 
-static int wpa_write_rsn_ie(struct hostapd_data *hapd, u8 *buf, size_t len)
+static int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
 	struct rsn_ie_hdr *hdr;
 	int num_suites;
 	u8 *pos, *count;
+	u16 capab;
 
 	hdr = (struct rsn_ie_hdr *) buf;
 	hdr->elem_id = WLAN_EID_RSN;
@@ -239,16 +589,17 @@
 	*pos++ = RSN_VERSION >> 8;
 	pos = (u8 *) (hdr + 1);
 
-	if (hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
+	if (conf->wpa_group == WPA_CIPHER_CCMP) {
 		memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
+	} else if (conf->wpa_group == WPA_CIPHER_TKIP) {
 		memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_WEP104) {
+	} else if (conf->wpa_group == WPA_CIPHER_WEP104) {
 		memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN);
-	} else if (hapd->conf->wpa_group == WPA_CIPHER_WEP40) {
+	} else if (conf->wpa_group == WPA_CIPHER_WEP40) {
 		memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN);
 	} else {
-		printf("Invalid group cipher (%d).\n", hapd->conf->wpa_group);
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
 		return -1;
 	}
 	pos += RSN_SELECTOR_LEN;
@@ -257,25 +608,25 @@
 	count = pos;
 	pos += 2;
 
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+	if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
 		memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+	if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
 		memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_pairwise & WPA_CIPHER_NONE) {
+	if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
 		memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN);
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
 
 	if (num_suites == 0) {
-		printf("Invalid pairwise cipher (%d).\n",
-		       hapd->conf->wpa_pairwise);
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->wpa_pairwise);
 		return -1;
 	}
 	*count++ = num_suites & 0xff;
@@ -285,12 +636,12 @@
 	count = pos;
 	pos += 2;
 
-	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
 		memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN);
 		pos += RSN_SELECTOR_LEN;
 		num_suites++;
 	}
-	if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
 		memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X,
 		       RSN_SELECTOR_LEN);
 		pos += RSN_SELECTOR_LEN;
@@ -298,16 +649,43 @@
 	}
 
 	if (num_suites == 0) {
-		printf("Invalid key management type (%d).\n",
-		       hapd->conf->wpa_key_mgmt);
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
 		return -1;
 	}
 	*count++ = num_suites & 0xff;
 	*count = (num_suites >> 8) & 0xff;
 
 	/* RSN Capabilities */
-	*pos++ = hapd->conf->rsn_preauth ? BIT(0) : 0;
-	*pos++ = 0;
+	capab = 0;
+	if (conf->rsn_preauth)
+		capab |= WPA_CAPABILITY_PREAUTH;
+	if (conf->peerkey)
+		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
+	if (conf->wme_enabled) {
+		/* 4 PTKSA replay counters when using WME */
+		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+	}
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != WPA_NO_IEEE80211W)
+		capab |= WPA_CAPABILITY_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+	*pos++ = capab & 0xff;
+	*pos++ = capab >> 8;
+
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != WPA_NO_IEEE80211W) {
+		if (pos + 2 + 4 > buf + len)
+			return -1;
+		/* PMKID Count */
+		WPA_PUT_LE16(pos, 0);
+		pos += 2;
+
+		/* Management Group Cipher Suite */
+		memcpy(pos, RSN_CIPHER_SUITE_AES_128_CMAC, RSN_SELECTOR_LEN);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
 
 	hdr->len = (pos - buf) - 2;
 
@@ -315,443 +693,260 @@
 }
 
 
-static int wpa_gen_wpa_ie(struct hostapd_data *hapd)
+static int wpa_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 {
 	u8 *pos, buf[100];
 	int res;
 
 	pos = buf;
 
-	if (hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) {
-		res = wpa_write_rsn_ie(hapd, pos, buf + sizeof(buf) - pos);
+	if (wpa_auth->conf.wpa & HOSTAPD_WPA_VERSION_WPA2) {
+		res = wpa_write_rsn_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos);
 		if (res < 0)
 			return res;
 		pos += res;
 	}
-	if (hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA) {
-		res = wpa_write_wpa_ie(hapd, pos, buf + sizeof(buf) - pos);
+	if (wpa_auth->conf.wpa & HOSTAPD_WPA_VERSION_WPA) {
+		res = wpa_write_wpa_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos);
 		if (res < 0)
 			return res;
 		pos += res;
 	}
 
-	free(hapd->wpa_ie);
-	hapd->wpa_ie = malloc(pos - buf);
-	if (hapd->wpa_ie == NULL)
+	free(wpa_auth->wpa_ie);
+	wpa_auth->wpa_ie = malloc(pos - buf);
+	if (wpa_auth->wpa_ie == NULL)
 		return -1;
-	memcpy(hapd->wpa_ie, buf, pos - buf);
-	hapd->wpa_ie_len = pos - buf;
+	memcpy(wpa_auth->wpa_ie, buf, pos - buf);
+	wpa_auth->wpa_ie_len = pos - buf;
 
 	return 0;
 }
 
 
-static void wpa_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta)
+static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
+			       const u8 *addr)
 {
-	hostapd_sta_deauth(hapd, sta->addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_AUTHORIZED);
-	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
-	sta->timeout_next = STA_REMOVE;
+	if (wpa_auth->cb.disconnect == NULL)
+		return;
+	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
 
 
 static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
 {
-	struct hostapd_data *hapd = eloop_ctx;
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
 
-	if (hapd->wpa_auth) {
-		if (hostapd_get_rand(hapd->wpa_auth->GMK, WPA_GMK_LEN)) {
-			printf("Failed to get random data for WPA "
-			       "initialization.\n");
-		} else {
-			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "GMK rekeyd");
-		}
+	if (hostapd_get_rand(wpa_auth->group->GMK, WPA_GMK_LEN)) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+	} else {
+		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
 	}
 
-	if (hapd->conf->wpa_gmk_rekey) {
-		eloop_register_timeout(hapd->conf->wpa_gmk_rekey, 0,
-				       wpa_rekey_gmk, hapd, NULL);
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
 	}
 }
 
 
 static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
 {
-	struct hostapd_data *hapd = eloop_ctx;
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_group *group;
 
-	if (hapd->wpa_auth) {
-		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_DEBUG, "rekeying GTK");
-		hapd->wpa_auth->GTKReKey = TRUE;
+	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
+	for (group = wpa_auth->group; group; group = group->next) {
+		group->GTKReKey = TRUE;
 		do {
-			hapd->wpa_auth->changed = FALSE;
-			wpa_group_sm_step(hapd);
-		} while (hapd->wpa_auth->changed);
-	}
-	if (hapd->conf->wpa_group_rekey) {
-		eloop_register_timeout(hapd->conf->wpa_group_rekey, 0,
-				       wpa_rekey_gtk, hapd, NULL);
-	}
-}
-
-
-#ifdef CONFIG_RSN_PREAUTH
-
-static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
-				const u8 *buf, size_t len)
-{
-	struct rsn_preauth_interface *piface = ctx;
-	struct hostapd_data *hapd = piface->hapd;
-	struct ieee802_1x_hdr *hdr;
-	struct sta_info *sta;
-	struct l2_ethhdr *ethhdr;
-
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: receive pre-auth packet "
-		      "from interface '%s'\n", piface->ifname);
-	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: too short pre-auth "
-			      "packet (len=%lu)\n", (unsigned long) len);
-		return;
-	}
-
-	ethhdr = (struct l2_ethhdr *) buf;
-	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
-
-	if (memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for "
-			      "foreign address " MACSTR "\n",
-			      MAC2STR(ethhdr->h_dest));
-		return;
-	}
-
-	sta = ap_get_sta(hapd, ethhdr->h_source);
-	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: pre-auth for "
-			      "already association STA " MACSTR "\n",
-			      MAC2STR(sta->addr));
-		return;
-	}
-	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
-		sta = (struct sta_info *) malloc(sizeof(struct sta_info));
-		if (sta == NULL)
-			return;
-		memset(sta, 0, sizeof(*sta));
-		memcpy(sta->addr, ethhdr->h_source, ETH_ALEN);
-		sta->flags = WLAN_STA_PREAUTH;
-		sta->next = hapd->sta_list;
-		sta->wpa = WPA_VERSION_WPA2;
-		hapd->sta_list = sta;
-		hapd->num_sta++;
-		ap_sta_hash_add(hapd, sta);
-
-		ieee802_1x_new_station(hapd, sta);
-		if (sta->eapol_sm == NULL) {
-			ap_free_sta(hapd, sta);
-			sta = NULL;
-		} else {
-			sta->eapol_sm->radius_identifier = -1;
-			sta->eapol_sm->portValid = TRUE;
-			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
-		}
-	}
-	if (sta == NULL)
-		return;
-	sta->preauth_iface = piface;
-	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
-			   len - sizeof(*ethhdr));
-}
-
-
-static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
-{
-	struct rsn_preauth_interface *piface;
-
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN pre-auth interface '%s'\n",
-		      ifname);
-
-	piface = malloc(sizeof(*piface));
-	if (piface == NULL)
-		return -1;
-	memset(piface, 0, sizeof(*piface));
-	piface->hapd = hapd;
-
-	piface->ifname = strdup(ifname);
-	if (piface->ifname == NULL) {
-		goto fail1;
-	}
-
-	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
-				    rsn_preauth_receive, piface, 1);
-	if (piface->l2 == NULL) {
-		printf("Failed to open register layer 2 access to "
-		       "ETH_P_PREAUTH\n");
-		goto fail2;
-	}
-
-	piface->next = hapd->preauth_iface;
-	hapd->preauth_iface = piface;
-	return 0;
-
-fail2:
-	free(piface->ifname);
-fail1:
-	free(piface);
-	return -1;
-}
-
-
-static void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
-{
-	struct rsn_preauth_interface *piface, *prev;
-
-	piface = hapd->preauth_iface;
-	hapd->preauth_iface = NULL;
-	while (piface) {
-		prev = piface;
-		piface = piface->next;
-		l2_packet_deinit(prev->l2);
-		free(prev->ifname);
-		free(prev);
-	}
-}
-
-
-static int rsn_preauth_iface_init(struct hostapd_data *hapd)
-{
-	char *tmp, *start, *end;
-
-	if (hapd->conf->rsn_preauth_interfaces == NULL)
-		return 0;
-
-	tmp = strdup(hapd->conf->rsn_preauth_interfaces);
-	if (tmp == NULL)
-		return -1;
-	start = tmp;
-	for (;;) {
-		while (*start == ' ')
-			start++;
-		if (*start == '\0')
-			break;
-		end = strchr(start, ' ');
-		if (end)
-			*end = '\0';
-
-		if (rsn_preauth_iface_add(hapd, start)) {
-			rsn_preauth_iface_deinit(hapd);
-			return -1;
-		}
-
-		if (end)
-			start = end + 1;
-		else
-			break;
-	}
-	free(tmp);
-	return 0;
-}
-
-
-static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
-		   MACSTR, MAC2STR(sta->addr));
-	ap_free_sta(hapd, sta);
-}
-
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-			  int success)
-{
-	u8 *key;
-	size_t len;
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
-		       success ? "succeeded" : "failed");
-
-	key = ieee802_1x_get_key_crypt(sta->eapol_sm, &len);
-	if (success && key) {
-		pmksa_cache_add(hapd, sta, key, dot11RSNAConfigPMKLifetime);
-	}
-
-	/*
-	 * Finish STA entry removal from timeout in order to avoid freeing
-	 * STA data before the caller has finished processing.
-	 */
-	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
-}
-
-
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-		      u8 *buf, size_t len)
-{
-	struct rsn_preauth_interface *piface;
-	struct l2_ethhdr *ethhdr;
-
-	piface = hapd->preauth_iface;
-	while (piface) {
-		if (piface == sta->preauth_iface)
-			break;
-		piface = piface->next;
+			group->changed = FALSE;
+			wpa_group_sm_step(wpa_auth, group);
+		} while (group->changed);
 	}
 
-	if (piface == NULL) {
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "RSN: Could not find "
-			      "pre-authentication interface for " MACSTR "\n",
-			      MAC2STR(sta->addr));
-		return;
-	}
-
-	ethhdr = malloc(sizeof(*ethhdr) + len);
-	if (ethhdr == NULL)
-		return;
-
-	memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
-	memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
-	ethhdr->h_proto = htons(ETH_P_PREAUTH);
-	memcpy(ethhdr + 1, buf, len);
-
-	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
-			   sizeof(*ethhdr) + len) < 0) {
-		printf("Failed to send preauth packet using l2_packet_send\n");
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
+				       0, wpa_rekey_gtk, wpa_auth, NULL);
 	}
-	free(ethhdr);
 }
 
-#else /* CONFIG_RSN_PREAUTH */
 
-static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
+static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
 {
+	if (sm->pmksa == ctx)
+		sm->pmksa = NULL;
 	return 0;
 }
 
-static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
-{
-}
-
-static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
-{
-}
-
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-			  int success)
-{
-}
 
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-		      u8 *buf, size_t len)
+static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+				   void *ctx)
 {
+	struct wpa_authenticator *wpa_auth = ctx;
+	wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
 }
 
-#endif /* CONFIG_RSN_PREAUTH */
-
 
-int wpa_init(struct hostapd_data *hapd)
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+					 int vlan_id)
 {
+	struct wpa_group *group;
+	u8 buf[ETH_ALEN + 8 + sizeof(group)];
 	u8 rkey[32];
-	u8 buf[ETH_ALEN + 8];
-
-	if (rsn_preauth_iface_init(hapd))
-		return -1;
-
-	if (hostapd_set_privacy(hapd, 1)) {
-		printf("Could not set PrivacyInvoked for interface %s\n",
-		       hapd->conf->iface);
-		return -1;
-	}
 
-	if (wpa_gen_wpa_ie(hapd)) {
-		printf("Could not generate WPA IE.\n");
-		return -1;
-	}
+	group = wpa_zalloc(sizeof(struct wpa_group));
+	if (group == NULL)
+		return NULL;
 
-	if (hostapd_set_generic_elem(hapd, hapd->wpa_ie, hapd->wpa_ie_len)) {
-		printf("Failed to configure WPA IE for the kernel driver.\n");
-		return -1;
-	}
+	group->GTKAuthenticator = TRUE;
+	group->vlan_id = vlan_id;
 
-	hapd->wpa_auth = malloc(sizeof(struct wpa_authenticator));
-	if (hapd->wpa_auth == NULL)
-		return -1;
-	memset(hapd->wpa_auth, 0, sizeof(struct wpa_authenticator));
-	hapd->wpa_auth->GTKAuthenticator = TRUE;
-	switch (hapd->conf->wpa_group) {
+	switch (wpa_auth->conf.wpa_group) {
 	case WPA_CIPHER_CCMP:
-		hapd->wpa_auth->GTK_len = 16;
+		group->GTK_len = 16;
 		break;
 	case WPA_CIPHER_TKIP:
-		hapd->wpa_auth->GTK_len = 32;
+		group->GTK_len = 32;
 		break;
 	case WPA_CIPHER_WEP104:
-		hapd->wpa_auth->GTK_len = 13;
+		group->GTK_len = 13;
 		break;
 	case WPA_CIPHER_WEP40:
-		hapd->wpa_auth->GTK_len = 5;
+		group->GTK_len = 5;
 		break;
 	}
 
 	/* Counter = PRF-256(Random number, "Init Counter",
 	 *                   Local MAC Address || Time)
 	 */
-	memcpy(buf, hapd->own_addr, ETH_ALEN);
-	hostapd_get_ntp_timestamp(buf + ETH_ALEN);
+	memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	wpa_get_ntp_timestamp(buf + ETH_ALEN);
+	memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
 	if (hostapd_get_rand(rkey, sizeof(rkey)) ||
-	    hostapd_get_rand(hapd->wpa_auth->GMK, WPA_GMK_LEN)) {
-		printf("Failed to get random data for WPA initialization.\n");
-		free(hapd->wpa_auth);
-		hapd->wpa_auth = NULL;
-		return -1;
+	    hostapd_get_rand(group->GMK, WPA_GMK_LEN)) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+		free(group);
+		return NULL;
 	}
 
 	sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
-		 hapd->wpa_auth->Counter, WPA_NONCE_LEN);
+		 group->Counter, WPA_NONCE_LEN);
 
-	if (hapd->conf->wpa_gmk_rekey) {
-		eloop_register_timeout(hapd->conf->wpa_gmk_rekey, 0,
-				       wpa_rekey_gmk, hapd, NULL);
+	group->GInit = TRUE;
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+
+	return group;
+}
+
+
+/**
+ * wpa_init - Initialize WPA authenticator
+ * @addr: Authenticator address
+ * @conf: Configuration for WPA authenticator
+ * Returns: Pointer to WPA authenticator data or %NULL on failure
+ */
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb)
+{
+	struct wpa_authenticator *wpa_auth;
+
+	wpa_auth = wpa_zalloc(sizeof(struct wpa_authenticator));
+	if (wpa_auth == NULL)
+		return NULL;
+	memcpy(wpa_auth->addr, addr, ETH_ALEN);
+	memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+
+	if (wpa_gen_wpa_ie(wpa_auth)) {
+		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+		free(wpa_auth);
+		return NULL;
 	}
 
-	if (hapd->conf->wpa_group_rekey) {
-		eloop_register_timeout(hapd->conf->wpa_group_rekey, 0,
-				       wpa_rekey_gtk, hapd, NULL);
+	wpa_auth->group = wpa_group_init(wpa_auth, 0);
+	if (wpa_auth->group == NULL) {
+		free(wpa_auth->wpa_ie);
+		free(wpa_auth);
+		return NULL;
 	}
 
-	hapd->wpa_auth->GInit = TRUE;
-	wpa_group_sm_step(hapd);
-	hapd->wpa_auth->GInit = FALSE;
-	wpa_group_sm_step(hapd);
+	wpa_auth->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, wpa_auth);
+	if (wpa_auth->pmksa == NULL) {
+		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+		free(wpa_auth->wpa_ie);
+		free(wpa_auth);
+		return NULL;
+	}
 
-	return 0;
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
+	}
+
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
+				       wpa_rekey_gtk, wpa_auth, NULL);
+	}
+
+	return wpa_auth;
 }
 
 
-void wpa_deinit(struct hostapd_data *hapd)
+/**
+ * wpa_deinit - Deinitialize WPA authenticator
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ */
+void wpa_deinit(struct wpa_authenticator *wpa_auth)
 {
-	rsn_preauth_iface_deinit(hapd);
+	struct wpa_group *group, *prev;
 
-	eloop_cancel_timeout(wpa_rekey_gmk, hapd, NULL);
-	eloop_cancel_timeout(wpa_rekey_gtk, hapd, NULL);
+	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 
-	if (hostapd_set_privacy(hapd, 0)) {
-		printf("Could not disable PrivacyInvoked for interface %s\n",
-		       hapd->conf->iface);
-	}
+	while (wpa_auth->stsl_negotiations)
+		wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
 
-	if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
-		printf("Could not remove generic information element from "
-		       "interface %s\n", hapd->conf->iface);
+	pmksa_cache_deinit(wpa_auth->pmksa);
+
+	free(wpa_auth->wpa_ie);
+
+	group = wpa_auth->group;
+	while (group) {
+		prev = group;
+		group = group->next;
+		free(prev);
 	}
 
-	free(hapd->wpa_ie);
-	hapd->wpa_ie = NULL;
-	free(hapd->wpa_auth);
-	hapd->wpa_auth = NULL;
+	free(wpa_auth);
+}
+
+
+/**
+ * wpa_reconfig - Update WPA authenticator configuration
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ * @conf: Configuration for WPA authenticator
+ */
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf)
+{
+	if (wpa_auth == NULL)
+		return 0;
 
-	pmksa_cache_free(hapd);
+	memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	/*
+	 * TODO:
+	 * Disassociate stations if configuration changed
+	 * Update WPA/RSN IE
+	 */
+	return 0;
 }
 
 
@@ -794,6 +989,10 @@
 		return WPA_CIPHER_CCMP;
 	if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0)
 		return WPA_CIPHER_WEP104;
+#ifdef CONFIG_IEEE80211W
+	if (memcmp(s, RSN_CIPHER_SUITE_AES_128_CMAC, RSN_SELECTOR_LEN) == 0)
+		return WPA_CIPHER_AES_128_CMAC;
+#endif /* CONFIG_IEEE80211W */
 	return 0;
 }
 
@@ -809,264 +1008,21 @@
 }
 
 
-static void rsn_pmkid(const u8 *pmk, const u8 *aa, const u8 *spa, u8 *pmkid)
+static u8 * wpa_add_kde(u8 *pos, const u8 *kde, const u8 *data,
+			size_t data_len, const u8 *data2, size_t data2_len)
 {
-	char *title = "PMK Name";
-	const u8 *addr[3];
-	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
-	unsigned char hash[SHA1_MAC_LEN];
-
-	addr[0] = (u8 *) title;
-	addr[1] = aa;
-	addr[2] = spa;
-
-	hmac_sha1_vector(pmk, PMK_LEN, 3, addr, len, hash);
-	memcpy(pmkid, hash, PMKID_LEN);
-}
-
-
-static void pmksa_cache_set_expiration(struct hostapd_data *hapd);
-
-
-static void _pmksa_cache_free_entry(struct rsn_pmksa_cache *entry)
-{
-	if (entry == NULL)
-		return;
-	free(entry->identity);
-	ieee802_1x_free_radius_class(&entry->radius_class);
-	free(entry);
-}
-
-
-static void pmksa_cache_free_entry(struct hostapd_data *hapd,
-				   struct rsn_pmksa_cache *entry)
-{
-	struct sta_info *sta;
-	struct rsn_pmksa_cache *pos, *prev;
-	hapd->pmksa_count--;
-	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
-		if (sta->pmksa == entry)
-			sta->pmksa = NULL;
-	}
-	pos = hapd->pmkid[PMKID_HASH(entry->pmkid)];
-	prev = NULL;
-	while (pos) {
-		if (pos == entry) {
-			if (prev != NULL) {
-				prev->hnext = pos->hnext;
-			} else {
-				hapd->pmkid[PMKID_HASH(entry->pmkid)] =
-					pos->hnext;
-			}
-			break;
-		}
-		prev = pos;
-		pos = pos->hnext;
-	}
-
-	pos = hapd->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (pos == entry) {
-			if (prev != NULL)
-				prev->next = pos->next;
-			else
-				hapd->pmksa = pos->next;
-			break;
-		}
-		prev = pos;
-		pos = pos->next;
-	}
-	_pmksa_cache_free_entry(entry);
-}
-
-
-static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
-{
-	struct hostapd_data *hapd = eloop_ctx;
-	time_t now;
-
-	time(&now);
-	while (hapd->pmksa && hapd->pmksa->expiration <= now) {
-		struct rsn_pmksa_cache *entry = hapd->pmksa;
-		hapd->pmksa = entry->next;
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
-			      "RSN: expired PMKSA cache entry for "
-			      MACSTR, MAC2STR(entry->spa));
-		pmksa_cache_free_entry(hapd, entry);
-	}
-
-	pmksa_cache_set_expiration(hapd);
-}
-
-
-static void pmksa_cache_set_expiration(struct hostapd_data *hapd)
-{
-	int sec;
-	eloop_cancel_timeout(pmksa_cache_expire, hapd, NULL);
-	if (hapd->pmksa == NULL)
-		return;
-	sec = hapd->pmksa->expiration - time(NULL);
-	if (sec < 0)
-		sec = 0;
-	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, hapd, NULL);
-}
-
-
-static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache *entry,
-					struct eapol_state_machine *eapol)
-{
-	if (eapol == NULL)
-		return;
-
-	if (eapol->identity) {
-		entry->identity = malloc(eapol->identity_len);
-		if (entry->identity) {
-			entry->identity_len = eapol->identity_len;
-			memcpy(entry->identity, eapol->identity,
-			       eapol->identity_len);
-		}
-	}
-
-	ieee802_1x_copy_radius_class(&entry->radius_class,
-				     &eapol->radius_class);
-}
-
-
-static void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache *entry,
-				      struct eapol_state_machine *eapol)
-{
-	if (entry == NULL || eapol == NULL)
-		return;
-
-	if (entry->identity) {
-		free(eapol->identity);
-		eapol->identity = malloc(entry->identity_len);
-		if (eapol->identity) {
-			eapol->identity_len = entry->identity_len;
-			memcpy(eapol->identity, entry->identity,
-			       entry->identity_len);
-		}
-		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
-				  eapol->identity, eapol->identity_len);
-	}
-
-	ieee802_1x_free_radius_class(&eapol->radius_class);
-	ieee802_1x_copy_radius_class(&eapol->radius_class,
-				     &entry->radius_class);
-	if (eapol->radius_class.attr) {
-		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
-			   "PMKSA", (unsigned long) eapol->radius_class.count);
-	}
-}
-
-
-void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
-		     int session_timeout)
-{
-	struct rsn_pmksa_cache *entry, *pos, *prev;
-
-	if (sta->wpa != WPA_VERSION_WPA2)
-		return;
-
-	entry = malloc(sizeof(*entry));
-	if (entry == NULL)
-		return;
-	memset(entry, 0, sizeof(*entry));
-	memcpy(entry->pmk, pmk, PMK_LEN);
-	rsn_pmkid(pmk, hapd->own_addr, sta->addr, entry->pmkid);
-	time(&entry->expiration);
-	if (session_timeout > 0)
-		entry->expiration += session_timeout;
-	else
-		entry->expiration += dot11RSNAConfigPMKLifetime;
-	entry->akmp = WPA_KEY_MGMT_IEEE8021X;
-	memcpy(entry->spa, sta->addr, ETH_ALEN);
-	pmksa_cache_from_eapol_data(entry, sta->eapol_sm);
-
-	/* Replace an old entry for the same STA (if found) with the new entry
-	 */
-	pos = pmksa_cache_get(hapd, sta->addr, NULL);
-	if (pos)
-		pmksa_cache_free_entry(hapd, pos);
-
-	if (hapd->pmksa_count >= pmksa_cache_max_entries && hapd->pmksa) {
-		/* Remove the oldest entry to make room for the new entry */
-		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
-			      "RSN: removed the oldest PMKSA cache entry (for "
-			      MACSTR ") to make room for new one",
-			      MAC2STR(hapd->pmksa->spa));
-		pmksa_cache_free_entry(hapd, hapd->pmksa);
-	}
-
-	/* Add the new entry; order by expiration time */
-	pos = hapd->pmksa;
-	prev = NULL;
-	while (pos) {
-		if (pos->expiration > entry->expiration)
-			break;
-		prev = pos;
-		pos = pos->next;
-	}
-	if (prev == NULL) {
-		entry->next = hapd->pmksa;
-		hapd->pmksa = entry;
-	} else {
-		entry->next = prev->next;
-		prev->next = entry;
-	}
-	entry->hnext = hapd->pmkid[PMKID_HASH(entry->pmkid)];
-	hapd->pmkid[PMKID_HASH(entry->pmkid)] = entry;
-
-	hapd->pmksa_count++;
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "added PMKSA cache entry");
-	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-		hostapd_hexdump("RSN: added PMKID", entry->pmkid, PMKID_LEN);
-	}
-}
-
-
-static void pmksa_cache_free(struct hostapd_data *hapd)
-{
-	struct rsn_pmksa_cache *entry, *prev;
-	int i;
-	struct sta_info *sta;
-
-	entry = hapd->pmksa;
-	hapd->pmksa = NULL;
-	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		_pmksa_cache_free_entry(prev);
-	}
-	eloop_cancel_timeout(pmksa_cache_expire, hapd, NULL);
-	for (i = 0; i < PMKID_HASH_SIZE; i++)
-		hapd->pmkid[i] = NULL;
-	for (sta = hapd->sta_list; sta; sta = sta->next)
-		sta->pmksa = NULL;
-}
-
-
-static struct rsn_pmksa_cache * pmksa_cache_get(struct hostapd_data *hapd,
-						u8 *spa, u8 *pmkid)
-{
-	struct rsn_pmksa_cache *entry;
-
-	if (pmkid)
-		entry = hapd->pmkid[PMKID_HASH(pmkid)];
-	else
-		entry = hapd->pmksa;
-	while (entry) {
-		if ((spa == NULL || memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
-		    (pmkid == NULL ||
-		     memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
-			return entry;
-		entry = pmkid ? entry->hnext : entry->next;
-	}
-	return NULL;
-}
+	*pos++ = GENERIC_INFO_ELEM;
+	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
+	memcpy(pos, kde, RSN_SELECTOR_LEN);
+	pos += RSN_SELECTOR_LEN;
+	memcpy(pos, data, data_len);
+	pos += data_len;
+	if (data2) {
+		memcpy(pos, data2, data2_len);
+		pos += data2_len;
+	}
+	return pos;
+}
 
 
 struct wpa_ie_data {
@@ -1076,6 +1032,7 @@
 	int capabilities;
 	size_t num_pmkid;
 	u8 *pmkid;
+	int mgmt_group_cipher;
 };
 
 
@@ -1091,6 +1048,7 @@
 	data->pairwise_cipher = WPA_CIPHER_TKIP;
 	data->group_cipher = WPA_CIPHER_TKIP;
 	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->mgmt_group_cipher = 0;
 
 	if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
 		return -1;
@@ -1170,6 +1128,11 @@
 	data->pairwise_cipher = WPA_CIPHER_CCMP;
 	data->group_cipher = WPA_CIPHER_CCMP;
 	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211W
+	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+#else /* CONFIG_IEEE80211W */
+	data->mgmt_group_cipher = 0;
+#endif /* CONFIG_IEEE80211W */
 
 	if (rsn_ie_len < sizeof(struct rsn_ie_hdr))
 		return -1;
@@ -1232,10 +1195,10 @@
 		data->num_pmkid = pos[0] | (pos[1] << 8);
 		pos += 2;
 		left -= 2;
-		if (left < data->num_pmkid * PMKID_LEN) {
-			printf("RSN: too short RSN IE for PMKIDs "
-			       "(num=%lu, left=%d)\n",
-			       (unsigned long) data->num_pmkid, left);
+		if (left < (int) data->num_pmkid * PMKID_LEN) {
+			wpa_printf(MSG_DEBUG, "RSN: too short RSN IE for "
+				   "PMKIDs (num=%lu, left=%d)",
+				   (unsigned long) data->num_pmkid, left);
 			return -9;
 		}
 		data->pmkid = pos;
@@ -1243,6 +1206,20 @@
 		left -= data->num_pmkid * PMKID_LEN;
 	}
 
+#ifdef CONFIG_IEEE80211W
+	if (left >= 4) {
+		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
+		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "RSN: Unsupported management "
+				   "group cipher 0x%x",
+				   data->mgmt_group_cipher);
+			return -10;
+		}
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
 	if (left > 0) {
 		return -8;
 	}
@@ -1251,12 +1228,25 @@
 }
 
 
-int wpa_validate_wpa_ie(struct hostapd_data *hapd, struct sta_info *sta,
-			const u8 *wpa_ie, size_t wpa_ie_len, int version)
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len)
 {
 	struct wpa_ie_data data;
-	int ciphers, key_mgmt, res, i;
+	int ciphers, key_mgmt, res, version;
 	const u8 *selector;
+	size_t i;
+
+	if (wpa_auth == NULL || sm == NULL)
+		return WPA_NOT_ENABLED;
+
+	if (wpa_ie == NULL || wpa_ie_len < 1)
+		return WPA_INVALID_IE;
+
+	if (wpa_ie[0] == WLAN_EID_RSN)
+		version = HOSTAPD_WPA_VERSION_WPA2;
+	else
+		version = HOSTAPD_WPA_VERSION_WPA;
 
 	if (version == HOSTAPD_WPA_VERSION_WPA2) {
 		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
@@ -1266,7 +1256,7 @@
 			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
 			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-		memcpy(hapd->wpa_auth->dot11RSNAAuthenticationSuiteSelected,
+		memcpy(wpa_auth->dot11RSNAAuthenticationSuiteSelected,
 		       selector, RSN_SELECTOR_LEN);
 
 		selector = RSN_CIPHER_SUITE_CCMP;
@@ -1280,7 +1270,7 @@
 			selector = RSN_CIPHER_SUITE_WEP40;
 		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
 			selector = RSN_CIPHER_SUITE_NONE;
-		memcpy(hapd->wpa_auth->dot11RSNAPairwiseCipherSelected,
+		memcpy(wpa_auth->dot11RSNAPairwiseCipherSelected,
 		       selector, RSN_SELECTOR_LEN);
 
 		selector = RSN_CIPHER_SUITE_CCMP;
@@ -1294,7 +1284,7 @@
 			selector = RSN_CIPHER_SUITE_WEP40;
 		else if (data.group_cipher & WPA_CIPHER_NONE)
 			selector = RSN_CIPHER_SUITE_NONE;
-		memcpy(hapd->wpa_auth->dot11RSNAGroupCipherSelected,
+		memcpy(wpa_auth->dot11RSNAGroupCipherSelected,
 		       selector, RSN_SELECTOR_LEN);
 	} else {
 		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
@@ -1304,7 +1294,7 @@
 			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
 			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
-		memcpy(hapd->wpa_auth->dot11RSNAAuthenticationSuiteSelected,
+		memcpy(wpa_auth->dot11RSNAAuthenticationSuiteSelected,
 		       selector, WPA_SELECTOR_LEN);
 
 		selector = WPA_CIPHER_SUITE_TKIP;
@@ -1318,7 +1308,7 @@
 			selector = WPA_CIPHER_SUITE_WEP40;
 		else if (data.pairwise_cipher & WPA_CIPHER_NONE)
 			selector = WPA_CIPHER_SUITE_NONE;
-		memcpy(hapd->wpa_auth->dot11RSNAPairwiseCipherSelected,
+		memcpy(wpa_auth->dot11RSNAPairwiseCipherSelected,
 		       selector, WPA_SELECTOR_LEN);
 
 		selector = WPA_CIPHER_SUITE_TKIP;
@@ -1332,99 +1322,291 @@
 			selector = WPA_CIPHER_SUITE_WEP40;
 		else if (data.group_cipher & WPA_CIPHER_NONE)
 			selector = WPA_CIPHER_SUITE_NONE;
-		memcpy(hapd->wpa_auth->dot11RSNAGroupCipherSelected,
+		memcpy(wpa_auth->dot11RSNAGroupCipherSelected,
 		       selector, WPA_SELECTOR_LEN);
 	}
 	if (res) {
-		printf("Failed to parse WPA/RSN IE from " MACSTR " (res=%d)\n",
-		       MAC2STR(sta->addr), res);
-		hostapd_hexdump("WPA/RSN IE", wpa_ie, wpa_ie_len);
+		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
+			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
+		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
 		return WPA_INVALID_IE;
 	}
 
-	if (data.group_cipher != hapd->conf->wpa_group) {
-		printf("Invalid WPA group cipher (0x%x) from " MACSTR "\n",
-		       data.group_cipher, MAC2STR(sta->addr));
+	if (data.group_cipher != wpa_auth->conf.wpa_group) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
+			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
 		return WPA_INVALID_GROUP;
 	}
 
-	key_mgmt = data.key_mgmt & hapd->conf->wpa_key_mgmt;
+	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
 	if (!key_mgmt) {
-		printf("Invalid WPA key mgmt (0x%x) from " MACSTR "\n",
-		       data.key_mgmt, MAC2STR(sta->addr));
+		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
+			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
 		return WPA_INVALID_AKMP;
 	}
 	if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
-		sta->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
 	else
-		sta->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
 
-	ciphers = data.pairwise_cipher & hapd->conf->wpa_pairwise;
+	ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
 	if (!ciphers) {
-		printf("Invalid WPA pairwise cipher (0x%x) from " MACSTR "\n",
-		       data.pairwise_cipher, MAC2STR(sta->addr));
+		wpa_printf(MSG_DEBUG, "Invalid WPA pairwise cipher (0x%x) "
+			   "from " MACSTR,
+			   data.pairwise_cipher, MAC2STR(sm->addr));
 		return WPA_INVALID_PAIRWISE;
 	}
 
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w == WPA_IEEE80211W_REQUIRED) {
+		if (!(data.capabilities &
+		      WPA_CAPABILITY_MGMT_FRAME_PROTECTION)) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "required, but client did not enable it");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (ciphers & WPA_CIPHER_TKIP) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "cannot use TKIP");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "Unsupported management group "
+				   "cipher %d", data.mgmt_group_cipher);
+			return WPA_INVALID_MGMT_GROUP_CIPHER;
+		}
+	}
+
+	if (wpa_auth->conf.ieee80211w == WPA_NO_IEEE80211W ||
+	    !(data.capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION))
+		sm->mgmt_frame_prot = 0;
+	else
+		sm->mgmt_frame_prot = 1;
+#endif /* CONFIG_IEEE80211W */
+
 	if (ciphers & WPA_CIPHER_CCMP)
-		sta->pairwise = WPA_CIPHER_CCMP;
+		sm->pairwise = WPA_CIPHER_CCMP;
 	else
-		sta->pairwise = WPA_CIPHER_TKIP;
+		sm->pairwise = WPA_CIPHER_TKIP;
 
 	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
 	if (wpa_ie[0] == WLAN_EID_RSN)
-		sta->wpa = WPA_VERSION_WPA2;
+		sm->wpa = WPA_VERSION_WPA2;
 	else
-		sta->wpa = WPA_VERSION_WPA;
+		sm->wpa = WPA_VERSION_WPA;
 
 	for (i = 0; i < data.num_pmkid; i++) {
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-			hostapd_hexdump("RSN IE: STA PMKID",
-					&data.pmkid[i * PMKID_LEN], PMKID_LEN);
-		}
-		sta->pmksa = pmksa_cache_get(hapd, sta->addr,
-					     &data.pmkid[i * PMKID_LEN]);
-		if (sta->pmksa) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "PMKID found from PMKSA cache");
-			if (hapd->wpa_auth) {
-				memcpy(hapd->wpa_auth->dot11RSNAPMKIDUsed,
-				       sta->pmksa->pmkid, PMKID_LEN);
-			}
+		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
+			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
+		sm->pmksa = pmksa_cache_get(wpa_auth->pmksa, sm->addr,
+					    &data.pmkid[i * PMKID_LEN]);
+		if (sm->pmksa) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PMKID found from PMKSA cache "
+					 "eap_type=%d vlan_id=%d",
+					 sm->pmksa->eap_type_authsrv,
+					 sm->pmksa->vlan_id);
+			memcpy(wpa_auth->dot11RSNAPMKIDUsed,
+			       sm->pmksa->pmkid, PMKID_LEN);
 			break;
 		}
 	}
 
+	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
+		free(sm->wpa_ie);
+		sm->wpa_ie = malloc(wpa_ie_len);
+		if (sm->wpa_ie == NULL)
+			return WPA_ALLOC_FAIL;
+	}
+	memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
+	sm->wpa_ie_len = wpa_ie_len;
+
 	return WPA_IE_OK;
 }
 
 
-void wpa_new_station(struct hostapd_data *hapd, struct sta_info *sta)
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+	const u8 *smk;
+	size_t smk_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *lifetime;
+	size_t lifetime_len;
+	const u8 *error;
+	size_t error_len;
+#endif /* CONFIG_PEERKEY */
+};
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    memcmp(pos + 2, WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0 &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		return 0;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < end &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    memcmp(pos + 2, RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN) == 0) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_MAC_ADDR, RSN_SELECTOR_LEN) == 0) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_SMK, RSN_SELECTOR_LEN) == 0) {
+		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_NONCE, RSN_SELECTOR_LEN) == 0) {
+		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_LIFETIME, RSN_SELECTOR_LEN) == 0) {
+		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    memcmp(pos + 2, RSN_KEY_DATA_ERROR, RSN_SELECTOR_LEN) == 0) {
+		ie->error = pos + 2 + RSN_SELECTOR_LEN;
+		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+#endif /* CONFIG_PEERKEY */
+
+	return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_parse_kde_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d)", pos[0], pos[1]);
+			ret = -1;
+			break;
+		}
+		if (*pos == RSN_INFO_ELEM) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+		} else if (*pos == GENERIC_INFO_ELEM) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+				    "Key Data IE", pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}
+
+
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
 {
 	struct wpa_state_machine *sm;
 
-	if (!hapd->conf->wpa)
+	sm = wpa_zalloc(sizeof(struct wpa_state_machine));
+	if (sm == NULL)
+		return NULL;
+	memcpy(sm->addr, addr, ETH_ALEN);
+
+	sm->wpa_auth = wpa_auth;
+	sm->group = wpa_auth->group;
+
+	return sm;
+}
+
+
+void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			     struct wpa_state_machine *sm)
+{
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
 		return;
 
-	if (sta->wpa_sm) {
-		sm = sta->wpa_sm;
+	if (sm->started) {
 		memset(sm->key_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
 		sm->ReAuthenticationRequest = TRUE;
 		wpa_sm_step(sm);
 		return;
 	}
 
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG, "start authentication");
-	sm = malloc(sizeof(struct wpa_state_machine));
-	if (sm == NULL)
-		return;
-	memset(sm, 0, sizeof(struct wpa_state_machine));
-
-	sm->hapd = hapd;
-	sm->sta = sta;
-	sta->wpa_sm = sm;
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"start authentication");
+	sm->started = 1;
 
 	sm->Init = TRUE;
 	wpa_sm_step(sm);
@@ -1434,58 +1616,445 @@
 }
 
 
-void wpa_free_station(struct sta_info *sta)
+static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
-	struct wpa_state_machine *sm = sta->wpa_sm;
+	free(sm->last_rx_eapol_key);
+	free(sm->wpa_ie);
+	free(sm);
+}
 
+
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
+{
 	if (sm == NULL)
 		return;
 
-	if (sm->hapd->conf->wpa_strict_rekey && sm->has_GTK) {
-		hostapd_logger(sm->hapd, sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_DEBUG, "strict rekeying - force "
-			       "GTK rekey since STA is leaving");
-		eloop_cancel_timeout(wpa_rekey_gtk, sm->hapd, NULL);
-		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->hapd,
+	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"strict rekeying - force GTK rekey since STA "
+				"is leaving");
+		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
+		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
 				       NULL);
 	}
 
-	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->hapd, sta);
-	eloop_cancel_timeout(wpa_sm_call_step, sm->hapd, sta->wpa_sm);
-	eloop_cancel_timeout(rsn_preauth_finished_cb, sm->hapd, sta);
-	free(sm->last_rx_eapol_key);
-	free(sm);
-	sta->wpa_sm = NULL;
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
+	if (sm->in_step_loop) {
+		/* Must not free state machine while wpa_sm_step() is running.
+		 * Freeing will be completed in the end of wpa_sm_step(). */
+		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		sm->pending_deinit = 1;
+	} else
+		wpa_free_sta_sm(sm);
+}
+
+
+static void wpa_request_new_ptk(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	sm->PTKRequest = TRUE;
+	sm->PTK_valid = 0;
+}
+
+
+#ifdef CONFIG_PEERKEY
+static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_stsl_negotiation *neg = timeout_ctx;
+#endif
+
+	/* TODO: ? */
+}
+
+
+struct wpa_stsl_search {
+	const u8 *addr;
+	struct wpa_state_machine *sm;
+};
+
+
+static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
+{
+	struct wpa_stsl_search *search = ctx;
+	if (memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
+		search->sm = sm;
+		return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
+			       struct wpa_state_machine *sm, const u8 *peer,
+			       u16 mui, u16 error_type)
+{
+	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
+	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
+	size_t kde_len;
+	u8 *pos;
+	struct rsn_error_kde error;
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK Error");
+
+	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde);
+	pos = kde;
+
+	if (peer) {
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
+				  NULL, 0);
+		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+	}
+
+	error.mui = host_to_be16(mui);
+	error.error_type = host_to_be16(error_type);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
+			  (u8 *) &error, sizeof(error), NULL, 0);
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
+			 NULL, NULL, kde, kde_len, 0, 0, 0);
+}
+
+
+static void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+		       struct wpa_state_machine *sm,
+		       struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      ntohs(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+	    kde.mac_addr_len < ETH_ALEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+			   "SMK M1");
+		return;
+	}
+
+	/* Initiator = sm->addr; Peer = kde.mac_addr */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+	buf = malloc(buf_len);
+	if (buf == NULL)
+		return;
+	/* Initiator RSN IE */
+	memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
+	pos = buf + kde.rsn_ie_len;
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* SMK M2:
+	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
+	 */
+
+	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
+			"Sending SMK M2");
+
+	__wpa_send_eapol(wpa_auth, search.sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, buf_len, 0, 0, 0);
+
+	free(buf);
+
+}
+
+
+static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M4:
+	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
+	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
+	 *           Lifetime KDE)
+	 */
+
+	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + WPA_PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* Initiator Nonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
+			  NULL, 0);
+
+	/* SMK with PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, WPA_PMK_LEN,
+			  key->key_nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M4");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, buf_len, 0, 1, 0);
+
+	free(buf);
 }
 
 
-static void wpa_request_new_ptk(struct hostapd_data *hapd,
-				struct sta_info *sta)
+static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk, const u8 *peer)
 {
-	struct wpa_state_machine *sm = sta->wpa_sm;
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M5:
+	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
+	 *                             Lifetime KDE))
+	 */
+
+	buf_len = kde->rsn_ie_len +
+		2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + WPA_PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Peer RSN IE */
+	memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
+	pos = buf + kde->rsn_ie_len;
+
+	/* Peer MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
+
+	/* PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
+			  WPA_NONCE_LEN, NULL, 0);
+
+	/* SMK and INonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, WPA_PMK_LEN,
+			  kde->nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M5");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, kde->nonce, buf, buf_len, 0, 1, 0);
+
+	free(buf);
+}
+
+
+static void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+		       struct wpa_state_machine *sm,
+		       struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      ntohs(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL ||
+	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
+			   "Nonce KDE in SMK M3");
+		return;
+	}
+
+	/* Peer = sm->addr; Initiator = kde.mac_addr;
+	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	if (hostapd_get_rand(smk, WPA_PMK_LEN)) {
+		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
+		return;
+	}
+
+	/* SMK = PRF-256(Random number, "SMK Derivation",
+	 *               AA || Time || INonce || PNonce)
+	 */
+	memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	pos = buf + ETH_ALEN;
+	wpa_get_ntp_timestamp(pos);
+	pos += 8;
+	memcpy(pos, kde.nonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
+	sha1_prf(smk, WPA_PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		 smk, WPA_PMK_LEN);
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, WPA_PMK_LEN);
+
+	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
+	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
+
+	/* Authenticator does not need SMK anymore and it is required to forget
+	 * it. */
+	memset(smk, 0, sizeof(*smk));
+}
+
+
+static void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+			  struct wpa_state_machine *sm,
+			  struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	struct rsn_error_kde error;
+	u16 mui, error_type;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      ntohs(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+		return;
+	}
+
+	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.error == NULL || kde.error_len < sizeof(error)) {
+		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
+			   "SMK Error");
+		return;
+	}
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
+			   "associated for SMK Error message from " MACSTR,
+			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
+		return;
+	}
+
+	memcpy(&error, kde.error, sizeof(error));
+	mui = be_to_host16(error.mui);
+	error_type = be_to_host16(error.error_type);
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "STA reported SMK Error: Peer " MACSTR
+			 " MUI %d Error Type %d",
+			 MAC2STR(kde.mac_addr), mui, error_type);
+
+	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
+}
+#endif /* CONFIG_PEERKEY */
+
+
+static int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+			   struct wpa_stsl_negotiation *neg)
+{
+#ifdef CONFIG_PEERKEY
+	struct wpa_stsl_negotiation *pos, *prev;
+
+	if (wpa_auth == NULL)
+		return -1;
+	pos = wpa_auth->stsl_negotiations;
+	prev = NULL;
+	while (pos) {
+		if (pos == neg) {
+			if (prev)
+				prev->next = pos->next;
+			else
+				wpa_auth->stsl_negotiations = pos->next;
 
-	if (sm == NULL)
-		return;
+			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
+			free(pos);
+			return 0;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+#endif /* CONFIG_PEERKEY */
 
-	sm->PTKRequest = TRUE;
-	sm->PTK_valid = 0;
+	return -1;
 }
 
 
-void wpa_receive(struct hostapd_data *hapd, struct sta_info *sta,
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len)
 {
-	struct wpa_state_machine *sm = sta->wpa_sm;
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
 	u16 key_info, key_data_length;
-	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST } msg;
+	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
+	       SMK_M1, SMK_M3, SMK_ERROR } msg;
 	char *msgtxt;
+	struct wpa_eapol_ie_parse kde;
 
-	if (!hapd->conf->wpa)
-		return;
-
-	if (sm == NULL)
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
 		return;
 
 	if (data_len < sizeof(*hdr) + sizeof(*key))
@@ -1507,7 +2076,19 @@
 	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
 	 * are set */
 
-	if (key_info & WPA_KEY_INFO_REQUEST) {
+	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
+	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
+		if (key_info & WPA_KEY_INFO_ERROR) {
+			msg = SMK_ERROR;
+			msgtxt = "SMK Error";
+		} else {
+			msg = SMK_M1;
+			msgtxt = "SMK M1";
+		}
+	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+		msg = SMK_M3;
+		msgtxt = "SMK M3";
+	} else if (key_info & WPA_KEY_INFO_REQUEST) {
 		msg = REQUEST;
 		msgtxt = "Request";
 	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
@@ -1522,13 +2103,12 @@
 	}
 
 	if (key_info & WPA_KEY_INFO_REQUEST) {
-		if (sta->req_replay_counter_used &&
-		    memcmp(key->replay_counter, sta->req_replay_counter,
+		if (sm->req_replay_counter_used &&
+		    memcmp(key->replay_counter, sm->req_replay_counter,
 			   WPA_REPLAY_COUNTER_LEN) <= 0) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_WARNING,
-				       "received EAPOL-Key request with "
-				       "replayed counter");
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+					"received EAPOL-Key request with "
+					"replayed counter");
 			return;
 		}
 	}
@@ -1537,18 +2117,13 @@
 	    (!sm->key_replay_counter_valid ||
 	     memcmp(key->replay_counter, sm->key_replay_counter,
 		    WPA_REPLAY_COUNTER_LEN) != 0)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_INFO,
-			       "received EAPOL-Key %s with unexpected replay "
-			       "counter", msgtxt);
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-			hostapd_hexdump("expected replay counter",
-					sm->key_replay_counter,
-					WPA_REPLAY_COUNTER_LEN);
-			hostapd_hexdump("received replay counter",
-					key->replay_counter,
-					WPA_REPLAY_COUNTER_LEN);
-		}
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+				 "received EAPOL-Key %s with unexpected "
+				 "replay counter", msgtxt);
+		wpa_hexdump(MSG_DEBUG, "expected replay counter",
+			    sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
+		wpa_hexdump(MSG_DEBUG, "received replay counter",
+			    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
 		return;
 	}
 
@@ -1556,142 +2131,170 @@
 	case PAIRWISE_2:
 		if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
 		    sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key msg 2/4 in invalid"
-				       " state (%d) - dropped",
-				       sm->wpa_ptk_state);
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
 			return;
 		}
-		if (sta->wpa_ie == NULL ||
-		    sta->wpa_ie_len != key_data_length ||
-		    memcmp(sta->wpa_ie, key + 1, key_data_length) != 0) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "WPA IE from (Re)AssocReq did not match"
-				       " with msg 2/4");
-			if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-				if (sta->wpa_ie) {
-					hostapd_hexdump("WPA IE in AssocReq",
-							sta->wpa_ie,
-							sta->wpa_ie_len);
-				}
-				hostapd_hexdump("WPA IE in msg 2/4",
-						(u8 *) (key + 1),
-						key_data_length);
+		if (sm->wpa_ie == NULL ||
+		    sm->wpa_ie_len != key_data_length ||
+		    memcmp(sm->wpa_ie, key + 1, key_data_length) != 0) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"WPA IE from (Re)AssocReq did not "
+					"match with msg 2/4");
+			if (sm->wpa_ie) {
+				wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+					    sm->wpa_ie, sm->wpa_ie_len);
 			}
+			wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+				    (u8 *) (key + 1), key_data_length);
 			/* MLME-DEAUTHENTICATE.request */
-			wpa_sta_disconnect(hapd, sta);
+			wpa_sta_disconnect(wpa_auth, sm->addr);
 			return;
 		}
 		break;
 	case PAIRWISE_4:
 		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
 		    !sm->PTK_valid) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key msg 4/4 in invalid"
-				       " state (%d) - dropped",
-				       sm->wpa_ptk_state);
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 4/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
 			return;
 		}
 		break;
 	case GROUP_2:
 		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
 		    || !sm->PTK_valid) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key msg 2/2 in invalid"
-				       " state (%d) - dropped",
-				       sm->wpa_ptk_group_state);
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/2 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_group_state);
+			return;
+		}
+		break;
+#ifdef CONFIG_PEERKEY
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		if (!wpa_auth->conf.peerkey) {
+			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
+				   "PeerKey use disabled - ignoring message");
+			return;
+		}
+		if (!sm->PTK_valid) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key msg SMK in "
+					"invalid state - dropped");
 			return;
 		}
 		break;
+#else /* CONFIG_PEERKEY */
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		return; /* STSL disabled - ignore SMK messages */
+#endif /* CONFIG_PEERKEY */
 	case REQUEST:
 		break;
 	}
 
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Key frame (%s)",
-		       msgtxt);
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "received EAPOL-Key frame (%s)", msgtxt);
 
 	if (key_info & WPA_KEY_INFO_ACK) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_INFO,
-			       "received invalid EAPOL-Key: Key Ack set");
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key Ack set");
 		return;
 	}
 
 	if (!(key_info & WPA_KEY_INFO_MIC)) {
-		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_INFO,
-			       "received invalid EAPOL-Key: Key MIC not set");
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key MIC not set");
 		return;
 	}
 
 	sm->MICVerified = FALSE;
 	if (sm->PTK_valid) {
 		if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key with invalid MIC");
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key with invalid MIC");
 			return;
 		}
 		sm->MICVerified = TRUE;
-		eloop_cancel_timeout(wpa_send_eapol_timeout, sta->wpa_sm->hapd,
-				     sta);
+		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
 	}
 
 	if (key_info & WPA_KEY_INFO_REQUEST) {
 		if (sm->MICVerified) {
-			sta->req_replay_counter_used = 1;
-			memcpy(sta->req_replay_counter, key->replay_counter,
+			sm->req_replay_counter_used = 1;
+			memcpy(sm->req_replay_counter, key->replay_counter,
 			       WPA_REPLAY_COUNTER_LEN);
 		} else {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key request with "
-				       "invalid MIC");
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key request with "
+					"invalid MIC");
 			return;
 		}
 
-		if (key_info & WPA_KEY_INFO_ERROR) {
+		/*
+		 * TODO: should decrypt key data field if encryption was used;
+		 * even though MAC address KDE is not normally encrypted,
+		 * supplicant is allowed to encrypt it.
+		 */
+		if (msg == SMK_ERROR) {
+#ifdef CONFIG_PEERKEY
+			wpa_smk_error(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+			return;
+		} else if (key_info & WPA_KEY_INFO_ERROR) {
 			/* Supplicant reported a Michael MIC error */
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key Error Request "
-				       "(STA detected Michael MIC failure)");
-			ieee80211_michael_mic_failure(hapd, sta->addr, 0);
-			sta->dot11RSNAStatsTKIPRemoteMICFailures++;
-			hapd->wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Error Request "
+					"(STA detected Michael MIC failure)");
+			wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+			sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+			wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
 			/* Error report is not a request for a new key
 			 * handshake, but since Authenticator may do it, let's
 			 * change the keys now anyway. */
-			wpa_request_new_ptk(hapd, sta);
+			wpa_request_new_ptk(sm);
 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key Request for new "
-				       "4-Way Handshake");
-			wpa_request_new_ptk(hapd, sta);
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for new "
+					"4-Way Handshake");
+			wpa_request_new_ptk(sm);
+#ifdef CONFIG_PEERKEY
+		} else if (msg == SMK_M1) {
+			wpa_smk_m1(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+		} else if (key_data_length > 0 &&
+			   wpa_parse_kde_ies((const u8 *) (key + 1),
+					     key_data_length, &kde) == 0 &&
+			   kde.mac_addr) {
 		} else {
-			/* TODO: this could also be a request for STAKey
-			 * if Key Data fields contains peer MAC address KDE.
-			 * STAKey request should have 0xdd <len> 00-0F-AC:2 in
-			 * the beginning of Key Data */
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "received EAPOL-Key Request for GTK "
-				       "rekeying");
-			wpa_request_new_ptk(hapd, sta);
-			eloop_cancel_timeout(wpa_rekey_gtk, hapd, NULL);
-			wpa_rekey_gtk(hapd, NULL);
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for GTK "
+					"rekeying");
+			/* FIX: why was this triggering PTK rekeying for the
+			 * STA that requested Group Key rekeying?? */
+			/* wpa_request_new_ptk(sta->wpa_sm); */
+			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+			wpa_rekey_gtk(wpa_auth, NULL);
 		}
 	} else {
 		/* Do not allow the same key replay counter to be reused. */
 		sm->key_replay_counter_valid = FALSE;
 	}
 
+#ifdef CONFIG_PEERKEY
+	if (msg == SMK_M3) {
+		wpa_smk_m3(wpa_auth, sm, key);
+		return;
+	}
+#endif /* CONFIG_PEERKEY */
+
 	free(sm->last_rx_eapol_key);
 	sm->last_rx_eapol_key = malloc(data_len);
 	if (sm->last_rx_eapol_key == NULL)
@@ -1707,8 +2310,7 @@
 }
 
 
-static void wpa_pmk_to_ptk(struct hostapd_data *hapd, const u8 *pmk,
-			   const u8 *addr1, const u8 *addr2,
+static void wpa_pmk_to_ptk(const u8 *pmk, const u8 *addr1, const u8 *addr2,
 			   const u8 *nonce1, const u8 *nonce2,
 			   u8 *ptk, size_t ptk_len)
 {
@@ -1739,15 +2341,13 @@
 	sha1_prf(pmk, WPA_PMK_LEN, "Pairwise key expansion",
 		 data, sizeof(data), ptk, ptk_len);
 
-	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-		hostapd_hexdump("PMK", pmk, WPA_PMK_LEN);
-		hostapd_hexdump("PTK", ptk, ptk_len);
-	}
+	wpa_hexdump_key(MSG_DEBUG, "PMK", pmk, WPA_PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "PTK", ptk, ptk_len);
 }
 
 
-static void wpa_gmk_to_gtk(struct hostapd_data *hapd, u8 *gmk,
-			   u8 *addr, u8 *gnonce, u8 *gtk, size_t gtk_len)
+static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce,
+			   u8 *gtk, size_t gtk_len)
 {
 	u8 data[ETH_ALEN + WPA_NONCE_LEN];
 
@@ -1758,25 +2358,19 @@
 	sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
 		 data, sizeof(data), gtk, gtk_len);
 
-	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-		hostapd_hexdump("GMK", gmk, WPA_GMK_LEN);
-		hostapd_hexdump("GTK", gtk, gtk_len);
-	}
+	wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
 }
 
 
 static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
 {
-	struct hostapd_data *hapd = eloop_ctx;
-	struct sta_info *sta = timeout_ctx;
-
-	if (!sta->wpa_sm || !(sta->flags & WLAN_STA_ASSOC))
-		return;
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_state_machine *sm = timeout_ctx;
 
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG, "EAPOL-Key timeout");
-	sta->wpa_sm->TimeoutEvt = TRUE;
-	wpa_sm_step(sta->wpa_sm);
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
+	sm->TimeoutEvt = TRUE;
+	wpa_sm_step(sm);
 }
 
 
@@ -1800,88 +2394,68 @@
 }
 
 
-static void wpa_send_eapol(struct hostapd_data *hapd, struct sta_info *sta,
-			   int secure, int mic, int ack, int install,
-			   int pairwise, u8 *key_rsc, u8 *nonce,
-			   u8 *ie, size_t ie_len, u8 *gtk, size_t gtk_len,
-			   int keyidx)
+static void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+			     struct wpa_state_machine *sm, int key_info,
+			     const u8 *key_rsc, const u8 *nonce,
+			     const u8 *kde, size_t kde_len,
+			     int keyidx, int encr, int force_version)
 {
-	struct wpa_state_machine *sm = sta->wpa_sm;
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
 	size_t len;
-	int key_info, alg;
-	int timeout_ms;
+	int alg;
 	int key_data_len, pad_len = 0;
 	u8 *buf, *pos;
-
-	if (sm == NULL)
-		return;
+	int version, pairwise;
 
 	len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
 
-	if (sta->wpa == WPA_VERSION_WPA2) {
-		key_data_len = ie_len + gtk_len;
-		if (gtk_len)
-			key_data_len += 2 + RSN_SELECTOR_LEN + 2;
-	} else {
-		if (pairwise) {
-			/* WPA does not include GTK in 4-Way Handshake */
-			gtk = NULL;
-			gtk_len = 0;
-
-			/* key_rsc is for group key, so mask it out in case of
-			 * WPA Pairwise key negotiation. */
-			key_rsc = NULL;
-		}
-		key_data_len = ie_len + gtk_len;
-	}
-
-	if (sta->pairwise == WPA_CIPHER_CCMP) {
-		key_info = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-		if (gtk) {
-			pad_len = key_data_len % 8;
-			if (pad_len)
-				pad_len = 8 - pad_len;
-			key_data_len += pad_len + 8;
-		}
-	} else {
-		key_info = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+	if (force_version)
+		version = force_version;
+	else if (sm->pairwise == WPA_CIPHER_CCMP)
+		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+
+	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(secure=%d mic=%d ack=%d "
+		   "install=%d pairwise=%d kde_len=%lu keyidx=%d encr=%d)",
+		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
+		   pairwise, (unsigned long) kde_len, keyidx, encr);
+
+	key_data_len = kde_len;
+
+	if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES && encr) {
+		pad_len = key_data_len % 8;
+		if (pad_len)
+			pad_len = 8 - pad_len;
+		key_data_len += pad_len + 8;
 	}
 
 	len += key_data_len;
 
-	hdr = malloc(len);
+	hdr = wpa_zalloc(len);
 	if (hdr == NULL)
 		return;
-	memset(hdr, 0, len);
-	hdr->version = EAPOL_VERSION;
+	hdr->version = wpa_auth->conf.eapol_version;
 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
 	hdr->length = htons(len  - sizeof(*hdr));
 	key = (struct wpa_eapol_key *) (hdr + 1);
 
-	key->type = sta->wpa == WPA_VERSION_WPA2 ?
+	key->type = sm->wpa == WPA_VERSION_WPA2 ?
 		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	if (secure)
-		key_info |= WPA_KEY_INFO_SECURE;
-	if (mic)
-		key_info |= WPA_KEY_INFO_MIC;
-	if (ack)
-		key_info |= WPA_KEY_INFO_ACK;
-	if (install)
-		key_info |= WPA_KEY_INFO_INSTALL;
-	if (pairwise)
-		key_info |= WPA_KEY_INFO_KEY_TYPE;
-	if (gtk && sta->wpa == WPA_VERSION_WPA2)
+	key_info |= version;
+	if (encr && sm->wpa == WPA_VERSION_WPA2)
 		key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
-	if (sta->wpa != WPA_VERSION_WPA2) {
-		if (pairwise)
-			keyidx = 0;
+	if (sm->wpa != WPA_VERSION_WPA2)
 		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
-	}
 	key->key_info = htons(key_info);
 
-	alg = pairwise ? sta->pairwise : hapd->conf->wpa_group;
+	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
 	switch (alg) {
 	case WPA_CIPHER_CCMP:
 		key->key_length = htons(16);
@@ -1896,7 +2470,10 @@
 		key->key_length = htons(13);
 		break;
 	}
+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+		key->key_length = htons(0);
 
+	/* FIX: STSL: what to use as key_replay_counter? */
 	inc_byte_array(sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
 	memcpy(key->replay_counter, sm->key_replay_counter,
 	       WPA_REPLAY_COUNTER_LEN);
@@ -1908,48 +2485,33 @@
 	if (key_rsc)
 		memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
 
-	if (ie && !gtk) {
-		memcpy(key + 1, ie, ie_len);
-		key->key_data_length = htons(ie_len);
-	} else if (gtk) {
-		buf = malloc(key_data_len);
+	if (kde && !encr) {
+		memcpy(key + 1, kde, kde_len);
+		key->key_data_length = htons(kde_len);
+	} else if (encr && kde) {
+		buf = wpa_zalloc(key_data_len);
 		if (buf == NULL) {
 			free(hdr);
 			return;
 		}
-		memset(buf, 0, key_data_len);
 		pos = buf;
-		if (ie) {
-			memcpy(pos, ie, ie_len);
-			pos += ie_len;
-		}
-		if (sta->wpa == WPA_VERSION_WPA2) {
-			*pos++ = WLAN_EID_GENERIC;
-			*pos++ = RSN_SELECTOR_LEN + 2 + gtk_len;
-			memcpy(pos, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN);
-			pos += RSN_SELECTOR_LEN;
-			*pos++ = keyidx & 0x03;
-			*pos++ = 0;
-		}
-		memcpy(pos, gtk, gtk_len);
-		pos += gtk_len;
+		memcpy(pos, kde, kde_len);
+		pos += kde_len;
+
 		if (pad_len)
 			*pos++ = 0xdd;
 
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-			hostapd_hexdump("Plaintext EAPOL-Key Key Data",
-					buf, key_data_len);
-		}
-		if (key_info & WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+				buf, key_data_len);
+		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 			aes_wrap(sm->PTK.encr_key, (key_data_len - 8) / 8, buf,
 				 (u8 *) (key + 1));
 			key->key_data_length = htons(key_data_len);
 		} else {
 			u8 ek[32];
 			memcpy(key->key_iv,
-			       hapd->wpa_auth->Counter + WPA_NONCE_LEN - 16,
-			       16);
-			inc_byte_array(hapd->wpa_auth->Counter, WPA_NONCE_LEN);
+			       sm->group->Counter + WPA_NONCE_LEN - 16, 16);
+			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
 			memcpy(ek, key->key_iv, 16);
 			memcpy(ek + 16, sm->PTK.encr_key, 16);
 			memcpy(key + 1, buf, key_data_len);
@@ -1959,28 +2521,46 @@
 		free(buf);
 	}
 
-	if (mic) {
+	if (key_info & WPA_KEY_INFO_MIC) {
 		if (!sm->PTK_valid) {
-			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_DEBUG, "PTK not valid "
-				       "when sending EAPOL-Key frame");
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					"PTK not valid when sending EAPOL-Key "
+					"frame");
 			free(hdr);
 			return;
 		}
-		wpa_calc_eapol_key_mic(key_info & WPA_KEY_INFO_TYPE_MASK,
+		wpa_calc_eapol_key_mic(version,
 				       sm->PTK.mic_key, (u8 *) hdr, len,
 				       key->key_mic);
 	}
 
-	if (sta->eapol_sm)
-		sta->eapol_sm->dot1xAuthEapolFramesTx++;
-	hostapd_send_eapol(hapd, sta->addr, (u8 *) hdr, len, sm->pairwise_set);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
+			   1);
+	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
+			    sm->pairwise_set);
 	free(hdr);
+}
+
+
+static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+			   struct wpa_state_machine *sm, int key_info,
+			   const u8 *key_rsc, const u8 *nonce,
+			   const u8 *kde, size_t kde_len,
+			   int keyidx, int encr)
+{
+	int timeout_ms;
+	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+
+	if (sm == NULL)
+		return;
+
+	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
+			 keyidx, encr, 0);
 
 	timeout_ms = pairwise ? dot11RSNAConfigPairwiseUpdateTimeOut :
 		dot11RSNAConfigGroupUpdateTimeOut;
 	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
-			       wpa_send_eapol_timeout, hapd, sta);
+			       wpa_send_eapol_timeout, wpa_auth, sm);
 }
 
 
@@ -1989,7 +2569,7 @@
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
 	u16 key_info;
-	int type, ret = 0;
+	int ret = 0;
 	u8 mic[16];
 
 	if (data_len < sizeof(*hdr) + sizeof(*key))
@@ -1998,7 +2578,6 @@
 	hdr = (struct ieee802_1x_hdr *) data;
 	key = (struct wpa_eapol_key *) (hdr + 1);
 	key_info = ntohs(key->key_info);
-	type = key_info & WPA_KEY_INFO_TYPE_MASK;
 	memcpy(mic, key->key_mic, 16);
 	memset(key->key_mic, 0, 16);
 	if (wpa_calc_eapol_key_mic(key_info & WPA_KEY_INFO_TYPE_MASK,
@@ -2010,16 +2589,23 @@
 }
 
 
-void wpa_sm_event(struct hostapd_data *hapd, struct sta_info *sta,
-		  wpa_event event)
+void wpa_remove_ptk(struct wpa_state_machine *sm)
+{
+	sm->PTK_valid = FALSE;
+	memset(&sm->PTK, 0, sizeof(sm->PTK));
+	wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0);
+	sm->pairwise_set = FALSE;
+}
+
+
+void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 {
-	struct wpa_state_machine *sm = sta->wpa_sm;
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "event %d notification", event);
 	if (sm == NULL)
 		return;
 
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "event %d notification", event);
+
 	switch (event) {
 	case WPA_AUTH:
 	case WPA_ASSOC:
@@ -2037,11 +2623,8 @@
 	sm->PTK_valid = FALSE;
 	memset(&sm->PTK, 0, sizeof(sm->PTK));
 
-	if (event != WPA_REAUTH_EAPOL) {
-		sm->pairwise_set = FALSE;
-		hostapd_set_encryption(sm->hapd, "none", sm->sta->addr, 0,
-				       (u8 *) "", 0);
-	}
+	if (event != WPA_REAUTH_EAPOL)
+		wpa_remove_ptk(sm);
 
 	wpa_sm_step(sm);
 }
@@ -2063,31 +2646,9 @@
 }
 
 
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct wpa_state_machine \
-*sm)
-
-#define SM_ENTRY(machine, _state, _data) \
-sm->changed = TRUE; \
-sm->_data ## _ ## state = machine ## _ ## _state; \
-if (sm->hapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \
-	printf("WPA: " MACSTR " " #machine " entering state " #_state \
-		"\n", MAC2STR(sm->sta->addr));
-
-#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct wpa_state_machine *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-
 SM_STATE(WPA_PTK, INITIALIZE)
 {
-	struct hostapd_data *hapd = sm->hapd;
-
-	SM_ENTRY(WPA_PTK, INITIALIZE, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
 	if (sm->Init) {
 		/* Init flag is not cleared here, so avoid busy
 		 * loop by claiming nothing changed. */
@@ -2096,64 +2657,75 @@
 
 	sm->keycount = 0;
 	if (sm->GUpdateStationKeys)
-		hapd->wpa_auth->GKeyDoneStations--;
+		sm->group->GKeyDoneStations--;
 	sm->GUpdateStationKeys = FALSE;
-	if (sm->sta->wpa == WPA_VERSION_WPA)
+	if (sm->wpa == WPA_VERSION_WPA)
 		sm->PInitAKeys = FALSE;
 	if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
 	       * Local AA > Remote AA)) */) {
 		sm->Pair = TRUE;
 	}
-	ieee802_1x_notify_port_enabled(sm->sta->eapol_sm, 0);
-	hostapd_set_encryption(sm->hapd, "none", sm->sta->addr, 0, (u8 *) "",
-			       0);
-	sm->pairwise_set = FALSE;
-	sm->PTK_valid = FALSE;
-	memset(&sm->PTK, 0, sizeof(sm->PTK));
-	ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 0);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
+	wpa_remove_ptk(sm);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
 	sm->TimeoutCtr = 0;
-	if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
-		ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 0);
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_authorized, 0);
+	}
 }
 
 
 SM_STATE(WPA_PTK, DISCONNECT)
 {
-	SM_ENTRY(WPA_PTK, DISCONNECT, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
 	sm->Disconnect = FALSE;
-	wpa_sta_disconnect(sm->hapd, sm->sta);
+	wpa_sta_disconnect(sm->wpa_auth, sm->addr);
 }
 
 
 SM_STATE(WPA_PTK, DISCONNECTED)
 {
-	SM_ENTRY(WPA_PTK, DISCONNECTED, wpa_ptk);
-	sm->hapd->wpa_auth->GNoStations--;
+	SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
+	if (sm->sta_counted) {
+		sm->group->GNoStations--;
+		sm->sta_counted = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPA: WPA_PTK::DISCONNECTED - did not "
+			   "decrease GNoStations (STA " MACSTR ")",
+			   MAC2STR(sm->addr));
+	}
 	sm->DeauthenticationRequest = FALSE;
 }
 
 
 SM_STATE(WPA_PTK, AUTHENTICATION)
 {
-	SM_ENTRY(WPA_PTK, AUTHENTICATION, wpa_ptk);
-	sm->hapd->wpa_auth->GNoStations++;
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
+	if (!sm->sta_counted) {
+		sm->group->GNoStations++;
+		sm->sta_counted = 1;
+	} else {
+		wpa_printf(MSG_DEBUG, "WPA: WPA_PTK::DISCONNECTED - did not "
+			   "increase GNoStations (STA " MACSTR ")",
+			   MAC2STR(sm->addr));
+	}
 	memset(&sm->PTK, 0, sizeof(sm->PTK));
 	sm->PTK_valid = FALSE;
-	if (sm->sta->eapol_sm) {
-		sm->sta->eapol_sm->portControl = Auto;
-		sm->sta->eapol_sm->portEnabled = TRUE;
-	}
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
+			   1);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
 	sm->AuthenticationRequest = FALSE;
 }
 
 
 SM_STATE(WPA_PTK, AUTHENTICATION2)
 {
-	SM_ENTRY(WPA_PTK, AUTHENTICATION2, wpa_ptk);
-	memcpy(sm->ANonce, sm->hapd->wpa_auth->Counter, WPA_NONCE_LEN);
-	inc_byte_array(sm->hapd->wpa_auth->Counter, WPA_NONCE_LEN);
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
+	memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+	inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
 	sm->ReAuthenticationRequest = FALSE;
-	/* IEEE 802.11i/D9.0 does not clear TimeoutCtr here, but this is more
+	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
 	 * logical place than INITIALIZE since AUTHENTICATION2 can be
 	 * re-entered on ReAuthenticationRequest without going through
 	 * INITIALIZE. */
@@ -2163,24 +2735,22 @@
 
 SM_STATE(WPA_PTK, INITPMK)
 {
-	u8 *key;
-	size_t len;
-	SM_ENTRY(WPA_PTK, INITPMK, wpa_ptk);
-	if (sm->sta->pmksa) {
+	size_t len = WPA_PMK_LEN;
+
+	SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
+	if (sm->pmksa) {
 		wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
-		memcpy(sm->PMK, sm->sta->pmksa->pmk, WPA_PMK_LEN);
-		pmksa_cache_to_eapol_data(sm->sta->pmksa, sm->sta->eapol_sm);
-	} else if ((key = ieee802_1x_get_key_crypt(sm->sta->eapol_sm, &len))) {
+		memcpy(sm->PMK, sm->pmksa->pmk, WPA_PMK_LEN);
+	} else if (wpa_auth_get_pmk(sm->wpa_auth, sm->addr, sm->PMK, &len) ==
+		   0) {
 		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
 			   "(len=%lu)", (unsigned long) len);
-		if (len > WPA_PMK_LEN)
-			len = WPA_PMK_LEN;
-		memcpy(sm->PMK, key, len);
 	} else {
 		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
 	}
-	sm->sta->req_replay_counter_used = 0;
-	/* IEEE 802.11i/D9.0 does not set keyRun to FALSE, but not doing this
+
+	sm->req_replay_counter_used = 0;
+	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
 	 * will break reauthentication since EAPOL state machines may not be
 	 * get into AUTHENTICATING state that clears keyRun before WPA state
 	 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
@@ -2188,45 +2758,57 @@
 	 * eventually fail in 4-Way Handshake because Supplicant uses PMK
 	 * derived from the new AAA Key. Setting keyRun = FALSE here seems to
 	 * be good workaround for this issue. */
-	if (sm->sta->eapol_sm)
-		sm->sta->eapol_sm->keyRun = FALSE;
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
 }
 
 
 SM_STATE(WPA_PTK, INITPSK)
 {
 	const u8 *psk;
-	SM_ENTRY(WPA_PTK, INITPSK, wpa_ptk);
-	psk = hostapd_get_psk(sm->hapd->conf, sm->sta->addr, NULL);
+	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
+	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
 	if (psk)
 		memcpy(sm->PMK, psk, WPA_PMK_LEN);
-	sm->sta->req_replay_counter_used = 0;
+	sm->req_replay_counter_used = 0;
 }
 
 
 SM_STATE(WPA_PTK, PTKSTART)
 {
-	u8 *pmkid = NULL;
+	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
 	size_t pmkid_len = 0;
 
-	SM_ENTRY(WPA_PTK, PTKSTART, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
 	sm->PTKRequest = FALSE;
 	sm->TimeoutEvt = FALSE;
-	hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "sending 1/4 msg of 4-Way Handshake");
-	if (sm->sta->pmksa &&
-	    (pmkid = malloc(2 + RSN_SELECTOR_LEN + PMKID_LEN))) {
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/4 msg of 4-Way Handshake");
+	/*
+	 * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
+	 * one possible PSK for this STA.
+	 */
+	if (sm->wpa == WPA_VERSION_WPA2 &&
+	    sm->wpa_key_mgmt != WPA_KEY_MGMT_PSK) {
+		pmkid = buf;
 		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
 		pmkid[0] = WLAN_EID_GENERIC;
 		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
 		memcpy(&pmkid[2], RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN);
-		memcpy(&pmkid[2 + RSN_SELECTOR_LEN], sm->sta->pmksa->pmkid,
-		       PMKID_LEN);
+		if (sm->pmksa)
+			memcpy(&pmkid[2 + RSN_SELECTOR_LEN], sm->pmksa->pmkid,
+			       PMKID_LEN);
+		else {
+			/*
+			 * Calculate PMKID since no PMKSA cache entry was
+			 * available with pre-calculated PMKID.
+			 */
+			rsn_pmkid(sm->PMK, WPA_PMK_LEN, sm->wpa_auth->addr,
+				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN]);
+		}
 	}
-	wpa_send_eapol(sm->hapd, sm->sta, 0, 0, 1, 0, 1, NULL, sm->ANonce,
-		       pmkid, pmkid_len, NULL, 0, 0);
-	free(pmkid);
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+		       sm->ANonce, pmkid, pmkid_len, 0, 0);
 	sm->TimeoutCtr++;
 }
 
@@ -2237,23 +2819,22 @@
 	int ok = 0;
 	const u8 *pmk = NULL;
 
-	SM_ENTRY(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
 	sm->EAPOLKeyReceived = FALSE;
 
 	/* WPA with IEEE 802.1X: use the derived PMK from EAP
 	 * WPA-PSK: iterate through possible PSKs and select the one matching
 	 * the packet */
 	for (;;) {
-		if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
-			pmk = hostapd_get_psk(sm->hapd->conf, sm->sta->addr,
-					      pmk);
+		if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
+			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
 			if (pmk == NULL)
 				break;
 		} else
 			pmk = sm->PMK;
 
-		wpa_pmk_to_ptk(sm->hapd, pmk, sm->hapd->own_addr,
-			       sm->sta->addr, sm->ANonce, sm->SNonce,
+		wpa_pmk_to_ptk(pmk, sm->wpa_auth->addr, sm->addr,
+			       sm->ANonce, sm->SNonce,
 			       (u8 *) &PTK, sizeof(PTK));
 
 		if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
@@ -2262,20 +2843,19 @@
 			break;
 		}
 
-		if (sm->sta->wpa_key_mgmt != WPA_KEY_MGMT_PSK)
+		if (sm->wpa_key_mgmt != WPA_KEY_MGMT_PSK)
 			break;
 	}
 
 	if (!ok) {
-		hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-			       HOSTAPD_LEVEL_DEBUG, "invalid MIC in msg 2/4 "
-			       "of 4-Way Handshake");
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"invalid MIC in msg 2/4 of 4-Way Handshake");
 		return;
 	}
 
-	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->hapd, sm->sta);
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
-	if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
+	if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
 		/* PSK may have changed from the previous choice, so update
 		 * state machine data based on whatever PSK was selected here.
 		 */
@@ -2291,99 +2871,199 @@
 
 SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
 {
-	SM_ENTRY(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
 	sm->TimeoutCtr = 0;
 }
 
 
+#ifdef CONFIG_IEEE80211W
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	if (sm->mgmt_frame_prot) {
+		return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_dhv_kde) +
+			2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+	}
+
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_dhv_kde dhv;
+	struct wpa_igtk_kde igtk;
+	struct wpa_group *gsm = sm->group;
+	u8 mac[32];
+	const u8 *addr[3];
+	size_t len[3];
+
+	if (!sm->mgmt_frame_prot)
+		return pos;
+
+	addr[0] = sm->wpa_auth->addr;
+	len[0] = ETH_ALEN;
+	addr[1] = sm->addr;
+	len[1] = ETH_ALEN;
+	addr[2] = gsm->DGTK;
+	len[2] = WPA_DGTK_LEN;
+	sha256_vector(3, addr, len, mac);
+	memcpy(dhv.dhv, mac, WPA_DHV_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: DHV", dhv.dhv, WPA_DHV_LEN);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_DHV,
+			  (const u8 *) &dhv, sizeof(dhv), NULL, 0);
+
+	igtk.keyid[0] = gsm->GN;
+	igtk.keyid[1] = 0;
+	if (wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN, igtk.pn) < 0)
+		memset(igtk.pn, 0, sizeof(igtk.pn));
+	memcpy(igtk.igtk, gsm->IGTK[gsm->GN - 1], WPA_IGTK_LEN);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
+			  (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+
+	return pos;
+}
+
+#else /* CONFIG_IEEE80211W */
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	return pos;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-	u8 rsc[WPA_KEY_RSC_LEN];
-	struct wpa_authenticator *gsm = sm->hapd->wpa_auth;
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+	size_t gtk_len, kde_len;
+	struct wpa_group *gsm = sm->group;
 	u8 *wpa_ie;
-	int wpa_ie_len;
+	int wpa_ie_len, secure, keyidx, encr = 0;
 
-	SM_ENTRY(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
 	sm->TimeoutEvt = FALSE;
 	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, GTK[GN])
 	 */
 	memset(rsc, 0, WPA_KEY_RSC_LEN);
-	hostapd_get_seqnum(sm->hapd, NULL, gsm->GN, rsc);
-	wpa_ie = sm->hapd->wpa_ie;
-	wpa_ie_len = sm->hapd->wpa_ie_len;
-	if (sm->sta->wpa == WPA_VERSION_WPA &&
-	    (sm->hapd->conf->wpa & HOSTAPD_WPA_VERSION_WPA2) &&
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	wpa_ie = sm->wpa_auth->wpa_ie;
+	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+	if (sm->wpa == WPA_VERSION_WPA &&
+	    (sm->wpa_auth->conf.wpa & HOSTAPD_WPA_VERSION_WPA2) &&
 	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
 		/* WPA-only STA, remove RSN IE */
 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		wpa_ie_len = wpa_ie[1] + 2;
 	}
-	hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "sending 3/4 msg of 4-Way Handshake");
-	wpa_send_eapol(sm->hapd, sm->sta,
-		       sm->sta->wpa == WPA_VERSION_WPA2 ? 1 : 0,
-		       1, 1, 1, 1, rsc, sm->ANonce,
-		       wpa_ie, wpa_ie_len,
-		       gsm->GTK[gsm->GN - 1], gsm->GTK_len, gsm->GN);
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 3/4 msg of 4-Way Handshake");
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		/* WPA2 send GTK in the 4-way handshake */
+		secure = 1;
+		gtk = gsm->GTK[gsm->GN - 1];
+		gtk_len = gsm->GTK_len;
+		keyidx = gsm->GN;
+		_rsc = rsc;
+		encr = 1;
+	} else {
+		/* WPA does not include GTK in msg 3/4 */
+		secure = 0;
+		gtk = NULL;
+		gtk_len = 0;
+		keyidx = 0;
+		_rsc = NULL;
+	}
+
+	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+	if (gtk)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+	kde = malloc(kde_len);
+	if (kde == NULL)
+		return;
+
+	pos = kde;
+	memcpy(pos, wpa_ie, wpa_ie_len);
+	pos += wpa_ie_len;
+	if (gtk) {
+		u8 hdr[2];
+		hdr[0] = keyidx & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gtk, gtk_len);
+	}
+	pos = ieee80211w_kde_add(sm, pos);
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+		       WPA_KEY_INFO_KEY_TYPE,
+		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+	free(kde);
 	sm->TimeoutCtr++;
 }
 
 
 SM_STATE(WPA_PTK, PTKINITDONE)
 {
-	SM_ENTRY(WPA_PTK, PTKINITDONE, wpa_ptk);
+	SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
 	sm->EAPOLKeyReceived = FALSE;
 	if (sm->Pair) {
 		char *alg;
 		int klen;
-		if (sm->sta->pairwise == WPA_CIPHER_TKIP) {
+		if (sm->pairwise == WPA_CIPHER_TKIP) {
 			alg = "TKIP";
 			klen = 32;
 		} else {
 			alg = "CCMP";
 			klen = 16;
 		}
-		if (hostapd_set_encryption(sm->hapd, alg, sm->sta->addr, 0,
-					   sm->PTK.tk1, klen)) {
-			wpa_sta_disconnect(sm->hapd, sm->sta);
+		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+				     sm->PTK.tk1, klen)) {
+			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
 			return;
 		}
 		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
 		sm->pairwise_set = TRUE;
 
-		if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
-			ieee802_1x_set_sta_authorized(sm->hapd, sm->sta, 1);
+		if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK) {
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_authorized, 1);
+		}
 	}
 
 	if (0 /* IBSS == TRUE */) {
 		sm->keycount++;
 		if (sm->keycount == 2) {
-			ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 1);
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_portValid, 1);
 		}
 	} else {
-		ieee802_1x_notify_port_valid(sm->sta->eapol_sm, 1);
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
+				   1);
 	}
-	if (sm->sta->eapol_sm) {
-		sm->sta->eapol_sm->keyAvailable = FALSE;
-		sm->sta->eapol_sm->keyDone = TRUE;
-	}
-	if (sm->sta->wpa == WPA_VERSION_WPA)
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+	if (sm->wpa == WPA_VERSION_WPA)
 		sm->PInitAKeys = TRUE;
 	else
 		sm->has_GTK = TRUE;
-	hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_INFO, "pairwise key handshake completed "
-		       "(%s)",
-		       sm->sta->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
-	if (sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
-		accounting_sta_start(sm->hapd, sm->sta);
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "pairwise key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
 }
 
 
 SM_STEP(WPA_PTK)
 {
-	struct wpa_authenticator *wpa_auth = sm->hapd->wpa_auth;
+	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
 
 	if (sm->Init)
 		SM_ENTER(WPA_PTK, INITIALIZE);
@@ -2411,15 +3091,17 @@
 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
 		break;
 	case WPA_PTK_AUTHENTICATION2:
-		if ((sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_IEEE8021X) &&
-		    sm->sta->eapol_sm && sm->sta->eapol_sm->keyRun)
+		if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_IEEE8021X) &&
+		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyRun) > 0)
 			SM_ENTER(WPA_PTK, INITPMK);
-		else if ((sm->sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
+		else if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
 			 /* FIX: && 802.1X::keyRun */)
 			SM_ENTER(WPA_PTK, INITPSK);
 		break;
 	case WPA_PTK_INITPMK:
-		if (sm->sta->eapol_sm && sm->sta->eapol_sm->keyAvailable)
+		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyAvailable) > 0)
 			SM_ENTER(WPA_PTK, PTKSTART);
 		else {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
@@ -2427,13 +3109,11 @@
 		}
 		break;
 	case WPA_PTK_INITPSK:
-		if (hostapd_get_psk(sm->hapd->conf, sm->sta->addr, NULL))
+		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
 			SM_ENTER(WPA_PTK, PTKSTART);
 		else {
-			hostapd_logger(sm->hapd, sm->sta->addr,
-				       HOSTAPD_MODULE_WPA,
-				       HOSTAPD_LEVEL_INFO,
-				       "no PSK configured for the STA");
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+					"no PSK configured for the STA");
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		}
@@ -2442,7 +3122,8 @@
 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
 		    sm->EAPOLKeyPairwise)
 			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
-		else if (sm->TimeoutCtr > dot11RSNAConfigPairwiseUpdateCount) {
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
@@ -2464,7 +3145,8 @@
 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
 		    sm->EAPOLKeyPairwise && sm->MICVerified)
 			SM_ENTER(WPA_PTK, PTKINITDONE);
-		else if (sm->TimeoutCtr > dot11RSNAConfigPairwiseUpdateCount) {
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
 			wpa_auth->dot11RSNA4WayHandshakeFailures++;
 			SM_ENTER(WPA_PTK, DISCONNECT);
 		} else if (sm->TimeoutEvt)
@@ -2478,7 +3160,7 @@
 
 SM_STATE(WPA_PTK_GROUP, IDLE)
 {
-	SM_ENTRY(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
+	SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
 	if (sm->Init) {
 		/* Init flag is not cleared here, so avoid busy
 		 * loop by claiming nothing changed. */
@@ -2491,46 +3173,69 @@
 SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
 {
 	u8 rsc[WPA_KEY_RSC_LEN];
-	struct wpa_authenticator *gsm = sm->hapd->wpa_auth;
+	struct wpa_group *gsm = sm->group;
+	u8 *kde, *pos, hdr[2];
+	size_t kde_len;
 
-	SM_ENTRY(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
-	if (sm->sta->wpa == WPA_VERSION_WPA)
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
+	if (sm->wpa == WPA_VERSION_WPA)
 		sm->PInitAKeys = FALSE;
 	sm->TimeoutEvt = FALSE;
 	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
 	memset(rsc, 0, WPA_KEY_RSC_LEN);
 	if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
-		hostapd_get_seqnum(sm->hapd, NULL, gsm->GN, rsc);
-	hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "sending 1/2 msg of Group Key Handshake");
-	wpa_send_eapol(sm->hapd, sm->sta, 1, 1, 1, !sm->Pair, 0, rsc,
-		       gsm->GNonce, NULL, 0,
-		       gsm->GTK[gsm->GN - 1], gsm->GTK_len, gsm->GN);
+		wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/2 msg of Group Key Handshake");
+
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
+			ieee80211w_kde_len(sm);
+		kde = malloc(kde_len);
+		if (kde == NULL)
+			return;
+
+		pos = kde;
+		hdr[0] = gsm->GN & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+		pos = ieee80211w_kde_add(sm, pos);
+	} else {
+		kde = gsm->GTK[gsm->GN - 1];
+		pos = kde + gsm->GTK_len;
+	}
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK |
+		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
+		       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
+	if (sm->wpa == WPA_VERSION_WPA2)
+		free(kde);
 	sm->GTimeoutCtr++;
 }
 
 
 SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
 {
-	SM_ENTRY(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
 	sm->EAPOLKeyReceived = FALSE;
 	sm->GUpdateStationKeys = FALSE;
-	sm->hapd->wpa_auth->GKeyDoneStations--;
+	sm->group->GKeyDoneStations--;
 	sm->GTimeoutCtr = 0;
 	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
-	hostapd_logger(sm->hapd, sm->sta->addr, HOSTAPD_MODULE_WPA,
-		       HOSTAPD_LEVEL_INFO, "group key handshake completed "
-		       "(%s)",
-		       sm->sta->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "group key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
 	sm->has_GTK = TRUE;
 }
 
 
 SM_STATE(WPA_PTK_GROUP, KEYERROR)
 {
-	SM_ENTRY(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
-	sm->hapd->wpa_auth->GKeyDoneStations--;
+	SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
+	sm->group->GKeyDoneStations--;
 	sm->GUpdateStationKeys = FALSE;
 	sm->Disconnect = TRUE;
 }
@@ -2543,14 +3248,15 @@
 	else switch (sm->wpa_ptk_group_state) {
 	case WPA_PTK_GROUP_IDLE:
 		if (sm->GUpdateStationKeys ||
-		    (sm->sta->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
+		    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
 			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
 		break;
 	case WPA_PTK_GROUP_REKEYNEGOTIATING:
 		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
 		    !sm->EAPOLKeyPairwise && sm->MICVerified)
 			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
-		else if (sm->GTimeoutCtr > dot11RSNAConfigGroupUpdateCount)
+		else if (sm->GTimeoutCtr >
+			 (int) dot11RSNAConfigGroupUpdateCount)
 			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
 		else if (sm->TimeoutEvt)
 			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
@@ -2565,159 +3271,185 @@
 }
 
 
-static void wpa_group_gtk_init(struct hostapd_data *hapd)
+static void wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+			   struct wpa_group *group)
 {
-	struct wpa_authenticator *sm = hapd->wpa_auth;
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "WPA: group state machine "
-		      "entering state GTK_INIT\n");
-	sm->changed = FALSE; /* GInit is not cleared here; avoid loop */
-	sm->wpa_group_state = WPA_GROUP_GTK_INIT;
+	/* FIX: is this the correct way of getting GNonce? */
+	memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+	inc_byte_array(group->Counter, WPA_NONCE_LEN);
+	wpa_gmk_to_gtk(group->GMK, wpa_auth->addr, group->GNonce,
+		       group->GTK[group->GN - 1], group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) {
+		hostapd_get_rand(group->DGTK, WPA_DGTK_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "DGTK", group->DGTK, WPA_DGTK_LEN);
+		hostapd_get_rand(group->IGTK[group->GN - 1], WPA_IGTK_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "IGTK",
+				group->IGTK[group->GN - 1], WPA_IGTK_LEN);
+	}
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
+			       struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+	group->wpa_group_state = WPA_GROUP_GTK_INIT;
 
 	/* GTK[0..N] = 0 */
-	memset(sm->GTK, 0, sizeof(sm->GTK));
-	sm->GN = 1;
-	sm->GM = 2;
+	memset(group->GTK, 0, sizeof(group->GTK));
+	group->GN = 1;
+	group->GM = 2;
 	/* GTK[GN] = CalcGTK() */
-	/* FIX: is this the correct way of getting GNonce? */
-	memcpy(sm->GNonce, sm->Counter, WPA_NONCE_LEN);
-	inc_byte_array(sm->Counter, WPA_NONCE_LEN);
-	wpa_gmk_to_gtk(hapd, sm->GMK, hapd->own_addr, sm->GNonce,
-		       sm->GTK[sm->GN - 1], sm->GTK_len);
+	wpa_gtk_update(wpa_auth, group);
 }
 
 
-static void wpa_group_setkeys(struct hostapd_data *hapd)
+static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 {
-	struct wpa_authenticator *sm = hapd->wpa_auth;
-	struct sta_info *sta;
-	int tmp;
-
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "WPA: group state machine "
-		      "entering state SETKEYS\n");
-	sm->changed = TRUE;
-	sm->wpa_group_state = WPA_GROUP_SETKEYS;
-	sm->GTKReKey = FALSE;
-	tmp = sm->GM;
-	sm->GM = sm->GN;
-	sm->GN = tmp;
-	sm->GKeyDoneStations = sm->GNoStations;
-	/* FIX: is this the correct way of getting GNonce? */
-	memcpy(sm->GNonce, sm->Counter, WPA_NONCE_LEN);
-	inc_byte_array(sm->Counter, WPA_NONCE_LEN);
-	wpa_gmk_to_gtk(hapd, sm->GMK, hapd->own_addr, sm->GNonce,
-		       sm->GTK[sm->GN - 1], sm->GTK_len);
-
-	sta = hapd->sta_list;
-	while (sta) {
-		if (sta->wpa_sm) {
-			sta->wpa_sm->GUpdateStationKeys = TRUE;
-			wpa_sm_step(sta->wpa_sm);
-		}
-		sta = sta->next;
-	}
+	sm->GUpdateStationKeys = TRUE;
+	wpa_sm_step(sm);
+	return 0;
 }
 
 
-static void wpa_group_setkeysdone(struct hostapd_data *hapd)
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
 {
-	struct wpa_authenticator *sm = hapd->wpa_auth;
+	int tmp;
 
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "WPA: group state machine "
-		      "entering state SETKEYSDONE\n");
-	sm->changed = TRUE;
-	sm->wpa_group_state = WPA_GROUP_SETKEYSDONE;
-	hostapd_set_encryption(hapd, wpa_alg_txt(hapd->conf->wpa_group),
-			       NULL, sm->GN, sm->GTK[sm->GN - 1], sm->GTK_len);
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYS;
+	group->GTKReKey = FALSE;
+	tmp = group->GM;
+	group->GM = group->GN;
+	group->GN = tmp;
+	group->GKeyDoneStations = group->GNoStations;
+	wpa_gtk_update(wpa_auth, group);
+
+	wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
 }
 
 
-static void wpa_group_sm_step(struct hostapd_data *hapd)
-{
-	struct wpa_authenticator *sm = hapd->wpa_auth;
-
-	if (sm->GInit) {
-		wpa_group_gtk_init(hapd);
-	} else if (sm->wpa_group_state == WPA_GROUP_GTK_INIT &&
-		   sm->GTKAuthenticator) {
-		wpa_group_setkeysdone(hapd);
-	} else if (sm->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
-		   sm->GTKReKey) {
-		wpa_group_setkeys(hapd);
-	} else if (sm->wpa_group_state == WPA_GROUP_SETKEYS) {
-		if (sm->GKeyDoneStations == 0)
-			wpa_group_setkeysdone(hapd);
-		else if (sm->GTKReKey)
-			wpa_group_setkeys(hapd);
-	}
+static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
+				  struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
+	wpa_auth_set_key(wpa_auth, group->vlan_id,
+			 wpa_alg_txt(wpa_auth->conf.wpa_group),
+			 NULL, group->GN, group->GTK[group->GN - 1],
+			 group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) {
+		wpa_auth_set_key(wpa_auth, group->vlan_id, "IGTK",
+				 NULL, group->GN, group->IGTK[group->GN - 1],
+				 WPA_IGTK_LEN);
+		wpa_auth_set_key(wpa_auth, group->vlan_id, "DGTK",
+				 NULL, 0, group->DGTK, WPA_DGTK_LEN);
+	}
+#endif /* CONFIG_IEEE80211W */
 }
 
 
-static int wpa_sm_sta_entry_alive(struct hostapd_data *hapd, u8 *addr)
-{
-	struct sta_info *sta;
-	sta = ap_get_sta(hapd, addr);
-	if (sta == NULL || sta->wpa_sm == NULL)
-		return 0;
-	return 1;
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
+{
+	if (group->GInit) {
+		wpa_group_gtk_init(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
+		   group->GTKAuthenticator) {
+		wpa_group_setkeysdone(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
+		   group->GTKReKey) {
+		wpa_group_setkeys(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
+		if (group->GKeyDoneStations == 0)
+			wpa_group_setkeysdone(wpa_auth, group);
+		else if (group->GTKReKey)
+			wpa_group_setkeys(wpa_auth, group);
+	}
 }
 
 
 static void wpa_sm_step(struct wpa_state_machine *sm)
 {
-	struct hostapd_data *hapd = sm->hapd;
-	u8 addr[6];
-	if (sm == NULL || sm->sta == NULL || sm->sta->wpa_sm == NULL)
+	if (sm == NULL)
+		return;
+
+	if (sm->in_step_loop) {
+		/* This should not happen, but if it does, make sure we do not
+		 * end up freeing the state machine too early by exiting the
+		 * recursive call. */
+		wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
 		return;
+	}
 
-	memcpy(addr, sm->sta->addr, 6);
+	sm->in_step_loop = 1;
 	do {
+		if (sm->pending_deinit)
+			break;
+
 		sm->changed = FALSE;
-		sm->hapd->wpa_auth->changed = FALSE;
+		sm->wpa_auth->group->changed = FALSE;
 
 		SM_STEP_RUN(WPA_PTK);
-		if (!wpa_sm_sta_entry_alive(hapd, addr))
+		if (sm->pending_deinit)
 			break;
 		SM_STEP_RUN(WPA_PTK_GROUP);
-		if (!wpa_sm_sta_entry_alive(hapd, addr))
+		if (sm->pending_deinit)
 			break;
-		wpa_group_sm_step(sm->hapd);
-		if (!wpa_sm_sta_entry_alive(hapd, addr))
-			break;
-	} while (sm->changed || sm->hapd->wpa_auth->changed);
+		wpa_group_sm_step(sm->wpa_auth, sm->group);
+	} while (sm->changed || sm->wpa_auth->group->changed);
+	sm->in_step_loop = 0;
+
+	if (sm->pending_deinit) {
+		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		wpa_free_sta_sm(sm);
+	}
 }
 
 
 static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
 {
-	struct wpa_state_machine *sm = timeout_ctx;
+	struct wpa_state_machine *sm = eloop_ctx;
 	wpa_sm_step(sm);
 }
 
 
-void wpa_sm_notify(struct hostapd_data *hapd, struct sta_info *sta)
+void wpa_auth_sm_notify(struct wpa_state_machine *sm)
 {
-	if (sta->wpa_sm == NULL)
+	if (sm == NULL)
 		return;
-	eloop_register_timeout(0, 0, wpa_sm_call_step, hapd, sta->wpa_sm);
+	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
 }
 
 
-void wpa_gtk_rekey(struct hostapd_data *hapd)
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
 {
-	struct wpa_authenticator *sm = hapd->wpa_auth;
 	int tmp, i;
+	struct wpa_group *group;
 
-	if (sm == NULL)
+	if (wpa_auth == NULL)
 		return;
 
+	group = wpa_auth->group;
+
 	for (i = 0; i < 2; i++) {
-		tmp = sm->GM;
-		sm->GM = sm->GN;
-		sm->GN = tmp;
-		memcpy(sm->GNonce, sm->Counter, WPA_NONCE_LEN);
-		inc_byte_array(sm->Counter, WPA_NONCE_LEN);
-		wpa_gmk_to_gtk(hapd, sm->GMK, hapd->own_addr, sm->GNonce,
-			       sm->GTK[sm->GN - 1], sm->GTK_len);
+		tmp = group->GM;
+		group->GM = group->GN;
+		group->GN = tmp;
+		wpa_gtk_update(wpa_auth, group);
 	}
 }
 
@@ -2748,151 +3480,317 @@
 #define RSN_SUITE "%02x-%02x-%02x-%d"
 #define RSN_SUITE_ARG(s) (s)[0], (s)[1], (s)[2], (s)[3]
 
-int wpa_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
 {
-	int len = 0, i;
-	char pmkid_txt[PMKID_LEN * 2 + 1], *pos;
+	int len = 0, ret;
+	char pmkid_txt[PMKID_LEN * 2 + 1];
 
-	len += snprintf(buf + len, buflen - len,
-			"dot11RSNAOptionImplemented=TRUE\n"
-			"dot11RSNAPreauthenticationImplemented=TRUE\n"
-			"dot11RSNAEnabled=%s\n"
-			"dot11RSNAPreauthenticationEnabled=%s\n",
-			wpa_bool_txt(hapd->conf->wpa &
-				     HOSTAPD_WPA_VERSION_WPA2),
-			wpa_bool_txt(hapd->conf->rsn_preauth));
+	if (wpa_auth == NULL)
+		return len;
 
-	if (hapd->wpa_auth == NULL)
+	ret = snprintf(buf + len, buflen - len,
+		       "dot11RSNAOptionImplemented=TRUE\n"
+#ifdef CONFIG_RSN_PREAUTH
+		       "dot11RSNAPreauthenticationImplemented=TRUE\n"
+#else /* CONFIG_RSN_PREAUTH */
+		       "dot11RSNAPreauthenticationImplemented=FALSE\n"
+#endif /* CONFIG_RSN_PREAUTH */
+		       "dot11RSNAEnabled=%s\n"
+		       "dot11RSNAPreauthenticationEnabled=%s\n",
+		       wpa_bool_txt(wpa_auth->conf.wpa &
+				    HOSTAPD_WPA_VERSION_WPA2),
+		       wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+	if (ret < 0 || (size_t) ret >= buflen - len)
 		return len;
+	len += ret;
 
-	pos = pmkid_txt;
-	for (i = 0; i < PMKID_LEN; i++) {
-		pos += sprintf(pos, "%02x",
-			       hapd->wpa_auth->dot11RSNAPMKIDUsed[i]);
-	}
-
-	len += snprintf(buf + len, buflen - len,
-			"dot11RSNAConfigVersion=%u\n"
-			"dot11RSNAConfigPairwiseKeysSupported=9999\n"
-			/* FIX: dot11RSNAConfigGroupCipher */
-			/* FIX: dot11RSNAConfigGroupRekeyMethod */
-			/* FIX: dot11RSNAConfigGroupRekeyTime */
-			/* FIX: dot11RSNAConfigGroupRekeyPackets */
-			"dot11RSNAConfigGroupRekeyStrict=%u\n"
-			"dot11RSNAConfigGroupUpdateCount=%u\n"
-			"dot11RSNAConfigPairwiseUpdateCount=%u\n"
-			"dot11RSNAConfigGroupCipherSize=%u\n"
-			"dot11RSNAConfigPMKLifetime=%u\n"
-			"dot11RSNAConfigPMKReauthThreshold=%u\n"
-			"dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
-			"dot11RSNAConfigSATimeout=%u\n"
-			"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
-			"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
-			"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
-			"dot11RSNAPMKIDUsed=%s\n"
-			"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
-			"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
-			"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
-			"dot11RSNATKIPCounterMeasuresInvoked=%u\n"
-			"dot11RSNA4WayHandshakeFailures=%u\n"
-			"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
-			RSN_VERSION,
-			!!hapd->conf->wpa_strict_rekey,
-			dot11RSNAConfigGroupUpdateCount,
-			dot11RSNAConfigPairwiseUpdateCount,
-			wpa_cipher_bits(hapd->conf->wpa_group),
-			dot11RSNAConfigPMKLifetime,
-			dot11RSNAConfigPMKReauthThreshold,
-			dot11RSNAConfigSATimeout,
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAAuthenticationSuiteSelected),
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAPairwiseCipherSelected),
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAGroupCipherSelected),
-			pmkid_txt,
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAAuthenticationSuiteRequested),
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAPairwiseCipherRequested),
-			RSN_SUITE_ARG(hapd->wpa_auth->
-				      dot11RSNAGroupCipherRequested),
-			hapd->wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
-			hapd->wpa_auth->dot11RSNA4WayHandshakeFailures);
+	wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+			 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
+
+	ret = snprintf(buf + len, buflen - len,
+		       "dot11RSNAConfigVersion=%u\n"
+		       "dot11RSNAConfigPairwiseKeysSupported=9999\n"
+		       /* FIX: dot11RSNAConfigGroupCipher */
+		       /* FIX: dot11RSNAConfigGroupRekeyMethod */
+		       /* FIX: dot11RSNAConfigGroupRekeyTime */
+		       /* FIX: dot11RSNAConfigGroupRekeyPackets */
+		       "dot11RSNAConfigGroupRekeyStrict=%u\n"
+		       "dot11RSNAConfigGroupUpdateCount=%u\n"
+		       "dot11RSNAConfigPairwiseUpdateCount=%u\n"
+		       "dot11RSNAConfigGroupCipherSize=%u\n"
+		       "dot11RSNAConfigPMKLifetime=%u\n"
+		       "dot11RSNAConfigPMKReauthThreshold=%u\n"
+		       "dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
+		       "dot11RSNAConfigSATimeout=%u\n"
+		       "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+		       "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+		       "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+		       "dot11RSNAPMKIDUsed=%s\n"
+		       "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+		       "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+		       "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+		       "dot11RSNATKIPCounterMeasuresInvoked=%u\n"
+		       "dot11RSNA4WayHandshakeFailures=%u\n"
+		       "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
+		       RSN_VERSION,
+		       !!wpa_auth->conf.wpa_strict_rekey,
+		       dot11RSNAConfigGroupUpdateCount,
+		       dot11RSNAConfigPairwiseUpdateCount,
+		       wpa_cipher_bits(wpa_auth->conf.wpa_group),
+		       dot11RSNAConfigPMKLifetime,
+		       dot11RSNAConfigPMKReauthThreshold,
+		       dot11RSNAConfigSATimeout,
+		       RSN_SUITE_ARG(wpa_auth->
+				     dot11RSNAAuthenticationSuiteSelected),
+		       RSN_SUITE_ARG(wpa_auth->
+				     dot11RSNAPairwiseCipherSelected),
+		       RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
+		       pmkid_txt,
+		       RSN_SUITE_ARG(wpa_auth->
+				     dot11RSNAAuthenticationSuiteRequested),
+		       RSN_SUITE_ARG(wpa_auth->
+				     dot11RSNAPairwiseCipherRequested),
+		       RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
+		       wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
+		       wpa_auth->dot11RSNA4WayHandshakeFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	/* TODO: dot11RSNAConfigPairwiseCiphersTable */
 	/* TODO: dot11RSNAConfigAuthenticationSuitesTable */
 
 	/* Private MIB */
-	len += snprintf(buf + len, buflen - len,
-			"hostapdWPAGroupState=%d\n",
-			hapd->wpa_auth->wpa_group_state);
+	ret = snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
+		       wpa_auth->group->wpa_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	return len;
 }
 
 
-int wpa_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-		    char *buf, size_t buflen)
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
 {
-	int len = 0;
+	int len = 0, ret;
 	u8 not_used[4] = { 0, 0, 0, 0 };
 	const u8 *pairwise = not_used;
 
+	if (sm == NULL)
+		return 0;
+
 	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
 
 	/* dot11RSNAStatsEntry */
 
-	if (sta->wpa == WPA_VERSION_WPA) {
-		if (sta->pairwise == WPA_CIPHER_CCMP)
+	if (sm->wpa == WPA_VERSION_WPA) {
+		if (sm->pairwise == WPA_CIPHER_CCMP)
 			pairwise = WPA_CIPHER_SUITE_CCMP;
-		else if (sta->pairwise == WPA_CIPHER_TKIP)
+		else if (sm->pairwise == WPA_CIPHER_TKIP)
 			pairwise = WPA_CIPHER_SUITE_TKIP;
-		else if (sta->pairwise == WPA_CIPHER_WEP104)
+		else if (sm->pairwise == WPA_CIPHER_WEP104)
 			pairwise = WPA_CIPHER_SUITE_WEP104;
-		else if (sta->pairwise == WPA_CIPHER_WEP40)
+		else if (sm->pairwise == WPA_CIPHER_WEP40)
 			pairwise = WPA_CIPHER_SUITE_WEP40;
-		else if (sta->pairwise == WPA_CIPHER_NONE)
+		else if (sm->pairwise == WPA_CIPHER_NONE)
 			pairwise = WPA_CIPHER_SUITE_NONE;
-	} else if (sta->wpa == WPA_VERSION_WPA2) {
-		if (sta->pairwise == WPA_CIPHER_CCMP)
+	} else if (sm->wpa == WPA_VERSION_WPA2) {
+		if (sm->pairwise == WPA_CIPHER_CCMP)
 			pairwise = RSN_CIPHER_SUITE_CCMP;
-		else if (sta->pairwise == WPA_CIPHER_TKIP)
+		else if (sm->pairwise == WPA_CIPHER_TKIP)
 			pairwise = RSN_CIPHER_SUITE_TKIP;
-		else if (sta->pairwise == WPA_CIPHER_WEP104)
+		else if (sm->pairwise == WPA_CIPHER_WEP104)
 			pairwise = RSN_CIPHER_SUITE_WEP104;
-		else if (sta->pairwise == WPA_CIPHER_WEP40)
+		else if (sm->pairwise == WPA_CIPHER_WEP40)
 			pairwise = RSN_CIPHER_SUITE_WEP40;
-		else if (sta->pairwise == WPA_CIPHER_NONE)
+		else if (sm->pairwise == WPA_CIPHER_NONE)
 			pairwise = RSN_CIPHER_SUITE_NONE;
 	} else
 		return 0;
 
-	len += snprintf(buf + len, buflen - len,
-			/* TODO: dot11RSNAStatsIndex */
-			"dot11RSNAStatsSTAAddress=" MACSTR "\n"
-			"dot11RSNAStatsVersion=1\n"
-			"dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
-			/* TODO: dot11RSNAStatsTKIPICVErrors */
-			"dot11RSNAStatsTKIPLocalMICFailures=%u\n"
-			"dot11RSNAStatsTKIPRemoveMICFailures=%u\n"
-			/* TODO: dot11RSNAStatsCCMPReplays */
-			/* TODO: dot11RSNAStatsCCMPDecryptErrors */
-			/* TODO: dot11RSNAStatsTKIPReplays */,
-			MAC2STR(sta->addr),
-			RSN_SUITE_ARG(pairwise),
-			sta->dot11RSNAStatsTKIPLocalMICFailures,
-			sta->dot11RSNAStatsTKIPRemoteMICFailures);
-
-	if (sta->wpa_sm == NULL)
+	ret = snprintf(buf + len, buflen - len,
+		       /* TODO: dot11RSNAStatsIndex */
+		       "dot11RSNAStatsSTAAddress=" MACSTR "\n"
+		       "dot11RSNAStatsVersion=1\n"
+		       "dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
+		       /* TODO: dot11RSNAStatsTKIPICVErrors */
+		       "dot11RSNAStatsTKIPLocalMICFailures=%u\n"
+		       "dot11RSNAStatsTKIPRemoveMICFailures=%u\n"
+		       /* TODO: dot11RSNAStatsCCMPReplays */
+		       /* TODO: dot11RSNAStatsCCMPDecryptErrors */
+		       /* TODO: dot11RSNAStatsTKIPReplays */,
+		       MAC2STR(sm->addr),
+		       RSN_SUITE_ARG(pairwise),
+		       sm->dot11RSNAStatsTKIPLocalMICFailures,
+		       sm->dot11RSNAStatsTKIPRemoteMICFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
 		return len;
+	len += ret;
 
 	/* Private MIB */
-	len += snprintf(buf + len, buflen - len,
-			"hostapdWPAPTKState=%d\n"
-			"hostapdWPAPTKGroupState=%d\n",
-			sta->wpa_sm->wpa_ptk_state,
-			sta->wpa_sm->wpa_ptk_group_state);
+	ret = snprintf(buf + len, buflen - len,
+		       "hostapdWPAPTKState=%d\n"
+		       "hostapdWPAPTKGroupState=%d\n",
+		       sm->wpa_ptk_state,
+		       sm->wpa_ptk_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	return len;
 }
+
+
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
+{
+	if (wpa_auth)
+		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
+}
+
+
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
+{
+	return sm && sm->pairwise_set;
+}
+
+
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return -1;
+	return sm->wpa_key_mgmt;
+}
+
+
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->wpa;
+}
+
+
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry)
+{
+	if (sm == NULL || sm->pmksa != entry)
+		return -1;
+	sm->pmksa = NULL;
+	return 0;
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
+{
+	return sm ? sm->pmksa : NULL;
+}
+
+
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
+{
+	if (sm)
+		sm->dot11RSNAStatsTKIPLocalMICFailures++;
+}
+
+
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
+{
+	if (wpa_auth == NULL)
+		return NULL;
+	*len = wpa_auth->wpa_ie_len;
+	return wpa_auth->wpa_ie;
+}
+
+
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       int session_timeout, struct eapol_state_machine *eapol)
+{
+	if (sm == NULL || sm->wpa != WPA_VERSION_WPA2)
+		return -1;
+
+	if (pmksa_cache_add(sm->wpa_auth->pmksa, pmk, WPA_PMK_LEN,
+			    sm->wpa_auth->addr, sm->addr, session_timeout,
+			    eapol))
+		return 0;
+
+	return -1;
+}
+
+
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+			       const u8 *pmk, size_t len, const u8 *sta_addr,
+			       int session_timeout,
+			       struct eapol_state_machine *eapol)
+{
+	if (wpa_auth == NULL)
+		return -1;
+
+	if (pmksa_cache_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+			    sta_addr, session_timeout, eapol))
+		return 0;
+
+	return -1;
+}
+
+
+static struct wpa_group *
+wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (wpa_auth == NULL || wpa_auth->group == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
+		   vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id);
+	if (group == NULL)
+		return NULL;
+
+	group->next = wpa_auth->group->next;
+	wpa_auth->group->next = group;
+
+	return group;
+}
+
+
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (sm == NULL || sm->wpa_auth == NULL)
+		return 0;
+
+	group = sm->wpa_auth->group;
+	while (group) {
+		if (group->vlan_id == vlan_id)
+			break;
+		group = group->next;
+	}
+
+	if (group == NULL) {
+		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
+		if (group == NULL)
+			return -1;
+	}
+
+	if (sm->group == group)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
+		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+
+	if (sm->group && sm->group != group && sm->sta_counted) {
+		sm->group->GNoStations--;
+		sm->sta_counted = 0;
+		wpa_printf(MSG_DEBUG, "WLA: Decreased GNoStations for the "
+			   "previously used group state machine");
+	}
+
+	sm->group = group;
+	return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
Index: eap_peap.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_peap.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_peap.c -L contrib/hostapd/eap_peap.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_peap.c
+++ contrib/hostapd/eap_peap.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-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
@@ -12,10 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -132,10 +129,9 @@
 {
 	struct eap_peap_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->peap_version = EAP_PEAP_VERSION;
 	data->force_version = -1;
 	if (sm->user && sm->user->force_version >= 0) {
@@ -293,12 +289,10 @@
 	struct eap_hdr *hdr;
 
 	req_len = sizeof(*hdr);
-	hdr = malloc(req_len);
-	if (hdr == NULL) {
+	hdr = wpa_zalloc(req_len);
+	if (hdr == NULL)
 		return NULL;
-	}
 
-	memset(hdr, 0, req_len);
 	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
 	hdr->identifier = id;
 	hdr->length = htons(req_len);
@@ -345,12 +339,11 @@
 {
 	struct eap_hdr *resp;
 	u8 *pos;
-	size_t len;
 
 	resp = (struct eap_hdr *) respData;
 	pos = (u8 *) (resp + 1);
 	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_PEAP ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	    (ntohs(resp->length)) > respDataLen) {
 		wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
 		return TRUE;
 	}
@@ -360,14 +353,15 @@
 
 
 static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
-				u8 eap_type)
+				EapType eap_type)
 {
 	if (data->phase2_priv && data->phase2_method) {
 		data->phase2_method->reset(sm, data->phase2_priv);
 		data->phase2_method = NULL;
 		data->phase2_priv = NULL;
 	}
-	data->phase2_method = eap_sm_get_eap_methods(eap_type);
+	data->phase2_method = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+						     eap_type);
 	if (!data->phase2_method)
 		return -1;
 
@@ -395,17 +389,17 @@
 
 	hdr = (struct eap_hdr *) in_data;
 	pos = (u8 *) (hdr + 1);
-	left = in_len - sizeof(*hdr);
 
 	if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+		left = in_len - sizeof(*hdr);
 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
 			    "allowed types", pos + 1, left - 1);
 		eap_sm_process_nak(sm, pos + 1, left - 1);
 		if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
-		    sm->user->methods[sm->user_eap_method_index] !=
+		    sm->user->methods[sm->user_eap_method_index].method !=
 		    EAP_TYPE_NONE) {
-			next_type =
-				sm->user->methods[sm->user_eap_method_index++];
+			next_type = sm->user->methods[
+				sm->user_eap_method_index++].method;
 			wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
 				   next_type);
 		} else {
@@ -447,7 +441,7 @@
 		}
 
 		eap_peap_state(data, PHASE2_METHOD);
-		next_type = sm->user->methods[0];
+		next_type = sm->user->methods[0].method;
 		sm->user_eap_method_index = 1;
 		wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
 		break;
@@ -480,8 +474,9 @@
 				    u8 *in_data, size_t in_len)
 {
 	u8 *in_decrypted;
-	int buf_len, len_decrypted, len, res;
+	int len_decrypted, len, res;
 	struct eap_hdr *hdr;
+	size_t buf_len;
 
 	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
 		   " Phase 2", (unsigned long) in_len);
@@ -540,7 +535,7 @@
 		in_decrypted = (u8 *) nhdr;
 	}
 	hdr = (struct eap_hdr *) in_decrypted;
-	if (len_decrypted < sizeof(*hdr)) {
+	if (len_decrypted < (int) sizeof(*hdr)) {
 		free(in_decrypted);
 		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
 			   "EAP frame (len=%d)", len_decrypted);
@@ -612,7 +607,6 @@
 			   "use version %d",
 			   peer_version, data->peap_version, peer_version);
 		data->peap_version = peer_version;
-			   
 	}
 	if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
 		if (left < 4) {
@@ -711,16 +705,27 @@
 }
 
 
-const struct eap_method eap_method_peap =
+int eap_server_peap_register(void)
 {
-	.method = EAP_TYPE_PEAP,
-	.name = "PEAP",
-	.init = eap_peap_init,
-	.reset = eap_peap_reset,
-	.buildReq = eap_peap_buildReq,
-	.check = eap_peap_check,
-	.process = eap_peap_process,
-	.isDone = eap_peap_isDone,
-	.getKey = eap_peap_getKey,
-	.isSuccess = eap_peap_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_peap_init;
+	eap->reset = eap_peap_reset;
+	eap->buildReq = eap_peap_buildReq;
+	eap->check = eap_peap_check;
+	eap->process = eap_peap_process;
+	eap->isDone = eap_peap_isDone;
+	eap->getKey = eap_peap_getKey;
+	eap->isSuccess = eap_peap_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
--- /dev/null
+++ contrib/hostapd/eloop_none.c
@@ -0,0 +1,390 @@
+/*
+ * Event loop - empty template (basic structure, but no OS specific operations)
+ * Copyright (c) 2002-2005, 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 "eloop.h"
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(void *eloop_ctx, void *sock_ctx);
+	struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+	int signaled;
+};
+
+struct eloop_data {
+	void *user_data;
+
+	int max_sock, reader_count;
+	struct eloop_sock *readers;
+
+	struct eloop_timeout *timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+	memset(&eloop, 0, sizeof(eloop));
+	eloop.user_data = user_data;
+	return 0;
+}
+
+
+int eloop_register_read_sock(int sock,
+			     void (*handler)(int sock, void *eloop_ctx,
+					     void *sock_ctx),
+			     void *eloop_data, void *user_data)
+{
+	struct eloop_sock *tmp;
+
+	tmp = (struct eloop_sock *)
+		realloc(eloop.readers,
+			(eloop.reader_count + 1) * sizeof(struct eloop_sock));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.reader_count].sock = sock;
+	tmp[eloop.reader_count].eloop_data = eloop_data;
+	tmp[eloop.reader_count].user_data = user_data;
+	tmp[eloop.reader_count].handler = handler;
+	eloop.reader_count++;
+	eloop.readers = tmp;
+	if (sock > eloop.max_sock)
+		eloop.max_sock = sock;
+	eloop.reader_table_changed = 1;
+
+	return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	int i;
+
+	if (eloop.readers == NULL || eloop.reader_count == 0)
+		return;
+
+	for (i = 0; i < eloop.reader_count; i++) {
+		if (eloop.readers[i].sock == sock)
+			break;
+	}
+	if (i == eloop.reader_count)
+		return;
+	if (i != eloop.reader_count - 1) {
+		memmove(&eloop.readers[i], &eloop.readers[i + 1],
+			(eloop.reader_count - i - 1) *
+			sizeof(struct eloop_sock));
+	}
+	eloop.reader_count--;
+	eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp, *prev;
+
+	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	os_get_time(&timeout->time);
+	timeout->time.sec += secs;
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	timeout->next = NULL;
+
+	if (eloop.timeout == NULL) {
+		eloop.timeout = timeout;
+		return 0;
+	}
+
+	prev = NULL;
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (os_time_before(&timeout->time, &tmp->time))
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (prev == NULL) {
+		timeout->next = eloop.timeout;
+		eloop.timeout = timeout;
+	} else {
+		timeout->next = prev->next;
+		prev->next = timeout;
+	}
+
+	return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev, *next;
+	int removed = 0;
+
+	prev = NULL;
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		next = timeout->next;
+
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			if (prev == NULL)
+				eloop.timeout = next;
+			else
+				prev->next = next;
+			free(timeout);
+			removed++;
+		} else
+			prev = timeout;
+
+		timeout = next;
+	}
+
+	return removed;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.user_data,
+						 eloop.signals[i].user_data);
+		}
+	}
+}
+
+
+int eloop_register_signal(int sig,
+			  void (*handler)(int sig, void *eloop_ctx,
+					  void *signal_ctx),
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = (struct eloop_signal *)
+		realloc(eloop.signals,
+			(eloop.signal_count + 1) *
+			sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+
+	/* TODO: register signal handler */
+
+	return 0;
+}
+
+
+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
+						    void *signal_ctx),
+				    void *user_data)
+{
+#if 0
+	/* TODO: for example */
+	int ret = eloop_register_signal(SIGINT, handler, user_data);
+	if (ret == 0)
+		ret = eloop_register_signal(SIGTERM, handler, user_data);
+	return ret;
+#endif
+	return 0;
+}
+
+
+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
+						   void *signal_ctx),
+				   void *user_data)
+{
+#if 0
+	/* TODO: for example */
+	return eloop_register_signal(SIGHUP, handler, user_data);
+#endif
+	return 0;
+}
+
+
+void eloop_run(void)
+{
+	int i;
+	struct os_time tv, now;
+
+	while (!eloop.terminate &&
+		(eloop.timeout || eloop.reader_count > 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;
+		}
+
+		/*
+		 * TODO: wait for any event (read socket ready, timeout (tv),
+		 * signal
+		 */
+		os_sleep(1, 0); /* just a dummy wait for testing */
+
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		if (eloop.timeout) {
+			struct eloop_timeout *tmp;
+
+			os_get_time(&now);
+			if (!os_time_before(&now, &eloop.timeout->time)) {
+				tmp = eloop.timeout;
+				eloop.timeout = eloop.timeout->next;
+				tmp->handler(tmp->eloop_data,
+					     tmp->user_data);
+				free(tmp);
+			}
+
+		}
+
+		eloop.reader_table_changed = 0;
+		for (i = 0; i < eloop.reader_count; i++) {
+			/*
+			 * TODO: call each handler that has pending data to
+			 * read
+			 */
+			if (0 /* TODO: eloop.readers[i].sock ready */) {
+				eloop.readers[i].handler(
+					eloop.readers[i].sock,
+					eloop.readers[i].eloop_data,
+					eloop.readers[i].user_data);
+				if (eloop.reader_table_changed)
+					break;
+			}
+		}
+	}
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		prev = timeout;
+		timeout = timeout->next;
+		free(prev);
+	}
+	free(eloop.readers);
+	free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+	/*
+	 * TODO: wait for the file descriptor to have something available for
+	 * reading
+	 */
+}
+
+
+void * eloop_get_user_data(void)
+{
+	return eloop.user_data;
+}
Index: tls_openssl.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/tls_openssl.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/tls_openssl.c -L contrib/hostapd/tls_openssl.c -u -r1.2 -r1.3
--- contrib/hostapd/tls_openssl.c
+++ contrib/hostapd/tls_openssl.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2006, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #ifndef CONFIG_SMARTCARD
 #ifndef OPENSSL_NO_ENGINE
@@ -235,7 +233,7 @@
 		goto err;
 	}
 
-	if (hash_size != flen) {
+	if ((int) hash_size != flen) {
 		wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
 			   (unsigned) hash_size, flen);
 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
@@ -248,7 +246,7 @@
 	}
 
 	len = RSA_size(rsa);
-	buf = malloc(len);
+	buf = os_malloc(len);
 	if (buf == NULL) {
 		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
 		goto err;
@@ -264,7 +262,7 @@
 	ret = len;
 
 err:
-	free(buf);
+	os_free(buf);
 	CryptDestroyHash(hash);
 
 	return ret;
@@ -287,14 +285,14 @@
 		CryptReleaseContext(priv->crypt_prov, 0);
 	if (priv->cert)
 		CertFreeCertificateContext(priv->cert);
-	free(priv);
+	os_free(priv);
 }
 
 
 static int cryptoapi_finish(RSA *rsa)
 {
 	cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
-	free((void *) rsa->meth);
+	os_free((void *) rsa->meth);
 	rsa->meth = NULL;
 	return 1;
 }
@@ -315,8 +313,7 @@
 
 	if (strncmp(name, "cert://", 7) == 0) {
 		unsigned short wbuf[255];
-		MultiByteToWideChar(CP_ACP, 0, name + 7, -1,
-				    wbuf, sizeof(wbuf));
+		MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
 		ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
 						 PKCS_7_ASN_ENCODING,
 						 0, CERT_FIND_SUBJECT_STR,
@@ -327,8 +324,8 @@
 		const char *hash = name + 7;
 		unsigned char *buf;
 
-		len = strlen(hash) / 2;
-		buf = malloc(len);
+		len = os_strlen(hash) / 2;
+		buf = os_malloc(len);
 		if (buf && hexstr2bin(hash, buf, len) == 0) {
 			blob.cbData = len;
 			blob.pbData = buf;
@@ -338,7 +335,7 @@
 							 0, CERT_FIND_HASH,
 							 &blob, NULL);
 		}
-		free(buf);
+		os_free(buf);
 	}
 
 	CertCloseStore(cs, 0);
@@ -359,17 +356,15 @@
 	     strncmp(name, "hash://", 7) != 0))
 		return -1;
 
-	priv = malloc(sizeof(*priv));
-	rsa_meth = malloc(sizeof(*rsa_meth));
+	priv = os_zalloc(sizeof(*priv));
+	rsa_meth = os_zalloc(sizeof(*rsa_meth));
 	if (priv == NULL || rsa_meth == NULL) {
 		wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
 			   "for CryptoAPI RSA method");
-		free(priv);
-		free(rsa_meth);
+		os_free(priv);
+		os_free(rsa_meth);
 		return -1;
 	}
-	memset(priv, 0, sizeof(*priv));
-	memset(rsa_meth, 0, sizeof(*rsa_meth));
 
 	priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
 	if (priv->cert == NULL) {
@@ -419,8 +414,11 @@
 		goto err;
 	}
 
-	if (!SSL_use_certificate(ssl, cert))
+	if (!SSL_use_certificate(ssl, cert)) {
+		RSA_free(rsa);
+		rsa = NULL;
 		goto err;
+	}
 	pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
 	X509_free(cert);
 	cert = NULL;
@@ -442,7 +440,7 @@
 	if (rsa)
 		RSA_free(rsa);
 	else {
-		free(rsa_meth);
+		os_free(rsa_meth);
 		cryptoapi_free_data(priv);
 	}
 	return -1;
@@ -455,6 +453,10 @@
 	PCCERT_CONTEXT ctx = NULL;
 	X509 *cert;
 	char buf[128];
+	const char *store;
+#ifdef UNICODE
+	WCHAR *wstore;
+#endif /* UNICODE */
 
 	if (mingw_load_crypto_func())
 		return -1;
@@ -462,10 +464,20 @@
 	if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
 		return -1;
 
-	cs = CertOpenSystemStore(0, name + 13);
+	store = name + 13;
+#ifdef UNICODE
+	wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
+	if (wstore == NULL)
+		return -1;
+	wsprintf(wstore, L"%S", store);
+	cs = CertOpenSystemStore(0, wstore);
+	os_free(wstore);
+#else /* UNICODE */
+	cs = CertOpenSystemStore(0, store);
+#endif /* UNICODE */
 	if (cs == NULL) {
 		wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
-			   "'%s': error=%d", __func__, name + 13,
+			   "'%s': error=%d", __func__, store,
 			   (int) GetLastError());
 		return -1;
 	}
@@ -643,21 +655,25 @@
 {
 	char *engine_id = "pkcs11";
 	const char *pre_cmd[] = {
-		"SO_PATH", pkcs11_so_path,
-		"ID", engine_id,
+		"SO_PATH", NULL /* pkcs11_so_path */,
+		"ID", NULL /* engine_id */,
 		"LIST_ADD", "1",
 		/* "NO_VCHECK", "1", */
 		"LOAD", NULL,
 		NULL, NULL
 	};
 	const char *post_cmd[] = {
-		"MODULE_PATH", pkcs11_module_path,
+		"MODULE_PATH", NULL /* pkcs11_module_path */,
 		NULL, NULL
 	};
 
 	if (!pkcs11_so_path || !pkcs11_module_path)
 		return 0;
 
+	pre_cmd[1] = pkcs11_so_path;
+	pre_cmd[3] = engine_id;
+	post_cmd[1] = pkcs11_module_path;
+
 	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
 		   pkcs11_so_path);
 
@@ -673,8 +689,8 @@
 {
 	char *engine_id = "opensc";
 	const char *pre_cmd[] = {
-		"SO_PATH", opensc_so_path,
-		"ID", engine_id,
+		"SO_PATH", NULL /* opensc_so_path */,
+		"ID", NULL /* engine_id */,
 		"LIST_ADD", "1",
 		"LOAD", NULL,
 		NULL, NULL
@@ -683,6 +699,9 @@
 	if (!opensc_so_path)
 		return 0;
 
+	pre_cmd[1] = opensc_so_path;
+	pre_cmd[3] = engine_id;
+
 	wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
 		   opensc_so_path);
 
@@ -853,15 +872,14 @@
 	SSL_CTX *ssl = ssl_ctx;
 	struct tls_connection *conn;
 
-	conn = malloc(sizeof(*conn));
+	conn = os_zalloc(sizeof(*conn));
 	if (conn == NULL)
 		return NULL;
-	memset(conn, 0, sizeof(*conn));
 	conn->ssl = SSL_new(ssl);
 	if (conn->ssl == NULL) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to initialize new SSL connection");
-		free(conn);
+		os_free(conn);
 		return NULL;
 	}
 
@@ -875,7 +893,7 @@
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to create a new BIO for ssl_in");
 		SSL_free(conn->ssl);
-		free(conn);
+		os_free(conn);
 		return NULL;
 	}
 
@@ -885,7 +903,7 @@
 				"Failed to create a new BIO for ssl_out");
 		SSL_free(conn->ssl);
 		BIO_free(conn->ssl_in);
-		free(conn);
+		os_free(conn);
 		return NULL;
 	}
 
@@ -899,12 +917,12 @@
 {
 	if (conn == NULL)
 		return;
-	free(conn->pre_shared_secret);
+	os_free(conn->pre_shared_secret);
 	SSL_free(conn->ssl);
 	tls_engine_deinit(conn);
-	free(conn->subject_match);
-	free(conn->altsubject_match);
-	free(conn);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	os_free(conn);
 }
 
 
@@ -928,55 +946,71 @@
 }
 
 
-static int tls_match_altsubject(X509 *cert, const char *match)
+static int tls_match_altsubject_component(X509 *cert, int type,
+					  const char *value, size_t len)
 {
 	GENERAL_NAME *gen;
-	char *field, *tmp;
 	void *ext;
 	int i, found = 0;
-	size_t len;
 
 	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 
 	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 		gen = sk_GENERAL_NAME_value(ext, i);
-		switch (gen->type) {
-		case GEN_EMAIL:
-			field = "EMAIL";
-			break;
-		case GEN_DNS:
-			field = "DNS";
-			break;
-		case GEN_URI:
-			field = "URI";
-			break;
-		default:
-			field = NULL;
-			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
-				   "unsupported type=%d", gen->type);
-			break;
-		}
-
-		if (!field)
+		if (gen->type != type)
 			continue;
-
-		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
-			   field, gen->d.ia5->data);
-		len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) +
-			1;
-		tmp = malloc(len);
-		if (tmp == NULL)
-			continue;
-		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
-		if (strstr(tmp, match))
+		if (os_strlen((char *) gen->d.ia5->data) == len &&
+		    os_memcmp(value, gen->d.ia5->data, len) == 0)
 			found++;
-		free(tmp);
 	}
 
 	return found;
 }
 
 
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	int type;
+	const char *pos, *end;
+	size_t len;
+
+	pos = match;
+	do {
+		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+			type = GEN_EMAIL;
+			pos += 6;
+		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
+			type = GEN_DNS;
+			pos += 4;
+		} else if (os_strncmp(pos, "URI:", 4) == 0) {
+			type = GEN_URI;
+			pos += 4;
+		} else {
+			wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
+				   "match '%s'", pos);
+			return 0;
+		}
+		end = os_strchr(pos, ';');
+		while (end) {
+			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
+			    os_strncmp(end + 1, "URI:", 4) == 0)
+				break;
+			end = os_strchr(end + 1, ';');
+		}
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (tls_match_altsubject_component(cert, type, pos, len) > 0)
+			return 1;
+		pos = end + 1;
+	} while (end);
+
+	return 0;
+}
+
+
 static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 {
 	char buf[256];
@@ -1006,7 +1040,7 @@
 			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
 			   preverify_ok, err,
 			   X509_verify_cert_error_string(err), depth, buf);
-		if (depth == 0 && match && strstr(buf, match) == NULL) {
+		if (depth == 0 && match && os_strstr(buf, match) == NULL) {
 			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
 				   "match with '%s'", buf, match);
 			preverify_ok = 0;
@@ -1071,11 +1105,20 @@
 		}
 
 		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+			unsigned long err = ERR_peek_error();
 			tls_show_errors(MSG_WARNING, __func__,
 					"Failed to add ca_cert_blob to "
 					"certificate store");
-			X509_free(cert);
-			return -1;
+			if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+			    ERR_GET_REASON(err) ==
+			    X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+					   "cert already in hash table error",
+					   __func__);
+			} else {
+				X509_free(cert);
+				return -1;
+			}
 		}
 		X509_free(cert);
 		wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
@@ -1128,9 +1171,8 @@
 }
 
 
-int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
 {
-	SSL_CTX *ssl_ctx = _ssl_ctx;
 	if (ca_cert) {
 		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
 		{
@@ -1174,23 +1216,22 @@
 }
 
 
-static int tls_connection_set_subject_match(void *ssl_ctx,
-					    struct tls_connection *conn,
+static int tls_connection_set_subject_match(struct tls_connection *conn,
 					    const char *subject_match,
 					    const char *altsubject_match)
 {
-	free(conn->subject_match);
+	os_free(conn->subject_match);
 	conn->subject_match = NULL;
 	if (subject_match) {
-		conn->subject_match = strdup(subject_match);
+		conn->subject_match = os_strdup(subject_match);
 		if (conn->subject_match == NULL)
 			return -1;
 	}
 
-	free(conn->altsubject_match);
+	os_free(conn->altsubject_match);
 	conn->altsubject_match = NULL;
 	if (altsubject_match) {
-		conn->altsubject_match = strdup(altsubject_match);
+		conn->altsubject_match = os_strdup(altsubject_match);
 		if (conn->altsubject_match == NULL)
 			return -1;
 	}
@@ -1219,8 +1260,7 @@
 }
 
 
-static int tls_connection_client_cert(void *ssl_ctx,
-				      struct tls_connection *conn,
+static int tls_connection_client_cert(struct tls_connection *conn,
 				      const char *client_cert,
 				      const u8 *client_cert_blob,
 				      size_t client_cert_blob_len)
@@ -1270,10 +1310,9 @@
 }
 
 
-int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
 {
 #ifndef OPENSSL_NO_STDIO
-	SSL_CTX *ssl_ctx = _ssl_ctx;
 	if (client_cert == NULL)
 		return 0;
 
@@ -1300,9 +1339,9 @@
 	if (password == NULL) {
 		return 0;
 	}
-	strncpy(buf, (char *) password, size);
+	os_strncpy(buf, (char *) password, size);
 	buf[size - 1] = '\0';
-	return strlen(buf);
+	return os_strlen(buf);
 }
 
 
@@ -1322,6 +1361,7 @@
 	if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
 		tls_show_errors(MSG_DEBUG, __func__,
 				"Failed to parse PKCS12 file");
+		PKCS12_free(p12);
 		return -1;
 	}
 	wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
@@ -1388,7 +1428,7 @@
 	FILE *f;
 	PKCS12 *p12;
 
-	f = fopen(private_key, "r");
+	f = fopen(private_key, "rb");
 	if (f == NULL)
 		return -1;
 
@@ -1434,8 +1474,7 @@
 }
 
 
-static int tls_connection_engine_private_key(void *_ssl_ctx,
-					     struct tls_connection *conn)
+static int tls_connection_engine_private_key(struct tls_connection *conn)
 {
 #ifndef OPENSSL_NO_ENGINE
 	if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
@@ -1472,7 +1511,7 @@
 		return 0;
 
 	if (private_key_passwd) {
-		passwd = strdup(private_key_passwd);
+		passwd = os_strdup(private_key_passwd);
 		if (passwd == NULL)
 			return -1;
 	} else
@@ -1582,13 +1621,13 @@
 
 	if (!ok) {
 		wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
-		free(passwd);
+		os_free(passwd);
 		ERR_clear_error();
 		return -1;
 	}
 	ERR_clear_error();
 	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
-	free(passwd);
+	os_free(passwd);
 	
 	if (!SSL_check_private_key(conn->ssl)) {
 		tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -1601,17 +1640,16 @@
 }
 
 
-int tls_global_private_key(void *_ssl_ctx, const char *private_key,
-			   const char *private_key_passwd)
+static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+				  const char *private_key_passwd)
 {
-	SSL_CTX *ssl_ctx = _ssl_ctx;
 	char *passwd;
 
 	if (private_key == NULL)
 		return 0;
 
 	if (private_key_passwd) {
-		passwd = strdup(private_key_passwd);
+		passwd = os_strdup(private_key_passwd);
 		if (passwd == NULL)
 			return -1;
 	} else
@@ -1629,11 +1667,11 @@
 	    tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
 		tls_show_errors(MSG_INFO, __func__,
 				"Failed to load private key");
-		free(passwd);
+		os_free(passwd);
 		ERR_clear_error();
 		return -1;
 	}
-	free(passwd);
+	os_free(passwd);
 	ERR_clear_error();
 	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
 	
@@ -1647,8 +1685,7 @@
 }
 
 
-static int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
-		      const char *dh_file)
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
 {
 #ifdef OPENSSL_NO_DH
 	if (dh_file == NULL)
@@ -1733,7 +1770,7 @@
 	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
 		return -1;
 
-	memset(keys, 0, sizeof(*keys));
+	os_memset(keys, 0, sizeof(*keys));
 	keys->master_key = ssl->session->master_key;
 	keys->master_key_len = ssl->session->master_key_length;
 	keys->client_random = ssl->s3->client_random;
@@ -1745,13 +1782,25 @@
 }
 
 
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	return -1;
+}
+
+
 u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
 			      const u8 *in_data, size_t in_len,
-			      size_t *out_len)
+			      size_t *out_len, u8 **appl_data,
+			      size_t *appl_data_len)
 {
 	int res;
 	u8 *out_data;
 
+	if (appl_data)
+		*appl_data = NULL;
+
 	/*
 	 * Give TLS handshake data from the server (if available) to OpenSSL
 	 * for processing.
@@ -1782,7 +1831,7 @@
 	/* Get the TLS handshake data to be sent to the server */
 	res = BIO_ctrl_pending(conn->ssl_out);
 	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
-	out_data = malloc(res == 0 ? 1 : res);
+	out_data = os_malloc(res == 0 ? 1 : res);
 	if (out_data == NULL) {
 		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
 			   "handshake output (%d bytes)", res);
@@ -1805,6 +1854,26 @@
 		return NULL;
 	}
 	*out_len = res;
+
+	if (SSL_is_init_finished(conn->ssl) && appl_data) {
+		*appl_data = os_malloc(in_len);
+		if (*appl_data) {
+			res = SSL_read(conn->ssl, *appl_data, in_len);
+			if (res < 0) {
+				tls_show_errors(MSG_INFO, __func__,
+						"Failed to read possible "
+						"Application Data");
+				os_free(*appl_data);
+				*appl_data = NULL;
+			} else {
+				*appl_data_len = res;
+				wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application"
+						" Data in Finish message",
+						*appl_data, *appl_data_len);
+			}
+		}
+	}
+
 	return out_data;
 }
 
@@ -1833,7 +1902,7 @@
 
 	res = BIO_ctrl_pending(conn->ssl_out);
 	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
-	out_data = malloc(res == 0 ? 1 : res);
+	out_data = os_malloc(res == 0 ? 1 : res);
 	if (out_data == NULL) {
 		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
 			   "handshake output (%d bytes)", res);
@@ -1930,7 +1999,7 @@
 }
 
 
-#ifdef EAP_FAST
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
 /* Pre-shared secred requires a patch to openssl, so this function is
  * commented out unless explicitly needed for EAP-FAST in order to be able to
  * build this file with unmodified openssl. */
@@ -1944,7 +2013,8 @@
 	if (conn == NULL || conn->pre_shared_secret == 0)
 		return 0;
 
-	memcpy(secret, conn->pre_shared_secret, conn->pre_shared_secret_len);
+	os_memcpy(secret, conn->pre_shared_secret,
+		  conn->pre_shared_secret_len);
 	*secret_len = conn->pre_shared_secret_len;
 
 	return 1;
@@ -1957,14 +2027,14 @@
 	if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
 		return -1;
 
-	free(conn->pre_shared_secret);
+	os_free(conn->pre_shared_secret);
 	conn->pre_shared_secret = NULL;
 	conn->pre_shared_secret_len = 0;
 
 	if (key) {
-		conn->pre_shared_secret = malloc(key_len);
+		conn->pre_shared_secret = os_malloc(key_len);
 		if (conn->pre_shared_secret) {
-			memcpy(conn->pre_shared_secret, key, key_len);
+			os_memcpy(conn->pre_shared_secret, key, key_len);
 			conn->pre_shared_secret_len = key_len;
 		}
 		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
@@ -1977,17 +2047,58 @@
 
 	return 0;
 }
-#endif /* EAP_FAST */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
 
 
-int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
 {
-	if (conn == NULL || conn->ssl == NULL)
+	char buf[100], *pos, *end;
+	u8 *c;
+	int ret;
+
+	if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
 		return -1;
 
-	if (SSL_set_cipher_list(conn->ssl, "ADH-AES128-SHA") != 1) {
+	buf[0] = '\0';
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	c = ciphers;
+	while (*c != TLS_CIPHER_NONE) {
+		const char *suite;
+
+		switch (*c) {
+		case TLS_CIPHER_RC4_SHA:
+			suite = "RC4-SHA";
+			break;
+		case TLS_CIPHER_AES128_SHA:
+			suite = "AES128-SHA";
+			break;
+		case TLS_CIPHER_RSA_DHE_AES128_SHA:
+			suite = "DHE-RSA-AES128-SHA";
+			break;
+		case TLS_CIPHER_ANON_DH_AES128_SHA:
+			suite = "ADH-AES128-SHA";
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
+				   "cipher selection: %d", *c);
+			return -1;
+		}
+		ret = os_snprintf(pos, end - pos, ":%s", suite);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		c++;
+	}
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+
+	if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
 		tls_show_errors(MSG_INFO, __func__,
-				"Anon DH configuration failed");
+				"Cipher suite configuration failed");
 		return -1;
 	}
 
@@ -2006,7 +2117,8 @@
 	if (name == NULL)
 		return -1;
 
-	snprintf(buf, buflen, "%s", name);
+	os_snprintf(buf, buflen, "%s", name);
+	buf[buflen - 1] = '\0';
 	return 0;
 }
 
@@ -2020,7 +2132,7 @@
 }
 
 
-#ifdef EAP_FAST
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
 /* ClientHello TLS extensions require a patch to openssl, so this function is
  * commented out unless explicitly needed for EAP-FAST in order to be able to
  * build this file with unmodified openssl. */
@@ -2037,7 +2149,7 @@
 
 	return 0;
 }
-#endif /* EAP_FAST */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
 
 
 int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -2078,7 +2190,7 @@
 			   __func__, ERR_error_string(err, NULL));
 	}
 
-	if (tls_connection_set_subject_match(tls_ctx, conn,
+	if (tls_connection_set_subject_match(conn,
 					     params->subject_match,
 					     params->altsubject_match))
 		return -1;
@@ -2087,7 +2199,7 @@
 				   params->ca_cert_blob_len,
 				   params->ca_path))
 		return -1;
-	if (tls_connection_client_cert(tls_ctx, conn, params->client_cert,
+	if (tls_connection_client_cert(conn, params->client_cert,
 				       params->client_cert_blob,
 				       params->client_cert_blob_len))
 		return -1;
@@ -2098,7 +2210,7 @@
 				      params->key_id);
 		if (ret)
 			return ret;
-		if (tls_connection_engine_private_key(tls_ctx, conn))
+		if (tls_connection_engine_private_key(conn))
 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 	} else if (tls_connection_private_key(tls_ctx, conn,
 					      params->private_key,
@@ -2110,7 +2222,7 @@
 		return -1;
 	}
 
-	if (tls_connection_dh(tls_ctx, conn, params->dh_file)) {
+	if (tls_connection_dh(conn, params->dh_file)) {
 		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
 			   params->dh_file);
 		return -1;
@@ -2122,6 +2234,31 @@
 }
 
 
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	SSL_CTX *ssl_ctx = tls_ctx;
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
+		return -1;
+
+	if (tls_global_client_cert(ssl_ctx, params->client_cert))
+		return -1;
+
+	if (tls_global_private_key(ssl_ctx, params->private_key,
+				   params->private_key_passwd))
+		return -1;
+
+	return 0;
+}
+
+
 int tls_connection_get_keyblock_size(void *tls_ctx,
 				     struct tls_connection *conn)
 {
@@ -2141,3 +2278,40 @@
 		    EVP_MD_size(h) +
 		    EVP_CIPHER_iv_length(c));
 }
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+			  int tls_ia)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+					  struct tls_connection *conn,
+					  int final,
+					  u8 *out_data, size_t out_len)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+					   struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const u8 *key, size_t key_len)
+{
+	return -1;
+}
Index: eap_tls_common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_tls_common.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_tls_common.h -L contrib/hostapd/eap_tls_common.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/eap_tls_common.h
+++ contrib/hostapd/eap_tls_common.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / EAP-TLS/PEAP/TTLS common functions
+ * Copyright (c) 2004-2005, 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_TLS_COMMON_H
 #define EAP_TLS_COMMON_H
 
--- /dev/null
+++ contrib/hostapd/ap_list.c
@@ -0,0 +1,459 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "ieee802_11.h"
+#include "eloop.h"
+#include "ap_list.h"
+#include "hw_features.h"
+#include "beacon.h"
+
+
+struct ieee80211_frame_info {
+	u32 version;
+	u32 length;
+	u64 mactime;
+	u64 hosttime;
+	u32 phytype;
+	u32 channel;
+	u32 datarate;
+	u32 antenna;
+	u32 priority;
+	u32 ssi_type;
+	u32 ssi_signal;
+	u32 ssi_noise;
+	u32 preamble;
+	u32 encoding;
+
+	/* Note: this structure is otherwise identical to capture format used
+	 * in linux-wlan-ng, but this additional field is used to provide meta
+	 * data about the frame to hostapd. This was the easiest method for
+	 * providing this information, but this might change in the future. */
+	u32 msg_type;
+} __attribute__ ((packed));
+
+
+enum ieee80211_phytype {
+	ieee80211_phytype_fhss_dot11_97  = 1,
+	ieee80211_phytype_dsss_dot11_97  = 2,
+	ieee80211_phytype_irbaseband     = 3,
+	ieee80211_phytype_dsss_dot11_b   = 4,
+	ieee80211_phytype_pbcc_dot11_b   = 5,
+	ieee80211_phytype_ofdm_dot11_g   = 6,
+	ieee80211_phytype_pbcc_dot11_g   = 7,
+	ieee80211_phytype_ofdm_dot11_a   = 8,
+	ieee80211_phytype_dsss_dot11_turbog = 255,
+	ieee80211_phytype_dsss_dot11_turbo = 256,
+};
+
+
+/* AP list is a double linked list with head->prev pointing to the end of the
+ * list and tail->next = NULL. Entries are moved to the head of the list
+ * whenever a beacon has been received from the AP in question. The tail entry
+ * in this link will thus be the least recently used entry. */
+
+
+static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
+
+	/* TODO: could send a notification message to an external program that
+	 * would then determine whether a rogue AP has been detected */
+}
+
+
+static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
+
+	/* TODO: could send a notification message to an external program */
+}
+
+
+static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	int i;
+
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+	    ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
+	    iface->conf->channel != ap->channel)
+		return 0;
+
+	if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
+		return 1;
+
+	for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+		int rate = (ap->supported_rates[i] & 0x7f) * 5;
+		if (rate == 60 || rate == 90 || rate > 110)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
+{
+	struct ap_info *s;
+
+	s = iface->ap_hash[STA_HASH(ap)];
+	while (s != NULL && memcmp(s->addr, ap, ETH_ALEN) != 0)
+		s = s->hnext;
+	return s;
+}
+
+
+static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	if (iface->ap_list) {
+		ap->prev = iface->ap_list->prev;
+		iface->ap_list->prev = ap;
+	} else
+		ap->prev = ap;
+	ap->next = iface->ap_list;
+	iface->ap_list = ap;
+}
+
+
+static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	if (iface->ap_list == ap)
+		iface->ap_list = ap->next;
+	else
+		ap->prev->next = ap->next;
+
+	if (ap->next)
+		ap->next->prev = ap->prev;
+	else if (iface->ap_list)
+		iface->ap_list->prev = ap->prev;
+}
+
+
+static void ap_ap_iter_list_add(struct hostapd_iface *iface,
+				struct ap_info *ap)
+{
+	if (iface->ap_iter_list) {
+		ap->iter_prev = iface->ap_iter_list->iter_prev;
+		iface->ap_iter_list->iter_prev = ap;
+	} else
+		ap->iter_prev = ap;
+	ap->iter_next = iface->ap_iter_list;
+	iface->ap_iter_list = ap;
+}
+
+
+static void ap_ap_iter_list_del(struct hostapd_iface *iface,
+				struct ap_info *ap)
+{
+	if (iface->ap_iter_list == ap)
+		iface->ap_iter_list = ap->iter_next;
+	else
+		ap->iter_prev->iter_next = ap->iter_next;
+
+	if (ap->iter_next)
+		ap->iter_next->iter_prev = ap->iter_prev;
+	else if (iface->ap_iter_list)
+		iface->ap_iter_list->iter_prev = ap->iter_prev;
+}
+
+
+static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
+	iface->ap_hash[STA_HASH(ap->addr)] = ap;
+}
+
+
+static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	struct ap_info *s;
+
+	s = iface->ap_hash[STA_HASH(ap->addr)];
+	if (s == NULL) return;
+	if (memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
+		iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL &&
+	       memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
+		s = s->hnext;
+	if (s->hnext != NULL)
+		s->hnext = s->hnext->hnext;
+	else
+		printf("AP: could not remove AP " MACSTR " from hash table\n",
+		       MAC2STR(ap->addr));
+}
+
+
+static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	ap_ap_hash_del(iface, ap);
+	ap_ap_list_del(iface, ap);
+	ap_ap_iter_list_del(iface, ap);
+
+	iface->num_ap--;
+	free(ap);
+}
+
+
+static void hostapd_free_aps(struct hostapd_iface *iface)
+{
+	struct ap_info *ap, *prev;
+
+	ap = iface->ap_list;
+
+	while (ap) {
+		prev = ap;
+		ap = ap->next;
+		ap_free_ap(iface, prev);
+	}
+
+	iface->ap_list = NULL;
+}
+
+
+int ap_ap_for_each(struct hostapd_iface *iface,
+		   int (*func)(struct ap_info *s, void *data), void *data)
+{
+	struct ap_info *s;
+	int ret = 0;
+
+	s = iface->ap_list;
+
+	while (s) {
+		ret = func(s, data);
+		if (ret)
+			break;
+		s = s->next;
+	}
+
+	return ret;
+}
+
+
+static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
+{
+	struct ap_info *ap;
+
+	ap = wpa_zalloc(sizeof(struct ap_info));
+	if (ap == NULL)
+		return NULL;
+
+	/* initialize AP info data */
+	memcpy(ap->addr, addr, ETH_ALEN);
+	ap_ap_list_add(iface, ap);
+	iface->num_ap++;
+	ap_ap_hash_add(iface, ap);
+	ap_ap_iter_list_add(iface, ap);
+
+	if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
+		wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
+			   MACSTR " from AP table", MAC2STR(ap->prev->addr));
+		if (iface->conf->passive_scan_interval > 0)
+			ap_list_expired_ap(iface, ap->prev);
+		ap_free_ap(iface, ap->prev);
+	}
+
+	return ap;
+}
+
+
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi)
+{
+	struct ap_info *ap;
+	int new_ap = 0;
+	size_t len;
+
+	if (iface->conf->ap_table_max_size < 1)
+		return;
+
+	ap = ap_get_ap(iface, mgmt->bssid);
+	if (!ap) {
+		ap = ap_ap_add(iface, mgmt->bssid);
+		if (!ap) {
+			printf("Failed to allocate AP information entry\n");
+			return;
+		}
+		new_ap = 1;
+	}
+
+	ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
+	ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
+
+	if (elems->ssid) {
+		len = elems->ssid_len;
+		if (len >= sizeof(ap->ssid))
+			len = sizeof(ap->ssid) - 1;
+		memcpy(ap->ssid, elems->ssid, len);
+		ap->ssid[len] = '\0';
+		ap->ssid_len = len;
+	}
+
+	memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
+	len = 0;
+	if (elems->supp_rates) {
+		len = elems->supp_rates_len;
+		if (len > WLAN_SUPP_RATES_MAX)
+			len = WLAN_SUPP_RATES_MAX;
+		memcpy(ap->supported_rates, elems->supp_rates, len);
+	}
+	if (elems->ext_supp_rates) {
+		int len2;
+		if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
+			len2 = WLAN_SUPP_RATES_MAX - len;
+		else
+			len2 = elems->ext_supp_rates_len;
+		memcpy(ap->supported_rates + len, elems->ext_supp_rates, len2);
+	}
+
+	ap->wpa = elems->wpa_ie != NULL;
+
+	if (elems->erp_info && elems->erp_info_len == 1)
+		ap->erp = elems->erp_info[0];
+	else
+		ap->erp = -1;
+
+	if (elems->ds_params && elems->ds_params_len == 1)
+		ap->channel = elems->ds_params[0];
+	else if (fi)
+		ap->channel = fi->channel;
+
+	ap->num_beacons++;
+	time(&ap->last_beacon);
+	if (fi) {
+		ap->phytype = fi->phytype;
+		ap->ssi_signal = fi->ssi_signal;
+		ap->datarate = fi->datarate;
+	}
+
+	if (new_ap) {
+		if (iface->conf->passive_scan_interval > 0)
+			ap_list_new_ap(iface, ap);
+	} else if (ap != iface->ap_list) {
+		/* move AP entry into the beginning of the list so that the
+		 * oldest entry is always in the end of the list */
+		ap_ap_list_del(iface, ap);
+		ap_ap_list_add(iface, ap);
+	}
+
+	if (!iface->olbc &&
+	    ap_list_beacon_olbc(iface, ap)) {
+		struct hostapd_data *hapd = iface->bss[0];
+		iface->olbc = 1;
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+			      "OLBC AP detected: " MACSTR " - enable "
+			      "protection\n", MAC2STR(ap->addr));
+		ieee802_11_set_beacons(hapd->iface);
+	}
+}
+
+
+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+	time_t now;
+	struct ap_info *ap;
+
+	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+
+	if (!iface->ap_list)
+		return;
+
+	time(&now);
+
+	/* FIX: it looks like jkm-Purina ended up in busy loop in this
+	 * function. Apparently, something can still cause a loop in the AP
+	 * list.. */
+
+	while (iface->ap_list) {
+		ap = iface->ap_list->prev;
+		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
+		    now)
+			break;
+
+		if (iface->conf->passive_scan_interval > 0)
+			ap_list_expired_ap(iface, ap);
+		ap_free_ap(iface, ap);
+	}
+
+	if (iface->olbc) {
+		int olbc = 0;
+		ap = iface->ap_list;
+		while (ap) {
+			if (ap_list_beacon_olbc(iface, ap)) {
+				olbc = 1;
+				break;
+			}
+			ap = ap->next;
+		}
+		if (!olbc) {
+			struct hostapd_data *hapd = iface->bss[0];
+			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+				      "OLBC not detected anymore\n");
+			iface->olbc = 0;
+			ieee802_11_set_beacons(hapd->iface);
+		}
+	}
+}
+
+
+int ap_list_init(struct hostapd_iface *iface)
+{
+	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+	return 0;
+}
+
+
+void ap_list_deinit(struct hostapd_iface *iface)
+{
+	eloop_cancel_timeout(ap_list_timer, iface, NULL);
+	hostapd_free_aps(iface);
+}
+
+
+int ap_list_reconfig(struct hostapd_iface *iface,
+		     struct hostapd_config *oldconf)
+{
+	time_t now;
+	struct ap_info *ap;
+
+	if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
+	    iface->conf->ap_table_expiration_time ==
+	    oldconf->ap_table_expiration_time)
+		return 0;
+
+	time(&now);
+
+	while (iface->ap_list) {
+		ap = iface->ap_list->prev;
+		if (iface->num_ap <= iface->conf->ap_table_max_size &&
+		    ap->last_beacon + iface->conf->ap_table_expiration_time >=
+		    now)
+			break;
+
+		if (iface->conf->passive_scan_interval > 0)
+			ap_list_expired_ap(iface, iface->ap_list->prev);
+		ap_free_ap(iface, iface->ap_list->prev);
+	}
+
+	return 0;
+}
--- /dev/null
+++ contrib/hostapd/eap_gpsk_common.h
@@ -0,0 +1,66 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-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_GPSK_COMMON_H
+#define EAP_GPSK_COMMON_H
+
+#define EAP_GPSK_OPCODE_GPSK_1 1
+#define EAP_GPSK_OPCODE_GPSK_2 2
+#define EAP_GPSK_OPCODE_GPSK_3 3
+#define EAP_GPSK_OPCODE_GPSK_4 4
+#define EAP_GPSK_OPCODE_FAIL 5
+#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6
+
+/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */
+#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001
+#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002
+#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003
+
+#define EAP_GPSK_RAND_LEN 32
+#define EAP_GPSK_MAX_SK_LEN 32
+#define EAP_GPSK_MAX_PK_LEN 32
+#define EAP_GPSK_MAX_MIC_LEN 32
+
+#define EAP_GPSK_VENDOR_IETF		0x000000
+#define EAP_GPSK_CIPHER_RESERVED	0x000000
+#define EAP_GPSK_CIPHER_AES		0x000001
+#define EAP_GPSK_CIPHER_SHA256		0x000002
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_gpsk_csuite {
+	u8 vendor[3];
+	u8 specifier[3];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier);
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+			 int specifier,
+			 const u8 *rand_client, const u8 *rand_server,
+			 const u8 *id_client, size_t id_client_len,
+			 const u8 *id_server, size_t id_server_len,
+			 u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+			 u8 *pk, size_t *pk_len);
+size_t eap_gpsk_mic_len(int vendor, int specifier);
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+			 int specifier, const u8 *data, size_t len, u8 *mic);
+
+#endif /* EAP_GPSK_COMMON_H */
Index: eapol_sm.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eapol_sm.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eapol_sm.h -L contrib/hostapd/eapol_sm.h -u -r1.2 -r1.3
--- contrib/hostapd/eapol_sm.h
+++ contrib/hostapd/eapol_sm.h
@@ -1,9 +1,23 @@
+/*
+ * hostapd / IEEE 802.1X Authenticator - EAPOL state machine
+ * Copyright (c) 2002-2005, 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 EAPOL_SM_H
 #define EAPOL_SM_H
 
 #include "defs.h"
 
-/* IEEE Std 802.1X-REV-d11, Ch. 8.2 */
+/* IEEE Std 802.1X-2004, Ch. 8.2 */
 
 typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
 	PortTypes;
@@ -11,22 +25,64 @@
 typedef enum { Both = 0, In = 1 } ControlledDirection;
 typedef unsigned int Counter;
 
+struct eap_sm;
+
+struct radius_attr_data {
+	u8 *data;
+	size_t len;
+};
+
+struct radius_class_data {
+	struct radius_attr_data *attr;
+	size_t count;
+};
+
+struct eapol_state_machine {
+	/* timers */
+	int aWhile;
+	int quietWhile;
+	int reAuthWhen;
 
-/* Authenticator PAE state machine */
-struct eapol_auth_pae_sm {
+	/* global variables */
+	Boolean authAbort;
+	Boolean authFail;
+	PortState authPortStatus;
+	Boolean authStart;
+	Boolean authTimeout;
+	Boolean authSuccess;
+	Boolean eapFail;
+	Boolean eapolEap;
+	Boolean eapSuccess;
+	Boolean eapTimeout;
+	Boolean initialize;
+	Boolean keyAvailable;
+	Boolean keyDone;
+	Boolean keyRun;
+	Boolean keyTxEnabled;
+	PortTypes portControl;
+	Boolean portEnabled;
+	Boolean portValid;
+	Boolean reAuthenticate;
+
+	/* Port Timers state machine */
+	/* 'Boolean tick' implicitly handled as registered timeout */
+
+	/* Authenticator PAE state machine */
+	enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
+	       AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
+	       AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
+	       AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } auth_pae_state;
 	/* variables */
 	Boolean eapolLogoff;
 	Boolean eapolStart;
 	Boolean eapRestart;
 	PortTypes portMode;
 	unsigned int reAuthCount;
-
 	/* constants */
 	unsigned int quietPeriod; /* default 60; 0..65535 */
 #define AUTH_PAE_DEFAULT_quietPeriod 60
 	unsigned int reAuthMax; /* default 2 */
 #define AUTH_PAE_DEFAULT_reAuthMax 2
-
 	/* counters */
 	Counter authEntersConnecting;
 	Counter authEapLogoffsWhileConnecting;
@@ -40,24 +96,18 @@
 	Counter authAuthEapStartsWhileAuthenticated;
 	Counter authAuthEapLogoffWhileAuthenticated;
 
-	enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
-	       AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
-	       AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
-	       AUTH_PAE_FORCE_UNAUTH, AUTH_PAE_RESTART } state;
-};
-
-
-/* Backend Authentication state machine */
-struct eapol_backend_auth_sm {
+	/* Backend Authentication state machine */
+	enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
+	       BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
+	       BE_AUTH_IGNORE
+	} be_auth_state;
 	/* variables */
 	Boolean eapNoReq;
 	Boolean eapReq;
 	Boolean eapResp;
-
 	/* constants */
 	unsigned int serverTimeout; /* default 30; 1..X */
 #define BE_AUTH_DEFAULT_serverTimeout 30
-
 	/* counters */
 	Counter backendResponses;
 	Counter backendAccessChallenges;
@@ -65,98 +115,29 @@
 	Counter backendAuthSuccesses;
 	Counter backendAuthFails;
 
-	enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
-	       BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE,
-	       BE_AUTH_IGNORE
-	} state;
-};
-
-
-/* Reauthentication Timer state machine */
-struct eapol_reauth_timer_sm {
+	/* Reauthentication Timer state machine */
+	enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE
+	} reauth_timer_state;
 	/* constants */
 	unsigned int reAuthPeriod; /* default 3600 s */
 	Boolean reAuthEnabled;
 
-	enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE } state;
-};
-
+	/* Authenticator Key Transmit state machine */
+	enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT
+	} auth_key_tx_state;
 
-/* Authenticator Key Transmit state machine */
-struct eapol_auth_key_tx {
-	enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT } state;
-};
-
-
-/* Key Receive state machine */
-struct eapol_key_rx {
+	/* Key Receive state machine */
+	enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } key_rx_state;
 	/* variables */
 	Boolean rxKey;
 
-	enum { KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE } state;
-};
-
-
-/* Controlled Directions state machine */
-struct eapol_ctrl_dir {
+	/* Controlled Directions state machine */
+	enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } ctrl_dir_state;
 	/* variables */
 	ControlledDirection adminControlledDirections;
 	ControlledDirection operControlledDirections;
 	Boolean operEdge;
 
-	enum { CTRL_DIR_FORCE_BOTH, CTRL_DIR_IN_OR_BOTH } state;
-};
-
-
-struct eap_sm;
-
-struct radius_attr_data {
-	u8 *data;
-	size_t len;
-};
-
-struct radius_class_data {
-	struct radius_attr_data *attr;
-	size_t count;
-};
-
-struct eapol_state_machine {
-	/* timers */
-	int aWhile;
-	int quietWhile;
-	int reAuthWhen;
-
-	/* global variables */
-	Boolean authAbort;
-	Boolean authFail;
-	PortState authPortStatus;
-	Boolean authStart;
-	Boolean authTimeout;
-	Boolean authSuccess;
-	Boolean eapFail;
-	Boolean eapolEap;
-	Boolean eapSuccess;
-	Boolean eapTimeout;
-	Boolean initialize;
-	Boolean keyAvailable;
-	Boolean keyDone;
-	Boolean keyRun;
-	Boolean keyTxEnabled;
-	PortTypes portControl;
-	Boolean portEnabled;
-	Boolean portValid;
-	Boolean reAuthenticate;
-
-	/* Port Timers state machine */
-	/* 'Boolean tick' implicitly handled as registered timeout */
-
-	struct eapol_auth_pae_sm auth_pae;
-	struct eapol_backend_auth_sm be_auth;
-	struct eapol_reauth_timer_sm reauth_timer;
-	struct eapol_auth_key_tx auth_key_tx;
-	struct eapol_key_rx key_rx;
-	struct eapol_ctrl_dir ctrl_dir;
-
 	/* Authenticator Statistics Table */
 	Counter dot1xAuthEapolFramesRx;
 	Counter dot1xAuthEapolFramesTx;
@@ -185,6 +166,9 @@
 	size_t last_eap_radius_len;
 	u8 *identity;
 	size_t identity_len;
+	u8 eap_type_authsrv; /* EAP type of the last EAP packet from
+			      * Authentication server */
+	u8 eap_type_supp; /* EAP type of the last EAP packet from Supplicant */
 	struct radius_class_data radius_class;
 
 	/* Keys for encrypting and signing EAPOL-Key frames */
@@ -205,6 +189,7 @@
 	u8 currentId;
 
 	Boolean initializing; /* in process of initializing state machines */
+	Boolean changed;
 
 	/* Somewhat nasty pointers to global hostapd and STA data to avoid
 	 * passing these to every function */
@@ -213,12 +198,13 @@
 };
 
 
-struct eapol_state_machine *eapol_sm_alloc(hostapd *hapd,
+struct eapol_state_machine *eapol_sm_alloc(struct hostapd_data *hapd,
 					   struct sta_info *sta);
 void eapol_sm_free(struct eapol_state_machine *sm);
 void eapol_sm_step(struct eapol_state_machine *sm);
 void eapol_sm_initialize(struct eapol_state_machine *sm);
 void eapol_sm_dump_state(FILE *f, const char *prefix,
 			 struct eapol_state_machine *sm);
+int eapol_sm_eap_pending_cb(struct eapol_state_machine *sm, void *ctx);
 
 #endif /* EAPOL_SM_H */
--- /dev/null
+++ contrib/hostapd/eloop_win.c
@@ -0,0 +1,604 @@
+/*
+ * Event loop based on Windows events and WaitForMultipleObjects
+ * Copyright (c) 2002-2006, 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 <winsock2.h>
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	eloop_sock_handler handler;
+	WSAEVENT event;
+};
+
+struct eloop_event {
+	void *eloop_data;
+	void *user_data;
+	eloop_event_handler handler;
+	HANDLE event;
+};
+
+struct eloop_timeout {
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	eloop_timeout_handler handler;
+	struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	eloop_signal_handler handler;
+	int signaled;
+};
+
+struct eloop_data {
+	void *user_data;
+
+	int max_sock;
+	size_t reader_count;
+	struct eloop_sock *readers;
+
+	size_t event_count;
+	struct eloop_event *events;
+
+	struct eloop_timeout *timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+
+	struct eloop_signal term_signal;
+	HANDLE term_event;
+
+	HANDLE *handles;
+	size_t num_handles;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+	os_memset(&eloop, 0, sizeof(eloop));
+	eloop.user_data = user_data;
+	eloop.num_handles = 1;
+	eloop.handles = os_malloc(eloop.num_handles *
+				  sizeof(eloop.handles[0]));
+	if (eloop.handles == NULL)
+		return -1;
+
+	eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+	if (eloop.term_event == NULL) {
+		printf("CreateEvent() failed: %d\n",
+		       (int) GetLastError());
+		os_free(eloop.handles);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eloop_prepare_handles(void)
+{
+	HANDLE *n;
+
+	if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
+		return 0;
+	n = os_realloc(eloop.handles,
+		       eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+	if (n == NULL)
+		return -1;
+	eloop.handles = n;
+	eloop.num_handles *= 2;
+	return 0;
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data)
+{
+	WSAEVENT event;
+	struct eloop_sock *tmp;
+
+	if (eloop_prepare_handles())
+		return -1;
+
+	event = WSACreateEvent();
+	if (event == WSA_INVALID_EVENT) {
+		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+		return -1;
+	}
+
+	if (WSAEventSelect(sock, event, FD_READ)) {
+		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+		WSACloseEvent(event);
+		return -1;
+	}
+	tmp = os_realloc(eloop.readers,
+			 (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+	if (tmp == NULL) {
+		WSAEventSelect(sock, event, 0);
+		WSACloseEvent(event);
+		return -1;
+	}
+
+	tmp[eloop.reader_count].sock = sock;
+	tmp[eloop.reader_count].eloop_data = eloop_data;
+	tmp[eloop.reader_count].user_data = user_data;
+	tmp[eloop.reader_count].handler = handler;
+	tmp[eloop.reader_count].event = event;
+	eloop.reader_count++;
+	eloop.readers = tmp;
+	if (sock > eloop.max_sock)
+		eloop.max_sock = sock;
+	eloop.reader_table_changed = 1;
+
+	return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	size_t i;
+
+	if (eloop.readers == NULL || eloop.reader_count == 0)
+		return;
+
+	for (i = 0; i < eloop.reader_count; i++) {
+		if (eloop.readers[i].sock == sock)
+			break;
+	}
+	if (i == eloop.reader_count)
+		return;
+
+	WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
+	WSACloseEvent(eloop.readers[i].event);
+
+	if (i != eloop.reader_count - 1) {
+		os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+			   (eloop.reader_count - i - 1) *
+			   sizeof(struct eloop_sock));
+	}
+	eloop.reader_count--;
+	eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_event(void *event, size_t event_size,
+			 eloop_event_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_event *tmp;
+	HANDLE h = event;
+
+	if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
+		return -1;
+
+	if (eloop_prepare_handles())
+		return -1;
+
+	tmp = os_realloc(eloop.events,
+			 (eloop.event_count + 1) * sizeof(struct eloop_event));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.event_count].eloop_data = eloop_data;
+	tmp[eloop.event_count].user_data = user_data;
+	tmp[eloop.event_count].handler = handler;
+	tmp[eloop.event_count].event = h;
+	eloop.event_count++;
+	eloop.events = tmp;
+
+	return 0;
+}
+
+
+void eloop_unregister_event(void *event, size_t event_size)
+{
+	size_t i;
+	HANDLE h = event;
+
+	if (eloop.events == NULL || eloop.event_count == 0 ||
+	    event_size != sizeof(HANDLE))
+		return;
+
+	for (i = 0; i < eloop.event_count; i++) {
+		if (eloop.events[i].event == h)
+			break;
+	}
+	if (i == eloop.event_count)
+		return;
+
+	if (i != eloop.event_count - 1) {
+		os_memmove(&eloop.events[i], &eloop.events[i + 1],
+			   (eloop.event_count - i - 1) *
+			   sizeof(struct eloop_event));
+	}
+	eloop.event_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   eloop_timeout_handler handler,
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp, *prev;
+
+	timeout = os_malloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	os_get_time(&timeout->time);
+	timeout->time.sec += secs;
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	timeout->next = NULL;
+
+	if (eloop.timeout == NULL) {
+		eloop.timeout = timeout;
+		return 0;
+	}
+
+	prev = NULL;
+	tmp = eloop.timeout;
+	while (tmp != NULL) {
+		if (os_time_before(&timeout->time, &tmp->time))
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (prev == NULL) {
+		timeout->next = eloop.timeout;
+		eloop.timeout = timeout;
+	} else {
+		timeout->next = prev->next;
+		prev->next = timeout;
+	}
+
+	return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev, *next;
+	int removed = 0;
+
+	prev = NULL;
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		next = timeout->next;
+
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			if (prev == NULL)
+				eloop.timeout = next;
+			else
+				prev->next = next;
+			os_free(timeout);
+			removed++;
+		} else
+			prev = timeout;
+
+		timeout = next;
+	}
+
+	return removed;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.user_data,
+						 eloop.signals[i].user_data);
+		}
+	}
+
+	if (eloop.term_signal.signaled) {
+		eloop.term_signal.signaled = 0;
+		eloop.term_signal.handler(eloop.term_signal.sig,
+					  eloop.user_data,
+					  eloop.term_signal.user_data);
+	}
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = os_realloc(eloop.signals,
+			 (eloop.signal_count + 1) *
+			 sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+
+	/* TODO: register signal handler */
+
+	return 0;
+}
+
+
+#ifndef _WIN32_WCE
+static BOOL eloop_handle_console_ctrl(DWORD type)
+{
+	switch (type) {
+	case CTRL_C_EVENT:
+	case CTRL_BREAK_EVENT:
+		eloop.signaled++;
+		eloop.term_signal.signaled++;
+		SetEvent(eloop.term_event);
+		return TRUE;
+	default:
+		return FALSE;
+	}
+}
+#endif /* _WIN32_WCE */
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data)
+{
+#ifndef _WIN32_WCE
+	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
+				  TRUE) == 0) {
+		printf("SetConsoleCtrlHandler() failed: %d\n",
+		       (int) GetLastError());
+		return -1;
+	}
+#endif /* _WIN32_WCE */
+
+	eloop.term_signal.handler = handler;
+	eloop.term_signal.user_data = user_data;
+		
+	return 0;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data)
+{
+	/* TODO */
+	return 0;
+}
+
+
+void eloop_run(void)
+{
+	struct os_time tv, now;
+	DWORD count, ret, timeout, err;
+	size_t i;
+
+	while (!eloop.terminate &&
+	       (eloop.timeout || eloop.reader_count > 0 ||
+		eloop.event_count > 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;
+		for (i = 0; i < eloop.event_count; i++)
+			eloop.handles[count++] = eloop.events[i].event;
+
+		for (i = 0; i < eloop.reader_count; i++)
+			eloop.handles[count++] = eloop.readers[i].event;
+
+		if (eloop.term_event)
+			eloop.handles[count++] = eloop.term_event;
+
+		if (eloop.timeout)
+			timeout = tv.sec * 1000 + tv.usec / 1000;
+		else
+			timeout = INFINITE;
+
+		if (count > MAXIMUM_WAIT_OBJECTS) {
+			printf("WaitForMultipleObjects: Too many events: "
+			       "%d > %d (ignoring extra events)\n",
+			       (int) count, MAXIMUM_WAIT_OBJECTS);
+			count = MAXIMUM_WAIT_OBJECTS;
+		}
+#ifdef _WIN32_WCE
+		ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
+					     timeout);
+#else /* _WIN32_WCE */
+		ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
+					       timeout, TRUE);
+#endif /* _WIN32_WCE */
+		err = GetLastError();
+
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		if (eloop.timeout) {
+			struct eloop_timeout *tmp;
+
+			os_get_time(&now);
+			if (!os_time_before(&now, &eloop.timeout->time)) {
+				tmp = eloop.timeout;
+				eloop.timeout = eloop.timeout->next;
+				tmp->handler(tmp->eloop_data,
+					     tmp->user_data);
+				os_free(tmp);
+			}
+
+		}
+
+		if (ret == WAIT_FAILED) {
+			printf("WaitForMultipleObjects(count=%d) failed: %d\n",
+			       (int) count, (int) err);
+			os_sleep(1, 0);
+			continue;
+		}
+
+#ifndef _WIN32_WCE
+		if (ret == WAIT_IO_COMPLETION)
+			continue;
+#endif /* _WIN32_WCE */
+
+		if (ret == WAIT_TIMEOUT)
+			continue;
+
+		while (ret >= WAIT_OBJECT_0 &&
+		       ret < WAIT_OBJECT_0 + eloop.event_count) {
+			eloop.events[ret].handler(
+				eloop.events[ret].eloop_data,
+				eloop.events[ret].user_data);
+			ret = WaitForMultipleObjects(eloop.event_count,
+						     eloop.handles, FALSE, 0);
+		}
+
+		eloop.reader_table_changed = 0;
+		for (i = 0; i < eloop.reader_count; i++) {
+			WSANETWORKEVENTS events;
+			if (WSAEnumNetworkEvents(eloop.readers[i].sock,
+						 eloop.readers[i].event,
+						 &events) == 0 &&
+			    (events.lNetworkEvents & FD_READ)) {
+				eloop.readers[i].handler(
+					eloop.readers[i].sock,
+					eloop.readers[i].eloop_data,
+					eloop.readers[i].user_data);
+				if (eloop.reader_table_changed)
+					break;
+			}
+		}
+	}
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+	SetEvent(eloop.term_event);
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+
+	timeout = eloop.timeout;
+	while (timeout != NULL) {
+		prev = timeout;
+		timeout = timeout->next;
+		os_free(prev);
+	}
+	os_free(eloop.readers);
+	os_free(eloop.signals);
+	if (eloop.term_event)
+		CloseHandle(eloop.term_event);
+	os_free(eloop.handles);
+	eloop.handles = NULL;
+	os_free(eloop.events);
+	eloop.events = NULL;
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+	WSAEVENT event;
+
+	event = WSACreateEvent();
+	if (event == WSA_INVALID_EVENT) {
+		printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+		return;
+	}
+
+	if (WSAEventSelect(sock, event, FD_READ)) {
+		printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+		WSACloseEvent(event);
+		return ;
+	}
+
+	WaitForSingleObject(event, INFINITE);
+	WSAEventSelect(sock, event, 0);
+	WSACloseEvent(event);
+}
+
+
+void * eloop_get_user_data(void)
+{
+	return eloop.user_data;
+}
--- /dev/null
+++ contrib/hostapd/aes.h
@@ -0,0 +1,25 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, 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 AES_H
+#define AES_H
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */
Index: eap_md5.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_md5.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_md5.c -L contrib/hostapd/eap_md5.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_md5.c
+++ contrib/hostapd/eap_md5.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-MD5 server
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004-2006, 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,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -36,10 +33,9 @@
 {
 	struct eap_md5_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = CONTINUE;
 
 	return data;
@@ -66,8 +62,8 @@
 		return NULL;
 	}
 
-	*reqDataLen = sizeof(*req) + 2 + CHALLENGE_LEN;
-	req = malloc(*reqDataLen);
+	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqDataLen,
+			    1 + CHALLENGE_LEN, EAP_CODE_REQUEST, id, &pos);
 	if (req == NULL) {
 		wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
 			   "request");
@@ -75,11 +71,6 @@
 		return NULL;
 	}
 
-	req->code = EAP_CODE_REQUEST;
-	req->identifier = id;
-	req->length = htons(*reqDataLen);
-	pos = (u8 *) (req + 1);
-	*pos++ = EAP_TYPE_MD5;
 	*pos++ = CHALLENGE_LEN;
 	memcpy(pos, data->challenge, CHALLENGE_LEN);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", pos, CHALLENGE_LEN);
@@ -93,23 +84,19 @@
 static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
 			     u8 *respData, size_t respDataLen)
 {
-	struct eap_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	size_t len;
 
-	resp = (struct eap_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_MD5 ||
-	    (len = ntohs(resp->length)) > respDataLen) {
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5,
+			       respData, respDataLen, &len);
+	if (pos == NULL || len < 1) {
 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
 		return TRUE;
 	}
-	pos++;
-	if (*pos != MD5_MAC_LEN ||
-	    sizeof(*resp) + 2 + MD5_MAC_LEN > len) {
+	if (*pos != MD5_MAC_LEN || 1 + MD5_MAC_LEN > len) {
 		wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
-			   "(response_len=%d respDataLen=%lu",
-			   *pos, (unsigned long) respDataLen);
+			   "(response_len=%d payload_len=%lu",
+			   *pos, (unsigned long) len);
 		return TRUE;
 	}
 
@@ -122,22 +109,28 @@
 {
 	struct eap_md5_data *data = priv;
 	struct eap_hdr *resp;
-	u8 *pos;
+	const u8 *pos;
 	const u8 *addr[3];
-	size_t len[3];
+	size_t len[3], plen;
 	u8 hash[MD5_MAC_LEN];
 
-	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+	if (sm->user == NULL || sm->user->password == NULL ||
+	    sm->user->password_hash) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not "
+			   "configured");
 		data->state = FAILURE;
 		return;
 	}
 
-	resp = (struct eap_hdr *) respData;
-	pos = (u8 *) (resp + 1);
-	pos += 2; /* Skip type and len */
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5,
+			       respData, respDataLen, &plen);
+	if (pos == NULL || *pos != MD5_MAC_LEN || plen < 1 + MD5_MAC_LEN)
+		return; /* Should not happen - frame already validated */
+
+	pos++; /* Skip response len */
 	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
 
+	resp = (struct eap_hdr *) respData;
 	addr[0] = &resp->identifier;
 	len[0] = 1;
 	addr[1] = sm->user->password;
@@ -170,15 +163,26 @@
 }
 
 
-const struct eap_method eap_method_md5 =
+int eap_server_md5_register(void)
 {
-	.method = EAP_TYPE_MD5,
-	.name = "MD5",
-	.init = eap_md5_init,
-	.reset = eap_md5_reset,
-	.buildReq = eap_md5_buildReq,
-	.check = eap_md5_check,
-	.process = eap_md5_process,
-	.isDone = eap_md5_isDone,
-	.isSuccess = eap_md5_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_md5_init;
+	eap->reset = eap_md5_reset;
+	eap->buildReq = eap_md5_buildReq;
+	eap->check = eap_md5_check;
+	eap->process = eap_md5_process;
+	eap->isDone = eap_md5_isDone;
+	eap->isSuccess = eap_md5_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: accounting.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/accounting.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -L contrib/hostapd/accounting.h -L contrib/hostapd/accounting.h -u -r1.1.1.1 -r1.2
--- contrib/hostapd/accounting.h
+++ contrib/hostapd/accounting.h
@@ -1,13 +1,27 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, 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 ACCOUNTING_H
 #define ACCOUNTING_H
 
-
-void accounting_sta_start(hostapd *hapd, struct sta_info *sta);
-void accounting_sta_interim(hostapd *hapd, struct sta_info *sta);
-void accounting_sta_stop(hostapd *hapd, struct sta_info *sta);
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
 void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
-int accounting_init(hostapd *hapd);
-void accounting_deinit(hostapd *hapd);
-
+int accounting_init(struct hostapd_data *hapd);
+void accounting_deinit(struct hostapd_data *hapd);
+int accounting_reconfig(struct hostapd_data *hapd,
+			struct hostapd_config *oldconf);
 
 #endif /* ACCOUNTING_H */
--- /dev/null
+++ contrib/hostapd/ap_list.h
@@ -0,0 +1,68 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j at w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * 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 AP_LIST_H
+#define AP_LIST_H
+
+struct ap_info {
+	/* Note: next/prev pointers are updated whenever a new beacon is
+	 * received because these are used to find the least recently used
+	 * entries. iter_next/iter_prev are updated only when adding new BSSes
+	 * and when removing old ones. These should be used when iterating
+	 * through the table in a manner that allows beacons to be received
+	 * during the iteration. */
+	struct ap_info *next; /* next entry in AP list */
+	struct ap_info *prev; /* previous entry in AP list */
+	struct ap_info *hnext; /* next entry in hash table list */
+	struct ap_info *iter_next; /* next entry in AP iteration list */
+	struct ap_info *iter_prev; /* previous entry in AP iteration list */
+	u8 addr[6];
+	u16 beacon_int;
+	u16 capability;
+	u8 supported_rates[WLAN_SUPP_RATES_MAX];
+	u8 ssid[33];
+	size_t ssid_len;
+	int wpa;
+	int erp; /* ERP Info or -1 if ERP info element not present */
+
+	int phytype; /* .11a / .11b / .11g / Atheros Turbo */
+	int channel;
+	int datarate; /* in 100 kbps */
+	int ssi_signal;
+
+	unsigned int num_beacons; /* number of beacon frames received */
+	time_t last_beacon;
+
+	int already_seen; /* whether API call AP-NEW has already fetched
+			   * information about this AP */
+};
+
+struct ieee802_11_elems;
+struct hostapd_frame_info;
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
+int ap_ap_for_each(struct hostapd_iface *iface,
+		   int (*func)(struct ap_info *s, void *data), void *data);
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi);
+int ap_list_init(struct hostapd_iface *iface);
+void ap_list_deinit(struct hostapd_iface *iface);
+int ap_list_reconfig(struct hostapd_iface *iface,
+		     struct hostapd_config *oldconf);
+
+#endif /* AP_LIST_H */
Index: FREEBSD-Xlist
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/FREEBSD-Xlist,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/FREEBSD-Xlist -L contrib/hostapd/FREEBSD-Xlist -u -r1.2 -r1.3
--- contrib/hostapd/FREEBSD-Xlist
+++ contrib/hostapd/FREEBSD-Xlist
@@ -1,12 +1,17 @@
-$FreeBSD: src/contrib/hostapd/FREEBSD-Xlist,v 1.1.2.1 2006/03/24 01:42:33 sam Exp $
+$FreeBSD: src/contrib/hostapd/FREEBSD-Xlist,v 1.3 2007/07/09 16:24:41 sam Exp $
 .cvsignore
 driver.c
 driver_bsd.c
+driver_devicescape.c
 driver_madwifi.c
 driver_prism54.c
 l2_packet_freebsd.c
 l2_packet_linux.c
+l2_packet_ndis.c
 l2_packet_pcap.c
+l2_packet_winpcap.c
+nt_password_hash.c
+os_win32.c
 prism54.h
 priv_netlink.h
 wireless_copy.h
Index: tls_none.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/tls_none.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/tls_none.c -L contrib/hostapd/tls_none.c -u -r1.2 -r1.3
--- contrib/hostapd/tls_none.c
+++ contrib/hostapd/tls_none.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant / SSL/TLS interface functions for no TLS case
- * Copyright (c) 2004, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2004, 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,8 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
+#include "includes.h"
 
 #include "common.h"
 #include "tls.h"
@@ -26,3 +25,217 @@
 void tls_deinit(void *ssl_ctx)
 {
 }
+
+
+#ifdef EAP_TLS_NONE
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	return NULL;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	return -1;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+			  int tls_ia)
+{
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	return -1;
+}
+
+
+u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
+			      const u8 *in_data, size_t in_len,
+			      size_t *out_len, u8 **appl_data,
+			      size_t *appl_data_len)
+{
+	return NULL;
+}
+
+
+u8 * tls_connection_server_handshake(void *tls_ctx,
+				     struct tls_connection *conn,
+				     const u8 *in_data, size_t in_len,
+				     size_t *out_len)
+{
+	return NULL;
+}
+
+
+int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
+			   const u8 *in_data, size_t in_len,
+			   u8 *out_data, size_t out_len)
+{
+	return -1;
+}
+
+
+int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
+			   const u8 *in_data, size_t in_len,
+			   u8 *out_data, size_t out_len)
+{
+	return -1;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
+				  const u8 *key, size_t key_len)
+{
+	return -1;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+					  struct tls_connection *conn,
+					  int final,
+					  u8 *out_data, size_t out_len)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+					   struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+					   struct tls_connection *conn,
+					   const u8 *key, size_t key_len)
+{
+	return -1;
+}
+
+#endif /* EAP_TLS_NONE */
Index: eap_pax.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_pax.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_pax.c -L contrib/hostapd/eap_pax.c -u -r1.1 -r1.2
--- contrib/hostapd/eap_pax.c
+++ contrib/hostapd/eap_pax.c
@@ -1,6 +1,6 @@
 /*
- * hostapd / EAP-PAX (draft-clancy-eap-pax-04.txt) server
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / EAP-PAX (RFC 4746) server
+ * Copyright (c) 2005-2006, 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,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -24,6 +21,11 @@
 
 /*
  * Note: only PAX_STD subprotocol is currently supported
+ *
+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
+ * RSAES-OAEP).
  */
 
 struct eap_pax_data {
@@ -50,13 +52,12 @@
 {
 	struct eap_pax_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = PAX_STD_1;
 	/*
-	 * TODO: make this configurable once EAP_PAX_MAC_AES_CBC_MAC_128 is
+	 * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
 	 * supported
 	 */
 	data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
@@ -161,6 +162,8 @@
 		    pos, EAP_PAX_MAC_LEN);
 	pos += EAP_PAX_MAC_LEN;
 
+	/* Optional ADE could be added here, if needed */
+
 	eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
 		    (u8 *) req, *reqDataLen - EAP_PAX_ICV_LEN,
 		    NULL, 0, NULL, 0, pos);
@@ -319,7 +322,7 @@
 	pos += EAP_PAX_RAND_LEN;
 	left -= EAP_PAX_RAND_LEN;
 
-	if (left < 2 || 2 + ((pos[0] << 8) | pos[1]) > left) {
+	if (left < 2 || (size_t) 2 + ((pos[0] << 8) | pos[1]) > left) {
 		wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
 		return;
 	}
@@ -331,7 +334,7 @@
 			   "CID");
 		return;
 	}
-	memcpy (data->cid, pos + 2, data->cid_len);
+	memcpy(data->cid, pos + 2, data->cid_len);
 	pos += 2 + data->cid_len;
 	left -= 2 + data->cid_len;
 	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
@@ -355,13 +358,18 @@
 	}
 
 	for (i = 0;
-	     i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
+	     i < EAP_MAX_METHODS &&
+		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+		      sm->user->methods[i].method != EAP_TYPE_NONE);
 	     i++) {
-		if (sm->user->methods[i] == EAP_TYPE_PAX)
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_PAX)
 			break;
 	}
 
-	if (sm->user->methods[i] != EAP_TYPE_PAX) {
+	if (i >= EAP_MAX_METHODS ||
+	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+	    sm->user->methods[i].method != EAP_TYPE_PAX) {
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP-PAX: EAP-PAX not enabled for CID",
 				  (u8 *) data->cid, data->cid_len);
@@ -451,7 +459,8 @@
 	struct eap_pax_hdr *resp;
 
 	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+		wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
+			   "configured");
 		data->state = FAILURE;
 		return;
 	}
@@ -484,14 +493,36 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	key = malloc(EAP_PAX_MSK_LEN);
+	key = malloc(EAP_MSK_LEN);
 	if (key == NULL)
 		return NULL;
 
-	*len = EAP_PAX_MSK_LEN;
+	*len = EAP_MSK_LEN;
 	eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
 		    "Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
-		    EAP_PAX_MSK_LEN, key);
+		    EAP_MSK_LEN, key);
+
+	return key;
+}
+
+
+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+		    "Extended Master Session Key",
+		    data->rand.e, 2 * EAP_PAX_RAND_LEN,
+		    EAP_EMSK_LEN, key);
 
 	return key;
 }
@@ -504,16 +535,28 @@
 }
 
 
-const struct eap_method eap_method_pax =
+int eap_server_pax_register(void)
 {
-	.method = EAP_TYPE_PAX,
-	.name = "PAX",
-	.init = eap_pax_init,
-	.reset = eap_pax_reset,
-	.buildReq = eap_pax_buildReq,
-	.check = eap_pax_check,
-	.process = eap_pax_process,
-	.isDone = eap_pax_isDone,
-	.getKey = eap_pax_getKey,
-	.isSuccess = eap_pax_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_pax_init;
+	eap->reset = eap_pax_reset;
+	eap->buildReq = eap_pax_buildReq;
+	eap->check = eap_pax_check;
+	eap->process = eap_pax_process;
+	eap->isDone = eap_pax_isDone;
+	eap->getKey = eap_pax_getKey;
+	eap->isSuccess = eap_pax_isSuccess;
+	eap->get_emsk = eap_pax_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: l2_packet.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/l2_packet.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/l2_packet.h -L contrib/hostapd/l2_packet.h -u -r1.2 -r1.3
--- contrib/hostapd/l2_packet.h
+++ contrib/hostapd/l2_packet.h
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - Layer2 packet interface definition
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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
@@ -42,11 +42,19 @@
  */
 struct l2_packet_data;
 
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
 struct l2_ethhdr {
 	u8 h_dest[ETH_ALEN];
 	u8 h_source[ETH_ALEN];
 	u16 h_proto;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
 
 /**
  * l2_packet_init - Initialize l2_packet interface
Index: ieee802_1x.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_1x.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ieee802_1x.c -L contrib/hostapd/ieee802_1x.c -u -r1.2 -r1.3
--- contrib/hostapd/ieee802_1x.c
+++ contrib/hostapd/ieee802_1x.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / IEEE 802.1X Authenticator
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / IEEE 802.1X Authenticator
+ * Copyright (c) 2002-2006, 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,20 +11,11 @@
  *
  * See README and COPYING for more details.
  *
- * $FreeBSD: src/contrib/hostapd/ieee802_1x.c,v 1.3.2.1 2006/03/24 01:42:34 sam Exp $
+ * $FreeBSD: src/contrib/hostapd/ieee802_1x.c,v 1.5 2007/07/09 16:20:41 sam Exp $
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <signal.h>
+#include "includes.h"
 #include <assert.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/socket.h>
 
 #include "hostapd.h"
 #include "ieee802_1x.h"
@@ -38,7 +28,10 @@
 #include "eloop.h"
 #include "sta_info.h"
 #include "wpa.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
 #include "driver.h"
+#include "hw_features.h"
 #include "eap.h"
 
 
@@ -46,8 +39,8 @@
 					struct sta_info *sta);
 
 
-static void ieee802_1x_send(hostapd *hapd, struct sta_info *sta, u8 type,
-			    u8 *data, size_t datalen)
+static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
+			    u8 type, u8 *data, size_t datalen)
 {
 	u8 *buf;
 	struct ieee802_1x_hdr *xhdr;
@@ -55,14 +48,13 @@
 	int encrypt = 0;
 
 	len = sizeof(*xhdr) + datalen;
-	buf = malloc(len);
+	buf = wpa_zalloc(len);
 	if (buf == NULL) {
 		printf("malloc() failed for ieee802_1x_send(len=%lu)\n",
 		       (unsigned long) len);
 		return;
 	}
 
-	memset(buf, 0, len);
 #if 0
 	/* TODO:
 	 * According to IEEE 802.1aa/D4 EAPOL-Key should be sent before any
@@ -76,14 +68,14 @@
 #endif
 
 	xhdr = (struct ieee802_1x_hdr *) buf;
-	xhdr->version = EAPOL_VERSION;
+	xhdr->version = hapd->conf->eapol_version;
 	xhdr->type = type;
 	xhdr->length = htons(datalen);
 
 	if (datalen > 0 && data != NULL)
 		memcpy(xhdr + 1, data, datalen);
 
-	if (sta->wpa_sm && sta->wpa_sm->pairwise_set)
+	if (wpa_auth_pairwise_set(sta->wpa_sm))
 		encrypt = 1;
 	if (sta->flags & WLAN_STA_PREAUTH) {
 		rsn_preauth_send(hapd, sta, buf, len);
@@ -95,23 +87,33 @@
 }
 
 
-void ieee802_1x_set_sta_authorized(hostapd *hapd, struct sta_info *sta,
-				   int authorized)
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized)
 {
+	int res;
+
 	if (sta->flags & WLAN_STA_PREAUTH)
 		return;
 
 	if (authorized) {
 		sta->flags |= WLAN_STA_AUTHORIZED;
+		res = hostapd_sta_set_flags(hapd, sta->addr,
+					    WLAN_STA_AUTHORIZED, ~0);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
 	} else {
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
+		res = hostapd_sta_set_flags(hapd, sta->addr,
+					    0, ~WLAN_STA_AUTHORIZED);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
 	}
 
-	hostapd_set_sta_authorized(hapd, sta->addr, authorized);
+	if (res && errno != ENOENT) {
+		printf("Could not set station " MACSTR " flags for kernel "
+		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+	}
+
 	if (authorized)
 		accounting_sta_start(hapd, sta);
 }
@@ -146,21 +148,19 @@
 		return;
 	}
 
-	if (sm == NULL || !sm->auth_pae.eapRestart)
+	if (sm == NULL || !sm->eapRestart)
 		return;
 
 	ieee802_1x_new_auth_session(hapd, sta);
 
 	tlen = sizeof(*eap) + 1 + hapd->conf->eap_req_id_text_len;
 
-	buf = malloc(tlen);
+	buf = wpa_zalloc(tlen);
 	if (buf == NULL) {
 		printf("Could not allocate memory for identity request\n");
 		return;
 	}
 
-	memset(buf, 0, tlen);
-
 	eap = (struct eap_hdr *) buf;
 	eap->code = EAP_CODE_REQUEST;
 	eap->identifier = ++sm->currentId;
@@ -172,7 +172,7 @@
 		       hapd->conf->eap_req_id_text_len);
 	}
 
-	sm->be_auth.eapReq = TRUE;
+	sm->eapReq = TRUE;
 	free(sm->last_eap_radius);
 	sm->last_eap_radius = buf;
 	sm->last_eap_radius_len = tlen;
@@ -186,7 +186,7 @@
 		      " (identifier %d, timeout 30)\n", MAC2STR(sta->addr),
 		      eap->identifier);
 
-	sm->auth_pae.eapRestart = FALSE;
+	sm->eapRestart = FALSE;
 }
 
 
@@ -250,24 +250,9 @@
 }
 
 
-void hostapd_get_ntp_timestamp(u8 *buf)
-{
-	struct timeval now;
-	u32 sec, usec;
-
-	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
-	gettimeofday(&now, NULL);
-	sec = htonl(now.tv_sec + 2208988800U); /* Epoch to 1900 */
-	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
-	usec = now.tv_usec;
-	usec = htonl(4295 * usec - (usec >> 5) - (usec >> 9));
-	memcpy(buf, (u8 *) &sec, 4);
-	memcpy(buf + 4, (u8 *) &usec, 4);
-}
-
-
-static void ieee802_1x_tx_key_one(hostapd *hapd, struct sta_info *sta,
-				  int index, int broadcast,
+static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
+				  struct sta_info *sta,
+				  int idx, int broadcast,
 				  u8 *key_data, size_t key_len)
 {
 	u8 *buf, *ekey;
@@ -280,16 +265,15 @@
 		return;
 
 	len = sizeof(*key) + key_len;
-	buf = malloc(sizeof(*hdr) + len);
+	buf = wpa_zalloc(sizeof(*hdr) + len);
 	if (buf == NULL)
 		return;
 
-	memset(buf, 0, sizeof(*hdr) + len);
 	hdr = (struct ieee802_1x_hdr *) buf;
 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
 	key->type = EAPOL_KEY_TYPE_RC4;
 	key->key_length = htons(key_len);
-	hostapd_get_ntp_timestamp(key->replay_counter);
+	wpa_get_ntp_timestamp(key->replay_counter);
 
 	if (hostapd_get_rand(key->key_iv, sizeof(key->key_iv))) {
 		printf("Could not get random numbers\n");
@@ -297,7 +281,7 @@
 		return;
 	}
 
-	key->key_index = index | (broadcast ? 0 : BIT(7));
+	key->key_index = idx | (broadcast ? 0 : BIT(7));
 	if (hapd->conf->eapol_key_index_workaround) {
 		/* According to some information, WinXP Supplicant seems to
 		 * interpret bit7 as an indication whether the key is to be
@@ -324,7 +308,7 @@
 
 	/* This header is needed here for HMAC-MD5, but it will be regenerated
 	 * in ieee802_1x_send() */
-	hdr->version = EAPOL_VERSION;
+	hdr->version = hapd->conf->eapol_version;
 	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
 	hdr->length = htons(len);
 	hmac_md5(sm->eapol_key_sign, sm->eapol_key_sign_len,
@@ -334,7 +318,7 @@
 	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
 		      "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
 		      " (%s index=%d)\n", MAC2STR(sm->addr),
-		      broadcast ? "broadcast" : "unicast", index);
+		      broadcast ? "broadcast" : "unicast", idx);
 	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
 	if (sta->eapol_sm)
 		sta->eapol_sm->dot1xAuthEapolFramesTx++;
@@ -342,9 +326,109 @@
 }
 
 
+static struct hostapd_wep_keys *
+ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
+{
+	struct hostapd_wep_keys *key;
+
+	key = wpa_zalloc(sizeof(*key));
+	if (key == NULL)
+		return NULL;
+
+	key->default_len = hapd->conf->default_wep_key_len;
+
+	if (key->idx >= hapd->conf->broadcast_key_idx_max ||
+	    key->idx < hapd->conf->broadcast_key_idx_min)
+		key->idx = hapd->conf->broadcast_key_idx_min;
+	else
+		key->idx++;
+
+	if (!key->key[key->idx])
+		key->key[key->idx] = malloc(key->default_len);
+	if (key->key[key->idx] == NULL ||
+	    hostapd_get_rand(key->key[key->idx], key->default_len)) {
+		printf("Could not generate random WEP key (dynamic VLAN).\n");
+		free(key->key[key->idx]);
+		key->key[key->idx] = NULL;
+		free(key);
+		return NULL;
+	}
+	key->len[key->idx] = key->default_len;
+
+	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
+		printf("%s: Default WEP idx %d for dynamic VLAN\n",
+		       ifname, key->idx);
+		wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
+				key->key[key->idx], key->len[key->idx]);
+	}
+
+	if (hostapd_set_encryption(ifname, hapd, "WEP", NULL, key->idx,
+				   key->key[key->idx], key->len[key->idx], 1))
+		printf("Could not set dynamic VLAN WEP encryption key.\n");
+
+	hostapd_set_ieee8021x(ifname, hapd, 1);
+
+	return key;
+}
+
+
+static struct hostapd_wep_keys *
+ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
+		     size_t vlan_id)
+{
+	const char *ifname;
+
+	if (vlan_id == 0)
+		return &ssid->wep;
+
+	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
+	    ssid->dyn_vlan_keys[vlan_id])
+		return ssid->dyn_vlan_keys[vlan_id];
+
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Creating new group "
+		      "state machine for VLAN ID %lu\n",
+		      (unsigned long) vlan_id);
+
+	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+	if (ifname == NULL) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "IEEE 802.1X: Unknown "
+			      "VLAN ID %lu - cannot create group key state "
+			      "machine\n", (unsigned long) vlan_id);
+		return NULL;
+	}
+
+	if (ssid->dyn_vlan_keys == NULL) {
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		ssid->dyn_vlan_keys = wpa_zalloc(size);
+		if (ssid->dyn_vlan_keys == NULL)
+			return NULL;
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	if (ssid->max_dyn_vlan_keys < vlan_id) {
+		struct hostapd_wep_keys **na;
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		na = realloc(ssid->dyn_vlan_keys, size);
+		if (na == NULL)
+			return NULL;
+		ssid->dyn_vlan_keys = na;
+		memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
+		       (vlan_id - ssid->max_dyn_vlan_keys) *
+		       sizeof(ssid->dyn_vlan_keys[0]));
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
+
+	return ssid->dyn_vlan_keys[vlan_id];
+}
+
+
 void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 {
+	struct hostapd_wep_keys *key = NULL;
 	struct eapol_state_machine *sm = sta->eapol_sm;
+	int vlan_id;
 
 	if (sm == NULL || !sm->eapol_key_sign || !sm->eapol_key_crypt)
 		return;
@@ -353,10 +437,21 @@
 		      "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR "\n",
 		      MAC2STR(sta->addr));
 
-	if (hapd->default_wep_key)
+	vlan_id = sta->vlan_id;
+	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
+		vlan_id = 0;
+
+	if (vlan_id) {
+		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
+		if (key && key->key[key->idx])
+			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
+					      key->key[key->idx],
+					      key->len[key->idx]);
+	} else if (hapd->default_wep_key) {
 		ieee802_1x_tx_key_one(hapd, sta, hapd->default_wep_key_idx, 1,
 				      hapd->default_wep_key,
 				      hapd->conf->default_wep_key_len);
+	}
 
 	if (hapd->conf->individual_wep_key_len > 0) {
 		u8 *ikey;
@@ -370,19 +465,18 @@
 			return;
 		}
 
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL))
-			hostapd_hexdump("Individual WEP key",
-					ikey,
-					hapd->conf->individual_wep_key_len);
+		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
+				ikey, hapd->conf->individual_wep_key_len);
 
 		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
 				      hapd->conf->individual_wep_key_len);
 
 		/* TODO: set encryption in TX callback, i.e., only after STA
 		 * has ACKed EAPOL-Key frame */
-		if (hostapd_set_encryption(hapd, "WEP", sta->addr, 0, ikey,
-					   hapd->conf->
-					   individual_wep_key_len)) {
+		if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP",
+					   sta->addr, 0, ikey,
+					   hapd->conf->individual_wep_key_len,
+					   1)) {
 			printf("Could not set individual WEP encryption.\n");
 		}
 
@@ -391,7 +485,38 @@
 }
 
 
-static void ieee802_1x_encapsulate_radius(hostapd *hapd, struct sta_info *sta,
+const char *radius_mode_txt(struct hostapd_data *hapd)
+{
+	if (hapd->iface->current_mode == NULL)
+		return "802.11";
+
+	switch (hapd->iface->current_mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		return "802.11a";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "802.11g";
+	case HOSTAPD_MODE_IEEE80211B:
+	default:
+		return "802.11b";
+	}
+}
+
+
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int i;
+	u8 rate = 0;
+
+	for (i = 0; i < sta->supported_rates_len; i++)
+		if ((sta->supported_rates[i] & 0x7f) > rate)
+			rate = sta->supported_rates[i] & 0x7f;
+
+	return rate;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta,
 					  u8 *eap, size_t len)
 {
 	struct radius_msg *msg;
@@ -451,7 +576,8 @@
 	}
 
 	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
-		 MAC2STR(hapd->own_addr), hapd->conf->ssid);
+		 MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
+	buf[sizeof(buf) - 1] = '\0';
 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
 				 (u8 *) buf, strlen(buf))) {
 		printf("Could not add Called-Station-Id\n");
@@ -460,6 +586,7 @@
 
 	snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
 		 MAC2STR(sta->addr));
+	buf[sizeof(buf) - 1] = '\0';
 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
 				 (u8 *) buf, strlen(buf))) {
 		printf("Could not add Calling-Station-Id\n");
@@ -480,7 +607,15 @@
 		goto fail;
 	}
 
-	snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+	if (sta->flags & WLAN_STA_PREAUTH) {
+		snprintf(buf, sizeof(buf), "IEEE 802.11i Pre-Authentication");
+	} else {
+		snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+			 radius_sta_rate(hapd, sta) / 2,
+			 (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+			 radius_mode_txt(hapd));
+	}
+	buf[sizeof(buf) - 1] = '\0';
 	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
 				 (u8 *) buf, strlen(buf))) {
 		printf("Could not add Connect-Info\n");
@@ -518,7 +653,7 @@
 }
 
 
-static char *eap_type_text(u8 type)
+char *eap_type_text(u8 type)
 {
 	switch (type) {
 	case EAP_TYPE_IDENTITY: return "Identity";
@@ -530,13 +665,18 @@
 	case EAP_TYPE_TLS: return "TLS";
 	case EAP_TYPE_TTLS: return "TTLS";
 	case EAP_TYPE_PEAP: return "PEAP";
+	case EAP_TYPE_SIM: return "SIM";
+	case EAP_TYPE_FAST: return "FAST";
+	case EAP_TYPE_SAKE: return "SAKE";
+	case EAP_TYPE_PSK: return "PSK";
 	default: return "Unknown";
 	}
 }
 
 
-static void handle_eap_response(hostapd *hapd, struct sta_info *sta,
-				struct eap_hdr *eap, u8 *data, size_t len)
+static void handle_eap_response(struct hostapd_data *hapd,
+				struct sta_info *sta, struct eap_hdr *eap,
+				u8 *data, size_t len)
 {
 	u8 type;
 	struct eapol_state_machine *sm = sta->eapol_sm;
@@ -569,7 +709,7 @@
 	memcpy(sm->last_eap_supp, eap, sizeof(*eap));
 	memcpy(sm->last_eap_supp + sizeof(*eap), data, len);
 
-	type = data[0];
+	sm->eap_type_supp = type = data[0];
 	data++;
 	len--;
 
@@ -581,7 +721,7 @@
 
 	if (type == EAP_TYPE_IDENTITY) {
 		char *buf, *pos;
-		int i;
+		size_t i;
 		buf = malloc(4 * len + 1);
 		if (buf) {
 			pos = buf;
@@ -620,8 +760,8 @@
 
 
 /* Process incoming EAP packet from Supplicant */
-static void handle_eap(hostapd *hapd, struct sta_info *sta, u8 *buf,
-		       size_t len)
+static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
+		       u8 *buf, size_t len)
 {
 	struct eap_hdr *eap;
 	u16 eap_len;
@@ -679,6 +819,7 @@
 	struct ieee802_1x_hdr *hdr;
 	struct ieee802_1x_eapol_key *key;
 	u16 datalen;
+	struct rsn_pmksa_cache_entry *pmksa;
 
 	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
 		return;
@@ -726,11 +867,13 @@
 	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
 	    (key->type == EAPOL_KEY_TYPE_WPA ||
 	     key->type == EAPOL_KEY_TYPE_RSN)) {
-		wpa_receive(hapd, sta, (u8 *) hdr, sizeof(*hdr) + datalen);
+		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
+			    sizeof(*hdr) + datalen);
 		return;
 	}
 
-	if (!hapd->conf->ieee802_1x || sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
+	if (!hapd->conf->ieee802_1x ||
+	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK)
 		return;
 
 	if (!sta->eapol_sm) {
@@ -755,16 +898,17 @@
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
 			       "from STA");
-		if (sta->pmksa) {
+		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+		if (pmksa) {
 			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
 				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
 				       "available - ignore it since "
 				       "STA sent EAPOL-Start");
-			sta->pmksa = NULL;
+			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
 		}
-		sta->eapol_sm->auth_pae.eapolStart = TRUE;
+		sta->eapol_sm->eapolStart = TRUE;
 		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
-		wpa_sm_event(hapd, sta, WPA_REAUTH_EAPOL);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
 		break;
 
 	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
@@ -773,7 +917,7 @@
 			       "from STA");
 		sta->acct_terminate_cause =
 			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
-		sta->eapol_sm->auth_pae.eapolLogoff = TRUE;
+		sta->eapol_sm->eapolLogoff = TRUE;
 		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
 		break;
 
@@ -803,9 +947,13 @@
 }
 
 
-void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta)
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
 {
-	if (!hapd->conf->ieee802_1x || sta->wpa_key_mgmt == WPA_KEY_MGMT_PSK)
+	struct rsn_pmksa_cache_entry *pmksa;
+	int reassoc = 1;
+
+	if (!hapd->conf->ieee802_1x ||
+	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK)
 		return;
 
 	if (sta->eapol_sm == NULL) {
@@ -819,11 +967,15 @@
 				       "failed to allocate state machine");
 			return;
 		}
+		reassoc = 0;
 	}
 
 	sta->eapol_sm->portEnabled = TRUE;
 
-	if (sta->pmksa) {
+	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+	if (pmksa) {
+		int old_vlanid;
+
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG,
 			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
@@ -831,19 +983,33 @@
 		 * because of existing PMKSA information in the cache. */
 		sta->eapol_sm->keyRun = TRUE;
 		sta->eapol_sm->keyAvailable = TRUE;
-		sta->eapol_sm->auth_pae.state = AUTH_PAE_AUTHENTICATING;
-		sta->eapol_sm->be_auth.state = BE_AUTH_SUCCESS;
+		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
 		sta->eapol_sm->authSuccess = TRUE;
 		if (sta->eapol_sm->eap)
 			eap_sm_notify_cached(sta->eapol_sm->eap);
-	} else
+		old_vlanid = sta->vlan_id;
+		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+		ap_sta_bind_vlan(hapd, sta, old_vlanid);
+	} else {
+		if (reassoc) {
+			/*
+			 * Force EAPOL state machines to start
+			 * re-authentication without having to wait for the
+			 * Supplicant to send EAPOL-Start.
+			 */
+			sta->eapol_sm->reAuthenticate = TRUE;
+		}
 		eapol_sm_step(sta->eapol_sm);
+	}
 }
 
 
 void ieee802_1x_free_radius_class(struct radius_class_data *class)
 {
-	int i;
+	size_t i;
 	if (class == NULL)
 		return;
 	for (i = 0; i < class->count; i++)
@@ -862,11 +1028,10 @@
 	if (src->attr == NULL)
 		return 0;
 
-	dst->attr = malloc(src->count * sizeof(struct radius_attr_data));
+	dst->attr = wpa_zalloc(src->count * sizeof(struct radius_attr_data));
 	if (dst->attr == NULL)
 		return -1;
 
-	memset(dst->attr, 0, src->count * sizeof(struct radius_attr_data));
 	dst->count = 0;
 
 	for (i = 0; i < src->count; i++) {
@@ -908,7 +1073,8 @@
 }
 
 
-static void ieee802_1x_decapsulate_radius(hostapd *hapd, struct sta_info *sta)
+static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta)
 {
 	u8 *eap;
 	size_t len;
@@ -920,7 +1086,7 @@
 
 	if (sm == NULL || sm->last_recv_radius == NULL) {
 		if (sm)
-			sm->be_auth.eapNoReq = TRUE;
+			sm->eapNoReq = TRUE;
 		return;
 	}
 
@@ -937,7 +1103,7 @@
 		free(sm->last_eap_radius);
 		sm->last_eap_radius = NULL;
 		sm->last_eap_radius_len = 0;
-		sm->be_auth.eapNoReq = TRUE;
+		sm->eapNoReq = TRUE;
 		return;
 	}
 
@@ -946,7 +1112,7 @@
 			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
 			       "received from authentication server");
 		free(eap);
-		sm->be_auth.eapNoReq = TRUE;
+		sm->eapNoReq = TRUE;
 		return;
 	}
 
@@ -956,6 +1122,8 @@
 	hdr = (struct eap_hdr *) eap;
 	switch (hdr->code) {
 	case EAP_CODE_REQUEST:
+		if (eap_type >= 0)
+			sm->eap_type_authsrv = eap_type;
 		snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
 			 eap_type >= 0 ? eap_type_text(eap_type) : "??",
 			 eap_type);
@@ -975,11 +1143,12 @@
 		snprintf(buf, sizeof(buf), "unknown EAP code");
 		break;
 	}
+	buf[sizeof(buf) - 1] = '\0';
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
 		       "id=%d len=%d) from RADIUS server: %s",
 		      hdr->code, hdr->identifier, ntohs(hdr->length), buf);
-	sm->be_auth.eapReq = TRUE;
+	sm->eapReq = TRUE;
 
 	free(sm->last_eap_radius);
 	sm->last_eap_radius = eap;
@@ -987,8 +1156,9 @@
 }
 
 
-static void ieee802_1x_get_keys(hostapd *hapd, struct sta_info *sta,
-				struct radius_msg *msg, struct radius_msg *req,
+static void ieee802_1x_get_keys(struct hostapd_data *hapd,
+				struct sta_info *sta, struct radius_msg *msg,
+				struct radius_msg *req,
 				u8 *shared_secret, size_t shared_secret_len)
 {
 	struct radius_ms_mppe_keys *keys;
@@ -1000,21 +1170,13 @@
 				      shared_secret_len);
 
 	if (keys) {
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL) && keys->send) {
-			size_t i;
-			printf("MS-MPPE-Send-Key (len=%lu):",
-			       (unsigned long) keys->send_len);
-			for (i = 0; i < keys->send_len; i++)
-				printf(" %02x", keys->send[i]);
-			printf("\n");
+		if (keys->send) {
+			wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+					keys->send, keys->send_len);
 		}
-		if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL) && keys->recv) {
-			size_t i;
-			printf("MS-MPPE-Recv-Key (len=%lu):",
-			       (unsigned long) keys->recv_len);
-			for (i = 0; i < keys->recv_len; i++)
-				printf(" %02x", keys->recv[i]);
-			printf("\n");
+		if (keys->recv) {
+			wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+					keys->recv, keys->recv_len);
 		}
 
 		if (keys->send && keys->recv) {
@@ -1057,12 +1219,11 @@
 	if (count <= 0)
 		return;
 
-	nclass = malloc(count * sizeof(struct radius_attr_data));
+	nclass = wpa_zalloc(count * sizeof(struct radius_attr_data));
 	if (nclass == NULL)
 		return;
 
 	nclass_count = 0;
-	memset(nclass, 0, count * sizeof(struct radius_attr_data));
 
 	class = NULL;
 	for (i = 0; i < count; i++) {
@@ -1170,7 +1331,7 @@
 	struct hostapd_data *hapd = data;
 	struct sta_info *sta;
 	u32 session_timeout = 0, termination_action, acct_interim_interval;
-	int session_timeout_set;
+	int session_timeout_set, old_vlanid = 0;
 	int eap_timeout;
 	struct eapol_state_machine *sm;
 	int override_eapReq = 0;
@@ -1244,10 +1405,35 @@
 
 	switch (msg->hdr->code) {
 	case RADIUS_CODE_ACCESS_ACCEPT:
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+		else {
+			old_vlanid = sta->vlan_id;
+			sta->vlan_id = radius_msg_get_vlanid(msg);
+		}
+		if (sta->vlan_id > 0 &&
+		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       sta->vlan_id)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "VLAN ID %d", sta->vlan_id);
+		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+			sta->eapol_sm->authFail = TRUE;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO, "authentication "
+				       "server did not include required VLAN "
+				       "ID in Access-Accept");
+			break;
+		}
+
+		ap_sta_bind_vlan(hapd, sta, old_vlanid);
+
 		/* RFC 3580, Ch. 3.17 */
 		if (session_timeout_set && termination_action ==
 		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
-			sm->reauth_timer.reAuthPeriod = session_timeout;
+			sm->reAuthPeriod = session_timeout;
 		} else if (session_timeout_set)
 			ap_sta_session_timeout(hapd, sta, session_timeout);
 
@@ -1257,10 +1443,13 @@
 				    shared_secret_len);
 		ieee802_1x_store_radius_class(hapd, sta, msg);
 		ieee802_1x_update_sta_identity(hapd, sta, msg);
-		if (sm->keyAvailable) {
-			pmksa_cache_add(hapd, sta, sm->eapol_key_crypt,
-					session_timeout_set ?
-					session_timeout : -1);
+		if (sm->keyAvailable &&
+		    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
+				       session_timeout_set ?
+				       (int) session_timeout : -1, sm) == 0) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Added PMKSA cache entry");
 		}
 		break;
 	case RADIUS_CODE_ACCESS_REJECT:
@@ -1287,7 +1476,7 @@
 
 	ieee802_1x_decapsulate_radius(hapd, sta);
 	if (override_eapReq)
-		sm->be_auth.eapReq = FALSE;
+		sm->eapReq = FALSE;
 
 	eapol_sm_step(sm);
 
@@ -1297,7 +1486,8 @@
 
 /* Handler for EAPOL Backend Authentication state machine sendRespToServer.
  * Forward the EAP Response from Supplicant to Authentication Server. */
-void ieee802_1x_send_resp_to_server(hostapd *hapd, struct sta_info *sta)
+void ieee802_1x_send_resp_to_server(struct hostapd_data *hapd,
+				    struct sta_info *sta)
 {
 	struct eapol_state_machine *sm = sta->eapol_sm;
 	if (sm == NULL)
@@ -1336,21 +1526,16 @@
 }
 
 
-void ieee802_1x_set_port_enabled(hostapd *hapd, struct sta_info *sta,
-				 int enabled)
+#ifdef HOSTAPD_DUMP_STATE
+static void fprint_char(FILE *f, char c)
 {
-	if (!sta->eapol_sm)
-		return;
-
-	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
-		      "IEEE 802.1X: station " MACSTR " port %s\n",
-		      MAC2STR(sta->addr), enabled ? "enabled" : "disabled");
-	sta->eapol_sm->portEnabled = enabled ? TRUE : FALSE;
-	eapol_sm_step(sta->eapol_sm);
+	if (c >= 32 && c < 127)
+		fprintf(f, "%c", c);
+	else
+		fprintf(f, "<%02x>", c);
 }
 
 
-#ifdef HOSTAPD_DUMP_STATE
 void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta)
 {
 	struct eapol_state_machine *sm = sta->eapol_sm;
@@ -1367,6 +1552,11 @@
 		fprintf(f, "\n");
 	}
 
+	fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
+		"Supplicant: %d (%s)\n", prefix,
+		sm->eap_type_authsrv, eap_type_text(sm->eap_type_authsrv),
+		sm->eap_type_supp, eap_type_text(sm->eap_type_supp));
+
 	fprintf(f, "%scached_packets=%s%s%s\n", prefix,
 		sm->last_recv_radius ? "[RX RADIUS]" : "",
 		sm->last_eap_radius ? "[EAP RADIUS]" : "",
@@ -1377,7 +1567,7 @@
 #endif /* HOSTAPD_DUMP_STATE */
 
 
-static int ieee802_1x_rekey_broadcast(hostapd *hapd)
+static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
 {
 	if (hapd->conf->default_wep_key_len < 1)
 		return 0;
@@ -1393,11 +1583,9 @@
 		return -1;
 	}
 
-	if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MINIMAL)) {
-		hostapd_hexdump("IEEE 802.1X: New default WEP key",
-				hapd->default_wep_key,
-				hapd->conf->default_wep_key_len);
-	}
+	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
+			hapd->default_wep_key,
+			hapd->conf->default_wep_key_len);
 
 	return 0;
 }
@@ -1438,10 +1626,10 @@
 
 	/* TODO: Could setup key for RX here, but change default TX keyid only
 	 * after new broadcast key has been sent to all stations. */
-	if (hostapd_set_encryption(hapd, "WEP", NULL,
+	if (hostapd_set_encryption(hapd->conf->iface, hapd, "WEP", NULL,
 				   hapd->default_wep_key_idx,
 				   hapd->default_wep_key,
-				   hapd->conf->default_wep_key_len)) {
+				   hapd->conf->default_wep_key_len, 1)) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
 			       "new broadcast key");
@@ -1459,12 +1647,12 @@
 }
 
 
-int ieee802_1x_init(hostapd *hapd)
+int ieee802_1x_init(struct hostapd_data *hapd)
 {
 	int i;
 
 	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
-	    hostapd_set_ieee8021x(hapd, 1))
+	    hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1))
 		return -1;
 
 	if (radius_client_register(hapd->radius, RADIUS_AUTH,
@@ -1472,8 +1660,11 @@
 		return -1;
 
 	if (hapd->conf->default_wep_key_len) {
+		hostapd_set_privacy(hapd, 1);
+
 		for (i = 0; i < 4; i++)
-			hostapd_set_encryption(hapd, "none", NULL, i, NULL, 0);
+			hostapd_set_encryption(hapd->conf->iface, hapd,
+					       "none", NULL, i, NULL, 0, 0);
 
 		ieee802_1x_rekey(hapd, NULL);
 
@@ -1485,11 +1676,20 @@
 }
 
 
-void ieee802_1x_deinit(hostapd *hapd)
+void ieee802_1x_deinit(struct hostapd_data *hapd)
 {
 	if (hapd->driver != NULL &&
 	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
-		hostapd_set_ieee8021x(hapd, 0);
+		hostapd_set_ieee8021x(hapd->conf->iface, hapd, 0);
+}
+
+
+int ieee802_1x_reconfig(struct hostapd_data *hapd, 
+			struct hostapd_config *oldconf,
+			struct hostapd_bss_config *oldbss)
+{
+	ieee802_1x_deinit(hapd);
+	return ieee802_1x_init(hapd);
 }
 
 
@@ -1515,8 +1715,8 @@
 }
 
 
-int ieee802_1x_tx_status(hostapd *hapd, struct sta_info *sta, u8 *buf,
-			 size_t len, int ack)
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 u8 *buf, size_t len, int ack)
 {
 	struct ieee80211_hdr *hdr;
 	struct ieee802_1x_hdr *xhdr;
@@ -1587,7 +1787,7 @@
 				 int idx)
 {
 	if (sm == NULL || sm->radius_class.attr == NULL ||
-	    idx >= sm->radius_class.count)
+	    idx >= (int) sm->radius_class.count)
 		return NULL;
 
 	*len = sm->radius_class.attr[idx].len;
@@ -1652,124 +1852,140 @@
 int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			   char *buf, size_t buflen)
 {
-	int len = 0;
+	int len = 0, ret;
 	struct eapol_state_machine *sm = sta->eapol_sm;
 
 	if (sm == NULL)
 		return 0;
 
-	len += snprintf(buf + len, buflen - len,
-			"dot1xPaePortNumber=%d\n"
-			"dot1xPaePortProtocolVersion=%d\n"
-			"dot1xPaePortCapabilities=1\n"
-			"dot1xPaePortInitialize=%d\n"
-			"dot1xPaePortReauthenticate=FALSE\n",
-			sta->aid,
-			EAPOL_VERSION,
-			sm->initialize);
+	ret = snprintf(buf + len, buflen - len,
+		       "dot1xPaePortNumber=%d\n"
+		       "dot1xPaePortProtocolVersion=%d\n"
+		       "dot1xPaePortCapabilities=1\n"
+		       "dot1xPaePortInitialize=%d\n"
+		       "dot1xPaePortReauthenticate=FALSE\n",
+		       sta->aid,
+		       EAPOL_VERSION,
+		       sm->initialize);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	/* dot1xAuthConfigTable */
-	len += snprintf(buf + len, buflen - len,
-			"dot1xAuthPaeState=%d\n"
-			"dot1xAuthBackendAuthState=%d\n"
-			"dot1xAuthAdminControlledDirections=%d\n"
-			"dot1xAuthOperControlledDirections=%d\n"
-			"dot1xAuthAuthControlledPortStatus=%d\n"
-			"dot1xAuthAuthControlledPortControl=%d\n"
-			"dot1xAuthQuietPeriod=%u\n"
-			"dot1xAuthServerTimeout=%u\n"
-			"dot1xAuthReAuthPeriod=%u\n"
-			"dot1xAuthReAuthEnabled=%s\n"
-			"dot1xAuthKeyTxEnabled=%s\n",
-			sm->auth_pae.state + 1,
-			sm->be_auth.state + 1,
-			sm->ctrl_dir.adminControlledDirections,
-			sm->ctrl_dir.operControlledDirections,
-			sm->authPortStatus,
-			sm->portControl,
-			sm->auth_pae.quietPeriod,
-			sm->be_auth.serverTimeout,
-			sm->reauth_timer.reAuthPeriod,
-			bool_txt(sm->reauth_timer.reAuthEnabled),
-			bool_txt(sm->keyTxEnabled));
+	ret = snprintf(buf + len, buflen - len,
+		       "dot1xAuthPaeState=%d\n"
+		       "dot1xAuthBackendAuthState=%d\n"
+		       "dot1xAuthAdminControlledDirections=%d\n"
+		       "dot1xAuthOperControlledDirections=%d\n"
+		       "dot1xAuthAuthControlledPortStatus=%d\n"
+		       "dot1xAuthAuthControlledPortControl=%d\n"
+		       "dot1xAuthQuietPeriod=%u\n"
+		       "dot1xAuthServerTimeout=%u\n"
+		       "dot1xAuthReAuthPeriod=%u\n"
+		       "dot1xAuthReAuthEnabled=%s\n"
+		       "dot1xAuthKeyTxEnabled=%s\n",
+		       sm->auth_pae_state + 1,
+		       sm->be_auth_state + 1,
+		       sm->adminControlledDirections,
+		       sm->operControlledDirections,
+		       sm->authPortStatus,
+		       sm->portControl,
+		       sm->quietPeriod,
+		       sm->serverTimeout,
+		       sm->reAuthPeriod,
+		       bool_txt(sm->reAuthEnabled),
+		       bool_txt(sm->keyTxEnabled));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	/* dot1xAuthStatsTable */
-	len += snprintf(buf + len, buflen - len,
-			"dot1xAuthEapolFramesRx=%u\n"
-			"dot1xAuthEapolFramesTx=%u\n"
-			"dot1xAuthEapolStartFramesRx=%u\n"
-			"dot1xAuthEapolLogoffFramesRx=%u\n"
-			"dot1xAuthEapolRespIdFramesRx=%u\n"
-			"dot1xAuthEapolRespFramesRx=%u\n"
-			"dot1xAuthEapolReqIdFramesTx=%u\n"
-			"dot1xAuthEapolReqFramesTx=%u\n"
-			"dot1xAuthInvalidEapolFramesRx=%u\n"
-			"dot1xAuthEapLengthErrorFramesRx=%u\n"
-			"dot1xAuthLastEapolFrameVersion=%u\n"
-			"dot1xAuthLastEapolFrameSource=" MACSTR "\n",
-			sm->dot1xAuthEapolFramesRx,
-			sm->dot1xAuthEapolFramesTx,
-			sm->dot1xAuthEapolStartFramesRx,
-			sm->dot1xAuthEapolLogoffFramesRx,
-			sm->dot1xAuthEapolRespIdFramesRx,
-			sm->dot1xAuthEapolRespFramesRx,
-			sm->dot1xAuthEapolReqIdFramesTx,
-			sm->dot1xAuthEapolReqFramesTx,
-			sm->dot1xAuthInvalidEapolFramesRx,
-			sm->dot1xAuthEapLengthErrorFramesRx,
-			sm->dot1xAuthLastEapolFrameVersion,
-			MAC2STR(sm->addr));
+	ret = snprintf(buf + len, buflen - len,
+		       "dot1xAuthEapolFramesRx=%u\n"
+		       "dot1xAuthEapolFramesTx=%u\n"
+		       "dot1xAuthEapolStartFramesRx=%u\n"
+		       "dot1xAuthEapolLogoffFramesRx=%u\n"
+		       "dot1xAuthEapolRespIdFramesRx=%u\n"
+		       "dot1xAuthEapolRespFramesRx=%u\n"
+		       "dot1xAuthEapolReqIdFramesTx=%u\n"
+		       "dot1xAuthEapolReqFramesTx=%u\n"
+		       "dot1xAuthInvalidEapolFramesRx=%u\n"
+		       "dot1xAuthEapLengthErrorFramesRx=%u\n"
+		       "dot1xAuthLastEapolFrameVersion=%u\n"
+		       "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
+		       sm->dot1xAuthEapolFramesRx,
+		       sm->dot1xAuthEapolFramesTx,
+		       sm->dot1xAuthEapolStartFramesRx,
+		       sm->dot1xAuthEapolLogoffFramesRx,
+		       sm->dot1xAuthEapolRespIdFramesRx,
+		       sm->dot1xAuthEapolRespFramesRx,
+		       sm->dot1xAuthEapolReqIdFramesTx,
+		       sm->dot1xAuthEapolReqFramesTx,
+		       sm->dot1xAuthInvalidEapolFramesRx,
+		       sm->dot1xAuthEapLengthErrorFramesRx,
+		       sm->dot1xAuthLastEapolFrameVersion,
+		       MAC2STR(sm->addr));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	/* dot1xAuthDiagTable */
-	len += snprintf(buf + len, buflen - len,
-			"dot1xAuthEntersConnecting=%u\n"
-			"dot1xAuthEapLogoffsWhileConnecting=%u\n"
-			"dot1xAuthEntersAuthenticating=%u\n"
-			"dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
-			"dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
-			"dot1xAuthAuthFailWhileAuthenticating=%u\n"
-			"dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
-			"dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
-			"dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
-			"dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
-			"dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
-			"dot1xAuthBackendResponses=%u\n"
-			"dot1xAuthBackendAccessChallenges=%u\n"
-			"dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
-			"dot1xAuthBackendAuthSuccesses=%u\n"
-			"dot1xAuthBackendAuthFails=%u\n",
-			sm->auth_pae.authEntersConnecting,
-			sm->auth_pae.authEapLogoffsWhileConnecting,
-			sm->auth_pae.authEntersAuthenticating,
-			sm->auth_pae.authAuthSuccessesWhileAuthenticating,
-			sm->auth_pae.authAuthTimeoutsWhileAuthenticating,
-			sm->auth_pae.authAuthFailWhileAuthenticating,
-			sm->auth_pae.authAuthEapStartsWhileAuthenticating,
-			sm->auth_pae.authAuthEapLogoffWhileAuthenticating,
-			sm->auth_pae.authAuthReauthsWhileAuthenticated,
-			sm->auth_pae.authAuthEapStartsWhileAuthenticated,
-			sm->auth_pae.authAuthEapLogoffWhileAuthenticated,
-			sm->be_auth.backendResponses,
-			sm->be_auth.backendAccessChallenges,
-			sm->be_auth.backendOtherRequestsToSupplicant,
-			sm->be_auth.backendAuthSuccesses,
-			sm->be_auth.backendAuthFails);
+	ret = snprintf(buf + len, buflen - len,
+		       "dot1xAuthEntersConnecting=%u\n"
+		       "dot1xAuthEapLogoffsWhileConnecting=%u\n"
+		       "dot1xAuthEntersAuthenticating=%u\n"
+		       "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
+		       "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
+		       "dot1xAuthAuthFailWhileAuthenticating=%u\n"
+		       "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
+		       "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
+		       "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
+		       "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
+		       "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
+		       "dot1xAuthBackendResponses=%u\n"
+		       "dot1xAuthBackendAccessChallenges=%u\n"
+		       "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
+		       "dot1xAuthBackendAuthSuccesses=%u\n"
+		       "dot1xAuthBackendAuthFails=%u\n",
+		       sm->authEntersConnecting,
+		       sm->authEapLogoffsWhileConnecting,
+		       sm->authEntersAuthenticating,
+		       sm->authAuthSuccessesWhileAuthenticating,
+		       sm->authAuthTimeoutsWhileAuthenticating,
+		       sm->authAuthFailWhileAuthenticating,
+		       sm->authAuthEapStartsWhileAuthenticating,
+		       sm->authAuthEapLogoffWhileAuthenticating,
+		       sm->authAuthReauthsWhileAuthenticated,
+		       sm->authAuthEapStartsWhileAuthenticated,
+		       sm->authAuthEapLogoffWhileAuthenticated,
+		       sm->backendResponses,
+		       sm->backendAccessChallenges,
+		       sm->backendOtherRequestsToSupplicant,
+		       sm->backendAuthSuccesses,
+		       sm->backendAuthFails);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	/* dot1xAuthSessionStatsTable */
-	len += snprintf(buf + len, buflen - len,
-			/* TODO: dot1xAuthSessionOctetsRx */
-			/* TODO: dot1xAuthSessionOctetsTx */
-			/* TODO: dot1xAuthSessionFramesRx */
-			/* TODO: dot1xAuthSessionFramesTx */
-			"dot1xAuthSessionId=%08X-%08X\n"
-			"dot1xAuthSessionAuthenticMethod=%d\n"
-			"dot1xAuthSessionTime=%u\n"
-			"dot1xAuthSessionTerminateCause=999\n"
-			"dot1xAuthSessionUserName=%s\n",
-			sta->acct_session_id_hi, sta->acct_session_id_lo,
-			sta->wpa_key_mgmt == WPA_KEY_MGMT_IEEE8021X ? 1 : 2,
-			(unsigned int) (time(NULL) - sta->acct_session_start),
-			sm->identity);
+	ret = snprintf(buf + len, buflen - len,
+		       /* TODO: dot1xAuthSessionOctetsRx */
+		       /* TODO: dot1xAuthSessionOctetsTx */
+		       /* TODO: dot1xAuthSessionFramesRx */
+		       /* TODO: dot1xAuthSessionFramesTx */
+		       "dot1xAuthSessionId=%08X-%08X\n"
+		       "dot1xAuthSessionAuthenticMethod=%d\n"
+		       "dot1xAuthSessionTime=%u\n"
+		       "dot1xAuthSessionTerminateCause=999\n"
+		       "dot1xAuthSessionUserName=%s\n",
+		       sta->acct_session_id_hi, sta->acct_session_id_lo,
+		       wpa_auth_sta_key_mgmt(sta->wpa_sm) ==
+		       WPA_KEY_MGMT_IEEE8021X ? 1 : 2,
+		       (unsigned int) (time(NULL) - sta->acct_session_start),
+		       sm->identity);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
 
 	return len;
 }
@@ -1784,7 +2000,11 @@
 	static const int dot11RSNAConfigPMKLifetime = 43200;
 
 	key = ieee802_1x_get_key_crypt(sta->eapol_sm, &len);
-	if (success && key) {
-		pmksa_cache_add(hapd, sta, key, dot11RSNAConfigPMKLifetime);
+	if (success && key &&
+	    wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+			       sta->eapol_sm) == 0) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Added PMKSA cache entry (IEEE 802.1X)");
 	}
 }
Index: config_types.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/config_types.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/config_types.h -L contrib/hostapd/config_types.h -u -r1.1 -r1.2
--- contrib/hostapd/config_types.h
+++ contrib/hostapd/config_types.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Shared configuration file defines
+ * Copyright (c) 2003-2005, 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 CONFIG_TYPES_H
 #define CONFIG_TYPES_H
 
Index: hostapd.conf
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/hostapd.conf,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/hostapd.conf -L contrib/hostapd/hostapd.conf -u -r1.2 -r1.3
--- contrib/hostapd/hostapd.conf
+++ contrib/hostapd/hostapd.conf
@@ -1,7 +1,7 @@
 ##### hostapd configuration file ##############################################
 # Empty lines and lines starting with # are ignored
 
-# AP netdevice name (without 'ap' prefix, i.e., wlan0 uses wlan0ap for
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
 # management frames); ath0 for madwifi
 interface=wlan0
 
@@ -26,6 +26,7 @@
 # bit 3 (8) = WPA
 # bit 4 (16) = driver interface
 # bit 5 (32) = IAPP
+# bit 6 (64) = MLME
 #
 # Levels (minimum value for logged events):
 #  0 = verbose debugging
@@ -76,7 +77,90 @@
 # SSID to be used in IEEE 802.11 management frames
 ssid=test
 
+# Country code (ISO/IEC 3166-1).  Used to set regulatory domain.
+# Modify as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+# (default: US)
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Enable IEEE 802.11h. This enables the TPC and DFS services when operating
+# in a regulatory domain which requires them.  Once enabled it will be 
+# operational only when working in hw_mode a and in countries where it is
+# required. The end user should not be allowed to disable this.
+# The country_code setting must be configured with the correct country for
+# IEEE 802.11h to function. 
+# When IEEE 802.11h is operational, the channel_policy and configured channel 
+# settings will be ignored but will behave as though the channel_policy is
+# set to "3" (automatic channel selection). When IEEE 802.11h is enabled but
+# not operational (for example, if the radio mode is changed from "a" to "b")
+# the channel_policy and channel settings take effect again. 
+# (default: 1 = enabled)
+#ieee80211h=1
+
+# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
+# Default: IEEE 802.11b
+hw_mode=a
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set, used with channel_policy=2)
+channel=60
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery trafic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# If this field is not included in hostapd.conf, hostapd will not control
+# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
+rts_threshold=2347
+
+# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# If this field is not included in hostapd.conf, hostapd will not control
+# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
+# it.
+fragm_threshold=2346
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
 # Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=devicescape, but not with driver=madwifi.
 # 0 = accept unless in deny list
 # 1 = deny unless in accept list
 # 2 = use external RADIUS server (accept/deny lists are searched first)
@@ -96,10 +180,197 @@
 # bit 1 = Shared Key Authentication (requires WEP)
 auth_algs=3
 
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+#     broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+#     with some clients that do not support empty SSID) and ignore probe
+#     requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# TX queue parameters (EDCF / bursting)
+# default for all these fields: not set, use hardware defaults
+# tx_queue_<queue name>_<param>
+# queues: data0, data1, data2, data3, after_beacon, beacon
+#		(data0 is the highest priority queue)
+# parameters:
+#   aifs: AIFS (default 2)
+#   cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
+#   cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+#   burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
+#          bursting
+#
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# These parameters are used by the access point when transmitting frames
+# to the clients.
+#
+# Low priority / AC_BK = background
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
+#
+# Normal priority / AC_BE = best effort
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
+#
+# High priority / AC_VI = video
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
+#
+# Highest priority / AC_VO = voice
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+#
+# Special queues; normally not user configurable
+#
+#tx_queue_after_beacon_aifs=2
+#tx_queue_after_beacon_cwmin=15
+#tx_queue_after_beacon_cwmax=1023
+#tx_queue_after_beacon_burst=0
+#
+#tx_queue_beacon_aifs=2
+#tx_queue_beacon_cwmin=3
+#tx_queue_beacon_cwmax=7
+#tx_queue_beacon_burst=1.5
+
+# 802.1D Tag to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag	802.1D Designation	Access Category	WMM Designation
+# 1		BK			AC_BK		Background
+# 2		-			AC_BK		Background
+# 0		BE			AC_BE		Best Effort
+# 3		EE			AC_VI		Video
+# 4		CL			AC_VI		Video
+# 5		VI			AC_VI		Video
+# 6		VO			AC_VO		Voice
+# 7		NC			AC_VO		Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
+
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# for 802.11a or 802.11g networks
+# These parameters are sent to WMM clients when they associate.
+# The parameters will be used by WMM clients for frames transmitted to the
+# access point.
+#
+# note - txop_limit is in units of 32microseconds
+# note - acm is admission control mandatory flag. 0 = admission control not
+# required, 1 = mandatory
+# note - here cwMin and cmMax are in exponent form. the actual cw value used
+# will be (2^n)-1 where n is the value given here
+#
+wme_enabled=1
+#
+# Low priority / AC_BK = background
+wme_ac_bk_cwmin=4
+wme_ac_bk_cwmax=10
+wme_ac_bk_aifs=7
+wme_ac_bk_txop_limit=0
+wme_ac_bk_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
+#
+# Normal priority / AC_BE = best effort
+wme_ac_be_aifs=3
+wme_ac_be_cwmin=4
+wme_ac_be_cwmax=10
+wme_ac_be_txop_limit=0
+wme_ac_be_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
+#
+# High priority / AC_VI = video
+wme_ac_vi_aifs=2
+wme_ac_vi_cwmin=3
+wme_ac_vi_cwmax=4
+wme_ac_vi_txop_limit=94
+wme_ac_vi_acm=0
+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
+#
+# Highest priority / AC_VO = voice
+wme_ac_vo_aifs=2
+wme_ac_vo_cwmin=2
+wme_ac_vo_cwmax=3
+wme_ac_vo_txop_limit=47
+wme_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
 # Associate as a station to another AP while still acting as an AP on the same
 # channel.
 #assoc_ap_addr=00:12:34:56:78:9a
 
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+
+# Enable/disable internal bridge for packets between associated stations.
+#
+# When IEEE 802.11 is used in managed mode, packets are usually send through
+# the AP even if they are from a wireless station to another wireless station.
+# This functionality requires that the AP has a bridge functionality that sends
+# frames back to the same interface if their destination is another associated
+# station. In addition, broadcast/multicast frames from wireless stations will
+# be sent both to the host system net stack (e.g., to eventually wired network)
+# and back to the wireless interface.
+#
+# The internal bridge is implemented within the wireless kernel module and it
+# bypasses kernel filtering (netfilter/iptables/ebtables). If direct
+# communication between the stations needs to be prevented, the internal
+# bridge can be disabled by setting bridge_packets=0.
+#
+# Note: If this variable is not included in hostapd.conf, hostapd does not
+# change the configuration and iwpriv can be used to set the value with
+# 'iwpriv wlan# param 10 0' command. If the variable is in hostapd.conf,
+# hostapd will override possible iwpriv configuration whenever configuration
+# file is reloaded.
+#
+# default: do not control from hostapd (80211.o defaults to 1=enabled)
+#bridge_packets=1
+
 
 ##### IEEE 802.1X-2004 related configuration ##################################
 
@@ -108,7 +379,7 @@
 
 # IEEE 802.1X/EAPOL version
 # hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
-# version 2. However, there are some clients that do not handle
+# version 2. However, there are many client implementations that do not handle
 # the new version number correctly (they seem to drop the frames completely).
 # In order to make hostapd interoperate with these clients, the version number
 # can be set to the older version (1) with this configuration value.
@@ -188,9 +459,10 @@
 
 # Configuration data for EAP-SIM database/authentication gateway interface.
 # This is a text string in implementation specific format. The example
-# implementation in eap_sim_db.c uses this as the file name for the GSM
-# authentication triplets.
-#eap_sim_db=/etc/hostapd.sim_db
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
 
 
 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
@@ -250,6 +522,32 @@
 # 60 (1 minute).
 #radius_acct_interim_interval=600
 
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). vlan_file option below must be configured if dynamic
+# VLANs are used.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=0
+
+# VLAN interface list for dynamic VLAN mode is read from a separate text file.
+# This list is used to map VLAN ID from the RADIUS server to a network
+# interface. Each station is bound to one interface in the same way as with
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on.  hostapd creates a bridge for
+# each VLAN.  Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
 
 ##### RADIUS authentication server configuration ##############################
 
@@ -339,3 +637,79 @@
 # pre-authentication is only used with APs other than the currently associated
 # one.
 #rsn_preauth_interfaces=eth0
+
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+
+# ieee80211w: Whether management frame protection is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+##### Passive scanning ########################################################
+# Scan different channels every N seconds. 0 = disable passive scanning.
+#passive_scan_interval=60
+
+# Listen N usecs on each channel when doing passive scanning.
+# This value plus the time needed for changing channels should be less than
+# 32 milliseconds (i.e. 32000 usec) to avoid interruptions to normal
+# operations. Time needed for channel changing varies based on the used wlan
+# hardware.
+# default: disabled (0)
+#passive_scan_listen=10000
+
+# Passive scanning mode:
+# 0 = scan all supported modes (802.11a/b/g/Turbo) (default)
+# 1 = scan only the mode that is currently used for normal operations
+#passive_scan_mode=1
+
+# Maximum number of entries kept in AP table (either for passive scanning or
+# for detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! Wi-Fi certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+# Multiple BSSID support
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>).
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...
Index: wpa.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/wpa.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/wpa.h -L contrib/hostapd/wpa.h -u -r1.2 -r1.3
--- contrib/hostapd/wpa.h
+++ contrib/hostapd/wpa.h
@@ -1,33 +1,30 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * Copyright (c) 2004-2006, 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 WPA_H
 #define WPA_H
 
-#define WPA_NONCE_LEN 32
+#include "wpa_common.h"
+
 #define WPA_PMK_LEN PMK_LEN
-#define WPA_REPLAY_COUNTER_LEN 8
 #define WPA_GMK_LEN 32
 #define WPA_GTK_MAX_LEN 32
-#define WPA_KEY_RSC_LEN 8
 #define PMKID_LEN 16
 
-struct rsn_pmksa_cache {
-	struct rsn_pmksa_cache *next, *hnext;
-	u8 pmkid[PMKID_LEN];
-	u8 pmk[PMK_LEN];
-	time_t expiration;
-	int akmp; /* WPA_KEY_MGMT_* */
-	u8 spa[ETH_ALEN];
-	u8 *identity;
-	size_t identity_len;
-	struct radius_class_data radius_class;
-};
-
-struct rsn_preauth_interface {
-	struct rsn_preauth_interface *next;
-	struct hostapd_data *hapd;
-	struct l2_packet_data *l2;
-	char *ifname;
-	int ifindex;
-};
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6)
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
 
 struct wpa_eapol_key {
 	u8 type;
@@ -58,6 +55,7 @@
 #define WPA_KEY_INFO_ERROR BIT(10)
 #define WPA_KEY_INFO_REQUEST BIT(11)
 #define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12)
+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
 
 
 /* per STA state machine data */
@@ -75,122 +73,114 @@
 	} u;
 } __attribute__ ((packed));
 
-struct wpa_state_machine {
-	struct hostapd_data *hapd;
-	struct sta_info *sta;
-
-	enum {
-		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
-		WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
-		WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
-		WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
-		WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
-	} wpa_ptk_state;
-
+struct wpa_authenticator;
+struct wpa_state_machine;
+struct rsn_pmksa_cache_entry;
+
+
+struct wpa_auth_config {
+	int wpa;
+	int wpa_key_mgmt;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int rsn_preauth;
+	int eapol_version;
+	int peerkey;
+	int wme_enabled;
+#ifdef CONFIG_IEEE80211W
 	enum {
-		WPA_PTK_GROUP_IDLE = 0,
-		WPA_PTK_GROUP_REKEYNEGOTIATING,
-		WPA_PTK_GROUP_REKEYESTABLISHED,
-		WPA_PTK_GROUP_KEYERROR
-	} wpa_ptk_group_state;
-
-	Boolean Init;
-	Boolean DeauthenticationRequest;
-	Boolean AuthenticationRequest;
-	Boolean ReAuthenticationRequest;
-	Boolean Disconnect;
-	int TimeoutCtr;
-	int GTimeoutCtr;
-	Boolean TimeoutEvt;
-	Boolean EAPOLKeyReceived;
-	Boolean EAPOLKeyPairwise;
-	Boolean EAPOLKeyRequest;
-	Boolean MICVerified;
-	Boolean GUpdateStationKeys;
-	u8 ANonce[WPA_NONCE_LEN];
-	u8 SNonce[WPA_NONCE_LEN];
-	u8 PMK[WPA_PMK_LEN];
-	struct wpa_ptk PTK;
-	Boolean PTK_valid;
-	Boolean pairwise_set;
-	int keycount;
-	Boolean Pair;
-	u8 key_replay_counter[WPA_REPLAY_COUNTER_LEN];
-	Boolean key_replay_counter_valid;
-	Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i/D8 */
-	Boolean PTKRequest; /* not in IEEE 802.11i state machine */
-	Boolean has_GTK;
-
-	u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
-	size_t last_rx_eapol_key_len;
-
-	Boolean changed;
+		WPA_NO_IEEE80211W = 0,
+		WPA_IEEE80211W_OPTIONAL = 1,
+		WPA_IEEE80211W_REQUIRED = 2
+	} ieee80211w;
+#endif /* CONFIG_IEEE80211W */
 };
 
-/* per authenticator data */
-struct wpa_authenticator {
-	Boolean GInit;
-	int GNoStations;
-	int GKeyDoneStations;
-	Boolean GTKReKey;
-	int GTK_len;
-	int GN, GM;
-	Boolean GTKAuthenticator;
-	u8 Counter[WPA_NONCE_LEN];
+typedef enum {
+	LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
+} logger_level;
 
-	enum {
-		WPA_GROUP_GTK_INIT = 0,
-		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
-	} wpa_group_state;
-
-	u8 GMK[WPA_GMK_LEN];
-	u8 GTK[2][WPA_GTK_MAX_LEN];
-	u8 GNonce[WPA_NONCE_LEN];
-	Boolean changed;
-
-	unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
-	u8 dot11RSNAAuthenticationSuiteSelected[4];
-	u8 dot11RSNAPairwiseCipherSelected[4];
-	u8 dot11RSNAGroupCipherSelected[4];
-	u8 dot11RSNAPMKIDUsed[PMKID_LEN];
-	u8 dot11RSNAAuthenticationSuiteRequested[4]; /* FIX: update */
-	u8 dot11RSNAPairwiseCipherRequested[4]; /* FIX: update */
-	u8 dot11RSNAGroupCipherRequested[4]; /* FIX: update */
-	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
-	unsigned int dot11RSNA4WayHandshakeFailures;
+typedef enum {
+	WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
+	WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
+	WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
+} wpa_eapol_variable;
+
+struct wpa_auth_callbacks {
+	void *ctx;
+	void (*logger)(void *ctx, const u8 *addr, logger_level level,
+		       const char *txt);
+	void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
+	void (*mic_failure_report)(void *ctx, const u8 *addr);
+	void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
+			  int value);
+	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
+	const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
+	int (*get_pmk)(void *ctx, const u8 *addr, u8 *pmk, size_t *len);
+	int (*set_key)(void *ctx, int vlan_id, const char *alg, const u8 *addr,
+		       int idx, u8 *key, size_t key_len);
+	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
+	int (*get_seqnum_igtk)(void *ctx, const u8 *addr, int idx, u8 *seq);
+	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
+			  size_t data_len, int encrypt);
+	int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+						 void *ctx), void *cb_ctx);
 };
 
-
-int wpa_init(struct hostapd_data *hapd);
-void wpa_deinit(struct hostapd_data *hapd);
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb);
+void wpa_deinit(struct wpa_authenticator *wpa_auth);
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf);
 
 enum {
 	WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
-	WPA_INVALID_AKMP
+	WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
+	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER
 };
 	
-int wpa_validate_wpa_ie(struct hostapd_data *hapd, struct sta_info *sta,
-			const u8 *wpa_ie, size_t wpa_ie_len, int version);
-void wpa_new_station(struct hostapd_data *hapd, struct sta_info *sta);
-void wpa_free_station(struct sta_info *sta);
-void wpa_receive(struct hostapd_data *hapd, struct sta_info *sta,
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len);
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
+void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			     struct wpa_state_machine *sm);
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len);
 typedef enum {
 	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
 	WPA_REAUTH_EAPOL
 } wpa_event;
-void wpa_sm_event(struct hostapd_data *hapd, struct sta_info *sta,
-		  wpa_event event);
-void wpa_sm_notify(struct hostapd_data *hapd, struct sta_info *sta);
-void pmksa_cache_add(struct hostapd_data *hapd, struct sta_info *sta, u8 *pmk,
-		     int session_timeout);
-void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
-			  int success);
-void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
-		      u8 *buf, size_t len);
-void wpa_gtk_rekey(struct hostapd_data *hapd);
-int wpa_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
-int wpa_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
-		    char *buf, size_t buflen);
+void wpa_remove_ptk(struct wpa_state_machine *sm);
+void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
+void wpa_auth_sm_notify(struct wpa_state_machine *sm);
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
+			       size_t *len);
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       int session_timeout, struct eapol_state_machine *eapol);
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+			       const u8 *pmk, size_t len, const u8 *sta_addr,
+			       int session_timeout,
+			       struct eapol_state_machine *eapol);
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
 
 #endif /* WPA_H */
Index: eap_sim_common.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_sim_common.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_sim_common.c -L contrib/hostapd/eap_sim_common.c -u -r1.2 -r1.3
--- contrib/hostapd/eap_sim_common.c
+++ contrib/hostapd/eap_sim_common.c
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "eap_i.h"
@@ -24,80 +22,98 @@
 #include "eap_sim_common.h"
 
 
-static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
 {
-	u8 xkey[64];
-	u32 t[5], _t[5];
-	int i, j, m, k;
-	u8 *xpos = x;
-	u32 carry;
-
-	/* FIPS 186-2 + change notice 1 */
-
-	memcpy(xkey, key, EAP_SIM_MK_LEN);
-	memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_LEN);
-	t[0] = 0x67452301;
-	t[1] = 0xEFCDAB89;
-	t[2] = 0x98BADCFE;
-	t[3] = 0x10325476;
-	t[4] = 0xC3D2E1F0;
-
-	m = xlen / 40;
-	for (j = 0; j < m; j++) {
-		/* XSEED_j = 0 */
-		for (i = 0; i < 2; i++) {
-			/* XVAL = (XKEY + XSEED_j) mod 2^b */
-
-			/* w_i = G(t, XVAL) */
-			memcpy(_t, t, 20);
-			sha1_transform((u8 *) _t, xkey);
-			_t[0] = host_to_be32(_t[0]);
-			_t[1] = host_to_be32(_t[1]);
-			_t[2] = host_to_be32(_t[2]);
-			_t[3] = host_to_be32(_t[3]);
-			_t[4] = host_to_be32(_t[4]);
-			memcpy(xpos, _t, 20);
-
-			/* XKEY = (1 + XKEY + w_i) mod 2^b */
-			carry = 1;
-			for (k = 19; k >= 0; k--) {
-				carry += xkey[k] + xpos[k];
-				xkey[k] = carry & 0xff;
-				carry >>= 8;
-			}
+	return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
+}
 
-			xpos += SHA1_MAC_LEN;
-		}
-		/* x_j = w_0|w_1 */
-	}
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *nonce_mt, u16 selected_version,
+		       const u8 *ver_list, size_t ver_list_len,
+		       int num_chal, const u8 *kc, u8 *mk)
+{
+	u8 sel_ver[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = identity;
+	len[0] = identity_len;
+	addr[1] = kc;
+	len[1] = num_chal * EAP_SIM_KC_LEN;
+	addr[2] = nonce_mt;
+	len[2] = EAP_SIM_NONCE_MT_LEN;
+	addr[3] = ver_list;
+	len[3] = ver_list_len;
+	addr[4] = sel_ver;
+	len[4] = 2;
+
+	WPA_PUT_BE16(sel_ver, selected_version);
+
+	/* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+	sha1_vector(5, addr, len, mk);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+}
+
+
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *ik, const u8 *ck, u8 *mk)
+{
+	const u8 *addr[3];
+	size_t len[3];
+
+	addr[0] = identity;
+	len[0] = identity_len;
+	addr[1] = ik;
+	len[1] = EAP_AKA_IK_LEN;
+	addr[2] = ck;
+	len[2] = EAP_AKA_CK_LEN;
+
+	/* MK = SHA1(Identity|IK|CK) */
+	sha1_vector(3, addr, len, mk);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
 }
 
 
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
 {
-	u8 buf[120], *pos;
-	eap_sim_prf(mk, buf, 120);
+	u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
+	       EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
+	if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
+		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+		return -1;
+	}
 	pos = buf;
-	memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+	os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
 	pos += EAP_SIM_K_ENCR_LEN;
-	memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+	os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
 	pos += EAP_SIM_K_AUT_LEN;
-	memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+	os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+	pos += EAP_SIM_KEYING_DATA_LEN;
+	os_memcpy(emsk, pos, EAP_EMSK_LEN);
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
 			k_encr, EAP_SIM_K_ENCR_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
-			k_aut, EAP_SIM_K_ENCR_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
+			k_aut, EAP_SIM_K_AUT_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
 			msk, EAP_SIM_KEYING_DATA_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+	os_memset(buf, 0, sizeof(buf));
+
+	return 0;
 }
 
 
-void eap_sim_derive_keys_reauth(u16 _counter,
-				const u8 *identity, size_t identity_len,
-				const u8 *nonce_s, const u8 *mk, u8 *msk)
+int eap_sim_derive_keys_reauth(u16 _counter,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *nonce_s, const u8 *mk, u8 *msk,
+			       u8 *emsk)
 {
 	u8 xkey[SHA1_MAC_LEN];
+	u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
 	u8 counter[2];
 	const u8 *addr[4];
 	size_t len[4];
@@ -125,9 +141,22 @@
 	sha1_vector(4, addr, len, xkey);
 	wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
 
-	eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
-	wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
-		    msk, EAP_SIM_KEYING_DATA_LEN);
+	if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
+		wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+		return -1;
+	}
+	if (msk) {
+		os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
+			    msk, EAP_SIM_KEYING_DATA_LEN);
+	}
+	if (emsk) {
+		os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+	}
+	os_memset(buf, 0, sizeof(buf));
+
+	return 0;
 }
 
 
@@ -143,7 +172,7 @@
 	    mac > req + req_len - EAP_SIM_MAC_LEN)
 		return -1;
 
-	tmp = malloc(req_len);
+	tmp = os_malloc(req_len);
 	if (tmp == NULL)
 		return -1;
 
@@ -153,12 +182,19 @@
 	len[1] = extra_len;
 
 	/* HMAC-SHA1-128 */
-	memcpy(tmp, req, req_len);
-	memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+	os_memcpy(tmp, req, req_len);
+	os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
+			k_aut, EAP_SIM_K_AUT_LEN);
 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
-	free(tmp);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
+		    hmac, EAP_SIM_MAC_LEN);
+	os_free(tmp);
 
-	return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+	return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
 }
 
 
@@ -175,9 +211,16 @@
 	len[1] = extra_len;
 
 	/* HMAC-SHA1-128 */
-	memset(mac, 0, EAP_SIM_MAC_LEN);
+	os_memset(mac, 0, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
+		    extra, extra_len);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
+			k_aut, EAP_SIM_K_AUT_LEN);
 	hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
-	memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+	os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
+		    mac, EAP_SIM_MAC_LEN);
 }
 
 
@@ -185,10 +228,9 @@
 		       struct eap_sim_attrs *attr, int aka, int encr)
 {
 	const u8 *pos = start, *apos;
-	size_t alen, plen;
-	int list_len, i;
+	size_t alen, plen, i, list_len;
 
-	memset(attr, 0, sizeof(*attr));
+	os_memset(attr, 0, sizeof(*attr));
 	attr->id_req = NO_ID_REQ;
 	attr->notification = -1;
 	attr->counter = -1;
@@ -219,7 +261,7 @@
 			apos += 2;
 			alen -= 2;
 			if ((!aka && (alen % GSM_RAND_LEN)) ||
-			    (aka && alen != AKA_RAND_LEN)) {
+			    (aka && alen != EAP_AKA_RAND_LEN)) {
 				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
 					   " (len %lu)",
 					   (unsigned long) alen);
@@ -237,7 +279,7 @@
 			}
 			apos += 2;
 			alen -= 2;
-			if (alen != AKA_AUTN_LEN) {
+			if (alen != EAP_AKA_AUTN_LEN) {
 				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
 					   " (len %lu)",
 					   (unsigned long) alen);
@@ -316,8 +358,9 @@
 			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
 			if (list_len < 2 || list_len > alen - 2) {
 				wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
-					   "AT_VERSION_LIST (list_len=%d "
-					   "attr_len=%lu)", list_len,
+					   "AT_VERSION_LIST (list_len=%lu "
+					   "attr_len=%lu)",
+					   (unsigned long) list_len,
 					   (unsigned long) alen);
 				return -1;
 			}
@@ -356,6 +399,22 @@
 			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
 				   attr->counter);
 			break;
+		case EAP_SIM_AT_COUNTER_TOO_SMALL:
+			if (!encr) {
+				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+					   "AT_COUNTER_TOO_SMALL");
+				return -1;
+			}
+			if (alen != 2) {
+				wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+					   "AT_COUNTER_TOO_SMALL (alen=%lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+				   "AT_COUNTER_TOO_SMALL");
+			attr->counter_too_small = 1;
+			break;
 		case EAP_SIM_AT_NONCE_S:
 			if (!encr) {
 				wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
@@ -444,6 +503,35 @@
 			attr->next_reauth_id = pos + 4;
 			attr->next_reauth_id_len = plen;
 			break;
+		case EAP_SIM_AT_RES:
+			wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
+			apos += 2;
+			alen -= 2;
+			if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
+			    alen > EAP_AKA_MAX_RES_LEN) {
+				wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
+					   "(len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->res = apos;
+			attr->res_len = alen;
+			break;
+		case EAP_SIM_AT_AUTS:
+			wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
+			if (!aka) {
+				wpa_printf(MSG_DEBUG, "EAP-SIM: "
+					   "Unexpected AT_AUTS");
+				return -1;
+			}
+			if (alen != EAP_AKA_AUTS_LEN) {
+				wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
+					   " (len %lu)",
+					   (unsigned long) alen);
+				return -1;
+			}
+			attr->auts = apos;
+			break;
 		default:
 			if (pos[0] < 128) {
 				wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
@@ -478,10 +566,10 @@
 		return NULL;
 	}
 
-	decrypted = malloc(encr_data_len);
+	decrypted = os_malloc(encr_data_len);
 	if (decrypted == NULL)
 		return NULL;
-	memcpy(decrypted, encr_data, encr_data_len);
+	os_memcpy(decrypted, encr_data, encr_data_len);
 
 	aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
@@ -491,7 +579,7 @@
 			       aka, 1)) {
 		wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
 			   "decrypted AT_ENCR_DATA");
-		free(decrypted);
+		os_free(decrypted);
 		return NULL;
 	}
 
@@ -514,17 +602,15 @@
 	struct eap_hdr *eap;
 	u8 *pos;
 
-	msg = malloc(sizeof(*msg));
+	msg = os_zalloc(sizeof(*msg));
 	if (msg == NULL)
 		return NULL;
-	memset(msg, 0, sizeof(*msg));
 
-	msg->buf = malloc(EAP_SIM_INIT_LEN);
+	msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
 	if (msg->buf == NULL) {
-		free(msg);
+		os_free(msg);
 		return NULL;
 	}
-	memset(msg->buf, 0, EAP_SIM_INIT_LEN);
 	msg->buf_len = EAP_SIM_INIT_LEN;
 	eap = (struct eap_hdr *) msg->buf;
 	eap->code = code;
@@ -561,7 +647,7 @@
 
 	*len = msg->used;
 	buf = msg->buf;
-	free(msg);
+	os_free(msg);
 	return buf;
 }
 
@@ -569,8 +655,8 @@
 void eap_sim_msg_free(struct eap_sim_msg *msg)
 {
 	if (msg) {
-		free(msg->buf);
-		free(msg);
+		os_free(msg->buf);
+		os_free(msg);
 	}
 }
 
@@ -578,7 +664,7 @@
 static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
 {
 	if (msg->used + add_len > msg->buf_len) {
-		u8 *nbuf = realloc(msg->buf, msg->used + add_len);
+		u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
 		if (nbuf == NULL)
 			return -1;
 		msg->buf = nbuf;
@@ -605,10 +691,10 @@
 	start = pos = msg->buf + msg->used;
 	*pos++ = attr;
 	*pos++ = attr_len / 4;
-	memcpy(pos, data, len);
+	os_memcpy(pos, data, len);
 	if (pad_len) {
 		pos += len;
-		memset(pos, 0, pad_len);
+		os_memset(pos, 0, pad_len);
 	}
 	msg->used += attr_len;
 	return start;
@@ -635,10 +721,10 @@
 	WPA_PUT_BE16(pos, value);
 	pos += 2;
 	if (data)
-		memcpy(pos, data, len);
+		os_memcpy(pos, data, len);
 	if (pad_len) {
 		pos += len;
-		memset(pos, 0, pad_len);
+		os_memset(pos, 0, pad_len);
 	}
 	msg->used += attr_len;
 	return start;
@@ -681,7 +767,7 @@
 {
 	size_t encr_len;
 
-	if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+	if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
 		return -1;
 
 	encr_len = msg->used - msg->encr - 4;
@@ -698,7 +784,7 @@
 		pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
 		if (pos == NULL)
 			return -1;
-		memset(pos + 4, 0, pad_len - 4);
+		os_memset(pos + 4, 0, pad_len - 4);
 		encr_len += pad_len;
 	}
 	wpa_printf(MSG_DEBUG, "   (AT_ENCR_DATA data len %lu)",
@@ -752,43 +838,3 @@
 		}
 	}
 }
-
-
-#ifdef TEST_MAIN_EAP_SIM_COMMON
-static int test_eap_sim_prf(void)
-{
-	/* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
-	u8 xkey[] = {
-		0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
-		0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
-		0xeb, 0x5a, 0x38, 0xb6
-	};
-	u8 w[] = {
-		0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
-		0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
-		0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
-		0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
-		0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
-	};
-	u8 buf[40];
-
-	printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
-	eap_sim_prf(xkey, buf, sizeof(buf));
-	if (memcmp(w, buf, sizeof(w) != 0)) {
-		printf("eap_sim_prf failed\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
-	int errors = 0;
-
-	errors += test_eap_sim_prf();
-
-	return errors;
-}
-#endif /* TEST_MAIN_EAP_SIM_COMMON */
Index: eap_psk.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_psk.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -L contrib/hostapd/eap_psk.c -L contrib/hostapd/eap_psk.c -u -r1.1 -r1.2
--- contrib/hostapd/eap_psk.c
+++ contrib/hostapd/eap_psk.c
@@ -1,6 +1,6 @@
 /*
- * hostapd / EAP-PSK (draft-bersani-eap-psk-09.txt) server
- * Copyright (c) 2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / EAP-PSK (RFC 4764) server
+ * Copyright (c) 2005-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
@@ -15,10 +15,7 @@
  * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
 
 #include "hostapd.h"
 #include "common.h"
@@ -34,7 +31,8 @@
 	u8 *id_p, *id_s;
 	size_t id_p_len, id_s_len;
 	u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
-	u8 msk[EAP_PSK_MSK_LEN];
+	u8 msk[EAP_MSK_LEN];
+	u8 emsk[EAP_EMSK_LEN];
 };
 
 
@@ -42,12 +40,11 @@
 {
 	struct eap_psk_data *data;
 
-	data = malloc(sizeof(*data));
+	data = wpa_zalloc(sizeof(*data));
 	if (data == NULL)
-		return data;
-	memset(data, 0, sizeof(*data));
+		return NULL;
 	data->state = PSK_1;
-	data->id_s = "hostapd";
+	data->id_s = (u8 *) "hostapd";
 	data->id_s_len = 7;
 
 	return data;
@@ -90,7 +87,7 @@
 	req->identifier = id;
 	req->length = htons(*reqDataLen);
 	req->type = EAP_TYPE_PSK;
-	req->flags = 0; /* T=0 */
+	req->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
 	memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
 	memcpy((u8 *) (req + 1), data->id_s, data->id_s_len);
 
@@ -120,13 +117,14 @@
 	req->identifier = id;
 	req->length = htons(*reqDataLen);
 	req->type = EAP_TYPE_PSK;
-	req->flags = 2; /* T=2 */
+	req->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
 	memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
 
 	/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
 	buflen = data->id_s_len + EAP_PSK_RAND_LEN;
 	buf = malloc(buflen);
 	if (buf == NULL) {
+		free(req);
 		data->state = FAILURE;
 		return NULL;
 	}
@@ -135,9 +133,11 @@
 	omac1_aes_128(data->ak, buf, buflen, req->mac_s);
 	free(buf);
 
-	eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk);
+	eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
+			    data->emsk);
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_PSK_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
 
 	memset(nonce, 0, sizeof(nonce));
 	pchannel = (u8 *) (req + 1);
@@ -189,7 +189,7 @@
 		wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
 		return TRUE;
 	}
-	t = resp->flags & 0x03;
+	t = EAP_PSK_FLAGS_GET_T(resp->flags);
 
 	wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
 
@@ -254,13 +254,18 @@
 	}
 
 	for (i = 0;
-	     i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
+	     i < EAP_MAX_METHODS &&
+		     (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+		      sm->user->methods[i].method != EAP_TYPE_NONE);
 	     i++) {
-		if (sm->user->methods[i] == EAP_TYPE_PSK)
+		if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+		    sm->user->methods[i].method == EAP_TYPE_PSK)
 			break;
 	}
 
-	if (sm->user->methods[i] != EAP_TYPE_PSK) {
+	if (i >= EAP_MAX_METHODS ||
+	    sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+	    sm->user->methods[i].method != EAP_TYPE_PSK) {
 		wpa_hexdump_ascii(MSG_DEBUG,
 				  "EAP-PSK: EAP-PSK not enabled for ID_P",
 				  data->id_p, data->id_p_len);
@@ -393,14 +398,15 @@
 	struct eap_psk_hdr *resp;
 
 	if (sm->user == NULL || sm->user->password == NULL) {
-		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+		wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
+			   "configured");
 		data->state = FAILURE;
 		return;
 	}
 
 	resp = (struct eap_psk_hdr *) respData;
 
-	switch (resp->flags & 0x03) {
+	switch (EAP_PSK_FLAGS_GET_T(resp->flags)) {
 	case 1:
 		eap_psk_process_2(sm, data, respData, respDataLen);
 		break;
@@ -426,11 +432,29 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	key = malloc(EAP_PSK_MSK_LEN);
+	key = malloc(EAP_MSK_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->msk, EAP_MSK_LEN);
+	*len = EAP_MSK_LEN;
+
+	return key;
+}
+
+
+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_EMSK_LEN);
 	if (key == NULL)
 		return NULL;
-	memcpy(key, data->msk, EAP_PSK_MSK_LEN);
-	*len = EAP_PSK_MSK_LEN;
+	memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
 
 	return key;
 }
@@ -443,16 +467,28 @@
 }
 
 
-const struct eap_method eap_method_psk =
+int eap_server_psk_register(void)
 {
-	.method = EAP_TYPE_PSK,
-	.name = "PSK",
-	.init = eap_psk_init,
-	.reset = eap_psk_reset,
-	.buildReq = eap_psk_buildReq,
-	.check = eap_psk_check,
-	.process = eap_psk_process,
-	.isDone = eap_psk_isDone,
-	.getKey = eap_psk_getKey,
-	.isSuccess = eap_psk_isSuccess,
-};
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_psk_init;
+	eap->reset = eap_psk_reset;
+	eap->buildReq = eap_psk_buildReq;
+	eap->check = eap_psk_check;
+	eap->process = eap_psk_process;
+	eap->isDone = eap_psk_isDone;
+	eap->getKey = eap_psk_getKey;
+	eap->isSuccess = eap_psk_isSuccess;
+	eap->get_emsk = eap_psk_get_emsk;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: rc4.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/rc4.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/rc4.h -L contrib/hostapd/rc4.h -u -r1.2 -r1.3
--- contrib/hostapd/rc4.h
+++ contrib/hostapd/rc4.h
@@ -1,6 +1,6 @@
 /*
  * RC4 stream cipher
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2002-2005, 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
Index: eap_sim_common.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/eap_sim_common.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/eap_sim_common.h -L contrib/hostapd/eap_sim_common.h -u -r1.2 -r1.3
--- contrib/hostapd/eap_sim_common.h
+++ contrib/hostapd/eap_sim_common.h
@@ -1,6 +1,6 @@
 /*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, 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
@@ -23,16 +23,65 @@
 #define EAP_SIM_K_ENCR_LEN 16
 #define EAP_SIM_KEYING_DATA_LEN 64
 #define EAP_SIM_IV_LEN 16
+#define EAP_SIM_KC_LEN 8
+#define EAP_SIM_SRES_LEN 4
 
 #define GSM_RAND_LEN 16
 
-#define AKA_RAND_LEN 16
-#define AKA_AUTN_LEN 16
+#define EAP_SIM_VERSION 1
 
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
-void eap_sim_derive_keys_reauth(u16 _counter,
-				const u8 *identity, size_t identity_len,
-				const u8 *nonce_s, const u8 *mk, u8 *msk);
+/* EAP-SIM Subtypes */
+#define EAP_SIM_SUBTYPE_START 10
+#define EAP_SIM_SUBTYPE_CHALLENGE 11
+#define EAP_SIM_SUBTYPE_NOTIFICATION 12
+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
+#define EAP_SIM_UNSUPPORTED_VERSION 1
+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
+#define EAP_SIM_RAND_NOT_FRESH 3
+
+#define EAP_SIM_MAX_FAST_REAUTHS 1000
+
+#define EAP_SIM_MAX_CHAL 3
+
+
+/* EAP-AKA Subtypes */
+#define EAP_AKA_SUBTYPE_CHALLENGE 1
+#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
+#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
+#define EAP_AKA_SUBTYPE_IDENTITY 5
+#define EAP_AKA_SUBTYPE_NOTIFICATION 12
+#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
+#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+#define EAP_AKA_MAX_FAST_REAUTHS 1000
+#define EAP_AKA_MIN_RES_LEN 4
+#define EAP_AKA_MAX_RES_LEN 16
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *nonce_mt, u16 selected_version,
+		       const u8 *ver_list, size_t ver_list_len,
+		       int num_chal, const u8 *kc, u8 *mk);
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+		       const u8 *ik, const u8 *ck, u8 *mk);
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk,
+			u8 *emsk);
+int eap_sim_derive_keys_reauth(u16 _counter,
+			       const u8 *identity, size_t identity_len,
+			       const u8 *nonce_s, const u8 *mk, u8 *msk,
+			       u8 *emsk);
 int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
 		       const u8 *mac, const u8 *extra, size_t extra_len);
 void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
@@ -42,8 +91,8 @@
 /* EAP-SIM/AKA Attributes (0..127 non-skippable) */
 #define EAP_SIM_AT_RAND 1
 #define EAP_SIM_AT_AUTN 2 /* only AKA */
-#define EAP_SIM_AT_RES 3 /* only AKA, only send */
-#define EAP_SIM_AT_AUTS 4 /* only AKA, only send */
+#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */
+#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */
 #define EAP_SIM_AT_PADDING 6 /* only encrypted */
 #define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
 #define EAP_SIM_AT_PERMANENT_ID_REQ 10
@@ -81,11 +130,12 @@
 struct eap_sim_attrs {
 	const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
 	const u8 *next_pseudonym, *next_reauth_id;
-	const u8 *nonce_mt, *identity;
+	const u8 *nonce_mt, *identity, *res, *auts;
 	size_t num_chal, version_list_len, encr_data_len;
-	size_t next_pseudonym_len, next_reauth_id_len, identity_len;
+	size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
 	enum eap_sim_id_req id_req;
 	int notification, counter, selected_version, client_error_code;
+	int counter_too_small;
 };
 
 int eap_sim_parse_attr(const u8 *start, const u8 *end,
--- /dev/null
+++ contrib/hostapd/md4.c
@@ -0,0 +1,282 @@
+/*
+ * MD4 hash implementation
+ * Copyright (c) 2006, 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 "crypto.h"
+
+
+#ifdef INTERNAL_MD4
+
+#define	MD4_BLOCK_LENGTH		64
+#define	MD4_DIGEST_LENGTH		16
+
+typedef struct MD4Context {
+	u32 state[4];			/* state */
+	u64 count;			/* number of bits, mod 2^64 */
+	u8 buffer[MD4_BLOCK_LENGTH];	/* input buffer */
+} MD4_CTX;
+
+
+static void MD4Init(MD4_CTX *ctx);
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	MD4_CTX ctx;
+	size_t i;
+
+	MD4Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		MD4Update(&ctx, addr[i], len[i]);
+	MD4Final(mac, &ctx);
+}
+
+
+/* ===== start - public domain MD4 implementation ===== */
+/*	$OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $	*/
+
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4Context structure, pass it to MD4Init, call MD4Update as
+ * needed on buffers full of bytes, and then call MD4Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#define	MD4_DIGEST_STRING_LENGTH	(MD4_DIGEST_LENGTH * 2 + 1)
+
+
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
+
+#define PUT_64BIT_LE(cp, value) do {					\
+	(cp)[7] = (value) >> 56;					\
+	(cp)[6] = (value) >> 48;					\
+	(cp)[5] = (value) >> 40;					\
+	(cp)[4] = (value) >> 32;					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+static u8 PADDING[MD4_BLOCK_LENGTH] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD4 accumulation.
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ */
+static void MD4Init(MD4_CTX *ctx)
+{
+	ctx->count = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	need = MD4_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+	ctx->count += (u64)len << 3;
+
+	if (len >= need) {
+		if (have != 0) {
+			os_memcpy(ctx->buffer + have, input, need);
+			MD4Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD4_BLOCK_LENGTH) {
+			MD4Transform(ctx->state, input);
+			input += MD4_BLOCK_LENGTH;
+			len -= MD4_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		os_memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD4Pad(MD4_CTX *ctx)
+{
+	u8 count[8];
+	size_t padlen;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD4_BLOCK_LENGTH -
+	    ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD4_BLOCK_LENGTH;
+	MD4Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
+	MD4Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
+ */
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
+{
+	int i;
+
+	MD4Pad(ctx);
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+		os_memset(ctx, 0, sizeof(*ctx));
+	}
+}
+
+
+/* The three core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F3(x, y, z) (x ^ y ^ z)
+
+/* This is the central step in the MD4 algorithm. */
+#define MD4STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s) )
+
+/*
+ * The core of the MD4 algorithm, this alters an existing MD4 hash to
+ * reflect the addition of 16 longwords of new data.  MD4Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
+{
+	u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	os_memcpy(in, block, sizeof(in));
+#else
+	for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
+		in[a] = (u32)(
+		    (u32)(block[a * 4 + 0]) |
+		    (u32)(block[a * 4 + 1]) <<  8 |
+		    (u32)(block[a * 4 + 2]) << 16 |
+		    (u32)(block[a * 4 + 3]) << 24);
+	}
+#endif
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD4STEP(F1, a, b, c, d, in[ 0],  3);
+	MD4STEP(F1, d, a, b, c, in[ 1],  7);
+	MD4STEP(F1, c, d, a, b, in[ 2], 11);
+	MD4STEP(F1, b, c, d, a, in[ 3], 19);
+	MD4STEP(F1, a, b, c, d, in[ 4],  3);
+	MD4STEP(F1, d, a, b, c, in[ 5],  7);
+	MD4STEP(F1, c, d, a, b, in[ 6], 11);
+	MD4STEP(F1, b, c, d, a, in[ 7], 19);
+	MD4STEP(F1, a, b, c, d, in[ 8],  3);
+	MD4STEP(F1, d, a, b, c, in[ 9],  7);
+	MD4STEP(F1, c, d, a, b, in[10], 11);
+	MD4STEP(F1, b, c, d, a, in[11], 19);
+	MD4STEP(F1, a, b, c, d, in[12],  3);
+	MD4STEP(F1, d, a, b, c, in[13],  7);
+	MD4STEP(F1, c, d, a, b, in[14], 11);
+	MD4STEP(F1, b, c, d, a, in[15], 19);
+
+	MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
+
+	MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
+/* ===== end - public domain MD4 implementation ===== */
+
+#endif /* INTERNAL_MD4 */
--- /dev/null
+++ contrib/hostapd/pmksa_cache.c
@@ -0,0 +1,366 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2006, 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 "hostapd.h"
+#include "common.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "sha1.h"
+#include "ieee802_1x.h"
+#include "eapol_sm.h"
+#include "pmksa_cache.h"
+
+
+static const int pmksa_cache_max_entries = 1024;
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_pmksa_cache {
+#define PMKID_HASH_SIZE 128
+#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
+	struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
+	struct rsn_pmksa_cache_entry *pmksa;
+	int pmksa_count;
+
+	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
+	void *ctx;
+};
+
+
+/**
+ * rsn_pmkid - Calculate PMK identifier
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of pmk in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ */
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA1_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+	hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+	memcpy(pmkid, hash, PMKID_LEN);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+	if (entry == NULL)
+		return;
+	free(entry->identity);
+	ieee802_1x_free_radius_class(&entry->radius_class);
+	free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
+	pmksa->pmksa_count--;
+	pmksa->free_cb(entry, pmksa->ctx);
+	pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL) {
+				prev->hnext = pos->hnext;
+			} else {
+				pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
+					pos->hnext;
+			}
+			break;
+		}
+		prev = pos;
+		pos = pos->hnext;
+	}
+
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL)
+				prev->next = pos->next;
+			else
+				pmksa->pmksa = pos->next;
+			break;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+	_pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+		pmksa->pmksa = entry->next;
+		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+			   MACSTR, MAC2STR(entry->spa));
+		pmksa_cache_free_entry(pmksa, entry);
+	}
+
+	pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+	int sec;
+	struct os_time now;
+
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	if (pmksa->pmksa == NULL)
+		return;
+	os_get_time(&now);
+	sec = pmksa->pmksa->expiration - now.sec;
+	if (sec < 0)
+		sec = 0;
+	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+}
+
+
+static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
+					struct eapol_state_machine *eapol)
+{
+	if (eapol == NULL)
+		return;
+
+	if (eapol->identity) {
+		entry->identity = malloc(eapol->identity_len);
+		if (entry->identity) {
+			entry->identity_len = eapol->identity_len;
+			memcpy(entry->identity, eapol->identity,
+			       eapol->identity_len);
+		}
+	}
+
+	ieee802_1x_copy_radius_class(&entry->radius_class,
+				     &eapol->radius_class);
+
+	entry->eap_type_authsrv = eapol->eap_type_authsrv;
+	entry->vlan_id = eapol->sta->vlan_id;
+}
+
+
+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+			       struct eapol_state_machine *eapol)
+{
+	if (entry == NULL || eapol == NULL)
+		return;
+
+	if (entry->identity) {
+		free(eapol->identity);
+		eapol->identity = malloc(entry->identity_len);
+		if (eapol->identity) {
+			eapol->identity_len = entry->identity_len;
+			memcpy(eapol->identity, entry->identity,
+			       entry->identity_len);
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
+				  eapol->identity, eapol->identity_len);
+	}
+
+	ieee802_1x_free_radius_class(&eapol->radius_class);
+	ieee802_1x_copy_radius_class(&eapol->radius_class,
+				     &entry->radius_class);
+	if (eapol->radius_class.attr) {
+		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
+			   "PMKSA", (unsigned long) eapol->radius_class.count);
+	}
+
+	eapol->eap_type_authsrv = entry->eap_type_authsrv;
+	eapol->sta->vlan_id = entry->vlan_id;
+}
+
+
+/**
+ * pmksa_cache_add - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Supplicant,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, int session_timeout,
+		struct eapol_state_machine *eapol)
+{
+	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+	struct os_time now;
+
+	if (pmk_len > PMK_LEN)
+		return NULL;
+
+	entry = wpa_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	memcpy(entry->pmk, pmk, pmk_len);
+	entry->pmk_len = pmk_len;
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
+	os_get_time(&now);
+	entry->expiration = now.sec;
+	if (session_timeout > 0)
+		entry->expiration += session_timeout;
+	else
+		entry->expiration += dot11RSNAConfigPMKLifetime;
+	entry->akmp = WPA_KEY_MGMT_IEEE8021X;
+	memcpy(entry->spa, spa, ETH_ALEN);
+	pmksa_cache_from_eapol_data(entry, eapol);
+
+	/* Replace an old entry for the same STA (if found) with the new entry
+	 */
+	pos = pmksa_cache_get(pmksa, spa, NULL);
+	if (pos)
+		pmksa_cache_free_entry(pmksa, pos);
+
+	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+		/* Remove the oldest entry to make room for the new entry */
+		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
+			   "entry (for " MACSTR ") to make room for new one",
+			   MAC2STR(pmksa->pmksa->spa));
+		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+	}
+
+	/* Add the new entry; order by expiration time */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos->expiration > entry->expiration)
+			break;
+		prev = pos;
+		pos = pos->next;
+	}
+	if (prev == NULL) {
+		entry->next = pmksa->pmksa;
+		pmksa->pmksa = entry;
+	} else {
+		entry->next = prev->next;
+		prev->next = entry;
+	}
+	entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
+
+	pmksa->pmksa_count++;
+	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
+		   MAC2STR(entry->spa));
+	wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
+
+	return entry;
+}
+
+
+/**
+ * pmksa_cache_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ */
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev;
+	int i;
+
+	if (pmksa == NULL)
+		return;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		prev = entry;
+		entry = entry->next;
+		_pmksa_cache_free_entry(prev);
+	}
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	for (i = 0; i < PMKID_HASH_SIZE; i++)
+		pmksa->pmkid[i] = NULL;
+	free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @spa: Supplicant address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *spa, const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	if (pmkid)
+		entry = pmksa->pmkid[PMKID_HASH(pmkid)];
+	else
+		entry = pmksa->pmksa;
+	while (entry) {
+		if ((spa == NULL || memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
+		    (pmkid == NULL ||
+		     memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
+			return entry;
+		entry = pmkid ? entry->hnext : entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx), void *ctx)
+{
+	struct rsn_pmksa_cache *pmksa;
+
+	pmksa = wpa_zalloc(sizeof(*pmksa));
+	if (pmksa) {
+		pmksa->free_cb = free_cb;
+		pmksa->ctx = ctx;
+	}
+
+	return pmksa;
+}
--- /dev/null
+++ contrib/hostapd/vlan_init.h
@@ -0,0 +1,31 @@
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ *
+ * 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 VLAN_INIT_H
+#define VLAN_INIT_H
+
+int vlan_init(struct hostapd_data *hapd);
+void vlan_deinit(struct hostapd_data *hapd);
+int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
+		  struct hostapd_bss_config *oldbss);
+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+				       struct hostapd_vlan *vlan,
+				       int vlan_id);
+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+			      struct hostapd_ssid *mssid,
+			      const char *dyn_vlan);
+
+#endif /* VLAN_INIT_H */
--- /dev/null
+++ contrib/hostapd/milenage.c
@@ -0,0 +1,1053 @@
+/*
+ * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006 <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.
+ *
+ * This file implements an example authentication algorithm defined for 3GPP
+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
+ * EAP-AKA to be tested properly with real USIM cards.
+ *
+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in
+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
+ * be AES (Rijndael).
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "milenage.h"
+#include "aes_wrap.h"
+
+
+/**
+ * milenage_f1 - Milenage f1 and f1* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sqn: SQN = 48-bit sequence number
+ * @amf: AMF = 16-bit authentication management field
+ * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
+ * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
+ */
+static void milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
+			const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	aes_128_encrypt_block(k, tmp1, tmp1);
+
+	/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
+	memcpy(tmp2, sqn, 6);
+	memcpy(tmp2 + 6, amf, 2);
+	memcpy(tmp2 + 8, tmp2, 8);
+
+	/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
+
+	/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
+	for (i = 0; i < 16; i++)
+		tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
+	/* XOR with TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= tmp1[i];
+	/* XOR with c1 (= ..00, i.e., NOP) */
+
+	/* f1 || f1* = E_K(tmp3) XOR OP_c */
+	aes_128_encrypt_block(k, tmp3, tmp1);
+	for (i = 0; i < 16; i++)
+		tmp1[i] ^= opc[i];
+	if (mac_a)
+		memcpy(mac_a, tmp1, 8); /* f1 */
+	if (mac_s)
+		memcpy(mac_s, tmp1 + 8, 8); /* f1* */
+}
+
+
+/**
+ * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
+ * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
+ */
+static void milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
+			   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	aes_128_encrypt_block(k, tmp1, tmp2);
+
+	/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
+	/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
+	/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
+	/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
+
+	/* f2 and f5 */
+	/* rotate by r2 (= 0, i.e., NOP) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = tmp2[i] ^ opc[i];
+	tmp1[15] ^= 1; /* XOR c2 (= ..01) */
+	/* f5 || f2 = E_K(tmp1) XOR OP_c */
+	aes_128_encrypt_block(k, tmp1, tmp3);
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= opc[i];
+	if (res)
+		memcpy(res, tmp3 + 8, 8); /* f2 */
+	if (ak)
+		memcpy(ak, tmp3, 6); /* f5 */
+
+	/* f3 */
+	if (ck) {
+		/* rotate by r3 = 0x20 = 4 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 2; /* XOR c3 (= ..02) */
+		aes_128_encrypt_block(k, tmp1, ck);
+		for (i = 0; i < 16; i++)
+			ck[i] ^= opc[i];
+	}
+
+	/* f4 */
+	if (ik) {
+		/* rotate by r4 = 0x40 = 8 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 4; /* XOR c4 (= ..04) */
+		aes_128_encrypt_block(k, tmp1, ik);
+		for (i = 0; i < 16; i++)
+			ik[i] ^= opc[i];
+	}
+
+	/* f5* */
+	if (akstar) {
+		/* rotate by r5 = 0x60 = 12 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 8; /* XOR c5 (= ..08) */
+		aes_128_encrypt_block(k, tmp1, tmp1);
+		for (i = 0; i < 6; i++)
+			akstar[i] = tmp1[i] ^ opc[i];
+	}
+}
+
+
+/**
+ * milenage_generate - Generate AKA AUTN,IK,CK,RES
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @amf: AMF = 16-bit authentication management field
+ * @k: K = 128-bit subscriber key
+ * @sqn: SQN = 48-bit sequence number
+ * @_rand: RAND = 128-bit random challenge
+ * @autn: Buffer for AUTN = 128-bit authentication token
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @res_len: Max length for res; set to used length or 0 on failure
+ */
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len)
+{
+	int i;
+	u8 mac_a[16], ak[6];
+
+	if (*res_len < 8) {
+		*res_len = 0;
+		return;
+	}
+	*res_len = 8;
+	milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL);
+	milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL);
+
+	/* AUTN = (SQN ^ AK) || AMF || MAC */
+	for (i = 0; i < 6; i++)
+		autn[i] = sqn[i] ^ ak[i];
+	memcpy(autn + 6, amf, 2);
+	memcpy(autn + 8, mac_a, 8);
+}
+
+
+/**
+ * milenage_auts - Milenage AUTS validation
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @auts: AUTS = 112-bit authentication token from client
+ * @sqn: Buffer for SQN = 48-bit sequence number
+ * Returns: 0 = success (sqn filled), -1 on failure
+ */
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn)
+{
+	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+	u8 ak[6], mac_s[8];
+	int i;
+
+	milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak);
+	for (i = 0; i < 6; i++)
+		sqn[i] = auts[i] ^ ak[i];
+	milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s);
+	if (memcmp(mac_s, auts + 6, 8) != 0)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sres: Buffer for SRES = 32-bit SRES
+ * @kc: Buffer for Kc = 64-bit Kc
+ */
+void gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
+		  u8 *kc)
+{
+	u8 res[8], ck[16], ik[16];
+	int i;
+
+	milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL);
+
+	for (i = 0; i < 8; i++)
+		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
+
+#ifdef GSM_MILENAGE_ALT_SRES
+	memcpy(sres, res, 4);
+#else /* GSM_MILENAGE_ALT_SRES */
+	for (i = 0; i < 4; i++)
+		sres[i] = res[i] ^ res[i + 4];
+#endif /* GSM_MILENAGE_ALT_SRES */
+}
+
+
+#ifdef TEST_MAIN_MILENAGE
+
+extern int wpa_debug_level;
+
+
+/**
+ * milenage_opc - Determine OPc from OP and K
+ * @op: OP = 128-bit operator variant algorithm configuration field
+ * @k: K = 128-bit subscriber key
+ * @opc: Buffer for OPc = 128-bit value derived from OP and K
+ */
+static void milenage_opc(const u8 *op, const u8 *k, u8 *opc)
+{
+	int i;
+	/* OP_C = OP XOR E_K(OP) */
+	aes_128_encrypt_block(k, op, opc);
+	for (i = 0; i < 16; i++)
+		opc[i] ^= op[i];
+}
+
+
+struct gsm_milenage_test_set {
+	u8 ki[16];
+	u8 rand[16];
+	u8 opc[16];
+	u8 sres1[4];
+	u8 sres2[4];
+	u8 kc[8];
+};
+
+static const struct gsm_milenage_test_set gsm_test_sets[] =
+{
+	{
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 1 */
+		{ 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+		  0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+		{ 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+		  0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+		{ 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+		  0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+		{ 0x46, 0xf8, 0x41, 0x6a },
+		{ 0xa5, 0x42, 0x11, 0xd5 },
+		{ 0xea, 0xe4, 0xbe, 0x82, 0x3a, 0xf9, 0xa0, 0x8b }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 2 */
+		{ 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0,
+		  0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f },
+		{ 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb,
+		  0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a },
+		{ 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6,
+		  0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 },
+		{ 0x8c, 0x30, 0x8a, 0x5e },
+		{ 0x80, 0x11, 0xc4, 0x8c },
+		{ 0xaa, 0x01, 0x73, 0x9b, 0x8c, 0xaa, 0x97, 0x6d }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 3 */
+		{ 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16,
+		  0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 },
+		{ 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a,
+		  0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 },
+		{ 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b,
+		  0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 },
+		{ 0xcf, 0xbc, 0xe3, 0xfe },
+		{ 0xf3, 0x65, 0xcd, 0x68 },
+		{ 0x9a, 0x8e, 0xc9, 0x5f, 0x40, 0x8c, 0xc5, 0x07 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 4 */
+		{ 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0,
+		  0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 },
+		{ 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33,
+		  0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 },
+		{ 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90,
+		  0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e },
+		{ 0x96, 0x55, 0xe2, 0x65 },
+		{ 0x58, 0x60, 0xfc, 0x1b },
+		{ 0xcd, 0xc1, 0xdc, 0x08, 0x41, 0xb8, 0x1a, 0x22 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 5 */
+		{ 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45,
+		  0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f },
+		{ 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a,
+		  0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 },
+		{ 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6,
+		  0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 },
+		{ 0x13, 0x68, 0x8f, 0x17 },
+		{ 0x16, 0xc8, 0x23, 0x3f },
+		{ 0xdf, 0x75, 0xbc, 0x5e, 0xa8, 0x99, 0x87, 0x9f }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 6 */
+		{ 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0,
+		  0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d },
+		{ 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7,
+		  0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e },
+		{ 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25,
+		  0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 },
+		{ 0x55, 0x3d, 0x00, 0xb3 },
+		{ 0x8c, 0x25, 0xa1, 0x6c },
+		{ 0x84, 0xb4, 0x17, 0xae, 0x3a, 0xea, 0xb4, 0xf3 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 7 */
+		{ 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10,
+		  0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 },
+		{ 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5,
+		  0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d },
+		{ 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc,
+		  0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 },
+		{ 0x59, 0xf1, 0xa4, 0x4a },
+		{ 0xa6, 0x32, 0x41, 0xe1 },
+		{ 0x3b, 0x4e, 0x24, 0x4c, 0xdc, 0x60, 0xce, 0x03 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 8 */
+		{ 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58,
+		  0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 },
+		{ 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb,
+		  0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca },
+		{ 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38,
+		  0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 },
+		{ 0x50, 0x58, 0x88, 0x61 },
+		{ 0x4a, 0x90, 0xb2, 0x17 },
+		{ 0x8d, 0x4e, 0xc0, 0x1d, 0xe5, 0x97, 0xac, 0xfe }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 9 */
+		{ 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3,
+		  0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb },
+		{ 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56,
+		  0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 },
+		{ 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48,
+		  0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 },
+		{ 0xcd, 0xe6, 0xb0, 0x27 },
+		{ 0x4b, 0xc2, 0x21, 0x2d },
+		{ 0xd8, 0xde, 0xbc, 0x4f, 0xfb, 0xcd, 0x60, 0xaa }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 10 */
+		{ 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8,
+		  0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d },
+		{ 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33,
+		  0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 },
+		{ 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c,
+		  0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 },
+		{ 0x02, 0xd1, 0x3a, 0xcd },
+		{ 0x6f, 0xc3, 0x0f, 0xee },
+		{ 0xf0, 0xea, 0xa5, 0x0a, 0x1e, 0xdc, 0xeb, 0xb7 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 11 */
+		{ 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1,
+		  0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 },
+		{ 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe,
+		  0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 },
+		{ 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3,
+		  0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 },
+		{ 0x44, 0x38, 0x9d, 0x01 },
+		{ 0xae, 0xfa, 0x35, 0x7b },
+		{ 0x82, 0xdb, 0xab, 0x7f, 0x83, 0xf0, 0x63, 0xda }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 12 */
+		{ 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87,
+		  0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb },
+		{ 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75,
+		  0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 },
+		{ 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68,
+		  0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 },
+		{ 0x03, 0xe0, 0xfd, 0x84 },
+		{ 0x98, 0xdb, 0xbd, 0x09 },
+		{ 0x3c, 0x66, 0xcb, 0x98, 0xca, 0xb2, 0xd3, 0x3d }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 13 */
+		{ 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23,
+		  0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa },
+		{ 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95,
+		  0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 },
+		{ 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57,
+		  0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 },
+		{ 0xbe, 0x73, 0xb3, 0xdc },
+		{ 0xaf, 0x4a, 0x41, 0x1e },
+		{ 0x96, 0x12, 0xb5, 0xd8, 0x8a, 0x41, 0x30, 0xbb }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 14 */
+		{ 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde,
+		  0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 },
+		{ 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b,
+		  0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a },
+		{ 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e,
+		  0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 },
+		{ 0x8f, 0xe0, 0x19, 0xc7 },
+		{ 0x7b, 0xff, 0xa5, 0xc2 },
+		{ 0x75, 0xa1, 0x50, 0xdf, 0x3c, 0x6a, 0xed, 0x08 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 15 */
+		{ 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41,
+		  0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 },
+		{ 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03,
+		  0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 },
+		{ 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc,
+		  0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 },
+		{ 0x27, 0x20, 0x2b, 0x82 },
+		{ 0x7e, 0x3f, 0x44, 0xc7 },
+		{ 0xb7, 0xf9, 0x2e, 0x42, 0x6a, 0x36, 0xfe, 0xc5 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 16 */
+		{ 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14,
+		  0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d },
+		{ 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b,
+		  0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 },
+		{ 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66,
+		  0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 },
+		{ 0xdd, 0xd7, 0xef, 0xe6 },
+		{ 0x70, 0xf6, 0xbd, 0xb9 },
+		{ 0x88, 0xd9, 0xde, 0x10, 0xa2, 0x20, 0x04, 0xc5 }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 17 */
+		{ 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62,
+		  0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf },
+		{ 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f,
+		  0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f },
+		{ 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74,
+		  0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 },
+		{ 0x67, 0xe4, 0xff, 0x3f },
+		{ 0x47, 0x9d, 0xd2, 0x5c },
+		{ 0xa8, 0x19, 0xe5, 0x77, 0xa8, 0xd6, 0x17, 0x5b }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 18 */
+		{ 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72,
+		  0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 },
+		{ 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
+		  0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
+		{ 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e,
+		  0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf },
+		{ 0x8a, 0x3b, 0x8d, 0x17 },
+		{ 0x28, 0xd7, 0xb0, 0xf2 },
+		{ 0x9a, 0x8d, 0x0e, 0x88, 0x3f, 0xf0, 0x88, 0x7a }
+	}, {
+		/* 3GPP TS 55.205 v6.0.0 - Test Set 19 */
+		{ 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf,
+		  0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 },
+		{ 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03,
+		  0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 },
+		{ 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d,
+		  0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 },
+		{ 0xdf, 0x58, 0x52, 0x2f },
+		{ 0xa9, 0x51, 0x00, 0xe2 },
+		{ 0xed, 0x29, 0xb2, 0xf1, 0xc2, 0x7f, 0x9f, 0x34 }
+	}
+};
+
+#define NUM_GSM_TESTS (sizeof(gsm_test_sets) / sizeof(gsm_test_sets[0]))
+
+
+struct milenage_test_set {
+	u8 k[16];
+	u8 rand[16];
+	u8 sqn[6];
+	u8 amf[2];
+	u8 op[16];
+	u8 opc[16];
+	u8 f1[8];
+	u8 f1star[8];
+	u8 f2[8];
+	u8 f3[16];
+	u8 f4[16];
+	u8 f5[6];
+	u8 f5star[6];
+};
+
+static const struct milenage_test_set test_sets[] =
+{
+	{
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.1 Test Set 1 */
+		{ 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+		  0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+		{ 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+		  0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+		{ 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 },
+		{ 0xb9, 0xb9 },
+		{ 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6,
+		  0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 },
+		{ 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+		  0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+		{ 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 },
+		{ 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 },
+		{ 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf },
+		{ 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05,
+		  0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb },
+		{ 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04,
+		  0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 },
+		{ 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 },
+		{ 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.2 Test Set 2 */
+		{ 0x46, 0x5b, 0x5c, 0xe8, 0xb1, 0x99, 0xb4, 0x9f,
+		  0xaa, 0x5f, 0x0a, 0x2e, 0xe2, 0x38, 0xa6, 0xbc },
+		{ 0x23, 0x55, 0x3c, 0xbe, 0x96, 0x37, 0xa8, 0x9d,
+		  0x21, 0x8a, 0xe6, 0x4d, 0xae, 0x47, 0xbf, 0x35 },
+		{ 0xff, 0x9b, 0xb4, 0xd0, 0xb6, 0x07 },
+		{ 0xb9, 0xb9 },
+		{ 0xcd, 0xc2, 0x02, 0xd5, 0x12, 0x3e, 0x20, 0xf6,
+		  0x2b, 0x6d, 0x67, 0x6a, 0xc7, 0x2c, 0xb3, 0x18 },
+		{ 0xcd, 0x63, 0xcb, 0x71, 0x95, 0x4a, 0x9f, 0x4e,
+		  0x48, 0xa5, 0x99, 0x4e, 0x37, 0xa0, 0x2b, 0xaf },
+		{ 0x4a, 0x9f, 0xfa, 0xc3, 0x54, 0xdf, 0xaf, 0xb3 },
+		{ 0x01, 0xcf, 0xaf, 0x9e, 0xc4, 0xe8, 0x71, 0xe9 },
+		{ 0xa5, 0x42, 0x11, 0xd5, 0xe3, 0xba, 0x50, 0xbf },
+		{ 0xb4, 0x0b, 0xa9, 0xa3, 0xc5, 0x8b, 0x2a, 0x05,
+		  0xbb, 0xf0, 0xd9, 0x87, 0xb2, 0x1b, 0xf8, 0xcb },
+		{ 0xf7, 0x69, 0xbc, 0xd7, 0x51, 0x04, 0x46, 0x04,
+		  0x12, 0x76, 0x72, 0x71, 0x1c, 0x6d, 0x34, 0x41 },
+		{ 0xaa, 0x68, 0x9c, 0x64, 0x83, 0x70 },
+		{ 0x45, 0x1e, 0x8b, 0xec, 0xa4, 0x3b }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.3 Test Set 3 */
+		{ 0xfe, 0xc8, 0x6b, 0xa6, 0xeb, 0x70, 0x7e, 0xd0,
+		  0x89, 0x05, 0x75, 0x7b, 0x1b, 0xb4, 0x4b, 0x8f },
+		{ 0x9f, 0x7c, 0x8d, 0x02, 0x1a, 0xcc, 0xf4, 0xdb,
+		  0x21, 0x3c, 0xcf, 0xf0, 0xc7, 0xf7, 0x1a, 0x6a },
+		{ 0x9d, 0x02, 0x77, 0x59, 0x5f, 0xfc },
+		{ 0x72, 0x5c },
+		{ 0xdb, 0xc5, 0x9a, 0xdc, 0xb6, 0xf9, 0xa0, 0xef,
+		  0x73, 0x54, 0x77, 0xb7, 0xfa, 0xdf, 0x83, 0x74 },
+		{ 0x10, 0x06, 0x02, 0x0f, 0x0a, 0x47, 0x8b, 0xf6,
+		  0xb6, 0x99, 0xf1, 0x5c, 0x06, 0x2e, 0x42, 0xb3 },
+		{ 0x9c, 0xab, 0xc3, 0xe9, 0x9b, 0xaf, 0x72, 0x81 },
+		{ 0x95, 0x81, 0x4b, 0xa2, 0xb3, 0x04, 0x43, 0x24 },
+		{ 0x80, 0x11, 0xc4, 0x8c, 0x0c, 0x21, 0x4e, 0xd2 },
+		{ 0x5d, 0xbd, 0xbb, 0x29, 0x54, 0xe8, 0xf3, 0xcd,
+		  0xe6, 0x65, 0xb0, 0x46, 0x17, 0x9a, 0x50, 0x98 },
+		{ 0x59, 0xa9, 0x2d, 0x3b, 0x47, 0x6a, 0x04, 0x43,
+		  0x48, 0x70, 0x55, 0xcf, 0x88, 0xb2, 0x30, 0x7b },
+		{ 0x33, 0x48, 0x4d, 0xc2, 0x13, 0x6b },
+		{ 0xde, 0xac, 0xdd, 0x84, 0x8c, 0xc6 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.4 Test Set 4 */
+		{ 0x9e, 0x59, 0x44, 0xae, 0xa9, 0x4b, 0x81, 0x16,
+		  0x5c, 0x82, 0xfb, 0xf9, 0xf3, 0x2d, 0xb7, 0x51 },
+		{ 0xce, 0x83, 0xdb, 0xc5, 0x4a, 0xc0, 0x27, 0x4a,
+		  0x15, 0x7c, 0x17, 0xf8, 0x0d, 0x01, 0x7b, 0xd6 },
+		{ 0x0b, 0x60, 0x4a, 0x81, 0xec, 0xa8 },
+		{ 0x9e, 0x09 },
+		{ 0x22, 0x30, 0x14, 0xc5, 0x80, 0x66, 0x94, 0xc0,
+		  0x07, 0xca, 0x1e, 0xee, 0xf5, 0x7f, 0x00, 0x4f },
+		{ 0xa6, 0x4a, 0x50, 0x7a, 0xe1, 0xa2, 0xa9, 0x8b,
+		  0xb8, 0x8e, 0xb4, 0x21, 0x01, 0x35, 0xdc, 0x87 },
+		{ 0x74, 0xa5, 0x82, 0x20, 0xcb, 0xa8, 0x4c, 0x49 },
+		{ 0xac, 0x2c, 0xc7, 0x4a, 0x96, 0x87, 0x18, 0x37 },
+		{ 0xf3, 0x65, 0xcd, 0x68, 0x3c, 0xd9, 0x2e, 0x96 },
+		{ 0xe2, 0x03, 0xed, 0xb3, 0x97, 0x15, 0x74, 0xf5,
+		  0xa9, 0x4b, 0x0d, 0x61, 0xb8, 0x16, 0x34, 0x5d },
+		{ 0x0c, 0x45, 0x24, 0xad, 0xea, 0xc0, 0x41, 0xc4,
+		  0xdd, 0x83, 0x0d, 0x20, 0x85, 0x4f, 0xc4, 0x6b },
+		{ 0xf0, 0xb9, 0xc0, 0x8a, 0xd0, 0x2e },
+		{ 0x60, 0x85, 0xa8, 0x6c, 0x6f, 0x63 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.5 Test Set 5 */
+		{ 0x4a, 0xb1, 0xde, 0xb0, 0x5c, 0xa6, 0xce, 0xb0,
+		  0x51, 0xfc, 0x98, 0xe7, 0x7d, 0x02, 0x6a, 0x84 },
+		{ 0x74, 0xb0, 0xcd, 0x60, 0x31, 0xa1, 0xc8, 0x33,
+		  0x9b, 0x2b, 0x6c, 0xe2, 0xb8, 0xc4, 0xa1, 0x86 },
+		{ 0xe8, 0x80, 0xa1, 0xb5, 0x80, 0xb6 },
+		{ 0x9f, 0x07 },
+		{ 0x2d, 0x16, 0xc5, 0xcd, 0x1f, 0xdf, 0x6b, 0x22,
+		  0x38, 0x35, 0x84, 0xe3, 0xbe, 0xf2, 0xa8, 0xd8 },
+		{ 0xdc, 0xf0, 0x7c, 0xbd, 0x51, 0x85, 0x52, 0x90,
+		  0xb9, 0x2a, 0x07, 0xa9, 0x89, 0x1e, 0x52, 0x3e },
+		{ 0x49, 0xe7, 0x85, 0xdd, 0x12, 0x62, 0x6e, 0xf2 },
+		{ 0x9e, 0x85, 0x79, 0x03, 0x36, 0xbb, 0x3f, 0xa2 },
+		{ 0x58, 0x60, 0xfc, 0x1b, 0xce, 0x35, 0x1e, 0x7e },
+		{ 0x76, 0x57, 0x76, 0x6b, 0x37, 0x3d, 0x1c, 0x21,
+		  0x38, 0xf3, 0x07, 0xe3, 0xde, 0x92, 0x42, 0xf9 },
+		{ 0x1c, 0x42, 0xe9, 0x60, 0xd8, 0x9b, 0x8f, 0xa9,
+		  0x9f, 0x27, 0x44, 0xe0, 0x70, 0x8c, 0xcb, 0x53 },
+		{ 0x31, 0xe1, 0x1a, 0x60, 0x91, 0x18 },
+		{ 0xfe, 0x25, 0x55, 0xe5, 0x4a, 0xa9 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.6 Test Set 6 */
+		{ 0x6c, 0x38, 0xa1, 0x16, 0xac, 0x28, 0x0c, 0x45,
+		  0x4f, 0x59, 0x33, 0x2e, 0xe3, 0x5c, 0x8c, 0x4f },
+		{ 0xee, 0x64, 0x66, 0xbc, 0x96, 0x20, 0x2c, 0x5a,
+		  0x55, 0x7a, 0xbb, 0xef, 0xf8, 0xba, 0xbf, 0x63 },
+		{ 0x41, 0x4b, 0x98, 0x22, 0x21, 0x81 },
+		{ 0x44, 0x64 },
+		{ 0x1b, 0xa0, 0x0a, 0x1a, 0x7c, 0x67, 0x00, 0xac,
+		  0x8c, 0x3f, 0xf3, 0xe9, 0x6a, 0xd0, 0x87, 0x25 },
+		{ 0x38, 0x03, 0xef, 0x53, 0x63, 0xb9, 0x47, 0xc6,
+		  0xaa, 0xa2, 0x25, 0xe5, 0x8f, 0xae, 0x39, 0x34 },
+		{ 0x07, 0x8a, 0xdf, 0xb4, 0x88, 0x24, 0x1a, 0x57 },
+		{ 0x80, 0x24, 0x6b, 0x8d, 0x01, 0x86, 0xbc, 0xf1 },
+		{ 0x16, 0xc8, 0x23, 0x3f, 0x05, 0xa0, 0xac, 0x28 },
+		{ 0x3f, 0x8c, 0x75, 0x87, 0xfe, 0x8e, 0x4b, 0x23,
+		  0x3a, 0xf6, 0x76, 0xae, 0xde, 0x30, 0xba, 0x3b },
+		{ 0xa7, 0x46, 0x6c, 0xc1, 0xe6, 0xb2, 0xa1, 0x33,
+		  0x7d, 0x49, 0xd3, 0xb6, 0x6e, 0x95, 0xd7, 0xb4 },
+		{ 0x45, 0xb0, 0xf6, 0x9a, 0xb0, 0x6c },
+		{ 0x1f, 0x53, 0xcd, 0x2b, 0x11, 0x13 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.7 Test Set 7 */
+		{ 0x2d, 0x60, 0x9d, 0x4d, 0xb0, 0xac, 0x5b, 0xf0,
+		  0xd2, 0xc0, 0xde, 0x26, 0x70, 0x14, 0xde, 0x0d },
+		{ 0x19, 0x4a, 0xa7, 0x56, 0x01, 0x38, 0x96, 0xb7,
+		  0x4b, 0x4a, 0x2a, 0x3b, 0x0a, 0xf4, 0x53, 0x9e },
+		{ 0x6b, 0xf6, 0x94, 0x38, 0xc2, 0xe4 },
+		{ 0x5f, 0x67 },
+		{ 0x46, 0x0a, 0x48, 0x38, 0x54, 0x27, 0xaa, 0x39,
+		  0x26, 0x4a, 0xac, 0x8e, 0xfc, 0x9e, 0x73, 0xe8 },
+		{ 0xc3, 0x5a, 0x0a, 0xb0, 0xbc, 0xbf, 0xc9, 0x25,
+		  0x2c, 0xaf, 0xf1, 0x5f, 0x24, 0xef, 0xbd, 0xe0 },
+		{ 0xbd, 0x07, 0xd3, 0x00, 0x3b, 0x9e, 0x5c, 0xc3 },
+		{ 0xbc, 0xb6, 0xc2, 0xfc, 0xad, 0x15, 0x22, 0x50 },
+		{ 0x8c, 0x25, 0xa1, 0x6c, 0xd9, 0x18, 0xa1, 0xdf },
+		{ 0x4c, 0xd0, 0x84, 0x60, 0x20, 0xf8, 0xfa, 0x07,
+		  0x31, 0xdd, 0x47, 0xcb, 0xdc, 0x6b, 0xe4, 0x11 },
+		{ 0x88, 0xab, 0x80, 0xa4, 0x15, 0xf1, 0x5c, 0x73,
+		  0x71, 0x12, 0x54, 0xa1, 0xd3, 0x88, 0xf6, 0x96 },
+		{ 0x7e, 0x64, 0x55, 0xf3, 0x4c, 0xf3 },
+		{ 0xdc, 0x6d, 0xd0, 0x1e, 0x8f, 0x15 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.8 Test Set 8 */
+		{ 0xa5, 0x30, 0xa7, 0xfe, 0x42, 0x8f, 0xad, 0x10,
+		  0x82, 0xc4, 0x5e, 0xdd, 0xfc, 0xe1, 0x38, 0x84 },
+		{ 0x3a, 0x4c, 0x2b, 0x32, 0x45, 0xc5, 0x0e, 0xb5,
+		  0xc7, 0x1d, 0x08, 0x63, 0x93, 0x95, 0x76, 0x4d },
+		{ 0xf6, 0x3f, 0x5d, 0x76, 0x87, 0x84 },
+		{ 0xb9, 0x0e },
+		{ 0x51, 0x1c, 0x6c, 0x4e, 0x83, 0xe3, 0x8c, 0x89,
+		  0xb1, 0xc5, 0xd8, 0xdd, 0xe6, 0x24, 0x26, 0xfa },
+		{ 0x27, 0x95, 0x3e, 0x49, 0xbc, 0x8a, 0xf6, 0xdc,
+		  0xc6, 0xe7, 0x30, 0xeb, 0x80, 0x28, 0x6b, 0xe3 },
+		{ 0x53, 0x76, 0x1f, 0xbd, 0x67, 0x9b, 0x0b, 0xad },
+		{ 0x21, 0xad, 0xfd, 0x33, 0x4a, 0x10, 0xe7, 0xce },
+		{ 0xa6, 0x32, 0x41, 0xe1, 0xff, 0xc3, 0xe5, 0xab },
+		{ 0x10, 0xf0, 0x5b, 0xab, 0x75, 0xa9, 0x9a, 0x5f,
+		  0xbb, 0x98, 0xa9, 0xc2, 0x87, 0x67, 0x9c, 0x3b },
+		{ 0xf9, 0xec, 0x08, 0x65, 0xeb, 0x32, 0xf2, 0x23,
+		  0x69, 0xca, 0xde, 0x40, 0xc5, 0x9c, 0x3a, 0x44 },
+		{ 0x88, 0x19, 0x6c, 0x47, 0x98, 0x6f },
+		{ 0xc9, 0x87, 0xa3, 0xd2, 0x31, 0x15 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.9 Test Set 9 */
+		{ 0xd9, 0x15, 0x1c, 0xf0, 0x48, 0x96, 0xe2, 0x58,
+		  0x30, 0xbf, 0x2e, 0x08, 0x26, 0x7b, 0x83, 0x60 },
+		{ 0xf7, 0x61, 0xe5, 0xe9, 0x3d, 0x60, 0x3f, 0xeb,
+		  0x73, 0x0e, 0x27, 0x55, 0x6c, 0xb8, 0xa2, 0xca },
+		{ 0x47, 0xee, 0x01, 0x99, 0x82, 0x0a },
+		{ 0x91, 0x13 },
+		{ 0x75, 0xfc, 0x22, 0x33, 0xa4, 0x42, 0x94, 0xee,
+		  0x8e, 0x6d, 0xe2, 0x5c, 0x43, 0x53, 0xd2, 0x6b },
+		{ 0xc4, 0xc9, 0x3e, 0xff, 0xe8, 0xa0, 0x81, 0x38,
+		  0xc2, 0x03, 0xd4, 0xc2, 0x7c, 0xe4, 0xe3, 0xd9 },
+		{ 0x66, 0xcc, 0x4b, 0xe4, 0x48, 0x62, 0xaf, 0x1f },
+		{ 0x7a, 0x4b, 0x8d, 0x7a, 0x87, 0x53, 0xf2, 0x46 },
+		{ 0x4a, 0x90, 0xb2, 0x17, 0x1a, 0xc8, 0x3a, 0x76 },
+		{ 0x71, 0x23, 0x6b, 0x71, 0x29, 0xf9, 0xb2, 0x2a,
+		  0xb7, 0x7e, 0xa7, 0xa5, 0x4c, 0x96, 0xda, 0x22 },
+		{ 0x90, 0x52, 0x7e, 0xba, 0xa5, 0x58, 0x89, 0x68,
+		  0xdb, 0x41, 0x72, 0x73, 0x25, 0xa0, 0x4d, 0x9e },
+		{ 0x82, 0xa0, 0xf5, 0x28, 0x7a, 0x71 },
+		{ 0x52, 0x7d, 0xbf, 0x41, 0xf3, 0x5f }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.10 Test Set 10 */
+		{ 0xa0, 0xe2, 0x97, 0x1b, 0x68, 0x22, 0xe8, 0xd3,
+		  0x54, 0xa1, 0x8c, 0xc2, 0x35, 0x62, 0x4e, 0xcb },
+		{ 0x08, 0xef, 0xf8, 0x28, 0xb1, 0x3f, 0xdb, 0x56,
+		  0x27, 0x22, 0xc6, 0x5c, 0x7f, 0x30, 0xa9, 0xb2 },
+		{ 0xdb, 0x5c, 0x06, 0x64, 0x81, 0xe0 },
+		{ 0x71, 0x6b },
+		{ 0x32, 0x37, 0x92, 0xfa, 0xca, 0x21, 0xfb, 0x4d,
+		  0x5d, 0x6f, 0x13, 0xc1, 0x45, 0xa9, 0xd2, 0xc1 },
+		{ 0x82, 0xa2, 0x6f, 0x22, 0xbb, 0xa9, 0xe9, 0x48,
+		  0x8f, 0x94, 0x9a, 0x10, 0xd9, 0x8e, 0x9c, 0xc4 },
+		{ 0x94, 0x85, 0xfe, 0x24, 0x62, 0x1c, 0xb9, 0xf6 },
+		{ 0xbc, 0xe3, 0x25, 0xce, 0x03, 0xe2, 0xe9, 0xb9 },
+		{ 0x4b, 0xc2, 0x21, 0x2d, 0x86, 0x24, 0x91, 0x0a },
+		{ 0x08, 0xce, 0xf6, 0xd0, 0x04, 0xec, 0x61, 0x47,
+		  0x1a, 0x3c, 0x3c, 0xda, 0x04, 0x81, 0x37, 0xfa },
+		{ 0xed, 0x03, 0x18, 0xca, 0x5d, 0xeb, 0x92, 0x06,
+		  0x27, 0x2f, 0x6e, 0x8f, 0xa6, 0x4b, 0xa4, 0x11 },
+		{ 0xa2, 0xf8, 0x58, 0xaa, 0x9e, 0x5d },
+		{ 0x74, 0xe7, 0x6f, 0xbb, 0xec, 0x38 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.11 Test Set 11 */
+		{ 0x0d, 0xa6, 0xf7, 0xba, 0x86, 0xd5, 0xea, 0xc8,
+		  0xa1, 0x9c, 0xf5, 0x63, 0xac, 0x58, 0x64, 0x2d },
+		{ 0x67, 0x9a, 0xc4, 0xdb, 0xac, 0xd7, 0xd2, 0x33,
+		  0xff, 0x9d, 0x68, 0x06, 0xf4, 0x14, 0x9c, 0xe3 },
+		{ 0x6e, 0x23, 0x31, 0xd6, 0x92, 0xad },
+		{ 0x22, 0x4a },
+		{ 0x4b, 0x9a, 0x26, 0xfa, 0x45, 0x9e, 0x3a, 0xcb,
+		  0xff, 0x36, 0xf4, 0x01, 0x5d, 0xe3, 0xbd, 0xc1 },
+		{ 0x0d, 0xb1, 0x07, 0x1f, 0x87, 0x67, 0x56, 0x2c,
+		  0xa4, 0x3a, 0x0a, 0x64, 0xc4, 0x1e, 0x8d, 0x08 },
+		{ 0x28, 0x31, 0xd7, 0xae, 0x90, 0x88, 0xe4, 0x92 },
+		{ 0x9b, 0x2e, 0x16, 0x95, 0x11, 0x35, 0xd5, 0x23 },
+		{ 0x6f, 0xc3, 0x0f, 0xee, 0x6d, 0x12, 0x35, 0x23 },
+		{ 0x69, 0xb1, 0xca, 0xe7, 0xc7, 0x42, 0x9d, 0x97,
+		  0x5e, 0x24, 0x5c, 0xac, 0xb0, 0x5a, 0x51, 0x7c },
+		{ 0x74, 0xf2, 0x4e, 0x8c, 0x26, 0xdf, 0x58, 0xe1,
+		  0xb3, 0x8d, 0x7d, 0xcd, 0x4f, 0x1b, 0x7f, 0xbd },
+		{ 0x4c, 0x53, 0x9a, 0x26, 0xe1, 0xfa },
+		{ 0x07, 0x86, 0x1e, 0x12, 0x69, 0x28 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.12 Test Set 12 */
+		{ 0x77, 0xb4, 0x58, 0x43, 0xc8, 0x8e, 0x58, 0xc1,
+		  0x0d, 0x20, 0x26, 0x84, 0x51, 0x5e, 0xd4, 0x30 },
+		{ 0x4c, 0x47, 0xeb, 0x30, 0x76, 0xdc, 0x55, 0xfe,
+		  0x51, 0x06, 0xcb, 0x20, 0x34, 0xb8, 0xcd, 0x78 },
+		{ 0xfe, 0x1a, 0x87, 0x31, 0x00, 0x5d },
+		{ 0xad, 0x25 },
+		{ 0xbf, 0x32, 0x86, 0xc7, 0xa5, 0x14, 0x09, 0xce,
+		  0x95, 0x72, 0x4d, 0x50, 0x3b, 0xfe, 0x6e, 0x70 },
+		{ 0xd4, 0x83, 0xaf, 0xae, 0x56, 0x24, 0x09, 0xa3,
+		  0x26, 0xb5, 0xbb, 0x0b, 0x20, 0xc4, 0xd7, 0x62 },
+		{ 0x08, 0x33, 0x2d, 0x7e, 0x9f, 0x48, 0x45, 0x70 },
+		{ 0xed, 0x41, 0xb7, 0x34, 0x48, 0x9d, 0x52, 0x07 },
+		{ 0xae, 0xfa, 0x35, 0x7b, 0xea, 0xc2, 0xa8, 0x7a },
+		{ 0x90, 0x8c, 0x43, 0xf0, 0x56, 0x9c, 0xb8, 0xf7,
+		  0x4b, 0xc9, 0x71, 0xe7, 0x06, 0xc3, 0x6c, 0x5f },
+		{ 0xc2, 0x51, 0xdf, 0x0d, 0x88, 0x8d, 0xd9, 0x32,
+		  0x9b, 0xcf, 0x46, 0x65, 0x5b, 0x22, 0x6e, 0x40 },
+		{ 0x30, 0xff, 0x25, 0xcd, 0xad, 0xf6 },
+		{ 0xe8, 0x4e, 0xd0, 0xd4, 0x67, 0x7e }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.13 Test Set 13 */
+		{ 0x72, 0x9b, 0x17, 0x72, 0x92, 0x70, 0xdd, 0x87,
+		  0xcc, 0xdf, 0x1b, 0xfe, 0x29, 0xb4, 0xe9, 0xbb },
+		{ 0x31, 0x1c, 0x4c, 0x92, 0x97, 0x44, 0xd6, 0x75,
+		  0xb7, 0x20, 0xf3, 0xb7, 0xe9, 0xb1, 0xcb, 0xd0 },
+		{ 0xc8, 0x5c, 0x4c, 0xf6, 0x59, 0x16 },
+		{ 0x5b, 0xb2 },
+		{ 0xd0, 0x4c, 0x9c, 0x35, 0xbd, 0x22, 0x62, 0xfa,
+		  0x81, 0x0d, 0x29, 0x24, 0xd0, 0x36, 0xfd, 0x13 },
+		{ 0x22, 0x8c, 0x2f, 0x2f, 0x06, 0xac, 0x32, 0x68,
+		  0xa9, 0xe6, 0x16, 0xee, 0x16, 0xdb, 0x4b, 0xa1 },
+		{ 0xff, 0x79, 0x4f, 0xe2, 0xf8, 0x27, 0xeb, 0xf8 },
+		{ 0x24, 0xfe, 0x4d, 0xc6, 0x1e, 0x87, 0x4b, 0x52 },
+		{ 0x98, 0xdb, 0xbd, 0x09, 0x9b, 0x3b, 0x40, 0x8d },
+		{ 0x44, 0xc0, 0xf2, 0x3c, 0x54, 0x93, 0xcf, 0xd2,
+		  0x41, 0xe4, 0x8f, 0x19, 0x7e, 0x1d, 0x10, 0x12 },
+		{ 0x0c, 0x9f, 0xb8, 0x16, 0x13, 0x88, 0x4c, 0x25,
+		  0x35, 0xdd, 0x0e, 0xab, 0xf3, 0xb4, 0x40, 0xd8 },
+		{ 0x53, 0x80, 0xd1, 0x58, 0xcf, 0xe3 },
+		{ 0x87, 0xac, 0x3b, 0x55, 0x9f, 0xb6 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.14 Test Set 14 */
+		{ 0xd3, 0x2d, 0xd2, 0x3e, 0x89, 0xdc, 0x66, 0x23,
+		  0x54, 0xca, 0x12, 0xeb, 0x79, 0xdd, 0x32, 0xfa },
+		{ 0xcf, 0x7d, 0x0a, 0xb1, 0xd9, 0x43, 0x06, 0x95,
+		  0x0b, 0xf1, 0x20, 0x18, 0xfb, 0xd4, 0x68, 0x87 },
+		{ 0x48, 0x41, 0x07, 0xe5, 0x6a, 0x43 },
+		{ 0xb5, 0xe6 },
+		{ 0xfe, 0x75, 0x90, 0x5b, 0x9d, 0xa4, 0x7d, 0x35,
+		  0x62, 0x36, 0xd0, 0x31, 0x4e, 0x09, 0xc3, 0x2e },
+		{ 0xd2, 0x2a, 0x4b, 0x41, 0x80, 0xa5, 0x32, 0x57,
+		  0x08, 0xa5, 0xff, 0x70, 0xd9, 0xf6, 0x7e, 0xc7 },
+		{ 0xcf, 0x19, 0xd6, 0x2b, 0x6a, 0x80, 0x98, 0x66 },
+		{ 0x5d, 0x26, 0x95, 0x37, 0xe4, 0x5e, 0x2c, 0xe6 },
+		{ 0xaf, 0x4a, 0x41, 0x1e, 0x11, 0x39, 0xf2, 0xc2 },
+		{ 0x5a, 0xf8, 0x6b, 0x80, 0xed, 0xb7, 0x0d, 0xf5,
+		  0x29, 0x2c, 0xc1, 0x12, 0x1c, 0xba, 0xd5, 0x0c },
+		{ 0x7f, 0x4d, 0x6a, 0xe7, 0x44, 0x0e, 0x18, 0x78,
+		  0x9a, 0x8b, 0x75, 0xad, 0x3f, 0x42, 0xf0, 0x3a },
+		{ 0x21, 0x7a, 0xf4, 0x92, 0x72, 0xad },
+		{ 0x90, 0x0e, 0x10, 0x1c, 0x67, 0x7e }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.15 Test Set 15 */
+		{ 0xaf, 0x7c, 0x65, 0xe1, 0x92, 0x72, 0x21, 0xde,
+		  0x59, 0x11, 0x87, 0xa2, 0xc5, 0x98, 0x7a, 0x53 },
+		{ 0x1f, 0x0f, 0x85, 0x78, 0x46, 0x4f, 0xd5, 0x9b,
+		  0x64, 0xbe, 0xd2, 0xd0, 0x94, 0x36, 0xb5, 0x7a },
+		{ 0x3d, 0x62, 0x7b, 0x01, 0x41, 0x8d },
+		{ 0x84, 0xf6 },
+		{ 0x0c, 0x7a, 0xcb, 0x8d, 0x95, 0xb7, 0xd4, 0xa3,
+		  0x1c, 0x5a, 0xca, 0x6d, 0x26, 0x34, 0x5a, 0x88 },
+		{ 0xa4, 0xcf, 0x5c, 0x81, 0x55, 0xc0, 0x8a, 0x7e,
+		  0xff, 0x41, 0x8e, 0x54, 0x43, 0xb9, 0x8e, 0x55 },
+		{ 0xc3, 0x7c, 0xae, 0x78, 0x05, 0x64, 0x20, 0x32 },
+		{ 0x68, 0xcd, 0x09, 0xa4, 0x52, 0xd8, 0xdb, 0x7c },
+		{ 0x7b, 0xff, 0xa5, 0xc2, 0xf4, 0x1f, 0xbc, 0x05 },
+		{ 0x3f, 0x8c, 0x3f, 0x3c, 0xcf, 0x76, 0x25, 0xbf,
+		  0x77, 0xfc, 0x94, 0xbc, 0xfd, 0x22, 0xfd, 0x26 },
+		{ 0xab, 0xcb, 0xae, 0x8f, 0xd4, 0x61, 0x15, 0xe9,
+		  0x96, 0x1a, 0x55, 0xd0, 0xda, 0x5f, 0x20, 0x78 },
+		{ 0x83, 0x7f, 0xd7, 0xb7, 0x44, 0x19 },
+		{ 0x56, 0xe9, 0x7a, 0x60, 0x90, 0xb1 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.16 Test Set 16 */
+		{ 0x5b, 0xd7, 0xec, 0xd3, 0xd3, 0x12, 0x7a, 0x41,
+		  0xd1, 0x25, 0x39, 0xbe, 0xd4, 0xe7, 0xcf, 0x71 },
+		{ 0x59, 0xb7, 0x5f, 0x14, 0x25, 0x1c, 0x75, 0x03,
+		  0x1d, 0x0b, 0xcb, 0xac, 0x1c, 0x2c, 0x04, 0xc7 },
+		{ 0xa2, 0x98, 0xae, 0x89, 0x29, 0xdc },
+		{ 0xd0, 0x56 },
+		{ 0xf9, 0x67, 0xf7, 0x60, 0x38, 0xb9, 0x20, 0xa9,
+		  0xcd, 0x25, 0xe1, 0x0c, 0x08, 0xb4, 0x99, 0x24 },
+		{ 0x76, 0x08, 0x9d, 0x3c, 0x0f, 0xf3, 0xef, 0xdc,
+		  0x6e, 0x36, 0x72, 0x1d, 0x4f, 0xce, 0xb7, 0x47 },
+		{ 0xc3, 0xf2, 0x5c, 0xd9, 0x43, 0x09, 0x10, 0x7e },
+		{ 0xb0, 0xc8, 0xba, 0x34, 0x36, 0x65, 0xaf, 0xcc },
+		{ 0x7e, 0x3f, 0x44, 0xc7, 0x59, 0x1f, 0x6f, 0x45 },
+		{ 0xd4, 0x2b, 0x2d, 0x61, 0x5e, 0x49, 0xa0, 0x3a,
+		  0xc2, 0x75, 0xa5, 0xae, 0xf9, 0x7a, 0xf8, 0x92 },
+		{ 0x0b, 0x3f, 0x8d, 0x02, 0x4f, 0xe6, 0xbf, 0xaf,
+		  0xaa, 0x98, 0x2b, 0x8f, 0x82, 0xe3, 0x19, 0xc2 },
+		{ 0x5b, 0xe1, 0x14, 0x95, 0x52, 0x5d },
+		{ 0x4d, 0x6a, 0x34, 0xa1, 0xe4, 0xeb }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.17 Test Set 17 */
+		{ 0x6c, 0xd1, 0xc6, 0xce, 0xb1, 0xe0, 0x1e, 0x14,
+		  0xf1, 0xb8, 0x23, 0x16, 0xa9, 0x0b, 0x7f, 0x3d },
+		{ 0xf6, 0x9b, 0x78, 0xf3, 0x00, 0xa0, 0x56, 0x8b,
+		  0xce, 0x9f, 0x0c, 0xb9, 0x3c, 0x4b, 0xe4, 0xc9 },
+		{ 0xb4, 0xfc, 0xe5, 0xfe, 0xb0, 0x59 },
+		{ 0xe4, 0xbb },
+		{ 0x07, 0x8b, 0xfc, 0xa9, 0x56, 0x46, 0x59, 0xec,
+		  0xd8, 0x85, 0x1e, 0x84, 0xe6, 0xc5, 0x9b, 0x48 },
+		{ 0xa2, 0x19, 0xdc, 0x37, 0xf1, 0xdc, 0x7d, 0x66,
+		  0x73, 0x8b, 0x58, 0x43, 0xc7, 0x99, 0xf2, 0x06 },
+		{ 0x69, 0xa9, 0x08, 0x69, 0xc2, 0x68, 0xcb, 0x7b },
+		{ 0x2e, 0x0f, 0xdc, 0xf9, 0xfd, 0x1c, 0xfa, 0x6a },
+		{ 0x70, 0xf6, 0xbd, 0xb9, 0xad, 0x21, 0x52, 0x5f },
+		{ 0x6e, 0xda, 0xf9, 0x9e, 0x5b, 0xd9, 0xf8, 0x5d,
+		  0x5f, 0x36, 0xd9, 0x1c, 0x12, 0x72, 0xfb, 0x4b },
+		{ 0xd6, 0x1c, 0x85, 0x3c, 0x28, 0x0d, 0xd9, 0xc4,
+		  0x6f, 0x29, 0x7b, 0xae, 0xc3, 0x86, 0xde, 0x17 },
+		{ 0x1c, 0x40, 0x8a, 0x85, 0x8b, 0x3e },
+		{ 0xaa, 0x4a, 0xe5, 0x2d, 0xaa, 0x30 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.18 Test Set 18 */
+		{ 0xb7, 0x3a, 0x90, 0xcb, 0xcf, 0x3a, 0xfb, 0x62,
+		  0x2d, 0xba, 0x83, 0xc5, 0x8a, 0x84, 0x15, 0xdf },
+		{ 0xb1, 0x20, 0xf1, 0xc1, 0xa0, 0x10, 0x2a, 0x2f,
+		  0x50, 0x7d, 0xd5, 0x43, 0xde, 0x68, 0x28, 0x1f },
+		{ 0xf1, 0xe8, 0xa5, 0x23, 0xa3, 0x6d },
+		{ 0x47, 0x1b },
+		{ 0xb6, 0x72, 0x04, 0x7e, 0x00, 0x3b, 0xb9, 0x52,
+		  0xdc, 0xa6, 0xcb, 0x8a, 0xf0, 0xe5, 0xb7, 0x79 },
+		{ 0xdf, 0x0c, 0x67, 0x86, 0x8f, 0xa2, 0x5f, 0x74,
+		  0x8b, 0x70, 0x44, 0xc6, 0xe7, 0xc2, 0x45, 0xb8 },
+		{ 0xeb, 0xd7, 0x03, 0x41, 0xbc, 0xd4, 0x15, 0xb0 },
+		{ 0x12, 0x35, 0x9f, 0x5d, 0x82, 0x22, 0x0c, 0x14 },
+		{ 0x47, 0x9d, 0xd2, 0x5c, 0x20, 0x79, 0x2d, 0x63 },
+		{ 0x66, 0x19, 0x5d, 0xbe, 0xd0, 0x31, 0x32, 0x74,
+		  0xc5, 0xca, 0x77, 0x66, 0x61, 0x5f, 0xa2, 0x5e },
+		{ 0x66, 0xbe, 0xc7, 0x07, 0xeb, 0x2a, 0xfc, 0x47,
+		  0x6d, 0x74, 0x08, 0xa8, 0xf2, 0x92, 0x7b, 0x36 },
+		{ 0xae, 0xfd, 0xaa, 0x5d, 0xdd, 0x99 },
+		{ 0x12, 0xec, 0x2b, 0x87, 0xfb, 0xb1 }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.19 Test Set 19 */
+		{ 0x51, 0x22, 0x25, 0x02, 0x14, 0xc3, 0x3e, 0x72,
+		  0x3a, 0x5d, 0xd5, 0x23, 0xfc, 0x14, 0x5f, 0xc0 },
+		{ 0x81, 0xe9, 0x2b, 0x6c, 0x0e, 0xe0, 0xe1, 0x2e,
+		  0xbc, 0xeb, 0xa8, 0xd9, 0x2a, 0x99, 0xdf, 0xa5 },
+		{ 0x16, 0xf3, 0xb3, 0xf7, 0x0f, 0xc2 },
+		{ 0xc3, 0xab },
+		{ 0xc9, 0xe8, 0x76, 0x32, 0x86, 0xb5, 0xb9, 0xff,
+		  0xbd, 0xf5, 0x6e, 0x12, 0x97, 0xd0, 0x88, 0x7b },
+		{ 0x98, 0x1d, 0x46, 0x4c, 0x7c, 0x52, 0xeb, 0x6e,
+		  0x50, 0x36, 0x23, 0x49, 0x84, 0xad, 0x0b, 0xcf },
+		{ 0x2a, 0x5c, 0x23, 0xd1, 0x5e, 0xe3, 0x51, 0xd5 },
+		{ 0x62, 0xda, 0xe3, 0x85, 0x3f, 0x3a, 0xf9, 0xd2 },
+		{ 0x28, 0xd7, 0xb0, 0xf2, 0xa2, 0xec, 0x3d, 0xe5 },
+		{ 0x53, 0x49, 0xfb, 0xe0, 0x98, 0x64, 0x9f, 0x94,
+		  0x8f, 0x5d, 0x2e, 0x97, 0x3a, 0x81, 0xc0, 0x0f },
+		{ 0x97, 0x44, 0x87, 0x1a, 0xd3, 0x2b, 0xf9, 0xbb,
+		  0xd1, 0xdd, 0x5c, 0xe5, 0x4e, 0x3e, 0x2e, 0x5a },
+		{ 0xad, 0xa1, 0x5a, 0xeb, 0x7b, 0xb8 },
+		{ 0xd4, 0x61, 0xbc, 0x15, 0x47, 0x5d }
+	}, {
+		/* 3GPP TS 35.208 v6.0.0 - 4.3.20 Test Set 20 */
+		{ 0x90, 0xdc, 0xa4, 0xed, 0xa4, 0x5b, 0x53, 0xcf,
+		  0x0f, 0x12, 0xd7, 0xc9, 0xc3, 0xbc, 0x6a, 0x89 },
+		{ 0x9f, 0xdd, 0xc7, 0x20, 0x92, 0xc6, 0xad, 0x03,
+		  0x6b, 0x6e, 0x46, 0x47, 0x89, 0x31, 0x5b, 0x78 },
+		{ 0x20, 0xf8, 0x13, 0xbd, 0x41, 0x41 },
+		{ 0x61, 0xdf },
+		{ 0x3f, 0xfc, 0xfe, 0x5b, 0x7b, 0x11, 0x11, 0x58,
+		  0x99, 0x20, 0xd3, 0x52, 0x8e, 0x84, 0xe6, 0x55 },
+		{ 0xcb, 0x9c, 0xcc, 0xc4, 0xb9, 0x25, 0x8e, 0x6d,
+		  0xca, 0x47, 0x60, 0x37, 0x9f, 0xb8, 0x25, 0x81 },
+		{ 0x09, 0xdb, 0x94, 0xea, 0xb4, 0xf8, 0x14, 0x9e },
+		{ 0xa2, 0x94, 0x68, 0xaa, 0x97, 0x75, 0xb5, 0x27 },
+		{ 0xa9, 0x51, 0x00, 0xe2, 0x76, 0x09, 0x52, 0xcd },
+		{ 0xb5, 0xf2, 0xda, 0x03, 0x88, 0x3b, 0x69, 0xf9,
+		  0x6b, 0xf5, 0x2e, 0x02, 0x9e, 0xd9, 0xac, 0x45 },
+		{ 0xb4, 0x72, 0x13, 0x68, 0xbc, 0x16, 0xea, 0x67,
+		  0x87, 0x5c, 0x55, 0x98, 0x68, 0x8b, 0xb0, 0xef },
+		{ 0x83, 0xcf, 0xd5, 0x4d, 0xb9, 0x13 },
+		{ 0x4f, 0x20, 0x39, 0x39, 0x2d, 0xdc }
+	}
+};
+
+#define NUM_TESTS (sizeof(test_sets) / sizeof(test_sets[0]))
+
+
+int main(int argc, char *argv[])
+{
+	u8 buf[16], buf2[16], buf3[16], buf4[16], buf5[16], opc[16];
+	u8 auts[14], sqn[6], _rand[16];
+	int ret = 0, res, i;
+	const struct milenage_test_set *t;
+	size_t res_len;
+
+	wpa_debug_level = 0;
+
+	printf("Milenage test sets\n");
+	for (i = 0; i < NUM_TESTS; i++) {
+		t = &test_sets[i];
+		printf("Test Set %d\n", i + 1);
+
+		milenage_opc(t->op, t->k, opc);
+		if (memcmp(opc, t->opc, 16) != 0) {
+			printf("- milenage_opc failed\n");
+			ret++;
+		}
+
+		milenage_f1(opc, t->k, t->rand, t->sqn, t->amf, buf, buf2);
+		if (memcmp(buf, t->f1, 8) != 0) {
+			printf("- milenage_f1 failed\n");
+			ret++;
+		}
+		if (memcmp(buf2, t->f1star, 8) != 0) {
+			printf("- milenage_f1* failed\n");
+			ret++;
+		}
+
+		milenage_f2345(opc, t->k, t->rand, buf, buf2, buf3, buf4,
+			       buf5);
+		if (memcmp(buf, t->f2, 8) != 0) {
+			printf("- milenage_f2 failed\n");
+			ret++;
+		}
+		if (memcmp(buf2, t->f3, 16) != 0) {
+			printf("- milenage_f3 failed\n");
+			ret++;
+		}
+		if (memcmp(buf3, t->f4, 16) != 0) {
+			printf("- milenage_f4 failed\n");
+			ret++;
+		}
+		if (memcmp(buf4, t->f5, 6) != 0) {
+			printf("- milenage_f5 failed\n");
+			ret++;
+		}
+		if (memcmp(buf5, t->f5star, 6) != 0) {
+			printf("- milenage_f5* failed\n");
+			ret++;
+		}
+	}
+
+	printf("milenage_auts test:\n");
+	memcpy(auts, "\x4f\x20\x39\x39\x2d\xdd", 6);
+	memcpy(auts + 6, "\x4b\xb4\x31\x6e\xd4\xa1\x46\x88", 8);
+	res = milenage_auts(t->opc, t->k, t->rand, auts, buf);
+	printf("AUTS for test set %d: %d / SQN=%02x%02x%02x%02x%02x%02x\n",
+	       i, res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+	if (res)
+		ret++;
+
+	memset(_rand, 0xaa, sizeof(_rand));
+	memcpy(auts,
+	       "\x43\x68\x1a\xd3\xda\xf0\x06\xbc\xde\x40\x5a\x20\x72\x67", 14);
+	res = milenage_auts(t->opc, t->k, _rand, auts, buf);
+	printf("AUTS from a test USIM: %d / SQN=%02x%02x%02x%02x%02x%02x\n",
+	       res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+	if (res)
+		ret++;
+
+	printf("milenage_generate test:\n");
+	memcpy(sqn, "\x00\x00\x00\x00\x40\x44", 6);
+	memcpy(_rand, "\x12\x69\xb8\x23\x41\x39\x35\x66\xfb\x99\x41\xe9\x84"
+	       "\x4f\xe6\x2f", 16);
+	res_len = 8;
+	milenage_generate(t->opc, t->amf, t->k, sqn, _rand, buf, buf2, buf3,
+			  buf4, &res_len);
+	wpa_hexdump(MSG_DEBUG, "SQN", sqn, 6);
+	wpa_hexdump(MSG_DEBUG, "RAND", _rand, 16);
+	wpa_hexdump(MSG_DEBUG, "AUTN", buf, 16);
+	wpa_hexdump(MSG_DEBUG, "IK", buf2, 16);
+	wpa_hexdump(MSG_DEBUG, "CK", buf3, 16);
+	wpa_hexdump(MSG_DEBUG, "RES", buf4, res_len);
+
+	printf("GSM-Milenage test sets\n");
+	for (i = 0; i < NUM_GSM_TESTS; i++) {
+		const struct gsm_milenage_test_set *g;
+		u8 sres[4], kc[8];
+		g = &gsm_test_sets[i];
+		printf("Test Set %d\n", i + 1);
+		gsm_milenage(g->opc, g->ki, g->rand, sres, kc);
+		if (memcmp(g->kc, kc, 8) != 0) {
+			printf("- gsm_milenage Kc failed\n");
+			ret++;
+		}
+#ifdef GSM_MILENAGE_ALT_SRES
+		if (memcmp(g->sres2, sres, 4) != 0) {
+			printf("- gsm_milenage SRES#2 failed\n");
+			ret++;
+		}
+#else /* GSM_MILENAGE_ALT_SRES */
+		if (memcmp(g->sres1, sres, 4) != 0) {
+			printf("- gsm_milenage SRES#1 failed\n");
+			ret++;
+		}
+#endif /* GSM_MILENAGE_ALT_SRES */
+	}
+
+	if (ret)
+		printf("Something failed\n");
+	else
+		printf("OK\n");
+
+	return ret;
+}
+#endif /* TEST_MAIN_MILENAGE */
--- /dev/null
+++ contrib/hostapd/sha256.h
@@ -0,0 +1,27 @@
+/*
+ * SHA256 hash implementation and interface functions
+ * Copyright (c) 2003-2006, 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 SHA256_H
+#define SHA256_H
+
+#define SHA256_MAC_LEN 32
+
+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		      const u8 *addr[], const size_t *len, u8 *mac);
+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		 size_t data_len, u8 *mac);
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+
+#endif /* SHA256_H */
Index: aes_wrap.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/aes_wrap.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/aes_wrap.c -L contrib/hostapd/aes_wrap.c -u -r1.2 -r1.3
--- contrib/hostapd/aes_wrap.c
+++ contrib/hostapd/aes_wrap.c
@@ -7,7 +7,7 @@
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
  *
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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,17 +19,18 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
+
 #include "common.h"
 #include "aes_wrap.h"
 #include "crypto.h"
 
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_AES
 #include "aes.c"
-#endif /* EAP_TLS_FUNCS */
+#endif /* INTERNAL_AES */
+
 
+#ifndef CONFIG_NO_AES_WRAP
 
 /**
  * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -49,8 +50,8 @@
 	r = cipher + 8;
 
 	/* 1) Initialize variables. */
-	memset(a, 0xa6, 8);
-	memcpy(r, plain, 8 * n);
+	os_memset(a, 0xa6, 8);
+	os_memcpy(r, plain, 8 * n);
 
 	ctx = aes_encrypt_init(kek, 16);
 	if (ctx == NULL)
@@ -66,12 +67,12 @@
 	for (j = 0; j <= 5; j++) {
 		r = cipher + 8;
 		for (i = 1; i <= n; i++) {
-			memcpy(b, a, 8);
-			memcpy(b + 8, r, 8);
+			os_memcpy(b, a, 8);
+			os_memcpy(b + 8, r, 8);
 			aes_encrypt(ctx, b, b);
-			memcpy(a, b, 8);
+			os_memcpy(a, b, 8);
 			a[7] ^= n * j + i;
-			memcpy(r, b + 8, 8);
+			os_memcpy(r, b + 8, 8);
 			r += 8;
 		}
 	}
@@ -86,6 +87,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_NO_AES_WRAP */
+
 
 /**
  * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -102,9 +105,9 @@
 	void *ctx;
 
 	/* 1) Initialize variables. */
-	memcpy(a, cipher, 8);
+	os_memcpy(a, cipher, 8);
 	r = plain;
-	memcpy(r, cipher + 8, 8 * n);
+	os_memcpy(r, cipher + 8, 8 * n);
 
 	ctx = aes_decrypt_init(kek, 16);
 	if (ctx == NULL)
@@ -120,13 +123,13 @@
 	for (j = 5; j >= 0; j--) {
 		r = plain + (n - 1) * 8;
 		for (i = n; i >= 1; i--) {
-			memcpy(b, a, 8);
+			os_memcpy(b, a, 8);
 			b[7] ^= n * j + i;
 
-			memcpy(b + 8, r, 8);
+			os_memcpy(b + 8, r, 8);
 			aes_decrypt(ctx, b, b);
-			memcpy(a, b, 8);
-			memcpy(r, b + 8, 8);
+			os_memcpy(a, b, 8);
+			os_memcpy(r, b + 8, 8);
 			r -= 8;
 		}
 	}
@@ -148,6 +151,8 @@
 
 #define BLOCK_SIZE 16
 
+#ifndef CONFIG_NO_AES_OMAC1
+
 static void gf_mulx(u8 *pad)
 {
 	int i, carry;
@@ -162,8 +167,8 @@
 
 
 /**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: Key for the hash operation
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
  * @data: Data buffer for which a MAC is determined
  * @data: Length of data buffer in bytes
  * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
@@ -174,13 +179,12 @@
 	void *ctx;
 	u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
 	const u8 *pos = data;
-	int i;
-	size_t left = data_len;
+	size_t i, left = data_len;
 
 	ctx = aes_encrypt_init(key, 16);
 	if (ctx == NULL)
 		return -1;
-	memset(cbc, 0, BLOCK_SIZE);
+	os_memset(cbc, 0, BLOCK_SIZE);
 
 	while (left >= BLOCK_SIZE) {
 		for (i = 0; i < BLOCK_SIZE; i++)
@@ -190,7 +194,7 @@
 		left -= BLOCK_SIZE;
 	}
 
-	memset(pad, 0, BLOCK_SIZE);
+	os_memset(pad, 0, BLOCK_SIZE);
 	aes_encrypt(ctx, pad, pad);
 	gf_mulx(pad);
 
@@ -208,6 +212,8 @@
 	return 0;
 }
 
+#endif /* CONFIG_NO_AES_OMAC1 */
+
 
 /**
  * aes_128_encrypt_block - Perform one AES 128-bit block operation
@@ -228,6 +234,8 @@
 }
 
 
+#ifndef CONFIG_NO_AES_CTR
+
 /**
  * aes_128_ctr_encrypt - AES-128 CTR mode encryption
  * @key: Key for encryption (16 bytes)
@@ -240,7 +248,7 @@
 			u8 *data, size_t data_len)
 {
 	void *ctx;
-	size_t len, left = data_len;
+	size_t j, len, left = data_len;
 	int i;
 	u8 *pos = data;
 	u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
@@ -248,14 +256,14 @@
 	ctx = aes_encrypt_init(key, 16);
 	if (ctx == NULL)
 		return -1;
-	memcpy(counter, nonce, BLOCK_SIZE);
+	os_memcpy(counter, nonce, BLOCK_SIZE);
 
 	while (left > 0) {
 		aes_encrypt(ctx, counter, buf);
 
 		len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
-		for (i = 0; i < len; i++)
-			pos[i] ^= buf[i];
+		for (j = 0; j < len; j++)
+			pos[j] ^= buf[j];
 		pos += len;
 		left -= len;
 
@@ -269,6 +277,10 @@
 	return 0;
 }
 
+#endif /* CONFIG_NO_AES_CTR */
+
+
+#ifndef CONFIG_NO_AES_EAX
 
 /**
  * aes_128_eax_encrypt - AES-128 EAX mode encryption
@@ -299,26 +311,26 @@
 		buf_len = hdr_len;
 	buf_len += 16;
 
-	buf = malloc(buf_len);
+	buf = os_malloc(buf_len);
 	if (buf == NULL)
 		return -1;
 
-	memset(buf, 0, 15);
+	os_memset(buf, 0, 15);
 
 	buf[15] = 0;
-	memcpy(buf + 16, nonce, nonce_len);
+	os_memcpy(buf + 16, nonce, nonce_len);
 	omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
 
 	buf[15] = 1;
-	memcpy(buf + 16, hdr, hdr_len);
+	os_memcpy(buf + 16, hdr, hdr_len);
 	omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
 
 	aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
 	buf[15] = 2;
-	memcpy(buf + 16, data, data_len);
+	os_memcpy(buf + 16, data, data_len);
 	omac1_aes_128(key, buf, 16 + data_len, data_mac);
 
-	free(buf);
+	os_free(buf);
 
 	for (i = 0; i < BLOCK_SIZE; i++)
 		tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
@@ -356,25 +368,25 @@
 		buf_len = hdr_len;
 	buf_len += 16;
 
-	buf = malloc(buf_len);
+	buf = os_malloc(buf_len);
 	if (buf == NULL)
 		return -1;
 
-	memset(buf, 0, 15);
+	os_memset(buf, 0, 15);
 
 	buf[15] = 0;
-	memcpy(buf + 16, nonce, nonce_len);
+	os_memcpy(buf + 16, nonce, nonce_len);
 	omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
 
 	buf[15] = 1;
-	memcpy(buf + 16, hdr, hdr_len);
+	os_memcpy(buf + 16, hdr, hdr_len);
 	omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
 
 	buf[15] = 2;
-	memcpy(buf + 16, data, data_len);
+	os_memcpy(buf + 16, data, data_len);
 	omac1_aes_128(key, buf, 16 + data_len, data_mac);
 
-	free(buf);
+	os_free(buf);
 
 	for (i = 0; i < BLOCK_SIZE; i++) {
 		if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
@@ -386,6 +398,10 @@
 	return 0;
 }
 
+#endif /* CONFIG_NO_AES_EAX */
+
+
+#ifndef CONFIG_NO_AES_CBC
 
 /**
  * aes_128_cbc_encrypt - AES-128 CBC encryption
@@ -405,14 +421,14 @@
 	ctx = aes_encrypt_init(key, 16);
 	if (ctx == NULL)
 		return -1;
-	memcpy(cbc, iv, BLOCK_SIZE);
+	os_memcpy(cbc, iv, BLOCK_SIZE);
 
 	blocks = data_len / BLOCK_SIZE;
 	for (i = 0; i < blocks; i++) {
 		for (j = 0; j < BLOCK_SIZE; j++)
 			cbc[j] ^= pos[j];
 		aes_encrypt(ctx, cbc, cbc);
-		memcpy(pos, cbc, BLOCK_SIZE);
+		os_memcpy(pos, cbc, BLOCK_SIZE);
 		pos += BLOCK_SIZE;
 	}
 	aes_encrypt_deinit(ctx);
@@ -438,288 +454,19 @@
 	ctx = aes_decrypt_init(key, 16);
 	if (ctx == NULL)
 		return -1;
-	memcpy(cbc, iv, BLOCK_SIZE);
+	os_memcpy(cbc, iv, BLOCK_SIZE);
 
 	blocks = data_len / BLOCK_SIZE;
 	for (i = 0; i < blocks; i++) {
-		memcpy(tmp, pos, BLOCK_SIZE);
+		os_memcpy(tmp, pos, BLOCK_SIZE);
 		aes_decrypt(ctx, pos, pos);
 		for (j = 0; j < BLOCK_SIZE; j++)
 			pos[j] ^= cbc[j];
-		memcpy(cbc, tmp, BLOCK_SIZE);
+		os_memcpy(cbc, tmp, BLOCK_SIZE);
 		pos += BLOCK_SIZE;
 	}
 	aes_decrypt_deinit(ctx);
 	return 0;
 }
 
-
-#ifdef TEST_MAIN
-
-#ifdef __i386__
-#define rdtscll(val) \
-     __asm__ __volatile__("rdtsc" : "=A" (val))
-
-static void test_aes_perf(void)
-{
-	const int num_iters = 10;
-	int i;
-	unsigned int start, end;
-	u8 key[16], pt[16], ct[16];
-	void *ctx;
-
-	printf("keySetupEnc:");
-	for (i = 0; i < num_iters; i++) {
-		rdtscll(start);
-		ctx = aes_encrypt_init(key, 16);
-		rdtscll(end);
-		aes_encrypt_deinit(ctx);
-		printf(" %d", end - start);
-	}
-	printf("\n");
-
-	printf("Encrypt:");
-	ctx = aes_encrypt_init(key, 16);
-	for (i = 0; i < num_iters; i++) {
-		rdtscll(start);
-		aes_encrypt(ctx, pt, ct);
-		rdtscll(end);
-		printf(" %d", end - start);
-	}
-	aes_encrypt_deinit(ctx);
-	printf("\n");
-}
-#endif /* __i386__ */
-
-
-static int test_eax(void)
-{
-	u8 msg[] = { 0xF7, 0xFB };
-	u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
-		     0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
-	u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
-		       0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
-	u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
-	u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
-			0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
-			0x67, 0xE5 };
-	u8 data[sizeof(msg)], tag[BLOCK_SIZE];
-
-	memcpy(data, msg, sizeof(msg));
-	if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
-				data, sizeof(data), tag)) {
-		printf("AES-128 EAX mode encryption failed\n");
-		return 1;
-	}
-	if (memcmp(data, cipher, sizeof(data)) != 0) {
-		printf("AES-128 EAX mode encryption returned invalid cipher "
-		       "text\n");
-		return 1;
-	}
-	if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
-		printf("AES-128 EAX mode encryption returned invalid tag\n");
-		return 1;
-	}
-
-	if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
-				data, sizeof(data), tag)) {
-		printf("AES-128 EAX mode decryption failed\n");
-		return 1;
-	}
-	if (memcmp(data, msg, sizeof(data)) != 0) {
-		printf("AES-128 EAX mode decryption returned invalid plain "
-		       "text\n");
-		return 1;
-	}
-
-	return 0;
-}
-
-
-static int test_cbc(void)
-{
-	struct cbc_test_vector {
-		u8 key[16];
-		u8 iv[16];
-		u8 plain[32];
-		u8 cipher[32];
-		size_t len;
-	} vectors[] = {
-		{
-			{ 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
-			  0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
-			{ 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
-			  0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
-			"Single block msg",
-			{ 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
-			  0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
-			16
-		},
-		{
-			{ 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
-			  0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
-			{ 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
-			  0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
-			{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-			  0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
-			  0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
-			  0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
-			{ 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
-			  0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
-			  0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
-			  0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
-			32
-		}
-	};
-	int i, ret = 0;
-	u8 *buf;
-
-	for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
-		struct cbc_test_vector *tv = &vectors[i];
-		buf = malloc(tv->len);
-		if (buf == NULL) {
-			ret++;
-			break;
-		}
-		memcpy(buf, tv->plain, tv->len);
-		aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
-		if (memcmp(buf, tv->cipher, tv->len) != 0) {
-			printf("AES-CBC encrypt %d failed\n", i);
-			ret++;
-		}
-		memcpy(buf, tv->cipher, tv->len);
-		aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
-		if (memcmp(buf, tv->plain, tv->len) != 0) {
-			printf("AES-CBC decrypt %d failed\n", i);
-			ret++;
-		}
-		free(buf);
-	}
-
-	return ret;
-}
-
-
-/* OMAC1 AES-128 test vectors from
- * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
- */
-
-struct omac1_test_vector {
-	u8 k[16];
-	u8 msg[64];
-	int msg_len;
-	u8 tag[16];
-};
-
-static struct omac1_test_vector test_vectors[] =
-{
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ },
-		0,
-		{ 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
-		  0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
-		16,
-		{ 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
-		  0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
-		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
-		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
-		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
-		40,
-		{ 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
-		  0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
-	},
-	{
-		{ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
-		  0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
-		{ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
-		  0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
-		  0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
-		  0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
-		  0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
-		  0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
-		  0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
-		  0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
-		64,
-		{ 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
-		  0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
-	},
-};
-
-
-int main(int argc, char *argv[])
-{
-	u8 kek[] = {
-		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
-		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
-	};
-	u8 plain[] = {
-		0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
-		0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
-	};
-	u8 crypt[] = {
-		0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
-		0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
-		0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
-	};
-	u8 result[24];
-	int ret = 0, i;
-	struct omac1_test_vector *tv;
-
-	if (aes_wrap(kek, 2, plain, result)) {
-		printf("AES-WRAP-128-128 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, crypt, 24) != 0) {
-		printf("AES-WRAP-128-128 failed\n");
-		ret++;
-	}
-	if (aes_unwrap(kek, 2, crypt, result)) {
-		printf("AES-UNWRAP-128-128 reported failure\n");
-		ret++;
-	}
-	if (memcmp(result, plain, 16) != 0) {
-		int i;
-		printf("AES-UNWRAP-128-128 failed\n");
-		ret++;
-		for (i = 0; i < 16; i++)
-			printf(" %02x", result[i]);
-		printf("\n");
-	}
-
-#ifdef __i386__
-	test_aes_perf();
-#endif /* __i386__ */
-
-	for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
-		tv = &test_vectors[i];
-		omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
-		if (memcmp(result, tv->tag, 16) != 0) {
-			printf("OMAC1-AES-128 test vector %d failed\n", i);
-			ret++;
-		}
-	}
-
-	ret += test_eax();
-
-	ret += test_cbc();
-
-	if (ret)
-		printf("FAILED!\n");
-
-	return ret;
-}
-#endif /* TEST_MAIN */
+#endif /* CONFIG_NO_AES_CBC */
Index: sha1.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/sha1.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/sha1.c -L contrib/hostapd/sha1.c -u -r1.2 -r1.3
--- contrib/hostapd/sha1.c
+++ contrib/hostapd/sha1.c
@@ -1,6 +1,6 @@
 /*
  * SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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,9 +12,7 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
 
 #include "common.h"
 #include "sha1.h"
@@ -36,9 +34,8 @@
 {
 	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
 	unsigned char tk[20];
-	int i;
 	const u8 *_addr[6];
-	size_t _len[6];
+	size_t _len[6], i;
 
 	if (num_elem > 5) {
 		/*
@@ -65,8 +62,8 @@
 	 * and text is the data being protected */
 
 	/* start out by storing key in ipad */
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 	/* XOR key with ipad values */
 	for (i = 0; i < 64; i++)
 		k_pad[i] ^= 0x36;
@@ -80,8 +77,8 @@
 	}
 	sha1_vector(1 + num_elem, _addr, _len, mac);
 
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 	/* XOR key with opad values */
 	for (i = 0; i < 64; i++)
 		k_pad[i] ^= 0x5c;
@@ -129,7 +126,7 @@
 	u8 zero = 0, counter = 0;
 	size_t pos, plen;
 	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = strlen(label);
+	size_t label_len = os_strlen(label);
 	const unsigned char *addr[4];
 	size_t len[4];
 
@@ -152,7 +149,7 @@
 		} else {
 			hmac_sha1_vector(key, key_len, 4, addr, len,
 					 hash);
-			memcpy(&buf[pos], hash, plen);
+			os_memcpy(&buf[pos], hash, plen);
 			break;
 		}
 		counter++;
@@ -180,7 +177,7 @@
 	unsigned char counter = 0;
 	size_t pos, plen;
 	u8 hash[SHA1_MAC_LEN];
-	size_t label_len = strlen(label);
+	size_t label_len = os_strlen(label);
 	u8 output_len[2];
 	const unsigned char *addr[5];
 	size_t len[5];
@@ -204,10 +201,10 @@
 		plen = buf_len - pos;
 		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
 		if (plen >= SHA1_MAC_LEN) {
-			memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
 			pos += SHA1_MAC_LEN;
 		} else {
-			memcpy(&buf[pos], hash, plen);
+			os_memcpy(&buf[pos], hash, plen);
 			break;
 		}
 		len[0] = SHA1_MAC_LEN;
@@ -224,18 +221,19 @@
  * @seed_len: Length of the seed
  * @out: Buffer for the generated pseudo-random key
  * @outlen: Number of bytes of key to generate
-*
+ * Returns: 0 on success, -1 on failure.
+ *
  * This function is used to derive new, cryptographically separate keys from a
  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
  */
 int tls_prf(const u8 *secret, size_t secret_len, const char *label,
 	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
 {
-	size_t L_S1, L_S2;
+	size_t L_S1, L_S2, i;
 	const u8 *S1, *S2;
 	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
 	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
-	int i, MD5_pos, SHA1_pos;
+	int MD5_pos, SHA1_pos;
 	const u8 *MD5_addr[3];
 	size_t MD5_len[3];
 	const unsigned char *SHA1_addr[3];
@@ -247,14 +245,14 @@
 	MD5_addr[0] = A_MD5;
 	MD5_len[0] = MD5_MAC_LEN;
 	MD5_addr[1] = (unsigned char *) label;
-	MD5_len[1] = strlen(label);
+	MD5_len[1] = os_strlen(label);
 	MD5_addr[2] = seed;
 	MD5_len[2] = seed_len;
 
 	SHA1_addr[0] = A_SHA1;
 	SHA1_len[0] = SHA1_MAC_LEN;
 	SHA1_addr[1] = (unsigned char *) label;
-	SHA1_len[1] = strlen(label);
+	SHA1_len[1] = os_strlen(label);
 	SHA1_addr[2] = seed;
 	SHA1_len[2] = seed_len;
 
@@ -297,7 +295,7 @@
 
 
 static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
-			  size_t ssid_len, int iterations, int count,
+			  size_t ssid_len, int iterations, unsigned int count,
 			  u8 *digest)
 {
 	unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
@@ -305,7 +303,7 @@
 	unsigned char count_buf[4];
 	const u8 *addr[2];
 	size_t len[2];
-	size_t passphrase_len = strlen(passphrase);
+	size_t passphrase_len = os_strlen(passphrase);
 
 	addr[0] = (u8 *) ssid;
 	len[0] = ssid_len;
@@ -323,12 +321,12 @@
 	count_buf[2] = (count >> 8) & 0xff;
 	count_buf[3] = count & 0xff;
 	hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp);
-	memcpy(digest, tmp, SHA1_MAC_LEN);
+	os_memcpy(digest, tmp, SHA1_MAC_LEN);
 
 	for (i = 1; i < iterations; i++) {
 		hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN,
 			  tmp2);
-		memcpy(tmp, tmp2, SHA1_MAC_LEN);
+		os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
 		for (j = 0; j < SHA1_MAC_LEN; j++)
 			digest[j] ^= tmp2[j];
 	}
@@ -351,7 +349,7 @@
 void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
 		 int iterations, u8 *buf, size_t buflen)
 {
-	int count = 0;
+	unsigned int count = 0;
 	unsigned char *pos = buf;
 	size_t left = buflen, plen;
 	unsigned char digest[SHA1_MAC_LEN];
@@ -361,24 +359,28 @@
 		pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count,
 			      digest);
 		plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
-		memcpy(pos, digest, plen);
+		os_memcpy(pos, digest, plen);
 		pos += plen;
 		left -= plen;
 	}
 }
 
 
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_SHA1
 
-typedef struct {
+struct SHA1Context {
 	u32 state[5];
 	u32 count[2];
 	unsigned char buffer[64];
-} SHA1_CTX;
+};
+
+typedef struct SHA1Context SHA1_CTX;
 
-static void SHA1Init(SHA1_CTX *context);
-static void SHA1Update(SHA1_CTX *context, const void *data, u32 len);
-static void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+#ifndef CONFIG_CRYPTO_INTERNAL
+static void SHA1Init(struct SHA1Context *context);
+static void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+static void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
 static void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
 
 
@@ -393,7 +395,7 @@
 		 u8 *mac)
 {
 	SHA1_CTX ctx;
-	int i;
+	size_t i;
 
 	SHA1Init(&ctx);
 	for (i = 0; i < num_elem; i++)
@@ -402,19 +404,57 @@
 }
 
 
-/**
- * sha1_transform - Perform one SHA-1 transform step
- * @state: SHA-1 state
- * @data: Input data for the SHA-1 transform
- *
- * This function is used to implement random number generation specified in
- * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
- * similar to SHA-1, but has different message padding and as such, access to
- * just part of the SHA-1 is needed.
- */
-void sha1_transform(u8 *state, const u8 data[64])
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
 {
-	SHA1Transform((u32 *) state, data);
+	u8 xkey[64];
+	u32 t[5], _t[5];
+	int i, j, m, k;
+	u8 *xpos = x;
+	u32 carry;
+
+	if (seed_len > sizeof(xkey))
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	os_memset(xkey + seed_len, 0, 64 - seed_len);
+	t[0] = 0x67452301;
+	t[1] = 0xEFCDAB89;
+	t[2] = 0x98BADCFE;
+	t[3] = 0x10325476;
+	t[4] = 0xC3D2E1F0;
+
+	m = xlen / 40;
+	for (j = 0; j < m; j++) {
+		/* XSEED_j = 0 */
+		for (i = 0; i < 2; i++) {
+			/* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+			/* w_i = G(t, XVAL) */
+			os_memcpy(_t, t, 20);
+			SHA1Transform(_t, xkey);
+			_t[0] = host_to_be32(_t[0]);
+			_t[1] = host_to_be32(_t[1]);
+			_t[2] = host_to_be32(_t[2]);
+			_t[3] = host_to_be32(_t[3]);
+			_t[4] = host_to_be32(_t[4]);
+			os_memcpy(xpos, _t, 20);
+
+			/* XKEY = (1 + XKEY + w_i) mod 2^b */
+			carry = 1;
+			for (k = 19; k >= 0; k--) {
+				carry += xkey[k] + xpos[k];
+				xkey[k] = carry & 0xff;
+				carry >>= 8;
+			}
+
+			xpos += SHA1_MAC_LEN;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
 }
 
 
@@ -479,11 +519,11 @@
 
 -----------------
 Modified 4/01
-By Jouni Malinen <jkmaline at cc.hut.fi>
+By Jouni Malinen <j at w1.fi>
 Minor changes to match the coding style used in Dynamics.
 
 Modified September 24, 2004
-By Jouni Malinen <jkmaline at cc.hut.fi>
+By Jouni Malinen <j at w1.fi>
 Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
 
 */
@@ -557,7 +597,7 @@
 #ifdef SHA1HANDSOFF
 	u32 workspace[16];
 	block = (CHAR64LONG16 *) workspace;
-	memcpy(block, buffer, 64);
+	os_memcpy(block, buffer, 64);
 #else
 	block = (CHAR64LONG16 *) buffer;
 #endif
@@ -597,14 +637,14 @@
 	/* Wipe variables */
 	a = b = c = d = e = 0;
 #ifdef SHA1HANDSOFF
-	memset(block, 0, 64);
+	os_memset(block, 0, 64);
 #endif
 }
 
 
 /* SHA1Init - Initialize new context */
 
-static void SHA1Init(SHA1_CTX* context)
+void SHA1Init(SHA1_CTX* context)
 {
 	/* SHA1 initialization constants */
 	context->state[0] = 0x67452301;
@@ -618,7 +658,7 @@
 
 /* Run your data through this. */
 
-static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
+void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
 {
 	u32 i, j;
 	const unsigned char *data = _data;
@@ -631,7 +671,7 @@
 		context->count[1]++;
 	context->count[1] += (len >> 29);
 	if ((j + len) > 63) {
-		memcpy(&context->buffer[j], data, (i = 64-j));
+		os_memcpy(&context->buffer[j], data, (i = 64-j));
 		SHA1Transform(context->state, context->buffer);
 		for ( ; i + 63 < len; i += 64) {
 			SHA1Transform(context->state, &data[i]);
@@ -639,7 +679,7 @@
 		j = 0;
 	}
 	else i = 0;
-	memcpy(&context->buffer[j], &data[i], len - i);
+	os_memcpy(&context->buffer[j], &data[i], len - i);
 #ifdef VERBOSE
 	SHAPrintContext(context, "after ");
 #endif
@@ -648,7 +688,7 @@
 
 /* Add padding and return the message digest. */
 
-static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
 {
 	u32 i;
 	unsigned char finalcount[8];
@@ -671,324 +711,12 @@
 	}
 	/* Wipe variables */
 	i = 0;
-	memset(context->buffer, 0, 64);
-	memset(context->state, 0, 20);
-	memset(context->count, 0, 8);
-	memset(finalcount, 0, 8);
+	os_memset(context->buffer, 0, 64);
+	os_memset(context->state, 0, 20);
+	os_memset(context->count, 0, 8);
+	os_memset(finalcount, 0, 8);
 }
 
 /* ===== end - public domain SHA1 implementation ===== */
 
-#endif /* EAP_TLS_FUNCS */
-
-
-#ifdef TEST_MAIN
-
-#include "md5.c"
-
-static int test_eap_fast(void)
-{
-	/* draft-cam-winget-eap-fast-01.txt */
-	const u8 pac_key[] = {
-		0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
-		0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
-		0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
-		0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
-	};
-	const u8 seed[] = {
-		0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
-		0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
-		0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
-		0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
-		0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
-		0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
-		0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
-		0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
-	};
-	const u8 master_secret[] = {
-		0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
-		0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
-		0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
-		0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
-		0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
-		0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2  
-	};
-	const u8 key_block[] = {
-		0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
-		0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
-		0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
-		0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
-		0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
-		0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
-		0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
-		0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
-		0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
-		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
-		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
-		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
-		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
-		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
-	};
-	const u8 sks[] = {
-		0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
-		0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
-		0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
-		0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
-		0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
-	};
-	const u8 isk[] = {
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-	};
-	const u8 imck[] = {
-		0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
-		0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
-		0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
-		0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
-		0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
-		0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
-		0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
-		0x15, 0xEC, 0x57, 0x7B
-	};
-	const u8 msk[] = {
-		0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
-		0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
-		0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
-		0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
-		0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
-		0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
-		0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
-		0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
-	};
-	u8 tlv[] = {
-		0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
-		0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
-		0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
-		0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
-		0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
-		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
-		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
-		0x05, 0xC5, 0x5B, 0xB7
-	};
-	const u8 compound_mac[] = {
-		0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
-		0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
-		0x05, 0xC5, 0x5B, 0xB7
-	};
-	u8 buf[512];
-	const u8 *simck, *cmk;
-	int errors = 0;
-
-	printf("EAP-FAST test cases\n");
-
-	printf("- T-PRF (SHA1) test case / master_secret\n");
-	sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash",
-		   seed, sizeof(seed), buf, sizeof(master_secret));
-	if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- PRF (TLS, SHA1/MD5) test case / key_block\n");
-	tls_prf(master_secret, sizeof(master_secret), "key expansion",
-		seed, sizeof(seed), buf, sizeof(key_block));
-	if (memcmp(key_block, buf, sizeof(key_block)) != 0) {
-		printf("PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- T-PRF (SHA1) test case / IMCK\n");
-	sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
-		   isk, sizeof(isk), buf, sizeof(imck));
-	if (memcmp(imck, buf, sizeof(imck)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	simck = imck;
-	cmk = imck + 40;
-
-	printf("- T-PRF (SHA1) test case / MSK\n");
-	sha1_t_prf(simck, 40, "Session Key Generating Function",
-		   "", 0, buf, sizeof(msk));
-	if (memcmp(msk, buf, sizeof(msk)) != 0) {
-		printf("T-PRF test - FAILED!\n");
-		errors++;
-	}
-
-	printf("- Compound MAC test case\n");
-	memset(tlv + sizeof(tlv) - 20, 0, 20);
-	hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20);
-	if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac))
-	    != 0) {
-		printf("Compound MAC test - FAILED!\n");
-		errors++;
-	}
-
-	return errors;
-}
-
-
-static u8 key0[] =
-{
-	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-	0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
-	0x0b, 0x0b, 0x0b, 0x0b
-};
-static u8 data0[] = "Hi There";
-static u8 prf0[] =
-{
-	0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
-	0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
-	0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
-	0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
-	0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
-	0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
-	0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
-	0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
-};
-
-static u8 key1[] = "Jefe";
-static u8 data1[] = "what do ya want for nothing?";
-static u8 prf1[] =
-{
-	0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
-	0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
-	0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
-	0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
-	0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
-	0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
-	0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
-	0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
-};
-
-
-static u8 key2[] =
-{
-	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-	0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
-	0xaa, 0xaa, 0xaa, 0xaa
-};
-static u8 data2[] =
-{
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
-	0xdd, 0xdd
-};
-static u8 prf2[] =
-{
-	0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
-	0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
-	0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
-	0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
-	0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
-	0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
-	0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
-	0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
-};
-
-
-struct passphrase_test {
-	char *passphrase;
-	char *ssid;
-	char psk[32];
-};
-
-static struct passphrase_test passphrase_tests[] =
-{
-	{
-		"password",
-		"IEEE",
-		{
-			0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
-			0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
-			0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
-			0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
-		}
-	},
-	{
-		"ThisIsAPassword",
-		"ThisIsASSID",
-		{
-			0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
-			0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
-			0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
-			0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
-		}
-	},
-	{
-		"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-		"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
-		{
-			0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
-			0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
-			0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
-			0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
-		}
-	},
-};
-
-#define NUM_PASSPHRASE_TESTS \
-(sizeof(passphrase_tests) / sizeof(passphrase_tests[0]))
-
-
-int main(int argc, char *argv[])
-{
-	u8 res[512];
-	int ret = 0, i;
-
-	printf("PRF-SHA1 test cases:\n");
-
-	sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
-		 res, sizeof(prf0));
-	if (memcmp(res, prf0, sizeof(prf0)) == 0)
-		printf("Test case 0 - OK\n");
-	else {
-		printf("Test case 0 - FAILED!\n");
-		ret++;
-	}
-
-	sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
-		 res, sizeof(prf1));
-	if (memcmp(res, prf1, sizeof(prf1)) == 0)
-		printf("Test case 1 - OK\n");
-	else {
-		printf("Test case 1 - FAILED!\n");
-		ret++;
-	}
-
-	sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
-		 res, sizeof(prf2));
-	if (memcmp(res, prf2, sizeof(prf2)) == 0)
-		printf("Test case 2 - OK\n");
-	else {
-		printf("Test case 2 - FAILED!\n");
-		ret++;
-	}
-
-	ret += test_eap_fast();
-
-	printf("PBKDF2-SHA1 Passphrase test cases:\n");
-	for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
-		u8 psk[32];
-		struct passphrase_test *test = &passphrase_tests[i];
-		pbkdf2_sha1(test->passphrase,
-			    test->ssid, strlen(test->ssid),
-			    4096, psk, 32);
-		if (memcmp(psk, test->psk, 32) == 0)
-			printf("Test case %d - OK\n", i);
-		else {
-			printf("Test case %d - FAILED!\n", i);
-			ret++;
-		}
-	}
-
-	return ret;
-}
-#endif /* TEST_MAIN */
+#endif /* INTERNAL_SHA1 */
--- /dev/null
+++ contrib/hostapd/eap_vendor_test.c
@@ -0,0 +1,228 @@
+/*
+ * hostapd / Test method for vendor specific (expanded) EAP type
+ * Copyright (c) 2005, 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 "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+
+
+#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_TYPE 0xfcfbfaf9
+
+
+struct eap_vendor_test_data {
+	enum { INIT, CONFIRM, SUCCESS, FAILURE } state;
+};
+
+
+static const char * eap_vendor_test_state_txt(int state)
+{
+	switch (state) {
+	case INIT:
+		return "INIT";
+	case CONFIRM:
+		return "CONFIRM";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	default:
+		return "?";
+	}
+}
+
+
+static void eap_vendor_test_state(struct eap_vendor_test_data *data,
+				  int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: %s -> %s",
+		   eap_vendor_test_state_txt(data->state),
+		   eap_vendor_test_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_vendor_test_init(struct eap_sm *sm)
+{
+	struct eap_vendor_test_data *data;
+
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = INIT;
+
+	return data;
+}
+
+
+static void eap_vendor_test_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	free(data);
+}
+
+
+static u8 * eap_vendor_test_buildReq(struct eap_sm *sm, void *priv, int id,
+				     size_t *reqDataLen)
+{
+	struct eap_vendor_test_data *data = priv;
+	struct eap_hdr *req;
+	u8 *pos;
+
+	*reqDataLen = sizeof(*req) + 8 + 1;
+	req = malloc(*reqDataLen);
+	if (req == NULL) {
+		wpa_printf(MSG_ERROR, "EAP-VENDOR-TEST: Failed to allocate "
+			   "memory for request");
+		return NULL;
+	}
+
+	req->code = EAP_CODE_REQUEST;
+	req->identifier = id;
+	req->length = htons(*reqDataLen);
+	pos = (u8 *) (req + 1);
+	*pos++ = EAP_TYPE_EXPANDED;
+	WPA_PUT_BE24(pos, EAP_VENDOR_ID);
+	pos += 3;
+	WPA_PUT_BE32(pos, EAP_VENDOR_TYPE);
+	pos += 4;
+	*pos = data->state == INIT ? 1 : 3;
+
+	return (u8 *) req;
+}
+
+
+static Boolean eap_vendor_test_check(struct eap_sm *sm, void *priv,
+				     u8 *respData, size_t respDataLen)
+{
+	struct eap_hdr *resp;
+	u8 *pos;
+	size_t len;
+	int vendor;
+	u32 method;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	if (respDataLen < sizeof(*resp))
+		return TRUE;
+	len = ntohs(resp->length);
+	if (len > respDataLen)
+		return TRUE;
+
+	if (len < sizeof(*resp) + 8 || *pos != EAP_TYPE_EXPANDED) {
+		wpa_printf(MSG_INFO, "EAP-VENDOR-TEST: Invalid frame");
+		return TRUE;
+	}
+	pos++;
+
+	vendor = WPA_GET_BE24(pos);
+	pos += 3;
+	method = WPA_GET_BE32(pos);
+	pos++;
+
+	if (vendor != EAP_VENDOR_ID || method != EAP_VENDOR_TYPE)
+		return TRUE;
+
+	return FALSE;
+}
+
+
+static void eap_vendor_test_process(struct eap_sm *sm, void *priv,
+				    u8 *respData, size_t respDataLen)
+{
+	struct eap_vendor_test_data *data = priv;
+	struct eap_hdr *resp;
+	u8 *pos;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	pos += 8; /* Skip expanded header */
+
+	if (data->state == INIT) {
+		if (*pos == 2)
+			eap_vendor_test_state(data, CONFIRM);
+		else
+			eap_vendor_test_state(data, FAILURE);
+	} else if (data->state == CONFIRM) {
+		if (*pos == 4)
+			eap_vendor_test_state(data, SUCCESS);
+		else
+			eap_vendor_test_state(data, FAILURE);
+	} else
+		eap_vendor_test_state(data, FAILURE);
+}
+
+
+static Boolean eap_vendor_test_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_vendor_test_data *data = priv;
+	u8 *key;
+	const int key_len = 64;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(key_len);
+	if (key == NULL)
+		return NULL;
+
+	memset(key, 0x11, key_len / 2);
+	memset(key + key_len / 2, 0x22, key_len / 2);
+	*len = key_len;
+
+	return key;
+}
+
+
+static Boolean eap_vendor_test_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_vendor_test_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_vendor_test_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_ID, EAP_VENDOR_TYPE,
+				      "VENDOR-TEST");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_vendor_test_init;
+	eap->reset = eap_vendor_test_reset;
+	eap->buildReq = eap_vendor_test_buildReq;
+	eap->check = eap_vendor_test_check;
+	eap->process = eap_vendor_test_process;
+	eap->isDone = eap_vendor_test_isDone;
+	eap->getKey = eap_vendor_test_getKey;
+	eap->isSuccess = eap_vendor_test_isSuccess;
+
+	ret = eap_server_method_register(eap);
+	if (ret)
+		eap_server_method_free(eap);
+	return ret;
+}
Index: iapp.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/iapp.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/iapp.c -L contrib/hostapd/iapp.c -u -r1.2 -r1.3
--- contrib/hostapd/iapp.c
+++ contrib/hostapd/iapp.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-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
@@ -11,6 +10,11 @@
  * license.
  *
  * See README and COPYING for more details.
+ *
+ * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
+ * and IEEE has withdrawn it. In other words, it is likely better to look at
+ * using some other mechanism for AP-to-AP communication than extenting the
+ * implementation here.
  */
 
 /* TODO:
@@ -33,15 +37,9 @@
  * - IEEE 802.11 context transfer
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <netinet/in.h>
+#include "includes.h"
 #include <net/if.h>
 #include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
 #ifdef USE_KERNEL_HEADERS
 #include <linux/if_packet.h>
 #else /* USE_KERNEL_HEADERS */
@@ -53,7 +51,6 @@
 #include "iapp.h"
 #include "eloop.h"
 #include "sta_info.h"
-#include "hostap_common.h"
 
 
 #define IAPP_MULTICAST "224.0.1.178"
@@ -181,7 +178,7 @@
 };
 
 
-static void iapp_send_add(struct iapp_data *iapp, u8 *macaddr, u16 seq_num)
+static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
 {
 	char buf[128];
 	struct iapp_hdr *hdr;
@@ -200,7 +197,7 @@
 	add = (struct iapp_add_notify *) (hdr + 1);
 	add->addr_len = ETH_ALEN;
 	add->reserved = 0;
-	memcpy(add->mac_addr, macaddr, ETH_ALEN);
+	memcpy(add->mac_addr, mac_addr, ETH_ALEN);
 
 	add->seq_num = host_to_be16(seq_num);
 	
@@ -323,8 +320,10 @@
 	fromlen = sizeof(from);
 	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
 		       (struct sockaddr *) &from, &fromlen);
-	if (len < 0)
+	if (len < 0) {
 		perror("recvfrom");
+		return;
+	}
 
 	if (from.sin_addr.s_addr == iapp->own.s_addr)
 		return; /* ignore own IAPP messages */
@@ -333,9 +332,9 @@
 		       HOSTAPD_LEVEL_DEBUG,
 		       "Received %d byte IAPP frame from %s%s\n",
 		       len, inet_ntoa(from.sin_addr),
-		       len < sizeof(*hdr) ? " (too short)" : "");
+		       len < (int) sizeof(*hdr) ? " (too short)" : "");
 
-	if (len < sizeof(*hdr))
+	if (len < (int) sizeof(*hdr))
 		return;
 
 	hdr = (struct iapp_hdr *) buf;
@@ -387,10 +386,9 @@
 	struct iapp_data *iapp;
 	struct ip_mreqn mreq;
 
-	iapp = malloc(sizeof(*iapp));
+	iapp = wpa_zalloc(sizeof(*iapp));
 	if (iapp == NULL)
 		return NULL;
-	memset(iapp, 0, sizeof(*iapp));
 	iapp->hapd = hapd;
 	iapp->udp_sock = iapp->packet_sock = -1;
 
@@ -459,12 +457,14 @@
 	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
 		       sizeof(mreq)) < 0) {
 		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (iapp->packet_sock < 0) {
 		perror("socket[PF_PACKET,SOCK_RAW]");
+		iapp_deinit(iapp);
 		return NULL;
 	}
 
@@ -474,12 +474,14 @@
 	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
 		 sizeof(addr)) < 0) {
 		perror("bind[PACKET]");
+		iapp_deinit(iapp);
 		return NULL;
 	}
 
 	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
 				     iapp, NULL)) {
 		printf("Could not register read socket for IAPP.\n");
+		iapp_deinit(iapp);
 		return NULL;
 	}
 
@@ -520,3 +522,23 @@
 	}
 	free(iapp);
 }
+
+int iapp_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
+		  struct hostapd_bss_config *oldbss)
+{
+	if (hapd->conf->ieee802_11f != oldbss->ieee802_11f ||
+	    strcmp(hapd->conf->iapp_iface, oldbss->iapp_iface) != 0) {
+
+		iapp_deinit(hapd->iapp);
+		hapd->iapp = NULL;
+
+		if (hapd->conf->ieee802_11f) {
+			hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface);
+
+			if (hapd->iapp == NULL)
+				return -1;
+		}
+	}
+
+	return 0;
+}
Index: ieee802_1x.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/ieee802_1x.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/ieee802_1x.h -L contrib/hostapd/ieee802_1x.h -u -r1.2 -r1.3
--- contrib/hostapd/ieee802_1x.h
+++ contrib/hostapd/ieee802_1x.h
@@ -1,26 +1,22 @@
-/* $FreeBSD: src/contrib/hostapd/ieee802_1x.h,v 1.2.2.1 2006/03/24 01:42:34 sam Exp $ */
+/* $FreeBSD: src/contrib/hostapd/ieee802_1x.h,v 1.4 2007/07/09 16:20:41 sam Exp $ */
+
+/*
+ * hostapd / IEEE 802.1X Authenticator
+ * Copyright (c) 2002-2005, 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 IEEE802_1X_H
 #define IEEE802_1X_H
 
-/* IEEE Std 802.1X-REV-d11, 7.2 */
-
-struct ieee802_1x_hdr {
-	u8 version;
-	u8 type;
-	u16 length;
-	/* followed by length octets of data */
-} __attribute__ ((packed));
-
-#define EAPOL_VERSION 2
-
-enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
-       IEEE802_1X_TYPE_EAPOL_START = 1,
-       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
-       IEEE802_1X_TYPE_EAPOL_KEY = 3,
-       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
-};
-
 /* draft-congdon-radius-8021x-20.txt */
 
 struct ieee802_1x_eapol_key {
@@ -45,32 +41,31 @@
 	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
 } __attribute__ ((packed));
 
-enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
-       EAPOL_KEY_TYPE_WPA = 254 };
-
 
 void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
 			size_t len);
-void ieee802_1x_new_station(hostapd *hapd, struct sta_info *sta);
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
 void ieee802_1x_free_station(struct sta_info *sta);
 
 void ieee802_1x_request_identity(struct hostapd_data *hapd,
 				 struct sta_info *sta);
 void ieee802_1x_tx_canned_eap(struct hostapd_data *hapd, struct sta_info *sta,
 			      int success);
-void ieee802_1x_tx_req(hostapd *hapd, struct sta_info *sta);
+void ieee802_1x_tx_req(struct hostapd_data *hapd, struct sta_info *sta);
 void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_send_resp_to_server(hostapd *hapd, struct sta_info *sta);
+void ieee802_1x_send_resp_to_server(struct hostapd_data *hapd,
+				    struct sta_info *sta);
 void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
-void ieee802_1x_set_sta_authorized(hostapd *hapd, struct sta_info *sta,
-				   int authorized);
-void ieee802_1x_set_port_enabled(hostapd *hapd, struct sta_info *sta,
-				 int enabled);
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized);
 void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
-int ieee802_1x_init(hostapd *hapd);
-void ieee802_1x_deinit(hostapd *hapd);
-int ieee802_1x_tx_status(hostapd *hapd, struct sta_info *sta, u8 *buf,
-			 size_t len, int ack);
+int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_deinit(struct hostapd_data *hapd);
+int ieee802_1x_reconfig(struct hostapd_data *hapd,
+			struct hostapd_config *oldconf,
+			struct hostapd_bss_config *oldbss);
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 u8 *buf, size_t len, int ack);
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 				 int idx);
@@ -86,6 +81,7 @@
 void hostapd_get_ntp_timestamp(u8 *buf);
 void ieee802_1x_finished(struct hostapd_data *hapd, struct sta_info *sta,
 			 int success);
+char *eap_type_text(u8 type);
 
 struct radius_class_data;
 
--- /dev/null
+++ contrib/hostapd/eap_methods.h
@@ -0,0 +1,49 @@
+/*
+ * hostapd / EAP method registration
+ * Copyright (c) 2004-2006, 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_METHODS_H
+#define EAP_METHODS_H
+
+const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method);
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+					    EapType method, const char *name);
+void eap_server_method_free(struct eap_method *method);
+int eap_server_method_register(struct eap_method *method);
+
+#ifdef EAP_SERVER
+
+EapType eap_get_type(const char *name, int *vendor);
+int eap_server_register_methods(void);
+void eap_server_unregister_methods(void);
+
+#else /* EAP_SERVER */
+
+static inline EapType eap_get_type(const char *name, int *vendor)
+{
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+static inline int eap_server_register_methods(void)
+{
+	return 0;
+}
+
+static inline void eap_server_unregister_methods(void)
+{
+}
+
+#endif /* EAP_SERVER */
+
+#endif /* EAP_METHODS_H */
Index: version.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/version.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/version.h -L contrib/hostapd/version.h -u -r1.2 -r1.3
--- contrib/hostapd/version.h
+++ contrib/hostapd/version.h
@@ -1,6 +1,6 @@
 #ifndef VERSION_H
 #define VERSION_H
 
-#define VERSION_STR "0.4.8"
+#define VERSION_STR "0.5.8"
 
 #endif /* VERSION_H */
Index: config.c
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/config.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/config.c -L contrib/hostapd/config.c -u -r1.2 -r1.3
--- contrib/hostapd/config.c
+++ contrib/hostapd/config.c
@@ -1,7 +1,6 @@
 /*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Configuration file
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * hostapd / Configuration file
+ * Copyright (c) 2003-2006, 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
@@ -13,63 +12,230 @@
  * See README and COPYING for more details.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
 #include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
 
 #include "hostapd.h"
 #include "driver.h"
 #include "sha1.h"
 #include "eap.h"
 #include "radius_client.h"
-#include "ieee802_1x.h"		/* XXX for EAPOL_VERSION */
+#include "wpa_common.h"
 
 
-static struct hostapd_config *hostapd_config_defaults(void)
+#define MAX_STA_COUNT 2007
+
+
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+					 const char *fname)
 {
-	struct hostapd_config *conf;
+	FILE *f;
+	char buf[128], *pos, *pos2;
+	int line = 0, vlan_id;
+	struct hostapd_vlan *vlan;
 
-	conf = malloc(sizeof(*conf) + sizeof(struct hostapd_radius_servers));
-	if (conf == NULL) {
+	f = fopen(fname, "r");
+	if (!f) {
+		printf("VLAN file '%s' not readable.\n", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (buf[0] == '*') {
+			vlan_id = VLAN_ID_WILDCARD;
+			pos = buf + 1;
+		} else {
+			vlan_id = strtol(buf, &pos, 10);
+			if (buf == pos || vlan_id < 1 ||
+			    vlan_id > MAX_VLAN_ID) {
+				printf("Invalid VLAN ID at line %d in '%s'\n",
+				       line, fname);
+				fclose(f);
+				return -1;
+			}
+		}
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		pos2 = pos;
+		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+			pos2++;
+		*pos2 = '\0';
+		if (*pos == '\0' || strlen(pos) > IFNAMSIZ) {
+			printf("Invalid VLAN ifname at line %d in '%s'\n",
+			       line, fname);
+			fclose(f);
+			return -1;
+		}
+
+		vlan = malloc(sizeof(*vlan));
+		if (vlan == NULL) {
+			printf("Out of memory while reading VLAN interfaces "
+			       "from '%s'\n", fname);
+			fclose(f);
+			return -1;
+		}
+
+		memset(vlan, 0, sizeof(*vlan));
+		vlan->vlan_id = vlan_id;
+		strncpy(vlan->ifname, pos, sizeof(vlan->ifname));
+		if (bss->vlan_tail)
+			bss->vlan_tail->next = vlan;
+		else
+			bss->vlan = vlan;
+		bss->vlan_tail = vlan;
+	}
+
+	fclose(f);
+
+	return 0;
+}
+
+
+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
+{
+	struct hostapd_vlan *vlan, *prev;
+
+	vlan = bss->vlan;
+	prev = NULL;
+	while (vlan) {
+		prev = vlan;
+		vlan = vlan->next;
+		free(prev);
+	}
+
+	bss->vlan = NULL;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+	int i, d;
+	char *pos;
+
+	i = atoi(value);
+	pos = strchr(value, '.');
+	d = 0;
+	if (pos) {
+		pos++;
+		if (*pos >= '0' && *pos <= '9')
+			d = *pos - '0';
+	}
+
+	return i * 10 + d;
+}
+
+
+static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+{
+	bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+	bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+	bss->logger_syslog = (unsigned int) -1;
+	bss->logger_stdout = (unsigned int) -1;
+
+	bss->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
+
+	bss->wep_rekeying_period = 300;
+	/* use key0 in individual key and key1 in broadcast key */
+	bss->broadcast_key_idx_min = 1;
+	bss->broadcast_key_idx_max = 2;
+	bss->eap_reauth_period = 3600;
+
+	bss->wpa_group_rekey = 600;
+	bss->wpa_gmk_rekey = 86400;
+	bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+	bss->wpa_pairwise = WPA_CIPHER_TKIP;
+	bss->wpa_group = WPA_CIPHER_TKIP;
+
+	bss->max_num_sta = MAX_STA_COUNT;
+
+	bss->dtim_period = 2;
+
+	bss->radius_server_auth_port = 1812;
+	bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+	bss->eapol_version = EAPOL_VERSION;
+}
+
+
+static struct hostapd_config * hostapd_config_defaults(void)
+{
+	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
+	int i;
+	const int aCWmin = 15, aCWmax = 1024;
+	const struct hostapd_wme_ac_params ac_bk =
+		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+	const struct hostapd_wme_ac_params ac_be =
+		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+	const struct hostapd_wme_ac_params ac_vi = /* video traffic */
+		{ aCWmin >> 1, aCWmin, 2, 3000 / 32, 1 };
+	const struct hostapd_wme_ac_params ac_vo = /* voice traffic */
+		{ aCWmin >> 2, aCWmin >> 1, 2, 1500 / 32, 1 };
+
+	conf = wpa_zalloc(sizeof(*conf));
+	bss = wpa_zalloc(sizeof(*bss));
+	if (conf == NULL || bss == NULL) {
 		printf("Failed to allocate memory for configuration data.\n");
+		free(conf);
+		free(bss);
 		return NULL;
 	}
-	memset(conf, 0, sizeof(*conf) + sizeof(struct hostapd_radius_servers));
-	conf->radius = (struct hostapd_radius_servers *) (conf + 1);
 
 	/* set default driver based on configuration */
 	conf->driver = driver_lookup("default");
 	if (conf->driver == NULL) {
 		printf("No default driver registered!\n");
 		free(conf);
+		free(bss);
 		return NULL;
 	}
 
-	conf->wep_rekeying_period = 300;
-	conf->eap_reauth_period = 3600;
+	bss->radius = wpa_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		free(conf);
+		free(bss);
+		return NULL;
+	}
 
-	conf->logger_syslog_level = HOSTAPD_LEVEL_INFO;
-	conf->logger_stdout_level = HOSTAPD_LEVEL_INFO;
-	conf->logger_syslog = (unsigned int) -1;
-	conf->logger_stdout = (unsigned int) -1;
-
-	conf->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
-	conf->eapol_version = EAPOL_VERSION;	/* NB: default version */
-
-	conf->wpa_group_rekey = 600;
-	conf->wpa_gmk_rekey = 86400;
-	conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
-	conf->wpa_pairwise = WPA_CIPHER_TKIP;
-	conf->wpa_group = WPA_CIPHER_TKIP;
+	hostapd_config_defaults_bss(bss);
 
-	conf->radius_server_auth_port = 1812;
+	conf->num_bss = 1;
+	conf->bss = bss;
+
+	conf->beacon_int = 100;
+	conf->rts_threshold = -1; /* use driver default: 2347 */
+	conf->fragm_threshold = -1; /* user driver default: 2346 */
+	conf->send_probe_response = 1;
+	conf->bridge_packets = INTERNAL_BRIDGE_DO_NOT_CONTROL;
+
+	memcpy(conf->country, "US ", 3);
+
+	for (i = 0; i < NUM_TX_QUEUES; i++)
+		conf->tx_queue[i].aifs = -1; /* use hw default */
+
+	conf->wme_ac_params[0] = ac_be;
+	conf->wme_ac_params[1] = ac_bk;
+	conf->wme_ac_params[2] = ac_vi;
+	conf->wme_ac_params[3] = ac_vo;
 
 	return conf;
 }
@@ -93,12 +259,19 @@
 }
 
 
-static int mac_comp(const void *a, const void *b)
+int hostapd_mac_comp(const void *a, const void *b)
 {
 	return memcmp(a, b, sizeof(macaddr));
 }
 
 
+int hostapd_mac_comp_empty(const void *a)
+{
+	macaddr empty = { 0 };
+	return memcmp(a, empty, sizeof(macaddr));
+}
+
+
 static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
 				       int *num)
 {
@@ -154,14 +327,14 @@
 
 	fclose(f);
 
-	qsort(*acl, *num, sizeof(macaddr), mac_comp);
+	qsort(*acl, *num, sizeof(macaddr), hostapd_mac_comp);
 
 	return 0;
 }
 
 
 static int hostapd_config_read_wpa_psk(const char *fname,
-				       struct hostapd_config *conf)
+				       struct hostapd_ssid *ssid)
 {
 	FILE *f;
 	char buf[128], *pos;
@@ -201,13 +374,12 @@
 			break;
 		}
 
-		psk = malloc(sizeof(*psk));
+		psk = wpa_zalloc(sizeof(*psk));
 		if (psk == NULL) {
 			printf("WPA PSK allocation failed\n");
 			ret = -1;
 			break;
 		}
-		memset(psk, 0, sizeof(*psk));
 		if (memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
 			psk->group = 1;
 		else
@@ -227,7 +399,7 @@
 		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
 			ok = 1;
 		else if (len >= 8 && len < 64) {
-			pbkdf2_sha1(pos, conf->ssid, conf->ssid_len,
+			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
 				    4096, psk->psk, PMK_LEN);
 			ok = 1;
 		}
@@ -239,8 +411,8 @@
 			break;
 		}
 
-		psk->next = conf->wpa_psk;
-		conf->wpa_psk = psk;
+		psk->next = ssid->wpa_psk;
+		ssid->wpa_psk = psk;
 	}
 
 	fclose(f);
@@ -249,42 +421,45 @@
 }
 
 
-int hostapd_setup_wpa_psk(struct hostapd_config *conf)
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
 {
-	if (conf->wpa_passphrase != NULL) {
-		if (conf->wpa_psk != NULL) {
+	struct hostapd_ssid *ssid = &conf->ssid;
+
+	if (ssid->wpa_passphrase != NULL) {
+		if (ssid->wpa_psk != NULL) {
 			printf("Warning: both WPA PSK and passphrase set. "
 			       "Using passphrase.\n");
-			free(conf->wpa_psk);
+			free(ssid->wpa_psk);
 		}
-		conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
-		if (conf->wpa_psk == NULL) {
+		ssid->wpa_psk = wpa_zalloc(sizeof(struct hostapd_wpa_psk));
+		if (ssid->wpa_psk == NULL) {
 			printf("Unable to alloc space for PSK\n");
 			return -1;
 		}
 		wpa_hexdump_ascii(MSG_DEBUG, "SSID",
-				  (u8 *) conf->ssid, conf->ssid_len);
+				  (u8 *) ssid->ssid, ssid->ssid_len);
 		wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
-				  (u8 *) conf->wpa_passphrase,
-				  strlen(conf->wpa_passphrase));
-		memset(conf->wpa_psk, 0, sizeof(struct hostapd_wpa_psk));
-		pbkdf2_sha1(conf->wpa_passphrase,
-			    conf->ssid, conf->ssid_len,
-			    4096, conf->wpa_psk->psk, PMK_LEN);
+				  (u8 *) ssid->wpa_passphrase,
+				  strlen(ssid->wpa_passphrase));
+		pbkdf2_sha1(ssid->wpa_passphrase,
+			    ssid->ssid, ssid->ssid_len,
+			    4096, ssid->wpa_psk->psk, PMK_LEN);
 		wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
-			    conf->wpa_psk->psk, PMK_LEN);
-		conf->wpa_psk->group = 1;
+			    ssid->wpa_psk->psk, PMK_LEN);
+		ssid->wpa_psk->group = 1;
 
-		memset(conf->wpa_passphrase, 0, strlen(conf->wpa_passphrase));
-		free(conf->wpa_passphrase);
-		conf->wpa_passphrase = 0;
+		memset(ssid->wpa_passphrase, 0,
+		       strlen(ssid->wpa_passphrase));
+		free(ssid->wpa_passphrase);
+		ssid->wpa_passphrase = NULL;
 	}
 
-	if (conf->wpa_psk_file) {
-		if (hostapd_config_read_wpa_psk(conf->wpa_psk_file, conf))
+	if (ssid->wpa_psk_file) {
+		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+						&conf->ssid))
 			return -1;
-		free(conf->wpa_psk_file);
-		conf->wpa_psk_file = NULL;
+		free(ssid->wpa_psk_file);
+		ssid->wpa_psk_file = NULL;
 	}
 
 	return 0;
@@ -293,7 +468,7 @@
 
 #ifdef EAP_SERVER
 static int hostapd_config_read_eap_user(const char *fname,
-					struct hostapd_config *conf)
+					struct hostapd_bss_config *conf)
 {
 	FILE *f;
 	char buf[512], *pos, *start, *pos2;
@@ -334,12 +509,11 @@
 			goto failed;
 		}
 
-		user = malloc(sizeof(*user));
+		user = wpa_zalloc(sizeof(*user));
 		if (user == NULL) {
 			printf("EAP user allocation failed\n");
 			goto failed;
 		}
-		memset(user, 0, sizeof(*user));
 		user->force_version = -1;
 
 		if (buf[0] == '*') {
@@ -363,6 +537,11 @@
 			}
 			memcpy(user->identity, start, pos - start);
 			user->identity_len = pos - start;
+
+			if (pos[0] == '"' && pos[1] == '*') {
+				user->wildcard_prefix = 1;
+				pos++;
+			}
 		}
 		pos++;
 		while (*pos == ' ' || *pos == '\t')
@@ -385,12 +564,17 @@
 		}
 		num_methods = 0;
 		while (*start) {
-			char *pos2 = strchr(start, ',');
-			if (pos2) {
-				*pos2++ = '\0';
-			}
-			user->methods[num_methods] = eap_get_type(start);
-			if (user->methods[num_methods] == EAP_TYPE_NONE) {
+			char *pos3 = strchr(start, ',');
+			if (pos3) {
+				*pos3++ = '\0';
+			}
+			user->methods[num_methods].method =
+				eap_get_type(start, &user->methods[num_methods]
+					     .vendor);
+			if (user->methods[num_methods].vendor ==
+			    EAP_VENDOR_IETF &&
+			    user->methods[num_methods].method == EAP_TYPE_NONE)
+			{
 				printf("Unsupported EAP type '%s' on line %d "
 				       "in '%s'\n", start, line, fname);
 				goto failed;
@@ -399,9 +583,9 @@
 			num_methods++;
 			if (num_methods >= EAP_USER_MAX_METHODS)
 				break;
-			if (pos2 == NULL)
+			if (pos3 == NULL)
 				break;
-			start = pos2;
+			start = pos3;
 		}
 		if (num_methods == 0) {
 			printf("No EAP types configured on line %d in '%s'\n",
@@ -453,6 +637,31 @@
 			user->password_len = pos - start;
 
 			pos++;
+		} else if (strncmp(pos, "hash:", 5) == 0) {
+			pos += 5;
+			pos2 = pos;
+			while (*pos2 != '\0' && *pos2 != ' ' &&
+			       *pos2 != '\t' && *pos2 != '#')
+				pos2++;
+			if (pos2 - pos != 32) {
+				printf("Invalid password hash on line %d in "
+				       "'%s'\n", line, fname);
+				goto failed;
+			}
+			user->password = malloc(16);
+			if (user->password == NULL) {
+				printf("Failed to allocate memory for EAP "
+				       "password hash\n");
+				goto failed;
+			}
+			if (hexstr2bin(pos, user->password, 16) < 0) {
+				printf("Invalid hash password on line %d in "
+				       "'%s'\n", line, fname);
+				goto failed;
+			}
+			user->password_len = 16;
+			user->password_hash = 1;
+			pos = pos2;
 		} else {
 			pos2 = pos;
 			while (*pos2 != '\0' && *pos2 != ' ' &&
@@ -496,6 +705,7 @@
 
 	failed:
 		if (user) {
+			free(user->password);
 			free(user->identity);
 			free(user);
 		}
@@ -562,7 +772,8 @@
 		else if (strcmp(start, "WPA-EAP") == 0)
 			val |= WPA_KEY_MGMT_IEEE8021X;
 		else {
-			printf("Line %d: invalid key_mgmt '%s'", line, start);
+			printf("Line %d: invalid key_mgmt '%s'\n",
+			       line, start);
 			free(buf);
 			return -1;
 		}
@@ -574,7 +785,7 @@
 
 	free(buf);
 	if (val == 0) {
-		printf("Line %d: no key_mgmt values configured.", line);
+		printf("Line %d: no key_mgmt values configured.\n", line);
 		return -1;
 	}
 
@@ -632,23 +843,308 @@
 }
 
 
-static int hostapd_config_check(struct hostapd_config *conf)
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf)
 {
-	if (conf->ieee802_1x && !conf->eap_server &&
-	    !conf->radius->auth_servers) {
+	if (bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
 		printf("Invalid IEEE 802.1X configuration (no EAP "
 		       "authenticator configured).\n");
 		return -1;
 	}
 
-	if (conf->wpa && (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
-	    conf->wpa_psk == NULL && conf->wpa_passphrase == NULL &&
-	    conf->wpa_psk_file == NULL) {
+	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL) {
 		printf("WPA-PSK enabled, but PSK or passphrase is not "
 		       "configured.\n");
 		return -1;
 	}
 
+	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if ((&conf->bss[i] != bss) &&
+			    (hostapd_mac_comp(conf->bss[i].bssid,
+					      bss->bssid) == 0)) {
+				printf("Duplicate BSSID " MACSTR
+				       " on interface '%s' and '%s'.\n",
+				       MAC2STR(bss->bssid),
+				       conf->bss[i].iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+	size_t i;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(&conf->bss[i], conf))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+				   char *val)
+{
+	size_t len = strlen(val);
+
+	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+		return -1;
+
+	if (val[0] == '"') {
+		if (len < 2 || val[len - 1] != '"')
+			return -1;
+		len -= 2;
+		wep->key[keyidx] = malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		memcpy(wep->key[keyidx], val + 1, len);
+		wep->len[keyidx] = len;
+	} else {
+		if (len & 1)
+			return -1;
+		len /= 2;
+		wep->key[keyidx] = malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		wep->len[keyidx] = len;
+		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+			return -1;
+	}
+
+	wep->keys_set++;
+
+	return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+	int *list;
+	int count;
+	char *pos, *end;
+
+	free(*rate_list);
+	*rate_list = NULL;
+
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		if (*pos == ' ')
+			count++;
+		pos++;
+	}
+
+	list = malloc(sizeof(int) * (count + 2));
+	if (list == NULL)
+		return -1;
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		end = strchr(pos, ' ');
+		if (end)
+			*end = '\0';
+
+		list[count++] = atoi(pos);
+		if (!end)
+			break;
+		pos = end + 1;
+	}
+	list[count] = -1;
+
+	*rate_list = list;
+	return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+	struct hostapd_bss_config *bss;
+
+	if (*ifname == '\0')
+		return -1;
+
+	bss = realloc(conf->bss, (conf->num_bss + 1) *
+		      sizeof(struct hostapd_bss_config));
+	if (bss == NULL) {
+		printf("Failed to allocate memory for multi-BSS entry\n");
+		return -1;
+	}
+	conf->bss = bss;
+
+	bss = &(conf->bss[conf->num_bss]);
+	memset(bss, 0, sizeof(*bss));
+	bss->radius = wpa_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		printf("Failed to allocate memory for multi-BSS RADIUS "
+		       "data\n");
+		return -1;
+	}
+
+	conf->num_bss++;
+	conf->last_bss = bss;
+
+	hostapd_config_defaults_bss(bss);
+	snprintf(bss->iface, sizeof(bss->iface), "%s", ifname);
+	memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+	return 0;
+}
+
+
+static int valid_cw(int cw)
+{
+	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+	IEEE80211_TX_QUEUE_DATA3 = 3, /* used for EDCA AC_BK data */
+	IEEE80211_TX_QUEUE_DATA4 = 4,
+	IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+	IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+				   char *val)
+{
+	int num;
+	char *pos;
+	struct hostapd_tx_queue_params *queue;
+
+	/* skip 'tx_queue_' prefix */
+	pos = name + 9;
+	if (strncmp(pos, "data", 4) == 0 &&
+	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+		num = pos[4] - '0';
+		pos += 6;
+	} else if (strncmp(pos, "after_beacon_", 13) == 0) {
+		num = IEEE80211_TX_QUEUE_AFTER_BEACON;
+		pos += 13;
+	} else if (strncmp(pos, "beacon_", 7) == 0) {
+		num = IEEE80211_TX_QUEUE_BEACON;
+		pos += 7;
+	} else {
+		printf("Unknown tx_queue name '%s'\n", pos);
+		return -1;
+	}
+
+	queue = &conf->tx_queue[num];
+
+	if (strcmp(pos, "aifs") == 0) {
+		queue->aifs = atoi(val);
+		if (queue->aifs < 0 || queue->aifs > 255) {
+			printf("Invalid AIFS value %d\n", queue->aifs);
+			return -1;
+		}
+	} else if (strcmp(pos, "cwmin") == 0) {
+		queue->cwmin = atoi(val);
+		if (!valid_cw(queue->cwmin)) {
+			printf("Invalid cwMin value %d\n", queue->cwmin);
+			return -1;
+		}
+	} else if (strcmp(pos, "cwmax") == 0) {
+		queue->cwmax = atoi(val);
+		if (!valid_cw(queue->cwmax)) {
+			printf("Invalid cwMax value %d\n", queue->cwmax);
+			return -1;
+		}
+	} else if (strcmp(pos, "burst") == 0) {
+		queue->burst = hostapd_config_read_int10(val);
+	} else {
+		printf("Unknown tx_queue field '%s'\n", pos);
+		return -1;
+	}
+
+	queue->configured = 1;
+
+	return 0;
+}
+
+
+static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
+				   char *val)
+{
+	int num, v;
+	char *pos;
+	struct hostapd_wme_ac_params *ac;
+
+	/* skip 'wme_ac_' prefix */
+	pos = name + 7;
+	if (strncmp(pos, "be_", 3) == 0) {
+		num = 0;
+		pos += 3;
+	} else if (strncmp(pos, "bk_", 3) == 0) {
+		num = 1;
+		pos += 3;
+	} else if (strncmp(pos, "vi_", 3) == 0) {
+		num = 2;
+		pos += 3;
+	} else if (strncmp(pos, "vo_", 3) == 0) {
+		num = 3;
+		pos += 3;
+	} else {
+		printf("Unknown wme name '%s'\n", pos);
+		return -1;
+	}
+
+	ac = &conf->wme_ac_params[num];
+
+	if (strcmp(pos, "aifs") == 0) {
+		v = atoi(val);
+		if (v < 1 || v > 255) {
+			printf("Invalid AIFS value %d\n", v);
+			return -1;
+		}
+		ac->aifs = v;
+	} else if (strcmp(pos, "cwmin") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			printf("Invalid cwMin value %d\n", v);
+			return -1;
+		}
+		ac->cwmin = v;
+	} else if (strcmp(pos, "cwmax") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			printf("Invalid cwMax value %d\n", v);
+			return -1;
+		}
+		ac->cwmax = v;
+	} else if (strcmp(pos, "txop_limit") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 0xffff) {
+			printf("Invalid txop value %d\n", v);
+			return -1;
+		}
+		ac->txopLimit = v;
+	} else if (strcmp(pos, "acm") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 1) {
+			printf("Invalid acm value %d\n", v);
+			return -1;
+		}
+		ac->admission_control_mandatory = v;
+	} else {
+		printf("Unknown wme_ac_ field '%s'\n", pos);
+		return -1;
+	}
+
 	return 0;
 }
 
@@ -656,14 +1152,12 @@
 struct hostapd_config * hostapd_config_read(const char *fname)
 {
 	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
 	FILE *f;
 	char buf[256], *pos;
 	int line = 0;
 	int errors = 0;
-	char *accept_mac_file = NULL, *deny_mac_file = NULL;
-#ifdef EAP_SERVER
-	char *eap_user_file = NULL;
-#endif /* EAP_SERVER */
+	size_t i;
 
 	f = fopen(fname, "r");
 	if (f == NULL) {
@@ -677,8 +1171,10 @@
 		fclose(f);
 		return NULL;
 	}
+	bss = conf->last_bss = conf->bss;
 
 	while (fgets(buf, sizeof(buf), f)) {
+		bss = conf->last_bss;
 		line++;
 
 		if (buf[0] == '#')
@@ -704,10 +1200,10 @@
 		pos++;
 
 		if (strcmp(buf, "interface") == 0) {
-			snprintf(conf->iface, sizeof(conf->iface), "%s", pos);
+			snprintf(conf->bss[0].iface,
+				 sizeof(conf->bss[0].iface), "%s", pos);
 		} else if (strcmp(buf, "bridge") == 0) {
-			snprintf(conf->bridge, sizeof(conf->bridge), "%s",
-				 pos);
+			snprintf(bss->bridge, sizeof(bss->bridge), "%s", pos);
 		} else if (strcmp(buf, "driver") == 0) {
 			conf->driver = driver_lookup(pos);
 			if (conf->driver == NULL) {
@@ -716,185 +1212,199 @@
 				errors++;
 			}
 		} else if (strcmp(buf, "debug") == 0) {
-			conf->debug = atoi(pos);
+			bss->debug = atoi(pos);
 		} else if (strcmp(buf, "logger_syslog_level") == 0) {
-			conf->logger_syslog_level = atoi(pos);
+			bss->logger_syslog_level = atoi(pos);
 		} else if (strcmp(buf, "logger_stdout_level") == 0) {
-			conf->logger_stdout_level = atoi(pos);
+			bss->logger_stdout_level = atoi(pos);
 		} else if (strcmp(buf, "logger_syslog") == 0) {
-			conf->logger_syslog = atoi(pos);
+			bss->logger_syslog = atoi(pos);
 		} else if (strcmp(buf, "logger_stdout") == 0) {
-			conf->logger_stdout = atoi(pos);
+			bss->logger_stdout = atoi(pos);
 		} else if (strcmp(buf, "dump_file") == 0) {
-			conf->dump_log_name = strdup(pos);
+			bss->dump_log_name = strdup(pos);
 		} else if (strcmp(buf, "ssid") == 0) {
-			conf->ssid_len = strlen(pos);
-			if (conf->ssid_len >= HOSTAPD_SSID_LEN ||
-			    conf->ssid_len < 1) {
+			bss->ssid.ssid_len = strlen(pos);
+			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+			    bss->ssid.ssid_len < 1) {
 				printf("Line %d: invalid SSID '%s'\n", line,
 				       pos);
 				errors++;
+			} else {
+				memcpy(bss->ssid.ssid, pos,
+				       bss->ssid.ssid_len);
+				bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
+				bss->ssid.ssid_set = 1;
 			}
-			memcpy(conf->ssid, pos, conf->ssid_len);
-			conf->ssid[conf->ssid_len] = '\0';
-			conf->ssid_set = 1;
 		} else if (strcmp(buf, "macaddr_acl") == 0) {
-			conf->macaddr_acl = atoi(pos);
-			if (conf->macaddr_acl != ACCEPT_UNLESS_DENIED &&
-			    conf->macaddr_acl != DENY_UNLESS_ACCEPTED &&
-			    conf->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+			bss->macaddr_acl = atoi(pos);
+			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
 				printf("Line %d: unknown macaddr_acl %d\n",
-				       line, conf->macaddr_acl);
+				       line, bss->macaddr_acl);
 			}
 		} else if (strcmp(buf, "accept_mac_file") == 0) {
-			accept_mac_file = strdup(pos);
-			if (!accept_mac_file) {
-				printf("Line %d: allocation failed\n", line);
+			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+							&bss->num_accept_mac))
+			{
+				printf("Line %d: Failed to read "
+				       "accept_mac_file '%s'\n",
+				       line, pos);
 				errors++;
 			}
 		} else if (strcmp(buf, "deny_mac_file") == 0) {
-			deny_mac_file = strdup(pos);
-			if (!deny_mac_file) {
-				printf("Line %d: allocation failed\n", line);
+			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+							&bss->num_deny_mac))
+			{
+				printf("Line %d: Failed to read "
+				       "deny_mac_file '%s'\n",
+				       line, pos);
 				errors++;
 			}
+		} else if (strcmp(buf, "ap_max_inactivity") == 0) {
+			bss->ap_max_inactivity = atoi(pos);
+		} else if (strcmp(buf, "country_code") == 0) {
+			memcpy(conf->country, pos, 2);
+			/* FIX: make this configurable */
+			conf->country[2] = ' ';
+		} else if (strcmp(buf, "ieee80211d") == 0) {
+			conf->ieee80211d = atoi(pos);
+		} else if (strcmp(buf, "ieee80211h") == 0) {
+			conf->ieee80211h = atoi(pos);
 		} else if (strcmp(buf, "assoc_ap_addr") == 0) {
-			if (hwaddr_aton(pos, conf->assoc_ap_addr)) {
+			if (hwaddr_aton(pos, bss->assoc_ap_addr)) {
 				printf("Line %d: invalid MAC address '%s'\n",
 				       line, pos);
 				errors++;
 			}
-			conf->assoc_ap = 1;
+			bss->assoc_ap = 1;
 		} else if (strcmp(buf, "ieee8021x") == 0) {
-			conf->ieee802_1x = atoi(pos);
+			bss->ieee802_1x = atoi(pos);
+		} else if (strcmp(buf, "eapol_version") == 0) {
+			bss->eapol_version = atoi(pos);
+			if (bss->eapol_version < 1 ||
+			    bss->eapol_version > 2) {
+				printf("Line %d: invalid EAPOL "
+				       "version (%d): '%s'.\n",
+				       line, bss->eapol_version, pos);
+				errors++;
+			} else
+				wpa_printf(MSG_DEBUG, "eapol_version=%d",
+					   bss->eapol_version);
 #ifdef EAP_SERVER
 		} else if (strcmp(buf, "eap_authenticator") == 0) {
-			conf->eap_server = atoi(pos);
+			bss->eap_server = atoi(pos);
 			printf("Line %d: obsolete eap_authenticator used; "
 			       "this has been renamed to eap_server\n", line);
 		} else if (strcmp(buf, "eap_server") == 0) {
-			conf->eap_server = atoi(pos);
+			bss->eap_server = atoi(pos);
 		} else if (strcmp(buf, "eap_user_file") == 0) {
-			free(eap_user_file);
-			eap_user_file = strdup(pos);
-			if (!eap_user_file) {
-				printf("Line %d: allocation failed\n", line);
+			if (hostapd_config_read_eap_user(pos, bss))
 				errors++;
-			}
 		} else if (strcmp(buf, "ca_cert") == 0) {
-			free(conf->ca_cert);
-			conf->ca_cert = strdup(pos);
+			free(bss->ca_cert);
+			bss->ca_cert = strdup(pos);
 		} else if (strcmp(buf, "server_cert") == 0) {
-			free(conf->server_cert);
-			conf->server_cert = strdup(pos);
+			free(bss->server_cert);
+			bss->server_cert = strdup(pos);
 		} else if (strcmp(buf, "private_key") == 0) {
-			free(conf->private_key);
-			conf->private_key = strdup(pos);
+			free(bss->private_key);
+			bss->private_key = strdup(pos);
 		} else if (strcmp(buf, "private_key_passwd") == 0) {
-			free(conf->private_key_passwd);
-			conf->private_key_passwd = strdup(pos);
+			free(bss->private_key_passwd);
+			bss->private_key_passwd = strdup(pos);
 		} else if (strcmp(buf, "check_crl") == 0) {
-			conf->check_crl = atoi(pos);
+			bss->check_crl = atoi(pos);
 #ifdef EAP_SIM
 		} else if (strcmp(buf, "eap_sim_db") == 0) {
-			free(conf->eap_sim_db);
-			conf->eap_sim_db = strdup(pos);
+			free(bss->eap_sim_db);
+			bss->eap_sim_db = strdup(pos);
 #endif /* EAP_SIM */
 #endif /* EAP_SERVER */
 		} else if (strcmp(buf, "eap_message") == 0) {
 			char *term;
-			conf->eap_req_id_text = strdup(pos);
-			if (conf->eap_req_id_text == NULL) {
+			bss->eap_req_id_text = strdup(pos);
+			if (bss->eap_req_id_text == NULL) {
 				printf("Line %d: Failed to allocate memory "
 				       "for eap_req_id_text\n", line);
 				errors++;
 				continue;
 			}
-			conf->eap_req_id_text_len =
-				strlen(conf->eap_req_id_text);
-			term = strstr(conf->eap_req_id_text, "\\0");
+			bss->eap_req_id_text_len =
+				strlen(bss->eap_req_id_text);
+			term = strstr(bss->eap_req_id_text, "\\0");
 			if (term) {
 				*term++ = '\0';
 				memmove(term, term + 1,
-					conf->eap_req_id_text_len -
-					(term - conf->eap_req_id_text) - 1);
-				conf->eap_req_id_text_len--;
+					bss->eap_req_id_text_len -
+					(term - bss->eap_req_id_text) - 1);
+				bss->eap_req_id_text_len--;
 			}
 		} else if (strcmp(buf, "wep_key_len_broadcast") == 0) {
-			conf->default_wep_key_len = atoi(pos);
-			if (conf->default_wep_key_len > 13) {
+			bss->default_wep_key_len = atoi(pos);
+			if (bss->default_wep_key_len > 13) {
 				printf("Line %d: invalid WEP key len %lu "
 				       "(= %lu bits)\n", line,
 				       (unsigned long)
-				       conf->default_wep_key_len,
+				       bss->default_wep_key_len,
 				       (unsigned long)
-				       conf->default_wep_key_len * 8);
+				       bss->default_wep_key_len * 8);
 				errors++;
 			}
 		} else if (strcmp(buf, "wep_key_len_unicast") == 0) {
-			conf->individual_wep_key_len = atoi(pos);
-			if (conf->individual_wep_key_len < 0 ||
-			    conf->individual_wep_key_len > 13) {
+			bss->individual_wep_key_len = atoi(pos);
+			if (bss->individual_wep_key_len < 0 ||
+			    bss->individual_wep_key_len > 13) {
 				printf("Line %d: invalid WEP key len %d "
 				       "(= %d bits)\n", line,
-				       conf->individual_wep_key_len,
-				       conf->individual_wep_key_len * 8);
+				       bss->individual_wep_key_len,
+				       bss->individual_wep_key_len * 8);
 				errors++;
 			}
 		} else if (strcmp(buf, "wep_rekey_period") == 0) {
-			conf->wep_rekeying_period = atoi(pos);
-			if (conf->wep_rekeying_period < 0) {
+			bss->wep_rekeying_period = atoi(pos);
+			if (bss->wep_rekeying_period < 0) {
 				printf("Line %d: invalid period %d\n",
-				       line, conf->wep_rekeying_period);
+				       line, bss->wep_rekeying_period);
 				errors++;
 			}
 		} else if (strcmp(buf, "eap_reauth_period") == 0) {
-			conf->eap_reauth_period = atoi(pos);
-			if (conf->eap_reauth_period < 0) {
+			bss->eap_reauth_period = atoi(pos);
+			if (bss->eap_reauth_period < 0) {
 				printf("Line %d: invalid period %d\n",
-				       line, conf->eap_reauth_period);
+				       line, bss->eap_reauth_period);
 				errors++;
 			}
 		} else if (strcmp(buf, "eapol_key_index_workaround") == 0) {
-			conf->eapol_key_index_workaround = atoi(pos);
-		} else if (strcmp(buf, "eapol_version") == 0) {
-			conf->eapol_version = atoi(pos);
-			if (conf->eapol_version < 1 ||
-			    conf->eapol_version > 2) {
-				printf("Line %d: invalid EAPOL "
-				       "version (%d): '%s'.\n",
-				       line, conf->eapol_version, pos);
-				errors++;
-			} else
-				wpa_printf(MSG_DEBUG, "eapol_version=%d",
-				   conf->eapol_version);
+			bss->eapol_key_index_workaround = atoi(pos);
 #ifdef CONFIG_IAPP
 		} else if (strcmp(buf, "iapp_interface") == 0) {
-			conf->ieee802_11f = 1;
-			snprintf(conf->iapp_iface, sizeof(conf->iapp_iface),
+			bss->ieee802_11f = 1;
+			snprintf(bss->iapp_iface, sizeof(bss->iapp_iface),
 				 "%s", pos);
 #endif /* CONFIG_IAPP */
 		} else if (strcmp(buf, "own_ip_addr") == 0) {
-			if (hostapd_parse_ip_addr(pos, &conf->own_ip_addr)) {
+			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
 				printf("Line %d: invalid IP address '%s'\n",
 				       line, pos);
 				errors++;
 			}
 		} else if (strcmp(buf, "nas_identifier") == 0) {
-			conf->nas_identifier = strdup(pos);
+			bss->nas_identifier = strdup(pos);
 		} else if (strcmp(buf, "auth_server_addr") == 0) {
 			if (hostapd_config_read_radius_addr(
-				    &conf->radius->auth_servers,
-				    &conf->radius->num_auth_servers, pos, 1812,
-				    &conf->radius->auth_server)) {
+				    &bss->radius->auth_servers,
+				    &bss->radius->num_auth_servers, pos, 1812,
+				    &bss->radius->auth_server)) {
 				printf("Line %d: invalid IP address '%s'\n",
 				       line, pos);
 				errors++;
 			}
-		} else if (conf->radius->auth_server &&
+		} else if (bss->radius->auth_server &&
 			   strcmp(buf, "auth_server_port") == 0) {
-			conf->radius->auth_server->port = atoi(pos);
-		} else if (conf->radius->auth_server &&
+			bss->radius->auth_server->port = atoi(pos);
+		} else if (bss->radius->auth_server &&
 			   strcmp(buf, "auth_server_shared_secret") == 0) {
 			int len = strlen(pos);
 			if (len == 0) {
@@ -903,22 +1413,22 @@
 				       "allowed.\n", line);
 				errors++;
 			}
-			conf->radius->auth_server->shared_secret =
+			bss->radius->auth_server->shared_secret =
 				(u8 *) strdup(pos);
-			conf->radius->auth_server->shared_secret_len = len;
+			bss->radius->auth_server->shared_secret_len = len;
 		} else if (strcmp(buf, "acct_server_addr") == 0) {
 			if (hostapd_config_read_radius_addr(
-				    &conf->radius->acct_servers,
-				    &conf->radius->num_acct_servers, pos, 1813,
-				    &conf->radius->acct_server)) {
+				    &bss->radius->acct_servers,
+				    &bss->radius->num_acct_servers, pos, 1813,
+				    &bss->radius->acct_server)) {
 				printf("Line %d: invalid IP address '%s'\n",
 				       line, pos);
 				errors++;
 			}
-		} else if (conf->radius->acct_server &&
+		} else if (bss->radius->acct_server &&
 			   strcmp(buf, "acct_server_port") == 0) {
-			conf->radius->acct_server->port = atoi(pos);
-		} else if (conf->radius->acct_server &&
+			bss->radius->acct_server->port = atoi(pos);
+		} else if (bss->radius->acct_server &&
 			   strcmp(buf, "acct_server_shared_secret") == 0) {
 			int len = strlen(pos);
 			if (len == 0) {
@@ -927,29 +1437,38 @@
 				       "allowed.\n", line);
 				errors++;
 			}
-			conf->radius->acct_server->shared_secret =
+			bss->radius->acct_server->shared_secret =
 				(u8 *) strdup(pos);
-			conf->radius->acct_server->shared_secret_len = len;
+			bss->radius->acct_server->shared_secret_len = len;
 		} else if (strcmp(buf, "radius_retry_primary_interval") == 0) {
-			conf->radius->retry_primary_interval = atoi(pos);
+			bss->radius->retry_primary_interval = atoi(pos);
 		} else if (strcmp(buf, "radius_acct_interim_interval") == 0) {
-			conf->radius->acct_interim_interval = atoi(pos);
+			bss->radius->acct_interim_interval = atoi(pos);
 		} else if (strcmp(buf, "auth_algs") == 0) {
-			conf->auth_algs = atoi(pos);
-			if (conf->auth_algs == 0) {
+			bss->auth_algs = atoi(pos);
+			if (bss->auth_algs == 0) {
 				printf("Line %d: no authentication algorithms "
 				       "allowed\n",
 				       line);
 				errors++;
 			}
+		} else if (strcmp(buf, "max_num_sta") == 0) {
+			bss->max_num_sta = atoi(pos);
+			if (bss->max_num_sta < 0 ||
+			    bss->max_num_sta > MAX_STA_COUNT) {
+				printf("Line %d: Invalid max_num_sta=%d; "
+				       "allowed range 0..%d\n", line,
+				       bss->max_num_sta, MAX_STA_COUNT);
+				errors++;
+			}
 		} else if (strcmp(buf, "wpa") == 0) {
-			conf->wpa = atoi(pos);
+			bss->wpa = atoi(pos);
 		} else if (strcmp(buf, "wpa_group_rekey") == 0) {
-			conf->wpa_group_rekey = atoi(pos);
+			bss->wpa_group_rekey = atoi(pos);
 		} else if (strcmp(buf, "wpa_strict_rekey") == 0) {
-			conf->wpa_strict_rekey = atoi(pos);
+			bss->wpa_strict_rekey = atoi(pos);
 		} else if (strcmp(buf, "wpa_gmk_rekey") == 0) {
-			conf->wpa_gmk_rekey = atoi(pos);
+			bss->wpa_gmk_rekey = atoi(pos);
 		} else if (strcmp(buf, "wpa_passphrase") == 0) {
 			int len = strlen(pos);
 			if (len < 8 || len > 63) {
@@ -957,106 +1476,253 @@
 				       " %d (expected 8..63)\n", line, len);
 				errors++;
 			} else {
-				free(conf->wpa_passphrase);
-				conf->wpa_passphrase = strdup(pos);
+				free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = strdup(pos);
 			}
 		} else if (strcmp(buf, "wpa_psk") == 0) {
-			free(conf->wpa_psk);
-			conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
-			if (conf->wpa_psk) {
-				memset(conf->wpa_psk, 0,
-				       sizeof(struct hostapd_wpa_psk));
-			}
-			if (conf->wpa_psk == NULL)
-				errors++;
-			else if (hexstr2bin(pos, conf->wpa_psk->psk, PMK_LEN)
-				 || pos[PMK_LEN * 2] != '\0') {
+			free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk =
+				wpa_zalloc(sizeof(struct hostapd_wpa_psk));
+			if (bss->ssid.wpa_psk == NULL)
+				errors++;
+			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+					    PMK_LEN) ||
+				 pos[PMK_LEN * 2] != '\0') {
 				printf("Line %d: Invalid PSK '%s'.\n", line,
 				       pos);
 				errors++;
 			} else {
-				conf->wpa_psk->group = 1;
+				bss->ssid.wpa_psk->group = 1;
 			}
 		} else if (strcmp(buf, "wpa_psk_file") == 0) {
-			free(conf->wpa_psk_file);
-			conf->wpa_psk_file = strdup(pos);
-			if (!conf->wpa_psk_file) {
+			free(bss->ssid.wpa_psk_file);
+			bss->ssid.wpa_psk_file = strdup(pos);
+			if (!bss->ssid.wpa_psk_file) {
 				printf("Line %d: allocation failed\n", line);
 				errors++;
 			}
 		} else if (strcmp(buf, "wpa_key_mgmt") == 0) {
-			conf->wpa_key_mgmt =
+			bss->wpa_key_mgmt =
 				hostapd_config_parse_key_mgmt(line, pos);
-			if (conf->wpa_key_mgmt == -1)
+			if (bss->wpa_key_mgmt == -1)
 				errors++;
 		} else if (strcmp(buf, "wpa_pairwise") == 0) {
-			conf->wpa_pairwise =
+			bss->wpa_pairwise =
 				hostapd_config_parse_cipher(line, pos);
-			if (conf->wpa_pairwise == -1 ||
-			    conf->wpa_pairwise == 0)
+			if (bss->wpa_pairwise == -1 ||
+			    bss->wpa_pairwise == 0)
 				errors++;
-			else if (conf->wpa_pairwise &
+			else if (bss->wpa_pairwise &
 				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
 				  WPA_CIPHER_WEP104)) {
 				printf("Line %d: unsupported pairwise "
 				       "cipher suite '%s'\n",
-				       conf->wpa_pairwise, pos);
+				       bss->wpa_pairwise, pos);
 				errors++;
 			} else {
-				if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
-					conf->wpa_group = WPA_CIPHER_TKIP;
+				if (bss->wpa_pairwise & WPA_CIPHER_TKIP)
+					bss->wpa_group = WPA_CIPHER_TKIP;
 				else
-					conf->wpa_group = WPA_CIPHER_CCMP;
+					bss->wpa_group = WPA_CIPHER_CCMP;
 			}
 #ifdef CONFIG_RSN_PREAUTH
 		} else if (strcmp(buf, "rsn_preauth") == 0) {
-			conf->rsn_preauth = atoi(pos);
+			bss->rsn_preauth = atoi(pos);
 		} else if (strcmp(buf, "rsn_preauth_interfaces") == 0) {
-			conf->rsn_preauth_interfaces = strdup(pos);
+			bss->rsn_preauth_interfaces = strdup(pos);
 #endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+		} else if (strcmp(buf, "peerkey") == 0) {
+			bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
 		} else if (strcmp(buf, "ctrl_interface") == 0) {
-			free(conf->ctrl_interface);
-			conf->ctrl_interface = strdup(pos);
+			free(bss->ctrl_interface);
+			bss->ctrl_interface = strdup(pos);
 		} else if (strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
 			struct group *grp;
 			char *endp;
 			const char *group = pos;
 
 			grp = getgrnam(group);
 			if (grp) {
-				conf->ctrl_interface_gid = grp->gr_gid;
-				conf->ctrl_interface_gid_set = 1;
+				bss->ctrl_interface_gid = grp->gr_gid;
+				bss->ctrl_interface_gid_set = 1;
 				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
 					   " (from group name '%s')",
-					   conf->ctrl_interface_gid, group);
+					   bss->ctrl_interface_gid, group);
 				continue;
 			}
 
 			/* Group name not found - try to parse this as gid */
-			conf->ctrl_interface_gid = strtol(group, &endp, 10);
+			bss->ctrl_interface_gid = strtol(group, &endp, 10);
 			if (*group == '\0' || *endp != '\0') {
 				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
 					   "'%s'", line, group);
 				errors++;
 				continue;
 			}
-			conf->ctrl_interface_gid_set = 1;
+			bss->ctrl_interface_gid_set = 1;
 			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
-				   conf->ctrl_interface_gid);
+				   bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
 #ifdef RADIUS_SERVER
 		} else if (strcmp(buf, "radius_server_clients") == 0) {
-			free(conf->radius_server_clients);
-			conf->radius_server_clients = strdup(pos);
+			free(bss->radius_server_clients);
+			bss->radius_server_clients = strdup(pos);
 		} else if (strcmp(buf, "radius_server_auth_port") == 0) {
-			conf->radius_server_auth_port = atoi(pos);
+			bss->radius_server_auth_port = atoi(pos);
 		} else if (strcmp(buf, "radius_server_ipv6") == 0) {
-			conf->radius_server_ipv6 = atoi(pos);
+			bss->radius_server_ipv6 = atoi(pos);
 #endif /* RADIUS_SERVER */
 		} else if (strcmp(buf, "test_socket") == 0) {
-			free(conf->test_socket);
-			conf->test_socket = strdup(pos);
+			free(bss->test_socket);
+			bss->test_socket = strdup(pos);
 		} else if (strcmp(buf, "use_pae_group_addr") == 0) {
-			conf->use_pae_group_addr = atoi(pos);
+			bss->use_pae_group_addr = atoi(pos);
+		} else if (strcmp(buf, "hw_mode") == 0) {
+			if (strcmp(pos, "a") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+			else if (strcmp(pos, "b") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+			else if (strcmp(pos, "g") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+			else {
+				printf("Line %d: unknown hw_mode '%s'\n",
+				       line, pos);
+				errors++;
+			}
+		} else if (strcmp(buf, "channel") == 0) {
+			conf->channel = atoi(pos);
+		} else if (strcmp(buf, "beacon_int") == 0) {
+			int val = atoi(pos);
+			/* MIB defines range as 1..65535, but very small values
+			 * cause problems with the current implementation.
+			 * Since it is unlikely that this small numbers are
+			 * useful in real life scenarios, do not allow beacon
+			 * period to be set below 15 TU. */
+			if (val < 15 || val > 65535) {
+				printf("Line %d: invalid beacon_int %d "
+				       "(expected 15..65535)\n",
+				       line, val);
+				errors++;
+			} else
+				conf->beacon_int = val;
+		} else if (strcmp(buf, "dtim_period") == 0) {
+			bss->dtim_period = atoi(pos);
+			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+				printf("Line %d: invalid dtim_period %d\n",
+				       line, bss->dtim_period);
+				errors++;
+			}
+		} else if (strcmp(buf, "rts_threshold") == 0) {
+			conf->rts_threshold = atoi(pos);
+			if (conf->rts_threshold < 0 ||
+			    conf->rts_threshold > 2347) {
+				printf("Line %d: invalid rts_threshold %d\n",
+				       line, conf->rts_threshold);
+				errors++;
+			}
+		} else if (strcmp(buf, "fragm_threshold") == 0) {
+			conf->fragm_threshold = atoi(pos);
+			if (conf->fragm_threshold < 256 ||
+			    conf->fragm_threshold > 2346) {
+				printf("Line %d: invalid fragm_threshold %d\n",
+				       line, conf->fragm_threshold);
+				errors++;
+			}
+		} else if (strcmp(buf, "send_probe_response") == 0) {
+			int val = atoi(pos);
+			if (val != 0 && val != 1) {
+				printf("Line %d: invalid send_probe_response "
+				       "%d (expected 0 or 1)\n", line, val);
+			} else
+				conf->send_probe_response = val;
+		} else if (strcmp(buf, "supported_rates") == 0) {
+			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+				printf("Line %d: invalid rate list\n", line);
+				errors++;
+			}
+		} else if (strcmp(buf, "basic_rates") == 0) {
+			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+				printf("Line %d: invalid rate list\n", line);
+				errors++;
+			}
+		} else if (strcmp(buf, "ignore_broadcast_ssid") == 0) {
+			bss->ignore_broadcast_ssid = atoi(pos);
+		} else if (strcmp(buf, "bridge_packets") == 0) {
+			conf->bridge_packets = atoi(pos);
+		} else if (strcmp(buf, "wep_default_key") == 0) {
+			bss->ssid.wep.idx = atoi(pos);
+			if (bss->ssid.wep.idx > 3) {
+				printf("Invalid wep_default_key index %d\n",
+				       bss->ssid.wep.idx);
+				errors++;
+			}
+		} else if (strcmp(buf, "wep_key0") == 0 ||
+			   strcmp(buf, "wep_key1") == 0 ||
+			   strcmp(buf, "wep_key2") == 0 ||
+			   strcmp(buf, "wep_key3") == 0) {
+			if (hostapd_config_read_wep(&bss->ssid.wep,
+						    buf[7] - '0', pos)) {
+				printf("Line %d: invalid WEP key '%s'\n",
+				       line, buf);
+				errors++;
+			}
+		} else if (strcmp(buf, "dynamic_vlan") == 0) {
+			bss->ssid.dynamic_vlan = atoi(pos);
+		} else if (strcmp(buf, "vlan_file") == 0) {
+			if (hostapd_config_read_vlan_file(bss, pos)) {
+				printf("Line %d: failed to read VLAN file "
+				       "'%s'\n", line, pos);
+				errors++;
+			}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		} else if (strcmp(buf, "vlan_tagged_interface") == 0) {
+			bss->ssid.vlan_tagged_interface = strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+		} else if (strcmp(buf, "passive_scan_interval") == 0) {
+			conf->passive_scan_interval = atoi(pos);
+		} else if (strcmp(buf, "passive_scan_listen") == 0) {
+			conf->passive_scan_listen = atoi(pos);
+		} else if (strcmp(buf, "passive_scan_mode") == 0) {
+			conf->passive_scan_mode = atoi(pos);
+		} else if (strcmp(buf, "ap_table_max_size") == 0) {
+			conf->ap_table_max_size = atoi(pos);
+		} else if (strcmp(buf, "ap_table_expiration_time") == 0) {
+			conf->ap_table_expiration_time = atoi(pos);
+		} else if (strncmp(buf, "tx_queue_", 9) == 0) {
+			if (hostapd_config_tx_queue(conf, buf, pos)) {
+				printf("Line %d: invalid TX queue item\n",
+				       line);
+				errors++;
+			}
+		} else if (strcmp(buf, "wme_enabled") == 0) {
+			bss->wme_enabled = atoi(pos);
+		} else if (strncmp(buf, "wme_ac_", 7) == 0) {
+			if (hostapd_config_wme_ac(conf, buf, pos)) {
+				printf("Line %d: invalid wme ac item\n",
+				       line);
+				errors++;
+			}
+		} else if (strcmp(buf, "bss") == 0) {
+			if (hostapd_config_bss(conf, pos)) {
+				printf("Line %d: invalid bss item\n", line);
+				errors++;
+			}
+		} else if (strcmp(buf, "bssid") == 0) {
+			if (bss == conf->bss) {
+				printf("Line %d: bssid item not allowed "
+				       "for the default interface\n", line);
+				errors++;
+			} else if (hwaddr_aton(pos, bss->bssid)) {
+				printf("Line %d: invalid bssid item\n", line);
+				errors++;
+			}
+#ifdef CONFIG_IEEE80211W
+		} else if (strcmp(buf, "ieee80211w") == 0) {
+			bss->ieee80211w = atoi(pos);
+#endif /* CONFIG_IEEE80211W */
 		} else {
 			printf("Line %d: unknown configuration item '%s'\n",
 			       line, buf);
@@ -1066,23 +1732,30 @@
 
 	fclose(f);
 
-	if (hostapd_config_read_maclist(accept_mac_file, &conf->accept_mac,
-					&conf->num_accept_mac))
-		errors++;
-	free(accept_mac_file);
-	if (hostapd_config_read_maclist(deny_mac_file, &conf->deny_mac,
-					&conf->num_deny_mac))
-		errors++;
-	free(deny_mac_file);
-
-#ifdef EAP_SERVER
-	if (hostapd_config_read_eap_user(eap_user_file, conf))
-		errors++;
-	free(eap_user_file);
-#endif /* EAP_SERVER */
-
-	conf->radius->auth_server = conf->radius->auth_servers;
-	conf->radius->acct_server = conf->radius->acct_servers;
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for broadcast
+		 * keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		bss = &conf->bss[i];
+
+		bss->radius->auth_server = bss->radius->auth_servers;
+		bss->radius->acct_server = bss->radius->acct_servers;
+
+		if (bss->wpa && bss->ieee802_1x) {
+			bss->ssid.security_policy = SECURITY_WPA;
+		} else if (bss->wpa) {
+			bss->ssid.security_policy = SECURITY_WPA_PSK;
+		} else if (bss->ieee802_1x) {
+			bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+			bss->ssid.wep.default_len = bss->default_wep_key_len;
+		} else if (bss->ssid.wep.keys_set)
+			bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		else
+			bss->ssid.security_policy = SECURITY_PLAINTEXT;
+	}
 
 	if (hostapd_config_check(conf))
 		errors++;
@@ -1098,6 +1771,20 @@
 }
 
 
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
+{
+	int i;
+
+	if (a->idx != b->idx || a->default_len != b->default_len)
+		return 1;
+	for (i = 0; i < NUM_WEP_KEYS; i++)
+		if (a->len[i] != b->len[i] ||
+		    memcmp(a->key[i], b->key[i], a->len[i]) != 0)
+			return 1;
+	return 0;
+}
+
+
 static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
 				       int num_servers)
 {
@@ -1118,7 +1805,17 @@
 }
 
 
-void hostapd_config_free(struct hostapd_config *conf)
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+	int i;
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		free(keys->key[i]);
+		keys->key[i] = NULL;
+	}
+}
+
+
+static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 {
 	struct hostapd_wpa_psk *psk, *prev;
 	struct hostapd_eap_user *user, *prev_user;
@@ -1126,15 +1823,18 @@
 	if (conf == NULL)
 		return;
 
-	psk = conf->wpa_psk;
+	psk = conf->ssid.wpa_psk;
 	while (psk) {
 		prev = psk;
 		psk = psk->next;
 		free(prev);
 	}
 
-	free(conf->wpa_passphrase);
-	free(conf->wpa_psk_file);
+	free(conf->ssid.wpa_passphrase);
+	free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
 
 	user = conf->eap_user;
 	while (user) {
@@ -1161,13 +1861,41 @@
 	free(conf->eap_sim_db);
 	free(conf->radius_server_clients);
 	free(conf->test_socket);
+	free(conf->radius);
+	hostapd_config_free_vlan(conf);
+	if (conf->ssid.dyn_vlan_keys) {
+		struct hostapd_ssid *ssid = &conf->ssid;
+		size_t i;
+		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+			if (ssid->dyn_vlan_keys[i] == NULL)
+				continue;
+			hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
+			free(ssid->dyn_vlan_keys[i]);
+		}
+		free(ssid->dyn_vlan_keys);
+		ssid->dyn_vlan_keys = NULL;
+	}
+}
+
+
+void hostapd_config_free(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf == NULL)
+		return;
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_config_free_bss(&conf->bss[i]);
+	free(conf->bss);
+
 	free(conf);
 }
 
 
 /* Perform a binary search for given MAC address from a pre-sorted list.
  * Returns 1 if address is in the list or 0 if not. */
-int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr)
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr)
 {
 	int start, end, middle, res;
 
@@ -1189,13 +1917,40 @@
 }
 
 
-const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
-			   const u8 *prev_psk)
+int hostapd_rate_found(int *list, int rate)
+{
+	int i;
+
+	if (list == NULL)
+		return 0;
+
+	for (i = 0; list[i] >= 0; i++)
+		if (list[i] == rate)
+			return 1;
+
+	return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+	struct hostapd_vlan *v = vlan;
+	while (v) {
+		if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+			return v->ifname;
+		v = v->next;
+	}
+	return NULL;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk)
 {
 	struct hostapd_wpa_psk *psk;
 	int next_ok = prev_psk == NULL;
 
-	for (psk = conf->wpa_psk; psk != NULL; psk = psk->next) {
+	for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
 		if (next_ok &&
 		    (psk->group || memcmp(psk->addr, addr, ETH_ALEN) == 0))
 			return psk->psk;
@@ -1209,7 +1964,7 @@
 
 
 const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
 		     size_t identity_len, int phase2)
 {
 	struct hostapd_eap_user *user = conf->eap_user;
@@ -1219,6 +1974,15 @@
 			/* Wildcard match */
 			break;
 		}
+
+		if (!phase2 && user->wildcard_prefix &&
+		    identity_len >= user->identity_len &&
+		    memcmp(user->identity, identity, user->identity_len) == 0)
+		{
+			/* Wildcard prefix match */
+			break;
+		}
+
 		if (user->phase2 == !!phase2 &&
 		    user->identity_len == identity_len &&
 		    memcmp(user->identity, identity, identity_len) == 0)
--- /dev/null
+++ contrib/hostapd/reconfig.c
@@ -0,0 +1,714 @@
+/*
+ * hostapd / Configuration reloading
+ * Copyright (c) 2002-2007, Jouni Malinen <j at w1.fi>
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * 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 "hostapd.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "sta_info.h"
+#include "radius_client.h"
+#include "ieee802_11.h"
+#include "iapp.h"
+#include "ap_list.h"
+#include "wpa.h"
+#include "vlan_init.h"
+#include "ieee802_11_auth.h"
+#include "ieee802_1x.h"
+#include "accounting.h"
+#include "eloop.h"
+
+
+/**
+ * struct hostapd_config_change - Configuration change information
+ * This is for two purposes:
+ * - Storing configuration information in the hostapd_iface during
+ *   the asynchronous parts of reconfiguration.
+ * - Passing configuration information for per-station reconfiguration.
+ */
+struct hostapd_config_change {
+	struct hostapd_data *hapd;
+	struct hostapd_config *newconf, *oldconf;
+	struct hostapd_bss_config *newbss, *oldbss;
+	int mac_acl_changed;
+	int num_sta_remove; /* number of STAs that need to be removed */
+	int beacon_changed;
+	struct hostapd_iface *hapd_iface;
+	struct hostapd_data **new_hapd, **old_hapd;
+	int num_old_hapd;
+};
+
+
+static int hostapd_config_reload_sta(struct hostapd_data *hapd,
+				     struct sta_info *sta, void *data)
+{
+	struct hostapd_config_change *change = data;
+	struct hostapd_bss_config *newbss, *oldbss;
+	int deauth = 0;
+	u8 reason = WLAN_REASON_PREV_AUTH_NOT_VALID;
+
+	newbss = change->newbss;
+	oldbss = change->oldbss;
+	hapd = change->hapd;
+
+	if (sta->ssid == &oldbss->ssid) {
+		sta->ssid = &newbss->ssid;
+
+		if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
+		    memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
+			   newbss->ssid.ssid_len) != 0) {
+			/* main SSID was changed - kick STA out */
+			deauth++;
+		}
+	}
+	sta->ssid_probe = sta->ssid;
+
+	/*
+	 * If MAC ACL configuration has changed, deauthenticate stations that
+	 * have been removed from accepted list or have been added to denied
+	 * list. If external RADIUS server is used for ACL, all stations are
+	 * deauthenticated and they will need to authenticate again. This
+	 * limits sudden load on the RADIUS server since the verification will
+	 * be done over the time needed for the STAs to reauthenticate
+	 * themselves.
+	 */
+	if (change->mac_acl_changed &&
+	    (newbss->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH ||
+	     !hostapd_allowed_address(hapd, sta->addr, NULL, 0, NULL, NULL,
+				      NULL)))
+		deauth++;
+
+	if (newbss->ieee802_1x != oldbss->ieee802_1x &&
+	    sta->ssid == &hapd->conf->ssid)
+		deauth++;
+
+	if (newbss->wpa != oldbss->wpa)
+		deauth++;
+
+	if (!newbss->wme_enabled && (sta->flags & WLAN_STA_WME))
+		deauth++;
+
+	if (newbss->auth_algs != oldbss->auth_algs &&
+	    ((sta->auth_alg == WLAN_AUTH_OPEN &&
+	      !(newbss->auth_algs & HOSTAPD_AUTH_OPEN)) ||
+	     (sta->auth_alg == WLAN_AUTH_SHARED_KEY &&
+	      !(newbss->auth_algs & HOSTAPD_AUTH_SHARED_KEY))))
+		deauth++;
+
+	if (change->num_sta_remove > 0) {
+		deauth++;
+		reason = WLAN_REASON_DISASSOC_AP_BUSY;
+	}
+
+	if (deauth) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "STA " MACSTR
+			      " deauthenticated during config reloading "
+			      "(reason=%d)\n", MAC2STR(sta->addr), reason);
+		ieee802_11_send_deauth(hapd, sta->addr, reason);
+		ap_sta_deauthenticate(hapd, sta, reason);
+		change->num_sta_remove--;
+	}
+
+	return 0;
+}
+
+
+static void hostapd_reconfig_tx_queue_params(struct hostapd_data *hapd,
+					     struct hostapd_config *newconf,
+					     struct hostapd_config *oldconf)
+{
+	int i;
+	struct hostapd_tx_queue_params *o, *n;
+
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
+		o = &oldconf->tx_queue[i];
+		n = &newconf->tx_queue[i];
+
+		if (!n->configured)
+			continue;
+
+		if ((n->aifs != o->aifs || n->cwmin != o->cwmin ||
+		     n->cwmax != o->cwmax || n->burst != o->burst) &&
+		    hostapd_set_tx_queue_params(hapd, i, n->aifs, n->cwmin,
+						n->cwmax, n->burst))
+			printf("Failed to set TX queue parameters for queue %d"
+			       ".\n", i);
+	}
+}
+
+
+static int hostapd_reconfig_wme(struct hostapd_data *hapd,
+				struct hostapd_config *newconf,
+				struct hostapd_config *oldconf)
+{
+	int beacon_changed = 0;
+	size_t i;
+	struct hostapd_wme_ac_params *o, *n;
+
+	for (i = 0; i < sizeof(newconf->wme_ac_params) /
+			sizeof(newconf->wme_ac_params[0]); i++) {
+		o = &oldconf->wme_ac_params[i];
+		n = &newconf->wme_ac_params[i];
+		if (n->cwmin != o->cwmin ||
+		    n->cwmax != o->cwmax ||
+		    n->aifs != o->aifs ||
+		    n->txopLimit != o->txopLimit ||
+		    n->admission_control_mandatory !=
+		    o->admission_control_mandatory) {
+			beacon_changed++;
+			hapd->parameter_set_count++;
+		}
+	}
+
+	return beacon_changed;
+}
+
+
+static int rate_array_diff(int *a1, int *a2)
+{
+	int i;
+
+	if (a1 == NULL && a2 == NULL)
+		return 0;
+	if (a1 == NULL || a2 == NULL)
+		return 1;
+
+	i = 0;
+	for (;;) {
+		if (a1[i] != a2[i])
+			return 1;
+		if (a1[i] == -1)
+			break;
+		i++;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_acl_diff(struct hostapd_bss_config *a,
+			    struct hostapd_bss_config *b)
+{
+	int i;
+
+	if (a->macaddr_acl != b->macaddr_acl ||
+	    a->num_accept_mac != b->num_accept_mac ||
+	    a->num_deny_mac != b->num_deny_mac)
+		return 1;
+
+	for (i = 0; i < a->num_accept_mac; i++) {
+		if (memcmp(a->accept_mac[i], b->accept_mac[i], ETH_ALEN) != 0)
+			return 1;
+	}
+
+	for (i = 0; i < a->num_deny_mac; i++) {
+		if (memcmp(a->deny_mac[i], b->deny_mac[i], ETH_ALEN) != 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * reload_iface2 - Part 2 of reload_iface
+ * @hapd_iface: Pointer to hostapd interface data.
+ */
+static void reload_iface2(struct hostapd_iface *hapd_iface)
+{
+	struct hostapd_data *hapd = hapd_iface->bss[0];
+	struct hostapd_config *newconf = hapd_iface->change->newconf;
+	struct hostapd_config *oldconf = hapd_iface->change->oldconf;
+	int beacon_changed = hapd_iface->change->beacon_changed;
+	hostapd_iface_cb cb = hapd_iface->reload_iface_cb;
+
+	if (newconf->preamble != oldconf->preamble) {
+		if (hostapd_set_preamble(hapd, hapd->iconf->preamble))
+			printf("Could not set preamble for kernel driver\n");
+		beacon_changed++;
+	}
+
+	if (newconf->beacon_int != oldconf->beacon_int) {
+		/* Need to change beacon interval if it has changed or if
+		 * auto channel selection was used. */
+		if (hostapd_set_beacon_int(hapd, newconf->beacon_int))
+			printf("Could not set beacon interval for kernel "
+			       "driver\n");
+		if (newconf->beacon_int != oldconf->beacon_int)
+			beacon_changed++;
+	}
+
+	if (newconf->cts_protection_type != oldconf->cts_protection_type)
+		beacon_changed++;
+
+	if (newconf->rts_threshold > -1 &&
+	    newconf->rts_threshold != oldconf->rts_threshold &&
+	    hostapd_set_rts(hapd, newconf->rts_threshold))
+		printf("Could not set RTS threshold for kernel driver\n");
+
+	if (newconf->fragm_threshold > -1 &&
+	    newconf->fragm_threshold != oldconf->fragm_threshold &&
+	    hostapd_set_frag(hapd, newconf->fragm_threshold))
+		printf("Could not set fragmentation threshold for kernel "
+		       "driver\n");
+
+	hostapd_reconfig_tx_queue_params(hapd, newconf, oldconf);
+
+	if (hostapd_reconfig_wme(hapd, newconf, oldconf) > 0)
+		beacon_changed++;
+
+	ap_list_reconfig(hapd_iface, oldconf);
+
+	hapd_iface->change->beacon_changed = beacon_changed;
+
+	hapd_iface->reload_iface_cb = NULL;
+	cb(hapd_iface, 0);
+}
+
+
+/**
+ * reload_iface2_handler - Handler that calls reload_face2
+ * @eloop_data: Stores the struct hostapd_iface for the interface.
+ * @user_ctx: Unused.
+ */
+static void reload_iface2_handler(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *hapd_iface = eloop_data;
+
+	reload_iface2(hapd_iface);
+}
+
+
+/**
+ * reload_hw_mode_done - Callback for after the HW mode is setup
+ * @hapd_iface: Pointer to interface data.
+ * @status: Status of the HW mode setup.
+ */
+static void reload_hw_mode_done(struct hostapd_iface *hapd_iface, int status)
+{
+	struct hostapd_data *hapd = hapd_iface->bss[0];
+	struct hostapd_config_change *change = hapd_iface->change;
+	struct hostapd_config *newconf = change->newconf;
+	hostapd_iface_cb cb;
+	int freq;
+
+	if (status) {
+		printf("Failed to select hw_mode.\n");
+
+		cb = hapd_iface->reload_iface_cb;
+		hapd_iface->reload_iface_cb = NULL;
+		cb(hapd_iface, -1);
+
+		return;
+	}
+
+	freq = hostapd_hw_get_freq(hapd, newconf->channel);
+	HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+		      "Mode: %s  Channel: %d  Frequency: %d MHz\n",
+		      hostapd_hw_mode_txt(newconf->hw_mode),
+		      newconf->channel, freq);
+
+	if (hostapd_set_freq(hapd, newconf->hw_mode, freq)) {
+		printf("Could not set channel %d (%d MHz) for kernel "
+		       "driver\n", newconf->channel, freq);
+	}
+
+	change->beacon_changed++;
+
+	reload_iface2(hapd_iface);
+}
+
+
+/**
+ * hostapd_config_reload_iface_start - Start interface reload
+ * @hapd_iface: Pointer to interface data.
+ * @cb: The function to callback when done.
+ * Returns:  0 if it starts successfully; cb will be called when done.
+ *          -1 on failure; cb will not be called.
+ */
+static int hostapd_config_reload_iface_start(struct hostapd_iface *hapd_iface,
+					     hostapd_iface_cb cb)
+{
+	struct hostapd_config_change *change = hapd_iface->change;
+	struct hostapd_config *newconf = change->newconf;
+	struct hostapd_config *oldconf = change->oldconf;
+	struct hostapd_data *hapd = hapd_iface->bss[0];
+
+	if (hapd_iface->reload_iface_cb) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: Interface reload already in progress.",
+			   hapd_iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	hapd_iface->reload_iface_cb = cb;
+
+	if (newconf->bridge_packets != oldconf->bridge_packets &&
+	    hapd->iconf->bridge_packets != INTERNAL_BRIDGE_DO_NOT_CONTROL &&
+	    hostapd_set_internal_bridge(hapd, hapd->iconf->bridge_packets))
+		printf("Failed to set bridge_packets for kernel driver\n");
+
+	if (newconf->channel != oldconf->channel ||
+	    newconf->hw_mode != oldconf->hw_mode ||
+	    rate_array_diff(newconf->supported_rates,
+			    oldconf->supported_rates) ||
+	    rate_array_diff(newconf->basic_rates, oldconf->basic_rates)) {
+		hostapd_free_stas(hapd);
+
+		if (hostapd_get_hw_features(hapd_iface)) {
+			printf("Could not read HW feature info from the kernel"
+			       " driver.\n");
+			hapd_iface->reload_iface_cb = NULL;
+			return -1;
+		}
+
+		if (hostapd_select_hw_mode_start(hapd_iface,
+						 reload_hw_mode_done)) {
+			printf("Failed to start select hw_mode.\n");
+			hapd_iface->reload_iface_cb = NULL;
+			return -1;
+		}
+
+		return 0;
+	}
+
+	eloop_register_timeout(0, 0, reload_iface2_handler, hapd_iface, NULL);
+	return 0;
+}
+
+
+static void hostapd_reconfig_bss(struct hostapd_data *hapd,
+				 struct hostapd_bss_config *newbss,
+				 struct hostapd_bss_config *oldbss,
+				 struct hostapd_config *oldconf,
+				 int beacon_changed)
+{
+	struct hostapd_config_change change;
+	int encr_changed = 0;
+	struct radius_client_data *old_radius;
+
+	radius_client_flush(hapd->radius, 0);
+
+	if (hostapd_set_dtim_period(hapd, newbss->dtim_period))
+		printf("Could not set DTIM period for kernel driver\n");
+
+	if (newbss->ssid.ssid_len != oldbss->ssid.ssid_len ||
+	    memcmp(newbss->ssid.ssid, oldbss->ssid.ssid,
+		   newbss->ssid.ssid_len) != 0) {
+		if (hostapd_set_ssid(hapd, (u8 *) newbss->ssid.ssid,
+				     newbss->ssid.ssid_len))
+			printf("Could not set SSID for kernel driver\n");
+		beacon_changed++;
+	}
+
+	if (newbss->ignore_broadcast_ssid != oldbss->ignore_broadcast_ssid)
+		beacon_changed++;
+
+	if (hostapd_wep_key_cmp(&newbss->ssid.wep, &oldbss->ssid.wep)) {
+		encr_changed++;
+		beacon_changed++;
+	}
+
+	vlan_reconfig(hapd, oldconf, oldbss);
+
+	if (beacon_changed) {
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Updating beacon frame "
+			      "information\n");
+		ieee802_11_set_beacon(hapd);
+	}
+
+	change.hapd = hapd;
+	change.oldconf = oldconf;
+	change.newconf = hapd->iconf;
+	change.oldbss = oldbss;
+	change.newbss = newbss;
+	change.mac_acl_changed = hostapd_acl_diff(newbss, oldbss);
+	if (newbss->max_num_sta != oldbss->max_num_sta &&
+	    newbss->max_num_sta < hapd->num_sta) {
+		change.num_sta_remove = hapd->num_sta - newbss->max_num_sta;
+	} else
+		change.num_sta_remove = 0;
+	ap_for_each_sta(hapd, hostapd_config_reload_sta, &change);
+
+	old_radius = hapd->radius;
+	hapd->radius = radius_client_reconfig(hapd->radius, hapd,
+					      oldbss->radius, newbss->radius);
+	hapd->radius_client_reconfigured = old_radius != hapd->radius ||
+		hostapd_ip_diff(&newbss->own_ip_addr, &oldbss->own_ip_addr);
+
+	ieee802_1x_reconfig(hapd, oldconf, oldbss);
+	iapp_reconfig(hapd, oldconf, oldbss);
+
+	hostapd_acl_reconfig(hapd, oldconf);
+	accounting_reconfig(hapd, oldconf);
+}
+
+
+/**
+ * config_reload2 - Part 2 of configuration reloading
+ * @hapd_iface:
+ */
+static void config_reload2(struct hostapd_iface *hapd_iface, int status)
+{
+	struct hostapd_config_change *change = hapd_iface->change;
+	struct hostapd_data *hapd = change->hapd;
+	struct hostapd_config *newconf = change->newconf;
+	struct hostapd_config *oldconf = change->oldconf;
+	int beacon_changed = change->beacon_changed;
+	struct hostapd_data **new_hapd = change->new_hapd;
+	struct hostapd_data **old_hapd = change->old_hapd;
+	int num_old_hapd = change->num_old_hapd;
+	size_t i, j, max_bss, same_bssid;
+	struct hostapd_bss_config *newbss, *oldbss;
+	u8 *prev_addr;
+	hostapd_iface_cb cb;
+
+	free(change);
+	hapd_iface->change = NULL;
+
+	if (status) {
+		printf("Failed to setup new interface config\n");
+
+		cb = hapd_iface->config_reload_cb;
+		hapd_iface->config_reload_cb = NULL;
+
+		/* Invalid configuration - cleanup and terminate hostapd */
+		hapd_iface->bss = old_hapd;
+		hapd_iface->num_bss = num_old_hapd;
+		hapd_iface->conf = hapd->iconf = oldconf;
+		hapd->conf = &oldconf->bss[0];
+		hostapd_config_free(newconf);
+		free(new_hapd);
+
+		cb(hapd_iface, -2);
+
+		return;
+	}
+
+	/*
+	 * If any BSSes have been removed, added, or had their BSSIDs changed,
+	 * completely remove and reinitialize such BSSes and all the BSSes
+	 * following them since their BSSID might have changed.
+	 */
+	max_bss = oldconf->num_bss;
+	if (max_bss > newconf->num_bss)
+		max_bss = newconf->num_bss;
+
+	for (i = 0; i < max_bss; i++) {
+		if (strcmp(oldconf->bss[i].iface, newconf->bss[i].iface) != 0
+		    || hostapd_mac_comp(oldconf->bss[i].bssid,
+					newconf->bss[i].bssid) != 0)
+			break;
+	}
+	same_bssid = i;
+
+	for (i = 0; i < oldconf->num_bss; i++) {
+		oldbss = &oldconf->bss[i];
+		newbss = NULL;
+		for (j = 0; j < newconf->num_bss; j++) {
+			if (strcmp(oldbss->iface, newconf->bss[j].iface) == 0)
+			{
+				newbss = &newconf->bss[j];
+				break;
+			}
+		}
+
+		if (newbss && i < same_bssid) {
+			hapd = hapd_iface->bss[j] = old_hapd[i];
+			hapd->iconf = newconf;
+			hapd->conf = newbss;
+			hostapd_reconfig_bss(hapd, newbss, oldbss, oldconf,
+					     beacon_changed);
+		} else {
+			hapd = old_hapd[i];
+			HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+				      "Removing BSS (ifname %s)\n",
+				      hapd->conf->iface);
+			hostapd_free_stas(hapd);
+			/* Send broadcast deauthentication for this BSS, but do
+			 * not clear all STAs from the driver since other BSSes
+			 * may have STA entries. The driver will remove all STA
+			 * entries for this BSS anyway when the interface is
+			 * being removed. */
+#if 0
+			hostapd_deauth_all_stas(hapd);
+			hostapd_cleanup(hapd);
+#endif
+
+			free(hapd);
+		}
+	}
+
+
+	prev_addr = hapd_iface->bss[0]->own_addr;
+	hapd = hapd_iface->bss[0];
+	for (j = 0; j < newconf->num_bss; j++) {
+		if (hapd_iface->bss[j] != NULL) {
+			prev_addr = hapd_iface->bss[j]->own_addr;
+			continue;
+		}
+
+		newbss = &newconf->bss[j];
+
+		HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Reconfiguration: adding "
+			      "new BSS (ifname=%s)\n", newbss->iface);
+
+#if 0
+		hapd = hapd_iface->bss[j] =
+			hostapd_alloc_bss_data(hapd_iface, newconf, newbss);
+#endif
+		if (hapd == NULL) {
+			printf("Failed to initialize new BSS\n");
+			/* FIX: This one is somewhat hard to recover
+			 * from.. Would need to remove this BSS from
+			 * conf and BSS list. */
+			exit(1);
+		}
+		hapd->driver = hapd_iface->bss[0]->driver;
+		hapd->iface = hapd_iface;
+		hapd->iconf = newconf;
+		hapd->conf = newbss;
+
+		memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+			prev_addr = hapd->own_addr;
+
+#if 0
+		if (hostapd_setup_bss(hapd, j == 0)) {
+			printf("Failed to setup new BSS\n");
+			/* FIX */
+			exit(1);
+		}
+#endif
+
+	}
+
+	free(old_hapd);
+	hostapd_config_free(oldconf);
+
+	cb = hapd_iface->config_reload_cb;
+	hapd_iface->config_reload_cb = NULL;
+
+	cb(hapd_iface, 0);
+}
+
+
+/**
+ * hostapd_config_reload_start - Start reconfiguration of an interface
+ * @hapd_iface: Pointer to hostapd interface data
+ * @cb: Function to be called back when done.
+ *      The status indicates:
+ *       0 = success, new configuration in use;
+ *      -1 = failed to update configuraiton, old configuration in use;
+ *      -2 = failed to update configuration and failed to recover; caller
+ *           should cleanup and terminate hostapd
+ * Returns:
+ *  0 = reconfiguration started;
+ * -1 = failed to update configuration, old configuration in use;
+ * -2 = failed to update configuration and failed to recover; caller
+ *      should cleanup and terminate hostapd
+ */
+int hostapd_config_reload_start(struct hostapd_iface *hapd_iface,
+				hostapd_iface_cb cb)
+{
+	struct hostapd_config *newconf, *oldconf;
+	struct hostapd_config_change *change;
+	struct hostapd_data *hapd = NULL;
+	struct hostapd_data **old_hapd, **new_hapd;
+	int num_old_hapd;
+
+	if (hapd_iface->config_reload_cb) {
+		wpa_printf(MSG_DEBUG, "%s: Config reload already in progress.",
+			   hapd_iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	newconf = hostapd_config_read(hapd_iface->config_fname);
+	if (newconf == NULL) {
+		printf("Failed to read new configuration file - continuing "
+		       "with old.\n");
+		return -1;
+	}
+
+	if (strcmp(newconf->bss[0].iface, hapd_iface->conf->bss[0].iface) !=
+	    0) {
+		printf("Interface name changing is not allowed in "
+		       "configuration reloading (%s -> %s).\n",
+		       hapd_iface->conf->bss[0].iface,  newconf->bss[0].iface);
+		hostapd_config_free(newconf);
+		return -1;
+	}
+
+	new_hapd = wpa_zalloc(newconf->num_bss *
+			      sizeof(struct hostapd_data *));
+	if (new_hapd == NULL) {
+		hostapd_config_free(newconf);
+		return -1;
+	}
+	old_hapd = hapd_iface->bss;
+	num_old_hapd = hapd_iface->num_bss;
+
+	hapd_iface->bss = new_hapd;
+	hapd_iface->num_bss = newconf->num_bss;
+	/*
+	 * First BSS remains the same since interface name changing was
+	 * prohibited above. Now, this is only used in
+	 * hostapd_config_reload_iface() and following loop will anyway set
+	 * this again.
+	 */
+	hapd = hapd_iface->bss[0] = old_hapd[0];
+
+	oldconf = hapd_iface->conf;
+	hapd->iconf = hapd_iface->conf = newconf;
+	hapd->conf = &newconf->bss[0];
+
+	change = wpa_zalloc(sizeof(struct hostapd_config_change));
+	if (change == NULL) {
+		hostapd_config_free(newconf);
+		return -1;
+	}
+
+	change->hapd = hapd;
+	change->newconf = newconf;
+	change->oldconf = oldconf;
+	change->beacon_changed = 0;
+	change->hapd_iface = hapd_iface;
+	change->new_hapd = new_hapd;
+	change->old_hapd = old_hapd;
+	change->num_old_hapd = num_old_hapd;
+
+	hapd_iface->config_reload_cb = cb;
+	hapd_iface->change = change;
+	if (hostapd_config_reload_iface_start(hapd_iface, config_reload2)) {
+		printf("Failed to start setup of new interface config\n");
+
+		hapd_iface->config_reload_cb = NULL;
+		free(change);
+		hapd_iface->change = NULL;
+
+		/* Invalid configuration - cleanup and terminate hostapd */
+		hapd_iface->bss = old_hapd;
+		hapd_iface->num_bss = num_old_hapd;
+		hapd_iface->conf = hapd->iconf = oldconf;
+		hapd->conf = &oldconf->bss[0];
+		hostapd_config_free(newconf);
+		free(new_hapd);
+		return -2;
+	}
+
+	return 0;
+}
Index: aes_wrap.h
===================================================================
RCS file: /home/cvs/src/contrib/hostapd/aes_wrap.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -L contrib/hostapd/aes_wrap.h -L contrib/hostapd/aes_wrap.h -u -r1.2 -r1.3
--- contrib/hostapd/aes_wrap.h
+++ contrib/hostapd/aes_wrap.h
@@ -7,7 +7,7 @@
  * - AES-128 EAX mode encryption/decryption
  * - AES-128 CBC
  *
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline at cc.hut.fi>
+ * Copyright (c) 2003-2005, 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
--- /dev/null
+++ contrib/hostapd/eap_aka.c
@@ -0,0 +1,848 @@
+/*
+ * hostapd / EAP-AKA (RFC 4187)
+ * Copyright (c) 2005-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 "hostapd.h"
+#include "common.h"
+#include "crypto.h"
+#include "eap_i.h"
+#include "eap_sim_common.h"
+#include "eap_sim_db.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_encr[EAP_SIM_K_ENCR_LEN];
+	u8 msk[EAP_SIM_KEYING_DATA_LEN];
+	u8 emsk[EAP_EMSK_LEN];
+	u8 rand[EAP_AKA_RAND_LEN];
+	u8 autn[EAP_AKA_AUTN_LEN];
+	u8 ck[EAP_AKA_CK_LEN];
+	u8 ik[EAP_AKA_IK_LEN];
+	u8 res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	enum {
+		IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
+	} state;
+	char *next_pseudonym;
+	char *next_reauth_id;
+	u16 counter;
+	struct eap_sim_reauth *reauth;
+	int auts_reported; /* whether the current AUTS has been reported to the
+			    * eap_sim_db */
+	u16 notification;
+};
+
+
+static void eap_aka_determine_identity(struct eap_sm *sm,
+				       struct eap_aka_data *data,
+				       int before_identity, int after_reauth);
+
+
+static const char * eap_aka_state_txt(int state)
+{
+	switch (state) {
+	case IDENTITY:
+		return "IDENTITY";
+	case CHALLENGE:
+		return "CHALLENGE";
+	case REAUTH:
+		return "REAUTH";
+	case SUCCESS:
+		return "SUCCESS";
+	case FAILURE:
+		return "FAILURE";
+	case NOTIFICATION:
+		return "NOTIFICATION";
+	default:
+		return "Unknown?!";
+	}
+}
+
+
+static void eap_aka_state(struct eap_aka_data *data, int state)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
+		   eap_aka_state_txt(data->state),
+		   eap_aka_state_txt(state));
+	data->state = state;
+}
+
+
+static void * eap_aka_init(struct eap_sm *sm)
+{
+	struct eap_aka_data *data;
+
+	if (sm->eap_sim_db_priv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
+		return NULL;
+	}
+
+	data = wpa_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->state = IDENTITY;
+	eap_aka_determine_identity(sm, data, 1, 0);
+
+	return data;
+}
+
+
+static void eap_aka_reset(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	free(data->next_pseudonym);
+	free(data->next_reauth_id);
+	free(data);
+}
+
+
+static u8 * eap_aka_build_identity(struct eap_sm *sm,
+				   struct eap_aka_data *data,
+				   int id, size_t *reqDataLen)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
+	msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+			       EAP_AKA_SUBTYPE_IDENTITY);
+	if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
+				      sm->identity_len)) {
+		wpa_printf(MSG_DEBUG, "   AT_PERMANENT_ID_REQ");
+		eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+	}
+	return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
+}
+
+
+static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
+			      struct eap_sim_msg *msg, u16 counter,
+			      const u8 *nonce_s)
+{
+	free(data->next_pseudonym);
+	data->next_pseudonym =
+		eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
+	free(data->next_reauth_id);
+	if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+		data->next_reauth_id =
+			eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
+			   "count exceeded - force full authentication");
+		data->next_reauth_id = NULL;
+	}
+
+	if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+	    counter == 0 && nonce_s == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "   AT_IV");
+	wpa_printf(MSG_DEBUG, "   AT_ENCR_DATA");
+	eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+	if (counter > 0) {
+		wpa_printf(MSG_DEBUG, "   *AT_COUNTER (%u)", counter);
+		eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+	}
+
+	if (nonce_s) {
+		wpa_printf(MSG_DEBUG, "   *AT_NONCE_S");
+		eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+				EAP_SIM_NONCE_S_LEN);
+	}
+
+	if (data->next_pseudonym) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_PSEUDONYM (%s)",
+			   data->next_pseudonym);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+				strlen(data->next_pseudonym),
+				(u8 *) data->next_pseudonym,
+				strlen(data->next_pseudonym));
+	}
+
+	if (data->next_reauth_id) {
+		wpa_printf(MSG_DEBUG, "   *AT_NEXT_REAUTH_ID (%s)",
+			   data->next_reauth_id);
+		eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+				strlen(data->next_reauth_id),
+				(u8 *) data->next_reauth_id,
+				strlen(data->next_reauth_id));
+	}
+
+	if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+			   "AT_ENCR_DATA");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static u8 * eap_aka_build_challenge(struct eap_sm *sm,
+				    struct eap_aka_data *data,
+				    int id, size_t *reqDataLen)
+{
+	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,
+			       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 (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
+static u8 * eap_aka_build_reauth(struct eap_sm *sm,
+				 struct eap_aka_data *data,
+				 int id, size_t *reqDataLen)
+{
+	struct eap_sim_msg *msg;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
+
+	if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+		return NULL;
+	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,
+			       EAP_AKA_SUBTYPE_REAUTHENTICATION);
+
+	if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+		eap_sim_msg_free(msg);
+		return NULL;
+	}
+
+	wpa_printf(MSG_DEBUG, "   AT_MAC");
+	eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+	return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
+static u8 * eap_aka_build_notification(struct eap_sm *sm,
+				       struct eap_aka_data *data,
+				       int id, size_t *reqDataLen)
+{
+	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,
+			       EAP_AKA_SUBTYPE_NOTIFICATION);
+	wpa_printf(MSG_DEBUG, "   AT_NOTIFICATION");
+	eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
+			NULL, 0);
+	return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_buildReq(struct eap_sm *sm, void *priv, int id,
+			     size_t *reqDataLen)
+{
+	struct eap_aka_data *data = priv;
+
+	data->auts_reported = 0;
+	switch (data->state) {
+	case IDENTITY:
+		return eap_aka_build_identity(sm, data, id, reqDataLen);
+	case CHALLENGE:
+		return eap_aka_build_challenge(sm, data, id, reqDataLen);
+	case REAUTH:
+		return eap_aka_build_reauth(sm, data, id, reqDataLen);
+	case NOTIFICATION:
+		return eap_aka_build_notification(sm, data, id, reqDataLen);
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+			   "buildReq", data->state);
+		break;
+	}
+	return NULL;
+}
+
+
+static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
+			     u8 *respData, size_t respDataLen)
+{
+	struct eap_hdr *resp;
+	u8 *pos;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_AKA ||
+	    (ntohs(resp->length)) > respDataLen) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
+{
+	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
+	    subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
+		return FALSE;
+
+	switch (data->state) {
+	case IDENTITY:
+		if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case CHALLENGE:
+		if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
+		    subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case REAUTH:
+		if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	case NOTIFICATION:
+		if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
+			wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+				   "subtype %d", subtype);
+			return TRUE;
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
+			   "processing a response", data->state);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+static void eap_aka_determine_identity(struct eap_sm *sm,
+				       struct eap_aka_data *data,
+				       int before_identity, int after_reauth)
+{
+	const u8 *identity;
+	size_t identity_len;
+	int res;
+
+	identity = NULL;
+	identity_len = 0;
+
+	if (after_reauth && data->reauth) {
+		identity = data->reauth->identity;
+		identity_len = data->reauth->identity_len;
+	} else if (sm->identity && sm->identity_len > 0 &&
+		   sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	} else {
+		identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
+						    sm->identity,
+						    sm->identity_len,
+						    &identity_len);
+		if (identity == NULL) {
+			data->reauth = eap_sim_db_get_reauth_entry(
+				sm->eap_sim_db_priv, sm->identity,
+				sm->identity_len);
+			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;
+				memcpy(data->mk, data->reauth->mk,
+				       EAP_SIM_MK_LEN);
+			}
+		}
+	}
+
+	if (identity == NULL ||
+	    eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
+				      sm->identity_len) < 0) {
+		if (before_identity) {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
+				   "not known - send AKA-Identity request");
+			eap_aka_state(data, IDENTITY);
+			return;
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
+				   "permanent user name is known; try to use "
+				   "it");
+			/* eap_sim_db_get_aka_auth() will report failure, if
+			 * this identity is not known. */
+		}
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
+			  identity, identity_len);
+
+	if (!after_reauth && data->reauth) {
+		eap_aka_state(data, REAUTH);
+		return;
+	}
+
+	res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
+				      identity_len, data->rand, data->autn,
+				      data->ik, data->ck, data->res,
+				      &data->res_len, sm);
+	if (res == EAP_SIM_DB_PENDING) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+			   "not yet available - pending request");
+		sm->method_pending = METHOD_PENDING_WAIT;
+		return;
+	}
+
+	data->reauth = NULL;
+	data->counter = 0; /* reset re-auth counter since this is full auth */
+
+	if (res != 0) {
+		wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
+			   "authentication data for the peer");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	if (sm->method_pending == METHOD_PENDING_WAIT) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+			   "available - abort pending wait");
+		sm->method_pending = METHOD_PENDING_NONE;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
+			  sm->identity, sm->identity_len);
+
+	eap_aka_derive_mk(sm->identity, sm->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);
+}
+
+
+static void eap_aka_process_identity(struct eap_sm *sm,
+				     struct eap_aka_data *data,
+				     u8 *respData, size_t respDataLen,
+				     struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
+
+	if (attr->mac || attr->iv || attr->encr_data) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
+			   "received in EAP-Response/AKA-Identity");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (attr->identity) {
+		free(sm->identity);
+		sm->identity = malloc(attr->identity_len);
+		if (sm->identity) {
+			memcpy(sm->identity, attr->identity,
+			       attr->identity_len);
+			sm->identity_len = attr->identity_len;
+		}
+	}
+
+	eap_aka_determine_identity(sm, data, 0, 0);
+}
+
+
+static void eap_aka_process_challenge(struct eap_sm *sm,
+				      struct eap_aka_data *data,
+				      u8 *respData, size_t respDataLen,
+				      struct eap_sim_attrs *attr)
+{
+	const u8 *identity;
+	size_t identity_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
+
+	if (attr->mac == NULL ||
+	    eap_sim_verify_mac(data->k_aut, respData, respDataLen, 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;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	if (attr->res == NULL || attr->res_len != data->res_len ||
+	    memcmp(attr->res, data->res, data->res_len) != 0) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
+			   "include valid AT_RES");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
+		   "correct AT_MAC");
+	eap_aka_state(data, SUCCESS);
+
+	identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
+					    sm->identity_len, &identity_len);
+	if (identity == NULL) {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	}
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+					 identity_len,
+					 data->next_pseudonym);
+		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);
+		data->next_reauth_id = NULL;
+	}
+}
+
+
+static void eap_aka_process_sync_failure(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 u8 *respData, size_t respDataLen,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
+
+	if (attr->auts == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
+			   "message did not include valid AT_AUTS");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	/* Avoid re-reporting AUTS when processing pending EAP packet by
+	 * maintaining a local flag stating whether this AUTS has already been
+	 * reported. */
+	if (!data->auts_reported &&
+	    eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
+				     sm->identity_len, attr->auts,
+				     data->rand)) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+	data->auts_reported = 1;
+
+	/* Try again after resynchronization */
+	eap_aka_determine_identity(sm, data, 0, 0);
+}
+
+
+static void eap_aka_process_reauth(struct eap_sm *sm,
+				   struct eap_aka_data *data,
+				   u8 *respData, size_t respDataLen,
+				   struct eap_sim_attrs *attr)
+{
+	struct eap_sim_attrs eattr;
+	u8 *decrypted = NULL;
+	const u8 *identity, *id2;
+	size_t identity_len, id2_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
+
+	if (attr->mac == NULL ||
+	    eap_sim_verify_mac(data->k_aut, respData, respDataLen, 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");
+		goto fail;
+	}
+
+	if (attr->encr_data == NULL || attr->iv == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+			   "message did not include encrypted data");
+		goto fail;
+	}
+
+	decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+				       attr->encr_data_len, attr->iv, &eattr,
+				       0);
+	if (decrypted == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+			   "data from reauthentication message");
+		goto fail;
+	}
+
+	if (eattr.counter != data->counter) {
+		wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
+			   "used incorrect counter %u, expected %u",
+			   eattr.counter, data->counter);
+		goto fail;
+	}
+	free(decrypted);
+	decrypted = NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
+		   "the correct AT_MAC");
+
+	if (eattr.counter_too_small) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+			   "included AT_COUNTER_TOO_SMALL - starting full "
+			   "authentication");
+		eap_aka_determine_identity(sm, data, 0, 1);
+		return;
+	}
+
+	eap_aka_state(data, SUCCESS);
+
+	if (data->reauth) {
+		identity = data->reauth->identity;
+		identity_len = data->reauth->identity_len;
+	} else {
+		identity = sm->identity;
+		identity_len = sm->identity_len;
+	}
+
+	id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
+				       identity_len, &id2_len);
+	if (id2) {
+		identity = id2;
+		identity_len = id2_len;
+	}
+
+	if (data->next_pseudonym) {
+		eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+					 identity_len, data->next_pseudonym);
+		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);
+		data->next_reauth_id = NULL;
+	} else {
+		eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+		data->reauth = NULL;
+	}
+
+	return;
+
+fail:
+	data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+	eap_aka_state(data, NOTIFICATION);
+	eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+	data->reauth = NULL;
+	free(decrypted);
+}
+
+
+static void eap_aka_process_client_error(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 u8 *respData, size_t respDataLen,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
+		   attr->client_error_code);
+	eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_authentication_reject(
+	struct eap_sm *sm, struct eap_aka_data *data,
+	u8 *respData, size_t respDataLen, struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
+	eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_notification(struct eap_sm *sm,
+					 struct eap_aka_data *data,
+					 u8 *respData, size_t respDataLen,
+					 struct eap_sim_attrs *attr)
+{
+	wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
+	eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process(struct eap_sm *sm, void *priv,
+			    u8 *respData, size_t respDataLen)
+{
+	struct eap_aka_data *data = priv;
+	struct eap_hdr *resp;
+	u8 *pos, subtype;
+	size_t len;
+	struct eap_sim_attrs attr;
+
+	resp = (struct eap_hdr *) respData;
+	pos = (u8 *) (resp + 1);
+	subtype = pos[1];
+
+	if (eap_aka_subtype_ok(data, subtype)) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
+			   "EAP-AKA Subtype in EAP Response");
+		data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+		eap_aka_state(data, NOTIFICATION);
+		return;
+	}
+
+	len = be_to_host16(resp->length);
+	pos += 4;
+
+	if (eap_sim_parse_attr(pos, respData + len, &attr, 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);
+		return;
+	}
+
+	if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
+		eap_aka_process_client_error(sm, data, respData, len, &attr);
+		return;
+	}
+
+	if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
+		eap_aka_process_authentication_reject(sm, data, respData, len,
+						      &attr);
+		return;
+	}
+
+	switch (data->state) {
+	case IDENTITY:
+		eap_aka_process_identity(sm, data, respData, len, &attr);
+		break;
+	case CHALLENGE:
+		if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+			eap_aka_process_sync_failure(sm, data, respData, len,
+						     &attr);
+		} else {
+			eap_aka_process_challenge(sm, data, respData, len,
+						  &attr);
+		}
+		break;
+	case REAUTH:
+		eap_aka_process_reauth(sm, data, respData, len, &attr);
+		break;
+	case NOTIFICATION:
+		eap_aka_process_notification(sm, data, respData, len, &attr);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+			   "process", data->state);
+		break;
+	}
+}
+
+
+static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_SIM_KEYING_DATA_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+	*len = EAP_SIM_KEYING_DATA_LEN;
+	return key;
+}
+
+
+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *key;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	key = malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+	memcpy(key, data->emsk, EAP_EMSK_LEN);
+	*len = EAP_EMSK_LEN;
+	return key;
+}
+
+
+static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
+{
+	struct eap_aka_data *data = priv;
+	return data->state == SUCCESS;
+}
+
+
+int eap_server_aka_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+				      EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_aka_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;
+}
--- /dev/null
+++ contrib/hostapd/doc/hostapd.fig
@@ -0,0 +1,264 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+6 3450 1200 4575 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
+-6
+6 8175 6600 9675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
+-6
+6 8700 3450 9375 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
+-6
+6 9600 3450 10275 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
+-6
+6 6000 5775 7200 6300
+6 6000 5775 7200 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
+4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
+-6
+4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
+-6
+6 8100 2250 8925 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
+4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
+-6
+6 3150 5475 4425 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
+4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
+-6
+6 1950 5550 2625 6075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
+4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
+4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
+-6
+6 1875 4725 2925 5250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
+4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
+4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+	 1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 9075 4425 9075 3750
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 3000 8700 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 4125 8700 3675
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 9900 4425 9900 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+	 4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 4425 4050 5475
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 7200 7200 5100 7800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+	 2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 6600 4650 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 5475 6600 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5025 4425 6000 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+	 4800 3900 5925 2550 8100 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 3900 8475 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 8925 2475 9450 2475
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2325 5550 2325 5250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2925 4950 4350 4275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+	 2850 4725 5775 2400 8100 2400
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
+4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
+4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
+4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
+4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
--- /dev/null
+++ contrib/hostapd/doc/eap.doxygen
@@ -0,0 +1,56 @@
+/**
+\page eap_module EAP server implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. hostapd uses a separate code module for EAP server
+implementation. This module was designed to use only a minimal set of
+direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the server state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP server implementation in hostapd.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the server state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_server_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_server_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/kerneldoc2doxygen.pl
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+#
+##########################################################################
+# Convert kernel-doc style comments to Doxygen comments.
+##########################################################################
+#
+# This script reads a C source file from stdin, and writes
+# to stdout.  Normal usage:
+#
+# $ mv file.c file.c.gtkdoc
+# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
+#
+# Or to do the same thing with multiple files:
+# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
+#
+# This script may also be suitable for use as a Doxygen input filter,
+# but that has not been tested.
+#
+# Back up your source files before using this script!!
+#
+##########################################################################
+# Copyright (C) 2003 Jonathan Foster <jon at jon-foster.co.uk>
+# Copyright (C) 2005 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
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+# or look at http://www.gnu.org/licenses/gpl.html
+##########################################################################
+
+
+##########################################################################
+#
+# This function converts a single comment from gtk-doc to Doxygen format.
+# The parameter does not include the opening or closing lines
+# (i.e. given a comment like this:
+#    "/**\n"
+#    " * FunctionName:\n"
+#    " * @foo: This describes the foo parameter\n"
+#    " * @bar: This describes the bar parameter\n"
+#    " * @Returns: This describes the return value\n"
+#    " *\n"
+#    " * This describes the function.\n"
+#    " */\n"
+# This function gets:
+#    " * FunctionName:\n"
+#    " * @foo: This describes the foo parameter\n"
+#    " * @bar: This describes the bar parameter\n"
+#    " * @Returns: This describes the return value\n"
+#    " *\n"
+#    " * This describes the function.\n"
+# And it returns:
+#    " * This describes the function.\n"
+#    " *\n"
+#    " * @param foo This describes the foo parameter\n"
+#    " * @param bar This describes the bar parameter\n"
+#    " * @return This describes the return value\n"
+# )
+#
+sub fixcomment {
+    $t = $_[0];
+
+    # " * func: foo" --> "\brief foo\n"
+    # " * struct bar: foo" --> "\brief foo\n"
+    # If this fails, not a kernel-doc comment ==> return unmodified.
+    ($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
+      or return $t;
+
+    # " * Returns: foo" --> "\return foo"
+    $t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
+
+    # " * @foo: bar" --> "\param foo bar"
+    # Handle two common typos: No ":", or "," instead of ":".
+    $t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
+
+    return $t;
+}
+
+##########################################################################
+# Start of main code
+
+# Read entire stdin into memory - one multi-line string.
+$_ = do { local $/; <> };
+
+s{^/\*\n \*}{/\*\* \\file\n\\brief};
+s{ \* Copyright}{\\par Copyright\nCopyright};
+
+# Fix any comments like "/*************" so they don't match.
+# "/***" ===> "/* *"
+s{/\*\*\*}{/\* \*}gs;
+
+# The main comment-detection code.
+s{
+    (               # $1 = Open comment
+        /\*\*       # Open comment
+        (?!\*)      # Do not match /*** (redundant due to fixup above).
+        [\t ]*\n?   # If 1st line is whitespace, match the lot (including the newline).
+    )
+    (.*?)           # $2 = Body of comment (multi-line)
+    (               # $3 = Close comment
+        (           # If possible, match the whitespace before the close-comment
+            (?<=\n) # This part only matches after a newline
+            [\t ]*  # Eat whitespace
+        )?
+        \*/         # Close comment
+    )
+ }
+ {
+    $1 . fixcomment($2) . $3
+ }gesx;
+# ^^^^ Modes: g - Global, match all occurances.
+#             e - Evaluate the replacement as an expression.
+#             s - Single-line - allows the pattern to match across newlines.
+#             x - eXtended pattern, ignore embedded whitespace
+#                 and allow comments.
+
+# Write results to stdout
+print $_;
+
--- /dev/null
+++ contrib/hostapd/doc/driver_wrapper.doxygen
@@ -0,0 +1,20 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the hostapd are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/code_structure.doxygen
@@ -0,0 +1,5 @@
+/**
+\page code_structure Structure of the source code
+
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/porting.doxygen
@@ -0,0 +1,5 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/mainpage.doxygen
@@ -0,0 +1,52 @@
+/**
+\mainpage Developers' documentation for hostapd
+
+hostapd includes IEEE 802.11 access point management (authentication /
+association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
+RADIUS authentication server functionality. It can be build with
+various configuration option, e.g., a standalone AP management
+solution or a RADIUS authentication server with support for number of
+EAP methods.
+
+The goal of this documentation and comments in the source code is to
+give enough information for other developers to understand how hostapd
+has been implemented, how it can be modified, how new drivers can be
+supported, and how hostapd can be ported to other operating
+systems. If any information is missing, feel free to contact Jouni
+Malinen <j at w1.fi> for more information. Contributions as
+patch files are also very welcome at the same address. Please note
+that hostapd is licensed under dual license, GPLv2 or BSD at user's
+choice. All contributions to hostapd are expected to use compatible
+licensing terms.
+
+The source code and read-only access to hostapd CVS repository
+is available from the project home page at
+http://hostap.epitest.fi/hostapd/. This developers' documentation
+is also available as a PDF file from
+http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
+
+The design goal for hostapd was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_module "EAP server implementation".
+Similarly, RADIUS authentication server is in its own separate module.
+Both IEEE 802.1X and RADIUS authentication server can use EAP server
+functionality.
+
+hostapd implements a \ref ctrl_iface_page "control interface" that can
+be used by external programs to control the operations of the hostapdt
+daemon and to get status information and event notifications. There is
+a small C library that provides helper functions to facilitate the use
+of the control interface. This library can also be used with C++.
+
+\image html hostapd.png "hostapd modules"
+\image latex hostapd.eps "hostapd modules" width=15cm
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/doxygen.fast
@@ -0,0 +1,233 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = hostapd
+PROJECT_NUMBER         = 0.5.x
+OUTPUT_DIRECTORY       = doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        =
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+DISTRIBUTE_GROUP_DOC   = NO
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = NO
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = YES
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = . \
+	../wpa_supplicant/eap_sim_common.c \
+	../wpa_supplicant/eap_sim_common.h
+FILE_PATTERNS          = *.c *.h *.doxygen
+RECURSIVE              = YES
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = doc
+INPUT_FILTER           = doc/kerneldoc2doxygen.pl
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 3
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = NO
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = NO
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = YES
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = NO
+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
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = NO
--- /dev/null
+++ contrib/hostapd/doc/ctrl_iface.doxygen
@@ -0,0 +1,66 @@
+/**
+\page ctrl_iface_page Control interface
+
+hostapd implements a control interface that can be used by
+external programs to control the operations of the hostapd
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+is an example program using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of hostapd is using UNIX domain sockets for the
+control interface. The use of the functions defined in wpa_ctrl.h can
+be used to hide the details of the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with hostapd should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+hostapd uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+hostapd. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by hostapd to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether hostapd is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and hostapd is processing commands.
+
+*/
--- /dev/null
+++ contrib/hostapd/doc/doxygen.full
@@ -0,0 +1,230 @@
+# Doxyfile 1.4.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME           = hostapd
+PROJECT_NUMBER         = 0.5.x
+OUTPUT_DIRECTORY       = doc
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+USE_WINDOWS_ENCODING   = NO
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       = "The $name class" \
+                         "The $name widget" \
+                         "The $name file" \
+                         is \
+                         provides \
+                         specifies \
+                         contains \
+                         represents \
+                         a \
+                         an \
+                         the
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = YES
+STRIP_FROM_PATH        =
+STRIP_FROM_INC_PATH    = 
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP         = NO
+INHERIT_DOCS           = YES
+DISTRIBUTE_GROUP_DOC   = NO
+TAB_SIZE               = 8
+ALIASES                = 
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+SUBGROUPING            = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = YES
+EXTRACT_LOCAL_METHODS  = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = NO
+HIDE_FRIEND_COMPOUNDS  = NO
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = YES
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_BRIEF_DOCS        = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       = 
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = YES
+SHOW_DIRECTORIES       = NO
+FILE_VERSION_FILTER    = 
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET                  = NO
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = YES
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           = 
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT                  = .
+FILE_PATTERNS          = *.c *.h *.doxygen
+RECURSIVE              = YES
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXAMPLE_PATH           = 
+EXAMPLE_PATTERNS       = *
+EXAMPLE_RECURSIVE      = NO
+IMAGE_PATH             = doc
+INPUT_FILTER           = kerneldoc2doxygen.pl
+FILTER_PATTERNS        = 
+FILTER_SOURCE_FILES    = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER         = YES
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION    = NO
+VERBATIM_HEADERS       = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 3
+IGNORE_PREFIX          = 
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = 
+HTML_FOOTER            = 
+HTML_STYLESHEET        = 
+HTML_ALIGN_MEMBERS     = YES
+GENERATE_HTMLHELP      = NO
+CHM_FILE               = 
+HHC_LOCATION           = 
+GENERATE_CHI           = NO
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+DISABLE_INDEX          = NO
+ENUM_VALUES_PER_LINE   = 4
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX         = YES
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         = 
+LATEX_HEADER           = 
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = YES
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    = 
+RTF_EXTENSIONS_FILE    = 
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN           = NO
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             = 
+XML_DTD                = 
+XML_PROGRAMLISTING     = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF   = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX = 
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = NO
+EXPAND_ONLY_PREDEF     = NO
+SEARCH_INCLUDES        = YES
+INCLUDE_PATH           = 
+INCLUDE_FILE_PATTERNS  = 
+PREDEFINED             = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED      = 
+SKIP_FUNCTION_MACROS   = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references   
+#---------------------------------------------------------------------------
+TAGFILES               = 
+GENERATE_TAGFILE       = 
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS         = NO
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = YES
+CLASS_GRAPH            = YES
+COLLABORATION_GRAPH    = YES
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = YES
+INCLUDED_BY_GRAPH      = YES
+CALL_GRAPH             = YES
+GRAPHICAL_HIERARCHY    = YES
+DIRECTORY_GRAPH        = NO
+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
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine   
+#---------------------------------------------------------------------------
+SEARCHENGINE           = YES


More information about the Midnightbsd-cvs mailing list