diff --git a/common/utils/ocp_itti/intertask_interface.h b/common/utils/ocp_itti/intertask_interface.h
index c6c9d447f1269cfa2ff2a3c4171cf4b51e310d69..cab545bb825c3b54058e7be1f74d6b161d9c55f9 100644
--- a/common/utils/ocp_itti/intertask_interface.h
+++ b/common/utils/ocp_itti/intertask_interface.h
@@ -345,6 +345,8 @@ void *rrc_enb_process_msg(void *);
   TASK_DEF(TASK_DU_F1,    TASK_PRIORITY_MED,  200, NULL, NULL) \
   TASK_DEF(TASK_RRC_UE_SIM,   TASK_PRIORITY_MED,  200, NULL, NULL)  \
   TASK_DEF(TASK_RRC_GNB_SIM,  TASK_PRIORITY_MED,  200, NULL, NULL)  \
+  TASK_DEF(TASK_RRC_NSA_UE,   TASK_PRIORITY_MED,  200, NULL, NULL)  \
+  TASK_DEF(TASK_RRC_NSA_NRUE,   TASK_PRIORITY_MED,  200, NULL, NULL)  \
   TASK_DEF(TASK_MAX,      TASK_PRIORITY_MED,  200, NULL, NULL)
 
 #define TASK_DEF(TaskID, pRIO, qUEUEsIZE, FuNc, ThreadFunc)          { pRIO, qUEUEsIZE, #TaskID, FuNc, ThreadFunc },
diff --git a/executables/nr-ru.c b/executables/nr-ru.c
index b1ceb03eb193d875fa44d0075e07eef7756941d1..c083032ee4baecb7f56a8336af4b40abde7d66a3 100644
--- a/executables/nr-ru.c
+++ b/executables/nr-ru.c
@@ -1445,8 +1445,6 @@ void *ru_thread( void *param ) {
   int                i = 0;
   int                aa;
 
-  nfapi_nr_config_request_scf_t *cfg = &ru->config;
-  
   // set default return value
   ru_thread_status = 0;
   // set default return value
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 7d86f3572e0465c32e18dfa228a709ea2566b93d..7f5c8cb040706ace09787b28db6df09f9dc5a826 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -182,6 +182,26 @@ void print_difftimes(void) {
   LOG_I(HW,"difftimes min = %lu ns ; max = %lu ns\n", min_diff_time.tv_nsec, max_diff_time.tv_nsec);
 }
 
+int create_tasks_nrue(uint32_t ue_nb) {
+  LOG_D(NR_RRC, "%s(ue_nb:%d)\n", __FUNCTION__, ue_nb);
+  itti_wait_ready(1);
+
+  if (ue_nb > 0) {
+    if (itti_create_task (TASK_RRC_NRUE, rrc_nrue_task, NULL) < 0) {
+      LOG_E(NR_RRC, "Create task for RRC UE failed\n");
+      return -1;
+    }
+  }
+  if (ue_nb > 0 && get_softmodem_params()->nsa == 1) {
+    if (itti_create_task (TASK_RRC_NSA_NRUE, recv_msgs_from_lte_ue, NULL) < 0) {
+      LOG_E(NR_RRC, "Create task for RRC NSA nr-UE failed\n");
+      return -1;
+    }
+  }
+  itti_wait_ready(0);
+  return 0;
+}
+
 void exit_function(const char *file, const char *function, const int line, const char *s) {
   int CC_id;
 
@@ -517,50 +537,55 @@ int main( int argc, char **argv ) {
   if (get_softmodem_params()->sa)
     AssertFatal(get_softmodem_params()->phy_test == 0,"Standalone mode and phy_test are mutually exclusive\n");
 
-  for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+  if (create_tasks_nrue(1) < 0) {
+    LOG_E(NR_RRC,"Cannot create ITTI tasks for RRC layer of nr-UE\n");
+    exit(-1);
+  }
+  if (!get_softmodem_params()->nsa) {
+    for (int CC_id=0; CC_id<MAX_NUM_CCs; CC_id++) {
+      PHY_vars_UE_g[0][CC_id] = (PHY_VARS_NR_UE *)malloc(sizeof(PHY_VARS_NR_UE));
+      UE[CC_id] = PHY_vars_UE_g[0][CC_id];
+      memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE));
+
+      set_options(CC_id, UE[CC_id]);
 
+      NR_UE_MAC_INST_t *mac = get_mac_inst(0);
+      if(mac->if_module != NULL && mac->if_module->phy_config_request != NULL)
+        mac->if_module->phy_config_request(&mac->phy_config);
 
-    PHY_vars_UE_g[0][CC_id] = (PHY_VARS_NR_UE *)malloc(sizeof(PHY_VARS_NR_UE));
-    UE[CC_id] = PHY_vars_UE_g[0][CC_id];
-    memset(UE[CC_id],0,sizeof(PHY_VARS_NR_UE));
+      fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config;
 
-    set_options(CC_id, UE[CC_id]);
+      nr_init_frame_parms_ue(&UE[CC_id]->frame_parms, nrUE_config, *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]);
 
-    NR_UE_MAC_INST_t *mac = get_mac_inst(0);
-    if(mac->if_module != NULL && mac->if_module->phy_config_request != NULL)
-      mac->if_module->phy_config_request(&mac->phy_config);
+      init_symbol_rotation(&UE[CC_id]->frame_parms, 0);
+      init_nr_ue_vars(UE[CC_id], 0, abstraction_flag);
 
-    fapi_nr_config_request_t *nrUE_config = &UE[CC_id]->nrUE_config;
+      #ifdef FR2_TEST
+      // Overwrite DL frequency (for FR2 testing)
+      if (downlink_frequency[0][0]!=0){
+        frame_parms[CC_id]->dl_CarrierFreq = downlink_frequency[0][0];
+        if (frame_parms[CC_id]->frame_type == TDD)
+          frame_parms[CC_id]->ul_CarrierFreq = downlink_frequency[0][0];
+      }
+      #endif
+    }
 
-    nr_init_frame_parms_ue(&UE[CC_id]->frame_parms, nrUE_config, *mac->scc->downlinkConfigCommon->frequencyInfoDL->frequencyBandList.list.array[0]);
-    init_symbol_rotation(&UE[CC_id]->frame_parms, UE[CC_id]->frame_parms.dl_CarrierFreq);
-    init_nr_ue_vars(UE[CC_id], 0, abstraction_flag);
+    init_openair0();
+    // init UE_PF_PO and mutex lock
+    pthread_mutex_init(&ue_pf_po_mutex, NULL);
+    memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
+    configure_linux();
+    mlockall(MCL_CURRENT | MCL_FUTURE);
 
-    #ifdef FR2_TEST
-    // Overwrite DL frequency (for FR2 testing)
-    if (downlink_frequency[0][0]!=0){
-      frame_parms[CC_id]->dl_CarrierFreq = downlink_frequency[0][0];
-      if (frame_parms[CC_id]->frame_type == TDD)
-        frame_parms[CC_id]->ul_CarrierFreq = downlink_frequency[0][0];
+    if(IS_SOFTMODEM_DOFORMS) {
+      load_softscope("nr",PHY_vars_UE_g[0][0]);
     }
-    #endif
-  }
 
-  init_openair0();
-  // init UE_PF_PO and mutex lock
-  pthread_mutex_init(&ue_pf_po_mutex, NULL);
-  memset (&UE_PF_PO[0][0], 0, sizeof(UE_PF_PO_t)*NUMBER_OF_UE_MAX*MAX_NUM_CCs);
-  configure_linux();
-  mlockall(MCL_CURRENT | MCL_FUTURE);
- 
-  if(IS_SOFTMODEM_DOFORMS) { 
-    load_softscope("nr",PHY_vars_UE_g[0][0]);
-  }     
+    init_NR_UE_threads(1);
+    printf("UE threads created by %ld\n", gettid());
+
+  }
 
-  
-  init_NR_UE_threads(1);
-  printf("UE threads created by %ld\n", gettid());
-  
   // wait for end of program
   printf("TYPE <CTRL-C> TO TERMINATE\n");
   // Sleep a while before checking all parameters have been used
diff --git a/executables/softmodem-common.h b/executables/softmodem-common.h
index 60a761c732a8bdbb3ad710516285ac6e9dec1d8b..05e6bfb2076cd84997b7a8ce0937604ce1ac8247 100644
--- a/executables/softmodem-common.h
+++ b/executables/softmodem-common.h
@@ -114,6 +114,7 @@ extern "C"
 #define USIM_TEST           softmodem_params.usim_test
 #define USE_256QAM_TABLE    softmodem_params.use_256qam_table
 #define NFAPI               softmodem_params.nfapi
+#define NSA                 softmodem_params.nsa
 
 #define DEFAULT_RFCONFIG_FILE    "/usr/local/etc/syriq/ue.band7.tm1.PRB100.NR40.dat";
 
@@ -144,10 +145,11 @@ extern "C"
     {"nokrnmod",             CONFIG_HLP_NOKRNMOD,     PARAMFLAG_BOOL, uptr:&nokrnmod,                     defintval:0,           TYPE_INT,    0},                     \
     {"nbiot-disable",        CONFIG_HLP_DISABLNBIOT,  PARAMFLAG_BOOL, uptr:&nonbiot,                      defuintval:0,          TYPE_INT,    0},                     \
     {"use-256qam-table",     CONFIG_HLP_256QAM,       PARAMFLAG_BOOL, iptr:&USE_256QAM_TABLE,             defintval:0,           TYPE_INT,    0},                     \
-    {"nfapi",                CONFIG_HLP_NFAPI,        0,              u8ptr:&nfapi_mode,                       defintval:0,           TYPE_UINT8,  0},                     \
+    {"nfapi",                CONFIG_HLP_NFAPI,        0,              u8ptr:&nfapi_mode,                  defintval:0,           TYPE_UINT8,  0},                     \
+    {"nsa",                  CONFIG_HLP_NSA,          PARAMFLAG_BOOL, iptr:&NSA,                          defintval:0,           TYPE_INT,    0},                     \
   }
 
-  
+#define CONFIG_HLP_NSA           "Enable NSA mode \n"
 #define CONFIG_HLP_FLOG          "Enable online log \n"
 #define CONFIG_HLP_LOGL          "Set the global log level, valid options: (4:trace, 3:debug, 2:info, 1:warn, (0:error))\n"
 #define CONFIG_HLP_LOGV          "Set the global log verbosity \n"
@@ -233,6 +235,7 @@ typedef struct {
   uint32_t       send_dmrs_sync;
   int            use_256qam_table;
   uint8_t        nfapi;
+  int            nsa;
 } softmodem_params_t;
 
 extern uint64_t get_softmodem_optmask(void);
diff --git a/nfapi/oai_integration/nfapi_pnf.c b/nfapi/oai_integration/nfapi_pnf.c
index 9219970decb93268f0ba05b8a1a01fb5f7ba7bd7..9b68f41eca5130f8d858e2893e69124c8e1f6425 100644
--- a/nfapi/oai_integration/nfapi_pnf.c
+++ b/nfapi/oai_integration/nfapi_pnf.c
@@ -1225,7 +1225,7 @@ int pnf_phy_dl_tti_req(gNB_L1_rxtx_proc_t *proc, nfapi_pnf_p7_config_t *pnf_p7,
   nfapi_nr_dl_tti_request_pdu_t *dl_tti_pdu_list = req->dl_tti_request_body.dl_tti_pdu_list;
 
   if (req->dl_tti_request_body.nPDUs)
-    NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX:%d/%d RX:%d/%d; sfn:%d, slot:%d, nGroup:%u, nPDUs: %u, nUE: %u, PduIdx: %u,\n",
+    NFAPI_TRACE(NFAPI_TRACE_INFO, "%s() TX:%d/%d RX:%d/%d; sfn:%d, slot:%d, nGroup:%u, nPDUs: %u, nUE: %p, PduIdx: %p,\n",
                 __FUNCTION__, proc->frame_tx, proc->slot_tx, proc->frame_rx, proc->slot_rx, // TODO: change subframes to slot
                 req->SFN,
                 req->Slot,
@@ -1790,7 +1790,6 @@ int start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy, nfapi
 
 int nr_start_request(nfapi_pnf_config_t *config, nfapi_pnf_phy_config_t *phy,  nfapi_nr_start_request_scf_t *req) {
   printf("[PNF] Received NFAPI_START_REQ phy_id:%d\n", req->header.phy_id);
-  nfapi_set_trace_level(NFAPI_TRACE_INFO);
   pnf_info *pnf = (pnf_info *)(config->user_data);
   phy_info *phy_info = pnf->phys;
   nfapi_pnf_p7_config_t *p7_config = nfapi_pnf_p7_config_create();
@@ -2295,15 +2294,13 @@ void oai_subframe_ind(uint16_t sfn, uint16_t sf) {
     uint16_t sfn_sf_tx = sfn<<4 | sf; 
 
     if ((sfn % 100 == 0) && sf==0) {
-      struct timespec ts;
-      clock_gettime(CLOCK_MONOTONIC, &ts);
-      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] %s %d.%d (sfn:%u sf:%u) SFN/SF(TX):%u\n", __FUNCTION__, ts.tv_sec, ts.tv_nsec, sfn, sf, NFAPI_SFNSF2DEC(sfn_sf_tx));
+      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] (sfn:%u sf:%u) SFN/SF(TX):%u\n", sfn, sf, NFAPI_SFNSF2DEC(sfn_sf_tx));
     }
 
     int subframe_ret = nfapi_pnf_p7_subframe_ind(p7_config_g, p7_config_g->phy_id, sfn_sf_tx);
 
     if (subframe_ret) {
-      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] %s(frame:%u subframe:%u) SFN/SF(TX):%u - PROBLEM with pnf_p7_subframe_ind()\n", __FUNCTION__, sfn, sf, sfn_sf_tx, NFAPI_SFNSF2DEC(sfn_sf_tx));
+      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] (frame:%u subframe:%u) SFN/SF(TX):%u - PROBLEM with pnf_p7_subframe_ind()\n", sfn, sf, sfn_sf_tx);
     } else {
       //NFAPI_TRACE(NFAPI_TRACE_INFO, "***NFAPI subframe handler finished *** \n");
     }
