wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_server.cpp
changeset 0 c40eb8fe8501
child 7 0abc8c98be24
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_server.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,2495 @@
+/*
+* Copyright (c) 2005-2009 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:  Main class for core server
+*
+*/
+
+/*
+* %version: 89 %
+*/
+
+#include "core_server.h"
+#include "abs_core_server_callback.h"
+#include "abs_core_driverif.h"
+#include "abs_core_timer.h"
+#include "abs_core_frame_handler.h"
+#include "abs_core_event_handler.h"
+#include "core_timer_factory.h"
+#include "core_operation_connect.h"
+#include "core_operation_update_device_settings.h"
+#include "core_operation_scan.h"
+#include "core_operation_get_available_iaps.h"
+#include "core_operation_release.h"
+#include "core_operation_unload_drivers.h"
+#include "core_operation_check_rcpi.h"
+#include "core_operation_handle_frame.h"
+#include "core_operation_null.h"
+#include "core_operation_get_rcpi.h"
+#include "core_operation_configure_multicast_group.h"
+#include "core_operation_update_power_mode.h"
+#include "core_operation_update_rxtx_parameters.h"
+#include "core_operation_get_statistics.h"
+#include "core_operation_set_uapsd_settings.h"
+#include "core_operation_set_power_save_settings.h"
+#include "core_operation_protected_setup.h"
+#include "core_operation_create_ts.h"
+#include "core_operation_delete_ts.h"
+#include "core_operation_power_save_test.h"
+#include "core_operation_set_arp_filter.h"
+#include "core_operation_directed_roam.h"
+#include "core_frame_ethernet.h"
+#include "core_connection_data.h"
+#include "core_eapol_handler.h"
+#include "core_frame_dot11.h"
+#include "core_frame_echo_test.h"
+#include "am_debug.h"
+#include "core_callback.h"
+#include "core_tools.h"
+#include "core_tools_parser.h"
+#include "core_wpx_adaptation_factory.h"
+#include "core_traffic_stream_list_iter.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_server_c::core_server_c(
+    abs_core_server_callback_c& callback,
+    abs_core_driverif_c& drivers,
+    const core_device_settings_s& settings,
+    const core_mac_address_s& mac_address,
+    u32_t features ) :
+    callback_m( callback ),
+    drivers_m( drivers ),
+    device_settings_m( settings ),
+    queue_m( ),
+    queue_timer_m( NULL ),
+    driver_unload_timer_m( NULL ),
+    core_settings_m( features ),
+    connection_data_m( NULL ),
+    own_mac_addr_m( mac_address ),
+    eapol_handler_m( NULL ),
+    eapol_m( NULL ),
+    cm_timer_m( ),
+    roam_timer_m( NULL ),
+    operation_timer_m( NULL ),
+    driver_dhcp_timer_m( NULL ),
+    frame_handler_m( NULL ),
+    event_handler_m( NULL ),
+    scan_list_m( ),
+    wpx_adaptation_m( NULL )
+    {
+    DEBUG( "core_server_c::core_server_c()" );
+    queue_m.clear();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_server_c::~core_server_c()
+    {
+    DEBUG( "core_server_c::~core_server_c()" );
+
+    queue_m.clear();
+    delete connection_data_m;
+
+    if ( queue_timer_m )
+        {
+        queue_timer_m->stop();
+        core_timer_factory_c::destroy_timer( queue_timer_m );
+        queue_timer_m = NULL;
+        }
+    if ( driver_unload_timer_m )
+        {
+        driver_unload_timer_m->stop();
+        core_timer_factory_c::destroy_timer( driver_unload_timer_m );
+        driver_unload_timer_m = NULL;
+        }
+    if ( roam_timer_m )
+        {
+        roam_timer_m->stop();
+        core_timer_factory_c::destroy_timer( roam_timer_m );
+        roam_timer_m = NULL;
+        }
+    if ( operation_timer_m )
+        {
+        operation_timer_m->stop();
+        core_timer_factory_c::destroy_timer( operation_timer_m );
+        operation_timer_m = NULL;
+        }
+    if ( driver_dhcp_timer_m )
+        {
+        driver_dhcp_timer_m->stop();
+        core_timer_factory_c::destroy_timer( driver_dhcp_timer_m );
+        driver_dhcp_timer_m = NULL;
+        }
+    if ( eapol_m )
+        {
+        eapol_m->shutdown();
+        delete eapol_m;
+        }
+    delete wpx_adaptation_m;
+    delete eapol_handler_m;
+    frame_handler_m = NULL;
+    event_handler_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::init()
+    {
+    DEBUG( "core_server_c::init()" );
+
+    drivers_m.init( this );
+
+    core_callback_c* queue_timer_callback = 
+        new core_callback_c( &(core_server_c::queue_timer_expired), this );
+    if( !queue_timer_callback )
+        {
+        DEBUG("ERROR creating callback object");
+        return core_error_no_memory;
+        }
+    queue_timer_m = core_timer_factory_c::create_timer( queue_timer_callback );
+    if( !queue_timer_m )
+        {
+        DEBUG( "ERROR creating timer" );
+        delete queue_timer_callback;
+        return core_error_no_memory;
+        }
+
+    core_callback_c* unload_timer_callback = 
+        new core_callback_c( &(core_server_c::unload_timer_expired), this );
+    if( !unload_timer_callback )
+        {
+        DEBUG("ERROR creating callback object");
+        return core_error_no_memory;
+        }
+    driver_unload_timer_m = core_timer_factory_c::create_timer( unload_timer_callback );
+    if( !driver_unload_timer_m )
+        {
+        DEBUG( "ERROR creating timer" );
+        delete unload_timer_callback;
+        return core_error_no_memory;
+        }
+    
+    core_callback_c* roam_timer_callback = 
+        new core_callback_c( &(core_server_c::roam_timer_expired), this );
+    if( !roam_timer_callback )
+        {
+        DEBUG("ERROR creating callback object");
+        return core_error_no_memory;
+        }
+    roam_timer_m = core_timer_factory_c::create_timer( roam_timer_callback );
+    if( !roam_timer_m )
+        {
+        DEBUG( "ERROR creating timer" );
+        delete roam_timer_callback;
+        return core_error_no_memory;
+        } 
+
+    core_callback_c* operation_timer_callback = 
+        new core_callback_c( &(core_server_c::operation_timer_expired), this );
+    if( !operation_timer_callback )
+        {
+        DEBUG("ERROR creating callback object");
+        return core_error_no_memory;
+        }
+    operation_timer_m = core_timer_factory_c::create_timer( operation_timer_callback );
+    if( !operation_timer_m )
+        {
+        DEBUG( "ERROR creating timer" );
+        delete operation_timer_callback;
+        return core_error_no_memory;
+        } 
+
+    core_callback_c* dhcp_timer_callback = 
+        new core_callback_c( &(core_server_c::dhcp_timer_expired), this );
+    if( !dhcp_timer_callback )
+        {
+        DEBUG("ERROR creating callback object");
+        return core_error_no_memory;
+        }        
+    driver_dhcp_timer_m = core_timer_factory_c::create_timer( dhcp_timer_callback );
+    if( !driver_dhcp_timer_m )
+        {
+        DEBUG( "ERROR creating timer" );
+        delete dhcp_timer_callback;
+        return core_error_no_memory;
+        } 
+
+    wpx_adaptation_m = core_wpx_adaptation_factory_c::instance(
+        this, &drivers_m, &callback_m );
+    if ( !wpx_adaptation_m )
+        {
+        DEBUG("ERROR creating WPX adaptation");
+        return core_error_no_memory;
+        }
+
+    eapol_handler_m = new core_eapol_handler_c(
+        this, &drivers_m, &callback_m );
+    if ( !eapol_handler_m )
+        {
+        DEBUG("ERROR creating eapol handler");
+        return core_error_no_memory;
+        }
+
+    core_settings_m.set_rcpi_boundaries(
+        device_settings_m.rcpi_trigger,
+        device_settings_m.rcpi_trigger + device_settings_m.rcpi_difference );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_device_settings_s& core_server_c::get_device_settings()
+    {
+    return device_settings_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_settings_c& core_server_c::get_core_settings()
+    {
+    return core_settings_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_connection_data_c* core_server_c::get_connection_data()
+    {
+    return connection_data_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_wlan_eapol_interface_c& core_server_c::get_eapol_instance()
+    {
+    return *eapol_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::set_eapol_handler(
+    abs_wlan_eapol_callback_interface_c* handler )
+    {
+    eapol_handler_m->set_eapol_handler( handler );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_mac_address_s& core_server_c::own_mac_addr()
+    {
+    return own_mac_addr_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::queue_int_operation(
+    core_operation_base_c* operation )
+    {
+    DEBUG( "core_server_c::queue_int_operation()" );
+
+    if ( !operation )
+        {
+        DEBUG( "core_server_c::queue_int_operation() - no operation" );
+
+        return core_error_no_memory;
+        }
+    else if ( operation->is_flags( core_operation_base_c::core_base_flag_only_one_instance ) &&
+        is_operation_in_queue_with_type( operation->operation_type() ) )
+        {
+        DEBUG( "core_server_c::queue_int_operation() - only one instance allowed in the operation queue" );
+
+        delete operation;
+        operation = NULL;
+
+        return core_error_already_exists;
+        }
+    else
+        {
+        core_error_e ret = queue_m.append( operation );
+        if ( ret != core_error_ok )
+            {
+            DEBUG1( "core_server_c::queue_int_operation() - unable to queue the request (%u)",
+                ret );
+
+            delete operation;
+            operation = NULL;
+
+            return ret;
+            }
+        }
+
+    return core_error_ok;    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::queue_int_operation_and_run_next(
+    core_operation_base_c* operation )
+    {
+    DEBUG( "core_server_c::queue_int_operation_and_run_next()" );
+
+    core_error_e ret = queue_int_operation( operation );
+    if ( ret != core_error_ok )
+        {
+        return ret;
+        }
+
+    schedule_operation();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::init_connection_data(
+    const core_iap_data_s& iap_data,
+    const core_device_settings_s& device_settings )
+    {
+    connection_data_m = new core_connection_data_c( iap_data, device_settings );
+
+    if ( !connection_data_m )
+        {
+        return core_error_no_memory;
+        }
+
+    return core_error_ok;
+    }
+   
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::clear_connection_data()
+    {
+    DEBUG( "core_server_c::clear_connection_data()" );
+    
+    delete connection_data_m;
+    connection_data_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::schedule_roam_timer(
+    u32_t delay )
+    {
+    DEBUG1( "core_server_c::schedule_roam_timer() - delay %u",
+        delay );
+
+    ASSERT( !roam_timer_m->is_active() );
+
+    roam_timer_m->start(
+        delay );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_roam_timer()
+    {
+    DEBUG( "core_server_c::cancel_roam_timer()" );
+    
+    roam_timer_m->stop();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::roam_timer_expired(
+    void* this_ptr )
+    {
+    DEBUG("core_server_c::roam_timer_expired()");
+    core_server_c* self = static_cast<core_server_c*>( this_ptr );
+
+    // send an indication to adaptation
+    self->callback_m.notify(
+        core_notification_rcpi_roam_attempt_started,
+        0, 
+        NULL );
+    
+    core_operation_base_c* command = new core_operation_check_rcpi_c(
+        REQUEST_ID_CORE_INTERNAL,
+        self,
+        &(self->drivers_m),
+        &(self->callback_m),
+        core_operation_check_rcpi_c::core_rcpi_check_reason_timer );
+
+    self->queue_int_operation_and_run_next( command );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::schedule_operation_timer(
+    u32_t delay )
+    {
+    DEBUG1( "core_server_c::schedule_operation_timer() - delay %u",
+        delay );
+
+    ASSERT( !operation_timer_m->is_active() );
+    operation_timer_m->start(
+        delay );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_operation_timer()
+    {
+    DEBUG( "core_server_c::cancel_operation_timer()" );
+    operation_timer_m->stop();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::operation_timer_expired(
+    void* this_ptr )
+    {
+    DEBUG("core_server_c::operation_timer_expired()");
+    core_server_c* self = static_cast<core_server_c*>( this_ptr );
+
+    core_operation_base_c* command = self->queue_m.first();
+    ASSERT( command );
+    ASSERT( command->is_executing() );
+    self->request_complete( command->request_id(), core_error_ok );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::is_operation_in_queue_with_flags(
+    u32_t feature_flags )
+    {
+    core_type_list_iterator_c<core_operation_base_c> iter( queue_m );
+    for( core_operation_base_c* current = iter.first(); current; current = iter.next() )
+        {
+        if ( current->is_flags( feature_flags ) )
+            {
+            return true_t;
+            }
+        }
+
+    return false_t;    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::is_operation_in_queue_with_type(
+    u32_t type )
+    {
+    core_type_list_iterator_c<core_operation_base_c> iter( queue_m );
+    for( core_operation_base_c* current = iter.first(); current; current = iter.next() )
+        {
+        if ( current->operation_type() == type )
+            {
+            return true_t;
+            }
+        }
+
+    return false_t;    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::is_dhcp_timer_active()
+    {
+    return driver_dhcp_timer_m->is_active();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::schedule_dhcp_timer(
+    u32_t delay )
+    {
+    DEBUG1( "core_server_c::schedule_dhcp_timer() - delay %u",
+        delay );
+
+    ASSERT( !is_dhcp_timer_active() );
+
+    driver_dhcp_timer_m->start(
+        delay );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_dhcp_timer()
+    {
+    DEBUG( "core_server_c::cancel_dhcp_timer()" );
+    
+    driver_dhcp_timer_m->stop();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::dhcp_timer_expired(
+    void* this_ptr )
+    {
+    DEBUG( "core_server_c::dhcp_timer_expired()" );
+
+    core_server_c* self = static_cast<core_server_c*>( this_ptr );
+
+    core_operation_base_c* command = new core_operation_power_save_test_c(
+        REQUEST_ID_CORE_INTERNAL,
+        self,
+        &(self->drivers_m),
+        &(self->callback_m) );        
+
+    self->queue_int_operation_and_run_next( command );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::schedule_unload_timer(
+    u32_t delay )
+    {
+    DEBUG1( "core_server_c::schedule_unload_timer() - delay %u",
+        delay );
+
+    ASSERT( !driver_unload_timer_m->is_active() );
+
+    driver_unload_timer_m->start(
+        delay );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_unload_timer()
+    {
+    DEBUG( "core_server_c::cancel_unload_timer()" );
+
+    driver_unload_timer_m->stop();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_operations_with_flags(
+    u32_t feature_flags )
+    {
+    DEBUG( "core_server_c::cancel_operations_with_flags()" );
+    DEBUG1( "core_server_c::cancel_operations_with_flags() - feature_flags %u",
+        feature_flags );
+
+    core_operation_base_c* command = queue_m.first();
+    while ( command )
+        {
+        if ( !command->is_executing() &&
+             command->is_flags( feature_flags ) )
+            {
+            DEBUG2( "core_server_c::cancel_operations_with_flags() - canceling operation (id %u, type %u)",
+                command->request_id(), command->operation_type() );
+            if ( command->request_id() != REQUEST_ID_CORE_INTERNAL )
+                {
+                DEBUG( "core_server_c::cancel_operations_with_flags() - adaptation request, completing it" );
+                callback_m.request_complete(
+                    command->request_id(),
+                    core_error_cancel );
+                }
+
+            queue_m.remove( command );
+            delete command;
+            command = queue_m.first();
+            }
+        else
+            {
+            command = queue_m.next();
+            }        
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_operations_with_type(
+    u32_t type )
+    {
+    DEBUG( "core_server_c::cancel_operation_with_type()" );
+    DEBUG1( "core_server_c::cancel_operation_with_type() - type %u",
+        type );
+
+    core_operation_base_c* command = queue_m.first();
+    while ( command )
+        {
+        if ( !command->is_executing() &&
+             command->operation_type() == type )
+            {
+            DEBUG2( "core_server_c::cancel_operation_with_type() - canceling operation (id %u, type %u)",
+                command->request_id(), command->operation_type() );
+            if ( command->request_id() != REQUEST_ID_CORE_INTERNAL )
+                {
+                DEBUG( "core_server_c::cancel_operation_with_type() - adaptation request, completing it" );
+                callback_m.request_complete(
+                    command->request_id(),
+                    core_error_cancel );
+                }
+
+            queue_m.remove( command );
+            delete command;
+            command = queue_m.first();
+            }
+        else
+            {
+            command = queue_m.next();
+            }
+        }       
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_all_operations(
+    bool_t is_graceful_cancel )
+    {
+    DEBUG( "core_server_c::cancel_all_operations()" );
+
+    core_operation_base_c* command = queue_m.first();
+    while ( command )
+        {
+        if ( !command->is_executing() )
+            {
+            DEBUG2( "core_server_c::cancel_all_operations() - canceling operation (id %u, type %u)",
+                command->request_id(), command->operation_type() );
+            if ( command->request_id() != REQUEST_ID_CORE_INTERNAL )
+                {
+                DEBUG( "core_server_c::cancel_all_operations() - adaptation request, completing it" );
+                callback_m.request_complete(
+                    command->request_id(),
+                    core_error_cancel );
+                }
+
+            queue_m.remove( command );
+            delete command;
+            command = queue_m.first();
+            }
+        else
+            {
+            command = queue_m.next();
+            }
+        }
+
+    command = queue_m.first();
+    if ( command )
+        {
+        if( is_graceful_cancel )
+            {
+            DEBUG2( "core_server_c::cancel_all_operations() - canceling currently executing operation (id %u, type %u) (graceful cancel)",
+                command->request_id(), command->operation_type() );
+            }
+        else
+            {
+            DEBUG2( "core_server_c::cancel_all_operations() - canceling currently executing operation (id %u, type %u) (forced cancel)",
+                command->request_id(), command->operation_type() );
+            }
+
+        ASSERT( command->is_executing() );
+
+        // Let operation handle it's own cancelling
+        command->user_cancel_operation( is_graceful_cancel );
+        }   
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::create_eapol_instance(
+    core_eapol_operating_mode_e mode )
+    {
+    DEBUG( "core_server_c::create_eapol_instance()" );
+
+    if ( eapol_m &&
+        eapol_m->operating_mode() == mode )
+        {
+        DEBUG( "core_server_c::create_eapol_instance() - an instance already exists" );
+
+        return true_t;
+        }
+
+    if ( eapol_m )
+        {
+        DEBUG( "core_server_c::create_eapol_instance() - deleting old core_wlan_eapol_interface_c instance" );
+
+        eapol_m->shutdown();
+        delete eapol_m;
+        eapol_m = NULL;
+        }
+    
+    DEBUG1( "core_server_c::create_eapol_instance() - creating core_wlan_eapol_interface_c (mode %u)",
+        mode );
+
+    eapol_m = new core_wlan_eapol_interface_c( callback_m );
+    if ( !eapol_m )
+        {
+        DEBUG( "core_server_c::create_eapol_instance() - unable to create core_wlan_eapol_interface_c" );
+        return false_t;
+        }
+    core_error_e error = eapol_m->load_eapol( mode, eapol_handler_m );
+    if ( error != core_error_ok )
+        {
+        DEBUG1( "core_server_c::create_eapol_instance() - load_eapol failed with %i", error );
+        delete eapol_m;
+        eapol_m = NULL;
+        return false_t;
+        }
+    error = eapol_m->configure();
+    if ( error != core_error_ok )
+        {
+        DEBUG1( "core_server_c::create_eapol_instance() - configure failed with %i", error );
+        delete eapol_m;
+        eapol_m = NULL;
+        return false_t;
+        }
+
+    return true_t;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+abs_core_frame_handler_c* core_server_c::frame_handler()
+    {
+    return frame_handler_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::register_frame_handler(
+    abs_core_frame_handler_c* handler )
+    {
+    ASSERT( handler );
+    ASSERT( handler == frame_handler_m || !frame_handler_m );
+
+    frame_handler_m = handler;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::unregister_frame_handler(
+    abs_core_frame_handler_c* handler )
+    {
+    ASSERT( handler );
+    
+    if ( frame_handler_m != handler )
+        {
+        DEBUG1( "core_server_c::unregister_frame_handler() - handler 0x%08X not registered",
+            handler );
+
+        return;
+        }
+
+    frame_handler_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_scan_list_c& core_server_c::get_scan_list()
+    {
+    return scan_list_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+abs_core_event_handler_c* core_server_c::event_handler()
+    {
+    return event_handler_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::register_event_handler(
+    abs_core_event_handler_c* handler )
+    {
+    ASSERT( handler );
+    ASSERT( handler == event_handler_m || !event_handler_m );
+
+    event_handler_m = handler;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::unregister_event_handler(
+    abs_core_event_handler_c* handler )
+    {
+    ASSERT( handler );
+
+    if ( event_handler_m != handler )
+        {
+        DEBUG1( "core_server_c::unregister_event_handler() - handler 0x%08X not registered",
+            handler );
+
+        return;
+        }
+
+    event_handler_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::schedule_roam(
+    core_operation_handle_bss_lost_c::core_bss_lost_reason_e reason )
+    {
+    if ( !is_operation_in_queue_with_type( core_operation_handle_bss_lost ) )
+        {       
+        DEBUG( "core_server_c::schedule_roam() - scheduling a core_operation_handle_bss_lost operation" );
+
+        core_operation_base_c* command = new core_operation_handle_bss_lost_c(
+            REQUEST_ID_CORE_INTERNAL,
+            this,
+            &drivers_m,
+            &callback_m,
+            reason );
+
+        queue_int_operation_and_run_next( command );
+        }
+    else
+        {
+        DEBUG( "core_server_c::schedule_roam() - core_operation_handle_bss_lost already in the queue" );
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::send_management_frame(
+    core_frame_type_e frame_type,
+    const u16_t frame_length,
+    const u8_t* const frame_data,
+    const core_mac_address_s& destination )
+    {
+    /** Management frames can be sent without downgraded user priority. */
+    drivers_m.send_frame(
+        frame_type,
+        frame_length,
+        frame_data,
+        core_tools_c::convert_ac_to_user_priority( core_access_class_voice ),
+        destination,
+        true_t );    
+
+    return true_t;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_server_c::send_data_frame(
+    const core_ap_data_c& ap_data,
+    core_frame_type_e frame_type,
+    const u16_t frame_length,
+    const u8_t* const frame_data,
+    core_access_class_e frame_priority,
+    const core_mac_address_s& destination,
+    bool_t send_unencrypted )
+    {
+    DEBUG( "core_server_c::send_data_frame()" );
+    
+    u8_t initial_priority(
+        core_tools_c::convert_ac_to_user_priority( frame_priority ) );
+    u8_t user_priority = initial_priority;
+      
+    if ( ap_data.is_wmm_ie_present() )
+        {
+        /**
+         * Collect a list of active streams per user priority.
+         */
+        bool_t is_ts_for_user_priority[MAX_QOS_USER_PRIORITY];
+        core_tools_c::fillz(
+            &is_ts_for_user_priority[0],
+            sizeof( is_ts_for_user_priority ) );
+
+        core_traffic_stream_list_iter_c iter(
+            get_connection_data()->traffic_stream_list() );
+
+        core_traffic_stream_c* entry = iter.first();
+        while( entry )
+            {
+            if ( entry->status() == core_traffic_stream_status_active )
+                {
+                is_ts_for_user_priority[entry->user_priority()] = true_t;
+                }
+
+            entry = iter.next();
+            }
+
+        /**
+         * See if downgrade should be done.
+         */
+        bool_t is_send_ok( false_t );        
+
+        while ( user_priority <= initial_priority && !is_send_ok )
+            {
+            core_access_class_e ac(
+                core_tools_c::convert_user_priority_to_ac( user_priority ) );
+
+#if 0
+            DEBUG1( "core_server_c::send_data_frame() - user_priority is %u",
+                user_priority );
+            DEBUG1( "core_server_c::send_data_frame() - ac is %u",
+                ac );
+            DEBUG1( "core_server_c::send_data_frame() - is_admission_control_required is %u",
+                ap_data.is_admission_control_required( ac ) );
+            DEBUG1( "core_server_c::send_data_frame() - is_ts_for_user_priority is %u",
+                is_ts_for_user_priority[user_priority] );
+#endif // 0
+
+            if ( !ap_data.is_admission_control_required( ac ) ||
+                 is_ts_for_user_priority[user_priority] )
+                {
+                is_send_ok = true_t;
+                }
+            else
+                {
+                user_priority--;
+                }
+            }
+
+        if ( !is_send_ok )
+            {
+            DEBUG( "core_server_c::send_data_frame() - unable to send the frame due to admission control settings" );
+            return false_t;
+            }
+        }
+
+    if ( user_priority == initial_priority )
+        {
+        DEBUG1( "core_server_c::send_data_frame() - no need to downgrade user priority %u",
+            user_priority );
+        }
+    else
+        {
+        DEBUG2( "core_server_c::send_data_frame() - user priority %u downgraded to %u",
+            initial_priority, user_priority );
+        }
+
+    drivers_m.send_frame(
+        frame_type,
+        frame_length,
+        frame_data,
+        user_priority,
+        destination,
+        send_unencrypted ); 
+
+    return true_t;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+abs_core_wpx_adaptation_c& core_server_c::get_wpx_adaptation_instance()
+    {
+    return *wpx_adaptation_m;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::set_protected_setup_handler(
+    abs_core_protected_setup_handler_c* handler )
+    {
+    eapol_handler_m->set_protected_setup_handler( handler );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::connect(
+    u32_t request_id,
+    const core_iap_data_s& settings,
+    core_connect_status_e& connect_status,
+    core_type_list_c<core_ssid_entry_s>* ssid_list )
+    {
+    DEBUG( "core_server_c::connect()" );
+
+    core_operation_base_c* command = new core_operation_connect_c(
+        request_id, this, &drivers_m, &callback_m, settings, ssid_list, connect_status );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::release(
+    u32_t request_id )
+    {
+    DEBUG( "core_server_c::release()" );
+
+    /**
+     * Cancel all pending roaming operations.
+     */
+    cancel_operations_with_flags(
+        core_operation_base_c::core_base_flag_roam_operation );
+
+    /**
+     * If there's an executing roam operation, let it handle
+     * its own cancel.
+     */
+    core_operation_base_c* operation = queue_m.first();
+    if( operation &&
+        operation->is_flags( core_operation_base_c::core_base_flag_roam_operation ) )
+        {
+        operation->user_cancel_operation( true_t ); // Using graceful cancel
+        }
+
+    core_operation_base_c* command = new core_operation_release_c(
+        request_id, this, &drivers_m, &callback_m, core_release_reason_external_request );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::get_scan_result(
+    u32_t request_id,
+    core_scan_mode_e scan_mode,
+    const core_ssid_s& scan_ssid,    
+    const core_scan_channels_s& scan_channels,
+    u8_t scan_max_age,
+    ScanList& scan_data,
+    bool_t is_current_ap_added )
+    {
+    DEBUG( "core_server_c::get_scan_result()" );
+    
+    core_operation_base_c* command = new core_operation_scan_c(
+        request_id, this, &drivers_m, &callback_m,
+        scan_mode, scan_ssid, scan_channels, scan_max_age, scan_data, 
+        true_t,
+        is_current_ap_added );
+
+    queue_ext_operation_and_run_next( command, request_id );    
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::get_available_iaps(
+    u32_t request_id,
+    bool_t is_active_scan_allowed,
+    core_type_list_c<core_iap_data_s>& iap_data_list,
+    core_type_list_c<u32_t>& iap_id_list,
+    core_type_list_c<core_ssid_entry_s>* iap_ssid_list,
+    ScanList& scan_data )
+    {
+    DEBUG( "core_server_c::get_available_iaps()" );
+
+    core_operation_base_c* command = new core_operation_get_available_iaps_c(
+        request_id, 
+        this, 
+        &drivers_m, 
+        &callback_m, 
+        is_active_scan_allowed, 
+        iap_data_list, 
+        iap_id_list,
+        iap_ssid_list,
+        scan_data );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::get_current_rcpi(
+    u32_t request_id,
+    u32_t& rcpi )
+    {
+    DEBUG( "core_server_c::get_current_rcpi()" );
+    
+    core_operation_base_c* command = new core_operation_get_rcpi_c(
+        request_id, this, &drivers_m, &callback_m, rcpi );
+
+    queue_ext_operation_and_run_next( command, request_id );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::disable_wlan(
+    u32_t request_id )
+    {
+    DEBUG( "core_server_c::disable_wlan()" );
+
+    get_core_settings().set_wlan_enabled( false_t );
+
+    /**
+     * Schedule an immediate driver unload.
+     */ 
+    unload_drivers();
+
+    core_operation_base_c* command = new core_operation_null_c(
+        request_id, this, &drivers_m, &callback_m, core_error_ok );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::enable_wlan(
+    u32_t request_id )
+    {
+    DEBUG( "core_server_c::enable_wlan()" );
+    
+    core_settings_m.set_wlan_enabled( true_t );
+    
+    core_operation_base_c* command = new core_operation_null_c(
+        request_id, this, &drivers_m, &callback_m, core_error_ok );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::unload_drivers()
+    {
+    DEBUG( "core_server_c::unload_drivers()" );
+
+    /**
+     * If drivers are loaded, schedule an immediate unload.
+     */
+    if( get_core_settings().is_driver_loaded() )
+        {
+        cancel_unload_timer();
+        schedule_unload_timer( CORE_TIMER_IMMEDIATELY );
+
+        return core_error_ok;
+        }
+    else
+        {
+        return core_error_drivers_not_loaded;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::get_packet_statistics(
+    u32_t request_id,
+    core_packet_statistics_s& statistics )
+    {
+    DEBUG( "core_server_c::get_packet_statistics()" );
+
+    core_operation_base_c* command = new core_operation_get_statistics_c(
+        request_id, this, &drivers_m, &callback_m, statistics );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::create_traffic_stream(
+    u32_t request_id,
+    u8_t tid,
+    u8_t user_priority,
+    bool_t is_automatic_stream,
+    const core_traffic_stream_params_s& params,
+    u32_t& stream_id,
+    core_traffic_stream_status_e& stream_status )
+    {
+    DEBUG( "core_server_c::create_traffic_stream()" );
+
+    core_operation_base_c* command = new core_operation_create_ts_c(
+        request_id,
+        this,
+        &drivers_m,
+        &callback_m,
+        tid,
+        user_priority,
+        is_automatic_stream,
+        params,
+        stream_id,
+        stream_status );
+   
+    queue_ext_operation_and_run_next( command, request_id );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::delete_traffic_stream(
+    u32_t request_id,
+    u32_t stream_id )
+    {
+    DEBUG( "core_server_c::delete_traffic_stream()" );
+
+    core_operation_base_c* command = new core_operation_delete_ts_c(
+        request_id,
+        this,
+        &drivers_m,
+        &callback_m,
+        stream_id );
+
+    queue_ext_operation_and_run_next( command, request_id );    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+// 
+void core_server_c::run_protected_setup(
+    u32_t request_id, 
+    const core_iap_data_s& iap_data,
+    core_type_list_c<core_iap_data_s>& iap_data_list,
+    core_protected_setup_status_e& protected_setup_status )
+    {
+    DEBUG( "core_server_c::run_protected_setup()" );
+    
+    core_operation_base_c* command = new core_operation_protected_setup_c(
+        request_id, this, &drivers_m, &callback_m, iap_data, iap_data_list,
+        protected_setup_status );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::directed_roam(
+    u32_t request_id,
+    const core_mac_address_s& bssid )
+    {
+    DEBUG( "core_server_c::directed_roam()" );
+
+    core_operation_base_c* command = new core_operation_directed_roam_c(
+        request_id, this, &drivers_m, &callback_m, bssid );
+
+    queue_ext_operation_and_run_next( command, request_id );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_bssid(
+    core_mac_address_s& bssid )
+    {
+    DEBUG( "core_server_c::get_current_bssid()" );
+
+    bssid = ZERO_MAC_ADDR;
+    if ( core_settings_m.is_connected() &&
+         connection_data_m &&
+         connection_data_m->current_ap_data() )
+        {
+        bssid = connection_data_m->current_ap_data()->bssid();
+
+        return core_error_ok;
+        }
+
+    return core_error_not_connected;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_ssid(
+    core_ssid_s& ssid )
+    {
+    DEBUG( "core_server_c::get_current_ssid()" );
+
+    ssid = BROADCAST_SSID;
+    if ( core_settings_m.is_connected() &&
+         connection_data_m &&
+         connection_data_m->current_ap_data() )
+        {
+        ssid = connection_data_m->ssid();
+
+        return core_error_ok;
+        }
+
+    return core_error_not_connected;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_security_mode(
+    core_connection_security_mode_e& mode )
+    {
+    DEBUG( "core_server_c::get_current_security_mode()" );
+
+    mode = core_connection_security_mode_open;
+    if ( core_settings_m.is_connected() &&
+         connection_data_m &&
+         connection_data_m->current_ap_data() )
+        {
+        mode = core_tools_c::security_mode(
+            connection_data_m->iap_data(),
+            *connection_data_m->current_ap_data() );
+
+        return core_error_ok;
+        }
+
+    return core_error_not_connected;
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_connection_state(
+    core_connection_state_e& state )
+    {
+    DEBUG( "core_server_c::get_current_connection_state()" );
+
+    state = core_settings_m.connection_state();
+
+    return core_error_ok;
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::update_device_settings(
+    core_device_settings_s& settings )
+    {
+    DEBUG( "core_server_c::update_device_settings()" );
+
+    device_settings_m = settings;
+
+    core_operation_base_c* command = new core_operation_update_device_settings_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::set_power_save_mode(
+    const core_power_save_mode_s& mode )
+    {
+    DEBUG( "core_server_c::set_power_save_mode()" );
+
+    core_settings_m.set_preferred_power_save_mode( mode );
+
+    core_operation_base_c* command = new core_operation_update_power_mode_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;        
+    }
+    
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::add_bssid_to_rogue_list(
+    const core_mac_address_s& bssid )
+    {
+    DEBUG( "core_server_c::add_bssid_to_rogue_list()" );
+
+    core_settings_m.add_mac_to_permanent_blacklist(
+        bssid, core_ap_blacklist_reason_external );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//   
+core_error_e core_server_c::remove_bssid_from_rogue_list(
+    const core_mac_address_s& bssid )
+    {
+    DEBUG( "core_server_c::remove_bssid_from_rogue_list()" );
+
+    core_settings_m.remove_mac_from_permanent_blacklist( bssid );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_rogue_list(
+    core_type_list_c<core_mac_address_s>& rogue_list )
+    {
+    DEBUG( "core_server_c::get_rogue_list()" );
+
+    core_type_list_c<core_ap_blacklist_entry_s>& perm_list = core_settings_m.permanent_blacklist();
+    DEBUG1( "core_server_c::get_rogue_list() - %d permanent addresses", perm_list.count() );
+
+    // Loop through permanent blacklist
+    core_ap_blacklist_entry_s* addr = perm_list.first();
+    while ( addr )
+        {
+        // Address must be copied, because rogue_list get ownership for its entries.
+        core_mac_address_s* copy_addr = new core_mac_address_s;
+        if ( !copy_addr )
+            {
+            return core_error_no_memory;
+            }
+        *copy_addr = addr->bssid;
+        DEBUG_MAC( copy_addr->addr );
+        
+        core_error_e status = rogue_list.append( copy_addr );
+        if ( status != core_error_ok )
+            {
+            return status;
+            }
+
+        addr = perm_list.next();
+        }
+
+    // Check if connection is available.
+    if ( connection_data_m )
+        {
+        core_type_list_c<core_ap_blacklist_entry_s>& temp_list = connection_data_m->temporary_blacklist();
+        DEBUG1( "core_server_c::get_rogue_list() - %d temporary addresses", temp_list.count() );
+        
+        // Loop through temporary blacklist
+        addr = temp_list.first();
+        while ( addr )
+            {
+            // Address must be copied, because rogue_list get ownership for its entries.
+            core_mac_address_s* copy_addr = new core_mac_address_s;
+            if ( !copy_addr )
+                {
+                return core_error_no_memory;
+                }
+            *copy_addr = addr->bssid;
+            DEBUG_MAC( copy_addr->addr );
+            
+            core_error_e status = rogue_list.append( copy_addr );
+            if ( status != core_error_ok )
+                {
+                return status;
+                }
+    
+            addr = temp_list.next();
+            }
+        }
+    else
+        {
+        DEBUG( "core_server_c::get_rogue_list() - connection is not available, temporary blacklist is empty" );
+        }
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//  
+core_error_e core_server_c::set_rcp_level_notification_boundary(
+    const i32_t rcp_level_boundary,
+    const i32_t hysteresis )
+    {
+    DEBUG( "core_server_c::set_rcp_level_notification_boundary()" );
+
+    core_settings_m.set_rcpi_boundaries(
+        rcp_level_boundary,
+        rcp_level_boundary + hysteresis );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::clear_packet_statistics()
+    {
+    DEBUG( "core_server_c::clear_packet_statistics()" );
+
+    core_settings_m.clear_connection_statistics();
+    core_settings_m.roam_metrics().clear_metrics();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+core_error_e core_server_c::get_uapsd_settings(
+    core_uapsd_settings_s& settings )
+    {
+    DEBUG( "core_server_c::get_uapsd_settings()" );
+
+    settings = core_settings_m.uapsd_settings();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//   
+core_error_e core_server_c::set_uapsd_settings(
+    const core_uapsd_settings_s& settings )
+    {
+    DEBUG( "core_server_c::set_uapsd_settings()" );
+
+    core_operation_base_c* command = new core_operation_set_uapsd_settings_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, settings );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;  
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+core_error_e core_server_c::get_power_save_settings(
+    core_power_save_settings_s& settings )
+    {
+    DEBUG( "core_server_c::get_power_save_settings()" );
+
+    settings = core_settings_m.power_save_settings();
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//   
+core_error_e core_server_c::set_power_save_settings(
+    const core_power_save_settings_s& settings )
+    {
+    DEBUG( "core_server_c::set_power_save_settings()" );
+
+    core_operation_base_c* command = new core_operation_set_power_save_settings_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, settings );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;  
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_ap_info(
+    core_ap_information_s& info )
+    {
+    DEBUG( "core_server_c::get_current_ap_info()" );
+
+    if ( core_settings_m.is_connected() &&
+         connection_data_m &&
+         connection_data_m->current_ap_data() )
+        {
+        info = core_tools_parser_c::get_ap_info(
+            connection_data_m->iap_data(),
+            *connection_data_m->current_ap_data() );
+
+        return core_error_ok;
+        }
+
+    return core_error_not_connected;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::get_roam_metrics(
+    core_roam_metrics_s& roam_metrics )
+    {
+    DEBUG( "core_server_c::get_roam_metrics()" );
+
+    core_roam_metrics_c& metrics = get_core_settings().roam_metrics();
+
+    roam_metrics.connection_attempt_total_count = metrics.roam_attempt_count( core_roam_reason_initial_connect );
+    roam_metrics.unsuccesfull_connection_attempt_count = 
+          metrics.roam_attempt_failed_count( core_roam_failed_reason_timeout )
+        + metrics.roam_attempt_failed_count( core_roam_failed_reason_ap_status_code )
+        + metrics.roam_attempt_failed_count( core_roam_failed_reason_eapol_failure )
+        + metrics.roam_attempt_failed_count( core_roam_failed_reason_other_failure );
+
+    roam_metrics.roaming_counter = metrics.roam_success_count();
+    roam_metrics.coverage_loss_count = metrics.roam_attempt_count( core_roam_reason_bss_lost );
+
+    roam_metrics.last_roam_total_duration = metrics.roam_total_delay() / MILLISECONDS_FROM_MICROSECONDS;
+    roam_metrics.last_roam_data_path_broken_duration = metrics.roam_total_delay() / MILLISECONDS_FROM_MICROSECONDS;
+
+    roam_metrics.last_roam_reason = core_roam_reason_none;
+    if ( get_connection_data() )
+        {
+        roam_metrics.last_roam_reason = get_connection_data()->last_roam_reason();
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::set_arp_filter(
+    const core_arp_filter_s& filter )
+    {
+    DEBUG( "core_server_c::set_arp_filter()" );
+
+    core_operation_base_c* command = new core_operation_set_arp_filter_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, filter );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::configure_multicast_group(
+    bool_t join_group,
+    const core_mac_address_s& multicast_addr )
+    {
+    DEBUG( "core_server_c::configure_multicast_group" );
+
+    core_operation_base_c* command = new core_operation_configure_multicast_group_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, join_group, multicast_addr );
+
+    queue_int_operation_and_run_next( command );
+
+    return core_error_ok;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_server_c::get_current_ac_traffic_info(
+    core_ac_traffic_information_s& info )
+    {
+    DEBUG( "core_server_c::get_current_ac_traffic_info()" );
+
+    if ( core_settings_m.is_connected() &&
+         connection_data_m &&
+         connection_data_m->current_ap_data() )
+        {
+        info.status_for_voice = connection_data_m->ac_traffic_status(
+            core_access_class_voice );
+        info.status_for_video = connection_data_m->ac_traffic_status(
+            core_access_class_video );
+        info.status_for_best_effort = connection_data_m->ac_traffic_status(
+            core_access_class_best_effort );
+        info.status_for_background = connection_data_m->ac_traffic_status(
+            core_access_class_background );
+        info.mode_for_voice = connection_data_m->ac_traffic_mode(
+            core_access_class_voice );
+        info.mode_for_video = connection_data_m->ac_traffic_mode(
+            core_access_class_video );
+        info.mode_for_best_effort = connection_data_m->ac_traffic_mode(
+            core_access_class_best_effort );
+        info.mode_for_background = connection_data_m->ac_traffic_mode(
+            core_access_class_background );
+
+        return core_error_ok;
+        }
+
+    return core_error_not_connected;    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::request_complete(
+    u32_t /* request_id */,
+    core_error_e status )
+    {
+    DEBUG( "core_server_c::request_complete()" );
+    
+    core_operation_base_c* operation = queue_m.first();
+    
+    ASSERT( operation );
+    ASSERT( operation->is_executing() );
+
+    core_error_e ret = operation->continue_operation( status );
+    if ( ret == core_error_request_pending )
+        {
+        DEBUG( "core_server_c::request_complete() - operation is not done yet" );
+        return;
+        }
+
+    DEBUG1( "core_server_c::request_complete() - operation completed with code %u",
+        ret );
+
+    if ( operation->request_id() != REQUEST_ID_CORE_INTERNAL )
+        {
+        callback_m.request_complete(
+            operation->request_id(),
+            ret );
+        }
+
+    queue_m.remove( operation );
+    delete operation;
+    operation = NULL;
+
+    schedule_operation();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::cancel_request(
+    u32_t request_id )
+    {
+    DEBUG( "core_server_c::cancel_request()" );
+    
+    // Find correct operation
+    core_operation_base_c* operation = queue_m.first();
+    while ( operation )
+        {
+        if ( operation->request_id() == request_id )
+            {
+            break;
+            }
+        operation = queue_m.next();
+        }
+    
+    if ( !operation )
+        {
+        DEBUG( "core_server_c::cancel_request() - operation not found" );
+        return;
+        }
+    
+    if ( operation->is_executing() )
+        {
+        // Let operation handle it's own cancelling
+        operation->user_cancel_operation( true_t ); // Using graceful cancel
+        }
+    else
+        {
+        // When operation is not yet running, we don't need to ask for it's permissions...
+        queue_m.remove( operation );
+        delete operation;
+        operation = NULL;
+        
+        // Use null operation for completing correctly
+        operation = new core_operation_null_c(
+            request_id, this, &drivers_m, &callback_m, core_error_cancel );
+        queue_ext_operation_and_run_next( operation, request_id );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//  
+void core_server_c::receive_frame(
+    core_frame_type_e frame_type,
+    const u16_t frame_length,
+    const u8_t* const frame_data,
+    u8_t frame_rcpi )
+    {
+    DEBUG( "core_server_c::receive_frame()" );
+
+    DEBUG1( "core_server_c::receive_frame() - frame type: %u", frame_type );
+    DEBUG1( "core_server_c::receive_frame() - frame (%u bytes): ",
+        frame_length );
+    DEBUG_BUFFER(
+        frame_length,
+        frame_data );
+
+    if ( frame_type == core_frame_type_ethernet )
+        {
+        core_frame_ethernet_c* frame = core_frame_ethernet_c::instance(
+            frame_length,
+            frame_data,
+            false_t );
+        if ( frame )             
+            {
+            /**
+             * Currently all Ethernet frames are for EAPOL.
+             */
+
+            /**
+             * If an Ethernet frame is received during a roam, store it
+             * for later use.
+             */
+            if ( get_connection_data()->is_eapol_connecting() )
+                {
+                DEBUG( "core_server_c::receive_frame() - (re-)association in progress, storing EAPOL frame" );
+
+                (void)eapol_m->store_frame( *frame );
+                }
+            /**
+             * Frames are discarded during disconnect.
+             */
+            else if ( get_connection_data()->is_disconnecting() )
+                {
+                DEBUG( "core_server_c::receive_frame() - disconnect in progress, discarding EAPOL frame" );
+                }
+            /**
+             * Otherwise send it to EAPOL for processing.
+             */
+            else if ( eapol_m )
+                {
+                // Clear stored frame so that it is not sent later.
+                eapol_m->clear_stored_frame();
+                
+                (void)eapol_m->process_frame( *frame );
+                }
+            else
+                {
+                DEBUG( "core_server_c::receive_frame() - EAPOL not instantiated, discarding EAPOL frame" );
+                }
+
+            delete frame;
+            frame = NULL;
+            }
+
+        return;
+        }
+
+    /**
+     * WPX frames are handled separately.
+     */
+    if ( wpx_adaptation_m->handle_wpx_frame(
+            frame_type,
+            frame_length,
+            frame_data ) )
+        {
+        return;
+        }
+
+    /**
+     * Offer dot11 and echo test frames to the registered frame handler.
+     */
+    bool_t is_handled( false_t );
+
+    if ( frame_type == core_frame_type_dot11 &&
+         frame_handler_m )
+        {                
+        core_frame_dot11_c* frame = core_frame_dot11_c::instance(
+            frame_length,
+            frame_data,
+            false_t );
+        if ( frame &&
+             frame_handler_m->receive_frame( frame, frame_rcpi ) )
+            {
+            DEBUG( "core_server_c::receive_frame() - dot11 frame handled by the operation" );
+
+            is_handled = true_t;
+            }
+
+        delete frame;
+        frame = NULL;
+        }
+    else if ( frame_type == core_frame_type_test &&
+              frame_handler_m )
+        {
+        core_frame_ethernet_c* frame = core_frame_ethernet_c::instance(
+            frame_length,
+            frame_data,
+            false_t );
+        if ( frame )
+            {
+            core_frame_echo_test_c* test_frame = core_frame_echo_test_c::instance(
+                *frame );
+            if ( test_frame &&
+                 frame_handler_m->receive_test_frame( test_frame, frame_rcpi ) )
+                {
+                DEBUG( "core_server_c::receive_frame() - echo test frame handled by the operation" );
+
+                is_handled = true_t;                
+                }
+
+            delete test_frame;
+            test_frame = NULL;
+
+            delete frame;
+            frame = NULL;            
+            }
+        }
+
+    /**
+     * All other frames are processed in an operation.
+     */
+    if ( !is_handled )
+        {
+        DEBUG( "core_server_c::receive_frame() - queueing the frame for processing" );
+
+        core_operation_base_c* command = new core_operation_handle_frame_c(
+            REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m,
+            frame_type, frame_length, frame_data );
+
+        queue_int_operation_and_run_next( command );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::notify(
+    core_am_indication_e indication )
+    {
+    DEBUG( "core_server_c::notify()" );
+
+#ifdef _DEBUG
+    switch ( indication )
+        {
+        case core_am_indication_wlan_media_disconnect:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_media_disconnect" );
+            break;
+        case core_am_indication_wlan_hw_failed:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_hw_failed" );
+            break;
+        case core_am_indication_wlan_beacon_lost:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_beacon_lost" );
+            break;
+        case core_am_indication_wlan_power_mode_failure:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_power_mode_failure" );
+            break;
+        case core_am_indication_wlan_tx_fail:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_tx_fail" );
+            break;
+        case core_am_indication_wlan_bss_regained:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_bss_regained" );
+            break;
+        case core_am_indication_wlan_wep_decrypt_failure:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_wep_decrypt_failure" );
+            break;
+        case core_am_indication_wlan_pairwise_key_mic_failure:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_pairwise_key_mic_failure" );
+            break;
+        case core_am_indication_wlan_group_key_mic_failure: 
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_group_key_mic_failure" );
+            break;
+        case core_am_indication_wlan_scan_complete:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_scan_complete" );
+            break;
+        case core_am_indication_wlan_rcpi_trigger:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_rcpi_trigger" );
+            break;
+        case core_am_indication_wlan_signal_loss_prediction:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_signal_loss_prediction" );
+            break;
+        case core_am_indication_wlan_power_save_test_trigger:
+            DEBUG( "core_server_c::notify() - core_am_indication_wlan_power_save_test_trigger" );
+            break;       
+        case core_am_indication_os_power_standby:
+            DEBUG( "core_server_c::notify() - core_am_indication_os_power_standby" );
+            break;
+        case core_am_indication_bt_connection_established:
+            DEBUG( "core_server_c::notify() - core_am_indication_bt_connection_established" );
+            break;
+        case core_am_indication_bt_connection_disconnected:
+            DEBUG( "core_server_c::notify() - core_am_indication_bt_connection_disconnected" );
+            break;
+        case core_am_indication_voice_call_on:
+            DEBUG( "core_server_c::notify() - core_am_indication_voice_call_on" );
+            break;
+        case core_am_indication_voice_call_off:
+            DEBUG( "core_server_c::notify() - core_am_indication_voice_call_off" );
+            break;
+        default:
+            break;
+        }
+#endif // _DEBUG
+
+    if ( event_handler_m &&
+         event_handler_m->notify( indication ) )
+        {
+        DEBUG( "core_server_c::notify() - indication handled by the operation" );
+
+        return;
+        }
+
+    switch ( indication )
+        {
+        case core_am_indication_os_power_standby:
+            {
+            /**
+             * Cancel all operations including the currently executing one.
+             */
+            cancel_all_operations( true_t );
+
+            /**
+             * Force an immediate driver unload.
+             */ 
+            queue_unload_drivers();
+
+            break;
+            }
+        case core_am_indication_wlan_hw_failed:
+            {
+            /**
+             * Cancel all operations including the currently executing one.
+             */
+            cancel_all_operations( false_t );
+
+            /**
+             * Force an immediate driver unload.
+             */
+            queue_unload_drivers();
+
+            break;
+            }
+        case core_am_indication_wlan_media_disconnect:
+            {
+            /**
+             * If the current operation is connect, handle_bss_lost or protected_setup, the indication
+             * is silently ignored. Otherwise this indication is handled like a BSS lost.
+             */
+            core_operation_base_c* op = queue_m.first();
+            if( op &&
+                op->is_executing() &&
+                ( op->operation_type() == core_operation_handle_bss_lost ||
+                  op->operation_type() == core_operation_connect ||
+                  op->operation_type() == core_operation_protected_setup ) )
+                {
+                DEBUG( "core_server_c::notify() - ignoring indication" );
+                }
+            else
+                {
+                schedule_roam(
+                    core_operation_handle_bss_lost_c::core_bss_lost_reason_media_disconnect );
+                }
+
+            break;
+            }
+        case core_am_indication_wlan_beacon_lost:
+            /** Falls through on purpose. */
+        case core_am_indication_wlan_power_mode_failure:
+            /** Falls through on purpose. */
+        case core_am_indication_wlan_tx_fail:
+            {
+            // bss_lost is only handled in infrastructure mode
+            if ( connection_data_m->iap_data().operating_mode() == core_operating_mode_infrastructure )
+                {
+                // send an indication to adaptation
+                callback_m.notify(
+                    core_notification_bss_lost,
+                    0, 
+                    NULL );
+
+                schedule_roam(
+                    core_operation_handle_bss_lost_c::core_bss_lost_reason_bss_lost );
+                }
+
+            break;
+            }
+        case core_am_indication_wlan_pairwise_key_mic_failure:
+            {
+            DEBUG( "core_server_c::notify() - a pairwise MIC failure has occured" );
+
+            mic_failure( false_t );
+            
+            break;
+            }
+        case core_am_indication_wlan_group_key_mic_failure:
+            {
+            DEBUG( "core_server_c::notify() - a group MIC failure has occured" );
+
+            mic_failure( true_t );
+
+            break;
+            }
+        case core_am_indication_wlan_bss_regained:
+            // Do nothing.
+            break;
+        case core_am_indication_wlan_wep_decrypt_failure:
+            // Do nothing.
+            break;
+        case core_am_indication_bt_connection_established:
+            {
+            core_settings_m.set_bt_connection_established( true_t );
+            core_operation_base_c* command = new core_operation_update_rxtx_parameters_c(
+                REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m );
+
+            queue_int_operation_and_run_next( command );
+
+            break;
+            }
+        case core_am_indication_bt_connection_disconnected:
+            {
+            core_settings_m.set_bt_connection_established( false_t );
+            core_operation_base_c* command = new core_operation_update_rxtx_parameters_c(
+                REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m );
+
+            queue_int_operation_and_run_next( command );
+
+            break;
+            }
+        case core_am_indication_wlan_scan_complete:
+            {
+            DEBUG( "core_server_c::notify() - scan complete received without pending scan operations" );
+            ASSERT( false_t );
+
+            break;
+            }
+        case core_am_indication_wlan_rcpi_trigger:
+            {
+            if ( !is_operation_in_queue_with_type( core_operation_check_rcpi ) && 
+                 !is_operation_in_queue_with_type( core_operation_handle_bss_lost ) )
+                {
+                // send an indication to adaptation
+                callback_m.notify(
+                    core_notification_rcpi_roam_attempt_started,
+                    0, 
+                    NULL );
+
+                // create operation to handle the indication
+                core_operation_base_c* command = new core_operation_check_rcpi_c(
+                    REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, core_operation_check_rcpi_c::core_rcpi_check_reason_rcpi_trigger );
+
+                queue_int_operation_and_run_next( command );
+                }
+            else
+                {
+                DEBUG( "core_server_c::notify() - roaming operation already in queue " );
+                }
+
+            break;
+            }
+        case core_am_indication_wlan_signal_loss_prediction:
+            {
+            if ( !is_operation_in_queue_with_type( core_operation_check_rcpi ) && 
+                 !is_operation_in_queue_with_type( core_operation_handle_bss_lost ) )
+                {
+                // send an indication to adaptation
+                /*
+                callback_m.notify(
+                    core_notification_rcpi_roam_attempt_started,
+                    0, 
+                    NULL );
+                 */
+
+                // create operation to handle the indication
+                /*
+                core_operation_base_c* command = new core_operation_check_rcpi_c(
+                    REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, core_operation_check_rcpi_c::core_rcpi_check_reason_signal_loss_prediction );
+
+                queue_int_operation_and_run_next( command, LIST_HIGH_PRIORITY );
+                 */
+                }
+            else
+                {
+                DEBUG( "core_server_c::notify() - roaming operation already in queue " );
+                }
+
+            break;
+            }
+        case core_am_indication_wlan_power_save_test_trigger:
+            {
+            DEBUG( "core_server_c::notify() - scheduling a power save test" );
+
+            core_operation_base_c* command = new core_operation_power_save_test_c(
+                REQUEST_ID_CORE_INTERNAL,
+                this,
+                &drivers_m,
+                &callback_m );
+
+            queue_int_operation_and_run_next( command );
+
+            break;
+            }
+        case core_am_indication_voice_call_on:
+            {
+            DEBUG( "core_server_c::notify() - voice call is on" );
+            connection_data_m->set_voice_call_state( true_t );
+            break;
+            }
+        case core_am_indication_voice_call_off:
+            {
+            DEBUG( "core_server_c::notify() - voice call is off" );
+            connection_data_m->set_voice_call_state( false_t );
+            break;
+            }
+        case core_am_indication_wlan_ap_ps_mode_error:
+            // Do nothing.
+            break;
+        default:
+            DEBUG( "core_server_c::notify() - unknown indication" );
+            ASSERT( false_t );
+            break;
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::schedule_operation()
+    {
+    DEBUG( "core_server_c::schedule_operation()" );
+    
+    core_operation_base_c* operation = queue_m.first();
+
+    DEBUG1( "core_server_c::schedule_operation() - %u operation(s) in the queue",
+        queue_m.count());
+
+#ifdef _DEBUG
+    if( operation && operation->is_executing() )
+        {
+        DEBUG2("core_server_c::schedule_operation() - operation 0x%08X (type %u) is executing",
+            operation, operation->operation_type() );
+        }
+#endif // _DEBUG
+
+    if( !operation &&
+        core_settings_m.connection_state() == core_connection_state_notconnected &&
+        core_settings_m.is_driver_loaded() &&
+        !driver_unload_timer_m->is_active() )
+        {
+        // If 1) no more operations and 
+        // 2) no connection exists and
+        // 3) drivers are loaded and
+        // 4) driver not already active,
+        // start unload timer
+        DEBUG( "core_server_c::schedule_operation() - starting unload timer" );
+        schedule_unload_timer(
+            device_settings_m.unload_driver_timer * SECONDS_FROM_MICROSECONDS );
+
+        return;
+        }
+
+    if ( operation &&
+         !operation->is_executing() &&
+         !queue_timer_m->is_active() )
+        {
+        DEBUG( "core_server_c::schedule_operation() - scheduling a new operation" );
+        queue_timer_m->start( CORE_TIMER_IMMEDIATELY );
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+// 
+bool_t core_server_c::is_cm_active()
+    {
+    return !cm_timer_m.is_wpa_allowed();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::queue_ext_operation_and_run_next(
+    core_operation_base_c* operation,
+    u32_t request_id )
+    {
+    DEBUG1( "core_server_c::queue_ext_operation_and_run_next() - request id %u",
+        request_id );
+    if( !operation )
+        {
+        DEBUG( "core_server_c::queue_ext_operation_and_run_next() - no operation, completing request." );
+        callback_m.request_complete( request_id, core_error_no_memory );
+        }
+    else if ( operation->is_flags( core_operation_base_c::core_base_flag_only_one_instance ) &&
+        is_operation_in_queue_with_type( operation->operation_type() ) )
+        {
+        DEBUG( "core_server_c::queue_ext_operation_and_run_next() - only one instance allowed in the operation queue, completing request" );
+        callback_m.request_complete( request_id, core_error_ok );
+
+        delete operation;
+        operation = NULL;
+        }
+    else
+        {
+        core_error_e ret = queue_m.append( operation );
+        if ( ret != core_error_ok )
+            {
+            DEBUG1( "core_server_c::queue_ext_operation_and_run_next() - unable to queue the request (%u)",
+                ret );
+            callback_m.request_complete( request_id, ret );
+
+            delete operation;
+            operation = NULL;
+            }
+        }
+ 
+    schedule_operation();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::queue_timer_expired( void* this_ptr )
+    {
+    DEBUG( "core_server_c::queue_timer_expired()" );    
+    core_server_c* self = static_cast<core_server_c*>( this_ptr );
+    
+    core_operation_base_c* operation = self->queue_m.first();
+    if( !operation )
+        {
+        /**
+         * This shouldn't normally happen but it can happen if we have
+         * schedule an operation and cancel it before it has a chance to
+         * start executing.
+         */
+
+        return;
+        }
+
+    ASSERT( operation );
+    ASSERT( !operation->is_executing() );
+
+    // Set operation priority in the queue to maximum
+    self->queue_m.remove( operation );
+    self->queue_m.append( operation, LIST_TOP_PRIORITY );
+    
+    // If operation says it needs drivers, stop driver unload timer
+    if( operation->is_flags( core_operation_base_c::core_base_flag_drivers_needed ) &&
+        self->driver_unload_timer_m->is_active() )
+        {
+        DEBUG( "core_server_c::queue_timer_expired() - stopping unload timer" );
+        self->cancel_unload_timer();
+        }
+    
+    core_error_e ret = operation->start_operation();
+    if( ret == core_error_request_pending )
+        {
+        DEBUG( "core_server_c::queue_timer_expired() - operation is not done yet" );
+        return;
+        }
+
+    DEBUG1( "core_server_c::queue_timer_expired() - operation completed with code %u",
+        ret );
+
+    if ( operation->request_id() != REQUEST_ID_CORE_INTERNAL )
+        {
+        self->callback_m.request_complete(
+            operation->request_id(),
+            ret );
+        }    
+
+    self->queue_m.remove( operation );
+    delete operation;
+    operation = NULL;
+
+    self->schedule_operation();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+void core_server_c::unload_timer_expired( void* this_ptr )
+    {
+    DEBUG("core_server_c::unload_timer_expired()");
+    core_server_c* self = static_cast<core_server_c*>( this_ptr );
+
+    /**
+     * Due to configurable unload timer value and different platform timing issues
+     * it's possible that a new operation has been added to the operation queue
+     * AFTER this timer was started but the queue timer has not yet been triggered.
+     * 
+     * Therefore we have to abort driver unloading if there's an operation in the
+     * queue that requires drivers.
+     */
+    if( self->is_operation_in_queue_with_flags(
+        core_operation_base_c::core_base_flag_drivers_needed ) )
+        {
+        DEBUG( "core_server_c::unload_timer_expired() - operation in queue, aborting driver unloading" );
+
+        return;
+        }
+
+    self->queue_unload_drivers();
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::mic_failure(
+    bool_t is_group_key_fail )
+    {
+    DEBUG( "core_server_c::mic_failure()" );
+    
+    core_connection_security_mode_e mode = core_connection_security_mode_open;
+    
+    if( core_error_ok != get_current_security_mode( mode ) )
+        {
+        DEBUG( "core_server_c::mic_failure() - not connected, ignoring mic failure" );
+        return;
+        }
+    
+    if( mode != core_connection_security_mode_wpa && 
+        mode != core_connection_security_mode_wpa_psk )
+        {
+        DEBUG( "core_server_c::mic_failure() - security mode not WPA, ignoring mic failure" );
+        return;
+        }
+
+    if( is_group_key_fail )
+        {
+        if( connection_data_m->current_ap_data() != NULL &&
+            connection_data_m->current_ap_data()->best_group_cipher() != core_cipher_suite_tkip )
+            {
+            DEBUG( "core_server_c::mic_failure() - TKIP not the best group cipher, ignoring mic failure" );
+            return;
+            }
+        }
+    else
+        {
+        if( connection_data_m->current_ap_data() != NULL &&
+            connection_data_m->current_ap_data()->best_pairwise_cipher() != core_cipher_suite_tkip )
+            {
+            DEBUG( "core_server_c::mic_failure() - TKIP not the best pairwise cipher, ignoring mic failure" );
+            return;
+            }
+        }
+        
+    const core_mac_address_s bssid(
+        connection_data_m->current_ap_data()->bssid() );
+
+    cm_timer_m.mic_failure();
+
+    network_id_c network_id(
+        const_cast<u8_t*>( &bssid.addr[0] ),
+        MAC_ADDR_LEN,
+        &own_mac_addr_m.addr[0],
+        MAC_ADDR_LEN,
+        eapol_m->ethernet_type() );
+
+    ASSERT( eapol_m );
+    (void)eapol_m->tkip_mic_failure(
+        &network_id,
+        !cm_timer_m.is_wpa_allowed() ? true_t : false_t,
+        is_group_key_fail ? wlan_eapol_if_eapol_tkip_mic_failure_type_group_key :
+            wlan_eapol_if_eapol_tkip_mic_failure_type_pairwise_key );
+
+
+    if ( !cm_timer_m.is_wpa_allowed() )
+        {
+        DEBUG( "core_server_c::mic_failure() - two MIC failures within 60 seconds, disconnecting" );
+                
+        core_operation_base_c* command = new core_operation_release_c(
+            REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m, core_release_reason_tkip_mic_failure );
+
+        queue_int_operation_and_run_next( command );
+        }        
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_server_c::queue_unload_drivers()
+    {
+    DEBUG( "core_server_c::queue_unload_drivers()" );
+
+    core_operation_base_c* command = new core_operation_unload_drivers_c(
+        REQUEST_ID_CORE_INTERNAL, this, &drivers_m, &callback_m );
+
+    queue_int_operation_and_run_next( command );    
+    }