diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_connect.cpp --- /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& 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(&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(&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; + }