@@ -2347,8 +2344,8 @@ void oai_slot_ind(uint16_t sfn, uint16_t slot) {
     int slot_ret = nfapi_pnf_p7_slot_ind(p7_config_g, p7_config_g->phy_id, sfn, slot); 
 
     // if (subframe_ret) {
-    if (slot_ret) { 
-      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF] %s(frame:%u slot:%u) SFN/SLOT(TX):%u - PROBLEM with pnf_p7_slot_ind()\n", __FUNCTION__, sfn, slot, sfn_slot_tx, NFAPI_SFNSLOT2DEC(sfn, slot));
+    if (slot_ret) {
+      NFAPI_TRACE(NFAPI_TRACE_INFO, "[PNF](frame:%u slot:%u) SFN/SLOT(TX):%u - PROBLEM with pnf_p7_slot_ind()\n", sfn, slot, sfn_slot_tx);
       // printing anything causes error: probably because there isn't enough time to accomodate a print statement
     } else {
       //NFAPI_TRACE(NFAPI_TRACE_INFO, "***NFAPI subframe handler finished *** \n");
diff --git a/nfapi/oai_integration/nfapi_vnf.c b/nfapi/oai_integration/nfapi_vnf.c
index 1207e55f60abd968700e5377e027b6b745bf1104..08f32c9a90aef0cc49116f4ce30940ef6b3c1334 100644
--- a/nfapi/oai_integration/nfapi_vnf.c
+++ b/nfapi/oai_integration/nfapi_vnf.c
@@ -646,8 +646,8 @@ int phy_subframe_indication(struct nfapi_vnf_p7_config *config, uint16_t phy_id,
 int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indication_t *ind) {
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_preambles:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
-  printf("[VNF] RACH_IND eNB:%p sfn_sf:%d number_of_preambles:%d\n", eNB, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  LOG_D(MAC, "[VNF] RACH_IND eNB:%p sfn_sf:%d number_of_preambles:%d\n", eNB, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rach_indication_body.number_of_preambles);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -659,7 +659,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
     for (int i=0; i<ind->rach_indication_body.number_of_preambles; i++) {
       if (ind->rach_indication_body.preamble_list[i].preamble_rel8.tl.tag == NFAPI_PREAMBLE_REL8_TAG) {
 
-        printf("preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
+        LOG_D(MAC, "preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
               i,
               ind->rach_indication_body.preamble_list[i].preamble_rel8.rnti,
               ind->rach_indication_body.preamble_list[i].preamble_rel8.preamble,
@@ -667,7 +667,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
               );
       }
       if(ind->rach_indication_body.preamble_list[i].preamble_rel13.tl.tag == NFAPI_PREAMBLE_REL13_TAG) {
-        printf("RACH PREAMBLE REL13 present\n");
+        LOG_D(MAC, "RACH PREAMBLE REL13 present\n");
       }
 
       UL_RCC_INFO.rach_ind[index].rach_indication_body.preamble_list[i] = ind->rach_indication_body.preamble_list[i];
@@ -678,7 +678,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
 
   for (int i=0; i<ind->rach_indication_body.number_of_preambles; i++) {
     if (ind->rach_indication_body.preamble_list[i].preamble_rel8.tl.tag == NFAPI_PREAMBLE_REL8_TAG) {
-      printf("preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
+      LOG_D(MAC, "preamble[%d]: rnti:%02x preamble:%d timing_advance:%d\n",
              i,
              ind->rach_indication_body.preamble_list[i].preamble_rel8.rnti,
              ind->rach_indication_body.preamble_list[i].preamble_rel8.preamble,
@@ -687,13 +687,13 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
     }
 
     if(ind->rach_indication_body.preamble_list[i].preamble_rel13.tl.tag == NFAPI_PREAMBLE_REL13_TAG) {
-      printf("RACH PREAMBLE REL13 present\n");
+      LOG_D(MAC, "RACH PREAMBLE REL13 present\n");
     }
 
     eNB->preamble_list[i] = ind->rach_indication_body.preamble_list[i];
   }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_rach_ind(p7_vnf->mac, ind);
   return 1;
@@ -702,7 +702,7 @@ int phy_rach_indication(struct nfapi_vnf_p7_config *config, nfapi_rach_indicatio
 int phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indication_t *ind) {
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_harqs:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->harq_indication_body.number_of_harqs);
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -726,7 +726,7 @@ int phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indicatio
              sizeof(eNB->UL_INFO.harq_ind.harq_indication_body.harq_pdu_list[i]));
     }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_harq_ind(p7_vnf->mac, ind);
   return 1;
@@ -734,7 +734,7 @@ int phy_harq_indication(struct nfapi_vnf_p7_config *config, nfapi_harq_indicatio
 
 int phy_crc_indication(struct nfapi_vnf_p7_config *config, nfapi_crc_indication_t *ind) {
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -778,7 +778,7 @@ int phy_crc_indication(struct nfapi_vnf_p7_config *config, nfapi_crc_indication_
           eNB->UL_INFO.crc_ind.crc_indication_body.crc_pdu_list[i].rx_ue_information.rnti);
   }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_crc_ind(p7_vnf->mac, ind);
   return 1;
@@ -791,7 +791,7 @@ int phy_rx_indication(struct nfapi_vnf_p7_config *config, nfapi_rx_indication_t
     LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_pdus:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->rx_indication_body.number_of_pdus);
   }
 
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -857,7 +857,7 @@ int phy_rx_indication(struct nfapi_vnf_p7_config *config, nfapi_rx_indication_t
          );
   }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_rx_ind(p7_vnf->mac, ind);
   return 1;
@@ -871,7 +871,7 @@ int phy_srs_indication(struct nfapi_vnf_p7_config *config, nfapi_srs_indication_
 int phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t *ind) {
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d srs:%d\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->sr_indication_body.number_of_srs);
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -906,7 +906,7 @@ int phy_sr_indication(struct nfapi_vnf_p7_config *config, nfapi_sr_indication_t
     memcpy(dest_pdu, src_pdu, sizeof(*src_pdu));
   }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   // vnf_p7_info* p7_vnf = (vnf_p7_info*)(config->user_data);
   //mac_sr_ind(p7_vnf->mac, ind);
   return 1;
@@ -947,7 +947,7 @@ int phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_
   //mac_cqi_ind(p7_vnf->mac, ind);
   struct PHY_VARS_eNB_s *eNB = RC.eNB[0][0];
   LOG_D(MAC, "%s() NFAPI SFN/SF:%d number_of_cqis:%u\n", __FUNCTION__, NFAPI_SFNSF2DEC(ind->sfn_sf), ind->cqi_indication_body.number_of_cqis);
-  pthread_mutex_lock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_lock(&eNB->UL_INFO_mutex)==0, "Mutex lock failed");
   if(NFAPI_MODE == NFAPI_MODE_VNF){
     int8_t index = NFAPI_SFNSF2SF(ind->sfn_sf);
 
@@ -989,7 +989,7 @@ int phy_cqi_indication(struct nfapi_vnf_p7_config *config, nfapi_cqi_indication_
            &ind->cqi_indication_body.cqi_raw_pdu_list[i], sizeof(nfapi_cqi_indication_raw_pdu_t));
   }
   }
-  pthread_mutex_unlock(&eNB->UL_INFO_mutex);
+  AssertFatal(pthread_mutex_unlock(&eNB->UL_INFO_mutex)==0, "Mutex unlock failed");
   return 1;
 }
 
@@ -1160,7 +1160,6 @@ void *vnf_nr_p7_thread_start(void *ptr) {
   p7_vnf->config->nrach_indication = &phy_nrach_indication;
   p7_vnf->config->malloc = &vnf_allocate;
   p7_vnf->config->free = &vnf_deallocate;
-  p7_vnf->config->trace = &vnf_trace;
   p7_vnf->config->vendor_ext = &phy_vendor_ext;
   p7_vnf->config->user_data = p7_vnf;
   p7_vnf->mac->user_data = p7_vnf;
@@ -1197,7 +1196,6 @@ void *vnf_p7_thread_start(void *ptr) {
   p7_vnf->config->nrach_indication = &phy_nrach_indication;
   p7_vnf->config->malloc = &vnf_allocate;
   p7_vnf->config->free = &vnf_deallocate;
-  p7_vnf->config->trace = &vnf_trace;
   p7_vnf->config->vendor_ext = &phy_vendor_ext;
   p7_vnf->config->user_data = p7_vnf;
   p7_vnf->mac->user_data = p7_vnf;
@@ -1507,7 +1505,6 @@ void configure_nr_nfapi_vnf(char *vnf_addr, int vnf_p5_port) {
   nfapi_vnf_config_t *config = nfapi_vnf_config_create();
   config->malloc = malloc;
   config->free = free;
-  config->trace = &vnf_trace;
   config->vnf_p5_port = vnf_p5_port;
   config->vnf_ipv4 = 1;
   config->vnf_ipv6 = 0;
@@ -1558,7 +1555,6 @@ void configure_nfapi_vnf(char *vnf_addr, int vnf_p5_port) {
   nfapi_vnf_config_t *config = nfapi_vnf_config_create();
   config->malloc = malloc;
   config->free = free;
-  config->trace = &vnf_trace;
   config->vnf_p5_port = vnf_p5_port;
   config->vnf_ipv4 = 1;
   config->vnf_ipv6 = 0;
diff --git a/nfapi/open-nFAPI/common/public_inc/debug.h b/nfapi/open-nFAPI/common/public_inc/debug.h
index 14f97a17f6f8fbe23bd2e3e414b51baaa90f4714..574b09730100b0b54bedb3f454aeeced9f065397 100644
--- a/nfapi/open-nFAPI/common/public_inc/debug.h
+++ b/nfapi/open-nFAPI/common/public_inc/debug.h
@@ -14,38 +14,31 @@
  * limitations under the License.
  */
 
+#pragma once
 
-#ifndef _DEBUG_H_
-#define _DEBUG_H_
+#include <string.h>
+#include <errno.h>
+
+#define ERR strerror(errno)
 
 /*! The trace levels used by the nfapi libraries */
 typedef enum nfapi_trace_level
 {
-	NFAPI_TRACE_ERROR = 1,
-	NFAPI_TRACE_WARN,
-	NFAPI_TRACE_NOTE,
-	NFAPI_TRACE_INFO,
-
-	NFAPI_TRACE_LEVEL_MAX
+    NFAPI_TRACE_NONE,
+    NFAPI_TRACE_ERROR,
+    NFAPI_TRACE_WARN,
+    NFAPI_TRACE_NOTE,
+    NFAPI_TRACE_INFO,
+    NFAPI_TRACE_DEBUG,
 } nfapi_trace_level_t;
 
-/*! The trace function pointer */
-typedef void (*nfapi_trace_fn_t)(nfapi_trace_level_t level, const char* format, ...);
-
-/*! Global trace function */
-extern nfapi_trace_fn_t nfapi_trace_g;
+void nfapi_trace(nfapi_trace_level_t, char const *caller, const char *format, ...)
+    __attribute__((format(printf, 3, 4)));
 
-/*! Global trace level */
-extern nfapi_trace_level_t nfapi_trace_level_g;
-
-/*! NFAPI trace macro */
-//#define NFAPI_TRACE(level, format, ...) { if(nfapi_trace_g && ((nfapi_trace_level_t)level <= nfapi_trace_level_g)) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); }
-#define NFAPI_TRACE(level, format, ...) { if (nfapi_trace_g) (*nfapi_trace_g)(level, format, ##__VA_ARGS__); }
-
-/*! Function to change the trace level 
- * \param new_level The modified trace level
- */
+nfapi_trace_level_t nfapi_trace_level(void);
 
-void nfapi_set_trace_level(nfapi_trace_level_t new_level);
+#define NFAPI_TRACE(LEVEL, FORMAT, ...) do {                            \
+    if (nfapi_trace_level() >= (LEVEL))                                 \
+        nfapi_trace(LEVEL, __func__, FORMAT, ##__VA_ARGS__);            \
+} while (0)
 
-#endif /* _DEBUG_H_ */
diff --git a/nfapi/open-nFAPI/common/src/debug.c b/nfapi/open-nFAPI/common/src/debug.c
index 1efe75405d4bbbcd1bbea6636933b282c83fb781..628e64d9473b103815ac0b8f2eab14f1faa92384 100644
--- a/nfapi/open-nFAPI/common/src/debug.c
+++ b/nfapi/open-nFAPI/common/src/debug.c
@@ -14,53 +14,74 @@
  * limitations under the License.
  */
 
-
+#include "debug.h"
 #include <stdio.h>
 #include <stdarg.h>
-#include <stdint.h>
 #include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/types.h>
+#include <time.h>
 #include <pthread.h>
-#include <syslog.h>
-
-#include <debug.h>
-
-#define MAX_MSG_LENGTH 			2096
-#define TRACE_HEADER_LENGTH		44
+#include <stdbool.h>
 
-void nfapi_trace_dbg(nfapi_trace_level_t level, const char *format, ...);
+static nfapi_trace_level_t trace_level = NFAPI_TRACE_WARN;
 
-// initialize the trace function to 0
-void (*nfapi_trace_g)(nfapi_trace_level_t level, const char* format, ...) = &nfapi_trace_dbg;
+static void nfapi_trace_init(void)
+{
+    static bool initialized;
+    if (initialized)
+        return;
+    initialized = true;
 
-nfapi_trace_level_t nfapi_trace_level_g = NFAPI_TRACE_ERROR;
-//nfapi_trace_level_t nfapi_trace_level_g = NFAPI_TRACE_WARN;
+    const char *env = getenv("NFAPI_TRACE_LEVEL");
+    if (!env)
+        return;
+    if (strcmp(env, "none") == 0)
+        trace_level = NFAPI_TRACE_NONE;
+    else if (strcmp(env, "error") == 0)
+        trace_level = NFAPI_TRACE_ERROR;
+    else if (strcmp(env, "warn") == 0)
+        trace_level = NFAPI_TRACE_WARN;
+    else if (strcmp(env, "note") == 0)
+        trace_level = NFAPI_TRACE_NOTE;
+    else if (strcmp(env, "info") == 0)
+        trace_level = NFAPI_TRACE_INFO;
+    else if (strcmp(env, "debug") == 0)
+        trace_level = NFAPI_TRACE_DEBUG;
+    else
+    {
+        nfapi_trace(NFAPI_TRACE_ERROR, __func__, "Invalid NFAPI_TRACE_LEVEL='%s'", env);
+        return;
+    }
+    nfapi_trace(trace_level, __func__, "NFAPI_TRACE_LEVEL='%s'", env);
+}
 
-void nfapi_set_trace_level(nfapi_trace_level_t new_level)
+nfapi_trace_level_t nfapi_trace_level()
 {
-	nfapi_trace_level_g = new_level;
+    nfapi_trace_init();
+    return trace_level;
 }
 
-void nfapi_trace_dbg(nfapi_trace_level_t level, const char *format, ...)
+void nfapi_trace(nfapi_trace_level_t level,
+                 char const *caller,
+                 char const *format, ...)
 {
-        if (level < nfapi_trace_level_g)
-                return;
-	char trace_buff[MAX_MSG_LENGTH + TRACE_HEADER_LENGTH];
-	va_list p_args;
-	struct timeval tv;
-	pthread_t tid = pthread_self();
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    printf("%ld%06ld [%c] %10u: %s: ",
+           ts.tv_sec,
+           ts.tv_nsec / 1000,
+           "XEWNID"[level], // NFAPI_TRACE_NONE, NFAPI_TRACE_ERROR, ...
+           (unsigned) pthread_self(),
+           caller);
+
+    va_list ap;
+    va_start(ap, format);
+    vprintf(format, ap);
+    va_end(ap);
 
-	(void)gettimeofday(&tv, NULL);
+    // Add a newline if the format string didn't have one
+    int len = strlen(format);
+    if (len == 0 || format[len - 1] != '\n')
+        putchar('\n');
 
-	snprintf(trace_buff, sizeof(trace_buff), "%04u.%06u: 0x%02x: %10u: ", ((uint32_t)tv.tv_sec) & 0x1FFF, (uint32_t)tv.tv_usec, (uint32_t)level, (uint32_t)tid);
-	int n = strlen(trace_buff);
-	va_start(p_args, format);
-	vsnprintf(trace_buff + n, sizeof(trace_buff) - n, format, p_args);
-	va_end(p_args);
-	fputs(trace_buff, stdout);
-	fflush(stdout);
+    fflush(stdout);
 }
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
index 0eb77a9d262d0c1a64c7d26bd9e0f718bfb69c6b..0273b13aa8f147489e1fb5ad15d9c4eab975f170 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/nfapi_interface.h
@@ -27,6 +27,8 @@
 #define NFAPI_PNF_PARAM_GENERAL_OUI_LENGTH 3
 #define NFAPI_MAX_NUM_RF_BANDS 16
 
+#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192
+
 // The following definition control the size of arrays used in the interface.
 // These may be changed if desired. They are used in the encoder to make sure 
 // that the user has not specified a 'count' larger than the max array, and also
diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi.c b/nfapi/open-nFAPI/nfapi/src/nfapi.c
index ba800c36348ca16dc50d91b0cf02d90ff692bdf2..55f678d806790744a6676e85d101f74f6d413c2c 100644
--- a/nfapi/open-nFAPI/nfapi/src/nfapi.c
+++ b/nfapi/open-nFAPI/nfapi/src/nfapi.c
@@ -729,7 +729,8 @@ int unpack_tlv_list(unpack_tlv_t unpack_fns[], uint16_t size, uint8_t **ppReadPa
 				// check if the length was right;
 				if(tl->length != (*ppReadPackedMsg - pStartOfValue))
 				{
-					NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %d\n", tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue));
+                                        NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %ld\n",
+                                                    tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue));
 				}
 			}
 		}
@@ -830,7 +831,8 @@ int unpack_p7_tlv_list(unpack_p7_tlv_t unpack_fns[], uint16_t size, uint8_t **pp
 				// check if the length was right;
 				if(tl->length != (*ppReadPackedMsg - pStartOfValue))
 				{
-					NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %d\n", tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue));
+					NFAPI_TRACE(NFAPI_TRACE_ERROR, "Warning tlv tag 0x%x length %d not equal to unpack %ld\n",
+                                                    tl->tag, tl->length, (*ppReadPackedMsg - pStartOfValue));
 				}
 			}
 		}
diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c
index b429e0a6ce586b1efd943e7f337464e7852e26a2..4c25bf96cf787c687eb4c3ad3839335d6d175bdb 100644
--- a/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c
+++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p4.c
@@ -31,7 +31,7 @@ static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd)
 {
 	if (msgEnd < msgHead)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %d, %d\n", msgHead, msgEnd);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "Error in pointers supplied %lu, %lu\n", msgHead, msgEnd);
 		return 0;
 	}
 
diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c
index 8aea9f590c91f8142884c0bcc8bd554780f9119d..820e0041ced729d7a1dcc364aec0ae969346d137 100644
--- a/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c
+++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p5.c
@@ -1217,7 +1217,7 @@ static uint32_t get_packed_msg_len(uintptr_t msgHead, uintptr_t msgEnd)
 {
 	if (msgEnd < msgHead)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "get_packed_msg_len: Error in pointers supplied %d, %d\n", msgHead, msgEnd);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "Error in pointers supplied %lu, %lu\n", msgHead, msgEnd);
 		return 0;
 	}
 
diff --git a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
index 4dfd58acea5d412b6b09b29d23626b58ee07fa2c..6b78cca0588e26cfa6f96a73c58dfb4ac8c81501 100755
--- a/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
+++ b/nfapi/open-nFAPI/nfapi/src/nfapi_p7.c
@@ -5771,7 +5771,7 @@ static uint8_t unpack_hi_dci0_request_body_value(void *tlv, uint8_t **ppReadPack
 		if(packedPduEnd > end)
 		{
 			// pdu end if past buffer end
-			NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s pdu size to big %d %d\n", __FUNCTION__, packedPduEnd, end);
+			NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s pdu size too big %s %s\n", __FUNCTION__, packedPduEnd, end);
 			return 0;
 		}
 
diff --git a/nfapi/open-nFAPI/pnf/inc/pnf.h b/nfapi/open-nFAPI/pnf/inc/pnf.h
index 2982caa5152250605104488f0826de655e877b3d..128b1c990ba60346eec17951c2aa8939bd36567d 100644
--- a/nfapi/open-nFAPI/pnf/inc/pnf.h
+++ b/nfapi/open-nFAPI/pnf/inc/pnf.h
@@ -18,8 +18,7 @@
 #ifndef _PNF_H_
 #define _PNF_H_
 
-#include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h"
-
+#include "nfapi_pnf_interface.h"
 
 typedef struct {
 
diff --git a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h
index 1e2e2fa21d25733a26ee24ffe4c1bd0381330db8..3b6d7747e306bb548631df10695606a87b72432a 100644
--- a/nfapi/open-nFAPI/pnf/inc/pnf_p7.h
+++ b/nfapi/open-nFAPI/pnf/inc/pnf_p7.h
@@ -25,8 +25,6 @@
 
 #include "nfapi_pnf_interface.h"
 
-#define NFAPI_MAX_PACKED_MESSAGE_SIZE 8192
-
 typedef struct {
 	uint16_t dl_conf_ontime;
 	uint16_t dl_tti_ontime;
diff --git a/nfapi/open-nFAPI/pnf/src/pnf.c b/nfapi/open-nFAPI/pnf/src/pnf.c
index 57b482e00651b4e326c170144806c02e739d3f33..b4158dbb40f6bec8c49126e789c2be8e262103d1 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf.c
@@ -1512,7 +1512,7 @@ void pnf_handle_vendor_extension(void* pRecvMsg, int recvMsgLen, pnf_t* pnf, uin
 
 			if(msg == 0)
 			{
-				NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n");
+				NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate vendor extention structure\n");
 				return;
 			}
 
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_interface.c
index 6c10029975955fb9863436a6f636809043562065..a53604640cfb12359d7c8aea02be85b8399f0dc9 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf_interface.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_interface.c
@@ -55,10 +55,6 @@ int nfapi_pnf_start(nfapi_pnf_config_t* config)
 	if(config == 0)
 		return -1;
 
-	// Make sure to set the defined trace function before using NFAPI_TRACE
-	if(config->trace)
-		nfapi_trace_g = config->trace;
-
 	NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
 
 	pnf_t* _this = (pnf_t*)(config);
@@ -89,10 +85,6 @@ int nfapi_nr_pnf_start(nfapi_pnf_config_t* config)
 	if(config == 0)
 		return -1;
 
-	// Make sure to set the defined trace function before using NFAPI_TRACE
-	if(config->trace)
-		nfapi_trace_g = config->trace;
-
 	NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
 
 	pnf_t* _this = (pnf_t*)(config);
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7.c b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
index 8ef0bc1952cf21e0d2fdfff5b37254bd21bb62b8..ee589498753db8768e65a5566d57237682aec0ad 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf_p7.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_p7.c
@@ -1642,7 +1642,7 @@ void pnf_handle_dl_tti_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7)
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_dl_tti_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_dl_tti_request structure\n");
 		return;
 	}
 	int unpack_result = nfapi_nr_p7_message_unpack(pRecvMsg, recvMsgLen, req, sizeof(nfapi_nr_dl_tti_request_t), &(pnf_p7->_public.codec_config));
@@ -1732,7 +1732,7 @@ void pnf_handle_dl_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_dl_config_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_dl_config_request structure\n");
 		return;
 	}
 
@@ -1823,7 +1823,7 @@ void pnf_handle_ul_tti_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7)
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_ul_tti_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_ul_tti_request structure\n");
 		return;
 	}
 
