diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_create_ts.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_create_ts.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,465 @@ +/* +* Copyright (c) 2006-2010 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 creating a traffic stream. +* +*/ + +/* +* %version: 6 % +*/ + +#include "core_operation_create_ts.h" +#include "core_operation_delete_ts.h" +#include "core_traffic_stream.h" +#include "core_sub_operation_create_ts.h" +#include "core_frame_wmm_ie.h" +#include "core_server.h" +#include "core_tools.h" +#include "core_traffic_stream_list_iter.h" +#include "core_virtual_traffic_stream_list_iter.h" +#include "am_debug.h" + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_create_ts_c::core_operation_create_ts_c( + u32_t request_id, + core_server_c* server, + abs_core_driverif_c* drivers, + abs_core_server_callback_c* adaptation, + u8_t tid, + u8_t user_priority, + bool_t is_automatic_stream, + const core_traffic_stream_params_s& params, + u32_t& stream_id, + core_traffic_stream_status_e& stream_status ) : + core_operation_base_c( core_operation_create_ts, request_id, server, drivers, adaptation, + core_base_flag_none ), + requested_tid_m( tid ), + tid_m( tid ), + user_priority_m( user_priority ), + access_class_m( core_access_class_best_effort ), + is_automatic_stream_m( is_automatic_stream ), + requested_params_m( params ), + params_m( params ), + stream_id_m( stream_id ), + stream_status_m( stream_status ), + stream_m( NULL ) + { + DEBUG( "core_operation_create_ts_c::core_operation_create_ts_c()" ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_operation_create_ts_c::~core_operation_create_ts_c() + { + DEBUG( "core_operation_create_ts_c::~core_operation_create_ts_c()" ); + + delete stream_m; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_operation_create_ts_c::next_state() + { + DEBUG( "core_operation_create_ts_c::next_state()" ); + + switch ( operation_state_m ) + { + case core_state_init: + { + if( !server_m->get_core_settings().is_connected() ) + { + DEBUG( "core_operation_create_ts_c::next_state() - not connected, nothing to do" ); + + return core_error_general; + } + if( !is_valid_params() ) + { + DEBUG( "core_operation_create_ts_c::next_state() - invalid traffic stream parameters" ); + + return core_error_illegal_argument; + } + access_class_m = core_tools_c::convert_user_priority_to_ac( user_priority_m ); + + core_traffic_stream_list_c& ts_list( + server_m->get_connection_data()->traffic_stream_list() ); + core_virtual_traffic_stream_list_c& virtual_ts_list( + server_m->get_connection_data()->virtual_traffic_stream_list() ); + core_traffic_stream_list_iter_c ts_iter( ts_list ); + core_virtual_traffic_stream_list_iter_c virtual_ts_iter( virtual_ts_list ); + + DEBUG( "core_operation_create_ts_c::next_state() - current traffic streams:" ); + virtual_ts_list.print_contents(); + ts_list.print_contents(); + + if( tid_m != TRAFFIC_STREAM_TID_NONE ) + { + /** + * If TID has been specified for the virtual traffic stream, check + * whether it clashes with an existing traffic stream. + */ + if( ts_list.is_traffic_stream_for_tid( tid_m ) ) + { + DEBUG1( "core_operation_create_ts_c::next_state() - stream already exists for TID %u", + tid_m ); + + return core_error_already_exists; + } + } + else + { + /** + * If TID has been left unspecified, select the next free + * TID. + * + * First try to select the next free TID from virtual traffic + * stream list. In the unlikely scenario where all TIDs are + * in use, try the traffic stream list next. + */ + tid_m = virtual_ts_list.next_tid(); + if( tid_m == MAX_TRAFFIC_STREAM_TID ) + { + tid_m = ts_list.next_tid(); + if( tid_m == MAX_TRAFFIC_STREAM_TID ) + { + DEBUG( "core_operation_create_ts_c::next_state() - no free TIDs" ); + + return core_error_general; + } + } + } + +#ifdef _DEBUG + DEBUG2( "core_operation_create_ts_c::next_state() - Traffic Stream TID is %u, UP is %u", + tid_m, user_priority_m ); + + DEBUG( "core_operation_create_ts_c::next_state() - trying to create a traffic stream with values:" ); + if( params_m.is_periodic_traffic ) + { + DEBUG( "core_operation_create_ts_c::next_state() - Traffic pattern: periodic" ); + } + else + { + DEBUG( "core_operation_create_ts_c::next_state() - Traffic pattern: aperiodic" ); + } + if( params_m.direction == core_traffic_stream_direction_uplink ) + { + DEBUG( "core_operation_create_ts_c::next_state() - Direction: uplink" ); + } + else if( params_m.direction == core_traffic_stream_direction_downlink ) + { + DEBUG( "core_operation_create_ts_c::next_state() - Direction: downlink" ); + } + else + { + DEBUG( "core_operation_create_ts_c::next_state() - Direction: bi-directional" ); + } + DEBUG2( "core_operation_create_ts_c::next_state() - Nominal MSDU Size: %u (0x%04X)", + params_m.nominal_msdu_size, params_m.nominal_msdu_size ); + DEBUG2( "core_operation_create_ts_c::next_state() - Maximum MSDU Size: %u (0x%04X)", + params_m.maximum_msdu_size, params_m.maximum_msdu_size ); + DEBUG2( "core_operation_create_ts_c::next_state() - Minimum Service Interval: %u (0x%08X)", + params_m.minimum_service_interval, params_m.minimum_service_interval ); + DEBUG2( "core_operation_create_ts_c::next_state() - Maximum Service Interval: %u (0x%08X)", + params_m.maximum_service_interval, params_m.maximum_service_interval ); + DEBUG2( "core_operation_create_ts_c::next_state() - Inactivity Interval: %u (0x%08X)", + params_m.inactivity_interval, params_m.inactivity_interval ); + DEBUG2( "core_operation_create_ts_c::next_state() - Suspension Interval: %u (0x%08X)", + params_m.suspension_interval, params_m.suspension_interval ); + DEBUG2( "core_operation_create_ts_c::next_state() - Service Start Time: %u (0x%08X)", + params_m.service_start_time, params_m.service_start_time ); + DEBUG2( "core_operation_create_ts_c::next_state() - Minimum Data Rate: %u (0x%08X)", + params_m.minimum_data_rate, params_m.minimum_data_rate ); + DEBUG2( "core_operation_create_ts_c::next_state() - Mean Data Rate: %u (0x%08X)", + params_m.mean_data_rate, params_m.mean_data_rate ); + DEBUG2( "core_operation_create_ts_c::next_state() - Peak Data Rate: %u (0x%08X)", + params_m.peak_data_rate, params_m.peak_data_rate ); + DEBUG2( "core_operation_create_ts_c::next_state() - Maximum Burst Size: %u (0x%08X)", + params_m.maximum_burst_size, params_m.maximum_burst_size ); + DEBUG2( "core_operation_create_ts_c::next_state() - Delay Bound: %u (0x%08X)", + params_m.delay_bound, params_m.delay_bound ); + DEBUG2( "core_operation_create_ts_c::next_state() - Minimum PHY Rate: %u (0x%08X)", + params_m.minimum_phy_rate, params_m.minimum_phy_rate ); + DEBUG2( "core_operation_create_ts_c::next_state() - Nominal PHY Rate: %u (0x%04X)", + params_m.nominal_phy_rate, params_m.nominal_phy_rate ); + DEBUG2( "core_operation_create_ts_c::next_state() - Surplus Bandwidth Allowance: %u (0x%04X)", + params_m.surplus_bandwidth_allowance, params_m.surplus_bandwidth_allowance ); +#endif // _DEBUG + + stream_m = new core_traffic_stream_c( + tid_m, + user_priority_m ); + if( !stream_m ) + { + DEBUG( "core_operation_create_ts_c::next_state() - unable to allocate a traffic stream instance" ); + + return core_error_no_memory; + } + + /** + * If the Max Tx MSDU Lifetime is not overridden, use the default value. + */ + if( !params_m.override_max_tx_msdu_lifetime ) + { + params_m.override_max_tx_msdu_lifetime = server_m->get_device_settings().max_tx_msdu_life_time; + } + + stream_m->set_default_traffic_values( params_m ); + stream_m->reset_to_default_values(); + + /** + * If this is a manual traffic stream, all automatic streams + * need to be deleted before continuing. + */ + if( !is_automatic_stream_m ) + { + server_m->get_connection_data()->set_ac_traffic_mode( + access_class_m, + core_access_class_traffic_mode_manual ); + + /** + * Send an indication to notify clients that traffic mode + * is now set to manual. + */ + u8_t buf[5]; + buf[0] = static_cast( + access_class_m ); + buf[1] = static_cast( + core_access_class_traffic_mode_manual ); + adaptation_m->notify( + core_notification_ac_traffic_mode_changed, + sizeof( buf ), + buf ); + + return goto_state( core_state_delete_streams ); + } + + /** + * Otherwise proceed with stream creation. + */ + return goto_state( core_state_create_stream ); + } + case core_state_delete_streams: + { + core_virtual_traffic_stream_list_iter_c virtual_ts_iter( + server_m->get_connection_data()->virtual_traffic_stream_list() ); + for( core_virtual_traffic_stream_c* iter = virtual_ts_iter.first(); iter; iter = virtual_ts_iter.next() ) + { + if( iter->access_class() == access_class_m && + iter->is_automatic_stream() ) + { + core_operation_base_c* operation = new core_operation_delete_ts_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + iter->id() ); + + return run_sub_operation( operation, core_state_delete_streams ); + } + } + + return asynch_goto( core_state_create_stream ); + } + case core_state_create_stream: + { + core_ap_data_c* current_ap = server_m->get_connection_data()->current_ap_data(); + if( !current_ap->is_wmm_ie_present() || + !current_ap->is_admission_control_required( access_class_m ) ) + { + DEBUG1( "core_operation_create_ts_c::next_state() - AP doesn't require admission control on AC %u", + access_class_m ); + + /** + * An actual traffic stream is not needed but the virtual traffic + * stream is still created. + */ + server_m->get_connection_data()->virtual_traffic_stream_list().add_traffic_stream( + requested_tid_m, + TRAFFIC_STREAM_TID_NONE, + user_priority_m, + is_automatic_stream_m, + requested_params_m, + stream_id_m, + core_traffic_stream_status_inactive_not_required ); + + return core_error_ok; + } + + /** + * Try to create the actual traffic stream. + */ + core_operation_base_c* operation = new core_sub_operation_create_ts_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + *server_m->get_connection_data()->current_ap_data(), + tid_m, + user_priority_m, + params_m, + stream_status_m ); + + return run_sub_operation( operation, core_state_create_stream_success ); + } + case core_state_create_stream_failed: + { + DEBUG( "core_operation_create_ts_c::next_state() - traffic stream creation failed" ); + + /** + * Eventhough the actual traffic stream couldn't be created, the virtual traffic + * stream is still created. + */ + server_m->get_connection_data()->virtual_traffic_stream_list().add_traffic_stream( + requested_tid_m, + TRAFFIC_STREAM_TID_NONE, + user_priority_m, + is_automatic_stream_m, + requested_params_m, + stream_id_m, + stream_status_m ); + + return core_error_ok; + } + case core_state_create_stream_success: + { + operation_state_m = core_state_parameters_set; + + DEBUG( "core_operation_create_ts_c::next_state() - traffic stream created successfully" ); + + server_m->get_connection_data()->virtual_traffic_stream_list().add_traffic_stream( + requested_tid_m, + tid_m, + user_priority_m, + is_automatic_stream_m, + requested_params_m, + stream_id_m, + core_traffic_stream_status_active ); + + /** + * Store the new traffic stream parameters. + */ + stream_m->set_status( core_traffic_stream_status_active ); + stream_m->set_traffic_values( params_m ); + server_m->get_connection_data()->traffic_stream_list().update_traffic_stream( + *stream_m ); + + if( params_m.direction == core_traffic_stream_direction_uplink || + params_m.direction == core_traffic_stream_direction_bidirectional ) + { + server_m->get_connection_data()->set_ac_traffic_status( + access_class_m, + core_access_class_traffic_status_admitted ); + + /** + * Send an indication to notify clients that this access class + * is now admitted. + */ + u8_t buf[5]; + buf[0] = static_cast( + access_class_m ); + buf[1] = static_cast( + core_access_class_traffic_status_admitted ); + adaptation_m->notify( + core_notification_ac_traffic_status_changed, + sizeof( buf ), + buf ); + + /** + * Set the parameters to the drivers based on the created + * traffic stream. + */ + DEBUG( "core_operation_create_ts_c::next_state() - setting tx queue parameters" ); + + drivers_m->set_tx_queue_parameters( + request_id_m, + stream_m->access_class(), + stream_m->medium_time(), + stream_m->max_tx_msdu_lifetime() ); + } + else + { + /** + * Since TX queue parameters apply only to uplink, there is nothing + * more to do on downlink streams. + */ + return core_error_ok; + } + + break; + } + case core_state_parameters_set: + { + DEBUG( "core_operation_create_ts_c::next_state() - tx queue parameters set" ); + + return core_error_ok; + } + default: + { + ASSERT( false_t ); + } + } + + return core_error_request_pending; + } + + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_operation_create_ts_c::cancel() + { + DEBUG( "core_operation_create_ts_c::cancel() " ); + + switch( operation_state_m ) + { + case core_state_create_stream_success: + { + return goto_state( core_state_create_stream_failed ); + } + default: + { + return failure_reason_m; + } + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +bool_t core_operation_create_ts_c::is_valid_params() + { + if( tid_m >= MAX_TRAFFIC_STREAM_TID && tid_m != TRAFFIC_STREAM_TID_NONE ) + { + DEBUG1( "core_operation_create_ts_c::is_valid_params() - invalid TID value: %u", + tid_m ); + + return false_t; + } + if( user_priority_m >= MAX_QOS_USER_PRIORITY ) + { + DEBUG1( "core_operation_create_ts_c::is_valid_params() - invalid user priority value: %u", + user_priority_m ); + + return false_t; + } + + return true_t; + } +