diff --git a/ci-scripts/Jenkinsfile-gitlab b/ci-scripts/Jenkinsfile-gitlab
index 0d9f37ed24b6c037c569c1ab243c4a95e7be4714..b050eff60e72dd12f63b4432c0a5c6d9567f0474 100644
--- a/ci-scripts/Jenkinsfile-gitlab
+++ b/ci-scripts/Jenkinsfile-gitlab
@@ -166,6 +166,14 @@ pipeline {
             }
         }
 
+        stage ("Start VM -- L2-Sim") {
+            steps {
+                timeout (time: 5, unit: 'MINUTES') {
+                    sh "./ci-scripts/oai-ci-vm-tool build --workspace $WORKSPACE --variant l2-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID} --daemon"
+                }
+            }
+        }
+
         stage ("Start VM -- phy-sim") {
             steps {
                 timeout (time: 5, unit: 'MINUTES') {
@@ -215,7 +223,7 @@ pipeline {
                     steps {
                         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"
+                                sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant enb-ethernet --job-name ${JOB_NAME} --build-id ${BUILD_ID}"
                             }
                         }
                     }
@@ -224,11 +232,20 @@ pipeline {
                     steps {
                         gitlabCommitStatus(name: "Build UE-ethernet") {
                             timeout (time: 20, unit: 'MINUTES') {
-                                sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant ue-ethernet --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
+                                sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant ue-ethernet --job-name ${JOB_NAME} --build-id ${BUILD_ID}"
                             }
                         }
                     }
                 }
+                stage ("Build L2-Simulator-eNB") {
+                    steps {
+                        //gitlabCommitStatus(name: "Build UE-ethernet") {
+                            timeout (time: 20, unit: 'MINUTES') {
+                                sh "./ci-scripts/oai-ci-vm-tool wait --workspace $WORKSPACE --variant l2-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID} --keep-vm-alive"
+                            }
+                        //}
+                    }
+                }
                 stage ("Build physical simulators") {
                     steps {
                         gitlabCommitStatus(name: "Build phy-sim") {
@@ -313,6 +330,15 @@ pipeline {
                         }
                     }
                 }
+                stage ("Test L2 simulator") {
+                    steps {
+                        //gitlabCommitStatus(name: "Test basic-sim") {
+                            timeout (time: 30, unit: 'MINUTES') {
+                                sh "./ci-scripts/oai-ci-vm-tool test --workspace $WORKSPACE --variant l2-sim --job-name ${JOB_NAME} --build-id ${BUILD_ID}"
+                            }
+                        //}
+                    }
+                }
                 stage ("Build Flexran Controller") {
                     when {
                         expression {doFlexranCtrlTest}
diff --git a/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf b/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c2a86f079e983672a2fcf8949e211d6862d00b94
--- /dev/null
+++ b/ci-scripts/conf_files/rcc.band7.tm1.nfapi.conf
@@ -0,0 +1,236 @@
+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; } );
+
+    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              			      = 7;
+      downlink_frequency      			      = 2685000000L;
+      uplink_frequency_offset 			      = -120000000;
+      Nid_cell					      = 0;
+      N_RB_DL                 			      = 50;
+      Nid_cell_mbsfn          			      = 0;
+      nb_antenna_ports                                = 1;
+      nb_antennas_tx          			      = 1;
+      nb_antennas_rx          			      = 1;
+      tx_gain                                            = 90;
+      rx_gain                                            = 125;
+      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";
+                            }
+                          );
+
+    NETWORK_INTERFACES :
+    {
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "ens3";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "CI_ENB_IP_ADDR";
+        ENB_INTERFACE_NAME_FOR_S1U               = "ens3";
+        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;
+      	local_s_if_name  = "lo:";			  
+      	remote_s_address = "127.0.0.1";
+    	local_s_address  = "127.0.0.2"; 
+    	local_s_portc    = 50001;	
+    	remote_s_portc   = 50000;
+    	local_s_portd    = 50011;	
+    	remote_s_portd   = 50010;
+	tr_s_preference = "nfapi";
+	tr_n_preference = "local_RRC";
+        }  
+);
+
+THREAD_STRUCT = (
+  {
+    #three config for level of parallelism "PARALLEL_SINGLE_THREAD", "PARALLEL_RU_L1_SPLIT", or "PARALLEL_RU_L1_TRX_SPLIT"
+    parallel_config    = "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/ue.nfapi.conf b/ci-scripts/conf_files/ue.nfapi.conf
new file mode 100644
index 0000000000000000000000000000000000000000..ea0236cab4e97b640b0c8ac17601ccb184c22c25
--- /dev/null
+++ b/ci-scripts/conf_files/ue.nfapi.conf
@@ -0,0 +1,44 @@
+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                     ="medium";
+  rlc_log_level                         ="info";
+  rlc_log_verbosity                     ="medium";
+  pdcp_log_level                        ="info";
+  pdcp_log_verbosity                    ="medium";
+  rrc_log_level                         ="info";
+  rrc_log_verbosity                     ="full";
+};
+
+
+L1s = (
+    	{
+	num_cc = 1;
+	tr_n_preference = "nfapi";
+    	local_n_if_name  = "lo";
+      	remote_n_address = "127.0.0.2";
+    	local_n_address  = "127.0.0.1";
+    	local_n_portc    = 50000;
+    	remote_n_portc   = 50001;
+    	local_n_portd    = 50010;
+    	remote_n_portd   = 50011;
+        }  
+);
+
+RUs = (
+    {		  
+       local_rf       = "yes"
+       nb_tx          = 1
+       nb_rx          = 1
+       att_tx         = 90
+       att_rx         = 0;
+       bands          = [7,38,42,43];
+       max_pdschReferenceSignalPower = -27;
+       max_rxgain                    = 125;
+    }		      
+);
diff --git a/ci-scripts/oai-ci-vm-tool b/ci-scripts/oai-ci-vm-tool
index 8bf7853d0ce1ab7516cb4a4e3efd4b66d1b60309..b787129302a705f40eceab46b96b1b0b967dbda6 100755
--- a/ci-scripts/oai-ci-vm-tool
+++ b/ci-scripts/oai-ci-vm-tool
@@ -40,6 +40,7 @@ function variant_usage {
     echo "    --variant cppcheck     OR -v4"
     echo "    --variant enb-ethernet OR -v7"
     echo "    --variant ue-ethernet  OR -v8"
+    echo "    --variant l2-sim       OR -v9"
     echo "    --variant flexran-rtc  OR -v10"
 }
 
@@ -285,6 +286,18 @@ case $key in
     NBARGS=$[$NBARGS+256]
     shift
     ;;
+    -v9)
+    VM_NAME=ci-l2-sim
+    VM_MEMORY=8192
+    VM_CPU=8
+    ARCHIVES_LOC=l2_sim
+    LOG_PATTERN=.Rel14.txt
+    NB_PATTERN_FILES=4
+    BUILD_OPTIONS="--eNB -t ETHERNET"
+    RUN_OPTIONS="complex"
+    NBARGS=$[$NBARGS+256]
+    shift
+    ;;
     -v10)
     VM_NAME=ci-flexran-rtc
     ARCHIVES_LOC=flexran
@@ -350,6 +363,18 @@ case $key in
         BUILD_OPTIONS="--UE -t ETHERNET --noS1"
         NBARGS=$[$NBARGS+256]
         ;;
+        l2-sim)
+        VM_NAME=ci-l2-sim
+        VM_MEMORY=8192
+        VM_CPU=8
+        ARCHIVES_LOC=l2_sim
+        LOG_PATTERN=.Rel14.txt
+        NB_PATTERN_FILES=4
+        BUILD_OPTIONS="--eNB -t ETHERNET"
+        RUN_OPTIONS="complex"
+        NBARGS=$[$NBARGS+256]
+        shift
+        ;;
         flexran-rtc)
         VM_NAME=ci-flexran-rtc
         ARCHIVES_LOC=flexran
diff --git a/ci-scripts/runTestOnVM.sh b/ci-scripts/runTestOnVM.sh
index bed46f0acefa478d2b34e49b8a79380e2e14610c..4d87ba579151e46765af0269f02e12feac142155 100755
--- a/ci-scripts/runTestOnVM.sh
+++ b/ci-scripts/runTestOnVM.sh
@@ -280,17 +280,171 @@ function recover_core_dump {
     fi
 }
 
