--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_adhoc.cpp Tue Feb 02 02:03:13 2010 +0200
@@ -0,0 +1,444 @@
+/*
+* 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 establishing an adhoc network
+*
+*/
+
+
+#include "core_sub_operation_adhoc.h"
+#include "core_tx_rate_policies.h"
+#include "core_frame_dot11.h"
+#include "core_server.h"
+#include "core_tools.h"
+#include "am_debug.h"
+
+/** The channel definition for automatic channel selection. */
+const u32_t AUTOMATIC_CHANNEL = 0;
+
+const u32_t CH_WEIGHT_1 = 4;
+const u32_t CH_WEIGHT_2 = 2;
+const u32_t CH_WEIGHT_3 = 1;
+
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_adhoc_c::core_sub_operation_adhoc_c(
+ u32_t request_id,
+ core_server_c* server,
+ abs_core_driverif_c* drivers,
+ abs_core_server_callback_c* adaptation,
+ core_ap_data_c** ap_data ) :
+ core_operation_base_c( core_operation_unspecified, request_id, server, drivers, adaptation,
+ core_base_flag_drivers_needed ),
+ ptr_ap_data_m( ap_data ),
+ channel_m( 0 )
+ {
+ DEBUG( "core_sub_operation_adhoc_c::core_sub_operation_adhoc_c()" );
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_sub_operation_adhoc_c::~core_sub_operation_adhoc_c()
+ {
+ DEBUG( "core_sub_operation_adhoc_c::~core_sub_operation_adhoc_c()" );
+
+ server_m->unregister_event_handler( this );
+ server_m->unregister_frame_handler( this );
+ ptr_ap_data_m = NULL;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_adhoc_c::next_state()
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state()" );
+
+ switch ( operation_state_m )
+ {
+ case core_state_init:
+ {
+ core_tools_c::fillz(
+ &noise_per_channel_m[0],
+ SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO * sizeof( u32_t ) );
+
+ core_iap_data_c* iap = &(server_m->get_connection_data()->iap_data());
+ ASSERT( iap->adhoc_channel() <= SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_FCC ); // FCC limitations: no ch 12 or 13
+ ASSERT( iap->ssid().length );
+ ASSERT( iap->ssid().length <= MAX_SSID_LEN );
+ ASSERT( iap->security_mode() == core_security_mode_allow_unsecure ||
+ iap->security_mode() == core_security_mode_wep );
+
+ channel_m = iap->adhoc_channel();
+ if ( channel_m != AUTOMATIC_CHANNEL )
+ {
+ return goto_state( core_state_req_set_tx_rate_policies );
+ }
+
+ /**
+ * Do a broadcast scan to detect the channel with least traffic.
+ */
+ operation_state_m = core_state_scan_start;
+
+ server_m->get_scan_list().remove_entries_by_age(
+ server_m->get_device_settings().scan_list_expiration_time );
+
+ 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,
+ server_m->get_core_settings().all_valid_scan_channels(),
+ server_m->get_device_settings().passive_scan_min_ch_time,
+ server_m->get_device_settings().passive_scan_max_ch_time,
+ false_t );
+
+ break;
+ }
+ case core_state_scan_start:
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - scan request completed, waiting for scan completion" );
+
+ break;
+ }
+ case core_state_scan_complete:
+ {
+ server_m->unregister_frame_handler( this );
+
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - selecting channel with least noise" );
+
+ /**
+ * All channels are now checked and the noise marked.
+ * Now, we have to found the smallest noise.
+ */
+ u32_t tmp_best_noise( 0xFFFFFFFF );
+ u8_t tmp_best_channel( 0 );
+ for ( u8_t idx = 0; idx < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_FCC; ++idx ) // Only ch 1 - 11
+ {
+ DEBUG2( "core_sub_operation_adhoc_c::next_state() - NoiseTable[%u] = %u",
+ idx, noise_per_channel_m[idx] );
+ if ( noise_per_channel_m[idx] < tmp_best_noise )
+ {
+ tmp_best_noise = noise_per_channel_m[idx];
+ tmp_best_channel = idx;
+ }
+ }
+ channel_m = tmp_best_channel + 1;
+ DEBUG1( "core_sub_operation_adhoc_c::next_state() - channel %u selected",
+ channel_m );
+
+ return goto_state( core_state_req_set_tx_rate_policies );
+ }
+ case core_state_req_set_tx_rate_policies:
+ {
+ operation_state_m = core_state_req_start_adhoc;
+
+ core_tx_rate_policies_s policies;
+ core_tx_rate_policy_mappings_s mappings;
+
+ if ( server_m->get_core_settings().is_bt_connection_established() )
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - using 802.11bg BT TX rate policy" );
+
+ policies.policy_count = 1;
+ policies.policy[0] = TX_RATE_POLICY_BLUETOOTH_BG;
+ mappings.policy_for_best_effort = 0;
+ mappings.policy_for_background = 0;
+ mappings.policy_for_video = 0;
+ mappings.policy_for_voice = 0;
+ }
+ else
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - using 802.11bg default and voice TX rate policy" );
+
+ policies.policy_count = 2;
+ policies.policy[0] = TX_RATE_POLICY_BG;
+ policies.policy[1] = TX_RATE_POLICY_VOICE_BG;
+ mappings.policy_for_best_effort = 0;
+ mappings.policy_for_background = 0;
+ mappings.policy_for_video = 0;
+ mappings.policy_for_voice = 1;
+ }
+
+ /**
+ * Fill in the default retry limits if not overridden by the policy.
+ */
+ for ( u8_t idx( 0 ); idx < policies.policy_count; ++idx )
+ {
+ if ( !policies.policy[idx].short_retry_limit )
+ {
+ policies.policy[idx].short_retry_limit =
+ server_m->get_device_settings().short_retry;
+ }
+ if ( ! policies.policy[idx].long_retry_limit )
+ {
+ policies.policy[idx].long_retry_limit =
+ server_m->get_device_settings().long_retry;
+ }
+ }
+
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - setting TX rate policies" );
+
+ drivers_m->set_tx_rate_policies(
+ request_id_m,
+ policies,
+ mappings );
+
+ break;
+ }
+ case core_state_req_start_adhoc:
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - TX rate policies set" );
+
+ operation_state_m = core_state_adhoc_started;
+
+ core_encryption_mode_e encryption_mode = core_encryption_mode_disabled;
+ if( server_m->get_connection_data()->iap_data().security_mode() ==
+ core_security_mode_wep )
+ {
+ encryption_mode = core_encryption_mode_wep;
+ }
+
+ DEBUG1( "core_sub_operation_adhoc_c::next_state() - starting the adhoc on channel %u",
+ channel_m );
+
+ server_m->register_frame_handler( this );
+
+ drivers_m->start_ibss(
+ request_id_m,
+ server_m->get_connection_data()->iap_data().ssid(),
+ server_m->get_device_settings().beacon,
+ channel_m,
+ encryption_mode );
+
+ break;
+ }
+ case core_state_adhoc_started:
+ {
+ /**
+ * If our own beacon has already been received, proceed to the
+ * next state.
+ */
+ if( *ptr_ap_data_m )
+ {
+ return goto_state( core_state_adhoc_complete );
+ }
+
+ return goto_state( core_state_adhoc_frame );
+ }
+ case core_state_adhoc_frame:
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - waiting for beacon frame" );
+
+ break;
+ }
+ case core_state_adhoc_complete:
+ {
+ server_m->unregister_frame_handler( this );
+
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - all done" );
+
+ return core_error_ok;
+ }
+ default:
+ {
+ ASSERT( false_t );
+ }
+ }
+
+ return core_error_request_pending;
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+core_error_e core_sub_operation_adhoc_c::cancel()
+ {
+ DEBUG( "core_sub_operation_adhoc_c::cancel() " );
+
+ switch ( operation_state_m )
+ {
+ case core_state_adhoc_started:
+ {
+ /** The connection attempt failed, we are no longer connected. */
+ return next_state();
+ }
+ default:
+ {
+ return failure_reason_m;
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+void core_sub_operation_adhoc_c::user_cancel(
+ bool_t do_graceful_cancel )
+ {
+ DEBUG( "core_sub_operation_adhoc_c::user_cancel()" );
+
+ 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 &&
+ server_m->event_handler() == this &&
+ server_m->frame_handler() == this )
+ {
+ asynch_default_user_cancel();
+
+ return;
+ }
+
+ /**
+ * If we are waiting for a beacon, we have to schedule our own
+ * event.
+ */
+ if ( operation_state_m == core_state_adhoc_frame )
+ {
+ 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_sub_operation_adhoc_c::receive_frame(
+ const core_frame_dot11_c* frame,
+ u8_t rcpi )
+ {
+ DEBUG( "core_sub_operation_adhoc_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_sub_operation_adhoc_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,
+ true_t );
+ if ( ap_data )
+ {
+ server_m->get_scan_list().update_entry( *ap_data );
+
+ if ( operation_state_m == core_state_scan_start )
+ {
+ u8_t channel = ap_data->channel();
+ DEBUG1( "core_sub_operation_adhoc_c::next_state() - AP in channel %u",
+ channel );
+
+ if ( channel && channel <= SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO )
+ {
+ /**
+ * Add the ch table as follows:
+ * channel of the AP ==> increase by CH_WEIGHT_1
+ * channels +-1 ==> increase by CH_WEIGHT_2
+ * channels +-2 ==> increase by CH_WEIGHT_3
+ *
+ * Note that the legal channels are 1 - 13 BUT the
+ * array is 0 - 12! Beware edges!
+ */
+ noise_per_channel_m[channel - 1] += CH_WEIGHT_1;
+ if ( channel > 1 )
+ {
+ noise_per_channel_m[channel - 2] += CH_WEIGHT_2;
+ }
+ if ( channel > 2)
+ {
+ noise_per_channel_m[channel - 3] += CH_WEIGHT_3;
+ }
+ if ( channel < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO -2 )
+ {
+ noise_per_channel_m[channel] += CH_WEIGHT_2;
+ }
+ if ( channel < SCAN_BAND_2DOT4GHZ_MAX_CHANNEL_EURO -3 )
+ {
+ noise_per_channel_m[channel + 1] += CH_WEIGHT_3;
+ }
+ }
+ }
+ else if ( operation_state_m == core_state_adhoc_started ||
+ operation_state_m == core_state_adhoc_frame )
+ {
+ if ( frame->type() == core_frame_dot11_c::core_dot11_type_beacon )
+ {
+ DEBUG( "core_sub_operation_adhoc_c::next_state() - beacon received" );
+
+ ASSERT( !ap_data->is_infra() );
+ ASSERT( !*ptr_ap_data_m );
+
+ *ptr_ap_data_m = ap_data;
+
+ /**
+ * If we are just waiting for the beacon frame, we have to schedule
+ * our own timer to proceed.
+ */
+ if( operation_state_m == core_state_adhoc_frame )
+ {
+ asynch_goto( core_state_adhoc_complete, CORE_TIMER_IMMEDIATELY );
+ }
+
+ return true_t;
+ }
+ }
+
+ delete ap_data;
+ ap_data = NULL;
+ }
+
+ return true_t;
+ }
+
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+bool_t core_sub_operation_adhoc_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_sub_operation_adhoc_c::notify() - scan complete" );
+
+ asynch_goto( core_state_scan_complete, CORE_TIMER_IMMEDIATELY );
+
+ return true_t;
+ }
+
+ return false_t;
+ }