diff --git a/README.txt b/README.txt
index 0a99216435635c0447563e915ff19667d0f7aba6..6280cd5ec6b5bbd4c894c0d31c1b4a960be5363f 100644
--- a/README.txt
+++ b/README.txt
@@ -43,17 +43,36 @@ openairinterface5g
 
 RELEASE NOTES:
 
-v0.1 -> Last stable commit on develop branch before enhancement-10-harmony
-v0.2 -> Merge of enhancement-10-harmony to include NGFI RRH + New Interface for RF/BBU
-v0.3 -> Last stable commit on develop branch before the merge of feature-131-new-license. This is the last commit with GPL License
-v0.4 -> Merge of feature-131-new-license. It closes issue#131 and changes the license to OAI Public License V1.0
-v0.5 -> Merge of enhancement-10-harmony-lts. It includes fixes for Ubuntu 16.04 support
-v0.5.1 -> Merge of bugfix-137-uplink-fixes. It includes stablity fixes for eNB
-v0.5.2 -> Last version with old code for oaisim (abstraction mode works)
-v0.6 -> RRH functionality, UE greatly improved, better TDD support,
-        a lot of bugs fixed. WARNING: oaisim in PHY abstraction mode does not
-        work, you need to use v0.5.2 for that.
-v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI.
+v1.1.0 -> July 2019. This version adds the following implemented features:
+           * Experimental support of LTE-M
+             - Single LTE-M UE attachment, legacy-LTE UE attachment is disabled
+           * X2 interface and handover (also X2-U interface)
+             - In FDD and TDD
+           * CU/DU split (F1 interface)
+             - Tested only in FDD
+           * CDRX
+             - Tested only in FDD
+           * Experimental eMBMS support (only on UE side)
+           * Experimental multi-RRU support
+             - Tested only in TDD
+          This version has an improved code quality:
+           * Simplification of the Build System
+             - A single build includes all full-stack simulators, S1/noS1 modes and one HW platform (such as USRP, BladeRF, ...)
+           * TUN interface is now used as default for the data plane
+             - for UE, eNB-noS1 and UE-noS1
+           * Code Cleanup
+           * Better Static Code Analysis:
+             - Limited number of errors in cppcheck
+             - Important Decrease on high Impact errors in CoverityScan
+           * Better Test Coverage in Continuous Integration:
+             - TM2, CDRX, IF4.5, F1
+             - OAI UE is tested in S1 and noS1 modes with USRP board
+             - Multi-RRU TDD mode
+             - X2 Handover in FDD mode
+
+v1.0.3 -> June 2019: Bug fix for LimeSuite v19.04.0 API
+v1.0.2 -> February 2019: Full OAI support for 3.13.1 UHD
+v1.0.1 -> February 2019: Bug fix for the UE L1 simulator.
 v1.0.0 -> January 2019. This version first implements the architectural split described in doc/oai_lte_enb_func_split_arch.png picture.
             Only FAPI, nFAPI and IF4.5 interfaces are implemented.
             Repository tree structure prepares future integrations of features such as LTE-M, nbIOT or 5G-NR.
@@ -61,6 +80,15 @@ v1.0.0 -> January 2019. This version first implements the architectural split de
             S1-flex has been introduced.
             New tools: config library, telnet server, ...
             A lot of bugfixes and a proper automated Continuous Integration process validates contributions.
-v1.0.1 -> February 2019: Bug fix for the UE L1 simulator.
-v1.0.2 -> February 2019: Full OAI support for 3.13.1 UHD
-v1.0.3 -> June 2019: Bug fix for LimeSuite v19.04.0 API
+
+v0.6.1 -> Mostly bugfixes. This is the last version without NFAPI.
+v0.6 -> RRH functionality, UE greatly improved, better TDD support,
+        a lot of bugs fixed. WARNING: oaisim in PHY abstraction mode does not
+        work, you need to use v0.5.2 for that.
+v0.5.2 -> Last version with old code for oaisim (abstraction mode works)
+v0.5.1 -> Merge of bugfix-137-uplink-fixes. It includes stablity fixes for eNB
+v0.5 -> Merge of enhancement-10-harmony-lts. It includes fixes for Ubuntu 16.04 support
+v0.4 -> Merge of feature-131-new-license. It closes issue#131 and changes the license to OAI Public License V1.0
+v0.3 -> Last stable commit on develop branch before the merge of feature-131-new-license. This is the last commit with GPL License
+v0.2 -> Merge of enhancement-10-harmony to include NGFI RRH + New Interface for RF/BBU
+v0.1 -> Last stable commit on develop branch before enhancement-10-harmony
diff --git a/ci-scripts/Jenkinsfile-gitlab b/ci-scripts/Jenkinsfile-gitlab
index 3569a22715e6742cbd21412a06926b104c961721..6ffac9a806cc8d696300db58a082568eb08c5f61 100644
--- a/ci-scripts/Jenkinsfile-gitlab
+++ b/ci-scripts/Jenkinsfile-gitlab
@@ -44,7 +44,7 @@ pipeline {
         disableConcurrentBuilds()
         timestamps()
         gitLabConnection('OAI GitLab')
-        gitlabBuilds(builds: ["Build gNb-usrp", "Build nr-UE-usrp", "Build eNb-USRP", "Build basic-sim", "Build phy-sim", "Build eNb-ethernet", "Build UE-ethernet", "Analysis with cppcheck", "Test phy-sim", "Test basic-sim", "Test L2-sim", "Test-Mono-FDD-Band7", "Test-Mono-TDD-Band40", "Test-IF4p5-FDD-Band7", "Test-IF4p5-TDD-Band40", "Test-Mono-FDD-Band13"])
+        gitlabBuilds(builds: ["Build gNB-USRP", "Build nr-UE-USRP", "Build eNB-USRP", "Build basic-sim", "Build phy-sim", "Build eNB-ethernet", "Build UE-ethernet", "Analysis with cppcheck", "Test phy-sim", "Test basic-sim", "Test L2-sim", "Test-Mono-FDD-Band7", "Test-Mono-TDD-Band40", "Test-IF4p5-FDD-Band7", "Test-IF4p5-TDD-Band40", "Test-Mono-FDD-Band13", "Test-Mono-FDD-Band13-X2-HO"])
         ansiColor('xterm')
     }
 
@@ -232,7 +232,7 @@ pipeline {
                 }
                 stage ("Build 5G gNB-USRP") {
                     steps {
-                        gitlabCommitStatus(name: "Build gNb-usrp") {
+                        gitlabCommitStatus(name: "Build gNB-USRP") {
                             timeout (time: 20, unit: 'MINUTES') {
                                 sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant gnb-usrp --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
                             }
@@ -241,16 +241,16 @@ pipeline {
                 }
                 stage ("Build 5G NR-UE-USRP") {
                     steps {
-                        gitlabCommitStatus(name: "Build nr-UE-usrp") {
+                        gitlabCommitStatus(name: "Build nr-UE-USRP") {
                             timeout (time: 20, unit: 'MINUTES') {
                                 sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant nr-ue-usrp --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
                             }
                         }
                     }
                 }
-                stage ("Build eNb-USRP") {
+                stage ("Build eNB-USRP") {
                     steps {
-                        gitlabCommitStatus(name: "Build eNb-USRP") {
+                        gitlabCommitStatus(name: "Build eNB-USRP") {
                             timeout (time: 20, unit: 'MINUTES') {
                                 sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant enb-usrp --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
                             }
@@ -266,9 +266,9 @@ pipeline {
                         }
                     }
                 }
-                stage ("Build eNb-ethernet") {
+                stage ("Build eNB-ethernet") {
                     steps {
-                        gitlabCommitStatus(name: "Build eNb-ethernet") {
+                        gitlabCommitStatus(name: "Build eNB-ethernet") {
                             timeout (time: 20, unit: 'MINUTES') {
                                 sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant enb-ethernet --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
                             }
@@ -284,12 +284,12 @@ pipeline {
                         }
                     }
                 }
-                stage ("Build eNb-USRP on Red Hat") {
+                stage ("Build eNB-USRP on Red Hat") {
                     when {
                         expression {doRedHatBuild}
                     }
                     steps {
-                        gitlabCommitStatus(name: "Build eNb-USRP-RHE") {
+                        gitlabCommitStatus(name: "Build eNB-USRP-RHE") {
                             script {
                                 try {
                                     withCredentials([
@@ -538,6 +538,7 @@ pipeline {
                 stage ("Test MONOLITHIC - FDD - Band 13 - B210") {
                     steps {
                         script {
+                            sh "sleep 60"
                             triggerSlaveJob ('eNB-CI-MONO-FDD-Band13-B210', 'Test-Mono-FDD-Band13')
                         }
                     }
@@ -554,6 +555,26 @@ pipeline {
                         }
                     }
                 }
+                stage ("Test X2 Handover - FDD - Band 13 - B210") {
+                    steps {
+                        script {
+                            sh "sleep 60"
+                            triggerSlaveJob ('eNB-CI-MONO-FDD-Band13-X2HO-B210', 'Test-Mono-FDD-Band13-X2-HO')
+                        }
+                    }
+                    post {
+                        always {
+                            script {
+                                finalizeSlaveJob('eNB-CI-MONO-FDD-Band13-X2HO-B210')
+                            }
+                        }
+                        failure {
+                            script {
+                                currentBuild.result = 'FAILURE'
+                            }
+                        }
+                    }
+                }
                 stage ("Test OAI UE - FDD - Band 20 - B200") {
                     steps {
                         script {
diff --git a/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
new file mode 100644
index 0000000000000000000000000000000000000000..2a7783da08bfbab86560711358f8b652c6253cba
--- /dev/null
+++ b/ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf
@@ -0,0 +1,271 @@
+Active_eNBs = ( "eNB-Eurecom-LTEBox");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+eNBs =
+(
+ {
+    ////////// Identification parameters:
+    eNB_ID    =  0xe01;
+
+    cell_type =  "CELL_MACRO_ENB";
+
+    eNB_name  =  "eNB-Eurecom-LTEBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  1;
+
+    plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } );
+
+    nr_cellid = 98765L;
+    tr_s_preference     = "local_mac"
+
+    ////////// Physical parameters:
+
+    component_carriers = (
+      {
+      node_function             = "3GPP_eNODEB";
+      node_timing               = "synch_to_ext_device";
+      node_synch_ref            = 0;
+      frame_type					      = "FDD";
+      tdd_config 					      = 3;
+      tdd_config_s            			      = 0;
+      prefix_type             			      = "NORMAL";
+      eutra_band              			      = 13;
+      downlink_frequency      			      = 751000000L;
+      uplink_frequency_offset 			      = 31000000;
+      Nid_cell					      = 1;
+      N_RB_DL                 			      = 25;
+      Nid_cell_mbsfn          			      = 0;
+      nb_antenna_ports                                = 1;
+      nb_antennas_tx          			      = 1;
+      nb_antennas_rx          			      = 1;
+      tx_gain                                            = 90;
+      rx_gain                                            = 110;
+      pbch_repetition                                 = "FALSE";
+      prach_root              			      = 0;
+      prach_config_index      			      = 0;
+      prach_high_speed        			      = "DISABLE";
+      prach_zero_correlation  			      = 1;
+      prach_freq_offset       			      = 2;
+      pucch_delta_shift       			      = 1;
+      pucch_nRB_CQI           			      = 0;
+      pucch_nCS_AN            			      = 0;
+      pucch_n1_AN             			      = 0;
+      pdsch_referenceSignalPower 			      = -27;
+      pdsch_p_b                  			      = 0;
+      pusch_n_SB                 			      = 1;
+      pusch_enable64QAM          			      = "DISABLE";
+      pusch_hoppingMode                                  = "interSubFrame";
+      pusch_hoppingOffset                                = 0;
+      pusch_groupHoppingEnabled  			      = "ENABLE";
+      pusch_groupAssignment      			      = 0;
+      pusch_sequenceHoppingEnabled		   	      = "DISABLE";
+      pusch_nDMRS1                                       = 1;
+      phich_duration                                     = "NORMAL";
+      phich_resource                                     = "ONESIXTH";
+      srs_enable                                         = "DISABLE";
+      /*  srs_BandwidthConfig                                =;
+      srs_SubframeConfig                                 =;
+      srs_ackNackST                                      =;
+      srs_MaxUpPts                                       =;*/
+
+      pusch_p0_Nominal                                   = -96;
+      pusch_alpha                                        = "AL1";
+      pucch_p0_Nominal                                   = -104;
+      msg3_delta_Preamble                                = 6;
+      pucch_deltaF_Format1                               = "deltaF2";
+      pucch_deltaF_Format1b                              = "deltaF3";
+      pucch_deltaF_Format2                               = "deltaF0";
+      pucch_deltaF_Format2a                              = "deltaF0";
+      pucch_deltaF_Format2b		    	      = "deltaF0";
+
+      rach_numberOfRA_Preambles                          = 64;
+      rach_preamblesGroupAConfig                         = "DISABLE";
+      /*
+      rach_sizeOfRA_PreamblesGroupA                      = ;
+      rach_messageSizeGroupA                             = ;
+      rach_messagePowerOffsetGroupB                      = ;
+      */
+      rach_powerRampingStep                              = 4;
+      rach_preambleInitialReceivedTargetPower            = -108;
+      rach_preambleTransMax                              = 10;
+      rach_raResponseWindowSize                          = 10;
+      rach_macContentionResolutionTimer                  = 48;
+      rach_maxHARQ_Msg3Tx                                = 4;
+
+      pcch_default_PagingCycle                           = 128;
+      pcch_nB                                            = "oneT";
+      bcch_modificationPeriodCoeff			      = 2;
+      ue_TimersAndConstants_t300			      = 1000;
+      ue_TimersAndConstants_t301			      = 1000;
+      ue_TimersAndConstants_t310			      = 1000;
+      ue_TimersAndConstants_t311			      = 10000;
+      ue_TimersAndConstants_n310			      = 20;
+      ue_TimersAndConstants_n311			      = 1;
+      ue_TransmissionMode                                    = 1;
+
+      //Parameters for SIB18
+      rxPool_sc_CP_Len                                       = "normal";
+      rxPool_sc_Period                                       = "sf40";
+      rxPool_data_CP_Len                                     = "normal";
+      rxPool_ResourceConfig_prb_Num                          = 20;
+      rxPool_ResourceConfig_prb_Start                        = 5;
+      rxPool_ResourceConfig_prb_End                          = 44;
+      rxPool_ResourceConfig_offsetIndicator_present          = "prSmall";
+      rxPool_ResourceConfig_offsetIndicator_choice           = 0;
+      rxPool_ResourceConfig_subframeBitmap_present           = "prBs40";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf              = "00000000000000000000";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_size             = 5;
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused      = 0;
+/*    rxPool_dataHoppingConfig_hoppingParameter                       = 0;
+      rxPool_dataHoppingConfig_numSubbands                            = "ns1";
+      rxPool_dataHoppingConfig_rbOffset                               = 0;
+      rxPool_commTxResourceUC-ReqAllowed                              = "TRUE";
+*/
+      // Parameters for SIB19
+      discRxPool_cp_Len                                               = "normal"
+      discRxPool_discPeriod                                           = "rf32"
+      discRxPool_numRetx                                              = 1;
+      discRxPool_numRepetition                                        = 2;
+      discRxPool_ResourceConfig_prb_Num                               = 5;
+      discRxPool_ResourceConfig_prb_Start                             = 3;
+      discRxPool_ResourceConfig_prb_End                               = 21;
+      discRxPool_ResourceConfig_offsetIndicator_present               = "prSmall";
+      discRxPool_ResourceConfig_offsetIndicator_choice                = 0;
+      discRxPool_ResourceConfig_subframeBitmap_present                = "prBs40";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf          = "f0ffffffff";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size         = 5;
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused  = 0;
+
+      }
+    );
+
+
+    srb1_parameters :
+    {
+        # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
+        timer_poll_retransmit    = 80;
+
+        # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
+        timer_reordering         = 35;
+
+        # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
+        timer_status_prohibit    = 0;
+
+        # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
+        poll_pdu                 =  4;
+
+        # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
+        poll_byte                =  99999;
+
+        # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
+        max_retx_threshold       =  4;
+    }
+
+    # ------- SCTP definitions
+    SCTP :
+    {
+        # Number of streams to use in input/output
+        SCTP_INSTREAMS  = 2;
+        SCTP_OUTSTREAMS = 2;
+    };
+
+
+    ////////// MME parameters:
+    mme_ip_address      = ( { ipv4       = "CI_MME_IP_ADDR";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "CI_ENB_IP_ADDR";
+        ENB_INTERFACE_NAME_FOR_S1U               = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "CI_ENB_IP_ADDR";
+        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "CI_ENB_IP_ADDR";
+        ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+  }
+);
+
+MACRLCs = (
+	{
+	num_cc = 1;
+	tr_s_preference = "local_L1";
+	tr_n_preference = "local_RRC";
+	phy_test_mode = 0;
+        puSch10xSnr     =  200;
+        puCch10xSnr     =  200;
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        }  
+);
+
+RUs = (
+    {		  
+       local_rf       = "yes"
+         nb_tx          = 1
+         nb_rx          = 1
+         att_tx         = 0
+         att_rx         = 0;
+         bands          = [7];
+         max_pdschReferenceSignalPower = -27;
+         max_rxgain                    = 125;
+         eNB_instances  = [0];
+
+    }
+);  
+
+NETWORK_CONTROLLER :
+{
+    FLEXRAN_ENABLED        = "no";
+    FLEXRAN_INTERFACE_NAME = "eth0";
+    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_PORT           = 2210;
+    FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
+    FLEXRAN_AWAIT_RECONF   = "no";
+};
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_SINGLE_THREAD";//PARALLEL_RU_L1_TRX_SPLIT";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+     log_config :
+     {
+       global_log_level                      ="info";
+       global_log_verbosity                  ="medium";
+       hw_log_level                          ="info";
+       hw_log_verbosity                      ="medium";
+       phy_log_level                         ="info";
+       phy_log_verbosity                     ="medium";
+       mac_log_level                         ="info";
+       mac_log_verbosity                     ="high";
+       rlc_log_level                         ="info";
+       rlc_log_verbosity                     ="medium";
+       pdcp_log_level                        ="info";
+       pdcp_log_verbosity                    ="medium";
+       rrc_log_level                         ="info";
+       rrc_log_verbosity                     ="medium";
+    };
+
diff --git a/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c76a664c15648bf2951fd04e5b359fd577a6ede6
--- /dev/null
+++ b/ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf
@@ -0,0 +1,276 @@
+Active_eNBs = ( "eNB-Eurecom-LTEBox");
+# Asn1_verbosity, choice in: none, info, annoying
+Asn1_verbosity = "none";
+
+eNBs =
+(
+ {
+    ////////// Identification parameters:
+    eNB_ID    =  0xe00;
+
+    cell_type =  "CELL_MACRO_ENB";
+
+    eNB_name  =  "eNB-Eurecom-LTEBox";
+
+    // Tracking area code, 0x0000 and 0xfffe are reserved values
+    tracking_area_code  =  1;
+
+    plmn_list = ( { mcc = 208; mnc = 93; mnc_length = 2; } );
+
+    nr_cellid = 123456L;
+    tr_s_preference     = "local_mac"
+
+    ////////// Physical parameters:
+
+    component_carriers = (
+      {
+      node_function             = "3GPP_eNODEB";
+      node_timing               = "synch_to_ext_device";
+      node_synch_ref            = 0;
+      frame_type					      = "FDD";
+      tdd_config 					      = 3;
+      tdd_config_s            			      = 0;
+      prefix_type             			      = "NORMAL";
+      eutra_band              			      = 13;
+      downlink_frequency      			      = 751000000L;
+      uplink_frequency_offset 			      = 31000000;
+      Nid_cell					      = 0;
+      N_RB_DL                 			      = 25;
+      Nid_cell_mbsfn          			      = 0;
+      nb_antenna_ports                                = 1;
+      nb_antennas_tx          			      = 1;
+      nb_antennas_rx          			      = 1;
+      tx_gain                                            = 90;
+      rx_gain                                            = 110;
+      pbch_repetition                                 = "FALSE";
+      prach_root              			      = 0;
+      prach_config_index      			      = 0;
+      prach_high_speed        			      = "DISABLE";
+      prach_zero_correlation  			      = 1;
+      prach_freq_offset       			      = 2;
+      pucch_delta_shift       			      = 1;
+      pucch_nRB_CQI           			      = 0;
+      pucch_nCS_AN            			      = 0;
+      pucch_n1_AN             			      = 0;
+      pdsch_referenceSignalPower 			      = -27;
+      pdsch_p_b                  			      = 0;
+      pusch_n_SB                 			      = 1;
+      pusch_enable64QAM          			      = "DISABLE";
+      pusch_hoppingMode                                  = "interSubFrame";
+      pusch_hoppingOffset                                = 0;
+      pusch_groupHoppingEnabled  			      = "ENABLE";
+      pusch_groupAssignment      			      = 0;
+      pusch_sequenceHoppingEnabled		   	      = "DISABLE";
+      pusch_nDMRS1                                       = 1;
+      phich_duration                                     = "NORMAL";
+      phich_resource                                     = "ONESIXTH";
+      srs_enable                                         = "DISABLE";
+      /*  srs_BandwidthConfig                                =;
+      srs_SubframeConfig                                 =;
+      srs_ackNackST                                      =;
+      srs_MaxUpPts                                       =;*/
+
+      pusch_p0_Nominal                                   = -96;
+      pusch_alpha                                        = "AL1";
+      pucch_p0_Nominal                                   = -104;
+      msg3_delta_Preamble                                = 6;
+      pucch_deltaF_Format1                               = "deltaF2";
+      pucch_deltaF_Format1b                              = "deltaF3";
+      pucch_deltaF_Format2                               = "deltaF0";
+      pucch_deltaF_Format2a                              = "deltaF0";
+      pucch_deltaF_Format2b		    	      = "deltaF0";
+
+      rach_numberOfRA_Preambles                          = 64;
+      rach_preamblesGroupAConfig                         = "DISABLE";
+      /*
+      rach_sizeOfRA_PreamblesGroupA                      = ;
+      rach_messageSizeGroupA                             = ;
+      rach_messagePowerOffsetGroupB                      = ;
+      */
+      rach_powerRampingStep                              = 4;
+      rach_preambleInitialReceivedTargetPower            = -108;
+      rach_preambleTransMax                              = 10;
+      rach_raResponseWindowSize                          = 10;
+      rach_macContentionResolutionTimer                  = 48;
+      rach_maxHARQ_Msg3Tx                                = 4;
+
+      pcch_default_PagingCycle                           = 128;
+      pcch_nB                                            = "oneT";
+      bcch_modificationPeriodCoeff			      = 2;
+      ue_TimersAndConstants_t300			      = 1000;
+      ue_TimersAndConstants_t301			      = 1000;
+      ue_TimersAndConstants_t310			      = 1000;
+      ue_TimersAndConstants_t311			      = 10000;
+      ue_TimersAndConstants_n310			      = 20;
+      ue_TimersAndConstants_n311			      = 1;
+      ue_TransmissionMode                                    = 1;
+
+      //Parameters for SIB18
+      rxPool_sc_CP_Len                                       = "normal";
+      rxPool_sc_Period                                       = "sf40";
+      rxPool_data_CP_Len                                     = "normal";
+      rxPool_ResourceConfig_prb_Num                          = 20;
+      rxPool_ResourceConfig_prb_Start                        = 5;
+      rxPool_ResourceConfig_prb_End                          = 44;
+      rxPool_ResourceConfig_offsetIndicator_present          = "prSmall";
+      rxPool_ResourceConfig_offsetIndicator_choice           = 0;
+      rxPool_ResourceConfig_subframeBitmap_present           = "prBs40";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_buf              = "00000000000000000000";
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_size             = 5;
+      rxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused      = 0;
+/*    rxPool_dataHoppingConfig_hoppingParameter                       = 0;
+      rxPool_dataHoppingConfig_numSubbands                            = "ns1";
+      rxPool_dataHoppingConfig_rbOffset                               = 0;
+      rxPool_commTxResourceUC-ReqAllowed                              = "TRUE";
+*/
+      // Parameters for SIB19
+      discRxPool_cp_Len                                               = "normal"
+      discRxPool_discPeriod                                           = "rf32"
+      discRxPool_numRetx                                              = 1;
+      discRxPool_numRepetition                                        = 2;
+      discRxPool_ResourceConfig_prb_Num                               = 5;
+      discRxPool_ResourceConfig_prb_Start                             = 3;
+      discRxPool_ResourceConfig_prb_End                               = 21;
+      discRxPool_ResourceConfig_offsetIndicator_present               = "prSmall";
+      discRxPool_ResourceConfig_offsetIndicator_choice                = 0;
+      discRxPool_ResourceConfig_subframeBitmap_present                = "prBs40";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_buf          = "f0ffffffff";
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_size         = 5;
+      discRxPool_ResourceConfig_subframeBitmap_choice_bs_bits_unused  = 0;
+
+      }
+    );
+
+
+    srb1_parameters :
+    {
+        # timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
+        timer_poll_retransmit    = 80;
+
+        # timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
+        timer_reordering         = 35;
+
+        # timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
+        timer_status_prohibit    = 0;
+
+        # poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
+        poll_pdu                 =  4;
+
+        # poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
+        poll_byte                =  99999;
+
+        # max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
+        max_retx_threshold       =  4;
+    }
+
+    # ------- SCTP definitions
+    SCTP :
+    {
+        # Number of streams to use in input/output
+        SCTP_INSTREAMS  = 2;
+        SCTP_OUTSTREAMS = 2;
+    };
+
+
+    ////////// MME parameters:
+    mme_ip_address      = ( { ipv4       = "CI_MME_IP_ADDR";
+                              ipv6       = "192:168:30::17";
+                              active     = "yes";
+                              preference = "ipv4";
+                            }
+                          );
+    ///X2
+    enable_x2 = "yes";
+    t_reloc_prep      = 1000;      /* unit: millisecond */
+    tx2_reloc_overall = 2000;      /* unit: millisecond */
+    target_enb_x2_ip_address      = (
+                                     { ipv4       = "CI_RCC_IP_ADDR";
+                                       ipv6       = "192:168:30::17";
+                                       preference = "ipv4";
+                                     }
+                                    );
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "CI_ENB_IP_ADDR";
+        ENB_INTERFACE_NAME_FOR_S1U               = "eth0";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "CI_ENB_IP_ADDR";
+        ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "CI_ENB_IP_ADDR";
+        ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+    };
+  }
+);
+
+MACRLCs = (
+	{
+	num_cc = 1;
+	tr_s_preference = "local_L1";
+	tr_n_preference = "local_RRC";
+	phy_test_mode = 0;
+        puSch10xSnr     =  200;
+        puCch10xSnr     =  200;
+        }  
+);
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "local_mac";
+        }  
+);
+
+RUs = (
+    {		  
+       local_rf       = "yes"
+         nb_tx          = 1
+         nb_rx          = 1
+         att_tx         = 0
+         att_rx         = 0;
+         bands          = [7];
+         max_pdschReferenceSignalPower = -27;
+         max_rxgain                    = 125;
+         eNB_instances  = [0];
+
+    }
+);  
+
+NETWORK_CONTROLLER :
+{
+    FLEXRAN_ENABLED        = "no";
+    FLEXRAN_INTERFACE_NAME = "eth0";
+    FLEXRAN_IPV4_ADDRESS   = "CI_MME_IP_ADDR";
+    FLEXRAN_PORT           = 2210;
+    FLEXRAN_CACHE          = "/mnt/oai_agent_cache";
+    FLEXRAN_AWAIT_RECONF   = "no";
+};
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "PARALLEL_SINGLE_THREAD";//PARALLEL_RU_L1_TRX_SPLIT";
+    #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
+    worker_config      = "WORKER_ENABLE";
+  }
+);
+
+     log_config :
+     {
+       global_log_level                      ="info";
+       global_log_verbosity                  ="medium";
+       hw_log_level                          ="info";
+       hw_log_verbosity                      ="medium";
+       phy_log_level                         ="info";
+       phy_log_verbosity                     ="medium";
+       mac_log_level                         ="info";
+       mac_log_verbosity                     ="high";
+       rlc_log_level                         ="info";
+       rlc_log_verbosity                     ="medium";
+       pdcp_log_level                        ="info";
+       pdcp_log_verbosity                    ="medium";
+       rrc_log_level                         ="info";
+       rrc_log_verbosity                     ="medium";
+    };
+
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf b/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf
index 81fc7eedce43275998cfca24428ee77563e79452..28bfd91560d9085aa446f3e1267b6cf7853ea665 100644
--- a/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf
+++ b/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf
@@ -218,7 +218,7 @@ MACRLCs = (
 THREAD_STRUCT = (
   {
     #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
-    parallel_config    = "PARALLEL_SINGLE_THREAD";
+    parallel_config    = "PARALLEL_RU_L1_SPLIT";
     #two option for worker "WORKER_DISABLE" or "WORKER_ENABLE"
     worker_config      = "WORKER_ENABLE";
   }
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 6079421190138e729276f3cbea58e07e1dae88b5..d465e7075cae04515e2cce3dfb6f9ec3b8d4b34d 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -63,6 +63,12 @@ UE_STATUS_DETACHING = 1
 UE_STATUS_ATTACHING = 2
 UE_STATUS_ATTACHED = 3
 
+X2_HO_REQ_STATE__IDLE = 0
+X2_HO_REQ_STATE__TARGET_RECEIVES_REQ = 1
+X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE = 2
+X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ = 3
+X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK = 10
+
 #-----------------------------------------------------------
 # Import
 #-----------------------------------------------------------
@@ -145,6 +151,10 @@ class SSHConnection():
 		self.htmlUEFailureMsg = ''
 		self.picocom_closure = False
 		self.idle_sleep_time = 0
+		self.x2_ho_options = 'network'
+		self.x2NbENBs = 0
+		self.x2ENBBsIds = []
+		self.x2ENBConnectedUEs = []
 		self.htmlTabRefs = []
 		self.htmlTabNames = []
 		self.htmlTabIcons = []
@@ -815,7 +825,10 @@ class SSHConnection():
 			# self.command('stdbuf -o0 adb -s ' + device_id + ' shell am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true', '\$', 60)
 			# a dedicated script has to be installed inside the UE
 			# airplane mode on means call /data/local/tmp/off
-			self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
+			if device_id == '84B7N16418004022':
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60)
+			else:
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
 			#airplane mode off means call /data/local/tmp/on
 			logging.debug('\u001B[1mUE (' + device_id + ') Initialize Completed\u001B[0m')
 			self.close()
@@ -1219,7 +1232,10 @@ class SSHConnection():
 	def AttachUE_common(self, device_id, statusQueue, lock):
 		try:
 			self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword)
-			self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60)
+			if device_id == '84B7N16418004022':
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60)
+			else:
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60)
 			time.sleep(2)
 			max_count = 45
 			count = max_count
@@ -1246,9 +1262,15 @@ class SSHConnection():
 				count = count - 1
 				if count == 15 or count == 30:
 					logging.debug('\u001B[1;30;43m Retry UE (' + device_id + ') Flight Mode Off \u001B[0m')
-					self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
+					if device_id == '84B7N16418004022':
+						self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60)
+					else:
+						self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
 					time.sleep(0.5)
-					self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60)
+					if device_id == '84B7N16418004022':
+						self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/on"', '\$', 60)
+					else:
+						self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/on', '\$', 60)
 					time.sleep(0.5)
 				logging.debug('\u001B[1mWait UE (' + device_id + ') a second until mDataConnectionState=2 (' + str(max_count-count) + ' times)\u001B[0m')
 				time.sleep(1)
@@ -1325,7 +1347,10 @@ class SSHConnection():
 	def DetachUE_common(self, device_id):
 		try:
 			self.open(self.ADBIPAddress, self.ADBUserName, self.ADBPassword)
-			self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
+			if device_id == '84B7N16418004022':
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell "su - root -c /data/local/tmp/off"', '\$', 60)
+			else:
+				self.command('stdbuf -o0 adb -s ' + device_id + ' shell /data/local/tmp/off', '\$', 60)
 			logging.debug('\u001B[1mUE (' + device_id + ') Detach Completed\u001B[0m')
 			self.close()
 		except:
@@ -2718,7 +2743,36 @@ class SSHConnection():
 		isRRU = False
 		isSlave = False
 		slaveReceivesFrameResyncCmd = False
+		X2HO_state = X2_HO_REQ_STATE__IDLE
+		X2HO_inNbProcedures = 0
+		X2HO_outNbProcedures = 0
 		for line in enb_log_file.readlines():
+			if X2HO_state == X2_HO_REQ_STATE__IDLE:
+				result = re.search('target eNB Receives X2 HO Req X2AP_HANDOVER_REQ', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__TARGET_RECEIVES_REQ
+				result = re.search('source eNB receives the X2 HO ACK X2AP_HANDOVER_REQ_ACK', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK
+			if X2HO_state == X2_HO_REQ_STATE__TARGET_RECEIVES_REQ:
+				result = re.search('Received LTE_RRCConnectionReconfigurationComplete from UE', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE
+			if X2HO_state == X2_HO_REQ_STATE__TARGET_RRC_RECFG_COMPLETE:
+				result = re.search('issue rrc_eNB_send_PATH_SWITCH_REQ', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ
+			if X2HO_state == X2_HO_REQ_STATE__TARGET_SENDS_SWITCH_REQ:
+				result = re.search('received path switch ack S1AP_PATH_SWITCH_REQ_ACK', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__IDLE
+					X2HO_inNbProcedures += 1
+			if X2HO_state == X2_HO_REQ_STATE__SOURCE_RECEIVES_REQ_ACK:
+				result = re.search('source eNB receives the X2 UE CONTEXT RELEASE X2AP_UE_CONTEXT_RELEASE', str(line))
+				if result is not None:
+					X2HO_state = X2_HO_REQ_STATE__IDLE
+					X2HO_outNbProcedures += 1
+
 			if self.eNBOptions[int(self.eNB_instance)] != '':
 				res1 = re.search('max_rxgain (?P<requested_option>[0-9]+)', self.eNBOptions[int(self.eNB_instance)])
 				res2 = re.search('max_rxgain (?P<applied_option>[0-9]+)',  str(line))
@@ -2854,6 +2908,14 @@ class SSHConnection():
 			rrcMsg = ' -- ' + str(rrcReestablishReject) + ' were rejected'
 			logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
 			self.htmleNBFailureMsg += rrcMsg + '\n'
+		if X2HO_inNbProcedures > 0:
+			rrcMsg = 'eNB completed ' + str(X2HO_inNbProcedures) + ' X2 Handover Connection procedure(s)'
+			logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
+			self.htmleNBFailureMsg += rrcMsg + '\n'
+		if X2HO_outNbProcedures > 0:
+			rrcMsg = 'eNB completed ' + str(X2HO_outNbProcedures) + ' X2 Handover Release procedure(s)'
+			logging.debug('\u001B[1;30;43m ' + rrcMsg + ' \u001B[0m')
+			self.htmleNBFailureMsg += rrcMsg + '\n'
 		if self.eNBOptions[int(self.eNB_instance)] != '':
 			res1 = re.search('drx_Config_present prSetup', self.eNBOptions[int(self.eNB_instance)])
 			if res1 is not None:
@@ -3355,6 +3417,116 @@ class SSHConnection():
 		time.sleep(self.idle_sleep_time)
 		self.CreateHtmlTestRow(str(self.idle_sleep_time) + ' sec', 'OK', ALL_PROCESSES_OK)
 
+	def X2_Status(self, idx, fileName):
+		cmd = "curl --silent http://" + self.EPCIPAddress + ":9999/stats | jq '.' > " + fileName
+		message = cmd + '\n'
+		logging.debug(cmd)
+		subprocess.run(cmd, shell=True)
+		if idx == 0:
+			cmd = "jq '.mac_stats | length' " + fileName
+			strNbEnbs = subprocess.check_output(cmd, shell=True, universal_newlines=True)
+			self.x2NbENBs = int(strNbEnbs.strip())
+		cnt = 0
+		while cnt < self.x2NbENBs:
+			cmd = "jq '.mac_stats[" + str(cnt) + "].bs_id' " + fileName
+			bs_id = subprocess.check_output(cmd, shell=True, universal_newlines=True)
+			self.x2ENBBsIds[idx].append(bs_id.strip())
+			cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats | length' " + fileName
+			stNbUEs = subprocess.check_output(cmd, shell=True, universal_newlines=True)
+			nbUEs = int(stNbUEs.strip())
+			ueIdx = 0
+			self.x2ENBConnectedUEs[idx].append([])
+			while ueIdx < nbUEs:
+				cmd = "jq '.mac_stats[" + str(cnt) + "].ue_mac_stats[" + str(ueIdx) + "].rnti' " + fileName
+				rnti = subprocess.check_output(cmd, shell=True, universal_newlines=True)
+				self.x2ENBConnectedUEs[idx][cnt].append(rnti.strip())
+				ueIdx += 1
+			cnt += 1
+
+		msg = "FlexRan Controller is connected to " + str(self.x2NbENBs) + " eNB(s)"
+		logging.debug(msg)
+		message += msg + '\n'
+		cnt = 0
+		while cnt < self.x2NbENBs:
+			msg = "   -- eNB: " + str(self.x2ENBBsIds[idx][cnt]) + " is connected to " + str(len(self.x2ENBConnectedUEs[idx][cnt])) + " UE(s)"
+			logging.debug(msg)
+			message += msg + '\n'
+			ueIdx = 0
+			while ueIdx < len(self.x2ENBConnectedUEs[idx][cnt]):
+				msg = "      -- UE rnti: " + str(self.x2ENBConnectedUEs[idx][cnt][ueIdx])
+				logging.debug(msg)
+				message += msg + '\n'
+				ueIdx += 1
+			cnt += 1
+		return message
+
+	def Perform_X2_Handover(self):
+		html_queue = SimpleQueue()
+		fullMessage = '<pre style="background-color:white">'
+		msg = 'Doing X2 Handover w/ option ' + self.x2_ho_options
+		logging.debug(msg)
+		fullMessage += msg + '\n'
+		if self.x2_ho_options == 'network':
+			if self.flexranCtrlInstalled and self.flexranCtrlStarted:
+				self.x2ENBBsIds = []
+				self.x2ENBConnectedUEs = []
+				self.x2ENBBsIds.append([])
+				self.x2ENBBsIds.append([])
+				self.x2ENBConnectedUEs.append([])
+				self.x2ENBConnectedUEs.append([])
+				fullMessage += self.X2_Status(0, self.testCase_id + '_pre_ho.json') 
+
+				msg = "Activating the X2 Net control on each eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				eNB_cnt = self.x2NbENBs
+				cnt = 0
+				while cnt < eNB_cnt:
+					cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/x2_ho_net_control/enb/" + str(self.x2ENBBsIds[0][cnt]) + "/1"
+					logging.debug(cmd)
+					fullMessage += cmd + '\n'
+					subprocess.run(cmd, shell=True)
+					cnt += 1
+				# Waiting for the activation to be active
+				time.sleep(10)
+				msg = "Switching UE(s) from eNB to eNB"
+				logging.debug(msg)
+				fullMessage += msg + '\n'
+				cnt = 0
+				while cnt < eNB_cnt:
+					ueIdx = 0
+					while ueIdx < len(self.x2ENBConnectedUEs[0][cnt]):
+						cmd = "curl -XPOST http://" + self.EPCIPAddress + ":9999/rrc/ho/senb/" + str(self.x2ENBBsIds[0][cnt]) + "/ue/" + str(self.x2ENBConnectedUEs[0][cnt][ueIdx]) + "/tenb/" + str(self.x2ENBBsIds[0][eNB_cnt - cnt - 1])
+						logging.debug(cmd)
+						fullMessage += cmd + '\n'
+						subprocess.run(cmd, shell=True)
+						ueIdx += 1
+					cnt += 1
+				time.sleep(10)
+				# check
+				logging.debug("Checking the Status after X2 Handover")
+				fullMessage += self.X2_Status(1, self.testCase_id + '_post_ho.json') 
+				cnt = 0
+				x2Status = True
+				while cnt < eNB_cnt:
+					if len(self.x2ENBConnectedUEs[0][cnt]) == len(self.x2ENBConnectedUEs[1][cnt]):
+						x2Status = False
+					cnt += 1
+				if x2Status:
+					msg = "X2 Handover was successful"
+					logging.debug(msg)
+					fullMessage += msg + '</pre>'
+					html_queue.put(fullMessage)
+					self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue)
+				else:
+					msg = "X2 Handover FAILED"
+					logging.error(msg)
+					fullMessage += msg + '</pre>'
+					html_queue.put(fullMessage)
+					self.CreateHtmlTestRowQueue('N/A', 'OK', len(self.UEDevices), html_queue)
+			else:
+				self.CreateHtmlTestRow('Cannot perform requested X2 Handover', 'KO', ALL_PROCESSES_OK)
+
 	def LogCollectBuild(self):
 		if (self.eNBIPAddress != '' and self.eNBUserName != '' and self.eNBPassword != ''):
 			IPAddress = self.eNBIPAddress
@@ -3892,7 +4064,7 @@ def Usage():
 	print('------------------------------------------------------------')
 
 def CheckClassValidity(action,id):
-	if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep':
+	if action != 'Build_eNB' and action != 'WaitEndBuild_eNB' and action != 'Initialize_eNB' and action != 'Terminate_eNB' and action != 'Initialize_UE' and action != 'Terminate_UE' and action != 'Attach_UE' and action != 'Detach_UE' and action != 'Build_OAI_UE' and action != 'Initialize_OAI_UE' and action != 'Terminate_OAI_UE' and action != 'DataDisable_UE' and action != 'DataEnable_UE' and action != 'CheckStatusUE' and action != 'Ping' and action != 'Iperf' and action != 'Reboot_UE' and action != 'Initialize_FlexranCtrl' and action != 'Terminate_FlexranCtrl' and action != 'Initialize_HSS' and action != 'Terminate_HSS' and action != 'Initialize_MME' and action != 'Terminate_MME' and action != 'Initialize_SPGW' and action != 'Terminate_SPGW' and action != 'Initialize_CatM_module' and action != 'Terminate_CatM_module' and action != 'Attach_CatM_module' and action != 'Detach_CatM_module' and action != 'Ping_CatM_module' and action != 'IdleSleep' and action != 'Perform_X2_Handover':
 		logging.debug('ERROR: test-case ' + id + ' has wrong class ' + action)
 		return False
 	return True
@@ -4011,6 +4183,18 @@ def GetParametersFromXML(action):
 		else:
 			SSH.idle_sleep_time = int(string_field)
 
+	if action == 'Perform_X2_Handover':
+		string_field = test.findtext('x2_ho_options')
+		if (string_field is None):
+			SSH.x2_ho_options = 'network'
+		else:
+			if string_field != 'network':
+				logging.error('ERROR: test-case has wrong option ' + string_field)
+				SSH.x2_ho_options = 'network'
+			else:
+				SSH.x2_ho_options = string_field
+
+
 #check if given test is in list
 #it is in list if one of the strings in 'list' is at the beginning of 'test'
 def test_in_list(test, list):
@@ -4421,6 +4605,8 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					SSH.TerminateFlexranCtrl()
 				elif action == 'IdleSleep':
 					SSH.IdleSleep()
+				elif action == 'Perform_X2_Handover':
+					SSH.Perform_X2_Handover()
 				else:
 					sys.exit('Invalid action')
 				if SSH.prematureExit:
diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh
index 7a31e2bab2cdb459d17b85f4920663d275bd2c2c..e93f23120c268492aa1323efd7316ad7e6a1ea8e 100755
--- a/ci-scripts/runTestOnVM.sh
+++ b/ci-scripts/runTestOnVM.sh
@@ -1843,7 +1843,7 @@ function run_test_on_vm {
                     fi
                 fi
 
-                if [ $S1_NOS1_CFG -eq 0 ]
+                if [ $S1_NOS1_CFG -eq 2 ]
                 then
                     get_enb_noS1_ip_addr $ENB_VM_CMDS $ENB_VM_IP_ADDR
                     echo "############################################################"
diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml
index 29c9a29c2d2f9eeae14cc68dea9c59f5a52a8fd2..a2e74c6de9329c1f0a1215d62592388b9ef18afd 100644
--- a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml
+++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1.xml
@@ -24,6 +24,7 @@
 	<htmlTabRef>test-05-tm1-nos1-tunnel</htmlTabRef>
 	<htmlTabName>Test-05MHz-TM1-noS1-tunnel</htmlTabName>
 	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>2</repeatCount>
 	<TestCaseRequestedList>
  030201 090109
  030101 000001 090101 000002 040501 040502 000001 040601 040602 040641 040642 000001 090109 030201
diff --git a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml
index 2e6b9a0dc6c25f7ef8d2ff45780b3074b6be6aa9..9f7546cab347cbfed1513460c2b0158402a55c0b 100644
--- a/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml
+++ b/ci-scripts/xml_files/enb_ue_usrp210_band7_test_05mhz_tm1_s1.xml
@@ -24,6 +24,7 @@
 	<htmlTabRef>test-05-tm1-tunnel</htmlTabRef>
 	<htmlTabName>Test-05MHz-TM1-tunnel</htmlTabName>
 	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>2</repeatCount>
 	<TestCaseRequestedList>
  030201 090109
  030102 000001 090102 000002 040503 000001 040603 040604 040643 040644 000001 090109 030201
diff --git a/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml b/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml
index a3f88307ec0057a0ca0c2ee94b483266eb741038..9c98ba4a8eb33677e1c7bf6c7093e47136e0ed59 100644
--- a/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml
+++ b/ci-scripts/xml_files/enb_usrp210_band40_test_05mhz_tm2.xml
@@ -25,6 +25,7 @@
 	<htmlTabRef>test-05-tm2</htmlTabRef>
 	<htmlTabName>Test-05MHz-TM2</htmlTabName>
 	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>2</repeatCount>
         <TestCaseRequestedList>
  030201
  040101
diff --git a/ci-scripts/xml_files/f1_usrp210_band7_test_05mhz.xml b/ci-scripts/xml_files/f1_usrp210_band7_test_05mhz.xml
index fc14f5f7ffc9679ee12cc800332e55cf4350c00f..c2a48037baf5c2e6b151059d3806d15e4d07e2f9 100644
--- a/ci-scripts/xml_files/f1_usrp210_band7_test_05mhz.xml
+++ b/ci-scripts/xml_files/f1_usrp210_band7_test_05mhz.xml
@@ -24,7 +24,7 @@
 	<htmlTabRef>test-f1-05</htmlTabRef>
 	<htmlTabName>Test-F1-CU-DU-05MHz</htmlTabName>
 	<htmlTabIcon>tasks</htmlTabIcon>
-	<repeatCount>4</repeatCount>
+	<repeatCount>2</repeatCount>
 	<TestCaseRequestedList>
  030201
  040101
diff --git a/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml b/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml
index 17ede3f8305ec26db5e8204c3080717c48811f7c..15d641efeb431917f96d24568558447d68d64080 100644
--- a/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml
+++ b/ci-scripts/xml_files/if4p5_usrp210_band40_test_20mhz.xml
@@ -24,6 +24,7 @@
 	<htmlTabRef>test-20</htmlTabRef>
 	<htmlTabName>Test-20MHz</htmlTabName>
 	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>2</repeatCount>
 	<TestCaseRequestedList>
  030201
  040101
diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0d2a122537d2caf3344e0dc43fc236bdaa7233d2
--- /dev/null
+++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_build.xml
@@ -0,0 +1,66 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>build-tab</htmlTabRef>
+	<htmlTabName>Build</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 010101
+ 010102
+ 050101 060101 070101
+	</TestCaseRequestedList>
+	<TestCaseExclusionList>
+	</TestCaseExclusionList>
+
+	<testCase id="010101">
+		<class>Build_eNB</class>
+		<desc>Build Master eNB (USRP)</desc>
+		<Build_eNB_args>-w USRP -c --eNB</Build_eNB_args>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="010102">
+		<class>Build_eNB</class>
+		<desc>Build Slave eNB (USRP)</desc>
+		<Build_eNB_args>-w USRP -c --eNB</Build_eNB_args>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+	</testCase>
+
+	<testCase id="050101">
+		<class>Initialize_HSS</class>
+		<desc>Initialize HSS</desc>
+	</testCase>
+
+	<testCase id="060101">
+		<class>Initialize_MME</class>
+		<desc>Initialize MME</desc>
+	</testCase>
+
+	<testCase id="070101">
+		<class>Initialize_SPGW</class>
+		<desc>Initialize SPGW</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_closure.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_closure.xml
new file mode 100644
index 0000000000000000000000000000000000000000..07fb6951f8e99a35cabd2ee4e48232d2bd035f41
--- /dev/null
+++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_epc_closure.xml
@@ -0,0 +1,47 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>epc-closure</htmlTabRef>
+	<htmlTabName>EPC-Closure</htmlTabName>
+	<htmlTabIcon>log-out</htmlTabIcon>
+	<TestCaseRequestedList>
+ 050201 060201 070201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="050201">
+		<class>Terminate_HSS</class>
+		<desc>Terminate HSS</desc>
+	</testCase>
+
+	<testCase id="060201">
+		<class>Terminate_MME</class>
+		<desc>Terminate MME</desc>
+	</testCase>
+
+	<testCase id="070201">
+		<class>Terminate_SPGW</class>
+		<desc>Terminate SPGW</desc>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_full_terminate.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_full_terminate.xml
new file mode 100644
index 0000000000000000000000000000000000000000..91280462b70b1b31887ce17edf0bb9a92be9a932
--- /dev/null
+++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_full_terminate.xml
@@ -0,0 +1,46 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>test-x2-ho-full-end</htmlTabRef>
+	<htmlTabName>Test-X2-HO-Full-Terminate</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<TestCaseRequestedList>
+ 030201 030202
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="030201">
+		<class>Terminate_eNB</class>
+		<desc>Terminate Master eNB</desc>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="030202">
+		<class>Terminate_eNB</class>
+		<desc>Terminate Slave eNB</desc>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+	</testCase>
+
+</testCaseList>
diff --git a/ci-scripts/xml_files/x2ho_enb_usrp210_band13_test_05mhz_tm1.xml b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_test_05mhz_tm1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c43be75a8721feda87fbfeba9e29d932d96154ac
--- /dev/null
+++ b/ci-scripts/xml_files/x2ho_enb_usrp210_band13_test_05mhz_tm1.xml
@@ -0,0 +1,191 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+ 030101 000002 030102 040301 040501 040601 040641 050401 000002 040502 040602 040642 050402 000002 040503 040603 040643 040401 040201 030201 030202
+-->
+<testCaseList>
+	<htmlTabRef>test-x2-ho-05-tm1</htmlTabRef>
+	<htmlTabName>Test-X2-HO-FDD-05MHz-TM1</htmlTabName>
+	<htmlTabIcon>tasks</htmlTabIcon>
+	<repeatCount>2</repeatCount>
+	<TestCaseRequestedList>
+ 030201 030202
+ 040101
+ 050102
+ 030101 000002 030102 040301 040501 050401 000002 040502 050402 000002 040503 040401 040201 030201 030202
+ 050202
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="000001">
+		<class>IdleSleep</class>
+		<desc>Waiting for 60 seconds</desc>
+		<idle_sleep_time_in_sec>60</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="000002">
+		<class>IdleSleep</class>
+		<desc>Waiting for 10 seconds</desc>
+		<idle_sleep_time_in_sec>10</idle_sleep_time_in_sec>
+	</testCase>
+
+	<testCase id="050102">
+		<class>Initialize_FlexranCtrl</class>
+		<desc>Starting Flexran Controller</desc>
+	</testCase>
+
+	<testCase id="050202">
+		<class>Terminate_FlexranCtrl</class>
+		<desc>Stopping Flexran Controller</desc>
+	</testCase>
+
+	<testCase id="030101">
+		<class>Initialize_eNB</class>
+		<desc>Initialize Master eNB (FDD/Band7/5MHz)</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.band13.tm1.25PRB.usrpb210.conf</Initialize_eNB_args>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="030102">
+		<class>Initialize_eNB</class>
+		<desc>Initialize Slave eNB (FDD/Band7/5MHz)</desc>
+		<Initialize_eNB_args>-O ci-scripts/conf_files/enb.slave.band13.tm1.25PRB.usrpb210.conf</Initialize_eNB_args>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+	</testCase>
+
+	<testCase id="030201">
+		<class>Terminate_eNB</class>
+		<desc>Terminate Master eNB</desc>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+	<testCase id="030202">
+		<class>Terminate_eNB</class>
+		<desc>Terminate Slave eNB</desc>
+		<eNB_instance>1</eNB_instance>
+		<eNB_serverId>1</eNB_serverId>
+	</testCase>
+
+	<testCase id="040101">
+		<class>Initialize_UE</class>
+		<desc>Initialize UE</desc>
+	</testCase>
+
+	<testCase id="040201">
+		<class>Terminate_UE</class>
+		<desc>Terminate UE</desc>
+	</testCase>
+
+	<testCase id="040301">
+		<class>Attach_UE</class>
+		<desc>Attach UE</desc>
+	</testCase>
+
+	<testCase id="040401">
+		<class>Detach_UE</class>
+		<desc>Detach UE</desc>
+	</testCase>
+
+	<testCase id="040501">
+		<class>Ping</class>
+		<desc>ping (5MHz - 20 sec)</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>5</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="040502">
+		<class>Ping</class>
+		<desc>ping (5MHz - 20 sec)</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>5</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="040503">
+		<class>Ping</class>
+		<desc>ping (5MHz - 20 sec)</desc>
+		<ping_args>-c 20</ping_args>
+		<ping_packetloss_threshold>5</ping_packetloss_threshold>
+	</testCase>
+
+	<testCase id="040601">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/8Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 8M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040602">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/8Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 8M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040603">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - DL/8Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 8M -t 30 -i 1</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040641">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/5Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 5M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040642">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/5Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 5M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="040643">
+		<class>Iperf</class>
+		<desc>iperf (5MHz - UL/5Mbps/UDP)(30 sec)</desc>
+		<iperf_args>-u -b 5M -t 30 -i 1 -R</iperf_args>
+		<iperf_packetloss_threshold>50</iperf_packetloss_threshold>
+		<iperf_profile>single-ue</iperf_profile>
+	</testCase>
+
+	<testCase id="050401">
+		<class>Perform_X2_Handover</class>
+		<desc>Doing a Flexran-Controlled X2 Handover</desc>
+		<x2_ho_options>network</x2_ho_options>
+	</testCase>
+
+	<testCase id="050402">
+		<class>Perform_X2_Handover</class>
+		<desc>Doing a Flexran-Controlled X2 Handover</desc>
+		<x2_ho_options>network</x2_ho_options>
+	</testCase>
+
+</testCaseList>
diff --git a/cmake_targets/build_ue b/cmake_targets/build_ue
deleted file mode 100755
index 9d9ca839d10c0164f038a8b6eb4a79f772e01d70..0000000000000000000000000000000000000000
--- a/cmake_targets/build_ue
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/bash
-#sudo ./build_oai -c -C -I --install-optional-packages --install-system-files --UE -w USRP -V 
-#sudo ./build_oai -c -C -I --install-optional-packages --UE -w USRP -V 
-#sudo ./build_oai -c -C --UE -w USRP -V
-sudo ./build_oai -c -C --UE -w USRP
-#sudo ./build_oai -c -C --UE -w USRP --build-eclipse
diff --git a/common/utils/LOG/log.c b/common/utils/LOG/log.c
index b4b9722ca41b55aadee6b282b4d3ef60e7be6127..186077035126d5e85d217c883a2fa00538a9678a 100644
--- a/common/utils/LOG/log.c
+++ b/common/utils/LOG/log.c
@@ -43,8 +43,22 @@
 #include <string.h>
 #include <linux/prctl.h>
 #include "common/config/config_userapi.h"
+
 // main log variables
 
+log_mem_cnt_t log_mem_d[2];
+int log_mem_flag=0;
+int log_mem_multi=1;
+volatile int log_mem_side=0;
+pthread_mutex_t log_mem_lock;
+pthread_cond_t log_mem_notify;
+pthread_t log_mem_thread;
+int log_mem_file_cnt=0;
+volatile int log_mem_write_flag=0;
+volatile int log_mem_write_side=0;
+char __log_mem_filename[1024]={0};
+char * log_mem_filename = &__log_mem_filename[0];
+char logmem_filename[1024] = {0};
 
 mapping log_level_names[] = {
   {"error",  OAILOG_ERR},
@@ -477,10 +491,14 @@ void logRecord_mt(const char *file,
 {
   char log_buffer[MAX_LOG_TOTAL]= {0};
   va_list args;
-  va_start(args, format);
-  log_header(log_buffer,MAX_LOG_TOTAL,comp, level,format);
-  g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer, args);
+  va_start(args,format);
+  if (log_mem_flag == 1) {
+    log_output_memory(file,func,line,comp,level,format,args);
+  } else {
+  log_header(log_buffer,MAX_LOG_TOTAL,comp,level,format);
+  g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer,args);
   fflush(g_log->log_component[comp].stream);
+  }
   va_end(args);
 }
 
@@ -493,8 +511,12 @@ void vlogRecord_mt(const char *file,
 				   va_list args )
 {
   char log_buffer[MAX_LOG_TOTAL];
+  if (log_mem_flag == 1) {
+    log_output_memory(file,func,line,comp,level, format,args);
+  } else {
   log_header(log_buffer,MAX_LOG_TOTAL,comp, level,format);
   g_log->log_component[comp].vprint(g_log->log_component[comp].stream,log_buffer, args);
+  }
 }
 
 void log_dump(int component,
@@ -696,6 +718,265 @@ void logClean (void)
   }
 }
 
+extern int oai_exit;
+void flush_mem_to_file(void)
+{
+  int fp;
+  char f_name[1024];
+  struct timespec slp_tm;
+  slp_tm.tv_sec = 0;
+  slp_tm.tv_nsec = 10000;
+  
+  pthread_setname_np( pthread_self(), "flush_mem_to_file");
+
+  while (!oai_exit) {
+    pthread_mutex_lock(&log_mem_lock);
+    log_mem_write_flag=0;
+    pthread_cond_wait(&log_mem_notify, &log_mem_lock);
+    log_mem_write_flag=1;
+    pthread_mutex_unlock(&log_mem_lock);
+    // write!
+    if(log_mem_d[log_mem_write_side].enable_flag==0){
+      if(log_mem_file_cnt>5){
+        log_mem_file_cnt=5;
+        printf("log over write!!!\n");
+      }
+      snprintf(f_name,1024, "%s_%d.log",log_mem_filename,log_mem_file_cnt);
+      fp=open(f_name, O_WRONLY | O_CREAT, 0666);
+      int ret = write(fp, log_mem_d[log_mem_write_side].buf_p, log_mem_d[log_mem_write_side].buf_index);
+      if ( ret < 0) {
+          fprintf(stderr,"{LOG} %s %d Couldn't write in %s \n",__FILE__,__LINE__,f_name);
+          exit(EXIT_FAILURE);
+      }
+      close(fp);
+      log_mem_file_cnt++;
+      log_mem_d[log_mem_write_side].buf_index=0;
+      log_mem_d[log_mem_write_side].enable_flag=1;
+    }else{
+      printf("If you'd like to write log, you should set enable flag to 0!!!\n");
+      nanosleep(&slp_tm,NULL);
+    }
+  }
+}
+
+char logmem_log_level[NUM_LOG_LEVEL]={'E','W','I','D','T'};
+
+void log_output_memory(const char *file, const char *func, int line, int comp, int level, const char* format,va_list args)
+{
+  //logRecord_mt(file,func,line, pthread_self(), comp, level, format, ##args)
+  int len = 0;
+  log_component_t *c;
+  char *log_start;
+  char *log_end;
+  /* The main difference with the version above is the use of this local log_buffer.
+   * The other difference is the return value of snprintf which was not used
+   * correctly. It was not a big problem because in practice MAX_LOG_TOTAL is
+   * big enough so that the buffer is never full.
+   */
+  char log_buffer[MAX_LOG_TOTAL];
+
+  /* for no gcc warnings */
+  (void)log_start;
+  (void)log_end;
+
+
+  c = &g_log->log_component[comp];
+
+  //VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LOG_RECORD, VCD_FUNCTION_IN);
+
+  // make sure that for log trace the extra info is only printed once, reset when the level changes
+  if (level == OAILOG_TRACE) {
+    log_start = log_buffer;
+    len = vsnprintf(log_buffer, MAX_LOG_TOTAL, format, args);
+    if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    log_end = log_buffer + len;
+  } else {
+    if ( (g_log->flag & 0x001) || (c->flag & 0x001) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s",
+                      log_level_highlight_start[level]);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    }
+
+    log_start = log_buffer + len;
+
+//    if ( (g_log->flag & 0x004) || (c->flag & 0x004) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]",
+                      g_log->log_component[comp].name);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+//    }
+
+    if ( (level >= OAILOG_ERR) && (level <= OAILOG_TRACE) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%c]",
+                      logmem_log_level[level]);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    }
+
+    if ( (g_log->flag & FLAG_THREAD) || (c->flag & FLAG_THREAD) ) {
+#     define THREAD_NAME_LEN 128
+      char threadname[THREAD_NAME_LEN];
+      if (pthread_getname_np(pthread_self(), threadname, THREAD_NAME_LEN) != 0)
+      {
+        perror("pthread_getname_np : ");
+      } else {
+        len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s]", threadname);
+        if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+      }
+#     undef THREAD_NAME_LEN
+    }
+
+    if ( (g_log->flag & FLAG_FUNCT) || (c->flag & FLAG_FUNCT) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s] ",
+                      func);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    }
+
+    if ( (g_log->flag & FLAG_FILE_LINE) || (c->flag & FLAG_FILE_LINE) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%s:%d]",
+                      file, line);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    }
+
+/*    len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%08lx]", thread_id);
+    if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+
+    struct timeval gettime;
+    gettimeofday(&gettime,NULL);
+    len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "[%ld.%06ld]", gettime.tv_sec, gettime.tv_usec);
+    if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+*/
+    if ( (g_log->flag & FLAG_NOCOLOR) || (c->flag & FLAG_NOCOLOR) ) {
+      len += snprintf(&log_buffer[len], MAX_LOG_TOTAL - len, "%s",
+          log_level_highlight_end[level]);
+      if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    }
+
+    len += vsnprintf(&log_buffer[len], MAX_LOG_TOTAL - len, format, args);
+    if (len > MAX_LOG_TOTAL) len = MAX_LOG_TOTAL;
+    log_end = log_buffer + len;
+  }
+
+  //va_end(args);
+
+  // OAI printf compatibility
+    if(log_mem_flag==1){
+      if(log_mem_d[log_mem_side].enable_flag==1){
+        int temp_index;
+        temp_index=log_mem_d[log_mem_side].buf_index;
+        if(temp_index+len+1 < LOG_MEM_SIZE){
+          log_mem_d[log_mem_side].buf_index+=len;
+          memcpy(&log_mem_d[log_mem_side].buf_p[temp_index],log_buffer,len);
+        }else{
+          log_mem_d[log_mem_side].enable_flag=0;
+          if(log_mem_d[1-log_mem_side].enable_flag==1){
+            temp_index=log_mem_d[1-log_mem_side].buf_index;
+            if(temp_index+len+1 < LOG_MEM_SIZE){
+              log_mem_d[1-log_mem_side].buf_index+=len;
+              log_mem_side=1-log_mem_side;
+              memcpy(&log_mem_d[log_mem_side].buf_p[temp_index],log_buffer,len);
+              /* write down !*/
+              if (pthread_mutex_lock(&log_mem_lock) != 0) {
+                return;
+              }
+              if(log_mem_write_flag==0){
+                log_mem_write_side=1-log_mem_side;
+                if(pthread_cond_signal(&log_mem_notify) != 0) {
+                }
+              }
+              if(pthread_mutex_unlock(&log_mem_lock) != 0) {
+                return;
+              }
+            }else{
+              log_mem_d[1-log_mem_side].enable_flag=0;
+            }
+          }
+        }
+      }
+    }else{
+      fwrite(log_buffer, len, 1, stdout);
+    }
+}
+
+int logInit_log_mem (void)
+{
+  if(log_mem_flag==1){
+    if(log_mem_multi==1){
+      printf("log-mem multi!!!\n");
+      log_mem_d[0].buf_p = malloc(LOG_MEM_SIZE);
+      log_mem_d[0].buf_index=0;
+      log_mem_d[0].enable_flag=1;
+      log_mem_d[1].buf_p = malloc(LOG_MEM_SIZE);
+      log_mem_d[1].buf_index=0;
+      log_mem_d[1].enable_flag=1;
+      log_mem_side=0;
+      if ((pthread_mutex_init (&log_mem_lock, NULL) != 0)
+          || (pthread_cond_init (&log_mem_notify, NULL) != 0)) {
+        log_mem_d[1].enable_flag=0;
+        return -1;
+      }
+      pthread_create(&log_mem_thread, NULL, (void *(*)(void *))flush_mem_to_file, (void*)NULL);
+    }else{
+      printf("log-mem single!!!\n");
+      log_mem_d[0].buf_p = malloc(LOG_MEM_SIZE);
+      log_mem_d[0].buf_index=0;
+      log_mem_d[0].enable_flag=1;
+      log_mem_d[1].enable_flag=0;
+      log_mem_side=0;
+    }
+  }else{
+    log_mem_d[0].buf_p=NULL;
+    log_mem_d[1].buf_p=NULL;
+    log_mem_d[0].enable_flag=0;
+    log_mem_d[1].enable_flag=0;
+  }
+
+  printf("log init done\n");
+  
+  return 0;
+}
+
+void close_log_mem(void){
+  int fp;
+  char f_name[1024];
+
+  if(log_mem_flag==1){
+    log_mem_d[0].enable_flag=0;
+    log_mem_d[1].enable_flag=0;
+    usleep(10); // wait for log writing
+    while(log_mem_write_flag==1){
+      usleep(100);
+    }
+    if(log_mem_multi==1){
+      snprintf(f_name,1024, "%s_%d.log",log_mem_filename,log_mem_file_cnt);
+      fp=open(f_name, O_WRONLY | O_CREAT, 0666);
+      int ret = write(fp, log_mem_d[0].buf_p, log_mem_d[0].buf_index);
+      if ( ret < 0) {
+          fprintf(stderr,"{LOG} %s %d Couldn't write in %s \n",__FILE__,__LINE__,f_name);
+          exit(EXIT_FAILURE);
+      }
+      close(fp);
+      free(log_mem_d[0].buf_p);
+      
+      snprintf(f_name,1024, "%s_%d.log",log_mem_filename,log_mem_file_cnt);
+      fp=open(f_name, O_WRONLY | O_CREAT, 0666);
+      ret = write(fp, log_mem_d[1].buf_p, log_mem_d[1].buf_index);
+      if ( ret < 0) {
+          fprintf(stderr,"{LOG} %s %d Couldn't write in %s \n",__FILE__,__LINE__,f_name);
+          exit(EXIT_FAILURE);
+      }
+      close(fp);
+      free(log_mem_d[1].buf_p);
+    }else{
+      fp=open(log_mem_filename, O_WRONLY | O_CREAT, 0666);
+      int ret = write(fp, log_mem_d[0].buf_p, log_mem_d[0].buf_index);
+      if ( ret < 0) {
+          fprintf(stderr,"{LOG} %s %d Couldn't write in %s \n",__FILE__,__LINE__,log_mem_filename);
+          exit(EXIT_FAILURE);
+       }
+      close(fp);
+      free(log_mem_d[0].buf_p);
+    }
+  }
+ }
 
 #ifdef LOG_TEST
 
diff --git a/common/utils/LOG/log.h b/common/utils/LOG/log.h
index ba27c87cc183d905e4de6bdf539cc99116d90ebf..cee14a27af92d98726d6a00d46565d35545f83cf 100644
--- a/common/utils/LOG/log.h
+++ b/common/utils/LOG/log.h
@@ -119,6 +119,8 @@ extern "C" {
 #define FLAG_NOCOLOR     0x0001  /*!< \brief use colors in log messages, depending on level */
 #define FLAG_THREAD      0x0008  /*!< \brief display thread name in log messages */
 #define FLAG_LEVEL       0x0010  /*!< \brief display log level in log messages */
+#define FLAG_FUNCT       0x0020
+#define FLAG_FILE_LINE   0x0040
 #define FLAG_TIME        0x0100
 #define FLAG_INITIALIZED 0x8000
 
@@ -314,6 +316,19 @@ int  is_newline( char *str, int size);
 
 int register_log_component(char *name, char *fext, int compidx);
 
+#define LOG_MEM_SIZE 100*1024*1024
+#define LOG_MEM_FILE "./logmem.log"
+void flush_mem_to_file(void);
+void log_output_memory(const char *file, const char *func, int line, int comp, int level, const char* format,va_list args);
+int logInit_log_mem(void);
+void close_log_mem(void);
+  
+typedef struct {
+  char* buf_p;
+  int buf_index;
+  int enable_flag;
+} log_mem_cnt_t;
+
 /* @}*/
 
 /*!\fn int32_t write_file_matlab(const char *fname, const char *vname, void *data, int length, int dec, char format);
diff --git a/common/utils/LOG/log_extern.h b/common/utils/LOG/log_extern.h
index 3c93d517ca76456f57927b34cfb915482b8b87c2..f6205889dc1477f2bc1bc86115ed89ff9ecaed72 100644
--- a/common/utils/LOG/log_extern.h
+++ b/common/utils/LOG/log_extern.h
@@ -27,4 +27,6 @@ extern log_t *g_log;
 extern mapping log_level_names[];
 extern mapping log_options[];
 extern mapping log_maskmap[];
-
+extern int log_mem_flag;
+extern char * log_mem_filename;
+extern char logmem_filename[1024];
diff --git a/common/utils/itti_analyzer/filters.xml b/common/utils/itti_analyzer/filters.xml
index e4a0e627d56f2297ec6b667bb115a2984704210f..7305a2294cd8e035f4ec4c8391e2cfb8af9e95a1 100644
--- a/common/utils/itti_analyzer/filters.xml
+++ b/common/utils/itti_analyzer/filters.xml
@@ -91,6 +91,8 @@
     <TASK_MAC_ENB enabled="1"/>
     <TASK_RLC_ENB enabled="1"/>
     <TASK_PDCP_ENB enabled="1"/>
+    <TASK_DATA_FORWARDING enabled="1"/>
+    <TASK_END_MARKER enabled="1"/>
     <TASK_RRC_ENB enabled="1"/>
     <TASK_RAL_ENB enabled="1"/>
     <TASK_S1AP enabled="1"/>
@@ -114,6 +116,8 @@
     <TASK_MAC_ENB enabled="1"/>
     <TASK_RLC_ENB enabled="1"/>
     <TASK_PDCP_ENB enabled="1"/>
+    <TASK_DATA_FORWARDING enabled="1"/>
+    <TASK_END_MARKER enabled="1"/>
     <TASK_RRC_ENB enabled="1"/>
     <TASK_RAL_ENB enabled="1"/>
     <TASK_S1AP enabled="1"/>
diff --git a/common/utils/itti_analyzer/filters_ue_enb.xml b/common/utils/itti_analyzer/filters_ue_enb.xml
index 38ed00ceae6d1fd7ae200c0e1f51d180dff1a89e..77859d20b694414a9d03a7c98b1d5bbcf8f74f31 100644
--- a/common/utils/itti_analyzer/filters_ue_enb.xml
+++ b/common/utils/itti_analyzer/filters_ue_enb.xml
@@ -130,6 +130,8 @@
     <TASK_MAC_ENB enabled="1"/>
     <TASK_RLC_ENB enabled="1"/>
     <TASK_PDCP_ENB enabled="1"/>
+    <TASK_DATA_FORWARDING enabled="1"/>
+    <TASK_END_MARKER enabled="1"/>
     <TASK_RRC_ENB enabled="1"/>
     <TASK_RAL_ENB enabled="1"/>
     <TASK_S1AP enabled="1"/>
@@ -153,6 +155,8 @@
     <TASK_MAC_ENB enabled="1"/>
     <TASK_RLC_ENB enabled="1"/>
     <TASK_PDCP_ENB enabled="1"/>
+    <TASK_DATA_FORWARDING enabled="1"/>
+    <TASK_END_MARKER enabled="1"/>
     <TASK_RRC_ENB enabled="1"/>
     <TASK_RAL_ENB enabled="1"/>
     <TASK_S1AP enabled="1"/>
diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h
index 99a2f2195f438b385f2729da5e32891c1191f8f0..868a9ba24555f314d7771f020f5ef3018b495fa4 100644
--- a/common/utils/ocp_itti/intertask_interface.h
+++ b/common/utils/ocp_itti/intertask_interface.h
@@ -283,6 +283,8 @@ typedef struct {
   TASK_DEF(TASK_RLC_ENB,  TASK_PRIORITY_MED, 200, NULL, NULL)   \
   TASK_DEF(TASK_RRC_ENB_NB_IoT,  TASK_PRIORITY_MED, 200, NULL, NULL) \
   TASK_DEF(TASK_PDCP_ENB, TASK_PRIORITY_MED, 200, NULL, NULL)   \
+  TASK_DEF(TASK_DATA_FORWARDING, TASK_PRIORITY_MED, 200, NULL, NULL)   \
+  TASK_DEF(TASK_END_MARKER, TASK_PRIORITY_MED, 200, NULL, NULL)   \
   TASK_DEF(TASK_RRC_ENB,  TASK_PRIORITY_MED,  200, NULL,NULL)\
   TASK_DEF(TASK_RRC_GNB,  TASK_PRIORITY_MED,  200, NULL,NULL)\
   TASK_DEF(TASK_RAL_ENB,  TASK_PRIORITY_MED,  200, NULL, NULL)  \
diff --git a/common/utils/telnetsrv/telnetsrv_ltemeasur_def.h b/common/utils/telnetsrv/telnetsrv_ltemeasur_def.h
index 2f479d8ee6f9e5f59b06720e751df617d871e3bb..160111f15e8bca2abd60af3f63ef4d487ed6a2a6 100644
--- a/common/utils/telnetsrv/telnetsrv_ltemeasur_def.h
+++ b/common/utils/telnetsrv/telnetsrv_ltemeasur_def.h
@@ -81,8 +81,8 @@
   {"total_num_pdus",	   &(macuestatptr->total_num_pdus),TELNET_VARTYPE_INT32,0},\
   {"overhead_bytes",	   &(macuestatptr->overhead_bytes),TELNET_VARTYPE_INT64,0},\
   {"crnti",	           &(macuestatptr->crnti),TELNET_VARTYPE_INT16,0},\
-  {"normalized_rx_power",  &(macuestatptr->normalized_rx_power),TELNET_VARTYPE_INT32,0},\
-  {"target_rx_power",	   &(macuestatptr->target_rx_power),TELNET_VARTYPE_INT32,0},\
+  {"snr",                  &(macuestatptr->snr),TELNET_VARTYPE_INT32,0},\
+  {"target_snr ",          &(macuestatptr->target_snr),TELNET_VARTYPE_INT32,0},\
   {"ulsch_mcs1",	   &(macuestatptr->ulsch_mcs1),TELNET_VARTYPE_INT8,0},\
   {"ulsch_mcs2",	   &(macuestatptr->ulsch_mcs2),TELNET_VARTYPE_INT8,0},\
   {"rbs_used_rx",	   &(macuestatptr->rbs_used_rx),TELNET_VARTYPE_INT32,0},\
diff --git a/doc/BASIC_SIM.md b/doc/BASIC_SIM.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab4c3489d9a3562cbb20acc59e0e101e84d922f6
--- /dev/null
+++ b/doc/BASIC_SIM.md
@@ -0,0 +1,191 @@
+<table style="border-collapse: collapse; border: none;">
+  <tr style="border-collapse: collapse; border: none;">
+    <td style="border-collapse: collapse; border: none;">
+      <a href="http://www.openairinterface.org/">
+         <img src="./images/oai_final_logo.png" alt="" border=3 height=50 width=150>
+         </img>
+      </a>
+    </td>
+    <td style="border-collapse: collapse; border: none; vertical-align: center;">
+      <b><font size = "5">Running OAI Basic Simulator</font></b>
+    </td>
+  </tr>
+</table>
+
+This page is valid on the following branches:
+
+- `master` starting from tag `v1.1.0`
+- `develop` starting from tag `2019.w11`
+
+# 1. Building the basic-simulator.
+
+After the build simplification, the basic simulator is available directly from the standard build.
+
+```bash
+$ source oaienv
+$ cd cmake_targets
+$ ./build_oai --eNB --UE
+```
+
+Both eNB (lte-softmodem) and UE (lte-uesoftmodem) are present on `cmake_targets/lte_build_oai/build` folder.
+
+More details are available on the [build page](BUILD.md).
+
+# 2. Running the basic simulator.
+
+The basic simulator is a oai device replacing the radio heads (for example the USRP device). It allows connecting the oai UE and the oai eNodeB through a network interface carrying the time-domain samples, getting rid of over the air unpredictable perturbations.
+
+This is the ideal tool to check signal processing algorithms and protocols implementation and having debug sessions without any HW radio equipment.
+
+The main limitations are:
+
+- A single OAI UE will connect to the OAI eNB
+- No channel noise
+
+## 2.1. Starting eNB
+
+The basic simulator is able to run with a connected EPC or without any (the so-called "noS1" mode).
+
+Example 1: running in FDD mode with EPC.
+
+```bash
+$ source oaienv
+$ cd cmake_targets/lte_build_oai/build
+$ ENODEB=1 sudo -E ./lte-softmodem -O $OPENAIR_HOME/ci-scripts/conf_files/lte-fdd-basic-sim.conf --basicsim
+```
+
+Edit previously the `ci-scripts/conf_files/lte-fdd-basic-sim.conf` file to modify:
+
+- `N_RB_DL` field to change the Bandwidth (25, 50, 100)
+- `CI_MME_IP_ADDR` with the EPC IP address
+- `CI_ENB_IP_ADDR` with the container (physical server, virtual machine, ...) on which you are executing the eNB soft-modem
+
+Example 2: running in TDD mode without any EPC.
+
+```bash
+$ source oaienv
+$ cd cmake_targets/lte_build_oai/build
+$ ENODEB=1 sudo -E ./lte-softmodem -O $OPENAIR_HOME/ci-scripts/conf_files/lte-tdd-basic-sim.conf --basicsim --noS1
+```
+
+## 2.2. Starting UE
+
+Before starting the UE, you may need to edit the SIM parameters to adapt to your eNB configuration and HSS database.
+
+The <conf> file to use for conf2uedate is `openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf`
+
+You need to set the correct OPC, USIM_API_K, MSIN (this is the end par of the IMSI), HPLMN (the front part of IMSI) to match values from HSS.
+
+```bash
+$ source oaienv
+# Edit openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf
+$ cd cmake_targets/lte_build_oai/build
+$ ../../nas_sim_tools/build/conf2uedata -c $OPENAIR_HOME/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf -o .
+$ sudo -E ./lte-uesoftmodem -C 2625000000 -r 25 --ue-rxgain 140 --basicsim [--noS1]
+```
+
+The `-r 25` is to use if in the conf file of the eNB you use N_RB_DL=25. Use 50 if you have N_RB_DL=50 and 100 if you have N_RB_DL=100.
+
+The `-C 2625000000` is the downlink frequency. Use the same value as `downlink_frequency` in the eNB configuration file.
+
+The `--noS1` is mandatory if you started the eNB in that mode.
+
+# 3. Testing the data plane
+
+# 3.1. In S1 mode
+
+First we need to retrieve the IP address allocated to the OAI UE.
+
+On the server that runs the UE:
+
+```bash
+$ ifconfig oaitun_ue1
+oaitun_ue1 Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
+            inet addr:192.172.0.2  P-t-P:192.172.0.2  Mask:255.255.255.0
+...
+```
+
+`192.172.0.2` is the IP address that has been allocated by the SPGW in the EPC.
+
+On the server that runs the EPC:
+
+```bash
+$ ping -c 20 192.172.0.2
+  --- 192.172.0.2 ping statistics ---
+  20 packets transmitted, 20 received, 0% packet loss, time 19020ms
+  rtt min/avg/max/mdev = 13.241/18.999/24.208/2.840 ms
+```
+
+You can ping the EPC from the UE:
+
+```bash
+$ ping -I oaitun_ue1 -c 20 192.172.0.1
+  --- 192.172.0.1 ping statistics ---
+...
+  20 packets transmitted, 20 received, 0% packet loss, time 19019ms
+  rtt min/avg/max/mdev = 13.015/18.674/23.738/2.917 ms
+```
+
+For DL iperf testing:
+
+On the server that runs the UE.
+
+```bash
+$  iperf -B 192.172.0.2 -u -s -i 1 -fm -p 5001
+```
+
+On the server that runs the EPC.
+
+```bash
+$  iperf -c 192.172.0.2 -u -t 30 -b 10M -i 1 -fm -B 192.172.0.1 -p 5001
+```
+
+For UL iperf testing:
+
+On the server that runs the EPC.
+
+```bash
+$  iperf -B 192.172.0.1 -u -s -i 1 -fm -p 5001
+```
+
+On the server that runs the UE.
+
+```bash
+$  iperf -c 192.172.0.1 -u -t 30 -b 2M -i 1 -fm -B 192.172.0.2 -p 5001
+```
+
+# 3.2. In noS1 mode
+
+The IP addresses are fixed. But we can still retrieve them programmatically.
+
+For the UE it is quite the same:
+
+```bash
+$ ifconfig oaitun_ue1
+oaitun_ue1 Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
+            inet addr:10.0.1.2  P-t-P:10.0.1.2  Mask:255.255.255.0
+...
+```
+
+For the eNB:
+
+```bash
+$ ifconfig oaitun_enb1
+oaitun_enb1 Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
+            inet addr:10.0.1.1  P-t-P:10.0.1.1  Mask:255.255.255.0
+...
+```
+
+Pinging like this:
+
+```bash
+$ ping -I oaitun_ue1 -c 20 10.0.1.1
+$ ping -I oaitun_enb1 -c 20 10.0.1.2
+```
+
+And the same for iperf:
+
+```bash
+$ iperf -B 10.0.1.2 -u -s -i 1 -fm
+$ iperf -c 10.0.1.2 -u -b 1.00M -t 30 -i 1 -fm -B 10.0.1.1
+```
diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index 4386382591201525dbaeaf55d1e38948ff24f1d9..e9355e51d2a88e479ebe991c85e45ec95bf8d9b2 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -41,10 +41,12 @@ The Physical layer implements **3GPP 36.211**, **36.212**, **36.213** and provid
 - Max number of antennas: 2
 - CQI/PMI reporting: aperiodic, feedback mode 3 - 0 and 3 - 1
 - PRACH preamble format 0
-- All downlink (DL) channels are supported: PSS, SSS, PBCH, PCFICH, PHICH, PDCCH, PDSCH, PMCH
-- All uplink (UL) channels are supported: PRACH, PUSCH, PUCCH (format 1/1a/1b), SRS, DRS
+- Downlink (DL) channels are supported: PSS, SSS, PBCH, PCFICH, PHICH, PDCCH, PDSCH, PMCH, MPDCCH
+- Uplink (UL) channels are supported: PRACH, PUSCH, PUCCH (format 1/1a/1b), SRS, DRS
 - HARQ support (UL and DL)
 - Highly optimized base band processing (including turbo decoder)
+- Multi-RRU support: over the air synchro b/ multi RRU in TDD mode
+- Support for CE-modeA for LTE-M. Limited support for repeatition, single-LTE-M connection, legacy-LTE UE attach is disabled.
 
 ### Performances ###
 
@@ -144,6 +146,7 @@ The X2AP layer is based on **3GPP 36.423** v14.6.0 and implements the following
  - UE Context Release
  - X2 timers (t_reloc_prep, tx2_reloc_overall)
  - Handover Cancel
+ - X2-U interface implemented
 
 ## eNB Advanced Features ##
 
diff --git a/doc/RUNMODEM.md b/doc/RUNMODEM.md
index 1c3636a56fb4e6b6b473777d55e55cd9ea2076f5..71354e663ab738770fbe29ed5bf4bc393aa53a50 100644
--- a/doc/RUNMODEM.md
+++ b/doc/RUNMODEM.md
@@ -14,6 +14,10 @@
 
 After you have [built the softmodem executables](BUILD.md) you can set your default directory  to the build directory `cmake_targets/ran_build/build/` and start testing some use cases. Below, the description of the different oai functionalities should help you choose the oai configuration that suits your need. 
 
+# Basic Simulator
+
+See the [dedicated page](BASIC_SIM.md).
+
 # RF Simulator
 
 The rf simulator is a oai device replacing the radio heads (for example the USRP device). It allows connecting the oai UE and the oai eNodeB through a network interface carrying the time-domain samples, getting rid of over the air unpredictable perturbations. This is the ideal tool to check signal processing algorithms and protocols implementation.
diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c
index c835f38e115a449b6ede31168954873b52219288..f07fb1ad23f13aadeeabfe0b2178655bb4c2722e 100644
--- a/nfapi/oai_integration/nfapi_pnf.c
+++ b/nfapi/oai_integration/nfapi_pnf.c
@@ -83,7 +83,7 @@ nfapi_tx_request_pdu_t *tx_request_pdu[1023][10][10]; // [frame][subframe][max_n
 
 uint8_t tx_pdus[32][8][4096];
 
-
+nfapi_ue_release_request_body_t release_rntis;
 uint16_t phy_antenna_capability_values[] = { 1, 2, 4, 8, 16 };
 
 nfapi_pnf_param_response_t g_pnf_param_resp;
@@ -197,19 +197,19 @@ static pthread_t pnf_start_pthread;
 int nfapitooai_level(int nfapi_level) {
   switch(nfapi_level) {
     case NFAPI_TRACE_ERROR:
-      return LOG_ERR;
+      return OAILOG_ERR;
 
     case NFAPI_TRACE_WARN:
-      return LOG_WARNING;
+      return OAILOG_WARNING;
 
     case NFAPI_TRACE_NOTE:
-      return LOG_INFO;
+      return OAILOG_INFO;
 
     case NFAPI_TRACE_INFO:
-      return LOG_DEBUG;
+      return OAILOG_DEBUG;
   }
 
-  return LOG_ERR;
+  return OAILOG_ERR;
 }
 
 void pnf_nfapi_trace(nfapi_trace_level_t nfapi_level, const char *message, ...) {
@@ -540,7 +540,6 @@ int config_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nfap
   }
 
   if(req->nfapi_config.earfcn.tl.tag == NFAPI_NFAPI_EARFCN_TAG) {
-    fp->eutra_band = 0;
     fp->dl_CarrierFreq = from_earfcn(fp->eutra_band, req->nfapi_config.earfcn.value);
     fp->ul_CarrierFreq = fp->dl_CarrierFreq - (get_uldl_offset(fp->eutra_band) * 1e5);
     num_tlv++;
@@ -896,6 +895,15 @@ int pnf_phy_lbt_dl_config_req(nfapi_pnf_p7_config_t *config, nfapi_lbt_dl_config
   return 0;
 }
 
+int pnf_phy_ue_release_req(nfapi_pnf_p7_config_t* config, nfapi_ue_release_request_t* req) {
+  if (req->ue_release_request_body.number_of_TLVs==0)
+    return -1;
+
+  release_rntis.number_of_TLVs = req->ue_release_request_body.number_of_TLVs;
+  memcpy(&release_rntis.ue_release_request_TLVs_list, req->ue_release_request_body.ue_release_request_TLVs_list, sizeof(nfapi_ue_release_request_TLVs_t)*req->ue_release_request_body.number_of_TLVs);
+  return 0;
+}
+
 int pnf_phy_vendor_ext(nfapi_pnf_p7_config_t *config, nfapi_p7_message_header_t *msg) {
   if(msg->message_id == P7_VENDOR_EXT_REQ) {
     //vendor_ext_p7_req* req = (vendor_ext_p7_req*)msg;
@@ -1024,7 +1032,7 @@ int start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nfapi
   p7_config->hi_dci0_req = &pnf_phy_hi_dci0_req;
   p7_config->tx_req = &pnf_phy_tx_req;
   p7_config->lbt_dl_config_req = &pnf_phy_lbt_dl_config_req;
-
+  p7_config->ue_release_req = &pnf_phy_ue_release_req;
   if (NFAPI_MODE==NFAPI_UE_STUB_PNF) {
     p7_config->dl_config_req = &memcpy_dl_config_req;
     p7_config->ul_config_req = &memcpy_ul_config_req;
@@ -1367,7 +1375,7 @@ void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr,
   printf("%s() PNF\n\n\n\n\n\n", __FUNCTION__);
 
   if(NFAPI_MODE!=NFAPI_UE_STUB_PNF) {
-    nfapi_setmode(NFAPI_PNF);  // PNF!
+    nfapi_setmode(NFAPI_MODE_PNF);  // PNF!
   }
 
   nfapi_pnf_config_t *config = nfapi_pnf_config_create();
diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c
index 64d454e6e7b39758604018e05a7b4392eb60eeb6..a0574221f5b8e1dafddd66bb3bd20064e3c83d72 100644
--- a/nfapi/oai_integration/nfapi_vnf.c
+++ b/nfapi/oai_integration/nfapi_vnf.c
@@ -42,6 +42,7 @@
 
 #include "common/ran_context.h"
 extern RAN_CONTEXT_t RC;
+extern UL_RCC_IND_t  UL_RCC_INFO;
 
 typedef struct {
   uint8_t enabled;
@@ -424,6 +425,40 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   printf("[VNF] RACH_IND eNB:%p sfn_sf:%d number_of_preambles:%d\n", eNB, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.rach_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_rach_indication : num of rach reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.rach_ind[index] = *ind;
+
+    if (ind->rach_indication_body.number_of_preambles > 0)
+      UL_RCC_INFO.rach_ind[index].rach_indication_body.preamble_list = malloc(sizeof(nfapi_preamble_pdu_t)*ind->rach_indication_body.number_of_preambles );
+
+    for (int i=0; i<ind->rach_indication_body.number_of_preambles; i++) {
+      if (ind->rach_indication_body.preamble_list[i].preamble_rel8.tl.tag == NFAPI_PREAMBLE_REL8_TAG) {
+
+        printf("preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
+              i,
+              ind->rach_indication_body.preamble_list[i].preamble_rel8.rnti,
+              ind->rach_indication_body.preamble_list[i].preamble_rel8.preamble,
+              ind->rach_indication_body.preamble_list[i].preamble_rel8.timing_advance
+              );
+      }
+      if(ind->rach_indication_body.preamble_list[i].preamble_rel13.tl.tag == NFAPI_PREAMBLE_REL13_TAG) {
+        printf("RACH PREAMBLE REL13 present\n");
+      }
+
+      UL_RCC_INFO.rach_ind[index].rach_indication_body.preamble_list[i] = ind->rach_indication_body.preamble_list[i];
+    }
+  }else{
   eNB->UL_INFO.rach_ind = *ind;
   eNB->UL_INFO.rach_ind.rach_indication_body.preamble_list = eNB->preamble_list;
 
@@ -443,7 +478,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
 
     eNB->preamble_list[i] = ind->rach_indication_body.preamble_list[i];
   }
-
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_rach_ind(p7_vnf->mac, ind);
@@ -454,13 +489,33 @@ int phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indicatio
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_harqs:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->harq_indication_body.number_of_harqs);
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.harq_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_harq_indication : num of harq reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.harq_ind[index] = *ind;
+
+    if (ind->harq_indication_body.number_of_harqs > 0)
+      UL_RCC_INFO.harq_ind[index].harq_indication_body.harq_pdu_list = malloc(sizeof(nfapi_harq_indication_pdu_t)*ind->harq_indication_body.number_of_harqs );
+    for (int i=0; i<ind->harq_indication_body.number_of_harqs; i++) {
+        memcpy(&UL_RCC_INFO.harq_ind[index].harq_indication_body.harq_pdu_list[i], &ind->harq_indication_body.harq_pdu_list[i], sizeof(nfapi_harq_indication_pdu_t));
+    }
+  }else{
   eNB->UL_INFO.harq_ind = *ind;
   eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list;
 
   for (int i=0; i<ind->harq_indication_body.number_of_harqs; i++) {
     memcpy(&eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i], &ind->harq_indication_body.harq_pdu_list[i], sizeof(eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i]));
   }
-
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_harq_ind(p7_vnf->mac, ind);
@@ -470,6 +525,37 @@ int phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indicatio
 int phy_crc_indication(struct nfapi_vnf_p7_config *config, nfapi_crc_indication_t *ind) {
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.crc_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+      }
+      if(UL_RCC_INFO.rx_ind[i].sfn_sf == ind->sfn_sf){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_crc_indication : num of crc reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.crc_ind[index] = *ind;
+
+    if (ind->crc_indication_body.number_of_crcs > 0)
+      UL_RCC_INFO.crc_ind[index].crc_indication_body.crc_pdu_list = malloc(sizeof(nfapi_crc_indication_pdu_t)*ind->crc_indication_body.number_of_crcs );
+
+    for (int i=0; i<ind->crc_indication_body.number_of_crcs; i++) {
+      memcpy(&UL_RCC_INFO.crc_ind[index].crc_indication_body.crc_pdu_list[i], &ind->crc_indication_body.crc_pdu_list[i], sizeof(ind->crc_indication_body.crc_pdu_list[0]));
+
+      LOG_D(MAC, "%s() NFAPI SFN/SF:%d CRC_IND:number_of_crcs:%u UL_INFO:crcs:%d PDU[%d] rnti:%04x UL_INFO:rnti:%04x\n",
+          __FUNCTION__,
+          NFAPI_SFNSF2DEC(ind->sfn_sf), ind->crc_indication_body.number_of_crcs, UL_RCC_INFO.crc_ind[index].crc_indication_body.number_of_crcs,
+          i,
+          ind->crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti,
+          UL_RCC_INFO.crc_ind[index].crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti);
+    }
+  }else{
   eNB->UL_INFO.crc_ind = *ind;
   nfapi_crc_indication_t *dest_ind = &eNB->UL_INFO.crc_ind;
   nfapi_crc_indication_pdu_t *dest_pdu_list = eNB->crc_pdu_list;
@@ -489,7 +575,7 @@ int phy_crc_indication(struct nfapi_vnf_p7_config *config, nfapi_crc_indication_
           ind->crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti,
           eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti);
   }
-
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_crc_ind(p7_vnf->mac, ind);
@@ -504,6 +590,52 @@ int phy_rx_indication(struct nfapi_vnf_p7_config *config, nfapi_rx_indication_t
   }
 
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.rx_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+      }
+      if(UL_RCC_INFO.crc_ind[i].sfn_sf == ind->sfn_sf){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_rx_indication : num of rx reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.rx_ind[index] = *ind;
+
+    if (ind->rx_indication_body.number_of_pdus > 0)
+      UL_RCC_INFO.rx_ind[index].rx_indication_body.rx_pdu_list = malloc(sizeof(nfapi_rx_indication_pdu_t)*ind->rx_indication_body.number_of_pdus );
+
+    for (int i=0; i<ind->rx_indication_body.number_of_pdus; i++) {
+      nfapi_rx_indication_pdu_t *dest_pdu = &UL_RCC_INFO.rx_ind[index].rx_indication_body.rx_pdu_list[i];
+      nfapi_rx_indication_pdu_t *src_pdu = &ind->rx_indication_body.rx_pdu_list[i];
+
+      memcpy(dest_pdu, src_pdu, sizeof(*src_pdu));
+      // DJP - TODO FIXME - intentional memory leak
+      if(dest_pdu->rx_indication_rel8.length > 0){
+        dest_pdu->data = malloc(dest_pdu->rx_indication_rel8.length);
+        memcpy(dest_pdu->data, src_pdu->data, dest_pdu->rx_indication_rel8.length);
+      }else{
+        dest_pdu->data = NULL;
+      }
+
+      LOG_D(PHY, "%s() NFAPI SFN/SF:%d PDUs:%d [PDU:%d] handle:%d rnti:%04x length:%d offset:%d ul_cqi:%d ta:%d data:%p\n",
+          __FUNCTION__,
+          NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rx_indication_body.number_of_pdus, i,
+          dest_pdu->rx_ue_information.handle,
+          dest_pdu->rx_ue_information.rnti,
+          dest_pdu->rx_indication_rel8.length,
+          dest_pdu->rx_indication_rel8.offset,
+          dest_pdu->rx_indication_rel8.ul_cqi,
+          dest_pdu->rx_indication_rel8.timing_advance,
+          dest_pdu->data
+          );
+    }
+  }else{
   nfapi_rx_indication_t *dest_ind = &eNB->UL_INFO.rx_ind;
   nfapi_rx_indication_pdu_t *dest_pdu_list = eNB->rx_pdu_list;
   *dest_ind = *ind;
@@ -528,7 +660,7 @@ int phy_rx_indication(struct nfapi_vnf_p7_config *config, nfapi_rx_indication_t
           dest_pdu->data
          );
   }
-
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_rx_ind(p7_vnf->mac, ind);
@@ -544,6 +676,32 @@ int phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d srs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->sr_indication_body.number_of_srs);
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.sr_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_sr_indication : num of sr reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.sr_ind[index] = *ind;
+    LOG_D(MAC,"%s() UL_INFO[%d].sr_ind.sr_indication_body.number_of_srs:%d\n", __FUNCTION__, index, eNB->UL_INFO.sr_ind.sr_indication_body.number_of_srs);
+    if (ind->sr_indication_body.number_of_srs > 0)
+      UL_RCC_INFO.sr_ind[index].sr_indication_body.sr_pdu_list = malloc(sizeof(nfapi_sr_indication_pdu_t)*ind->sr_indication_body.number_of_srs );
+
+    for (int i=0; i<ind->sr_indication_body.number_of_srs; i++) {
+        nfapi_sr_indication_pdu_t *dest_pdu = &UL_RCC_INFO.sr_ind[index].sr_indication_body.sr_pdu_list[i];
+        nfapi_sr_indication_pdu_t *src_pdu = &ind->sr_indication_body.sr_pdu_list[i];
+
+        LOG_D(MAC, "SR_IND[PDU:%d %d][rnti:%x cqi:%d channel:%d]\n", index, i, src_pdu->rx_ue_information.rnti, src_pdu->ul_cqi_information.ul_cqi, src_pdu->ul_cqi_information.channel);
+
+        memcpy(dest_pdu, src_pdu, sizeof(*src_pdu));
+    }
+  }else{
   nfapi_sr_indication_t *dest_ind = &eNB->UL_INFO.sr_ind;
   nfapi_sr_indication_pdu_t *dest_pdu_list = eNB->sr_pdu_list;
   *dest_ind = *ind;
@@ -556,7 +714,7 @@ int phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t
     LOG_D(MAC, "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", i, src_pdu->rx_ue_information.rnti, src_pdu->ul_cqi_information.ul_cqi, src_pdu->ul_cqi_information.channel);
     memcpy(dest_pdu, src_pdu, sizeof(*src_pdu));
   }
-
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_sr_ind(p7_vnf->mac, ind);
@@ -569,7 +727,48 @@ int phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_cqis:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->cqi_indication_body.number_of_cqis);
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
-  eNB->UL_INFO.cqi_ind = ind->cqi_indication_body;
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    int8_t index = -1;
+    for(uint8_t i= 0;i< NUM_NFPAI_SUBFRAME;i++){
+      if((UL_RCC_INFO.cqi_ind[i].header.message_id == 0) && (index == -1)){
+        index = i;
+        break;
+      }
+    }
+    if(index == -1){
+      LOG_E(MAC,"phy_cqi_indication : num of cqi reach max \n");
+      return 0;
+    }
+    UL_RCC_INFO.cqi_ind[index] = *ind;
+    if (ind->cqi_indication_body.number_of_cqis > 0){
+      UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_pdu_list = malloc(sizeof(nfapi_cqi_indication_pdu_t)*ind->cqi_indication_body.number_of_cqis );
+      UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_raw_pdu_list = malloc(sizeof(nfapi_cqi_indication_raw_pdu_t)*ind->cqi_indication_body.number_of_cqis );
+    }
+    for (int i=0; i<ind->cqi_indication_body.number_of_cqis; i++) {
+        nfapi_cqi_indication_pdu_t *src_pdu = &ind->cqi_indication_body.cqi_pdu_list[i];
+        LOG_D(MAC, "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", i, src_pdu->rx_ue_information.rnti,
+                    src_pdu->ul_cqi_information.ul_cqi, src_pdu->ul_cqi_information.channel);
+        memcpy(&UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_pdu_list[i],
+               src_pdu, sizeof(nfapi_cqi_indication_pdu_t));
+
+        memcpy(&UL_RCC_INFO.cqi_ind[index].cqi_indication_body.cqi_raw_pdu_list[i],
+               &ind->cqi_indication_body.cqi_raw_pdu_list[i], sizeof(nfapi_cqi_indication_raw_pdu_t));
+    }
+  }else{
+  nfapi_cqi_indication_t *dest_ind = &eNB->UL_INFO.cqi_ind;
+  *dest_ind = *ind;
+  dest_ind->cqi_indication_body.cqi_pdu_list = ind->cqi_indication_body.cqi_pdu_list;
+  dest_ind->cqi_indication_body.cqi_raw_pdu_list = ind->cqi_indication_body.cqi_raw_pdu_list;
+  for(int i=0; i<ind->cqi_indication_body.number_of_cqis; i++) {
+    nfapi_cqi_indication_pdu_t *src_pdu = &ind->cqi_indication_body.cqi_pdu_list[i];
+    LOG_D(MAC, "SR_IND[PDU:%d][rnti:%x cqi:%d channel:%d]\n", i, src_pdu->rx_ue_information.rnti,
+                src_pdu->ul_cqi_information.ul_cqi, src_pdu->ul_cqi_information.channel);
+    memcpy(&dest_ind->cqi_indication_body.cqi_pdu_list[i],
+           src_pdu, sizeof(nfapi_cqi_indication_pdu_t));
+    memcpy(&dest_ind->cqi_indication_body.cqi_raw_pdu_list[i],
+           &ind->cqi_indication_body.cqi_raw_pdu_list[i], sizeof(nfapi_cqi_indication_raw_pdu_t));
+  }
+  }
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
   return 1;
 }
@@ -947,6 +1146,7 @@ void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port) {
   config->deallocate_p4_p5_vendor_ext = &vnf_deallocate_p4_p5_vendor_ext;
   config->codec_config.allocate = &vnf_allocate;
   config->codec_config.deallocate = &vnf_deallocate;
+  memset(&UL_RCC_INFO,0,sizeof(UL_RCC_IND_t));
   NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Creating VNF NFAPI start thread %s\n", __FUNCTION__);
   pthread_create(&vnf_start_pthread, NULL, (void *)&vnf_start_thread, config);
   NFAPI_TRACE(NFAPI_TRACE_INFO, "[VNF] Created VNF NFAPI start thread %s\n", __FUNCTION__);
@@ -1040,3 +1240,21 @@ int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) {
 
   return retval;
 }
+
+int oai_nfapi_ue_release_req(nfapi_ue_release_request_t *release_req){
+    if(release_req->ue_release_request_body.number_of_TLVs <= 0)
+        return 0;
+    nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
+
+    release_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
+    release_req->header.message_id = NFAPI_UE_RELEASE_REQUEST;
+    release_req->ue_release_request_body.tl.tag = NFAPI_UE_RELEASE_BODY_TAG;
+
+    int retval = nfapi_vnf_p7_ue_release_req(p7_config, release_req);
+    if (retval!=0) {
+      LOG_E(PHY, "%s() Problem sending retval:%d\n", __FUNCTION__, retval);
+    } else {
+        release_req->ue_release_request_body.number_of_TLVs = 0;
+    }
+    return retval;
+}
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
index 901b4956c4ccdf78ed55b464197c68b508bc6a11..2c31af4bc1a3cae039498cd1ad4d17f177b2c54c 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
@@ -150,6 +150,8 @@ typedef enum {
 	NFAPI_LBT_DL_INDICATION,
 	NFAPI_NB_HARQ_INDICATION,
 	NFAPI_NRACH_INDICATION,
+	NFAPI_UE_RELEASE_REQUEST,
+	NFAPI_UE_RELEASE_RESPONSE,
 
 	NFAPI_PNF_PARAM_REQUEST = 0x0100,
 	NFAPI_PNF_PARAM_RESPONSE,
@@ -2424,6 +2426,19 @@ typedef struct {
 } nfapi_tx_request_body_t;
 #define NFAPI_TX_REQUEST_BODY_TAG 0x2022
 
+#define  NFAPI_RELEASE_MAX_RNTI  256
+typedef struct {
+    uint32_t handle;
+    uint16_t rnti;
+} nfapi_ue_release_request_TLVs_t;
+
+typedef struct {
+    nfapi_tl_t tl;
+    uint16_t number_of_TLVs;
+    nfapi_ue_release_request_TLVs_t ue_release_request_TLVs_list[NFAPI_RELEASE_MAX_RNTI];
+} nfapi_ue_release_request_body_t;
+#define NFAPI_UE_RELEASE_BODY_TAG 0x2068
+
 // P7 Message Structures
 typedef struct {
 	nfapi_p7_message_header_t header;
@@ -3450,6 +3465,19 @@ typedef struct {
 	nfapi_vendor_extension_tlv_t vendor_extension;
 } nfapi_error_indication_t;
 
+typedef struct {
+    nfapi_p7_message_header_t header;
+    uint16_t sfn_sf;
+    nfapi_ue_release_request_body_t ue_release_request_body;
+    nfapi_vendor_extension_tlv_t vendor_extension;
+} nfapi_ue_release_request_t;
+
+typedef struct {
+	nfapi_p7_message_header_t header;
+	uint32_t error_code;
+	nfapi_vendor_extension_tlv_t vendor_extension;
+} nfapi_ue_release_response_t;
+
 // 
 // P4 Messages
 // 
diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
old mode 100644
new mode 100755
index 2daf1450c852c9bbb7b5ff1003e308903b494ba4..be9205d035ea075803e8e548925f1c8f3a9f1e8c
--- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
+++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
@@ -81,13 +81,19 @@ void* nfapi_p7_allocate(size_t size, nfapi_p7_codec_config_t* config)
 	if(size == 0)
 		return 0;
 
+       void* buffer_p = NULL;
 	if(config && config->allocate)
 	{
-		return (config->allocate)(size);
+               buffer_p = (config->allocate)(size);
+               if(buffer_p != NULL){
+               memset(buffer_p,0,size);
+               }
+               return buffer_p;
 	}
 	else
 	{
-		return calloc(1, size);
+               buffer_p = calloc(1, size);
+               return buffer_p;
 	}
 }
 
@@ -1577,7 +1583,43 @@ static uint8_t pack_tx_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *e
 
         return x && y && z;
 }
-
+
+static uint8_t pack_release_request_body_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end)
+{
+  nfapi_ue_release_request_body_t* value = (nfapi_ue_release_request_body_t*)tlv;
+  if(push16(value->number_of_TLVs, ppWritePackedMsg, end) == 0){
+    return 0;
+  }
+
+  uint8_t j;
+  uint16_t num = value->number_of_TLVs;
+  for(j = 0; j < num; ++j){
+    if(push16(value->ue_release_request_TLVs_list[j].rnti, ppWritePackedMsg, end) == 0){
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static uint8_t pack_ue_release_request(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config)
+{
+  nfapi_ue_release_request_t *pNfapiMsg = (nfapi_ue_release_request_t*)msg;
+  int x = push16(pNfapiMsg->sfn_sf, ppWritePackedMsg, end);
+  int y = pack_tlv(NFAPI_UE_RELEASE_BODY_TAG, &pNfapiMsg->ue_release_request_body, ppWritePackedMsg, end, &pack_release_request_body_value);
+  int z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config);
+  return x && y && z;
+}
+
+static uint8_t pack_ue_release_response(void *msg, uint8_t **ppWritePackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config)
+{
+
+	nfapi_ue_release_response_t *pNfapiMsg = (nfapi_ue_release_response_t*)msg;
+
+	int x = push32(pNfapiMsg->error_code, ppWritePackedMsg, end);
+	int z = pack_p7_vendor_extension_tlv(pNfapiMsg->vendor_extension, ppWritePackedMsg, end, config);
+	return x && z;
+}
+
 static uint8_t pack_rx_ue_information_value(void* tlv, uint8_t **ppWritePackedMsg, uint8_t *end)
 {
 	nfapi_rx_ue_information* value = (nfapi_rx_ue_information*)tlv;
@@ -2665,7 +2707,15 @@ int nfapi_p7_message_pack(void *pMessageBuf, void *pPackedBuf, uint32_t packedBu
                         //NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() NFAPI_TX_REQUEST\n", __FUNCTION__);
 			result = pack_tx_request(pMessageHeader, &pWritePackedMessage, end, config);
 			break;
-
+
+		case NFAPI_UE_RELEASE_REQUEST:
+			result =pack_ue_release_request(pMessageHeader, &pWritePackedMessage, end, config);
+			break;
+
+		case NFAPI_UE_RELEASE_RESPONSE:
+			result =pack_ue_release_response(pMessageHeader, &pWritePackedMessage, end, config);
+			break;
+
 		case NFAPI_HARQ_INDICATION:
 			result = pack_harq_indication(pMessageHeader, &pWritePackedMessage, end, config);
 			break;
@@ -4479,7 +4529,55 @@ static uint8_t unpack_tx_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *
 
 	return 1;
 }
-
+
+static uint8_t unpack_ue_release_request(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config)
+{
+    uint8_t proceed = 1;
+    nfapi_ue_release_request_t *pNfapiMsg = (nfapi_ue_release_request_t*)msg;
+
+    if(pull16(ppReadPackedMsg, &pNfapiMsg->sfn_sf, end) == 0)
+        return 0;
+
+    while (((uint8_t*)(*ppReadPackedMsg) < end) && proceed)
+    {
+        nfapi_tl_t generic_tl;
+        if(unpack_tl(ppReadPackedMsg, &generic_tl, end) == 0)
+            return 0;
+
+        switch(generic_tl.tag)
+        {
+            case NFAPI_UE_RELEASE_BODY_TAG:
+            {
+                pNfapiMsg->ue_release_request_body.tl = generic_tl;
+                if( pull16(ppReadPackedMsg, &pNfapiMsg->ue_release_request_body.number_of_TLVs, end) == 0)
+                    return 0;
+
+                if(pNfapiMsg->ue_release_request_body.number_of_TLVs > NFAPI_RELEASE_MAX_RNTI)
+                {
+                    NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s number of relese rnti's exceed maxium (count:%d max:%d)\n", __FUNCTION__, pNfapiMsg->ue_release_request_body.number_of_TLVs, NFAPI_RELEASE_MAX_RNTI);
+                    return 0;
+                } else {
+                    uint8_t j;
+                    uint16_t num = pNfapiMsg->ue_release_request_body.number_of_TLVs;
+                    for(j = 0; j < num; ++j){
+                    		if(pull16(ppReadPackedMsg, &pNfapiMsg->ue_release_request_body.ue_release_request_TLVs_list[j].rnti, end) == 0){
+                    				return 0;
+                    		}
+                    }
+                }
+            }
+            break;
+            default:
+            {
+              NFAPI_TRACE(NFAPI_TRACE_ERROR, "unpack_ue_release_request FIXME : Invalid type %d \n", generic_tl.tag );
+            }
+            break;
+        };
+    }
+
+    return 1;
+}
+
 static uint8_t unpack_harq_indication_tdd_harq_data_bundling(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end)
 {
 	nfapi_harq_indication_tdd_harq_data_bundling_t* value = (nfapi_harq_indication_tdd_harq_data_bundling_t*)tlv;
@@ -5727,7 +5825,18 @@ static uint8_t unpack_nrach_indication_rel13_value(void *tlv, uint8_t **ppReadPa
 			pull8(ppReadPackedMsg, &value->nrach_ce_level, end));
 }
 
-
+static uint8_t unpack_ue_release_resp(uint8_t **ppReadPackedMsg, uint8_t *end, void *msg, nfapi_p7_codec_config_t* config)
+{
+	nfapi_ue_release_response_t *pNfapiMsg = (nfapi_ue_release_response_t*)msg;
+	if(pull32(ppReadPackedMsg, &pNfapiMsg->error_code, end) == 0){
+		return 0;
+	}
+	else{
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "ue_release_response:error_code = %d\n", pNfapiMsg->error_code);
+	}
+	return 1;
+}
+
 static uint8_t unpack_nrach_indication_body_value(void* tlv, uint8_t **ppReadPackedMsg, uint8_t *end, nfapi_p7_codec_config_t* config)
 {
 	nfapi_nrach_indication_body_t* value = (nfapi_nrach_indication_body_t*)tlv;
@@ -5940,7 +6049,17 @@ static int check_unpack_length(nfapi_message_id_e msgId, uint32_t unpackedBufLen
 			if (unpackedBufLen >= sizeof(nfapi_timing_info_t))
 				retLen = sizeof(nfapi_timing_info_t);
 			break;
-
+
+		case NFAPI_UE_RELEASE_REQUEST:
+			if (unpackedBufLen >= sizeof(nfapi_ue_release_request_t))
+				retLen = sizeof(nfapi_ue_release_request_t);
+			break;
+
+		case NFAPI_UE_RELEASE_RESPONSE:
+			if (unpackedBufLen >= sizeof(nfapi_ue_release_response_t))
+				retLen = sizeof(nfapi_ue_release_response_t);
+			break;
+
 		default:
 			NFAPI_TRACE(NFAPI_TRACE_ERROR, "Unknown message ID %d\n", msgId);
 			break;
@@ -6060,7 +6179,14 @@ int nfapi_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUn
 			else
 				return -1;
 			break;
-
+
+		case NFAPI_UE_RELEASE_REQUEST:
+			if (check_unpack_length(NFAPI_UE_RELEASE_REQUEST, unpackedBufLen))
+				result = unpack_ue_release_request(&pReadPackedMessage,  end, pMessageHeader, config);
+			else
+				return -1;
+			break;
+
 		case NFAPI_HARQ_INDICATION:
 			if (check_unpack_length(NFAPI_HARQ_INDICATION, unpackedBufLen))
 				result = unpack_harq_indication(&pReadPackedMessage,  end, pMessageHeader, config);
@@ -6158,7 +6284,14 @@ int nfapi_p7_message_unpack(void *pMessageBuf, uint32_t messageBufLen, void *pUn
 			else
 				return -1;
 			break;
-
+
+		case NFAPI_UE_RELEASE_RESPONSE:
+			if (check_unpack_length(NFAPI_UE_RELEASE_RESPONSE, unpackedBufLen))
+				result = unpack_ue_release_resp(&pReadPackedMessage,  end, pMessageHeader, config);
+			else
+				return -1;
+			break;
+
 		default:
 
 			if(pMessageHeader->message_id >= NFAPI_VENDOR_EXT_MSG_MIN && 
diff --git a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h
index b25caf28760ff6e06ef4607b2d49f7e1a46e1de5..8d17416a418a98a822494726b1f1261aa1f66e54 100644
--- a/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h
+++ b/nfapi/open-nFAPI/pnf/public_inc/nfapi_pnf_interface.h
@@ -546,7 +546,7 @@ typedef struct
 	nfapi_hi_dci0_request_t* hi_dci0_req;
 	nfapi_tx_request_t* tx_req;
 	nfapi_lbt_dl_config_request_t* lbt_dl_config_req;
-
+	nfapi_ue_release_request_t* ue_release_req;
 } nfapi_pnf_p7_subframe_buffer_t;
 
 typedef struct nfapi_pnf_p7_config nfapi_pnf_p7_config_t;
@@ -652,6 +652,17 @@ typedef struct nfapi_pnf_p7_config
 	 * \return not currently used
 	 */
 	int (*lbt_dl_config_req)(nfapi_pnf_p7_config_t* config, nfapi_lbt_dl_config_request_t* req);
+
+    /*! A callback for the UE_RELEASE_REQ.request
+     * \param config A poiner to the PNF P7 config
+     * \param req A pointer to the release rnti request message structure
+     * \return not currently used
+     *
+     * The release request contains pointers to the release rnti to be sent. In the case that the FAPI interface
+     * will 'keep' the pointers until they are transmitted the callee should set the pointers in the req to 0
+     * and then use the p7 codec config free function to release the rnti when appropriate.
+     */
+    int (*ue_release_req)(nfapi_pnf_p7_config_t* config, nfapi_ue_release_request_t* req);
 	
 	/*! A callback for vendor extension messages
 	 * \param config A poiner to the PNF P7 config
@@ -796,6 +807,7 @@ int nfapi_pnf_p7_nrach_ind(nfapi_pnf_p7_config_t* config, nfapi_nrach_indication
  */
 int nfapi_pnf_p7_vendor_extension(nfapi_pnf_p7_config_t* config, nfapi_p7_message_header_t* msg);
 
+int nfapi_pnf_ue_release_resp(nfapi_pnf_p7_config_t* config, nfapi_ue_release_response_t* resp);
 #if defined(__cplusplus)
 }
 #endif
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
index 81abed81a95b27935df7b19bb21ddb8b5c25f97d..944673037500c6f8478b3352f0998f28e840cc07 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
@@ -36,7 +36,7 @@ extern uint16_t sf_ahead;
 
 void add_sf(uint16_t *frameP, uint16_t *subframeP, int offset)
 {
-    *frameP    = *frameP + ((*subframeP + offset) / 10);
+    *frameP    = (*frameP + ((*subframeP + offset) / 10))%1024;
 
     *subframeP = ((*subframeP + offset) % 10);
 }
@@ -241,6 +241,16 @@ void deallocate_nfapi_lbt_dl_config_request(nfapi_lbt_dl_config_request_t* req,
 	pnf_p7_free(pnf_p7, req);
 }
 
+nfapi_ue_release_request_t* allocate_nfapi_ue_release_request(pnf_p7_t* pnf_p7)
+{
+    return pnf_p7_malloc(pnf_p7, sizeof(nfapi_ue_release_request_t));
+}
+
+void deallocate_nfapi_ue_release_request(nfapi_ue_release_request_t* req, pnf_p7_t* pnf_p7)
+{
+	pnf_p7_free(pnf_p7, req);
+}
+
 pnf_p7_rx_message_t* pnf_p7_rx_reassembly_queue_add_segment(pnf_p7_t* pnf_p7, pnf_p7_rx_reassembly_queue_t* queue, uint32_t rx_hr_time, uint16_t sequence_number, uint16_t segment_number, uint8_t m, uint8_t* data, uint16_t data_len)
 {
 	pnf_p7_rx_message_t* msg = 0;
@@ -720,6 +730,21 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf)
 				}
 			}
 
+			if(tx_subframe_buffer->ue_release_req != 0)
+			{
+				if(pnf_p7->_public.ue_release_req)
+					(pnf_p7->_public.ue_release_req)(&(pnf_p7->_public), tx_subframe_buffer->ue_release_req);
+			}
+			else
+			{
+				//send dummy
+				if(pnf_p7->_public.ue_release_req && pnf_p7->_public.dummy_subframe.ue_release_req)
+				{
+					pnf_p7->_public.dummy_subframe.ue_release_req->sfn_sf = sfn_sf_tx;
+					(pnf_p7->_public.ue_release_req)(&(pnf_p7->_public), pnf_p7->_public.dummy_subframe.ue_release_req);
+				}
+			}
+
                         if(tx_subframe_buffer->dl_config_req != 0)
                         {
                           deallocate_nfapi_dl_config_request(tx_subframe_buffer->dl_config_req, pnf_p7);
@@ -735,6 +760,10 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf)
                           deallocate_nfapi_hi_dci0_request(tx_subframe_buffer->hi_dci0_req, pnf_p7);
                           tx_subframe_buffer->hi_dci0_req = 0;
                         }
+                        if(tx_subframe_buffer->ue_release_req != 0){
+                            deallocate_nfapi_ue_release_request(tx_subframe_buffer->ue_release_req, pnf_p7);
+                            tx_subframe_buffer->ue_release_req = 0;
+                        }
                 }
 		else
 		{
@@ -799,7 +828,7 @@ int pnf_p7_subframe_ind(pnf_p7_t* pnf_p7, uint16_t phy_id, uint16_t sfn_sf)
                         }
                 } // sfn_sf match
 
-                if (subframe_buffer->dl_config_req == 0 && subframe_buffer->tx_req == 0 && subframe_buffer->ul_config_req == 0 && subframe_buffer->lbt_dl_config_req == 0)
+                if (subframe_buffer->dl_config_req == 0 && subframe_buffer->tx_req == 0 && subframe_buffer->ul_config_req == 0 && subframe_buffer->lbt_dl_config_req == 0 && subframe_buffer->ue_release_req == 0)
                 {
                   memset(&(pnf_p7->subframe_buffer[buffer_index]), 0, sizeof(nfapi_pnf_p7_subframe_buffer_t));
                   pnf_p7->subframe_buffer[buffer_index].sfn_sf = -1;
@@ -1310,6 +1339,80 @@ void pnf_handle_p7_vendor_extension(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pn
 	
 }
 
+void pnf_handle_ue_release_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7)
+{
+    nfapi_ue_release_request_t* req = allocate_nfapi_ue_release_request(pnf_p7);
+    if(req == NULL)
+    {
+        NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to alloced nfapi_ue_release_request structure\n");
+        return;
+    }
+
+    int unpack_result = nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_ue_release_request_t), &pnf_p7->_public.codec_config);
+    if(unpack_result == 0)
+    {
+        if(pthread_mutex_lock(&(pnf_p7->mutex)) != 0)
+        {
+            NFAPI_TRACE(NFAPI_TRACE_ERROR, "failed to lock mutex\n");
+            return;
+        }
+
+        if(is_p7_request_in_window(req->sfn_sf, "ue_release_request", pnf_p7))
+        {
+            uint32_t sfn_sf_dec = NFAPI_SFNSF2DEC(req->sfn_sf);
+            uint8_t buffer_index = sfn_sf_dec % pnf_p7->_public.subframe_buffer_size;
+
+            struct timespec t;
+            clock_gettime(CLOCK_MONOTONIC, &t);
+
+            NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() %ld.%09ld POPULATE UE_RELEASE_REQ sfn_sf:%d buffer_index:%d\n", __FUNCTION__, t.tv_sec, t.tv_nsec, sfn_sf_dec, buffer_index);
+
+            if (0 && NFAPI_SFNSF2DEC(req->sfn_sf)%100==0) NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() UE_RELEASE_REQ.req sfn_sf:%d rntis:%d - UE_RELEASE_REQ is within window\n",
+                            __FUNCTION__,
+                            NFAPI_SFNSF2DEC(req->sfn_sf),
+                            req->ue_release_request_body.number_of_TLVs);
+
+            if(pnf_p7->subframe_buffer[buffer_index].ue_release_req != 0)
+            {
+                deallocate_nfapi_ue_release_request(pnf_p7->subframe_buffer[buffer_index].ue_release_req, pnf_p7);
+            }
+
+            pnf_p7->subframe_buffer[buffer_index].sfn_sf = req->sfn_sf;
+            pnf_p7->subframe_buffer[buffer_index].ue_release_req = req;
+
+            pnf_p7->stats.tx_ontime++;
+        }
+        else
+        {
+            NFAPI_TRACE(NFAPI_TRACE_INFO,"%s() UE_RELEASE_REQUEST Request is outside of window REQ:SFN_SF:%d CURR:SFN_SF:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(req->sfn_sf), NFAPI_SFNSF2DEC(pnf_p7->sfn_sf));
+
+            deallocate_nfapi_ue_release_request(req, pnf_p7);
+            if(pnf_p7->_public.timing_info_mode_aperiodic)
+            {
+                pnf_p7->timing_info_aperiodic_send = 1;
+            }
+
+            pnf_p7->stats.tx_late++;
+        }
+        nfapi_ue_release_response_t resp;
+        memset(&resp, 0, sizeof(resp));
+        resp.header.message_id = NFAPI_UE_RELEASE_RESPONSE;
+        resp.header.phy_id = req->header.phy_id;
+        resp.error_code = NFAPI_MSG_OK;
+        nfapi_pnf_ue_release_resp(&(pnf_p7->_public), &resp);
+        NFAPI_TRACE(NFAPI_TRACE_INFO, "do ue_release_response\n");
+
+        if(pthread_mutex_unlock(&(pnf_p7->mutex)) != 0)
+        {
+            NFAPI_TRACE(NFAPI_TRACE_ERROR, "failed to unlock mutex\n");
+            return;
+        }
+    }
+    else
+    {
+        deallocate_nfapi_ue_release_request(req, pnf_p7);
+    }
+}
 
 uint32_t calculate_t2(uint32_t now_time_hr, uint16_t sfn_sf, uint32_t sf_start_time_hr)
 {
@@ -1445,7 +1548,11 @@ void pnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7,
 		case NFAPI_LBT_DL_CONFIG_REQUEST:
 			pnf_handle_lbt_dl_config_request(pRecvMsg, recvMsgLen, pnf_p7);
 			break;
-		
+
+		case NFAPI_UE_RELEASE_REQUEST:
+			pnf_handle_ue_release_request(pRecvMsg, recvMsgLen, pnf_p7);
+			break;
+
 		default:
 			{
 				if(header.message_id >= NFAPI_VENDOR_EXT_MSG_MIN &&
@@ -1536,7 +1643,7 @@ void pnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7,  ui
 					NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate PNF_P7 reassemby buffer len:%d\n", length);
 					return;
 				}
-
+                                memset(pnf_p7->reassemby_buffer, 0, length);
 				pnf_p7->reassemby_buffer_size = length;
 			}
 			
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
index 74de5e5d785e5d251dfcc65133fd2154219b7641..24e73ae9b3c6fb54efd362b6ed855a941b6cb932 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
@@ -223,3 +223,15 @@ int nfapi_pnf_p7_vendor_extension(nfapi_pnf_p7_config_t* config, nfapi_p7_messag
 	return pnf_p7_pack_and_send_p7_message(_this, msg, 0);
 }
 
+int nfapi_pnf_ue_release_resp(nfapi_pnf_p7_config_t* config, nfapi_ue_release_response_t* resp)
+{
+	if (config == NULL || resp == NULL)
+	{
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__);
+		return -1;
+	}
+
+	pnf_p7_t* _this = (pnf_p7_t*)(config);
+
+	return pnf_p7_pack_and_send_p7_message(_this, &(resp->header), sizeof(nfapi_ue_release_response_t));
+}
diff --git a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
index 525490629ac23f1d24baaa5842f3d5d29d653762..5d463afdaea976eef6800be0f5912e36ac462a56 100644
--- a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
+++ b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
@@ -990,6 +990,15 @@ int nfapi_vnf_p7_lbt_dl_config_req(nfapi_vnf_p7_config_t* config, nfapi_lbt_dl_c
  */
 int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* msg);
 
+/*! Send the RELEASE_RNTI.request
+ *  \param config A pointer to the vnf p7 configuration
+ *  \param req A data structure for the decoded RELEASE_RNTI.request.
+ *  \return A status value. 0 equal success, -1 indicates failure
+ *
+ *  The caller is responsiable for memory management of any pointers set in the req, which
+ *  may be released after this function call has returned or at a later pointer
+ */
+int nfapi_vnf_p7_ue_release_req(nfapi_vnf_p7_config_t* config, nfapi_ue_release_request_t* req);
 #if defined(__cplusplus)
 }
 #endif
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
index 4b7acabec3637af74e3d95f8d9d805ea3337b118..985a6f830a6835db67f38ff587c6e0d86f5a99b4 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
@@ -822,6 +822,28 @@ void vnf_handle_nrach_indication(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p
 	}
 }
 
+void vnf_handle_ue_release_resp(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
+{
+
+	// ensure it's valid
+	if (pRecvMsg == NULL || vnf_p7 == NULL)
+	{
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: NULL parameters\n", __FUNCTION__);
+	}
+	else
+	{
+		nfapi_ue_release_response_t resp;
+
+		if(nfapi_p7_message_unpack(pRecvMsg, recvMsgLen, &resp, sizeof(resp), &vnf_p7->_public.codec_config) < 0)
+		{
+			NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s: Failed to unpack message\n", __FUNCTION__);
+		}
+
+
+		vnf_p7_codec_free(vnf_p7, resp.vendor_extension);
+	}
+}
+
 void vnf_handle_p7_vendor_extension(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7, uint16_t message_id)
 {
 	if (pRecvMsg == NULL || vnf_p7 == NULL)
@@ -1334,6 +1356,10 @@ void vnf_dispatch_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
 			vnf_handle_nrach_indication(pRecvMsg, recvMsgLen, vnf_p7);
 			break;			
 
+		case NFAPI_UE_RELEASE_RESPONSE:
+			vnf_handle_ue_release_resp(pRecvMsg, recvMsgLen, vnf_p7);
+			break;
+
 		default:
 			{
 				if(header.message_id >= NFAPI_VENDOR_EXT_MSG_MIN &&
@@ -1430,7 +1456,7 @@ void vnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
 						NFAPI_TRACE(NFAPI_TRACE_NOTE, "Failed to allocate VNF_P7 reassemby buffer len:%d\n", length);
 						return;
 					}
-
+                                       memset(phy->reassembly_buffer, 0, length);
 					phy->reassembly_buffer_size = length;
 				}
 
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
index 2798e04ae6d50402eee4cbf51fea2b32cae0b964..8b601224835d732f45b9b9febe2acf7585a48325 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
@@ -534,6 +534,14 @@ int nfapi_vnf_p7_vendor_extension(nfapi_vnf_p7_config_t* config, nfapi_p7_messag
 	return vnf_p7_pack_and_send_p7_msg(vnf_p7, header);
 }
 
+int nfapi_vnf_p7_ue_release_req(nfapi_vnf_p7_config_t* config, nfapi_ue_release_request_t* req)
+{
+    if(config == 0 || req == 0)
+        return -1;
+
+    vnf_p7_t* vnf_p7 = (vnf_p7_t*)config;
+    return vnf_p7_pack_and_send_p7_msg(vnf_p7, &req->header);
+}
 
 int nfapi_vnf_p7_release_msg(nfapi_vnf_p7_config_t* config, nfapi_p7_message_header_t* header)
 {
diff --git a/openair1/PHY/INIT/lte_init.c b/openair1/PHY/INIT/lte_init.c
index 8a165ed78138b48cde44b8f994225b78e8792b8c..368910ee05b563b42e75040a3b5ac0ed4c84c84c 100644
--- a/openair1/PHY/INIT/lte_init.c
+++ b/openair1/PHY/INIT/lte_init.c
@@ -34,6 +34,7 @@
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "assertions.h"
 #include <math.h>
+#include "nfapi/oai_integration/vendor_ext.h"
 
 extern uint32_t from_earfcn(int eutra_bandP,uint32_t dl_earfcn);
 extern int32_t get_uldl_offset(int eutra_bandP);
@@ -409,6 +410,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
 
 
     
+  if (NFAPI_MODE!=NFAPI_MODE_VNF){
   common_vars->rxdata  = (int32_t **)NULL;
   common_vars->txdataF = (int32_t **)malloc16(NB_ANTENNA_PORTS_ENB*sizeof(int32_t*));
   common_vars->rxdataF = (int32_t **)malloc16(64*sizeof(int32_t*));
@@ -512,6 +514,7 @@ int phy_init_lte_eNB(PHY_VARS_eNB *eNB,
 
   for (UE_id = 0; UE_id < NUMBER_OF_UE_MAX; UE_id++)
     eNB->UE_stats_ptr[UE_id] = &eNB->UE_stats[UE_id];
+  }
 
   eNB->pdsch_config_dedicated->p_a = dB0;       //defaul value until overwritten by RRCConnectionReconfiguration
 
diff --git a/openair1/PHY/LTE_TRANSPORT/dci.h b/openair1/PHY/LTE_TRANSPORT/dci.h
index c5654aa7428203ca04b4c709eaedae3612adf84d..cd76f209197f3854948cb14854fb7985a56fef9b 100644
--- a/openair1/PHY/LTE_TRANSPORT/dci.h
+++ b/openair1/PHY/LTE_TRANSPORT/dci.h
@@ -38,7 +38,7 @@
 #define CCEBITS 72
 #define CCEPERSYMBOL 33  // This is for 1200 RE
 #define CCEPERSYMBOL0 22  // This is for 1200 RE
-#define DCI_BITS_MAX ((2*CCEPERSYMBOL+CCEPERSYMBOL0)*CCEBITS)
+#define DCI_BITS_MAX ((2*CCEPERSYMBOL+CCEPERSYMBOL0)*CCEBITS + 64)
 
 //#define Mquad (Msymb/4)
 
diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c
index 21d7602a97fe463341c84821b198d583809033c5..80e7b6f8cdb9886c37ea41cb6eba5ed082c9eaff 100644
--- a/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c
+++ b/openair1/PHY/LTE_TRANSPORT/dlsch_coding.c
@@ -379,9 +379,8 @@ int dlsch_encoding_2threads(PHY_VARS_eNB *eNB,
   unsigned int G;
   unsigned int crc=1;
   unsigned char harq_pid = dlsch->harq_ids[frame%2][subframe];
-
-  if(harq_pid >= dlsch->Mdlharq) {
-    LOG_E(PHY,"dlsch_encoding_2threads illegal harq_pid %d\n", harq_pid);
+  if((harq_pid < 0) || (harq_pid >= dlsch->Mdlharq)) {
+    LOG_E(PHY,"dlsch_encoding_2threads illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
     return(-1);
   }
 
@@ -564,7 +563,12 @@ int dlsch_encoding_all(PHY_VARS_eNB *eNB,
                        time_stats_t *i_stats) {
   int encoding_return = 0;
   unsigned int L,C,B;
-  B = dlsch->harq_processes[dlsch->harq_ids[frame%2][subframe]]->B;
+  uint8_t harq_pid = dlsch->harq_ids[frame%2][subframe];
+  if(harq_pid >= dlsch->Mdlharq) {
+    LOG_E(PHY,"dlsch_encoding_all illegal harq_pid %d\n", harq_pid);
+    return(-1);
+  }
+  B = dlsch->harq_processes[harq_pid]->B;
 
   LOG_D(PHY,"B %d, harq_pid %d\n",B,dlsch->harq_ids[frame%2][subframe]);
 
@@ -671,9 +675,8 @@ int dlsch_encoding(PHY_VARS_eNB *eNB,
   unsigned int crc=1;
   LTE_DL_FRAME_PARMS *frame_parms = &eNB->frame_parms;
   unsigned char harq_pid = dlsch->harq_ids[frame%2][subframe];
-
-  if(harq_pid >= dlsch->Mdlharq) {
-    LOG_E(PHY,"dlsch_encoding illegal harq_pid %d\n", harq_pid);
+  if((harq_pid < 0) || (harq_pid >= dlsch->Mdlharq)) {
+    LOG_E(PHY,"dlsch_encoding illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
     return(-1);
   }
 
diff --git a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
index e8b56f3bdfe99292b3a5db85d91b5d99f1fba697..8a3649cf8727d5ad00ec73ae3a754593406afef2 100644
--- a/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
+++ b/openair1/PHY/LTE_TRANSPORT/dlsch_modulation.c
@@ -2257,8 +2257,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB,
   if ((dlsch0 != NULL) && (dlsch1 != NULL)){
 
     harq_pid = dlsch0->harq_ids[frame%2][subframe_offset];
-    if(harq_pid >= dlsch0->Mdlharq) {
-      LOG_E(PHY,"illegal harq_pid %d\n", harq_pid);
+    if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
+      LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
       return(-1);
     }
     dlsch0_harq = dlsch0->harq_processes[harq_pid];
@@ -2278,8 +2278,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB,
   }else if ((dlsch0 != NULL) && (dlsch1 == NULL)){
 
     harq_pid = dlsch0->harq_ids[frame%2][subframe_offset];
-    if(harq_pid >= dlsch0->Mdlharq) {
-      LOG_E(PHY,"illegal harq_pid %d\n", harq_pid);
+    if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
+      LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
       return(-1);
     }
     dlsch0_harq = dlsch0->harq_processes[harq_pid];
@@ -2299,8 +2299,8 @@ int dlsch_modulation(PHY_VARS_eNB* phy_vars_eNB,
   }else if ((dlsch0 == NULL) && (dlsch1 != NULL)){
 
     harq_pid = dlsch1->harq_ids[frame%2][subframe_offset];
-    if(harq_pid >= dlsch1->Mdlharq) {
-      LOG_E(PHY,"illegal harq_pid %d\n", harq_pid);
+    if((harq_pid < 0) || (harq_pid >= dlsch1->Mdlharq)) {
+      LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
       return(-1);
     }
     dlsch1_harq = dlsch1->harq_processes[harq_pid];
diff --git a/openair1/PHY/LTE_TRANSPORT/pucch.c b/openair1/PHY/LTE_TRANSPORT/pucch.c
index 676d753ab5d61bcf7c42f19200a5e9a57f728d05..72be96c95bfb4509bc821d8ad75346077798af02 100644
--- a/openair1/PHY/LTE_TRANSPORT/pucch.c
+++ b/openair1/PHY/LTE_TRANSPORT/pucch.c
@@ -1063,7 +1063,7 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
 #endif
           }
 
-          for (l2=0,l=(nsymb>>1); l<(nsymb-1); l++,l2++) {
+          for (l2=0,l=(nsymb>>1); l < nsymb; l++,l2++) {
             stat_re += (((rxcomp[aa][off]*(int32_t)cfo[l2<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l2<<1)])>>15))/nsymb;
             stat_im += (((rxcomp[aa][off]*(int32_t)cfo[1+(l2<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l2<<1)])>>15))/nsymb;
             off+=2;
@@ -1092,7 +1092,7 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
 
 //    stat_max *= nsymb;  // normalize to energy per symbol
 //    stat_max /= (frame_parms->N_RB_UL*12); //
-    stat_max /= (nsymb*12);
+    stat_max /= 12;
     
 #ifdef DEBUG_PUCCH_RX
     printf("[eNB] PUCCH: stat %d, stat_max %d, phase_max %d\n", stat,stat_max,phase_max);
@@ -1181,7 +1181,7 @@ uint32_t rx_pucch(PHY_VARS_eNB *eNB,
           stat_ref_re=0;
           stat_ref_im=0;
 
-          for (l2=0,l=(nsymb>>1); l<(nsymb-1); l++,l2++) {
+          for (l2=0,l=(nsymb>>1); l< nsymb; l++,l2++) {
             if ((l2<2) || ((l2>(nsymb>>1) - 3)) ) {  // data symbols
               stat_re += ((rxcomp[aa][off]*(int32_t)cfo[l2<<1])>>15)     - ((rxcomp[aa][1+off]*(int32_t)cfo[1+(l2<<1)])>>15);
               stat_im += ((rxcomp[aa][off]*(int32_t)cfo[1+(l2<<1)])>>15) + ((rxcomp[aa][1+off]*(int32_t)cfo[(l2<<1)])>>15);
diff --git a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h
index cedd7729c2bd5047475ac2b084dcc5907d379d32..735b8fd7ff2d2ce13eaba59387f136f2219d2fba 100644
--- a/openair1/PHY/LTE_TRANSPORT/transport_eNB.h
+++ b/openair1/PHY/LTE_TRANSPORT/transport_eNB.h
@@ -328,6 +328,8 @@ typedef struct {
   uint8_t     subframe;
   /// corresponding UE RNTI
   uint16_t    rnti;
+  /// UE ID from Layer2
+  uint16_t    ue_id;
   /// Type (SR, HARQ, CQI, HARQ_SR, HARQ_CQI, SR_CQI, HARQ_SR_CQI)
   UCI_type_t  type;
   /// SRS active flag
diff --git a/openair1/PHY/LTE_TRANSPORT/uci_tools.c b/openair1/PHY/LTE_TRANSPORT/uci_tools.c
index 88c652133b783bb627f708985c08c0d4004ca707..c301c8510f03f4ab7d22b50496cdf507435336de 100644
--- a/openair1/PHY/LTE_TRANSPORT/uci_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/uci_tools.c
@@ -41,7 +41,7 @@ int16_t find_uci(uint16_t rnti, int frame, int subframe, PHY_VARS_eNB *eNB,find_
   uint16_t i;
   int16_t first_free_index=-1;
   AssertFatal(eNB!=NULL,"eNB is null\n");
-  for (i=0; i<NUMBER_OF_UE_MAX; i++) {
+  for (i=0; i<NUMBER_OF_UCI_VARS_MAX; i++) {
     if ((eNB->uci_vars[i].active >0) &&
 	(eNB->uci_vars[i].rnti==rnti) &&
 	(eNB->uci_vars[i].frame==frame) &&
diff --git a/openair1/PHY/defs_eNB.h b/openair1/PHY/defs_eNB.h
index 7280ab69f1104dff3f189a719ff2d7f8f848b94d..314d6cc31bd6755ccc1fd5a666c7ef3c05f732f7 100644
--- a/openair1/PHY/defs_eNB.h
+++ b/openair1/PHY/defs_eNB.h
@@ -521,7 +521,7 @@ typedef struct PHY_VARS_eNB_s {
   LTE_eNB_PRACH        prach_vars_br;
 #endif
   LTE_eNB_COMMON       common_vars;
-  LTE_eNB_UCI          uci_vars[NUMBER_OF_UE_MAX];
+  LTE_eNB_UCI          uci_vars[NUMBER_OF_UCI_VARS_MAX];
   LTE_eNB_SRS          srs_vars[NUMBER_OF_UE_MAX];
   LTE_eNB_PBCH         pbch;
   LTE_eNB_PUSCH       *pusch_vars[NUMBER_OF_UE_MAX];
diff --git a/openair1/PHY/phy_vars.h b/openair1/PHY/phy_vars.h
index 1ae23e28b1c9a030e57de4672cd46d36992aa22a..492abe7e8d3a600638b53e0d4882aaa1ea533640 100644
--- a/openair1/PHY/phy_vars.h
+++ b/openair1/PHY/phy_vars.h
@@ -42,9 +42,9 @@ int16_t *primary_synch2_time;
 #include "PHY/MODULATION/modulation_vars.h"
 
 
-
 PHY_VARS_UE ***PHY_vars_UE_g;
 RAN_CONTEXT_t RC;
+UL_RCC_IND_t UL_RCC_INFO;
 
 unsigned short rev[2048],rev_times4[8192],rev_half[1024];
 unsigned short rev256[256],rev512[512],rev1024[1024],rev4096[4096],rev2048[2048],rev8192[8192];
diff --git a/openair1/SCHED/fapi_l1.c b/openair1/SCHED/fapi_l1.c
index b311149532432a4e0f1d6e09923929eedc897a05..5f8b4ec3db810495192e35e18b601322fa92db17 100644
--- a/openair1/SCHED/fapi_l1.c
+++ b/openair1/SCHED/fapi_l1.c
@@ -42,7 +42,7 @@ int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req);
 int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req);
 int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req);
 
-
+int oai_nfapi_ue_release_req(nfapi_ue_release_request_t *release_req);
 void handle_nfapi_dci_dl_pdu(PHY_VARS_eNB *eNB,
                              int frame, int subframe,
                              L1_rxtx_proc_t *proc,
@@ -186,21 +186,11 @@ void handle_nfapi_dlsch_pdu(PHY_VARS_eNB *eNB,int frame,int subframe,L1_rxtx_pro
 
 #endif
   harq_pid        = dlsch0->harq_ids[proc->frame_tx%2][proc->subframe_tx];
-  AssertFatal((harq_pid>=0) && (harq_pid<8),"harq_pid %d not in 0...7 frame:%d subframe:%d subframe(TX):%d rnti:%x UE_id:%d dlsch0[harq_ids:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d]\n",
-              harq_pid,
-              frame,subframe,
-              proc->subframe_tx,rel8->rnti,UE_id,
-              dlsch0->harq_ids[proc->frame_tx%2][0],
-              dlsch0->harq_ids[proc->frame_tx%2][1],
-              dlsch0->harq_ids[proc->frame_tx%2][2],
-              dlsch0->harq_ids[proc->frame_tx%2][3],
-              dlsch0->harq_ids[proc->frame_tx%2][4],
-              dlsch0->harq_ids[proc->frame_tx%2][5],
-              dlsch0->harq_ids[proc->frame_tx%2][6],
-              dlsch0->harq_ids[proc->frame_tx%2][7],
-              dlsch0->harq_ids[proc->frame_tx%2][8],
-              dlsch0->harq_ids[proc->frame_tx%2][9]
-             );
+  if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
+    LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
+    return;
+  }
+
   dlsch0_harq     = dlsch0->harq_processes[harq_pid];
   dlsch1_harq     = dlsch1->harq_processes[harq_pid];
   AssertFatal(dlsch0_harq!=NULL,"dlsch_harq is null\n");
@@ -588,6 +578,7 @@ void handle_uci_sr_pdu(PHY_VARS_eNB *eNB,
   uci->frame               = frame;
   uci->subframe            = subframe;
   uci->rnti                = ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti;
+  uci->ue_id               = find_dlsch(ul_config_pdu->uci_sr_pdu.ue_information.ue_information_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE);
   uci->type                = SR;
   uci->pucch_fmt           = pucch_format1;
   uci->num_antenna_ports   = 1;
@@ -615,6 +606,7 @@ void handle_uci_sr_harq_pdu(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_request_
   uci->frame               = frame;
   uci->subframe            = subframe;
   uci->rnti                = ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti;
+  uci->ue_id               = find_dlsch(ul_config_pdu->uci_sr_harq_pdu.ue_information.ue_information_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE);
   uci->type                = HARQ_SR;
   uci->num_antenna_ports   = 1;
   uci->num_pucch_resources = 1;
@@ -638,6 +630,7 @@ void handle_uci_harq_pdu(PHY_VARS_eNB *eNB,int UE_id,nfapi_ul_config_request_pdu
   uci->frame             = frame;
   uci->subframe          = subframe;
   uci->rnti              = ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti;
+  uci->ue_id             = find_dlsch(ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti,eNB,SEARCH_EXIST_OR_FREE);
   uci->type              = HARQ;
   uci->srs_active        = srs_active;
   uci->num_antenna_ports = ul_config_pdu->uci_harq_pdu.harq_information.harq_information_rel11.num_ant_ports;
@@ -809,7 +802,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
     harq_pid = subframe2harq_pid(fp,ul_frame,ul_subframe);
 
     // clear DCI allocation maps for new subframe
-
+    if (NFAPI_MODE!=NFAPI_MODE_VNF)
     for (i=0; i<NUMBER_OF_UE_MAX; i++) {
       if (eNB->ulsch[i]) {
         ulsch_harq = eNB->ulsch[i]->harq_processes[harq_pid];
@@ -825,7 +818,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
     //LOG_D(PHY,"NFAPI: dl_pdu %d : type %d\n",i,dl_config_pdu->pdu_type);
     switch (dl_config_pdu->pdu_type) {
       case NFAPI_DL_CONFIG_DCI_DL_PDU_TYPE:
-        handle_nfapi_dci_dl_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu);
+        if (NFAPI_MODE!=NFAPI_MODE_VNF)
+          handle_nfapi_dci_dl_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu);
         eNB->pdcch_vars[NFAPI_SFNSF2SF(DL_req->sfn_sf)&1].num_dci++;
         //LOG_E(PHY,"Incremented num_dci:%d but already set??? dl_config:num_dci:%d\n", eNB->pdcch_vars[subframe&1].num_dci, number_dci);
         do_oai=1;
@@ -840,7 +834,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
         do_oai=1;
         //LOG_D(PHY,"%s() NFAPI_DL_CONFIG_BCH_PDU_TYPE TX:%d/%d RX:%d/%d TXREQ:%d/%d\n",
         //__FUNCTION__, proc->frame_tx, proc->subframe_tx, proc->frame_rx, proc->subframe_rx, NFAPI_SFNSF2SFN(TX_req->sfn_sf), NFAPI_SFNSF2SF(TX_req->sfn_sf));
-        handle_nfapi_bch_pdu(eNB,proc,dl_config_pdu,
+        if (NFAPI_MODE!=NFAPI_MODE_VNF)
+          handle_nfapi_bch_pdu(eNB,proc,dl_config_pdu,
                              TX_req->tx_request_body.tx_pdu_list[dl_config_pdu->bch_pdu.bch_pdu_rel8.pdu_index].segments[0].segment_data);
         break;
 
@@ -872,7 +867,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
                     dlsch_pdu_rel8->transport_blocks);
 
         if (1) { //sdu != NULL)
-          handle_nfapi_dlsch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, dlsch_pdu_rel8->transport_blocks-1, sdu);
+            if (NFAPI_MODE!=NFAPI_MODE_VNF)
+              handle_nfapi_dlsch_pdu(eNB,NFAPI_SFNSF2SFN(DL_req->sfn_sf),NFAPI_SFNSF2SF(DL_req->sfn_sf),proc,dl_config_pdu, dlsch_pdu_rel8->transport_blocks-1, sdu);
         } else {
           dont_send=1;
           LOG_E(MAC,"%s() NFAPI_DL_CONFIG_DLSCH_PDU_TYPE sdu is NULL DL_CFG:SFN/SF:%d:pdu_index:%d TX_REQ:SFN/SF:%d:pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(DL_req->sfn_sf), pdu_index,
@@ -913,7 +909,8 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
 
       case NFAPI_DL_CONFIG_MPDCCH_PDU_TYPE:
-        handle_nfapi_mpdcch_pdu(eNB,proc,dl_config_pdu);
+        if (NFAPI_MODE!=NFAPI_MODE_VNF)
+          handle_nfapi_mpdcch_pdu(eNB,proc,dl_config_pdu);
         eNB->mpdcch_vars[subframe&1].num_dci++;
         break;
 #endif
@@ -921,16 +918,24 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
   }
 
   if ((NFAPI_MODE!=NFAPI_MONOLITHIC) && do_oai && !dont_send) {
-    oai_nfapi_tx_req(Sched_INFO->TX_req);
+    if(Sched_INFO->TX_req->tx_request_body.number_of_pdus > 0){
+      Sched_INFO->TX_req->sfn_sf = frame << 4 | subframe;
+      oai_nfapi_tx_req(Sched_INFO->TX_req);
+    }
+    Sched_INFO->DL_req->sfn_sf = frame << 4 | subframe;
     oai_nfapi_dl_config_req(Sched_INFO->DL_req); // DJP - .dl_config_request_body.dl_config_pdu_list[0]); // DJP - FIXME TODO - yuk - only copes with 1 pdu
+    Sched_INFO->UE_release_req->sfn_sf = frame << 4 | subframe;
+    oai_nfapi_ue_release_req(Sched_INFO->UE_release_req);
   }
 
   if ((NFAPI_MODE!=NFAPI_MONOLITHIC) && number_hi_dci0_pdu!=0) {
+    HI_DCI0_req->sfn_sf = frame << 4 | subframe;
     oai_nfapi_hi_dci0_req(HI_DCI0_req);
     eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_dci=0;
     eNB->pdcch_vars[NFAPI_SFNSF2SF(HI_DCI0_req->sfn_sf)&1].num_pdcch_symbols=0;
   }
 
+if (NFAPI_MODE!=NFAPI_MODE_VNF)
   for (i=0; i<number_hi_dci0_pdu; i++) {
     hi_dci0_req_pdu = &HI_DCI0_req->hi_dci0_request_body.hi_dci0_pdu_list[i];
     LOG_D(PHY,"NFAPI: hi_dci0_pdu %d : type %d\n",i,hi_dci0_req_pdu->pdu_type);
@@ -955,6 +960,7 @@ void schedule_response(Sched_Rsp_t *Sched_INFO) {
   if (NFAPI_MODE!=NFAPI_MONOLITHIC) {
     if (number_ul_pdu>0) {
       //LOG_D(PHY, "UL_CONFIG to send to PNF\n");
+      UL_req->sfn_sf = frame << 4 | subframe;
       oai_nfapi_ul_config_req(UL_req);
       UL_req->ul_config_request_body.number_of_pdus=0;
       number_ul_pdu=0;
diff --git a/openair1/SCHED/phy_procedures_lte_eNb.c b/openair1/SCHED/phy_procedures_lte_eNb.c
index 47b3f77d3e279bfdf6c1d37f5b4282cb8be01097..2d493f807289238eec1bba6cc180cf92270a4087 100644
--- a/openair1/SCHED/phy_procedures_lte_eNb.c
+++ b/openair1/SCHED/phy_procedures_lte_eNb.c
@@ -48,8 +48,7 @@
 
 #include "intertask_interface.h"
 
-
-
+nfapi_ue_release_request_body_t release_rntis;
 
 int16_t get_hundred_times_delta_IF_eNB(PHY_VARS_eNB *eNB,uint16_t UE_id,uint8_t harq_pid, uint8_t bw_factor) {
   uint32_t Nre,sumKr,MPR_x100,Kr,r;
@@ -460,6 +459,11 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME(VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO,num_pdcch_symbols);
   VCD_SIGNAL_DUMPER_DUMP_VARIABLE_BY_NAME (VCD_SIGNAL_DUMPER_VARIABLES_DCI_INFO, (frame * 10) + subframe);
 
+  if (num_pdcch_symbols == 0){
+    LOG_E(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols);
+    return;
+  }
+
   if (num_dci > 0)
     LOG_D(PHY,"[eNB %"PRIu8"] Frame %d, subframe %d: Calling generate_dci_top (pdcch) (num_dci %"PRIu8") num_pdcch_symbols:%d\n",eNB->Mod_id,frame, subframe, num_dci, num_pdcch_symbols);
 
@@ -507,9 +511,9 @@ void phy_procedures_eNB_TX(PHY_VARS_eNB *eNB,
        ) {
       // get harq_pid
       harq_pid = dlsch0->harq_ids[frame%2][subframe];
-      AssertFatal(harq_pid>=0,"harq_pid is negative\n");
+	//AssertFatal(harq_pid>=0,"harq_pid is negative\n");
 
-      if (harq_pid>=8) {
+        if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
 
         if (dlsch0->ue_type==0)
@@ -598,7 +602,7 @@ void fill_sr_indication(PHY_VARS_eNB *eNB,uint16_t rnti,int frame,int subframe,u
   //  pdu->rx_ue_information.handle                       = handle;
   pdu->rx_ue_information.tl.tag                       = NFAPI_RX_UE_INFORMATION_TAG;
   pdu->rx_ue_information.rnti                         = rnti;
-  int SNRtimes10 = dB_fixed_times10(stat) - 300;//(10*eNB->measurements.n0_power_dB[0]);
+  int SNRtimes10 = dB_fixed_times10(stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
 
   if      (SNRtimes10 < -640) pdu->ul_cqi_information.ul_cqi=0;
@@ -631,7 +635,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
   LTE_eNB_UCI *uci = NULL;
   LTE_DL_FRAME_PARMS *fp = &(eNB->frame_parms);
 
-  for (int i = 0; i < NUMBER_OF_UE_MAX; i++) {
+  for (int i = 0; i < NUMBER_OF_UCI_VARS_MAX; i++) {
     uci = &(eNB->uci_vars[i]);
 
     if ((uci->active == 1) && (uci->frame == frame) && (uci->subframe == subframe)) {
@@ -679,7 +683,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
           int pucch1_thres = (uci->ue_type == 0) ? eNB->pucch1_DTX_threshold : eNB->pucch1_DTX_threshold_emtc[0];
           metric_SR = rx_pucch(eNB,
                                uci->pucch_fmt,
-                               i,
+                               uci->ue_id,
                                uci->n_pucch_1_0_sr[0],
                                0, // n2_pucch
                                uci->srs_active, // shortened format
@@ -721,7 +725,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
                   SR_payload);
             metric[0] = rx_pucch(eNB,
                                  uci->pucch_fmt,
-                                 i,
+                                 uci->ue_id,
                                  uci->n_pucch_1[0][0],
                                  0, //n2_pucch
                                  uci->srs_active, // shortened format
@@ -745,7 +749,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
               SR_payload = 1;
               metric[0]=rx_pucch(eNB,
                                  uci->pucch_fmt,
-                                 i,
+                                 uci->ue_id,
                                  uci->n_pucch_1_0_sr[0],
                                  0, //n2_pucch
                                  uci->srs_active, // shortened format
@@ -775,7 +779,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
 #if 1
             metric[0] = rx_pucch(eNB,
                                  uci->pucch_fmt,
-                                 i,
+                                 uci->ue_id,
                                  uci->n_pucch_1[0][0],
                                  0, //n2_pucch
                                  uci->srs_active, // shortened format
@@ -795,7 +799,7 @@ uci_procedures(PHY_VARS_eNB *eNB,
               SR_payload = 1;
               metric[0] = rx_pucch(eNB,
                                    pucch_format1b,
-                                   i,
+                                   uci->ue_id,
                                    uci->n_pucch_1_0_sr[0],
                                    0, //n2_pucch
                                    uci->srs_active, // shortened format
@@ -1133,11 +1137,11 @@ uci_procedures(PHY_VARS_eNB *eNB,
           if (SR_payload == 1) {
             LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d Got SR for PUSCH, transmitting to MAC\n", eNB->Mod_id, uci->rnti, frame, subframe);
 
-            if (eNB->first_sr[i] == 1) {    // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4
-              eNB->first_sr[i] = 0;
-              eNB->dlsch[i][0]->harq_processes[0]->round = 0;
-              eNB->dlsch[i][0]->harq_processes[0]->status = SCH_IDLE;
-              LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[i]->rnti, frame, subframe);
+            if (eNB->first_sr[uci->ue_id] == 1) {    // this is the first request for uplink after Connection Setup, so clear HARQ process 0 use for Msg4
+              eNB->first_sr[uci->ue_id] = 0;
+              eNB->dlsch[uci->ue_id][0]->harq_processes[0]->round = 0;
+              eNB->dlsch[uci->ue_id][0]->harq_processes[0]->status = SCH_IDLE;
+              LOG_D (PHY, "[eNB %d][SR %x] Frame %d subframe %d First SR\n", eNB->Mod_id, eNB->ulsch[uci->ue_id]->rnti, frame, subframe);
             }
           }
       }
@@ -1466,7 +1470,7 @@ void fill_rx_indication(PHY_VARS_eNB *eNB,
 
   pdu->rx_indication_rel8.timing_advance = timing_advance_update;
   // estimate UL_CQI for MAC (from antenna port 0 only)
-  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 300;//(10*eNB->measurements.n0_power_dB[0]);
+  int SNRtimes10 = dB_fixed_times10(eNB->pusch_vars[UE_id]->ulsch_power[0]) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
 
   if (SNRtimes10 < -640)
     pdu->rx_indication_rel8.ul_cqi = 0;
@@ -1519,8 +1523,10 @@ static void do_release_harq(PHY_VARS_eNB *eNB,
 
     harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
 
-    AssertFatal((harq_pid >= 0) && (harq_pid < 8),"harq_pid %d not in 0...7\n", harq_pid);
-
+    if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
+      LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
+      return;
+    }
     dlsch0_harq = dlsch0->harq_processes[harq_pid];
     dlsch1_harq = dlsch1->harq_processes[harq_pid];
     
@@ -1569,37 +1575,39 @@ static void do_release_harq(PHY_VARS_eNB *eNB,
       if (((1 << m) & mask) > 0) {
         harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
 
-        if ((harq_pid >= 0) && (harq_pid < dlsch0->Mdlharq)) {
-          dlsch0_harq = dlsch0->harq_processes[harq_pid];
-          dlsch1_harq = dlsch1->harq_processes[harq_pid];
+        if((harq_pid < 0) || (harq_pid >= dlsch0->Mdlharq)) {
+          LOG_E(PHY,"illegal harq_pid %d %s:%d\n", harq_pid, __FILE__, __LINE__);
+          return;
+        }
+        dlsch0_harq = dlsch0->harq_processes[harq_pid];
+        dlsch1_harq = dlsch1->harq_processes[harq_pid];
 
-          AssertFatal(dlsch0_harq != NULL, "Dlsch0_harq is null\n");
+        AssertFatal(dlsch0_harq != NULL, "Dlsch0_harq is null\n");
 
 #if T_TRACER
-          if (after_rounds != -1) {
-            T(T_ENB_PHY_DLSCH_UE_NACK,
-              T_INT(0),
-              T_INT(frame),
-              T_INT(subframe),
-              T_INT(dlsch0->rnti),
-              T_INT(harq_pid));
-          } else {
-            T(T_ENB_PHY_DLSCH_UE_ACK,
-              T_INT(0),
-              T_INT(frame),
-              T_INT(subframe),
-              T_INT(dlsch0->rnti),
-              T_INT(harq_pid));
-          }
+        if (after_rounds != -1) {
+          T(T_ENB_PHY_DLSCH_UE_NACK,
+            T_INT(0),
+            T_INT(frame),
+            T_INT(subframe),
+            T_INT(dlsch0->rnti),
+            T_INT(harq_pid));
+        } else {
+          T(T_ENB_PHY_DLSCH_UE_ACK,
+            T_INT(0),
+            T_INT(frame),
+            T_INT(subframe),
+            T_INT(dlsch0->rnti),
+            T_INT(harq_pid));
+        }
 #endif
-          if (dlsch0_harq->round >= after_rounds) {
-            dlsch0_harq->status = SCH_IDLE;
+        if (dlsch0_harq->round >= after_rounds) {
+          dlsch0_harq->status = SCH_IDLE;
 
-            if ((dlsch1_harq == NULL) || ((dlsch1_harq != NULL) && (dlsch1_harq->status == SCH_IDLE))) {
-              dlsch0->harq_mask &= ~(1 << harq_pid);
-            }
+          if ((dlsch1_harq == NULL) || ((dlsch1_harq != NULL) && (dlsch1_harq->status == SCH_IDLE))) {
+            dlsch0->harq_mask &= ~(1 << harq_pid);
           }
-	    } // end if ((harq_pid >= 0) && (harq_pid < dlsch0->Mdlharq))
+        }
       } // end if (((1 << m) & mask) > 0)
     } // end for (int m=0; m < M; m++)
   } // end if TDD
@@ -1638,7 +1646,7 @@ int getM(PHY_VARS_eNB *eNB,int frame,int subframe) {
 
     harq_pid = dlsch0->harq_ids[frame_tx%2][subframe_tx];
 
-    if (harq_pid>=0 && harq_pid<10) {
+    if (harq_pid>=0 && harq_pid<dlsch0->Mdlharq) {
       dlsch0_harq     = dlsch0->harq_processes[harq_pid];
       dlsch1_harq     = dlsch1->harq_processes[harq_pid];
       AssertFatal(dlsch0_harq!=NULL,"dlsch0_harq is null\n");
@@ -1654,8 +1662,9 @@ int getM(PHY_VARS_eNB *eNB,int frame,int subframe) {
 
 void fill_ulsch_cqi_indication (PHY_VARS_eNB *eNB, uint16_t frame, uint8_t subframe, LTE_UL_eNB_HARQ_t *ulsch_harq, uint16_t rnti) {
   pthread_mutex_lock (&eNB->UL_INFO_mutex);
-  nfapi_cqi_indication_pdu_t *pdu = &eNB->UL_INFO.cqi_ind.cqi_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis];
-  nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.number_of_cqis];
+  nfapi_cqi_indication_pdu_t *pdu         = &eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list[eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis];
+  nfapi_cqi_indication_raw_pdu_t *raw_pdu = &eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list[eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis];
+  pdu->instance_length = 0;
   pdu->rx_ue_information.tl.tag          = NFAPI_RX_UE_INFORMATION_TAG;
   pdu->rx_ue_information.rnti = rnti;
 
@@ -1681,9 +1690,11 @@ void fill_ulsch_cqi_indication (PHY_VARS_eNB *eNB, uint16_t frame, uint8_t subfr
 
   pdu->cqi_indication_rel9.number_of_cc_reported = 1;
   pdu->ul_cqi_information.channel = 1;  // PUSCH
+  pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
   memcpy ((void *) raw_pdu->pdu, ulsch_harq->o, pdu->cqi_indication_rel9.length);
-  eNB->UL_INFO.cqi_ind.number_of_cqis++;
-  LOG_D(PHY,"eNB->UL_INFO.cqi_ind.number_of_cqis:%d\n", eNB->UL_INFO.cqi_ind.number_of_cqis);
+  eNB->UL_INFO.cqi_ind.cqi_indication_body.tl.tag = NFAPI_CQI_INDICATION_BODY_TAG;
+  eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis++;
+  LOG_D(PHY,"eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis:%d\n", eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis);
   pthread_mutex_unlock(&eNB->UL_INFO_mutex);
 }
 
@@ -1772,7 +1783,7 @@ void fill_uci_harq_indication (PHY_VARS_eNB *eNB, LTE_eNB_UCI *uci, int frame, i
   pdu->rx_ue_information.rnti                         = uci->rnti;
   // estimate UL_CQI for MAC (from antenna port 0 only)
   pdu->ul_cqi_information.tl.tag = NFAPI_UL_CQI_INFORMATION_TAG;
-  int SNRtimes10 = dB_fixed_times10(uci->stat) - 300;//(10*eNB->measurements.n0_power_dB[0]);
+  int SNRtimes10 = dB_fixed_times10(uci->stat) - 10 * eNB->measurements.n0_subband_power_dB[0][0];
 
   if (SNRtimes10 < -100)
     LOG_I (PHY, "uci->stat %d \n", uci->stat);
@@ -2000,3 +2011,44 @@ void phy_procedures_eNB_uespec_RX(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc) {
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_PHY_PROCEDURES_ENB_RX_UESPEC, 0 );
 }
+
+void release_rnti_of_phy(module_id_t mod_id){
+    int i,j;
+    int CC_id;
+    rnti_t rnti;
+    PHY_VARS_eNB *eNB_PHY = NULL;
+    LTE_eNB_ULSCH_t *ulsch = NULL;
+    LTE_eNB_DLSCH_t *dlsch = NULL;
+    for(i = 0; i< release_rntis.number_of_TLVs;i++){
+        for (CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
+          eNB_PHY = RC.eNB[mod_id][CC_id];
+          rnti = release_rntis.ue_release_request_TLVs_list[i].rnti;
+          for (j=0; j<NUMBER_OF_UE_MAX; j++) {
+              ulsch = eNB_PHY->ulsch[j];
+              if((ulsch != NULL) && (ulsch->rnti == rnti)){
+                LOG_I(PHY, "clean_eNb_ulsch ulsch[%d] UE %x\n", j, rnti);
+                clean_eNb_ulsch(ulsch);
+              }
+
+              dlsch = eNB_PHY->dlsch[j][0];
+              if((dlsch != NULL) && (dlsch->rnti == rnti)){
+                LOG_I(PHY, "clean_eNb_dlsch dlsch[%d] UE %x \n", j, rnti);
+                clean_eNb_dlsch(dlsch);
+              }
+          }
+          ulsch = eNB_PHY->ulsch[j];
+          if((ulsch != NULL) && (ulsch->rnti == rnti)){
+            LOG_I(PHY, "clean_eNb_ulsch ulsch[%d] UE %x\n", j, rnti);
+            clean_eNb_ulsch(ulsch);
+          }
+          for(j=0; j<NUMBER_OF_UCI_VARS_MAX; j++) {
+              if(eNB_PHY->uci_vars[j].rnti == rnti){
+                LOG_I(PHY, "clean eNb uci_vars[%d] UE %x \n",j, rnti);
+                memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI));
+              }
+
+          }
+        }
+    }
+    memset(&release_rntis, 0, sizeof(nfapi_ue_release_request_body_t));
+}
diff --git a/openair1/SCHED/sched_eNB.h b/openair1/SCHED/sched_eNB.h
index dccfbf7c388ac204771e391eaa1044cffea9e4cd..7fcabdc5ddf8163b063edc655cdca442a0f0617c 100644
--- a/openair1/SCHED/sched_eNB.h
+++ b/openair1/SCHED/sched_eNB.h
@@ -219,6 +219,7 @@ int is_srs_occasion_common(LTE_DL_FRAME_PARMS *frame_parms,int frame_tx,int subf
 
 void compute_srs_pos(lte_frame_type_t frameType,uint16_t isrs,uint16_t *psrsPeriodicity,uint16_t *psrsOffset);
 
+void release_rnti_of_phy(module_id_t mod_id);
 /*@}*/
 
 
diff --git a/openair1/SIMULATION/LTE_PHY/dummy_functions.c b/openair1/SIMULATION/LTE_PHY/dummy_functions.c
index 7d478f3f942a4d0ecafe9ebdf309755a08755296..5ec0f6e6967cc2ae27bfe8b9b3b5d3d199b9525c 100644
--- a/openair1/SIMULATION/LTE_PHY/dummy_functions.c
+++ b/openair1/SIMULATION/LTE_PHY/dummy_functions.c
@@ -91,7 +91,7 @@ int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) { return(0);}
 int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req) { return(0); }
 
 int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req) { return(0); }
-
+int oai_nfapi_ue_release_req(nfapi_ue_release_request_t *release_req){ return(0); }
 int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) { return(0); }
 
 
diff --git a/openair1/SIMULATION/LTE_PHY/ulsim.c b/openair1/SIMULATION/LTE_PHY/ulsim.c
index 8cd9b98bb701f3f3879bd5ce39aa98483f777084..be69e96897b633d93e512ba989e84b70d5161bb9 100644
--- a/openair1/SIMULATION/LTE_PHY/ulsim.c
+++ b/openair1/SIMULATION/LTE_PHY/ulsim.c
@@ -619,8 +619,8 @@ int main(int argc, char **argv) {
   eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list;
   eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list;
   eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list;
-  eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list;
-  eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
+  eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list = eNB->cqi_pdu_list;
+  eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
   printf("lte_param_init done\n");
   // for a call to phy_reset_ue later we need PHY_vars_UE_g allocated and pointing to UE
   PHY_vars_UE_g = (PHY_VARS_UE ** *)malloc(sizeof(PHY_VARS_UE **));
diff --git a/openair2/COMMON/gtpv1_u_messages_def.h b/openair2/COMMON/gtpv1_u_messages_def.h
index 27723eec15937c7ce204bc4f4e6e9190b7505bfb..1948f1596addcac0e9a3a865791b4f67362a60a1 100644
--- a/openair2/COMMON/gtpv1_u_messages_def.h
+++ b/openair2/COMMON/gtpv1_u_messages_def.h
@@ -25,4 +25,8 @@ MESSAGE_DEF(GTPV1U_ENB_DELETE_TUNNEL_REQ,   MESSAGE_PRIORITY_MED, gtpv1u_enb_del
 MESSAGE_DEF(GTPV1U_ENB_DELETE_TUNNEL_RESP,  MESSAGE_PRIORITY_MED, gtpv1u_enb_delete_tunnel_resp_t, Gtpv1uDeleteTunnelResp)
 MESSAGE_DEF(GTPV1U_ENB_TUNNEL_DATA_IND,     MESSAGE_PRIORITY_MED, gtpv1u_enb_tunnel_data_ind_t,    Gtpv1uTunnelDataInd)
 MESSAGE_DEF(GTPV1U_ENB_TUNNEL_DATA_REQ,     MESSAGE_PRIORITY_MED, gtpv1u_enb_tunnel_data_req_t,    Gtpv1uTunnelDataReq)
+MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_REQ, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_req_t,Gtpv1uDataForwardingReq)
+MESSAGE_DEF(GTPV1U_ENB_DATA_FORWARDING_IND, MESSAGE_PRIORITY_MED, gtpv1u_enb_data_forwarding_ind_t,Gtpv1uDataForwardingInd)
+MESSAGE_DEF(GTPV1U_ENB_END_MARKER_REQ,      MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_req_t,    Gtpv1uEndMarkerReq)
+MESSAGE_DEF(GTPV1U_ENB_END_MARKER_IND,      MESSAGE_PRIORITY_MED, gtpv1u_enb_end_marker_ind_t,    Gtpv1uEndMarkerInd)
 MESSAGE_DEF(GTPV1U_ENB_S1_REQ,        MESSAGE_PRIORITY_MED, Gtpv1uS1Req,    gtpv1uS1Req)
diff --git a/openair2/COMMON/gtpv1_u_messages_types.h b/openair2/COMMON/gtpv1_u_messages_types.h
index c398b55e3ef2fc40d2bb21946c0d9fb68ff2751b..4f81c22fb0bee322e307222890e6ff51c456ddb8 100644
--- a/openair2/COMMON/gtpv1_u_messages_types.h
+++ b/openair2/COMMON/gtpv1_u_messages_types.h
@@ -33,10 +33,33 @@
 #define GTPV1U_ENB_DELETE_TUNNEL_RESP(mSGpTR) (mSGpTR)->ittiMsg.Gtpv1uDeleteTunnelResp
 #define GTPV1U_ENB_TUNNEL_DATA_IND(mSGpTR)    (mSGpTR)->ittiMsg.Gtpv1uTunnelDataInd
 #define GTPV1U_ENB_TUNNEL_DATA_REQ(mSGpTR)    (mSGpTR)->ittiMsg.Gtpv1uTunnelDataReq
+#define GTPV1U_ENB_DATA_FORWARDING_REQ(mSGpTR)    (mSGpTR)->ittiMsg.Gtpv1uDataForwardingReq
+#define GTPV1U_ENB_DATA_FORWARDING_IND(mSGpTR)    (mSGpTR)->ittiMsg.Gtpv1uDataForwardingInd
+#define GTPV1U_ENB_END_MARKER_REQ(mSGpTR)     (mSGpTR)->ittiMsg.Gtpv1uEndMarkerReq
+#define GTPV1U_ENB_END_MARKER_IND(mSGpTR)     (mSGpTR)->ittiMsg.Gtpv1uEndMarkerInd
+
 #define GTPV1U_ENB_S1_REQ(mSGpTR)    (mSGpTR)->ittiMsg.gtpv1uS1Req
 
 #define GTPV1U_ALL_TUNNELS_TEID (teid_t)0xFFFFFFFF
 
+typedef struct gtpv1u_enb_create_x2u_tunnel_req_s {
+  rnti_t                 rnti;
+  int                    num_tunnels;
+  teid_t                 tenb_X2u_teid[GTPV1U_MAX_BEARERS_PER_UE];  ///< Tunnel Endpoint Identifier
+  ebi_t                  eps_bearer_id[GTPV1U_MAX_BEARERS_PER_UE];
+  transport_layer_addr_t enb_addr[GTPV1U_MAX_BEARERS_PER_UE];
+} gtpv1u_enb_create_x2u_tunnel_req_t;
+
+typedef struct gtpv1u_enb_create_x2u_tunnel_resp_s {
+  uint8_t                status;               ///< Status of S1U endpoint creation (Failed = 0xFF or Success = 0x0)
+  rnti_t                 rnti;
+  int                    num_tunnels;
+  teid_t                 enb_X2u_teid[GTPV1U_MAX_BEARERS_PER_UE];  ///< Tunnel Endpoint Identifier
+  ebi_t                  eps_bearer_id[GTPV1U_MAX_BEARERS_PER_UE];
+  transport_layer_addr_t enb_addr;
+} gtpv1u_enb_create_x2u_tunnel_resp_t;
+
+
 typedef struct gtpv1u_enb_create_tunnel_req_s {
   rnti_t                 rnti;
   int                    num_tunnels;
@@ -99,6 +122,50 @@ typedef struct gtpv1u_enb_tunnel_data_req_s {
   rb_id_t                rab_id;
 } gtpv1u_enb_tunnel_data_req_t;
 
+typedef struct gtpv1u_enb_data_forwarding_req_s {
+  uint8_t               *buffer;
+  uint32_t               length;
+  uint32_t               offset;               ///< start of message offset in buffer
+  rnti_t                 rnti;
+  rb_id_t                rab_id;
+} gtpv1u_enb_data_forwarding_req_t;
+
+typedef struct gtpv1u_enb_data_forwarding_ind_s {
+  uint32_t 				 frame;
+  uint8_t 				 enb_flag;
+  uint32_t 				 rb_id;
+  uint32_t 				 muip;
+  uint32_t 				 confirmp;
+  uint32_t 				 sdu_size;
+  uint8_t 				 *sdu_p;
+  uint8_t 				 mode;
+  uint16_t     			 rnti;
+  uint8_t      			 module_id;
+  uint8_t 				 eNB_index;
+} gtpv1u_enb_data_forwarding_ind_t;
+
+typedef struct gtpv1u_enb_end_marker_req_s {
+	  uint8_t               *buffer;
+	  uint32_t               length;
+	  uint32_t               offset;               ///< start of message offset in buffer
+	  rnti_t                 rnti;
+	  rb_id_t                rab_id;
+} gtpv1u_enb_end_marker_req_t;
+
+typedef struct gtpv1u_enb_end_marker_ind_s {
+  uint32_t 			 frame;
+  uint8_t 			 enb_flag;
+  uint32_t 			 rb_id;
+  uint32_t 			 muip;
+  uint32_t 			 confirmp;
+  uint32_t 			 sdu_size;
+  uint8_t 			 *sdu_p;
+  uint8_t 			 mode;
+  uint16_t     			 rnti;
+  uint8_t      			 module_id;
+  uint8_t 			 eNB_index;
+} gtpv1u_enb_end_marker_ind_t;
+
 typedef struct {
   in_addr_t             enb_ip_address_for_S1u_S12_S4_up;
   tcp_udp_port_t        enb_port_for_S1u_S12_S4_up;
diff --git a/openair2/COMMON/x2ap_messages_types.h b/openair2/COMMON/x2ap_messages_types.h
index 5a35b85fdb4e413d9f71fd3d475e163cdad09f3d..5f2a95f576611df8596103ee9652e94127cb08a7 100644
--- a/openair2/COMMON/x2ap_messages_types.h
+++ b/openair2/COMMON/x2ap_messages_types.h
@@ -107,6 +107,8 @@ typedef struct x2ap_register_enb_req_s {
   lte_frame_type_t        frame_type[MAX_NUM_CCs];
   uint32_t                fdd_earfcn_DL[MAX_NUM_CCs];
   uint32_t                fdd_earfcn_UL[MAX_NUM_CCs];
+  uint32_t                subframeAssignment[MAX_NUM_CCs];
+  uint32_t                specialSubframe[MAX_NUM_CCs];
   int                     num_cc;
 
   /* To be considered for TDD */
diff --git a/openair2/ENB_APP/enb_config.c b/openair2/ENB_APP/enb_config.c
index ea54e48e73c04eae958e24a8d57fd7527d7a1bd6..a0527d5d7b88d6122dfa17d81b49ff20acd45439 100644
--- a/openair2/ENB_APP/enb_config.c
+++ b/openair2/ENB_APP/enb_config.c
@@ -157,7 +157,7 @@ void RCconfig_L1(void) {
         LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_inst=1 this is because phy_init_RU() uses that to index and not RC.num_eNB - why the 2 similar variables?\n", __FUNCTION__);
         LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_CC[0]=%d for init_eNB_afterRU()\n", __FUNCTION__, RC.nb_CC[0]);
         LOG_I(PHY,"%s() NFAPI PNF mode - RC.nb_macrlc_inst:%d because used by mac_top_init_eNB()\n", __FUNCTION__, RC.nb_macrlc_inst);
-        //mac_top_init_eNB();
+        mac_top_init_eNB();
         configure_nfapi_pnf(RC.eNB[j][0]->eth_params_n.remote_addr, RC.eNB[j][0]->eth_params_n.remote_portc, RC.eNB[j][0]->eth_params_n.my_addr, RC.eNB[j][0]->eth_params_n.my_portd,
                             RC.eNB[j][0]->eth_params_n     .remote_portd);
       } else { // other midhaul
@@ -2505,6 +2505,8 @@ int RCconfig_X2(MessageDef *msg_p, uint32_t i) {
                   X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = FDD;
                 } else  if (strcmp(ccparams_lte.frame_type, "TDD") == 0) {
                   X2AP_REGISTER_ENB_REQ (msg_p).frame_type[J] = TDD;
+                  X2AP_REGISTER_ENB_REQ (msg_p).subframeAssignment[J] = ccparams_lte.tdd_config;
+                  X2AP_REGISTER_ENB_REQ (msg_p).specialSubframe[J] = ccparams_lte.tdd_config_s;
                 } else {
                   AssertFatal (0,
                                "Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for frame_type choice: FDD or TDD !\n",
diff --git a/openair2/LAYER2/MAC/config.c b/openair2/LAYER2/MAC/config.c
index 8337b94ddb2c05026aab76a7fb4dacaf91366e9a..26cbf8688d1600bbb8e8cd14dd879459f90533dc 100644
--- a/openair2/LAYER2/MAC/config.c
+++ b/openair2/LAYER2/MAC/config.c
@@ -1,4 +1,3 @@
-
 /*
  * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
  * contributor license agreements.  See the NOTICE file distributed with
@@ -27,7 +26,6 @@
  * \version 0.1
  * \email: navid.nikaein@eurecom.fr
  * @ingroup _mac
-
  */
 
 #include "COMMON/platform_types.h"
@@ -81,56 +79,55 @@ typedef struct band_info_s {
 } band_info_t;
 
 
-
 static const eutra_bandentry_t eutra_bandtable[] = {
-  {1,  19200, 19800, 21100, 21700, 0    },
-  {2,  18500, 19100, 19300, 19900, 6000 },
-  {3,  17100, 17850, 18050, 18800, 12000},
-  {4,  17100, 17550, 21100, 21550, 19500},
-  {5,  8240,  8490,  8690,  8940,  24000},
-  {6,  8300,  8400,  8750,  8850,  26500},
-  {7,  25000, 25700, 26200, 26900, 27500},
-  {8,  8800,  9150,  9250,  9600,  34500},
-  {9,  17499, 17849, 18449, 18799, 38000},
-  {10, 17100, 17700, 21100, 21700, 41500},
-  {11, 14279, 14529, 14759, 15009, 47500},
-  {12, 6980,  7160,  7280,  7460,  50100},
-  {13, 7770,  7870,  7460,  7560,  51800},
-  {14, 7880,  7980,  7580,  7680,  52800},
-  {17, 7040,  7160,  7340,  7460,  57300},
-  {18, 8150,  9650,  8600,  10100, 58500},
-  {19, 8300,  8450,  8750,  8900,  60000},
-  {20, 8320,  8620,  7910,  8210,  61500},
-  {21, 14479, 14629, 14959, 15109, 64500},
-  {22, 34100, 34900, 35100, 35900, 66000},
-  {23, 20000, 20200, 21800, 22000, 75000},
-  {24, 16126, 16605, 15250, 15590, 77000},
-  {25, 18500, 19150, 19300, 19950, 80400},
-  {26, 8140,  8490,  8590,  8940,  86900},
-  {27, 8070,  8240,  8520,  8690,  90400},
-  {28, 7030,  7580,  7580,  8130,  92100},
-  {29, 0,     0,     7170,  7280,  96600},
-  {30, 23050, 23250, 23500, 23600, 97700},
-  {31, 45250, 34900, 46250, 35900, 98700},
-  {32, 0,     0,     14520, 14960, 99200},
-  {33, 19000, 19200, 19000, 19200, 36000},
-  {34, 20100, 20250, 20100, 20250, 36200},
-  {35, 18500, 19100, 18500, 19100, 36350},
-  {36, 19300, 19900, 19300, 19900, 36950},
-  {37, 19100, 19300, 19100, 19300, 37550},
-  {38, 25700, 26200, 25700, 26300, 37750},
-  {39, 18800, 19200, 18800, 19200, 38250},
-  {40, 23000, 24000, 23000, 24000, 38650},
-  {41, 24960, 26900, 24960, 26900, 39650},
-  {42, 34000, 36000, 34000, 36000, 41590},
-  {43, 36000, 38000, 36000, 38000, 43590},
-  {44, 7030,  8030,  7030,  8030,  45590},
-  {45, 14470, 14670, 14470, 14670, 46590},
-  {46, 51500, 59250, 51500, 59250, 46790},
-  {65, 19200, 20100, 21100, 22000, 65536},
-  {66, 17100, 18000, 21100, 22000, 66436},
-  {67, 0,     0,     7380,  7580,  67336},
-  {68, 6980,  7280,  7530,  7830,  67536}
+  {1,  19200, 19800, 21100, 21700, 0     },
+  {2,  18500, 19100, 19300, 19900, 6000  },
+  {3,  17100, 17850, 18050, 18800, 12000 },
+  {4,  17100, 17550, 21100, 21550, 19500 },
+  {5,  8240,  8490,  8690,  8940,  24000 },
+  {6,  8300,  8400,  8750,  8850,  26500 },
+  {7,  25000, 25700, 26200, 26900, 27500 },
+  {8,  8800,  9150,  9250,  9600,  34500 },
+  {9,  17499, 17849, 18449, 18799, 38000 },
+  {10, 17100, 17700, 21100, 21700, 41500 },
+  {11, 14279, 14529, 14759, 15009, 47500 },
+  {12, 6980,  7160,  7280,  7460,  50100 },
+  {13, 7770,  7870,  7460,  7560,  51800 },
+  {14, 7880,  7980,  7580,  7680,  52800 },
+  {17, 7040,  7160,  7340,  7460,  57300 },
+  {18, 8150,  9650,  8600,  10100, 58500 },
+  {19, 8300,  8450,  8750,  8900,  60000 },
+  {20, 8320,  8620,  7910,  8210,  61500 },
+  {21, 14479, 14629, 14959, 15109, 64500 },
+  {22, 34100, 34900, 35100, 35900, 66000 },
+  {23, 20000, 20200, 21800, 22000, 75000 },
+  {24, 16126, 16605, 15250, 15590, 77000 },
+  {25, 18500, 19150, 19300, 19950, 80400 },
+  {26, 8140,  8490,  8590,  8940,  86900 },
+  {27, 8070,  8240,  8520,  8690,  90400 },
+  {28, 7030,  7580,  7580,  8130,  92100 },
+  {29, 0,     0,     7170,  7280,  96600 },
+  {30, 23050, 23250, 23500, 23600, 97700 },
+  {31, 45250, 34900, 46250, 35900, 98700 },
+  {32, 0,     0,     14520, 14960, 99200 },
+  {33, 19000, 19200, 19000, 19200, 360000},
+  {34, 20100, 20250, 20100, 20250, 362000},
+  {35, 18500, 19100, 18500, 19100, 363500},
+  {36, 19300, 19900, 19300, 19900, 369500},
+  {37, 19100, 19300, 19100, 19300, 375500},
+  {38, 25700, 26200, 25700, 26300, 377500},
+  {39, 18800, 19200, 18800, 19200, 382500},
+  {40, 23000, 24000, 23000, 24000, 386500},
+  {41, 24960, 26900, 24960, 26900, 396500},
+  {42, 34000, 36000, 34000, 36000, 415900},
+  {43, 36000, 38000, 36000, 38000, 435900},
+  {44, 7030,  8030,  7030,  8030,  455900},
+  {45, 14470, 14670, 14470, 14670, 465900},
+  {46, 51500, 59250, 51500, 59250, 467900},
+  {65, 19200, 20100, 21100, 22000, 655360},
+  {66, 17100, 18000, 21100, 22000, 664360},
+  {67, 0,     0,     7380,  7580,  67336 },
+  {68, 6980,  7280,  7530,  7830,  67536 }
 };
 
 
diff --git a/openair2/LAYER2/MAC/defs.h b/openair2/LAYER2/MAC/defs.h
index 4e781e5b3f33f6873ee159b163aa8dd62dc6844f..45b46aae549a2b737b1f83dba3009dd5e4006535 100644
--- a/openair2/LAYER2/MAC/defs.h
+++ b/openair2/LAYER2/MAC/defs.h
@@ -600,10 +600,10 @@ typedef struct {
   uint32_t rbs_used_retx_rx;
   ///  total rb used for a new uplink transmission
   uint32_t total_rbs_used_rx;
-  /// normalized rx power
-  int32_t      normalized_rx_power;
-   /// target rx power
-  int32_t    target_rx_power;
+  /// snr
+  int32_t      snr;
+   /// target snr
+  int32_t    target_snr;
 
   /// num rx pdu
   uint32_t num_pdu_rx[NB_RB_MAX];
diff --git a/openair2/LAYER2/MAC/eNB_scheduler.c b/openair2/LAYER2/MAC/eNB_scheduler.c
index d284660364e7f408c9ef1296dfc086b65c30610c..bb2cb0bc11acdd4c2d7a0656eb68c5a35751a62b 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler.c
@@ -128,9 +128,11 @@ void schedule_SRS(module_id_t module_idP,
             continue;
           }
 
-          AssertFatal(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated != NULL,
-                      "physicalConfigDedicated is null for UE %d\n",
-                      UE_id);
+	      if(UE_list->UE_template[CC_id][UE_id].physicalConfigDedicated == NULL) {
+	        LOG_E(MAC,"physicalConfigDedicated is null for UE %d\n",UE_id);
+	        printf("physicalConfigDedicated is null for UE %d\n",UE_id);
+	        return;
+	      }
 
           /* CDRX condition on Active Time and SRS type-0 report (36.321 5.7) */
           UE_scheduling_control = &(UE_list->UE_sched_ctrl[UE_id]);
@@ -464,6 +466,7 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
       DL_req[CC_id].dl_config_request_body.number_dci++;
       DL_req[CC_id].dl_config_request_body.number_pdu++;
       DL_req[CC_id].dl_config_request_body.tl.tag                      = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
+      DL_req[CC_id].sfn_sf = frameP<<4 | subframeP;
       LOG_D(MAC,
             "UE %d rnti %x: sending PDCCH order for RAPROC (failure timer %d), resource_block_coding %d \n",
             UE_id, rnti,
@@ -508,6 +511,13 @@ check_ul_failure(module_id_t module_idP, int CC_id, int UE_id,
       UE_list->UE_sched_ctrl[UE_id].ul_out_of_sync   = 1;
     }
   }       // ul_failure_timer>0
+  
+  UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer++;
+  if((U_PLANE_INACTIVITY_VALUE != 0) && (UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer > (U_PLANE_INACTIVITY_VALUE * 10))){
+     LOG_D(MAC,"UE %d rnti %x: U-Plane Failure after repeated PDCCH orders: Triggering RRC \n",UE_id,rnti); 
+     mac_eNB_rrc_uplane_failure(module_idP,CC_id,frameP,subframeP,rnti);
+     UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer  = 0;
+  }// time > 60s
 }
 
 void
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
index e7ee2c8a357a94164671bd515a56879328f71c7e..24b6e74bf0dd4de589f54e4039e23d8276f36fa6 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
@@ -868,8 +868,10 @@ generate_Msg4(module_id_t module_idP,
       ul_config_pdu = &ul_req_body->ul_config_pdu_list[ul_req_body->number_of_pdus];
       ul_config_pdu->pdu_type = NFAPI_UL_CONFIG_UCI_HARQ_PDU_TYPE;
       ul_config_pdu->pdu_size = (uint8_t) (2 + sizeof (nfapi_ul_config_uci_harq_pdu));
+      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL8_TAG;
       ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.handle = 0;      // don't know how to use this
       ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel8.rnti = ra->rnti;
+      ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.tl.tag = NFAPI_UL_CONFIG_REQUEST_UE_INFORMATION_REL13_TAG;
       ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.ue_type = (ra->rach_resource_type < 3) ? 1 : 2;
       ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.empty_symbols = 0;
       ul_config_pdu->uci_harq_pdu.ue_information.ue_information_rel13.total_number_of_repetitions = pucchreps[ra->rach_resource_type - 1];
@@ -957,9 +959,12 @@ generate_Msg4(module_id_t module_idP,
                              1, // tpc, none
                              getRIV(N_RB_DL, first_rb, 4),  // resource_block_coding
                              ra->msg4_mcs,  // mcs
-                             1, // ndi
+				 1 - UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
                              0, // rv
                              0);  // vrb_flag
+    	
+    	UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid] = 1 - UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid];
+
         LOG_D(MAC,
               "Frame %d, subframe %d: Msg4 DCI pdu_num %d (rnti %x,rnti_type %d,harq_pid %d, resource_block_coding (%p) %d\n",
               frameP, subframeP, dl_req_body->number_pdu,
@@ -1049,7 +1054,7 @@ generate_Msg4(module_id_t module_idP,
           mac->TX_req[CC_idP].sfn_sf =
             fill_nfapi_tx_req(&mac->TX_req[CC_idP].tx_request_body,
                               (frameP * 10) + subframeP,
-                              rrc_sdu_length,
+				      rrc_sdu_length+offset,
                               mac->pdu_index[CC_idP],
                               mac->UE_list.
                               DLSCH_pdu[CC_idP][0][(unsigned char)UE_id].payload[0]);
@@ -1194,7 +1199,7 @@ check_Msg4_retransmission(module_id_t module_idP, int CC_idP,
                              1, // tpc, none
                              getRIV(N_RB_DL, first_rb, 4),  // resource_block_coding
                              ra->msg4_mcs,  // mcs
-                             1, // ndi
+				     UE_list->UE_template[CC_idP][UE_id].oldNDI[ra->harq_pid],
                              round & 3, // rv
                              0);  // vrb_flag
 
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_bch.c b/openair2/LAYER2/MAC/eNB_scheduler_bch.c
index fb80c9e1d6058a9c50b33c869063c4cb6da40929..d523fb4e17b6f7aa031b6b7849a4a9b51430f756 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_bch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_bch.c
@@ -1158,6 +1158,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
 		    LOG_D(MAC, "Frame %d: Subframe %d : Adding common DCI for S_RNTI\n", frameP, subframeP);
 		    dl_req->number_dci++;
 		    dl_req->number_pdu++;
+                    dl_req->tl.tag   = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
 		    dl_config_pdu = &dl_req->dl_config_pdu_list[dl_req->number_pdu];
 		    memset((void *) dl_config_pdu, 0,
 			   sizeof(nfapi_dl_config_request_pdu_t));
@@ -1188,6 +1189,7 @@ schedule_SI(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
 		    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.num_bf_vector                          = 1;
 		    //    dl_config_pdu->dlsch_pdu.dlsch_pdu_rel8.bf_vector                    = ; 
 		    dl_req->number_pdu++;
+		    dl_req->tl.tag = NFAPI_DL_CONFIG_REQUEST_BODY_TAG;
 
                     // Rel10 fields
                     dl_config_pdu->dlsch_pdu.dlsch_pdu_rel10.tl.tag                                = NFAPI_DL_CONFIG_REQUEST_DLSCH_PDU_REL10_TAG;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
index e7857a33ccdc75bcd0b3d349bd4857db79d6dc53..051b1cd77311a722eb9871ee2483f08ae5bd0166 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_dlsch.c
@@ -489,7 +489,7 @@ schedule_ue_spec(module_id_t module_idP,
   COMMON_channels_t *cc = eNB->common_channels;
   UE_list_t *UE_list = &eNB->UE_list;
   int continue_flag = 0;
-  int32_t normalized_rx_power, target_rx_power;
+  int32_t snr, target_snr;
   int tpc = 1;
   UE_sched_ctrl_t *ue_sched_ctrl;
   int mcs;
@@ -718,9 +718,12 @@ schedule_ue_spec(module_id_t module_idP,
       eNB_UE_stats->harq_pid = harq_pid;
       eNB_UE_stats->harq_round = round_DL;
 
+      if (eNB_UE_stats->rrc_status < RRC_RECONFIGURED) {
+        ue_sched_ctrl->uplane_inactivity_timer = 0;
+      }
+
       if (eNB_UE_stats->rrc_status < RRC_CONNECTED) {
-        LOG_D(MAC, "UE %d is not in RRC_CONNECTED\n",
-              UE_id);
+        LOG_D(MAC, "UE %d is not in RRC_CONNECTED\n", UE_id);
         continue;
       }
 
@@ -734,7 +737,7 @@ schedule_ue_spec(module_id_t module_idP,
                 eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
       */
       if (NFAPI_MODE != NFAPI_MONOLITHIC) {
-        eNB_UE_stats->dlsch_mcs1 = 10; // cqi_to_mcs[ue_sched_ctrl->dl_cqi[CC_id]];
+        eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctrl->dl_cqi[CC_id]];
       } else { // this operation is also done in the preprocessor
         eNB_UE_stats->dlsch_mcs1 = cmin(eNB_UE_stats->dlsch_mcs1,
                                         eNB->slice_info.dl[slice_idxP].maxmcs);  // cmin(eNB_UE_stats->dlsch_mcs1, openair_daq_vars.target_ue_dl_mcs);
@@ -1007,9 +1010,11 @@ schedule_ue_spec(module_id_t module_idP,
                                               , 0
 #endif
                                              );
-            pthread_mutex_lock(&rrc_release_freelist);
 
             if((rrc_release_info.num_UEs > 0) && (rlc_am_mui.rrc_mui_num > 0)) {
+              while(pthread_mutex_trylock(&rrc_release_freelist)){
+                /* spin... */
+              }
               uint16_t release_total = 0;
 
               for (release_num = 0, release_ctrl = &rrc_release_info.RRC_release_ctrl[0];
@@ -1056,9 +1061,9 @@ schedule_ue_spec(module_id_t module_idP,
                 if(release_total >= rrc_release_info.num_UEs)
                   break;
               }
+              pthread_mutex_unlock(&rrc_release_freelist);
             }
 
-            pthread_mutex_unlock(&rrc_release_freelist);
 
             for (ra_ii = 0, ra = &eNB->common_channels[CC_id].ra[0]; ra_ii < NB_RA_PROC_MAX; ra_ii++, ra++) {
               if ((ra->rnti == rnti) && (ra->state == MSGCRNTI)) {
@@ -1478,11 +1483,11 @@ schedule_ue_spec(module_id_t module_idP,
           }
 
           // do PUCCH power control
-          // this is the normalized RX power
+          // this is the snr
           // unit is not dBm, it's special from nfapi
-          // converting to dBm: ToDo: Noise power hard coded to 30
-          normalized_rx_power = (((5 * ue_sched_ctrl->pucch1_snr[CC_id]) - 640) / 10) + 30;
-          target_rx_power= (eNB->puCch10xSnr / 10) + 30;
+          // converting to dBm
+          snr = (5 * ue_sched_ctrl->pucch1_snr[CC_id] - 640) / 10;
+          target_snr = eNB->puCch10xSnr / 10;
           // this assumes accumulated tpc
           // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
           int32_t framex10psubframe = ue_template->pucch_tpc_tx_frame * 10 + ue_template->pucch_tpc_tx_subframe;
@@ -1494,22 +1499,22 @@ schedule_ue_spec(module_id_t module_idP,
               ue_template->pucch_tpc_tx_frame = frameP;
               ue_template->pucch_tpc_tx_subframe = subframeP;
 
-              if (normalized_rx_power > (target_rx_power + 4)) {
+              if (snr > target_snr + 4) {
                 tpc = 0;  //-1
-              } else if (normalized_rx_power < (target_rx_power - 4)) {
+              } else if (snr < target_snr - 4) {
                 tpc = 2;  //+1
               } else {
                 tpc = 1;  //0
               }
 
-              LOG_D(MAC, "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n",
+              LOG_D(MAC, "[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, snr/target snr %d/%d\n",
                     module_idP,
                     frameP,
                     subframeP,
                     harq_pid,
                     tpc,
-                    normalized_rx_power,
-                    target_rx_power);
+                    snr,
+                    target_snr);
             } // Po_PUCCH has been updated
             else {
               tpc = 1;  //0
@@ -1890,8 +1895,8 @@ schedule_ue_spec_br(module_id_t module_idP,
   int round_DL = 0;
   int ta_update = 0;
   int32_t tpc = 1;
-  int32_t normalized_rx_power = 0;
-  int32_t target_rx_power = 0;
+  int32_t snr = 0;
+  int32_t target_snr = 0;
   uint16_t TBS = 0;
   uint16_t j = 0;
   uint16_t sdu_lengths[NB_RB_MAX];
@@ -2369,10 +2374,10 @@ schedule_ue_spec_br(module_id_t module_idP,
             T_INT(harq_pid),
             T_BUFFER(UE_list->DLSCH_pdu[CC_id][0][UE_id].payload[0], TBS));
           /* Do PUCCH power control */
-          /* This is the normalized RX power */
-          /* TODO: fix how we deal with power, unit is not dBm, it's special from nfapi */
-          normalized_rx_power = (5 * ue_sched_ctl->pucch1_snr[CC_id]-640) / 10 + 30;
-          target_rx_power = mac->puCch10xSnr / 10 + 30;
+          /* This is the snr */
+          /* unit is not dBm, it's special from nfapi, convert to dBm */
+          snr = (5 * ue_sched_ctl->pucch1_snr[CC_id] - 640) / 10;
+          target_snr = mac->puCch10xSnr / 10;
           /* This assumes accumulated tpc */
           /* Make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out */
           int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame * 10 + UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe;
@@ -2385,22 +2390,22 @@ schedule_ue_spec_br(module_id_t module_idP,
               UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame = frameP;
               UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe = subframeP;
 
-              if (normalized_rx_power > (target_rx_power + 4)) {
+              if (snr > target_snr + 4) {
                 tpc = 0; //-1
-              } else if (normalized_rx_power<(target_rx_power - 4)) {
+              } else if (snr < target_snr - 4) {
                 tpc = 2; //+1
               } else {
                 tpc = 1; //0
               }
 
-              LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, normalized/target rx power %d/%d\n",
+              LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, snr/target snr %d/%d\n",
                     module_idP,
                     frameP,
                     subframeP,
                     harq_pid,
                     tpc,
-                    normalized_rx_power,
-                    target_rx_power);
+                    snr,
+                    target_snr);
             } else { // Po_PUCCH has been updated
               tpc = 1; // 0
             }
@@ -3085,11 +3090,9 @@ schedule_PCH(module_id_t module_idP,
         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                  = NFAPI_DL_DCI_FORMAT_1A;
         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.harq_process                = 0;
         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tpc                         = 1; // no TPC
-        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1        = 1;
-        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1        = 1;
-        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding       = getRIV(n_rb_dl,
-            first_rb,
-            4);
+	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.new_data_indicator_1        = 0;
+	    dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.redundancy_version_1        = 0;
+        dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.resource_block_coding = getRIV(n_rb_dl, first_rb, 4);
         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.virtual_resource_block_assignment_flag = 0;
 #endif
         dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level           = 4;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
index 697c738b807b2d37668ec79177b99b2c10246d18..c071c1f505d7aad17b990ff33b0b9a9b0e51e906 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
@@ -585,6 +585,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
   //  uint16_t r1=0;
   uint8_t CC_id;
   UE_list_t *UE_list = &RC.mac[Mod_id]->UE_list;
+  int N_RB_DL;
   UE_sched_ctrl_t *ue_sched_ctl;
   //  int rrc_status           = RRC_IDLE;
   COMMON_channels_t *cc;
@@ -600,6 +601,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
 #endif
   memset(rballoc_sub[0],0,(MAX_NUM_CCs)*(N_RBG_MAX)*sizeof(unsigned char));
   memset(min_rb_unit,0,sizeof(min_rb_unit));
+  memset(MIMO_mode_indicator[0], 0, MAX_NUM_CCs*N_RBG_MAX*sizeof(unsigned char));
 
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
     if (mbsfn_flag[CC_id] > 0)  // If this CC is allocated for MBSFN skip it here
@@ -640,7 +642,18 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
     average_rbs_per_user[CC_id] = 0;
     cc = &RC.mac[Mod_id]->common_channels[CC_id];
     // Get total available RBS count and total UE count
-    temp_total_rbs_count = RC.mac[Mod_id]->eNB_stats[CC_id].available_prbs;
+    N_RB_DL = to_prb(cc->mib->message.dl_Bandwidth);
+    temp_total_rbs_count = 0;
+    for(uint8_t rbg_i = 0;rbg_i < N_RBG[CC_id];rbg_i++ ){
+      if(rballoc_sub[CC_id][rbg_i] == 0){
+        if((rbg_i == N_RBG[CC_id] -1) &&
+           ((N_RB_DL == 25) || (N_RB_DL == 50))){
+          temp_total_rbs_count += (min_rb_unit[CC_id] -1);
+        }else{
+          temp_total_rbs_count += min_rb_unit[CC_id];
+        }
+      }
+    }
     temp_total_ue_count = dlsch_ue_select[CC_id].ue_num;
 
     for (i = 0; i < dlsch_ue_select[CC_id].ue_num; i++) {
@@ -825,7 +838,7 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
   COMMON_channels_t *cc = eNB->common_channels;
   UE_list_t *UE_list = &eNB->UE_list;
   // int continue_flag = 0;
-  int32_t normalized_rx_power, target_rx_power;
+  int32_t snr, target_snr;
   int32_t tpc = 1;
   static int32_t tpc_accumulated = 0;
   UE_sched_ctrl_t *ue_sched_ctl;
@@ -1001,6 +1014,10 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
       UE_list->eNB_UE_stats[CC_id][UE_id].harq_pid = harq_pid;
       UE_list->eNB_UE_stats[CC_id][UE_id].harq_round = round;
 
+      if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status < RRC_RECONFIGURED) {
+        UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
+      }
+
       if (UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status <
           RRC_CONNECTED)
         continue;
@@ -1013,7 +1030,7 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
          eNB_UE_stats->dl_cqi, MIN_CQI_VALUE, MAX_CQI_VALUE);
        */
       if (NFAPI_MODE != NFAPI_MONOLITHIC) {
-        eNB_UE_stats->dlsch_mcs1 = 10;//cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
+        eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
       } else {
         eNB_UE_stats->dlsch_mcs1 = cqi_to_mcs[ue_sched_ctl->dl_cqi[CC_id]];
       }
@@ -1287,9 +1304,11 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
                                               ,0, 0
 #endif
                                              );
-            pthread_mutex_lock(&rrc_release_freelist);
 
-            if((rrc_release_info.num_UEs > 0) && (rlc_am_mui.rrc_mui_num > 0)) {
+            if((rrc_release_info.num_UEs > 0) && (rlc_am_mui.rrc_mui_num > 0)){
+              while(pthread_mutex_trylock(&rrc_release_freelist)) {
+                /* spin... */
+              }
               uint16_t release_total = 0;
 
               for(uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) {
@@ -1326,9 +1345,9 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
                 if(release_total >= rrc_release_info.num_UEs)
                   break;
               }
+              pthread_mutex_unlock(&rrc_release_freelist);
             }
 
-            pthread_mutex_unlock(&rrc_release_freelist);
             RA_t *ra = &eNB->common_channels[CC_id].ra[0];
 
             for (uint8_t ra_ii = 0; ra_ii < NB_RA_PROC_MAX; ra_ii++) {
@@ -1720,11 +1739,11 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
           }
 
           // do PUCCH power control
-          // this is the normalized RX power
+          // this is the snr
           eNB_UE_stats =  &UE_list->eNB_UE_stats[CC_id][UE_id];
           /* Unit is not dBm, it's special from nfapi */
-          normalized_rx_power = (5*ue_sched_ctl->pucch1_snr[CC_id]-640)/10+30;//(+eNB->measurements.n0_power_dB[0])
-          target_rx_power= eNB->puCch10xSnr/10 + 30;//(+eNB->measurements.n0_power_dB[0])
+          snr = (5 * ue_sched_ctl->pucch1_snr[CC_id] - 640) / 10;
+          target_snr = eNB->puCch10xSnr / 10;
           // this assumes accumulated tpc
           // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
           int32_t framex10psubframe = UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame*10+UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe;
@@ -1736,19 +1755,19 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
               UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_frame=frameP;
               UE_list->UE_template[CC_id][UE_id].pucch_tpc_tx_subframe=subframeP;
 
-              if (normalized_rx_power>(target_rx_power+4)) {
+              if (snr > target_snr + 4) {
                 tpc = 0; //-1
                 tpc_accumulated--;
-              } else if (normalized_rx_power<(target_rx_power-4)) {
+              } else if (snr < target_snr - 4) {
                 tpc = 2; //+1
                 tpc_accumulated++;
               } else {
                 tpc = 1; //0
               }
 
-              LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
+              LOG_D(MAC,"[eNB %d] DLSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n",
                     module_idP,frameP, subframeP,harq_pid,tpc,
-                    tpc_accumulated,normalized_rx_power,target_rx_power);
+                    tpc_accumulated,snr,target_snr);
             } // Po_PUCCH has been updated
             else {
               tpc = 1; //0
@@ -1763,6 +1782,7 @@ schedule_ue_spec_fairRR(module_id_t module_idP,
           dl_config_pdu->pdu_size                                               = (uint8_t)(2+sizeof(nfapi_dl_config_dci_dl_pdu));
           dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.dci_format                  = NFAPI_DL_DCI_FORMAT_1;
           dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.aggregation_level           = get_aggregation(get_bw_index(module_idP,CC_id),ue_sched_ctl->dl_cqi[CC_id],format1);
+          dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.tl.tag                      = NFAPI_DL_CONFIG_REQUEST_DCI_DL_PDU_REL8_TAG;
           dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti                        = rnti;
           dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.rnti_type                   = 1;    // CRNTI : see Table 4-10 from SCF082 - nFAPI specifications
           dl_config_pdu->dci_dl_pdu.dci_dl_pdu_rel8.transmission_power          = 6000; // equal to RS power
@@ -1972,7 +1992,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
   uint8_t cc_id_flag[MAX_NUM_CCs];
   uint8_t harq_pid = 0,round = 0;
   UE_list_t *UE_list= &eNB->UE_list;
-  uint8_t                        aggregation = 2;
+  uint8_t                        aggregation;
   int                            format_flag;
   nfapi_hi_dci0_request_body_t   *HI_DCI0_req;
   nfapi_hi_dci0_request_pdu_t    *hi_dci0_pdu;
@@ -2031,7 +2051,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
     if ( round > 0 ) {
       hi_dci0_pdu   = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi];
       format_flag = 2;
-
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id],format0);
       if (CCE_allocation_infeasible(module_idP,CC_id,format_flag,subframeP,aggregation,rnti) == 1) {
         cc_id_flag[CC_id] = 1;
         continue;
@@ -2110,7 +2130,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
       hi_dci0_pdu   = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi];
       format_flag = 2;
       rnti = UE_RNTI(module_idP,first_ue_id[CC_id][temp]);
-
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[first_ue_id[CC_id][temp]].dl_cqi[CC_id],format0); 
       if (CCE_allocation_infeasible(module_idP,CC_id,format_flag,subframeP,aggregation,rnti) == 1) {
         cc_id_flag[CC_id] = 1;
         break;
@@ -2182,7 +2202,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
          ((UE_sched_ctl->ul_inactivity_timer>10)&&(UE_sched_ctl->ul_scheduled==0)&&(mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP,UE_id)) < RRC_CONNECTED)) ) {
       hi_dci0_pdu   = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi];
       format_flag = 2;
-
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[UE_id].dl_cqi[CC_id],format0);
       if (CCE_allocation_infeasible(module_idP,CC_id,format_flag,subframeP,aggregation,rnti) == 1) {
         cc_id_flag[CC_id] = 1;
         continue;
@@ -2235,7 +2255,7 @@ void ulsch_scheduler_pre_ue_select_fairRR(
       hi_dci0_pdu   = &HI_DCI0_req->hi_dci0_pdu_list[HI_DCI0_req->number_of_dci+HI_DCI0_req->number_of_hi];
       format_flag = 2;
       rnti = UE_RNTI(module_idP,ul_inactivity_id[CC_id][temp]);
-
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id),UE_list->UE_sched_ctrl[ul_inactivity_id[CC_id][temp]].dl_cqi[CC_id],format0);
       if (CCE_allocation_infeasible(module_idP,CC_id,format_flag,subframeP,aggregation,rnti) == 1) {
         cc_id_flag[CC_id] = 1;
         continue;
@@ -2402,8 +2422,8 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
             while ( (tbs < bytes_to_schedule) && (rb_table[rb_table_index]<(frame_parms->N_RB_UL-num_pucch_rb-first_rb[CC_id])) &&
                     ((UE_template->phr_info - tx_power) > 0) && (rb_table_index < 32 )) {
               rb_table_index++;
-              tbs = get_TBS_UL(mcs,rb_table[rb_table_index])<<3;
-              tx_power= estimate_ue_tx_power(tbs,rb_table[rb_table_index],0,frame_parms->Ncp,0);
+              tbs = get_TBS_UL(mcs,rb_table[rb_table_index]);
+              tx_power= estimate_ue_tx_power(tbs*8,rb_table[rb_table_index],0,frame_parms->Ncp,0);
             }
 
             if ( rb_table[rb_table_index]<3 ) {
@@ -2434,12 +2454,20 @@ void ulsch_scheduler_pre_processor_fairRR(module_id_t module_idP,
               UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul = mcs;
             }
           } else {
-            // assigne RBS( 3 RBs)
-            first_rb[CC_id] = first_rb[CC_id] + 3;
-            UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[0] = 3;
-            UE_list->UE_template[CC_id][UE_id].pre_allocated_rb_table_index_ul = 2;
-            UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul = 10;
-          }
+            if (mac_eNB_get_rrc_status(module_idP,UE_RNTI(module_idP, UE_id)) < RRC_CONNECTED){
+              // assigne RBS( 6 RBs)
+              first_rb[CC_id] = first_rb[CC_id] + 6;
+              UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[0] = 6;
+              UE_list->UE_template[CC_id][UE_id].pre_allocated_rb_table_index_ul = 5;
+              UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul = 10;
+            }else{
+              // assigne RBS( 3 RBs)
+              first_rb[CC_id] = first_rb[CC_id] + 3;
+              UE_list->UE_template[CC_id][UE_id].pre_allocated_nb_rb_ul[0] = 3;
+              UE_list->UE_template[CC_id][UE_id].pre_allocated_rb_table_index_ul = 2;
+              UE_list->UE_template[CC_id][UE_id].pre_assigned_mcs_ul = 10;
+            }
+           }
         } else if ( ulsch_ue_select[CC_id].list[ulsch_ue_num].ue_priority  == SCH_UL_INACTIVE ) {
           // assigne RBS( 3 RBs)
           first_rb[CC_id] = first_rb[CC_id] + 3;
@@ -2609,7 +2637,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
                                 unsigned char sched_subframeP,
                                 ULSCH_UE_SELECT  ulsch_ue_select[MAX_NUM_CCs]) {
   int16_t           UE_id;
-  uint8_t           aggregation    = 2;
+  uint8_t           aggregation;
   uint16_t          first_rb[MAX_NUM_CCs];
   uint8_t           ULSCH_first_end;
   rnti_t            rnti           = -1;
@@ -2618,8 +2646,8 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
   uint8_t           status         = 0;
   uint8_t           rb_table_index = -1;
   uint32_t          cqi_req,cshift,ndi,tpc;
-  int32_t           normalized_rx_power;
-  int32_t           target_rx_power=-90;
+  int32_t           snr;
+  int32_t           target_snr=0;
   static int32_t    tpc_accumulated=0;
   int               CC_id,ulsch_ue_num;
   int               N_RB_UL;
@@ -2738,6 +2766,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
       UE_sched_ctrl = &UE_list->UE_sched_ctrl[UE_id];
       harq_pid      = subframe2harqpid(cc,sched_frame,sched_subframeP);
       rnti = UE_RNTI(CC_id,UE_id);
+      aggregation=get_aggregation(get_bw_index(module_idP,CC_id),UE_sched_ctrl[UE_id].dl_cqi[CC_id],format0); 
       LOG_D(MAC,"[eNB %d] frame %d subframe %d,Checking PUSCH %d for UE %d/%x CC %d : aggregation level %d, N_RB_UL %d\n",
             module_idP,frameP,subframeP,harq_pid,UE_id,rnti,CC_id, aggregation,N_RB_UL);
       int bytes_to_schedule = UE_template->estimated_ul_buffer - UE_template->scheduled_ul_bytes;
@@ -2757,12 +2786,12 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         if (cc->tdd_Config) {
           switch (cc->tdd_Config->subframeAssignment) {
             case 1:
-              if( subframeP == 1 || subframeP == 6 ) cqi_req=0;
+              if( sched_subframeP == 1 || sched_subframeP == 6 ) cqi_req=0;
 
               break;
 
             case 3:
-              if( subframeP == 1 ) cqi_req=0;
+              if( sched_subframeP == 1 ) cqi_req=0;
 
               break;
 
@@ -2782,8 +2811,8 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
       //power control
       //compute the expected ULSCH RX power (for the stats)
       // this is the normalized RX power and this should be constant (regardless of mcs
-      normalized_rx_power = (5*UE_sched_ctrl->pusch_snr[CC_id]-640)/10+30; //(+eNB->measurements.n0_power_dB[0])
-      target_rx_power= eNB->puSch10xSnr/10 + 30; //(+eNB->measurements.n0_power_dB[0])
+      snr = (5 * UE_sched_ctrl->pusch_snr[CC_id] - 640) / 10;
+      target_snr = eNB->puSch10xSnr / 10;
       // this assumes accumulated tpc
       // make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out
       int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame*10+UE_template->pusch_tpc_tx_subframe;
@@ -2793,10 +2822,10 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         UE_template->pusch_tpc_tx_frame=frameP;
         UE_template->pusch_tpc_tx_subframe=subframeP;
 
-        if (normalized_rx_power>(target_rx_power+4)) {
+        if (snr > target_snr + 4) {
           tpc = 0; //-1
           tpc_accumulated--;
-        } else if (normalized_rx_power<(target_rx_power-4)) {
+        } else if (snr < target_snr - 4) {
           tpc = 2; //+1
           tpc_accumulated++;
         } else {
@@ -2807,9 +2836,9 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
       }
 
       if (tpc!=1) {
-        LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
+        LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n",
               module_idP,frameP,subframeP,harq_pid,tpc,
-              tpc_accumulated,normalized_rx_power,target_rx_power);
+              tpc_accumulated,snr,target_snr);
       }
 
       // new transmission
@@ -2822,8 +2851,8 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
               UE_sched_ctrl->cqi_req_timer);
         ndi = 1-UE_template->oldNDI_UL[harq_pid];
         UE_template->oldNDI_UL[harq_pid]=ndi;
-        UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power;
-        UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power;
+        UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
+        UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
         UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1=UE_template->pre_assigned_mcs_ul;
         UE_template->mcs_UL[harq_pid] = UE_template->pre_assigned_mcs_ul;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS
 
@@ -2872,6 +2901,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         memset((void *)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t));
         hi_dci0_pdu->pdu_type                                               = NFAPI_HI_DCI0_DCI_PDU_TYPE;
         hi_dci0_pdu->pdu_size                                               = 2+sizeof(nfapi_hi_dci0_dci_pdu);
+        hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag                            = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format                        = NFAPI_UL_DCI_FORMAT_0;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level                 = aggregation;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti                              = rnti;
@@ -2998,8 +3028,8 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         T(T_ENB_MAC_UE_UL_SCHEDULE_RETRANSMISSION, T_INT(module_idP), T_INT(CC_id), T_INT(rnti), T_INT(frameP),
           T_INT(subframeP), T_INT(harq_pid), T_INT(UE_template->mcs_UL[harq_pid]), T_INT(ulsch_ue_select[CC_id].list[ulsch_ue_num].start_rb), T_INT(ulsch_ue_select[CC_id].list[ulsch_ue_num].nb_rb),
           T_INT(round));
-        UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power;
-        UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power;
+        UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
+        UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
         uint8_t mcs_rv = 0;
 
         if(rvidx_tab[round&3]==1) {
@@ -3029,6 +3059,7 @@ void schedule_ulsch_rnti_fairRR(module_id_t   module_idP,
         memset((void *)hi_dci0_pdu,0,sizeof(nfapi_hi_dci0_request_pdu_t));
         hi_dci0_pdu->pdu_type                                               = NFAPI_HI_DCI0_DCI_PDU_TYPE;
         hi_dci0_pdu->pdu_size                                               = 2+sizeof(nfapi_hi_dci0_dci_pdu);
+        hi_dci0_pdu->dci_pdu.dci_pdu_rel8.tl.tag                            = NFAPI_HI_DCI0_REQUEST_DCI_PDU_REL8_TAG;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.dci_format                        = NFAPI_UL_DCI_FORMAT_0;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.aggregation_level                 = aggregation;
         hi_dci0_pdu->dci_pdu.dci_pdu_rel8.rnti                              = rnti;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_phytest.c b/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
index 4f74ab0d09a908a0f139cc0c705ef90a8e442935..18f35d4fe3ad8303ded74420dcd2085ff177b774 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_phytest.c
@@ -199,8 +199,8 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
   uint8_t           mcs            = 20;
   uint8_t           harq_pid       = 0;
   uint32_t          cqi_req = 0,cshift,ndi,tpc = 1;
-  int32_t           normalized_rx_power;
-  int32_t           target_rx_power= 178;
+  int32_t           snr;
+  int32_t           target_snr = 10; /* TODO: target_rx_power was 178, what to put? is it meaningful? */
   int               CC_id = 0;
   int               nb_rb = 24;
   int               N_RB_UL;
@@ -258,15 +258,15 @@ void schedule_ulsch_phy_test(module_id_t module_idP,frame_t frameP,sub_frame_t s
       //power control
       //compute the expected ULSCH RX power (for the stats)
 	  
-      // this is the normalized RX power and this should be constant (regardless of mcs
-      normalized_rx_power = (5*UE_sched_ctrl->pusch_snr[CC_id]-640)/10+30;
+      // this is the snr and this should be constant (regardless of mcs)
+      snr = (5 * UE_sched_ctrl->pusch_snr[CC_id] - 640) / 10;
 	  
       // new transmission
 	  
       ndi = 1-UE_template->oldNDI_UL[harq_pid];
       UE_template->oldNDI_UL[harq_pid]=ndi;
-	  UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power=normalized_rx_power;
-	  UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power=target_rx_power;
+	  UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
+	  UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
 	  UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = mcs;
       UE_template->mcs_UL[harq_pid] = mcs;//cmin (UE_template->pre_assigned_mcs_ul, openair_daq_vars.target_ue_ul_mcs); // adjust, based on user-defined MCS
       UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = mcs;
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
index 856045166f7b3f3b277e3d23947948b0527b8438..63f838f652daa216fa49b6d02c7b8c8848de23ce 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -2193,8 +2193,8 @@ add_new_ue(module_id_t mod_idP,
     UE_list->UE_sched_ctrl[UE_id].ta_update = 31;
 
     for (j = 0; j < 8; j++) {
-      UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = (j == 0) ? 1 : 0; // 1 because first transmission is with format1A (Msg4) for harq_pid 0
-      UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = (j == harq_pidP) ? 0 : 1;  // 1st transmission is with Msg3;
+      UE_list->UE_template[cc_idP][UE_id].oldNDI[j] = 0;
+      UE_list->UE_template[cc_idP][UE_id].oldNDI_UL[j] = 0;
       UE_list->UE_sched_ctrl[UE_id].round[cc_idP][j] = 8;
       UE_list->UE_sched_ctrl[UE_id].round_UL[cc_idP][j] = 0;
     }
@@ -2319,9 +2319,10 @@ rrc_mac_remove_ue(module_id_t mod_idP,
                    rntiP);
   }
 
-  pthread_mutex_lock(&rrc_release_freelist);
-
-  if (rrc_release_info.num_UEs > 0) {
+  if(rrc_release_info.num_UEs > 0){
+    while(pthread_mutex_trylock(&rrc_release_freelist)) {
+      /* spin... */
+    }
     uint16_t release_total = 0;
 
     for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) {
@@ -2341,6 +2342,7 @@ rrc_mac_remove_ue(module_id_t mod_idP,
         break;
       }
     }
+    pthread_mutex_unlock(&rrc_release_freelist);
   }
 
   pthread_mutex_unlock(&rrc_release_freelist);
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
index dd228c4250eca1fb13b85294e7ff199765981d46..be1f838aaadaba7db8841bdb61d81b9649565714 100644
--- a/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_ulsch.c
@@ -460,7 +460,7 @@ rx_sdu(const module_id_t enb_mod_idP,
 
             if (RA_id != -1) {
               RA_t *ra = &(mac->common_channels[CC_idP].ra[RA_id]);
-              mac_rrc_data_ind(enb_mod_idP,
+              int8_t ret = mac_rrc_data_ind(enb_mod_idP,
                                CC_idP,
                                frameP, subframeP,
                                UE_id,
@@ -474,6 +474,7 @@ rx_sdu(const module_id_t enb_mod_idP,
 #endif
                               );
               /* Received a new rnti */
+              if (ret == 0) {
               ra->state = MSGCRNTI;
               LOG_I(MAC, "[eNB %d] Frame %d, Subframe %d CC_id %d : (rnti %x UE_id %d) Received rnti(Msg4)\n",
                     enb_mod_idP,
@@ -502,6 +503,9 @@ rx_sdu(const module_id_t enb_mod_idP,
               }
               UE_template_ptr->ul_SR = 1;
               UE_scheduling_control->crnti_reconfigurationcomplete_flag = 1;
+              } else {
+                cancel_ra_proc(enb_mod_idP, CC_idP, frameP, current_rnti);
+              }
               // break;
             }
           }
@@ -797,6 +801,10 @@ rx_sdu(const module_id_t enb_mod_idP,
           mac_rlc_data_ind(enb_mod_idP, current_rnti, enb_mod_idP, frameP, ENB_FLAG_YES, MBMS_FLAG_NO, rx_lcids[i], (char *) payload_ptr, rx_lengths[i], 1, NULL);  //(unsigned int*)crc_status);
           UE_list->eNB_UE_stats[CC_idP][UE_id].num_pdu_rx[rx_lcids[i]] += 1;
           UE_list->eNB_UE_stats[CC_idP][UE_id].num_bytes_rx[rx_lcids[i]] += rx_lengths[i];
+        
+          if (mac_eNB_get_rrc_status(enb_mod_idP, current_rnti) < RRC_RECONFIGURED) {
+            UE_list->UE_sched_ctrl[UE_id].uplane_inactivity_timer = 0;
+          }
         }
 
         break;
@@ -1329,8 +1337,8 @@ schedule_ulsch_rnti(module_id_t   module_idP,
   uint32_t cshift = 0;
   uint32_t ndi = 0;
   uint32_t tpc = 0;
-  int32_t normalized_rx_power = 0;
-  int32_t target_rx_power = 0;
+  int32_t snr = 0;
+  int32_t target_snr = 0;
   int32_t framex10psubframe = 0;
   static int32_t tpc_accumulated = 0;
   int sched_frame = 0;
@@ -1555,13 +1563,12 @@ schedule_ulsch_rnti(module_id_t   module_idP,
 
           /* Power control */
           /*
-           * Compute the expected ULSCH RX power (for the stats)
-           * This is the normalized RX power and this should be constant (regardless of mcs)
+           * Compute the expected ULSCH RX snr (for the stats)
+           * This is the normalized RX snr and this should be constant (regardless of mcs)
            * Is not in dBm, unit from nfapi, converting to dBm
-           * ToDo: Noise power hard coded to 30
            */
-          normalized_rx_power = ((5 * UE_sched_ctrl_ptr->pusch_snr[CC_id] - 640) / 10) + 30;
-          target_rx_power = (mac->puSch10xSnr / 10) + 30;
+          snr = (5 * UE_sched_ctrl_ptr->pusch_snr[CC_id] - 640) / 10;
+          target_snr = mac->puSch10xSnr / 10;
 
           /*
            * This assumes accumulated tpc
@@ -1575,10 +1582,10 @@ schedule_ulsch_rnti(module_id_t   module_idP,
             UE_template_ptr->pusch_tpc_tx_frame = frameP;
             UE_template_ptr->pusch_tpc_tx_subframe = subframeP;
 
-            if (normalized_rx_power > (target_rx_power + 4)) {
+            if (snr > target_snr + 4) {
               tpc = 0; // -1
               tpc_accumulated--;
-            } else if (normalized_rx_power < (target_rx_power - 4)) {
+            } else if (snr < target_snr - 4) {
               tpc = 2; // +1
               tpc_accumulated++;
             } else {
@@ -1589,21 +1596,21 @@ schedule_ulsch_rnti(module_id_t   module_idP,
           }
 
           if (tpc != 1) {
-            LOG_D(MAC, "[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
+            LOG_D(MAC, "[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n",
               module_idP,
               frameP,
               subframeP,
               harq_pid,
               tpc,
               tpc_accumulated,
-              normalized_rx_power,
-              target_rx_power);
+              snr,
+              target_snr);
           }
 
           ndi = 1 - UE_template_ptr->oldNDI_UL[harq_pid]; // NDI: new data indicator
           UE_template_ptr->oldNDI_UL[harq_pid] = ndi;
-          UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power = normalized_rx_power;
-          UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = target_rx_power;
+          UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
+          UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
           UE_template_ptr->mcs_UL[harq_pid] = cmin(UE_template_ptr->pre_assigned_mcs_ul, sli->ul[slice_idx].maxmcs);
           UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1= UE_template_ptr->mcs_UL[harq_pid];
 
@@ -1941,8 +1948,8 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
   uint8_t           status         = 0;
   uint32_t          cshift         = 0;
   uint32_t          ndi            = 0;
-  int32_t           normalized_rx_power = 0;
-  int32_t           target_rx_power = -90;
+  int32_t           snr = 0;
+  int32_t           target_snr = 0;
   int               n       = 0;
   int               CC_id = 0;
   int               N_RB_UL = 0;
@@ -2050,10 +2057,10 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
         UE_template->ul_SR = 0;
         status = mac_eNB_get_rrc_status(module_idP,rnti);
         cqi_req = 0;
-        /* Power control: compute the expected ULSCH RX power (for the stats) */
-        /* This is the normalized RX power and this should be constant (regardless of mcs) */
-        normalized_rx_power = UE_sched_ctrl->pusch_snr[CC_id];
-        target_rx_power = 178;
+        /* Power control: compute the expected ULSCH RX snr (for the stats) */
+        /* This is the normalized snr and this should be constant (regardless of mcs) */
+        snr = (5 * UE_sched_ctrl->pusch_snr[CC_id] - 640) / 10;
+        target_snr = eNB->puSch10xSnr / 10; /* TODO: target_rx_power was 178, what to put? */
         /* This assumes accumulated tpc */
         /* Make sure that we are only sending a tpc update once a frame, otherwise the control loop will freak out */
         int32_t framex10psubframe = UE_template->pusch_tpc_tx_frame * 10 + UE_template->pusch_tpc_tx_subframe;
@@ -2063,10 +2070,10 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
           UE_template->pusch_tpc_tx_frame = frameP;
           UE_template->pusch_tpc_tx_subframe = subframeP;
 
-          if (normalized_rx_power > (target_rx_power + 4)) {
+          if (snr > target_snr + 4) {
             tpc = 0; //-1
             UE_sched_ctrl->tpc_accumulated[CC_id]--;
-          } else if (normalized_rx_power < (target_rx_power - 4)) {
+          } else if (snr < target_snr - 4) {
             tpc = 2; //+1
             UE_sched_ctrl->tpc_accumulated[CC_id]++;
           } else {
@@ -2077,15 +2084,15 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
         }
 
         if (tpc != 1) {
-          LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, normalized/target rx power %d/%d\n",
+          LOG_D(MAC,"[eNB %d] ULSCH scheduler: frame %d, subframe %d, harq_pid %d, tpc %d, accumulated %d, snr/target snr %d/%d\n",
                 module_idP,
                 frameP,
                 subframeP,
                 harq_pid,
                 tpc,
                 UE_sched_ctrl->tpc_accumulated[CC_id],
-                normalized_rx_power,
-                target_rx_power);
+                snr,
+                target_snr);
         }
 
         /* New transmission */
@@ -2094,8 +2101,8 @@ void schedule_ulsch_rnti_emtc(module_id_t   module_idP,
           UE_template->oldNDI_UL[harq_pid] = ndi;
           UE_template->mcs_UL[harq_pid] = 4;
           UE_template->TBS_UL[harq_pid] = get_TBS_UL(UE_template->mcs_UL[harq_pid], 6);
-          UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power = normalized_rx_power;
-          UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power = target_rx_power;
+          UE_list->eNB_UE_stats[CC_id][UE_id].snr = snr;
+          UE_list->eNB_UE_stats[CC_id][UE_id].target_snr = target_snr;
           UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1 = 4;
           UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2 = UE_template->mcs_UL[harq_pid];
           UE_list->eNB_UE_stats[CC_id][UE_id].total_rbs_used_rx += 6;
diff --git a/openair2/LAYER2/MAC/mac.h b/openair2/LAYER2/MAC/mac.h
index 276f1e4e6f25af1a85c256d0eda2a48a10d553a7..1760355f6152f12640c1916f84f6d3458032d567 100644
--- a/openair2/LAYER2/MAC/mac.h
+++ b/openair2/LAYER2/MAC/mac.h
@@ -169,7 +169,7 @@
 #define MAX_NUM_SLICES 10
 
 
-#define U_PLANE_INACTIVITY_VALUE 6000
+#define U_PLANE_INACTIVITY_VALUE 0   /* defined 10ms order (zero means infinity) */
 
 /*
  * eNB part
@@ -754,10 +754,10 @@ typedef struct {
     uint32_t rbs_used_retx_rx;
     ///  total rb used for a new uplink transmission
     uint32_t total_rbs_used_rx;
-    /// normalized rx power
-    int32_t normalized_rx_power;
-    /// target rx power
-    int32_t target_rx_power;
+    /// snr
+    int32_t snr;
+    /// target snr
+    int32_t target_snr;
 
     /// num rx pdu
     uint32_t num_pdu_rx[NB_RB_MAX];
@@ -1438,6 +1438,8 @@ typedef struct eNB_MAC_INST_s {
   tx_request_pdu[NFAPI_CC_MAX][MAX_NUM_TX_REQUEST_PDU];
   /// NFAPI DL PDU structure
   nfapi_tx_request_t TX_req[NFAPI_CC_MAX];
+  /// NFAPI UE_release_req structure
+  nfapi_ue_release_request_t UE_release_req;
   /// UL handle
   uint32_t ul_handle;
   UE_list_t UE_list;
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
index 2f001bdcfd82eef375e29051555a352289bbbe1f..4d34338ea98097d1229d9ee26e79624ff17a951a 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_retransmit.c
@@ -806,6 +806,7 @@ mem_block_t * rlc_am_get_pdu_to_retransmit(
 	  rlc_sn_t             sn          = rlc_pP->vt_a;
 	  rlc_sn_t             sn_end      = rlc_pP->vt_s;
 	  mem_block_t*         pdu_p        = NULL;
+	  mem_block_t*         mb_p         = NULL;
 	  rlc_am_tx_data_pdu_management_t* tx_data_pdu_management;
 //Assertion(eNB)_PRAN_DesignDocument_annex No.769
       if((rlc_pP->retrans_num_pdus <= 0) || (rlc_pP->vt_a ==  rlc_pP->vt_s))
@@ -884,6 +885,18 @@ mem_block_t * rlc_am_get_pdu_to_retransmit(
 					                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
 									tx_data_pdu_management->retx_count_next,
 					                sn);
+					  mb_p = rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE].mem_block;
+					  if(mb_p != NULL){
+					    free_mem_block(mb_p, __func__);
+					    tx_data_pdu_management->mem_block = NULL;
+					    tx_data_pdu_management->flags.retransmit = 0;
+					    tx_data_pdu_management->flags.ack = 1;
+					    tx_data_pdu_management->flags.transmitted = 0;
+					    rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_management->retx_payload_size;
+					    tx_data_pdu_management->retx_payload_size = 0;
+					    tx_data_pdu_management->num_holes = 0;
+					    rlc_pP->retrans_num_pdus --;
+					  }
 				  }
 			  }
 			  else if (rlc_pP->nb_bytes_requested_by_mac >= 5)
@@ -938,6 +951,18 @@ mem_block_t * rlc_am_get_pdu_to_retransmit(
 					  					                PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
 					  									tx_data_pdu_management->retx_count_next,
 					  					                sn);
+					  mb_p = rlc_pP->tx_data_pdu_buffer[sn % RLC_AM_WINDOW_SIZE].mem_block;
+					  if(mb_p != NULL){
+					    free_mem_block(mb_p, __func__);
+					    tx_data_pdu_management->mem_block = NULL;
+					    tx_data_pdu_management->flags.retransmit = 0;
+					    tx_data_pdu_management->flags.ack = 1;
+					    tx_data_pdu_management->flags.transmitted = 0;
+					    rlc_pP->retrans_num_bytes_to_retransmit -= tx_data_pdu_management->retx_payload_size;
+					    tx_data_pdu_management->retx_payload_size = 0;
+					    tx_data_pdu_management->num_holes = 0;
+					    rlc_pP->retrans_num_pdus --;
+					  }
 				  }
 			  }
 
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c
index 9d69882923d84e02d97cde5047c4cb50f00a85af..4a065539013f323cb16a146cf2dd07b975ff7a6d 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_rx_list.c
@@ -938,7 +938,7 @@ rlc_am_rx_check_all_byte_segments(
   rlc_am_pdu_info_t  *pdu_info_p        = &((rlc_am_rx_pdu_management_t*)(tb_pP->data))->pdu_info;
   mem_block_t        *cursor_p        = NULL;
   mem_block_t        *first_cursor_p  = NULL;
-  rlc_sn_t            sn              = pdu_info_p->sn;
+  rlc_usn_t            sn              = pdu_info_p->sn;
   sdu_size_t          next_waited_so;
   sdu_size_t          last_end_so;
 
@@ -969,6 +969,9 @@ rlc_am_rx_check_all_byte_segments(
   // the so field of the first PDU should be 0
   //cursor_p = list.head;
   //we start from the first stored PDU segment of this SN
+  if(cursor_p->data == NULL){
+    return;
+  }
   pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
 
   // if the first segment does not have SO = 0 then no need to continue
@@ -985,6 +988,9 @@ rlc_am_rx_check_all_byte_segments(
   while (cursor_p->next != NULL) {
     //msg("rlc_am_rx_check_all_byte_segments(%d) @4\n",sn);
     cursor_p = cursor_p->next;
+  if(cursor_p->data == NULL){
+    return;
+  }
     pdu_info_p = &((rlc_am_rx_pdu_management_t*)(cursor_p->data))->pdu_info;
 
     if (pdu_info_p->sn == sn) {
diff --git a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
index 40bab6ff0b0b9f4021e7204fd3ab4e8b5fdf0e19..dbe55c483da8322bb1e1e76a76faca01630ee795 100644
--- a/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
+++ b/openair2/LAYER2/RLC/AM_v9.3.0/rlc_am_segment.c
@@ -358,8 +358,6 @@ void rlc_am_segment_10 (
               PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
               pdu_remaining_size);
         //msg ("[FRAME %05d][%s][RLC_AM][MOD %u/%u][RB %u][SEGMENT] pdu_mem_p %p pdu_p %p pdu_p->data %p data %p data_sdu_p %p pdu_remaining_size %d\n", rlc_pP->module_id, rlc_pP->rb_id, ctxt_pP->frame, pdu_mem_p, pdu_p, pdu_p->data, data, data_sdu_p,pdu_remaining_size);
-        rlc_am_mui.rrc_mui[rlc_am_mui.rrc_mui_num] = sdu_mngt_p->mui;
-        rlc_am_mui.rrc_mui_num++;
 
         memcpy(data, data_sdu_p, pdu_remaining_size);
         pdu_mngt_p->payload_size += pdu_remaining_size;
@@ -397,8 +395,6 @@ void rlc_am_segment_10 (
         continue_fill_pdu_with_sdu = 0;
         pdu_remaining_size = 0;
       } else if ((sdu_mngt_p->sdu_remaining_size + (li_length_in_bytes ^ 3)) < pdu_remaining_size ) {
-        rlc_am_mui.rrc_mui[rlc_am_mui.rrc_mui_num] = sdu_mngt_p->mui;
-        rlc_am_mui.rrc_mui_num++;
         if (fill_num_li == (RLC_AM_MAX_SDU_IN_PDU - 1)) {
           LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] [SIZE %d] REACHING RLC_AM_MAX_SDU_IN_PDU LIs -> STOP SEGMENTATION FOR THIS PDU SDU\n",
                 PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
@@ -416,6 +412,8 @@ void rlc_am_segment_10 (
           // reduce the size of the PDU
           continue_fill_pdu_with_sdu = 0;
           fi_last_byte_pdu_is_last_byte_sdu = 1;
+          rlc_am_mui.rrc_mui[rlc_am_mui.rrc_mui_num] = sdu_mngt_p->mui;
+          rlc_am_mui.rrc_mui_num++;
         } else {
           LOG_T(RLC, PROTOCOL_RLC_AM_CTXT_FMT"[SEGMENT] Filling  PDU with %d all remaining bytes of SDU\n",
                 PROTOCOL_RLC_AM_CTXT_ARGS(ctxt_pP,rlc_pP),
diff --git a/openair2/LAYER2/openair2_proc.c b/openair2/LAYER2/openair2_proc.c
index 2251344c47f1c6714bfdcf9b6c3a3ea613c0248f..32c4d9788cf84a59afe502babf54db8fd4a6044c 100644
--- a/openair2/LAYER2/openair2_proc.c
+++ b/openair2/LAYER2/openair2_proc.c
@@ -176,13 +176,13 @@ int dump_eNB_l2_stats(char *buffer, int length) {
                                UE_list->eNB_UE_stats[CC_id][UE_id].total_overhead_bytes,
                                UE_list->eNB_UE_stats[CC_id][UE_id].avg_overhead_bytes
                               );
-                len += sprintf(&buffer[len],"[MAC] UE %d (ULSCH), Status %s, Failute timer %d, RNTI %x : rx power (normalized %d,  target %d), MCS (pre %d, post %d), RB (rx %d, retx %d, total %d), Current TBS %d \n",
+                len += sprintf(&buffer[len],"[MAC] UE %d (ULSCH), Status %s, Failute timer %d, RNTI %x : snr (%d,  target %d), MCS (pre %d, post %d), RB (rx %d, retx %d, total %d), Current TBS %d \n",
                                UE_id,
                                map_int_to_str(rrc_status_names, UE_list->eNB_UE_stats[CC_id][UE_id].rrc_status),
                                UE_list->UE_sched_ctrl[UE_id].ul_failure_timer,
                                UE_list->eNB_UE_stats[CC_id][UE_id].crnti,
-                               UE_list->eNB_UE_stats[CC_id][UE_id].normalized_rx_power,
-                               UE_list->eNB_UE_stats[CC_id][UE_id].target_rx_power,
+                               UE_list->eNB_UE_stats[CC_id][UE_id].snr,
+                               UE_list->eNB_UE_stats[CC_id][UE_id].target_snr,
                                UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs1,
                                UE_list->eNB_UE_stats[CC_id][UE_id].ulsch_mcs2,
                                UE_list->eNB_UE_stats[CC_id][UE_id].rbs_used_rx,
diff --git a/openair2/PHY_INTERFACE/IF_Module.c b/openair2/PHY_INTERFACE/IF_Module.c
index ad49a16cec2e52534bd4e8a1f318924c8b50878b..2cc43189c696134b92bf82d14c53411516c35f13 100644
--- a/openair2/PHY_INTERFACE/IF_Module.c
+++ b/openair2/PHY_INTERFACE/IF_Module.c
@@ -17,10 +17,34 @@ extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind);
 extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind);
 
 extern uint16_t sf_ahead;
+extern UL_RCC_IND_t  UL_RCC_INFO;
+
 uint16_t frame_cnt=0;
 void handle_rach(UL_IND_t *UL_info) {
   int i;
-
+  if(NFAPI_MODE == NFAPI_MODE_VNF){
+    for(uint8_t j = 0;j < NUM_NFPAI_SUBFRAME;j++){
+     if (UL_RCC_INFO.rach_ind[j].rach_indication_body.number_of_preambles>0) {
+
+       AssertFatal(UL_RCC_INFO.rach_ind[j].rach_indication_body.number_of_preambles==1,"More than 1 preamble not supported\n");
+       LOG_D(MAC,"UL_info[Frame %d, Subframe %d] Calling initiate_ra_proc RACH:SFN/SF:%d\n",UL_info->frame,UL_info->subframe, NFAPI_SFNSF2DEC(UL_RCC_INFO.rach_ind[j].sfn_sf));
+       initiate_ra_proc(UL_info->module_id,
+                        UL_info->CC_id,
+                        NFAPI_SFNSF2SFN(UL_RCC_INFO.rach_ind[j].sfn_sf),
+                        NFAPI_SFNSF2SF(UL_RCC_INFO.rach_ind[j].sfn_sf),
+                        UL_RCC_INFO.rach_ind[j].rach_indication_body.preamble_list[0].preamble_rel8.preamble,
+                        UL_RCC_INFO.rach_ind[j].rach_indication_body.preamble_list[0].preamble_rel8.timing_advance,
+                        UL_RCC_INFO.rach_ind[j].rach_indication_body.preamble_list[0].preamble_rel8.rnti
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+                        ,0
+#endif
+       );
+       free(UL_RCC_INFO.rach_ind[j].rach_indication_body.preamble_list);
+       UL_RCC_INFO.rach_ind[j].rach_indication_body.number_of_preambles = 0;
+       UL_RCC_INFO.rach_ind[j].header.message_id = 0;
+     }
+   }
+  }else{
   if (UL_info->rach_ind.rach_indication_body.number_of_preambles>0) {
     AssertFatal(UL_info->rach_ind.rach_indication_body.number_of_preambles==1,"More than 1 preamble not supported\n");
     UL_info->rach_ind.rach_indication_body.number_of_preambles=0;
@@ -37,6 +61,7 @@ void handle_rach(UL_IND_t *UL_info) {
 #endif
                     );
   }
+  }
 
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
 
@@ -72,6 +97,22 @@ void handle_sr(UL_IND_t *UL_info) {
     if (UL_info->sr_ind.sr_indication_body.number_of_srs>0) {
       oai_nfapi_sr_indication(&UL_info->sr_ind);
     }
+  } else if(NFAPI_MODE == NFAPI_MODE_VNF){
+    for(uint8_t j = 0;j < NUM_NFPAI_SUBFRAME;j++){
+      if(UL_RCC_INFO.sr_ind[j].sr_indication_body.number_of_srs > 0){
+        for (i=0;i<UL_RCC_INFO.sr_ind[j].sr_indication_body.number_of_srs;i++){
+          SR_indication(UL_info->module_id,
+              UL_info->CC_id,
+              NFAPI_SFNSF2SFN(UL_RCC_INFO.sr_ind[j].sfn_sf),
+              NFAPI_SFNSF2SF(UL_RCC_INFO.sr_ind[j].sfn_sf),
+              UL_RCC_INFO.sr_ind[j].sr_indication_body.sr_pdu_list[i].rx_ue_information.rnti,
+              UL_RCC_INFO.sr_ind[j].sr_indication_body.sr_pdu_list[i].ul_cqi_information.ul_cqi);
+        }
+        free(UL_RCC_INFO.sr_ind[j].sr_indication_body.sr_pdu_list);
+        UL_RCC_INFO.sr_ind[j].sr_indication_body.number_of_srs=0;
+        UL_RCC_INFO.sr_ind[j].header.message_id = 0;
+      }
+    }
   } else {
     for (i=0; i<UL_info->sr_ind.sr_indication_body.number_of_srs; i++)
       SR_indication(UL_info->module_id,
@@ -89,27 +130,46 @@ void handle_cqi(UL_IND_t *UL_info) {
   int i;
 
   if (NFAPI_MODE==NFAPI_MODE_PNF) {
-    if (UL_info->cqi_ind.number_of_cqis>0) {
-      LOG_D(PHY,"UL_info->cqi_ind.number_of_cqis:%d\n", UL_info->cqi_ind.number_of_cqis);
-      nfapi_cqi_indication_t ind;
-      ind.header.message_id = NFAPI_RX_CQI_INDICATION;
-      ind.sfn_sf = UL_info->frame<<4 | UL_info->subframe;
-      ind.cqi_indication_body = UL_info->cqi_ind;
-      oai_nfapi_cqi_indication(&ind);
-      UL_info->cqi_ind.number_of_cqis=0;
+    if (UL_info->cqi_ind.cqi_indication_body.number_of_cqis>0) {
+      LOG_D(PHY,"UL_info->cqi_ind.number_of_cqis:%d\n", UL_info->cqi_ind.cqi_indication_body.number_of_cqis);
+      UL_info->cqi_ind.header.message_id = NFAPI_RX_CQI_INDICATION;
+      UL_info->cqi_ind.sfn_sf = UL_info->frame<<4 | UL_info->subframe;
+
+      oai_nfapi_cqi_indication(&UL_info->cqi_ind);
+      UL_info->cqi_ind.cqi_indication_body.number_of_cqis=0;
+    }
+  } else if (NFAPI_MODE == NFAPI_MODE_VNF) {
+    for(uint8_t j = 0;j < NUM_NFPAI_SUBFRAME;j++){
+      if(UL_RCC_INFO.cqi_ind[j].cqi_indication_body.number_of_cqis > 0){
+        for (i=0;i<UL_RCC_INFO.cqi_ind[j].cqi_indication_body.number_of_cqis;i++){
+          cqi_indication(UL_info->module_id,
+                         UL_info->CC_id,
+                         NFAPI_SFNSF2SFN(UL_RCC_INFO.cqi_ind[j].sfn_sf),
+                         NFAPI_SFNSF2SF(UL_RCC_INFO.cqi_ind[j].sfn_sf),
+                         UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_pdu_list[i].rx_ue_information.rnti,
+                         &UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_pdu_list[i].cqi_indication_rel9,
+                         UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_raw_pdu_list[i].pdu,
+                         &UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_pdu_list[i].ul_cqi_information);
+        }
+
+        free(UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_pdu_list);
+        free(UL_RCC_INFO.cqi_ind[j].cqi_indication_body.cqi_raw_pdu_list);
+        UL_RCC_INFO.cqi_ind[j].cqi_indication_body.number_of_cqis=0;
+        UL_RCC_INFO.cqi_ind[j].header.message_id = 0;
+      }
     }
   } else {
-    for (i=0; i<UL_info->cqi_ind.number_of_cqis; i++)
+    for (i=0;i<UL_info->cqi_ind.cqi_indication_body.number_of_cqis;i++)
       cqi_indication(UL_info->module_id,
                      UL_info->CC_id,
-                     UL_info->frame,
-                     UL_info->subframe,
-                     UL_info->cqi_ind.cqi_pdu_list[i].rx_ue_information.rnti,
-                     &UL_info->cqi_ind.cqi_pdu_list[i].cqi_indication_rel9,
-                     UL_info->cqi_ind.cqi_raw_pdu_list[i].pdu,
-                     &UL_info->cqi_ind.cqi_pdu_list[i].ul_cqi_information);
-
-    UL_info->cqi_ind.number_of_cqis=0;
+          NFAPI_SFNSF2SFN(UL_info->cqi_ind.sfn_sf),
+          NFAPI_SFNSF2SF(UL_info->cqi_ind.sfn_sf),
+          UL_info->cqi_ind.cqi_indication_body.cqi_pdu_list[i].rx_ue_information.rnti,
+          &UL_info->cqi_ind.cqi_indication_body.cqi_pdu_list[i].cqi_indication_rel9,
+          UL_info->cqi_ind.cqi_indication_body.cqi_raw_pdu_list[i].pdu,
+          &UL_info->cqi_ind.cqi_indication_body.cqi_pdu_list[i].ul_cqi_information);
+
+    UL_info->cqi_ind.cqi_indication_body.number_of_cqis=0;
   }
 }
 
@@ -123,7 +183,22 @@ void handle_harq(UL_IND_t *UL_info) {
     }
 
     UL_info->harq_ind.harq_indication_body.number_of_harqs = 0;
+  }else if(NFAPI_MODE == NFAPI_MODE_VNF){
+    for(uint8_t j = 0;j < NUM_NFPAI_SUBFRAME;j++){
+      if(UL_RCC_INFO.harq_ind[j].harq_indication_body.number_of_harqs > 0){
+        for (int i=0;i<UL_RCC_INFO.harq_ind[j].harq_indication_body.number_of_harqs;i++){
+          harq_indication(UL_info->module_id,
+                         UL_info->CC_id,
+                         NFAPI_SFNSF2SFN(UL_RCC_INFO.harq_ind[j].sfn_sf),
+                         NFAPI_SFNSF2SF(UL_RCC_INFO.harq_ind[j].sfn_sf),
+                         &UL_RCC_INFO.harq_ind[j].harq_indication_body.harq_pdu_list[i]);
+        }
 
+        free(UL_RCC_INFO.harq_ind[j].harq_indication_body.harq_pdu_list);
+        UL_RCC_INFO.harq_ind[j].harq_indication_body.number_of_harqs=0;
+        UL_RCC_INFO.harq_ind[j].header.message_id = 0;
+      }
+    }
   } else {
     for (int i=0; i < UL_info->harq_ind.harq_indication_body.number_of_harqs; i++)
       harq_indication(UL_info->module_id,
@@ -151,6 +226,56 @@ void handle_ulsch(UL_IND_t *UL_info) {
       oai_nfapi_rx_ind(&UL_info->rx_ind);
       UL_info->rx_ind.rx_indication_body.number_of_pdus = 0;
     }
+  } else if(NFAPI_MODE == NFAPI_MODE_VNF){
+    for(uint8_t k = 0;k < NUM_NFPAI_SUBFRAME;k++){
+      if((UL_RCC_INFO.rx_ind[k].rx_indication_body.number_of_pdus>0) && (UL_RCC_INFO.crc_ind[k].crc_indication_body.number_of_crcs>0)){
+        for (i=0;i<UL_RCC_INFO.rx_ind[k].rx_indication_body.number_of_pdus;i++) {
+          for (j=0;j<UL_RCC_INFO.crc_ind[k].crc_indication_body.number_of_crcs;j++) {
+            // find crc_indication j corresponding rx_indication i
+            LOG_D(PHY,"UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].rx_ue_information.rnti:%04x UL_info->rx_ind.rx_indication_body.rx_pdu_list[%d].rx_ue_information.rnti:%04x\n",
+                       j,UL_RCC_INFO.crc_ind[k].crc_indication_body.crc_pdu_list[j].rx_ue_information.rnti, i,UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti);
+            if (UL_RCC_INFO.crc_ind[k].crc_indication_body.crc_pdu_list[j].rx_ue_information.rnti == UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti) {
+              LOG_D(PHY, "UL_info->crc_ind.crc_indication_body.crc_pdu_list[%d].crc_indication_rel8.crc_flag:%d\n",
+                          j, UL_RCC_INFO.crc_ind[k].crc_indication_body.crc_pdu_list[j].crc_indication_rel8.crc_flag);
+              if (UL_RCC_INFO.crc_ind[k].crc_indication_body.crc_pdu_list[j].crc_indication_rel8.crc_flag == 1) { // CRC error indication
+                LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC error) \n",UL_info->frame,UL_info->subframe);
+                  rx_sdu(UL_info->module_id,
+                      UL_info->CC_id,
+                      NFAPI_SFNSF2SFN(UL_RCC_INFO.rx_ind[k].sfn_sf), //UL_info->frame,
+                      NFAPI_SFNSF2SF(UL_RCC_INFO.rx_ind[k].sfn_sf), //UL_info->subframe,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti,
+                      (uint8_t *)NULL,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi);
+              }
+              else {
+                  LOG_D(MAC,"Frame %d, Subframe %d Calling rx_sdu (CRC ok) \n",UL_info->frame,UL_info->subframe);
+                  rx_sdu(UL_info->module_id,
+                      UL_info->CC_id,
+                      NFAPI_SFNSF2SFN(UL_RCC_INFO.rx_ind[k].sfn_sf), //UL_info->frame,
+                      NFAPI_SFNSF2SF(UL_RCC_INFO.rx_ind[k].sfn_sf), //UL_info->subframe,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_ue_information.rnti,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].data,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.length,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.timing_advance,
+                      UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].rx_indication_rel8.ul_cqi);
+              }
+              if(UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].data != NULL){
+                free(UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list[i].data);
+              }
+              break;
+            } //if (UL_info->crc_ind.crc_pdu_list[j].rx_ue_information.rnti == UL_info->rx_ind.rx_pdu_list[i].rx_ue_information.rnti)
+          } //    for (j=0;j<UL_info->crc_ind.crc_indication_body.number_of_crcs;j++)
+        } //   for (i=0;i<UL_info->rx_ind.number_of_pdus;i++)
+        free(UL_RCC_INFO.crc_ind[k].crc_indication_body.crc_pdu_list);
+        free(UL_RCC_INFO.rx_ind[k].rx_indication_body.rx_pdu_list);
+        UL_RCC_INFO.crc_ind[k].crc_indication_body.number_of_crcs = 0;
+        UL_RCC_INFO.crc_ind[k].header.message_id =0;
+        UL_RCC_INFO.rx_ind[k].rx_indication_body.number_of_pdus = 0;
+        UL_RCC_INFO.rx_ind[k].header.message_id = 0;
+      }
+    }
   } else {
     if (UL_info->rx_ind.rx_indication_body.number_of_pdus>0 && UL_info->crc_ind.crc_indication_body.number_of_crcs>0) {
       for (i=0; i<UL_info->rx_ind.rx_indication_body.number_of_pdus; i++) {
@@ -574,11 +699,11 @@ void UL_indication(UL_IND_t *UL_info) {
   Sched_Rsp_t  *sched_info = &Sched_INFO[module_id][CC_id];
   IF_Module_t  *ifi        = if_inst[module_id];
   eNB_MAC_INST *mac        = RC.mac[module_id];
+
   LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rx_ind:%d harqs:%d crcs:%d cqis:%d preambles:%d sr_ind:%d]\n",
         UL_info->frame,UL_info->subframe,
         module_id,CC_id,
-        UL_info->rx_ind.rx_indication_body.number_of_pdus, UL_info->harq_ind.harq_indication_body.number_of_harqs, UL_info->crc_ind.crc_indication_body.number_of_crcs, UL_info->cqi_ind.number_of_cqis,
-        UL_info->rach_ind.rach_indication_body.number_of_preambles, UL_info->sr_ind.sr_indication_body.number_of_srs);
+        UL_info->rx_ind.rx_indication_body.number_of_pdus, UL_info->harq_ind.harq_indication_body.number_of_harqs, UL_info->crc_ind.crc_indication_body.number_of_crcs, UL_info->cqi_ind.cqi_indication_body.number_of_cqis, UL_info->rach_ind.rach_indication_body.number_of_preambles, UL_info->sr_ind.sr_indication_body.number_of_srs);
 
   if(UL_info->frame==1023&&UL_info->subframe==6) { // dl scheduling (0,0)
     frame_cnt= (frame_cnt + 1)%7; // to prevent frame_cnt get too big
@@ -604,6 +729,7 @@ void UL_indication(UL_IND_t *UL_info) {
   handle_sr(UL_info);
   handle_cqi(UL_info);
   handle_harq(UL_info);
+
   // clear HI prior to handling ULSCH
   uint8_t sf_ahead_dl = ul_subframe2_k_phich(&mac->common_channels[CC_id], UL_info->subframe);
 
@@ -634,6 +760,9 @@ void UL_indication(UL_IND_t *UL_info) {
         sched_info->UL_req      = NULL;
 
       sched_info->TX_req      = &mac->TX_req[CC_id];
+      pthread_mutex_lock(&lock_ue_freelist);
+      sched_info->UE_release_req = &mac->UE_release_req;
+      pthread_mutex_unlock(&lock_ue_freelist);
 #ifdef DUMP_FAPI
       dump_dl(sched_info);
 #endif
diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h
index b6ede7d598a05f1e06e802fb0d52b46a96510b50..c42ba992c912c9e1c008b9e4dad89e08ff5c6ffa 100644
--- a/openair2/PHY_INTERFACE/IF_Module.h
+++ b/openair2/PHY_INTERFACE/IF_Module.h
@@ -71,7 +71,7 @@ typedef struct{
   nfapi_sr_indication_t sr_ind;
 
   /// CQI indication list
-  nfapi_cqi_indication_body_t cqi_ind;
+  nfapi_cqi_indication_t cqi_ind;
 
   /// RACH indication list
   nfapi_rach_indication_t rach_ind;
@@ -90,7 +90,27 @@ typedef struct{
 } UL_IND_t;
 
 // Downlink subframe P7
+#define NUM_NFPAI_SUBFRAME 5
+typedef struct{
+  /// harq indication list
+  nfapi_harq_indication_t harq_ind[NUM_NFPAI_SUBFRAME];
+
+  /// crc indication list
+  nfapi_crc_indication_t crc_ind[NUM_NFPAI_SUBFRAME];
+
+  /// SR indication list
+  nfapi_sr_indication_t sr_ind[NUM_NFPAI_SUBFRAME];
+
+  /// CQI indication list
+  nfapi_cqi_indication_t cqi_ind[NUM_NFPAI_SUBFRAME];
+
+  /// RACH indication list
+  nfapi_rach_indication_t rach_ind[NUM_NFPAI_SUBFRAME];
+
+  /// RX indication
+  nfapi_rx_indication_t rx_ind[NUM_NFPAI_SUBFRAME];
 
+} UL_RCC_IND_t;
 
 typedef struct{
   /// Module ID
@@ -109,6 +129,8 @@ typedef struct{
   nfapi_hi_dci0_request_t *HI_DCI0_req;
   /// Pointers to DL SDUs
   nfapi_tx_request_t *TX_req;
+  /// Pointers to ue_release
+  nfapi_ue_release_request_t *UE_release_req;
 }Sched_Rsp_t;
 
 typedef struct {
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c
index 8d625fbdc59337c86d4609e9a386314e411243c5..930387c742489c1a413cd76b3bb3a56bb3f74502 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.c
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.c
@@ -236,8 +236,8 @@ void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, uint16_t frame,uint8_t subfram
 	// change for mutiple UE's simulation.
 	//pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
 	pthread_mutex_lock(&fill_ul_mutex.cqi_mutex);
-	nfapi_cqi_indication_pdu_t *pdu         = &UL_INFO->cqi_ind.cqi_pdu_list[UL_INFO->cqi_ind.number_of_cqis];
-	nfapi_cqi_indication_raw_pdu_t *raw_pdu = &UL_INFO->cqi_ind.cqi_raw_pdu_list[UL_INFO->cqi_ind.number_of_cqis];
+	nfapi_cqi_indication_pdu_t *pdu         = &UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list[UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis];
+	nfapi_cqi_indication_raw_pdu_t *raw_pdu = &UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list[UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis];
 
 	pdu->rx_ue_information.tl.tag          = NFAPI_RX_UE_INFORMATION_TAG;
 	pdu->rx_ue_information.rnti = rnti;
@@ -263,7 +263,7 @@ void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, uint16_t frame,uint8_t subfram
 
 
 
-  UL_INFO->cqi_ind.number_of_cqis++;
+  UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis++;
   // change for mutiple UE's simulation.
   //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
   pthread_mutex_unlock(&fill_ul_mutex.cqi_mutex);
diff --git a/openair2/RRC/LTE/L2_interface.c b/openair2/RRC/LTE/L2_interface.c
index de96213a7581b1f96ca322a48136ac2d4f40e6f2..b4281637a1b6ca9b2969fe07a1fd851f1b518e5c 100644
--- a/openair2/RRC/LTE/L2_interface.c
+++ b/openair2/RRC/LTE/L2_interface.c
@@ -310,10 +310,13 @@ mac_rrc_data_ind(
     ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt.module_id],rntiP);
 
     if(ue_context_p) {
-      rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt,
-          ue_context_p,
-          0);
-      ue_context_p->ue_context.Status = RRC_RECONFIGURED;
+      if (ue_context_p->ue_context.Status != RRC_RECONFIGURED) {
+        LOG_E(RRC,"[eNB %d] Received C-RNTI ,but UE %x status(%d) not RRC_RECONFIGURED\n",module_idP,rntiP,ue_context_p->ue_context.Status);
+        return (-1);
+      } else {
+        rrc_eNB_generate_defaultRRCConnectionReconfiguration(&ctxt,ue_context_p,0);
+        ue_context_p->ue_context.Status = RRC_RECONFIGURED;
+      }
     }
   }
 
@@ -363,8 +366,7 @@ void mac_eNB_rrc_ul_failure(const module_id_t Mod_instP,
     flexran_agent_get_rrc_xface(Mod_instP)->flexran_agent_notify_ue_state_change(Mod_instP,
 								     rntiP, PROTOCOL__FLEX_UE_STATE_CHANGE_TYPE__FLUESC_DEACTIVATED);
   }
-
-  rrc_mac_remove_ue(Mod_instP,rntiP);
+  //rrc_mac_remove_ue(Mod_instP,rntiP);
 }
 
 void mac_eNB_rrc_uplane_failure(const module_id_t Mod_instP,
diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.c b/openair2/RRC/LTE/MESSAGES/asn1_msg.c
index f2845a50d7b124ee44c73a4000b9afc2a1ea2bf9..d4e00ca96d08ca44c4c5969792c5c9fd71740b9a 100644
--- a/openair2/RRC/LTE/MESSAGES/asn1_msg.c
+++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.c
@@ -4071,6 +4071,7 @@ do_RRCConnectionReestablishment(
   LTE_DL_CCCH_Message_t dl_ccch_msg;
   LTE_RRCConnectionReestablishment_t *rrcConnectionReestablishment = NULL;
   int i = 0;
+  ue_context_pP->ue_context.reestablishment_xid = Transaction_id;
   LTE_SRB_ToAddModList_t **SRB_configList2 = NULL;
   SRB_configList2 = &ue_context_pP->ue_context.SRB_configList2[Transaction_id];
 
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index 559b2bfb3844251603cb2b44fb621f7e6371f890..8cb53e577b4029b0029af9be48821c204663b88d 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -348,11 +348,24 @@ typedef enum HO_STATE_e {
   HO_COMPLETE, // initiated by the target eNB
   HO_REQUEST,
   HO_ACK,
+  HO_FORWARDING,
   HO_CONFIGURED,
+  HO_END_MARKER,
+  HO_FORWARDING_COMPLETE,
   HO_RELEASE,
   HO_CANCEL
 } HO_STATE_t;
 
+typedef enum DATA_FORWARDING_STATE_e {
+  FORWARDING_EMPTY=0,
+  FORWARDING_NO_EMPTY
+} DATA_FORWARDING_STATE_t;
+
+typedef enum DATA_ENDMARK_STATE_e {
+  ENDMARK_EMPTY=0,
+  ENDMARK_NO_EMPTY
+} DATA_ENDMARK_STATE_t;
+
 typedef enum SL_TRIGGER_e {
   SL_RECEIVE_COMMUNICATION=0,
   SL_TRANSMIT_RELAY_ONE_TO_ONE,
@@ -477,6 +490,9 @@ typedef struct HANDOVER_INFO_s {
   uint8_t buf[RRC_BUF_SIZE];  /* ASN.1 encoded handoverCommandMessage */
   int size;   /* size of above message in bytes */
   int x2_id;   /* X2AP UE ID in the target eNB */
+  uint32_t x2u_teid;
+  DATA_FORWARDING_STATE_t forwarding_state;
+  DATA_ENDMARK_STATE_t endmark_state;
 } HANDOVER_INFO;
 
 typedef struct PER_EVENT_s {
@@ -693,6 +709,12 @@ typedef struct eNB_RRC_UE_s {
   uint32_t                           enb_gtp_teid[S1AP_MAX_E_RAB];
   transport_layer_addr_t             enb_gtp_addrs[S1AP_MAX_E_RAB];
   rb_id_t                            enb_gtp_ebi[S1AP_MAX_E_RAB];
+  /* Total number of e_rab already setup in the list */
+  uint8_t                            nb_x2u_e_rabs;
+  // LG: For GTPV1 TUNNELS(X2U)
+  uint32_t                           enb_gtp_x2u_teid[S1AP_MAX_E_RAB];
+  transport_layer_addr_t             enb_gtp_x2u_addrs[S1AP_MAX_E_RAB];
+  rb_id_t                            enb_gtp_x2u_ebi[S1AP_MAX_E_RAB];
   uint32_t                           ul_failure_timer;
   uint32_t                           ue_release_timer;
   uint32_t                           ue_release_timer_thres;
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index 78a94e5245eee868ac43a650ddd1831a9e5a30aa..2c4dea77af82a8eb8f46a630530a2c0593e5afeb 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -1114,6 +1114,8 @@ void put_UE_in_freelist(module_id_t mod_id, rnti_t rnti, boolean_t removeFlag) {
   free_list->UE_free_ctrl[free_list->tail_freelist].rnti = rnti;
   free_list->UE_free_ctrl[free_list->tail_freelist].removeContextFlg = removeFlag;
   free_list->num_UEs++;
+  eNB_MAC->UE_release_req.ue_release_request_body.ue_release_request_TLVs_list[eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs].rnti = rnti;
+  eNB_MAC->UE_release_req.ue_release_request_body.number_of_TLVs++;
   free_list->tail_freelist = (free_list->tail_freelist + 1) % (NUMBER_OF_UE_MAX+1);
   pthread_mutex_unlock(&lock_ue_freelist);
 }
@@ -1158,28 +1160,32 @@ void release_UE_in_freeList(module_id_t mod_id) {
 
         for (i=0; i<MAX_MOBILES_PER_ENB; i++) {
           ulsch = eNB_PHY->ulsch[i];
-
           if((ulsch != NULL) && (ulsch->rnti == rnti)) {
             void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
             LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti);
             clean_eNb_ulsch(ulsch);
           }
 
-          if(eNB_PHY->uci_vars[i].rnti == rnti) {
-            LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti);
-            memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI));
-          }
-        }
-
-        for (i=0; i<MAX_MOBILES_PER_ENB; i++) {
           dlsch = eNB_PHY->dlsch[i][0];
-
           if((dlsch != NULL) && (dlsch->rnti == rnti)) {
             void clean_eNb_dlsch(LTE_eNB_DLSCH_t *dlsch);
             LOG_I(RRC, "clean_eNb_dlsch dlsch[%d] UE %x \n", i, rnti);
             clean_eNb_dlsch(dlsch);
           }
         }
+        ulsch = eNB_PHY->ulsch[i];
+        if((ulsch != NULL) && (ulsch->rnti == rnti)) {
+          void clean_eNb_ulsch(LTE_eNB_ULSCH_t *ulsch);
+          LOG_I(RRC, "clean_eNb_ulsch ulsch[%d] UE %x\n", i, rnti);
+          clean_eNb_ulsch(ulsch);
+        }
+
+        for (i=0; i<NUMBER_OF_UCI_VARS_MAX; i++) {
+          if(eNB_PHY->uci_vars[i].rnti == rnti) {
+            LOG_I(MAC, "clean eNb uci_vars[%d] UE %x \n",i, rnti);
+            memset(&eNB_PHY->uci_vars[i],0,sizeof(LTE_eNB_UCI));
+          }
+        }
 
         if (flexran_agent_get_rrc_xface(mod_id)) {
           flexran_agent_get_rrc_xface(mod_id)->flexran_agent_notify_ue_state_change(
@@ -1241,6 +1247,34 @@ void release_UE_in_freeList(module_id_t mod_id) {
   }
 }
 
+int rrc_eNB_previous_SRB2(rrc_eNB_ue_context_t*         ue_context_pP)
+{
+  struct LTE_SRB_ToAddMod                *SRB2_config = NULL;
+  uint8_t i;
+  LTE_SRB_ToAddModList_t*                 SRB_configList = ue_context_pP->ue_context.SRB_configList;
+  LTE_SRB_ToAddModList_t**                SRB_configList2 = &ue_context_pP->ue_context.SRB_configList2[ue_context_pP->ue_context.reestablishment_xid];
+  if (*SRB_configList2 != NULL) {
+    if((*SRB_configList2)->list.count!=0){
+      LOG_D(RRC, "rrc_eNB_previous_SRB2 SRB_configList2(%p) count is %d\n           SRB_configList2->list.array[0] addr is %p",
+              SRB_configList2, (*SRB_configList2)->list.count,  (*SRB_configList2)->list.array[0]);
+    }
+    for (i = 0; (i < (*SRB_configList2)->list.count) && (i < 3); i++) {
+      if ((*SRB_configList2)->list.array[i]->srb_Identity == 2 ){
+        SRB2_config = (*SRB_configList2)->list.array[i];
+        break;
+      }
+    }
+  }else{
+    LOG_E(RRC, "rrc_eNB_previous_SRB2 SRB_configList2 NULL\n");
+  }
+
+  if (SRB2_config != NULL) {
+    ASN_SEQUENCE_ADD(&SRB_configList->list, SRB2_config);
+  }else{
+    LOG_E(RRC, "rrc_eNB_previous_SRB2 SRB2_config NULL\n");
+  }
+  return 0;
+}
 //-----------------------------------------------------------------------------
 /*
 * Process the rrc connection setup complete message from UE (SRB1 Active)
@@ -1556,10 +1590,6 @@ rrc_eNB_generate_RRCConnectionReestablishment(
           rnti);
   }
 
-  /* Activate release timer, if RRCComplete not received after 100 frames, remove UE */
-  ue_context_pP->ue_context.ue_reestablishment_timer = 1;
-  /* Remove UE after 100 frames after LTE_RRCConnectionReestablishmentReject is triggered */
-  ue_context_pP->ue_context.ue_reestablishment_timer_thres = 1000;
 }
 
 //-----------------------------------------------------------------------------
@@ -1606,6 +1636,8 @@ rrc_eNB_process_RRCConnectionReestablishmentComplete(
   LTE_C_RNTI_t                           *cba_RNTI                         = NULL;
   int                                    measurements_enabled;
   uint8_t next_xid = rrc_eNB_get_next_transaction_identifier(ctxt_pP->module_id);
+  int ret = 0;
+
   ue_context_pP->ue_context.Status = RRC_CONNECTED;
   ue_context_pP->ue_context.ue_rrc_inactivity_timer = 1; // set rrc inactivity when UE goes into RRC_CONNECTED
   ue_context_pP->ue_context.reestablishment_xid = next_xid;
@@ -1711,10 +1743,36 @@ rrc_eNB_process_RRCConnectionReestablishmentComplete(
 
   create_tunnel_req.rnti       = ctxt_pP->rnti; // warning put zero above
   create_tunnel_req.num_tunnels    = j;
-  gtpv1u_update_s1u_tunnel(
+
+    ret = gtpv1u_update_s1u_tunnel(
     ctxt_pP->instance,
     &create_tunnel_req,
     reestablish_rnti);
+    if ( ret != 0 ) {
+      LOG_E(RRC,"gtpv1u_update_s1u_tunnel failed,start to release UE %x\n",reestablish_rnti);
+      // update s1u tunnel failed,reset rnti?
+      if (eNB_ue_s1ap_id > 0) {
+        h_rc = hashtable_get(rrc_instance_p->s1ap_id2_s1ap_ids, (hash_key_t)eNB_ue_s1ap_id, (void**)&rrc_ue_s1ap_ids_p);
+        if (h_rc == HASH_TABLE_OK ) {
+          rrc_ue_s1ap_ids_p->ue_rnti = reestablish_rnti;
+        }
+      }
+      if (ue_initial_id != 0) {
+        h_rc = hashtable_get(rrc_instance_p->initial_id2_s1ap_ids, (hash_key_t)ue_initial_id, (void**)&rrc_ue_s1ap_ids_p);
+        if (h_rc == HASH_TABLE_OK ) {
+          rrc_ue_s1ap_ids_p->ue_rnti = reestablish_rnti;
+        }
+      }
+      ue_context_pP->ue_context.ue_release_timer_s1 = 1;
+      ue_context_pP->ue_context.ue_release_timer_thres_s1 = 100;
+      ue_context_pP->ue_context.ue_release_timer = 0;
+      ue_context_pP->ue_context.ue_reestablishment_timer = 0;
+      ue_context_pP->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ
+      rrc_eNB_free_UE(ctxt_pP->module_id,ue_context_pP);
+      ue_context_pP->ue_context.ul_failure_timer = 0;
+      put_UE_in_freelist(ctxt_pP->module_id, ctxt_pP->rnti, 0);
+      return;
+    }
   } /* EPC_MODE_ENABLED */
 
   /* Update RNTI in ue_context */
@@ -2236,8 +2294,9 @@ rrc_eNB_generate_RRCConnectionRelease(
     ue_context_pP->ue_context.rnti,
     rrc_eNB_mui,
     size);
-  pthread_mutex_lock(&rrc_release_freelist);
-
+  while (pthread_mutex_trylock(&rrc_release_freelist)) {
+    /* spin... */
+  }
   for (uint16_t release_num = 0; release_num < NUMBER_OF_UE_MAX; release_num++) {
     if (rrc_release_info.RRC_release_ctrl[release_num].flag == 0) {
       if (ue_context_pP->ue_context.ue_release_timer_s1 > 0) {
@@ -4060,8 +4119,40 @@ flexran_rrc_eNB_generate_defaultRRCConnectionReconfiguration(const protocol_ctxt
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0] = 0;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.size = 1;
   MeasObj->measObject.choice.measObjectEUTRA.neighCellConfig.bits_unused = 6;
-  MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = (LTE_Q_OffsetRange_t *) CALLOC(1,sizeof(LTE_Q_OffsetRange_t));
-  *(MeasObj->measObject.choice.measObjectEUTRA.offsetFreq) = ue_context_pP->ue_context.measurement_info->offsetFreq;   // Default is 15 or 0dB
+//<<<<<<< HEAD
+  MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = NULL;   // Default is 15 or 0dB
+  if (rrc_inst->carrier[0].sib1->tdd_Config!=NULL) {
+    MeasObj->measObject.choice.measObjectEUTRA.ext1 = CALLOC(1, sizeof(struct LTE_MeasObjectEUTRA__ext1));
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measCycleSCell_r10 = NULL;
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10 = CALLOC(1, sizeof(struct LTE_MeasSubframePatternConfigNeigh_r10));
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->present=LTE_MeasSubframePatternConfigNeigh_r10_PR_setup;
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.present=LTE_MeasSubframePattern_r10_PR_subframePatternTDD_r10;
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.present=LTE_MeasSubframePattern_r10__subframePatternTDD_r10_PR_subframeConfig1_5_r10;
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf=CALLOC(3, sizeof(uint8_t));
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.size=3;
+    MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.bits_unused=4; 
+    switch (rrc_inst->carrier[0].sib1->tdd_Config->subframeAssignment) {
+    case 1: //subframe 0,4,5,9
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[0]=0x8C;
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[1]=0x63;
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[2]=0x10;
+      break;
+
+    default: //subframe 0 , 5
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[0]=0x84;
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[1]=0x21;
+      MeasObj->measObject.choice.measObjectEUTRA.ext1->measSubframePatternConfigNeigh_r10->choice.setup.measSubframePatternNeigh_r10.choice.subframePatternTDD_r10.choice.subframeConfig1_5_r10.buf[2]=0x00;
+      break;
+    }
+  }
+
+  MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
+    (LTE_CellsToAddModList_t *) CALLOC(1, sizeof(*CellsToAddModList));
+  CellsToAddModList = MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList;
+//=======
+//  MeasObj->measObject.choice.measObjectEUTRA.offsetFreq = (LTE_Q_OffsetRange_t *) CALLOC(1,sizeof(LTE_Q_OffsetRange_t));
+//  *(MeasObj->measObject.choice.measObjectEUTRA.offsetFreq) = ue_context_pP->ue_context.measurement_info->offsetFreq;   // Default is 15 or 0dB
+//>>>>>>> origin/OAI_develop
 
   if (RC.rrc[ctxt_pP->module_id]->num_neigh_cells > 0) {
     MeasObj->measObject.choice.measObjectEUTRA.cellsToAddModList =
@@ -4557,7 +4648,9 @@ rrc_eNB_process_MeasurementReport(
     /* HO info struct may not be needed anymore */
     ue_context_pP->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_pP->ue_context.handover_info)));
     ue_context_pP->ue_context.Status = RRC_HO_EXECUTION;
+
     ue_context_pP->ue_context.handover_info->state = HO_REQUEST;
+
     /* HO Preparation message */
     msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ);
     rrc_eNB_generate_HandoverPreparationInformation(
@@ -4685,8 +4778,8 @@ void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_re
   RB_INSERT(rrc_ue_tree_s, &RC.rrc[mod_id]->rrc_ue_head, ue_context_target_p);
   LOG_D(RRC, "eNB %d: Created new UE context uid %u\n", mod_id, ue_context_target_p->local_uid);
   ue_context_target_p->ue_context.handover_info = CALLOC(1, sizeof(*(ue_context_target_p->ue_context.handover_info)));
-  ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
-  ue_context_target_p->ue_context.handover_info->state = HO_ACK;
+  //ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
+  //ue_context_target_p->ue_context.handover_info->state = HO_ACK;
   ue_context_target_p->ue_context.handover_info->x2_id = m->x2_id;
   ue_context_target_p->ue_context.handover_info->assoc_id = m->target_assoc_id;
   memset (ue_context_target_p->ue_context.nh, 0, 32);
@@ -4760,6 +4853,10 @@ void rrc_eNB_process_handoverPreparationInformation(int mod_id, x2ap_handover_re
           ue_context_target_p->ue_context.e_rab[i].param.e_rab_id,
           ue_context_target_p->ue_context.e_rab[i].param.gtp_teid);
   }
+  rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(mod_id, ue_context_target_p);
+
+  ue_context_target_p->ue_context.Status = RRC_HO_EXECUTION;
+  ue_context_target_p->ue_context.handover_info->state = HO_ACK;
 }
 
 void rrc_eNB_process_handoverCommand(
@@ -4975,7 +5072,8 @@ check_handovers(
       if (ue_context_p->ue_context.handover_info->state == HO_ACK) {
         MessageDef *msg;
         // Configure target
-        ue_context_p->ue_context.handover_info->state = HO_CONFIGURED;
+        ue_context_p->ue_context.handover_info->state = HO_FORWARDING;
+
         msg = itti_alloc_new_message(TASK_RRC_ENB, X2AP_HANDOVER_REQ_ACK);
         rrc_eNB_generate_HO_RRCConnectionReconfiguration(ctxt_pP, ue_context_p, X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer,
             &X2AP_HANDOVER_REQ_ACK(msg).rrc_buffer_size);
@@ -4988,13 +5086,162 @@ check_handovers(
         X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = ue_context_p->ue_context.setup_e_rabs;
 
         for (int i=0; i<ue_context_p->ue_context.setup_e_rabs; i++) {
+          /* set gtpv teid info */
           X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id = ue_context_p->ue_context.e_rab[i].param.e_rab_id;
+	  X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid = ue_context_p->ue_context.enb_gtp_x2u_teid[i];
+          X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr = ue_context_p->ue_context.enb_gtp_x2u_addrs[i];
         }
 
         itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(ctxt_pP->module_id), msg);
         LOG_I(RRC, "RRC Sends X2 HO ACK to the source eNB at frame %d and subframe %d \n", ctxt_pP->frame,ctxt_pP->subframe);
       }
     }
+
+    if (ue_context_p->ue_context.Status == RRC_RECONFIGURED 
+	&& ue_context_p->ue_context.handover_info != NULL && 
+	ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_NO_EMPTY ) {
+
+#if defined(ENABLE_ITTI)
+      MessageDef	 *msg_p;
+      int		 result;
+      protocol_ctxt_t  ctxt;
+
+      do {
+        // Checks if a message has been sent to PDCP sub-task
+	itti_poll_msg (TASK_DATA_FORWARDING, &msg_p);
+  
+	if (msg_p != NULL) {
+  
+	  switch (ITTI_MSG_ID(msg_p)) {
+	    case GTPV1U_ENB_DATA_FORWARDING_IND:
+	    PROTOCOL_CTXT_SET_BY_MODULE_ID(
+			&ctxt,
+			GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).module_id,
+			GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).enb_flag,
+			GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rnti,
+			GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).frame, 
+		        0,
+		        GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).eNB_index);
+	    LOG_D(RRC, PROTOCOL_CTXT_FMT"[check_handovers]Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n",
+		  PROTOCOL_CTXT_ARGS(&ctxt),
+		  ITTI_MSG_NAME (msg_p),
+		  ITTI_MSG_ORIGIN_NAME(msg_p),
+		  ITTI_MSG_INSTANCE (msg_p),
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode);
+  
+	    LOG_I(RRC, "Before calling pdcp_data_req from check_handovers! GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id: %d \n", GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id);
+            result = pdcp_data_req (&ctxt,
+				    SRB_FLAG_NO,
+			            GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+				    GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+				    GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+			            GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_size,
+				    GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_p,
+				    GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+				    , NULL, NULL
+#endif
+				    );
+	    if (result != TRUE){
+              LOG_E(RRC, "target enb send data forwarding buffer to PDCP request failed!\n");   
+            }else{
+              LOG_D(RRC, "target enb send data forwarding buffer to PDCP!\n");
+            }
+
+            // Message buffer has been processed, free it now.
+	    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).sdu_p);
+	    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+            break;
+  
+	default:
+	  LOG_E(RRC, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
+	  break;
+	}
+  
+	result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+	AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+      }
+    } while(msg_p != NULL);
+    ue_context_p->ue_context.handover_info->forwarding_state = FORWARDING_EMPTY;
+    }
+    if( ue_context_p->ue_context.Status == RRC_RECONFIGURED &&
+	ue_context_p->ue_context.handover_info != NULL &&
+	ue_context_p->ue_context.handover_info->forwarding_state == FORWARDING_EMPTY &&
+	ue_context_p->ue_context.handover_info->endmark_state == ENDMARK_NO_EMPTY &&
+	ue_context_p->ue_context.handover_info->state == HO_END_MARKER	  ){
+
+      MessageDef	 *msg_p;
+      int		 result;
+      protocol_ctxt_t  ctxt;
+
+      do {
+        // Checks if a message has been sent to PDCP sub-task
+        itti_poll_msg (TASK_END_MARKER, &msg_p);
+
+        if (msg_p != NULL) {
+
+	switch (ITTI_MSG_ID(msg_p)) {
+	  case GTPV1U_ENB_END_MARKER_IND:
+	    PROTOCOL_CTXT_SET_BY_MODULE_ID(
+	        &ctxt,
+		GTPV1U_ENB_END_MARKER_IND (msg_p).module_id,
+	        GTPV1U_ENB_END_MARKER_IND (msg_p).enb_flag,
+		GTPV1U_ENB_END_MARKER_IND (msg_p).rnti,
+		GTPV1U_ENB_END_MARKER_IND (msg_p).frame,
+		0,
+		GTPV1U_ENB_END_MARKER_IND (msg_p).eNB_index);
+	    LOG_I(RRC, PROTOCOL_CTXT_FMT"[check_handovers]Received %s from %s: instance %d, rb_id %d, muiP %d, confirmP %d, mode %d\n",
+		  PROTOCOL_CTXT_ARGS(&ctxt),
+		  ITTI_MSG_NAME (msg_p),
+		  ITTI_MSG_ORIGIN_NAME(msg_p),
+		  ITTI_MSG_INSTANCE (msg_p),
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).muip,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).confirmp,
+		  GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).mode);
+
+	    LOG_D(RRC, "Before calling pdcp_data_req from check_handovers! GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id: %d \n", GTPV1U_ENB_DATA_FORWARDING_IND (msg_p).rb_id);
+	    result = pdcp_data_req (&ctxt,
+		  		    SRB_FLAG_NO,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).rb_id,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).muip,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).confirmp,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_size,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_p,
+		  		    GTPV1U_ENB_END_MARKER_IND (msg_p).mode
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+		  		    , NULL, NULL
+#endif
+		  		   );
+	    if (result != TRUE){
+              LOG_E(RRC, "target enb send spgw buffer to PDCP request failed!\n");
+	    }else{
+	      LOG_D(RRC, "target enb send spgw buffer to PDCP!\n");
+	    }
+
+	    // Message buffer has been processed, free it now.
+	    result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), GTPV1U_ENB_END_MARKER_IND (msg_p).sdu_p);
+	    AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+	    break;
+
+	    default:
+	      LOG_E(RRC, "Received unexpected message %s\n", ITTI_MSG_NAME (msg_p));
+	      break;
+          }
+
+          result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
+          AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+        }
+      } while(msg_p != NULL);
+
+      ue_context_p->ue_context.handover_info->endmark_state = ENDMARK_EMPTY;
+      ue_context_p->ue_context.handover_info->state = HO_FORWARDING_COMPLETE;
+
+#endif
+    }
   }
 }
 
@@ -7006,15 +7253,51 @@ rrc_eNB_decode_ccch(
             rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id);
             break;
           }
-
+      if((RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer > 0) &&
+         (RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer_thres > 20)){
+         LOG_E(RRC,
+               PROTOCOL_RRC_CTXT_UE_FMT" RCConnectionReestablishmentComplete(Previous) don't receive, delete the c-rnti UE\n",
+               PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP));
+         RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 1000;
+         rrc_eNB_previous_SRB2(ue_context_p);
+         ue_context_p->ue_context.ue_reestablishment_timer = 0;
+      }
+      //previous rnti
+      rnti_t previous_rnti = 0;
+      for (i = 0; i < MAX_MOBILES_PER_ENB; i++) {
+        if (reestablish_rnti_map[i][1] == c_rnti) {
+          previous_rnti = reestablish_rnti_map[i][0];
+          break;
+        }
+      }
+      if(previous_rnti != 0){
+        UE_id = find_UE_id(ctxt_pP->module_id, previous_rnti);
+        if(UE_id == -1){
+            LOG_E(RRC,
+                  PROTOCOL_RRC_CTXT_UE_FMT" RRCConnectionReestablishmentRequest without UE_id(MAC) previous rnti %x, let's reject the UE\n",
+                  PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),previous_rnti);
+            rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id);
+            break;
+        }
           if((RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer > 0) &&
               (RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer_thres > 20)) {
             LOG_E(RRC,
                   PROTOCOL_RRC_CTXT_UE_FMT" RCConnectionReestablishmentComplete(Previous) don't receive, delete the Previous UE\n",
                   PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP));
             RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 1000;
-            ue_context_p->ue_context.ue_reestablishment_timer = 0;
-          }
+          rrc_eNB_previous_SRB2(ue_context_p);
+          ue_context_p->ue_context.ue_reestablishment_timer = 0;
+        }
+      }
+
+      //c-plane not end
+      if((ue_context_p->ue_context.Status != RRC_RECONFIGURED) && (ue_context_p->ue_context.reestablishment_cause == LTE_ReestablishmentCause_spare1)) {
+        LOG_E(RRC,
+             PROTOCOL_RRC_CTXT_UE_FMT" LTE_RRCConnectionReestablishmentRequest (UE %x c-plane is not end), let's reject the UE\n",
+             PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),c_rnti);
+        rrc_eNB_generate_RRCConnectionReestablishmentReject(ctxt_pP, ue_context_p, CC_id);
+        break;
+      }
 
           if(ue_context_p->ue_context.ue_reestablishment_timer > 0) {
             LOG_E(RRC,
@@ -7557,6 +7840,9 @@ rrc_eNB_decode_dcch(
               dedicated_DRB = 3;
               RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].crnti_reconfigurationcomplete_flag = 0;
               ue_context_p->ue_context.Status = RRC_RECONFIGURED;
+	      if(ue_context_p->ue_context.handover_info){
+	        ue_context_p->ue_context.handover_info->state = HO_CONFIGURED;
+	      }
               LOG_I(RRC,
                     PROTOCOL_RRC_CTXT_UE_FMT" UE State = RRC_HO_EXECUTION (xid %ld)\n",
                     PROTOCOL_RRC_CTXT_UE_ARGS(ctxt_pP),ul_dcch_msg->message.choice.c1.choice.rrcConnectionReconfigurationComplete.rrc_TransactionIdentifier);
@@ -7635,6 +7921,7 @@ rrc_eNB_decode_dcch(
             }
           } else if(dedicated_DRB == 0) {
             if(ue_context_p->ue_context.reestablishment_cause == LTE_ReestablishmentCause_spare1) {
+              
               rrc_eNB_send_S1AP_INITIAL_CONTEXT_SETUP_RESP(ctxt_pP,
                   ue_context_p);
             } else {
@@ -7729,7 +8016,7 @@ rrc_eNB_decode_dcch(
           }
 
           RC.mac[ctxt_pP->module_id]->UE_list.UE_sched_ctrl[UE_id].ue_reestablishment_reject_timer = 0;
-          ue_context_p->ue_context.ue_reestablishment_timer = 0;
+          ue_context_p->ue_context.reestablishment_xid = -1;
 
           if (ul_dcch_msg->message.choice.c1.choice.rrcConnectionReestablishmentComplete.criticalExtensions.present ==
               LTE_RRCConnectionReestablishmentComplete__criticalExtensions_PR_rrcConnectionReestablishmentComplete_r8) {
@@ -8540,7 +8827,7 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
   instance = ITTI_MSG_INSTANCE(msg_p);
   /* RRC_SUBFRAME_PROCESS is sent every subframe, do not log it */
   if (ITTI_MSG_ID(msg_p) != RRC_SUBFRAME_PROCESS)
-    LOG_I(RRC,"Received message %s\n",msg_name_p);
+    LOG_D(RRC,"Received message %s\n",msg_name_p);
 
   switch (ITTI_MSG_ID(msg_p)) {
     case TERMINATE_MESSAGE:
@@ -8679,6 +8966,9 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
 
     case X2AP_HANDOVER_REQ_ACK: {
       struct rrc_eNB_ue_context_s        *ue_context_p = NULL;
+      x2ap_handover_req_ack_t 			  *x2ap_handover_req_ack = NULL;
+      hashtable_rc_t                	  hash_rc      = HASH_TABLE_KEY_NOT_EXISTS;
+      gtpv1u_ue_data_t             		  *gtpv1u_ue_data_p = NULL;
       ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instance], X2AP_HANDOVER_REQ_ACK(msg_p).rnti);
       if (ue_context_p == NULL) {
         /* is it possible? */
@@ -8690,7 +8980,44 @@ void *rrc_enb_process_itti_msg(void *notUsed) {
       DevAssert(ue_context_p != NULL);
 
       if (ue_context_p->ue_context.handover_info->state != HO_REQUEST) abort();
+	  
+      hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, ue_context_p->ue_context.rnti, (void**)&gtpv1u_ue_data_p);
+      /* set target enb gtp teid */
+      if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+        LOG_E(RRC, "X2AP_HANDOVER_REQ_ACK func(), hashtable_get failed: while getting ue rnti %x in hashtable ue_mapping\n", ue_context_p->ue_context.rnti);
+      } else {
+        uint8_t nb_e_rabs_tobesetup = 0;
+	ebi_t   eps_bearer_id       = 0;
+	int     ip_offset           = 0;
+	in_addr_t  in_addr;
+	x2ap_handover_req_ack = &X2AP_HANDOVER_REQ_ACK(msg_p);
+	nb_e_rabs_tobesetup = x2ap_handover_req_ack->nb_e_rabs_tobesetup;
+        ue_context_p->ue_context.nb_x2u_e_rabs = nb_e_rabs_tobesetup;
+	for(int i=0; i< nb_e_rabs_tobesetup; i++){
+	  ip_offset               = 0;
+	  eps_bearer_id = x2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id;
+          ue_context_p->ue_context.enb_gtp_x2u_ebi[i] = eps_bearer_id;
+          ue_context_p->ue_context.enb_gtp_x2u_teid[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid;
+	  gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB = x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid; 
+			
+	  if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 4) ||
+	      (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) {
+	      in_addr = *((in_addr_t*)x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer);
+	      ip_offset = 4;
+	      gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr = in_addr;
+              ue_context_p->ue_context.enb_gtp_x2u_addrs[i] = x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr;
+	  }
+
+	  if ((x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 16) ||
+	      (x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length == 20)) {
+	      memcpy(gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip6_addr.s6_addr,
+		     &x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer[ip_offset],
+		     16);
+          }
 
+        }
+      }
+	  
       rrc_eNB_process_handoverCommand(instance, ue_context_p, &X2AP_HANDOVER_REQ_ACK(msg_p));
       ue_context_p->ue_context.handover_info->state = HO_PREPARE;
       break;
diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
index ff8f455d6cb5d1c88e6b884984e6db5b46563e3d..d873a825ba9ee2661c5c88ec4dab6c876a4955cf 100644
--- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
+++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.c
@@ -27,14 +27,19 @@
  * \email: lionel.gauthier@eurecom.fr
  */
 
+//#if defined(ENABLE_USE_MME)
 # include "rrc_defs.h"
 # include "rrc_extern.h"
 # include "RRC/LTE/MESSAGES/asn1_msg.h"
 # include "rrc_eNB_GTPV1U.h"
 # include "rrc_eNB_UE_context.h"
 # include "msc.h"
+
+//# if defined(ENABLE_ITTI)
 #   include "asn1_conversions.h"
 #   include "intertask_interface.h"
+//#endif
+
 # include "common/ran_context.h"
 
 extern RAN_CONTEXT_t RC;
@@ -88,6 +93,88 @@ rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP(
   }
 }
 
+//------------------------------------------------------------------------------
+boolean_t
+gtpv_data_req(
+  const protocol_ctxt_t*   const ctxt_pP,
+  const rb_id_t                  rb_idP,
+  const mui_t                    muiP,
+  const confirm_t                confirmP,
+  const sdu_size_t               sdu_sizeP,
+  uint8_t*                 const buffer_pP,
+  const pdcp_transmission_mode_t modeP,
+  uint32_t task_id
+)
+//------------------------------------------------------------------------------
+{
+  if(sdu_sizeP == 0)
+  {
+    LOG_I(GTPU,"gtpv_data_req sdu_sizeP == 0");
+    return FALSE;
+  }
+  LOG_D(GTPU,"gtpv_data_req ue rnti %x sdu_sizeP %d rb id %d", ctxt_pP->rnti, sdu_sizeP, rb_idP);
+#if defined(ENABLE_ITTI)
+  {
+    MessageDef *message_p;
+    // Uses a new buffer to avoid issue with PDCP buffer content that could be changed by PDCP (asynchronous message handling).
+    uint8_t *message_buffer;
+
+    if(task_id == TASK_DATA_FORWARDING){
+
+      LOG_I(GTPU,"gtpv_data_req task_id = TASK_DATA_FORWARDING\n");
+
+      message_buffer = itti_malloc (TASK_GTPV1_U, TASK_DATA_FORWARDING, sdu_sizeP);
+
+      memcpy (message_buffer, buffer_pP, sdu_sizeP);
+
+      message_p = itti_alloc_new_message (TASK_GTPV1_U, GTPV1U_ENB_DATA_FORWARDING_IND);
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).frame 	= ctxt_pP->frame;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).enb_flag	= ctxt_pP->enb_flag;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).rb_id 	= rb_idP;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).muip		= muiP;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).confirmp	= confirmP;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).sdu_size	= sdu_sizeP;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).sdu_p 	= message_buffer;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).mode		= modeP;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).module_id = ctxt_pP->module_id;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).rnti		 = ctxt_pP->rnti;
+      GTPV1U_ENB_DATA_FORWARDING_IND (message_p).eNB_index = ctxt_pP->eNB_index;
+
+      itti_send_msg_to_task (TASK_DATA_FORWARDING, ctxt_pP->instance, message_p);
+      return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway.
+    }else if(task_id == TASK_END_MARKER){
+      
+      LOG_I(GTPU,"gtpv_data_req task_id = TASK_END_MARKER\n");
+
+      message_buffer = itti_malloc (TASK_GTPV1_U, TASK_END_MARKER, sdu_sizeP);
+
+      memcpy (message_buffer, buffer_pP, sdu_sizeP);
+
+      message_p = itti_alloc_new_message (TASK_GTPV1_U, GTPV1U_ENB_END_MARKER_IND);
+      GTPV1U_ENB_END_MARKER_IND (message_p).frame 	= ctxt_pP->frame;
+      GTPV1U_ENB_END_MARKER_IND (message_p).enb_flag	= ctxt_pP->enb_flag;
+      GTPV1U_ENB_END_MARKER_IND (message_p).rb_id 	= rb_idP;
+      GTPV1U_ENB_END_MARKER_IND (message_p).muip		= muiP;
+      GTPV1U_ENB_END_MARKER_IND (message_p).confirmp	= confirmP;
+      GTPV1U_ENB_END_MARKER_IND (message_p).sdu_size	= sdu_sizeP;
+      GTPV1U_ENB_END_MARKER_IND (message_p).sdu_p 	= message_buffer;
+      GTPV1U_ENB_END_MARKER_IND (message_p).mode		= modeP;
+      GTPV1U_ENB_END_MARKER_IND (message_p).module_id = ctxt_pP->module_id;
+      GTPV1U_ENB_END_MARKER_IND (message_p).rnti		 = ctxt_pP->rnti;
+      GTPV1U_ENB_END_MARKER_IND (message_p).eNB_index = ctxt_pP->eNB_index;
+
+      itti_send_msg_to_task (TASK_END_MARKER, ctxt_pP->instance, message_p);
+      return TRUE; // TODO should be changed to a CNF message later, currently RRC lite does not used the returned value anyway.
+    }
+  }
+#endif
+
+  return TRUE;
+
+}
+
+//#endif
+
 void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
   module_id_t enb_mod_idP,
   const rrc_eNB_ue_context_t* const ue_context_pP
@@ -112,3 +199,5 @@ void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
   }
   itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(enb_mod_idP), msg);
 }
+
+
diff --git a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
index 23806f6a0482544ee0bb8845dc89d043760422d5..00c7490359031a138200ee8c59db35023dcd4957 100644
--- a/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
+++ b/openair2/RRC/LTE/rrc_eNB_GTPV1U.h
@@ -53,4 +53,16 @@ void rrc_eNB_send_GTPV1U_ENB_DELETE_TUNNEL_REQ(
   const rrc_eNB_ue_context_t* const ue_context_pP
 );
 
+boolean_t
+gtpv_data_req(
+  const protocol_ctxt_t*   const ctxt_pP,
+  const rb_id_t                  rb_idP,
+  const mui_t                    muiP,
+  const confirm_t                confirmP,
+  const sdu_size_t               sdu_sizeP,
+  uint8_t*                 const buffer_pP,
+  const pdcp_transmission_mode_t modeP,
+  uint32_t task_id
+);
+
 #endif /* RRC_ENB_GTPV1U_H_ */
diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.c b/openair2/RRC/LTE/rrc_eNB_S1AP.c
index 7bbd3a595dc6986b101e3d0a0056d969ae2d0273..115dc0126d3a373c1ebaec603cdba4ed945ba266 100644
--- a/openair2/RRC/LTE/rrc_eNB_S1AP.c
+++ b/openair2/RRC/LTE/rrc_eNB_S1AP.c
@@ -256,6 +256,15 @@ rrc_eNB_S1AP_get_ue_ids(
         }
 
         if (ue_desc_p != NULL) {
+          struct s1ap_eNB_ue_context_s *s1ap_ue_context_p = NULL;
+          if ((s1ap_ue_context_p = RB_REMOVE(s1ap_ue_map, &s1ap_eNB_instance_p->s1ap_ue_head, ue_desc_p)) != NULL) {
+            LOG_E(RRC, "Removed UE context eNB_ue_s1ap_id %u\n", s1ap_ue_context_p->eNB_ue_s1ap_id);
+            s1ap_eNB_free_ue_context(s1ap_ue_context_p);
+          } else {
+            LOG_E(RRC, "Removing UE context eNB_ue_s1ap_id %u: did not find context\n",ue_desc_p->eNB_ue_s1ap_id);
+          }
+          return NULL; //skip the operation below to avoid loop
+          result = rrc_eNB_S1AP_get_ue_ids(rrc_instance_pP, ue_desc_p->ue_initial_id, eNB_ue_s1ap_id);
           if (ue_desc_p->ue_initial_id != UE_INITIAL_ID_INVALID) {
             result = rrc_eNB_S1AP_get_ue_ids(rrc_instance_pP, ue_desc_p->ue_initial_id, eNB_ue_s1ap_id);
 
@@ -934,6 +943,8 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char
   gtpv1u_enb_create_tunnel_req_t  create_tunnel_req;
   gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
   uint8_t                         inde_list[NB_RB_MAX - 3]= {0};
+  int                             ret;
+
   struct rrc_eNB_ue_context_s *ue_context_p = NULL;
   protocol_ctxt_t              ctxt;
   ue_initial_id  = S1AP_INITIAL_CONTEXT_SETUP_REQ (msg_p).ue_initial_id;
@@ -975,10 +986,23 @@ int rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, const char
 
       create_tunnel_req.rnti       = ue_context_p->ue_context.rnti; // warning put zero above
       //      create_tunnel_req.num_tunnels    = i;
-      gtpv1u_create_s1u_tunnel(
+
+      ret = gtpv1u_create_s1u_tunnel(
         instance,
         &create_tunnel_req,
         &create_tunnel_resp);
+      if ( ret != 0 ) {
+        LOG_E(RRC,"rrc_eNB_process_S1AP_INITIAL_CONTEXT_SETUP_REQ : gtpv1u_create_s1u_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti);
+        ue_context_p->ue_context.ue_release_timer_s1 = 1;
+        ue_context_p->ue_context.ue_release_timer_thres_s1 = 100;
+        ue_context_p->ue_context.ue_release_timer = 0;
+        ue_context_p->ue_context.ue_reestablishment_timer = 0;
+        ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ
+        rrc_eNB_free_UE(ctxt.module_id,ue_context_p);
+        ue_context_p->ue_context.ul_failure_timer = 0;
+        return (0);
+      }
+
       rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP(
         &ctxt,
         &create_tunnel_resp,
@@ -1251,6 +1275,8 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name
   struct rrc_eNB_ue_context_s *ue_context_p = NULL;
   protocol_ctxt_t              ctxt;
   uint8_t                      e_rab_done;
+  int                          ret = 0;
+
   ue_initial_id  = S1AP_E_RAB_SETUP_REQ (msg_p).ue_initial_id;
   eNB_ue_s1ap_id = S1AP_E_RAB_SETUP_REQ (msg_p).eNB_ue_s1ap_id;
   ue_context_p   = rrc_eNB_get_ue_context_from_s1ap_ids(instance, ue_initial_id, eNB_ue_s1ap_id);
@@ -1313,10 +1339,22 @@ int rrc_eNB_process_S1AP_E_RAB_SETUP_REQ(MessageDef *msg_p, const char *msg_name
       create_tunnel_req.rnti       = ue_context_p->ue_context.rnti; // warning put zero above
       create_tunnel_req.num_tunnels    = e_rab_done;
       // NN: not sure if we should create a new tunnel: need to check teid, etc.
-      gtpv1u_create_s1u_tunnel(
+      ret = gtpv1u_create_s1u_tunnel(
         instance,
         &create_tunnel_req,
         &create_tunnel_resp);
+      if ( ret != 0 ) {
+        LOG_E(RRC,"rrc_eNB_process_S1AP_E_RAB_SETUP_REQ : gtpv1u_create_s1u_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti);
+        ue_context_p->ue_context.ue_release_timer_s1 = 1;
+        ue_context_p->ue_context.ue_release_timer_thres_s1 = 100;
+        ue_context_p->ue_context.ue_release_timer = 0;
+        ue_context_p->ue_context.ue_reestablishment_timer = 0;
+        ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ
+        rrc_eNB_free_UE(ctxt.module_id,ue_context_p);
+        ue_context_p->ue_context.ul_failure_timer = 0;
+        return (0);
+      }
+
       rrc_eNB_process_GTPV1U_CREATE_TUNNEL_RESP(
         &ctxt,
         &create_tunnel_resp,
@@ -2039,6 +2077,68 @@ int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t *const ctxt_pP,
   return 0;
 }
 
+int rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(instance_t instance, rrc_eNB_ue_context_t* const ue_context_target_p) {
+  gtpv1u_enb_create_x2u_tunnel_req_t  create_tunnel_req;
+  gtpv1u_enb_create_x2u_tunnel_resp_t create_tunnel_resp;
+  uint8_t                      		  e_rab_done;
+  uint8_t                         	  inde_list[NB_RB_MAX - 3]= {0};
+  
+  if (ue_context_target_p == NULL) {
+    
+    return (-1);
+  } else {
+    
+    /* Save e RAB information for later */
+    {
+      LOG_I(RRC, "[eNB %d] rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ: rnti %u nb_of_e_rabs %d\n",
+            instance, ue_context_target_p->ue_context.rnti, ue_context_target_p->ue_context.nb_of_e_rabs);
+      int i;
+      memset(&create_tunnel_req, 0, sizeof(create_tunnel_req));
+      uint8_t nb_e_rabs_tosetup = ue_context_target_p->ue_context.nb_of_e_rabs;
+      e_rab_done = 0;
+
+      for (i = 0;i < nb_e_rabs_tosetup; i++) {
+
+        if(ue_context_target_p->ue_context.e_rab[i].status >= E_RAB_STATUS_DONE)
+          continue;
+
+        create_tunnel_req.eps_bearer_id[e_rab_done]       = ue_context_target_p->ue_context.e_rab[i].param.e_rab_id;
+        LOG_I(RRC,"x2 tunnel setup: local index %d UE id %x, eps id %d \n",
+              i,
+              ue_context_target_p->ue_context.rnti,
+              create_tunnel_req.eps_bearer_id[i] );
+		inde_list[i] = e_rab_done;
+        e_rab_done++;
+      }
+
+      create_tunnel_req.rnti           = ue_context_target_p->ue_context.rnti; // warning put zero above
+      create_tunnel_req.num_tunnels    = e_rab_done;
+      // NN: not sure if we should create a new tunnel: need to check teid, etc.
+      gtpv1u_create_x2u_tunnel(
+        instance,
+        &create_tunnel_req,
+        &create_tunnel_resp);
+
+          ue_context_target_p->ue_context.nb_x2u_e_rabs = create_tunnel_resp.num_tunnels;
+	  for (i = 0; i < create_tunnel_resp.num_tunnels; i++) {
+		ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]]  = create_tunnel_resp.enb_X2u_teid[i];
+	    ue_context_target_p->ue_context.enb_gtp_x2u_addrs[inde_list[i]] = create_tunnel_resp.enb_addr;
+		ue_context_target_p->ue_context.enb_gtp_x2u_ebi[inde_list[i]]   = create_tunnel_resp.eps_bearer_id[i];
+
+		LOG_I(RRC, "rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ tunnel (%u, %u) bearer UE context index %u, msg index %u, eps bearer id %u, gtp addr len %d \n",
+            create_tunnel_resp.enb_X2u_teid[i],
+            ue_context_target_p->ue_context.enb_gtp_x2u_teid[inde_list[i]],            
+            inde_list[i],
+	    	i,
+            create_tunnel_resp.eps_bearer_id[i],
+	    	create_tunnel_resp.enb_addr.length);
+	  }
+    }
+
+    return (0);
+  }
+}
+
 int rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p,
 		                                      const char *msg_name,
 											  instance_t instance)
diff --git a/openair2/RRC/LTE/rrc_eNB_S1AP.h b/openair2/RRC/LTE/rrc_eNB_S1AP.h
index 5feb55d635c63461b237b439f5f1654d9e2882dc..e5ff9c27d600d6371132e3f33782caeb4a3a96eb 100644
--- a/openair2/RRC/LTE/rrc_eNB_S1AP.h
+++ b/openair2/RRC/LTE/rrc_eNB_S1AP.h
@@ -278,6 +278,7 @@ int rrc_eNB_send_S1AP_E_RAB_RELEASE_RESPONSE(const protocol_ctxt_t *const ctxt_p
 
 int rrc_eNB_send_PATH_SWITCH_REQ(const protocol_ctxt_t *const ctxt_pP,
                                  rrc_eNB_ue_context_t          *const ue_context_pP);
+int rrc_eNB_process_X2AP_TUNNEL_SETUP_REQ(instance_t instance, rrc_eNB_ue_context_t* const ue_context_target_p);
 int rrc_eNB_process_S1AP_PATH_SWITCH_REQ_ACK (MessageDef *msg_p, const char *msg_name, instance_t instance);
 
 int rrc_eNB_send_X2AP_UE_CONTEXT_RELEASE(const protocol_ctxt_t* const ctxt_pP, rrc_eNB_ue_context_t* const ue_context_pP);
diff --git a/openair2/X2AP/x2ap_eNB_defs.h b/openair2/X2AP/x2ap_eNB_defs.h
index e1a8b506bcabeea022da333856c3b0a03626b481..03d8216b5666a0904fac6492c264384eef0862bd 100644
--- a/openair2/X2AP/x2ap_eNB_defs.h
+++ b/openair2/X2AP/x2ap_eNB_defs.h
@@ -173,6 +173,8 @@ typedef struct x2ap_eNB_instance_s {
   lte_frame_type_t        frame_type[MAX_NUM_CCs];
   uint32_t                fdd_earfcn_DL[MAX_NUM_CCs];
   uint32_t                fdd_earfcn_UL[MAX_NUM_CCs];
+  uint32_t                subframeAssignment[MAX_NUM_CCs];
+  uint32_t                specialSubframe[MAX_NUM_CCs];
   int                     num_cc;
 
   net_ip_address_t target_enb_x2_ip_address[X2AP_MAX_NB_ENB_IP_ADDRESS];
diff --git a/openair2/X2AP/x2ap_eNB_generate_messages.c b/openair2/X2AP/x2ap_eNB_generate_messages.c
index 53ec8574fd80e4305fc5e6744d5b8b7748d8f459..38ebd732ac390c02832b9f9645c67b96e63fd84e 100644
--- a/openair2/X2AP/x2ap_eNB_generate_messages.c
+++ b/openair2/X2AP/x2ap_eNB_generate_messages.c
@@ -144,7 +144,92 @@ int x2ap_eNB_generate_x2_setup_request(
           }
         }
         else {
-          AssertFatal(0,"X2Setuprequest not supported for TDD!");
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+          switch (instance_p->subframeAssignment[i]) {
+            case 0:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+              break;
+            case 1:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+              break;
+            case 2:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+              break;
+            case 3:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+              break;
+            case 4:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+              break;
+            case 5:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+              break;
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+          }
+          switch (instance_p->specialSubframe[i]) {
+            case 0:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+              break;
+            case 1:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+              break;
+            case 2:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+              break;
+            case 3:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+              break;
+            case 4:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+              break;
+            case 5:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+              break;
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+              break;
+            case 7:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+              break;
+            case 8:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+          }
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+          
+          switch (instance_p->N_RB_DL[i]) {
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+              break;
+            case 15:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+              break;
+            case 25:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+              break;
+            case 50:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+              break;
+            case 75:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+              break;
+            case 100:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+              break;
+          }
         }
       }
       ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
@@ -279,7 +364,92 @@ int x2ap_eNB_generate_x2_setup_response(x2ap_eNB_instance_t *instance_p, x2ap_eN
           }
         }
         else {
-          AssertFatal(0,"X2Setupresponse not supported for TDD!");
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.present = X2AP_EUTRA_Mode_Info_PR_tDD;
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.eARFCN = instance_p->fdd_earfcn_DL[i];
+          switch (instance_p->subframeAssignment[i]) {
+            case 0:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa0;
+              break;
+            case 1:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa1;
+              break;
+            case 2:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa2;
+              break;
+            case 3:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa3;
+              break;
+            case 4:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa4;
+              break;
+            case 5:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa5;
+              break;
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.subframeAssignment = X2AP_SubframeAssignment_sa6;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+          }
+          switch (instance_p->specialSubframe[i]) {
+            case 0:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp0;
+              break;
+            case 1:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp1;
+              break;
+            case 2:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp2;
+              break;
+            case 3:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp3;
+              break;
+            case 4:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp4;
+              break;
+            case 5:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp5;
+              break;
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp6;
+              break;
+            case 7:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp7;
+              break;
+            case 8:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.specialSubframePatterns = X2AP_SpecialSubframePatterns_ssp8;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for subframeAssignment");
+              break;
+          }
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixDL=X2AP_CyclicPrefixDL_normal;
+          servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.specialSubframe_Info.cyclicPrefixUL=X2AP_CyclicPrefixUL_normal;
+          
+          switch (instance_p->N_RB_DL[i]) {
+            case 6:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw6;
+              break;
+            case 15:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw15;
+              break;
+            case 25:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw25;
+              break;
+            case 50:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw50;
+              break;
+            case 75:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw75;
+              break;
+            case 100:
+              servedCellMember->servedCellInfo.eUTRA_Mode_Info.choice.tDD.transmission_Bandwidth = X2AP_Transmission_Bandwidth_bw100;
+              break;
+            default:
+              AssertFatal(0,"Failed: Check value for N_RB_DL/N_RB_UL");
+              break;
+          }
         }
       }
       ASN_SEQUENCE_ADD(&ie->value.choice.ServedCells.list, servedCellMember);
@@ -627,6 +797,27 @@ int x2ap_eNB_generate_x2_handover_request_ack (x2ap_eNB_instance_t *instance_p,
         e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item;
         {
           e_RABs_Admitted_Item->e_RAB_ID = x2ap_handover_req_ack->e_rabs_tobesetup[i].e_rab_id;
+	  e_RABs_Admitted_Item->uL_GTP_TunnelEndpoint = NULL;
+	  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint = (X2AP_GTPtunnelEndpoint_t *)calloc(1, sizeof(*e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint));
+		  
+	  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size = (uint8_t)x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.length;
+          e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.bits_unused = 0;
+          e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf =
+                        calloc(1, e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+
+          memcpy (e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf,
+                  x2ap_handover_req_ack->e_rabs_tobesetup[i].eNB_addr.buffer,
+                  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+
+          X2AP_DEBUG("X2 handover response target ip addr. length %lu bits_unused %d buf %d.%d.%d.%d\n",
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size,
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.bits_unused,
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[0],
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[1],
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[2],
+		  e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf[3]);
+		  
+          INT32_TO_OCTET_STRING(x2ap_handover_req_ack->e_rabs_tobesetup[i].gtp_teid, &e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->gTP_TEID);
         }
         ASN_SEQUENCE_ADD(&ie->value.choice.E_RABs_Admitted_List.list, e_RABS_Admitted_ItemIEs);
       }
diff --git a/openair2/X2AP/x2ap_eNB_handler.c b/openair2/X2AP/x2ap_eNB_handler.c
index 41d92a695e0da3b933a190502a44cdab1a831d08..33fd9c5295fb8ad890f297a4de96bb564f1f4b00 100644
--- a/openair2/X2AP/x2ap_eNB_handler.c
+++ b/openair2/X2AP/x2ap_eNB_handler.c
@@ -749,6 +749,8 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
 {
   X2AP_HandoverRequestAcknowledge_t             *x2HandoverRequestAck;
   X2AP_HandoverRequestAcknowledge_IEs_t         *ie;
+  X2AP_E_RABs_Admitted_ItemIEs_t		 		*e_RABS_Admitted_ItemIEs;
+  X2AP_E_RABs_Admitted_Item_t 		   			*e_RABs_Admitted_Item;
 
   x2ap_eNB_instance_t                           *instance_p;
   x2ap_eNB_data_t                               *x2ap_eNB_data;
@@ -816,6 +818,56 @@ int x2ap_eNB_handle_handover_response (instance_t instance,
 
   X2AP_HANDOVER_REQ_ACK(msg).rnti = rnti;
 
+
+  X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
+                             X2AP_ProtocolIE_ID_id_E_RABs_Admitted_List, true);
+
+  if (ie == NULL ) {
+    X2AP_ERROR("%s %d: ie is a NULL pointer \n", __FILE__, __LINE__);
+    return -1;
+  }else{
+    if (ie->value.choice.E_RABs_Admitted_List.list.count > 0) {
+  
+      uint8_t nb_e_rabs_tobesetup;
+      nb_e_rabs_tobesetup = ie->value.choice.E_RABs_Admitted_List.list.count;
+      X2AP_HANDOVER_REQ_ACK(msg).nb_e_rabs_tobesetup = nb_e_rabs_tobesetup;
+  
+      for (int i=0; i<nb_e_rabs_tobesetup; i++) {
+        e_RABS_Admitted_ItemIEs = (X2AP_E_RABs_Admitted_ItemIEs_t *) ie->value.choice.E_RABs_Admitted_List.list.array[i];
+	e_RABs_Admitted_Item = &e_RABS_Admitted_ItemIEs->value.choice.E_RABs_Admitted_Item;
+  
+	X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id = e_RABs_Admitted_Item->e_RAB_ID ;
+	X2AP_ERROR("x2u tunnel: index %d e_rab_id %d\n", i, X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].e_rab_id);
+		  
+	if(e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint == NULL){
+	  X2AP_DEBUG("%s %d: X2AP_E_RABs_Admitted_Item_t->dL_GTP_TunnelEndpoint is a NULL pointer \n", __FILE__, __LINE__);
+	  continue;
+	}
+		  
+         memcpy(X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer,
+		e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.buf,
+		e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size);
+  
+	X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length = e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->transportLayerAddress.size;
+  
+	OCTET_STRING_TO_INT32(&e_RABs_Admitted_Item->dL_GTP_TunnelEndpoint->gTP_TEID,
+			      X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
+  
+  
+        X2AP_DEBUG("x2u tunnel: index %d target enb ip %d.%d.%d.%d length %d gtp teid %u\n", 
+		    i, 
+		    X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[0],
+		    X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[1],
+		    X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[2],
+		    X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.buffer[3],
+		    X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].eNB_addr.length,
+	            X2AP_HANDOVER_REQ_ACK(msg).e_rabs_tobesetup[i].gtp_teid);
+        }
+	
+      }
+
+    }
+  
   X2AP_FIND_PROTOCOLIE_BY_ID(X2AP_HandoverRequestAcknowledge_IEs_t, ie, x2HandoverRequestAck,
                              X2AP_ProtocolIE_ID_id_TargeteNBtoSource_eNBTransparentContainer, true);
 
diff --git a/openair3/GTPV1-U/gtpv1u_eNB.c b/openair3/GTPV1-U/gtpv1u_eNB.c
index fcadb0530e45be25a03b1985234ffa95cbd2c91a..e56edb8fe6b54f5e811d1f9fbe33fe79d746724c 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB.c
+++ b/openair3/GTPV1-U/gtpv1u_eNB.c
@@ -50,12 +50,18 @@
 #include "common/ran_context.h"
 #include "gtpv1u_eNB_defs.h"
 #include "gtpv1u_eNB_task.h"
+#include "rrc_eNB_GTPV1U.h"
 
 #undef GTP_DUMP_SOCKET
 
 extern unsigned char NB_eNB_INST;
 extern RAN_CONTEXT_t RC;
 
+extern struct rrc_eNB_ue_context_s*
+rrc_eNB_get_ue_context(
+  eNB_RRC_INST* rrc_instance_pP,
+  rnti_t rntiP);
+
 #if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
 #include <linux/if.h>
 static int           gtpv1u_dump_socket_g;
@@ -105,6 +111,27 @@ static void gtpv1u_eNB_write_dump_socket(uint8_t *buffer_pP, uint32_t buffer_len
 
 #endif
 
+//-----------------------------------------------------------------------------
+static int gtpv1u_eNB_get_msgsource(struct rrc_eNB_ue_context_s *ue_context_p, teid_t teid)
+{
+  int erab_index = 0;
+
+  /* source enb */
+  if(ue_context_p->ue_context.handover_info != NULL && ue_context_p->ue_context.handover_info->state == HO_COMPLETE)
+  {
+    return GTPV1U_MSG_FROM_SPGW; 
+  }
+
+  /* target enb */
+  for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+    if(ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index] == teid){
+      return GTPV1U_MSG_FROM_SOURCE_ENB;  
+    }
+  }
+  
+  return GTPV1U_MSG_FROM_SPGW;  
+}
+
 //-----------------------------------------------------------------------------
 static int gtpv1u_eNB_send_init_udp(const Gtpv1uS1Req *req) {
   // Create and alloc new message
@@ -198,10 +225,16 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
     case NW_GTPV1U_ULP_API_RECV_TPDU: {
       uint8_t              buffer[4096];
       uint32_t             buffer_len;
+      struct rrc_eNB_ue_context_s        *ue_context_p;	
+      uint16_t             msgType = NW_GTP_GPDU;
+      NwGtpv1uMsgT 		 *pMsg = NULL;
+
       /* Nw-gptv1u stack has processed a PDU. we can schedule it to PDCP
        * for transmission.
        */
       teid = pUlpApi->apiInfo.recvMsgInfo.teid;
+      pMsg = (NwGtpv1uMsgT *) pUlpApi->apiInfo.recvMsgInfo.hMsg;
+      msgType = pMsg->msgType;
 
       if (NW_GTPV1U_OK != nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg,
                                              buffer, &buffer_len)) {
@@ -243,6 +276,158 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
           0,0,
           (gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
           buffer_len);
+
+    ue_context_p = rrc_eNB_get_ue_context(RC.rrc[ctxt.module_id], ctxt.rnti);
+    if((ue_context_p != NULL) && 
+       (ue_context_p->ue_context.handover_info != NULL) &&
+       (ue_context_p->ue_context.handover_info->state < HO_FORWARDING_COMPLETE)) {
+
+      if(msgType == NW_GTP_END_MARKER){
+        /* in the source enb, UE in RRC_HO_EXECUTION mode */
+        if (ue_context_p->ue_context.Status == RRC_HO_EXECUTION && ue_context_p->ue_context.handover_info->state == HO_COMPLETE) {
+          /* set handover state */
+          //ue_context_p->ue_context.handover_info->state = HO_END_MARKER;
+                
+          MessageDef *msg;
+          // Configure end marker
+          msg = itti_alloc_new_message(TASK_GTPV1_U, GTPV1U_ENB_END_MARKER_REQ);
+          GTPV1U_ENB_END_MARKER_REQ(msg).buffer = itti_malloc(TASK_GTPV1_U, TASK_GTPV1_U, GTPU_HEADER_OVERHEAD_MAX + buffer_len);
+          memcpy(&GTPV1U_ENB_END_MARKER_REQ(msg).buffer[GTPU_HEADER_OVERHEAD_MAX], buffer, buffer_len);
+          GTPV1U_ENB_END_MARKER_REQ(msg).length = buffer_len;
+          GTPV1U_ENB_END_MARKER_REQ(msg).rnti   = ctxt.rnti;
+          GTPV1U_ENB_END_MARKER_REQ(msg).rab_id = gtpv1u_teid_data_p->eps_bearer_id;
+          GTPV1U_ENB_END_MARKER_REQ(msg).offset = GTPU_HEADER_OVERHEAD_MAX;
+          LOG_I(GTPU, "Send End Marker to GTPV1-U at frame %d and subframe %d \n", ctxt.frame,ctxt.subframe);
+          itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), msg);
+          return NW_GTPV1U_OK;
+	}
+      }
+	  
+      if (ue_context_p->ue_context.Status == RRC_HO_EXECUTION || ue_context_p->ue_context.Status == RRC_RECONFIGURED) {
+
+        int msgsrc = gtpv1u_eNB_get_msgsource(ue_context_p, teid);
+
+        LOG_D(GTPU,"UE INFO.ueStatus %d, handover state %d, forwarding state %d, from %s. message type %s\n", 
+              ue_context_p->ue_context.Status, 
+              ue_context_p->ue_context.handover_info->state,
+              ue_context_p->ue_context.handover_info->forwarding_state,
+              msgsrc == GTPV1U_MSG_FROM_SOURCE_ENB?"Source eNB":"EPC",
+              msgsrc != GTPV1U_MSG_FROM_SOURCE_ENB? "UDP DATA" :
+              msgType == NW_GTP_END_MARKER?"END MARKER":"DATA FORWARDING");
+
+	/* target enb */
+	if(msgType == NW_GTP_END_MARKER){
+	  LOG_I(GTPU, "target end receive END MARKER\n");
+	  ue_context_p->ue_context.handover_info->state = HO_END_MARKER;
+          gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req;
+          memset(&delete_tunnel_req, 0 , sizeof(delete_tunnel_req));
+          delete_tunnel_req.rnti = ctxt.rnti;
+    	  gtpv1u_delete_x2u_tunnel(ctxt.module_id, &delete_tunnel_req, GTPV1U_TARGET_ENB);
+	  return NW_GTPV1U_OK;
+	}
+
+        /* form source eNB message */
+        if(msgsrc == GTPV1U_MSG_FROM_SOURCE_ENB)
+        {
+          LOG_I(GTPU, "Received a message data forwarding length %d\n", buffer_len);
+
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+          LOG_T(GTPU, "forwarding data info:\n", buffer_len);	  
+
+          for(int i=1;i<=buffer_len; i++){
+	    LOG_T(GTPU, "%02x ", buffer[i-1]);
+	    if(i%20 == 0)LOG_T(GTPU, "\n");
+	  }
+	  LOG_T(GTPU, "\n");
+#endif
+			
+	  result = gtpv_data_req(
+				&ctxt,
+				(gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
+				0, // mui
+				SDU_CONFIRM_NO, // confirm
+				buffer_len,
+				buffer,
+				PDCP_TRANSMISSION_MODE_DATA,
+                                TASK_DATA_FORWARDING
+				);
+			
+          if ( result == FALSE ) {
+	    LOG_W(GTPU, "DATA FORWARDING message save failed\n");	
+	    return NW_GTPV1U_FAILURE;
+	  }
+	  ue_context_p->ue_context.handover_info->forwarding_state = FORWARDING_NO_EMPTY;
+          return NW_GTPV1U_OK;
+	}
+        /* from epc message */
+        else
+        {
+          /* in the source enb, UE in RRC_HO_EXECUTION mode */
+          if (ue_context_p->ue_context.handover_info->state == HO_COMPLETE) {
+          MessageDef *msg;
+          // Configure target
+          msg = itti_alloc_new_message(TASK_GTPV1_U, GTPV1U_ENB_DATA_FORWARDING_REQ);
+          GTPV1U_ENB_DATA_FORWARDING_REQ(msg).buffer = itti_malloc(TASK_GTPV1_U, TASK_GTPV1_U, GTPU_HEADER_OVERHEAD_MAX + buffer_len);
+          memcpy(&GTPV1U_ENB_DATA_FORWARDING_REQ(msg).buffer[GTPU_HEADER_OVERHEAD_MAX], buffer, buffer_len);
+          GTPV1U_ENB_DATA_FORWARDING_REQ(msg).length = buffer_len;
+          GTPV1U_ENB_DATA_FORWARDING_REQ(msg).rnti   = ctxt.rnti;
+          GTPV1U_ENB_DATA_FORWARDING_REQ(msg).rab_id = gtpv1u_teid_data_p->eps_bearer_id;
+          GTPV1U_ENB_DATA_FORWARDING_REQ(msg).offset = GTPU_HEADER_OVERHEAD_MAX;
+
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+
+          LOG_T(GTPU, "Send data forwarding sdu_buffer to target enb. len %d info\n", buffer);
+          for(int i=1; i<=buffer_len; i++){
+            LOG_T(GTPU, "%02x ", buffer[i-1]);
+            if(i%20 == 0)LOG_T(GTPU, "\n");
+          }
+          LOG_T(GTPU, "\n");
+#endif
+
+          LOG_I(GTPU, "Send data forwarding to GTPV1-U at frame %d and subframe %d \n", ctxt.frame,ctxt.subframe);
+          itti_send_msg_to_task(TASK_GTPV1_U, ENB_MODULE_ID_TO_INSTANCE(ctxt.module_id), msg);
+          return NW_GTPV1U_OK;
+        }
+
+          /* target eNB. x2ho forwarding is processing. spgw message save to TASK_END_MARKER */
+          if(ue_context_p->ue_context.handover_info->state != HO_COMPLETE &&
+             ue_context_p->ue_context.handover_info->state != HO_END_MARKER )
+          {
+            LOG_I(GTPU, "x2ho forwarding is processing. Received a spgw message. length %d\n", buffer_len);
+#if defined(LOG_GTPU) && LOG_GTPU > 0				
+	  LOG_T(GTPU, "spgw data info:\n", buffer_len);			
+	  for(int i=1;i<=buffer_len; i++){
+	    LOG_T(GTPU, "%02x ", buffer[i-1]);
+	    if(i%20 == 0)LOG_T(GTPU, "\n");
+	  }
+	  LOG_T(GTPU, "\n");
+#endif
+			
+	  result = gtpv_data_req(
+			&ctxt,
+			(gtpv1u_teid_data_p->eps_bearer_id) ? gtpv1u_teid_data_p->eps_bearer_id - 4: 5-4,
+			0, // mui
+			SDU_CONFIRM_NO, // confirm
+			buffer_len,
+			buffer,
+			PDCP_TRANSMISSION_MODE_DATA,
+		        TASK_END_MARKER
+			);
+
+	if ( result == FALSE ) {
+	  LOG_W(GTPU, "DATA FORWARDING message save failed\n");
+	  return NW_GTPV1U_FAILURE;
+        }
+
+	ue_context_p->ue_context.handover_info->endmark_state = ENDMARK_NO_EMPTY;
+        return NW_GTPV1U_OK;
+      }
+
+     }
+
+    }
+
+  }
         result = pdcp_data_req(
                    &ctxt,
                    SRB_FLAG_NO,
@@ -259,7 +444,7 @@ NwGtpv1uRcT gtpv1u_eNB_process_stack_req(
 
         if ( result == FALSE ) {
           if (ctxt.configured == FALSE )
-            LOG_W(GTPU, "PDCP data request failed, cause: RB is not configured!\n") ;
+            LOG_W(GTPU, "PDCP data request failed, cause: [UE:%x]RB is not configured!\n", ctxt.rnti) ;
           else
             LOG_W(GTPU, "PDCP data request failed\n");
 
@@ -550,6 +735,154 @@ gtpv1u_new_data_req(
   return 0;
 }
 
+//-----------------------------------------------------------------------------
+int
+gtpv1u_create_x2u_tunnel(
+  const instance_t                              instanceP,
+  const gtpv1u_enb_create_x2u_tunnel_req_t * const  create_tunnel_req_pP,
+        gtpv1u_enb_create_x2u_tunnel_resp_t * const create_tunnel_resp_pP
+  )
+{
+  /* Create a new nw-gtpv1-u stack req using API */
+  NwGtpv1uUlpApiT          stack_req;
+  NwGtpv1uRcT              rc                   = NW_GTPV1U_FAILURE;
+  /* Local tunnel end-point identifier */
+  teid_t                   x2u_teid             = 0;
+  gtpv1u_teid_data_t      *gtpv1u_teid_data_p   = NULL;
+  hashtable_rc_t           hash_rc              = HASH_TABLE_KEY_NOT_EXISTS;
+  int                      i;
+  ebi_t                    eps_bearer_id        = 0;
+
+  MSC_LOG_RX_MESSAGE(
+		  MSC_GTPU_ENB,
+		  MSC_RRC_ENB,
+		  NULL,0,
+		  MSC_AS_TIME_FMT" CREATE_X2U_TUNNEL_REQ RNTI %"PRIx16" inst %u ntuns %u ebid %u enb-x2u teid %u",
+		  0,0,create_tunnel_req_pP->rnti, instanceP,
+		  create_tunnel_req_pP->num_tunnels, create_tunnel_req_pP->eps_bearer_id[0],
+		  create_tunnel_req_pP->tenb_X2u_teid[0]);
+
+  create_tunnel_resp_pP->rnti        = create_tunnel_req_pP->rnti;
+  create_tunnel_resp_pP->status      = 0;
+  create_tunnel_resp_pP->num_tunnels = 0;
+
+  for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) {
+    eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i];
+    LOG_D(GTPU, "Rx GTPV1U_ENB_CREATE_X2U_TUNNEL_REQ ue rnti %x eps bearer id %u\n",
+          create_tunnel_req_pP->rnti, eps_bearer_id);
+    memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+    stack_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT;
+
+    do {
+      x2u_teid = gtpv1u_new_teid();
+      LOG_D(GTPU, "gtpv1u_create_x2u_tunnel() 0x%x %u(dec)\n", x2u_teid, x2u_teid);
+      stack_req.apiInfo.createTunnelEndPointInfo.teid          = x2u_teid;
+      stack_req.apiInfo.createTunnelEndPointInfo.hUlpSession   = 0;
+      stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0;
+
+      rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+      LOG_D(GTPU, ".\n");
+    } while (rc != NW_GTPV1U_OK);
+
+      memcpy(&create_tunnel_resp_pP->enb_addr.buffer,
+             &RC.gtpv1u_data_g->enb_ip_address_for_S1u_S12_S4_up,
+             sizeof (in_addr_t));
+
+      LOG_D(GTPU, "gtpv1u_create_x2u_tunnel() end addr %d.%d.%d.%d\n",
+		create_tunnel_resp_pP->enb_addr.buffer[0],
+		create_tunnel_resp_pP->enb_addr.buffer[1],
+		create_tunnel_resp_pP->enb_addr.buffer[2],
+		create_tunnel_resp_pP->enb_addr.buffer[3]);
+
+    create_tunnel_resp_pP->enb_addr.length  = sizeof (in_addr_t);
+    create_tunnel_resp_pP->eps_bearer_id[i] = eps_bearer_id;
+    create_tunnel_resp_pP->num_tunnels      += 1;
+
+    //-----------------------
+    // GTPV1U->PDCP mapping
+    //-----------------------
+    create_tunnel_resp_pP->enb_X2u_teid[i] = x2u_teid;
+    hash_rc = hashtable_get(RC.gtpv1u_data_g->teid_mapping, x2u_teid, (void**)&gtpv1u_teid_data_p);
+
+    if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+      gtpv1u_teid_data_p = calloc (1, sizeof(gtpv1u_teid_data_t));
+      gtpv1u_teid_data_p->enb_id        = 0; // TO DO
+      gtpv1u_teid_data_p->ue_id         = create_tunnel_req_pP->rnti;
+      gtpv1u_teid_data_p->eps_bearer_id = eps_bearer_id;
+      hash_rc = hashtable_insert(RC.gtpv1u_data_g->teid_mapping, x2u_teid, gtpv1u_teid_data_p);
+      AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting teid mapping in GTPV1U hashtable");
+    } else {
+      create_tunnel_resp_pP->enb_X2u_teid[i] = 0;
+      create_tunnel_resp_pP->status         = 0xFF;
+    }
+  }
+  MSC_LOG_TX_MESSAGE(
+		  MSC_GTPU_ENB,
+		  MSC_RRC_ENB,
+		  NULL,0,
+		  "0 GTPV1U_ENB_CREATE_TUNNEL_RESP rnti %x teid %x",
+		  create_tunnel_resp_pP->rnti,
+		  x2u_teid);
+
+  LOG_D(GTPU, "Tx GTPV1U_ENB_CREATE_TUNNEL_RESP ue rnti %x status %d\n",
+        create_tunnel_req_pP->rnti,
+        create_tunnel_resp_pP->status);
+  return 0;
+}
+
+//-----------------------------------------------------------------------------
+int gtpv1u_delete_x2u_tunnel(
+  const instance_t                             instanceP,
+  const gtpv1u_enb_delete_tunnel_req_t * const req_pP,
+  int                             enbflag)
+{
+  gtpv1u_ue_data_t        *gtpv1u_ue_data_p     = NULL;
+  hashtable_rc_t           hash_rc              = HASH_TABLE_KEY_NOT_EXISTS;
+  int                      erab_index           = 0;
+  ebi_t                    eps_bearer_id        = 0;
+  struct rrc_eNB_ue_context_s *ue_context_p     = NULL;
+
+  ue_context_p = rrc_eNB_get_ue_context(RC.rrc[instanceP], req_pP->rnti);
+  if(ue_context_p != NULL){
+    /* in the source enb */
+    if(enbflag == GTPV1U_SOURCE_ENB){
+      hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, req_pP->rnti, (void**)&gtpv1u_ue_data_p);
+
+      if (hash_rc == HASH_TABLE_OK) {
+        for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+          eps_bearer_id = ue_context_p->ue_context.enb_gtp_x2u_ebi[erab_index];
+          LOG_I(GTPU, "gtpv1u_delete_x2u_tunnel user rnti %x teNB X2U teid %u eps bearer id %u\n",
+            req_pP->rnti, 
+            gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB,
+            ue_context_p->ue_context.enb_gtp_x2u_ebi[erab_index]);
+          
+          gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].teid_teNB = 0;
+          gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr = 0;
+          //gtpv1u_ue_data_p->bearers[eps_bearer_id - GTPV1U_BEARER_OFFSET].tenb_ip6_addr = 0;
+        }
+        ue_context_p->ue_context.nb_x2u_e_rabs = 0;
+      }
+    }
+    /* in the target enb */
+    else{
+      for (erab_index = 0; erab_index < ue_context_p->ue_context.nb_x2u_e_rabs; erab_index++) {
+        //-----------------------
+        // GTPV1U->PDCP mapping
+        //-----------------------
+        hash_rc = hashtable_remove(RC.gtpv1u_data_g->teid_mapping, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+        LOG_I(GTPU, "Removed user rnti %x , enb X2U teid %u\n", req_pP->rnti, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+
+        if (hash_rc != HASH_TABLE_OK) {
+          LOG_D(GTPU, "Removed user rnti %x , enb X2U teid %u not found\n", req_pP->rnti, ue_context_p->ue_context.enb_gtp_x2u_teid[erab_index]);
+        }
+      }
+      ue_context_p->ue_context.nb_x2u_e_rabs = 0;
+    }
+  }
+  return 0;
+}
+
 //-----------------------------------------------------------------------------
 int
 gtpv1u_create_s1u_tunnel(
@@ -572,6 +905,10 @@ gtpv1u_create_s1u_tunnel(
   int                      ip_offset            = 0;
   in_addr_t                in_addr;
   int                      addrs_length_in_bytes= 0;
+  int                      loop_counter         = 0;
+  int                      ret                  = 0;
+
+
   MSC_LOG_RX_MESSAGE(
     MSC_GTPU_ENB,
     MSC_RRC_ENB,
@@ -586,6 +923,7 @@ gtpv1u_create_s1u_tunnel(
 
   for (i = 0; i < create_tunnel_req_pP->num_tunnels; i++) {
     ip_offset               = 0;
+    loop_counter            = 0;
     eps_bearer_id = create_tunnel_req_pP->eps_bearer_id[i];
     LOG_D(GTPU, "Rx GTPV1U_ENB_CREATE_TUNNEL_REQ ue rnti %x eps bearer id %u\n",
           create_tunnel_req_pP->rnti, eps_bearer_id);
@@ -600,7 +938,13 @@ gtpv1u_create_s1u_tunnel(
       stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0;
       rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
       LOG_D(GTPU, ".\n");
-    } while (rc != NW_GTPV1U_OK);
+      loop_counter++;
+    } while (rc != NW_GTPV1U_OK && loop_counter < 10);
+    if ( rc != NW_GTPV1U_OK && loop_counter == 10 ) {
+      LOG_E(GTPU,"NwGtpv1uCreateTunnelEndPoint failed 10 times,start next loop\n");
+      ret = -1;
+      continue;
+    }
 
     //-----------------------
     // PDCP->GTPV1U mapping
@@ -682,7 +1026,8 @@ gtpv1u_create_s1u_tunnel(
   LOG_D(GTPU, "Tx GTPV1U_ENB_CREATE_TUNNEL_RESP ue rnti %x status %d\n",
         create_tunnel_req_pP->rnti,
         create_tunnel_resp_pP->status);
-  return 0;
+  //return 0;
+  return ret;
 }
 
 int gtpv1u_update_s1u_tunnel(
@@ -713,9 +1058,15 @@ int gtpv1u_update_s1u_tunnel(
   memcpy(gtpv1u_ue_data_new_p,gtpv1u_ue_data_p,sizeof(gtpv1u_ue_data_t));
   gtpv1u_ue_data_new_p->ue_id       = create_tunnel_req_pP->rnti;
   hash_rc = hashtable_insert(RC.gtpv1u_data_g->ue_mapping, create_tunnel_req_pP->rnti, gtpv1u_ue_data_new_p);
-  AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable");
+  //AssertFatal(hash_rc == HASH_TABLE_OK, "Error inserting ue_mapping in GTPV1U hashtable");
+  if ( hash_rc != HASH_TABLE_OK ) {
+    LOG_E(GTPU,"Failed to insert ue_mapping(rnti=%x) in GTPV1U hashtable\n",create_tunnel_req_pP->rnti);
+    return -1;
+  } else {
   LOG_I(GTPU, "inserting ue_mapping(rnti=%x) in GTPV1U hashtable\n",
         create_tunnel_req_pP->rnti);
+  }
+
   hash_rc = hashtable_remove(RC.gtpv1u_data_g->ue_mapping, prior_rnti);
   LOG_I(GTPU, "hashtable_remove ue_mapping(rnti=%x) in GTPV1U hashtable\n",
         prior_rnti);
@@ -1043,6 +1394,176 @@ void *gtpv1u_eNB_process_itti_msg(void *notUsed) {
     }
     break;
 
+    case GTPV1U_ENB_DATA_FORWARDING_REQ: {
+    gtpv1u_enb_data_forwarding_req_t *data_req_p           = NULL;
+    NwGtpv1uUlpApiT               stack_req;
+    NwGtpv1uRcT                   rc                   = NW_GTPV1U_FAILURE;
+    hashtable_rc_t                hash_rc              = HASH_TABLE_KEY_NOT_EXISTS;
+    gtpv1u_ue_data_t             *gtpv1u_ue_data_p     = NULL;
+    teid_t                        enb_s1u_teid         = 0;
+    teid_t                        tenb_x2u_teid         = 0;
+
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_IN);
+    data_req_p = &GTPV1U_ENB_DATA_FORWARDING_REQ(received_message_p);
+    //ipv4_send_data(ipv4_data_p->sd, data_ind_p->buffer, data_ind_p->length);
+
+#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
+    gtpv1u_eNB_write_dump_socket(&data_req_p->buffer[data_req_p->offset],data_req_p->length);
+#endif
+    memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+    hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, (uint64_t)data_req_p->rnti, (void**)&gtpv1u_ue_data_p);
+
+    if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+      LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: while getting ue rnti %x in hashtable ue_mapping\n", data_req_p->rnti);
+    } else {
+      if ((data_req_p->rab_id >= GTPV1U_BEARER_OFFSET) && (data_req_p->rab_id <= max_val_LTE_DRB_Identity)) {
+        enb_s1u_teid                        = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_eNB;
+        tenb_x2u_teid                       = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_teNB; // target enb teid
+        stack_req.apiType                   = NW_GTPV1U_ULP_API_SEND_TPDU;
+        stack_req.apiInfo.sendtoInfo.teid   = tenb_x2u_teid;
+        stack_req.apiInfo.sendtoInfo.ipAddr = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr;// target enb ip
+
+        rc = nwGtpv1uGpduMsgNew(
+               RC.gtpv1u_data_g->gtpv1u_stack,
+               tenb_x2u_teid,
+               NW_FALSE,
+               RC.gtpv1u_data_g->seq_num++,
+               data_req_p->buffer,
+               data_req_p->length,
+               data_req_p->offset,
+               &(stack_req.apiInfo.sendtoInfo.hMsg));
+
+        if (rc != NW_GTPV1U_OK) {
+          LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc);
+          MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+          		enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+          (void)enb_s1u_teid; /* avoid gcc warning "set but not used" */
+        } else {
+          rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+
+          if (rc != NW_GTPV1U_OK) {
+            LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc);
+            MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+            		enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+          } else {
+            MSC_LOG_TX_MESSAGE(
+            		MSC_GTPU_ENB,
+            		MSC_GTPU_SGW,
+            		NULL,
+            		0,
+            		MSC_AS_TIME_FMT" G-PDU ltid %u rtid %u size %u",
+            		0,0,
+            		enb_s1u_teid,
+            		tenb_x2u_teid,
+            		data_req_p->length);
+
+        }
+
+        rc = nwGtpv1uMsgDelete(RC.gtpv1u_data_g->gtpv1u_stack,
+                               stack_req.apiInfo.sendtoInfo.hMsg);
+
+        if (rc != NW_GTPV1U_OK) {
+          LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc);
+        }
+      }
+    }
+  }
+
+  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_OUT);
+  /* Buffer still needed, do not free it */
+  //itti_free(ITTI_MSG_ORIGIN_ID(received_message_p), data_req_p->buffer)
+  }
+  break;
+
+  case GTPV1U_ENB_END_MARKER_REQ:{
+    gtpv1u_enb_end_marker_req_t   *data_req_p           = NULL;
+    NwGtpv1uUlpApiT               stack_req;
+    NwGtpv1uRcT                   rc                    = NW_GTPV1U_FAILURE;
+    hashtable_rc_t                hash_rc               = HASH_TABLE_KEY_NOT_EXISTS;
+    gtpv1u_ue_data_t              *gtpv1u_ue_data_p     = NULL;
+    teid_t                        enb_s1u_teid          = 0;
+    teid_t                        tenb_x2u_teid         = 0;
+    NwGtpv1uMsgT		  *pMsg                 = NULL;
+
+    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_IN);
+    data_req_p = &GTPV1U_ENB_END_MARKER_REQ(received_message_p);
+    //ipv4_send_data(ipv4_data_p->sd, data_ind_p->buffer, data_ind_p->length);
+
+#if defined(GTP_DUMP_SOCKET) && GTP_DUMP_SOCKET > 0
+    gtpv1u_eNB_write_dump_socket(&data_req_p->buffer[data_req_p->offset],data_req_p->length);
+#endif
+    memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT));
+
+    hash_rc = hashtable_get(RC.gtpv1u_data_g->ue_mapping, (uint64_t)data_req_p->rnti, (void**)&gtpv1u_ue_data_p);
+
+    if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) {
+      LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: while getting ue rnti %x in hashtable ue_mapping\n", data_req_p->rnti);
+    } else {
+      if ((data_req_p->rab_id >= GTPV1U_BEARER_OFFSET) && (data_req_p->rab_id <= max_val_LTE_DRB_Identity)) {
+        enb_s1u_teid                        = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_eNB;
+        tenb_x2u_teid                       = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].teid_teNB; // target enb teid
+        stack_req.apiType                   = NW_GTPV1U_ULP_API_SEND_TPDU;
+        stack_req.apiInfo.sendtoInfo.teid   = tenb_x2u_teid;
+        stack_req.apiInfo.sendtoInfo.ipAddr = gtpv1u_ue_data_p->bearers[data_req_p->rab_id - GTPV1U_BEARER_OFFSET].tenb_ip_addr;// target enb ip
+
+	rc = nwGtpv1uGpduMsgNew(
+               RC.gtpv1u_data_g->gtpv1u_stack,
+               tenb_x2u_teid,
+               NW_FALSE,
+               RC.gtpv1u_data_g->seq_num++,
+               data_req_p->buffer,
+               data_req_p->length,
+               data_req_p->offset,
+               &(stack_req.apiInfo.sendtoInfo.hMsg));
+
+        if (rc != NW_GTPV1U_OK) {
+          LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc);
+          MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+            		enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+          (void)enb_s1u_teid; /* avoid gcc warning "set but not used" */
+        } else {
+	  pMsg = (NwGtpv1uMsgT *) stack_req.apiInfo.sendtoInfo.hMsg;
+	  pMsg->msgType = NW_GTP_END_MARKER;
+          rc = nwGtpv1uProcessUlpReq(RC.gtpv1u_data_g->gtpv1u_stack, &stack_req);
+
+          if (rc != NW_GTPV1U_OK) {
+            LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc);
+            MSC_LOG_EVENT(MSC_GTPU_ENB,"0 Failed send G-PDU ltid %u rtid %u size %u",
+              		enb_s1u_teid,tenb_x2u_teid,data_req_p->length);
+          } else {
+            MSC_LOG_TX_MESSAGE(
+            	        MSC_GTPU_ENB,
+            	        MSC_GTPU_SGW,
+            		NULL,
+            		0,
+            		MSC_AS_TIME_FMT" G-PDU ltid %u rtid %u size %u",
+            		0,0,
+            		enb_s1u_teid,
+            		tenb_x2u_teid,
+            		data_req_p->length);
+
+          }
+
+          rc = nwGtpv1uMsgDelete(RC.gtpv1u_data_g->gtpv1u_stack,
+                                 stack_req.apiInfo.sendtoInfo.hMsg);
+
+          if (rc != NW_GTPV1U_OK) {
+            LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc);
+          }
+
+          gtpv1u_enb_delete_tunnel_req_t delete_tunnel_req;
+          memset(&delete_tunnel_req, 0 , sizeof(delete_tunnel_req));
+          delete_tunnel_req.rnti = data_req_p->rnti;
+	  gtpv1u_delete_x2u_tunnel(instance, &delete_tunnel_req, GTPV1U_SOURCE_ENB);
+        }
+       }
+      }
+
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_GTPV1U_PROCESS_TUNNEL_DATA_REQ, VCD_FUNCTION_OUT);
+    }
+    break;
+
     case TERMINATE_MESSAGE: {
       if (RC.gtpv1u_data_g->ue_mapping != NULL) {
         hashtable_destroy (&(RC.gtpv1u_data_g->ue_mapping));
diff --git a/openair3/GTPV1-U/gtpv1u_eNB_defs.h b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
index 978a3c58bc01731a463bde048fcac72cb07a836a..79d9a1dcdd54cb28c850d38b0cd161c6d3478719 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB_defs.h
+++ b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
@@ -40,6 +40,11 @@
 
 #define GTPV1U_MAX_BEARERS_ID     (max_val_LTE_DRB_Identity - GTPV1U_BEARER_OFFSET)
 
+#define GTPV1U_SOURCE_ENB (0)
+#define GTPV1U_TARGET_ENB (1)
+#define GTPV1U_MSG_FROM_SOURCE_ENB (0)
+#define GTPV1U_MSG_FROM_SPGW (1)
+
 typedef enum {
   BEARER_DOWN = 0,
   BEARER_IN_CONFIG,
@@ -65,6 +70,9 @@ typedef struct gtpv1u_bearer_s {
   teid_t          teid_sgw;                ///< Remote TEID
   in_addr_t       sgw_ip_addr;
   struct in6_addr sgw_ip6_addr;
+  teid_t          teid_teNB;
+  in_addr_t       tenb_ip_addr;				///< target eNB ipv4
+  struct in6_addr tenb_ip6_addr;				///< target eNB ipv6
   tcp_udp_port_t  port;
   //NwGtpv1uStackSessionHandleT stack_session;
   bearer_state_t state;
diff --git a/openair3/GTPV1-U/gtpv1u_eNB_task.h b/openair3/GTPV1-U/gtpv1u_eNB_task.h
index 9830ea6169975439e708a840e20e29ea4af91cee..a6e26259415bee26adf21407707cc01d3d46baf2 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB_task.h
+++ b/openair3/GTPV1-U/gtpv1u_eNB_task.h
@@ -44,6 +44,12 @@ int   gtpv1u_eNB_init(void);
 void *gtpv1u_eNB_process_itti_msg(void*);
 void *gtpv1u_eNB_task(void *args);
 
+int
+gtpv1u_create_x2u_tunnel(
+  const instance_t instanceP,
+  const gtpv1u_enb_create_x2u_tunnel_req_t *  const create_tunnel_req_pP,
+        gtpv1u_enb_create_x2u_tunnel_resp_t * const create_tunnel_resp_pP);
+
 int
 gtpv1u_create_s1u_tunnel(
   const instance_t instanceP,
@@ -55,4 +61,9 @@ gtpv1u_update_s1u_tunnel(
     const instance_t                              instanceP,
     const gtpv1u_enb_create_tunnel_req_t * const  create_tunnel_req_pP,
     const rnti_t                                  prior_rnti);
+
+int gtpv1u_delete_x2u_tunnel(
+  const instance_t                             instanceP,
+  const gtpv1u_enb_delete_tunnel_req_t * const req_pP,
+  int                             enbflag);
 #endif /* GTPV1U_ENB_TASK_H_ */
diff --git a/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c b/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
index 3e8da5d015faa56051c35f48185908137d81afeb..0c7663921b71dbd85c74323715c30ab19b316995 100644
--- a/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
+++ b/openair3/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c
@@ -378,9 +378,14 @@ NwGtpv1uCreateTunnelEndPoint( NW_IN  NwGtpv1uStackT *thiz,
       *phStackSession = (NwGtpv1uStackSessionHandleT) pTunnelEndPoint;
       pTunnelEndPoint = RB_FIND(NwGtpv1uTunnelEndPointIdentifierMap,
                                 &(thiz->teidMap), pTunnelEndPoint);
-      NW_ASSERT(pTunnelEndPoint);
-      GTPU_DEBUG("Tunnel end-point 0x%p creation successful for teid 0x%x %u(dec)",
-                 pTunnelEndPoint, (unsigned int)teid, (unsigned int)teid);
+      //NW_ASSERT(pTunnelEndPoint);
+      if (!pTunnelEndPoint) {
+        GTPU_ERROR("Tunnel end-point cannot be NULL");
+        rc = NW_GTPV1U_FAILURE;
+      } else {
+        GTPU_DEBUG("Tunnel end-point 0x%p creation successful for teid 0x%x %u(dec)",
+                   pTunnelEndPoint, (unsigned int)teid, (unsigned int)teid);
+      }
     }
 
   } else {
@@ -893,8 +898,14 @@ nwGtpv1uProcessUdpReq( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle,
     break;
 
   case NW_GTP_END_MARKER:
-    GTPU_DEBUG("NW_GTP_END_MARKER\n");
-    ret = NW_GTPV1U_OK;
+#if defined(LOG_GTPU) && LOG_GTPU > 0
+    for(int i =1; i<= udpDataLen; i++){
+      printf("%02x ", udpData[i-1]);
+      if(i % 20 == 0)printf("\n");
+    }
+#endif  	
+    GTPU_INFO("NW_GTP_END_MARKER\n");
+    ret = nwGtpv1uProcessGpdu(thiz, udpData, udpDataLen, peerIp);
     break;
 
   default:
diff --git a/openair3/S1AP/s1ap_eNB_handlers.c b/openair3/S1AP/s1ap_eNB_handlers.c
index e11fa11950d38af5426cda03f0f7d5ddaad54ec5..4b50f1de8279f3cbbfea727ebc67239239484ea4 100644
--- a/openair3/S1AP/s1ap_eNB_handlers.c
+++ b/openair3/S1AP/s1ap_eNB_handlers.c
@@ -1519,7 +1519,7 @@ int s1ap_eNB_handle_s1_path_switch_request_ack(uint32_t               assoc_id,
   if (stream == 0) {
     S1AP_ERROR("[SCTP %d] Received s1 path switch request ack on stream (%d)\n",
                assoc_id, stream);
-    return -1;
+    //return -1;
   }
 
   if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
diff --git a/openair3/UDP/udp_eNB_task.c b/openair3/UDP/udp_eNB_task.c
index 27f754badc28af6d805eda340143c34912de03ef..90ee87900df1136baf30eb536cf53d8225a07c57 100644
--- a/openair3/UDP/udp_eNB_task.c
+++ b/openair3/UDP/udp_eNB_task.c
@@ -371,13 +371,13 @@ void *udp_eNB_task(void *args_p)
         udp_sd = udp_sock_p->sd;
         pthread_mutex_unlock(&udp_socket_list_mutex);
 
-#if defined(LOG_UDP) && LOG_UDP > 0
+//#if defined(LOG_UDP) && LOG_UDP > 0
         LOG_D(UDP_, "[%d] Sending message of size %u to "IPV4_ADDR" and port %u\n",
               udp_sd,
               udp_data_req_p->buffer_length,
               IPV4_ADDR_FORMAT(udp_data_req_p->peer_address),
               udp_data_req_p->peer_port);
-#endif
+//#endif
         bytes_written = sendto(
                           udp_sd,
                           &udp_data_req_p->buffer[udp_data_req_p->buffer_offset],
diff --git a/targets/COMMON/openairinterface5g_limits.h b/targets/COMMON/openairinterface5g_limits.h
index b55b4922c57bbf327f9ebc7b68afd2d4e2bfab10..fcb3c94b902693bc08feae7d30e326a864b762a7 100644
--- a/targets/COMMON/openairinterface5g_limits.h
+++ b/targets/COMMON/openairinterface5g_limits.h
@@ -16,23 +16,27 @@
 #                ifndef UESIM_EXPANSION
 #                    define NUMBER_OF_UE_MAX 16
 #                    define NUMBER_OF_NR_UE_MAX 16
+#                    define NUMBER_OF_UCI_VARS_MAX 56
 #                    define NUMBER_OF_CONNECTED_eNB_MAX 3
 #                    define NUMBER_OF_CONNECTED_gNB_MAX 3
 #            	 else
 #                    define NUMBER_OF_UE_MAX 256
 #                    define NUMBER_OF_NR_UE_MAX 16
+#                    define NUMBER_OF_UCI_VARS_MAX 256
 #                    define NUMBER_OF_CONNECTED_eNB_MAX 1
 #                    define NUMBER_OF_CONNECTED_gNB_MAX 3
 #                endif
 #            else
 #                    define NUMBER_OF_UE_MAX 256
 #                    define NUMBER_OF_NR_UE_MAX 256
+#                    define NUMBER_OF_UCI_VARS_MAX 256
 #                    define NUMBER_OF_CONNECTED_eNB_MAX 1
 #                    define NUMBER_OF_CONNECTED_gNB_MAX 1
 #            endif
 #        else
 #                    define NUMBER_OF_UE_MAX 1
 #                    define NUMBER_OF_NR_UE_MAX 1
+#                    define NUMBER_OF_UCI_VARS_MAX 56
 #                    define NUMBER_OF_CONNECTED_eNB_MAX 1
 #                    define NUMBER_OF_CONNECTED_gNB_MAX 1
 #        endif
@@ -50,17 +54,20 @@ and the other are using MAX_MOBILES_PER_ENB in for-loop.
 #            ifndef UESIM_EXPANSION
 #                define NUMBER_OF_UE_MAX 16
 #                define NUMBER_OF_NR_UE_MAX 20
+#                define NUMBER_OF_UCI_VARS_MAX 56
 #                define NUMBER_OF_CONNECTED_eNB_MAX 3
 #                define NUMBER_OF_CONNECTED_gNB_MAX 3
 #            else
 #                define NUMBER_OF_UE_MAX 256
 #                define NUMBER_OF_NR_UE_MAX 20
+#                define NUMBER_OF_UCI_VARS_MAX 256
 #                define NUMBER_OF_CONNECTED_eNB_MAX 1
 #                define NUMBER_OF_CONNECTED_gNB_MAX 3
 #            endif
 #        else
 #                define NUMBER_OF_UE_MAX 256
 #                define NUMBER_OF_NR_UE_MAX 256
+#                define NUMBER_OF_UCI_VARS_MAX 256
 #                define NUMBER_OF_CONNECTED_eNB_MAX 1
 #                define NUMBER_OF_CONNECTED_gNB_MAX 1
 #        endif
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
index df2c81c21cec356c970237186d4a896af0c45ce4..6634ae51d29cbed9c1f477ab9f6a0e6e92cc82aa 100644
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -194,14 +194,14 @@ static inline int rxtx(PHY_VARS_eNB *eNB,
         eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs ||
         eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs ||
         eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles ||
-        eNB->UL_INFO.cqi_ind.number_of_cqis
+        eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis
        ) {
       LOG_D(PHY, "UL_info[rx_ind:%05d:%d harqs:%05d:%d crcs:%05d:%d preambles:%05d:%d cqis:%d] RX:%04d%d TX:%04d%d num_pdcch_symbols:%d\n",
             NFAPI_SFNSF2DEC(eNB->UL_INFO.rx_ind.sfn_sf),   eNB->UL_INFO.rx_ind.rx_indication_body.number_of_pdus,
             NFAPI_SFNSF2DEC(eNB->UL_INFO.harq_ind.sfn_sf), eNB->UL_INFO.harq_ind.harq_indication_body.number_of_harqs,
             NFAPI_SFNSF2DEC(eNB->UL_INFO.crc_ind.sfn_sf),  eNB->UL_INFO.crc_ind.crc_indication_body.number_of_crcs,
             NFAPI_SFNSF2DEC(eNB->UL_INFO.rach_ind.sfn_sf), eNB->UL_INFO.rach_ind.rach_indication_body.number_of_preambles,
-            eNB->UL_INFO.cqi_ind.number_of_cqis,
+          eNB->UL_INFO.cqi_ind.cqi_indication_body.number_of_cqis, 
             proc->frame_rx, proc->subframe_rx,
             proc->frame_tx, proc->subframe_tx, eNB->pdcch_vars[proc->subframe_tx&1].num_pdcch_symbols);
     }
@@ -223,9 +223,11 @@ static inline int rxtx(PHY_VARS_eNB *eNB,
     wakeup_prach_eNB_br(eNB,NULL,proc->frame_rx,proc->subframe_rx);
 #endif
   }
-
-  release_UE_in_freeList(eNB->Mod_id);
-
+  if (NFAPI_MODE!=NFAPI_MODE_PNF) {
+    release_UE_in_freeList(eNB->Mod_id);
+  } else {
+    release_rnti_of_phy(eNB->Mod_id);
+  }
   // UE-specific RX processing for subframe n
   if (NFAPI_MODE==NFAPI_MONOLITHIC || NFAPI_MODE==NFAPI_MODE_PNF) {
     phy_procedures_eNB_uespec_RX(eNB, proc);
@@ -436,13 +438,12 @@ static void *L1_thread( void *param )
     }
 
     LOG_D(PHY,"L1 RX %d.%d done\n",proc->frame_rx,proc->subframe_rx);
-
-    if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT)              phy_procedures_eNB_TX(eNB, proc, 1);
-
-
     if (NFAPI_MODE!=NFAPI_MODE_VNF) {
-      if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)      wakeup_tx(eNB,proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx);
-      else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT)     wakeup_txfh(eNB,proc,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx);
+      if(get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT)     wakeup_tx(eNB,proc->frame_rx,proc->subframe_rx,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx); 
+      else if(get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) {
+        phy_procedures_eNB_TX(eNB, proc, 1);
+        wakeup_txfh(eNB,proc,proc->frame_tx,proc->subframe_tx,proc->timestamp_tx);
+      }
     }
 
     if (release_thread(&proc->mutex,&proc->instance_cnt,thread_name)<0) break;
@@ -968,7 +969,9 @@ void init_eNB_proc(int inst)
 
     LOG_I(PHY,"eNB->single_thread_flag:%d\n", eNB->single_thread_flag);
 
-    if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) {
+    if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) {
+      pthread_create( &L1_proc->pthread, attr0, L1_thread, proc );
+    } else if ((get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && NFAPI_MODE!=NFAPI_MODE_VNF) {
       pthread_create( &L1_proc->pthread, attr0, L1_thread, proc );
       pthread_create( &L1_proc_tx->pthread, attr1, L1_thread_tx, proc);
     } else if (NFAPI_MODE==NFAPI_MODE_VNF) { // this is neccesary in VNF or L2 FAPI simulator.
@@ -979,10 +982,12 @@ void init_eNB_proc(int inst)
       pthread_create( &L1_proc_tx->pthread, attr1, L1_thread, L1_proc_tx);
     }
 
-    pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB );
+    if (NFAPI_MODE!=NFAPI_MODE_VNF) {
+      pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB );
 #if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
-    pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB );
+      pthread_create( &proc->pthread_prach_br, attr_prach_br, eNB_thread_prach_br, eNB );
 #endif
+    }
     AssertFatal(proc->instance_cnt_prach == -1,"instance_cnt_prach = %d\n",proc->instance_cnt_prach);
 
     if (opp_enabled == 1) pthread_create(&proc->process_stats_thread,NULL,process_stats_thread,(void *)eNB);
@@ -1144,6 +1149,7 @@ void init_transport(PHY_VARS_eNB *eNB)
   LTE_DL_FRAME_PARMS *fp = &eNB->frame_parms;
   LOG_I(PHY, "Initialise transport\n");
 
+if (NFAPI_MODE!=NFAPI_MODE_VNF) {
   for (i=0; i<NUMBER_OF_UE_MAX; i++) {
     LOG_D(PHY,"Allocating Transport Channel Buffers for DLSCH, UE %d\n",i);
 
@@ -1186,6 +1192,7 @@ void init_transport(PHY_VARS_eNB *eNB)
   LOG_D(PHY,"eNB %d.%d : RA %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_ra);
   eNB->dlsch_MCH = new_eNB_dlsch(1,8,NSOFT,fp->N_RB_DL, 0, fp);
   LOG_D(PHY,"eNB %d.%d : MCH %p\n",eNB->Mod_id,eNB->CC_id,eNB->dlsch_MCH);
+}
   eNB->rx_total_gain_dB=130;
 
   for(i=0; i<NUMBER_OF_UE_MAX; i++)
@@ -1328,8 +1335,8 @@ void init_eNB(int single_thread_flag,
       eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list = eNB->crc_pdu_list;
       eNB->UL_INFO.sr_ind.sr_indication_body.sr_pdu_list = eNB->sr_pdu_list;
       eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list = eNB->harq_pdu_list;
-      eNB->UL_INFO.cqi_ind.cqi_pdu_list = eNB->cqi_pdu_list;
-      eNB->UL_INFO.cqi_ind.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
+      eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_pdu_list = eNB->cqi_pdu_list;
+      eNB->UL_INFO.cqi_ind.cqi_indication_body.cqi_raw_pdu_list = eNB->cqi_raw_pdu_list;
       eNB->prach_energy_counter = 0;
     }
   }
diff --git a/targets/RT/USER/lte-softmodem-common.c b/targets/RT/USER/lte-softmodem-common.c
index dd91f540047e7108102f04bb6102216395ce60b7..a5fee5397fdd7cababcceb9dce14af44d273c6b5 100644
--- a/targets/RT/USER/lte-softmodem-common.c
+++ b/targets/RT/USER/lte-softmodem-common.c
@@ -62,6 +62,7 @@ void get_common_options(void) {
   uint32_t nonbiot;
   uint32_t rfsim;
   uint32_t basicsim;
+  char *logmem_filename = NULL;
   uint32_t do_forms;
   paramdef_t cmdline_params[] =CMDLINE_PARAMS_DESC ;
   paramdef_t cmdline_logparams[] =CMDLINE_LOGPARAMS_DESC ;
@@ -83,6 +84,13 @@ void get_common_options(void) {
     load_module_shlib("telnetsrv",NULL,0,NULL);
   }
 
+  if (logmem_filename != NULL && strlen(logmem_filename) > 0) {
+    log_mem_filename = &logmem_filename[0];
+    log_mem_flag = 1;
+    printf("Enabling OPT for log save at memory %s\n",log_mem_filename);
+    logInit_log_mem();
+  }
+
   if (noS1) {
     set_softmodem_optmask(SOFTMODEM_NOS1_BIT);
   }
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
index a842cba853a38246b762f818e3af4f7e26519624..24a15816a20f08597d5c59f2b759c096bd86c90d 100644
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -259,7 +259,7 @@ void exit_function(const char *file, const char *function, const int line, const
   if (s != NULL) {
     printf("%s:%d %s() Exiting OAI softmodem: %s\n",file,line, function, s);
   }
-
+  close_log_mem();
   oai_exit = 1;
 
   if (RC.ru == NULL)
@@ -523,6 +523,7 @@ int main ( int argc, char **argv )
   int i;
   int CC_id = 0;
   int ru_id;
+  int node_type = ngran_eNB;
 
   if ( load_configmodule(argc,argv,0) == NULL) {
     exit_fun("[SOFTMODEM] Error, configuration module init failed\n");
@@ -603,12 +604,13 @@ int main ( int argc, char **argv )
       RRC_CONFIGURATION_REQ(msg_p) = RC.rrc[enb_id]->configuration;
       itti_send_msg_to_task (TASK_RRC_ENB, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
     }
+    node_type = RC.rrc[0]->node_type;
   } else {
     printf("RC.nb_inst = 0, Initializing L1\n");
     RCconfig_L1();
   }
 
-  if (RC.nb_inst > 0 && NODE_IS_CU(RC.rrc[0]->node_type)) {
+  if (RC.nb_inst > 0 && NODE_IS_CU(node_type)) {
     protocol_ctxt_t ctxt;
     ctxt.module_id = 0 ;
     ctxt.instance = 0;
@@ -620,7 +622,7 @@ int main ( int argc, char **argv )
   }
     
   /* start threads if only L1 or not a CU */
-  if (RC.nb_inst == 0 || !NODE_IS_CU(RC.rrc[0]->node_type)) {
+  if (RC.nb_inst == 0 || !NODE_IS_CU(node_type) || NFAPI_MODE == NFAPI_MODE_PNF || NFAPI_MODE == NFAPI_MODE_VNF) {
     // init UE_PF_PO and mutex lock
     pthread_mutex_init(&ue_pf_po_mutex, NULL);
     memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*MAX_MOBILES_PER_ENB*MAX_NUM_CCs);
@@ -719,7 +721,7 @@ int main ( int argc, char **argv )
   LOG_I(ENB_APP,"oai_exit=%d\n",oai_exit);
   // stop threads
 
-  if (RC.nb_inst == 0 || !NODE_IS_CU(RC.rrc[0]->node_type)) {
+  if (RC.nb_inst == 0 || !NODE_IS_CU(node_type)) {
     if(IS_SOFTMODEM_DOFORMS)
       end_forms();
 
diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h
index f2be4d54e6a78b8ef67a775a2ef29c13e576aa44..5b58a5daabfb02f3f7ea225f93703d9980279a02 100644
--- a/targets/RT/USER/lte-softmodem.h
+++ b/targets/RT/USER/lte-softmodem.h
@@ -216,16 +216,17 @@
 #define CONFIG_HLP_LOGV          "Set the global log verbosity \n"
 #define CONFIG_HLP_TELN          "Start embedded telnet server \n"
 #define CONFIG_HLP_MSC           "Enable the MSC tracing utility \n"
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
-/*                                            command line parameters for LOG utility                                                                                        */
-/*   optname         helpstr          paramflags        XXXptr                     defXXXval            type           numelt    */
-/*---------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
+/*----------------------------------------------------------------------------------------------------------------------------*/
+/*                                            command line parameters for LOG utility                                         */
+/*   optname         helpstr          paramflags        XXXptr                     defXXXval            type           numelt */
+/*----------------------------------------------------------------------------------------------------------------------------*/
 #define START_MSC                softmodem_params.start_msc
 #define CMDLINE_LOGPARAMS_DESC {  \
-    {"R" ,           CONFIG_HLP_FLOG, 0,                uptr:&online_log_messages, defintval:1,         TYPE_INT,      0},        \
-    {"g" ,           CONFIG_HLP_LOGL, 0,                uptr:&glog_level,          defintval:0,         TYPE_UINT,     0},        \
-	{"telnetsrv",    CONFIG_HLP_TELN, PARAMFLAG_BOOL,   uptr:&start_telnetsrv,     defintval:0,         TYPE_UINT,     0},        \
-    {"msc",          CONFIG_HLP_MSC,  PARAMFLAG_BOOL,   uptr:&START_MSC,           defintval:0,         TYPE_UINT,     0},        \
+    {"R" ,           CONFIG_HLP_FLOG, 0,                uptr:&online_log_messages, defintval:1,         TYPE_INT,      0},     \
+    {"g" ,           CONFIG_HLP_LOGL, 0,                uptr:&glog_level,          defintval:0,         TYPE_UINT,     0},     \
+	{"telnetsrv",    CONFIG_HLP_TELN, PARAMFLAG_BOOL,   uptr:&start_telnetsrv,     defintval:0,         TYPE_UINT,     0},     \
+    {"msc",          CONFIG_HLP_MSC,  PARAMFLAG_BOOL,   uptr:&START_MSC,           defintval:0,         TYPE_UINT,     0},     \
+	{"log-mem",      NULL,            0,      strptr:(char **)&logmem_filename,    defstrval:NULL,      TYPE_STRING,   0},     \
   }
 
 #define CMDLINE_ONLINELOG_IDX     0
@@ -235,10 +236,11 @@
 
 /* check function for global log level */
 #define CMDLINE_LOGPARAMS_CHECK_DESC { \
-    { .s5= {NULL }} ,                         \
-    { .s2=  { config_check_intrange, {0,4}}}, \
-    { .s5= {NULL }} ,                         \
-    { .s5= {NULL }} ,                         \
+    { .s5= {NULL} } ,                       \
+    { .s2= {config_check_intrange, {0,4}}}, \
+    { .s5= {NULL} } ,                       \
+    { .s5= {NULL} } ,                       \
+    { .s5= {NULL} } ,                       \
   }
 
 /***************************************************************************************************************************************/
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
index 10fc476868adfe6947ec95592f7fb2b987817c45..8a4172965e55b3b081d3f757d0658d9af6b9bf94 100644
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -1074,9 +1074,9 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg)
       UL_INFO->harq_ind.harq_indication_body.number_of_harqs = 0;
       UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = (nfapi_sr_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_sr_indication_pdu_t));
       UL_INFO->sr_ind.sr_indication_body.number_of_srs = 0;
-      UL_INFO->cqi_ind.cqi_pdu_list =  (nfapi_cqi_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_pdu_t));
-      UL_INFO->cqi_ind.cqi_raw_pdu_list = (nfapi_cqi_indication_raw_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_raw_pdu_t));
-      UL_INFO->cqi_ind.number_of_cqis = 0;
+      UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list =  (nfapi_cqi_indication_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_pdu_t));
+      UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = (nfapi_cqi_indication_raw_pdu_t *)malloc(NB_UE_INST*sizeof(nfapi_cqi_indication_raw_pdu_t));
+      UL_INFO->cqi_ind.cqi_indication_body.number_of_cqis = 0;
 
       if (pthread_mutex_lock(&phy_stub_ticking->mutex_single_thread) != 0) {
         LOG_E( MAC, "[SCHED][UE] error locking mutex for ue_thread_id %d (mutex_single_thread)\n",ue_thread_id);
@@ -1283,10 +1283,10 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg)
       free(UL_INFO->sr_ind.sr_indication_body.sr_pdu_list);
       UL_INFO->sr_ind.sr_indication_body.sr_pdu_list = NULL;
       //}
-      free(UL_INFO->cqi_ind.cqi_pdu_list);
-      UL_INFO->cqi_ind.cqi_pdu_list = NULL;
-      free(UL_INFO->cqi_ind.cqi_raw_pdu_list);
-      UL_INFO->cqi_ind.cqi_raw_pdu_list = NULL;
+      free(UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list);
+      UL_INFO->cqi_ind.cqi_indication_body.cqi_pdu_list = NULL;
+      free(UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list);
+      UL_INFO->cqi_ind.cqi_indication_body.cqi_raw_pdu_list = NULL;
       free(UL_INFO);
       UL_INFO = NULL;