diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_handle_frame.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_handle_frame.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,409 @@ +/* +* 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 handling a frame received from drivers +* +*/ + + +#include "core_operation_handle_frame.h" +#include "core_operation_ibss_merge.h" +#include "core_operation_handle_delete_ts.h" +#include "core_operation_update_power_mode.h" +#include "core_operation_handle_measurement_request.h" +#include "core_operation_handle_neighbor_response.h" +#include "core_frame_radio_measurement_action.h" +#include "core_frame_action_wmm.h" +#include "core_frame_wmm_ie_tspec.h" +#include "core_frame_action_rm.h" +#include "core_frame_action_nr.h" +#include "core_frame_tim_ie.h" +#include "core_frame_dot11.h" +#include "core_server.h" +#include "core_tools.h" +#include "am_debug.h" + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_handle_frame_c::core_operation_handle_frame_c( + u32_t request_id, + core_server_c* server, + abs_core_driverif_c* drivers, + abs_core_server_callback_c* adaptation, + core_frame_type_e frame_type, + u16_t data_length, + const u8_t* data ) : + core_operation_base_c( core_operation_handle_frame, request_id, server, drivers, adaptation, + core_base_flag_drivers_needed | core_base_flag_connection_needed ), + type_m( frame_type ), + data_length_m( data_length ), + data_m( NULL ), + frame_m( NULL ) + { + DEBUG( "core_operation_handle_frame_c::core_operation_handle_frame_c()" ); + + data_m = new u8_t[data_length_m]; + if ( data_m ) + { + core_tools_c::copy( + data_m, + data, + data_length ); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_handle_frame_c::~core_operation_handle_frame_c() + { + DEBUG( "core_operation_handle_frame_c::~core_operation_handle_frame_c()" ); + + delete frame_m; + frame_m = NULL; + delete[] data_m; + data_m = NULL; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_operation_handle_frame_c::next_state() + { + DEBUG( "core_operation_handle_frame_c::next_state()" ); + + switch ( operation_state_m ) + { + case core_state_init: + { + if ( !data_m ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - no frame, aborting" ); + failure_reason_m = core_error_no_memory; + + return cancel(); + } + + if ( !server_m->get_core_settings().is_connected() ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - not connected, discarding frame" ); + + return core_error_ok; + } + + switch ( type_m ) + { + case core_frame_type_dot11: + { + DEBUG( "core_operation_handle_frame_c::next_state() - core_frame_type_dot11" ); + frame_m = core_frame_dot11_c::instance( + data_length_m, + data_m, + false_t ); + if ( !frame_m ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - unable to create parser" ); + failure_reason_m = core_error_general; + + return cancel(); + } + +#ifdef _DEBUG + DEBUG1( "core_operation_handle_frame_c::next_state() - frame control: %04X", + frame_m->frame_control() ); + if ( frame_m->frame_control() & core_frame_dot11_c::core_dot11_frame_control_to_ds_mask ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - frame control ToDS: enabled" ); + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - frame control ToDS: disabled" ); + } + if ( frame_m->frame_control() & core_frame_dot11_c::core_dot11_frame_control_from_ds_mask ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - frame control FromDS: enabled" ); + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - frame control FromDS: disabled" ); + } + DEBUG1( "core_operation_handle_frame_c::next_state() - duration: %04X", + frame_m->duration() ); + + core_mac_address_s mac( ZERO_MAC_ADDR ); + mac = frame_m->destination(); + DEBUG6( "core_operation_handle_frame_c::next_state() - destination: %02X:%02X:%02X:%02X:%02X:%02X", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5] ); + + mac = frame_m->source(); + DEBUG6( "core_operation_handle_frame_c::next_state() - source: %02X:%02X:%02X:%02X:%02X:%02X", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5] ); + + mac = frame_m->bssid(); + DEBUG6( "core_operation_handle_frame_c::next_state() - bssid: %02X:%02X:%02X:%02X:%02X:%02X", + mac.addr[0], mac.addr[1], mac.addr[2], + mac.addr[3], mac.addr[4], mac.addr[5] ); +#endif // _DEBUG + + if ( frame_m->type() == core_frame_dot11_c::core_dot11_type_beacon && + server_m->get_core_settings().is_connected() ) + { + if ( server_m->get_connection_data()->iap_data().operating_mode() == core_operating_mode_ibss ) + { + operation_state_m = core_state_done; + + DEBUG( "core_operation_handle_frame_c::next_state() - beacon received in IBSS mode" ); + + /** + * Beacons received in IBSS mode are an indication that a merge + * is needed. + */ + core_operation_base_c* operation = new core_operation_ibss_merge_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + frame_m ); + + return run_sub_operation( operation ); + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - beacon received in infrastructure mode" ); + + /** + * Beacons received in infrastructure mode happen after an association. + * + * They are used to update the current AP data since beacons contain + * fields not present in probe responses. + */ + if ( server_m->get_connection_data() && + server_m->get_connection_data()->current_ap_data() && + server_m->get_connection_data()->current_ap_data()->bssid() == frame_m->bssid() ) + { + core_frame_beacon_c* beacon = core_frame_beacon_c::instance( + *frame_m ); + if ( beacon ) + { + for( core_frame_dot11_ie_c* ie = beacon->first_ie(); ie; ie = beacon->next_ie() ) + { + if ( ie->element_id() == core_frame_dot11_ie_c::core_frame_dot11_ie_element_id_tim ) + { + core_frame_tim_ie_c* tim_ie = core_frame_tim_ie_c::instance( *ie ); + if ( tim_ie && + tim_ie->dtim_period() ) + { + DEBUG1( "core_operation_handle_frame_c::next_state() - updating AP DTIM period to %u", + tim_ie->dtim_period() ); + + server_m->get_connection_data()->current_ap_data()->set_dtim_period( + tim_ie->dtim_period() ); + + /** + * Schedule a power mode update since we may have to adjust the wakeup interval + * if DTIM skipping is used. + * + * We should avoid changing power mode if DHCP timer is active. + */ + if( !server_m->is_dhcp_timer_active() ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - scheduling a power save update" ); + + core_operation_base_c* operation = new core_operation_update_power_mode_c( + request_id_m, + server_m, + drivers_m, + adaptation_m ); + + server_m->queue_int_operation( operation ); + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - DHCP timer active, no power mode update" ); + } + } + + delete tim_ie; + tim_ie = NULL; + } + + delete ie; + ie = NULL; + } + + delete beacon; + beacon = NULL; + } + } + } + } + else if ( frame_m->type() == core_frame_dot11_c::core_dot11_type_action ) + { + core_frame_action_c* action = core_frame_action_c::instance( + *frame_m ); + if ( action ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - 802.11 action frame found" ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 action category: 0x%02X", + action->category() ); + if ( action->category() == core_frame_action_c::core_dot11_action_category_wmm_qos ) + { + core_frame_action_wmm_c* wmm_action = core_frame_action_wmm_c::instance( *action ); + if ( wmm_action ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - 802.11 WMM action frame found" ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 WMM action type: 0x%02X", + wmm_action->action_type() ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 WMM action dialog token: 0x%02X", + wmm_action->dialog_token() ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 WMM action status: 0x%02X", + wmm_action->status() ); + + if ( wmm_action->action_type() == core_frame_action_wmm_c::core_dot11_action_wmm_type_delts ) + { + for( core_frame_dot11_ie_c* ie = wmm_action->first_ie(); ie; ie = wmm_action->next_ie() ) + { + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 WMM action IE ID: 0x%02X", + ie->element_id() ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 WMM action IE length: 0x%02X", + ie->length() ); + + if ( ie->element_id() == core_frame_dot11_ie_c::core_frame_dot11_ie_element_id_wmm_tspec ) + { + core_frame_wmm_ie_tspec_c* tspec_ie = core_frame_wmm_ie_tspec_c::instance( *ie ); + if ( tspec_ie ) + { + core_operation_base_c* operation = new core_operation_handle_delete_ts_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + tspec_ie->tid() ); + + server_m->queue_int_operation( operation ); + + delete tspec_ie; + tspec_ie = NULL; + } + } + + delete ie; + ie = NULL; + } + } + + delete wmm_action; + wmm_action = NULL; + } + } + else if ( action->category() == core_frame_action_c::core_dot11_action_category_rm ) + { + core_frame_radio_measurement_action_c* radio_measurement_action = core_frame_radio_measurement_action_c::instance( *action, true_t ); + if ( radio_measurement_action ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - 802.11 RM action frame found" ); + DEBUG1( "core_operation_handle_frame_c::next_state() - 802.11 RM action type: 0x%02X", + radio_measurement_action->action_type() ); + + if ( radio_measurement_action->action_type() == core_frame_radio_measurement_action_c::core_dot11_action_rm_type_meas_req ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - Measurement Request received -> create operation to handle it" ); + + // copy received frame to a new memory location, rm_action will have the ownership of the new data + core_frame_action_rm_c* rm_action = core_frame_action_rm_c::instance( *action, true_t ); + if ( rm_action ) + { + // operation will deallocate rm_action when finished + core_operation_base_c* operation = new core_operation_handle_measurement_request_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + rm_action ); + + server_m->queue_int_operation( operation ); + } + } + else if ( radio_measurement_action->action_type() == core_frame_radio_measurement_action_c::core_dot11_action_rm_type_neighbor_resp ) + { + DEBUG( "core_operation_handle_frame_c::next_state() - Neighbor Report Response received -> create operation to handle it" ); + + // copy received frame to a new memory location, nr_action will have the ownership of the new data + core_frame_action_nr_c* nr_action = core_frame_action_nr_c::instance( *action, true_t ); + if ( nr_action ) + { + // operation will deallocate nr_action when finished + core_operation_base_c* operation = new core_operation_handle_neighbor_response_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + nr_action ); + + server_m->queue_int_operation( operation ); + } + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - 802.11 RM action type not supported, ignoring..." ); + } + + delete radio_measurement_action; + radio_measurement_action = NULL; + } + } + + delete action; + action = NULL; + } + } + else + { + DEBUG( "core_operation_handle_frame_c::next_state() - unknown frame, discarding" ); + } + + return core_error_ok; + } + case core_frame_type_snap: + { + DEBUG( "core_operation_handle_frame_c::next_state() - core_frame_type_snap, discarding" ); + + return core_error_ok; + } + default: + { + DEBUG( "core_operation_handle_frame_c::next_state() - unknown frame type, discarding" ); + + return core_error_ok; + } + } + } + case core_state_done: + { + DEBUG( "core_operation_handle_frame_c::next_state() - frame processing done" ); + + return core_error_ok; + } + default: + { + ASSERT( false_t ); + } + } + + return core_error_request_pending; + }