-function terminate_ltebox_epc {
-    echo "echo \"cd /opt/ltebox/tools\"" > $1
-    echo "cd /opt/ltebox/tools" >> $1
-    echo "echo \"sudo ./stop_ltebox\"" >> $1
-    echo "sudo ./stop_ltebox" >> $1
-    echo "echo \"sudo daemon --name=simulated_hss --stop\"" >> $1
-    echo "sudo daemon --name=simulated_hss --stop" >> $1
-    echo "echo \"sudo killall --signal SIGKILL hss_sim\"" >> $1
-    echo "sudo killall --signal SIGKILL hss_sim" >> $1
-    ssh -o StrictHostKeyChecking=no ubuntu@$2 < $1
-    rm $1
+function install_epc_on_vm {
+    local LOC_EPC_VM_NAME=$1
+    local LOC_EPC_VM_CMDS=$2
+
+    if [ -d /opt/ltebox-archives/ ]
+    then
+        # Checking if all ltebox archives are available to run ltebx epc on a brand new VM
+        if [ -f /opt/ltebox-archives/ltebox_2.2.70_16_04_amd64.deb ] && [ -f /opt/ltebox-archives/etc-conf.zip ] && [ -f /opt/ltebox-archives/hss-sim.zip ]
+        then
+            echo "############################################################"
+            echo "Test EPC on VM ($EPC_VM_NAME) will be using ltebox"
+            echo "############################################################"
+            LTEBOX=1
+        fi
+    fi
+    # Here we could have other types of EPC detection
+
+    # Do we need to start the EPC VM
+    echo "EPC_VM_CMD_FILE     = $LOC_EPC_VM_CMDS"
+    IS_EPC_VM_ALIVE=`uvt-kvm list | grep -c $LOC_EPC_VM_NAME`
+    if [ $IS_EPC_VM_ALIVE -eq 0 ]
+    then
+        echo "############################################################"
+        echo "Creating test EPC VM ($LOC_EPC_VM_NAME) on Ubuntu Cloud Image base"
+        echo "############################################################"
+        uvt-kvm create $LOC_EPC_VM_NAME release=xenial --unsafe-caching
+    fi
+
+    uvt-kvm wait $LOC_EPC_VM_NAME --insecure
+    local LOC_EPC_VM_IP_ADDR=`uvt-kvm ip $LOC_EPC_VM_NAME`
+    echo "$LOC_EPC_VM_NAME has for IP addr = $LOC_EPC_VM_IP_ADDR"
+    scp -o StrictHostKeyChecking=no /etc/apt/apt.conf.d/01proxy ubuntu@$LOC_EPC_VM_IP_ADDR:/home/ubuntu
+
+    # ltebox specific actions (install and start)
+    LTE_BOX_TO_INSTALL=1
+    if [ $LTEBOX -eq 1 ]
+    then
+        echo "ls -ls /opt/ltebox/tools/start_ltebox" > $LOC_EPC_VM_CMDS
+        RESPONSE=`ssh -o StrictHostKeyChecking=no ubuntu@$LOC_EPC_VM_IP_ADDR < $LOC_EPC_VM_CMDS`
+        NB_EXES=`echo $RESPONSE | grep -c ltebox`
+        if [ $NB_EXES -eq 1 ]; then LTE_BOX_TO_INSTALL=0; fi
+    fi
+
+    if [ $LTEBOX -eq 1 ] && [ $LTE_BOX_TO_INSTALL -eq 1 ]
+    then
+        echo "############################################################"
+        echo "Copying ltebox archives into EPC VM ($LOC_EPC_VM_NAME)" 
+        echo "############################################################"
+        scp -o StrictHostKeyChecking=no /opt/ltebox-archives/ltebox_2.2.70_16_04_amd64.deb ubuntu@$LOC_EPC_VM_IP_ADDR:/home/ubuntu
+        scp -o StrictHostKeyChecking=no /opt/ltebox-archives/etc-conf.zip ubuntu@$LOC_EPC_VM_IP_ADDR:/home/ubuntu
+        scp -o StrictHostKeyChecking=no /opt/ltebox-archives/hss-sim.zip ubuntu@$LOC_EPC_VM_IP_ADDR:/home/ubuntu
+
+        echo "############################################################"
+        echo "Install EPC on EPC VM ($LOC_EPC_VM_NAME)"
+        echo "############################################################"
+        echo "sudo cp 01proxy /etc/apt/apt.conf.d/" > $LOC_EPC_VM_CMDS
+        echo "touch /home/ubuntu/.hushlogin" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo apt-get --yes --quiet install zip openjdk-8-jre libconfuse-dev libreadline-dev liblog4c-dev libgcrypt-dev libsctp-dev python2.7 python2.7-dev daemon iperf\"" >> $LOC_EPC_VM_CMDS
+        echo "sudo apt-get update > zip-install.txt 2>&1" >> $LOC_EPC_VM_CMDS
+        echo "sudo apt-get --yes install zip openjdk-8-jre libconfuse-dev libreadline-dev liblog4c-dev libgcrypt-dev libsctp-dev python2.7 python2.7-dev daemon iperf >> zip-install.txt 2>&1" >> $LOC_EPC_VM_CMDS
+
+        # Installing HSS
+        echo "echo \"cd /opt\"" >> $LOC_EPC_VM_CMDS
+        echo "cd /opt" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo unzip -qq /home/ubuntu/hss-sim.zip\"" >> $LOC_EPC_VM_CMDS
+        echo "sudo unzip -qq /home/ubuntu/hss-sim.zip" >> $LOC_EPC_VM_CMDS
+        echo "echo \"cd /opt/hss_sim0609\"" >> $LOC_EPC_VM_CMDS
+        echo "cd /opt/hss_sim0609" >> $LOC_EPC_VM_CMDS
+
+        # Installing ltebox
+        echo "echo \"cd /home/ubuntu\"" >> $LOC_EPC_VM_CMDS
+        echo "cd /home/ubuntu" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo dpkg -i ltebox_2.2.70_16_04_amd64.deb \"" >> $LOC_EPC_VM_CMDS
+        echo "sudo dpkg -i ltebox_2.2.70_16_04_amd64.deb >> zip-install.txt 2>&1" >> $LOC_EPC_VM_CMDS
+
+        echo "echo \"cd /opt/ltebox/etc/\"" >> $LOC_EPC_VM_CMDS
+        echo "cd /opt/ltebox/etc/" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo unzip -qq -o /home/ubuntu/etc-conf.zip\"" >> $LOC_EPC_VM_CMDS
+        echo "sudo unzip -qq -o /home/ubuntu/etc-conf.zip" >> $LOC_EPC_VM_CMDS
+        echo "sudo sed -i  -e 's#EPC_VM_IP_ADDRESS#$LOC_EPC_VM_IP_ADDR#' gw.conf" >> $LOC_EPC_VM_CMDS
+        echo "sudo sed -i  -e 's#EPC_VM_IP_ADDRESS#$LOC_EPC_VM_IP_ADDR#' mme.conf" >> $LOC_EPC_VM_CMDS
+
+        ssh -o StrictHostKeyChecking=no ubuntu@$LOC_EPC_VM_IP_ADDR < $LOC_EPC_VM_CMDS
+        rm -f $LOC_EPC_VM_CMDS
+    fi
+}
+
+function start_epc {
+    local LOC_EPC_VM_NAME=$1
+    local LOC_EPC_VM_CMDS=$2
+    local LOC_EPC_VM_IP_ADDR=$3
+
+    if [ $LTEBOX -eq 1 ]
+    then
+        echo "############################################################"
+        echo "Start EPC on EPC VM ($LOC_EPC_VM_NAME)"
+        echo "############################################################"
+        echo "echo \"cd /opt/hss_sim0609\"" > $LOC_EPC_VM_CMDS
+        echo "cd /opt/hss_sim0609" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real\"" >> $LOC_EPC_VM_CMDS
+        echo "sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real" >> $LOC_EPC_VM_CMDS
+
+        echo "echo \"cd /opt/ltebox/tools/\"" >> $LOC_EPC_VM_CMDS
+        echo "cd /opt/ltebox/tools/" >> $LOC_EPC_VM_CMDS
+        echo "echo \"sudo ./start_ltebox\"" >> $LOC_EPC_VM_CMDS
+        echo "nohup sudo ./start_ltebox > /home/ubuntu/ltebox.txt" >> $LOC_EPC_VM_CMDS
+
+        ssh -o StrictHostKeyChecking=no ubuntu@$LOC_EPC_VM_IP_ADDR < $LOC_EPC_VM_CMDS
+        rm -f $LOC_EPC_VM_CMDS
+
+        i="0"
+        echo "ifconfig tun5 | egrep -c \"inet addr\"" > $LOC_EPC_VM_CMDS
+        while [ $i -lt 10 ]
+        do
+            sleep 2
+            CONNECTED=`ssh -o StrictHostKeyChecking=no ubuntu@$LOC_EPC_VM_IP_ADDR < $LOC_EPC_VM_CMDS`
+            if [ $CONNECTED -eq 1 ]
+            then
+                i="100"
+            else
+                i=$[$i+1]
+            fi
+        done
+        rm $LOC_EPC_VM_CMDS
+        if [ $i -lt 50 ]
+        then
+            echo "Problem w/ starting ltebox EPC"
+            echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
+            exit -1
+        fi
+    fi
+
+    # HERE ADD ANY INSTALL ACTIONS FOR ANOTHER EPC
+
+}
+
+function retrieve_real_epc_ip_addr {
+    local LOC_EPC_VM_NAME=$1
+    local LOC_EPC_VM_CMDS=$2
+    local LOC_EPC_VM_IP_ADDR=$3
+
+    if [ $LTEBOX -eq 1 ]
+    then
+        # in our configuration file, we are using pool 5
+        echo "ifconfig tun5 | egrep \"inet addr\" | sed -e 's#^.*inet addr:##' -e 's#  P-t-P:.*\$##'" > $LOC_EPC_VM_CMDS
+        REAL_EPC_IP_ADDR=`ssh -o StrictHostKeyChecking=no ubuntu@$LOC_EPC_VM_IP_ADDR < $LOC_EPC_VM_CMDS`
+        echo "EPC IP Address     is : $REAL_EPC_IP_ADDR"
+        rm $LOC_EPC_VM_CMDS
+    fi
+}
+
+function terminate_epc {
+    if [ $LTEBOX -eq 1 ]
+    then
+        echo "echo \"cd /opt/ltebox/tools\"" > $1
+        echo "cd /opt/ltebox/tools" >> $1
+        echo "echo \"sudo ./stop_ltebox\"" >> $1
+        echo "sudo ./stop_ltebox" >> $1
+        echo "echo \"sudo daemon --name=simulated_hss --stop\"" >> $1
+        echo "sudo daemon --name=simulated_hss --stop" >> $1
+        echo "echo \"sudo killall --signal SIGKILL hss_sim\"" >> $1
+        echo "sudo killall --signal SIGKILL hss_sim" >> $1
+        ssh -o StrictHostKeyChecking=no ubuntu@$2 < $1
+        rm $1
+    fi
 }
 
 function start_flexran_ctrl {
@@ -322,6 +476,85 @@ function query_flexran_ctrl_status {
     rm $1
 }
 
+function build_ue_on_separate_folder {
+    echo "mkdir tmp-ue" > $1
+    echo "cd tmp-ue" >> $1
+    echo "echo \"unzip -qq -DD ../localZip.zip\"" >> $1
+    echo "unzip -qq -DD ../localZip.zip" >> $1
+
+    # We may have some adaptation to do
+    if [ -f /opt/ltebox-archives/adapt_ue_l2_sim.txt ]
+    then
+        echo "############################################################"
+        echo "Doing some adaptation on UE side"
+        echo "############################################################"
+        cat /opt/ltebox-archives/adapt_ue_l2_sim.txt >> $1
+    fi
+
+    echo "echo \"source oaienv\"" >> $1
+    echo "source oaienv" >> $1
+    echo "cd cmake_targets/" >> $1
+    echo "mkdir log" >> $1
+    echo "chmod 777 log" >> $1
+    echo "echo \"./build_oai --UE -t ETHERNET \"" >> $1
+    echo "./build_oai --UE -t ETHERNET > log/ue-build.txt 2>&1" >> $1
+    echo "cd tools" >> $1
+    echo "sudo ifconfig lo: 127.0.0.2 netmask 255.0.0.0 up" >> $1
+    echo "sudo chmod 666 /etc/iproute2/rt_tables" >> $1
+    echo "source init_nas_s1 UE" >> $1
+    echo "ifconfig" >> $1
+    ssh -o StrictHostKeyChecking=no ubuntu@$2 < $1
+    rm -f $1
+}
+
+function start_l2_sim_enb {
+    local LOC_VM_IP_ADDR=$2
+    local LOC_EPC_IP_ADDR=$3
+    local LOC_LOG_FILE=$4
+    local LOC_NB_RBS=$5
+    local LOC_CONF_FILE=$6
+    echo "cd /home/ubuntu/tmp" > $1
+    echo "echo \"sudo apt-get --yes --quiet install daemon \"" >> $1
+    echo "sudo apt-get --yes install daemon >> /home/ubuntu/tmp/cmake_targets/log/daemon-install.txt 2>&1" >> $1
+    echo "echo \"source oaienv\"" >> $1
+    echo "source oaienv" >> $1
+    echo "cd ci-scripts/conf_files/" >> $1
+    echo "cp $LOC_CONF_FILE ci-$LOC_CONF_FILE" >> $1
+    echo "sed -i -e 's#N_RB_DL.*=.*;#N_RB_DL                                         = $LOC_NB_RBS;#' -e 's#CI_MME_IP_ADDR#$LOC_EPC_IP_ADDR#' -e 's#CI_ENB_IP_ADDR#$LOC_VM_IP_ADDR#' ci-$LOC_CONF_FILE" >> $1
+    echo "echo \"grep N_RB_DL ci-$LOC_CONF_FILE\"" >> $1
+    echo "grep N_RB_DL ci-$LOC_CONF_FILE | sed -e 's#N_RB_DL.*=#N_RB_DL =#'" >> $1
+    echo "echo \"cd /home/ubuntu/tmp/cmake_targets/lte_build_oai/build/\"" >> $1
+    echo "sudo chmod 777 /home/ubuntu/tmp/cmake_targets/lte_build_oai/build/" >> $1
+    echo "cd /home/ubuntu/tmp/cmake_targets/lte_build_oai/build/" >> $1
+    echo "echo \"ulimit -c unlimited && ./lte-softmodem -O /home/ubuntu/tmp/ci-scripts/conf_files/ci-$LOC_CONF_FILE\" > ./my-lte-softmodem-run.sh " >> $1
+    echo "chmod 775 ./my-lte-softmodem-run.sh" >> $1
+    echo "cat ./my-lte-softmodem-run.sh" >> $1
+    echo "if [ -e /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE ]; then sudo sudo rm -f /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE; fi" >> $1
+    echo "sudo -E daemon --inherit --unsafe --name=enb_daemon --chdir=/home/ubuntu/tmp/cmake_targets/lte_build_oai/build/ -o /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE ./my-lte-softmodem-run.sh" >> $1
+
+    ssh -o StrictHostKeyChecking=no ubuntu@$LOC_VM_IP_ADDR < $1
+    sleep 10
+    rm $1
+}
+
+function start_l2_sim_ue {
+    local LOC_VM_IP_ADDR=$2
+    local LOC_LOG_FILE=$3
+    local LOC_CONF_FILE=$4
+    echo "echo \"cd /home/ubuntu/tmp-ue/cmake_targets/lte_build_oai/build/\"" >> $1
+    echo "sudo chmod 777 /home/ubuntu/tmp-ue/cmake_targets/lte_build_oai/build/" >> $1
+    echo "cd /home/ubuntu/tmp-ue/cmake_targets/lte_build_oai/build/" >> $1
+    echo "echo \"ulimit -c unlimited && ./lte-uesoftmodem -O /home/ubuntu/tmp-ue/ci-scripts/conf_files/$LOC_CONF_FILE --L2-emul 3 --num-ues 1\" > ./my-lte-softmodem-run.sh " >> $1
+    echo "chmod 775 ./my-lte-softmodem-run.sh" >> $1
+    echo "cat ./my-lte-softmodem-run.sh" >> $1
+    echo "if [ -e /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE ]; then sudo sudo rm -f /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE; fi" >> $1
+    echo "sudo -E daemon --inherit --unsafe --name=ue_daemon --chdir=/home/ubuntu/tmp-ue/cmake_targets/lte_build_oai/build/ -o /home/ubuntu/tmp/cmake_targets/log/$LOC_LOG_FILE ./my-lte-softmodem-run.sh" >> $1
+
+    ssh -o StrictHostKeyChecking=no ubuntu@$LOC_VM_IP_ADDR < $1
+    sleep 10
+    rm $1
+}
+
 function run_test_on_vm {
     echo "############################################################"
     echo "OAI CI VM script"
@@ -459,148 +692,26 @@ function run_test_on_vm {
         fi
         mkdir --parents $ARCHIVES_LOC
 
+        # Creating a VM for EPC and installing SW
         EPC_VM_NAME=`echo $VM_NAME | sed -e "s#basic-sim#epc#"`
+        EPC_VM_CMDS=${EPC_VM_NAME}_cmds.txt
         LTEBOX=0
-        if [ -d /opt/ltebox-archives/ ]
-        then
-            # Checking if all ltebox archives are available to run ltebx epc on a brand new VM
-            if [ -f /opt/ltebox-archives/ltebox_2.2.70_16_04_amd64.deb ] && [ -f /opt/ltebox-archives/etc-conf.zip ] && [ -f /opt/ltebox-archives/hss-sim.zip ]
-            then
-                echo "############################################################"
-                echo "Test EPC on VM ($EPC_VM_NAME) will be using ltebox"
-                echo "############################################################"
-                LTEBOX=1
-            fi
-        fi
-        # Here we could have other types of EPC detection
-
-        # Do we need to start the EPC VM
-        EPC_VM_CMDS=`echo $VM_CMDS | sed -e "s#cmds#epc-cmds#"`
-        echo "EPC_VM_CMD_FILE     = $EPC_VM_CMDS"
-        IS_EPC_VM_ALIVE=`uvt-kvm list | grep -c $EPC_VM_NAME`
-        if [ $IS_EPC_VM_ALIVE -eq 0 ]
-        then
-            echo "############################################################"
-            echo "Creating test EPC VM ($EPC_VM_NAME) on Ubuntu Cloud Image base"
-            echo "############################################################"
-            uvt-kvm create $EPC_VM_NAME release=xenial --unsafe-caching
-        fi
-
-        uvt-kvm wait $EPC_VM_NAME --insecure
+        install_epc_on_vm $EPC_VM_NAME $EPC_VM_CMDS
         EPC_VM_IP_ADDR=`uvt-kvm ip $EPC_VM_NAME`
-        echo "$EPC_VM_NAME has for IP addr = $EPC_VM_IP_ADDR"
-        scp -o StrictHostKeyChecking=no /etc/apt/apt.conf.d/01proxy ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu
-
-        # ltebox specific actions (install and start)
-        LTE_BOX_TO_INSTALL=1
-        if [ $LTEBOX -eq 1 ]
-        then
-            echo "ls -ls /opt/ltebox/tools/start_ltebox" > $EPC_VM_CMDS
-            RESPONSE=`ssh -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR < $EPC_VM_CMDS`
-            NB_EXES=`echo $RESPONSE | grep -c ltebox`
-            if [ $NB_EXES -eq 1 ]; then LTE_BOX_TO_INSTALL=0; fi
-        fi
 
-        if [ $LTEBOX -eq 1 ] && [ $LTE_BOX_TO_INSTALL -eq 1 ]
-        then
-            echo "############################################################"
-            echo "Copying ltebox archives into EPC VM ($EPC_VM_NAME)" 
-            echo "############################################################"
-            scp -o StrictHostKeyChecking=no /opt/ltebox-archives/ltebox_2.2.70_16_04_amd64.deb ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu
-            scp -o StrictHostKeyChecking=no /opt/ltebox-archives/etc-conf.zip ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu
-            scp -o StrictHostKeyChecking=no /opt/ltebox-archives/hss-sim.zip ubuntu@$EPC_VM_IP_ADDR:/home/ubuntu
+        # Starting EPC
+        start_epc $EPC_VM_NAME $EPC_VM_CMDS $EPC_VM_IP_ADDR
 
-            echo "############################################################"
-            echo "Install EPC on EPC VM ($EPC_VM_NAME)"
-            echo "############################################################"
-            echo "sudo cp 01proxy /etc/apt/apt.conf.d/" > $EPC_VM_CMDS
-            echo "touch /home/ubuntu/.hushlogin" >> $EPC_VM_CMDS
-            echo "echo \"sudo apt-get --yes --quiet install zip openjdk-8-jre libconfuse-dev libreadline-dev liblog4c-dev libgcrypt-dev libsctp-dev python2.7 python2.7-dev daemon iperf\"" >> $EPC_VM_CMDS
-            echo "sudo apt-get update > zip-install.txt 2>&1" >> $EPC_VM_CMDS
-            echo "sudo apt-get --yes install zip openjdk-8-jre libconfuse-dev libreadline-dev liblog4c-dev libgcrypt-dev libsctp-dev python2.7 python2.7-dev daemon iperf >> zip-install.txt 2>&1" >> $EPC_VM_CMDS
-
-            # Installing HSS
-            echo "echo \"cd /opt\"" >> $EPC_VM_CMDS
-            echo "cd /opt" >> $EPC_VM_CMDS
-            echo "echo \"sudo unzip -qq /home/ubuntu/hss-sim.zip\"" >> $EPC_VM_CMDS
-            echo "sudo unzip -qq /home/ubuntu/hss-sim.zip" >> $EPC_VM_CMDS
-            echo "echo \"cd /opt/hss_sim0609\"" >> $EPC_VM_CMDS
-            echo "cd /opt/hss_sim0609" >> $EPC_VM_CMDS
-
-            # Installing ltebox
-            echo "echo \"cd /home/ubuntu\"" >> $EPC_VM_CMDS
-            echo "cd /home/ubuntu" >> $EPC_VM_CMDS
-            echo "echo \"sudo dpkg -i ltebox_2.2.70_16_04_amd64.deb \"" >> $EPC_VM_CMDS
-            echo "sudo dpkg -i ltebox_2.2.70_16_04_amd64.deb >> zip-install.txt 2>&1" >> $EPC_VM_CMDS
-
-            echo "echo \"cd /opt/ltebox/etc/\"" >> $EPC_VM_CMDS
-            echo "cd /opt/ltebox/etc/" >> $EPC_VM_CMDS
-            echo "echo \"sudo unzip -qq -o /home/ubuntu/etc-conf.zip\"" >> $EPC_VM_CMDS
-            echo "sudo unzip -qq -o /home/ubuntu/etc-conf.zip" >> $EPC_VM_CMDS
-            echo "sudo sed -i  -e 's#EPC_VM_IP_ADDRESS#$EPC_VM_IP_ADDR#' gw.conf" >> $EPC_VM_CMDS
-            echo "sudo sed -i  -e 's#EPC_VM_IP_ADDRESS#$EPC_VM_IP_ADDR#' mme.conf" >> $EPC_VM_CMDS
-        fi
+        # Retrieve EPC real IP address
+        retrieve_real_epc_ip_addr $EPC_VM_NAME $EPC_VM_CMDS $EPC_VM_IP_ADDR
 
-        # Starting EPC
-        if [ $LTEBOX -eq 1 ]
+        # We may have some adaptation to do
+        if [ -f /opt/ltebox-archives/adapt_ue_sim.txt ]
         then
             echo "############################################################"
-            echo "Start EPC on EPC VM ($EPC_VM_NAME)"
+            echo "Doing some adaptation on UE side"
             echo "############################################################"
-            echo "echo \"cd /opt/hss_sim0609\"" >> $EPC_VM_CMDS
-            echo "cd /opt/hss_sim0609" >> $EPC_VM_CMDS
-            echo "echo \"sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real\"" >> $EPC_VM_CMDS
-            echo "sudo daemon --unsafe --name=simulated_hss --chdir=/opt/hss_sim0609 ./starthss_real" >> $EPC_VM_CMDS
-
-            echo "echo \"cd /opt/ltebox/tools/\"" >> $EPC_VM_CMDS
-            echo "cd /opt/ltebox/tools/" >> $EPC_VM_CMDS
-            echo "echo \"sudo ./start_ltebox\"" >> $EPC_VM_CMDS
-            echo "nohup sudo ./start_ltebox > /home/ubuntu/ltebox.txt" >> $EPC_VM_CMDS
-
-            ssh -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR < $EPC_VM_CMDS
-            rm -f $EPC_VM_CMDS
-
-            # We may have some adaptation to do
-            if [ -f /opt/ltebox-archives/adapt_ue_sim.txt ]
-            then
-                echo "############################################################"
-                echo "Doing some adaptation on UE side"
-                echo "############################################################"
-                ssh -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR < /opt/ltebox-archives/adapt_ue_sim.txt
-            fi
-
-            i="0"
-            echo "ifconfig tun5 | egrep -c \"inet addr\"" > $EPC_VM_CMDS
-            while [ $i -lt 10 ]
-            do
-                sleep 2
-                CONNECTED=`ssh -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR < $EPC_VM_CMDS`
-                if [ $CONNECTED -eq 1 ]
-                then
-                    i="100"
-                else
-                    i=$[$i+1]
-                fi
-            done
-            rm $EPC_VM_CMDS
-            if [ $i -lt 50 ]
-            then
-                echo "Problem w/ starting ltebox EPC"
-                echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
-                exit -1
-            fi
-        fi
-
-        # HERE ADD ANY INSTALL ACTIONS FOR ANOTHER EPC
-
-        # Retrieve EPC real IP address
-        if [ $LTEBOX -eq 1 ]
-        then
-            # in our configuration file, we are using pool 5
-            echo "ifconfig tun5 | egrep \"inet addr\" | sed -e 's#^.*inet addr:##' -e 's#  P-t-P:.*\$##'" > $EPC_VM_CMDS
-            REAL_EPC_IP_ADDR=`ssh -o StrictHostKeyChecking=no ubuntu@$EPC_VM_IP_ADDR < $EPC_VM_CMDS`
-            echo "EPC IP Address     is : $REAL_EPC_IP_ADDR"
-            rm $EPC_VM_CMDS
+            ssh -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR < /opt/ltebox-archives/adapt_ue_sim.txt
         fi
 
         echo "############################################################"
@@ -621,7 +732,7 @@ function run_test_on_vm {
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
             recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
             exit -1
         fi
@@ -680,7 +791,7 @@ function run_test_on_vm {
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
             recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
             exit -1
         fi
@@ -739,7 +850,7 @@ function run_test_on_vm {
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
             recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
             exit -1
         fi
@@ -791,7 +902,7 @@ function run_test_on_vm {
             if [ $j -lt 50 ]
             then
                 echo "ERROR: compiling flexran controller on vm went wrong"
-                terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+                terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
                 echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
                 exit -1
             fi
@@ -801,7 +912,7 @@ function run_test_on_vm {
             if [ $IS_FLEXRAN_VM_ALIVE -eq 0 ]
             then
                 echo "ERROR: Flexran Ctl VM is not alive"
-                terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+                terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
                 echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
                 exit -1
             fi
@@ -835,7 +946,7 @@ function run_test_on_vm {
                 scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
                 scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
                 recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-                terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+                terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
                 stop_flexran_ctrl $FLEXRAN_CTL_VM_CMDS $FLEXRAN_CTL_VM_IP_ADDR
                 echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
                 exit -1
@@ -878,7 +989,7 @@ function run_test_on_vm {
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
             recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
             exit -1
         fi
@@ -929,7 +1040,7 @@ function run_test_on_vm {
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
             scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
             recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
             exit -1
         fi
@@ -980,7 +1091,7 @@ function run_test_on_vm {
 #            scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
 #            scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
 #            recover_core_dump $VM_CMDS $VM_IP_ADDR $ARCHIVES_LOC/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
-#            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+#            terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
 #            echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
 #            exit -1
 #        fi
@@ -1016,10 +1127,7 @@ function run_test_on_vm {
         echo "Terminate EPC"
         echo "############################################################"
 
-        if [ $LTEBOX -eq 1 ]
-        then
-            terminate_ltebox_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
-        fi
+        terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
 
         if [ $KEEP_VM_ALIVE -eq 0 ]
         then
@@ -1051,4 +1159,78 @@ function run_test_on_vm {
             echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
         fi
     fi
+
+    if [[ "$RUN_OPTIONS" == "complex" ]] && [[ $VM_NAME =~ .*-l2-sim.* ]]
+    then
+        PING_STATUS=0
+        IPERF_STATUS=0
+        if [ -d $ARCHIVES_LOC ]
+        then
+            rm -Rf $ARCHIVES_LOC
+        fi
+        mkdir --parents $ARCHIVES_LOC
+
+        # Building UE elsewhere in VM
+        build_ue_on_separate_folder $VM_CMDS $VM_IP_ADDR
+
+        # Creating a VM for EPC and installing SW
+        EPC_VM_NAME=`echo $VM_NAME | sed -e "s#l2-sim#l2-epc#"`
+        EPC_VM_CMDS=${EPC_VM_NAME}_cmds.txt
+        LTEBOX=0
+        install_epc_on_vm $EPC_VM_NAME $EPC_VM_CMDS
+        EPC_VM_IP_ADDR=`uvt-kvm ip $EPC_VM_NAME`
+
+        # Starting EPC
+        start_epc $EPC_VM_NAME $EPC_VM_CMDS $EPC_VM_IP_ADDR
+
+        # Retrieve EPC real IP address
+        retrieve_real_epc_ip_addr $EPC_VM_NAME $EPC_VM_CMDS $EPC_VM_IP_ADDR
+
+        echo "############################################################"
+        echo "Starting the eNB in FDD-5MHz mode"
+        echo "############################################################"
+        CURRENT_ENB_LOG_FILE=fdd_05MHz_enb.log
+        start_l2_sim_enb $VM_CMDS $VM_IP_ADDR $EPC_VM_IP_ADDR $CURRENT_ENB_LOG_FILE 25 rcc.band7.tm1.nfapi.conf
+
+        echo "############################################################"
+        echo "Starting the UEs"
+        echo "############################################################"
+        CURRENT_UE_LOG_FILE=fdd_05MHz_ue.log
+        start_l2_sim_ue $VM_CMDS $VM_IP_ADDR $CURRENT_UE_LOG_FILE ue.nfapi.conf
+
+        sleep 30
+        echo "ping -I oip1 -c 20 $REAL_EPC_IP_ADDR" > $VM_CMDS
+        ssh -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR < $VM_CMDS
+
+        echo "############################################################"
+        echo "Terminate enb/ue simulators"
+        echo "############################################################"
+        terminate_enb_ue_basic_sim $VM_CMDS $VM_IP_ADDR
+        scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_ENB_LOG_FILE $ARCHIVES_LOC
+        scp -o StrictHostKeyChecking=no ubuntu@$VM_IP_ADDR:/home/ubuntu/tmp/cmake_targets/log/$CURRENT_UE_LOG_FILE $ARCHIVES_LOC
+
+        echo "############################################################"
+        echo "Terminate EPC"
+        echo "############################################################"
+
+        terminate_epc $EPC_VM_CMDS $EPC_VM_IP_ADDR
+
+        if [ $KEEP_VM_ALIVE -eq 0 ]
+        then
+            echo "############################################################"
+            echo "Destroying VMs"
+            echo "############################################################"
+            uvt-kvm destroy $VM_NAME
+            ssh-keygen -R $VM_IP_ADDR
+            uvt-kvm destroy $EPC_VM_NAME
+            ssh-keygen -R $EPC_VM_IP_ADDR
+        fi
+
+        if [ $STATUS -eq 0 ]
+        then
+            echo "TEST_OK" > $ARCHIVES_LOC/test_final_status.log
+        else
+            echo "TEST_KO" > $ARCHIVES_LOC/test_final_status.log
+        fi
+    fi
 }
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
old mode 100644
new mode 100755
index 6ec1239a74187c22f84e820816d50a8ce28b111b..8f6396f8298d0084b30ea8b49dec0bd554e36183
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -615,6 +615,7 @@ add_boolean_option(MESSAGE_CHART_GENERATOR_PHY     False "trace some PHY exchang
 add_boolean_option(UE_EXPANSION             False         "enable UE_EXPANSION with max 256 UE")
 add_boolean_option(PHY_TX_THREAD            False         "enable UE_EXPANSION with max 256 UE")
 add_boolean_option(PRE_SCD_THREAD           False         "enable UE_EXPANSION with max 256 UE")
+add_boolean_option(UESIM_EXPANSION          False         "enable UESIM_EXPANSION with max 256 UE")
 
 ########################
 # Include order
diff --git a/cmake_targets/build_oai b/cmake_targets/build_oai
index 01f4b63a8f91c6539aba13157350302cbfa9e7dd..2728cac9b1721298ccad67a1867709cfd71defde 100755
--- a/cmake_targets/build_oai
+++ b/cmake_targets/build_oai
@@ -43,6 +43,7 @@ conf_nvram_path=$OPENAIR_DIR/openair3/NAS/TOOLS/ue_eurecom_test_sfr.conf
 MSC_GEN=0
 XFORMS="True"
 UE_EXPANSION="False"
+UESIM_EXPANSION="False"
 PRINT_STATS="False"
 VCD_TIMING="False"
 DEADLINE_SCHEDULER_FLAG_USER="False"
@@ -218,6 +219,10 @@ function main() {
             UE_EXPANSION="True"
             echo_info "Will compile with UE_EXPANSION"
             shift;;
+       --musim)
+            UESIM_EXPANSION="True"
+            echo_info "Will compile with UESIM_EXPANSION"
+            shift;;
        --UE-conf-nvram)
             conf_nvram_path=$(readlink -f $2)
             shift 2;;
@@ -551,6 +556,7 @@ function main() {
     echo "set ( UE_EXPANSION $UE_EXPANSION )"      >>  $cmake_file
 #    echo "set ( PHY_TX_THREAD $UE_EXPANSION )"     >>  $cmake_file
     echo "set ( PRE_SCD_THREAD $UE_EXPANSION )"    >>  $cmake_file
+    echo "set ( UESIM_EXPANSION $UESIM_EXPANSION )"      >>  $cmake_file
     echo "set ( RRC_ASN1_VERSION \"${REL}\")"      >>  $cmake_file
     echo "set ( ENABLE_VCD_FIFO $VCD_TIMING )"     >>  $cmake_file
     echo "set ( RF_BOARD \"${HW}\")"               >>  $cmake_file
diff --git a/cmake_targets/tools/init_nas_s1 b/cmake_targets/tools/init_nas_s1
index cab4ad047bf4d42d9a4ba1890c9cef9967ec2a00..b78ab34ff9f90d825303e3bb807e0f8e177f3df6 100755
--- a/cmake_targets/tools/init_nas_s1
+++ b/cmake_targets/tools/init_nas_s1
@@ -52,20 +52,20 @@ load_module ../../targets/bin/ue_ip.ko
 
 if [ "$1" = "UE" ]; then
   echo "bring up $LTEIF interface for UE"
-  ifconfig $LTEIF up
+  sudo ifconfig $LTEIF up
 fi
 
-ip route flush cache
+sudo ip route flush cache
 sleep 1
-sysctl -w net.ipv4.conf.all.log_martians=1
+sudo sysctl -w net.ipv4.conf.all.log_martians=1
 echo "Disabling reverse path filtering"
-sysctl -w net.ipv4.conf.all.rp_filter=0
-ip route flush cache
+sudo sysctl -w net.ipv4.conf.all.rp_filter=0
+sudo ip route flush cache
 
 # Check table 200 lte in /etc/iproute2/rt_tables
 fgrep lte /etc/iproute2/rt_tables  > /dev/null 
 if [ $? -ne 0 ]; then
     echo "200 lte " >> /etc/iproute2/rt_tables
 fi
-ip rule add fwmark 1 table lte
-ip route add default dev $LTEIF table lte
+sudo ip rule add fwmark 1 table lte
+sudo ip route add default dev $LTEIF table lte
diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c
old mode 100644
new mode 100755
index a8e5d665f6640f4daa03c2224b5b4cc121f3e000..25463a32890458efb5a99474ba6b7ccd34fa095b
--- a/nfapi/oai_integration/nfapi_vnf.c
+++ b/nfapi/oai_integration/nfapi_vnf.c
@@ -1110,7 +1110,7 @@ int oai_nfapi_dl_config_req(nfapi_dl_config_request_t *dl_config_req)
   nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
 
   dl_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
-
+  dl_config_req->header.message_id = NFAPI_DL_CONFIG_REQUEST;
   int retval = nfapi_vnf_p7_dl_config_req(p7_config, dl_config_req);
 
   dl_config_req->dl_config_request_body.number_pdcch_ofdm_symbols           = 1;
@@ -1129,7 +1129,7 @@ int oai_nfapi_tx_req(nfapi_tx_request_t *tx_req)
   nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
 
   tx_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
-
+  tx_req->header.message_id = NFAPI_TX_REQUEST;
   //LOG_D(PHY, "[VNF] %s() TX_REQ sfn_sf:%d number_of_pdus:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(tx_req->sfn_sf), tx_req->tx_request_body.number_of_pdus);
 
   int retval = nfapi_vnf_p7_tx_req(p7_config, tx_req);
@@ -1147,7 +1147,7 @@ int oai_nfapi_hi_dci0_req(nfapi_hi_dci0_request_t *hi_dci0_req) {
   nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
 
   hi_dci0_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
-
+  hi_dci0_req->header.message_id = NFAPI_HI_DCI0_REQUEST;
   //LOG_D(PHY, "[VNF] %s() HI_DCI0_REQ sfn_sf:%d dci:%d hi:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(hi_dci0_req->sfn_sf), hi_dci0_req->hi_dci0_request_body.number_of_dci, hi_dci0_req->hi_dci0_request_body.number_of_hi);
 
   int retval = nfapi_vnf_p7_hi_dci0_req(p7_config, hi_dci0_req);
@@ -1166,7 +1166,7 @@ int oai_nfapi_ul_config_req(nfapi_ul_config_request_t *ul_config_req) {
   nfapi_vnf_p7_config_t *p7_config = vnf.p7_vnfs[0].config;
 
   ul_config_req->header.phy_id = 1; // DJP HACK TODO FIXME - need to pass this around!!!!
-
+  ul_config_req->header.message_id = NFAPI_UL_CONFIG_REQUEST;
   //LOG_D(PHY, "[VNF] %s() header message_id:%02x\n", __FUNCTION__, ul_config_req->header.message_id);
 
   //LOG_D(PHY, "[VNF] %s() UL_CONFIG sfn_sf:%d PDUs:%d rach_prach_frequency_resources:%d srs_present:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ul_config_req->sfn_sf), ul_config_req->ul_config_request_body.number_of_pdus, ul_config_req->ul_config_request_body.rach_prach_frequency_resources, ul_config_req->ul_config_request_body.srs_present);
diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c
old mode 100644
new mode 100755
index d0a7fa6fd12140dd38ab66c1f866ec8d9abe3d09..0cacf8c66f1599f88cf74443488a4ef65169e63b
--- a/nfapi/open-nFAPI/pnf/src/pnf.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf.c
@@ -1260,7 +1260,7 @@ int pnf_connect(pnf_t* pnf)
 			address = inet_ntoa(addr->sin_addr);
 		}
 
-		NFAPI_TRACE(NFAPI_TRACE_NOTE, "Host address info  %d Family:%s Address:%s\n", i++, family, address);
+		//NFAPI_TRACE(NFAPI_TRACE_NOTE, "Host address info  %d Family:%s Address:%s\n", i++, family, address);
 
 		if (pnf->sctp)
 		{
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
old mode 100644
new mode 100755
index 8d94c23476b1f77f1e7c8a9610d109204a013f7b..81abed81a95b27935df7b19bb21ddb8b5c25f97d
--- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
@@ -379,7 +379,7 @@ static uint32_t get_sf_time(uint32_t now_hr, uint32_t sf_start_hr)
 {
 	if(now_hr < sf_start_hr)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr);
+		//NFAPI_TRACE(NFAPI_TRACE_INFO, "now is earlier than start of subframe now_hr:%u sf_start_hr:%u\n", now_hr, sf_start_hr);
 		return 0;
 	}
 	else
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
old mode 100644
new mode 100755
index cea259c35b354d3179d178da2ce6faf3f9104f70..4b7acabec3637af74e3d95f8d9d805ea3337b118
--- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
@@ -1203,12 +1203,12 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
 
 			if(phy->in_sync == 0)
 			{
-				NFAPI_TRACE(NFAPI_TRACE_NOTE, "***** Adjusting VNF phy_id:%d SFN/SF (%s) from %d to %d (%d) mode:%s zeroCount:%u sync:%s\n", 
+				/*NFAPI_TRACE(NFAPI_TRACE_NOTE, "***** Adjusting VNF phy_id:%d SFN/SF (%s) from %d to %d (%d) mode:%s zeroCount:%u sync:%s\n",
 					ind.header.phy_id, (phy->in_sync ? "via sfn" : "now"),
 					NFAPI_SFNSF2DEC(curr_sfn_sf), NFAPI_SFNSF2DEC(new_sfn_sf), phy->adjustment, 
 					phy->filtered_adjust ? "FILTERED" : "ABSOLUTE",
 					phy->zero_count,
-					phy->in_sync ? "IN_SYNC" : "OUT_OF_SYNC");
+					phy->in_sync ? "IN_SYNC" : "OUT_OF_SYNC");*/
 
 				phy->sfn_sf = new_sfn_sf;
 			}
diff --git a/openair1/PHY/defs_UE.h b/openair1/PHY/defs_UE.h
old mode 100644
new mode 100755
index a303902b0795fce0965fcdb646da227d50ef9a96..5beb6e3ba0e524cfa39d232110b66bfa48ce26da
--- a/openair1/PHY/defs_UE.h
+++ b/openair1/PHY/defs_UE.h
@@ -204,6 +204,12 @@ typedef struct {
 	/// condition variable for timer_thread;
 	pthread_cond_t cond_ticking;
 	//time_stats_t timer_stats;
+
+	// below 3 members is used for waiting each UE threads(multiple UEs test) in L2 FAPI simulator.
+	// This used in UE_phy_stub_single_thread_rxn_txnp4
+	pthread_mutex_t mutex_single_thread;
+	pthread_cond_t  cond_single_thread;
+	int             num_single_thread[NUMBER_OF_UE_MAX];
 } SF_ticking;
 
 typedef struct {
@@ -890,6 +896,7 @@ typedef struct {
 struct rx_tx_thread_data {
   PHY_VARS_UE    *UE;
   UE_rxtx_proc_t *proc;
+  uint16_t       ue_thread_id;
 };
 
 
diff --git a/openair2/COMMON/platform_constants.h b/openair2/COMMON/platform_constants.h
old mode 100644
new mode 100755
index 6a3b7f80050d8d173f63087c73c8bd8186a3db55..2b28b760a813fcfcf0a98e6ebff5d20779d7cddd
--- a/openair2/COMMON/platform_constants.h
+++ b/openair2/COMMON/platform_constants.h
@@ -64,6 +64,16 @@
 #    define MAX_MODULES                NB_MODULES_MAX
 
 #ifndef UE_EXPANSION
+// TODO:L2 FAPI simulator.
+// UESIM_EXPANSION is used to be same value of MAX_MOBILES_PER_ENB
+// in eNB and UE.
+// now , if we use --mu option in UE, compiling error will occur.
+// This problem will be fixed in the future.
+# ifdef UESIM_EXPANSION
+#    define MAX_MOBILES_PER_ENB         256
+#    define MAX_MOBILES_PER_ENB_NB_IoT  256
+#    define MAX_eNB                      2
+# else
 # ifdef LARGE_SCALE
 #    define MAX_MOBILES_PER_ENB         128
 #    define MAX_MOBILES_PER_ENB_NB_IoT  128
@@ -73,6 +83,7 @@
 #    define MAX_MOBILES_PER_ENB_NB_IoT  16
 #    define MAX_eNB                      2
 # endif
+#endif
 #else
 #    define MAX_MOBILES_PER_ENB 256
 #    define MAX_MOBILES_PER_ENB_NB_IoT 256
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_RA.c b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
old mode 100644
new mode 100755
index cc06571a381525bccb13042a95e6ab2f92600b46..fc954c5050aac46a01afb9d173efa8084b466bb8
--- a/openair2/LAYER2/MAC/eNB_scheduler_RA.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_RA.c
@@ -1426,7 +1426,7 @@ schedule_RA(module_id_t module_idP, frame_t frameP, sub_frame_t subframeP)
 
 	    if (ra->state == MSG2)
 		generate_Msg2(module_idP, CC_id, frameP, subframeP, ra);
-	    else if (ra->state == MSG4 && ra->Msg4_frame == frameP && ra->Msg4_subframe == subframeP )
+		else if (ra->state == MSG4 && ra->Msg4_frame == frameP && ra->Msg4_subframe == subframeP )
 		generate_Msg4(module_idP, CC_id, frameP, subframeP, ra);
 	    else if (ra->state == WAITMSG4ACK)
 		check_Msg4_retransmission(module_idP, CC_id, frameP,
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
old mode 100644
new mode 100755
index 61617f1bb9babb9da243585f09ee63b4bcb81bc5..838995bdb402d923a7d0d0d3fcb342bd312a69f7
--- a/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_fairRR.c
@@ -594,6 +594,7 @@ void dlsch_scheduler_pre_processor_fairRR (module_id_t   Mod_id,
   LTE_eNB_UE_stats *eNB_UE_stats2 = NULL;
   UE_sched_ctrl *ue_sched_ctl1, *ue_sched_ctl2;
 #endif
+  memset(rballoc_sub[0],0,(MAX_NUM_CCs)*(N_RBG_MAX)*sizeof(unsigned char));
   memset(min_rb_unit,0,sizeof(min_rb_unit));
 
   for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
diff --git a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
old mode 100644
new mode 100755
index 06e7a7f4b2eb4947a0d090dc5924e28fb8c23202..4052f1fb21e1436e9e27b366481d18c17e7ca747
--- a/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
+++ b/openair2/LAYER2/MAC/eNB_scheduler_primitives.c
@@ -61,6 +61,7 @@ extern uint16_t frame_cnt;
 #include "SCHED/sched_common.h"
 
 extern RAN_CONTEXT_t RC;
+extern uint8_t nfapi_mode;
 
 int choose(int n, int k)
 {
@@ -1286,6 +1287,7 @@ fill_nfapi_ulsch_harq_information(module_id_t                            module_
   */
 #endif
   harq_information->harq_information_rel10.delta_offset_harq = puschConfigDedicated->betaOffset_ACK_Index;
+  harq_information->harq_information_rel10.tl.tag = NFAPI_UL_CONFIG_REQUEST_ULSCH_HARQ_INFORMATION_REL10_TAG;
   AssertFatal(UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated != NULL,
 	      "pucch_ConfigDedicated is null!\n");
   if ((UE_list->UE_template[CC_idP][UE_id].physicalConfigDedicated->pucch_ConfigDedicated->tdd_AckNackFeedbackMode != NULL)
@@ -3629,9 +3631,19 @@ extract_harq(module_id_t mod_idP, int CC_idP, int UE_id,
 	AssertFatal(num_ack_nak == 1,
 		    "num_ack_nak %d > 1 for 1 CC and single-layer transmission frame:%d subframe:%d\n",
 		    num_ack_nak,frameP,subframeP);
-	AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8,
-		    "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",
-		    harq_pid, UE_id, rnti);
+
+	// In case of nFAPI, sometimes timing of eNB and UE become different.
+	// So if nfapi_mode == 2(VNF) , this function don't check assertion to avoid process exit.
+	if (nfapi_mode != 2){
+		AssertFatal(sched_ctl->round[CC_idP][harq_pid] < 8,
+			    "Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",
+			    harq_pid, UE_id, rnti);
+	} else {
+		if(sched_ctl->round[CC_idP][harq_pid] == 8){
+			LOG_E(MAC,"Got ACK/NAK for inactive harq_pid %d for UE %d/%x\n",harq_pid, UE_id, rnti);
+			return;
+		}
+	 }		
 	AssertFatal(pdu[0] == 1 || pdu[0] == 2
 		    || pdu[0] == 4,
 		    "Received ACK/NAK %d which is not 1 or 2 for harq_pid %d from UE %d/%x\n",
diff --git a/openair2/LAYER2/MAC/mac_extern.h b/openair2/LAYER2/MAC/mac_extern.h
old mode 100644
new mode 100755
index ca72882471f11122633b5dc76af58740f73ce757..fd9ffb6a87ebce7c297cb0c8b3fce8b25aee361d
--- a/openair2/LAYER2/MAC/mac_extern.h
+++ b/openair2/LAYER2/MAC/mac_extern.h
@@ -64,7 +64,8 @@ extern eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES
 extern unsigned char NB_INST;
 #endif
 extern unsigned char NB_eNB_INST;
-extern unsigned char NB_UE_INST;
+extern uint16_t NB_UE_INST;
+extern uint16_t NB_THREAD_INST;
 extern unsigned char NB_RN_INST;
 extern unsigned short NODE_ID[1];
 
diff --git a/openair2/LAYER2/MAC/mac_vars.h b/openair2/LAYER2/MAC/mac_vars.h
old mode 100644
new mode 100755
index 4090d954bc538b80152f7381c235b3c7d5c892c7..7126301a7c82292a399914bb455f713059912b39
--- a/openair2/LAYER2/MAC/mac_vars.h
+++ b/openair2/LAYER2/MAC/mac_vars.h
@@ -95,7 +95,7 @@ const uint8_t cqi2fmt2x_agg[MAX_SUPPORTED_BW][CQI_VALUE_RANGE] = {
 
 uint32_t RRC_CONNECTION_FLAG;
 
-UE_MAC_INST *UE_mac_inst;	//[NB_MODULE_MAX];
+UE_MAC_INST *UE_mac_inst = NULL;	//[NB_MODULE_MAX];
 MAC_RLC_XFACE *Mac_rlc_xface;
 
 /// Primary component carrier index of eNB
@@ -109,7 +109,8 @@ eNB_DLSCH_INFO eNB_dlsch_info[NUMBER_OF_eNB_MAX][MAX_NUM_CCs][MAX_MOBILES_PER_EN
 
 #ifdef OPENAIR2
 unsigned char NB_eNB_INST = 0;
-unsigned char NB_UE_INST = 0;
+uint16_t NB_UE_INST = 0;
+uint16_t NB_THREAD_INST = 0;
 unsigned char NB_RN_INST = 0;
 unsigned char NB_INST = 0;
 #endif
diff --git a/openair2/LAYER2/MAC/main_ue.c b/openair2/LAYER2/MAC/main_ue.c
old mode 100644
new mode 100755
index 95f25c7ff51b72648bf1c9d2a4e5d058bce2baa3..1168ed265abde1667da8f9e28f5395c96d093bc4
--- a/openair2/LAYER2/MAC/main_ue.c
+++ b/openair2/LAYER2/MAC/main_ue.c
@@ -43,7 +43,8 @@
 
 
 #include "common/ran_context.h"
-
+extern FILL_UL_INFO_MUTEX_t fill_ul_mutex;
+extern uint8_t nfapi_mode;
 extern void openair_rrc_top_init_ue( int eMBMS_active, char* uecap_xer, uint8_t cba_group_active, uint8_t HO_active);
 
 void dl_phy_sync_success(module_id_t module_idP, frame_t frameP, unsigned char eNB_index, uint8_t first_sync)	//init as MR
@@ -103,6 +104,15 @@ mac_top_init_ue(int eMBMS_active, char *uecap_xer,
 	UE_mac_inst = NULL;
     }
 
+    // mutex below are used for multiple UE's L2 FAPI simulation.
+    if (nfapi_mode == 3){
+      pthread_mutex_init(&fill_ul_mutex.rx_mutex,NULL);
+      pthread_mutex_init(&fill_ul_mutex.crc_mutex,NULL);
+      pthread_mutex_init(&fill_ul_mutex.sr_mutex,NULL);
+      pthread_mutex_init(&fill_ul_mutex.harq_mutex,NULL);
+      pthread_mutex_init(&fill_ul_mutex.cqi_mutex,NULL);
+      pthread_mutex_init(&fill_ul_mutex.rach_mutex,NULL);
+    }
 
     LOG_I(MAC, "[MAIN] calling RRC\n");
     openair_rrc_top_init_ue(eMBMS_active, uecap_xer, cba_group_active,
diff --git a/openair2/LAYER2/MAC/ue_procedures.c b/openair2/LAYER2/MAC/ue_procedures.c
old mode 100644
new mode 100755
index 080e241c86c086745deb5f402b0079893b4bd0ce..19765cff040b230f2190e93ff54f7de81c373bd7
--- a/openair2/LAYER2/MAC/ue_procedures.c
+++ b/openair2/LAYER2/MAC/ue_procedures.c
@@ -69,6 +69,8 @@
 extern UL_IND_t *UL_INFO;
 
 extern uint8_t  nfapi_mode;
+extern int next_ra_frame;
+extern module_id_t next_Mod_id;
 
 /*
  *
@@ -2523,44 +2525,50 @@ ue_scheduler(const module_id_t module_idP,
 				   UE_mac_inst[module_idP].crnti, txFrameP,
 				   txSubframeP, eNB_indexP);
 #if defined(ENABLE_ITTI)
+    if(module_idP == 0){
+      do {
+	  // Checks if a message has been sent to MAC sub-task
+	  itti_poll_msg(TASK_MAC_UE, &msg_p);
 
-    do {
-	// Checks if a message has been sent to MAC sub-task
-	itti_poll_msg(TASK_MAC_UE, &msg_p);
+	    if (msg_p != NULL) {
 
-	if (msg_p != NULL) {
+	      switch (ITTI_MSG_ID(msg_p)) {
+	      case RRC_MAC_CCCH_DATA_REQ:
+		  LOG_I(MAC,
+		        "Received %s from %s: instance %d, frameP %d, eNB_index %d\n",
+		        ITTI_MSG_NAME(msg_p), ITTI_MSG_ORIGIN_NAME(msg_p), ITTI_MSG_INSTANCE(msg_p),
+		        RRC_MAC_CCCH_DATA_REQ(msg_p).frame,
+		        RRC_MAC_CCCH_DATA_REQ(msg_p).enb_index);
 
-	    switch (ITTI_MSG_ID(msg_p)) {
-	    case RRC_MAC_CCCH_DATA_REQ:
-		LOG_I(MAC,
-		      "Received %s from %s: instance %d, frameP %d, eNB_index %d\n",
-		      ITTI_MSG_NAME(msg_p), ITTI_MSG_ORIGIN_NAME(msg_p), ITTI_MSG_INSTANCE(msg_p),
-		      RRC_MAC_CCCH_DATA_REQ(msg_p).frame,
-		      RRC_MAC_CCCH_DATA_REQ(msg_p).enb_index);
+		  // TODO process CCCH data req.
+		  break;
 
-		// TODO process CCCH data req.
-		break;
 
+	      default:
+		  LOG_E(MAC, "Received unexpected message %s\n", ITTI_MSG_NAME(msg_p));
+		  break;
+	      }
 
-	    default:
-		LOG_E(MAC, "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);
 	    }
-
-	    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);
-
+    }
 #endif
 
     //Mac_rlc_xface->frameP=frameP;
     //Rrc_xface->Frame_index=Mac_rlc_xface->frameP;
     //if (subframe%5 == 0)
     //LG#ifdef EXMIMO
-    pdcp_run(&ctxt);
+
+    // data to/from NETLINK is treated in pdcp_run.
+    // one socket is used in multiple UE's L2 FAPI simulator and
+    // only first UE need to do this.
+    if(module_idP == 0){
+      pdcp_run(&ctxt);
+    }
     //#endif
     UE_mac_inst[module_idP].txFrame = txFrameP;
     UE_mac_inst[module_idP].txSubframe = txSubframeP;
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
old mode 100644
new mode 100755
index 47723f9b40f2f41bccfc3c14306fb8d2bbf23dbb..b21a5c24220b565f002cd448ce73dfac3e5971ea
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c
@@ -49,7 +49,7 @@
 #include "platform_constants.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
 #include "msc.h"
-
+#include "targets/COMMON/openairinterface5g_limits.h"
 #if defined(ENABLE_SECURITY)
 # include "UTIL/OSA/osa_defs.h"
 #endif
@@ -64,9 +64,12 @@
 #endif
 
 extern int otg_enabled;
-
+#if defined(ENABLE_USE_MME)
+extern uint8_t nfapi_mode;
+#endif
 #include "common/ran_context.h"
 extern RAN_CONTEXT_t RC;
+hash_table_t  *pdcp_coll_p = NULL;
 
 #ifdef MBMS_MULTICAST_OUT
 # include <sys/types.h>
@@ -798,12 +801,21 @@ pdcp_data_ind(
          * for the UE compiled in noS1 mode, we need 0
          * TODO: be sure of this
          */
-        ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = 1;
+        if (nfapi_mode == 3) {
+#ifdef UESIM_EXPANSION
+          ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = 0;
+#else
+          ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = ctxt_pP->module_id;
+#endif
+        } else {
+          ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = 1;
+        }
 #endif
       } else {
         ((pdcp_data_ind_header_t*) new_sdu_p->data)->rb_id = rb_id + (ctxt_pP->module_id * LTE_maxDRB);
+        ((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = ctxt_pP->module_id;
       }
-
+      // new_sdu_p->data->inst is set again in UE case so move to above.
       //Panos: Commented this out because it cancels the assignment in #if defined(ENABLE_USE_MME) case
       //((pdcp_data_ind_header_t*) new_sdu_p->data)->inst  = ctxt_pP->module_id;
 
@@ -2021,7 +2033,7 @@ void pdcp_layer_init(void)
    * Initialize SDU list
    */
   list_init(&pdcp_sdu_list, NULL);
-  pdcp_coll_p = hashtable_create ((LTE_maxDRB + 2) * 16, NULL, pdcp_free);
+  pdcp_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, pdcp_free);
   AssertFatal(pdcp_coll_p != NULL, "UNRECOVERABLE error, PDCP hashtable_create failed");
 
   for (instance = 0; instance < MAX_MOBILES_PER_ENB; instance++) {
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
old mode 100644
new mode 100755
index bc3bdac828828cce47915f50165b47bae83f41ce..69157b639837bf146ef29b8306f997597314809b
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
@@ -542,7 +542,7 @@ sdu_size_t             pdcp_input_sdu_remaining_size_to_read;
     (((hash_key_t)(sESSION_ID)) << 37) | \
     (((hash_key_t)(0x0000000000000001))  << 63))
 
-hash_table_t  *pdcp_coll_p;
+extern hash_table_t  *pdcp_coll_p;
 
 #endif
 /*@}*/
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
old mode 100644
new mode 100755
index cf89a6dc1b75c09d74f448665fa2bfa6121a2a51..906fbaba5a4f626cb2457c89f9687138f88b36b0
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
@@ -82,10 +82,13 @@ extern struct msghdr nas_msg_tx;
 extern struct msghdr nas_msg_rx;
 
 unsigned char pdcp_read_state_g = 0;
+extern uint8_t nfapi_mode;
+#ifdef UESIM_EXPANSION
+extern uint16_t inst_pdcp_list[NUMBER_OF_UE_MAX];
+#endif
 #endif
 
 extern Packet_OTG_List_t *otg_pdcp_buffer;
-
 #if defined(LINK_ENB_PDCP_TO_GTPV1U)
 #  include "gtpv1u_eNB_task.h"
 #  include "gtpv1u_eNB_defs.h"
@@ -168,7 +171,12 @@ int pdcp_fifo_flush_sdus(const protocol_ctxt_t* const  ctxt_pP)
             ((pdcp_data_ind_header_t*) sdu_p->data)->inst,
             ((pdcp_data_ind_header_t *) sdu_p->data)->data_size);
 #else
-      //((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0;
+      // Raphael: was suppressed by Raymond --> should be suppressed?
+      // value of sdu_p->data->inst is set in pdcp_data_ind
+      // it's necessary to set 1 in case of UE with S1.
+      //if (ctxt_pP->enb_flag){
+      //  ((pdcp_data_ind_header_t *)(sdu_p->data))->inst = 0;
+      //}
 #endif
 
 #if defined(LINK_ENB_PDCP_TO_GTPV1U)
@@ -927,7 +935,15 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const  ctxt_pP)
             rab_id      = pdcp_read_header_g.rb_id % LTE_maxDRB;
             ctxt.rnti          = pdcp_eNB_UE_instance_to_rnti[pdcp_read_header_g.rb_id / LTE_maxDRB];
           } else {
-            ctxt.module_id = 0;
+            if (nfapi_mode == 3) {
+#ifdef UESIM_EXPANSION
+              ctxt.module_id = inst_pdcp_list[pdcp_read_header_g.inst];
+#else
+              ctxt.module_id = pdcp_read_header_g.inst;
+#endif
+            } else {
+              ctxt.module_id = 0;
+            }
             rab_id      = pdcp_read_header_g.rb_id % LTE_maxDRB;
             ctxt.rnti          = pdcp_UE_UE_module_id_to_rnti[ctxt.module_id];
           }
@@ -1072,7 +1088,22 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const  ctxt_pP)
                                           pdcp_read_header_g.rb_id,
                                           rab_id,
                                           pdcp_read_header_g.data_size);
-
+                        if(nfapi_mode == 3){
+                        pdcp_data_req(
+                              &ctxt,
+                              SRB_FLAG_NO,
+                              rab_id,
+                              RLC_MUI_UNDEFINED,
+                              RLC_SDU_CONFIRM_NO,
+                              pdcp_read_header_g.data_size,
+                              (unsigned char *)NLMSG_DATA(nas_nlh_rx),
+                              PDCP_TRANSMISSION_MODE_DATA
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+                              ,NULL
+                              ,NULL
+#endif
+                              );
+                        }else{
                         pdcp_data_req(
                               &ctxt,
                               SRB_FLAG_NO,
@@ -1087,6 +1118,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const  ctxt_pP)
                               ,&pdcp_read_header_g.destinationL2Id
 #endif
                               );
+                        }
                      } else {
                         MSC_LOG_RX_DISCARDED_MESSAGE(
                               (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE,
@@ -1130,7 +1162,22 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const  ctxt_pP)
                                        pdcp_read_header_g.rb_id,
                                        DEFAULT_RAB_ID,
                                        pdcp_read_header_g.data_size);
-
+                     if(nfapi_mode == 3){
+                     pdcp_data_req (
+                           &ctxt,
+                           SRB_FLAG_NO,
+                           DEFAULT_RAB_ID,
+                           RLC_MUI_UNDEFINED,
+                           RLC_SDU_CONFIRM_NO,
+                           pdcp_read_header_g.data_size,
+                           (unsigned char *)NLMSG_DATA(nas_nlh_rx),
+                           PDCP_TRANSMISSION_MODE_DATA
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+                           ,NULL
+                           ,NULL
+#endif
+                               );
+                     }else{
                      pdcp_data_req (
                            &ctxt,
                            SRB_FLAG_NO,
@@ -1145,6 +1192,7 @@ int pdcp_fifo_read_input_sdus (const protocol_ctxt_t* const  ctxt_pP)
                            ,&pdcp_read_header_g.destinationL2Id
 #endif
                            );
+                     }
                   }
                }
 
diff --git a/openair2/LAYER2/RLC/rlc.c b/openair2/LAYER2/RLC/rlc.c
old mode 100644
new mode 100755
index b65f2b02744c8cb344e28f4b2c365be4f1d7d256..428f3c19c714e4000f7e8cc349479fa8440c03f0
--- a/openair2/LAYER2/RLC/rlc.c
+++ b/openair2/LAYER2/RLC/rlc.c
@@ -34,7 +34,7 @@
 #include "common/utils/LOG/log.h"
 #include "UTIL/OCG/OCG_vars.h"
 #include "common/utils/LOG/vcd_signal_dumper.h"
-
+#include "targets/COMMON/openairinterface5g_limits.h"
 #include "assertions.h"
 
 extern boolean_t pdcp_data_ind(
@@ -656,7 +656,7 @@ rlc_module_init (void)
   rlc_rrc_data_ind  = NULL;
   rlc_rrc_data_conf = NULL;
 
-  rlc_coll_p = hashtable_create ((LTE_maxDRB + 2) * 16, NULL, rb_free_rlc_union);
+  rlc_coll_p = hashtable_create ((LTE_maxDRB + 2) * NUMBER_OF_UE_MAX, NULL, rb_free_rlc_union);
   //AssertFatal(rlc_coll_p != NULL, "UNRECOVERABLE error, RLC hashtable_create failed");
   if(rlc_coll_p == NULL) {
     LOG_E(RLC, "UNRECOVERABLE error, RLC hashtable_create failed\n");
diff --git a/openair2/NETWORK_DRIVER/MESH/local.h b/openair2/NETWORK_DRIVER/MESH/local.h
old mode 100644
new mode 100755
index e23188d357006d2bebf16f58c5650cbea5d39266..f3f30f92244148cc0ee8f571306e66e4b9f9cb2f
--- a/openair2/NETWORK_DRIVER/MESH/local.h
+++ b/openair2/NETWORK_DRIVER/MESH/local.h
@@ -64,6 +64,8 @@
 #include "rrc_nas_primitives.h"
 #include "COMMON/platform_types.h"
 
+#define MAKE_VERSION(a,b,c) ((a)*256+(b)*16+(c))
+
 struct rb_entity {
   nasRadioBearerId_t rab_id;
   nasSapId_t sapi;
@@ -160,6 +162,10 @@ typedef struct pdcp_data_req_header_s {
   sdu_size_t          data_size;
   signed int          inst;
   ip_traffic_type_t   traffic_type;
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+  uint32_t sourceL2Id;
+  uint32_t destinationL2Id;
+#endif
 } pdcp_data_req_header_t;
 
 typedef struct pdcp_data_ind_header_s {
@@ -167,6 +173,10 @@ typedef struct pdcp_data_ind_header_s {
   sdu_size_t          data_size;
   signed int          inst;
   ip_traffic_type_t   dummy_traffic_type;
+#if (LTE_RRC_VERSION >= MAKE_VERSION(14, 0, 0))
+  uint32_t sourceL2Id;
+  uint32_t destinationL2Id;
+#endif
 } pdcp_data_ind_header_t;
 
 extern struct net_device *nasdev[NB_INSTANCES_MAX];
diff --git a/openair2/NETWORK_DRIVER/UE_IP/common.c b/openair2/NETWORK_DRIVER/UE_IP/common.c
index 87d8ca01edfe1af115b36b37180739b743650509..1f0545270828579ca49903ea2aa9989d7898224e 100644
--- a/openair2/NETWORK_DRIVER/UE_IP/common.c
+++ b/openair2/NETWORK_DRIVER/UE_IP/common.c
@@ -304,7 +304,16 @@ ue_ip_common_ip2wireless(
     if (dst_addr) {
       printk("[UE_IP_DRV][%s] Dest %d.%d.%d.%d\n",__FUNCTION__, dst_addr[0],dst_addr[1],dst_addr[2],dst_addr[3]);
     }
-
+    // modify inst by IP address for the U-Plane of multiple UEs while L2 fapi simulator start
+#ifdef UESIM_EXPANSION
+    if ((src_addr[3] - 2)> instP) {
+        pdcph.inst = src_addr[3] - 2;
+        printk("[UE_IP_DRV] change INST from %d to %d\n",instP, pdcph.inst);
+        instP = src_addr[3] - 2;
+        priv_p=netdev_priv(ue_ip_dev[instP]);
+    }
+#endif
+    // modify inst by IP address for the U-Plane of multiple UEs while L2 fapi simulator end
     //get Ipv4 address and pass to PCDP header
     printk("[UE_IP_DRV] source Id: 0x%08x\n",pdcph.sourceL2Id );
     printk("[UE_IP_DRV] destinationL2Id Id: 0x%08x\n",pdcph.destinationL2Id );
diff --git a/openair2/NETWORK_DRIVER/UE_IP/device.c b/openair2/NETWORK_DRIVER/UE_IP/device.c
index 47c820fe775330dd0aa9de35052667f31e4b0266..4f295543dca310e933694d9b296a7f2c0b7ce87b 100644
--- a/openair2/NETWORK_DRIVER/UE_IP/device.c
+++ b/openair2/NETWORK_DRIVER/UE_IP/device.c
@@ -394,7 +394,7 @@ int init_module (void)
 
   for (inst=0; inst<UE_IP_NB_INSTANCES_MAX; inst++) {
     printk("[UE_IP_DRV][%s] begin init instance %d\n", __FUNCTION__,inst);
-    sprintf(devicename,"oip%d",inst);
+    sprintf(devicename,"oip%d",inst+1);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
     ue_ip_dev[inst]  = alloc_netdev(sizeof(ue_ip_priv_t),devicename, ue_ip_init);
 #else
diff --git a/openair2/PHY_INTERFACE/IF_Module.h b/openair2/PHY_INTERFACE/IF_Module.h
old mode 100644
new mode 100755
index 26c9a60476b35ece534d996b3cb9bdab2eda9f24..b6ede7d598a05f1e06e802fb0d52b46a96510b50
--- a/openair2/PHY_INTERFACE/IF_Module.h
+++ b/openair2/PHY_INTERFACE/IF_Module.h
@@ -128,6 +128,17 @@ typedef struct IF_Module_s{
   pthread_mutex_t if_mutex;
 }IF_Module_t;
 
+// These mutex is used for multiple UEs L2 FAPI simulator.
+// Each UEs set these value in UL and UL_INFO is shared in all UE's thread.
+typedef struct {
+  pthread_mutex_t rx_mutex;
+  pthread_mutex_t crc_mutex;
+  pthread_mutex_t sr_mutex;
+  pthread_mutex_t harq_mutex;
+  pthread_mutex_t cqi_mutex;
+  pthread_mutex_t rach_mutex;
+}FILL_UL_INFO_MUTEX_t;
+
 /*Initial */
 IF_Module_t *IF_Module_init(int Mod_id);
 void IF_Module_kill(int Mod_id);
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c
old mode 100644
new mode 100755
index 18e2fa4cb742a03820ba376fc0cd78894ce149f0..0c961d9fbbb99a4f6b938c88137f0e7533887f0e
--- a/openair2/PHY_INTERFACE/phy_stub_UE.c
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.c
@@ -25,7 +25,11 @@ extern int oai_nfapi_rach_ind(nfapi_rach_indication_t *rach_ind);
 void configure_nfapi_pnf(char *vnf_ip_addr, int vnf_p5_port, char *pnf_ip_addr, int pnf_p7_port, int vnf_p7_port);
 
 
-
+UL_IND_t *UL_INFO = NULL;
+nfapi_tx_request_pdu_t* tx_request_pdu_list = NULL;
+nfapi_dl_config_request_t* dl_config_req = NULL;
+nfapi_ul_config_request_t* ul_config_req = NULL;
+nfapi_hi_dci0_request_t* hi_dci0_req = NULL;
 
 //extern uint8_t nfapi_pnf;
 //UL_IND_t *UL_INFO;
@@ -47,7 +51,9 @@ void fill_rx_indication_UE_MAC(module_id_t Mod_id,int frame,int subframe, UL_IND
 	  int timing_advance_update;
 
 
-	  pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	  // pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	  // change for mutiple UE's simulation.
+	  pthread_mutex_lock(&fill_ul_mutex.rx_mutex);
 
 
 	  UL_INFO->rx_ind.sfn_sf                    = frame<<4| subframe;
@@ -65,7 +71,11 @@ void fill_rx_indication_UE_MAC(module_id_t Mod_id,int frame,int subframe, UL_IND
 	  //pdu->rx_indication_rel8.length         = eNB->ulsch[UE_id]->harq_processes[harq_pid]->TBS>>3;
 	  pdu->rx_indication_rel8.length         = buflen;
 	  pdu->rx_indication_rel8.offset         = 1;   // DJP - I dont understand - but broken unless 1 ????  0;  // filled in at the end of the UL_INFO formation
-	  pdu->data                              = ulsch_buffer;
+
+	  // ulsch_buffer is necessary to keep its value. 
+	  //pdu->data                              = ulsch_buffer;
+	  pdu->data = malloc(buflen);
+	  memcpy(pdu->data,ulsch_buffer,buflen);
 	  // estimate timing advance for MAC
 	  //sync_pos                               = lte_est_timing_advance_pusch(eNB,UE_id);
 	  timing_advance_update                  = 0;  // Don't know what to put here
@@ -80,7 +90,9 @@ void fill_rx_indication_UE_MAC(module_id_t Mod_id,int frame,int subframe, UL_IND
 
 	  UL_INFO->rx_ind.rx_indication_body.number_of_pdus++;
 	  UL_INFO->rx_ind.sfn_sf = frame<<4 | subframe;
-	  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	  // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	  // change for mutiple UE's simulation.
+	  pthread_mutex_unlock(&fill_ul_mutex.rx_mutex);
 
 
 }
@@ -88,7 +100,9 @@ void fill_rx_indication_UE_MAC(module_id_t Mod_id,int frame,int subframe, UL_IND
 void fill_sr_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint16_t rnti) {
 
 
-  pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_lock(&fill_ul_mutex.sr_mutex);
 
   nfapi_sr_indication_t       *sr_ind = &UL_INFO->sr_ind;
   nfapi_sr_indication_body_t  *sr_ind_body =    &sr_ind->sr_indication_body;
@@ -122,13 +136,17 @@ void fill_sr_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_I
 
   //UL_INFO->rx_ind.rx_indication_body.number_of_pdus++;
   sr_ind_body->number_of_srs++;
-  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_unlock(&fill_ul_mutex.sr_mutex);
 }
 
 
 void fill_crc_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint8_t crc_flag, int index, uint16_t rnti) {
 
-  pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_lock(&fill_ul_mutex.crc_mutex);
 
   // REMEMBER HAVE EXCHANGED THE FOLLOWING TWO LINES HERE!
   nfapi_crc_indication_pdu_t *pdu =   &UL_INFO->crc_ind.crc_indication_body.crc_pdu_list[UL_INFO->crc_ind.crc_indication_body.number_of_crcs];
@@ -151,14 +169,21 @@ void fill_crc_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_
 
   LOG_D(PHY, "%s() rnti:%04x pdus:%d\n", __FUNCTION__, pdu->rx_ue_information.rnti, UL_INFO->crc_ind.crc_indication_body.number_of_crcs);
 
-  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_unlock(&fill_ul_mutex.crc_mutex);
 }
 
 void fill_rach_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL_INFO, uint8_t ra_PreambleIndex, uint16_t ra_RNTI) {
 
 	LOG_D(MAC, "fill_rach_indication_UE_MAC 1 \n");
-	pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
-	UL_INFO = (UL_IND_t*)malloc(sizeof(UL_IND_t));
+
+	// change for mutiple UE's simulation.
+	// pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	pthread_mutex_lock(&fill_ul_mutex.rach_mutex);
+	
+	// memory allocation and free memory of UL_INFO are done in UE_phy_stub_single_thread_rxn_txnp4.
+	// UL_INFO = (UL_IND_t*)malloc(sizeof(UL_IND_t));
 
 	    UL_INFO->rach_ind.rach_indication_body.number_of_preambles                 = 1;
 
@@ -195,16 +220,22 @@ void fill_rach_indication_UE_MAC(int Mod_id,int frame,int subframe, UL_IND_t *UL
 	          // with that branch.
 	          oai_nfapi_rach_ind(&UL_INFO->rach_ind);
 	          free(UL_INFO->rach_ind.rach_indication_body.preamble_list);
-	          free(UL_INFO);
+
+	         // memory allocation and free memory of UL_INFO are done in UE_phy_stub_single_thread_rxn_txnp4.
+	          //free(UL_INFO);
 
 	        //}
-	      pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	      // change for mutiple UE's simulation.
+	      // pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	      pthread_mutex_unlock(&fill_ul_mutex.rach_mutex);
 
 }
 
 void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, uint16_t frame,uint8_t subframe, UL_IND_t *UL_INFO, uint16_t rnti) {
 
-	pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+	// 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];
 
@@ -233,14 +264,18 @@ void fill_ulsch_cqi_indication_UE_MAC(int Mod_id, uint16_t frame,uint8_t subfram
 
 
   UL_INFO->cqi_ind.number_of_cqis++;
-  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
-
+  // 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);
 }
 
 void fill_ulsch_harq_indication_UE_MAC(int Mod_id, int frame,int subframe, UL_IND_t *UL_INFO, nfapi_ul_config_ulsch_harq_information *harq_information, uint16_t rnti)
 {
 
-  pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_lock(&fill_ul_mutex.harq_mutex);
+
   nfapi_harq_indication_pdu_t *pdu =   &UL_INFO->harq_ind.harq_indication_body.harq_pdu_list[UL_INFO->harq_ind.harq_indication_body.number_of_harqs];
   int i;
 
@@ -271,8 +306,9 @@ void fill_ulsch_harq_indication_UE_MAC(int Mod_id, int frame,int subframe, UL_IN
     }
 
   UL_INFO->harq_ind.harq_indication_body.number_of_harqs++;
-  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
-}
+  // change for mutiple UE's simulation.
+  //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_unlock(&fill_ul_mutex.harq_mutex);}
 
 
 void fill_uci_harq_indication_UE_MAC(int Mod_id,
@@ -285,7 +321,10 @@ void fill_uci_harq_indication_UE_MAC(int Mod_id,
 			      uint16_t tdd_multiplexing_mask*/) {
 
 
-  pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  //pthread_mutex_lock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_lock(&fill_ul_mutex.harq_mutex);
+
   nfapi_harq_indication_t *ind       = &UL_INFO->harq_ind;
   nfapi_harq_indication_body_t *body = &ind->harq_indication_body;
   nfapi_harq_indication_pdu_t *pdu =   &body->harq_pdu_list[UL_INFO->harq_ind.harq_indication_body.number_of_harqs];
@@ -311,6 +350,7 @@ void fill_uci_harq_indication_UE_MAC(int Mod_id,
   else if (SNRtimes10 >  635) pdu->ul_cqi_information.ul_cqi=255;
   else                        pdu->ul_cqi_information.ul_cqi=(640+SNRtimes10)/5;
   pdu->ul_cqi_information.channel = 0;
+  if(harq_information->harq_information_rel9_fdd.tl.tag == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL9_FDD_TAG){
       if ((harq_information->harq_information_rel9_fdd.ack_nack_mode == 0) &&
           (harq_information->harq_information_rel9_fdd.harq_size == 1)) {
 
@@ -332,12 +372,31 @@ void fill_uci_harq_indication_UE_MAC(int Mod_id,
       pdu->harq_indication_fdd_rel13.harq_tb_n[1] = 1; // Assuming always an ACK (No NACK or DTX)
 
     }
-    else AssertFatal(1==0,"only format 1a/b for now, received \n");
+  }else if(harq_information->harq_information_rel10_tdd.tl.tag == NFAPI_UL_CONFIG_REQUEST_HARQ_INFORMATION_REL10_TDD_TAG ){
+      if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 0) &&
+          (harq_information->harq_information_rel10_tdd.harq_size == 1)) {
+        pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
+        pdu->harq_indication_tdd_rel13.mode = 0;
+        pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1;
+        pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1;
+
+      }  else if ((harq_information->harq_information_rel10_tdd.ack_nack_mode == 1) &&
+                  (harq_information->harq_information_rel10_tdd.harq_size == 2)) {
+        pdu->harq_indication_tdd_rel13.tl.tag = NFAPI_HARQ_INDICATION_TDD_REL13_TAG;
+        pdu->harq_indication_tdd_rel13.mode = 0;
+        pdu->harq_indication_tdd_rel13.number_of_ack_nack = 1;
+        pdu->harq_indication_tdd_rel13.harq_data[0].bundling.value_0 = 1;
+        pdu->harq_indication_tdd_rel13.harq_data[1].bundling.value_0 = 1;
+
+      }
+  } else AssertFatal(1==0,"only format 1a/b for now, received \n");
 
 
   UL_INFO->harq_ind.harq_indication_body.number_of_harqs++;
   LOG_D(PHY,"Incremented eNB->UL_INFO.harq_ind.number_of_harqs:%d\n", UL_INFO->harq_ind.harq_indication_body.number_of_harqs);
-  pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  // change for mutiple UE's simulation.
+  //pthread_mutex_unlock(&UE_mac_inst[Mod_id].UL_INFO_mutex);
+  pthread_mutex_unlock(&fill_ul_mutex.harq_mutex);
 
 }
 
@@ -622,7 +681,8 @@ int dl_config_req_UE_MAC(nfapi_dl_config_request_t* req, module_id_t Mod_id) //,
 				//if(tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_data!= NULL && tx_request_pdu_list[dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index].segments[0].segment_length >0){
 				*/
 
-				if(dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1){
+				// to avoid unexpected error , add check pdu_index is more than 0.
+				if((dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index >= 0) &&(dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index <= tx_req_num_elems -1)){
 				//if(tx_request_pdu_list + dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index!= NULL){
 
 					LOG_E(MAC, "dl_config_req_UE_MAC 2 Received data: sfn/sf:%d PDU[%d] size:%d, TX_PDU index: %d, tx_req_num_elems: %d \n", NFAPI_SFNSF2DEC(req->sfn_sf), i, dl_config_pdu_list[i].pdu_size, dl_config_pdu_tmp->dlsch_pdu.dlsch_pdu_rel8.pdu_index, tx_req_num_elems);
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.h b/openair2/PHY_INTERFACE/phy_stub_UE.h
old mode 100644
new mode 100755
index 9060951b26068a974ed92c7b21e25772054ac96b..21fb8518fad866e88c1d78f21aecd232657916c4
--- a/openair2/PHY_INTERFACE/phy_stub_UE.h
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.h
@@ -17,19 +17,23 @@
 //#include "openair1/PHY/defs.h"
 //#include "openair1/PHY/LTE_TRANSPORT/defs.h"
 
-UL_IND_t *UL_INFO;
-
-nfapi_tx_request_pdu_t* tx_request_pdu_list;
+// this mutex is used to set multiple UE's UL value in L2 FAPI simulator.
+FILL_UL_INFO_MUTEX_t fill_ul_mutex;
+//below 2 difinitions move to phy_stub_UE.c to add initialization when difinition.
+extern UL_IND_t *UL_INFO;
+extern nfapi_tx_request_pdu_t* tx_request_pdu_list;
 // New
 /// Pointers to config_request types. Used from nfapi callback functions.
-nfapi_dl_config_request_t* dl_config_req;
-nfapi_ul_config_request_t* ul_config_req;
-nfapi_hi_dci0_request_t* hi_dci0_req;
+//below 3 difinitions move to phy_stub_UE.c to add initialization when difinition.
+extern nfapi_dl_config_request_t* dl_config_req;
+extern nfapi_ul_config_request_t* ul_config_req;
+extern nfapi_hi_dci0_request_t* hi_dci0_req;
 
 int	tx_req_num_elems;
 
-int next_ra_frame;
-module_id_t next_Mod_id;
+//below 2 difinitions move to lte-ue.c to add initialization when difinition.
+//int next_ra_frame;
+//module_id_t next_Mod_id;
 eth_params_t         stub_eth_params;
 
 
diff --git a/openair2/RRC/LTE/rrc_extern.h b/openair2/RRC/LTE/rrc_extern.h
old mode 100644
new mode 100755
index 624a7efb75aaca1a7ec5ffa7de6c79e565c3a2b8..e3b9ecb00be2dd745c31ad0d1beb468c99c55fad
--- a/openair2/RRC/LTE/rrc_extern.h
+++ b/openair2/RRC/LTE/rrc_extern.h
@@ -51,7 +51,7 @@ extern LTE_LogicalChannelConfig_t SRB2_logicalChannelConfig_defaultValue;
 extern unsigned char NB_INST;
 #endif
 extern unsigned char NB_eNB_INST;
-extern unsigned char NB_UE_INST;
+extern uint16_t NB_UE_INST;
 extern unsigned short NODE_ID[1];
 #endif
 
diff --git a/openair2/RRC/LTE/rrc_vars.h b/openair2/RRC/LTE/rrc_vars.h
old mode 100644
new mode 100755
index e328ce13599597bbfdd2774822c9078d0a47f205..512d421168d80c2808726eff0c8129c88fbfaaae
--- a/openair2/RRC/LTE/rrc_vars.h
+++ b/openair2/RRC/LTE/rrc_vars.h
@@ -38,7 +38,7 @@
 
 UE_PF_PO_t UE_PF_PO[NFAPI_CC_MAX][MAX_MOBILES_PER_ENB];
 pthread_mutex_t ue_pf_po_mutex;
-UE_RRC_INST *UE_rrc_inst;
+UE_RRC_INST *UE_rrc_inst = NULL;
 #include "LAYER2/MAC/mac_extern.h"
 #define MAX_U32 0xFFFFFFFF
 
diff --git a/openair3/NAS/UE/ESM/esm_ebr_context.c b/openair3/NAS/UE/ESM/esm_ebr_context.c
old mode 100644
new mode 100755
index e2a327f4886c1fd4cf84c78d7901a1bb5bfcc307..7404cd8b8a83a751e21fad46eca07033e41afcac
--- a/openair3/NAS/UE/ESM/esm_ebr_context.c
+++ b/openair3/NAS/UE/ESM/esm_ebr_context.c
@@ -57,7 +57,13 @@ Description Defines functions used to handle EPS bearer contexts.
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
-
+#ifdef PDCP_USE_NETLINK
+#ifdef UESIM_EXPANSION
+  #include "openairinterface5g_limits.h"
+  extern uint16_t inst_pdcp_list[NUMBER_OF_UE_MAX];
+#endif
+#endif
+extern uint8_t  nfapi_mode;
 
 /****************************************************************************/
 /****************  E X T E R N A L    D E F I N I T I O N S  ****************/
@@ -208,7 +214,7 @@ int esm_ebr_context_create(
            char           broadcast[INET_ADDRSTRLEN];
            struct in_addr in_addr;
            char           command_line[500];
-           int            res;
+           int            res = -1;
 
            switch (pdn->type) {
            case NET_PDN_TYPE_IPV4V6:
@@ -272,7 +278,38 @@ int esm_ebr_context_create(
                strcpy(broadcast, ipv4_addr);
              }
 
-             res = sprintf(command_line,
+             if(nfapi_mode ==3){
+                // this is for L2 FAPI simulator.
+                // change for multiple UE's like 256UEs.
+                // if it's made too many tables , OS may crush so we use one table.
+#ifdef PDCP_USE_NETLINK
+#ifdef UESIM_EXPANSION
+                uint16_t inst_nic = (pdn->ip_addr[3] & 0x000000FF) - 2;
+                res = sprintf(command_line,
+                           "ifconfig oip%d %s netmask %s broadcast %s up && "
+                           "ip rule add from %s/24 table %d && "
+                           "ip rule add to %s/24 table %d && "
+                           "ip route add default dev oip%d table %d",
+                           inst_nic + 1, ipv4_addr, netmask, broadcast,
+                           ipv4_addr, 201,
+                           ipv4_addr, 201,
+                           inst_nic + 1, 201);
+
+               inst_pdcp_list[inst_nic] = ueid;
+#else
+               res = sprintf(command_line,
+                          "ifconfig oip%d %s netmask %s broadcast %s up && "
+                          "ip rule add from %s/32 table %d && "
+                          "ip rule add to %s/32 table %d && "
+                          "ip route add default dev oip%d table %d",
+                          ueid + 1, ipv4_addr, netmask, broadcast,
+                          ipv4_addr, ueid + 201,
+                          ipv4_addr, ueid + 201,
+                          ueid + 1, ueid + 201);
+#endif
+#endif
+             } else {
+               res = sprintf(command_line,
                            "ifconfig oip%d %s netmask %s broadcast %s up && "
                            "ip rule add from %s/32 table %d && "
                            "ip rule add to %s/32 table %d && "
@@ -281,6 +318,7 @@ int esm_ebr_context_create(
                            ipv4_addr, ueid + 201,
                            ipv4_addr, ueid + 201,
                            ueid + 1, ueid + 201);
+             }
              if ( res<0 ) {
                 LOG_TRACE(WARNING, "ESM-PROC  - Failed to system command string");
              }
diff --git a/openair3/NAS/UE/nas_ue_task.c b/openair3/NAS/UE/nas_ue_task.c
old mode 100644
new mode 100755
index 529ac5e602b79a342932af73d3ec45a12cae06ab..6df66666389ce1c3f7f36163f51cccf0205b5249
--- a/openair3/NAS/UE/nas_ue_task.c
+++ b/openair3/NAS/UE/nas_ue_task.c
@@ -40,7 +40,7 @@
 
 // FIXME review these externs
 extern unsigned char NB_eNB_INST;
-extern unsigned char NB_UE_INST;
+extern uint16_t NB_UE_INST;
 
 char *make_port_str_from_ueid(const char *base_port_str, int ueid);
 
diff --git a/targets/COMMON/openairinterface5g_limits.h b/targets/COMMON/openairinterface5g_limits.h
old mode 100644
new mode 100755
index 1c27f655851f12b0d58eab503ca6e4e52346fc4a..644952ca794a041a046d86efdf054ccaff1b7c39
--- a/targets/COMMON/openairinterface5g_limits.h
+++ b/targets/COMMON/openairinterface5g_limits.h
@@ -5,8 +5,18 @@
 #        define NUMBER_OF_eNB_MAX 1
 #        define NUMBER_OF_RU_MAX 2
 #        ifndef UE_EXPANSION
+// TODO:L2 FAPI simulator.
+// UESIM_EXPANSION is used to be same value of NUMBER_OF_UE_MAX
+// in eNB and UE.
+// now , if we use --mu option in UE, compiling error will occur.
+// This problem will be fixed in the future.
+#            ifndef UESIM_EXPANSION
 #                define NUMBER_OF_UE_MAX 16
 #                define NUMBER_OF_CONNECTED_eNB_MAX 3
+#            else
+#                define NUMBER_OF_UE_MAX 256
+#                define NUMBER_OF_CONNECTED_eNB_MAX 1
+#            endif
 #        else
 #                define NUMBER_OF_UE_MAX 256
 #                define NUMBER_OF_CONNECTED_eNB_MAX 1
@@ -15,8 +25,18 @@
 #        define NUMBER_OF_eNB_MAX 7
 #        define NUMBER_OF_RU_MAX 32
 #        ifndef UE_EXPANSION
-#                define NUMBER_OF_UE_MAX 20
+/* if the value of MAX_MOBILES_PER_ENB and NUMBER_OF_UE_MAX is different,
+eNB process will exit because unexpected access happens.
+Now some parts are using NUMBER_OF_UE_MAX
+and the other are using MAX_MOBILES_PER_ENB in for-loop.
+*/
+#            ifndef UESIM_EXPANSION
+#                define NUMBER_OF_UE_MAX 16
 #                define NUMBER_OF_CONNECTED_eNB_MAX 3
+#            else
+#                define NUMBER_OF_UE_MAX 256
+#                define NUMBER_OF_CONNECTED_eNB_MAX 1
+#            endif
 #        else
 #                define NUMBER_OF_UE_MAX 256
 #                define NUMBER_OF_CONNECTED_eNB_MAX 1
diff --git a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf
index ced031163d242aef51b065bf8a73cdc5142547cc..472d84c7e2319d84d3436081f91839cd44b72160 100644
--- a/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf
+++ b/targets/PROJECTS/GENERIC-LTE-EPC/CONF/rcc.band7.tm1.50PRB.nfapi.conf
@@ -172,7 +172,7 @@ eNBs =
 
 
     ////////// MME parameters:
-    mme_ip_address      = ( { ipv4       = "127.0.0.3";
+    mme_ip_address      = ( { ipv4       = "192.168.12.26";
                               ipv6       = "192:168:30::17";
                               active     = "yes";
                               preference = "ipv4";
@@ -181,14 +181,24 @@ eNBs =
 
     NETWORK_INTERFACES :
     {
-        ENB_INTERFACE_NAME_FOR_S1_MME            = "lo";
-        ENB_IPV4_ADDRESS_FOR_S1_MME              = "127.0.0.2/24";
-        ENB_INTERFACE_NAME_FOR_S1U               = "lo";
-        ENB_IPV4_ADDRESS_FOR_S1U                 = "127.0.0.5/24";
+        #ENB_INTERFACE_NAME_FOR_S1_MME            = "lo";
+        #ENB_IPV4_ADDRESS_FOR_S1_MME              = "127.0.0.2/24";
+        #ENB_INTERFACE_NAME_FOR_S1U               = "lo";
+        #ENB_IPV4_ADDRESS_FOR_S1U                 = "127.0.0.5/24";
+        #ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
+
+        #ENB_IPV4_ADDRESS_FOR_X2C                 = "127.0.0.2/24";
+        #ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+        
+        ENB_INTERFACE_NAME_FOR_S1_MME            = "enp0s31f6";
+        ENB_IPV4_ADDRESS_FOR_S1_MME              = "192.168.12.188/24";
+        ENB_INTERFACE_NAME_FOR_S1U               = "enp0s31f6";
+        ENB_IPV4_ADDRESS_FOR_S1U                 = "192.168.12.188/24";
         ENB_PORT_FOR_S1U                         = 2152; # Spec 2152
-
-        ENB_IPV4_ADDRESS_FOR_X2C                 = "127.0.0.2/24";
+        
+        ENB_IPV4_ADDRESS_FOR_X2C                 = "192.168.12.188/24";
         ENB_PORT_FOR_X2C                         = 36422; # Spec 36422
+        
     };
   }
 );
@@ -196,7 +206,7 @@ eNBs =
 MACRLCs = (
 	{
 	num_cc = 1;
-      	local_s_if_name  = "lo";			  
+      	local_s_if_name  = "lo:";			  
       	remote_s_address = "127.0.0.1";
     	local_s_address  = "127.0.0.2"; 
     	local_s_portc    = 50001;	
diff --git a/targets/RT/USER/lte-enb.c b/targets/RT/USER/lte-enb.c
old mode 100644
new mode 100755
index cc25ca088535774423a57d2f57bbe069f52bf740..9db1684bd27b7c351d7459d0319d6ab649f3608d
--- a/targets/RT/USER/lte-enb.c
+++ b/targets/RT/USER/lte-enb.c
@@ -164,6 +164,10 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name
 
   // *******************************************************************
 
+#if defined(PRE_SCD_THREAD)
+    RU_t *ru = RC.ru[0];
+#endif
+
   if (nfapi_mode == 1) {
     // I am a PNF and I need to let nFAPI know that we have a (sub)frame tick
     uint16_t frame = proc->frame_rx;
@@ -218,6 +222,40 @@ static inline int rxtx(PHY_VARS_eNB *eNB,L1_rxtx_proc_t *proc, char *thread_name
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_ENB_DLSCH_ULSCH_SCHEDULER, 1 );
 
+#if defined(PRE_SCD_THREAD)
+    if (nfapi_mode == 2){
+      new_dlsch_ue_select_tbl_in_use = dlsch_ue_select_tbl_in_use;
+      dlsch_ue_select_tbl_in_use = !dlsch_ue_select_tbl_in_use;
+
+// L2-emulator can work only one eNB.
+//      memcpy(&pre_scd_eNB_UE_stats,&RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX);
+//      memcpy(&pre_scd_activeUE, &RC.mac[ru->eNB_list[0]->Mod_id]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX);
+      memcpy(&pre_scd_eNB_UE_stats,&RC.mac[0]->UE_list.eNB_UE_stats, sizeof(eNB_UE_STATS)*MAX_NUM_CCs*NUMBER_OF_UE_MAX);
+      memcpy(&pre_scd_activeUE, &RC.mac[0]->UE_list.active, sizeof(boolean_t)*NUMBER_OF_UE_MAX);
+
+      if (pthread_mutex_lock(&ru->proc.mutex_pre_scd)!= 0) {
+          LOG_E( PHY, "[eNB] error locking proc mutex for eNB pre scd\n");
+          exit_fun("error locking mutex_time");
+      }
+
+      ru->proc.instance_pre_scd++;
+
+      if (ru->proc.instance_pre_scd == 0) {
+          if (pthread_cond_signal(&ru->proc.cond_pre_scd) != 0) {
+              LOG_E( PHY, "[eNB] ERROR pthread_cond_signal for eNB pre scd\n" );
+              exit_fun( "ERROR pthread_cond_signal cond_pre_scd" );
+          }
+      }else{
+          LOG_E( PHY, "[eNB] frame %d subframe %d rxtx busy instance_pre_scd %d\n",
+                 proc->frame_rx,proc->subframe_rx,ru->proc.instance_pre_scd );
+      }
+
+      if (pthread_mutex_unlock(&ru->proc.mutex_pre_scd)!= 0) {
+          LOG_E( PHY, "[eNB] error unlocking mutex_pre_scd mutex for eNB pre scd\n");
+          exit_fun("error unlocking mutex_pre_scd");
+      }
+    }
+#endif
 
   pthread_mutex_lock(&eNB->UL_INFO_mutex);
   eNB->UL_INFO.frame     = proc->frame_rx;
@@ -906,6 +944,12 @@ void init_eNB_proc(int inst) {
     if ((get_thread_parallel_conf() == PARALLEL_RU_L1_SPLIT || get_thread_parallel_conf() == PARALLEL_RU_L1_TRX_SPLIT) && nfapi_mode!=2) {
       pthread_create( &L1_proc->pthread, attr0, L1_thread, proc );
       pthread_create( &L1_proc_tx->pthread, attr1, L1_thread_tx, proc);
+    } else if (nfapi_mode == 2) { // this is neccesary in VNF or L2 FAPI simulator.
+      // Original Code from Fujitsu w/ old structure/field name
+      //pthread_create( &proc_rxtx[0].pthread_rxtx, attr0, eNB_thread_rxtx, &proc_rxtx[0] );
+      //pthread_create( &proc_rxtx[1].pthread_rxtx, attr1, eNB_thread_rxtx, &proc_rxtx[1] );
+      pthread_create( &L1_proc->pthread, attr0, L1_thread, L1_proc );
+      pthread_create( &L1_proc_tx->pthread, attr1, L1_thread, L1_proc_tx);
     }
 
     pthread_create( &proc->pthread_prach, attr_prach, eNB_thread_prach, eNB );
diff --git a/targets/RT/USER/lte-ru.c b/targets/RT/USER/lte-ru.c
old mode 100644
new mode 100755
index 7df0a8c623524d08eb62da5a1201e8ee8c251140..ddc7fdf94bc19e176ba66034ea51dcc8295a0fd1
--- a/targets/RT/USER/lte-ru.c
+++ b/targets/RT/USER/lte-ru.c
@@ -118,7 +118,11 @@ static int DEFENBS[] = {0};
 #include "pdcp.h"
 
 extern volatile int                    oai_exit;
-
+extern int emulate_rf;
+extern int numerology;
+extern clock_source_t clock_source;
+extern uint8_t dlsch_ue_select_tbl_in_use;
+extern uint8_t nfapi_mode;
 
 extern PARALLEL_CONF_t get_thread_parallel_conf(void);
 extern WORKER_CONF_t   get_thread_worker_conf(void);
@@ -141,6 +145,11 @@ int connect_rau(RU_t *ru);
 
 extern uint16_t sf_ahead;
 
+#if defined(PRE_SCD_THREAD)
+void init_ru_vnf(void);
+#endif
+
+
 /*************************************************************/
 /* Functions to attach and configure RRU                     */
 
@@ -1942,7 +1951,12 @@ void* pre_scd_thread( void* param ){
     int                     CC_id;
     int                     Mod_id;
     RU_t               *ru      = (RU_t*)param;
-    Mod_id = ru->eNB_list[0]->Mod_id;
+
+    // L2-emulator can work only one eNB
+    if( nfapi_mode == 2)
+       Mod_id = 0;
+    else 
+       Mod_id = ru->eNB_list[0]->Mod_id;
 
     frame = 0;
     subframe = 4;
@@ -2820,6 +2834,114 @@ void stop_RU(int nb_ru)
   }
 }
 
+//Some of the member of ru pointer is used in pre_scd.
+//This funtion is for initializing ru pointer for L2 FAPI simulator.
+#if defined(PRE_SCD_THREAD)
+void init_ru_vnf(void) {
+  
+  int ru_id;
+  RU_t *ru;
+  RU_proc_t *proc;
+//  PHY_VARS_eNB *eNB0= (PHY_VARS_eNB *)NULL;
+  int i;
+  int CC_id;
+
+
+  dlsch_ue_select_tbl_in_use = 1;
+
+
+  // create status mask
+  RC.ru_mask = 0;
+  pthread_mutex_init(&RC.ru_mutex,NULL);
+  pthread_cond_init(&RC.ru_cond,NULL);
+
+  // read in configuration file)
+  printf("configuring RU from file\n");
+  RCconfig_RU();
+  LOG_I(PHY,"number of L1 instances %d, number of RU %d, number of CPU cores %d\n",RC.nb_L1_inst,RC.nb_RU,get_nprocs());
+
+  if (RC.nb_CC != 0)
+    for (i=0;i<RC.nb_L1_inst;i++) 
+      for (CC_id=0;CC_id<RC.nb_CC[i];CC_id++) RC.eNB[i][CC_id]->num_RU=0;
+
+  LOG_D(PHY,"Process RUs RC.nb_RU:%d\n",RC.nb_RU);
+  for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
+    LOG_D(PHY,"Process RC.ru[%d]\n",ru_id);
+    ru               = RC.ru[ru_id];
+//    ru->rf_config_file = rf_config_file;
+    ru->idx          = ru_id;              
+    ru->ts_offset    = 0;
+    // use eNB_list[0] as a reference for RU frame parameters
+    // NOTE: multiple CC_id are not handled here yet!
+
+    if (ru->num_eNB > 0) {
+//      LOG_D(PHY, "%s() RC.ru[%d].num_eNB:%d ru->eNB_list[0]:%p RC.eNB[0][0]:%p rf_config_file:%s\n", __FUNCTION__, ru_id, ru->num_eNB, ru->eNB_list[0], RC.eNB[0][0], ru->rf_config_file);
+
+      if (ru->eNB_list[0] == 0)
+      {
+        LOG_E(PHY,"%s() DJP - ru->eNB_list ru->num_eNB are not initialized - so do it manually\n", __FUNCTION__);
+        ru->eNB_list[0] = RC.eNB[0][0];
+        ru->num_eNB=1;
+      //
+      // DJP - feptx_prec() / feptx_ofdm() parses the eNB_list (based on num_eNB) and copies the txdata_F to txdata in RU
+      //
+      }
+      else
+      {
+        LOG_E(PHY,"DJP - delete code above this %s:%d\n", __FILE__, __LINE__);
+      }
+    }
+
+// frame_parms is not used in L2 FAPI simulator
+/*
+    eNB0             = ru->eNB_list[0];
+    LOG_D(PHY, "RU FUnction:%d ru->if_south:%d\n", ru->function, ru->if_south);
+    LOG_D(PHY, "eNB0:%p\n", eNB0);
+    if (eNB0)
+    {
+      if ((ru->function != NGFI_RRU_IF5) && (ru->function != NGFI_RRU_IF4p5))
+        AssertFatal(eNB0!=NULL,"eNB0 is null!\n");
+
+      if (eNB0) {
+        LOG_I(PHY,"Copying frame parms from eNB %d to ru %d\n",eNB0->Mod_id,ru->idx);
+        memcpy((void*)&ru->frame_parms,(void*)&eNB0->frame_parms,sizeof(LTE_DL_FRAME_PARMS));
+
+        // attach all RU to all eNBs in its list/
+        LOG_D(PHY,"ru->num_eNB:%d eNB0->num_RU:%d\n", ru->num_eNB, eNB0->num_RU);
+        for (i=0;i<ru->num_eNB;i++) {
+          eNB0 = ru->eNB_list[i];
+          eNB0->RU_list[eNB0->num_RU++] = ru;
+        }
+      }
+    }
+*/
+    LOG_I(PHY,"Initializing RRU descriptor %d : (%s,%s,%d)\n",ru_id,ru_if_types[ru->if_south],eNB_timing[ru->if_timing],ru->function);
+
+//    set_function_spec_param(ru);
+    LOG_I(PHY,"Starting ru_thread %d\n",ru_id);
+
+//    init_RU_proc(ru);
+  
+    proc = &ru->proc;
+    memset((void*)proc,0,sizeof(RU_proc_t));
+
+    proc->instance_pre_scd = -1;
+    pthread_mutex_init( &proc->mutex_pre_scd, NULL);
+    pthread_cond_init( &proc->cond_pre_scd, NULL);
+    pthread_create(&proc->pthread_pre_scd, NULL, pre_scd_thread, (void*)ru);
+    pthread_setname_np(proc->pthread_pre_scd, "pre_scd_thread");
+
+  } // for ru_id
+  
+
+
+  //  sleep(1);
+  LOG_D(HW,"[lte-softmodem.c] RU threads created\n");
+  
+
+}
+#endif
+
 
 /* --------------------------------------------------------*/
 /* from here function to use configuration module          */
diff --git a/targets/RT/USER/lte-softmodem.c b/targets/RT/USER/lte-softmodem.c
old mode 100644
new mode 100755
index 2ded10d3b05cf5f4cade0dce818c4c484a1d1f1a..872340e28caca653b7497260efdf498ac4efdc1d
--- a/targets/RT/USER/lte-softmodem.c
+++ b/targets/RT/USER/lte-softmodem.c
@@ -879,8 +879,14 @@ int main( int argc, char **argv ) {
 
   printf("NFAPI MODE:%s\n", nfapi_mode_str);
 
-  if (nfapi_mode==2) // VNF
+
+if (nfapi_mode==2) {// VNF
+#if defined(PRE_SCD_THREAD)
+    init_ru_vnf();  // ru pointer is necessary for pre_scd.
+#endif
     wait_nfapi_init("main?");
+  }
+
 
   printf("START MAIN THREADS\n");
   // start the main threads
@@ -896,13 +902,16 @@ int main( int argc, char **argv ) {
 
   printf("wait_eNBs()\n");
   wait_eNBs();
+
   printf("About to Init RU threads RC.nb_RU:%d\n", RC.nb_RU);
 
-  if (RC.nb_RU >0) {
+  // RU thread and some L1 procedure aren't necessary in VNF or L2 FAPI simulator.
+  // but RU thread deals with pre_scd and this is necessary in VNF and simulator.
+  // some initialization is necessary and init_ru_vnf do this.
+  if (RC.nb_RU >0 && nfapi_mode != 2) {
     printf("Initializing RU threads\n");
     init_RU(get_softmodem_params()->rf_config_file);
-
-    for (ru_id=0; ru_id<RC.nb_RU; ru_id++) {
+    for (ru_id=0;ru_id<RC.nb_RU;ru_id++) {
       RC.ru[ru_id]->rf_map.card=0;
       RC.ru[ru_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset);
     }
diff --git a/targets/RT/USER/lte-softmodem.h b/targets/RT/USER/lte-softmodem.h
old mode 100644
new mode 100755
index 6d182b16cfd9e3513dc8301d49ae8ceaeb7e0174..81f84e133b6fdf2cbf1a5722464be8fc1f6f92c4
--- a/targets/RT/USER/lte-softmodem.h
+++ b/targets/RT/USER/lte-softmodem.h
@@ -150,6 +150,7 @@
 {"emul-iface",                 CONFIG_HLP_EMULIFACE,   0,               strptr:&emul_iface,		    defstrval:"lo",       TYPE_STRING,   100}, \
 {"L2-emul",                    NULL,  		       0,               u8ptr:&nfapi_mode,		    defuintval:3,         TYPE_UINT8,	 0},   \
 {"num-ues",     	       NULL,                   0,               u8ptr:&(NB_UE_INST),		    defuintval:1,         TYPE_UINT8,	 0},   \
+{"nums_ue_thread",             NULL,                   0,               u16ptr:&(NB_THREAD_INST),           defuintval:1,         TYPE_UINT16,   0},   \
 {"r"  ,                        CONFIG_HLP_PRB,         0,               u8ptr:&(frame_parms[0]->N_RB_DL),   defintval:25,         TYPE_UINT8,    0},   \
 {"dlsch-demod-shift",          CONFIG_HLP_DLSHIFT,     0,		iptr:(int32_t *)&dlsch_demod_shift, defintval:0,          TYPE_INT,	 0},   \
 {"usrp-args",                  CONFIG_HLP_USRP_ARGS,   0,               strptr:(char **)&usrp_args,         defstrval:"type=b200",TYPE_STRING,   0},   \
@@ -158,7 +159,7 @@
 {"clock",                      CONFIG_HLP_CLK,         0,               uptr:&clock_source,                 defintval:0,          TYPE_UINT,     0},   \
 {"s" ,                         CONFIG_HLP_SNR,         0,               iptr:&snr_dB,                       defintval:25,         TYPE_INT,      0},   \
 {"T" ,                         CONFIG_HLP_TDD,         PARAMFLAG_BOOL,  iptr:&tddflag,                      defintval:0,          TYPE_INT,      0},   \
-{"A",                          CONFIG_HLP_TADV,        0,               iptr:&(timingadv),                    defintval:0,          TYPE_INT,      0}    \
+{"A",                          CONFIG_HLP_TADV,        0,               iptr:&(timingadv),                  defintval:0,          TYPE_INT,      0}    \
 }
 
 /*-------------------------------------------------------------------------------------------------------------------------------------------------------*/
@@ -306,6 +307,7 @@ extern void kill_eNB_proc(int inst);
 // In lte-ru.c
 extern void init_RU(char*);
 extern void stop_ru(RU_t *ru);
+extern void init_ru_vnf(void);
 extern void init_RU_proc(RU_t *ru);
 extern void stop_RU(int nb_ru);
 extern void kill_RU_proc(RU_t *ru);
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
old mode 100644
new mode 100755
index 784c14fa4d53a8b58324f656e35bdf37f1271690..31857026ee41cd44f2ce60a4fbc4564461086de8
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -94,7 +94,7 @@ extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind);
 extern int multicast_link_write_sock(int groupP, char *dataP, uint32_t sizeP);
 
 extern int simL1flag;
-
+extern uint16_t sf_ahead;
 //extern int tx_req_UE_MAC1();
 
 void ue_stub_rx_handler(unsigned int, char *);
@@ -102,9 +102,11 @@ void ue_stub_rx_handler(unsigned int, char *);
 int32_t **rxdata;
 int32_t **txdata;
 
-int timer_subframe;
-int timer_frame;
-SF_ticking *phy_stub_ticking;
+int timer_subframe = 0;
+int timer_frame = 0;
+SF_ticking *phy_stub_ticking = NULL;
+int next_ra_frame = 0;
+module_id_t next_Mod_id = 0;
 
 #define KHz (1000UL)
 #define MHz (1000*KHz)
@@ -386,7 +388,7 @@ void init_UE_stub_single_thread(int nb_inst,int eMBMS_active, int uecap_xer_in,
   for (inst=0;inst<nb_inst;inst++) {
 
     LOG_I(PHY,"Initializing memory for UE instance %d (%p)\n",inst,PHY_vars_UE_g[inst]);
-    PHY_vars_UE_g[inst][0] = init_ue_vars(NULL,inst,0);
+    // PHY_vars_UE_g[inst][0] = init_ue_vars(NULL,inst,0);
   }
   init_timer_thread();
   init_UE_single_thread_stub(nb_inst);
@@ -963,31 +965,53 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
 	thread_top_init("UE_phy_stub_thread_rxn_txnp4",1,870000L,1000000L,1000000L);
 
-	module_id_t Mod_id = 0;
+	// for multipule UE's L2-emulator
+	//module_id_t Mod_id = 0;
+
 	//int init_ra_UE = -1; // This counter is used to initiate the RA of each UE in different SFrames
   static __thread int UE_thread_rxtx_retval;
   struct rx_tx_thread_data *rtd = arg;
   UE_rxtx_proc_t *proc = rtd->proc;
 
-  // Initializations for nfapi-L2-emulator mode
-  dl_config_req = NULL;
-  ul_config_req = NULL;
-  hi_dci0_req	= NULL;
-  tx_request_pdu_list = NULL;
-
+  // settings for nfapi-L2-emulator mode
+  module_id_t ue_thread_id = rtd->ue_thread_id;
+  uint16_t     ue_index = 0;
+  uint16_t     ue_num = NB_UE_INST/NB_THREAD_INST+((NB_UE_INST%NB_THREAD_INST > ue_thread_id) ? 1 :0);
+  module_id_t ue_Mod_id;
   PHY_VARS_UE    *UE;   //= rtd->UE;
   int ret;
+  uint8_t   end_flag;
+  proc = &PHY_vars_UE_g[0][0]->proc.proc_rxtx[0];
+  phy_stub_ticking->num_single_thread[ue_thread_id] = -1;
+
+  if(ue_thread_id == 0){
+    phy_stub_ticking->ticking_var = -1;
+    proc->subframe_rx=proc->sub_frame_start;
+    // Initializations for nfapi-L2-emulator mode
+    dl_config_req = NULL;
+    ul_config_req = NULL;
+    hi_dci0_req        = NULL;
+    tx_request_pdu_list = NULL;
+
+    // waiting for all UE's threads set phy_stub_ticking->num_single_thread[ue_thread_id] = -1.
+    do{
+      end_flag = 1;
+      for(uint16_t i = 0;i< NB_THREAD_INST;i++){
+        if(phy_stub_ticking->num_single_thread[i] == 0){
+          end_flag = 0;
+        }
+      }
+   }while(end_flag == 0);
 
-
-  phy_stub_ticking->ticking_var = -1;
-  proc->subframe_rx=proc->sub_frame_start;
+    sync_var=0;
+  }
 
 
   //PANOS: CAREFUL HERE!
   wait_sync("UE_phy_stub_single_thread_rxn_txnp4");
 
   while (!oai_exit) {
-
+    if(ue_thread_id == 0){
     if (pthread_mutex_lock(&phy_stub_ticking->mutex_ticking) != 0) {
       LOG_E( MAC, "[SCHED][UE] error locking mutex for UE RXTX\n" );
       exit_fun("nothing to add");
@@ -1006,12 +1030,19 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
     proc->subframe_rx=timer_subframe;
     proc->frame_rx = timer_frame;
-    proc->subframe_tx=(timer_subframe+4)%10;
-    proc->frame_tx = proc->frame_rx + (proc->subframe_rx>5?1:0);
+    
+    // FDD and TDD tx timing settings.
+    // XXX:It is the result of timing adjustment in debug.
+    // It is necessary to investigate why this will work in the future.
+    proc->subframe_tx=(timer_subframe+sf_ahead)%10;
+    proc->frame_tx = proc->frame_rx + (proc->subframe_rx>(9-sf_ahead)?1:0);
     //oai_subframe_ind(proc->frame_rx, proc->subframe_rx);
 
-
-    oai_subframe_ind(timer_frame, timer_subframe);
+    if(UE->frame_parms.frame_type == FDD){
+    oai_subframe_ind(proc->frame_rx, proc->subframe_rx);
+    }else{
+    oai_subframe_ind(proc->frame_tx,proc->subframe_tx);
+    }
 
     //Guessing that the next 4 lines are not needed for the phy_stub mode.
     /*initRefTimes(t2);
@@ -1035,14 +1066,45 @@ 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->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;
+
+        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);
+          exit_fun("nothing to add");
+        }
+        memset(&phy_stub_ticking->num_single_thread[0],0,sizeof(int)*NB_THREAD_INST);
+        pthread_cond_broadcast(&phy_stub_ticking->cond_single_thread);
+
+        if (pthread_mutex_unlock(&phy_stub_ticking->mutex_single_thread) != 0) {
+          LOG_E( MAC, "[SCHED][UE] error unlocking mutex for ue_thread_id %d (mutex_single_thread)\n",ue_thread_id);
+          exit_fun("nothing to add");
+        }
+    }else{
+        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);
+           exit_fun("nothing to add");
+        }
+        while (phy_stub_ticking->num_single_thread[ue_thread_id] < 0) {
+          // most of the time, the thread is waiting here
+          LOG_D(MAC,"Waiting for single_thread (ue_thread_id %d)\n",ue_thread_id);
+          pthread_cond_wait( &phy_stub_ticking->cond_single_thread, &phy_stub_ticking->mutex_single_thread);
+        }
+        if (pthread_mutex_unlock(&phy_stub_ticking->mutex_single_thread) != 0) {
+          LOG_E( MAC, "[SCHED][UE] error unlocking mutex for ue_thread_id %d (mutex_single_thread)\n",ue_thread_id);
+          exit_fun("nothing to add");
+        }
+    }
 
-    for (Mod_id=0; Mod_id<NB_UE_INST; Mod_id++) {
-    	//LOG_D(MAC, "UE_phy_stub_single_thread_rxn_txnp4, NB_UE_INST:%d, Mod_id:%d \n", NB_UE_INST, Mod_id);
-    	UE = PHY_vars_UE_g[Mod_id][0];
+    //for (Mod_id=0; Mod_id<NB_UE_INST; Mod_id++) {
+    for (ue_index=0; ue_index < ue_num; ue_index++) {
+    ue_Mod_id = ue_thread_id + NB_THREAD_INST*ue_index;
+    UE = PHY_vars_UE_g[ue_Mod_id][0];
+    //LOG_D(MAC, "UE_phy_stub_single_thread_rxn_txnp4, NB_UE_INST:%d, Mod_id:%d \n", NB_UE_INST, Mod_id);
+    //UE = PHY_vars_UE_g[Mod_id][0];
     lte_subframe_t sf_type = subframe_select( &UE->frame_parms, proc->subframe_rx);
     if ((sf_type == SF_DL) ||
 	(UE->frame_parms.frame_type == FDD) ||
@@ -1068,12 +1130,12 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
       if (dl_config_req!=NULL && tx_request_pdu_list!=NULL){
     	  //if(dl_config_req!= NULL) {
-    	  dl_config_req_UE_MAC(dl_config_req, Mod_id);
+    	  dl_config_req_UE_MAC(dl_config_req, ue_Mod_id);
 
       }
 
       if (hi_dci0_req!=NULL && hi_dci0_req->hi_dci0_request_body.hi_dci0_pdu_list!=NULL){
-    	  hi_dci0_req_UE_MAC(hi_dci0_req, Mod_id);
+    	  hi_dci0_req_UE_MAC(hi_dci0_req, ue_Mod_id);
       }
 
       if(nfapi_mode!=3)
@@ -1087,7 +1149,7 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
     if (UE->mac_enabled==1) {
 
-      ret = ue_scheduler(UE->Mod_id,
+      ret = ue_scheduler(ue_Mod_id,
 			 proc->frame_rx,
 			 proc->subframe_rx,
 			 proc->frame_tx,
@@ -1113,34 +1175,37 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
     // We make the start of RA between consecutive UEs differ by 20 frames
 	//if ((UE_mac_inst[Mod_id].UE_mode[0] == PRACH  && Mod_id == 0) || (UE_mac_inst[Mod_id].UE_mode[0] == PRACH && Mod_id>0 && proc->frame_rx >= UE_mac_inst[Mod_id-1].ra_frame + 20) ) {
-	if (UE_mac_inst[Mod_id].UE_mode[0] == PRACH  && Mod_id == next_Mod_id && proc->frame_rx >= next_ra_frame) {
-
+	if (UE_mac_inst[ue_Mod_id].UE_mode[0] == PRACH  && ue_Mod_id == next_Mod_id) {
+          next_ra_frame++;
+          if(next_ra_frame > 200){
 	  // check if we have PRACH opportunity
 
-	  if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx) &&  UE_mac_inst[Mod_id].SI_Decoded == 1) {
+	  if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx) &&  UE_mac_inst[ue_Mod_id].SI_Decoded == 1) {
 
 	  // The one working strangely...
       //if (is_prach_subframe(&UE->frame_parms,proc->frame_tx, proc->subframe_tx && Mod_id == (module_id_t) init_ra_UE) ) {
 
-	    PRACH_RESOURCES_t *prach_resources = ue_get_rach(Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx);
+	    PRACH_RESOURCES_t *prach_resources = ue_get_rach(ue_Mod_id, 0, proc->frame_tx, 0, proc->subframe_tx);
 	    if(prach_resources!=NULL ) {
-	    	UE_mac_inst[Mod_id].ra_frame = proc->frame_rx;
-	      LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d \n", Mod_id );
-	      fill_rach_indication_UE_MAC(Mod_id, proc->frame_tx ,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI);
-	      Msg1_transmitted(Mod_id, 0, proc->frame_tx, 0);
-	      UE_mac_inst[Mod_id].UE_mode[0] = RA_RESPONSE;
-	      next_Mod_id = Mod_id + 1;
-	      next_ra_frame = (proc->frame_rx + 20)%1000;
+	    	UE_mac_inst[ue_Mod_id].ra_frame = proc->frame_rx;
+	      LOG_D(MAC, "UE_phy_stub_thread_rxn_txnp4 before RACH, Mod_id: %d frame %d subframe %d\n", ue_Mod_id ,proc->frame_tx, proc->subframe_tx);
+	      fill_rach_indication_UE_MAC(ue_Mod_id, proc->frame_tx ,proc->subframe_tx, UL_INFO, prach_resources->ra_PreambleIndex, prach_resources->ra_RNTI);
+	      Msg1_transmitted(ue_Mod_id, 0, proc->frame_tx, 0);
+	      UE_mac_inst[ue_Mod_id].UE_mode[0] = RA_RESPONSE;
+	      next_Mod_id = ue_Mod_id + 1;
+	      //next_ra_frame = (proc->frame_rx + 20)%1000;
+              next_ra_frame = 0;
 	    }
 
 	    //ue_prach_procedures(ue,proc,eNB_id,abstraction_flag,mode);
 	  }
+          }
 	} // mode is PRACH
 	// Substitute call to phy_procedures Tx with call to phy_stub functions in order to trigger
 	// UE Tx procedures directly at the MAC layer, based on the received ul_config requests from the vnf (eNB).
 	// Generate UL_indications which correspond to UL traffic.
 	if(ul_config_req!=NULL){ //&& UE_mac_inst[Mod_id].ul_config_req->ul_config_request_body.ul_config_pdu_list != NULL){
-		ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, Mod_id);
+		ul_config_req_UE_MAC(ul_config_req, timer_frame, timer_subframe, ue_Mod_id);
 	}
       }
 
@@ -1149,6 +1214,19 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
 
     } //for (Mod_id=0; Mod_id<NB_UE_INST; Mod_id++)
 
+    phy_stub_ticking->num_single_thread[ue_thread_id] = -1;
+
+    // waiting for all UE's threads set phy_stub_ticking->num_single_thread[ue_thread_id] = -1.
+    if(ue_thread_id == 0){
+      do{
+        end_flag = 1;
+        for(uint16_t i = 0;i< NB_THREAD_INST;i++){
+          if(phy_stub_ticking->num_single_thread[i] == 0){
+             end_flag = 0;
+          }
+        }
+      }while(end_flag == 0);
+
 
     if (UL_INFO->crc_ind.crc_indication_body.number_of_crcs>0)
       {
@@ -1163,6 +1241,9 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
     	  //LOG_D(PHY,"UL_info->rx_ind.number_of_pdus:%d RX_IND:SFN/SF:%d\n", UL_info->rx_ind.rx_indication_body.number_of_pdus, NFAPI_SFNSF2DEC(UL_info->rx_ind.sfn_sf));
     	  //LOG_I(MAC, "ul_config_req_UE_MAC 2.3, SFN/SF of PNF counter:%d.%d, number_of_pdus: %d \n", timer_frame, timer_subframe, UL_INFO->rx_ind.rx_indication_body.number_of_pdus);
     	  oai_nfapi_rx_ind(&UL_INFO->rx_ind);
+          for(uint8_t num_pdu = 0;num_pdu < UL_INFO->rx_ind.rx_indication_body.number_of_pdus;num_pdu++){
+            free(UL_INFO->rx_ind.rx_indication_body.rx_pdu_list[num_pdu].data);
+          }
     	  //LOG_I(MAC, "ul_config_req_UE_MAC 2.31 \n");
     	  UL_INFO->rx_ind.rx_indication_body.number_of_pdus = 0;
       }
@@ -1199,14 +1280,19 @@ 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);
       UL_INFO = NULL;
 
       // De-allocate memory of nfapi requests copies before next subframe round
       if(dl_config_req!=NULL){
-    	  if(dl_config_req->vendor_extension)
-    		  free(dl_config_req->vendor_extension);
+    	  if(dl_config_req->vendor_extension!=NULL){
+            free(dl_config_req->vendor_extension);
+            dl_config_req->vendor_extension = NULL;
+          }
     	  if(dl_config_req->dl_config_request_body.dl_config_pdu_list!=NULL){
     		  free(dl_config_req->dl_config_request_body.dl_config_pdu_list);
     		  dl_config_req->dl_config_request_body.dl_config_pdu_list = NULL;
@@ -1236,7 +1322,7 @@ static void *UE_phy_stub_single_thread_rxn_txnp4(void *arg) {
     	  hi_dci0_req = NULL;
       }
 
-
+    }
 
   }
   // thread finished
@@ -1780,6 +1866,13 @@ void init_UE_single_thread_stub(int nb_inst) {
 	  AssertFatal(PHY_vars_UE_g!=NULL,"PHY_vars_UE_g is NULL\n");
 	  AssertFatal(PHY_vars_UE_g[i]!=NULL,"PHY_vars_UE_g[inst] is NULL\n");
 	  AssertFatal(PHY_vars_UE_g[i][0]!=NULL,"PHY_vars_UE_g[inst][0] is NULL\n");
+	  if(nfapi_mode == 3){
+#ifdef NAS_UE
+          MessageDef *message_p;
+          message_p = itti_alloc_new_message(TASK_NAS_UE, INITIALIZE_MESSAGE);
+         itti_send_msg_to_task (TASK_NAS_UE, i + NB_eNB_INST, message_p);
+#endif
+	  }
   }
   UE = PHY_vars_UE_g[0][0];
 
@@ -1794,19 +1887,22 @@ void init_UE_single_thread_stub(int nb_inst) {
   // In phy_stub_UE mode due to less heavy processing operations we don't need two threads
   //int nb_threads=RX_NB_TH;
   int nb_threads=1;
-  for (int i=0; i<nb_threads; i++) {
-    rtd = calloc(1, sizeof(struct rx_tx_thread_data));
-    if (rtd == NULL) abort();
-    rtd->UE = UE;
-    rtd->proc = &UE->proc.proc_rxtx[i];
-
-    pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_rxtx,NULL);
-    pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL);
-    UE->proc.proc_rxtx[i].sub_frame_start=i;
-    UE->proc.proc_rxtx[i].sub_frame_step=nb_threads;
-    printf("Init_UE_threads rtd %d proc %d nb_threads %d i %d\n",rtd->proc->sub_frame_start, UE->proc.proc_rxtx[i].sub_frame_start,nb_threads, i);
-    pthread_create(&UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_phy_stub_single_thread_rxn_txnp4, rtd);
-
+  for(uint16_t ue_thread_id = 0;ue_thread_id < NB_THREAD_INST;ue_thread_id++){
+    UE = PHY_vars_UE_g[ue_thread_id][0];
+    for (int i=0; i<nb_threads; i++) {
+      rtd = calloc(1, sizeof(struct rx_tx_thread_data));
+      if (rtd == NULL) abort();
+      rtd->UE = UE;
+      rtd->proc = &UE->proc.proc_rxtx[i];
+      rtd->ue_thread_id = ue_thread_id;
+
+      pthread_mutex_init(&UE->proc.proc_rxtx[i].mutex_rxtx,NULL);
+      pthread_cond_init(&UE->proc.proc_rxtx[i].cond_rxtx,NULL);
+      UE->proc.proc_rxtx[i].sub_frame_start=i;
+      UE->proc.proc_rxtx[i].sub_frame_step=nb_threads;
+      printf("Init_UE_threads rtd %d proc %d nb_threads %d i %d\n",rtd->proc->sub_frame_start, UE->proc.proc_rxtx[i].sub_frame_start,nb_threads, i);
+      pthread_create(&UE->proc.proc_rxtx[i].pthread_rxtx, NULL, UE_phy_stub_single_thread_rxn_txnp4, rtd);
+    }
   }
   // Remove thread for UE_sync in phy_stub_UE mode.
   //pthread_create(&UE->proc.pthread_synch,NULL,UE_thread_synch,(void*)UE);
@@ -2076,8 +2172,11 @@ int init_timer_thread(void) {
   pthread_mutex_init(&UE->timer_mutex,NULL);
   pthread_cond_init(&UE->timer_cond,NULL);
   UE->instance_cnt_timer = -1;
+  memset(&phy_stub_ticking->num_single_thread[0],0,sizeof(int)*NB_THREAD_INST);
   pthread_mutex_init(&phy_stub_ticking->mutex_ticking,NULL);
   pthread_cond_init(&phy_stub_ticking->cond_ticking,NULL);
+  pthread_mutex_init(&phy_stub_ticking->mutex_single_thread,NULL);
+  pthread_cond_init(&phy_stub_ticking->cond_single_thread,NULL);
   pthread_create(&phy_stub_ticking->pthread_timer, NULL, &timer_thread, NULL);
   return 0;
 }
diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c
old mode 100644
new mode 100755
index 38937226e528a9459b7e1ca006a00e996665048a..4583b6ac97cc56d8d2671da7c805d20b07d260de
--- a/targets/RT/USER/lte-uesoftmodem.c
+++ b/targets/RT/USER/lte-uesoftmodem.c
@@ -110,9 +110,13 @@ pthread_mutex_t nfapi_sync_mutex;
 int nfapi_sync_var=-1; //!< protected by mutex \ref nfapi_sync_mutex
 
 uint8_t nfapi_mode = 0;
-
+#ifdef PDCP_USE_NETLINK
+#ifdef UESIM_EXPANSION
+uint16_t inst_pdcp_list[NUMBER_OF_UE_MAX];
+#endif
+#endif
 uint16_t sf_ahead=2;
-
+int tddflag;
 char *emul_iface;
 
 
@@ -491,10 +495,12 @@ static void get_options(void) {
   }
 
   UE_scan=0;
-
+   
   if (tddflag > 0) {
-    for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++)
+    for (CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
       frame_parms[CC_id]->frame_type = TDD;
+      frame_parms[CC_id]->tdd_config = tddflag;
+    }
   }
 
   if (frame_parms[0]->N_RB_DL !=0) {
@@ -722,9 +728,15 @@ int main( int argc, char **argv ) {
 #endif
   int CC_id;
   uint8_t  abstraction_flag=0;
+#ifdef PDCP_USE_NETLINK
+#ifdef UESIM_EXPANSION
+  memset(inst_pdcp_list, 0, sizeof(inst_pdcp_list));
+#endif
+#endif
   // Default value for the number of UEs. It will hold,
   // if not changed from the command line option --num-ues
   NB_UE_INST=1;
+  NB_THREAD_INST=1;
 #if defined (XFORMS)
   int ret;
 #endif
@@ -746,12 +758,36 @@ int main( int argc, char **argv ) {
   get_options ();
   printf("Running with %d UE instances\n",NB_UE_INST);
 
-  if (NB_UE_INST > 1 && simL1flag != 1) {
+  if (NB_UE_INST > 1 && simL1flag != 1 && nfapi_mode != 3) {
     printf("Running with more than 1 UE instance and simL1 is not active, this will result in undefined behaviour for now, exiting.\n");
     abort();
   }
 
   printf("NFAPI_MODE value: %d \n", nfapi_mode);
+
+  // Checking option of nums_ue_thread.
+  if(NB_THREAD_INST < 1){
+    printf("Running with 0 UE rxtx thread, exiting.\n");
+    abort();
+  }
+  // Checking option's relation between nums_ue_thread and num-ues
+  if(NB_UE_INST <NB_THREAD_INST ){
+    printf("Number of UEs < number of UE rxtx threads, exiting.\n");
+    abort();
+  }
+  // Not sure if the following is needed here
+  /*if (CONFIG_ISFLAGSET(CONFIG_ABORT)) {
+      if (UE_flag == 0) {
+        fprintf(stderr,"Getting configuration failed\n");
+        exit(-1);
+      }
+      else {
+        printf("Setting nfapi mode to UE_STUB_OFFNET\n");
+        nfapi_mode = 4;
+      }
+    }*/
+
+
 #if T_TRACER
   T_Config_Init();
 #endif
@@ -834,6 +870,8 @@ int main( int argc, char **argv ) {
     RCConfig_sim();
   }
 
+// source code written in below moved to later to avoid keeping waiting for nfapi_sync_cond in wait_nfapi_init.
+/*
   // start the main UE threads
   int eMBMS_active = 0;
 
@@ -862,7 +900,8 @@ int main( int argc, char **argv ) {
       PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset);
     }
   }
-
+*/
+  
   cpuf=get_cpu_freq_GHz();
 #ifndef DEADLINE_SCHEDULER
   printf("NO deadline scheduler\n");
@@ -907,8 +946,7 @@ int main( int argc, char **argv ) {
   LOG_I(HW, "CPU Affinity of main() function is... %s\n", cpu_affinity);
 #endif
 #if defined(ENABLE_ITTI)
-
-  if (create_tasks_ue(1) < 0) {
+  if (create_tasks_ue(NB_UE_INST) < 0) {
     printf("cannot create ITTI tasks\n");
     exit(-1); // need a softer mode
   }
@@ -922,6 +960,8 @@ int main( int argc, char **argv ) {
   mlockall(MCL_CURRENT | MCL_FUTURE);
   rt_sleep_ns(10*100000000ULL);
   const char *nfapi_mode_str = "<UNKNOWN>";
+  // start the main UE threads
+  int eMBMS_active = 0;
 
   switch(nfapi_mode) {
     case 0:
@@ -951,6 +991,33 @@ int main( int argc, char **argv ) {
 
   printf("NFAPI MODE:%s\n", nfapi_mode_str);
 
+  if (nfapi_mode==3) // UE-STUB-PNF
+  {
+      config_sync_var=0;
+      wait_nfapi_init("main?");
+      //Panos: Temporarily we will be using single set of threads for multiple UEs.
+      //init_UE_stub(1,eMBMS_active,uecap_xer_in,emul_iface);
+      init_UE_stub_single_thread(NB_UE_INST,eMBMS_active,uecap_xer_in,emul_iface);
+  }
+  else {
+      init_UE(NB_UE_INST,eMBMS_active,uecap_xer_in,0,get_softmodem_params()->phy_test,UE_scan,UE_scan_carrier,mode,(int)rx_gain[0][0],tx_max_power[0],
+              frame_parms[0]);
+  }
+
+
+  if (get_softmodem_params()->phy_test==0) {
+    printf("Filling UE band info\n");
+    fill_ue_band_info();
+    dl_phy_sync_success (0, 0, 0, 1);
+  }
+
+  if (nfapi_mode!=3){
+      number_of_cards = 1;
+      for(CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+              PHY_vars_UE_g[0][CC_id]->rf_map.card=0;
+              PHY_vars_UE_g[0][CC_id]->rf_map.chain=CC_id+(get_softmodem_params()->chain_offset);
+      }
+  }
   // connect the TX/RX buffers
 
   /*