wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_connect.cpp
changeset 0 c40eb8fe8501
child 3 6524e815f76f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_connect.cpp	Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,381 @@
+/*
+* 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:  Statemachine for connecting to a network
+*
+*/
+
+
+#include "core_sub_operation_connect.h"
+#include "core_operation_update_tx_rate_policies.h"
+#include "core_frame_beacon.h"
+#include "core_frame_dot11_ie.h"
+#include "core_frame_assoc_resp.h"
+#include "core_server.h"
+#include "core_tools.h"
+#include "am_debug.h"
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_connect_c::core_sub_operation_connect_c(
+    u32_t request_id,
+    core_server_c* server,
+    abs_core_driverif_c* drivers,
+    abs_core_server_callback_c* adaptation,
+    bool_t& is_connected,
+    core_management_status_e& connect_status,
+    const core_ssid_s& ssid,
+    core_ap_data_c& ap_data,
+    u16_t auth_algorithm,
+    core_encryption_mode_e encryption_level,
+    core_cipher_key_type_e pairwise_key_type,
+    core_type_list_c<core_frame_dot11_ie_c>& assoc_ie_list,
+    core_frame_assoc_resp_c** assoc_resp,
+    bool_t is_pairwise_key_invalidated,
+    bool_t is_group_key_invalidated ) :
+    core_operation_base_c( core_operation_unspecified, request_id, server, drivers, adaptation,
+        core_base_flag_drivers_needed ),
+    is_connected_m( is_connected ),
+    connect_status_m( connect_status ),
+    ssid_m( ssid ),
+    ap_data_m( ap_data ),
+    auth_algorithm_m( auth_algorithm ),
+    encryption_m( encryption_level ),
+    pairwise_key_type_m( pairwise_key_type ),
+    tx_level_m( 0 ),
+    assoc_ie_list_m( assoc_ie_list ),
+    assoc_ie_data_m( NULL ),
+    assoc_resp_m( assoc_resp ),
+    is_pairwise_key_invalidated_m( is_pairwise_key_invalidated ),
+    is_group_key_invalidated_m( is_group_key_invalidated )
+    {
+    DEBUG( "core_sub_operation_connect_c::core_sub_operation_connect_c()" );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_connect_c::~core_sub_operation_connect_c()
+    {    
+    DEBUG( "core_sub_operation_connect_c::~core_sub_operation_connect_c()" );
+
+    server_m->unregister_frame_handler( this );
+    delete[] assoc_ie_data_m;   
+    assoc_resp_m = NULL;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_connect_c::next_state()
+    {
+    DEBUG( "core_sub_operation_connect_c::next_state()" );
+
+    switch ( operation_state_m )
+        {
+        case core_state_init:
+            {
+            operation_state_m = core_state_req_set_tx_level;
+
+            tx_level_m = server_m->get_device_settings().tx_power_level;
+
+            u32_t max_tx_power_level = ap_data_m.max_tx_power_level();
+            if ( max_tx_power_level < tx_level_m )
+                {
+                tx_level_m = max_tx_power_level;
+                DEBUG1( "core_sub_operation_connect_c::next_state() - setting maximum tx level to %u",
+                    tx_level_m );
+
+                drivers_m->set_tx_power_level(
+                    request_id_m,
+                    tx_level_m );                    
+                }
+            else
+                {
+                DEBUG( "core_sub_operation_connect_c::next_state() - no reason to set tx level" );
+
+                return next_state();
+                }
+
+            break;
+            }
+        case core_state_req_set_tx_level:
+            {
+            operation_state_m = core_state_req_set_tx_rate_policies;
+
+            if ( server_m->get_connection_data()->last_tx_level() != tx_level_m )
+                {
+                DEBUG( "core_sub_operation_connect_c::next_state() - TX level has changed, notifying change" );
+
+                adaptation_m->notify(
+                    core_notification_tx_power_level_changed,
+                    sizeof( tx_level_m ),
+                    reinterpret_cast<u8_t*>(&tx_level_m) );
+
+                server_m->get_connection_data()->set_last_tx_level( tx_level_m );
+                }
+
+            core_operation_base_c* operation = new core_operation_update_tx_rate_policies_c(
+                request_id_m,
+                server_m,
+                drivers_m,
+                adaptation_m,
+                ap_data_m );
+
+            return run_sub_operation( operation );
+            }
+        case core_state_req_set_tx_rate_policies:
+            {
+            operation_state_m = core_state_connect;
+
+            DEBUG6( "core_sub_operation_connect_c::next_state() - trying to associate to %02X:%02X:%02X:%02X:%02X:%02X",
+                ap_data_m.bssid().addr[0], ap_data_m.bssid().addr[1], ap_data_m.bssid().addr[2],
+                ap_data_m.bssid().addr[3], ap_data_m.bssid().addr[4], ap_data_m.bssid().addr[5] );
+
+            server_m->get_wpx_adaptation_instance().get_association_request_wpx_ie(
+                ap_data_m,
+                assoc_ie_list_m );
+
+            if( ap_data_m.is_radio_measurement_supported() == true_t &&
+                server_m->get_core_settings().is_feature_enabled( core_feature_802dot11k ) )
+                {
+                u8_t max_capability = ap_data_m.max_tx_power_level();
+
+                /**
+                 * Power capability IE.
+                 */        
+                core_frame_radio_mgmt_ie_c* capability_ie = core_frame_radio_mgmt_ie_c::instance(
+                    CORE_FRAME_RADIO_MGMT_IE_LENGTH,
+                    CORE_FRAME_RADIO_MGMT_IE_MIN_POWER_CAPABILITY,
+                    max_capability );
+                if ( capability_ie )
+                    {
+                    assoc_ie_list_m.append(
+                        capability_ie,
+                        capability_ie->element_id() );            
+                    }
+
+                /**
+                 * RRM enabled capabilities IE.
+                 */        
+                const u64_t rrm_capability( RRM_CAPABILITY_BIT_MASK );
+
+                core_frame_rrm_mgmt_ie_c* rrm_capability_ie = core_frame_rrm_mgmt_ie_c::instance(
+                    reinterpret_cast<const u8_t*>(&rrm_capability) );
+                if ( rrm_capability_ie )
+                    {
+                    assoc_ie_list_m.append(
+                        rrm_capability_ie,
+                        rrm_capability_ie->element_id() );            
+                    }
+                }
+
+            /**
+             * Copy all the IEs to a buffer.
+             */
+            u32_t assoc_ie_data_length( 0 );
+            u32_t assoc_ie_data_index( 0 );
+            
+            core_frame_dot11_ie_c* ie = assoc_ie_list_m.first();
+            while( ie )
+                {
+                assoc_ie_data_length += ie->data_length();
+
+                ie = assoc_ie_list_m.next();
+                }
+
+            if ( assoc_ie_data_length )
+                {
+                assoc_ie_data_m = new u8_t[assoc_ie_data_length];
+                ie = assoc_ie_list_m.first();
+                while( ie )
+                    {
+                    DEBUG2( "core_sub_operation_connect_c::next_state() - adding IE ID %u (0x%02X)",
+                        ie->element_id(), ie->element_id() );
+                    DEBUG_BUFFER(
+                        ie->data_length(),
+                        ie->data() );
+
+                    core_tools_c::copy(
+                        &assoc_ie_data_m[assoc_ie_data_index],
+                        ie->data(),
+                        ie->data_length() );
+
+                    assoc_ie_data_index += ie->data_length();
+                    ie = assoc_ie_list_m.next();
+                    }
+                }
+            else
+                {
+                DEBUG( "core_sub_operation_connect_c::next_state() - no IEs to add to the (re-)association request" );
+                }
+
+            server_m->get_core_settings().roam_metrics().set_roam_ts_connect_started();
+
+            server_m->register_frame_handler( this );
+
+            drivers_m->connect(                
+                request_id_m,
+                connect_status_m,
+                ssid_m,
+                ap_data_m.bssid(),
+                auth_algorithm_m,
+                encryption_m,
+                pairwise_key_type_m,
+                ap_data_m.is_infra(),
+                assoc_ie_data_length,
+                assoc_ie_data_m,
+                ap_data_m.frame()->payload_data_length(),
+                ap_data_m.frame()->payload_data(),
+                is_pairwise_key_invalidated_m,
+                is_group_key_invalidated_m,
+                ap_data_m.is_radio_measurement_supported() );
+
+            break;    
+            }
+        case core_state_connect:
+            {
+            operation_state_m = core_state_connect_frame;
+
+            /**
+             * If (re-)association response frame is not needed or it has
+             * already been received, proceed to the next state.
+             */            
+            if( !assoc_resp_m ||
+                *assoc_resp_m )
+                {
+                return goto_state( core_state_connect_complete );
+                }
+
+            return goto_state( core_state_connect_frame );
+            }
+        case core_state_connect_frame:
+            {
+            DEBUG( "core_sub_operation_connect_c::next_state() - waiting for (re-)association response frame" );
+
+            break;
+            }
+        case core_state_connect_complete:
+            {
+            server_m->unregister_frame_handler( this );
+            server_m->get_core_settings().roam_metrics().set_roam_ts_connect_completed();
+            server_m->get_wpx_adaptation_instance().handle_association_response(
+                ap_data_m,
+                assoc_resp_m ? *assoc_resp_m : NULL );
+
+            return core_error_ok;
+            }
+        default:
+            {
+            ASSERT( false_t );
+            }
+        }
+
+    return core_error_request_pending;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_sub_operation_connect_c::user_cancel(
+    bool_t do_graceful_cancel )
+    {
+    DEBUG( "core_sub_operation_connect_c::user_cancel()" );
+
+    if ( !do_graceful_cancel )
+        {
+        /**
+         * If we are waiting for a beacon, we have to schedule our own
+         * event.
+         */
+        if ( operation_state_m == core_state_connect_frame )
+            {
+            asynch_default_user_cancel();
+
+            return;            
+            }
+        }
+
+    /**
+     * Everything else is handled by the default implementation.
+     */
+    core_operation_base_c::user_cancel( do_graceful_cancel );
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_connect_c::cancel()
+    {
+    DEBUG( "core_sub_operation_connect_c::cancel() " );    
+    
+    switch ( operation_state_m )
+        {              
+        case core_state_connect:
+            {
+            /** The connection attempt failed, we are no longer connected. */
+            is_connected_m = false_t;
+
+            return goto_state( core_state_connect_complete );
+            }
+        default:
+            {
+            return failure_reason_m;
+            }
+        }    
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//    
+bool_t core_sub_operation_connect_c::receive_frame(
+    const core_frame_dot11_c* frame,
+    u8_t /* rcpi */ )
+    {
+    DEBUG( "core_sub_operation_connect_c::receive_frame()" );
+    
+    if ( frame->type() != core_frame_dot11_c::core_dot11_type_association_resp &&
+         frame->type() != core_frame_dot11_c::core_dot11_type_reassociation_resp )
+        {
+        DEBUG( "core_sub_operation_connect_c::receive_frame() - not a (re-)association response" );
+        return false_t;
+        }
+
+    if ( !assoc_resp_m )
+        {
+        DEBUG( "core_sub_operation_connect_c::receive_frame() - parent operation not interested in (re-)association response" );
+        return true_t;
+        }
+    else if ( *assoc_resp_m )
+        {
+        DEBUG( "core_sub_operation_connect_c::receive_frame() - (re-)association response already received" );
+        return true_t;       
+        }    
+
+    DEBUG( "core_sub_operation_connect_c::receive_frame() - (re-)association response received" );
+    *assoc_resp_m = core_frame_assoc_resp_c::instance( *frame, true_t );
+
+    /**
+     * If we are just waiting for the response frame, we have to schedule
+     * our own timer to proceed.
+     */
+    if( operation_state_m == core_state_connect_frame )
+        {
+        asynch_goto( core_state_connect_complete, CORE_TIMER_IMMEDIATELY );
+        }
+
+    return true_t;
+    }