@@ -1896,7 +1896,7 @@ void pnf_handle_ul_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_ul_config_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_ul_config_request structure\n");
 		return;
 	}
 
@@ -1969,7 +1969,7 @@ void pnf_handle_ul_dci_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7)
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate nfapi_ul_dci_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_ul_dci_request structure\n");
 		return;
 	}
 
@@ -2040,7 +2040,7 @@ void pnf_handle_hi_dci0_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_hi_dci0_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_hi_dci0_request structure\n");
 		return;
 	}
 
@@ -2109,7 +2109,7 @@ void pnf_handle_tx_data_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_tx_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_tx_request structure\n");
 		return;
 	}
 
@@ -2189,7 +2189,7 @@ void pnf_handle_tx_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7)
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_tx_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_tx_request structure\n");
 		return;
 	}
 
@@ -2263,7 +2263,7 @@ void pnf_handle_lbt_dl_config_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t*
 
 	if(req == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to alloced nfapi_lbt_dl_config_request structure\n");
+		NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate nfapi_lbt_dl_config_request structure\n");
 		return;
 	}
 
@@ -2326,7 +2326,7 @@ void pnf_handle_p7_vendor_extension(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pn
 
 		if(msg == 0)
 		{
-			NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n");
+			NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate vendor extention structure\n");
 			return;
 		}
 
@@ -2350,7 +2350,7 @@ void pnf_handle_ue_release_request(void* pRecvMsg, int recvMsgLen, pnf_p7_t* pnf
     nfapi_ue_release_request_t* req = allocate_nfapi_ue_release_request(pnf_p7);
     if(req == NULL)
     {
-        NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s failed to alloced nfapi_ue_release_request structure\n");
+        NFAPI_TRACE(NFAPI_TRACE_ERROR, "failed to allocate nfapi_ue_release_request structure\n");
         return;
     }
 
@@ -2452,7 +2452,7 @@ uint32_t calculate_nr_t2(uint32_t now_time_hr, uint16_t sfn,uint16_t slot, uint3
         {
           static uint32_t prev_t2 = 0;
 
-          NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s(now_time_hr:%u sfn:%d slot:%d slot_start_time_Hr:%u) slot_time_us:%u t2:%u prev_t2:%u diff:%u\n",
+          NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s(now_time_hr:%u sfn to slot:%d slot_start_time_Hr:%u) slot_time_us:%u t2:%u prev_t2:%u diff:%u\n",
               __FUNCTION__,
               now_time_hr, NFAPI_SFNSLOT2DEC(sfn, slot), slot_start_time_hr,
               slot_time_us,
@@ -2729,7 +2729,7 @@ void pnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7,  ui
 	// validate the input params
 	if(pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, pnf_p7);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, pnf_p7);
 		return;
 	}
 
@@ -2835,7 +2835,7 @@ void pnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, pnf_p7_t* pnf_p7,
 	// validate the input params
 	if(pRecvMsg == NULL || recvMsgLen < 4 || pnf_p7 == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, pnf_p7);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "pnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, pnf_p7);
 		return;
 	}
 
@@ -2963,7 +2963,7 @@ void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time)
 
 			// read the segment
 			recvfrom_result = recvfrom(pnf_p7->p7_sock, pnf_p7->rx_message_buffer, pnf_p7->rx_message_buffer_size,
-									   MSG_DONTWAIT | MSG_TRUNC, (struct sockaddr*)&remote_addr, &remote_addr_size);
+                                                   MSG_DONTWAIT | MSG_TRUNC, (struct sockaddr*)&remote_addr, &remote_addr_size);
 
 		now_hr_time = pnf_get_current_time_hr(); //DJP - moved to here - get closer timestamp???
 
@@ -2971,8 +2971,8 @@ void pnf_nfapi_p7_read_dispatch_message(pnf_p7_t* pnf_p7, uint32_t now_hr_time)
 			{
 				if (recvfrom_result != header.message_length)
 				{
-					NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s(%d). Received unexpected number of bytes. %d != %d",
-								__FUNCTION__, __LINE__, recvfrom_result, header.message_length);
+					NFAPI_TRACE(NFAPI_TRACE_ERROR, "(%d) Received unexpected number of bytes. %d != %d",
+                                                    __LINE__, recvfrom_result, header.message_length);
 					break;
 				}
 				pnf_handle_p7_message(pnf_p7->rx_message_buffer, recvfrom_result, pnf_p7, now_hr_time);
diff --git a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
index 7635f39ed05aa87d0b020c1d5bb92830668cd57e..863016d9848b9d8131bc593db7e1d6822ce72abc 100644
--- a/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
+++ b/nfapi/open-nFAPI/pnf/src/pnf_p7_interface.c
@@ -64,10 +64,6 @@ int nfapi_pnf_p7_start(nfapi_pnf_p7_config_t* config)
 	if(config == 0)
 		return -1;
 
-	// Make sure to set the defined trace function before using NFAPI_TRACE
-	if(config->trace)
-		nfapi_trace_g = config->trace;
-
 	pnf_p7_t* _this = (pnf_p7_t*)(config);
 
 	NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
@@ -83,10 +79,6 @@ int nfapi_nr_pnf_p7_start(nfapi_pnf_p7_config_t* config)
 	if(config == 0)
 		return -1;
 
-	// Make sure to set the defined trace function before using NFAPI_TRACE
-	if(config->trace)
-		nfapi_trace_g = config->trace;
-
 	pnf_p7_t* _this = (pnf_p7_t*)(config);
 
 	NFAPI_TRACE(NFAPI_TRACE_INFO, "%s\n", __FUNCTION__);
diff --git a/nfapi/open-nFAPI/vnf/inc/vnf.h b/nfapi/open-nFAPI/vnf/inc/vnf.h
index e5a9c36b8537fe4fcd2dc00c0b127deee422c2ff..b16b842606dab220fc4c63e8c1f1786b2a4b491b 100644
--- a/nfapi/open-nFAPI/vnf/inc/vnf.h
+++ b/nfapi/open-nFAPI/vnf/inc/vnf.h
@@ -18,7 +18,6 @@
 #ifndef _VNF_H_
 #define _VNF_H_
 
-#include "pnf_p7.h"
 #include "nfapi_vnf_interface.h"
 
 typedef struct 
diff --git a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
index 217b396ef815bd622f952f2a4753985ca606e997..c3925512a9f5b458aa1dc69c465b734050f30b5d 100644
--- a/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
+++ b/nfapi/open-nFAPI/vnf/public_inc/nfapi_vnf_interface.h
@@ -84,8 +84,6 @@ typedef struct nfapi_vnf_config
 	void* (*malloc)(size_t size);
 	/*! A user define callback to override the default memory deallocation */
 	void (*free)(void*);
-	/*! A user define callback to handle trace from the pnf */
-	void (*trace)(nfapi_trace_level_t level, const char* message, ...);
 
 	/*! The port the VNF P5 SCTP connection listens on
 	 *
@@ -661,12 +659,6 @@ typedef struct nfapi_vnf_p7_config
 	 */
 	void (*free)(void*);
 
-	/*! A user define callback to handle trace from the pnf
-	 * \param level The trace level
-	 * \param message The trace string
-	 */
-	void (*trace)(nfapi_trace_level_t level, const char* message, ...);
-
 	/*! The port the vnf p7 will receive on */
 	int port;
 
diff --git a/nfapi/open-nFAPI/vnf/src/vnf.c b/nfapi/open-nFAPI/vnf/src/vnf.c
index 1d6b9717303434d2aa5be197aaa5315fae3edefa..e0431ced174fb9185319201fe748cd8e41b1f8fe 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf.c
@@ -85,7 +85,7 @@ void nfapi_vnf_pnf_list_add(nfapi_vnf_config_t* config, nfapi_vnf_pnf_info_t* no
 
 nfapi_vnf_pnf_info_t* nfapi_vnf_pnf_list_find(nfapi_vnf_config_t* config, int p5_idx)
 {
-	NFAPI_TRACE(NFAPI_TRACE_ERROR, "%s : config->pnf_list:%p\n", __FUNCTION__, config->pnf_list);
+	NFAPI_TRACE(NFAPI_TRACE_DEBUG, "config->pnf_list:%p\n", config->pnf_list);
 
 	nfapi_vnf_pnf_info_t* curr = config->pnf_list;
 	while(curr != 0)
@@ -1051,7 +1051,7 @@ void vnf_handle_vendor_extension(void* pRecvMsg, int recvMsgLen, nfapi_vnf_confi
 		}
 		else
 		{
-			NFAPI_TRACE(NFAPI_TRACE_INFO, "%s failed to allocate vendor extention structure\n");
+			NFAPI_TRACE(NFAPI_TRACE_INFO, "failed to allocate vendor extention structure\n");
 		}
 	}
 }
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_interface.c
index 6e9a5d795f8862a6dc79cb98cab437528c04c4d8..01d3423692bcc5d9674fb237b5516f96f6c055dd 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf_interface.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_interface.c
@@ -70,10 +70,6 @@ int nfapi_nr_vnf_start(nfapi_vnf_config_t* config)
 	if(config == 0)
 		return -1;
 
-	// Make sure to set the defined trace function before using NFAPI_TRACE
-	if(config->trace)
-		nfapi_trace_g = (nfapi_trace_fn_t)config->trace;
-
 	NFAPI_TRACE(NFAPI_TRACE_INFO, "%s()\n", __FUNCTION__);
 
 	int p5ListenSock, p5Sock; 
@@ -219,7 +215,7 @@ int nfapi_nr_vnf_start(nfapi_vnf_config_t* config)
 		initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS;  // number of output streams can be greater
 		if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0)
 		{
-			NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno)
+			NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno);
 			close(p5ListenSock);
 			return 0;
 		}
@@ -624,7 +620,7 @@ int nfapi_vnf_start(nfapi_vnf_config_t* config)
 		initMsg.sinit_max_instreams = 5; //MAX_SCTP_STREAMS;  // number of output streams can be greater
 		if (setsockopt(p5ListenSock, IPPROTO_SCTP, SCTP_INITMSG, &initMsg, sizeof(initMsg)) < 0)
 		{
-			NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno)
+			NFAPI_TRACE(NFAPI_TRACE_ERROR, "After setsockopt (SCTP_INITMSG) errno: %d\n", errno);
 			close(p5ListenSock);
 			return 0;
 		}
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7.c b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
index 5842f0139ccaf0a1fdcd7c3d695aeb94e44bd79e..f82c9abf5736e2e7b00947ebc89f945da021a7ba 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf_p7.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_p7.c
@@ -1165,7 +1165,7 @@ void vnf_handle_ul_node_sync(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
                   struct timespec ts;
                   clock_gettime(CLOCK_MONOTONIC, &ts);
 
-			NFAPI_TRACE(NFAPI_TRACE_INFO, "(%4d/%1d) %d.%d PNF to VNF phy_id:%2d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d(avg:%4d) offset(us):%8d filtered(us):%8d wrap[t1:%u t2:%u]\n",
+			NFAPI_TRACE(NFAPI_TRACE_INFO, "(%4d/%1d) %ld.%ld PNF to VNF phy_id:%2d (t1/2/3/4:%8u, %8u, %8u, %8u) txrx:%4u procT:%3u latency(us):%4d(avg:%4d) offset(us):%8d filtered(us):%8d wrap[t1:%u t2:%u]\n",
 					NFAPI_SFNSF2SFN(phy->sfn_sf), NFAPI_SFNSF2SF(phy->sfn_sf), ts.tv_sec, ts.tv_nsec, ind.header.phy_id,
 					ind.t1, ind.t2, ind.t3, t4, 
 					tx_2_rx, pnf_proc_time, latency, phy->average_latency, phy->sf_offset, phy->sf_offset_filtered,
@@ -2108,7 +2108,7 @@ void vnf_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
 	// validate the input params
 	if(pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, vnf_p7);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, vnf_p7);
 		return;
 	}
 
@@ -2226,7 +2226,7 @@ void vnf_nr_handle_p7_message(void *pRecvMsg, int recvMsgLen, vnf_p7_t* vnf_p7)
 	// validate the input params
 	if(pRecvMsg == NULL || recvMsgLen < 4 || vnf_p7 == NULL)
 	{
-		NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%d %d %d)\n", pRecvMsg, recvMsgLen, vnf_p7);
+		NFAPI_TRACE(NFAPI_TRACE_ERROR, "vnf_handle_p7_message: invalid input params (%p %d %p)\n", pRecvMsg, recvMsgLen, vnf_p7);
 		return;
 	}
 
diff --git a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
index 39d250becae7ab067b0d5ce14b8fc837f731b9f9..3777e02153a108a57965f7c99c6d4c8a6570117d 100644
--- a/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
+++ b/nfapi/open-nFAPI/vnf/src/vnf_p7_interface.c
@@ -175,7 +175,7 @@ int nfapi_nr_vnf_p7_start(nfapi_vnf_p7_config_t* config)
 //	sf_start = timespec_add(sf_start, sf_duration);
 	slot_start = timespec_add(slot_start, slot_duration);
 
-	NFAPI_TRACE(NFAPI_TRACE_INFO, "next slot will start at %d.%d\n", slot_start.tv_sec, slot_start.tv_nsec);
+	NFAPI_TRACE(NFAPI_TRACE_INFO, "next slot will start at %ld.%ld\n", slot_start.tv_sec, slot_start.tv_nsec);
 
 	while(vnf_p7->terminate == 0)
 	{
@@ -272,7 +272,7 @@ if (selectRetval==-1 && errno == 22)
 //  phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment,
 //  sf_duration.tv_sec, sf_duration.tv_nsec);
 
-NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%d.%ld adj[dur:%d adj:%d], sf_dur:%d.%ld\n",
+NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%ld.%ld adj[dur:%d adj:%d], sf_dur:%ld.%ld\n",
   pselect_timeout.tv_sec, pselect_timeout.tv_nsec,
   phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment,
   slot_duration.tv_sec, slot_duration.tv_nsec);
@@ -432,7 +432,7 @@ struct timespec current_time;
 			}
 			else
 			{
-				NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond);
+				NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%ld.%ld orginal:%ld.%ld last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond);
 				// should we exit now?
                                 if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration
                                 {
@@ -527,7 +527,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config)
 	clock_gettime(CLOCK_MONOTONIC, &sf_start);
 	long millisecond = sf_start.tv_nsec / 1e6;
 	sf_start = timespec_add(sf_start, sf_duration);
