diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_frame_dot11.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_frame_dot11.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,588 @@ +/* +* 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: Class for parsing 802.11 frames +* +*/ + + +#include "core_frame_dot11.h" +#include "core_frame_dot11_ie.h" +#include "core_tools.h" +#include "am_debug.h" + +const u16_t CORE_DOT11_LENGTH = 24; +const u16_t CORE_DOT11_QOS_CONTROL_LENGTH = 2; +const u16_t CORE_DOT11_HT_CONTROL_LENGTH = 4; +const u16_t CORE_DOT11_FRAME_CONTROL_INDEX = 0; +const u16_t CORE_DOT11_DURATION_INDEX = 2; +const u16_t CORE_DOT11_ADDRESS1_INDEX = 4; +const u16_t CORE_DOT11_ADDRESS2_INDEX = 10; +const u16_t CORE_DOT11_ADDRESS3_INDEX = 16; +const u16_t CORE_DOT11_NO_IE_OFFSET = 0; +const u16_t CORE_DOT11_FRAME_CONTROL_DEFAULT = 0x0000; + +/** Defining this enables IE iterator related traces. */ +//#define WLAN_CORE_DEEP_DEBUG 1 + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_c* core_frame_dot11_c::instance( + u16_t data_length, + const u8_t* data, + bool_t is_copied ) + { + DEBUG( "core_frame_dot11_c::instance()" ); + DEBUG1( "core_frame_dot11_c::instance() - is_copied %u", + is_copied ); + + if( data_length < CORE_DOT11_LENGTH ) + { + DEBUG( "core_frame_dot11_c::instance() - not a valid 802.11 frame, frame is too short" ); + + return NULL; + } + + u8_t* buffer = const_cast( data ); + u16_t buffer_length( 0 ); + + if( is_copied ) + { + buffer_length = data_length; + buffer = new u8_t[buffer_length]; + + if( !buffer ) + { + DEBUG( "core_frame_dot11_c::instance() - not able to allocate buffer for copying" ); + + return NULL; + } + + core_tools_c::copy( + buffer, + data, + buffer_length ); + } + + core_frame_dot11_c* instance = new core_frame_dot11_c( + data_length, + buffer, + buffer_length ); + if( !instance ) + { + DEBUG( "core_frame_dot11_c::instance() - unable to create an instance" ); + if( is_copied ) + { + delete[] buffer; + } + + return NULL; + } + + u16_t required_length( CORE_DOT11_LENGTH ); + if( instance->is_qos_m ) + { + required_length += CORE_DOT11_QOS_CONTROL_LENGTH; + + DEBUG( "core_frame_dot11_c::instance() - this frame includes QoS Control field" ); + } + + if( instance->is_ht_m ) + { + required_length += CORE_DOT11_HT_CONTROL_LENGTH; + + DEBUG( "core_frame_dot11_c::instance() - this frame includes HT Control field" ); + } + + if( data_length < required_length ) + { + DEBUG( "core_frame_dot11_c::instance() - not a valid 802.11 frame, frame is too short" ); + delete instance; + + return NULL; + } + + return instance; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_c::~core_frame_dot11_c() + { + DEBUG( "core_frame_dot11_c::~core_frame_dot11_c" ); + + /** + * If maximum frame length has been defined, we have allocated + * the frame buffer ourselves. + */ + if( max_data_length_m ) + { + delete[] data_m; + } + data_m = NULL; + current_ie_m = NULL; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::frame_control() const + { + return core_tools_c::get_u16( data_m, CORE_DOT11_FRAME_CONTROL_INDEX ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_c::core_dot11_type_e core_frame_dot11_c::type() const + { + return static_cast( + frame_control() & core_dot11_frame_control_type_subtype_mask ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::duration() const + { + return core_tools_c::get_u16( data_m, CORE_DOT11_DURATION_INDEX ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_mac_address_s core_frame_dot11_c::destination() const + { + u16_t index( 0 ); + + if( frame_control() & core_dot11_frame_control_to_ds_mask ) + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + index = CORE_DOT11_ADDRESS3_INDEX; + } + else + { + index = CORE_DOT11_ADDRESS3_INDEX; + } + } + else + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + index = CORE_DOT11_ADDRESS1_INDEX; + } + else + { + index = CORE_DOT11_ADDRESS1_INDEX; + } + } + + return mac_address( index ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_mac_address_s core_frame_dot11_c::source() const + { + u16_t index( 0 ); + + if( frame_control() & core_dot11_frame_control_to_ds_mask ) + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + return ZERO_MAC_ADDR; + } + else + { + index = CORE_DOT11_ADDRESS2_INDEX; + } + } + else + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + index = CORE_DOT11_ADDRESS3_INDEX; + } + else + { + index = CORE_DOT11_ADDRESS2_INDEX; + } + } + + return mac_address( index ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_frame_dot11_c::set_destination( const core_mac_address_s& da ) + { + core_mac_address_s destination = da; + core_tools_c::copy( + &data_m[CORE_DOT11_ADDRESS2_INDEX], + &destination, + MAC_ADDR_LEN ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_frame_dot11_c::set_source( const core_mac_address_s& sa ) + { + core_mac_address_s source = sa; + core_tools_c::copy( + &data_m[CORE_DOT11_ADDRESS1_INDEX], + &source, + MAC_ADDR_LEN ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_mac_address_s core_frame_dot11_c::bssid() const + { + u16_t index( 0 ); + + if( frame_control() & core_dot11_frame_control_to_ds_mask ) + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + return ZERO_MAC_ADDR; + } + else + { + index = CORE_DOT11_ADDRESS1_INDEX; + } + } + else + { + if( frame_control() & core_dot11_frame_control_from_ds_mask ) + { + index = CORE_DOT11_ADDRESS2_INDEX; + } + else + { + index = CORE_DOT11_ADDRESS3_INDEX; + } + } + + return mac_address( index ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_mac_address_s core_frame_dot11_c::mac_address( + u16_t index ) const + { + core_mac_address_s mac( ZERO_MAC_ADDR ); + + core_tools_c::copy( + &mac.addr[0], + &data_m[index], + MAC_ADDR_LEN ); + + return mac; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::data_length() const + { + return data_length_m; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +const u8_t* core_frame_dot11_c::data() const + { + return data_m; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::payload_data_length() const + { + u16_t length( data_length_m - CORE_DOT11_LENGTH ); + if( is_qos_m ) + { + length -= CORE_DOT11_QOS_CONTROL_LENGTH; + } + if( is_ht_m ) + { + length -= CORE_DOT11_HT_CONTROL_LENGTH; + } + + return length; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +const u8_t* core_frame_dot11_c::payload_data() const + { + u8_t* data( data_m + CORE_DOT11_LENGTH ); + if( is_qos_m ) + { + data += CORE_DOT11_QOS_CONTROL_LENGTH; + } + if( is_ht_m ) + { + data += CORE_DOT11_HT_CONTROL_LENGTH; + } + + return data; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_ie_c* core_frame_dot11_c::first_ie() + { + u16_t offset = first_ie_offset(); + if( !offset ) + { + DEBUG( "core_frame_dot11_c::instance() - the frame has no IEs" ); + return NULL; + } + + current_ie_m = payload_data() + offset; + current_ie_max_length_m = payload_data_length() - offset; + + return next_ie(); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_ie_c* core_frame_dot11_c::next_ie() + { +#ifdef WLAN_CORE_DEEP_DEBUG + DEBUG1( "core_frame_dot11_c::next_ie() - real frame length: %u", + data_length_m ); + DEBUG1( "core_frame_dot11_c::next_ie() - data_m is at %08X", + data_m ); + DEBUG1( "core_frame_dot11_c::next_ie() - current_ie_m is at %08X", + current_ie_m ); + DEBUG1( "core_frame_dot11_c::next_ie() - data end is at %08X", + data_m + data_length_m ); + DEBUG1( "core_frame_dot11_c::next_ie() - maximum IE length is %u", + current_ie_max_length_m ); +#endif // WLAN_CORE_DEEP_DEBUG + + if( !current_ie_max_length_m ) + { + return NULL; + } + + core_frame_dot11_ie_c* instance = + core_frame_dot11_ie_c::instance( current_ie_max_length_m, current_ie_m ); + if( !instance ) + { + DEBUG( "core_frame_dot11_c::instance() - unable to create IE parser" ); + + return NULL; + } + + current_ie_m += instance->data_length(); + +#ifdef WLAN_CORE_DEEP_DEBUG + DEBUG1( "core_frame_dot11_c::next_ie() - IE ID is %u", + instance->element_id() ); + DEBUG1( "core_frame_dot11_c::next_ie() - IE length is %u", + instance->length() ); + DEBUG1( "core_frame_dot11_c::next_ie() - IE data length is %u", + instance->data_length() ); +#endif // WLAN_CORE_DEEP_DEBUG + + ASSERT( current_ie_m <= data_m + data_length_m ); + current_ie_max_length_m -= instance->data_length(); + + return instance; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_frame_dot11_c::append_ie( + const core_frame_dot11_ie_c* ie ) + { + if( !ie ) + { + return; + } + +#ifdef WLAN_CORE_DEEP_DEBUG + DEBUG1( "core_frame_dot11_c::append_ie() - real frame length: %u", + data_length_m ); + DEBUG1( "core_frame_dot11_c::append_ie() - maximum frame length: %u", + max_data_length_m ); + DEBUG1( "core_frame_dot11_c::append_ie() - ie length: %u", + ie->data_length() ); +#endif // WLAN_CORE_DEEP_DEBUG + + if( data_length_m + ie->data_length() <= max_data_length_m ) + { + core_tools_c::copy( + &data_m[data_length_m], + ie->data(), + ie->data_length() ); + data_length_m += ie->data_length(); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::first_ie_offset() const + { + /** + * By default the frame doesn't have any IEs. + */ + return CORE_DOT11_NO_IE_OFFSET; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +u16_t core_frame_dot11_c::first_fixed_element_offset() const + { + u16_t offset = CORE_DOT11_LENGTH; + + if( is_qos_m ) + { + offset += CORE_DOT11_QOS_CONTROL_LENGTH; + } + if( is_ht_m ) + { + offset += CORE_DOT11_HT_CONTROL_LENGTH; + } + + return offset; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_frame_dot11_c::generate( + u8_t type, + u16_t duration, + const core_mac_address_s& destination, + const core_mac_address_s& source, + const core_mac_address_s& bssid, + u16_t sequence_control ) + { + ASSERT( !data_length_m ); + ASSERT( max_data_length_m ); + + // Frame Control + u16_t temp16( CORE_DOT11_FRAME_CONTROL_DEFAULT ); + temp16 |= type; + + // Data frames sent by a station must have the ToDS bit set. + if( ( type & core_dot11_frame_control_type_mask ) == core_dot11_frame_control_type_data ) + { + temp16 |= core_dot11_frame_control_to_ds_mask; + } + + core_tools_c::copy( + &data_m[data_length_m], + reinterpret_cast(&temp16), + sizeof( temp16 ) ); + data_length_m += sizeof( temp16 ); + + // Duration + temp16 = duration; + core_tools_c::copy( + &data_m[data_length_m], + reinterpret_cast(&temp16), + sizeof( temp16 ) ); + data_length_m += sizeof( temp16 ); + + // BSSID + core_tools_c::copy( + &data_m[data_length_m], + &bssid.addr[0], + MAC_ADDR_LEN ); + data_length_m += MAC_ADDR_LEN; + + // Source MAC + core_tools_c::copy( + &data_m[data_length_m], + &source.addr[0], + MAC_ADDR_LEN ); + data_length_m += MAC_ADDR_LEN; + + // Destination MAC + core_tools_c::copy( + &data_m[data_length_m], + &destination.addr[0], + MAC_ADDR_LEN ); + data_length_m += MAC_ADDR_LEN; + + // Sequence Control + temp16 = sequence_control; + core_tools_c::copy( + &data_m[data_length_m], + reinterpret_cast(&temp16), + sizeof( temp16 ) ); + data_length_m += sizeof( temp16 ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_frame_dot11_c::core_frame_dot11_c( + u16_t data_length, + const u8_t* data, + u16_t max_data_length ) : + data_length_m( data_length ), + data_m( NULL ), + max_data_length_m( max_data_length ), + is_qos_m( false_t ), + is_ht_m( false_t ), + current_ie_m( NULL ), + current_ie_max_length_m( 0 ) + { + DEBUG( "core_frame_dot11_c::core_frame_dot11_c" ); + + /** + * The reason the const is discarded is that the same pointer + * is used when we have allocated the frame buffer ourselves. + */ + data_m = const_cast( data ); + + core_dot11_frame_control_type_e type_field = + static_cast( + frame_control() & core_dot11_frame_control_type_mask ); + + if( type_field == core_dot11_frame_control_type_data && + frame_control() & core_dot11_frame_control_subtype_qos_mask ) + { + is_qos_m = true_t; + } + + if( ( type_field == core_dot11_frame_control_type_management || + is_qos_m ) && + frame_control() & core_dot11_frame_control_order_mask ) + { + is_ht_m = true_t; + } + }