diff -r 000000000000 -r c40eb8fe8501 wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_roam_update_ts.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_roam_update_ts.cpp Tue Feb 02 02:03:13 2010 +0200 @@ -0,0 +1,736 @@ +/* +* Copyright (c) 2005-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 updating traffic stream statuses after roam. +* +*/ + +/* +* %version: 12 % +*/ + +#include "core_sub_operation_roam_update_ts.h" +#include "core_sub_operation_create_ts.h" +#include "core_frame_wmm_ie.h" +#include "core_server.h" +#include "core_tools.h" +#include "am_debug.h" + +// ======== MEMBER FUNCTIONS ======== + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_sub_operation_roam_update_ts_c::core_sub_operation_roam_update_ts_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_none ), + current_ap_m( ap_data ), + virtual_stream_list_m(), + virtual_stream_iter_m( virtual_stream_list_m ), + stream_list_m(), + stream_iter_m( stream_list_m ), + tid_m( 0 ), + user_priority_m( 0 ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::core_sub_operation_roam_update_ts_c()" ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_sub_operation_roam_update_ts_c::~core_sub_operation_roam_update_ts_c() + { + DEBUG( "core_sub_operation_roam_update_ts_c::~core_sub_operation_roam_update_ts_c()" ); + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_sub_operation_roam_update_ts_c::next_state() + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state()" ); + + switch( operation_state_m ) + { + case core_state_init: + { + if( !server_m->get_core_settings().is_connected() ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - not connected, nothing to do" ); + + return core_error_general; + } + + bool_t is_ac_required[MAX_QOS_ACCESS_CLASS] = + { + current_ap_m.is_admission_control_required( + core_access_class_best_effort ), + current_ap_m.is_admission_control_required( + core_access_class_background ), + current_ap_m.is_admission_control_required( + core_access_class_video ), + current_ap_m.is_admission_control_required( + core_access_class_voice ) + }; + + /** + * If admission control is mandatory for an access class, send an indication + * to notify clients that this access class is no longer admitted. + * + * If admission control is not mandatory, send an indication that + * this access class is admitted. + */ + for( u8_t idx( 0 ); idx < MAX_QOS_ACCESS_CLASS; ++idx ) + { + if( is_ac_required[idx] ) + { + server_m->get_connection_data()->set_ac_traffic_status( + static_cast( idx ), + core_access_class_traffic_status_not_admitted ); + + DEBUG1( "core_operation_handle_delete_ts_c::next_state() - traffic no longer admitted on AC %u, notifying clients", + idx ); + + u8_t buf[5]; + buf[0] = idx; + buf[1] = static_cast( + core_access_class_traffic_status_not_admitted ); + adaptation_m->notify( + core_notification_ac_traffic_status_changed, + sizeof( buf ), + buf ); + } + else + { + server_m->get_connection_data()->set_ac_traffic_status( + static_cast( idx ), + core_access_class_traffic_status_admitted ); + + DEBUG1( "core_operation_handle_delete_ts_c::next_state() - traffic admitted on AC %u, notifying clients", + idx ); + + u8_t buf[5]; + buf[0] = idx; + buf[1] = static_cast( + core_access_class_traffic_status_admitted ); + adaptation_m->notify( + core_notification_ac_traffic_status_changed, + sizeof( buf ), + buf ); + } + } + + 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_sub_operation_roam_update_ts_c::next_state() - traffic streams before processing:" ); + virtual_ts_list.print_contents(); + ts_list.print_contents(); + + /** + * Create a list of virtual traffic streams that are currently + * inactive and need to be created, i.e. admission control is + * mandatory for the access class. + */ + core_virtual_traffic_stream_c* virtual_iter = virtual_ts_iter.first(); + while( virtual_iter ) + { + if( is_ac_required[virtual_iter->access_class()] && + virtual_iter->status() != core_traffic_stream_status_active ) + { + DEBUG1( "core_sub_operation_roam_update_ts_c::next_state() - virtual traffic stream with ID %u needs to created", + virtual_iter->id() ); + + virtual_stream_list_m.add_traffic_stream( + *virtual_iter ); + } + + virtual_iter = virtual_ts_iter.next(); + } + + /** + * Delete all traffic streams that are no longer needed or that have + * been marked as rejected. Create a list of traffic streams that + * need to be re-created. + * + * There is no need to reset the TX queue parameters since + * UMAC will reset them automatically after an association. + */ + core_traffic_stream_c* iter = ts_iter.first(); + while( iter ) + { + if( !is_ac_required[iter->access_class()] ) + { + DEBUG2( "core_sub_operation_roam_update_ts_c::next_state() - traffic stream (TID %u, user priority %u) is no longer needed, deleting", + iter->tid(), iter->user_priority() ); + + /** + * Send a status update to all affected virtual traffic streams. + */ + set_virtual_traffic_stream_inactive_by_tid( + iter->tid(), + core_traffic_stream_status_inactive_not_required ); + + /** + * Delete the actual traffic stream. + */ + server_m->get_wpx_adaptation_instance().handle_ts_delete( + iter->tid(), iter->user_priority() ); + ts_iter.remove(); + } + else if( iter->status() == core_traffic_stream_status_undefined ) + { + DEBUG2( "core_sub_operation_roam_update_ts_c::next_state() - traffic stream (TID %u, user priority %u) needs to be re-created", + iter->tid(), iter->user_priority() ); + + stream_list_m.update_traffic_stream( *iter ); + } + else if( iter->status() != core_traffic_stream_status_active ) + { + DEBUG2( "core_sub_operation_roam_update_ts_c::next_state() - traffic stream (TID %u, user priority %u) is marked as rejected, deleting", + iter->tid(), iter->user_priority() ); + + /** + * Send a status update to all affected virtual traffic streams. + */ + set_virtual_traffic_stream_inactive_by_tid( + iter->tid(), + iter->status() ); + + /** + * Delete the actual traffic stream. + */ + server_m->get_wpx_adaptation_instance().handle_ts_delete( + iter->tid(), iter->user_priority() ); + ts_iter.remove(); + } + + iter = ts_iter.next(); + } + + (void)stream_iter_m.first(); + + return goto_state( core_state_recreate_next ); + } + case core_state_recreate_next: + { + core_traffic_stream_c* iter = stream_iter_m.current(); + if( !iter ) + { + /** + * All previously active traffic streams have now been re-created, + * process the virtual traffic streams that need to be created next. + */ + (void)virtual_stream_iter_m.first(); + + return goto_state( core_state_recreate_virtual_next ); + } + + tid_m = iter->tid(); + user_priority_m = iter->user_priority(); + + DEBUG2( "core_sub_operation_roam_update_ts_c::next_state() - trying to recreate traffic stream (TID %u, user priority %u)", + tid_m, user_priority_m ); + + params_m.is_periodic_traffic = iter->is_periodic_traffic(); + params_m.direction = iter->direction(); + params_m.nominal_msdu_size = iter->nominal_msdu_size(); + params_m.maximum_msdu_size = iter->maximum_msdu_size(); + params_m.minimum_service_interval = iter->minimum_service_interval(); + params_m.maximum_service_interval = iter->maximum_service_interval(); + params_m.inactivity_interval = iter->inactivity_interval(); + params_m.suspension_interval = iter->suspension_interval(); + params_m.service_start_time = iter->service_start_time(); + params_m.minimum_data_rate = iter->minimum_data_rate(); + params_m.mean_data_rate = iter->mean_data_rate(); + params_m.peak_data_rate = iter->peak_data_rate(); + params_m.maximum_burst_size = iter->maximum_burst_size(); + params_m.delay_bound = iter->delay_bound(); + params_m.minimum_phy_rate = iter->minimum_phy_rate(); + params_m.surplus_bandwidth_allowance = iter->surplus_bandwidth_allowance(); + params_m.medium_time = iter->medium_time(); + params_m.nominal_phy_rate = iter->nominal_phy_rate(); + params_m.override_rates = iter->override_rates(); + params_m.override_max_tx_msdu_lifetime = iter->max_tx_msdu_lifetime(); + + core_operation_base_c* operation = new core_sub_operation_create_ts_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + current_ap_m, + tid_m, + user_priority_m, + params_m, + stream_status_m ); + + return run_sub_operation( operation, core_state_recreate_success ); + } + case core_state_recreate_success: + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - traffic stream created successfully" ); + + /** + * Store the new traffic stream parameters. + */ + core_traffic_stream_c* iter = stream_iter_m.current(); + iter->set_status( core_traffic_stream_status_active ); + iter->set_traffic_values( params_m ); + server_m->get_connection_data()->traffic_stream_list().update_traffic_stream( *iter ); + + /** + * Move to the next entry. + */ + stream_iter_m.remove(); + (void)stream_iter_m.first(); + + return goto_state( core_state_recreate_next ); + } + case core_state_recreate_fail: + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - traffic stream creation failed" ); + + /** + * Send a status update to all affected virtual traffic streams. + */ + set_virtual_traffic_stream_inactive_by_tid( + tid_m, + core_traffic_stream_status_inactive_other ); + + /** + * Delete the actual traffic stream. + */ + server_m->get_wpx_adaptation_instance().handle_ts_delete( + tid_m, user_priority_m ); + server_m->get_connection_data()->traffic_stream_list().remove_traffic_stream_by_tid( tid_m ); + + /** + * Move to the next entry. + */ + stream_iter_m.remove(); + (void)stream_iter_m.first(); + + return goto_state( core_state_recreate_next ); + } + case core_state_recreate_virtual_next: + { + core_virtual_traffic_stream_c* virtual_iter = virtual_stream_iter_m.current(); + if( !virtual_iter ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - traffic streams after processing:" ); + server_m->get_connection_data()->virtual_traffic_stream_list().print_contents(); + server_m->get_connection_data()->traffic_stream_list().print_contents(); + (void)server_m->get_connection_data()->traffic_stream_list().first(); + + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - setting TX queue parameters" ); + return goto_state( core_state_set_params_next ); + } + + tid_m = virtual_iter->requested_tid(); + user_priority_m = virtual_iter->user_priority(); + params_m = virtual_iter->params(); + stream_status_m = core_traffic_stream_status_inactive_other; + 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( server_m->get_connection_data()->traffic_stream_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 goto_state( core_state_recreate_virtual_fail ); + } + } + 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 = server_m->get_connection_data()->virtual_traffic_stream_list().next_tid(); + if( tid_m == MAX_TRAFFIC_STREAM_TID ) + { + tid_m = server_m->get_connection_data()->traffic_stream_list().next_tid(); + if( tid_m == MAX_TRAFFIC_STREAM_TID ) + { + DEBUG1( "core_operation_create_ts_c::next_state() - no free TIDs for stream ID %u", + virtual_iter->id() ); + + return goto_state( core_state_recreate_virtual_fail ); + } + } + } + + /** + * Traffic stream to be created. + */ + core_traffic_stream_c iter( + tid_m, + user_priority_m ); + iter.set_default_traffic_values( params_m ); + iter.reset_to_default_values(); + stream_list_m.update_traffic_stream( + iter ); + (void)stream_iter_m.first(); + + DEBUG2( "core_sub_operation_roam_update_ts_c::next_state() - trying to create traffic stream (TID %u, user priority %u)", + tid_m, user_priority_m ); + + core_operation_base_c* operation = new core_sub_operation_create_ts_c( + request_id_m, + server_m, + drivers_m, + adaptation_m, + current_ap_m, + tid_m, + user_priority_m, + params_m, + stream_status_m ); + + return run_sub_operation( operation, core_state_recreate_virtual_success ); + } + case core_state_recreate_virtual_success: + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - virtual traffic stream created successfully" ); + + /** + * Store the new traffic stream parameters. + */ + core_virtual_traffic_stream_c* virtual_iter = virtual_stream_iter_m.current(); + core_traffic_stream_c* iter = stream_iter_m.current(); + iter->set_status( core_traffic_stream_status_active ); + iter->set_traffic_values( params_m ); + server_m->get_connection_data()->traffic_stream_list().update_traffic_stream( *iter ); + + /** + * Send a status update to all affected virtual traffic streams. + */ + set_virtual_traffic_stream_active_by_id( + virtual_iter->id(), + tid_m ); + + /** + * Move to the next entry. + */ + stream_iter_m.remove(); + virtual_stream_iter_m.remove(); + (void)virtual_stream_iter_m.first(); + + return goto_state( core_state_recreate_virtual_next ); + } + case core_state_recreate_virtual_fail: + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - virtual traffic stream creation failed" ); + + core_virtual_traffic_stream_c* iter = virtual_stream_iter_m.current(); + + /** + * Send a status update to all affected virtual traffic streams. + */ + set_virtual_traffic_stream_inactive_by_id( + iter->id(), + stream_status_m ); + + /** + * Move to the next entry. + */ + stream_iter_m.remove(); + virtual_stream_iter_m.remove(); + (void)virtual_stream_iter_m.first(); + + return goto_state( core_state_recreate_virtual_next ); + } + case core_state_set_params_next: + { + operation_state_m = core_state_set_params_success; + + core_traffic_stream_c* iter = server_m->get_connection_data()->traffic_stream_list().current(); + if( !iter ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::next_state() - all TX queue parameters set" ); + + return core_error_ok; + } + + ASSERT( iter->status() == core_traffic_stream_status_active ); + + if( iter->direction() == core_traffic_stream_direction_uplink || + iter->direction() == core_traffic_stream_direction_bidirectional ) + { + server_m->get_connection_data()->set_ac_traffic_status( + iter->access_class(), + 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( + iter->access_class() ); + buf[1] = static_cast( + core_access_class_traffic_status_admitted ); + adaptation_m->notify( + core_notification_ac_traffic_status_changed, + sizeof( buf ), + buf ); + + /** + * Set TX queue parameters to the drivers based on the created + * traffic stream. + */ + DEBUG3( "core_sub_operation_roam_update_ts_c::next_state() - setting queue_id %u; medium_time %u, max_tx_msdu_lifetime %u", + iter->access_class(), + iter->medium_time(), + iter->max_tx_msdu_lifetime() ); + + drivers_m->set_tx_queue_parameters( + request_id_m, + iter->access_class(), + iter->medium_time(), + iter->max_tx_msdu_lifetime() ); + } + else + { + /** + * Since TX queue parameters apply only to uplink, there is nothing + * more to do on downlink streams. Move to the next entry. + */ + (void)server_m->get_connection_data()->traffic_stream_list().next(); + + return goto_state( core_state_set_params_next ); + } + + break; + } + case core_state_set_params_success: + { + /** + * Move to the next entry. + */ + (void)server_m->get_connection_data()->traffic_stream_list().next(); + + return goto_state( core_state_set_params_next ); + } + default: + { + ASSERT( false_t ); + } + } + + return core_error_request_pending; + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +core_error_e core_sub_operation_roam_update_ts_c::cancel() + { + DEBUG( "core_sub_operation_roam_update_ts_c::cancel()" ); + + switch ( operation_state_m ) + { + case core_state_recreate_success: + { + /** + * Unable to create a traffic stream. + */ + return goto_state( core_state_recreate_fail ); + } + case core_state_recreate_virtual_success: + { + /** + * Unable to create a virtual traffic stream. + */ + return goto_state( core_state_recreate_virtual_fail ); + } + case core_state_set_params_success: + { + /** + * Ignore errors when setting TX queue parameters. + */ + return goto_state( core_state_set_params_success ); + } + default: + { + return failure_reason_m; + } + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_tid( + u8_t tid, + core_traffic_stream_status_e stream_status ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_tid()" ); + + core_virtual_traffic_stream_list_c& virtual_ts_list( + server_m->get_connection_data()->virtual_traffic_stream_list() ); + core_virtual_traffic_stream_list_iter_c virtual_ts_iter( virtual_ts_list ); + + core_virtual_traffic_stream_c* virtual_iter = virtual_ts_iter.first(); + while( virtual_iter ) + { + if( virtual_iter->tid() == tid ) + { + u32_t id( virtual_iter->id() ); + + /** + * The virtual traffic stream is no longer mapped to any actual + * traffic stream. + */ + virtual_iter->set_tid( + TRAFFIC_STREAM_TID_NONE ); + virtual_iter->set_status( + stream_status ); + + DEBUG1( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_tid() - virtual traffic stream with ID %u is inactive", + id ); + + u8_t buf[5]; + core_tools_c::copy( + &buf[0], + reinterpret_cast( &id ), + sizeof( u32_t ) ); + buf[4] = static_cast( stream_status ); + + adaptation_m->notify( + core_notification_ts_status_changed, + sizeof( buf ), + buf ); + } + + virtual_iter = virtual_ts_iter.next(); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_id( + u32_t id, + core_traffic_stream_status_e stream_status ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_id()" ); + + core_virtual_traffic_stream_list_c& virtual_ts_list( + server_m->get_connection_data()->virtual_traffic_stream_list() ); + core_virtual_traffic_stream_list_iter_c virtual_ts_iter( virtual_ts_list ); + + core_virtual_traffic_stream_c* virtual_iter = virtual_ts_iter.first(); + while( virtual_iter ) + { + if( virtual_iter->id() == id ) + { + u32_t id( virtual_iter->id() ); + + /** + * The virtual traffic stream is no longer mapped to any actual + * traffic stream. + */ + virtual_iter->set_tid( + TRAFFIC_STREAM_TID_NONE ); + virtual_iter->set_status( + stream_status ); + + DEBUG1( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_inactive_by_tid() - virtual traffic stream with ID %u is inactive", + id ); + + u8_t buf[5]; + core_tools_c::copy( + &buf[0], + reinterpret_cast( &id ), + sizeof( u32_t ) ); + buf[4] = static_cast( stream_status ); + + adaptation_m->notify( + core_notification_ts_status_changed, + sizeof( buf ), + buf ); + + return; + } + + virtual_iter = virtual_ts_iter.next(); + } + } + +// --------------------------------------------------------------------------- +// --------------------------------------------------------------------------- +// +void core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_active_by_id( + u32_t id, + u8_t tid ) + { + DEBUG( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_active_by_id()" ); + + core_virtual_traffic_stream_list_c& virtual_ts_list( + server_m->get_connection_data()->virtual_traffic_stream_list() ); + core_virtual_traffic_stream_list_iter_c virtual_ts_iter( virtual_ts_list ); + + core_virtual_traffic_stream_c* virtual_iter = virtual_ts_iter.first(); + while( virtual_iter ) + { + if( virtual_iter->id() == id ) + { + u32_t id( virtual_iter->id() ); + + /** + * The virtual traffic stream is no longer mapped to any actual + * traffic stream. + */ + virtual_iter->set_tid( + tid ); + virtual_iter->set_status( + core_traffic_stream_status_active ); + + DEBUG1( "core_sub_operation_roam_update_ts_c::set_virtual_traffic_stream_active_by_id() - virtual traffic stream with ID %u is active", + id ); + + u8_t buf[5]; + core_tools_c::copy( + &buf[0], + reinterpret_cast( &id ), + sizeof( u32_t ) ); + buf[4] = static_cast( core_traffic_stream_status_active ); + + adaptation_m->notify( + core_notification_ts_status_changed, + sizeof( buf ), + buf ); + + return; + } + + virtual_iter = virtual_ts_iter.next(); + } + }