wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_connect.cpp
changeset 0 c40eb8fe8501
child 8 e0f767079796
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_connect.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,506 @@
+/*
+* 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:  Statemachine for connecting to a network
+*
+*/
+
+/*
+* %version: 40 %
+*/
+
+#include "genscaninfo.h"
+#include "core_operation_connect.h"
+#include "core_sub_operation_set_static_wep.h"
+#include "core_sub_operation_roam_scan.h"
+#include "core_operation_roam.h"
+#include "core_operation_release.h"
+#include "core_operation_update_power_mode.h"
+#include "core_operation_power_save_test.h"
+#include "abs_core_timer.h"
+#include "core_timer_factory.h"
+#include "core_server.h"
+#include "core_tools.h"
+#include "core_tools_parser.h"
+#include "am_debug.h"
+
+/** The time to wait for DHCP completion after connect */
+const u32_t UPDATE_IP_ADDR_TIMEOUT = 7*1000000; // 7 seconds
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_operation_connect_c::core_operation_connect_c(
+    u32_t request_id,
+    core_server_c* server,
+    abs_core_driverif_c* drivers,
+    abs_core_server_callback_c* adaptation,
+    const core_iap_data_s& settings,
+    core_type_list_c<core_ssid_entry_s>* ssid_list,
+    core_connect_status_e& connect_status ) :
+    core_operation_base_c( core_operation_connect, request_id, server, drivers, adaptation, 
+        core_base_flag_drivers_needed | core_base_flag_roam_operation ),
+    settings_m( settings ),
+    connect_status_m( connect_status ),
+    failure_count_m( 0 ),
+    is_connected_m( false_t ),
+    ssid_m( settings.ssid ),
+    ssid_list_m( ssid_list ),
+    release_reason_m( core_release_reason_max_roam_attempts_exceeded )
+    {
+    DEBUG( "core_operation_connect_c::core_operation_connect_c()" );
+
+    connect_status_m = core_connect_undefined;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_operation_connect_c::~core_operation_connect_c()
+    {
+    DEBUG( "core_operation_connect_c::~core_operation_connect_c()" );
+    }
+   
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_operation_connect_c::next_state()
+    {
+    DEBUG( "core_operation_connect_c::next_state()" );
+
+    switch ( operation_state_m )
+        {
+        case core_state_init:
+            {
+            if ( server_m->get_core_settings().is_connected() )
+                {
+                DEBUG( "core_operation_connect_c::next_state() - already connected, completing request" );
+
+                return core_error_connection_already_active;
+                }            
+
+            core_error_e ret = server_m->init_connection_data(
+                settings_m,
+                server_m->get_device_settings() );
+            if( ret != core_error_ok )
+                {
+                DEBUG1( "core_operation_connect_c::next_state() - unable to initialize connection data (%d)", ret );
+                
+                return ret;
+                }
+
+            if( server_m->get_connection_data()->iap_data().is_eap_used() &&
+                !server_m->create_eapol_instance( core_eapol_operating_mode_wfa ) )
+                {
+                DEBUG( "core_operation_connect_c::next_state() - unable to instantiate EAPOL (WFA)" );
+
+                return core_error_no_memory;               
+                }
+            else if( server_m->get_connection_data()->iap_data().is_wapi_used() &&
+                     !server_m->create_eapol_instance( core_eapol_operating_mode_wapi ) )
+                {
+                DEBUG( "core_operation_connect_c::next_state() - unable to instantiate EAPOL (WAPI)" );
+
+                return core_error_no_memory;               
+                }
+            
+            if( server_m->get_connection_data()->iap_data().operating_mode() == core_operating_mode_ibss &&
+                ( server_m->get_connection_data()->iap_data().security_mode() != core_security_mode_allow_unsecure && 
+                  server_m->get_connection_data()->iap_data().security_mode() != core_security_mode_wep ) )
+                {
+                DEBUG1( "core_operation_connect_c::next_state() - ad-hoc with security mode %d not supported",
+                        server_m->get_connection_data()->iap_data().security_mode() );
+
+                return core_error_not_supported;
+                }
+
+            server_m->get_core_settings().clear_connection_statistics();
+            server_m->get_core_settings().roam_metrics().set_roam_ts_userdata_disabled();
+
+            server_m->get_connection_data()->set_last_roam_reason(
+                core_roam_reason_initial_connect );
+            server_m->get_core_settings().roam_metrics().inc_roam_attempt_count(
+                core_roam_reason_initial_connect );
+
+            DEBUG( "core_operation_connect_c::next_state() - reseting RCPI roam check interval" );
+            server_m->get_connection_data()->reset_rcpi_roam_interval();
+
+            /**
+             * Indicate core_connection_state_searching state to adaptation.
+             */
+            core_connection_state_e state = core_connection_state_searching;
+            server_m->get_core_settings().set_connection_state( state );
+
+            if ( server_m->get_connection_data()->last_connection_state() != state )
+                {
+                u8_t buf[5];
+                buf[0] = static_cast<u8_t>( state );
+                adaptation_m->notify(
+                    core_notification_connection_state_changed,
+                    1,
+                    buf );
+
+                server_m->get_connection_data()->set_last_connection_state(
+                    state );
+                }
+
+            /**
+             * Disable the power save mode before first connect.
+             */
+            core_operation_base_c* operation = new core_operation_update_power_mode_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                CORE_POWER_SAVE_MODE_NONE );
+
+            return run_sub_operation( operation, core_state_power_mode );
+            }
+        case core_state_power_mode:
+            {
+            if ( ssid_list_m &&
+                 ssid_list_m->count() )
+                {
+                DEBUG1( "core_operation_connect_c::next_state() - IAP has %u secondary SSID(s) defined",
+                    ssid_list_m->count() );
+
+                operation_state_m = core_state_secondary_ssid_scan_start;
+                }
+            else
+                {
+                operation_state_m = core_state_scan_start;
+                }
+
+            if ( server_m->get_connection_data()->iap_data().security_mode() == core_security_mode_wep )
+                {
+                core_operation_base_c* operation = new core_sub_operation_set_static_wep_c(
+                    request_id_m,
+                    server_m,
+                    drivers_m,
+                    adaptation_m );
+
+                return run_sub_operation( operation );
+                }
+
+            return next_state();
+            }
+        case core_state_secondary_ssid_scan_start:
+            {
+            DEBUG( "core_operation_connect_c::next_state() - doing a broadcast scan to detect available secondary SSIDs" );
+
+            ASSERT( ssid_list_m );
+            ASSERT( ssid_list_m->count() );
+            (void)ssid_list_m->first();
+
+            server_m->get_scan_list().set_tag(
+                core_scan_list_tag_scan );
+
+            core_operation_base_c* operation = new core_sub_operation_roam_scan_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                BROADCAST_SSID,
+                server_m->get_core_settings().all_valid_scan_channels(),
+                false_t,
+                false_t );
+
+            return run_sub_operation( operation, core_state_secondary_ssid_scan );
+            }
+        case core_state_secondary_ssid_scan:
+            {
+            ASSERT( ssid_list_m );
+            ASSERT( ssid_list_m->count() );
+
+            core_ssid_entry_s* entry =
+                ssid_list_m->current();
+            ASSERT( entry );
+
+            DEBUG( "core_operation_connect_c::next_state() - searching broadcast scan results for the secondary SSID:" );
+            DEBUG1S( "core_operation_connect_c::next_state() - ssid: ",
+                entry->ssid.length, &entry->ssid.ssid[0] );
+            DEBUG1S( "core_operation_connect_c::next_state() - used_ssid: ",
+                entry->used_ssid.length, &entry->used_ssid.ssid[0] );
+
+            core_scan_list_iterator_by_tag_and_ssid_c iter(
+                server_m->get_scan_list(),
+                core_scan_list_tag_scan,
+                entry->ssid );
+
+            if ( iter.first() != NULL )
+                {
+                DEBUG( "core_operation_connect_c::next_state() - secondary SSID match found" );
+                ssid_m = entry->used_ssid;
+
+                return goto_state( core_state_scan_start );
+                }
+
+            DEBUG( "core_operation_connect_c::next_state() - secondary SSID match not found" );
+
+            return goto_state( core_state_connect_secondary_ssid_failure );
+            }
+        case core_state_scan_start:
+            {
+            operation_state_m = core_state_scan_complete;
+
+            DEBUG( "core_operation_connect_c::next_state() - starting a direct scan on all channels" );
+
+            server_m->get_scan_list().set_tag(
+                core_scan_list_tag_roam_scan );
+
+            core_operation_base_c* operation = new core_sub_operation_roam_scan_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                ssid_m,
+                server_m->get_core_settings().all_valid_scan_channels(),
+                false_t,
+                false_t );
+
+            return run_sub_operation( operation );
+            }
+        case core_state_scan_complete:
+            {
+            operation_state_m = core_state_connect_success;
+
+            DEBUG1S( "core_operation_connect_c::next_state() - trying to connect to SSID ",
+                ssid_m.length, &ssid_m.ssid[0] );
+
+            core_operation_base_c* operation = new core_operation_roam_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                is_connected_m,
+                core_scan_list_tag_roam_scan,
+                RCPI_VALUE_NONE,
+                MEDIUM_TIME_NOT_DEFINED,                                
+                ssid_m,
+                BROADCAST_MAC_ADDR );
+
+            return run_sub_operation( operation );
+            }            
+        case core_state_connect_failure:
+            {
+            if ( failure_reason_m == core_error_not_found )
+                {
+                failure_count_m++;
+
+                if ( ssid_list_m &&
+                     ssid_list_m->count() )
+                    {
+                    return goto_state( core_state_connect_secondary_ssid_failure );
+                    }
+                }
+            else
+                {
+                failure_count_m = 0;
+                }
+
+            DEBUG1( "core_operation_connect_c::next_state() - connecting has failed %u time(s)",
+                failure_count_m );
+            DEBUG1( "core_operation_connect_c::next_state() - failure_reason_m is %u",
+                failure_reason_m );
+            DEBUG1( "core_operation_connect_c::next_state() - connect_status is %u",
+                server_m->get_connection_data()->connect_status() );
+
+            /**
+             * If EAPOL has notified about a total failure or we have tried too many times,
+             * close down the connection. Otherwise, try again.
+             */
+            if ( failure_reason_m == core_error_eapol_total_failure ||
+                 failure_reason_m == core_error_eapol_canceled_by_user ||
+                 failure_count_m >= server_m->get_device_settings().max_tries_to_find_nw )
+                {
+                return goto_state( core_state_connect_total_failure );
+                }
+
+            return asynch_goto(
+                core_state_scan_start,
+                server_m->get_device_settings().delay_between_find_nw );
+            }
+        case core_state_connect_secondary_ssid_failure:
+            {
+            DEBUG( "core_operation_connect_c::next_state() - trying the next secondary SSID entry" );
+
+            core_ssid_entry_s* entry =
+                ssid_list_m->next();
+            if ( entry )
+                {
+                return asynch_goto( core_state_secondary_ssid_scan );
+                }
+
+            DEBUG( "core_operation_connect_c::next_state() - no more secondary SSID entries to try, closing connection" );
+            if ( server_m->get_connection_data()->connect_status() == core_connect_undefined )
+                {
+                server_m->get_connection_data()->set_connect_status( core_connect_network_not_found );
+                }
+
+            return goto_state( core_state_connect_total_failure );
+            }
+        case core_state_connect_total_failure:
+            {
+            operation_state_m = core_state_connect_disconnect;
+
+            DEBUG1( "core_operation_connect_c::next_state() - gave up connecting after %u tries",
+                failure_count_m );
+
+            /**
+             * Complete adaptation with the same status as was set to connection data.
+             */
+            connect_status_m = server_m->get_connection_data()->connect_status();
+
+            core_operation_base_c* operation = new core_operation_release_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                release_reason_m );
+
+            return run_sub_operation( operation );
+            }
+        case core_state_connect_disconnect:
+            {
+            DEBUG( "core_operation_connect_c::next_state() - connection closed successfully" );            
+            return core_error_ok;
+            }
+        case core_state_connect_success:
+            {
+            operation_state_m = core_state_set_rcpi_trigger;
+
+            DEBUG( "core_operation_connect_c::next_state() - connected successfully" );
+
+            /**
+             * If no roaming between APs is allowed, add the current AP to the
+             * whitelist to prevent roaming in BSS lost situations.
+             */
+            if ( !server_m->get_connection_data()->iap_data().is_roaming_allowed() &&
+                 server_m->get_connection_data()->iap_data().operating_mode() == core_operating_mode_infrastructure )
+                {
+                const core_mac_address_s current_bssid =
+                    server_m->get_connection_data()->current_ap_data()->bssid();
+
+                server_m->get_connection_data()->iap_data().add_mac_to_iap_whitelist(
+                    current_bssid );
+                }
+
+            /**
+             * If power save is enabled in infrastructure mode, schedule a power save test.
+             */
+            if ( server_m->get_connection_data()->iap_data().operating_mode() == core_operating_mode_infrastructure &&
+                 server_m->get_device_settings().power_save_enabled )
+                {
+                if ( server_m->get_connection_data()->iap_data().is_dynamic_ip_addr() )
+                    {
+                    DEBUG( "core_operation_connect_c::next_state() - scheduling a power save test after DHCP timeout" );
+                    server_m->schedule_dhcp_timer( UPDATE_IP_ADDR_TIMEOUT );
+                    }
+                else
+                    {
+                    DEBUG( "core_operation_connect_c::next_state() - scheduling a power save test" );
+
+                    core_operation_base_c* operation = new core_operation_power_save_test_c(
+                        REQUEST_ID_CORE_INTERNAL,
+                        server_m,
+                        drivers_m,
+                        adaptation_m );
+
+                    server_m->queue_int_operation( operation );
+                    }
+                }
+
+            /**
+             * RCPI trigger is only used in infrastructure mode.
+             */
+            if ( server_m->get_connection_data()->iap_data().operating_mode() !=
+                core_operating_mode_infrastructure )
+                {
+                return next_state();
+                }
+
+            DEBUG1( "core_operation_connect_c::next_state() - internal RCPI threshold level is %u",
+                server_m->get_device_settings().rcpi_trigger );
+            DEBUG1( "core_operation_connect_c::next_state() - external RCPI threshold level is %u",
+                server_m->get_core_settings().rcp_decline_boundary() );
+
+            u8_t trigger_level = server_m->get_core_settings().rcp_decline_boundary();
+            if ( trigger_level < server_m->get_device_settings().rcpi_trigger )
+                {
+                trigger_level = server_m->get_device_settings().rcpi_trigger;
+                }
+            DEBUG1( "core_operation_connect_c::next_state() - arming RCPI roam trigger (%u)",
+                trigger_level );
+
+            drivers_m->set_rcpi_trigger_level(
+                request_id_m,
+                trigger_level );
+
+            break;
+            }
+        case core_state_set_rcpi_trigger:
+            {
+            // Connection is OK, complete connection data
+            server_m->get_connection_data()->set_connect_status( core_connect_ok );
+            // complete adaptation status
+            connect_status_m = core_connect_ok;
+            // complete operation
+
+            return core_error_ok;
+            }
+        default:
+            {
+            ASSERT( false_t );
+            }
+        }
+
+    return core_error_request_pending;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_operation_connect_c::user_cancel(
+    bool_t /* do_graceful_cancel */ )
+    {
+    DEBUG( "core_operation_connect_c::user_cancel()" );
+
+    release_reason_m = core_release_reason_external_request;
+
+    operation_state_m = core_state_connect_total_failure;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_operation_connect_c::cancel()
+    {
+    DEBUG( "core_operation_connect_c::cancel() " );    
+
+    switch( operation_state_m )
+        {
+        case core_state_connect_success:
+            {
+            return goto_state( core_state_connect_failure );
+            }
+        default:
+            {
+            // complete adaptation with the same status as was just set to connection data
+            connect_status_m = server_m->get_connection_data()->connect_status();
+            // connect operation returns OK if possible
+            return core_error_ok;
+            }
+        }
+    }