-	NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %d.%d\n", sf_start.tv_sec, sf_start.tv_nsec);
+	NFAPI_TRACE(NFAPI_TRACE_INFO, "next subframe will start at %ld.%ld\n", sf_start.tv_sec, sf_start.tv_nsec);
 
 	while(vnf_p7->terminate == 0)
 	{
@@ -617,7 +617,7 @@ int nfapi_vnf_p7_start(nfapi_vnf_p7_config_t* config)
 
 if (selectRetval==-1 && errno == 22)
 {
-  NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%d.%ld adj[dur:%d adj:%d], sf_dur:%d.%ld\n",
+  NFAPI_TRACE(NFAPI_TRACE_ERROR, "INVAL: pselect_timeout:%ld.%ld adj[dur:%d adj:%d], sf_dur:%ld.%ld\n",
   pselect_timeout.tv_sec, pselect_timeout.tv_nsec,
   phy->insync_minor_adjustment_duration, phy->insync_minor_adjustment,
   sf_duration.tv_sec, sf_duration.tv_nsec);
@@ -677,7 +677,7 @@ if (selectRetval==-1 && errno == 22)
 					//phy->insync_minor_adjustment = 0;
                                         phy->insync_minor_adjustment_duration--;
 
-                                        NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] AFTER adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%d duration:%u\n",
+                                        NFAPI_TRACE(NFAPI_TRACE_NOTE, "[VNF] AFTER adjustment - Subframe minor adjustment %dus sf_start.tv_nsec:%ld duration:%u\n",
                                             phy->insync_minor_adjustment, sf_start.tv_nsec, phy->insync_minor_adjustment_duration);
 
                                         if (phy->insync_minor_adjustment_duration==0)
@@ -749,7 +749,7 @@ if (selectRetval==-1 && errno == 22)
 			}
 			else
 			{
-				NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%d.%d orginal:%d.%d last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond);
+				NFAPI_TRACE(NFAPI_TRACE_INFO, "P7 select failed result %d errno %d timeout:%ld.%ld orginal:%ld.%ld last_ms:%ld ms:%ld\n", selectRetval, errno, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, pselect_timeout.tv_sec, pselect_timeout.tv_nsec, last_millisecond, millisecond);
 				// should we exit now?
                                 if (selectRetval == -1 && errno == 22) // invalid argument??? not sure about timeout duration
                                 {
diff --git a/openair1/PHY/LTE_TRANSPORT/dci_tools.c b/openair1/PHY/LTE_TRANSPORT/dci_tools.c
index 0d5d5ad3f1c6a339004320fe9c1d8f11d757e624..7b4e7821814150652ae1ce7c9a95cfca8e0d03ad 100644
--- a/openair1/PHY/LTE_TRANSPORT/dci_tools.c
+++ b/openair1/PHY/LTE_TRANSPORT/dci_tools.c
@@ -59,8 +59,10 @@ int16_t find_dlsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type) {
   AssertFatal(eNB!=NULL,"eNB is null\n");
 
   for (i=0; i<NUMBER_OF_UE_MAX; i++) {
-    AssertFatal(eNB->dlsch[i]!=NULL,"eNB->dlsch[%d] is null\n",i);
-    AssertFatal(eNB->dlsch[i]!=NULL,"eNB->dlsch[%d][0] is null\n",i);
+    if (eNB->dlsch[i]==NULL || eNB->dlsch[i][0]==NULL) {
+      LOG_W(PHY, "eNB->dlsch[%d] or eNB->dlsch[%d][0] is null.\n", i, i);
+      continue;
+    }
     LOG_D(PHY,"searching for rnti %x : UE index %d=> harq_mask %x, rnti %x, first_free_index %d\n", rnti,i,eNB->dlsch[i][0]->harq_mask,eNB->dlsch[i][0]->rnti,first_free_index);
 
     if ((eNB->dlsch[i][0]->harq_mask >0) &&
@@ -84,8 +86,10 @@ int16_t find_ulsch(uint16_t rnti, PHY_VARS_eNB *eNB,find_type_t type) {
   AssertFatal(eNB!=NULL,"eNB is null\n");
 
   for (i=0; i<NUMBER_OF_UE_MAX; i++) {
-    if (eNB->ulsch[i] == NULL)
+    if (eNB->ulsch[i] == NULL) {
+      LOG_W(PHY, "eNB->ulsch[%d] is null.\n", i);
       continue;
+    }
 
     if ((eNB->ulsch[i]->harq_mask >0) &&
         (eNB->ulsch[i]->rnti==rnti))       return i;
diff --git a/openair2/COMMON/pdcp_messages_def.h b/openair2/COMMON/pdcp_messages_def.h
index b148ae0e1f79174b4dc2ad3ca4e8339e1fbfc43a..de9e021e76699866d37072d6207f5b92d3db6a5e 100644
--- a/openair2/COMMON/pdcp_messages_def.h
+++ b/openair2/COMMON/pdcp_messages_def.h
@@ -31,6 +31,7 @@
 MESSAGE_DEF(RRC_DCCH_DATA_REQ,          MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataReq,              rrc_dcch_data_req)
 MESSAGE_DEF(RRC_DCCH_DATA_IND,          MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd,              rrc_dcch_data_ind)
 MESSAGE_DEF(RRC_PCCH_DATA_REQ,          MESSAGE_PRIORITY_MED_PLUS, RrcPcchDataReq,              rrc_pcch_data_req)
+MESSAGE_DEF(RRC_DCCH_DATA_COPY_IND,     MESSAGE_PRIORITY_MED_PLUS, RrcDcchDataInd,         rrc_dcch_data_copy_ind)
 
 // gNB
 MESSAGE_DEF(NR_RRC_DCCH_DATA_IND,       MESSAGE_PRIORITY_MED_PLUS, NRRrcDcchDataInd,           nr_rrc_dcch_data_ind)
diff --git a/openair2/COMMON/pdcp_messages_types.h b/openair2/COMMON/pdcp_messages_types.h
index daf8ba7cac9eb8b0175d4298da3e361db7694954..8c27af61c447fe0a54eb6f7f9a046266c33295a0 100644
--- a/openair2/COMMON/pdcp_messages_types.h
+++ b/openair2/COMMON/pdcp_messages_types.h
@@ -34,6 +34,7 @@
 #define RRC_DCCH_DATA_REQ(mSGpTR)               (mSGpTR)->ittiMsg.rrc_dcch_data_req
 #define RRC_DCCH_DATA_IND(mSGpTR)               (mSGpTR)->ittiMsg.rrc_dcch_data_ind
 #define RRC_PCCH_DATA_REQ(mSGpTR)               (mSGpTR)->ittiMsg.rrc_pcch_data_req
+#define RRC_DCCH_DATA_COPY_IND(mSGpTR)          (mSGpTR)->ittiMsg.rrc_dcch_data_copy_ind
 
 // gNB
 #define NR_RRC_DCCH_DATA_IND(mSGpTR)            (mSGpTR)->ittiMsg.nr_rrc_dcch_data_ind
@@ -64,6 +65,13 @@ typedef struct RrcDcchDataInd_s {
   uint8_t      eNB_index; // LG: needed in UE
 } RrcDcchDataInd;
 
+typedef struct RrcDcchDataCopyInd_s {
+  uint8_t dcch_index;
+  uint32_t sdu_size;
+  uint8_t *sdu_p;
+  uint8_t      eNB_index;
+} RrcDcchDataCopyInd;
+
 typedef struct NRRrcDcchDataInd_s {
   uint32_t frame;
   uint8_t dcch_index;
diff --git a/openair2/COMMON/platform_types.h b/openair2/COMMON/platform_types.h
index d425b9e7d7a895eb8696db1b51b7ddfb8f2c47e0..f83de63b33a058e4cf99ca2741d3e0247e15151a 100644
--- a/openair2/COMMON/platform_types.h
+++ b/openair2/COMMON/platform_types.h
@@ -220,6 +220,14 @@ typedef enum config_action_e {
   CONFIG_ACTION_MBMS_MODIFY       = 11
 } config_action_t;
 
+/* Maximum size of any message we might send or receive (e.g., via a socket) */
+#define MAX_MESSAGE_SIZE 8192
+
+typedef struct nsa_msg_t {
+  uint8_t msg_type;
+  uint8_t msg_buffer[MAX_MESSAGE_SIZE];
+} nsa_msg_t;
+
 //-----------------------------------------------------------------------------
 // GTPV1U TYPES
 //-----------------------------------------------------------------------------
diff --git a/openair2/COMMON/tasks_def.h b/openair2/COMMON/tasks_def.h
index 33b6d5f9d4670223009230f876405917050c3e2c..bb913db98878c91c5984f92cd914979cfe8cb6c2 100644
--- a/openair2/COMMON/tasks_def.h
+++ b/openair2/COMMON/tasks_def.h
@@ -75,6 +75,8 @@ TASK_DEF(TASK_PROTO_AGENT,  TASK_PRIORITY_MED,          200)
 ///   Radio Resource Control task
 TASK_DEF(TASK_RRC_UE,   TASK_PRIORITY_MED,          200)
 TASK_DEF(TASK_RRC_NRUE,   TASK_PRIORITY_MED,          200)
+TASK_DEF(TASK_RRC_NSA_NRUE,   TASK_PRIORITY_MED,          200)
+TASK_DEF(TASK_RRC_NSA_UE,   TASK_PRIORITY_MED,          200)
 ///   Non Access Stratum task
 TASK_DEF(TASK_NAS_UE,   TASK_PRIORITY_MED,          200)
 TASK_DEF(TASK_RAL_UE,   TASK_PRIORITY_MED,          200)
diff --git a/openair2/LAYER2/MAC/ra_procedures.c b/openair2/LAYER2/MAC/ra_procedures.c
index 237560917a34fe3f73c3c7cfbef44fcf5e44a3d5..abb67aa5e7802816bd15aa7a65aa61b977f5f50e 100644
--- a/openair2/LAYER2/MAC/ra_procedures.c
+++ b/openair2/LAYER2/MAC/ra_procedures.c
@@ -287,7 +287,7 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id,
                                sub_frame_t subframeP) {
   uint8_t Size = 0;
   UE_MODE_t UE_mode;
-
+  protocol_ctxt_t ctxt;
   // Modification for phy_stub_ue operation
   if(NFAPI_MODE == NFAPI_UE_STUB_PNF || NFAPI_MODE == NFAPI_MODE_STANDALONE_PNF) { // phy_stub_ue mode
     UE_mode = UE_mac_inst[module_idP].UE_mode[0];
@@ -320,6 +320,19 @@ PRACH_RESOURCES_t *ue_get_rach(module_id_t module_idP, int CC_id,
 
     if (UE_mac_inst[module_idP].RA_active == 0) {
       LOG_I(MAC, "RA not active\n");
+
+      if (UE_rrc_inst[ctxt.module_id].Info[eNB_indexP].T300_cnt
+          != T300[UE_rrc_inst[ctxt.module_id].sib2[eNB_indexP]->ue_TimersAndConstants.t300]) {
+            /* Calling rrc_ue_generate_RRCConnectionRequest here to ensure that
+               every time we fill the UE_mac_inst context we generate new random
+               values in msg3. When the T300 timer has expired, rrc_common.c will
+               call rrc_ue_generate_RRCConnectionRequest, so we do not want to call
+               when UE_rrc_inst[ctxt.module_id].Info[eNB_indexP].T300_cnt ==
+               T300[UE_rrc_inst[ctxt.module_id].sib2[eNB_indexP]->ue_TimersAndConstants.t300. */
+            UE_rrc_inst[ctxt.module_id].Srb0[eNB_indexP].Tx_buffer.payload_size = 0;
+            rrc_ue_generate_RRCConnectionRequest(&ctxt, eNB_indexP);
+      }
+
       // check if RRC is ready to initiate the RA procedure
       Size = mac_rrc_data_req_ue(module_idP,
                                  CC_id,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
index 4ada9eb9f3a5f70184f3f8a5cf69440867bf1a98..2bafdd70ebfe3a52ba039a07e097b52ecbd978c3 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler.c
@@ -306,8 +306,6 @@ bool is_xlsch_in_slot(uint64_t bitmap, sub_frame_t slot) {
 void gNB_dlsch_ulsch_scheduler(module_id_t module_idP,
                                frame_t frame,
                                sub_frame_t slot){
-  gNB_MAC_INST     *mac        = RC.nrmac[module_idP];
-  nfapi_nr_config_request_scf_t *cfg = &mac->config[0];
   protocol_ctxt_t   ctxt;
   PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, module_idP, ENB_FLAG_YES, NOT_A_RNTI, frame, slot,module_idP);
   int nb_periods_per_frame;
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index 3ae3707962c7e9434dd735427d84d1db592134ba..7c4ab693058368b425cb844a6727b12938459ac7 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -336,7 +336,7 @@ void handle_nr_uci_pucch_0_1(module_id_t mod_id,
 
   // NR_ServingCellConfigCommon_t *scc = RC.nrmac[mod_id]->common_channels->ServingCellConfigCommon;
   // const int num_slots = nr_slots_per_frame[*scc->ssbSubcarrierSpacing];
-  const int num_slots = 20;
+  //const int num_slots = 20;
   
   // if (((uci_01->pduBitmap >> 1) & 0x01)) {
   //   // iterate over received harq bits
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
index 98c25e4228daa665aa5c626bcc894660e263e749..684ef89be58a9bb95170c4e6917a63596092eb86 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h
@@ -44,7 +44,6 @@
 #include "LTE_SRB-ToAddModList.h"
 #include "LTE_MBMS-SessionInfoList-r9.h"
 #include "LTE_PMCH-InfoList-r9.h"
-#include "common/utils/ocp_itti/intertask_interface.h"
 
 typedef rlc_op_status_t  (*send_rlc_data_req_func_t)(const protocol_ctxt_t *const,
     const srb_flag_t, const MBMS_flag_t,
diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
index 27973576ab87ad073c6038dc6075053c1504a2f0..1703e00d6f4d764e18abfda9226449a3c4c22932 100644
--- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
+++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_fifo.c
@@ -658,19 +658,17 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const  ctxt_pP)
   /* avoid gcc warnings */
   (void)data_p;
   pdcp_t                        *pdcp_p    = NULL;
-  //TTN for D2D (PC5S)
-  int prose_addr_len = sizeof(prose_pdcp_addr);
-  char send_buf[BUFSIZE], receive_buf[BUFSIZE];
-  //int optval;
   int bytes_received;
   sidelink_pc5s_element *sl_pc5s_msg_send = NULL;
   pc5s_header_t *pc5s_header = NULL;
   rb_id_t          rab_id  = 0;
   //TTN for D2D (PC5S)
   // receive a message from ProSe App
-  memset(receive_buf, 0, BUFSIZE);
-  bytes_received = recvfrom(pdcp_pc5_sockfd, receive_buf, BUFSIZE, MSG_TRUNC,
-                            (struct sockaddr *) &prose_pdcp_addr, (socklen_t *)&prose_addr_len);
+  char receive_buf[MAX_MESSAGE_SIZE];
+  memset(receive_buf, 0, sizeof(receive_buf));
+  socklen_t prose_addr_len = sizeof(prose_pdcp_addr);
+  bytes_received = recvfrom(pdcp_pc5_sockfd, receive_buf, sizeof(receive_buf), MSG_TRUNC,
+                            (struct sockaddr *) &prose_pdcp_addr, &prose_addr_len);
   if (bytes_received == -1) {
     LOG_E(PDCP, "%s(%d). recvfrom failed. %s\n", __FUNCTION__, __LINE__, strerror(errno));
     return;
@@ -678,7 +676,7 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const  ctxt_pP)
   if (bytes_received == 0) {
     LOG_E(PDCP, "%s(%d). EOF pdcp_pc5_sockfd.\n", __FUNCTION__, __LINE__);
   }
-  if (bytes_received > BUFSIZE) {
+  if (bytes_received > sizeof(receive_buf)) {
     LOG_E(PDCP, "%s(%d). Message truncated. %d\n", __FUNCTION__, __LINE__, bytes_received);
     return;
   }
@@ -686,17 +684,19 @@ void pdcp_fifo_read_input_sdus_frompc5s (const protocol_ctxt_t *const  ctxt_pP)
     pc5s_header = calloc(1, sizeof(pc5s_header_t));
     memcpy((void *)pc5s_header, (void *)receive_buf, sizeof(pc5s_header_t));
 
+    char send_buf[MAX_MESSAGE_SIZE];
     switch(pc5s_header->traffic_type) {
       case TRAFFIC_PC5S_SESSION_INIT :
         //send reply to ProSe app
         LOG_D(PDCP,"Received a request to open PDCP socket and establish a new PDCP session ... send response to ProSe App \n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, sizeof(send_buf));
         sl_pc5s_msg_send = calloc(1, sizeof(sidelink_pc5s_element));
         sl_pc5s_msg_send->pc5s_header.traffic_type = TRAFFIC_PC5S_SESSION_INIT;
         sl_pc5s_msg_send->pc5sPrimitive.status = 1;
-        memcpy((void *)send_buf, (void *)sl_pc5s_msg_send, sizeof(sidelink_pc5s_element));
+        memcpy(send_buf, sl_pc5s_msg_send, sizeof(sidelink_pc5s_element));
         int prose_addr_len = sizeof(prose_pdcp_addr);
-        int bytes_sent = sendto(pdcp_pc5_sockfd, (char *)send_buf, sizeof(sidelink_pc5s_element), 0, (struct sockaddr *)&prose_pdcp_addr, prose_addr_len);
+        int bytes_sent = sendto(pdcp_pc5_sockfd, send_buf, sizeof(sidelink_pc5s_element), 0,
+                                (struct sockaddr *) &prose_pdcp_addr, prose_addr_len);
         free (sl_pc5s_msg_send);
 
         if (bytes_sent < 0) {
diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
index fdb38e0c9c32948d896fa42f12f9bb853009196e..24c853dc8884ce5e1b2fea029952d7c9632e83b0 100644
--- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
+++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c
@@ -377,11 +377,14 @@ uint64_t pdcp_module_init(uint64_t _pdcp_optmask, int id)
     nas_getparams();
 
     if(UE_NAS_USE_TUN) {
+      /* TODO: Brute force changes made below to allow nr-UE to have unique tunnel interfaces.
+         When the NODE_NUMBER param is not used to determine functionality and LTE tunnel
+         interfaces, we should update the netlink_init_tun() and nas_config() calls below as well. */
       int num_if = (NFAPI_MODE == NFAPI_UE_STUB_PNF || IS_SOFTMODEM_SIML1 )? MAX_MOBILES_PER_ENB : 1;
-      netlink_init_tun("ue", num_if, id);
+      netlink_init_tun("nrue", num_if, id);
       //Add --nr-ip-over-lte option check for next line
       if (IS_SOFTMODEM_NOS1)
-          nas_config(1, 1, 2, "ue");
+          nas_config(1, 1, 3, "nrue");
       LOG_I(PDCP, "UE pdcp will use tun interface\n");
       start_pdcp_tun_ue();
     } else if(ENB_NAS_USE_TUN) {
diff --git a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
index 7b249da14c653d9e508ce5afc38dfc23deb91f24..03ea436b407fb3753b54f766a681f29cff921499 100644
--- a/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_PHY_INTERFACE/NR_IF_Module.c
@@ -182,7 +182,6 @@ void NR_UL_indication(NR_UL_IND_t *UL_info) {
   NR_Sched_Rsp_t   *sched_info = &Sched_INFO[module_id][CC_id];
   NR_IF_Module_t   *ifi        = if_inst[module_id];
   gNB_MAC_INST     *mac        = RC.nrmac[module_id];
-  nfapi_nr_config_request_scf_t *cfg = &mac->config[CC_id];
   LOG_D(PHY,"SFN/SF:%d%d module_id:%d CC_id:%d UL_info[rach_pdus:%d rx_ind:%d crcs:%d]\n",
         UL_info->frame,UL_info->slot,
         module_id,CC_id, UL_info->rach_ind.number_of_pdus,
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.c b/openair2/PHY_INTERFACE/phy_stub_UE.c
index d1e9b047fbd4fed4f317df1ba08dd890acde328c..48e302d335b1c984ab45cb20acd4c940b63ac69c 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.c
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.c
@@ -72,6 +72,7 @@ extern nfapi_tx_request_pdu_t* tx_request_pdu[1023][NUM_NFAPI_SUBFRAME][10]; //T
 //extern int timer_subframe;
 //extern int timer_frame;
 
+extern UE_RRC_INST *UE_rrc_inst;
 extern uint16_t sf_ahead;
 
 void Msg1_transmitted(module_id_t module_idP,uint8_t CC_id,frame_t frameP, uint8_t eNB_id);
@@ -1301,26 +1302,6 @@ void *ue_standalone_pnf_task(void *context)
         abort();
       }
     }
-    else if (len == sizeof(channel_info))
-    {
-      channel_info * ch_info = malloc(sizeof(channel_info));
-
-      memcpy(ch_info, buffer, sizeof(channel_info));
-      current_sfn_sf = ch_info->sfn_sf;
-      if (sem_post(&sfn_semaphore) != 0)
-      {
-        LOG_E(MAC, "sem_post() error\n");
-        abort();
-      }
-        uint16_t sf = ch_info->sfn_sf & 15;
-        if(sf > 10 && sf < 0)
-        {
-          LOG_E(MAC, "sf out of bounds, sfn: %d\n", sf);
-          abort();
-        }
-        sf_rnti_mcs[sf].sinr = ch_info->sinr;
-        LOG_D(MAC, "Received_SINR = %f\n",ch_info->sinr);
-    }
     else if (len == sizeof(phy_channel_params_t))
     {
       phy_channel_params_t ch_info;
@@ -1333,6 +1314,9 @@ void *ue_standalone_pnf_task(void *context)
       }
       uint16_t sf = ch_info.sfn_sf & 15;
       assert(sf < 10);
+
+      sf_rnti_mcs[sf].sinr = ch_info.sinr;
+      LOG_D(MAC, "Received_SINR = %f\n",ch_info.sinr);
     }
     else
     {
@@ -2075,8 +2059,30 @@ static float get_bler_val(uint8_t mcs, int sinr)
 
 }
 
+static inline bool is_channel_modeling(void)
+{
+  /* TODO: For now we enable channel modeling based on the node_number.
+     Replace with a command line option to enable/disable channel modeling. */
+  return node_number == 0;
+}
+
 static bool should_drop_transport_block(int sf, uint16_t rnti)
 {
+  if (!is_channel_modeling())
+  {
+    return false;
+  }
+
+  /* We want to avoid dropping setup messages because this would be pathological.
+     This assumes were in standalone_pnf mode where
+     UE_rrc_inst[0] is module_id = 0 and Info[0] is eNB_index = 0. */
+  UE_STATE_t state = UE_rrc_inst[0].Info[0].State;
+  if (state < RRC_CONNECTED)
+  {
+    LOG_I(MAC, "Not dropping because state: %d", state);
+    return false;
+  }
+
   /* Get block error rate (bler_val) from table based on every saved
      MCS and SINR to be used as the cutoff rate for dropping packets.
      Generate random uniform vairable to compare against bler_val. */
diff --git a/openair2/PHY_INTERFACE/phy_stub_UE.h b/openair2/PHY_INTERFACE/phy_stub_UE.h
index c590d15cab2db0869c9bf0f52c99a8d77cc9531b..c60f6d258dc453b36d17f7d69cdbbc162423d221 100644
--- a/openair2/PHY_INTERFACE/phy_stub_UE.h
+++ b/openair2/PHY_INTERFACE/phy_stub_UE.h
@@ -19,7 +19,6 @@
 //#include "openair1/PHY/LTE_TRANSPORT/defs.h"
 //#include "openair1/PHY/defs.h"
 //#include "openair1/PHY/LTE_TRANSPORT/defs.h"
-#include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h"
 #include "queue.h"
 
 #define NUM_MCS 28
@@ -41,13 +40,6 @@ eth_params_t         stub_eth_params;
 
 typedef struct
 {
-    uint16_t sfn_sf;
-    float sinr;
-    // Incomplete, need all channel parameters
-} channel_info;
-
-typedef struct 
-{   
     uint8_t sf;
     uint16_t rnti[256];
     uint8_t mcs[256];
diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.c b/openair2/RRC/LTE/MESSAGES/asn1_msg.c
index 61bce26b2c1cc2d006ad67bcba98b06630f3ef16..64018729ecc43171c2d1715bc6d4d632adfe61ef 100644
--- a/openair2/RRC/LTE/MESSAGES/asn1_msg.c
+++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.c
@@ -4374,7 +4374,161 @@ int do_HandoverCommand(char *ho_buf, int ho_size, char *rrc_buf, int rrc_size) {
   return((enc_rval.encoded+7)/8);
 }
 
-OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) {
+//-----------------------------------------------------------------------------
+int
+is_en_dc_supported(
+  LTE_UE_EUTRA_Capability_t *c
+)
+//-----------------------------------------------------------------------------
+{
+  LOG_D(RRC, "Entered %s \n", __FUNCTION__);
+  /* to be refined - check that the bands supported by the UE include
+   * the band of the gNB
+   */
+#define NCE nonCriticalExtension
+  return c != NULL
+         && c->NCE != NULL
+         && c->NCE->NCE != NULL
+         && c->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15 != NULL
+         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 != NULL
+         && *c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 ==
+         LTE_IRAT_ParametersNR_r15__en_DC_r15_supported;
+#undef NCE
+}
+
+void allocate_en_DC_r15(LTE_UE_EUTRA_Capability_t *cap)
+{
+  LOG_D(RRC, "Entered %s\n", __FUNCTION__);
+  if (!cap->nonCriticalExtension)
+    cap->nonCriticalExtension = CALLOC(1, sizeof(*cap->nonCriticalExtension));
+
+  typeof(cap->nonCriticalExtension) nce1 = cap->nonCriticalExtension;
+  if (!nce1->nonCriticalExtension)
+    nce1->nonCriticalExtension = CALLOC(1, sizeof(*nce1->nonCriticalExtension));
+
+  typeof(nce1->nonCriticalExtension) nce2 = nce1->nonCriticalExtension;
+  if (!nce2->nonCriticalExtension)
+    nce2->nonCriticalExtension = CALLOC(1, sizeof(*nce2->nonCriticalExtension));
+
+  typeof(nce2->nonCriticalExtension) nce3 = nce2->nonCriticalExtension;
+  if (!nce3->nonCriticalExtension)
+    nce3->nonCriticalExtension = CALLOC(1, sizeof(*nce3->nonCriticalExtension));
+
+  typeof(nce3->nonCriticalExtension) nce4 = nce3->nonCriticalExtension;
+  if (!nce4->nonCriticalExtension)
+    nce4->nonCriticalExtension = CALLOC(1, sizeof(*nce4->nonCriticalExtension));
+
+  typeof(nce4->nonCriticalExtension) nce5 = nce4->nonCriticalExtension;
+  if (!nce5->nonCriticalExtension)
+    nce5->nonCriticalExtension = CALLOC(1, sizeof(*nce5->nonCriticalExtension));
+
+  typeof(nce5->nonCriticalExtension) nce6 = nce5->nonCriticalExtension;
+  if (!nce6->nonCriticalExtension)
+    nce6->nonCriticalExtension = CALLOC(1, sizeof(*nce6->nonCriticalExtension));
+
+  typeof(nce6->nonCriticalExtension) nce7 = nce6->nonCriticalExtension;
+  if (!nce7->nonCriticalExtension)
+    nce7->nonCriticalExtension = CALLOC(1, sizeof(*nce7->nonCriticalExtension));
+
+  typeof(nce7->nonCriticalExtension) nce8 = nce7->nonCriticalExtension;
+  if (!nce8->nonCriticalExtension)
+    nce8->nonCriticalExtension = CALLOC(1, sizeof(*nce8->nonCriticalExtension));
+
+  typeof(nce8->nonCriticalExtension) nce9 = nce8->nonCriticalExtension;
+  if (!nce9->nonCriticalExtension)
+    nce9->nonCriticalExtension = CALLOC(1, sizeof(*nce9->nonCriticalExtension));
+
+  typeof(nce9->nonCriticalExtension) nce10 = nce9->nonCriticalExtension;
+  if (!nce10->nonCriticalExtension)
+    nce10->nonCriticalExtension = CALLOC(1, sizeof(*nce10->nonCriticalExtension));
+
+  typeof(nce10->nonCriticalExtension) nce11 = nce10->nonCriticalExtension;
+  if (!nce11->nonCriticalExtension)
+    nce11->nonCriticalExtension = CALLOC(1, sizeof(*nce11->nonCriticalExtension));
+
+  typeof(nce11->nonCriticalExtension) nce12 = nce11->nonCriticalExtension;
+  if (!nce12->nonCriticalExtension)
+    nce12->nonCriticalExtension = CALLOC(1, sizeof(*nce12->nonCriticalExtension));
+
+  typeof(nce12->nonCriticalExtension) nce13 = nce12->nonCriticalExtension;
+  if (!nce13->nonCriticalExtension)
+    nce13->nonCriticalExtension = CALLOC(1, sizeof(*nce13->nonCriticalExtension));
+
+  typeof(nce13->nonCriticalExtension) nce14 = nce13->nonCriticalExtension;
+  if (!nce14->nonCriticalExtension)
+    nce14->nonCriticalExtension = CALLOC(1, sizeof(*nce14->nonCriticalExtension));
+
+  typeof(nce14->nonCriticalExtension) nce15 = nce14->nonCriticalExtension;
+  if (!nce15->nonCriticalExtension)
+    nce15->nonCriticalExtension = CALLOC(1, sizeof(*nce15->nonCriticalExtension));
+
+  typeof(nce15->nonCriticalExtension) nce16 = nce15->nonCriticalExtension;
+  if (!nce16->nonCriticalExtension)
+    nce16->nonCriticalExtension = CALLOC(1, sizeof(*nce16->nonCriticalExtension));
+
+  typeof(nce16->nonCriticalExtension) nce17 = nce16->nonCriticalExtension;
+  if (!nce17->nonCriticalExtension)
+    nce17->nonCriticalExtension = CALLOC(1, sizeof(*nce17->nonCriticalExtension));
+
+  typeof(nce17->nonCriticalExtension) nce18 = nce17->nonCriticalExtension;
+  if (!nce18->nonCriticalExtension)
+    nce18->nonCriticalExtension = CALLOC(1, sizeof(*nce18->nonCriticalExtension));
+
+  typeof(nce18->nonCriticalExtension) nce19 = nce18->nonCriticalExtension;
+  if (!nce19->nonCriticalExtension)
+    nce19->nonCriticalExtension = CALLOC(1, sizeof(*nce19->nonCriticalExtension));
+
+  typeof(nce19->nonCriticalExtension) nce20 = nce19->nonCriticalExtension;
+  if (!nce20->nonCriticalExtension)
+    nce20->nonCriticalExtension = CALLOC(1, sizeof(*nce20->nonCriticalExtension));
+
+  typeof(nce20->nonCriticalExtension) nce21 = nce20->nonCriticalExtension;
+  if (!nce21->nonCriticalExtension)
+    nce21->nonCriticalExtension = CALLOC(1, sizeof(*nce21->nonCriticalExtension));
+
+  typeof(nce21->nonCriticalExtension) nce22 = nce21->nonCriticalExtension;
+  if (!nce22->nonCriticalExtension)
+    nce22->nonCriticalExtension = CALLOC(1, sizeof(*nce22->nonCriticalExtension));
+
+  typeof(nce22->nonCriticalExtension) nce23 = nce22->nonCriticalExtension;
+  if (!nce23->nonCriticalExtension)
+    nce23->nonCriticalExtension = CALLOC(1, sizeof(*nce23->nonCriticalExtension));
+
+  typeof(nce23->nonCriticalExtension) nce24 = nce23->nonCriticalExtension;
+  if (!nce24->irat_ParametersNR_r15)
+    nce24->irat_ParametersNR_r15 = CALLOC(1, sizeof(*nce24->irat_ParametersNR_r15));
+
+  typeof(nce24->irat_ParametersNR_r15) irat = nce24->irat_ParametersNR_r15;
+  if (!irat->en_DC_r15)
+    irat->en_DC_r15 = CALLOC(1, sizeof(*irat->en_DC_r15));
+
+  *irat->en_DC_r15 = LTE_IRAT_ParametersNR_r15__en_DC_r15_supported;
+
+}
+
+OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname, bool received_nr_msg) {
   static OAI_UECapability_t UECapability; /* TODO declared static to allow returning this has an address should be allocated in a cleaner way. */
   static LTE_SupportedBandEUTRA_t Bandlist[4]; // the macro ASN_SEQUENCE_ADD() does not copy the source, but only stores a reference to it
   static LTE_InterFreqBandInfo_t InterFreqBandInfo[4][4]; // the macro ASN_SEQUENCE_ADD() does not copy the source, but only stores a reference to it
@@ -4472,7 +4626,13 @@ OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname) {
       UE_EUTRA_Capability->featureGroupIndicators = bit_string;
     }
 
-    // UE_EUTRA_Capability->interRAT_Parameters     // null
+    if (get_softmodem_params()->nsa && received_nr_msg)
+    {
+       allocate_en_DC_r15(UE_EUTRA_Capability);
+       if (!is_en_dc_supported(UE_EUTRA_Capability)){
+         LOG_E(RRC, "We did not properly allocate en_DC_r15 for UE_EUTRA_Capability\n");
+       }
+    }
   } else {
     FILE *f = fopen(UE_EUTRA_Capability_xer_fname, "r");
     assert(f);
diff --git a/openair2/RRC/LTE/MESSAGES/asn1_msg.h b/openair2/RRC/LTE/MESSAGES/asn1_msg.h
index 0d9fe65aeb0a03ed3e6eb49ac36e574f887d40cc..026f4577dc10df00a38871c9c80ef8fb3ea4e566 100644
--- a/openair2/RRC/LTE/MESSAGES/asn1_msg.h
+++ b/openair2/RRC/LTE/MESSAGES/asn1_msg.h
@@ -353,7 +353,11 @@ int do_HandoverPreparation(char *ho_buf, int ho_size, LTE_UE_EUTRA_Capability_t
 
 int do_HandoverCommand(char *ho_buf, int ho_size, char *rrc_buf, int rrc_size);
 
-OAI_UECapability_t *fill_ue_capability(char *LTE_UE_EUTRA_Capability_xer);
+OAI_UECapability_t *fill_ue_capability(char *LTE_UE_EUTRA_Capability_xer, bool received_nr_msg);
+
+int is_en_dc_supported(LTE_UE_EUTRA_Capability_t *c);
+
+void allocate_en_DC_r15(LTE_UE_EUTRA_Capability_t *cap);
 
 uint8_t
 do_UECapabilityEnquiry(
diff --git a/openair2/RRC/LTE/rrc_UE.c b/openair2/RRC/LTE/rrc_UE.c
index 9547a28e3dcc93f1c214819d4fbe3ee8c56dd240..67b72a6251f22f3a8b1e7ca27d75b16fb1377060 100644
--- a/openair2/RRC/LTE/rrc_UE.c
+++ b/openair2/RRC/LTE/rrc_UE.c
@@ -92,8 +92,10 @@
 
 //for D2D
 int ctrl_sock_fd;
-#define BUFSIZE 1024
 struct sockaddr_in prose_app_addr;
+static const char nsa_ipaddr[] = "127.0.0.1";
+static int from_nr_ue_fd = -1;
+static int to_nr_ue_fd = -1;
 int slrb_id;
 int send_ue_information = 0;
 
@@ -123,6 +125,11 @@ static int decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_
 
 static int decode_SIB1_MBMS( const protocol_ctxt_t *const ctxt_pP, const uint8_t eNB_index, const uint8_t rsrq, const uint8_t rsrp );
 
+typedef struct rrc_dcch_data_copy_t
+{
+    LTE_DL_DCCH_Message_t *dl_dcch_msg;
+} rrc_dcch_data_copy_t;
+
 
 /** \brief Generates/Encodes RRCConnnectionSetupComplete message at UE
  *  \param ctxt_pP Running context
@@ -166,7 +173,10 @@ rrc_ue_process_MBMSCountingRequest(
   LTE_MBMSCountingRequest_r10_t *MBMSCountingRequest,
   uint8_t eNB_index
 		);
- 
+
+static void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len);
+static void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type);
+
 protocol_ctxt_t ctxt_pP_local;
 
 
@@ -421,15 +431,6 @@ void rrc_ue_generate_RRCConnectionRequest( const protocol_ctxt_t *const ctxt_pP,
 #endif
       LOG_T(RRC,"%x.",rv[i]);
     }
-    rv[0] = ctxt_pP->module_id; // Debugging duplicate random values
-    LOG_A(RRC, "%s: random = %02X %02X %02X %02X %02X %02X\n",
-          __func__,
-          rv[0],
-          rv[1],
-          rv[2],
-          rv[3],
-          rv[4],
-          rv[5]);
 
     LOG_T(RRC,"\n");
     UE_rrc_inst[ctxt_pP->module_id].Srb0[eNB_index].Tx_buffer.payload_size =
@@ -809,6 +810,24 @@ rrc_ue_process_measConfig(
                 measObj->measObject.choice.measObjectEUTRA.neighCellConfig.buf[0]);
           UE_rrc_inst[ctxt_pP->module_id].MeasObj[eNB_index][ind-1]=measObj;
         }
+        if (measObj->measObject.present == LTE_MeasObjectToAddMod__measObject_PR_measObjectNR_r15) {
+          LOG_I(RRC,"NR_r15 Measurement : carrierFreq %ld\n",
+                measObj->measObject.choice.measObjectNR_r15.carrierFreq_r15);
+          if (!get_softmodem_params()->nsa) {
+            LOG_E(RRC, "Not in NSA mode but attempting to send measurement request to NR-UE\n");
+            return;
+          }
+          uint8_t buffer[RRC_BUF_SIZE];
+          asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_LTE_MeasObjectToAddMod,
+                                                          NULL,
+                                                          measObj,
+                                                          buffer,
+                                                          sizeof(buffer));
+          AssertFatal (enc_rval.encoded > 0, "ASN1 message encoding failed (%s, %zu)!\n",
+                        enc_rval.failed_type->name, enc_rval.encoded);
+          LOG_I(RRC, "Calling nsa_sendmsg_to_nr_ue to send a RRC_MEASUREMENT_PROCEDURE\n");
+          nsa_sendmsg_to_nrue(buffer, (enc_rval.encoded + 7)/8, RRC_MEASUREMENT_PROCEDURE);
+        }
       }
     }
 
@@ -2229,10 +2248,27 @@ rrc_ue_decode_dcch(
           LOG_I(RRC, "[UE %d] Received Capability Enquiry (eNB %d)\n",
                 ctxt_pP->module_id,
                 eNB_indexP);
-          rrc_ue_process_ueCapabilityEnquiry(
-            ctxt_pP,
-            &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry,
-            eNB_indexP);
+          if (get_softmodem_params()->nsa) {
+              LTE_UECapabilityEnquiry_t *ueCapabilityEnquiry_nsa = &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry;
+              OCTET_STRING_t * requestedFreqBandsNR = ueCapabilityEnquiry_nsa->
+                                    criticalExtensions.choice.c1.choice.ueCapabilityEnquiry_r8.nonCriticalExtension->
+                                    nonCriticalExtension->nonCriticalExtension->nonCriticalExtension->
+                                    nonCriticalExtension->requestedFreqBandsNR_MRDC_r15;
+              nsa_sendmsg_to_nrue(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, UE_CAPABILITY_ENQUIRY);
+              // Save ueCapabilityEnquiry so we can use in nsa mode after nrUE response is received
+              UE_RRC_INFO *info = &UE_rrc_inst[ctxt_pP->module_id].Info[eNB_indexP];
+              if (info->dl_dcch_msg != NULL) {
+                SEQUENCE_free(&asn_DEF_LTE_DL_DCCH_Message, info->dl_dcch_msg, ASFM_FREE_EVERYTHING);
+              }
+              info->dl_dcch_msg = dl_dcch_msg;
+              dl_dcch_msg = NULL;
+          }
+          else {
+            rrc_ue_process_ueCapabilityEnquiry(
+              ctxt_pP,
+              &dl_dcch_msg->message.choice.c1.choice.ueCapabilityEnquiry,
+              eNB_indexP);
+          }
           break;
 
         case LTE_DL_DCCH_MessageType__c1_PR_counterCheck:
@@ -4923,7 +4959,8 @@ openair_rrc_top_init_ue(
     memset (UE_rrc_inst, 0, NB_UE_INST * sizeof(UE_RRC_INST));
     LOG_D(RRC, "ALLOCATE %d Bytes for UE_RRC_INST @ %p\n", (unsigned int)(NB_UE_INST*sizeof(UE_RRC_INST)), UE_rrc_inst);
     // fill UE capability
-    UECap = fill_ue_capability (uecap_xer);
+    bool received_nr_msg = false;
+    UECap = fill_ue_capability (uecap_xer, received_nr_msg);
 
     for (module_id = 0; module_id < NB_UE_INST; module_id++) {
       UE_rrc_inst[module_id].UECap = UECap;
@@ -4941,6 +4978,11 @@ openair_rrc_top_init_ue(
      * crashes when calling this function.
      */
     //init_SL_preconfig(&UE_rrc_inst[module_id],0);
+    if (get_softmodem_params()->nsa == 1)
+    {
+      LOG_I(RRC, "Calling process_nsa_message\n");
+      //process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, buffer,msg_len);
+    }
   } else {
     UE_rrc_inst = NULL;
   }
@@ -5214,9 +5256,6 @@ void rrc_control_socket_init() {
 
 //--------------------------------------------------------
 void *rrc_control_socket_thread_fct(void *arg) {
-  int prose_addr_len;
-  char send_buf[BUFSIZE];
-  char receive_buf[BUFSIZE];
   //int optval;
   int n;
   struct sidelink_ctrl_element *sl_ctrl_msg_recv = NULL;
@@ -5235,15 +5274,16 @@ void *rrc_control_socket_thread_fct(void *arg) {
   int j = 0;
   int i = 0;
   //from the main program, listen for the incoming messages from control socket (ProSe App)
-  prose_addr_len = sizeof(prose_app_addr);
 
   //int enable_notification = 1;
   while (1) {
     LOG_I(RRC,"Listening to incoming connection from ProSe App \n");
     // receive a message from ProSe App
-    memset(receive_buf, 0, BUFSIZE);
-    n = recvfrom(ctrl_sock_fd, receive_buf, BUFSIZE, MSG_TRUNC,
-                 (struct sockaddr *) &prose_app_addr, (socklen_t *)&prose_addr_len);
+    char receive_buf[MAX_MESSAGE_SIZE];
+    memset(receive_buf, 0, sizeof(receive_buf));
+    socklen_t prose_addr_len = sizeof(prose_app_addr);
+    n = recvfrom(ctrl_sock_fd, receive_buf, sizeof(receive_buf), MSG_TRUNC,
+                 (struct sockaddr *) &prose_app_addr, &prose_addr_len);
 
     if (n < 0) {
       LOG_E(RRC, "ERROR: Failed to receive from ProSe App\n");
@@ -5252,7 +5292,7 @@ void *rrc_control_socket_thread_fct(void *arg) {
     if (n == 0) {
       LOG_E(RRC, "%s(%d). EOF for ctrl_sock_fd\n", __FUNCTION__, __LINE__);
     }
-    if (n > BUFSIZE) {
+    if (n > MAX_MESSAGE_SIZE) {
       LOG_E(RRC, "%s(%d). Message truncated. %d\n", __FUNCTION__, __LINE__, n);
       exit(EXIT_FAILURE);
     }
@@ -5263,6 +5303,7 @@ void *rrc_control_socket_thread_fct(void *arg) {
     memcpy((void *)sl_ctrl_msg_recv, (void *)receive_buf, sizeof(struct sidelink_ctrl_element));
 
     //process the message
+    char send_buf[MAX_MESSAGE_SIZE];
     switch (sl_ctrl_msg_recv->type) {
       case SESSION_INIT_REQ:
         if (LOG_DEBUGFLAG(DEBUG_CTRLSOCKET)) {
@@ -5271,14 +5312,14 @@ void *rrc_control_socket_thread_fct(void *arg) {
 
         //TODO: get SL_UE_STATE from lower layer
         LOG_I(RRC,"Send UEStateInformation to ProSe App \n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, MAX_MESSAGE_SIZE);
         sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
         sl_ctrl_msg_send->type = UE_STATUS_INFO;
         sl_ctrl_msg_send->sidelinkPrimitive.ue_state = UE_STATE_OFF_NETWORK; //off-network
         memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
         free(sl_ctrl_msg_send);
-        prose_addr_len = sizeof(prose_app_addr);
-        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
         if (n < 0) {
           LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
@@ -5424,14 +5465,14 @@ void *rrc_control_socket_thread_fct(void *arg) {
                               (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                              );
         LOG_I(RRC,"Send GroupCommunicationEstablishResp to ProSe App\n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, MAX_MESSAGE_SIZE);
         sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
         sl_ctrl_msg_send->type = GROUP_COMMUNICATION_ESTABLISH_RSP;
         sl_ctrl_msg_send->sidelinkPrimitive.slrb_id = 3; //slrb_id
         memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
         free(sl_ctrl_msg_send);
-        prose_addr_len = sizeof(prose_app_addr);
-        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
         if (n < 0) {
           LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
@@ -5485,7 +5526,7 @@ void *rrc_control_socket_thread_fct(void *arg) {
                               (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                              );
         LOG_I(RRC,"Send GroupCommunicationReleaseResponse to ProSe App \n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, MAX_MESSAGE_SIZE);
         sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
         sl_ctrl_msg_send->type = GROUP_COMMUNICATION_RELEASE_RSP;
 
@@ -5499,8 +5540,8 @@ void *rrc_control_socket_thread_fct(void *arg) {
 
         memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
         free(sl_ctrl_msg_send);
-        prose_addr_len = sizeof(prose_app_addr);
-        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
         if (n < 0) {
           LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
@@ -5628,14 +5669,14 @@ void *rrc_control_socket_thread_fct(void *arg) {
                               (LTE_MBSFN_AreaInfoList_r9_t *)NULL
                              );
         LOG_I(RRC,"Send DirectCommunicationEstablishResp to ProSe App\n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, MAX_MESSAGE_SIZE);
         sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
         sl_ctrl_msg_send->type = DIRECT_COMMUNICATION_ESTABLISH_RSP;
         sl_ctrl_msg_send->sidelinkPrimitive.slrb_id = 3; //slrb_id
         memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
         free(sl_ctrl_msg_send);
-        prose_addr_len = sizeof(prose_app_addr);
-        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
         if (n < 0) {
           LOG_E(RRC, "ERROR: Failed to send to ProSe App\n");
@@ -5815,15 +5856,15 @@ void *rrc_control_socket_thread_fct(void *arg) {
         }
 
         LOG_I(RRC,"Send PC5EstablishRsp to ProSe App\n");
-        memset(send_buf, 0, BUFSIZE);
+        memset(send_buf, 0, MAX_MESSAGE_SIZE);
         sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
         sl_ctrl_msg_send->type = PC5S_ESTABLISH_RSP;
         sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid28 = 10;
         sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid29 = 10;
         sl_ctrl_msg_send->sidelinkPrimitive.pc5s_establish_rsp.slrbid_lcid30 = 10;
         memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
-        prose_addr_len = sizeof(prose_app_addr);
-        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+        n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+                   (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
         //         free(sl_ctrl_msg_send);
         if (n < 0) {
@@ -5863,27 +5904,24 @@ int decode_SL_Discovery_Message(
   const uint8_t                eNB_index,
   const uint8_t               *Sdu,
   const uint8_t                Sdu_len) {
-  int prose_addr_len;
-  char send_buf[BUFSIZE];
+  char send_buf[MAX_MESSAGE_SIZE];
   int n;
   struct sidelink_ctrl_element *sl_ctrl_msg_send = NULL;
   //from the main program, listen for the incoming messages from control socket (ProSe App)
-  prose_addr_len = sizeof(prose_app_addr);
   //Store in Rx_buffer
   memcpy((void *)&UE_rrc_inst[ctxt_pP->module_id].SL_Discovery[0].Rx_buffer.Payload[0], (void *)Sdu, Sdu_len);
   UE_rrc_inst[ctxt_pP->module_id].SL_Discovery[0].Rx_buffer.payload_size = Sdu_len;
-  memset(send_buf, 0, BUFSIZE);
+  memset(send_buf, 0, MAX_MESSAGE_SIZE);
   //send to ProSeApp
   memcpy((void *)send_buf, (void *)Sdu, Sdu_len);
-  prose_addr_len = sizeof(prose_app_addr);
   sl_ctrl_msg_send = calloc(1, sizeof(struct sidelink_ctrl_element));
   sl_ctrl_msg_send->type = PC5_DISCOVERY_MESSAGE;
   // TODO:  Add a check for the SDU size.
   memcpy((void *)&sl_ctrl_msg_send->sidelinkPrimitive.pc5_discovery_message.payload[0], (void *) Sdu,  PC5_DISCOVERY_PAYLOAD_SIZE);
   memcpy((void *)send_buf, (void *)sl_ctrl_msg_send, sizeof(struct sidelink_ctrl_element));
   free(sl_ctrl_msg_send);
-  prose_addr_len = sizeof(prose_app_addr);
-  n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0, (struct sockaddr *)&prose_app_addr, prose_addr_len);
+  n = sendto(ctrl_sock_fd, (char *)send_buf, sizeof(struct sidelink_ctrl_element), 0,
+             (struct sockaddr *)&prose_app_addr, sizeof(prose_app_addr));
 
   if (n < 0) {
     // TODO:  We should not just exit if the Prose App has not yet attached.  It creates a race condition.
@@ -6007,3 +6045,155 @@ rrc_rx_tx_ue(
   return (RRC_OK);
 }
 
+void *recv_msgs_from_nr_ue(void *args_p)
+{
+    itti_mark_task_ready (TASK_RRC_NSA_UE);
+    for (;;)
+    {
+        nsa_msg_t msg;
+        int recvLen = recvfrom(from_nr_ue_fd, &msg, sizeof(msg),
+                               MSG_WAITALL | MSG_TRUNC, NULL, NULL);
+        if (recvLen == -1)
+        {
+            LOG_E(RRC, "%s: recvfrom: %s\n", __func__, strerror(errno));
+            continue;
+        }
+        if (recvLen > sizeof(msg))
+        {
+            LOG_E(NR_RRC, "%s: Received a truncated message %d\n", __func__, recvLen);
+            continue;
+        }
+        LOG_I(RRC, "We have received a msg. Calling process_nr_nsa_msg\n");
+        process_nr_nsa_msg(&msg, recvLen);
+    }
+
+}
+
+void nsa_sendmsg_to_nrue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type)
+{
+    LOG_I(RRC, "Entered %s \n", __FUNCTION__);
+    nsa_msg_t n_msg;
+    if (msg_len > sizeof(n_msg.msg_buffer))
+    {
+        LOG_E(RRC, "%s: message too big: %zu\n", __func__, msg_len);
+        abort();
+    }
+    n_msg.msg_type = msg_type;
+    memcpy(n_msg.msg_buffer, message, msg_len);
+    size_t to_send = sizeof(n_msg.msg_type) + msg_len;
+
+    struct sockaddr_in sa =
+    {
+        .sin_family = AF_INET,
+        .sin_port = htons(6008),
+    };
+    int sent = sendto(to_nr_ue_fd, &n_msg, to_send, 0,
+                      (struct sockaddr *)&sa, sizeof(sa));
+    if (sent == -1)
+    {
+        LOG_E(RRC, "%s: sendto: %s\n", __func__, strerror(errno));
+        return;
+    }
+    if (sent != to_send)
+    {
+        LOG_E(RRC, "%s: Short send %d != %zu\n", __func__, sent, to_send);
+        return;
+    }
+    LOG_I(RRC, "Sent a %d message to the nrUE (%zu bytes) \n", msg_type, to_send);
+}
+
+void init_connections_with_nr_ue(void)
+{
+    struct sockaddr_in sa =
+    {
+        .sin_family = AF_INET,
+        .sin_port = htons(6007),
+    };
+    AssertFatal(from_nr_ue_fd == -1, "from_nr_ue_fd was assigned already");
+    from_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (from_nr_ue_fd == -1)
+    {
+        LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, from_nr_ue_fd, errno, strerror(errno));
+        abort();
+    }
+
+    if (inet_aton(nsa_ipaddr, &sa.sin_addr) == 0)
+    {
+        LOG_E(RRC, "Bad nsa_ipaddr '%s'\n", nsa_ipaddr);
+        abort();
+    }
+
+    if (bind(from_nr_ue_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1)
+    {
+        LOG_E(RRC,"%s: Failed to bind the socket\n", __FUNCTION__);
+        abort();
+    }
+
+    AssertFatal(to_nr_ue_fd == -1, "to_nr_ue_fd was assigned already");
+    to_nr_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (to_nr_ue_fd == -1)
+    {
+        LOG_E(RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, to_nr_ue_fd, errno, strerror(errno));
+        abort();
+    }
+
+}
+
+void process_nr_nsa_msg(nsa_msg_t *msg, int msg_len)
+{
+    LOG_I(RRC, "We are processing an NSA message \n");
+    Rrc_Msg_Type_t msg_type = msg->msg_type;
+    uint8_t *const msg_buffer = msg->msg_buffer;
+    bool received_nr_msg = true;
+    protocol_ctxt_t ctxt;
+
+    switch (msg_type)
+    {
+        case UE_CAPABILITY_INFO:
+        {
+            LOG_I(RRC, "Processing a UE_CAPABILITY_INFO message \n");
+            /* Melissa:
+            1. Set these parameters if we get UE_CAPABILITY_INFO message:
+                a. irat-ParametersNR-r15
+                b. featureSetsEUTRA-r15
+                c. pdcp-ParametersNR-r15
+            2. Print the contents of each parameter
+            3. Call OAI_UECapability_t *fill_ue_capability(char *UE_EUTRA_Capability_xer_fname)
+               and pass in the UE CAPABILITY INFO */
+            break;
+        }
+        case UE_CAPABILITY_DUMMY:
+        {
+            fill_ue_capability(NULL, received_nr_msg);
+            for (module_id_t module_id = 0; module_id < NB_UE_INST; module_id++) {
+                UE_rrc_inst[module_id].UECap = UE_rrc_inst->UECap;
+                UE_rrc_inst[module_id].UECapability = UE_rrc_inst->UECap->sdu;
+                UE_rrc_inst[module_id].UECapability_size = UE_rrc_inst->UECap->sdu_size;
+            }
+            if (!is_en_dc_supported(UE_rrc_inst->UECap->UE_EUTRA_Capability))
+            {
+              LOG_E(RRC, "en_dc is NOT supported! Not sending RRC_DCCH_DATA_COPY_IND to update UE_Capability_INFO\n");
+              break;
+            }
+
+            LOG_I(RRC, "Send itti msg to trigger processing of capabilites b/c we have a UE_CAPABILITY_DUMMY\n");
+            MessageDef *message_p;
+            rrc_dcch_data_copy_t *dl_dcch_buffer = itti_malloc (TASK_RRC_NSA_UE,
+                                                                TASK_RRC_UE,
+                                                                sizeof(rrc_dcch_data_copy_t));
+            UE_RRC_INFO *info = &UE_rrc_inst[ctxt.module_id].Info[0];
+            dl_dcch_buffer->dl_dcch_msg = info->dl_dcch_msg;
+            info->dl_dcch_msg = NULL;
+            message_p = itti_alloc_new_message (TASK_RRC_UE, 0, RRC_DCCH_DATA_COPY_IND);
+            RRC_DCCH_DATA_COPY_IND (message_p).sdu_p = (void *)dl_dcch_buffer;
+            RRC_DCCH_DATA_COPY_IND (message_p).sdu_size = sizeof(rrc_dcch_data_copy_t);
+            RRC_DCCH_DATA_COPY_IND (message_p).eNB_index = 0;
+            itti_send_msg_to_task (TASK_RRC_UE, 0, message_p);
+            LOG_D(RRC, "Sent itti RRC_DCCH_DATA_COPY_IND\n");
+            break;
+        }
+        default:
+            LOG_E(RRC, "No NSA Message Found\n");
+    }
+}
+
diff --git a/openair2/RRC/LTE/rrc_defs.h b/openair2/RRC/LTE/rrc_defs.h
index 4f55f94121f1b63c0e64978de42b9cd6aba1652a..4b353638a214bf377dd9b7ae150d7075c0f3ade9 100644
--- a/openair2/RRC/LTE/rrc_defs.h
+++ b/openair2/RRC/LTE/rrc_defs.h
@@ -52,7 +52,6 @@
 
 //for D2D
 #define DEBUG_CTRL_SOCKET
-#define BUFSIZE                1024
 #define CONTROL_SOCKET_PORT_NO 8888
 #define MAX_NUM_DEST           10
 //netlink
@@ -67,6 +66,8 @@
 
 #define MAX_NUM_NEIGH_CELLs 6 /* maximum neighbouring cells number */
 
+#define MAX_NUM_GNB_CELLs 1   /* maximum gNB cells number */
+
 #define UE_STATE_NOTIFICATION_INTERVAL      50
 
 #define IPV4_ADDR    "%u.%u.%u.%u"
@@ -374,6 +375,7 @@ typedef struct UE_RRC_INFO_s {
   uint32_t N310_cnt;
   uint32_t N311_cnt;
   rnti_t   rnti;
+  struct LTE_DL_DCCH_Message *dl_dcch_msg;
 } __attribute__ ((__packed__)) UE_RRC_INFO;
 
 typedef struct UE_S_TMSI_s {
@@ -804,10 +806,17 @@ typedef struct eNB_RRC_INST_s {
   int num_neigh_cells_cc[MAX_NUM_CCs];
   uint32_t neigh_cells_id[MAX_NUM_NEIGH_CELLs][MAX_NUM_CCs];
 
+  // gNB cells connected to this eNB
+  int num_gnb_cells;
+  int num_gnb_cells_cc[MAX_NUM_GNB_CELLs];
+  uint32_t gnb_cells_id[MAX_NUM_GNB_CELLs][MAX_NUM_CCs];
+
   // Nr scc freq band and SSB absolute frequency
   uint32_t nr_neigh_freq_band[MAX_NUM_NEIGH_CELLs][MAX_NUM_CCs];
+  uint32_t nr_gnb_freq_band[MAX_NUM_GNB_CELLs][MAX_NUM_CCs];
   int nr_scg_ssb_freq;
 
+
   // other RAN parameters
   int srb1_timer_poll_retransmit;
   int srb1_poll_pdu;
diff --git a/openair2/RRC/LTE/rrc_eNB.c b/openair2/RRC/LTE/rrc_eNB.c
index 94d63e865222e3ff78fc0aac3c9ba3cc5745cd72..5e90c31464f2199fd2b55e2870bd0e2b2cf3f8c9 100644
--- a/openair2/RRC/LTE/rrc_eNB.c
+++ b/openair2/RRC/LTE/rrc_eNB.c
@@ -99,7 +99,6 @@
 #define ASN_MAX_ENCODE_SIZE 4096
 #define NUMBEROF_DRBS_TOBE_ADDED 1
 static int encode_CG_ConfigInfo(char *buffer,int buffer_size,rrc_eNB_ue_context_t *const ue_context_pP,int *enc_size);
-static int is_en_dc_supported(LTE_UE_EUTRA_Capability_t *c);
 
 extern RAN_CONTEXT_t RC;
 
@@ -7581,49 +7580,6 @@ rrc_eNB_decode_ccch(
   return rval;
 }
 
-//-----------------------------------------------------------------------------
-static int
-is_en_dc_supported(
-  LTE_UE_EUTRA_Capability_t *c
-)
-//-----------------------------------------------------------------------------
-{
-  /* to be refined - check that the eNB is connected to a gNB, check that
-   * the bands supported by the UE include the band of the gNB
-   */
-#define NCE nonCriticalExtension
-  return c != NULL
-         && c->NCE != NULL
-         && c->NCE->NCE != NULL
-         && c->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15 != NULL
-         && c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 != NULL
-         && *c->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->NCE->irat_ParametersNR_r15->en_DC_r15 ==
-         LTE_IRAT_ParametersNR_r15__en_DC_r15_supported;
-#undef NCE
-}
-
 //-----------------------------------------------------------------------------
 int
 rrc_eNB_decode_dcch(
@@ -8289,8 +8245,19 @@ rrc_eNB_decode_dcch(
           ue_context_p->ue_context.UE_Capability = 0;
         }
 
-        if (dec_rval.code == RC_OK)
-          ue_context_p->ue_context.does_nr = is_en_dc_supported(ue_context_p->ue_context.UE_Capability);
+        if (dec_rval.code == RC_OK) {
+          /* do NR only if at least one gNB connected */
+          if (RC.rrc[ctxt_pP->module_id]->num_gnb_cells != 0)
+          {
+            allocate_en_DC_r15(ue_context_p->ue_context.UE_Capability);
+            if (!is_en_dc_supported(ue_context_p->ue_context.UE_Capability)){
+                    LOG_E(RRC, "We did not properly allocate en_DC_r15 for UE_EUTRA_Capability\n");
+            }
+            ue_context_p->ue_context.does_nr = is_en_dc_supported(ue_context_p->ue_context.UE_Capability);
+          }
+          else
+            ue_context_p->ue_context.does_nr = 0;
+        }
 
         if (EPC_MODE_ENABLED) {
           rrc_eNB_send_S1AP_UE_CAPABILITIES_IND(ctxt_pP,
diff --git a/openair2/RRC/LTE/rrc_proto.h b/openair2/RRC/LTE/rrc_proto.h
index c50ddf3189e9fcb3e7d463835871d065baefa0ce..51ad0f8ba30b4d94a383dbff186c0a7e2345fe5b 100644
--- a/openair2/RRC/LTE/rrc_proto.h
+++ b/openair2/RRC/LTE/rrc_proto.h
@@ -31,6 +31,8 @@
  *  @{
  */
 
+#pragma once
+
 #include "RRC/LTE/rrc_defs.h"
 #include "x2ap_messages_types.h"
 #include "flexran_agent_extern.h"
@@ -354,6 +356,12 @@ void *rrc_enb_task(void *args_p);
    \param void *args_p Pointer on arguments to start the task. */
 void *rrc_ue_task(void *args_p);
 
+/**\brief RRC NSA UE task.
+   \param void *args_p Pointer on arguments to start the task. */
+void *recv_msgs_from_nr_ue(void *args_p);
+
+void init_connections_with_nr_ue(void);
+
 void rrc_eNB_process_x2_setup_request(int mod_id, x2ap_setup_req_t *m);
 
 void rrc_eNB_process_x2_setup_response(int mod_id, x2ap_setup_resp_t *m);
@@ -519,6 +527,16 @@ rrc_data_req_ue(
   const pdcp_transmission_mode_t modeP
 );
 
+uint8_t
+rrc_data_req_nr_ue(
+  const protocol_ctxt_t   *const ctxt_pP,
+  const rb_id_t                  rb_idP,
+  const mui_t                    muiP,
+  const confirm_t                confirmP,
+  const sdu_size_t               sdu_sizeP,
+  uint8_t                 *const buffer_pP,
+  const pdcp_transmission_mode_t modeP
+);
 
 void
 rrc_data_ind(
diff --git a/openair2/RRC/LTE/rrc_types.h b/openair2/RRC/LTE/rrc_types.h
index 9c1e37494f1eda3b3546709d458fced10d5b6de3..2d717e7cc3f07f1f4360cb8a084ee128518241f5 100644
--- a/openair2/RRC/LTE/rrc_types.h
+++ b/openair2/RRC/LTE/rrc_types.h
@@ -61,4 +61,12 @@ typedef enum Rrc_Sub_State_e {
   RRC_SUB_STATE_CONNECTED_LAST = RRC_SUB_STATE_CONNECTED,
 } Rrc_Sub_State_t;
 
+typedef enum Rrc_Msg_Type_e {
+  UE_CAPABILITY_DUMMY = 0xa0,
+  UE_CAPABILITY_ENQUIRY,
+  UE_CAPABILITY_INFO,
+  RRC_MEASUREMENT_PROCEDURE,
+} Rrc_Msg_Type_t;
+
+
 #endif /* RRC_TYPES_H_ */
diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c
index 5ad6746696bb98b8829331336af83e9c5dc2b349..28a2ce1958212fad25148dd91cffc92a4caccc3e 100644
--- a/openair2/RRC/NR_UE/L2_interface_ue.c
+++ b/openair2/RRC/NR_UE/L2_interface_ue.c
@@ -71,7 +71,7 @@ int8_t mac_rrc_nr_data_req_ue(const module_id_t Mod_idP,
 }
 
 uint8_t
-rrc_data_req_ue(
+rrc_data_req_nr_ue(
   const protocol_ctxt_t   *const ctxt_pP,
   const rb_id_t                  rb_idP,
   const mui_t                    muiP,
diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c
index 460dbf1d22b5f06a6ff41b9da7f2d2d370cec00a..17451349a38596120c8462ce9844c0e13e6e9f6a 100644
--- a/openair2/RRC/NR_UE/rrc_UE.c
+++ b/openair2/RRC/NR_UE/rrc_UE.c
@@ -129,6 +129,10 @@ nr_rrc_ue_generate_rrcReestablishmentComplete(
 mui_t nr_rrc_mui=0;
 uint8_t first_rrcreconfigurationcomplete = 0;
 
+static const char nsa_ipaddr[] = "127.0.0.1";
+static int from_lte_ue_fd = -1;
+static int to_lte_ue_fd = -1;
+
 static Rrc_State_NR_t nr_rrc_get_state (module_id_t ue_mod_idP) {
   return NR_UE_rrc_inst[ue_mod_idP].nrRrcState;
 }
@@ -201,6 +205,9 @@ extern rlc_op_status_t nr_rrc_rlc_config_asn1_req (const protocol_ctxt_t   * con
     const LTE_PMCH_InfoList_r9_t * const pmch_InfoList_r9_pP,
     struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_bearer2add_list);
 
+static void process_lte_nsa_msg(nsa_msg_t *msg, int msg_len);
+static void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, MessagesIds msg_type);
+
 // from LTE-RRC DL-DCCH RRCConnectionReconfiguration nr-secondary-cell-group-config (encoded)
 int8_t nr_rrc_ue_decode_secondary_cellgroup_config(
     const module_id_t module_id,
@@ -371,7 +378,7 @@ void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type,
                                 msg_len); 
         
         if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
-          LOG_E(RRC,"NR_RRCReconfiguration decode error\n");
+          LOG_E(NR_RRC, "NR_RRCReconfiguration decode error\n");
           // free the memory
           SEQUENCE_free( &asn_DEF_NR_RRCReconfiguration, RRCReconfiguration, 1 );
           return;
@@ -390,7 +397,7 @@ void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type,
                                 msg_len); 
         
         if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
-          LOG_E(RRC,"NR_RadioBearerConfig decode error\n");
+          LOG_E(NR_RRC, "NR_RadioBearerConfig decode error\n");
           // free the memory
           SEQUENCE_free( &asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1 );
           return;
@@ -486,7 +493,6 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* rrc_config_path){
                   strerror(errno));
       int msg_len=fread(buffer,1,1024,fd);
       fclose(fd);
-      process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, buffer,msg_len);
       if (rrc_config_path)
         sprintf(filename,"%s/rbconfig.raw",rrc_config_path);
       else
@@ -499,7 +505,11 @@ NR_UE_RRC_INST_t* openair_rrc_top_init_ue_nr(char* rrc_config_path){
                   strerror(errno));
       msg_len=fread(buffer,1,1024,fd);
       fclose(fd);
-      process_nsa_message(NR_UE_rrc_inst, nr_RadioBearerConfigX_r15, buffer,msg_len); 
+
+    }
+    else if (get_softmodem_params()->nsa)
+    {
+      //process_nsa_message(NR_UE_rrc_inst, nr_SecondaryCellGroupConfig_r15, buffer,msg_len);
     }
   }else{
     NR_UE_rrc_inst = NULL;
@@ -1019,7 +1029,7 @@ int nr_decode_SI( const protocol_ctxt_t *const ctxt_pP, const uint8_t gNB_index
   //  if (NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].SIcnt == sib1->schedulingInfoList.list.count)
   //    rrc_set_sub_state( ctxt_pP->module_id, RRC_SUB_STATE_IDLE_SIB_COMPLETE );
 
-  //  LOG_I(RRC,"SIStatus %x, SIcnt %d/%d\n",
+  //  LOG_I(NR_RRC, "SIStatus %x, SIcnt %d/%d\n",
   //        NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].SIStatus,
   //        NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].SIcnt,
   //        sib1->schedulingInfoList.list.count);
@@ -1132,7 +1142,7 @@ int nr_decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t gNB_inde
   LOG_I( RRC, "[FRAME unknown][RRC_UE][MOD %02"PRIu8"][][--- MAC_CONFIG_REQ (SIB1 params gNB %"PRIu8") --->][MAC_UE][MOD %02"PRIu8"][]\n",
          ctxt_pP->module_id, gNB_index, ctxt_pP->module_id );
   //rrc_mac_config_req_ue
-  LOG_I(RRC,"Setting SIStatus bit 0 to 1\n");
+  LOG_I(NR_RRC, "Setting SIStatus bit 0 to 1\n");
   NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].SIStatus = 1;
   //NR_UE_rrc_inst[ctxt_pP->module_id].Info[gNB_index].SIB1systemInfoValueTag = sib1->systemInfoValueTag;
 
@@ -1193,7 +1203,7 @@ int nr_decode_SIB1( const protocol_ctxt_t *const ctxt_pP, const uint8_t gNB_inde
       MessageDef  *msg_p;
       msg_p = itti_alloc_new_message(TASK_RRC_NRUE, 0, PHY_FIND_NEXT_CELL_REQ);
       itti_send_msg_to_task(TASK_PHY_UE, ctxt_pP->instance, msg_p);
-      LOG_E(RRC,
+      LOG_E(NR_RRC, 
             "Synched with a cell, but PLMN doesn't match our SIM "
             "(selected_plmn_identity %ld), the message PHY_FIND_NEXT_CELL_REQ "
             "is sent but lost in current UE implementation!\n",
@@ -1239,7 +1249,7 @@ int nr_decode_BCCH_DLSCH_Message(
     LOG_E( RRC, "[UE %"PRIu8"] Failed to decode BCCH_DLSCH_MESSAGE (%zu bits)\n",
            ctxt_pP->module_id,
            dec_rval.consumed );
-    log_dump(RRC, Sdu, Sdu_len, LOG_DUMP_CHAR,"   Received bytes:\n" );
+    log_dump(NR_RRC,  Sdu, Sdu_len, LOG_DUMP_CHAR,"   Received bytes:\n" );
     // free the memory
     SEQUENCE_free( &asn_DEF_LTE_BCCH_DL_SCH_Message, (void *)bcch_message, 1 );
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME( VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_BCCH, VCD_FUNCTION_OUT );
@@ -1383,7 +1393,7 @@ static void rrc_ue_generate_RRCSetupComplete(
        "[FRAME %05d][RRC_UE][MOD %02d][][--- PDCP_DATA_REQ/%d Bytes (RRCConnectionSetupComplete to gNB %d MUI %d) --->][PDCP][MOD %02d][RB %02d]\n",
        ctxt_pP->frame, ctxt_pP->module_id+NB_RN_INST, size, gNB_index, nr_rrc_mui, ctxt_pP->module_id+NB_eNB_INST, DCCH);
    // ctxt_pP_local.rnti = ctxt_pP->rnti;
-  rrc_data_req_ue(
+  rrc_data_req_nr_ue(
       ctxt_pP,
       DCCH,
       nr_rrc_mui++,
@@ -1409,7 +1419,7 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB
     asn_dec_rval_t dec_rval;
     int rval=0;
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_IN);
-    //    LOG_D(RRC,"[UE %d] Decoding DL-CCCH message (%d bytes), State %d\n",ue_mod_idP,Srb_info->Rx_buffer.payload_size,
+    //    LOG_D(NR_RRC, "[UE %d] Decoding DL-CCCH message (%d bytes), State %d\n",ue_mod_idP,Srb_info->Rx_buffer.payload_size,
     //    NR_UE_rrc_inst[ue_mod_idP].Info[gNB_index].State);
     dec_rval = uper_decode(NULL,
                            &asn_DEF_NR_DL_CCCH_Message,
@@ -1422,7 +1432,7 @@ int8_t nr_rrc_ue_decode_ccch( const protocol_ctxt_t *const ctxt_pP, const NR_SRB
     // }
     
     if ((dec_rval.code != RC_OK) && (dec_rval.consumed==0)) {
-      LOG_E(RRC,"[UE %d] Frame %d : Failed to decode DL-CCCH-Message (%zu bytes)\n",ctxt_pP->module_id,ctxt_pP->frame,dec_rval.consumed);
+      LOG_E(NR_RRC, "[UE %d] Frame %d : Failed to decode DL-CCCH-Message (%zu bytes)\n",ctxt_pP->module_id,ctxt_pP->frame,dec_rval.consumed);
       VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_UE_DECODE_CCCH, VCD_FUNCTION_OUT);
       return -1;
     }
@@ -1501,7 +1511,7 @@ int8_t nr_rrc_ue_decode_NR_SIB1_Message(module_id_t module_id, uint8_t gNB_index
                                                   buffer_len);
 
   if ((dec_rval.code != RC_OK) || (dec_rval.consumed == 0)) {
-    LOG_D(RRC,"NR_BCCH_DL_SCH decode error\n");
+    LOG_D(NR_RRC, "NR_BCCH_DL_SCH decode error\n");
     SEQUENCE_free( &asn_DEF_NR_BCCH_DL_SCH_Message, (void *)bcch_message, 1 );
     return -1;
   }
@@ -1512,7 +1522,7 @@ int8_t nr_rrc_ue_decode_NR_SIB1_Message(module_id_t module_id, uint8_t gNB_index
     }
     sib1 = bcch_message->message.choice.c1->choice.systemInformationBlockType1;
     if (*(int64_t*)sib1 != 1) {
-      LOG_I(RRC, "SIB1 decoded\n");
+      LOG_I(NR_RRC,  "SIB1 decoded\n");
       if( g_log->log_component[RRC].level >= OAILOG_DEBUG  )
         xer_fprint(stdout, &asn_DEF_NR_SIB1, (const void*)sib1);
     }
@@ -2302,7 +2312,7 @@ void nr_rrc_ue_generate_RRCReconfigurationComplete( const protocol_ctxt_t *const
   itti_send_msg_to_task (TASK_RRC_GNB_SIM, ctxt_pP->instance, message_p);
 
 #else
-  rrc_data_req_ue (
+  rrc_data_req_nr_ue (
     ctxt_pP,
     DCCH,
     nr_rrc_mui++,
@@ -2538,7 +2548,9 @@ void *rrc_nrue_task( void *args_p ) {
   NR_SRB_INFO   *srb_info_p;
   protocol_ctxt_t  ctxt;
   itti_mark_task_ready (TASK_RRC_NRUE);
-
+  /* TODO: Add case to handle nr-UE messages we want from nrUE RRC layer
+     The first one is the UE capability message from LTE UE. In the capability inquiry
+     with a particular special field, then we query the 5G side. */
   while(1) {
     // Wait for a message
     itti_receive_msg (TASK_RRC_NRUE, &msg_p);
@@ -2632,14 +2644,14 @@ void *rrc_nrue_task( void *args_p ) {
 #else
         // check if SRB2 is created, if yes request data_req on DCCH1 (SRB2)
         if(NR_UE_rrc_inst[ue_mod_id].SRB2_config[0] == NULL) {
-          rrc_data_req_ue (&ctxt,
+          rrc_data_req_nr_ue (&ctxt,
                            DCCH,
                            nr_rrc_mui++,
                            SDU_CONFIRM_NO,
                            length, buffer,
                            PDCP_TRANSMISSION_MODE_CONTROL);
         } else {
-          rrc_data_req_ue (&ctxt,
+          rrc_data_req_nr_ue (&ctxt,
                            DCCH1,
                            nr_rrc_mui++,
                            SDU_CONFIRM_NO,
@@ -2740,6 +2752,8 @@ nr_rrc_ue_process_ueCapabilityEnquiry(
   OCTET_STRING_fromBuf(&ue_CapabilityRAT_Container.ue_CapabilityRAT_Container,
                        (const char *)NR_UE_rrc_inst[ctxt_pP->module_id].UECapability,
                        NR_UE_rrc_inst[ctxt_pP->module_id].UECapability_size);
+  OCTET_STRING_t * requestedFreqBandsNR = UECapabilityEnquiry->criticalExtensions.choice.ueCapabilityEnquiry->ue_CapabilityEnquiryExt;
+  nsa_sendmsg(requestedFreqBandsNR->buf, requestedFreqBandsNR->size, UE_CAPABILITY_INFO);
   //  ue_CapabilityRAT_Container.ueCapabilityRAT_Container.buf  = UE_rrc_inst[ue_mod_idP].UECapability;
   // ue_CapabilityRAT_Container.ueCapabilityRAT_Container.size = UE_rrc_inst[ue_mod_idP].UECapability_size;
   AssertFatal(UECapabilityEnquiry->criticalExtensions.present == NR_UECapabilityEnquiry__criticalExtensions_PR_ueCapabilityEnquiry,
@@ -2765,7 +2779,7 @@ nr_rrc_ue_process_ueCapabilityEnquiry(
         xer_fprint(stdout, &asn_DEF_NR_UL_DCCH_Message, (void *)&ul_dcch_msg);
       }
 
-      LOG_I(RRC,"UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8);
+      LOG_I(NR_RRC, "UECapabilityInformation Encoded %zd bits (%zd bytes)\n",enc_rval.encoded,(enc_rval.encoded+7)/8);
 #ifdef ITTI_SIM
       MessageDef *message_p;
       uint8_t *message_buffer;
@@ -2849,3 +2863,180 @@ nr_rrc_ue_generate_rrcReestablishmentComplete(
 
 #endif
 }
+
+void *recv_msgs_from_lte_ue(void *args_p)
+{
+    itti_mark_task_ready (TASK_RRC_NSA_NRUE);
+    for (;;)
+    {
+        nsa_msg_t msg;
+        int recvLen = recvfrom(from_lte_ue_fd, &msg, sizeof(msg),
+                               MSG_WAITALL | MSG_TRUNC, NULL, NULL);
+        if (recvLen == -1)
+        {
+            LOG_E(NR_RRC, "%s: recvfrom: %s\n", __func__, strerror(errno));
+            continue;
+        }
+        if (recvLen > sizeof(msg))
+        {
+            LOG_E(NR_RRC, "%s: Received truncated message %d\n", __func__, recvLen);
+            continue;
+        }
+        process_lte_nsa_msg(&msg, recvLen);
+    }
+    return NULL;
+}
+
+void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, MessagesIds msg_type)
+{
+    LOG_I(NR_RRC, "Entered %s \n", __FUNCTION__);
+    nsa_msg_t n_msg;
+    if (msg_len > sizeof(n_msg.msg_buffer))
+    {
+        LOG_E(NR_RRC, "%s: message too big: %zu\n", __func__, msg_len);
+        abort();
+    }
+    n_msg.msg_type = msg_type;
+    memcpy(n_msg.msg_buffer, message, msg_len);
+    size_t to_send = sizeof(n_msg.msg_type) + msg_len;
+
+    struct sockaddr_in sa =
+    {
+        .sin_family = AF_INET,
+        .sin_port = htons(6007),
+    };
+    int sent = sendto(from_lte_ue_fd, n_msg.msg_buffer, to_send, 0,
+                      (struct sockaddr *)&sa, sizeof(sa));
+    if (sent == -1)
+    {
+        LOG_E(NR_RRC, "%s: sendto: %s\n", __func__, strerror(errno));
+        return;
+    }
+    if (sent != to_send)
+    {
+        LOG_E(RRC, "%s: Short send %d != %zu\n", __func__, sent, to_send);
+        return;
+    }
+}
+
+void init_connections_with_lte_ue(void)
+{
+    struct sockaddr_in sa =
+    {
+        .sin_family = AF_INET,
+        .sin_port = htons(6008),
+    };
+    AssertFatal(from_lte_ue_fd == -1, "from_lte_ue_fd was assigned already");
+    from_lte_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (from_lte_ue_fd == -1)
+    {
+        LOG_E(NR_RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, from_lte_ue_fd, errno, strerror(errno));
+        abort();
+    }
+
+    if (inet_aton(nsa_ipaddr, &sa.sin_addr) == 0)
+    {
+        LOG_E(NR_RRC, "Bad nsa_ipaddr '%s'\n", nsa_ipaddr);
+        abort();
+    }
+
+    if (bind(from_lte_ue_fd, (struct sockaddr *) &sa, sizeof(sa)) == -1)
+    {
+        LOG_E(NR_RRC,"%s: Failed to bind the socket\n", __FUNCTION__);
+        abort();
+    }
+
+    AssertFatal(to_lte_ue_fd == -1, "to_lte_ue_fd was assigned already");
+    to_lte_ue_fd = socket(AF_INET, SOCK_DGRAM, 0);
+    if (to_lte_ue_fd == -1)
+    {
+        LOG_E(NR_RRC, "%s: Error opening socket %d (%d:%s)\n", __FUNCTION__, to_lte_ue_fd, errno, strerror(errno));
+        abort();
+    }
+    LOG_I(NR_RRC, "Started LTE-NR link in the nr-UE\n");
+}
+
+static void process_measurement_objects_nr(LTE_MeasObjectToAddMod_t *buf)
+{
+    LOG_I(NR_RRC, "NR carrierFreq_r15 (ssb): %ld and sub carrier spacing:%ld and band: %ld.\n",
+          buf->measObject.choice.measObjectNR_r15.carrierFreq_r15,
+          buf->measObject.choice.measObjectNR_r15.rs_ConfigSSB_r15.subcarrierSpacingSSB_r15,
+          buf->measObject.choice.measObjectNR_r15.ext1->bandNR_r15);
+    #if 0
+    uint16_t node_num = get_softmodem_params()->node_number;
+    /* Receiving the RRC_Reconfiguration with the measurement objects
+       from the LTE UE should trigger the socket to be opened between
+       the NRUE(s) and the proxy. This allows us to start receiving
+       nFAPI messages from the gNB via the proxy. */
+    ue_id_g = (node_num == 0)? 0 : node_num-2;
+    init_nrUE_standalone_thread(ue_id_g);
+    #endif
+
+}
+
+
+void process_lte_nsa_msg(nsa_msg_t *msg, int msg_len)
+{
+    LOG_I(NR_RRC, "We are processing an NSA message\n");
+    Rrc_Msg_Type_t msg_type = msg->msg_type;
+    uint8_t *const msg_buffer = msg->msg_buffer;
+    msg_len -= sizeof(msg->msg_type);
+    switch (msg_type)
+    {
+        case UE_CAPABILITY_ENQUIRY:
+        {
+            LOG_I(NR_RRC, "We are processing a %d message \n", msg_type);
+            NR_FreqBandList_t *nr_freq_band_list = NULL;
+            asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
+                            &asn_DEF_NR_FreqBandList,
+                            (void **)&nr_freq_band_list,
+                            msg_buffer,
+                            msg_len);
+            if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0))
+            {
+              SEQUENCE_free(&asn_DEF_NR_FreqBandList, nr_freq_band_list, ASFM_FREE_EVERYTHING);
+              LOG_E(RRC, "Failed to decode UECapabilityInfo (%zu bits)\n", dec_rval.consumed);
+              break;
+            }
+            for (int i = 0; i < nr_freq_band_list->list.count; i++)
+            {
+                LOG_D(NR_RRC, "Received NR band information: %ld.\n",
+                     nr_freq_band_list->list.array[i]->choice.bandInformationNR->bandNR);
+            }
+
+            MessageDef *dummy_msg = itti_alloc_new_message(TASK_RRC_NSA_UE, 0, UE_CAPABILITY_DUMMY);
+            LOG_I(NR_RRC, "We are calling nsa_sendmsg_to_lte_ue to send a UE_CAPABILITY_DUMMY\n");
+            nsa_sendmsg_to_lte_ue(dummy_msg, sizeof(dummy_msg), UE_CAPABILITY_DUMMY);
+            LOG_I(NR_RRC, "We have sent a UE_CAPABILITY_DUMMY\n");
+            break;
+        }
+
+        case RRC_MEASUREMENT_PROCEDURE:
+            LOG_I(NR_RRC, "We are processing a %d message \n", msg_type);
+
+            LTE_MeasObjectToAddMod_t *nr_meas_obj = NULL;
+            asn_dec_rval_t dec_rval = uper_decode_complete(NULL,
+                            &asn_DEF_LTE_MeasObjectToAddMod,
+                            (void **)&nr_meas_obj,
+                            msg_buffer,
+                            msg_len);
+            if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0))
+            {
+              SEQUENCE_free(&asn_DEF_LTE_MeasObjectToAddMod, nr_meas_obj, ASFM_FREE_EVERYTHING);
+              LOG_E(RRC, "Failed to decode measurement object (%zu bits) %d\n", dec_rval.consumed, dec_rval.code);
+              break;
+            }
+            process_measurement_objects_nr(nr_meas_obj);
+            /* Create a processs RRC_MEASUREMENT_PROCEDURE function. This
+               function will tell the NR UE which frequency to take measurements
+               on. You can log these values for fun. This will trigger 5G UE socket with proxy
+               to be opened. It will listen for PBCH from gNB (proxy technically). Then it will
+               call the ususal MIB functions to handle the MIB. Intervene in 5G stack to decode the MIB.
+               Also, after receiving PBCH it will start sending SSB index/cellID and some info from MIB to UE
+               as measurement reporting message */
+            break;
+
+        default:
+            LOG_E(NR_RRC, "No NSA Message Found\n");
+    }
+}
diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h
index 401924844172addc98a54e43da71463080b8ce21..43e4f25088529be1247dd1277d19cedc9aa6276d 100644
--- a/openair2/RRC/NR_UE/rrc_proto.h
+++ b/openair2/RRC/NR_UE/rrc_proto.h
@@ -126,6 +126,10 @@ int8_t mac_rrc_nr_data_req_ue(const module_id_t Mod_idP,
    \param void *args_p Pointer on arguments to start the task. */
 void *rrc_nrue_task(void *args_p);
 
+/**\brief RRC NSA UE task.
+   \param void *args_p Pointer on arguments to start the task. */
+void *recv_msgs_from_lte_ue(void *args_p);
+
 /**\brief RRC UE generate RRCSetupRequest message.
    \param ctxt_pP    protocol context 
    \param gNB_index  gNB index  */
diff --git a/openair2/SIMULATION/NR_RRC/itti_sim.c b/openair2/SIMULATION/NR_RRC/itti_sim.c
index 41dc564b99213c724930c99631e96ef5833e8c69..5de69daa2195ac36716382a0a2380cae846b6d1d 100644
--- a/openair2/SIMULATION/NR_RRC/itti_sim.c
+++ b/openair2/SIMULATION/NR_RRC/itti_sim.c
@@ -399,11 +399,16 @@ int create_tasks_nrue(uint32_t ue_nb) {
   itti_wait_ready(1);
 
   if (ue_nb > 0) {
-    printf("create TASK_RRC_NRUE\n");
+    LOG_D(NR_RRC, "create TASK_RRC_NRUE\n");
     if (itti_create_task (TASK_RRC_NRUE, rrc_nrue_task, NULL) < 0) {
       LOG_E(NR_RRC, "Create task for RRC UE failed\n");
       return -1;
     }
+    if (itti_create_task (TASK_RRC_NSA_NRUE, recv_msgs_from_lte_ue, NULL) < 0) {
+      LOG_E(RRC, "Create task for RRC NSA UE failed\n");
+      return -1;
+    }
+
   }
 
 
diff --git a/openair3/GTPV1-U/gtpv1u_eNB_defs.h b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
index fb35d65f18c7150cabd996712f6fb34c44def14a..79d9a1dcdd54cb28c850d38b0cd161c6d3478719 100644
--- a/openair3/GTPV1-U/gtpv1u_eNB_defs.h
+++ b/openair3/GTPV1-U/gtpv1u_eNB_defs.h
@@ -29,7 +29,6 @@
 
 #include "hashtable.h"
 #include "LTE_asn_constant.h"
-#include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h"
 
 #ifndef GTPV1U_ENB_DEFS_H_
 #define GTPV1U_ENB_DEFS_H_
diff --git a/openair3/UDP/udp_eNB_task.h b/openair3/UDP/udp_eNB_task.h
index 5b1f49a698a7a4dddaeac3b8d69744293b958f45..8b783f7455c08f6aec5a0d80788b51746a9feb51 100644
--- a/openair3/UDP/udp_eNB_task.h
+++ b/openair3/UDP/udp_eNB_task.h
@@ -31,7 +31,6 @@
 #ifndef UDP_ENB_TASK_H_
 #define UDP_ENB_TASK_H_
 #include "enb_config.h"
-#include "nfapi/open-nFAPI/pnf/inc/pnf_p7.h"
 
 
 /** \brief UDP recv callback prototype. Will be called every time a payload is
diff --git a/targets/COMMON/create_tasks_ue.c b/targets/COMMON/create_tasks_ue.c
index 06f36641e73e695bc015c4fc7068b043e3a55a51..92391248137852dc45671e093fb90145ac364cd8 100644
--- a/targets/COMMON/create_tasks_ue.c
+++ b/targets/COMMON/create_tasks_ue.c
@@ -22,6 +22,7 @@
 # include "intertask_interface.h"
 # include "create_tasks.h"
 # include "common/utils/LOG/log.h"
+# include "executables/softmodem-common.h"
 
 #ifdef OPENAIR2
   #include "sctp_eNB_task.h"
@@ -65,6 +66,14 @@ int create_tasks_ue(uint32_t ue_nb) {
       LOG_E(RRC, "Create task for RRC UE failed\n");
       return -1;
     }
+    if (get_softmodem_params()->nsa) {
+      init_connections_with_nr_ue();
+      LOG_I(RRC, "Started LTE-NR link in the LTE UE\n");
+      if (itti_create_task (TASK_RRC_NSA_UE, recv_msgs_from_nr_ue, NULL) < 0) {
+        LOG_E(RRC, "Create task for RRC NSA UE failed\n");
+        return -1;
+      }
+    }
   }
 
   itti_wait_ready(0);
diff --git a/targets/RT/USER/lte-ue.c b/targets/RT/USER/lte-ue.c
index 183bd6d2c7bdb36230c0fca98af5df881375f59a..47b6ea2d6ef376aceba39a7a212824f41e85c1f4 100644
--- a/targets/RT/USER/lte-ue.c
+++ b/targets/RT/USER/lte-ue.c
@@ -80,18 +80,10 @@ void init_UE_threads(int);
 void init_UE_threads_stub(int);
 void init_UE_single_thread_stub(int);
 void *UE_thread(void *arg);
-void init_UE(int nb_inst,int eMBMS_active, int uecap_xer_in, int timing_correction, int phy_test, int UE_scan, int UE_scan_carrier, runmode_t mode,int rxgain,int txpowermax,LTE_DL_FRAME_PARMS *fp);
-void init_UE_stub(int nb_inst,int,int,char *);
-void init_UE_stub_single_thread(int nb_inst,int,int,char *);
 int init_timer_thread(void);
-extern void oai_subframe_ind(uint16_t sfn, uint16_t sf);
 extern void multicast_link_start(void (*rx_handlerP) (unsigned int, char *),
-                                 unsigned char _multicast_group, char *multicast_ifname);
-extern int oai_nfapi_crc_indication(nfapi_crc_indication_t *crc_ind);
-extern int oai_nfapi_cqi_indication(nfapi_cqi_indication_t *cqi_ind);
-extern int oai_nfapi_harq_indication(nfapi_harq_indication_t *harq_ind);
-extern int oai_nfapi_sr_indication(nfapi_sr_indication_t *ind);
-extern int oai_nfapi_rx_ind(nfapi_rx_indication_t *ind);
+                                 unsigned char _multicast_group,
+                                 char *multicast_ifname);
 extern int multicast_link_write_sock(int groupP, char *dataP, uint32_t sizeP);
 
 
diff --git a/targets/RT/USER/lte-uesoftmodem.c b/targets/RT/USER/lte-uesoftmodem.c
index f0fb0155a692f4c46a445571f9dda8e013cfb3dc..3b768ef30bcba8ee478651ff9e6a3697297a8640 100644
--- a/targets/RT/USER/lte-uesoftmodem.c
+++ b/targets/RT/USER/lte-uesoftmodem.c
@@ -870,7 +870,6 @@ void init_bler_table(void)
 
   for (unsigned int i = 0; i < NUM_MCS; i++)
   {
-    // Filename needs to be changed to dynamic name
     char fName[1024];
     snprintf(fName, sizeof(fName), "%s/openair1/SIMULATION/LTE_PHY/BLER_SIMULATIONS/AWGN/AWGN_results/bler_tx1_chan18_nrx1_mcs%d.csv", openair_dir, i);
     FILE *pFile = fopen(fName, "r");
@@ -908,7 +907,7 @@ void init_bler_table(void)
 
         token = strtok_r(NULL, ";", &temp);
       }
-      nlines++;        
+      nlines++;
     }
     bler_data[i].length = nlines;
     fclose(pFile);