--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_scan.cpp Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,575 @@
+/*
+* 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:
+* ST-Ericsson
+*
+* Description: Statemachine for scanning
+*
+*/
+
+
+#include "core_operation_scan.h"
+#include "core_server.h"
+#include "core_tools.h"
+#include "core_frame_beacon.h"
+#include "core_scan_list.h"
+#include "am_debug.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_operation_scan_c::core_operation_scan_c(
+ u32_t request_id,
+ core_server_c* server,
+ abs_core_driverif_c* drivers,
+ abs_core_server_callback_c* adaptation,
+ 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 passive_scan_all_channels,
+ bool_t is_current_ap_added ) :
+ core_operation_base_c( core_operation_scan, request_id, server, drivers, adaptation,
+ core_base_flag_drivers_needed ),
+ scan_mode_m( scan_mode ),
+ scan_ssid_m( scan_ssid ),
+ scan_channels_m( scan_channels ),
+ scan_max_age_m( scan_max_age ),
+ scan_data_m( scan_data ),
+ passive_scan_all_channels_m( passive_scan_all_channels ),
+ region_from_ap_m( core_wlan_region_fcc ),
+ is_current_ap_added_m( is_current_ap_added ),
+ current_rcpi_m( 0 )
+ {
+ DEBUG( "core_operation_scan_c::core_operation_scan_c()" );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_operation_scan_c::~core_operation_scan_c()
+ {
+ DEBUG( "core_operation_scan_c::~core_operation_scan_c()" );
+
+ server_m->unregister_event_handler( this );
+ server_m->unregister_frame_handler( this );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_operation_scan_c::next_state()
+ {
+ DEBUG( "core_operation_scan_c::next_state()" );
+
+ switch ( operation_state_m )
+ {
+ case core_state_init:
+ {
+ operation_state_m = core_state_scan_start;
+
+ u32_t min_ch_time( server_m->get_device_settings().active_scan_min_ch_time );
+ u32_t max_ch_time( server_m->get_device_settings().active_scan_max_ch_time );
+ if ( scan_mode_m == core_scan_mode_passive )
+ {
+ min_ch_time = server_m->get_device_settings().passive_scan_min_ch_time;
+ max_ch_time = server_m->get_device_settings().passive_scan_max_ch_time;
+ }
+
+ if ( scan_ssid_m.length )
+ {
+ DEBUG1S( "core_operation_scan_c::next_state() - requesting a direct scan with SSID ",
+ scan_ssid_m.length, &scan_ssid_m.ssid[0] );
+ }
+ else
+ {
+ DEBUG( "core_operation_scan_c::next_state() - requesting a broadcast scan" );
+ }
+
+ bool_t is_split_scan( false_t );
+ if ( server_m->get_core_settings().is_connected() )
+ {
+ is_split_scan = true_t;
+ DEBUG( "core_operation_scan_c::next_state() - requesting a split-scan" );
+ }
+ else
+ {
+ DEBUG( "core_operation_scan_c::next_state() - requesting a regular scan" );
+ }
+
+ server_m->get_scan_list().remove_entries_by_age(
+ server_m->get_device_settings().scan_list_expiration_time );
+
+ server_m->get_scan_list().set_tag(
+ core_scan_list_tag_scan );
+
+ server_m->register_event_handler( this );
+ server_m->register_frame_handler( this );
+
+ drivers_m->scan(
+ request_id_m,
+ scan_mode_m,
+ scan_ssid_m,
+ server_m->get_device_settings().scan_rate,
+ server_m->get_core_settings().valid_scan_channels( scan_channels_m ),
+ min_ch_time,
+ max_ch_time,
+ is_split_scan );
+
+ break;
+ }
+ case core_state_scan_start:
+ {
+ DEBUG( "core_operation_scan_c::next_state() - scan request completed, waiting for scan completion" );
+
+ break;
+ }
+ case core_state_scan_complete:
+ {
+ /* If country information is not known then channels 12 and 13 can be scanned in passive mode */
+ if ( server_m->get_core_settings().mcc_known() || scan_ssid_m.length || !passive_scan_all_channels_m )
+ {
+ /* All possible scans are done.
+ * When MCC information is known, the allowed scan channels are known and handled already.
+ * If SSID is given then direct scan would be required so no need to do passive broadcast scan.
+ * If operation does not require passive scanning on channels 12 and 13, this is not done.
+ */
+ return goto_state( core_state_scan_complete_handle_result );
+ }
+
+ operation_state_m = core_state_scan_start_unknown_region;
+
+ u32_t min_ch_time( server_m->get_device_settings().passive_scan_min_ch_time );
+ u32_t max_ch_time( server_m->get_device_settings().passive_scan_max_ch_time );
+
+ bool_t is_split_scan( false_t );
+ if ( server_m->get_core_settings().is_connected() )
+ {
+ is_split_scan = true_t;
+ DEBUG( "core_operation_scan_c::next_state() - requesting a split-scan for channels 12 and 13" );
+ }
+ else
+ {
+ DEBUG( "core_operation_scan_c::next_state() - requesting a regular scan for channels 12 and 13" );
+ }
+
+ server_m->register_event_handler( this );
+ server_m->register_frame_handler( this );
+
+ drivers_m->scan(
+ request_id_m,
+ core_scan_mode_passive,
+ scan_ssid_m,
+ server_m->get_device_settings().scan_rate,
+ server_m->get_core_settings().invalid_scan_channels( scan_channels_m ),
+ min_ch_time,
+ max_ch_time,
+ is_split_scan );
+
+ break;
+ }
+ case core_state_scan_start_unknown_region:
+ {
+ DEBUG( "core_operation_scan_c::next_state() - scan request for channels 12 and 13 completed, waiting for scan completion" );
+
+ break;
+ }
+ case core_state_scan_complete_unknown_region:
+ {
+ server_m->unregister_frame_handler( this );
+ server_m->get_scan_list().print_contents(); // Additional print
+
+ operation_state_m = core_state_scan_complete_store_country_info;
+
+ /* If WLAN region was not known before the scan, then check if country information is present
+ * in the scan results. APs on channels 12 and 13 must be ignored if country information indicates this.
+ */
+ core_scan_list_iterator_by_tag_c iter_country_beacon(
+ server_m->get_scan_list(),
+ core_scan_list_tag_scan );
+
+ core_wlan_region_e found_region = core_wlan_region_undefined;
+ bool_t inconsistent_info( false_t );
+ for ( core_ap_data_c* ap_data = iter_country_beacon.first(); ap_data; ap_data = iter_country_beacon.next() )
+ {
+ core_country_string_s country_info = ap_data->country_info();
+ core_wlan_region_e ap_region = core_wlan_region_undefined;
+ if ( country_info.country[0] != 0 )
+ {
+ ap_region = core_tools_c::convert_country_to_region( country_info );
+ if ( found_region != core_wlan_region_undefined )
+ {
+ if ( ap_region != found_region )
+ {
+ inconsistent_info = true_t;
+ }
+ }
+ else
+ {
+ found_region = ap_region;
+ }
+ }
+ }
+ if ( found_region != core_wlan_region_undefined )
+ {
+ if ( !inconsistent_info )
+ {
+ region_from_ap_m = found_region;
+ }
+ else
+ {
+ region_from_ap_m = core_wlan_region_etsi;
+ }
+ adaptation_m->store_ap_country_info( request_id_m, region_from_ap_m, inconsistent_info );
+ }
+ else
+ {
+ DEBUG( "core_operation_scan_c::next_state() - country info not found, continue with handling scan results" );
+ return goto_state( core_state_scan_complete_handle_result );
+ }
+ break;
+ }
+
+ case core_state_scan_complete_store_country_info:
+ {
+ operation_state_m = core_state_scan_complete_handle_result;
+
+ /* Set the new region information also to core settings */
+ DEBUG1( "core_operation_scan_c::next_state() - current region %u",
+ region_from_ap_m );
+ server_m->get_core_settings().set_regional_domain(
+ region_from_ap_m );
+ server_m->get_core_settings().set_mcc_known( true_t );
+
+ return goto_state( core_state_scan_complete_handle_result );
+ }
+
+ case core_state_scan_complete_handle_result:
+ {
+ /* If region is FCC, then ignore and remove the APs from channels 12 and 13 */
+ if ( server_m->get_core_settings().regional_domain() == core_wlan_region_fcc )
+ {
+ DEBUG( "core_operation_scan_c::next_state() - remove APs that were found on channels 12 and 13" );
+ remove_disallowed_aps();
+ }
+
+ DEBUG( "core_operation_scan_c::next_state() - final scan list" );
+ server_m->get_scan_list().print_contents(); // Additional print
+
+ /**
+ * If we have an ongoing connection, we'll have to see whether
+ * the current AP was found in the scan.
+ */
+ core_ssid_s current_ssid( BROADCAST_SSID );
+ core_mac_address_s current_bssid( ZERO_MAC_ADDR );
+ bool_t is_current_ap_in_list( true_t );
+ if ( is_current_ap_added_m &&
+ server_m->get_connection_data() &&
+ server_m->get_connection_data()->current_ap_data() )
+ {
+ current_ssid =
+ server_m->get_connection_data()->ssid();
+ current_bssid =
+ server_m->get_connection_data()->current_ap_data()->bssid();
+
+ /**
+ * Current AP only needs to be added in a broadcast scan or a direct
+ * scan done with the same SSID.
+ */
+ if ( !scan_ssid_m.length ||
+ scan_ssid_m == current_ssid )
+ {
+ is_current_ap_in_list = false_t;
+ }
+ }
+
+ if ( scan_ssid_m.length )
+ {
+ core_scan_list_iterator_by_tag_and_ssid_c iter(
+ server_m->get_scan_list(),
+ core_scan_list_tag_scan,
+ scan_ssid_m );
+ for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() )
+ {
+ const core_mac_address_s bssid = ap_data->bssid();
+
+ if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) )
+ {
+ if ( !is_current_ap_in_list &&
+ current_bssid == bssid &&
+ current_ssid == ap_data->ssid() )
+ {
+ is_current_ap_in_list = true_t;
+ }
+
+ core_tools_c::add_beacon_to_scan_list(
+ scan_data_m,
+ *ap_data,
+ ap_data->rcpi() );
+ }
+ }
+ }
+ else if ( !scan_max_age_m )
+ {
+ core_scan_list_iterator_by_tag_c iter(
+ server_m->get_scan_list(),
+ core_scan_list_tag_scan );
+ for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() )
+ {
+ const core_mac_address_s bssid = ap_data->bssid();
+
+ if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) )
+ {
+ if ( !is_current_ap_in_list &&
+ current_bssid == bssid &&
+ current_ssid == ap_data->ssid() )
+ {
+ is_current_ap_in_list = true_t;
+ }
+
+ core_tools_c::add_beacon_to_scan_list(
+ scan_data_m,
+ *ap_data,
+ ap_data->rcpi() );
+ }
+ }
+ }
+ else
+ {
+ core_scan_list_iterator_by_age_c iter(
+ server_m->get_scan_list(),
+ scan_max_age_m );
+ for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() )
+ {
+ const core_mac_address_s bssid = ap_data->bssid();
+
+ if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) )
+ {
+ if ( !is_current_ap_in_list &&
+ current_bssid == bssid &&
+ current_ssid == ap_data->ssid() )
+ {
+ is_current_ap_in_list = true_t;
+ }
+
+ core_tools_c::add_beacon_to_scan_list(
+ scan_data_m,
+ *ap_data,
+ ap_data->rcpi() );
+ }
+ }
+ }
+
+ if ( is_current_ap_in_list )
+ {
+ return goto_state( core_state_scanning_done );
+ }
+
+ operation_state_m = core_state_rcpi_received;
+
+ DEBUG( "core_operation_scan_c::next_state() - current AP was not found in scan" );
+ DEBUG( "core_operation_scan_c::next_state() - requesting RCPI" );
+
+ drivers_m->get_current_rcpi(
+ request_id_m,
+ current_rcpi_m );
+
+ break;
+ }
+ case core_state_rcpi_received:
+ {
+ DEBUG1( "core_operation_scan_c::next_state() - current RCPI is %u",
+ current_rcpi_m );
+ DEBUG( "core_operation_scan_c::next_state() - appending current AP to the scan list" );
+
+ core_tools_c::add_beacon_to_scan_list(
+ scan_data_m,
+ *server_m->get_connection_data()->current_ap_data(),
+ current_rcpi_m );
+
+ return goto_state( core_state_scanning_done );
+ }
+ case core_state_scanning_done:
+ {
+ DEBUG( "core_operation_scan_c::next_state() - scan complete" );
+ DEBUG1( "core_operation_scan_c::next_state() - scan list contains %u AP(s)",
+ scan_data_m.Count() );
+ DEBUG1( "core_operation_scan_c::next_state() - scan list size is %u bytes",
+ scan_data_m.Size() );
+
+ return core_error_ok;
+ }
+ default:
+ {
+ ASSERT( false_t );
+ }
+ }
+
+ return core_error_request_pending;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_operation_scan_c::user_cancel(
+ bool_t do_graceful_cancel )
+ {
+ DEBUG1( "core_operation_scan_c::user_cancel(do_graceful_cancel=%d)", do_graceful_cancel );
+
+ /**
+ * If region is FCC and region information is not known, then ignore
+ * and remove the APs from channels 12 and 13
+ */
+ if ( !server_m->get_core_settings().mcc_known() &&
+ server_m->get_core_settings().regional_domain() == core_wlan_region_fcc )
+ {
+ DEBUG( "core_operation_scan_c::next_state() - remove APs that were found on channels 12 and 13" );
+ remove_disallowed_aps();
+ }
+
+ if ( !do_graceful_cancel )
+ {
+ /**
+ * If we are in a middle of a scan, we have to schedule our own
+ * event.
+ */
+ if ( ( operation_state_m == core_state_scan_start ||
+ operation_state_m == core_state_scan_start_unknown_region ) &&
+ server_m->event_handler() == this &&
+ server_m->frame_handler() == this )
+ {
+ asynch_default_user_cancel();
+
+ return;
+ }
+
+ /**
+ * Everything else is handled by the default implementation.
+ */
+ core_operation_base_c::user_cancel( do_graceful_cancel );
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_operation_scan_c::receive_frame(
+ const core_frame_dot11_c* frame,
+ u8_t rcpi )
+ {
+ DEBUG( "core_operation_scan_c::receive_frame()" );
+
+ if ( frame->type() != core_frame_dot11_c::core_dot11_type_beacon &&
+ frame->type() != core_frame_dot11_c::core_dot11_type_probe_resp )
+ {
+ DEBUG( "core_operation_scan_c::receive_frame() - not a beacon or a probe" );
+ return false_t;
+ }
+
+ core_ap_data_c* ap_data = core_ap_data_c::instance(
+ server_m->get_wpx_adaptation_instance(),
+ frame,
+ rcpi,
+ false_t );
+ if ( ap_data )
+ {
+ const core_ssid_s ssid = ap_data->ssid();
+ DEBUG1S( "core_operation_scan_c::receive_frame() - SSID: ",
+ ssid.length, &ssid.ssid[0] );
+
+ core_mac_address_s bssid(
+ ap_data->bssid() );
+ DEBUG6( "core_operation_scan_c::receive_frame() - BSSID: %02X:%02X:%02X:%02X:%02X:%02X",
+ bssid.addr[0], bssid.addr[1], bssid.addr[2],
+ bssid.addr[3], bssid.addr[4], bssid.addr[5] );
+
+ server_m->get_scan_list().update_entry( *ap_data );
+
+ delete ap_data;
+ ap_data = NULL;
+ }
+
+ return true_t;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_operation_scan_c::notify(
+ core_am_indication_e indication )
+ {
+ if ( operation_state_m == core_state_scan_start &&
+ indication == core_am_indication_wlan_scan_complete )
+ {
+ server_m->unregister_event_handler( this );
+
+ DEBUG( "core_operation_scan_c::notify() - scan complete" );
+
+ asynch_goto( core_state_scan_complete, CORE_TIMER_IMMEDIATELY );
+
+ return true_t;
+ }
+ else if ( operation_state_m == core_state_scan_start_unknown_region &&
+ indication == core_am_indication_wlan_scan_complete )
+ {
+ server_m->unregister_event_handler( this );
+
+ DEBUG( "core_operation_scan_c::notify() - scan complete for channels 12 and 13" );
+
+ asynch_goto( core_state_scan_complete_unknown_region, CORE_TIMER_IMMEDIATELY );
+
+ return true_t;
+ }
+
+ return false_t;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_operation_scan_c::remove_disallowed_aps()
+ {
+ core_type_list_c<core_mac_address_s> remove_ap_list;
+
+ core_scan_list_iterator_by_tag_c iter_removed_aps(
+ server_m->get_scan_list(),
+ core_scan_list_tag_scan );
+
+ core_ap_data_c* ap_data = iter_removed_aps.first();
+ while (ap_data)
+ {
+ if ( !server_m->get_core_settings().is_valid_channel(
+ SCAN_BAND_2DOT4GHZ,
+ ap_data->channel() ) )
+ {
+ core_mac_address_s* ignored_ap = new core_mac_address_s;
+ if ( ignored_ap )
+ {
+ *ignored_ap = ap_data->bssid();
+ remove_ap_list.append( ignored_ap );
+ }
+ }
+ ap_data = iter_removed_aps.next();
+ }
+
+ core_mac_address_s* ignored_bssid = remove_ap_list.first();
+ while (ignored_bssid )
+ {
+ server_m->get_scan_list().remove_entries_by_bssid( *ignored_bssid );
+ ignored_bssid = remove_ap_list.next();
+ }
+ remove_ap_list.clear();
+
+ }