wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_sub_operation_roam_update_ts.cpp
changeset 0 c40eb8fe8501
child 12 af3fb27c7511
--- /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<core_access_class_e>( 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<u8_t>(
+                        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<core_access_class_e>( 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<u8_t>(
+                        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<u8_t>( 
+                    iter->access_class() );
+                buf[1] = static_cast<u8_t>(
+                    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<u8_t*>( &id ),
+                sizeof( u32_t ) );
+            buf[4] = static_cast<u8_t>( 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<u8_t*>( &id ),
+                sizeof( u32_t ) );
+            buf[4] = static_cast<u8_t>( 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<u8_t*>( &id ),
+                sizeof( u32_t ) );
+            buf[4] = static_cast<u8_t>( core_traffic_stream_status_active );
+
+            adaptation_m->notify(
+                core_notification_ts_status_changed,
+                sizeof( buf ),
+                buf ); 
+
+            return;
+            }
+
+        virtual_iter = virtual_ts_iter.next();
+        }
+    }