wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_handle_frame.cpp
changeset 0 c40eb8fe8501
--- /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;
+    }