diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index 4f897322a3a90c5feda6bfccf9152162b58b15df..ad8409de69db0484f684c48ed49236a01adf42ff 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -46,6 +46,9 @@
 #include "NR_MIB.h"
 #include "LAYER2/NR_MAC_COMMON/nr_mac_common.h"
 
+/* Softmodem params */
+#include "executables/softmodem-common.h"
+
 extern RAN_CONTEXT_t RC;
 //extern int l2_init_gNB(void);
 extern void mac_top_init_gNB(void);
@@ -347,9 +350,8 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
   if (secondaryCellGroup) {
 
     NR_UE_info_t *UE_info = &RC.nrmac[Mod_idP]->UE_info;
-    int UE_id;
-    if (add_ue == 1) {
-      UE_id = add_new_nr_ue(Mod_idP,rnti);
+    if (add_ue == 1 && get_softmodem_params()->phy_test) {
+      const int UE_id = add_new_nr_ue(Mod_idP,rnti);
       UE_info->secondaryCellGroup[UE_id] = secondaryCellGroup;
       struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList =
           secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList;
@@ -358,16 +360,22 @@ int rrc_mac_config_req_gNB(module_id_t Mod_idP,
                   bwpList->list.count);
       const int bwp_id = 1;
       UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
-      uint8_t num_preamble = secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list.count;
-      UE_info->preambles[UE_id].num_preambles = num_preamble;
-      UE_info->preambles[UE_id].preamble_list = (uint8_t *) malloc(num_preamble*sizeof(uint8_t));
-      for (int i=0; i<num_preamble; i++) {
-        UE_info->preambles[UE_id].preamble_list[i] = secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list.array[i]->ra_PreambleIndex;
-      }
       LOG_I(PHY,"Added new UE_id %d/%x with initial secondaryCellGroup\n",UE_id,rnti);
-    }
-    else { // secondaryCellGroup has been updated
-      UE_id = find_nr_UE_id(Mod_idP,rnti);
+    } else if (add_ue == 1 && !get_softmodem_params()->phy_test) {
+      /* TODO: should check for free RA process */
+      const int CC_id = 0;
+      NR_RA_t *ra = &RC.nrmac[Mod_idP]->common_channels[CC_id].ra[0];
+      ra->state = RA_IDLE;
+      ra->secondaryCellGroup = secondaryCellGroup;
+      ra->crnti = rnti;
+      uint8_t num_preamble = secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list.count;
+      ra->preambles.num_preambles = num_preamble;
+      ra->preambles.preamble_list = (uint8_t *) malloc(num_preamble*sizeof(uint8_t));
+      for (int i = 0; i < num_preamble; i++)
+        ra->preambles.preamble_list[i] = secondaryCellGroup->spCellConfig->reconfigurationWithSync->rach_ConfigDedicated->choice.uplink->cfra->resources.choice.ssb->ssb_ResourceList.list.array[i]->ra_PreambleIndex;
+      LOG_I(PHY,"Added new RA process for UE RNTI %04x with initial secondaryCellGroup\n", rnti);
+    } else { // secondaryCellGroup has been updated
+      const int UE_id = find_nr_UE_id(Mod_idP,rnti);
       UE_info->secondaryCellGroup[UE_id] = secondaryCellGroup;
       LOG_I(PHY,"Modified UE_id %d/%x with secondaryCellGroup\n",UE_id,rnti);
     }
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index b073029da0cf4685f236c36828a218ca87bdfd78..413727b9cb89c35f2e6c4e971b2c15d9633d7a8c 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -247,14 +247,11 @@ void nr_initiate_ra_proc(module_id_t module_idP,
 
   uint8_t ul_carrier_id = 0; // 0 for NUL 1 for SUL
   NR_SearchSpace_t *ss;
-  int UE_id = 0;
   // ra_rnti from 5.1.3 in 38.321
   uint16_t ra_rnti=1+symbol+(slotP*14)+(freq_index*14*80)+(ul_carrier_id*14*80*8);
 
   uint16_t msg2_frame, msg2_slot,monitoring_slot_period,monitoring_offset;
   gNB_MAC_INST *nr_mac = RC.nrmac[module_idP];
-  NR_UE_info_t *UE_info = &nr_mac->UE_info;
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
   NR_COMMON_channels_t *cc = &nr_mac->common_channels[CC_id];
   NR_ServingCellConfigCommon_t *scc = cc->ServingCellConfigCommon;
   NR_RA_t *ra = &cc->ra[0];
@@ -262,21 +259,21 @@ void nr_initiate_ra_proc(module_id_t module_idP,
   // if the preamble received correspond to one of the listed
   // the UE sent a RACH either for starting RA procedure or RA procedure failed and UE retries
   int pr_found=0;
-  for (int i=0;i<UE_info->preambles[UE_id].num_preambles;i++) {
-    if (preamble_index == UE_info->preambles[UE_id].preamble_list[i]) {
+  for (int i = 0; i < ra->preambles.num_preambles; i++) {
+    if (preamble_index == ra->preambles.preamble_list[i]) {
       pr_found=1;
       break;
     }
   }
   if (!pr_found) {
-    LOG_E(MAC, "[gNB %d][RAPROC] FAILURE: preamble %d does not correspond to any of the ones in rach_ConfigDedicated for UE_id %d\n",
-          module_idP, preamble_index, UE_id);
+    LOG_E(MAC, "[gNB %d][RAPROC] FAILURE: preamble %d does not correspond to any of the ones in rach_ConfigDedicated\n",
+          module_idP, preamble_index);
     return; // if the PRACH preamble does not correspond to any of the ones sent through RRC abort RA proc
   }
 
   // This should be handled differently when we use the initialBWP for RA
   ra->bwp_id=1;
-  NR_BWP_Downlink_t *bwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1];
+  NR_BWP_Downlink_t *bwp=ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id-1];
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_INITIATE_RA_PROC, 1);
 
@@ -323,7 +320,6 @@ void nr_initiate_ra_proc(module_id_t module_idP,
 
     ra->RA_rnti = ra_rnti;
     ra->preamble_index = preamble_index;
-    UE_info->tc_rnti[UE_id] = ra->rnti;
 
     LOG_I(MAC,"[gNB %d][RAPROC] CC_id %d Frame %d Activating Msg2 generation in frame %d, slot %d using RA rnti %x\n",
       module_idP,
@@ -421,7 +417,6 @@ void nr_schedule_reception_msg3(module_id_t module_idP, int CC_id, frame_t frame
       ul_req->pdus_list[ul_req->n_pdus].pdu_size = sizeof(nfapi_nr_pusch_pdu_t);
       ul_req->pdus_list[ul_req->n_pdus].pusch_pdu = ra->pusch_pdu;
       ul_req->n_pdus+=1;
-      ra->state = RA_IDLE;
     }
   }
 }
@@ -432,8 +427,6 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
   NR_COMMON_channels_t                            *cc = &mac->common_channels[CC_id];
   NR_ServingCellConfigCommon_t                   *scc = cc->ServingCellConfigCommon;
   NR_RA_t                                         *ra = &cc->ra[0];
-  NR_UE_info_t                               *UE_info = &mac->UE_info;
-  int UE_id = 0;
 
   if (ra->state == RA_IDLE) {
     LOG_W(MAC,"RA is not active for RA %X. skipping msg3 scheduling\n", ra->rnti);
@@ -445,13 +438,12 @@ void nr_add_msg3(module_id_t module_idP, int CC_id, frame_t frameP, sub_frame_t
   nfapi_nr_pusch_pdu_t  *pusch_pdu = &ra->pusch_pdu;
   memset(pusch_pdu, 0, sizeof(nfapi_nr_pusch_pdu_t));
 
-
-  AssertFatal(!UE_info->active[UE_id], "UE_id %d is already active\n", UE_id);
-
-  NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-  AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
-    "downlinkBWP_ToAddModList has %d BWP!\n", secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
-  NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1];
+  AssertFatal(ra->secondaryCellGroup,
+              "no secondaryCellGroup for RNTI %04x\n",
+              ra->crnti);
+  AssertFatal(ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
+    "downlinkBWP_ToAddModList has %d BWP!\n", ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
+  NR_BWP_Uplink_t *ubwp = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id - 1];
   LOG_D(MAC, "Frame %d, Subframe %d Adding Msg3 UL Config Request for (%d,%d) : (%d,%d,%d) for rnti: %d\n",
     frameP,
     slotP,
@@ -540,12 +532,11 @@ void nr_generate_Msg2(module_id_t module_idP,
                       frame_t frameP,
                       sub_frame_t slotP){
 
-  int UE_id = 0, dci_formats[2], rnti_types[2], mcsIndex;
+  int dci_formats[2], rnti_types[2], mcsIndex;
   int startSymbolAndLength = 0, StartSymbolIndex = -1, NrOfSymbols = 14, StartSymbolIndex_tmp, NrOfSymbols_tmp, x_Overhead, time_domain_assignment = 0;
   gNB_MAC_INST                      *nr_mac = RC.nrmac[module_idP];
   NR_COMMON_channels_t                  *cc = &nr_mac->common_channels[0];
   NR_RA_t                               *ra = &cc->ra[0];
-  NR_UE_info_t                     *UE_info = &nr_mac->UE_info;
   NR_SearchSpace_t *ss = ra->ra_ss;
 
   uint16_t RA_rnti = ra->RA_rnti;
@@ -594,11 +585,13 @@ void nr_generate_Msg2(module_id_t module_idP,
     // This code from this point on will not work on initialBWP or CORESET0
     AssertFatal(ra->bwp_id>0,"cannot work on initialBWP for now\n");
 
-    NR_CellGroupConfig_t *secondaryCellGroup = UE_info->secondaryCellGroup[UE_id];
-    AssertFatal(secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
-      "downlinkBWP_ToAddModList has %d BWP!\n", secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
-    NR_BWP_Downlink_t *bwp = secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id - 1];
-    NR_BWP_Uplink_t *ubwp=secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1];
+    AssertFatal(ra->secondaryCellGroup,
+                "no secondaryCellGroup for RNTI %04x\n",
+                ra->crnti);
+    AssertFatal(ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count == 1,
+      "downlinkBWP_ToAddModList has %d BWP!\n", ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.count);
+    NR_BWP_Downlink_t *bwp = ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList->list.array[ra->bwp_id - 1];
+    NR_BWP_Uplink_t *ubwp=ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->uplinkConfig->uplinkBWP_ToAddModList->list.array[ra->bwp_id-1];
 
     LOG_D(MAC, "[RAPROC] Scheduling common search space DCI type 1 dlBWP BW %d\n", dci10_bw);
 
@@ -690,7 +683,7 @@ void nr_generate_Msg2(module_id_t module_idP,
         0); // m
 
     if (CCEIndex < 0) {
-      LOG_E(MAC, "%s(): cannot find free CCE for UE %d!\n", __func__, UE_id);
+      LOG_E(MAC, "%s(): cannot find free CCE for RA RNTI %04x!\n", __func__, ra->rnti);
       return;
     }
     nr_configure_pdcch(nr_mac,
@@ -716,7 +709,7 @@ void nr_generate_Msg2(module_id_t module_idP,
       pdcch_pdu_rel15->StartSymbolIndex,
       pdcch_pdu_rel15->DurationSymbols);
 
-    fill_dci_pdu_rel15(scc,secondaryCellGroup,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types,dci10_bw,ra->bwp_id);
+    fill_dci_pdu_rel15(scc,ra->secondaryCellGroup,pdcch_pdu_rel15, &dci_pdu_rel15[0], dci_formats, rnti_types,dci10_bw,ra->bwp_id);
 
     dl_req->nPDUs+=2;
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index d19dc7b056a34b258e583e199acc2e55744ca508..237ad3764838619657dc88dcf30eb4015817cc68 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -63,9 +63,6 @@
 #define ENABLE_MAC_PAYLOAD_DEBUG
 #define DEBUG_gNB_SCHEDULER 1
 
-/*Softmodem params*/
-#include "executables/softmodem-common.h"
-
 #include "common/ran_context.h"
 
 extern RAN_CONTEXT_t RC;
@@ -1640,12 +1637,7 @@ int add_new_nr_ue(module_id_t mod_idP, rnti_t rntiP){
 
     int UE_id = i;
     UE_info->num_UEs++;
-    /* if real softmodem: not yet active, we wait for RA! FIXME: This opens a
-     * data race: a UE should complete RA before adding the next, or by the
-     * above condition, we overwrite the current UE with the following one.
-     *
-     * if phytest: there is no RA, so enable directly */
-    UE_info->active[UE_id] = get_softmodem_params()->phy_test;
+    UE_info->active[UE_id] = true;
     UE_info->rnti[UE_id] = rntiP;
     add_nr_ue_list(&UE_info->list, UE_id);
     memset((void *) &UE_info->UE_sched_ctrl[UE_id],
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
index 0e977c535249fe427b73f761a853b43760d98fc3..b87d8787bfb7ebaf9baeb4b0784f1fb8f8632e2b 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_ulsch.c
@@ -365,18 +365,44 @@ void nr_rx_sdu(const module_id_t gnb_mod_idP,
 
     }
   }
-  else {
+  else if (sduP != NULL) { // if the CRC passed
     // random access pusch with TC-RNTI
-    if (sduP != NULL) { // if the CRC passed
-      for (int i = 0; i < MAX_MOBILES_PER_GNB; i++) {
-        if (UE_info->tc_rnti[i] == current_rnti) {
-          // for now the only thing we are doing is set the UE as active
-          UE_info->active[i] = true;
-          LOG_W(MAC, "[gNB %d][RAPROC] PUSCH with TC_RNTI %x received correctly and UE_id %d is now 5G connected\n",
-                gnb_mod_idP, current_rnti, i);
-        }
-      }
+    NR_RA_t *ra = &gNB_mac->common_channels[CC_idP].ra[0];
+    if (ra->state != WAIT_Msg3) {
+      LOG_E(MAC,
+            "expected RA state WAIT_Msg3/%d (but is %d) for RA-RNTI %04x\n",
+            WAIT_Msg3,
+            ra->state,
+            ra->rnti);
+      return;
+    }
+    if (ra->rnti != current_rnti) {
+      LOG_E(MAC,
+            "expected RA-RNTI %04x (C-RNTI %04x) to match current RNTI %04x\n",
+            ra->rnti,
+            ra->crnti,
+            current_rnti);
+      return;
     }
+    free(ra->preambles.preamble_list);
+    ra->state = RA_IDLE;
+    LOG_I(MAC, "reset RA state information for RA-RNTI %04x\n", ra->rnti);
+    const int UE_id = add_new_nr_ue(gnb_mod_idP, ra->crnti);
+    UE_info->secondaryCellGroup[UE_id] = ra->secondaryCellGroup;
+    struct NR_ServingCellConfig__downlinkBWP_ToAddModList *bwpList =
+        ra->secondaryCellGroup->spCellConfig->spCellConfigDedicated->downlinkBWP_ToAddModList;
+    AssertFatal(bwpList->list.count == 1,
+                "downlinkBWP_ToAddModList has %d BWP!\n",
+                bwpList->list.count);
+    const int bwp_id = 1;
+    UE_info->UE_sched_ctrl[UE_id].active_bwp = bwpList->list.array[bwp_id - 1];
+    LOG_W(MAC,
+          "[gNB %d][RAPROC] PUSCH with TC_RNTI %x received correctly, "
+          "adding UE MAC Context UE_id %d/RNTI %04x\n",
+          gnb_mod_idP,
+          current_rnti,
+          UE_id,
+          ra->crnti);
   }
 }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 2bedb0750f0e0e18d756914df9c6127c08e53746..f94bfc61aade9bc2baba092f2a2d06a08790446e 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -83,6 +83,11 @@ typedef enum {
   WAIT_Msg4_ACK = 4
 } RA_gNB_state_t;
 
+typedef struct NR_preamble_ue {
+  uint8_t num_preambles;
+  uint8_t *preamble_list;
+} NR_preamble_ue_t;
+
 /*! \brief gNB template for the Random access information */
 typedef struct {
   /// Flag to indicate this process is active
@@ -141,6 +146,12 @@ typedef struct {
   int msg4_mcs;
   /// RA search space
   NR_SearchSpace_t *ra_ss;
+  /// secondaryCellGroup for UE in NSA that is to come
+  NR_CellGroupConfig_t *secondaryCellGroup;
+  /// Preambles for contention-free access
+  NR_preamble_ue_t preambles;
+  /// NSA: the UEs C-RNTI to use
+  rnti_t crnti;
 } NR_RA_t;
 
 /*! \brief gNB common channels */
@@ -325,11 +336,6 @@ typedef struct {
   NR_UE_mac_ce_ctrl_t UE_mac_ce_ctrl;// MAC CE related information
 } NR_UE_sched_ctrl_t;
 
-typedef struct NR_preamble_ue {
-  uint8_t num_preambles;
-  uint8_t *preamble_list;
-} NR_preamble_ue;
-
 typedef struct {
 
   int lc_bytes_tx[64];
@@ -361,8 +367,6 @@ typedef struct {
   int num_UEs;
   bool active[MAX_MOBILES_PER_GNB];
   rnti_t rnti[MAX_MOBILES_PER_GNB];
-  rnti_t tc_rnti[MAX_MOBILES_PER_GNB];
-  NR_preamble_ue preambles[MAX_MOBILES_PER_GNB];
   NR_CellGroupConfig_t *secondaryCellGroup[MAX_MOBILES_PER_GNB];
 } NR_UE_info_t;