/*
* 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: 90 %
*/
#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;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
//
core_error_e core_server_c::set_enabled_features(
u32_t features )
{
DEBUG( "core_server_c::set_enabled_features()" );
core_settings_m.set_enabled_features( features );
return core_error_ok;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
//
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 );
}