wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_wpa_connect.cpp
changeset 0 c40eb8fe8501
child 3 6524e815f76f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_wpa_connect.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,1016 @@
+/*
+* Copyright (c) 2005-2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  State machine for connecting to a WPA network
+*
+*/
+
+
+#include "core_sub_operation_wpa_connect.h"
+#include "core_sub_operation_connect.h"
+#include "core_server.h"
+#include "core_tools.h"
+#include "core_tools_parser.h"
+#include "core_ap_data.h"
+#include "core_frame_rsn_ie.h"
+#include "core_frame_wpa_ie.h"
+#include "core_frame_wapi_ie.h"
+#include "am_debug.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_wpa_connect_c::core_sub_operation_wpa_connect_c(
+    u32_t request_id,
+    core_server_c* server,
+    abs_core_driverif_c* drivers,
+    abs_core_server_callback_c* adaptation,
+    bool_t& is_connected,
+    core_management_status_e& connect_status,
+    const core_ssid_s& ssid,
+    core_ap_data_c& ap_data,
+    bool_t& is_cached_sa_used,
+    core_type_list_c<core_frame_dot11_ie_c>& assoc_ie_list,
+    core_frame_assoc_resp_c** assoc_resp ) :
+    core_operation_base_c( core_operation_unspecified, request_id, server, drivers, adaptation,
+        core_base_flag_drivers_needed ),
+    abs_wlan_eapol_callback_interface_c(),
+    is_connected_m( is_connected ),
+    is_cached_sa_used_m( is_cached_sa_used ),
+    connect_status_m( connect_status ),
+    ssid_m( ssid ),
+    ap_data_m( ap_data ),
+    current_bssid_m( ZERO_MAC_ADDR ),
+    pmkid_length_m( 0 ),
+    sent_ie_m( NULL ),
+    auth_algorithm_m( core_authentication_mode_open ),
+    eapol_auth_type_m( wlan_eapol_if_eapol_key_authentication_type_none ),
+    assoc_ie_list_m( assoc_ie_list ),
+    assoc_resp_m( assoc_resp ),
+    is_key_caching_used_m( false_t )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::core_sub_operation_wpa_connect_c()" );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_wpa_connect_c::~core_sub_operation_wpa_connect_c()
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::~core_sub_operation_wpa_connect_c()" );
+
+    /**
+     * Ownership of sent_ie_m has been transferred to assoc_ie_list_m,
+     * no need delete it.
+     */
+    sent_ie_m = NULL;
+
+    server_m->set_eapol_handler( NULL );
+    server_m->unregister_event_handler( this );
+    assoc_resp_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::next_state()
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::next_state()" );
+
+    switch ( operation_state_m )
+        {
+        case core_state_init:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_authentication_started as true" );
+            server_m->get_connection_data()->set_eapol_authentication_started(
+                true_t );
+            server_m->get_connection_data()->set_eapol_auth_bssid(
+                ZERO_MAC_ADDR );
+
+            eapol_auth_type_m = core_tools_c::eap_authentication_type(
+                server_m->get_connection_data()->iap_data(),
+                ap_data_m );
+            current_bssid_m = ap_data_m.bssid();
+
+            server_m->set_eapol_handler( this );
+
+            server_m->get_eapol_instance().clear_stored_frame();
+
+            /**
+             * If roaming to a WPA2-EAP AP without a cached PMKSA, attempt
+             * to use proactive key caching if not previously done so.
+             */
+            if( !is_key_caching_used_m &&
+                !is_cached_sa_used_m &&              
+                server_m->get_connection_data()->current_ap_data() &&
+                eapol_auth_type_m == wlan_eapol_if_eapol_key_authentication_type_rsna_eap )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - attempting to use proactive key caching" );
+
+                is_cached_sa_used_m = true_t;
+                is_key_caching_used_m = true_t;
+                }
+            else if( is_key_caching_used_m )
+                {
+                is_cached_sa_used_m = false_t;
+                is_key_caching_used_m = false_t;                
+                }
+
+            // update_wlan_database_reference_values must be sent before start_authentication and start_reassociation.
+            u32_t reference[2] = {
+                3, // ELan
+                server_m->get_connection_data()->iap_data().id() };
+            core_error_e ret = server_m->get_eapol_instance().update_wlan_database_reference_values(
+                reinterpret_cast<u8_t*>( reference ), 2*sizeof( u32_t ) );
+
+            if( is_cached_sa_used_m )
+                {
+                if( eapol_auth_type_m == wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam )
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - starting a WPX fast-roam reassociation" );
+
+                    core_error_e ret = server_m->get_wpx_adaptation_instance().handle_fast_roam_start_reassociation(
+                        ap_data_m,
+                        assoc_ie_list_m );
+                    DEBUG1( "core_sub_operation_wpa_connect_c::next_state() - handle_fast_roam_start_reassociation returned with %u",
+                        ret );
+                    /*
+                     *  State machine will move forward from here by:
+                     * - complete_start_wpx_fast_roam_reassociation() 
+                     *     -> core_state_do_connect
+                     * - Error message (start_wpx_fast_roam_reassociation) 
+                     *     -> core_state_init (with is_cached_sa_used_m = false_t)
+                     */
+                    }
+                else
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - starting a reassociation" );
+                    
+                    operation_state_m = core_state_do_connect;
+                    
+                    core_mac_address_s previous_bssid( ZERO_MAC_ADDR );
+                    if( server_m->get_connection_data()->current_ap_data() )
+                        {
+                        previous_bssid = server_m->get_connection_data()->current_ap_data()->bssid();
+                        }
+
+                    network_id_c previous_ap(
+                        &previous_bssid.addr[0],
+                        MAC_ADDR_LEN,
+                        &server_m->own_mac_addr().addr[0],
+                        MAC_ADDR_LEN,
+                        server_m->get_eapol_instance().ethernet_type() );
+    
+                    network_id_c new_ap(
+                        &current_bssid_m.addr[0],
+                        MAC_ADDR_LEN,
+                        &server_m->own_mac_addr().addr[0],
+                        MAC_ADDR_LEN,
+                        server_m->get_eapol_instance().ethernet_type() );
+                    
+                    ret = server_m->get_eapol_instance().start_reassociation(
+                        &previous_ap, &new_ap, eapol_auth_type_m );
+                    DEBUG1( "core_sub_operation_wpa_connect_c::next_state() - start_reassociation returned with %u",
+                        ret );
+                    /*
+                     *  State machine will move forward from here by:
+                     * - reassociate(), when reassociation is possible 
+                     *     -> core_state_do_connect
+                     * - Error message (start_reassociation), when start_reassociation is not possible 
+                     *     -> core_state_start_authentication_needed
+                     */
+                    }
+                }
+            else
+                {
+                // Full authentication is needed.
+                operation_state_m = core_state_start_authentication_needed;
+                return next_state();
+                }
+            break;
+            }
+        case core_state_start_authentication_needed:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - starting a full authentication" );
+
+            operation_state_m = core_state_do_connect;
+
+            network_id_c network_id(
+                &current_bssid_m.addr[0],
+                MAC_ADDR_LEN,
+                &server_m->own_mac_addr().addr[0],
+                MAC_ADDR_LEN,
+                server_m->get_eapol_instance().ethernet_type() );
+
+            core_error_e ret = server_m->get_eapol_instance().start_authentication(
+                const_cast<u8_t*>( &ssid_m.ssid[0] ), ssid_m.length,
+                eapol_auth_type_m,
+                const_cast<u8_t*>( &server_m->get_connection_data()->iap_data().psk_key().key_data[0] ),
+                server_m->get_connection_data()->iap_data().psk_key().key_length,
+                server_m->get_connection_data()->iap_data().is_psk_overridden(),
+                &network_id );
+            DEBUG1( "core_sub_operation_wpa_connect_c::next_state() - start_authentication returned with %u",
+                ret );
+            
+            break;
+            }
+        case core_state_do_connect:
+            {
+            core_key_management_e key_management( core_key_management_eap );
+            core_encryption_mode_e encryption_mode( core_encryption_mode_wpa );
+            bool_t is_pairwise_key_invalidated( true_t );
+            
+            switch ( eapol_auth_type_m )
+                {
+                case wlan_eapol_if_eapol_key_authentication_type_rsna_eap:
+                    /** Falls through on purpose. */
+                case wlan_eapol_if_eapol_key_authentication_type_wpa_eap:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_eap" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_wpa" );
+                    key_management = core_key_management_eap;
+                    encryption_mode = core_encryption_mode_wpa;                    
+                    break;
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_wfa_sc:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_eap" );
+                    key_management = core_key_management_eap;
+
+                    if ( ap_data_m.is_privacy_enabled() )
+                        {
+                        DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_wpa" );
+                        encryption_mode = core_encryption_mode_wpa;
+                        }
+                    else
+                        {
+                        DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_disabled" );
+                        encryption_mode = core_encryption_mode_disabled;
+                        }
+                    break;
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_rsna_psk:
+                    /** Falls through on purpose. */
+                case wlan_eapol_if_eapol_key_authentication_type_wpa_psk:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_preshared" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_wpa" );
+                    key_management = core_key_management_preshared;
+                    encryption_mode = core_encryption_mode_wpa;
+                    break;
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_802_1x:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_eap" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_802dot1x" );
+                    key_management = core_key_management_eap;
+                    encryption_mode = core_encryption_mode_802dot1x;
+                    break;
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_encryption_mode_802dot1x" );
+                    key_management = core_key_management_wpx_fast_roam;
+                    encryption_mode = core_encryption_mode_802dot1x;
+                    if( is_cached_sa_used_m )
+                        {
+                        is_pairwise_key_invalidated = false_t;
+                        }
+                    break;
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_wapi:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_wapi_certificate" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_security_mode_wapi" );
+                    key_management = core_key_management_wapi_certificate;
+                    encryption_mode = core_encryption_mode_wpi;
+                    break;                    
+                    }
+                case wlan_eapol_if_eapol_key_authentication_type_wapi_psk:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using key management core_key_management_wapi_psk" );
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - using encryption mode core_security_mode_wapi" );
+                    key_management = core_key_management_wapi_psk;
+                    encryption_mode = core_encryption_mode_wpi;
+                    break;                    
+                    }
+                default:
+                    {
+                    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - unknown authentication type" );
+                    ASSERT( false_t );
+                    }
+                }
+            
+            operation_state_m = core_state_req_connect;
+
+            if( ap_data_m.is_rsn_ie_present() )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - generating RSN IE" );
+
+                sent_ie_m = core_frame_rsn_ie_c::instance(
+                    server_m->get_wpx_adaptation_instance(),
+                    ap_data_m.best_group_cipher(),
+                    ap_data_m.best_pairwise_cipher(),
+                    key_management,
+                    pmkid_length_m,
+                    &pmkid_data_m[0] );
+                }
+            else if( ap_data_m.is_wpa_ie_present() )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - generating WPA IE" );
+
+                sent_ie_m = core_frame_wpa_ie_c::instance(
+                    server_m->get_wpx_adaptation_instance(),
+                    ap_data_m.best_group_cipher(),
+                    ap_data_m.best_pairwise_cipher(),
+                    key_management );
+                }
+            else if( ap_data_m.is_wapi_ie_present() )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - generating WAPI IE" );
+
+                sent_ie_m = core_frame_wapi_ie_c::instance(
+                    ap_data_m.best_group_cipher(),
+                    ap_data_m.best_pairwise_cipher(),
+                    key_management,
+                    0,
+                    pmkid_length_m,
+                    &pmkid_data_m[0] );
+                }
+            
+            if( sent_ie_m &&
+                eapol_auth_type_m != wlan_eapol_if_eapol_key_authentication_type_wfa_sc )
+                {
+                assoc_ie_list_m.append(
+                    sent_ie_m,
+                    sent_ie_m->element_id() );
+                }
+
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_connecting as true" );
+            server_m->get_connection_data()->set_eapol_connecting(
+                true_t );
+
+            core_operation_base_c* operation = new core_sub_operation_connect_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                is_connected_m,
+                connect_status_m,
+                ssid_m,
+                ap_data_m,
+                auth_algorithm_m,
+                server_m->get_wpx_adaptation_instance().encryption_mode(
+                    ap_data_m, encryption_mode ),
+                core_tools_c::cipher_key_type(
+                    ap_data_m.best_pairwise_cipher() ),
+                assoc_ie_list_m,
+                assoc_resp_m,
+                is_pairwise_key_invalidated,
+                true_t );
+
+            return run_sub_operation( operation );
+            }
+        case core_state_req_connect:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - connection success" );
+
+            operation_state_m = core_state_req_state_notification;
+
+            network_id_c network(
+                &current_bssid_m.addr[0],
+                MAC_ADDR_LEN,
+                &server_m->own_mac_addr().addr[0],
+                MAC_ADDR_LEN,
+                server_m->get_eapol_instance().ethernet_type() );
+
+            const core_frame_dot11_ie_c* ie = NULL;
+            if( ap_data_m.is_rsn_ie_present() )
+                {
+                ie = ap_data_m.rsn_ie();
+                }
+            else if( ap_data_m.is_wpa_ie_present() )
+                {
+                ie = ap_data_m.wpa_ie();
+                }
+            else if( ap_data_m.is_wapi_ie_present() )
+                {
+                ie = ap_data_m.wapi_ie();
+                }
+
+            core_frame_dot11_ie_c * recv_ie = NULL;
+            core_frame_dot11_ie_c * sent_ie = NULL;
+
+            if ( sent_ie_m )
+                {
+                sent_ie = sent_ie_m;
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - sent IE: " );
+                DEBUG_BUFFER( sent_ie_m->data_length(), sent_ie_m->data() );
+                }
+    
+            if ( ie )
+                {
+                recv_ie = core_frame_dot11_ie_c::instance( ie->data_length(), ie->data() );
+
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - received IE: " );
+                DEBUG_BUFFER( ie->data_length(), ie->data() );
+                }
+
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_connecting as false" );
+            server_m->get_connection_data()->set_eapol_connecting(
+                false_t );
+            server_m->get_connection_data()->set_eapol_auth_bssid(
+                current_bssid_m );
+
+            /**
+             * WPX fast-roam reassociation is handled differently, EAPOL indication will
+             * move the state machine forward.
+             */
+            if ( is_cached_sa_used_m &&
+                 eapol_auth_type_m == wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam )
+                {
+                server_m->get_wpx_adaptation_instance().handle_fast_roam_reassoc_resp(
+                    assoc_resp_m ? *assoc_resp_m : NULL );
+
+                delete recv_ie;
+                recv_ie = NULL;
+                delete ie;
+                ie = NULL;
+                return core_error_request_pending;
+                }
+
+            u8_t * temp_recv_ie( NULL );
+            u32_t temp_recv_ie_length( 0 );
+            u8_t * temp_sent_ie( NULL );
+            u32_t temp_sent_ie_length( 0 );
+            
+            if ( recv_ie )
+                {
+                temp_recv_ie = const_cast<u8_t*>( recv_ie->data() );
+                temp_recv_ie_length = recv_ie->data_length();
+                }
+            if ( sent_ie_m )
+                {
+                temp_sent_ie = const_cast<u8_t*>( sent_ie->data() );
+                temp_sent_ie_length = sent_ie->data_length();
+                }
+                
+            if ( is_cached_sa_used_m )                 
+                {
+                server_m->get_eapol_instance().complete_reassociation(
+                    wlan_eapol_if_eapol_wlan_authentication_state_association_ok,
+                    &network,
+                    temp_recv_ie, temp_recv_ie_length,
+                    temp_sent_ie, temp_sent_ie_length,
+                    core_tools_c::eapol_cipher( ap_data_m.best_pairwise_cipher() ),
+                    core_tools_c::eapol_cipher( ap_data_m.best_group_cipher() ) );
+                }
+            else
+                {
+                server_m->get_eapol_instance().complete_association(                
+                    wlan_eapol_if_eapol_wlan_authentication_state_association_ok,
+                    &network,
+                    temp_recv_ie, temp_recv_ie_length,
+                    temp_sent_ie, temp_sent_ie_length,
+                    core_tools_c::eapol_cipher( ap_data_m.best_pairwise_cipher() ),
+                    core_tools_c::eapol_cipher( ap_data_m.best_group_cipher() ) );
+                }
+
+            delete recv_ie;
+            recv_ie = NULL;
+            delete ie;
+            ie = NULL;
+            
+            // Send EAPOL frame after timer. This will allow new EAPOL frames to come from queue.
+            return asynch_goto( core_state_process_eapol_frame, CORE_TIMER_IMMEDIATELY );
+            }
+        case core_state_process_eapol_frame:
+            {
+            operation_state_m = core_state_req_state_notification;
+            
+            server_m->get_eapol_instance().process_stored_frame();
+            server_m->register_event_handler( this );
+
+            break;
+            }
+        case core_state_req_state_notification:
+            {
+            server_m->unregister_event_handler( this );
+
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - authentication success" );
+
+            return core_error_ok;
+            }
+        case core_state_req_connect_failed:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - connection failed" );
+
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_authentication_started as false" );
+            server_m->get_connection_data()->set_eapol_authentication_started(
+                false_t );
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_connecting as false" );
+            server_m->get_connection_data()->set_eapol_connecting(
+                false_t );
+
+            /** The connection attempt failed, we are no longer connected. */
+            is_connected_m = false_t;
+
+            /**
+             * WPX fast-roam reassociation is handled differently, EAPOL indication will
+             * move the state machine forward.
+             * 
+             * This completion should be before clearing eapol_handler. 
+             * Otherwise we don't get error message.
+             */
+            if ( is_cached_sa_used_m &&
+                 eapol_auth_type_m == wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::next_state() - calling EAPOL complete_fast_roam_reassociation (this_ap_failed)" );
+                server_m->get_wpx_adaptation_instance().handle_fast_roam_reassoc_resp( NULL );
+
+                return core_error_request_pending;
+                }
+
+            /**
+             * We already know the connection has failed so don't process the failure
+             * indication from EAPOL.
+             */
+            server_m->set_eapol_handler( NULL );
+
+            wlan_eapol_if_eapol_wlan_authentication_state_e eapol_reason(
+                wlan_eapol_if_eapol_wlan_authentication_state_this_ap_failed );
+
+            if ( connect_status_m == core_management_status_auth_algo_not_supported )
+                {
+                eapol_reason = wlan_eapol_if_eapol_wlan_authentication_state_802_11_auth_algorithm_not_supported;
+                }
+            else if ( failure_reason_m == core_error_timeout )
+                {
+                eapol_reason = wlan_eapol_if_eapol_wlan_authentication_state_no_response;
+                }
+
+            network_id_c network(
+                &current_bssid_m.addr[0],
+                MAC_ADDR_LEN,
+                &server_m->own_mac_addr().addr[0],
+                MAC_ADDR_LEN,
+                server_m->get_eapol_instance().ethernet_type() );
+
+            if ( is_cached_sa_used_m )
+                {
+                DEBUG1( "core_sub_operation_wpa_connect_c::next_state() - calling EAPOL complete_reassociation with code %u",
+                    eapol_reason );
+
+                server_m->get_eapol_instance().complete_reassociation(
+                    eapol_reason,
+                    &network,
+                    NULL, 0,
+                    NULL, 0,
+                    wlan_eapol_if_rsna_cipher_none,
+                    wlan_eapol_if_rsna_cipher_none );
+                }
+            else
+                {
+                DEBUG1( "core_sub_operation_wpa_connect_c::next_state() - calling EAPOL complete_association with code %u",
+                    eapol_reason );
+
+                server_m->get_eapol_instance().complete_association(
+                    eapol_reason,
+                    &network,
+                    NULL, 0,
+                    NULL, 0,
+                    wlan_eapol_if_rsna_cipher_none,
+                    wlan_eapol_if_rsna_cipher_none );
+                }
+
+            return cancel();
+            }
+        case core_state_req_association_failed:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - association, reassociation or WPX fast-roam reassociation failed" );
+            
+            server_m->set_eapol_handler( NULL );
+
+            return cancel();
+            }
+        case core_state_bss_lost:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - authentication failed due to BSS lost" );
+
+            /** The connection attempt failed, we are no longer connected. */
+            is_connected_m = false_t;
+            
+            return core_error_timeout;
+            }
+        case core_state_user_cancel:
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::next_state() - pending request has been completed, proceeding with user cancel" );
+
+            network_id_c network(
+                &current_bssid_m.addr[0],
+                MAC_ADDR_LEN,
+                &server_m->own_mac_addr().addr[0],
+                MAC_ADDR_LEN,
+                server_m->get_eapol_instance().ethernet_type() );
+
+            DEBUG6( "core_sub_operation_wpa_connect_c::next_state() - EAPOL disassociation from BSSID %02X:%02X:%02X:%02X:%02X:%02X",
+                current_bssid_m.addr[0], current_bssid_m.addr[1], current_bssid_m.addr[2],
+                current_bssid_m.addr[3], current_bssid_m.addr[4], current_bssid_m.addr[5] );
+
+            server_m->get_eapol_instance().disassociation( &network );
+
+            /** The connection attempt failed, we are no longer connected. */
+            is_connected_m = false_t;            
+
+            return core_error_cancel;
+            }
+        default:
+            {
+            ASSERT( false_t );
+            }
+        }
+
+    return core_error_request_pending;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::cancel()
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::cancel()" );
+
+    switch( operation_state_m )
+        {
+        case core_state_req_connect:
+            {
+            return goto_state( core_state_req_connect_failed );
+            }
+        case core_state_req_state_notification:
+            {
+            if( server_m->get_connection_data()->is_eapol_require_immediate_reconnect() ||
+                ( is_key_caching_used_m &&
+                  failure_reason_m == core_error_eapol_auth_start_timeout ) )
+                {
+                DEBUG( "core_sub_operation_wpa_connect_c::cancel() - re-attempting authentication" );
+                server_m->get_connection_data()->set_eapol_require_immediate_reconnect( false_t );
+                assoc_ie_list_m.clear();
+
+                return asynch_goto( core_state_init, 100000 ); // 100 ms delay before new connect
+                }
+
+            /** The connection attempt failed, we are no longer connected. */
+            is_connected_m = false_t;            
+
+            return failure_reason_m;
+            }
+        default:
+            {
+            return failure_reason_m;
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_sub_operation_wpa_connect_c::user_cancel(
+    bool_t /* do_graceful_cancel */ )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::user_cancel()" );
+
+    /**
+     * Do not handle any EAPOL indications that might occur during our
+     * transition to core_state_user_cancel state.
+     */
+    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_authenticating as false" );
+    server_m->get_connection_data()->set_eapol_authenticating(
+        false_t );
+    DEBUG( "core_sub_operation_wpa_connect_c::next_state() - marking is_eapol_authentication_started as false" );
+    server_m->get_connection_data()->set_eapol_authentication_started(
+        false_t );
+    
+    /**
+     * If we are waiting for an EAPOL indication, we'll have to schedule
+     * our own timer to proceed.
+     */
+    if( operation_state_m == core_state_req_state_notification )
+        {
+        asynch_goto( core_state_user_cancel, CORE_TIMER_IMMEDIATELY );
+
+        return;
+        }
+
+    /**
+     * Otherwise we'll just wait for the pending request complete
+     * before continuing.
+     */    
+    operation_state_m = core_state_user_cancel;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::packet_send(
+    network_id_c * send_network_id,
+    u8_t * packet_data,
+    u32_t packet_data_length,
+    bool_t send_unencrypted )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::packet_send()" );    
+
+    server_m->send_data_frame(
+        ap_data_m,
+        core_frame_type_ethernet,
+        static_cast<u16_t>( packet_data_length ),
+        packet_data,
+        core_access_class_voice,
+        send_network_id->destination(),
+        send_unencrypted );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::associate(
+    wlan_eapol_if_eapol_key_authentication_mode_e authentication_mode )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::associate()" );
+
+    auth_algorithm_m = server_m->get_wpx_adaptation_instance().authentication_algorithm(
+        eapol_auth_type_m,
+        authentication_mode );
+
+    next_state();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::disassociate(
+    network_id_c * /*receive_network_id*/,
+    const bool_t /* self_disassociation */ )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::disassociate()" );
+    
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::packet_data_session_key(
+    network_id_c * send_network_id,
+    session_key_c * key )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::packet_data_session_key()" );
+    ASSERT ( key != NULL );
+    ASSERT ( send_network_id != NULL );
+
+    core_mac_address_s mac( BROADCAST_MAC_ADDR );
+
+    if ( key->eapol_key_type == wlan_eapol_if_eapol_key_type_unicast )
+        {
+        mac = send_network_id->destination();
+        }
+
+    core_cipher_key_type_e type =
+        core_tools_c::cipher_key_type(
+            key->eapol_key_type,
+            ap_data_m.best_pairwise_cipher(),
+            ap_data_m.best_group_cipher() );
+
+    ASSERT( drivers_m );
+    drivers_m->add_cipher_key(
+        type,
+        static_cast<u8_t>( key->key_index ),
+        static_cast<u16_t>( key->key_length ),
+        key->key,
+        mac,
+        true_t );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//	    
+void core_sub_operation_wpa_connect_c::state_notification(
+    state_notification_c * /*state*/ )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::state_notification()" );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//	    
+core_error_e core_sub_operation_wpa_connect_c::reassociate(
+    network_id_c * /* send_network_id */,
+    const wlan_eapol_if_eapol_key_authentication_type_e /* authentication_type */,
+    u8_t * PMKID,
+    u32_t PMKID_length )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::reassociate()" );
+
+    if( PMKID )
+        {
+        pmkid_length_m = PMKID_length;
+        core_tools_c::copy(
+            &pmkid_data_m[0],
+            PMKID,
+            pmkid_length_m );
+        }
+
+    DEBUG( "core_sub_operation_wpa_connect_c::reassociate() - using open authentication algorithm" );
+    auth_algorithm_m = core_authentication_mode_open;
+
+    next_state();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::complete_check_pmksa_cache(
+    core_type_list_c<network_id_c> & /* network_id_list */ )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::complete_check_pmksa_cache()" );
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::complete_start_wpx_fast_roam_reassociation(
+    network_id_c * /* receive_network_id */,
+    u8_t * reassociation_request_ie,
+    u32_t reassociation_request_ie_length )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::complete_start_wpx_fast_roam_reassociation()" );
+    
+    // Generate a WPX fast-roam IE and append it to assoc_ie_list.
+    // Actually this could be done with core_wpx_frame_fast_roam_req_ie_c::instance() to make sure it's size is correct.
+    core_frame_dot11_ie_c* ie = core_frame_dot11_ie_c::instance(
+        reassociation_request_ie_length,
+        reassociation_request_ie,
+        true_t );
+    if ( !ie )
+        {
+        DEBUG( "core_sub_operation_wpa_connect_c::complete_start_wpx_fast_roam_reassociation() - unable to generate a dot11 IE" );
+        is_cached_sa_used_m = false_t;
+        //asynch_goto( core_state_init, CORE_TIMER_IMMEDIATELY );
+        return core_error_no_memory;
+        }
+
+    assoc_ie_list_m.append(
+        ie,
+        ie->element_id() );
+
+    if( eapol_auth_type_m == wlan_eapol_if_eapol_key_authentication_type_wpx_fast_roam &&
+        is_cached_sa_used_m )
+        {
+        server_m->get_connection_data()->set_eapol_authenticating(
+            true_t ); 
+        }
+
+    asynch_goto( core_state_do_connect, CORE_TIMER_IMMEDIATELY );
+    return core_error_ok;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_wpa_connect_c::new_protected_setup_credentials(
+    core_type_list_c< protected_setup_credential_c > & /* credential_list */ )
+    {
+    DEBUG( "core_sub_operation_wpa_connect_c::new_protected_setup_credentials()" );
+    
+    ASSERT( false_t );
+    
+    return core_error_ok;
+    }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_sub_operation_wpa_connect_c::handle_error(
+    wlan_eapol_if_error_e errorcode,
+    wlan_eapol_if_message_type_function_e function )
+    {
+    DEBUG3( "core_sub_operation_wpa_connect_c::handle_error() - Received error message: errorcode=%i, function=%i (operation_state_m=%i)", 
+        errorcode, 
+        function, 
+        operation_state_m );
+    
+    if ( errorcode != wlan_eapol_if_error_ok 
+        && errorcode != wlan_eapol_if_error_pending_request )
+        {
+        if ( function == wlan_eapol_if_message_type_function_start_reassociation )
+            {
+            // Full authentication is needed.
+            is_cached_sa_used_m = false_t;
+            asynch_goto( core_state_start_authentication_needed, CORE_TIMER_IMMEDIATELY );
+            }
+        else if ( function == wlan_eapol_if_message_type_function_start_wpx_fast_roam_reassociation )
+            {
+            is_cached_sa_used_m = false_t;
+
+            asynch_goto( core_state_init, CORE_TIMER_IMMEDIATELY );
+            }
+        else if ( function == wlan_eapol_if_message_type_function_complete_association
+               || function == wlan_eapol_if_message_type_function_complete_reassociation
+               || function == wlan_eapol_if_message_type_function_complete_wpx_fast_roam_reassociation  )
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::handle_error() - (WPX fast-roam) (re-)association failed" );
+            asynch_goto( core_state_req_association_failed, CORE_TIMER_IMMEDIATELY );
+            }
+        /*else if ( function == wlan_eapol_if_message_type_function_start_authentication )
+            {
+            }*/
+        else
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::handle_error() - Error ignored." );
+            }
+        }
+    }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_sub_operation_wpa_connect_c::notify(
+    core_am_indication_e indication )
+    {
+    if ( operation_state_m == core_state_req_state_notification &&
+         ( indication == core_am_indication_wlan_media_disconnect ||
+           indication == core_am_indication_wlan_beacon_lost ||
+           indication == core_am_indication_wlan_power_mode_failure ||
+           indication == core_am_indication_wlan_tx_fail ) )
+        {
+        server_m->unregister_event_handler( this );
+
+        if ( indication == core_am_indication_wlan_media_disconnect )
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::notify() - AP has disconnected us during authentication, notifying EAPOL" );
+            }
+        else
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::notify() - connection to the AP has been lost, notifying EAPOL" );
+            }
+
+        network_id_c network(
+            &current_bssid_m.addr[0],
+            MAC_ADDR_LEN,
+            &server_m->own_mac_addr().addr[0],
+            MAC_ADDR_LEN,
+            server_m->get_eapol_instance().ethernet_type() );
+
+        DEBUG6( "core_sub_operation_wpa_connect_c::notify() - EAPOL disassociation from BSSID %02X:%02X:%02X:%02X:%02X:%02X",
+            current_bssid_m.addr[0], current_bssid_m.addr[1], current_bssid_m.addr[2],
+            current_bssid_m.addr[3], current_bssid_m.addr[4], current_bssid_m.addr[5] );
+
+        server_m->get_eapol_instance().disassociation( &network );
+
+        if ( indication != core_am_indication_wlan_media_disconnect )
+            {
+            DEBUG( "core_sub_operation_wpa_connect_c::notify() - marking is_eapol_authenticating as false" );
+            server_m->get_connection_data()->set_eapol_authenticating(
+                false_t );
+            DEBUG( "core_sub_operation_wpa_connect_c::notify() - marking is_eapol_authentication_started as false" );
+            server_m->get_connection_data()->set_eapol_authentication_started(
+                false_t );
+
+            asynch_goto( core_state_bss_lost );
+
+            return true_t;
+            }
+
+        /**
+         * EAPOL indication will move the state machine forward.
+         */
+
+        return true_t;
+        }
+
+    return false_t;
+    }