diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_get_available_iaps.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_get_available_iaps.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,1321 @@ +/* +* Copyright (c) 2005-2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: State machine for IAP availability. +* +*/ + +/* +* %version: 40.1.2 % +*/ + +#include "core_operation_get_available_iaps.h" +#include "core_server.h" +#include "core_tools.h" +#include "core_tools_parser.h" +#include "core_frame_dot11.h" +#include "core_frame_dot11_ie.h" +#include "am_debug.h" + +/** Defining this enables IAP related traces. */ +//#define WLAN_CORE_DEEP_DEBUG 1 + +/** The channel time used in the long passive scan. */ +const u32_t LONG_PASSIVE_SCAN_CHANNEL_TIME = 210; + +/** + * If the phone has at least this many IAPs marked as hidden, + * limiting algorithm will be used for detecting available IAPs. + */ +const u8_t MIN_HIDDEN_IAPS_FOR_LIMITING_ALGORITHM = 15; + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_get_available_iaps_c::core_operation_get_available_iaps_c( + u32_t request_id, + core_server_c* server, + abs_core_driverif_c* drivers, + abs_core_server_callback_c* adaptation, + bool_t is_active_scan_allowed, + core_type_list_c& iap_data_list, + core_type_list_c& iap_id_list, + core_type_list_c* iap_ssid_list, + ScanList& scan_data ) : + core_operation_base_c( core_operation_get_available_iaps, request_id, server, drivers, adaptation, + core_base_flag_drivers_needed ), + is_active_scan_allowed_m( is_active_scan_allowed ), + is_limiting_algorithm_used_m( false_t ), + iap_data_list_m( iap_data_list ), + iap_id_list_m( iap_id_list ), + iap_ssid_list_m( iap_ssid_list ), + client_scan_data_m( scan_data ), + active_channels_m( ), + broadcast_channels_m( ), + long_broadcast_count_m( 0 ), + non_found_iaps_list_m( ), + is_split_scan_m( false_t ), + bss_count_m( 0 ), + direct_scanned_ssid_m( ), + region_from_ap_m( core_wlan_region_fcc ) + { + DEBUG( "core_operation_get_available_iaps_c::core_operation_get_available_iaps_c()" ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_get_available_iaps_c::~core_operation_get_available_iaps_c() + { + DEBUG( "core_operation_get_available_iaps_c::~core_operation_get_available_iaps_c()" ); + + server_m->unregister_event_handler( this ); + server_m->unregister_frame_handler( this ); + non_found_iaps_list_m.clear(); + iap_ssid_list_m = NULL; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_operation_get_available_iaps_c::next_state() + { + DEBUG( "core_operation_get_available_iaps_c::next_state()" ); + + switch ( operation_state_m ) + { + case core_state_init: + { + operation_state_m = core_state_long_broadcast_scan_start; + +#ifdef WLAN_CORE_DEEP_DEBUG + DEBUG( "core_operation_get_available_iaps_c::next_state() - IAP data list:" ); + + core_iap_data_s* iter_data = iap_data_list_m.first(); + while( iter_data ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - ID: %u", + iter_data->id ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - SSID: ", + iter_data->ssid.length, iter_data->ssid.ssid ); + + iter_data = iap_data_list_m.next(); + } + + if ( iap_ssid_list_m ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state()" ); + DEBUG( "core_operation_get_available_iaps_c::next_state() - Secondary SSID list:" ); + + core_ssid_entry_s* iter_entry = iap_ssid_list_m->first(); + while( iter_entry ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - ID: %u", + iter_entry->id ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - SSID: ", + iter_entry->ssid.length, iter_entry->ssid.ssid ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - Used SSID: ", + iter_entry->used_ssid.length, iter_entry->used_ssid.ssid ); + + iter_entry = iap_ssid_list_m->next(); + } + DEBUG( "core_operation_get_available_iaps_c::next_state()" ); + } +#endif // WLAN_CORE_DEEP_DEBUG + + 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 ); + + if ( server_m->get_core_settings().is_connected() ) + { + is_split_scan_m = true_t; + DEBUG( "core_operation_get_available_iaps_c::next_state() - using a split-scan" ); + } + else + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - using a regular scan" ); + } + + /** + * Limiting algorithm is only used when there's a certain amount of IAPs + * marked as hidden. + */ + if ( hidden_iap_count( iap_data_list_m ) >= MIN_HIDDEN_IAPS_FOR_LIMITING_ALGORITHM ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - %u hidden IAPs defined, using limiting algorithm", + hidden_iap_count( iap_data_list_m ) ); + + is_limiting_algorithm_used_m = true_t; + } + + /** + * Construct a channel mask of channels that have previously contained + * APs with long beacon intervals. + */ + core_long_beacon_interval_channels_s& long_beacon_interval_channels( + server_m->get_core_settings().long_beacon_interval_channels() ); + + for ( u8_t idx( 0 ); idx < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO; ++idx ) + { + if ( long_beacon_interval_channels.channel_scan_count[idx] ) + { + long_beacon_interval_channels.channel_scan_count[idx]--; + const u8_t channel( idx + 1); + + if ( server_m->get_core_settings().mcc_known() ) + { + if ( server_m->get_core_settings().is_valid_channel( + SCAN_BAND_2DOT4GHZ, + channel ) ) + { + long_broadcast_count_m++; + + broadcast_channels_m.add( + SCAN_BAND_2DOT4GHZ, + channel ); + } + } + else + { + long_broadcast_count_m++; + broadcast_channels_m.add( + SCAN_BAND_2DOT4GHZ, + channel ); + } + } + } + + /** + * If we can active scan or the channel mask is empty, we can jump + * directly to the main broadcast scan. + */ + if ( is_active_scan_allowed_m || + !long_broadcast_count_m ) + { + long_broadcast_count_m = 0; + + return goto_state( core_state_long_broadcast_scan_done ); + } + + const core_scan_channels_s channels( + broadcast_channels_m.channels() ); + + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting long passive broadcast scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_passive, + BROADCAST_SSID, + server_m->get_device_settings().scan_rate, + channels, + LONG_PASSIVE_SCAN_CHANNEL_TIME, + LONG_PASSIVE_SCAN_CHANNEL_TIME, + is_split_scan_m ); + + break; + } + case core_state_long_broadcast_scan_start: + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - long broadcast scan request completed, waiting for scan completion" ); + + break; + } + case core_state_long_broadcast_scan_done: + { + operation_state_m = core_state_broadcast_scan_start; + + if ( !long_broadcast_count_m ) + { + broadcast_channels_m.set( + server_m->get_core_settings().all_valid_scan_channels() ); + } + else + { + broadcast_channels_m.invert_channels(); + } + + const core_scan_channels_s channels( + server_m->get_core_settings().valid_scan_channels( broadcast_channels_m.channels() ) ); + + + if ( !is_active_scan_allowed_m || + is_limiting_algorithm_used_m ) + { + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting passive broadcast scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_passive, + BROADCAST_SSID, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().passive_scan_min_ch_time, + server_m->get_device_settings().passive_scan_max_ch_time, + is_split_scan_m ); + } + else + { + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting active broadcast scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_active, + BROADCAST_SSID, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().active_scan_min_ch_time, + server_m->get_device_settings().active_scan_max_ch_time, + is_split_scan_m ); + } + + break; + } + case core_state_broadcast_scan_start: + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - broadcast scan request completed, waiting for scan completion" ); + + break; + } + case core_state_broadcast_scan_done: + { + if ( server_m->get_core_settings().mcc_known() ) + { + /* When WLAN region is known, the allowed scan channels are known and + * handled already */ + return goto_state( core_state_broadcast_scan_done_handle_result ); + } + + operation_state_m = core_state_broadcast_scan_start_unknown_region; + + broadcast_channels_m.set( + server_m->get_core_settings().all_valid_scan_channels() ); + + const core_scan_channels_s channels( + server_m->get_core_settings().invalid_scan_channels( broadcast_channels_m.channels() ) ); + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_passive, + BROADCAST_SSID, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().passive_scan_min_ch_time, + server_m->get_device_settings().passive_scan_max_ch_time, + is_split_scan_m ); + + break; + } + case core_state_broadcast_scan_start_unknown_region: + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - broadcast scan request for channels 12 and 13 completed, waiting for scan completion" ); + + break; + } + case core_state_broadcast_scan_complete_unknown_region: + { + operation_state_m = core_state_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 + { + return goto_state( core_state_broadcast_scan_done_handle_result ); + } + break; + } + case core_state_store_country_info: + { + operation_state_m = core_state_broadcast_scan_done_handle_result; + + /* Set the new region information also to core settings */ + DEBUG1( "core_operation_get_available_iaps_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_broadcast_scan_done_handle_result ); + } + + case core_state_broadcast_scan_done_handle_result: + { + operation_state_m = core_state_direct_scan_start; + /* If region information is not known, channels 12 and 13 are now been scanned in passive mode in any case */ + + /* 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_get_available_iaps_c::next_state() - remove APs that were found on channels 12 and 13" ); + remove_disallowed_aps(); + } + + /* If WLAN regional domain is not ETSI, we have to remove the high channels from + * from the active channels mask to prevent direct scans on those channels. + */ + if ( server_m->get_core_settings().regional_domain() != core_wlan_region_etsi ) + { + for ( u8_t idx( SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_FCC ); idx < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO; ++idx ) + { + const u8_t channel( idx + 1); + if ( !server_m->get_core_settings().is_valid_channel( + SCAN_BAND_2DOT4GHZ, + channel ) ) + { + active_channels_m.remove( + SCAN_BAND_2DOT4GHZ, + channel ); + } + } + } + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - broadcast scan done, %u beacon(s)/probe(s) received", + bss_count_m ); + + /** + * Add the results from the broadcast scan to the scan list so that + * they can be cached in adaptation. + */ + 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 ) ) + { + core_tools_c::add_beacon_to_scan_list( + client_scan_data_m, + *ap_data, + ap_data->rcpi() ); + } + } + + /** + * Go through the broadcast scan results and remove matching IAPs. + */ + process_scan_results( + core_scan_list_tag_scan ); + + /** + * Direct scans are only needed if active scanning is allowed. If limiting algorithm + * is used, channel activity based on broadcast scan is also required. + */ + if ( ( is_active_scan_allowed_m && + !is_limiting_algorithm_used_m ) || + ( is_active_scan_allowed_m && + is_limiting_algorithm_used_m && + bss_count_m ) ) + { + remove_non_hidden_iaps(); + + /** + * If limiting algorithm is used, only the current active_channels_m + * will be used. + */ + if ( is_limiting_algorithm_used_m ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - limiting channels based on WLAN activity" ); + } + else + { + active_channels_m.set( + server_m->get_core_settings().all_valid_scan_channels() ); + } + + /** + * iap_data_list_m now contains only hidden ssid IAPs, + * that will be direct scanned next. + */ + core_iap_data_s* iap = iap_data_list_m.first(); + if( !iap ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - nothing to direct scan" ); + + /** No hidden IAP entries in the request, move on.. */ + return goto_state( core_state_secondary_ssid_check ); + } + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - going to direct scan %u IAP(s)", + iap_data_list_m.count() ); + + direct_scanned_ssid_m = iap->ssid; + DEBUG1( "core_operation_get_available_iaps_c::next_state() - direct scanning IAP ID %u", + iap->id ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - SSID: ", + direct_scanned_ssid_m.length, direct_scanned_ssid_m.ssid ); + + server_m->get_scan_list().set_tag( + core_scan_list_tag_direct_scan ); + + const core_scan_channels_s& channels( + active_channels_m.channels() ); + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + bss_count_m = 0; + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_active, + direct_scanned_ssid_m, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().active_scan_min_ch_time, + server_m->get_device_settings().active_scan_max_ch_time, + is_split_scan_m ); + + break; + } + else + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - no reason to direct scan anything" ); + remove_non_hidden_iaps(); + + return goto_state( core_state_scanning_done ); + } + } + case core_state_direct_scan_start: + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - direct scan request completed, waiting for scan completion" ); + + break; + } + case core_state_direct_scan_done: + { + operation_state_m = core_state_direct_scan_start; + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - direct scan done, %u beacon(s)/probe(s) received", + bss_count_m ); + DEBUG1( "core_operation_get_available_iaps_c::next_state() - max %u direct scans left", + iap_data_list_m.count() ); + + /** + * Go through the direct scan results and remove the matching IAPs. + */ + process_scan_results( + core_scan_list_tag_direct_scan ); + + /** + * If the first entry is still the same the one that was scanned, + * it means the IAP was not found. + */ + core_iap_data_s* iap = iap_data_list_m.first(); + if ( iap && iap->ssid == direct_scanned_ssid_m ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - IAP ID %u not found in direct scan", + iap->id ); + + core_error_e ret = iap_data_list_m.remove( iap ); + if( ret != core_error_ok ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - error while removing IAP entry (%d)", + ret ); + } + + non_found_iaps_list_m.append( iap ); + } + + iap = iap_data_list_m.first(); + if( iap ) + { + direct_scanned_ssid_m = iap->ssid; + DEBUG1( "core_operation_get_available_iaps_c::next_state() - direct scanning IAP ID %u", + iap->id ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - SSID: ", + direct_scanned_ssid_m.length, direct_scanned_ssid_m.ssid ); + + server_m->get_scan_list().set_tag( + core_scan_list_tag_direct_scan ); + + const core_scan_channels_s& channels( + active_channels_m.channels() ); + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + bss_count_m = 0; + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_active, + direct_scanned_ssid_m, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().active_scan_min_ch_time, + server_m->get_device_settings().active_scan_max_ch_time, + is_split_scan_m ); + } + else + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - nothing to direct scan" ); + + return goto_state( core_state_secondary_ssid_check ); + } + + break; + } + case core_state_secondary_ssid_check: + { + ASSERT( !iap_data_list_m.count() ); + ASSERT( !iap_data_list_m.first() ); + + /** + * All the IAPs that were not found are contained in non_found_iaps_list_m + * list. Those that have secondary SSIDs defined, will be moved back to + * iap_data_list_m for scanning. + */ + + if ( iap_ssid_list_m ) + { + core_iap_data_s* iap = non_found_iaps_list_m.first(); + while( iap ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - checking IAP ID %u for secondary SSIDs", + iap->id ); + + if ( is_id_in_secondary_ssid_list( iap->id ) ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - IAP has secondary SSID(s) defined" ); + + /** Using a temporary pointer to guarantee list iterator working. */ + core_iap_data_s* temp = iap; + iap = non_found_iaps_list_m.next(); + + non_found_iaps_list_m.remove( temp ); + iap_data_list_m.append( temp ); + } + else + { + iap = non_found_iaps_list_m.next(); + } + } + } + + if ( !iap_data_list_m.count() ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - no IAPs with secondary SSID(s) defined" ); + + return goto_state( core_state_scanning_done ); + } + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - %u IAP(s) with secondary SSID(s) defined", + iap_data_list_m.count() ); + + if ( iap_ssid_list_m ) + { + (void)iap_ssid_list_m->first(); + } + (void)iap_data_list_m.first(); + + return goto_state( core_state_secondary_ssid_next ); + } + case core_state_secondary_ssid_next: + { + operation_state_m = core_state_secondary_ssid_start; + + core_iap_data_s* iap = iap_data_list_m.current(); + if ( !iap ) + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - all IAPs with secondary SSID(s) handled" ); + + return goto_state( core_state_scanning_done ); + } + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - current IAP ID %u", + iap->id ); + core_ssid_entry_s* entry = iap_ssid_list_m->current(); + while ( entry ) + { + if ( iap->id == entry->id ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - ID: %u", + entry->id ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - SSID: ", + entry->ssid.length, entry->ssid.ssid ); + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - Used SSID: ", + entry->used_ssid.length, entry->used_ssid.ssid ); + + if ( is_ssid_in_scanlist( + entry->ssid, + client_scan_data_m ) ) + { + direct_scanned_ssid_m = entry->used_ssid; + + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - matching SSID found, doing a direct scan for SSID ", + direct_scanned_ssid_m.length, direct_scanned_ssid_m.ssid ); + + server_m->get_scan_list().set_tag( + core_scan_list_tag_direct_scan ); + + const core_scan_channels_s& channels( + active_channels_m.channels() ); + DEBUG2( "core_operation_get_available_iaps_c::next_state() - requesting scan on channels 0x%02X%02X", + channels.channels2dot4ghz[1], + channels.channels2dot4ghz[0] ); + + bss_count_m = 0; + + server_m->register_event_handler( this ); + server_m->register_frame_handler( this ); + + drivers_m->scan( + request_id_m, + core_scan_mode_active, + direct_scanned_ssid_m, + server_m->get_device_settings().scan_rate, + channels, + server_m->get_device_settings().active_scan_min_ch_time, + server_m->get_device_settings().active_scan_max_ch_time, + is_split_scan_m ); + + return core_error_request_pending; + } + else + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - matching SSID not found, moving to next entry" ); + + entry = iap_ssid_list_m->next(); + } + } + else + { + entry = iap_ssid_list_m->next(); + } + } + + DEBUG1( "core_operation_get_available_iaps_c::next_state() - no more entries for IAP ID %u, moving to next IAP", + iap->id ); + + remove_secondary_ssid_entries_by_id( iap->id ); + iap_data_list_m.remove( iap ); + non_found_iaps_list_m.append( iap ); + (void)iap_ssid_list_m->first(); + (void)iap_data_list_m.first(); + + return asynch_goto( core_state_secondary_ssid_next ); + } + case core_state_secondary_ssid_start: + { + DEBUG( "core_operation_get_available_iaps_c::next_state() - direct scan request completed, waiting for scan completion" ); + + break; + } + case core_state_secondary_ssid_done: + { + core_iap_data_s* iap = iap_data_list_m.current(); + ASSERT( iap ); + + core_ssid_entry_s* entry = iap_ssid_list_m->current(); + ASSERT( entry ); + + core_scan_list_iterator_by_tag_and_ssid_c iter( + server_m->get_scan_list(), + core_scan_list_tag_direct_scan, + direct_scanned_ssid_m ); + + for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() ) + { + core_iap_data_c iap_data( *iap ); + if ( core_tools_parser_c::is_ap_compatible_with_iap( + server_m->get_wpx_adaptation_instance(), + *ap_data, + iap_data, + server_m->get_core_settings(), + false_t, + false_t ) == core_connect_ok ) + { + DEBUG1( "core_operation_get_available_iaps_c::next_state() - secondary SSID match for IAP ID %u", + iap->id ); + + u32_t* iap_id = new u32_t; + if( iap_id ) + { + *iap_id = iap->id; + iap_id_list_m.append( iap_id ); + iap_id = NULL; + } + + remove_secondary_ssid_entries_by_id( iap->id ); + iap_data_list_m.remove( iap ); + (void)iap_ssid_list_m->first(); + (void)iap_data_list_m.first(); + + delete iap; + iap = NULL; + + return goto_state( core_state_secondary_ssid_next ); + } + } + + DEBUG1S( "core_operation_get_available_iaps_c::next_state() - no matching SSID ", + direct_scanned_ssid_m.length, direct_scanned_ssid_m.ssid ); + + (void)iap_ssid_list_m->next(); + + return goto_state( core_state_secondary_ssid_next ); + } + case core_state_scanning_done: + { + server_m->unregister_frame_handler( this ); + + server_m->get_scan_list().print_contents(); // Additional print + + DEBUG( "core_operation_get_available_iaps_c::next_state() - all scanning done" ); + DEBUG1( "core_operation_get_available_iaps_c::next_state() - scan list contains %u AP(s)", + client_scan_data_m.Count() ); + DEBUG1( "core_operation_get_available_iaps_c::next_state() - scan list size is %u bytes", + client_scan_data_m.Size() ); + DEBUG1( "core_operation_get_available_iaps_c::next_state() - %u IAP(s) found", + iap_id_list_m.count() ); + DEBUG1( "core_operation_get_available_iaps_c::next_state() - %u IAP(s) not found", + non_found_iaps_list_m.count() ); + + /** + * Detect channels that have APs with long beacon intervals. + */ + const u32_t long_beacon_interval( + server_m->get_device_settings().passive_scan_max_ch_time ); + + core_long_beacon_interval_channels_s& long_beacon_interval_channels( + server_m->get_core_settings().long_beacon_interval_channels() ); + + core_scan_list_iterator_by_tag_c iter_long_beacon( + server_m->get_scan_list(), + core_scan_list_tag_scan ); + + for ( core_ap_data_c* ap_data = iter_long_beacon.first(); ap_data; ap_data = iter_long_beacon.next() ) + { + if ( ap_data->beacon_interval() > long_beacon_interval ) + { + const u8_t channel( ap_data->channel() ); + const core_mac_address_s bssid = ap_data->bssid(); + + DEBUG8( "core_operation_get_available_iaps_c::next_state() - BSSID %02X:%02X:%02X:%02X:%02X:%02X on channel %u has a long beacon interval (%u)", + bssid.addr[0], bssid.addr[1], bssid.addr[2], + bssid.addr[3], bssid.addr[4], bssid.addr[5], + channel, + ap_data->beacon_interval() ); + if ( channel && + channel <= SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO ) + { + long_beacon_interval_channels.channel_scan_count[channel - 1] = + server_m->get_device_settings().long_beacon_find_count; + } + } + } + + return core_error_ok; + } + default: + { + } + } + + return core_error_request_pending; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::user_cancel( + bool_t do_graceful_cancel ) + { + DEBUG( "core_operation_get_available_iaps_c::user_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_get_available_iaps_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_long_broadcast_scan_start || + operation_state_m == core_state_broadcast_scan_start || + operation_state_m == core_state_broadcast_scan_start_unknown_region || + operation_state_m == core_state_direct_scan_start || + operation_state_m == core_state_secondary_ssid_start ) && + 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 ); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::remove_non_hidden_iaps() + { + DEBUG("core_operation_get_available_iaps_c::remove_non_hidden_iaps()"); + + core_iap_data_s* iap = iap_data_list_m.first(); + while( iap ) + { + if( !iap->is_hidden ) + { + DEBUG1("core_operation_get_available_iaps_c::remove_non_hidden_iaps() - removing IAP ID %u", + iap->id ); + + core_iap_data_s* temp = iap; + iap = iap_data_list_m.next(); + core_error_e ret = iap_data_list_m.remove( temp ); + if( ret != core_error_ok ) + { + DEBUG1("core_operation_get_available_iaps_c::remove_non_hidden_iaps() - error while removing IAP entry (%d)", + ret ); + } + non_found_iaps_list_m.append( temp ); + } + else + { + DEBUG1("core_operation_get_available_iaps_c::remove_non_hidden_iaps() - leaving IAP ID %u", + iap->id ); + + iap = iap_data_list_m.next(); + } + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::process_scan_results( + u8_t tag ) + { + DEBUG( "core_operation_get_available_iaps_c::process_scan_results()" ); + + core_scan_list_iterator_by_tag_c iter( + server_m->get_scan_list(), + tag ); + + for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() ) + { + remove_matching_iaps( *ap_data ); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::remove_matching_iaps( + core_ap_data_c& ap_data ) + { + DEBUG( "core_operation_get_available_iaps_c::remove_matching_iaps()" ); + + if ( ap_data.rcpi() < server_m->get_device_settings().iap_availability_rcpi_threshold ) + { + DEBUG2( "core_operation_get_available_iaps_c::remove_matching_iaps() - AP not considered, signal too weak (%u vs %u)", + ap_data.rcpi(), server_m->get_device_settings().iap_availability_rcpi_threshold ); + + return; + } + + u8_t treshold_val = + static_cast(server_m->get_core_settings().rcp_improve_boundary()); + + /** + * Loop through the IAP list. + */ + core_iap_data_s* iap = iap_data_list_m.first(); + while( iap ) + { + core_iap_data_c iap_data( *iap ); + if ( iap->ssid == ap_data.ssid() && + core_tools_parser_c::is_ap_compatible_with_iap( + server_m->get_wpx_adaptation_instance(), + ap_data, + iap_data, + server_m->get_core_settings(), + false_t, + false_t ) == core_connect_ok ) + { + DEBUG1("core_operation_get_available_iaps_c::remove_matching_iaps() - match found for IAP ID %u", + iap->id ); + + u32_t* iap_id = new u32_t; + if( iap_id ) + { + if ( server_m->get_core_settings().is_iap_id_in_weak_list( iap->id) ) + { + DEBUG( "core_operation_get_available_iaps_c::remove_matching_iaps() - IAP ID is in weak list" ); + + if ( ap_data.rcpi() > treshold_val ) + { + DEBUG( "core_operation_get_available_iaps_c::remove_matching_iaps() - RCPI improved enough, remove IAP ID from weak list" ); + *iap_id = iap->id; + iap_id_list_m.append( iap_id ); + iap_id = NULL; + + server_m->get_core_settings().remove_iap_id_from_weak_list( iap->id ); + } + + } + else + { + *iap_id = iap->id; + iap_id_list_m.append( iap_id ); + iap_id = NULL; + } + } + + /** Using a temporary pointer to guarantee list iterator working. */ + core_iap_data_s* temp = iap; + + iap = iap_data_list_m.next(); + core_error_e ret = iap_data_list_m.remove( temp ); + if( ret != core_error_ok ) + { + if( iap ) + { + DEBUG1("core_operation_get_available_iaps_c::remove_matching_iaps() - error while removing IAP entry (%d)", + iap->id ); + } + } + + delete temp; + temp = NULL; + delete iap_id; + iap_id = NULL; + } + else + { + iap = iap_data_list_m.next(); + } + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u8_t core_operation_get_available_iaps_c::hidden_iap_count( + core_type_list_c& iap_data_list ) + { + DEBUG( "core_operation_get_available_iaps_c::hidden_iap_count()" ); + + u8_t count( 0 ); + core_iap_data_s* iap = iap_data_list.first(); + + while( iap ) + { + if( iap->is_hidden ) + { + ++count; + } + + iap = iap_data_list.next(); + } + + return count; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::remove_disallowed_aps() + { + core_type_list_c 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(); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +bool_t core_operation_get_available_iaps_c::is_id_in_secondary_ssid_list( + u32_t id ) + { + for( core_ssid_entry_s* iter = iap_ssid_list_m->first(); iter; iter = iap_ssid_list_m->next() ) + { + if ( id == iter->id ) + { + return true_t; + } + } + + return false_t; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_operation_get_available_iaps_c::remove_secondary_ssid_entries_by_id( + u32_t id ) + { + core_ssid_entry_s* iter = iap_ssid_list_m->first(); + while( iter ) + { + if ( id == iter->id ) + { + /** Using a temporary pointer to guarantee list iterator working. */ + core_ssid_entry_s* temp = iter; + iter = iap_ssid_list_m->next(); + + core_error_e ret = iap_ssid_list_m->remove( temp ); + if( ret != core_error_ok ) + { + DEBUG1("core_operation_get_available_iaps_c::remove_secondary_ssid_entries_by_id() - error while removing an entry (%u)", + ret ); + } + + delete temp; + temp = NULL; + } + else + { + iter = iap_ssid_list_m->next(); + } + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +bool_t core_operation_get_available_iaps_c::is_ssid_in_scanlist( + const core_ssid_s& ssid, + const ScanList& scan_data ) + { + u8_t ie_len( 0 ); + const u8_t* ie_data = NULL; + ScanInfo info( scan_data ); + + for ( info.First(); !info.IsDone(); info.Next() ) + { + if( !info.InformationElement( core_frame_dot11_ie_c::core_frame_dot11_ie_element_id_ssid, ie_len, &ie_data ) ) + { + if( core_tools_c::compare( + ssid.ssid, ssid.length, + ie_data, ie_len ) == 0 ) + { + return true_t; + } + } + } + + return false_t; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +bool_t core_operation_get_available_iaps_c::receive_frame( + const core_frame_dot11_c* frame, + u8_t rcpi ) + { + DEBUG( "core_operation_get_available_iaps_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_get_available_iaps_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_get_available_iaps_c::receive_frame() - SSID: ", + ssid.length, &ssid.ssid[0] ); + + const core_mac_address_s bssid = ap_data->bssid(); + DEBUG6( "core_operation_get_available_iaps_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 ); + + active_channels_m.add( + ap_data->band(), + ap_data->channel() ); + + bss_count_m++; + + delete ap_data; + ap_data = NULL; + } + + return true_t; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +bool_t core_operation_get_available_iaps_c::notify( + core_am_indication_e indication ) + { + if ( indication == core_am_indication_wlan_scan_complete ) + { + server_m->unregister_event_handler( this ); + + if ( operation_state_m == core_state_long_broadcast_scan_start ) + { + DEBUG( "core_operation_get_available_iaps_c::notify() - long broadcast scan complete" ); + + asynch_goto( core_state_long_broadcast_scan_done, CORE_TIMER_IMMEDIATELY ); + } + else if ( operation_state_m == core_state_broadcast_scan_start ) + { + DEBUG( "core_operation_get_available_iaps_c::notify() - broadcast scan complete" ); + + asynch_goto( core_state_broadcast_scan_done, CORE_TIMER_IMMEDIATELY ); + } + else if ( operation_state_m == core_state_broadcast_scan_start_unknown_region ) + { + DEBUG( "core_operation_get_available_iaps_c::notify() - broadcast scan complete for channels 12 and 13" ); + + asynch_goto( core_state_broadcast_scan_complete_unknown_region, CORE_TIMER_IMMEDIATELY ); + } + else if ( operation_state_m == core_state_direct_scan_start ) + { + DEBUG( "core_operation_get_available_iaps_c::notify() - direct scan complete" ); + + asynch_goto( core_state_direct_scan_done, CORE_TIMER_IMMEDIATELY ); + } + else if ( operation_state_m == core_state_secondary_ssid_start ) + { + DEBUG( "core_operation_get_available_iaps_c::notify() - direct scan complete" ); + + asynch_goto( core_state_secondary_ssid_done, CORE_TIMER_IMMEDIATELY ); + } + else + { + DEBUG( "core_operation_get_available_iaps_c::notify() - scan complete in unknown state" ); + ASSERT( false_t ); + } + + return true_t; + } + + return false_t; + }