diff --git a/ci-scripts/Jenkinsfile-GitLab-Container b/ci-scripts/Jenkinsfile-GitLab-Container
index 37e6a0554b94b1fe032ee7e2cb2f027d2b26d746..3ad376f3da4b60ac4de36783874574b9436c1846 100644
--- a/ci-scripts/Jenkinsfile-GitLab-Container
+++ b/ci-scripts/Jenkinsfile-GitLab-Container
@@ -65,8 +65,8 @@ pipeline {
               message += " - ~BUILD-ONLY (execute only build stages)\n"
               message += " - ~4G-LTE (perform 4G tests)\n"
               message += " - ~5G-NR (perform 5G tests)\n"
-              message += " - ~CI (perform both 4G and 5G tests)\n\n"
-              message += " - ~nrUE (perform only 5G-UE related tests including physims excluding LDPC tests)\n"
+              message += " - ~CI (perform both 4G and 5G tests)\n"
+              message += " - ~nrUE (perform only 5G-UE related tests including physims excluding LDPC tests)\n\n"
               message += "Not performing CI due to lack of labels"
               addGitLabMRComment comment: message
               error('Not performing CI due to lack of labels')
diff --git a/ci-scripts/cls_cluster.py b/ci-scripts/cls_cluster.py
index 7293e252a16f3d2c60e54114ba1410e595c8afd5..bfa315b28ed250021541768a73bfdf86b6f96498 100644
--- a/ci-scripts/cls_cluster.py
+++ b/ci-scripts/cls_cluster.py
@@ -72,8 +72,8 @@ def OC_deploy_CN(cmd, ocUserName, ocPassword, ocNamespace, path):
 	succeeded = OC_login(cmd, ocUserName, ocPassword, ocNamespace)
 	if not succeeded:
 		return False, CONST.OC_LOGIN_FAIL
-	cmd.run('helm uninstall oai5gcn --wait --timeout 60s')
-	ret = cmd.run(f'helm install --wait --timeout 120s oai5gcn {path}/ci-scripts/charts/oai-5g-basic/.')
+	cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait')
+	ret = cmd.run(f'helm install --wait oai5gcn {path}/ci-scripts/charts/oai-5g-basic/.')
 	if ret.returncode != 0:
 		logging.error('OC OAI CN5G: Deployment failed')
 		OC_logout(cmd)
@@ -100,10 +100,10 @@ def OC_undeploy_CN(cmd, ocUserName, ocPassword, ocNamespace, path):
 			cmd.run(f'oc logs -f {podName} {ci} &> {path}/logs/{ii}.log &')
 	cmd.run(f'cd {path}/logs && zip -r -qq test_logs_CN.zip *.log')
 	cmd.copyin(f'{path}/logs/test_logs_CN.zip','test_logs_CN.zip')
-	ret = cmd.run('helm uninstall --wait --timeout 60s oai5gcn')
+	ret = cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait')
 	if ret.returncode != 0:
 		logging.error('OC OAI CN5G: Undeployment failed')
-		cmd.run('helm uninstall --wait --timeout 60s oai5gcn')
+		cmd.run(f'helm list -aq -n {ocNamespace} | xargs -r helm uninstall -n {ocNamespace} --wait')
 		OC_logout(cmd)
 		return False, CONST.OC_PROJECT_FAIL
 	report = cmd.run('oc get pods')
@@ -330,7 +330,7 @@ class Cluster:
 			self._recreate_bc('ran-base', baseTag, 'openshift/ran-base-bc.yaml')
 			ranbase_job = self._start_build('ran-base')
 			attemptedImages += ['ran-base']
-			status = ranbase_job is not None and self._wait_build_end([ranbase_job], 800)
+			status = ranbase_job is not None and self._wait_build_end([ranbase_job], 1000)
 			if not status: logging.error('failure during build of ran-base')
 			self.cmd.run(f'oc logs {ranbase_job} &> cmake_targets/log/ran-base.log') # cannot use cmd.run because of redirect
 			# recover logs by mounting image
@@ -392,7 +392,7 @@ class Cluster:
 			gnb_aw2s_job = self._start_build('oai-gnb-aw2s')
 			attemptedImages += ['oai-gnb-aw2s']
 
-			wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 600)
+			wait = enb_job is not None and gnb_job is not None and gnb_aw2s_job is not None and self._wait_build_end([enb_job, gnb_job, gnb_aw2s_job], 800)
 			if not wait: logging.error('error during build of eNB/gNB')
 			status = status and wait
 			# recover logs
@@ -421,7 +421,7 @@ class Cluster:
 			nrue_job = self._start_build('oai-nr-ue')
 			attemptedImages += ['oai-nr-ue']
 
-			wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 600)
+			wait = nr_cuup_job is not None and lteue_job is not None and nrue_job is not None and self._wait_build_end([nr_cuup_job, lteue_job, nrue_job], 800)
 			if not wait: logging.error('error during build of nr-cuup/lteUE/nrUE')
 			status = status and wait
 			# recover logs
diff --git a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml
index 5c2a0691220699b14fd6b8a34daafcc1e6b1c9a3..fe80891678ef72ee11ea908995a45039a93363b7 100644
--- a/ci-scripts/xml_files/container_5g_rfsim_24prb.xml
+++ b/ci-scripts/xml_files/container_5g_rfsim_24prb.xml
@@ -34,6 +34,9 @@
  020002
  030001
  030002
+ 040001
+ 000004
+ 020002
  100001
  222222
         </TestCaseRequestedList>
@@ -76,6 +79,12 @@
                 <nodes>cacofonix</nodes>
         </testCase>
 
+        <testCase id="000004">
+                <class>IdleSleep</class>
+                <desc>Sleep</desc>
+                <idle_sleep_time_in_sec>5</idle_sleep_time_in_sec>
+        </testCase>
+
         <testCase id="020001">
                 <class>Ping</class>
                 <desc>Ping ext-dn from NR-UE</desc>
@@ -118,6 +127,14 @@
                 <iperf_bitrate_threshold>90</iperf_bitrate_threshold>
         </testCase>
 
+        <testCase id="040001">
+                <class>Custom_Command</class>
+                <desc>Force Msg3 C-RNTI RA</desc>
+                <node>cacofonix</node>
+                <command>echo ciUE force_crnti_ra | nc 192.168.71.150 8091</command>
+                <command_fail>yes</command_fail>
+        </testCase>
+
         <testCase id="100001">
                 <class>Undeploy_Object</class>
                 <always_exec>true</always_exec>
diff --git a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
index ae74649a8309e191d375a63b41f55e31e940d618..2fd9a3e1fb8f00079770231e0e20a3e51cffffba 100644
--- a/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
+++ b/ci-scripts/yaml_files/5g_rfsimulator_24prb/docker-compose.yaml
@@ -109,7 +109,10 @@ services:
             - NET_ADMIN  # for interface bringup
             - NET_RAW    # for ping
         environment:
-            USE_ADDITIONAL_OPTIONS: --rfsim -r 24 --ssb 24 --numerology 1 -C 3604800000 --uicc0.imsi 208990100001100 --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
+            USE_ADDITIONAL_OPTIONS: --rfsim -r 24 --ssb 24 --numerology 1 -C 3604800000 --uicc0.imsi 208990100001100
+                                    --rfsimulator.serveraddr 192.168.71.140 --log_config.global_log_options level,nocolor,time
+                                    --telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.150 --telnetsrv.listenport 8091
+            ASAN_OPTIONS: detect_leaks=0:detect_odr_violation=0
         depends_on:
             - oai-gnb
         networks:
diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c
index 1d1e683dce4c0b675b913ce8878e6671508681b8..58c18bfd368bcf1dc5ee1fa75ea772d2993eacfd 100644
--- a/common/utils/nr/nr_common.c
+++ b/common/utils/nr/nr_common.c
@@ -1380,15 +1380,22 @@ int set_default_nta_offset(frequency_range_t freq_range, uint32_t samples_per_su
 void nr_timer_start(NR_timer_t *timer)
 {
   timer->active = true;
+  timer->suspended = false;
   timer->counter = 0;
 }
 
 void nr_timer_stop(NR_timer_t *timer)
 {
   timer->active = false;
+  timer->suspended = false;
   timer->counter = 0;
 }
 
+void nr_timer_suspension(NR_timer_t *timer)
+{
+  timer->suspended = !timer->suspended;
+}
+
 bool nr_timer_is_active(const NR_timer_t *timer)
 {
   return timer->active;
@@ -1399,7 +1406,7 @@ bool nr_timer_tick(NR_timer_t *timer)
   bool expired = false;
   if (timer->active) {
     timer->counter += timer->step;
-    if (timer->target == UINT_MAX) // infinite target, never expires
+    if (timer->target == UINT_MAX || timer->suspended) // infinite target, never expires
       return false;
     expired = nr_timer_expired(timer);
     if (expired)
@@ -1410,7 +1417,7 @@ bool nr_timer_tick(NR_timer_t *timer)
 
 bool nr_timer_expired(const NR_timer_t *timer)
 {
-  if (timer->target == UINT_MAX) // infinite target, never expires
+  if (timer->target == UINT_MAX || timer->suspended) // infinite target, never expires
     return false;
   return timer->counter >= timer->target;
 }
diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h
index ce71500eb002da429594ef3ebf0bf49c0eebb19f..1dc6a1169df70c9e9289f66d2087a8cadeae29f9 100644
--- a/common/utils/nr/nr_common.h
+++ b/common/utils/nr/nr_common.h
@@ -156,6 +156,7 @@ typedef struct {
 
 typedef struct {
   bool active;
+  bool suspended;
   uint32_t counter;
   uint32_t target;
   uint32_t step;
@@ -171,6 +172,12 @@ void nr_timer_start(NR_timer_t *timer);
  * @param timer Timer to stopped
  */
 void nr_timer_stop(NR_timer_t *timer);
+/**
+ * @brief To suspend/resume a timer
+ * @param timer Timer to be stopped/suspended
+ */
+void nr_timer_suspension(NR_timer_t *timer);
+
 /**
  * @brief If active, it increases timer counter by an amout of units equal to step. It stops timer if expired
  * @param timer Timer to be handled
diff --git a/common/utils/telnetsrv/telnetsrv_ciUE.c b/common/utils/telnetsrv/telnetsrv_ciUE.c
index dd95f8009c0fe2318cd7493cb0bf2730475bbb8a..721cb0e5cd772e4d9d9b76e244772850e2adc7d0 100644
--- a/common/utils/telnetsrv/telnetsrv_ciUE.c
+++ b/common/utils/telnetsrv/telnetsrv_ciUE.c
@@ -94,11 +94,20 @@ int force_RRC_IDLE(char *buf, int debug, telnet_printfunc_t prnt)
   return 0;
 }
 
+/** @brief Trigger RA with Msg3 C-RNTI */
+int force_crnti_ra(char *buf, int debug, telnet_printfunc_t prnt)
+{
+  NR_UE_MAC_INST_t *mac = get_mac_inst(0);
+  trigger_MAC_UE_RA(mac, NULL);
+  return 0;
+}
+
 /* Telnet shell command definitions */
 static telnetshell_cmddef_t cicmds[] = {
   {"sync_state", "[UE_ID(int,opt)]", get_sync_state},
   {"force_rlf", "", force_rlf},
   {"force_RRC_IDLE", "", force_RRC_IDLE},
+  {"force_crnti_ra", "", force_crnti_ra},
   {"", "", NULL},
 };
 
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index cc72eed263067d4ad28a3c15b15b77a35c7888a3..41032a3d42c131042b3a55881f5c61e9b989ec50 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -147,6 +147,24 @@ static void *nrL1_UE_stats_thread(void *param)
   return NULL;
 }
 
+static int determine_N_TA_offset(PHY_VARS_NR_UE *ue) {
+  if (ue->sl_mode == 2)
+    return 0;
+  else {
+    int N_TA_offset = ue->nrUE_config.cell_config.N_TA_offset;
+    if (N_TA_offset == -1) {
+      return set_default_nta_offset(ue->frame_parms.freq_range, ue->frame_parms.samples_per_subframe);
+    } else {
+      // Return N_TA_offet in samples, as described in 38.211 4.1 and 4.3.1
+      // T_c[s] =  1/(Δf_max x N_f) = 1 / (480 * 1000 * 4096)
+      // N_TA_offset[s] = N_TA_offset x T_c
+      // N_TA_offset[samples] = samples_per_second x N_TA_offset[s]
+      // N_TA_offset[samples] = N_TA_offset x samples_per_subframe x 1000 x T_c
+      return (N_TA_offset * ue->frame_parms.samples_per_subframe) / (4096 * 480);
+    }
+  }
+}
+
 void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id)
 {
   int nb_connected_gNB = 1;
@@ -165,8 +183,8 @@ void init_nr_ue_vars(PHY_VARS_NR_UE *ue, uint8_t UE_id)
   // intialize transport
   init_nr_ue_transport(ue);
 
-  // init N_TA offset
-  init_N_TA_offset(ue);
+  ue->ta_frame = -1;
+  ue->ta_slot = -1;
 }
 
 void init_nrUE_standalone_thread(int ue_idx)
@@ -519,7 +537,7 @@ void processSlotTX(void *arg)
   bool sl_tx_action = false;
 
   if (UE->if_inst)
-    UE->if_inst->slot_indication(UE->Mod_id);
+    UE->if_inst->slot_indication(UE->Mod_id, true);
 
   if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT) {
     if (UE->sl_mode == 2 && proc->tx_slot_type == NR_SIDELINK_SLOT) {
@@ -650,6 +668,9 @@ static int UE_dl_preprocessing(PHY_VARS_NR_UE *UE,
     }
   }
 
+  if (UE->if_inst)
+    UE->if_inst->slot_indication(UE->Mod_id, false);
+
   bool dl_slot = false;
   if (proc->rx_slot_type == NR_DOWNLINK_SLOT || proc->rx_slot_type == NR_MIXED_SLOT) {
     dl_slot = true;
@@ -867,6 +888,7 @@ void *UE_thread(void *arg)
   initNotifiedFIFO_nothreadSafe(&freeBlocks);
 
   int timing_advance = UE->timing_advance;
+  UE->N_TA_offset = determine_N_TA_offset(UE);
   NR_UE_MAC_INST_t *mac = get_mac_inst(UE->Mod_id);
 
   bool syncRunning = false;
@@ -1095,9 +1117,16 @@ void *UE_thread(void *arg)
 
     // but use current UE->timing_advance value to compute writeBlockSize
     int writeBlockSize = fp->get_samples_per_slot((slot_nr + duration_rx_to_tx) % nb_slot_frame, fp) - iq_shift_to_apply;
-    if (UE->timing_advance != timing_advance) {
-      writeBlockSize -= UE->timing_advance - timing_advance;
-      timing_advance = UE->timing_advance;
+    int new_timing_advance = UE->timing_advance;
+    if (new_timing_advance != timing_advance) {
+      writeBlockSize -= new_timing_advance- timing_advance;
+      timing_advance = new_timing_advance;
+    }
+    int new_N_TA_offset = determine_N_TA_offset(UE);
+    if (new_N_TA_offset != UE->N_TA_offset) {
+      LOG_I(PHY, "N_TA_offset changed from %d to %d\n", UE->N_TA_offset, new_N_TA_offset);
+      writeBlockSize -= new_N_TA_offset - UE->N_TA_offset;
+      UE->N_TA_offset = new_N_TA_offset;
     }
 
     if (curMsg.proc.nr_slot_tx == 0)
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index d5f4a528ffd19c93d26be660881da7876cbdb7f6..2ba05ae20037180fe6568cdce2274b2f45c0bc31 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -465,6 +465,10 @@ int main(int argc, char **argv)
     get_channel_model_mode(uniqCfg);
   }
 
+  // Delay to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
+  if (IS_SOFTMODEM_RFSIM && !get_softmodem_params()->phy_test)
+    sleep(3);
+
   if (!get_softmodem_params()->nsa && get_softmodem_params()->emulate_l1)
     start_oai_nrue_threads();
 
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
index 881d7fad8e0c60ad347915408cd0393bea71bc92..a5d6087856c2ac916c2f47410abe01d8d4e59ca5 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_interface.h
@@ -551,7 +551,6 @@ typedef struct {
  int ta_frame;
  int ta_slot;
  int ta_command;
- int ta_offset;
  bool is_rar;
 } fapi_nr_ta_command_pdu;
 
@@ -616,7 +615,7 @@ typedef struct
 {
   uint8_t phy_cell_id;//Physical Cell ID, 𝑁_{𝐼𝐷}^{𝑐𝑒𝑙𝑙} [38.211, sec 7.4.2.1] Value: 0 ->1007
   uint8_t frame_duplex_type;//Frame duplex type Value: 0 = FDD 1 = TDD
-
+  uint32_t N_TA_offset;
 } fapi_nr_cell_config_t;
 
 typedef struct 
diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c
index 9b36197e45ee9ea22a04fbfe55f4d50d5d6e8cdf..c7bb47c581a56ba3424b0fd0cc32d77650b101e5 100644
--- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c
+++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_segment/nrLDPC_coding_segment_decoder.c
@@ -218,7 +218,7 @@ static void nr_process_decode_segment(void *arg)
   int decodeIterations =
       LDPCdecoder(p_decoderParms, 0, 0, 0, l, llrProcBuf, p_procTime, rdata->abort_decode);
 
-  if (decodeIterations <= p_decoderParms->numMaxIter) {
+  if (decodeIterations < p_decoderParms->numMaxIter) {
     memcpy(rdata->c, llrProcBuf, K >> 3);
     *rdata->decodeSuccess = true;
   } else {
diff --git a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
index 7960215ab7bb8ba76f081196f82eb9d4c2e375a1..b23db3781da1106585b9171846c5f86a634fb156 100644
--- a/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
+++ b/openair1/PHY/CODING/nrLDPC_coding/nrLDPC_coding_xdma/nrLDPC_coding_xdma.c
@@ -277,8 +277,8 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int s
 
   for (uint32_t job = 0; job < num_threads_prepare; job++) {
     args_fpga_decode_prepare_t *args = &arr[job];
-    if (args->no_iteration_ldpc > TB_params->max_ldpc_iterations)
-      no_iteration_ldpc = TB_params->max_ldpc_iterations + 1;
+    if (args->no_iteration_ldpc >= TB_params->max_ldpc_iterations)
+      no_iteration_ldpc = TB_params->max_ldpc_iterations;
   }
 
   // launch decode with FPGA
@@ -306,12 +306,12 @@ int decoder_xdma(nrLDPC_TB_decoding_parameters_t *TB_params, int frame_rx, int s
 #ifdef DEBUG_CRC
       LOG_I(PHY, "segment %d CRC NOK\n", r);
 #endif
-      no_iteration_ldpc = TB_params->max_ldpc_iterations + 1;
+      no_iteration_ldpc = TB_params->max_ldpc_iterations;
     }
     for (int i = 0; i < out_CBoffset; i++) {
       segment_params->c[i] = multi_outdata[i + r * out_CBoffset];
     }
-    segment_params->decodeSuccess = (no_iteration_ldpc <= TB_params->max_ldpc_iterations);
+    segment_params->decodeSuccess = (no_iteration_ldpc < TB_params->max_ldpc_iterations);
     if (segment_params->decodeSuccess) {
       *TB_params->processedSegments = *TB_params->processedSegments + 1;
     }
@@ -396,7 +396,7 @@ void nr_ulsch_FPGA_decoding_prepare_blocks(void *args)
         == -1) {
       stop_meas(&segment_params->ts_rate_unmatch);
       LOG_E(PHY, "ulsch_decoding.c: Problem in rate_matching\n");
-      no_iteration_ldpc = max_ldpc_iterations + 1;
+      no_iteration_ldpc = max_ldpc_iterations;
       arguments->no_iteration_ldpc = no_iteration_ldpc;
       return;
     } else {
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
index fcee71c1510b303d6fa5cea5a5c34ab7885ddfa3..e2ed7fce10fa491649d36ae987efc01fdd844368 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder.c
@@ -187,7 +187,7 @@ int32_t LDPCdecoder(t_nrLDPC_dec_params* p_decParams,
 
   // Launch LDPC decoder core for one segment
   int numIter = nrLDPC_decoder_core(p_llr, p_out, numLLR, p_lut, p_decParams, p_profiler, ab);
-  if (numIter > p_decParams->numMaxIter) {
+  if (numIter >= p_decParams->numMaxIter) {
     LOG_D(PHY, "set abort: %d, %d\n", numIter, p_decParams->numMaxIter);
     set_abort(ab, true);
   }
@@ -549,13 +549,11 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr,
     // estimated after only one iteration
 
     // First iteration finished
-    uint32_t numIter = 1;
+    uint32_t numIter = 0;
     int32_t pcRes = 1; // pcRes is 0 if the ldpc decoder is succesful
-    while ((numIter <= numMaxIter) && (pcRes != 0)) {
-      // Increase iteration counter
-      numIter++;
+    while ((numIter < numMaxIter) && (pcRes != 0)) {
       if (check_abort(ab)) {
-        numIter = numMaxIter + 2;
+        numIter = numMaxIter;
         break;
       }
       // CN processing
@@ -847,7 +845,7 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr,
             pcRes = nrLDPC_cnProcPc_BG2(p_lut, cnProcBuf, cnProcBufRes, Z);
           NR_LDPC_PROFILER_DETAIL(stop_meas(&p_profiler->cnProcPc));
         } else {
-          if (numIter > 2) {
+          if (numIter > 0) {
             int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__((aligned(64))) = {0};
             int8_t* p_llrOut = outMode == nrLDPC_outMode_LLRINT8 ? p_out : llrOut;
             nrLDPC_llrRes2llrOut(p_lut, p_llrOut, llrRes, Z, BG);
@@ -861,6 +859,8 @@ static inline uint32_t nrLDPC_decoder_core(int8_t* p_llr,
             }
           }
         }
+      // Increase iteration counter
+      numIter++;
     }
     if (!p_decParams->check_crc) {
       int8_t llrOut[NR_LDPC_MAX_NUM_LLR] __attribute__((aligned(64))) = {0};
diff --git a/openair1/PHY/INIT/nr_init_ue.c b/openair1/PHY/INIT/nr_init_ue.c
index 019e386fd0944dc230f3dd97eb5eb402b308930e..19816e215fda7a5d337cc758ff42ad0592068077 100644
--- a/openair1/PHY/INIT/nr_init_ue.c
+++ b/openair1/PHY/INIT/nr_init_ue.c
@@ -492,24 +492,6 @@ void clean_UE_harq(PHY_VARS_NR_UE *UE)
   }
 }
 
-
-void init_N_TA_offset(PHY_VARS_NR_UE *ue)
-{
-  NR_DL_FRAME_PARMS *fp = &ue->frame_parms;
-
-  // No timing offset for Sidelink, refer to 3GPP 38.211 Section 8.5
-  if (ue->sl_mode == 2)
-    ue->N_TA_offset = 0;
-  else
-    ue->N_TA_offset = set_default_nta_offset(fp->freq_range, fp->samples_per_subframe);
-  ue->ta_frame = -1;
-  ue->ta_slot = -1;
-
-  LOG_I(PHY,
-        "UE %d Setting N_TA_offset to %d samples (UL Freq %lu, N_RB %d, mu %d)\n",
-        ue->Mod_id, ue->N_TA_offset, fp->ul_CarrierFreq, fp->N_RB_DL, fp->numerology_index);
-}
-
 void phy_init_nr_top(PHY_VARS_NR_UE *ue) {
   NR_DL_FRAME_PARMS *frame_parms = &ue->frame_parms;
   init_delay_table(frame_parms->ofdm_symbol_size, MAX_DELAY_COMP, NR_MAX_OFDM_SYMBOL_SIZE, frame_parms->delay_table);
diff --git a/openair1/PHY/INIT/nr_phy_init.h b/openair1/PHY/INIT/nr_phy_init.h
index d2c65e939f20836f49bb08009919a011b04dd783..1b1a0fa1b084c7502bccb3beb946cb0ac0088640 100644
--- a/openair1/PHY/INIT/nr_phy_init.h
+++ b/openair1/PHY/INIT/nr_phy_init.h
@@ -36,7 +36,6 @@ int nr_init_frame_parms_ue_sl(NR_DL_FRAME_PARMS *fp,
 int init_nr_ue_signal(PHY_VARS_NR_UE *ue,int nb_connected_eNB);
 void term_nr_ue_signal(PHY_VARS_NR_UE *ue, int nb_connected_gNB);
 void init_nr_ue_transport(PHY_VARS_NR_UE *ue);
-void init_N_TA_offset(PHY_VARS_NR_UE *ue);
 void nr_dump_frame_parms(NR_DL_FRAME_PARMS *frame_parms);
 void phy_init_nr_gNB(PHY_VARS_gNB *gNB);
 int init_codebook_gNB(PHY_VARS_gNB *gNB);
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
index a3138f5d7fd80b4f7e267589000cf0e30844dfe2..e6b4503e1bbc53009aee909e9fac4f62e69e8be7 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_dlsch_decoding.c
@@ -59,14 +59,14 @@ void nr_dlsch_unscrambling(int16_t *llr, uint32_t size, uint8_t q, uint32_t Nid,
 
 /*! \brief Prepare necessary parameters for nrLDPC_coding_interface
  */
-uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
-                           const UE_nr_rxtx_proc_t *proc,
-                           NR_UE_DLSCH_t *dlsch,
-                           int16_t **dlsch_llr,
-                           uint8_t **b,
-                           int *G,
-                           int nb_dlsch,
-                           uint8_t *DLSCH_ids)
+void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
+                       const UE_nr_rxtx_proc_t *proc,
+                       NR_UE_DLSCH_t *dlsch,
+                       int16_t **dlsch_llr,
+                       uint8_t **b,
+                       int *G,
+                       int nb_dlsch,
+                       uint8_t *DLSCH_ids)
 {
   nrLDPC_TB_decoding_parameters_t TBs[nb_dlsch];
   memset(TBs, 0, sizeof(TBs));
@@ -100,7 +100,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
     if (!harq_process) {
       LOG_E(PHY, "dlsch_decoding_slot.c: NULL harq_process pointer\n");
-      return dlsch[DLSCH_id].max_ldpc_iterations + 1;
+      return;
     }
 
     nrLDPC_TB_decoding_parameters_t *TB_parameters = &TBs[pdsch_id];
@@ -164,7 +164,7 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
       if (harq_process->C > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * TB_parameters->nb_layers) {
         LOG_E(PHY, "nr_segmentation.c: too many segments %d, A %d\n", harq_process->C, TB_parameters->A);
-        return dlsch[DLSCH_id].max_ldpc_iterations + 1;
+        return;
       }
 
       if (LOG_DEBUGFLAG(DEBUG_DLSCH_DECOD) && (!slot_parameters.frame % 100))
@@ -242,7 +242,8 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
   int ret_decoder = phy_vars_ue->nrLDPC_coding_interface.nrLDPC_coding_decoder(&slot_parameters);
 
   if (ret_decoder != 0) {
-    return dlsch->max_ldpc_iterations + 1;
+    LOG_E(PHY, "nrLDPC_coding_decoder returned an error: %d\n", ret_decoder);
+    return;
   }
 
   // post decode
@@ -316,11 +317,11 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
     if (harq_process->decodeResult) {
       LOG_D(PHY, "DLSCH received ok \n");
       harq_process->status = SCH_IDLE;
-      dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations;
+      dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations - 1;
     } else {
       LOG_D(PHY, "DLSCH received nok \n");
       kpiStructure.nb_nack++;
-      dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations + 1;
+      dlsch->last_iteration_cnt = dlsch->max_ldpc_iterations;
       UEdumpScopeData(phy_vars_ue, proc->nr_slot_rx, proc->frame_rx, "DLSCH_NACK");
     }
 
@@ -355,5 +356,4 @@ uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
 
   }
 
-  return dlsch[0].last_iteration_cnt;
 }
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
index 0ca616ba341bf6f545dbec457b521d438ec4b1d6..bb1a6c03df85fd98c49642cb103c930b88b083f5 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_proto_ue.h
@@ -81,14 +81,14 @@ void nr_conjch0_mult_ch1(int *ch0,
     @param[in] DLSCH_ids array of active downlink shared channels
     @returns 0 on success, 1 on unsuccessful decoding
 */
-uint32_t nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
-                           const UE_nr_rxtx_proc_t *proc,
-                           NR_UE_DLSCH_t *dlsch,
-                           short **dlsch_llr,
-                           uint8_t **b,
-                           int *G,
-                           int nb_dlsch,
-                           uint8_t *DLSCH_ids);
+void nr_dlsch_decoding(PHY_VARS_NR_UE *phy_vars_ue,
+                       const UE_nr_rxtx_proc_t *proc,
+                       NR_UE_DLSCH_t *dlsch,
+                       short **dlsch_llr,
+                       uint8_t **b,
+                       int *G,
+                       int nb_dlsch,
+                       uint8_t *DLSCH_ids);
 
 /** \brief This is the alternative top-level entry point for ULSCH encoding in UE.
     It handles all the HARQ processes in only one call. The routine first
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
index 419988a9612a9912985c4ee09a3c84ff30fe2127..07917b9075e6461702e084c6e8cc1cecf38c0973 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_transport_ue.h
@@ -147,7 +147,7 @@ typedef struct {
   /// Maximum number of LDPC iterations
   uint8_t max_ldpc_iterations;
   /// number of iterations used in last turbo decoding
-  uint8_t last_iteration_cnt;
+  int8_t last_iteration_cnt;
   /// bit mask of PT-RS ofdm symbol indicies
   uint16_t ptrs_symbols;
   // PTRS symbol index, to be updated every PTRS symbol within a slot.
diff --git a/openair1/PHY/defs_gNB.h b/openair1/PHY/defs_gNB.h
index eb0a1acc0e92ef4e038acf7145f2ca27075b280e..47d41db44bc7a5562a0592f3f6426ff94561f536 100644
--- a/openair1/PHY/defs_gNB.h
+++ b/openair1/PHY/defs_gNB.h
@@ -239,7 +239,7 @@ typedef struct {
   /// Maximum number of LDPC iterations
   uint8_t max_ldpc_iterations;
   /// number of iterations used in last LDPC decoding
-  uint8_t last_iteration_cnt;
+  int8_t last_iteration_cnt;
   /// Status Flag indicating for this ULSCH
   bool active;
   /// Flag to indicate that the UL configuration has been handled. Used to remove a stale ULSCH when frame wraps around
diff --git a/openair1/SCHED_NR/phy_procedures_nr_gNB.c b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
index 1484d44ddfb21cff71dc5cc36d651fd45806988d..4f1f8ff01004ea67e06f025a12e3b332f065de92 100644
--- a/openair1/SCHED_NR/phy_procedures_nr_gNB.c
+++ b/openair1/SCHED_NR/phy_procedures_nr_gNB.c
@@ -424,7 +424,7 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo
       LOG_D(PHY, "ULSCH received ok \n");
       ulsch->active = false;
       ulsch_harq->round = 0;
-      ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure
+      ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations - 1; // Setting to max_ldpc_iterations - 1 is sufficient given that this variable is only used for checking for failure
     } else {
       LOG_D(PHY,
             "[gNB %d] ULSCH: Setting NAK for SFN/SF %d/%d (pid %d, ndi %d, status %d, round %d, RV %d, prb_start %d, prb_size %d, "
@@ -444,7 +444,7 @@ static int nr_ulsch_procedures(PHY_VARS_gNB *gNB, int frame_rx, int slot_rx, boo
       gNBdumpScopeData(gNB, ulsch->slot, ulsch->frame, "ULSCH_NACK");
       ulsch->handled = 1;
       LOG_D(PHY, "ULSCH %d in error\n",ULSCH_id);
-      ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations + 1; // Setting to max_ldpc_iterations + 1 is sufficient given that this variable is only used for checking for failure
+      ulsch->last_iteration_cnt = ulsch->max_ldpc_iterations; // Setting to max_ldpc_iterations is sufficient given that this variable is only used for checking for failure
     }
   }
 
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
index fbfc9d838903df9cba79f588373964663a6a5347..ba4ad4a0f7b0d9d7700b94a12d222106b4b78b18 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
@@ -419,15 +419,6 @@ static void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_
   LOG_D(PHY,
         "TA command received in %d.%d Starting UL time alignment procedures. TA update will be applied at frame %d slot %d\n",
         ta_command_pdu->ta_frame, ta_command_pdu->ta_slot, ue->ta_frame, ue->ta_slot);
-
-  if (ta_command_pdu->ta_offset != -1) {
-    // ta_offset_samples : ta_offset = samples_per_subframe : (Δf_max x N_f / 1000)
-    // As described in Section 4.3.1 in 38.211
-    int ta_offset_samples = (ta_command_pdu->ta_offset * samples_per_subframe) / (4096 * 480);
-    ue->N_TA_offset = ta_offset_samples;
-    LOG_D(PHY, "Received N_TA offset %d from upper layers. Corresponds to %d samples.\n",
-          ta_command_pdu->ta_offset, ta_offset_samples);
-  }
 }
 
 static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac,
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index b57bf4eff34e0ff39ecd95b9b26892c0221a4979..283673a6df921e9137c365e2c72232e3157ae349 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -686,20 +686,18 @@ static uint32_t compute_csi_rm_unav_res(fapi_nr_dl_config_dlsch_pdu_rel15_t *dls
 
 /*! \brief Process the whole DLSCH slot
  */
-static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
+static void nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
                                    const UE_nr_rxtx_proc_t *proc,
                                    NR_UE_DLSCH_t dlsch[2],
                                    int16_t *llr[2]) {
   if (dlsch[0].active == false) {
     LOG_E(PHY, "DLSCH should be active when calling this function\n");
-    return true;
+    return;
   }
 
-  bool dec = false;
   int harq_pid = dlsch[0].dlsch_config.harq_process_nbr;
   int frame_rx = proc->frame_rx;
   int nr_slot_rx = proc->nr_slot_rx;
-  uint32_t ret = UINT32_MAX;
   NR_DL_UE_HARQ_t *dl_harq0 = &ue->dl_harq_processes[0][harq_pid];
   NR_DL_UE_HARQ_t *dl_harq1 = &ue->dl_harq_processes[1][harq_pid];
   uint16_t dmrs_len = get_num_dmrs(dlsch[0].dlsch_config.dlDmrsSymbPos);
@@ -732,7 +730,7 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
     const int ack_nack_slot_and_frame =
         (proc->nr_slot_rx + dlsch[0].dlsch_config.k1_feedback) + proc->frame_rx * ue->frame_parms.slots_per_frame;
     dynamic_barrier_join(&ue->process_slot_tx_barriers[ack_nack_slot_and_frame % NUM_PROCESS_SLOT_TX_BARRIERS]);
-    return false;
+    return;
   }
 
   int G[2];
@@ -765,11 +763,9 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
   }
 
   start_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
-  ret = nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
+  nr_dlsch_decoding(ue, proc, dlsch, llr, p_b, G, nb_dlsch, DLSCH_ids);
   stop_meas_nr_ue_phy(ue, DLSCH_DECODING_STATS);
 
-  if (ret < ue->max_ldpc_iterations + 1) dec = true;
-
   int ind_type = -1;
   switch (dlsch[0].rnti_type) {
     case TYPE_RA_RNTI_:
@@ -829,7 +825,6 @@ static bool nr_ue_dlsch_procedures(PHY_VARS_NR_UE *ue,
   else if (ue->phy_sim_dlsch_b && is_cw1_active == ACTIVE)
     memcpy(ue->phy_sim_dlsch_b, p_b[1], dlsch_bytes);
 
-  return dec;
 }
 
 static bool is_ssb_index_transmitted(const PHY_VARS_NR_UE *ue, const int index)
diff --git a/openair1/SIMULATION/NR_PHY/dlschsim.c b/openair1/SIMULATION/NR_PHY/dlschsim.c
index de5c598015d8bd0673652bfcd6a40300798c877e..977970c9f7394d22dae085141ed2368601b532b5 100644
--- a/openair1/SIMULATION/NR_PHY/dlschsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlschsim.c
@@ -123,7 +123,6 @@ int main(int argc, char **argv)
   NR_DL_FRAME_PARMS *frame_parms;
   double sigma;
   unsigned char qbits = 8;
-  int ret;
   int loglvl = OAILOG_WARNING;
   uint8_t dlsch_threads = 0;
   float target_error_rate = 0.01;
@@ -577,18 +576,18 @@ int main(int argc, char **argv)
       short *p_channel_output_fixed = channel_output_fixed;
       uint8_t *p_b = b;
       int available_bits_array[1] = { available_bits };
-      ret = nr_dlsch_decoding(UE,
-                              &proc,
-                              dlsch0_ue,
-                              &p_channel_output_fixed,
-                              &p_b,
-                              available_bits_array,
-                              1,
-                              DLSCH_ids);
+      nr_dlsch_decoding(UE,
+                        &proc,
+                        dlsch0_ue,
+                        &p_channel_output_fixed,
+                        &p_b,
+                        available_bits_array,
+                        1,
+                        DLSCH_ids);
 
       vcd_signal_dumper_dump_function_by_name(VCD_SIGNAL_DUMPER_FUNCTIONS_DLSCH_DECODING0, VCD_FUNCTION_OUT);
 
-      if (ret > dlsch0_ue->max_ldpc_iterations)
+      if (dlsch0_ue->last_iteration_cnt > dlsch0_ue->max_ldpc_iterations)
 				n_errors++;
 
 			//count errors
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 9014cd33ef07758dee3f05875a0fe09ef4efc40e..76c888194553c2dc233449f6a77c9d3fa4962252 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -1163,7 +1163,7 @@ printf("%d\n", slot);
         //---------------------- count errors ----------------------
         //----------------------------------------------------------
 
-        if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations+1)
+        if (dlsch0->last_iteration_cnt >= dlsch0->max_ldpc_iterations)
           n_errors[round]++;
 
         int16_t *UE_llr = (int16_t*)UE->phy_sim_pdsch_llr;
diff --git a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c
index d55322156b3a2a3a5b53d9f48a62f5a460ce30d7..973aa60930075eac9fbf54a56b248d4db9be6f4e 100644
--- a/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c
+++ b/openair1/SIMULATION/NR_PHY/nr_dummy_functions.c
@@ -36,7 +36,7 @@ void nr_mac_rrc_sync_ind(const module_id_t module_id,
 
 void nr_mac_rrc_msg3_ind(const module_id_t mod_id, int rnti, int gnb_id) {}
 
-void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success) {}
+void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success) {}
 
 void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id) {}
 
diff --git a/openair1/SIMULATION/NR_PHY/prachsim.c b/openair1/SIMULATION/NR_PHY/prachsim.c
index ce00f6ae9e761ed51e062d0f6028360498a6ded3..eb3537650b1e2189f763ee5f3864dbc6ca12c68f 100644
--- a/openair1/SIMULATION/NR_PHY/prachsim.c
+++ b/openair1/SIMULATION/NR_PHY/prachsim.c
@@ -136,13 +136,11 @@ int main(int argc, char **argv){
   c16_t **txdata;
   int N_RB_UL = 106, delay = 0, NCS_config = 13, rootSequenceIndex = 1, threequarter_fs = 0, mu = 1, fd_occasion = 0, loglvl = OAILOG_INFO, numRA = 0, prachStartSymbol = 0;
   uint8_t snr1set = 0, ue_speed1set = 0, transmission_mode = 1, n_tx = 1, n_rx = 1, awgn_flag = 0, msg1_frequencystart = 0, num_prach_fd_occasions = 1, prach_format=0;
-  uint8_t config_index = 98, prach_sequence_length = 1, restrictedSetConfig = 0, N_dur, N_t_slot, start_symbol;
-  uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format, format0, format1;
+  uint8_t config_index = 98, prach_sequence_length = 1, restrictedSetConfig = 0;
+  uint16_t Nid_cell = 0, preamble_tx = 0, preamble_delay, format0, format1;
   uint32_t tx_lev = 10000, prach_errors = 0; //,tx_lev_dB;
   uint64_t SSB_positions = 0x01;
   uint16_t RA_sfn_index;
-  uint8_t N_RA_slot;
-  uint8_t config_period;
   int prachOccasion = 0;
   double DS_TDL = .03;
 
@@ -482,25 +480,24 @@ int main(int argc, char **argv){
   gNB->gNB_config.prach_config.num_prach_fd_occasions.value = num_prach_fd_occasions;
   gNB->gNB_config.prach_config.num_prach_fd_occasions_list = (nfapi_nr_num_prach_fd_occasions_t *) malloc(num_prach_fd_occasions*sizeof(nfapi_nr_num_prach_fd_occasions_t));
 
-  gNB->proc.slot_rx       = slot;
-
-  int ret = get_nr_prach_info_from_index(config_index,
-					 (int)frame,
-					 (int)slot,
-					 absoluteFrequencyPointA,
-					 mu,
-					 frame_parms->frame_type,
-					 &format,
-					 &start_symbol,
-					 &N_t_slot,
-					 &N_dur,
-					 &RA_sfn_index,
-					 &N_RA_slot,
-					 &config_period);
-
-  if (ret == 0) {printf("No prach in %d.%d, mu %d, config_index %d\n",frame,slot,mu,config_index); exit(-1);}
-  format0 = format&0xff;      // first column of format from table
-  format1 = (format>>8)&0xff; // second column of format from table
+  gNB->proc.slot_rx = slot;
+  frequency_range_t freq_range = absoluteFrequencyPointA > 2016666 ? FR2 : FR1;
+  nr_prach_info_t prach_info = get_nr_prach_occasion_info_from_index(config_index, freq_range, frame_parms->frame_type);
+  int ret = get_nr_prach_sched_from_info(prach_info,
+                                         config_index,
+                                         frame,
+                                         slot,
+                                         mu,
+                                         freq_range,
+                                         &RA_sfn_index,
+                                         frame_parms->frame_type);
+
+  if (ret == 0) {
+    printf("No prach in %d.%d, mu %d, config_index %d\n", frame, slot, mu, config_index);
+    exit(-1);
+  }
+  format0 = prach_info.format & 0xff; // first column of format from table
+  format1 = (prach_info.format >> 8) & 0xff; // second column of format from table
 
   if (format1 != 0xff) {
     switch(format0) {
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index b45ca38254a8583bbe5cfb60f4eefd54011485c4..4013951cab82ceba1706eaf52c1add29e27d12b2 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -1420,7 +1420,7 @@ int main(int argc, char *argv[])
                 0);
         }
 
-        if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations + 1) || ul_proc_error == 1) {
+        if ((ulsch_gNB->last_iteration_cnt >= ulsch_gNB->max_ldpc_iterations) || ul_proc_error == 1) {
           error_flag = 1;
           n_errors[round]++;
           crc_status = 1;
diff --git a/openair2/COMMON/mac_messages_types.h b/openair2/COMMON/mac_messages_types.h
index bc9e8f6c8aec2926720c6241604fdb8d3fef0042..ebbda2fc268e398c71279d1fc32e05dadba7e555 100644
--- a/openair2/COMMON/mac_messages_types.h
+++ b/openair2/COMMON/mac_messages_types.h
@@ -72,13 +72,13 @@
 // Messages between RRC and MAC layers
 
 typedef struct NRRrcMacRaInd_s {
-  uint32_t frame;
   bool RA_succeeded;
 } NRRrcMacRaInd;
 
 typedef struct NRRrcMacMsg3Ind_s {
   uint16_t rnti;
   int gnb_id;
+  bool prepare_payload;
 } NRRrcMacMsg3Ind;
 
 typedef struct NRRrcMacInacInd_s {
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h
index 143d4623d70f51419369374dd31c77ab83954dcb..a83c85dd254b6b3017a8343bc94ea8c912daa470 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac.h
@@ -461,36 +461,6 @@ typedef struct {
 #define NR_MAX_NUM_LCGID              8
 #define MAX_RLC_SDU_SUBHEADER_SIZE          3
 
-//===========
-// PRACH defs
-//===========
-
-// ===============================================
-// SSB to RO mapping public defines and structures
-// ===============================================
-#define MAX_SSB_PER_RO (16) // Maximum number of SSBs that can be mapped to a single RO
-#define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot
-#define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot
-
-// PRACH occasion details
-typedef struct prach_occasion_info {
-  uint8_t start_symbol; // 0 - 13 (14 symbols in a slot)
-  uint8_t fdm; // 0-7 (possible values of msg1-FDM: 1, 2, 4 or 8)
-  uint8_t slot; // 0 - 159 (maximum number of slots in a 10ms frame - @ 240kHz)
-  uint8_t frame; // 0 - 15 (maximum number of frames in a 160ms association pattern)
-  uint8_t mapped_ssb_idx[MAX_SSB_PER_RO]; // List of mapped SSBs
-  uint8_t nb_mapped_ssb;
-  uint16_t format; // RO preamble format
-} prach_occasion_info_t;
-
-// PRACH occasion slot details
-// A PRACH occasion slot is a series of PRACH occasions in time (symbols) and frequency
-typedef struct prach_occasion_slot {
-  prach_occasion_info_t *prach_occasion; // Starting symbol of each PRACH occasions in a slot
-  uint8_t nb_of_prach_occasion_in_time;
-  uint8_t nb_of_prach_occasion_in_freq;
-} prach_occasion_slot_t;
-
 //=========
 // DCI defs
 //=========
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index f3693e2791097a16932d9c731b7859d5468cf294..2da3d9df93c8d95b774268293873ea6471c5d2b6 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -571,34 +571,33 @@ NR_tda_info_t get_dl_tda_info(const NR_UE_DL_BWP_t *dl_BWP,
   return tda_info;
 }
 
-uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config) {
-
-  LOG_D(MAC,"get_NCS: indx %d,format0 %d, restriced_set_config %d\n",
-	index,format0,restricted_set_config);
+uint16_t get_NCS(uint8_t index, uint16_t format0, uint8_t restricted_set_config)
+{
+  LOG_D(NR_MAC, "get_NCS: indx %d,format0 %d, restriced_set_config %d\n", index, format0, restricted_set_config);
 
   if (format0 < 3) {
-    switch(restricted_set_config){
+    switch (restricted_set_config) {
       case 0:
         return(NCS_unrestricted_delta_f_RA_125[index]);
       case 1:
         return(NCS_restricted_TypeA_delta_f_RA_125[index]);
       case 2:
         return(NCS_restricted_TypeB_delta_f_RA_125[index]);
-    default:
-      AssertFatal(1==0,"Invalid restricted set config value %d",restricted_set_config);
+      default:
+        AssertFatal(false, "Invalid restricted set config value %d", restricted_set_config);
     }
   }
   else {
     if (format0 == 3) {
-      switch(restricted_set_config){
+      switch (restricted_set_config) {
         case 0:
           return(NCS_unrestricted_delta_f_RA_5[index]);
         case 1:
           return(NCS_restricted_TypeA_delta_f_RA_5[index]);
         case 2:
           return(NCS_restricted_TypeB_delta_f_RA_5[index]);
-      default:
-        AssertFatal(1==0,"Invalid restricted set config value %d",restricted_set_config);
+        default:
+          AssertFatal(false, "Invalid restricted set config value %d", restricted_set_config);
       }
     }
     else
@@ -1418,11 +1417,9 @@ static const int64_t table_6_3_3_2_4_prachConfig_Index[256][10] = {
     {0xa3, 0xb3, 1, 0, -1, 733007751850, 2, 1, 2, 6} // (subframe number :1,3,5,7,…,37,39)
 };
 
-int get_format0(uint8_t index,
-                uint8_t unpaired,
-		frequency_range_t frequency_range){
-
-  uint16_t format=0;
+int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range)
+{
+  int format = 0;
   if (unpaired) {
     if (frequency_range==FR1)
       format = table_6_3_3_2_3_prachConfig_Index[index][0];
@@ -1438,23 +1435,6 @@ int get_format0(uint8_t index,
   return format;
 }
 
-const int64_t *get_prach_config_info(frequency_range_t freq_range, uint8_t index, uint8_t unpaired)
-{
-  const int64_t *prach_config_info_p;
-
-  if (freq_range == FR2) { //FR2
-    prach_config_info_p = table_6_3_3_2_4_prachConfig_Index[index];
-  }
-  else { // FR1
-    if (unpaired)
-      prach_config_info_p = table_6_3_3_2_3_prachConfig_Index[index];
-    else
-      prach_config_info_p = table_6_3_3_2_2_prachConfig_Index[index];
-  } // FR2 / FR1
-
-  return prach_config_info_p;
-}
-
 void find_aggregation_candidates(uint8_t *aggregation_level,
                                  uint8_t *nr_of_candidates,
                                  const NR_SearchSpace_t *ss,
@@ -1567,97 +1547,83 @@ void set_monitoring_periodicity_offset(NR_SearchSpace_t *ss,
 }
 
 
-int get_nr_prach_occasion_info_from_index(uint8_t index,
-                                          uint32_t pointa,
-                                          uint8_t mu,
-                                          uint8_t unpaired,
-                                          uint16_t *format,
-                                          uint8_t *start_symbol,
-                                          uint8_t *N_t_slot,
-                                          uint8_t *N_dur,
-                                          uint8_t *N_RA_slot,
-                                          uint16_t *N_RA_sfn,
-                                          uint8_t *max_association_period)
+nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired)
 {
-  int x;
-  uint64_t s_map;
   uint8_t format2 = 0xff;
-  if (pointa > 2016666) { //FR2
-    x = table_6_3_3_2_4_prachConfig_Index[index][2];
-    s_map = table_6_3_3_2_4_prachConfig_Index[index][5];
-    *N_RA_sfn += count_bits64(s_map);
-    *N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; // Number of RACH slots within a subframe
-    *max_association_period = 160/(x * 10); 
-    if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
-      *start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6];//multiple prach occasions in diff slot
-      *N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8];
-      *N_dur = table_6_3_3_2_4_prachConfig_Index[index][9];
-      if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1)
-        format2 = (uint8_t) table_6_3_3_2_4_prachConfig_Index[index][1];
-        
-      *format = ((uint8_t) table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2<<8);
-      LOG_D(MAC,"Getting Total PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n",
-            index,
-            pointa,
-            mu,
-            unpaired,
-            *start_symbol,
-            *N_t_slot,
-            *N_dur,
-	    *N_RA_sfn);
-    }
-    return 1;
- }
-  else {
-    if (unpaired) {
-      x = table_6_3_3_2_3_prachConfig_Index[index][2];
-      s_map = table_6_3_3_2_3_prachConfig_Index[index][4];
-      *N_RA_sfn += count_bits64(s_map);
-      *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe
-      *max_association_period = 160/(x * 10); 
-      if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
-        *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5];
-        *N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7];
-        *N_dur = table_6_3_3_2_3_prachConfig_Index[index][8];
-        if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1)
-          format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1];
-        *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8);
-        LOG_D(NR_MAC,"Getting Total PRACH info from index %d (col %lu ) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n",
-              index, table_6_3_3_2_3_prachConfig_Index[index][6],
-              pointa,
-              mu,
-              unpaired,
-              *start_symbol,
-              *N_t_slot,
-              *N_dur,
-              *N_RA_sfn);
-      }
-      return 1;
-    }
-    else { // FDD
-      x = table_6_3_3_2_2_prachConfig_Index[index][2];
-      s_map = table_6_3_3_2_2_prachConfig_Index[index][4];
-      *N_RA_sfn += count_bits64(s_map);
-      *N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6];
-      if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
-        *start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5];
-        *N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7];
-        *N_dur = table_6_3_3_2_2_prachConfig_Index[index][8];
-        if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1)
-          format2 = (uint8_t) table_6_3_3_2_2_prachConfig_Index[index][1];
-        *format = ((uint8_t) table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2<<8);
-        LOG_D(MAC,"Getting Total PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n",
-              index,
-              pointa,
-              mu,
-              unpaired,
-              *start_symbol,
-              *N_t_slot,
-              *N_dur);
-      }
-      return 1;
-    }
+  nr_prach_info_t info;
+  if (freq_range == FR2) {
+    info.x = table_6_3_3_2_4_prachConfig_Index[index][2];
+    info.y = table_6_3_3_2_4_prachConfig_Index[index][3];
+    info.y2 = table_6_3_3_2_4_prachConfig_Index[index][4];
+    info.s_map = table_6_3_3_2_4_prachConfig_Index[index][5];
+    info.N_RA_sfn += count_bits64(info.s_map);
+    info.N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7];
+    info.max_association_period = 160 / (info.x * 10);
+    info.start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6];
+    info.N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8];
+    info.N_dur = table_6_3_3_2_4_prachConfig_Index[index][9];
+    if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1)
+      format2 = (uint8_t)table_6_3_3_2_4_prachConfig_Index[index][1];
+    info.format = ((uint8_t)table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2 << 8);
+    LOG_D(NR_MAC,
+          "PRACH info from index %d frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n",
+          index,
+          unpaired,
+          info.start_symbol,
+          info.N_t_slot,
+          info.N_dur,
+          info.N_RA_sfn);
+    return info;
+  }
+
+  if (unpaired) { // FR1 TDD
+    info.x = table_6_3_3_2_3_prachConfig_Index[index][2];
+    info.y = table_6_3_3_2_3_prachConfig_Index[index][3];
+    info.y2 = -1;
+    info.s_map = table_6_3_3_2_3_prachConfig_Index[index][4];
+    info.N_RA_sfn += count_bits64(info.s_map);
+    info.N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6];
+    info.max_association_period = 160 / (info.x * 10);
+    info.start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5];
+    info.N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7];
+    info.N_dur = table_6_3_3_2_3_prachConfig_Index[index][8];
+    if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1)
+      format2 = (uint8_t)table_6_3_3_2_3_prachConfig_Index[index][1];
+    info.format = ((uint8_t)table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2 << 8);
+    LOG_D(NR_MAC,
+          "PRACH info from index %d (col %lu) frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_sfn = %u\n",
+          index,
+          table_6_3_3_2_3_prachConfig_Index[index][6],
+          unpaired,
+          info.start_symbol,
+          info.N_t_slot,
+          info.N_dur,
+          info.N_RA_sfn);
+    return info;
   }
+
+  // FR1 FDD
+  info.x = table_6_3_3_2_2_prachConfig_Index[index][2];
+  info.y = table_6_3_3_2_2_prachConfig_Index[index][3];
+  info.y2 = -1;
+  info.s_map = table_6_3_3_2_2_prachConfig_Index[index][4];
+  info.N_RA_sfn += count_bits64(info.s_map);
+  info.N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6];
+  info.max_association_period = 160 / (info.x * 10);
+  info.start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5];
+  info.N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7];
+  info.N_dur = table_6_3_3_2_2_prachConfig_Index[index][8];
+  if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1)
+    format2 = (uint8_t)table_6_3_3_2_2_prachConfig_Index[index][1];
+  info.format = ((uint8_t)table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2 << 8);
+  LOG_D(NR_MAC,
+        "PRACH info from index %d frame_type %u start_symbol %u N_t_slot %u N_dur %u \n",
+        index,
+        unpaired,
+        info.start_symbol,
+        info.N_t_slot,
+        info.N_dur);
+  return info;
 }
 
 uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired)
@@ -1682,177 +1648,83 @@ uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t
   return format;
 }
 
-int get_nr_prach_info_from_index(uint8_t index,
-                                 int frame,
-                                 int slot,
-                                 uint32_t pointa,
-                                 uint8_t mu,
-                                 uint8_t unpaired,
-                                 uint16_t *format,
-                                 uint8_t *start_symbol,
-                                 uint8_t *N_t_slot,
-                                 uint8_t *N_dur,
-                                 uint16_t *RA_sfn_index,
-                                 uint8_t *N_RA_slot,
-                                 uint8_t *config_period)
+bool get_nr_prach_sched_from_info(nr_prach_info_t info,
+                                  int config_index,
+                                  int frame,
+                                  int slot,
+                                  int mu,
+                                  frequency_range_t freq_range,
+                                  uint16_t *RA_sfn_index,
+                                  uint8_t unpaired)
 {
-  int x,y;
-  int64_t s_map;
-  uint8_t format2 = 0xff;
-
-  if (pointa > 2016666) { //FR2
-    int y2;
-    uint8_t slot_60khz;
-    x = table_6_3_3_2_4_prachConfig_Index[index][2];
-    y = table_6_3_3_2_4_prachConfig_Index[index][3];
-    y2 = table_6_3_3_2_4_prachConfig_Index[index][4];
+  if (freq_range == FR2) {
     // checking n_sfn mod x = y
-    if ((frame % x) == y || (frame % x) == y2) {
-      slot_60khz = slot >> (mu - 2); // in table slots are numbered wrt 60kHz
-      s_map = table_6_3_3_2_4_prachConfig_Index[index][5];
-      if ((s_map >> slot_60khz) & 0x01) {
+    if ((frame % info.x) == info.y || (frame % info.x) == info.y2) {
+      int slot_60khz = slot >> (mu - 2); // in table slots are numbered wrt 60kHz
+      if ((info.s_map >> slot_60khz) & 0x01) {
         for(int i = 0; i <= slot_60khz ;i++) {
-          if ((s_map >> i) & 0x01) {
+          if ((info.s_map >> i) & 0x01) {
             (*RA_sfn_index)++;
           }
         }
       }
-      if (((s_map >> slot_60khz) & 0x01)) {
-        *N_RA_slot = table_6_3_3_2_4_prachConfig_Index[index][7]; // Number of RACH slots within a subframe
+      if (((info.s_map >> slot_60khz) & 0x01)) {
         if (mu == 3) {
-          if ((*N_RA_slot == 1) && (slot % 2 == 0) )
-            return 0; // no prach in even slots @ 120kHz for 1 prach per 60khz slot
-        }
-        if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
-          *config_period = x;
-          *start_symbol = table_6_3_3_2_4_prachConfig_Index[index][6];
-          *N_t_slot = table_6_3_3_2_4_prachConfig_Index[index][8];
-          *N_dur = table_6_3_3_2_4_prachConfig_Index[index][9];
-          if (table_6_3_3_2_4_prachConfig_Index[index][1] != -1)
-            format2 = (uint8_t) table_6_3_3_2_4_prachConfig_Index[index][1];
-          *format = ((uint8_t) table_6_3_3_2_4_prachConfig_Index[index][0]) | (format2<<8);
-          LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u\n",
-                frame,
-                slot,
-                index,
-                pointa,
-                mu,
-                unpaired,
-                *start_symbol,
-                *N_t_slot,
-                *N_dur,
-                *N_RA_slot,
-                *RA_sfn_index);
+          if ((info.N_RA_slot == 1) && (slot % 2 == 0))
+            return false; // no prach in even slots @ 120kHz for 1 prach per 60khz slot
         }
-        return 1;
-      }
-      else
-        return 0; // no prach in current slot
+        return true;
+      } else
+        return false; // no prach in current slot
     }
     else
-      return 0; // no prach in current frame
-  }
-  else {
-    uint8_t subframe;
-    if (unpaired) {
-      x = table_6_3_3_2_3_prachConfig_Index[index][2];
-      y = table_6_3_3_2_3_prachConfig_Index[index][3];
-      if ((frame % x) == y) {
-        subframe = slot >> mu;
-        s_map = table_6_3_3_2_3_prachConfig_Index[index][4];
-        if ((s_map >> subframe) & 0x01) {
+      return false; // no prach in current frame
+  } else {
+    if (unpaired) { // TDD
+      if ((frame % info.x) == info.y) {
+        int subframe = slot >> mu;
+        if ((info.s_map >> subframe) & 0x01) {
           for(int i = 0; i <= subframe ;i++) {
-            if ((s_map >> i) & 0x01) {
+            if ((info.s_map >> i) & 0x01) {
               (*RA_sfn_index)++;
             }
           }
         }
-        if ((s_map >> subframe) & 0x01 ) {
-         *N_RA_slot = table_6_3_3_2_3_prachConfig_Index[index][6]; // Number of RACH slots within a subframe
-          if (index >= 67) {
-            if ((mu == 1) && (*N_RA_slot <= 1) && (slot % 2 == 0))
-              return 0; // no prach in even slots @ 30kHz for 1 prach per subframe 
+        if ((info.s_map >> subframe) & 0x01) {
+          if (config_index >= 67) {
+            if ((mu == 1) && (info.N_RA_slot <= 1) && (slot % 2 == 0))
+              return false; // no prach in even slots @ 30kHz for 1 prach per subframe
           } else {
             if ((slot % 2) && (mu > 0))
-              return 0; // slot does not contain start symbol of this prach time resource
-          }
-          if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL) {
-            *config_period = x;
-            *start_symbol = table_6_3_3_2_3_prachConfig_Index[index][5];
-            *N_t_slot = table_6_3_3_2_3_prachConfig_Index[index][7];
-            *N_dur = table_6_3_3_2_3_prachConfig_Index[index][8];
-            if (table_6_3_3_2_3_prachConfig_Index[index][1] != -1)
-              format2 = (uint8_t) table_6_3_3_2_3_prachConfig_Index[index][1];
-            *format = ((uint8_t) table_6_3_3_2_3_prachConfig_Index[index][0]) | (format2<<8);
-            LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d (col 6 %lu) absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u N_RA_slot %u RA_sfn_index %u \n",
-                  frame,
-                  slot,
-                  index,
-                  table_6_3_3_2_3_prachConfig_Index[index][6],
-                  pointa,
-                  mu,
-                  unpaired,
-                  *start_symbol,
-                  *N_t_slot,
-                  *N_dur,
-                  *N_RA_slot,
-                  *RA_sfn_index);
+              return false; // slot does not contain start symbol of this prach time resource
           }
-          return 1;
-        }
-        else
-          return 0; // no prach in current slot
-      }
-      else
-        return 0; // no prach in current frame
-    }
-    else { // FDD
-      x = table_6_3_3_2_2_prachConfig_Index[index][2];
-      y = table_6_3_3_2_2_prachConfig_Index[index][3];
-      if ((frame % x) == y) {
-        subframe = slot >> mu;
-        s_map = table_6_3_3_2_2_prachConfig_Index[index][4];
-        if ((s_map>>subframe) & 0x01) {
-          *N_RA_slot = table_6_3_3_2_2_prachConfig_Index[index][6]; // Number of RACH slots within a subframe
-          if (index >= 87) {
-            if ((mu == 1) && (*N_RA_slot <= 1) && (slot % 2 == 0)) {
-              return 0; // no prach in even slots @ 30kHz for 1 prach per subframe
+          return true;
+        } else
+          return false; // no prach in current slot
+      } else
+        return false; // no prach in current frame
+    } else { // FDD
+      if ((frame % info.x) == info.y) {
+        int subframe = slot >> mu;
+        if ((info.s_map >> subframe) & 0x01) {
+          if (config_index >= 87) {
+            if ((mu == 1) && (info.N_RA_slot <= 1) && (slot % 2 == 0)) {
+              return false; // no prach in even slots @ 30kHz for 1 prach per subframe
             }
           } else {
             if ((slot % 2) && (mu > 0))
               return 0; // slot does not contain start symbol of this prach time resource
           }
           for(int i = 0; i <= subframe ; i++) {
-            if ((s_map >> i) & 0x01) {
+            if ((info.s_map >> i) & 0x01) {
               (*RA_sfn_index)++;
             }
           }
-          if (start_symbol != NULL && N_t_slot != NULL && N_dur != NULL && format != NULL){
-            *start_symbol = table_6_3_3_2_2_prachConfig_Index[index][5];
-            *config_period = x;
-            *N_t_slot = table_6_3_3_2_2_prachConfig_Index[index][7];
-            *N_dur = table_6_3_3_2_2_prachConfig_Index[index][8];
-            if (table_6_3_3_2_2_prachConfig_Index[index][1] != -1)
-              format2 = (uint8_t) table_6_3_3_2_2_prachConfig_Index[index][1];
-            *format = ((uint8_t) table_6_3_3_2_2_prachConfig_Index[index][0]) | (format2<<8);
-            LOG_D(MAC,"Frame %d slot %d: Getting PRACH info from index %d absoluteFrequencyPointA %u mu %u frame_type %u start_symbol %u N_t_slot %u N_dur %u \n",
-                  frame,
-                  slot,
-                  index,
-                  pointa,
-                  mu,
-                  unpaired,
-                  *start_symbol,
-                  *N_t_slot,
-                  *N_dur);
-          }
-          return 1;
-        }
-        else
-          return 0; // no prach in current slot
-      }
-      else
-        return 0; // no prach in current frame
+          return true;
+        } else
+          return false; // no prach in current slot
+      } else
+        return false; // no prach in current frame
     }
   }
 }
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index e5f7fb4fcf614c4f0415782c8138cfac3c70852f..b8d1fae38c59a5d9ff493f6da46ef7391a43fa54 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -52,6 +52,20 @@ typedef enum {
   pusch_len2 = 2
 } pusch_maxLength_t;
 
+typedef struct {
+  uint32_t format;
+  uint32_t start_symbol;
+  uint32_t N_t_slot;
+  uint32_t N_dur;
+  uint32_t N_RA_slot;
+  uint32_t N_RA_sfn;
+  uint32_t max_association_period;
+  int x;
+  int y;
+  int y2;
+  uint64_t s_map;
+} nr_prach_info_t;
+
 uint32_t get_Y(const NR_SearchSpace_t *ss, int slot, rnti_t rnti);
 
 uint8_t get_BG(uint32_t A, uint16_t R);
@@ -144,31 +158,16 @@ void find_aggregation_candidates(uint8_t *aggregation_level,
 
 uint16_t get_nr_prach_format_from_index(uint8_t index, uint32_t pointa, uint8_t unpaired);
 
-int get_nr_prach_info_from_index(uint8_t index,
-                                 int frame,
-                                 int slot,
-                                 uint32_t pointa,
-                                 uint8_t mu,
-                                 uint8_t unpaired,
-                                 uint16_t *format,
-                                 uint8_t *start_symbol,
-                                 uint8_t *N_t_slot,
-                                 uint8_t *N_dur,
-                                 uint16_t *RA_sfn_index,
-                                 uint8_t *N_RA_slot,
-                                 uint8_t *config_period);
-
-int get_nr_prach_occasion_info_from_index(uint8_t index,
-                                 uint32_t pointa,
-                                 uint8_t mu,
-                                 uint8_t unpaired,
-                                 uint16_t *format,
-                                 uint8_t *start_symbol,
-                                 uint8_t *N_t_slot,
-                                 uint8_t *N_dur,
-                                 uint8_t *N_RA_slot,
-                                 uint16_t *N_RA_sfn,
-                                 uint8_t *max_association_period);
+bool get_nr_prach_sched_from_info(nr_prach_info_t info,
+                                  int config_index,
+                                  int frame,
+                                  int slot,
+                                  int mu,
+                                  frequency_range_t freq_range,
+                                  uint16_t *RA_sfn_index,
+                                  uint8_t unpaired);
+
+nr_prach_info_t get_nr_prach_occasion_info_from_index(uint8_t index, frequency_range_t freq_range, uint8_t unpaired);
 
 uint8_t get_pusch_mcs_table(long *mcs_Table,
                             int is_tp,
@@ -186,9 +185,7 @@ int ul_ant_bits(NR_DMRS_UplinkConfig_t *NR_DMRS_UplinkConfig, long transformPrec
 
 uint8_t get_pdsch_mcs_table(long *mcs_Table, int dci_format, int rnti_type, int ss_type);
 
-int get_format0(uint8_t index, uint8_t unpaired,frequency_range_t);
-
-const int64_t *get_prach_config_info(frequency_range_t freq_range, uint8_t index, uint8_t unpaired);
+int get_format0(uint8_t index, uint8_t unpaired, frequency_range_t frequency_range);
 
 uint16_t get_NCS(uint8_t index, uint16_t format, uint8_t restricted_set_config);
 int compute_pucch_crc_size(int O_uci);
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index 09d0eb29281a117f3c069b9f2c4484afeca9009b..8c905a8f588ca7d86dede52898fe44eacc17f5a2 100644
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -44,6 +44,44 @@
 #include "oai_asn1.h"
 #include "executables/position_interface.h"
 
+// Build the list of all the valid/transmitted SSBs according to the config
+static void build_ssb_list(NR_UE_MAC_INST_t *mac)
+{
+  // Create the list of transmitted SSBs
+  memset(&mac->ssb_list, 0, sizeof(ssb_list_info_t));
+  ssb_list_info_t *ssb_list = &mac->ssb_list;
+  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
+  ssb_list->nb_tx_ssb = 0;
+
+  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
+    uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask;
+    // check if if current SSB is transmitted
+    if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) {
+      ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb;
+      ssb_list->nb_tx_ssb++;
+    } else
+      ssb_list->nb_ssb_per_index[ssb_index] = -1;
+  }
+}
+
+static int get_ta_offset(long *n_TimingAdvanceOffset)
+{
+  if (!n_TimingAdvanceOffset)
+    return -1;
+
+  switch (*n_TimingAdvanceOffset) {
+    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n0 :
+      return 0;
+    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n25600 :
+      return 25600;
+    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n39936 :
+      return 39936;
+    default :
+      AssertFatal(false, "Invalid n-TimingAdvanceOffset\n");
+  }
+  return -1;
+}
+
 static void set_tdd_config_nr_ue(fapi_nr_tdd_table_t *tdd_table, const frame_structure_t *fs)
 {
   tdd_table->tdd_period_in_slots = fs->numb_slots_period;
@@ -142,6 +180,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
   // cell config
   cfg->cell_config.phy_cell_id = mac->physCellId;
   cfg->cell_config.frame_duplex_type = frame_type;
+  cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
 
   // SSB config
   cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
@@ -187,8 +226,7 @@ static void config_common_ue_sa(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommo
   else {
     // If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839)
     int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
-    const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, frame_type);
-    int format = prach_config_info_p[0];
+    int format = get_format0(config_index, frame_type, mac->frequency_range);
     cfg->prach_config.prach_sub_c_spacing = get_delta_f_RA_long(format);
   }
 
@@ -344,6 +382,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
   // cell config
   cfg->cell_config.phy_cell_id = *scc->physCellId;
   cfg->cell_config.frame_duplex_type = frame_type;
+  cfg->cell_config.N_TA_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
 
   // SSB config
   cfg->ssb_config.ss_pbch_power = scc->ss_PBCH_BlockPower;
@@ -411,8 +450,7 @@ static void config_common_ue(NR_UE_MAC_INST_t *mac, NR_ServingCellConfigCommon_t
     else {
       // If absent, the UE applies the SCS as derived from the prach-ConfigurationIndex (for 839)
       int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
-      const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, frame_type);
-      int format = prach_config_info_p[0];
+      int format = get_format0(config_index, frame_type, mac->frequency_range);
       cfg->prach_config.prach_sub_c_spacing = format == 3 ? 5 : 4;
     }
 
@@ -1399,7 +1437,7 @@ static void setup_srsconfig(NR_UE_UL_BWP_t *bwp, NR_SRS_Config_t *source, NR_SRS
   }
 }
 
-static NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
+NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
 {
   NR_UE_DL_BWP_t *bwp = NULL;
   for (int i = 0; i < mac->dl_BWPs.count; i++) {
@@ -1423,7 +1461,7 @@ static NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, b
   return bwp;
 }
 
-static NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
+NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
 {
   NR_UE_UL_BWP_t *bwp = NULL;
   for (int i = 0; i < mac->ul_BWPs.count; i++) {
@@ -1684,24 +1722,6 @@ void nr_rrc_mac_config_req_reset(module_id_t module_id, NR_UE_MAC_reset_cause_t
   AssertFatal(!ret, "mutex failed %d\n", ret);
 }
 
-static int get_ta_offset(long *n_TimingAdvanceOffset)
-{
-  if (!n_TimingAdvanceOffset)
-    return -1;
-
-  switch (*n_TimingAdvanceOffset) {
-    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n0 :
-      return 0;
-    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n25600 :
-      return 25600;
-    case NR_ServingCellConfigCommonSIB__n_TimingAdvanceOffset_n39936 :
-      return 39936;
-    default :
-      AssertFatal(false, "Invalid n-TimingAdvanceOffset\n");
-  }
-  return -1;
-}
-
 static void configure_si_schedulingInfo(NR_UE_MAC_INST_t *mac,
                                         NR_SI_SchedulingInfo_t *si_SchedulingInfo,
                                         NR_SI_SchedulingInfo_v1700_t *si_SchedulingInfo_v1700)
@@ -1743,17 +1763,18 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si
   AssertFatal(scc, "SIB1 SCC should not be NULL\n");
   UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
   configure_si_schedulingInfo(mac, si_SchedulingInfo, si_SchedulingInfo_v1700);
-  mac->n_ta_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
 
   config_common_ue_sa(mac, scc, cc_idP);
-  configure_common_BWP_dl(mac,
-                          0, // bwp-id
-                          &scc->downlinkConfigCommon.initialDownlinkBWP);
+
+  // Build the list of all the valid/transmitted SSBs according to the config
+  LOG_D(NR_MAC, "Build SSB list\n");
+  build_ssb_list(mac);
+
+  int bwp_id = 0;
+  configure_common_BWP_dl(mac, bwp_id, &scc->downlinkConfigCommon.initialDownlinkBWP);
   if (scc->uplinkConfigCommon) {
     mac->timeAlignmentTimerCommon = scc->uplinkConfigCommon->timeAlignmentTimerCommon;
-    configure_common_BWP_ul(mac,
-                            0, // bwp-id
-                            &scc->uplinkConfigCommon->initialUplinkBWP);
+    configure_common_BWP_ul(mac, bwp_id, &scc->uplinkConfigCommon->initialUplinkBWP);
   }
   // set current BWP only if coming from non-connected state
   // otherwise it is just a periodically update of the SIB1 content
@@ -1767,9 +1788,6 @@ void nr_rrc_mac_config_req_sib1(module_id_t module_id, int cc_idP, NR_SIB1_t *si
   if (mac->state == UE_RECEIVING_SIB && can_start_ra)
     mac->state = UE_PERFORMING_RA;
 
-  // Setup the SSB to Rach Occasions mapping according to the config
-  build_ssb_to_ro_map(mac);
-
   if (!get_softmodem_params()->emulate_l1)
     mac->if_module->phy_config_request(&mac->phy_config);
   ret = pthread_mutex_unlock(&mac->if_mutex);
@@ -1812,12 +1830,15 @@ static void handle_reconfiguration_with_sync(NR_UE_MAC_INST_t *mac,
 
   if (reconfWithSync->spCellConfigCommon) {
     NR_ServingCellConfigCommon_t *scc = reconfWithSync->spCellConfigCommon;
-    mac->n_ta_offset = get_ta_offset(scc->n_TimingAdvanceOffset);
     if (scc->physCellId)
       mac->physCellId = *scc->physCellId;
     mac->dmrs_TypeA_Position = scc->dmrs_TypeA_Position;
     UPDATE_IE(mac->tdd_UL_DL_ConfigurationCommon, scc->tdd_UL_DL_ConfigurationCommon, NR_TDD_UL_DL_ConfigCommon_t);
     config_common_ue(mac, scc, cc_idP);
+    // Build the list of all the valid/transmitted SSBs according to the config
+    LOG_D(NR_MAC,"Build SSB list\n");
+    build_ssb_list(mac);
+
     const int bwp_id = 0;
     if (scc->downlinkConfigCommon)
       configure_common_BWP_dl(mac, bwp_id, scc->downlinkConfigCommon->initialDownlinkBWP);
@@ -2625,11 +2646,6 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
   if (ue_Capability)
     handle_mac_uecap_info(mac, ue_Capability);
 
-  // Setup the SSB to Rach Occasions mapping according to the config
-  // Only if RACH is configured for current BWP
-  if (mac->current_UL_BWP->rach_ConfigCommon)
-    build_ssb_to_ro_map(mac);
-
   if (!mac->dl_config_request || !mac->ul_config_request)
     ue_init_config_request(mac, mac->frame_structure.numb_slots_frame);
   ret = pthread_mutex_unlock(&mac->if_mutex);
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index fbd96532f98892b804bb40ffe4c6b11a73274dcb..cfa3952759ed227fa31299d09f8c1dfd55d35e26 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -79,23 +79,7 @@
 /*!\brief value for indicating BSR Timer is not running */
 #define NR_MAC_UE_BSR_TIMER_NOT_RUNNING   (0xFFFF)
 
-// ================================================
-// SSB to RO mapping private defines and structures
-// ================================================
-
-#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD (16) // Maximum association period is 16
-#define MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max association pattern period is 160ms and minimum PRACH configuration period is 10ms
-#define MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD (16) // Max nb of association periods in an association pattern period of 160ms
-#define MAX_NB_FRAME_IN_PRACH_CONF_PERIOD (16) // Max PRACH configuration period is 160ms and frame is 10ms
-#define MAX_NB_SLOT_IN_FRAME (160) // Max number of slots in a frame (@ SCS 240kHz = 160)
-#define MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD (16) // Maximum number of frames in the maximum association pattern period
 #define MAX_NB_SSB (64) // Maximum number of possible SSB indexes
-#define MAX_RO_PER_SSB (8) // Maximum number of consecutive ROs that can be mapped to an SSB according to the ssb_per_RACH config
-
-// Maximum number of ROs that can be mapped to an SSB in an association pattern
-// This is to reserve enough elements in the SSBs list for each mapped ROs for a single SSB
-// An arbitrary maximum number is chosen to be safe: maximum number of slots in an association pattern * maximum number of ROs in a slot
-#define MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN (MAX_TDM*MAX_FDM*MAX_NB_SLOT_IN_FRAME*MAX_NB_FRAME_IN_ASSOCIATION_PATTERN_PERIOD)
 
 // ===============
 // DCI fields defs
@@ -169,6 +153,23 @@
   UE_STATE(UE_CONNECTED) \
   UE_STATE(UE_DETACHING)
 
+// ===============================================
+// SSB to RO mapping public defines and structures
+// ===============================================
+#define MAX_SSB_PER_RO (16) // Maximum number of SSBs that can be mapped to a single RO
+#define MAX_TDM (7) // Maximum nb of PRACH occasions TDMed in a slot
+#define MAX_FDM (8) // Maximum nb of PRACH occasions FDMed in a slot
+
+// PRACH occasion details
+typedef struct prach_occasion_info {
+  int start_symbol; // 0 - 13 (14 symbols in a slot)
+  int fdm; // 0-7 (possible values of msg1-FDM: 1, 2, 4 or 8)
+  int slot;
+  int format; // RO preamble format
+  int frame_info[2];
+  int association_period_idx;
+} prach_occasion_info_t;
+
 typedef enum {
   phr_cause_prohibit_timer = 0,
   phr_cause_periodic_timer,
@@ -272,42 +273,41 @@ static const char *const nrra_ue_text[] =
     {"UE_IDLE", "GENERATE_PREAMBLE", "WAIT_RAR", "WAIT_MSGB", "WAIT_CONTENTION_RESOLUTION", "RA_SUCCEEDED", "RA_FAILED"};
 
 typedef struct {
-  /// PRACH format retrieved from prach_ConfigIndex
-  uint16_t prach_format;
   /// Preamble Tx Counter
-  uint8_t RA_PREAMBLE_TRANSMISSION_COUNTER;
+  uint8_t preamble_tx_counter;
   /// Preamble Power Ramping Counter
-  uint8_t RA_PREAMBLE_POWER_RAMPING_COUNTER;
+  uint8_t preamble_power_ramping_cnt;
   /// 2-step RA power offset
-  int POWER_OFFSET_2STEP_RA;
+  int power_offset_2step;
   /// Target received power at gNB. Baseline is range -202..-60 dBm. Depends on delta preamble, power ramping counter and step.
-  int ra_PREAMBLE_RECEIVED_TARGET_POWER;
-  /// PRACH index for TDD (0 ... 6) depending on TDD configuration and prachConfigIndex
-  uint8_t ra_TDD_map_index;
+  int ra_preamble_rx_target_power;
   /// RA Preamble Power Ramping Step in dB
-  uint32_t RA_PREAMBLE_POWER_RAMPING_STEP;
-  ///
-  uint8_t RA_PREAMBLE_BACKOFF;
-  ///
-  uint8_t RA_SCALING_FACTOR_BI;
-  /// Indicating whether it is 2-step or 4-step RA
-  nr_ra_type_t RA_TYPE;
+  uint32_t preamble_power_ramping_step;
   /// UE configured maximum output power
-  int RA_PCMAX;
+  int Pc_max;
 } NR_PRACH_RESOURCES_t;
 
 typedef struct {
+  float ssb_per_ro;
+  int preambles_per_ssb;
+} ssb_ro_preambles_t;
+
+typedef struct {
+  bool active;
+  uint32_t preamble_index;
+  uint32_t ssb_index;
+  uint32_t prach_mask;
+} NR_pdcch_order_config_t;
 
+typedef struct {
   // pointer to RACH config dedicated
   NR_RACH_ConfigDedicated_t *rach_ConfigDedicated;
   /// state of RA procedure
   nrRA_UE_state_t ra_state;
   /// RA contention type
-  uint8_t cfra;
+  bool cfra;
   /// RA type
   nr_ra_type_t ra_type;
-  /// RA rx frame offset: compensate RA rx offset introduced by OAI gNB.
-  uint8_t RA_offset;
   /// MsgB SuccessRAR MAC subheader
   int8_t MsgB_R;
   int8_t MsgB_CH_ACESS_CPEXT;
@@ -321,53 +321,51 @@ typedef struct {
   uint16_t MsgB_rnti;
   /// Temporary CRNTI
   uint16_t t_crnti;
-  /// number of attempt for rach
-  uint8_t RA_attempt_number;
   /// Random-access procedure flag
   bool RA_active;
   /// Random-access preamble index
   int ra_PreambleIndex;
-  // When multiple SSBs per RO is configured, this indicates which one is selected in this RO -> this is used to properly compute the PRACH preamble
-  uint8_t ssb_nb_in_ro;
-
-  /// Random-access window counter
-  int16_t RA_window_cnt;
-  /// Flag to monitor if matching RAPID was received in RAR
-  uint8_t RA_RAPID_found;
-  /// Flag to monitor if BI was received in RAR
-  uint8_t RA_BI_found;
-  /// Random-access backoff counter
-  int16_t RA_backoff_indicator;
-  /// Flag to indicate whether preambles Group A was used
-  uint8_t RA_usedGroupA;
-  /// RA backoff counter
-  int16_t RA_backoff_cnt;
+  int zeroCorrelationZoneConfig;
+  int restricted_set_config;
+  // selected SSB for RACH (not the SSB-Index but the cumulative index, excluding not trasmitted SSBs)
+  int ra_ssb;
+  /// Random-access response window timer
+  NR_timer_t response_window_timer;
+  int response_window_setup_time;
+  /// Random-access backoff timer
+  NR_timer_t RA_backoff_timer;
+  int RA_backoff_limit;
+  uint8_t scaling_factor_bi;
+  /// Flag to indicate whether preambles Group A is selected
+  bool RA_GroupA;
   /// RA max number of preamble transmissions
   int preambleTransMax;
-  /// Nb of preambles per SSB
-  long cb_preambles_per_ssb;
-  int starting_preamble_nb;
-
   /// Received TPC command (in dB) from RAR
   int8_t Msg3_TPC;
-  /// Flag to indicate whether it is the first Msg3 to be transmitted
-  bool first_Msg3;
   /// RA Msg3 size in bytes
   uint8_t Msg3_size;
   /// Msg3 buffer
   uint8_t *Msg3_buffer;
-
-  bool msg3_C_RNTI;
-
+  // initial Random Access Preamble power
+  int preambleRxTargetPower;
+  int msg3_deltaPreamble;
+  int preambleReceivedTargetPower_config;
   /// Random-access Contention Resolution Timer
   NR_timer_t contention_resolution_timer;
   /// Transmitted UE Contention Resolution Identifier
   uint8_t cont_res_id[6];
 
-  /// BeamfailurerecoveryConfig
-  NR_BeamFailureRecoveryConfig_t RA_BeamFailureRecoveryConfig;
+  NR_pdcch_order_config_t pdcch_order;
 
   NR_PRACH_RESOURCES_t prach_resources;
+
+  bool new_ssb;
+  int num_fd_occasions;
+  int ra_config_index;
+  ssb_ro_preambles_t ssb_ro_config;
+  int association_periods;
+  prach_occasion_info_t sched_ro_info;
+  int ro_mask_index;
 } RA_config_t;
 
 typedef struct {
@@ -435,39 +433,8 @@ typedef struct NR_UL_TIME_ALIGNMENT {
   int slot;
 } NR_UL_TIME_ALIGNMENT_t;
 
-// The PRACH Config period is a series of selected slots in one or multiple frames
-typedef struct prach_conf_period {
-  prach_occasion_slot_t prach_occasion_slot_map[MAX_NB_FRAME_IN_PRACH_CONF_PERIOD][MAX_NB_SLOT_IN_FRAME];
-  uint16_t nb_of_prach_occasion; // Total number of PRACH occasions in the PRACH Config period
-  uint8_t nb_of_frame; // Size of the PRACH Config period in number of 10ms frames
-  uint8_t nb_of_slot; // Nb of slots in each frame
-} prach_conf_period_t;
-
-// The association period is a series of PRACH Config periods
-typedef struct prach_association_period {
-  prach_conf_period_t *prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PERIOD];
-  uint8_t nb_of_prach_conf_period; // Nb of PRACH configuration periods within the association period
-  uint8_t nb_of_frame; // Total number of frames included in the association period
-} prach_association_period_t;
-
-// The association pattern is a series of Association periods
-typedef struct prach_association_pattern {
-  prach_association_period_t prach_association_period_list[MAX_NB_ASSOCIATION_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD];
-  prach_conf_period_t prach_conf_period_list[MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD];
-  uint8_t nb_of_assoc_period; // Nb of association periods within the association pattern
-  uint8_t nb_of_prach_conf_period_in_max_period; // Nb of PRACH configuration periods within the maximum association pattern period (according to the size of the configured PRACH
-  uint8_t nb_of_frame; // Total number of frames included in the association pattern period (after mapping the SSBs and determining the real association pattern length)
-} prach_association_pattern_t;
-
-// SSB details
-typedef struct ssb_info {
-  prach_occasion_info_t *mapped_ro[MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN]; // List of mapped RACH Occasions to this SSB index
-  uint32_t nb_mapped_ro; // Total number of mapped ROs to this SSB index
-} ssb_info_t;
-
 // List of all the possible SSBs and their details
 typedef struct ssb_list_info {
-  ssb_info_t *tx_ssb;
   int nb_tx_ssb;
   int nb_ssb_per_index[MAX_NB_SSB];
 } ssb_list_info_t;
@@ -571,14 +538,12 @@ typedef struct NR_UE_MAC_INST_s {
   NR_UE_L2_STATE_t state;
   int servCellIndex;
   long physCellId;
-  int first_sync_frame;
   bool get_sib1;
   bool get_otherSI;
   NR_MIB_t *mib;
 
   si_schedInfo_t si_SchedInfo;
-  ssb_list_info_t ssb_list[MAX_NUM_BWP_UE];
-  prach_association_pattern_t prach_assoc_pattern[MAX_NUM_BWP_UE];
+  ssb_list_info_t ssb_list;
 
   NR_UE_ServingCell_Info_t sc_info;
   A_SEQUENCE_OF(NR_UE_DL_BWP_t) dl_BWPs;
@@ -632,7 +597,6 @@ typedef struct NR_UE_MAC_INST_s {
   int dmrs_TypeA_Position;
   int p_Max;
   int p_Max_alt;
-  int n_ta_offset; // -1 not present, otherwise value to be applied
 
   ntn_timing_advance_componets_t ntn_ta;
 
@@ -670,6 +634,7 @@ typedef struct NR_UE_MAC_INST_s {
   int f_b_f_c;
   bool pusch_power_control_initialized;
   int delta_msg2;
+  bool msg3_C_RNTI;
   pthread_mutex_t if_mutex;
   ue_mac_stats_t stats;
 } NR_UE_MAC_INST_t;
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index fbc98964e3fc277c2a7974275f2e3b5061713b7a..a2b2e0f777bd67334a33009ea999c7f0bb903d33 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -45,8 +45,12 @@
    \param mac      MAC pointer */
 void nr_ue_init_mac(NR_UE_MAC_INST_t *mac);
 
+NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup);
+NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup);
+
 void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data);
-void update_mac_timers(NR_UE_MAC_INST_t *mac);
+void update_mac_ul_timers(NR_UE_MAC_INST_t *mac);
+void update_mac_dl_timers(NR_UE_MAC_INST_t *mac);
 NR_LC_SCHEDULING_INFO *get_scheduling_info_from_lcid(NR_UE_MAC_INST_t *mac, NR_LogicalChannelIdentity_t lcid);
 
 /**\brief apply default configuration values in nr_mac instance
@@ -177,8 +181,6 @@ typedef struct {
   enum { b_none, b_long, b_short, b_short_trunc, b_long_trunc } type_bsr;
 } type_bsr_t;
 
-int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end);
-
 int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
                           NR_UE_MAC_INST_t *mac,
                           NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom,
@@ -211,7 +213,6 @@ void set_harq_status(NR_UE_MAC_INST_t *mac,
 bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sched_t *pucch);
 initial_pucch_resource_t get_initial_pucch_resource(const int idx);
 void multiplex_pucch_resource(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, int num_res);
-uint32_t get_backoff_indicator(int idx);
 int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
                               int scs,
                               NR_PUCCH_Config_t *pucch_Config,
@@ -274,6 +275,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac,
                      dci_pdu_rel15_t *dci,
                      nr_dci_format_t dci_format);
 
+bool init_RA(NR_UE_MAC_INST_t *mac, int frame);
+
 /* Random Access */
 /* \brief This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211 tables 6.3.3.2.x
 and fills the PRACH PDU per each FD occasion.
@@ -290,56 +293,17 @@ void configure_csi_resource_mapping(fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_c
                                     uint32_t bwp_size,
                                     uint32_t bwp_start);
 
-/* \brief This function schedules the Msg3 transmission
-@param
-@param
-@param
-@returns void
-*/
-void nr_ue_msg3_scheduler(NR_UE_MAC_INST_t *mac, frame_t current_frame, slot_t current_slot, uint8_t Msg3_tda_id);
-
-void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, int slot, NR_PRACH_RESOURCES_t *prach_resources);
-
-void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_resources, frame_t frame, int slot);
 
+void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac);
 void nr_ra_succeeded(NR_UE_MAC_INST_t *mac, const uint8_t gNB_index, const frame_t frame, const int slot);
-
-int16_t nr_get_RA_window_2Step(const NR_MsgA_ConfigCommon_r16_t *msgA_ConfigCommon_r16);
-
-int16_t nr_get_RA_window_4Step(const NR_RACH_ConfigCommon_t *rach_ConfigCommon);
-
+void nr_ra_backoff_setting(RA_config_t *ra);
 void nr_get_RA_window(NR_UE_MAC_INST_t *mac);
-
-/* \brief Function called by PHY to retrieve information to be transmitted using the RA procedure.
-If the UE is not in PUSCH mode for a particular eNB index, this is assumed to be an Msg3 and MAC
-attempts to retrieves the CCCH message from RRC. If the UE is in PUSCH mode for a particular eNB
-index and PUCCH format 0 (Scheduling Request) is not activated, the MAC may use this resource for
-andom-access to transmit a BSR along with the C-RNTI control element (see 5.1.4 from 38.321)
-@param mod_id Index of UE instance
-@param CC_id Component Carrier Index
-@param frame
-@param gNB_id gNB index
-@param nr_slot_tx slot for PRACH transmission
-@returns indication to generate PRACH to phy */
-void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB_id, int nr_slot_tx);
-
-/* \brief Function implementing the routine for the selection of Random Access resources (5.1.2 TS 38.321).
-@param mac pointer to MAC instance
-@param CC_id Component Carrier Index
-@param gNB_index gNB index
-@param rach_ConfigDedicated
-@returns void */
-void nr_get_prach_resources(NR_UE_MAC_INST_t *mac,
-                            int CC_id,
-                            uint8_t gNB_id,
-                            NR_PRACH_RESOURCES_t *prach_resources,
-                            NR_RACH_ConfigDedicated_t * rach_ConfigDedicated);
-
 void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack);
 void configure_initial_pucch(PUCCH_sched_t *pucch, int res_ind);
 void release_PUCCH_SRS(NR_UE_MAC_INST_t *mac);
 void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac);
 void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int cc_id, const fapi_nr_synch_request_t *sync_req);
+bool is_ss_monitor_occasion(const int frame, const int slot, const int slots_per_frame, const NR_SearchSpace_t *ss);
 
 /**
  * @brief   Get UE sync state
@@ -348,18 +312,12 @@ void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int
  */
 NR_UE_L2_STATE_t nr_ue_get_sync_state(module_id_t mod_id);
 
-void init_RA(NR_UE_MAC_INST_t *mac,
-             NR_PRACH_RESOURCES_t *prach_resources,
-             NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon,
-             NR_RACH_ConfigGeneric_t *rach_ConfigGeneric,
-             NR_RACH_ConfigDedicated_t *rach_ConfigDedicated);
-
 int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac);
-void free_rach_structures(NR_UE_MAC_INST_t *nr_mac, int bwp_id);
 void schedule_RA_after_SR_failure(NR_UE_MAC_INST_t *mac);
-void nr_Msg1_transmitted(NR_UE_MAC_INST_t *mac);
+void nr_rar_not_successful(NR_UE_MAC_INST_t *mac);
+void ra_resource_selection(NR_UE_MAC_INST_t *mac);
 void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, slot_t slotP, uint8_t gNB_id);
-void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac);
+void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order);
 void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS_max);
 void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac);
 int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
@@ -370,9 +328,7 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p
                                                       int start_DLBWP,
                                                       dci_field_t frequency_domain_assignment);
 
-void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac);
-
-void ue_init_config_request(NR_UE_MAC_INST_t *mac, int slots_per_frame);
+void ue_init_config_request(NR_UE_MAC_INST_t *mac, int scs);
 
 fapi_nr_dl_config_request_t *get_dl_config_request(NR_UE_MAC_INST_t *mac, int slot);
 
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_tables.c b/openair2/LAYER2/NR_MAC_UE/mac_tables.c
index bd4cc6d8f381088ae5127b16dde6950cf0ec6980..a3136006099a6e9e9ec7bf838b9b9f2f9a3d78ca 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_tables.c
+++ b/openair2/LAYER2/NR_MAC_UE/mac_tables.c
@@ -412,30 +412,6 @@ static const uint8_t table_7_3_2_3_3_4_twoCodeword[6][14] = {
   {2,1,1,1,1,0,0,1,1,1,1,0,0,2},
 };
 
-// table 7.2-1 TS 38.321
-static const uint32_t table_7_2_1[16] = {
-  5,    // row index 0
-  10,   // row index 1
-  20,   // row index 2
-  30,   // row index 3
-  40,   // row index 4
-  60,   // row index 5
-  80,   // row index 6
-  120,  // row index 7
-  160,  // row index 8
-  240,  // row index 9
-  320,  // row index 10
-  480,  // row index 11
-  960,  // row index 12
-  1920, // row index 13
-};
-
-uint32_t get_backoff_indicator(int idx)
-{
-  AssertFatal(idx < 16, "Backoff indicator index %d exeeding table size\n", idx);
-  return table_7_2_1[idx];
-}
-
 static inline uint16_t packBits(const uint8_t *toPack, const int nb)
 {
   int res = 0;
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index 35167b6173d47dcaebc86a54f8e9f9acb15c8a34..8df19c7139f1d217a5ded8bacf15cde194cd8807 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -68,7 +68,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac)
   mac->uecap_maxMIMO_PUSCH_layers_nocb = 0;
   mac->p_Max = INT_MIN;
   mac->p_Max_alt = INT_MIN;
-  mac->n_ta_offset = -1;
+  mac->msg3_C_RNTI = false;
   mac->ntn_ta.ntn_params_changed = false;
   reset_mac_inst(mac);
 
@@ -77,8 +77,7 @@ void nr_ue_init_mac(NR_UE_MAC_INST_t *mac)
 
   memset(&mac->ssb_measurements, 0, sizeof(mac->ssb_measurements));
   memset(&mac->ul_time_alignment, 0, sizeof(mac->ul_time_alignment));
-  memset(mac->ssb_list, 0, sizeof(mac->ssb_list));
-  memset(mac->prach_assoc_pattern, 0, sizeof(mac->prach_assoc_pattern));
+  memset(&mac->ssb_list, 0, sizeof(mac->ssb_list));
 
   for (int i = 0; i < NR_MAX_SR_ID; i++)
     memset(&mac->scheduling_info.sr_info[i], 0, sizeof(mac->scheduling_info.sr_info[i]));
@@ -115,7 +114,6 @@ void nr_ue_send_synch_request(NR_UE_MAC_INST_t *mac, module_id_t module_id, int
 void nr_ue_reset_sync_state(NR_UE_MAC_INST_t *mac)
 {
   // reset synchornization status
-  mac->first_sync_frame = -1;
   mac->state = UE_NOT_SYNC;
   mac->ra.ra_state = nrRA_UE_IDLE;
 }
@@ -181,9 +179,11 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac)
   if (nr_mac->data_inactivity_timer)
     nr_timer_stop(nr_mac->data_inactivity_timer);
   nr_timer_stop(&nr_mac->time_alignment_timer);
-  nr_timer_stop(&nr_mac->ra.contention_resolution_timer);
   nr_timer_stop(&nr_mac->scheduling_info.sr_DelayTimer);
   nr_timer_stop(&nr_mac->scheduling_info.retxBSR_Timer);
+  nr_timer_stop(&nr_mac->ra.response_window_timer);
+  nr_timer_stop(&nr_mac->ra.RA_backoff_timer);
+  nr_timer_stop(&nr_mac->ra.contention_resolution_timer);
   for (int i = 0; i < NR_MAX_SR_ID; i++)
     nr_timer_stop(&nr_mac->scheduling_info.sr_info[i].prohibitTimer);
 
@@ -195,8 +195,10 @@ void reset_mac_inst(NR_UE_MAC_INST_t *nr_mac)
     nr_mac->ul_harq_info[k].last_ndi = -1; // initialize to invalid value
 
   // stop any ongoing RACH procedure
-  if (nr_mac->ra.ra_state < nrRA_SUCCEEDED)
+  if (nr_mac->ra.RA_active) {
     nr_mac->ra.ra_state = nrRA_UE_IDLE;
+    nr_mac->ra.RA_active = false;
+  }
 
   // discard explicitly signalled contention-free Random Access Resources
   // TODO not sure what needs to be done here
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
index 51a3ad8c9df51823be8939623b5c99d031f08a93..01b33465e75872188a29e8bbd90e97a72566c1e4 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
@@ -38,126 +38,18 @@
 #include "LAYER2/NR_MAC_UE/mac_proto.h"
 #include <executables/softmodem-common.h>
 #include "openair2/LAYER2/RLC/rlc.h"
-#include "openair2/LAYER2/NR_MAC_UE/mac_defs.h"
-
 
 int16_t get_prach_tx_power(NR_UE_MAC_INST_t *mac)
 {
   RA_config_t *ra = &mac->ra;
   int16_t pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
-  int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_PREAMBLE_RECEIVED_TARGET_POWER + pathloss);
-  return min(ra->prach_resources.RA_PCMAX, ra_preamble_rx_power);
+  int16_t ra_preamble_rx_power = (int16_t)(ra->prach_resources.ra_preamble_rx_target_power + pathloss);
+  return min(ra->prach_resources.Pc_max, ra_preamble_rx_power);
 }
 
-// Random Access procedure initialization as per 5.1.1 and initialization of variables specific
-// to Random Access type as specified in clause 5.1.1a (3GPP TS 38.321 version 16.2.1 Release 16)
-// todo:
-// - check if carrier to use is explicitly signalled then do (1) RA CARRIER SELECTION (SUL, NUL) (2) set PCMAX (currently hardcoded to 0)
-void init_RA(NR_UE_MAC_INST_t *mac,
-             NR_PRACH_RESOURCES_t *prach_resources,
-             NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon,
-             NR_RACH_ConfigGeneric_t *rach_ConfigGeneric,
-             NR_RACH_ConfigDedicated_t *rach_ConfigDedicated)
+static void set_preambleTransMax(RA_config_t *ra, long preambleTransMax)
 {
-  mac->state = UE_PERFORMING_RA;
-  RA_config_t *ra = &mac->ra;
-  ra->RA_active = true;
-  ra->ra_PreambleIndex = -1;
-  ra->RA_usedGroupA = 1;
-  ra->RA_RAPID_found = 0;
-  ra->preambleTransMax = 0;
-  ra->first_Msg3 = true;
-  ra->starting_preamble_nb = 0;
-  ra->RA_backoff_cnt = 0;
-  ra->RA_window_cnt = -1;
-
-  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
-
-  prach_resources->RA_PREAMBLE_BACKOFF = 0;
-  NR_SubcarrierSpacing_t prach_scs;
-  int scs_for_pcmax; // for long prach the UL BWP SCS is used for calculating RA_PCMAX
-  if (nr_rach_ConfigCommon && nr_rach_ConfigCommon->msg1_SubcarrierSpacing) {
-    prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
-    scs_for_pcmax = prach_scs;
-  } else {
-    const unsigned int index = rach_ConfigGeneric->prach_ConfigurationIndex;
-    const unsigned int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
-    const unsigned int format = get_format0(index, unpaired, mac->frequency_range);
-    prach_scs = get_delta_f_RA_long(format);
-    scs_for_pcmax = mac->current_UL_BWP->scs;
-  }
-  int n_prbs = get_N_RA_RB(prach_scs, mac->current_UL_BWP->scs);
-  int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + mac->current_UL_BWP->BWPStart;
-  // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
-  prach_resources->RA_PCMAX = nr_get_Pcmax(mac->p_Max,
-                                           mac->nr_band,
-                                           mac->frame_structure.frame_type,
-                                           mac->frequency_range,
-                                           mac->current_UL_BWP->channel_bandwidth,
-                                           2,
-                                           false,
-                                           scs_for_pcmax,
-                                           cfg->carrier_config.dl_grid_size[scs_for_pcmax],
-                                           true,
-                                           n_prbs,
-                                           start_prb);
-  prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
-  prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER = 1;
-  prach_resources->POWER_OFFSET_2STEP_RA = 0;
-  prach_resources->RA_SCALING_FACTOR_BI = 1;
-
-
-  // Contention Free
-  if (rach_ConfigDedicated) {
-    if (rach_ConfigDedicated->cfra){
-      LOG_I(MAC, "Initialization of 4-Step CFRA procedure\n");
-      prach_resources->RA_TYPE = RA_4_STEP;
-      ra->ra_type = RA_4_STEP;
-      ra->cfra = 1;
-    } else if (rach_ConfigDedicated->ext1){
-      if (rach_ConfigDedicated->ext1->cfra_TwoStep_r16) {
-        LOG_I(MAC, "Initialization of 2-Step CFRA procedure\n");
-        prach_resources->RA_TYPE = RA_2_STEP;
-        ra->ra_type = RA_2_STEP;
-        ra->cfra = 1;
-      } else {
-        LOG_E(NR_MAC, "Config not handled\n");
-      }
-    } else {
-      LOG_E(NR_MAC, "Config not handled\n");
-    }
-    // Contention Based
-  } else if (mac->current_UL_BWP->msgA_ConfigCommon_r16) {
-    LOG_I(MAC, "Initialization of 2-Step CBRA procedure\n");
-    prach_resources->RA_TYPE = RA_2_STEP;
-    ra->ra_type = RA_2_STEP;
-    ra->cfra = 0;
-  } else if (nr_rach_ConfigCommon) {
-    LOG_I(MAC, "Initialization of 4-Step CBRA procedure\n");
-    prach_resources->RA_TYPE = RA_4_STEP;
-    ra->ra_type = RA_4_STEP;
-    ra->cfra = 0;
-  } else {
-    LOG_E(MAC, "Config not handled\n");
-    AssertFatal(false, "In %s: config not handled\n", __FUNCTION__);
-  }
-
-  switch (rach_ConfigGeneric->powerRampingStep){ // in dB
-    case 0:
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 0;
-      break;
-    case 1:
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 2;
-      break;
-    case 2:
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 4;
-      break;
-    case 3:
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = 6;
-      break;
-  }
-
-  switch (rach_ConfigGeneric->preambleTransMax) {
+  switch (preambleTransMax) {
     case 0:
       ra->preambleTransMax = 3;
       break;
@@ -191,404 +83,983 @@ void init_RA(NR_UE_MAC_INST_t *mac,
     case 10:
       ra->preambleTransMax = 200;
       break;
+    default:
+      AssertFatal(false, "Invalid preambleTransMax\n");
   }
+}
 
-  if (ra->ra_type == RA_2_STEP) {
-    if (nr_rach_ConfigCommon->ext1 && nr_rach_ConfigCommon->ext1->ra_PrioritizationForAccessIdentity_r16) {
-      LOG_D(MAC, "Missing implementation for Access Identity initialization procedures\n");
-    }
-    // Perform initialization of variables specific to Random Access type as specified in clause 5.1.1a of TS 38.321
-    NR_RACH_ConfigGenericTwoStepRA_r16_t nr_ra_ConfigGenericTwoStepRA_r16 =
-        mac->current_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16.rach_ConfigGenericTwoStepRA_r16;
-    // Takes the value of 2-Step RA variable
-    if (nr_ra_ConfigGenericTwoStepRA_r16.msgA_PreamblePowerRampingStep_r16) {
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = *nr_ra_ConfigGenericTwoStepRA_r16.msgA_PreamblePowerRampingStep_r16;
-    } else {
-      // If 2-Step variable does not exist, it takes the value of 4-Step RA variable
-      prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP = nr_rach_ConfigCommon->rach_ConfigGeneric.powerRampingStep;
-    }
-    prach_resources->RA_SCALING_FACTOR_BI = 1;
-    // Takes the value of 2-Step RA variable
-    if (nr_ra_ConfigGenericTwoStepRA_r16.preambleTransMax_r16) {
-      ra->preambleTransMax = (int)*nr_ra_ConfigGenericTwoStepRA_r16.preambleTransMax_r16;
-    } else {
-      // If 2-Step variable does not exist, it takes the value of 4-Step RA variable
-      ra->preambleTransMax = (int)nr_rach_ConfigCommon->rach_ConfigGeneric.preambleTransMax;
-    }
+static int get_Msg3SizeGroupA(long ra_Msg3SizeGroupA)
+{
+  int bits = 0;
+  switch (ra_Msg3SizeGroupA) {
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b56:
+      bits = 56;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b144:
+      bits = 144;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b208:
+      bits = 208;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b256:
+      bits = 256;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b282:
+      bits = 282;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b480:
+      bits = 480;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b640:
+      bits = 640;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b800:
+      bits = 800;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b1000:
+      bits = 1000;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__ra_Msg3SizeGroupA_b72:
+      bits = 72;
+      break;
+    default:
+      AssertFatal(false, "Unknown ra-Msg3SizeGroupA %lu\n", ra_Msg3SizeGroupA);
   }
+  return bits / 8; // returning bytes
 }
 
-/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */
-static int8_t nr_get_DELTA_PREAMBLE(const NR_UE_MAC_INST_t *mac, int CC_id, uint16_t prach_format)
+static int get_messagePowerOffsetGroupB(long messagePowerOffsetGroupB)
 {
-  const NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
-  int prach_sequence_length = nr_rach_ConfigCommon->prach_RootSequenceIndex.present - 1;
-
-  AssertFatal(CC_id == 0, "Transmission on secondary CCs is not supported yet\n");
-
-  // Preamble formats given by prach_ConfigurationIndex and tables 6.3.3.2-2 and 6.3.3.2-2 in TS 38.211
-
-  unsigned int prachConfigIndex = nr_rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
-
-  if (prach_sequence_length == 0) {
-    AssertFatal(prach_format < 4, "Illegal PRACH format %d for sequence length 839\n", prach_format);
-    switch (prach_format) {
-
-      // long preamble formats
-      case 0:
-      case 3:
-      return  0;
-
-      case 1:
-      return -3;
-
-      case 2:
-      return -6;
-
-      default:
-      AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n",
-                  mac->ue_id,
-                  prach_format,
-                  prachConfigIndex);
-    }
-  } else {
-    // SCS configuration from msg1_SubcarrierSpacing and table 4.2-1 in TS 38.211
-
-    AssertFatal(nr_rach_ConfigCommon->msg1_SubcarrierSpacing, "msg1_SubcarrierSpacing required but missing\n");
-    NR_SubcarrierSpacing_t scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
-    AssertFatal(scs >= NR_SubcarrierSpacing_kHz15 && scs <= NR_SubcarrierSpacing_spare1, "Unknown msg1_SubcarrierSpacing %lu\n", scs);
-    const unsigned int mu = scs;
-
-    switch (prach_format) { // short preamble formats
-      case 0:
-      case 3:
-      return 8 + 3*mu;
-
-      case 1:
-      case 4:
-      case 8:
-      return 5 + 3*mu;
-
-      case 2:
-      case 5:
-      return 3 + 3*mu;
-
-      case 6:
-      return 3*mu;
-
-      case 7:
-      return 5 + 3*mu;
-
-      default:
-      AssertFatal(1 == 0, "[UE %d] ue_procedures.c: FATAL, Illegal preambleFormat %d, prachConfigIndex %d\n",
-                  mac->ue_id,
-                  prach_format,
-                  prachConfigIndex);
-    }
+  int pow_offset = 0;
+  switch (messagePowerOffsetGroupB) {
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_minusinfinity:
+      pow_offset = INT_MIN;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB0:
+      pow_offset = 0;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB5:
+      pow_offset = 5;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB8:
+      pow_offset = 8;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB10:
+      pow_offset = 10;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB12:
+      pow_offset = 12;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB15:
+      pow_offset = 15;
+      break;
+    case NR_RACH_ConfigCommon__groupBconfigured__messagePowerOffsetGroupB_dB18:
+      pow_offset = 18;
+      break;
+    default:
+      AssertFatal(false, "Unknown messagePowerOffsetGroupB %lu\n", messagePowerOffsetGroupB);
   }
-  return 0;
+  return pow_offset;
 }
 
-// TS 38.321 subclause 5.1.3 - RA preamble transmission - ra_PREAMBLE_RECEIVED_TARGET_POWER configuration
-// Measurement units:
-// - preambleReceivedTargetPower      dBm (-202..-60, 2 dBm granularity)
-// - delta_preamble                   dB
-// - RA_PREAMBLE_POWER_RAMPING_STEP   dB
-// - POWER_OFFSET_2STEP_RA            dB
-// returns receivedTargerPower in dBm
-static int nr_get_Po_NOMINAL_PUSCH(NR_UE_MAC_INST_t *mac, NR_PRACH_RESOURCES_t *prach_resources, uint8_t CC_id)
+static void select_preamble_group(NR_UE_MAC_INST_t *mac)
 {
-  int8_t receivedTargerPower;
-  int8_t delta_preamble;
-
-  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
-  long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower;
-  delta_preamble = nr_get_DELTA_PREAMBLE(mac, CC_id, prach_resources->prach_format);
-
-  receivedTargerPower = preambleReceivedTargetPower +
-                        delta_preamble +
-                        (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP +
-                        prach_resources->POWER_OFFSET_2STEP_RA;
-
-  LOG_D(MAC, "ReceivedTargerPower is %d dBm \n", receivedTargerPower);
-  return receivedTargerPower;
+  RA_config_t *ra = &mac->ra;
+  // TODO if the RA_TYPE is switched from 2-stepRA to 4-stepRA
+
+  if (!ra->Msg3_buffer) { // if Msg3 buffer is empty
+    NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
+    if (nr_rach_ConfigCommon && nr_rach_ConfigCommon->groupBconfigured) { // if Random Access Preambles group B is configured
+      struct NR_RACH_ConfigCommon__groupBconfigured *groupB = nr_rach_ConfigCommon->groupBconfigured;
+      // if the potential Msg3 size (UL data available for transmission plus MAC subheader(s) and,
+      // where required, MAC CEs) is greater than ra-Msg3SizeGroupA
+      // if the pathloss is less than PCMAX (of the Serving Cell performing the Random Access Procedure)
+      // – preambleReceivedTargetPower – msg3-DeltaPreamble – messagePowerOffsetGroupB
+      int groupB_pow_offset = get_messagePowerOffsetGroupB(groupB->messagePowerOffsetGroupB);
+      int PLThreshold = ra->prach_resources.Pc_max - ra->preambleRxTargetPower - ra->msg3_deltaPreamble - groupB_pow_offset;
+      int pathloss = compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm);
+      // TODO if the Random Access procedure was initiated for the CCCH logical channel and the CCCH SDU size
+      // plus MAC subheader is greater than ra-Msg3SizeGroupA
+      if (ra->Msg3_size > get_Msg3SizeGroupA(groupB->ra_Msg3SizeGroupA) && pathloss < PLThreshold)
+        ra->RA_GroupA = false;
+      else
+        ra->RA_GroupA = true;
+    } else
+      ra->RA_GroupA = true;
+  }
+  // else if Msg3 is being retransmitted, we keep what used in first transmission of Msg3
 }
 
-void ssb_rach_config(RA_config_t *ra, NR_PRACH_RESOURCES_t *prach_resources, NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon)
+static ssb_ro_preambles_t get_ssb_ro_preambles_4step(struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *config)
 {
-  // Determine the SSB to RACH mapping ratio
-  // =======================================
-
-  NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
-  bool multiple_ssb_per_ro; // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
-  uint8_t ssb_rach_ratio; // Nb of SSBs per RACH or RACHs per SSB
-  int total_preambles_per_ssb;
-  uint8_t ssb_nb_in_ro;
-  int numberOfRA_Preambles = 64;
-
-  switch (ssb_perRACH_config){
+  ssb_ro_preambles_t ret = {0};
+  switch (config->present) {
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
-      multiple_ssb_per_ro = false;
-      ssb_rach_ratio = 8;
-      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneEighth + 1);
+      ret.ssb_per_ro = 0.125;
+      ret.preambles_per_ssb = (config->choice.oneEighth + 1) << 2;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneFourth:
-      multiple_ssb_per_ro = false;
-      ssb_rach_ratio = 4;
-      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneFourth + 1);
+      ret.ssb_per_ro = 0.25;
+      ret.preambles_per_ssb = (config->choice.oneFourth + 1) << 2;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneHalf:
-      multiple_ssb_per_ro = false;
-      ssb_rach_ratio = 2;
-      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneHalf + 1);
+      ret.ssb_per_ro = 0.5;
+      ret.preambles_per_ssb = (config->choice.oneHalf + 1) << 2;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_one:
-      multiple_ssb_per_ro = true;
-      ssb_rach_ratio = 1;
-      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.one + 1);
+      ret.ssb_per_ro = 1;
+      ret.preambles_per_ssb = (config->choice.one + 1) << 2;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_two:
-      multiple_ssb_per_ro = true;
-      ssb_rach_ratio = 2;
-      ra->cb_preambles_per_ssb = 4 * (nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.two + 1);
+      ret.ssb_per_ro = 2;
+      ret.preambles_per_ssb = (config->choice.two + 1) << 2;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_four:
-      multiple_ssb_per_ro = true;
-      ssb_rach_ratio = 4;
-      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.four;
+      ret.ssb_per_ro = 4;
+      ret.preambles_per_ssb = config->choice.four;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_eight:
-      multiple_ssb_per_ro = true;
-      ssb_rach_ratio = 8;
-      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.eight;
+      ret.ssb_per_ro = 8;
+      ret.preambles_per_ssb = config->choice.eight;
       break;
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen:
-      multiple_ssb_per_ro = true;
-      ssb_rach_ratio = 16;
-      ra->cb_preambles_per_ssb = nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.sixteen;
+      ret.ssb_per_ro = 16;
+      ret.preambles_per_ssb = config->choice.sixteen;
       break;
     default:
-      AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_config);
+      AssertFatal(false, "Invalid ssb_perRACH_OccasionAndCB_PreamblesPerSSB\n");
   }
+  LOG_D(NR_MAC, "SSB per RO %f preambles per SSB %d\n", ret.ssb_per_ro, ret.preambles_per_ssb);
+  return ret;
+}
 
-  if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles)
-    numberOfRA_Preambles = *(nr_rach_ConfigCommon->totalNumberOfRA_Preambles);
+static ssb_ro_preambles_t get_ssb_ro_preambles_2step(struct NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16 *config)
+{
+  ssb_ro_preambles_t ret = {0};
+  switch (config->present) {
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneEighth :
+      ret.ssb_per_ro = 0.125;
+      ret.preambles_per_ssb = (config->choice.oneEighth + 1) << 2;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneFourth :
+      ret.ssb_per_ro = 0.25;
+      ret.preambles_per_ssb = (config->choice.oneFourth + 1) << 2;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_oneHalf :
+      ret.ssb_per_ro = 0.5;
+      ret.preambles_per_ssb = (config->choice.oneHalf + 1) << 2;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_one :
+      ret.ssb_per_ro = 1;
+      ret.preambles_per_ssb = (config->choice.one + 1) << 2;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_two :
+      ret.ssb_per_ro = 2;
+      ret.preambles_per_ssb = (config->choice.two + 1) << 2;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_four :
+      ret.ssb_per_ro = 4;
+      ret.preambles_per_ssb = config->choice.four;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_eight :
+      ret.ssb_per_ro = 8;
+      ret.preambles_per_ssb = config->choice.eight;
+      break;
+    case NR_RACH_ConfigCommonTwoStepRA_r16__msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16_PR_sixteen :
+      ret.ssb_per_ro = 16;
+      ret.preambles_per_ssb = config->choice.sixteen;
+      break;
+    default :
+      AssertFatal(false, "Invalid msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16\n");
+  }
+  return ret;
+}
 
-  // Compute the proper Preamble selection params according to the selected SSB and the ssb_perRACH_OccasionAndCB_PreamblesPerSSB configuration
-  if ((true == multiple_ssb_per_ro) && (ssb_rach_ratio > 1)) {
-    total_preambles_per_ssb = numberOfRA_Preambles / ssb_rach_ratio;
+static void config_preamble_index(NR_UE_MAC_INST_t *mac)
+{
+  RA_config_t *ra = &mac->ra;
+  // Random seed generation
+  unsigned int seed;
+  if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
+    // Overwrite seed with non-random seed for IQ player/recorder
+    seed = 1;
+  } else {
+    // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int)
+    seed = (unsigned int)(rdtsc_oai() & ~0);
+  }
 
-    ssb_nb_in_ro = ra->ssb_nb_in_ro;
-    ra->starting_preamble_nb = total_preambles_per_ssb * ssb_nb_in_ro;
+  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
+  int nb_of_preambles = 64;
+  bool groupBconfigured = false;
+  int preamb_ga = 0;
+  if (ra->ra_type == RA_4_STEP) {
+    AssertFatal(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB,
+                "Not expeting ssb_perRACH_OccasionAndCB_PreamblesPerSSB to be NULL here\n");
+    ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
+    if (nr_rach_ConfigCommon->totalNumberOfRA_Preambles)
+      nb_of_preambles = *nr_rach_ConfigCommon->totalNumberOfRA_Preambles;
+    // Amongst the contention-based Random Access Preambles associated with an SSB the first numberOfRA-PreamblesGroupA
+    // included in groupBconfigured Random Access Preambles belong to Random Access Preambles group A.
+    // The remaining Random Access Preambles associated with the SSB belong to Random Access Preambles group B (if configured)
+    select_preamble_group(mac);
+    if (nr_rach_ConfigCommon->groupBconfigured) {
+      groupBconfigured = true;
+      preamb_ga = nr_rach_ConfigCommon->groupBconfigured->numberOfRA_PreamblesGroupA;
+    }
   } else {
-    total_preambles_per_ssb = numberOfRA_Preambles;
-    ra->starting_preamble_nb = 0;
+    NR_RACH_ConfigCommonTwoStepRA_r16_t *twostep = &mac->current_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16;
+    AssertFatal(twostep->groupB_ConfiguredTwoStepRA_r16 == NULL, "GroupB preambles not supported for 2-step RA\n");
+    ra->RA_GroupA = true;
+    // The field is mandatory present if the 2-step random access type occasions are shared with 4-step random access type,
+    // otherwise the field is not present
+    bool sharedROs = twostep->msgA_CB_PreamblesPerSSB_PerSharedRO_r16 != NULL;
+    AssertFatal(sharedROs == false, "Shared ROs between 2- and 4-step RA not supported\n");
+
+    // For Type-2 random access procedure with separate configuration of PRACH occasions with Type-1 random access procedure
+    // configuration by msgA-SSB-PerRACH-OccasionAndCB-PreamblesPerSSB when provided;
+    // otherwise, by ssb-perRACH-OccasionAndCB-PreamblesPerSSB
+    if (twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16)
+      ra->ssb_ro_config = get_ssb_ro_preambles_2step(twostep->msgA_SSB_PerRACH_OccasionAndCB_PreamblesPerSSB_r16);
+    else
+      ra->ssb_ro_config = get_ssb_ro_preambles_4step(nr_rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB);
+    if (twostep->msgA_TotalNumberOfRA_Preambles_r16)
+      nb_of_preambles = *twostep->msgA_TotalNumberOfRA_Preambles_r16;
+  }
+
+  int groupOffset = 0;
+  if (groupBconfigured) {
+    AssertFatal(preamb_ga < nb_of_preambles, "Nb of preambles for groupA not compatible with total number of preambles\n");
+    if (!ra->RA_GroupA) { // groupB
+      groupOffset = preamb_ga;
+      nb_of_preambles = nb_of_preambles - preamb_ga;
+    } else {
+      nb_of_preambles = preamb_ga;
+    }
+  }
+  int rand_preamb = (rand_r(&seed) % ra->ssb_ro_config.preambles_per_ssb);
+  if (ra->ssb_ro_config.ssb_per_ro < 1)
+    ra->ra_PreambleIndex = groupOffset + rand_preamb;
+  else {
+    int ssb_pr_idx = mac->ssb_list.nb_ssb_per_index[mac->mib_ssb] % (int)ra->ssb_ro_config.ssb_per_ro;
+    ra->ra_PreambleIndex = groupOffset + (ssb_pr_idx * ra->ssb_ro_config.preambles_per_ssb) + rand_preamb;
+  }
+  AssertFatal(ra->ra_PreambleIndex < nb_of_preambles,
+              "Error! Selected preamble %d which exceeds number of prambles available %d\n",
+              ra->ra_PreambleIndex,
+              nb_of_preambles);
+}
+
+static void configure_ra_preamble(NR_UE_MAC_INST_t *mac)
+{
+  RA_config_t *ra = &mac->ra;
+  int ssb = -1; // init as not selected
+  ra->ro_mask_index = -1; // init as not selected
+  NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated;
+  if (ra->ra_type == RA_4_STEP) {
+    // TODO if the Random Access procedure was initiated for SpCell beam failure recovery
+    // TODO if the Random Access procedure was initiated for SI request
+
+    if (ra->pdcch_order.active && ra->pdcch_order.preamble_index != 0xb000000) {
+      // set the PREAMBLE_INDEX to the signalled ra-PreambleIndex;
+      ra->ra_PreambleIndex = ra->pdcch_order.preamble_index;
+      // select the SSB signalled by PDCCH
+      ssb = ra->pdcch_order.ssb_index;
+      ra->ro_mask_index = ra->pdcch_order.prach_mask;
+    } else if (rach_ConfigDedicated && rach_ConfigDedicated->cfra) {
+      NR_CFRA_t *cfra = rach_ConfigDedicated->cfra;
+      AssertFatal(cfra->occasions == NULL, "Dedicated PRACH occasions for CFRA not supported\n");
+      AssertFatal(cfra->resources.present == NR_CFRA__resources_PR_ssb, "SSB-based CFRA supported only\n");
+      struct NR_CFRA__resources__ssb *ssb_list = cfra->resources.choice.ssb;
+      for (int i = 0; i < ssb_list->ssb_ResourceList.list.count; i++) {
+        NR_CFRA_SSB_Resource_t *res = ssb_list->ssb_ResourceList.list.array[i];
+        // TODO select an SSB with SS-RSRP above rsrp-ThresholdSSB amongst the associated SSBs
+        if (res->ssb == mac->mib_ssb) {
+          ssb = mac->mib_ssb;
+          // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB
+          ra->ra_PreambleIndex = res->ra_PreambleIndex;
+          ra->ro_mask_index = ssb_list->ra_ssb_OccasionMaskIndex;
+          break;
+        }
+      }
+    } else { // for the contention-based Random Access preamble selection
+      // TODO if at least one of the SSBs with SS-RSRP above rsrp-ThresholdSSB is available
+      // else select any SSB
+      ssb = mac->mib_ssb;
+      config_preamble_index(mac);
+    }
+  } else { // 2-step RA
+    // if the contention-free 2-step RA type Resources associated with SSBs have been explicitly provided in rach-ConfigDedicated
+    // TODO and at least one SSB with SS-RSRP above msgA-RSRP-ThresholdSSB amongst the associated SSBs is available
+    if (ra->cfra) {
+      AssertFatal(rach_ConfigDedicated->ext1 && rach_ConfigDedicated->ext1->cfra_TwoStep_r16,
+                  "Two-step CFRA should be configured here\n");
+      NR_CFRA_TwoStep_r16_t *cfra = rach_ConfigDedicated->ext1->cfra_TwoStep_r16;
+      AssertFatal(cfra->occasionsTwoStepRA_r16 == NULL, "Dedicated PRACH occasions for CFRA not supported\n");
+      for (int i = 0; i < cfra->resourcesTwoStep_r16.ssb_ResourceList.list.count; i++) {
+        NR_CFRA_SSB_Resource_t *res = cfra->resourcesTwoStep_r16.ssb_ResourceList.list.array[i];
+        if (res->ssb == mac->mib_ssb) {
+          ssb = mac->mib_ssb;
+          // set the PREAMBLE_INDEX to a ra-PreambleIndex corresponding to the selected SSB
+          ra->ra_PreambleIndex = res->ra_PreambleIndex;
+          ra->ro_mask_index = cfra->resourcesTwoStep_r16.ra_ssb_OccasionMaskIndex;
+          break;
+        }
+      }
+    } else { // for the contention-based Random Access Preamble selection
+      // TODO if at least one of the SSBs with SS-RSRP above msgA-RSRP-ThresholdSSB is available
+      // else select any SSB
+      ssb = mac->mib_ssb;
+      config_preamble_index(mac);
+    }
   }
+  AssertFatal(ssb >= 0, "Something wrong! RA resource selection didn't set any SSB\n");
+  // setting the RA ssb value as the progressive number of SSB transmitted
+  // non-transmitted SSBs are not taken into account
+  int ssb_idx = mac->ssb_list.nb_ssb_per_index[ssb];
+  ra->new_ssb = ssb != ssb_idx ? true : false;
+  ra->ra_ssb = ssb_idx;
+
+  // TODO not sure how to handle the RO mask when it is limiting the RO occasions
+  AssertFatal(ra->ro_mask_index <= 0, "Handling of RACH occasion masking indication not implemented\n");
 }
 
-// This routine implements RA preamble configuration according to
-// section 5.1 (Random Access procedure) of 3GPP TS 38.321 version 16.2.1 Release 16
-void ra_preambles_config(NR_PRACH_RESOURCES_t *prach_resources, NR_UE_MAC_INST_t *mac, int16_t dl_pathloss){
+static bool check_mixed_slot_prach(frame_structure_t *fs, int slot, int start_prach, int end_prach)
+{
+  bool is_mixed = is_mixed_slot(slot, fs);
+  if (is_mixed) {
+    tdd_bitmap_t *bitmap = &fs->period_cfg.tdd_slot_bitmap[slot % fs->numb_slots_period];
+    if (bitmap->num_ul_symbols == 0)
+      return false;
+    int ul_end = NR_NUMBER_OF_SYMBOLS_PER_SLOT - 1;
+    int ul_start = NR_NUMBER_OF_SYMBOLS_PER_SLOT - bitmap->num_ul_symbols;
+    if (start_prach < ul_start || end_prach > ul_end)
+      return false;
+  }
+  return true;
+}
 
-  int messageSizeGroupA = 0;
-  int sizeOfRA_PreamblesGroupA = 0;
-  int messagePowerOffsetGroupB = 0;
-  int PLThreshold = 0;
-  long deltaPreamble_Msg3 = 0;
-  uint8_t noGroupB = 0;
-  // Random seed generation
+static void select_prach_occasion(RA_config_t *ra,
+                                  int nb_tx_ssb,
+                                  int n,
+                                  prach_occasion_info_t ra_occasions_period[n],
+                                  int num_ra_occasions_period)
+{
   unsigned int seed;
-
   if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
     // Overwrite seed with non-random seed for IQ player/recorder
     seed = 1;
   } else {
     // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int)
-    seed = (unsigned int) (rdtsc_oai() & ~0);
+    seed = (unsigned int)(rdtsc_oai() & ~0);
   }
 
+  int num_ros_per_ssb = 0;
+  int idx_ssb = 0;
+  int temp_idx = 0;
+  if (ra->ssb_ro_config.ssb_per_ro < 1) {
+    num_ros_per_ssb = (int)(1 / ra->ssb_ro_config.ssb_per_ro);
+    idx_ssb = (rand_r(&seed) % num_ros_per_ssb);
+    temp_idx = ra->ra_ssb * num_ros_per_ssb + idx_ssb;
+  } else {
+    int ssb_per_ro = nb_tx_ssb < ra->ssb_ro_config.ssb_per_ro ? nb_tx_ssb : ra->ssb_ro_config.ssb_per_ro;
+    num_ros_per_ssb = ra->association_periods * ssb_per_ro * num_ra_occasions_period / nb_tx_ssb;
+    idx_ssb = (rand_r(&seed) % num_ros_per_ssb);
+    int eq_ssb = ra->ra_ssb + (idx_ssb * nb_tx_ssb);
+    temp_idx = eq_ssb / ra->ssb_ro_config.ssb_per_ro;
+  }
+  int ro_index = temp_idx % num_ra_occasions_period;
+  int ass_period_idx = temp_idx / num_ra_occasions_period;
+  ra->sched_ro_info = ra_occasions_period[ro_index];
+  ra->sched_ro_info.association_period_idx = ass_period_idx;
+}
+
+static void configure_prach_occasions(NR_UE_MAC_INST_t *mac, int scs)
+{
   RA_config_t *ra = &mac->ra;
-  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
+  int num_ra_occasions_period = 0;
+  frame_structure_t *fs = &mac->frame_structure;
+  nr_prach_info_t prach_info =  get_nr_prach_occasion_info_from_index(ra->ra_config_index, mac->frequency_range, fs->frame_type);
+  int max_num_occasions = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * ra->num_fd_occasions;
+  prach_occasion_info_t ra_occasions_period[max_num_occasions];
+  // Number of PRACH slots within a subframe (or 60kHz slot) to be taken into account only for 30 and 120kHz
+  // as defined in 5.3.2 of 211
+  int prach_slots_in_sf = (scs == 1 || scs == 3) ? prach_info.N_RA_slot : 1;
+  uint64_t temp_s_map = prach_info.s_map;
+  int n_frames = prach_info.y2 == -1 ? 1 : 2;
+  for (int n = 0; n < n_frames; n++) {
+    int sf = 0;
+    for (int s = 0; s < prach_info.N_RA_sfn; s++) { // subframe/60kHz slot occasions in period
+      while (((temp_s_map >> sf) & 0x01) == 0)
+        sf++;
+      int sl = sf;
+      for (int i = 0; i < prach_slots_in_sf; i++) { // slot per subframe/60kHz slot
+        int add_slot = i;
+        if (scs == 1 || scs == 3) {
+          sl *= 2;
+          // if only 1 slot per subframe (or 60kHz slot) in case of 30 or 120kHz it's the odd one
+          // as defined in 5.3.2 of 211
+          if (prach_slots_in_sf == 1)
+            add_slot = 1;
+        }
+        int slot = sl + add_slot;
+        if (!is_ul_slot(slot, fs))
+          continue; // valid PRACH occasion only if slot is UL
+        for (int t = 0; t < prach_info.N_t_slot; t++) { // td occasions within a slot
+          // see 5.3.2 in 211
+          int temp_format = prach_info.format >> 8; // B1, B2 or B3 if A1/B1, A2/B2 or A3/B3 formats in tables
+          if (t != prach_info.N_t_slot - 1 || temp_format == 0xff)
+            temp_format = prach_info.format & 0xff;
+          int start_symbol = prach_info.start_symbol + t * prach_info.N_dur;
+          int end_symbol = start_symbol + prach_info.N_dur;
+          // valid occasion only if PRACH symbols are UL symbols in mixed slot
+          if (fs->frame_type == TDD && !check_mixed_slot_prach(fs, slot, start_symbol, end_symbol))
+            continue;
+          for (int f = 0; f < ra->num_fd_occasions; f++) { // fd occasions
+            ra_occasions_period[num_ra_occasions_period] =
+                (prach_occasion_info_t){.slot = slot,
+                                        .frame_info[0] = prach_info.x,
+                                        .frame_info[1] = n == 0 ? prach_info.y : prach_info.y2,
+                                        .start_symbol = start_symbol,
+                                        .fdm = f,
+                                        .format = temp_format};
+            LOG_D(NR_MAC,
+                  "RA occasion %d: slot %d start symbol %d fd occasion %d\n",
+                  num_ra_occasions_period,
+                  slot,
+                  start_symbol,
+                  f);
+            num_ra_occasions_period++;
+          }
+        }
+      }
+      sf++;
+    }
+  }
 
-  if (mac->current_UL_BWP->msg3_DeltaPreamble) {
-    deltaPreamble_Msg3 = (*mac->current_UL_BWP->msg3_DeltaPreamble) * 2; // dB
-    LOG_D(MAC, "In %s: deltaPreamble_Msg3 set to %ld\n", __FUNCTION__, deltaPreamble_Msg3);
+  int config_period = prach_info.x; // configuration period
+  ra->association_periods = 1;
+  int nb_eq_ssb = mac->ssb_list.nb_tx_ssb;
+  if (ra->ssb_ro_config.ssb_per_ro < 1)
+    nb_eq_ssb *= (int)(1 / ra->ssb_ro_config.ssb_per_ro);
+  int nb_eq_ro = num_ra_occasions_period;
+  if (ra->ssb_ro_config.ssb_per_ro > 1)
+    nb_eq_ro *= (int)ra->ssb_ro_config.ssb_per_ro;
+  while (nb_eq_ssb > nb_eq_ro) {
+    // not enough PRACH occasions -> need to increase association period
+    ra->association_periods <<= 1;
+    AssertFatal(ra->association_periods * config_period <= 16,
+                "Cannot find an association period for %d SSB and %d RO with %f SSB per RO\n",
+                mac->ssb_list.nb_tx_ssb,
+                num_ra_occasions_period,
+                ra->ssb_ro_config.ssb_per_ro);
+    nb_eq_ro <<= 1; // doubling the association period -> doubling ROs
   }
+  LOG_D(NR_MAC, "PRACH configuration period %d association period %d\n", config_period, ra->association_periods);
 
-  if (!setup->groupBconfigured) {
-    noGroupB = 1;
-    LOG_D(MAC, "In %s:%d: preambles group B is not configured...\n", __FUNCTION__, __LINE__);
-  } else {
-    // RA preambles group B is configured
-    // - Random Access Preambles group B is configured for 4-step RA type
-    // - Defining the number of RA preambles in RA Preamble Group A for each SSB
-    LOG_D(MAC, "In %s:%d: preambles group B is configured...\n", __FUNCTION__, __LINE__);
-    sizeOfRA_PreamblesGroupA = setup->groupBconfigured->numberOfRA_PreamblesGroupA;
-    switch (setup->groupBconfigured->ra_Msg3SizeGroupA){
-      /* - Threshold to determine the groups of RA preambles */
-      case 0:
-      messageSizeGroupA = 56;
+  select_prach_occasion(ra, mac->ssb_list.nb_tx_ssb, max_num_occasions, ra_occasions_period, num_ra_occasions_period);
+}
+
+/* TS 38.321 subclause 7.3 - return DELTA_PREAMBLE values in dB */
+static int nr_get_delta_preamble(int scs, int prach_format)
+{
+  int delta = 0;
+  switch (prach_format) {
+    case 0:
+    case 3:
+      delta = 0;
       break;
-      case 1:
-      messageSizeGroupA = 144;
+    case 1:
+      delta = -3;
       break;
-      case 2:
-      messageSizeGroupA = 208;
+    case 2:
+      delta = -6;
       break;
-      case 3:
-      messageSizeGroupA = 256;
+    case 0xa1:
+    case 0xb1:
+      delta = 8 + 3 * scs;
       break;
-      case 4:
-      messageSizeGroupA = 282;
+    case 0xa2:
+    case 0xb2:
+    case 0xc2:
+      delta = 5 + 3 * scs;
       break;
-      case 5:
-      messageSizeGroupA = 480;
+    case 0xa3:
+    case 0xb3:
+      delta = 3 + 3 * scs;
       break;
-      case 6:
-      messageSizeGroupA = 640;
+    case 0xb4:
+      delta = 3 * scs;
       break;
-      case 7:
-      messageSizeGroupA = 800;
+    case 0xc0:
+      delta = 11 + 3 * scs;
       break;
-      case 8:
-      messageSizeGroupA = 1000;
+    default:
+      AssertFatal(false, "Invalid preamble format %x\n", prach_format);
+  }
+  return delta;
+}
+
+static int get_ra_preamble_rx_target_power(RA_config_t *ra, int scs)
+{
+  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
+  int delta_preamble = nr_get_delta_preamble(scs, ra->sched_ro_info.format);
+  int tp = ra->preambleReceivedTargetPower_config + delta_preamble + prach_resources->power_offset_2step;
+  tp += (prach_resources->preamble_power_ramping_cnt - 1) * prach_resources->preamble_power_ramping_step;
+  return tp;
+}
+
+// 38.321 Sections 5.1.3 and .3a
+static void ra_preamble_msga_transmission(RA_config_t *ra, int scs)
+{
+  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
+  if (prach_resources->preamble_tx_counter > 1) {
+    // TODO if the notification of suspending power ramping counter has not been received from lower layers (not implemented)
+    //      this happens if the L1 does not transmit PRACH of if the spacial filter changed (UE transmitting in another beam)
+    // TODO if LBT failure indication was not received from lower layers (LBT not implemented)
+    // if SSB or CSI-RS selected is not changed from the selection in the last Random Access Preamble transmission
+    if (!ra->new_ssb)
+      prach_resources->preamble_power_ramping_cnt++;
+  }
+
+
+  prach_resources->ra_preamble_rx_target_power = get_ra_preamble_rx_target_power(ra, scs);
+
+  ra->ra_rnti = nr_get_ra_rnti(ra->sched_ro_info.start_symbol, ra->sched_ro_info.slot, ra->sched_ro_info.fdm, 0);
+  if (ra->ra_type == RA_2_STEP)
+    ra->MsgB_rnti = nr_get_MsgB_rnti(ra->sched_ro_info.start_symbol, ra->sched_ro_info.slot, ra->sched_ro_info.fdm, 0);
+}
+
+// 38.321 Section 5.1.2 Random Access Resource selection
+void ra_resource_selection(NR_UE_MAC_INST_t *mac)
+{
+  configure_ra_preamble(mac);
+  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
+  const int ul_mu = mac->current_UL_BWP->scs;
+  const int mu = nr_get_prach_or_ul_mu(mac->current_UL_BWP->msgA_ConfigCommon_r16, current_UL_BWP->rach_ConfigCommon, ul_mu);
+  configure_prach_occasions(mac, mu);
+  ra_preamble_msga_transmission(&mac->ra, mu);
+}
+
+static int nr_get_RA_window_2Step_v17(long msgB_ResponseWindow)
+{
+  switch (msgB_ResponseWindow) {
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl240:
+      return 240;
       break;
-      case 9:
-      messageSizeGroupA = 72;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl640:
+      return 640;
       break;
-      default:
-      AssertFatal(1 == 0, "Unknown ra_Msg3SizeGroupA %lu\n", setup->groupBconfigured->ra_Msg3SizeGroupA);
-      /* todo cases 10 -15*/
-      }
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl960:
+      return 960;
+      break;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl1280:
+      return 1280;
+      break;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl1920:
+      return 1920;
+      break;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__ext1__msgB_ResponseWindow_v1700_sl2560:
+      return 2590;
+    default:
+      AssertFatal(false, "illegal msgB_responseWindow value %ld\n", msgB_ResponseWindow);
+      break;
+  }
+  return 0;
+}
 
-      /* Power offset for preamble selection in dB */
-      messagePowerOffsetGroupB = -9999;
-      switch (setup->groupBconfigured->messagePowerOffsetGroupB){
-      case 0:
-      messagePowerOffsetGroupB = -9999;
+static int nr_get_RA_window_2Step_v16(long msgB_ResponseWindow)
+{
+  switch (msgB_ResponseWindow) {
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl1:
+      return 1;
       break;
-      case 1:
-      messagePowerOffsetGroupB = 0;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl2:
+      return 2;
       break;
-      case 2:
-      messagePowerOffsetGroupB = 5;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl4:
+      return 4;
       break;
-      case 3:
-      messagePowerOffsetGroupB = 8;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl8:
+      return 8;
       break;
-      case 4:
-      messagePowerOffsetGroupB = 10;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl10:
+      return 10;
       break;
-      case 5:
-      messagePowerOffsetGroupB = 12;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl20:
+      return 20;
       break;
-      case 6:
-      messagePowerOffsetGroupB = 15;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl40:
+      return 40;
       break;
-      case 7:
-      messagePowerOffsetGroupB = 18;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl80:
+      return 80;
       break;
-      default:
-      AssertFatal(1 == 0,"Unknown messagePowerOffsetGroupB %lu\n", setup->groupBconfigured->messagePowerOffsetGroupB);
-    }
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl160:
+      return 160;
+      break;
+    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl320:
+      return 360;
+      break;
+    default:
+      AssertFatal(false, "illegal msgB_responseWindow value %ld\n", msgB_ResponseWindow);
+      break;
+  }
+  return 0;
+}
 
-    PLThreshold = prach_resources->RA_PCMAX - rach_ConfigGeneric->preambleReceivedTargetPower - deltaPreamble_Msg3 - messagePowerOffsetGroupB;
+static int nr_get_RA_window_4Step_v16(long ra_ResponseWindow)
+{
+  switch (ra_ResponseWindow) {
+    case NR_RACH_ConfigGeneric__ext1__ra_ResponseWindow_v1610_sl60:
+      return 60;
+    case NR_RACH_ConfigGeneric__ext1__ra_ResponseWindow_v1610_sl160:
+      return 160;
+    default:
+      AssertFatal(false, "illegal ra_ResponseWindow value %ld\n", ra_ResponseWindow);
+  }
+  return 0;
+}
 
+static int nr_get_RA_window_4Step_v17(long ra_ResponseWindow)
+{
+  switch (ra_ResponseWindow) {
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl240:
+      return 240;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl320:
+      return 320;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl640:
+      return 640;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl960:
+      return 960;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl1280:
+      return 1280;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl1920:
+      return 1920;
+    case NR_RACH_ConfigGeneric__ext2__ra_ResponseWindow_v1700_sl2560:
+      return 2590;
+    default:
+      AssertFatal(false, "illegal msgB_responseWindow value %ld\n", ra_ResponseWindow);
   }
+  return 0;
+}
 
-  /* Msg3 has not been transmitted yet */
-  if (ra->first_Msg3) {
-    if(ra->ra_PreambleIndex < 0 || ra->ra_PreambleIndex > 63) {
-      if (noGroupB) {
-        // use Group A preamble
-        ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % ra->cb_preambles_per_ssb);
-        ra->RA_usedGroupA = 1;
-      } else if ((ra->Msg3_size < messageSizeGroupA) && (dl_pathloss > PLThreshold)) {
-        // Group B is configured and RA preamble Group A is used
-        // - todo add condition on CCCH_sdu_size for initiation by CCCH
-        ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % sizeOfRA_PreamblesGroupA);
-        ra->RA_usedGroupA = 1;
-      } else {
-        // Group B preamble is configured and used
-        // the first sizeOfRA_PreamblesGroupA RA preambles belong to RA Preambles Group A
-        // the remaining belong to RA Preambles Group B
-        ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
-        ra->RA_usedGroupA = 0;
-      }
+static int nr_get_RA_window_4Step(long ra_ResponseWindow)
+{
+  switch (ra_ResponseWindow) {
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1:
+      return 1;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl2:
+      return 2;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl4:
+      return 4;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl8:
+      return 8;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10:
+      return 10;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20:
+      return 20;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl40:
+      return 40;
+      break;
+    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80:
+      return 80;
+      break;
+    default:
+      AssertFatal(false, "illegal ra_ResponseWindow value %ld\n", ra_ResponseWindow);
+      break;
+  }
+  return 0;
+}
+
+static void setup_ra_response_window(RA_config_t *ra,
+                                     int slots_per_frame,
+                                     NR_NTN_Config_r17_t *ntn_Config_r17,
+                                     NR_RACH_ConfigGeneric_t *configGeneric,
+                                     NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep,
+                                     ntn_timing_advance_componets_t *ntn_ta)
+{
+  int respwind_value = 0;
+  if (ra->ra_type == RA_2_STEP) {
+    long *msgB_ResponseWindow = twostep->msgB_ResponseWindow_r16;
+    if (msgB_ResponseWindow)
+      respwind_value = nr_get_RA_window_2Step_v16(*msgB_ResponseWindow);
+    if (twostep->ext1 && twostep->ext1->msgB_ResponseWindow_v1700) {
+      AssertFatal(msgB_ResponseWindow == NULL,
+                  "The network does not configure msgB-ResponseWindow-r16 simultaneously with msgB-ResponseWindow-v1700\n");
+      msgB_ResponseWindow = twostep->ext1->msgB_ResponseWindow_v1700;
+      if (msgB_ResponseWindow)
+        respwind_value = nr_get_RA_window_2Step_v17(*msgB_ResponseWindow);
     }
-  } else { // Msg3 is being retransmitted
-    if (ra->RA_usedGroupA && noGroupB) {
-      ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % ra->cb_preambles_per_ssb);
-    } else if (ra->RA_usedGroupA && !noGroupB){
-      ra->ra_PreambleIndex = ra->starting_preamble_nb + (rand_r(&seed) % sizeOfRA_PreamblesGroupA);
-    } else {
-      ra->ra_PreambleIndex = ra->starting_preamble_nb + sizeOfRA_PreamblesGroupA + (rand_r(&seed) % (ra->cb_preambles_per_ssb - sizeOfRA_PreamblesGroupA));
+    // The network configures a value lower than or equal to 40ms
+    int slots_40ms = 4 * slots_per_frame;
+    AssertFatal(respwind_value != 0 && respwind_value <= slots_40ms, "Invalid MSGB response window value\n");
+  } else {
+    AssertFatal(ra->ra_type == RA_4_STEP, "Invalid RA type\n");
+    long *response_window = NULL;
+    if (configGeneric->ext1 && configGeneric->ext1->ra_ResponseWindow_v1610)
+      respwind_value = nr_get_RA_window_4Step_v16(*configGeneric->ext1->ra_ResponseWindow_v1610);
+    if (configGeneric->ext2 && configGeneric->ext2->ra_ResponseWindow_v1700) {
+      AssertFatal(response_window == NULL, "ra_ResponseWindow_v1610 and ra_ResponseWindow_v1700 are mutually exclusive\n");
+      respwind_value = nr_get_RA_window_4Step_v17(*configGeneric->ext2->ra_ResponseWindow_v1700);
     }
+    if (!response_window)
+      respwind_value = nr_get_RA_window_4Step(configGeneric->ra_ResponseWindow);
+    // The network configures a value lower than or equal to 10ms
+    AssertFatal(respwind_value != 0, "Invalid RAR response window value\n");
+    if (respwind_value > slots_per_frame)
+      LOG_E(NR_MAC, "RA-ResponseWindow need to be configured to a value lower than or equal to 10 ms\n");
+  }
+
+  int ta_Common_slots = 0;
+  if (ntn_Config_r17) {
+    const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(ntn_ta);
+    ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_frame / 10);
   }
+
+  ra->response_window_setup_time = respwind_value + ta_Common_slots;
 }
 
-// This routine implements Section 5.1.2 (UE Random Access Resource Selection)
-// and Section 5.1.3 (Random Access Preamble Transmission) from 3GPP TS 38.321
-// - currently the PRACH preamble is set through RRC configuration for 4-step CFRA mode
-// todo:
-// - determine next available PRACH occasion
-// -- if RA initiated for SI request and ra_AssociationPeriodIndex and si-RequestPeriod are configured
-// -- else if SSB is selected above
-// -- else if CSI-RS is selected above
-// - switch initialisation cases
-// -- RA initiated by beam failure recovery operation (subclause 5.17 TS 38.321)
-// --- SSB selection, set ra_PreambleIndex
-// -- RA initiated by PDCCH: ra_preamble_index provided by PDCCH && ra_PreambleIndex != 0b000000
-// --- set PREAMBLE_INDEX to ra_preamble_index
-// --- select the SSB signalled by PDCCH
-// -- RA initiated for SI request:
-// --- SSB selection, set ra_PreambleIndex
-// - condition on notification of suspending power ramping counter from lower layer (5.1.3 TS 38.321)
-// - check if SSB or CSI-RS have not changed since the selection in the last RA Preamble tranmission
-// - Contention-based RA preamble selection:
-// -- selection of SSB with SS-RSRP above rsrp-ThresholdSSB else select any SSB
-void nr_get_prach_resources(NR_UE_MAC_INST_t *mac,
-                            int CC_id,
-                            uint8_t gNB_id,
-                            NR_PRACH_RESOURCES_t *prach_resources,
-                            NR_RACH_ConfigDedicated_t *rach_ConfigDedicated)
+// Random Access procedure initialization as per 5.1.1 and initialization of variables specific
+// to Random Access type as specified in clause 5.1.1a (3GPP TS 38.321 version 16.2.1 Release 16)
+bool init_RA(NR_UE_MAC_INST_t *mac, int frame)
 {
   RA_config_t *ra = &mac->ra;
+  LOG_D(NR_MAC, "Initialization of RA\n");
+  ra->ra_state = nrRA_GENERATE_PREAMBLE;
+
+  // TODO this piece of code is required to compute MSG3_size that is used by ra_preambles_config function
+  // Not a good implementation, it needs improvements
+  int size_sdu = 0;
+
+  // Concerning the C-RNTI MAC CE,
+  // it has to be included if the UL transmission (Msg3) is not being made for the CCCH logical channel.
+  // Therefore it has been assumed that this event only occurs only when RA is done and it is not SA mode.
+  if (get_softmodem_params()->nsa) {
+
+    uint8_t mac_sdus[34 * 1056];
+    uint16_t sdu_lengths[NB_RB_MAX] = {0};
+    int TBS_bytes = 848;
+    int mac_ce_len = 0;
+    unsigned short post_padding = 1;
+
+    // fill ulsch_buffer with random data
+    for (int i = 0; i < TBS_bytes; i++) {
+      mac_sdus[i] = (unsigned char)(rand()&0xff);
+    }
+    // Sending SDUs with size 1
+    // Initialize elements of sdu_lengths
+    sdu_lengths[0] = TBS_bytes - 3 - post_padding - mac_ce_len;
+    size_sdu += sdu_lengths[0];
+
+    if (size_sdu > 0) {
+      memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6);
+      ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
+    }
 
-  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = mac->current_UL_BWP->rach_ConfigCommon;
-
-  LOG_D(MAC, "Getting PRACH resources frame (first_Msg3 %d)\n", ra->first_Msg3);
+  } else if (!IS_SA_MODE(get_softmodem_params()))
+    ra->Msg3_size = sizeof(uint16_t) + sizeof(NR_MAC_SUBHEADER_FIXED);
 
-  if (rach_ConfigDedicated) {
-    if (rach_ConfigDedicated->cfra){
-      uint8_t cfra_ssb_resource_idx = 0;
-      ra->ra_PreambleIndex = rach_ConfigDedicated->cfra->resources.choice.ssb->ssb_ResourceList.list.array[cfra_ssb_resource_idx]->ra_PreambleIndex;
-      LOG_D(MAC, "Selected RA preamble index %d for contention-free random access procedure for SSB with Id %d\n", 
-            ra->ra_PreambleIndex,
-            cfra_ssb_resource_idx);
+  // Random acces procedure initialization
+  mac->state = UE_PERFORMING_RA;
+  ra->RA_active = true;
+  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
+  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
+  // flush MSG3 buffer
+  free_and_zero(ra->Msg3_buffer);
+  // set the PREAMBLE_TRANSMISSION_COUNTER to 1
+  prach_resources->preamble_tx_counter = 1;
+  // set the PREAMBLE_POWER_RAMPING_COUNTER to 1
+  prach_resources->preamble_power_ramping_cnt = 1;
+  // set POWER_OFFSET_2STEP_RA to 0 dB
+  prach_resources->power_offset_2step = 0;
+
+  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
+  // perform the BWP operation as specified in clause 5.15
+  // if PRACH occasions are not configured for the active UL BWP
+  if (!current_UL_BWP->rach_ConfigCommon) {
+    // switch the active UL BWP to BWP indicated by initialUplinkBWP
+    current_UL_BWP = get_ul_bwp_structure(mac, 0, false);
+    // if the Serving Cell is an SpCell
+    // switch the active DL BWP to BWP indicated by initialDownlinkBWP
+    mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false);
+  } else {
+    // if the active DL BWP does not have the same bwp-Id as the active UL BWP
+    if (current_UL_BWP->bwp_id != mac->current_DL_BWP->bwp_id) {
+      // switch the active DL BWP to the DL BWP with the same bwp-Id as the active UL BWP
+      mac->current_DL_BWP = get_dl_bwp_structure(mac, 0, false);
     }
+  }
+
+  NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = current_UL_BWP->rach_ConfigCommon;
+  AssertFatal(nr_rach_ConfigCommon, "rach-ConfigCommon should be configured here\n");
+  // stop the bwp-InactivityTimer associated with the active DL BWP of this Serving Cell, if running
+  // TODO bwp-InactivityTimer not implemented
+
+  // if the carrier to use for the Random Access procedure is explicitly signalled (always the case for us)
+  // PRACH shall be as specified for QPSK modulated DFT-s-OFDM of equivalent RB allocation (38.101-1)
+  NR_SubcarrierSpacing_t prach_scs;
+  int scs_for_pcmax; // for long prach the UL BWP SCS is used for calculating RA_PCMAX
+  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &nr_rach_ConfigCommon->rach_ConfigGeneric;
+  if (nr_rach_ConfigCommon->msg1_SubcarrierSpacing) {
+    prach_scs = *nr_rach_ConfigCommon->msg1_SubcarrierSpacing;
+    scs_for_pcmax = prach_scs;
   } else {
-    /* TODO: This controls the tx_power of UE and the ramping procedure of RA of UE. Later we
-             can abstract this, perhaps in the proxy. But for the time being lets leave it as below. */
-    int16_t dl_pathloss = !get_softmodem_params()->emulate_l1 ? compute_nr_SSB_PL(mac, mac->ssb_measurements.ssb_rsrp_dBm) : 0;
-    ssb_rach_config(ra, prach_resources, nr_rach_ConfigCommon);
-    ra_preambles_config(prach_resources, mac, dl_pathloss);
-    LOG_D(MAC, "[RAPROC] - Selected RA preamble index %d for contention-based random access procedure... \n", ra->ra_PreambleIndex);
+    const unsigned int index = rach_ConfigGeneric->prach_ConfigurationIndex;
+    const unsigned int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
+    const unsigned int format = get_format0(index, unpaired, mac->frequency_range);
+    prach_scs = get_delta_f_RA_long(format);
+    scs_for_pcmax = mac->current_UL_BWP->scs;
+  }
+  int n_prbs = get_N_RA_RB(prach_scs, current_UL_BWP->scs);
+  int start_prb = rach_ConfigGeneric->msg1_FrequencyStart + current_UL_BWP->BWPStart;
+  prach_resources->Pc_max = nr_get_Pcmax(mac->p_Max,
+                                         mac->nr_band,
+                                         mac->frame_structure.frame_type,
+                                         mac->frequency_range,
+                                         current_UL_BWP->channel_bandwidth,
+                                         2,
+                                         false,
+                                         scs_for_pcmax,
+                                         cfg->carrier_config.dl_grid_size[scs_for_pcmax],
+                                         true,
+                                         n_prbs,
+                                         start_prb);
+
+
+  // TODO if the Random Access procedure was initiated for SI request
+  // and the Random Access Resources for SI request have been explicitly provided by RRC
+
+  // TODO if the Random Access procedure was initiated for SpCell beam failure recovery
+  // and if the contention-free Random Access Resources for beam failure recovery request for 4-step RA type
+  // have been explicitly provided by RRC for the BWP selected for Random Access procedure
+
+  NR_RACH_ConfigCommonTwoStepRA_r16_t *twostep_conf = NULL;
+  NR_RACH_ConfigDedicated_t *rach_Dedicated = ra->rach_ConfigDedicated;
+
+  // if the Random Access procedure is initiated by PDCCH order
+  // and if the ra-PreambleIndex explicitly provided by PDCCH is not 0b000000
+  bool pdcch_order = (ra->pdcch_order.active && ra->pdcch_order.preamble_index != 0xb000000) ? true : false;
+  // or if the Random Access procedure was initiated for reconfiguration with sync and
+  // if the contention-free Random Access Resources for 4-step RA type have been explicitly provided
+  // in rach-ConfigDedicated for the BWP selected for Random Access procedure
+  if ((rach_Dedicated && rach_Dedicated->cfra) || pdcch_order) {
+    LOG_I(MAC, "Initialization of 4-Step CFRA procedure\n");
+    ra->ra_type = RA_4_STEP;
+    ra->cfra = true;
+  } else {
+    bool twostep_cfra = (rach_Dedicated && rach_Dedicated->ext1) ? (rach_Dedicated->ext1->cfra_TwoStep_r16 ? true : false) : false;
+    if (twostep_cfra) {
+      // if the Random Access procedure was initiated for reconfiguration with sync and
+      // if the contention-free Random Access Resources for 2-step RA type have been explicitly provided in rach-ConfigDedicated
+      LOG_I(MAC, "Initialization of 2-Step CFRA procedure\n");
+      ra->ra_type = RA_2_STEP;
+      ra->cfra = true;
+    } else {
+      bool twostep = false;
+      if (current_UL_BWP->msgA_ConfigCommon_r16) {
+        twostep_conf = &current_UL_BWP->msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16;
+        if (nr_rach_ConfigCommon) {
+          // if the BWP selected for Random Access procedure is configured with both 2- and 4-step RA type Random Access Resources
+          // and the RSRP of the downlink pathloss reference is above msgA-RSRP-Threshold
+          AssertFatal(twostep_conf->msgA_RSRP_Threshold_r16,
+                      "msgA_RSRP_Threshold_r16 is mandatory present if both 2-step and 4-step random access types are configured\n");
+          // For thresholds the RSRP value is (IE value – 156) dBm except for the IE 127 in which case the actual value is infinity
+          int rsrp_msga_thr = *twostep_conf->msgA_RSRP_Threshold_r16 - 156;
+          if (*twostep_conf->msgA_RSRP_Threshold_r16 != 127 && mac->ssb_measurements.ssb_rsrp_dBm > rsrp_msga_thr)
+            twostep = true;
+        } else {
+          // if the BWP selected for Random Access procedure is only configured with 2-step RA type Random Access
+          twostep = true;
+        }
+      }
+      if (twostep) {
+        LOG_I(MAC, "Initialization of 2-Step CBRA procedure\n");
+        ra->ra_type = RA_2_STEP;
+        ra->cfra = false;
+      } else {
+        LOG_I(MAC, "Initialization of 4-Step CBRA procedure\n");
+        ra->ra_type = RA_4_STEP;
+        ra->cfra = false;
+      }
+    }
   }
 
-  if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER > 1)
-    prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER++;
-  prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources, CC_id);
+  // need to ask RRC to send the MSG3 data to transmit if needed (CBRA originating from upper layers)
+  if (!mac->msg3_C_RNTI && ra->cfra == false)
+    nr_mac_rrc_msg3_ind(mac->ue_id, 0, true);
 
-}
+  NR_RACH_ConfigGenericTwoStepRA_r16_t *twostep_generic = twostep_conf ? &twostep_conf->rach_ConfigGenericTwoStepRA_r16 : NULL;
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreamblePowerRampingStep_r16)
+    prach_resources->preamble_power_ramping_step = *twostep_generic->msgA_PreamblePowerRampingStep_r16 << 1;
+  else
+    prach_resources->preamble_power_ramping_step = rach_ConfigGeneric->powerRampingStep << 1;
 
-// TbD: RA_attempt_number not used
-void nr_Msg1_transmitted(NR_UE_MAC_INST_t *mac)
-{
-  RA_config_t *ra = &mac->ra;
-  ra->ra_state = nrRA_WAIT_RAR;
-  ra->RA_attempt_number++;
+  ra->scaling_factor_bi = 1;
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreambleReceivedTargetPower_r16)
+    ra->preambleReceivedTargetPower_config = *twostep_generic->msgA_PreambleReceivedTargetPower_r16;
+  else
+    ra->preambleReceivedTargetPower_config = rach_ConfigGeneric->preambleReceivedTargetPower;
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->preambleTransMax_r16)
+    set_preambleTransMax(ra, *twostep_generic->preambleTransMax_r16);
+  else
+    set_preambleTransMax(ra, rach_ConfigGeneric->preambleTransMax);
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_ZeroCorrelationZoneConfig_r16)
+    ra->zeroCorrelationZoneConfig = *twostep_generic->msgA_ZeroCorrelationZoneConfig_r16;
+  else
+    ra->zeroCorrelationZoneConfig = rach_ConfigGeneric->zeroCorrelationZoneConfig;
+  if (ra->ra_type == RA_2_STEP && twostep_conf && twostep_conf->msgA_RestrictedSetConfig_r16)
+    ra->restricted_set_config = *twostep_conf->msgA_RestrictedSetConfig_r16;
+  else
+    ra->restricted_set_config = nr_rach_ConfigCommon->restrictedSetConfig;
+
+  // TODO msgA-TransMax not implemented
+  // TODO ra-Prioritization not implemented
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PreambleReceivedTargetPower_r16)
+    ra->preambleRxTargetPower = *twostep_generic->msgA_PreambleReceivedTargetPower_r16;
+  else
+    ra->preambleRxTargetPower = rach_ConfigGeneric->preambleReceivedTargetPower;
+
+  if (ra->ra_type == RA_2_STEP
+      && current_UL_BWP->msgA_ConfigCommon_r16
+      && current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16
+      && current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_DeltaPreamble_r16)
+    ra->msg3_deltaPreamble = *current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_DeltaPreamble_r16 << 1;
+  else
+    ra->msg3_deltaPreamble = mac->current_UL_BWP->msg3_DeltaPreamble ? *mac->current_UL_BWP->msg3_DeltaPreamble << 1 : 0;
+
+  ra->new_ssb = false;
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_PRACH_ConfigurationIndex_r16)
+    ra->ra_config_index = *twostep_generic->msgA_PRACH_ConfigurationIndex_r16;
+  else {
+    if (rach_ConfigGeneric->ext1 && rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610)
+      ra->ra_config_index = *rach_ConfigGeneric->ext1->prach_ConfigurationIndex_v1610;
+    else
+      ra->ra_config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
+  }
+
+  if (ra->ra_type == RA_2_STEP && twostep_generic && twostep_generic->msgA_RO_FDM_r16)
+    ra->num_fd_occasions = 1 << *twostep_generic->msgA_RO_FDM_r16;
+  else
+    ra->num_fd_occasions = 1 << rach_ConfigGeneric->msg1_FDM;
+
+  setup_ra_response_window(ra,
+                           mac->frame_structure.numb_slots_frame,
+                           mac->sc_info.ntn_Config_r17,
+                           rach_ConfigGeneric,
+                           twostep_generic,
+                           &mac->ntn_ta);
+  return true;
 }
 
 void nr_Msg3_transmitted(NR_UE_MAC_INST_t *mac, uint8_t CC_id, frame_t frameP, slot_t slotP, uint8_t gNB_id)
@@ -663,7 +1134,7 @@ void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS
   }
 
   uint8_t *pdu = buf;
-  if (ra->msg3_C_RNTI)
+  if (mac->msg3_C_RNTI)
     pdu = fill_msg3_crnti_pdu(ra, pdu, mac->crnti);
   else
     pdu = fill_msg3_pdu_from_rlc(mac, pdu, TBS_max);
@@ -679,253 +1150,6 @@ void nr_get_Msg3_MsgA_PUSCH_payload(NR_UE_MAC_INST_t *mac, uint8_t *buf, int TBS
   memcpy(ra->Msg3_buffer, buf, sizeof(uint8_t) * TBS_max);
 }
 
-/**
- * Function:            handles Random Access Preamble Initialization (5.1.1 TS 38.321)
- *                      handles Random Access Response reception (5.1.4 TS 38.321)
- * Note:                In SA mode the Msg3 contains a CCCH SDU, therefore no C-RNTI MAC CE is transmitted.
- *
- * @prach_resources     pointer to PRACH resources
- * @prach_pdu           pointer to FAPI UL PRACH PDU
- * @mod_id              module ID
- * @CC_id               CC ID
- * @frame               current UL TX frame
- * @gNB_id              gNB ID
- * @nr_slot_tx          current UL TX slot
- */
-void nr_ue_get_rach(NR_UE_MAC_INST_t *mac, int CC_id, frame_t frame, uint8_t gNB_id, int nr_slot_tx)
-{
-  RA_config_t *ra = &mac->ra;
-  NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = ra->rach_ConfigDedicated;
-  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
-
-  // Delay init RA procedure to allow the convergence of the IIR filter on PRACH noise measurements at gNB side
-  if (ra->ra_state == nrRA_UE_IDLE) {
-    LOG_D(NR_MAC,
-          "ra->ra_state %d frame %d mac->first_sync_frame %d xxx %d",
-          ra->ra_state,
-          frame,
-          mac->first_sync_frame,
-          ((MAX_FRAME_NUMBER + frame - mac->first_sync_frame) % MAX_FRAME_NUMBER) > 10);
-      if ((mac->first_sync_frame > -1 || get_softmodem_params()->do_ra || get_softmodem_params()->nsa)
-          && ((MAX_FRAME_NUMBER + frame - mac->first_sync_frame) % MAX_FRAME_NUMBER) > 150) {
-        ra->ra_state = nrRA_GENERATE_PREAMBLE;
-        LOG_D(NR_MAC, "PRACH Condition met: ra state %d, frame %d, sync_frame %d\n", ra->ra_state, frame, mac->first_sync_frame);
-      } else {
-        LOG_D(NR_MAC,
-              "PRACH Condition not met: ra state %d, frame %d, sync_frame %d\n",
-              ra->ra_state,
-              frame,
-              mac->first_sync_frame);
-        return;
-      }
-  }
-
-  LOG_D(NR_MAC, "[UE %d][%d.%d]: ra_state %d, RA_active %d\n", mac->ue_id, frame, nr_slot_tx, ra->ra_state, ra->RA_active);
-
-  if (ra->ra_state > nrRA_UE_IDLE && ra->ra_state < nrRA_SUCCEEDED) {
-    if (!ra->RA_active) {
-      NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-      NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
-      init_RA(mac, &ra->prach_resources, setup, rach_ConfigGeneric, ra->rach_ConfigDedicated);
-
-      // TODO this piece of code is required to compute MSG3_size that is used by ra_preambles_config function
-      // Not a good implementation, it needs improvements
-      int size_sdu = 0;
-
-      // Concerning the C-RNTI MAC CE, it has to be included if the UL transmission (Msg3) is not being made for the CCCH logical channel.
-      // Therefore it has been assumed that this event only occurs only when RA is done and it is not SA mode.
-      if (get_softmodem_params()->nsa) {
-
-        uint8_t mac_sdus[34*1056];
-        uint16_t sdu_lengths[NB_RB_MAX] = {0};
-        int TBS_bytes = 848;
-        int mac_ce_len = 0;
-        unsigned short post_padding = 1;
-
-        // fill ulsch_buffer with random data
-        for (int i = 0; i < TBS_bytes; i++){
-          mac_sdus[i] = (unsigned char) (rand()&0xff);
-        }
-        //Sending SDUs with size 1
-        //Initialize elements of sdu_lengths
-        sdu_lengths[0] = TBS_bytes - 3 - post_padding - mac_ce_len;
-        size_sdu += sdu_lengths[0];
-
-        if (size_sdu > 0) {
-          memcpy(ra->cont_res_id, mac_sdus, sizeof(uint8_t) * 6);
-          ra->Msg3_size = size_sdu + sizeof(NR_MAC_SUBHEADER_SHORT) + sizeof(NR_MAC_SUBHEADER_SHORT);
-        }
-
-      } else if (!IS_SA_MODE(get_softmodem_params())) {
-        uint8_t temp_pdu[16] = {0};
-        size_sdu = nr_write_ce_msg3_pdu(temp_pdu, mac, mac->crnti, temp_pdu + sizeof(temp_pdu));
-        ra->Msg3_size = size_sdu;
-      }
-    } else if (ra->RA_window_cnt != -1) { // RACH is active
-
-      LOG_D(MAC, "[%d.%d] RA is active: RA window count %d, RA backoff count %d\n", frame, nr_slot_tx, ra->RA_window_cnt, ra->RA_backoff_cnt);
-
-      if (ra->RA_BI_found){
-        prach_resources->RA_PREAMBLE_BACKOFF = prach_resources->RA_SCALING_FACTOR_BI * ra->RA_backoff_indicator;
-      } else {
-        prach_resources->RA_PREAMBLE_BACKOFF = 0;
-      }
-
-      if (ra->RA_window_cnt >= 0 && ra->RA_RAPID_found == 1) {
-
-        if(ra->cfra) {
-          // Reset RA_active flag: it disables Msg3 retransmission (8.3 of TS 38.213)
-          nr_ra_succeeded(mac, gNB_id, frame, nr_slot_tx);
-        }
-
-      } else if (ra->RA_window_cnt == 0 && !ra->RA_RAPID_found && ra->ra_state != nrRA_WAIT_MSGB) {
-        LOG_W(MAC, "[UE %d][%d:%d] RAR reception failed \n", mac->ue_id, frame, nr_slot_tx);
-
-        nr_ra_failed(mac, CC_id, prach_resources, frame, nr_slot_tx);
-
-      } else if (ra->RA_window_cnt > 0) {
-
-        LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA window count %d) \n", mac->ue_id, frame, nr_slot_tx, ra->RA_window_cnt);
-
-        // Fill in preamble and PRACH resources
-        ra->RA_window_cnt--;
-        if (ra->ra_state == nrRA_GENERATE_PREAMBLE) {
-          nr_get_prach_resources(mac, CC_id, gNB_id, prach_resources, rach_ConfigDedicated);
-        }
-      } else if (ra->RA_backoff_cnt > 0) {
-
-        LOG_D(MAC, "[UE %d][%d.%d]: RAR not received yet (RA backoff count %d) \n", mac->ue_id, frame, nr_slot_tx, ra->RA_backoff_cnt);
-
-        ra->RA_backoff_cnt--;
-
-        if ((ra->RA_backoff_cnt > 0 && ra->ra_state == nrRA_GENERATE_PREAMBLE) || ra->RA_backoff_cnt == 0) {
-          nr_get_prach_resources(mac, CC_id, gNB_id, prach_resources, rach_ConfigDedicated);
-        }
-      }
-    }
-  }
-
-  if (nr_timer_is_active(&ra->contention_resolution_timer)) {
-    nr_ue_contention_resolution(mac, CC_id, frame, nr_slot_tx, prach_resources);
-  }
-}
-
-int16_t nr_get_RA_window_2Step(const NR_MsgA_ConfigCommon_r16_t *msgA_ConfigCommon_r16)
-{
-  int16_t ra_ResponseWindow = *msgA_ConfigCommon_r16->rach_ConfigCommonTwoStepRA_r16
-                              .rach_ConfigGenericTwoStepRA_r16.msgB_ResponseWindow_r16;
-
-  switch (ra_ResponseWindow) {
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl1:
-      return 1;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl2:
-      return 2;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl4:
-      return 4;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl8:
-      return 8;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl10:
-      return 10;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl20:
-      return 20;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl40:
-      return 40;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl80:
-      return 80;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl160:
-      return 160;
-      break;
-    case NR_RACH_ConfigGenericTwoStepRA_r16__msgB_ResponseWindow_r16_sl320:
-      return 360;
-      break;
-    default:
-      AssertFatal(false, "illegal msgB_responseWindow value %d\n", ra_ResponseWindow);
-      break;
-  }
-  return 0;
-}
-
-int16_t nr_get_RA_window_4Step(const NR_RACH_ConfigCommon_t *rach_ConfigCommon)
-{
-  int16_t ra_ResponseWindow = rach_ConfigCommon->rach_ConfigGeneric.ra_ResponseWindow;
-
-  switch (ra_ResponseWindow) {
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl1:
-      return 1;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl2:
-      return 2;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl4:
-      return 4;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl8:
-      return 8;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl10:
-      return 10;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl20:
-      return 20;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl40:
-      return 40;
-      break;
-    case NR_RACH_ConfigGeneric__ra_ResponseWindow_sl80:
-      return 80;
-      break;
-    default:
-      AssertFatal(false, "illegal ra_ResponseWindow value %d\n", ra_ResponseWindow);
-      break;
-  }
-  return 0;
-}
-
-void nr_get_RA_window(NR_UE_MAC_INST_t *mac)
-{
-  RA_config_t *ra = &mac->ra;
-  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-  AssertFatal(&setup->rach_ConfigGeneric != NULL, "In %s: FATAL! rach_ConfigGeneric is NULL...\n", __FUNCTION__);
-  const double ta_Common_ms = GET_COMPLETE_TIME_ADVANCE_MS(&mac->ntn_ta);
-  int slots_per_frame = mac->frame_structure.numb_slots_frame;
-  const int slots_per_ms = slots_per_frame / 10;
-  const int ra_Offset_slots = ra->RA_offset * slots_per_frame;
-  const int ta_Common_slots = (int)ceil(ta_Common_ms * slots_per_ms);
-
-  ra->RA_window_cnt = ra_Offset_slots + ta_Common_slots; // taking into account the 2 frames gap introduced by OAI gNB
-
-  ra->RA_window_cnt += ra->ra_type == RA_2_STEP ? nr_get_RA_window_2Step(mac->current_UL_BWP->msgA_ConfigCommon_r16)
-                                                : nr_get_RA_window_4Step(mac->current_UL_BWP->rach_ConfigCommon);
-}
-
-////////////////////////////////////////////////////////////////////////////
-/////////* Random Access Contention Resolution (5.1.35 TS 38.321) */////////
-////////////////////////////////////////////////////////////////////////////
-// Handling contention resolution timer
-// WIP todo:
-// - beam failure recovery
-// - RA completed
-void nr_ue_contention_resolution(NR_UE_MAC_INST_t *mac, int cc_id, frame_t frame, int slot, NR_PRACH_RESOURCES_t *prach_resources)
-{
-  RA_config_t *ra = &mac->ra;
-
-  if (nr_timer_expired(&ra->contention_resolution_timer)) {
-    ra->t_crnti = 0;
-    nr_timer_stop(&ra->contention_resolution_timer);
-    // Signal PHY to quit RA procedure
-    LOG_E(MAC, "[UE %d] 4-Step CBRA: Contention resolution timer has expired, RA procedure has failed...\n", mac->ue_id);
-    nr_ra_failed(mac, cc_id, prach_resources, frame, slot);
-  }
-}
-
 // Handlig successful RA completion @ MAC layer
 // according to section 5 of 3GPP TS 38.321 version 16.2.1 Release 16
 // todo:
@@ -936,90 +1160,95 @@ void nr_ra_succeeded(NR_UE_MAC_INST_t *mac, const uint8_t gNB_index, const frame
 
   if (ra->cfra) {
     LOG_I(MAC, "[UE %d][%d.%d][RAPROC] RA procedure succeeded. CFRA: RAR successfully received.\n", mac->ue_id, frame, slot);
-    ra->RA_window_cnt = -1;
-  } else if (ra->ra_type == RA_2_STEP) {
-    LOG_A(MAC,
-          "[UE %d][%d.%d][RAPROC] 2-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n",
-          mac->ue_id,
-          frame,
-          slot);
-    mac->crnti = ra->t_crnti;
-    ra->t_crnti = 0;
-    LOG_D(MAC, "[UE %d][%d.%d] CBRA: cleared response window timer...\n", mac->ue_id, frame, slot);
   } else {
     LOG_A(MAC,
-          "[UE %d][%d.%d][RAPROC] 4-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n",
+          "[UE %d][%d.%d][RAPROC] %d-Step RA procedure succeeded. CBRA: Contention Resolution is successful.\n",
           mac->ue_id,
           frame,
-          slot);
-    nr_timer_stop(&ra->contention_resolution_timer);
+          slot,
+          ra->ra_type == RA_2_STEP ? 2 : 4);
     mac->crnti = ra->t_crnti;
     ra->t_crnti = 0;
-    LOG_D(MAC, "[UE %d][%d.%d] CBRA: cleared contention resolution timer...\n", mac->ue_id, frame, slot);
+    nr_timer_stop(&ra->contention_resolution_timer);
   }
 
-  LOG_D(MAC, "[UE %d] clearing RA_active flag...\n", mac->ue_id);
   ra->RA_active = false;
-  ra->msg3_C_RNTI = false;
+  mac->msg3_C_RNTI = false;
   ra->ra_state = nrRA_SUCCEEDED;
   mac->state = UE_CONNECTED;
   free_and_zero(ra->Msg3_buffer);
-  nr_mac_rrc_ra_ind(mac->ue_id, frame, true);
+  nr_mac_rrc_ra_ind(mac->ue_id, true);
 }
 
-// Handling failure of RA procedure @ MAC layer
-// according to section 5 of 3GPP TS 38.321 version 16.2.1 Release 16
-// todo:
-// - complete handling of received contention-based RA preamble
-void nr_ra_failed(NR_UE_MAC_INST_t *mac, uint8_t CC_id, NR_PRACH_RESOURCES_t *prach_resources, frame_t frame, int slot)
+void nr_ra_backoff_setting(RA_config_t *ra)
 {
-  RA_config_t *ra = &mac->ra;
-  // Random seed generation
-  unsigned int seed;
+  // select a random backoff time according to a uniform distribution
+  // between 0 and the PREAMBLE_BACKOFF
+  uint32_t seed = (unsigned int)(rdtsc_oai() & ~0);
+  uint32_t random_backoff = ra->RA_backoff_limit ? rand_r(&seed) % ra->RA_backoff_limit : 0; // in slots
+  nr_timer_setup(&ra->RA_backoff_timer, random_backoff, 1);
+  nr_timer_start(&ra->RA_backoff_timer);
+}
 
-  if (IS_SOFTMODEM_IQPLAYER || IS_SOFTMODEM_IQRECORDER) {
-    // Overwrite seed with non-random seed for IQ player/recorder
-    seed = 1;
+void nr_ra_contention_resolution_failed(NR_UE_MAC_INST_t *mac)
+{
+  LOG_W(MAC, "[UE %d] Contention resolution failed\n", mac->ue_id);
+  RA_config_t *ra = &mac->ra;
+  // discard the TEMPORARY_C-RNTI
+  ra->t_crnti = 0;
+  // flush MSG3 buffer
+  free_and_zero(ra->Msg3_buffer);
+  nr_mac_rrc_msg3_ind(mac->ue_id, 0, true);
+  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
+  prach_resources->preamble_tx_counter++;
+  if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) {
+    // indicate a Random Access problem to upper layers
+    nr_mac_rrc_ra_ind(mac->ue_id, false);
   } else {
-    // & to truncate the int64_t and keep only the LSB bits, up to sizeof(int)
-    seed = (unsigned int) (rdtsc_oai() & ~0);
+    // TODO handle msgA-TransMax (go back to 4-step if the threshold is reached)
+    // starting backoff time
+    nr_ra_backoff_setting(ra);
   }
-  
-  ra->first_Msg3 = true;
-  ra->ra_PreambleIndex = -1;
-  ra->ra_state = nrRA_UE_IDLE;
-
-  prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER++;
-
-  // when the Contention Resolution is considered not successful
-  // stop timeAlignmentTimer
-  nr_timer_stop(&mac->time_alignment_timer);
-
-  if (prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER == ra->preambleTransMax + 1) {
-
-    LOG_D(NR_MAC,
-          "[UE %d][%d.%d] Maximum number of RACH attempts (%d) reached, selecting backoff time...\n",
-          mac->ue_id,
-          frame,
-          slot,
-          ra->preambleTransMax);
-
-    ra->RA_backoff_cnt = rand_r(&seed) % (prach_resources->RA_PREAMBLE_BACKOFF + 1);
-    prach_resources->RA_PREAMBLE_TRANSMISSION_COUNTER = 1;
-    prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP += 2; // 2 dB increment
-    prach_resources->ra_PREAMBLE_RECEIVED_TARGET_POWER = nr_get_Po_NOMINAL_PUSCH(mac, prach_resources, CC_id);
+}
 
-  } else {
-    nr_get_RA_window(mac);
+void nr_rar_not_successful(NR_UE_MAC_INST_t *mac)
+{
+  LOG_W(MAC, "[UE %d] RAR reception failed\n", mac->ue_id);
+  RA_config_t *ra = &mac->ra;
+  NR_PRACH_RESOURCES_t *prach_resources = &ra->prach_resources;
+  prach_resources->preamble_tx_counter++;
+  bool ra_completed = false;
+  if (prach_resources->preamble_tx_counter == ra->preambleTransMax + 1) {
+    // if the Random Access Preamble is transmitted on the SpCell
+    // TODO to be verified, this means SA if I'm not mistaken
+    if (IS_SA_MODE(get_softmodem_params())) {
+      // indicate a Random Access problem to upper layers
+      nr_mac_rrc_ra_ind(mac->ue_id, false);
+    } else {
+      // if the Random Access Preamble is transmitted on an SCell:
+      // consider the Random Access procedure unsuccessfully completed.
+      ra_completed = true;
+      ra->ra_state = nrRA_UE_IDLE;
+    }
+  }
+  if (!ra_completed) {
+    nr_ra_backoff_setting(ra);
   }
 }
 
-void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac)
+void trigger_MAC_UE_RA(NR_UE_MAC_INST_t *mac, dci_pdu_rel15_t *pdcch_order)
 {
   LOG_W(NR_MAC, "Triggering new RA procedure for UE with RNTI %x\n", mac->crnti);
   mac->state = UE_PERFORMING_RA;
   reset_ra(mac, false);
-  mac->ra.msg3_C_RNTI = true;
+  RA_config_t *ra = &mac->ra;
+  mac->msg3_C_RNTI = true;
+  if (pdcch_order) {
+    ra->pdcch_order.active = true;
+    ra->pdcch_order.preamble_index = pdcch_order->ra_preamble_index;
+    ra->pdcch_order.ssb_index = pdcch_order->ss_pbch_index;
+    ra->pdcch_order.prach_mask = pdcch_order->prach_mask_index;
+  }
 }
 
 void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack)
@@ -1048,16 +1277,6 @@ void prepare_msg4_msgb_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack)
   release_ul_config(pdu, false);
 }
 
-void free_rach_structures(NR_UE_MAC_INST_t *nr_mac, int bwp_id)
-{
-  for (int j = 0; j < MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD; j++)
-    for (int k = 0; k < MAX_NB_FRAME_IN_PRACH_CONF_PERIOD; k++)
-      for (int l = 0; l < MAX_NB_SLOT_IN_FRAME; l++)
-        free(nr_mac->prach_assoc_pattern[bwp_id].prach_conf_period_list[j].prach_occasion_slot_map[k][l].prach_occasion);
-
-  free(nr_mac->ssb_list[bwp_id].tx_ssb);
-}
-
 void reset_ra(NR_UE_MAC_INST_t *nr_mac, bool free_prach)
 {
   RA_config_t *ra = &nr_mac->ra;
@@ -1067,7 +1286,4 @@ void reset_ra(NR_UE_MAC_INST_t *nr_mac, bool free_prach)
 
   if (!free_prach)
     return;
-
-  for (int i = 0; i < MAX_NUM_BWP_UE; i++)
-    free_rach_structures(nr_mac, i);
 }
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
index aeeab40b7462f431a5273ddf350e4267ca4e9e88..3817e067593fcc49407761d18b7be15d660498d5 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_dci_configuration.c
@@ -442,8 +442,8 @@ bool search_space_monitoring_ocasion_other_si(NR_UE_MAC_INST_t *mac,
   get_monitoring_period_offset(ss, &period, &offset);
   for (int i = 0; i < duration; i++) {
     if (((frame * slots_per_frame + slot - offset - i) % period) == 0) {
-      int N = mac->ssb_list[bwp_id].nb_tx_ssb;
-      int K = mac->ssb_list->nb_ssb_per_index[mac->mib_ssb];
+      int N = mac->ssb_list.nb_tx_ssb;
+      int K = mac->ssb_list.nb_ssb_per_index[mac->mib_ssb];
 
       // numbering current frame and slot in terms of monitoring occasions in window
       int rel_slot = abs_slot - mac->si_SchedInfo.si_window_start;
@@ -560,12 +560,13 @@ void ue_dci_configuration(NR_UE_MAC_INST_t *mac, fapi_nr_dl_config_request_t *dl
       config_dci_pdu(mac, dl_config, TYPE_SI_RNTI_, slot, ss);
     }
   }
-  if (mac->state == UE_PERFORMING_RA && mac->ra.ra_state >= nrRA_WAIT_RAR) {
+  RA_config_t *ra = &mac->ra;
+  if (mac->state == UE_PERFORMING_RA && ra->ra_state >= nrRA_WAIT_RAR) {
     // if RA is ongoing use RA search space
     if (is_ss_monitor_occasion(frame, slot, slots_per_frame, pdcch_config->ra_SS)) {
       nr_rnti_type_t rnti_type = 0;
-      if (mac->ra.ra_type == RA_4_STEP) {
-        rnti_type = mac->ra.ra_state == nrRA_WAIT_RAR ? TYPE_RA_RNTI_ : TYPE_TC_RNTI_;
+      if (ra->ra_type == RA_4_STEP) {
+        rnti_type = ra->ra_state == nrRA_WAIT_RAR ? TYPE_RA_RNTI_ : TYPE_TC_RNTI_;
       } else {
         rnti_type = TYPE_MSGB_RNTI_;
       }
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
index 7083b4a14100464fecb1e16f681207c870a083b0..9db464f0152fbe066618f5f910f356db8bd63ffa 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_power_procedures.c
@@ -372,8 +372,8 @@ int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
     if (mac->pucch_power_control_initialized == false) {
       // Initialize power control state
       // Assuming only sending on PCell
-      NR_PRACH_RESOURCES_t* prach_resources = &mac->ra.prach_resources;
-      float DELTA_P_rampup_requested = (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP;
+      NR_PRACH_RESOURCES_t *prach_res = &mac->ra.prach_resources;
+      float DELTA_P_rampup_requested = (prach_res->preamble_power_ramping_cnt - 1) * prach_res->preamble_power_ramping_step;
       float DELTA_P_rampup = P_CMAX - (P_O_PUCCH + pathloss + delta_F_PUCCH + DELTA_TF + sum_delta_pucch);
       DELTA_P_rampup = max(min(0, DELTA_P_rampup), DELTA_P_rampup_requested);
       mac->G_b_f_c = DELTA_P_rampup + sum_delta_pucch;
@@ -492,9 +492,7 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac,
     if (current_UL_BWP->msg3_DeltaPreamble) {
       DELTA_PREAMBLE_MSG3 = *current_UL_BWP->msg3_DeltaPreamble;
     }
-    NR_RACH_ConfigCommon_t *nr_rach_ConfigCommon = current_UL_BWP->rach_ConfigCommon;
-    long preambleReceivedTargetPower = nr_rach_ConfigCommon->rach_ConfigGeneric.preambleReceivedTargetPower;
-    int P_O_PRE = preambleReceivedTargetPower;
+    int P_O_PRE = mac->ra.prach_resources.ra_preamble_rx_target_power;
     P_O_NOMINAL_PUSCH = P_O_PRE + DELTA_PREAMBLE_MSG3;
 
     if (has_pusch_power_control_config && pusch_Config->pusch_PowerControl->msg3_Alpha) {
@@ -572,8 +570,8 @@ int get_pusch_tx_power_ue(NR_UE_MAC_INST_t *mac,
     f_b_f_c = delta_pusch;
   } else {
     if (!mac->pusch_power_control_initialized && is_rar_tx_retx) {
-      NR_PRACH_RESOURCES_t* prach_resources = &mac->ra.prach_resources;
-      float DELTA_P_rampup_requested = (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP;
+      NR_PRACH_RESOURCES_t *prach_res = &mac->ra.prach_resources;
+      float DELTA_P_rampup_requested = (prach_res->preamble_power_ramping_cnt - 1) * prach_res->preamble_power_ramping_step;
       float DELTA_P_rampup = P_CMAX - (P_O_PUSCH + M_pusch_component + alpha * pathloss + DELTA_TF + delta_pusch);
       DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup));
       mac->f_b_f_c = DELTA_P_rampup + delta_pusch;
@@ -654,9 +652,8 @@ int get_srs_tx_power_ue(NR_UE_MAC_INST_t *mac,
 
     if (!is_tpc_accumulation_provided && (!is_configured_for_pusch_on_current_bwp || separate_pc_adjustment_state)) {
       if (!current_UL_BWP->srs_power_control_initialized) {
-        NR_PRACH_RESOURCES_t *prach_resources = &mac->ra.prach_resources;
-        float DELTA_P_rampup_requested =
-            (prach_resources->RA_PREAMBLE_POWER_RAMPING_COUNTER - 1) * prach_resources->RA_PREAMBLE_POWER_RAMPING_STEP;
+        NR_PRACH_RESOURCES_t *prach = &mac->ra.prach_resources;
+        float DELTA_P_rampup_requested = (prach->preamble_power_ramping_cnt - 1) * prach->preamble_power_ramping_step;
         float DELTA_P_rampup = P_CMAX - (P_0_SRS + m_srs_component + alpha * pathloss);
         DELTA_P_rampup = min(DELTA_P_rampup_requested, max(0, DELTA_P_rampup));
         current_UL_BWP->srs_power_control_initialized = true;
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index c150cc29cdf67497be2242ba135bcc3fe3fdd06c..83bbcadbe5341068e5146594c1adfecc17eff007 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -59,6 +59,25 @@
 // #define DEBUG_MIB
 // #define ENABLE_MAC_PAYLOAD_DEBUG 1
 // #define DEBUG_RAR
+
+// table 7.2-1 TS 38.321
+const uint16_t table_7_2_1[16] = {
+    5,    // row index 0
+    10,   // row index 1
+    20,   // row index 2
+    30,   // row index 3
+    40,   // row index 4
+    60,   // row index 5
+    80,   // row index 6
+    120,  // row index 7
+    160,  // row index 8
+    240,  // row index 9
+    320,  // row index 10
+    480,  // row index 11
+    960,  // row index 12
+    1920, // row index 13
+};
+
 /* TS 36.213 Table 9.2.3-3: Mapping of values for one HARQ-ACK bit to sequences */
 static const int sequence_cyclic_shift_1_harq_ack_bit[2]
 /*        HARQ-ACK Value        0    1 */
@@ -219,9 +238,6 @@ void nr_ue_decode_mib(NR_UE_MAC_INST_t *mac, int cc_id)
   mac->ssb_subcarrier_offset = ssb_subcarrier_offset;
   mac->dmrs_TypeA_Position = mac->mib->dmrs_TypeA_Position;
 
-  if (mac->first_sync_frame == -1)
-    mac->first_sync_frame = frame;
-
   if (get_softmodem_params()->phy_test)
     mac->state = UE_CONNECTED;
   else if (mac->state == UE_NOT_SYNC) {
@@ -701,7 +717,7 @@ static int nr_ue_process_dci_dl_10(NR_UE_MAC_INST_t *mac,
       dlsch_pdu->SubcarrierSpacing = mac->mib->subCarrierSpacingCommon + 2;
   } else {
     dlsch_pdu->SubcarrierSpacing = current_DL_BWP->scs;
-    if (mac->ra.RA_window_cnt >= 0 && rnti_type == TYPE_RA_RNTI_) {
+    if (nr_timer_is_active(&mac->ra.response_window_timer) && rnti_type == TYPE_RA_RNTI_) {
       dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH;
     } else {
       dl_conf_req->pdu_type = FAPI_NR_DL_CONFIG_TYPE_DLSCH;
@@ -2929,7 +2945,7 @@ void nr_ue_send_sdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, in
         nr_timer_start(mac->data_inactivity_timer);
       // DL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
       if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
-        trigger_MAC_UE_RA(mac);
+        trigger_MAC_UE_RA(mac, NULL);
         break;
       }
       nr_ue_process_mac_pdu(mac, dl_info, pdu_id);
@@ -2991,7 +3007,11 @@ static void extract_10_si_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dc
   EXTRACT_DCI_ITEM(dci_pdu_rel15->system_info_indicator, 1);
 }
 
-static void extract_10_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci_pdu, int pos, const int N_RB)
+static bool extract_10_c_rnti(NR_UE_MAC_INST_t *mac,
+                              dci_pdu_rel15_t *dci_pdu_rel15,
+                              const uint8_t *dci_pdu,
+                              int pos,
+                              const int N_RB)
 {
   LOG_D(NR_MAC_DCI, "Received dci 1_0 C rnti\n");
 
@@ -3014,29 +3034,31 @@ static void extract_10_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci
     EXTRACT_DCI_ITEM(dci_pdu_rel15->ss_pbch_index, 6);
     //  prach_mask_index  4 bits
     EXTRACT_DCI_ITEM(dci_pdu_rel15->prach_mask_index, 4);
+    trigger_MAC_UE_RA(mac, dci_pdu_rel15);
+    return true;
   } // end if
-  else {
-    // Time domain assignment 4bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->time_domain_assignment.val, 4);
-    // VRB to PRB mapping  1bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->vrb_to_prb_mapping.val, 1);
-    // MCS 5bit  //bit over 32, so dci_pdu ++
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->mcs, 5);
-    // New data indicator 1bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->ndi, 1);
-    // Redundancy version  2bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->rv, 2);
-    // HARQ process number  4/5 bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->harq_pid.val, dci_pdu_rel15->harq_pid.nbits);
-    // Downlink assignment index  2bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->dai[0].val, 2);
-    // TPC command for scheduled PUCCH  2bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->tpc, 2);
-    // PUCCH resource indicator  3bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->pucch_resource_indicator, 3);
-    // PDSCH-to-HARQ_feedback timing indicator 3bit
-    EXTRACT_DCI_ITEM(dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val, 3);
-  } // end else
+
+  // Time domain assignment 4bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->time_domain_assignment.val, 4);
+  // VRB to PRB mapping  1bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->vrb_to_prb_mapping.val, 1);
+  // MCS 5bit  //bit over 32, so dci_pdu ++
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->mcs, 5);
+  // New data indicator 1bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->ndi, 1);
+  // Redundancy version  2bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->rv, 2);
+  // HARQ process number  4/5 bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->harq_pid.val, dci_pdu_rel15->harq_pid.nbits);
+  // Downlink assignment index  2bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->dai[0].val, 2);
+  // TPC command for scheduled PUCCH  2bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->tpc, 2);
+  // PUCCH resource indicator  3bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->pucch_resource_indicator, 3);
+  // PDSCH-to-HARQ_feedback timing indicator 3bit
+  EXTRACT_DCI_ITEM(dci_pdu_rel15->pdsch_to_harq_feedback_timing_indicator.val, 3);
+  return false;
 }
 
 static void extract_00_c_rnti(dci_pdu_rel15_t *dci_pdu_rel15, const uint8_t *dci_pdu, int pos)
@@ -3297,7 +3319,9 @@ static nr_dci_format_t nr_extract_dci_00_10(NR_UE_MAC_INST_t *mac,
         int n_RB = get_nrb_for_dci(mac, format, ss_type);
         if (n_RB == 0)
           return NR_DCI_NONE;
-        extract_10_c_rnti(dci_pdu_rel15, dci_pdu, pos, n_RB);
+        bool pdcch_order = extract_10_c_rnti(mac, dci_pdu_rel15, dci_pdu, pos, n_RB);
+        if (pdcch_order)
+          return NR_DCI_NONE;
       }
       else {
         format = NR_UL_DCI_FORMAT_0_0;
@@ -3406,11 +3430,11 @@ static bool check_ra_contention_resolution(const uint8_t *pdu, const uint8_t *co
 }
 
 static int nr_ue_validate_successrar(uint8_t *pduP,
-                              int32_t pdu_len,
-                              NR_UE_MAC_INST_t *mac,
-                              uint8_t gNB_index,
-                              frame_t frameP,
-                              int slot)
+                                     int32_t pdu_len,
+                                     NR_UE_MAC_INST_t *mac,
+                                     uint8_t gNB_index,
+                                     frame_t frameP,
+                                     int slot)
 {
   // TS 38.321 - Figure 6.1.5a-1: BI MAC subheader
   // TS 38.321 - Figure 6.1.5a-3: SuccessRAR MAC subheader
@@ -3418,6 +3442,7 @@ static int nr_ue_validate_successrar(uint8_t *pduP,
   uint8_t E = 1;
   uint8_t cont_res_id[6];
   RA_config_t *ra = &mac->ra;
+  ra->RA_backoff_limit = 0;
 
   while (n < pdu_len && E) {
     E = (pduP[n] >> 7) & 0x1;
@@ -3425,7 +3450,9 @@ static int nr_ue_validate_successrar(uint8_t *pduP,
     if (SUCESS_RAR_header_T1 == 0) { // T2 exist
       int SUCESS_RAR_header_T2 = (pduP[n] >> 5) & 0x1;
       if (SUCESS_RAR_header_T2 == 0) { // BI
-        ra->RA_backoff_indicator = pduP[n] & 0x0F;
+        int bi_ms = table_7_2_1[(pduP[n] & 0x0F)] * ra->scaling_factor_bi;
+        int slots_per_ms = mac->frame_structure.numb_slots_frame / 10;
+        ra->RA_backoff_limit = bi_ms * slots_per_ms;
         n++;
       } else { // S
         n++;
@@ -3468,11 +3495,10 @@ static int nr_ue_validate_successrar(uint8_t *pduP,
         bool ra_success = check_ra_contention_resolution(cont_res_id, ra->cont_res_id);
 
         if (ra->RA_active && ra_success) {
+          nr_timer_stop(&ra->response_window_timer);
           nr_ra_succeeded(mac, gNB_index, frameP, slot);
         } else if (!ra_success) {
-          // nr_ra_failed(mac, CC_id, &ra->prach_resources, frameP, slot);
-          ra->ra_state = nrRA_UE_IDLE;
-          ra->RA_active = 0;
+          nr_ra_backoff_setting(ra);
         }
       }
     } else { // RAPID
@@ -3675,7 +3701,8 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i
         mac_len = 6;
 
         if (ra->ra_state == nrRA_WAIT_CONTENTION_RESOLUTION) {
-          LOG_I(MAC, "[UE %d]Frame %d Contention resolution identity: 0x%02x%02x%02x%02x%02x%02x Terminating RA procedure\n",
+          LOG_D(NR_MAC,
+                "[UE %d]Frame %d Contention resolution identity: 0x%02x%02x%02x%02x%02x%02x Terminating RA procedure\n",
                 mac->ue_id,
                 frameP,
                 pduP[1],
@@ -3685,15 +3712,15 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i
                 pduP[5],
                 pduP[6]);
 
+          nr_timer_stop(&ra->contention_resolution_timer);
           bool ra_success = check_ra_contention_resolution(&pduP[1], ra->cont_res_id);
 
           if (ra->RA_active && ra_success) {
             nr_ra_succeeded(mac, gNB_index, frameP, slot);
           } else if (!ra_success) {
-            // TODO: Handle failure of RA procedure @ MAC layer
-            //  nr_ra_failed(module_idP, CC_id, prach_resources, frameP, slot); // prach_resources is a PHY structure
-            ra->ra_state = nrRA_UE_IDLE;
-            ra->RA_active = false;
+            // consider this Contention Resolution not successful and discard the successfully decoded MAC PDU
+            nr_ra_contention_resolution_failed(mac);
+            return;
           }
         }
         break;
@@ -3731,21 +3758,6 @@ void nr_ue_process_mac_pdu(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_i
   }
 }
 
-int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end)
-{
-  uint8_t *pdu = mac_ce;
-  if (IS_SA_MODE(get_softmodem_params()) && mac->ra.ra_state != nrRA_SUCCEEDED) {
-    LOG_D(NR_MAC, "Generating C-RNTI MAC CE with C-RNTI %x\n", crnti);
-    *(NR_MAC_SUBHEADER_FIXED *)mac_ce = (NR_MAC_SUBHEADER_FIXED){.R = 0, .LCID = UL_SCH_LCID_C_RNTI};
-    mac_ce += sizeof(NR_MAC_SUBHEADER_FIXED);
-    // C-RNTI MAC CE (2 octets)
-    memcpy(mac_ce, &crnti, sizeof(crnti));
-    // update pointer and length
-    mac_ce += sizeof(crnti);
-  }
-  return mac_ce - pdu;
-}
-
 /**
  * Function:      generating MAC CEs (MAC CE and subheader) for the ULSCH PDU
  * Parameters:
@@ -3848,6 +3860,117 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
   return mac_ce - pdu;
 }
 
+static void handle_rar_reception(NR_UE_MAC_INST_t *mac, NR_MAC_RAR *rar, frame_t frame, int slot)
+{
+  RAR_grant_t rar_grant;
+  RA_config_t *ra = &mac->ra;
+#ifdef DEBUG_RAR
+  // CSI
+  unsigned char csi_req = (unsigned char)(rar->UL_GRANT_4 & 0x01);
+#endif
+
+  // TPC
+  unsigned char tpc_command = (unsigned char)((rar->UL_GRANT_4 >> 1) & 0x07);
+  ra->Msg3_TPC = (tpc_command << 1) - 6;
+
+  // MCS
+  rar_grant.mcs = (unsigned char)(rar->UL_GRANT_4 >> 4);
+  // time alloc
+  rar_grant.Msg3_t_alloc = (unsigned char)(rar->UL_GRANT_3 & 0x0f);
+  // frequency alloc
+  rar_grant.Msg3_f_alloc = (uint16_t)((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12));
+  // frequency hopping
+  rar_grant.freq_hopping = (unsigned char)(rar->UL_GRANT_1 >> 2);
+
+  // Schedule Msg3
+  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
+  const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
+  const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id];
+  NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP,
+                                           *pdcch_config->ra_SS->controlResourceSetId,
+                                           pdcch_config->ra_SS->searchSpaceType->present,
+                                           TYPE_RA_RNTI_,
+                                           rar_grant.Msg3_t_alloc);
+  if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) {
+    LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n");
+    // resume RAR response window timer if MSG2 decoding failed
+    nr_timer_suspension(&mac->ra.response_window_timer);
+    return;
+  }
+  frame_t frame_tx = 0;
+  int slot_tx = 0;
+  const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs);
+  int ret = nr_ue_pusch_scheduler(mac, 1, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset);
+
+  // TA command
+  // if the timeAlignmentTimer associated with this TAG is not running
+  if (!nr_timer_is_active(&mac->time_alignment_timer)) {
+    const int ta = rar->TA2 + (rar->TA1 << 5);
+    set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx);
+    LOG_W(MAC, "received TA command %d\n", 31 + ta);
+  }
+  // else ignore the received Timing Advance Command
+
+#ifdef DEBUG_RAR
+  LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E);
+  LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T);
+  LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID);
+
+  LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R);
+  LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1);
+
+  LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2);
+  LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1);
+
+  LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2);
+  LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3);
+  LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4);
+
+  LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1);
+  LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2);
+
+  LOG_I(NR_MAC,
+        "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n",
+        frame,
+        slot,
+        mac->ue_id,
+        rar_grant.Msg3_t_alloc,
+        rar_grant.Msg3_f_alloc,
+        ta_command,
+        rar_grant.mcs,
+        rar_grant.freq_hopping,
+        tpc_command);
+#endif
+
+  if (ret != -1) {
+    uint16_t rnti = mac->crnti;
+    // Upon successful reception, set the T-CRNTI to the RAR value
+    // if the RA preamble is selected among the contention-based RA Preambles
+    if (!ra->cfra) {
+      ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8);
+      rnti = ra->t_crnti;
+      if (!mac->msg3_C_RNTI)
+        nr_mac_rrc_msg3_ind(mac->ue_id, rnti, false);
+    }
+    fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
+    if (!pdu)
+      return;
+    // Config Msg3 PDU
+    int ret = nr_config_pusch_pdu(mac,
+                                  &tda_info,
+                                  &pdu->pusch_config_pdu,
+                                  NULL,
+                                  NULL,
+                                  &rar_grant,
+                                  rnti,
+                                  NR_SearchSpace__searchSpaceType_PR_common,
+                                  NR_DCI_NONE);
+    if (ret != 0)
+      remove_ul_config_last_item(pdu);
+    release_ul_config(pdu, false);
+  }
+}
+
 /////////////////////////////////////
 //    Random Access Response PDU   //
 //         TS 38.213 ch 8.2        //
@@ -3892,13 +4015,10 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
   }
 
   RA_config_t *ra = &mac->ra;
+  ra->t_crnti = 0;
   uint8_t n_subPDUs  = 0;  // number of RAR payloads
   uint8_t n_subheaders = 0;  // number of MAC RAR subheaders
   uint8_t *dlsch_buffer = dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu;
-  uint8_t is_Msg3 = 1;
-  frame_t frame_tx = 0;
-  int slot_tx = 0;
-  int ret = 0;
   NR_RA_HEADER_RAPID *rarh = (NR_RA_HEADER_RAPID *) dlsch_buffer; // RAR subheader pointer
   NR_MAC_RAR *rar = (NR_MAC_RAR *) (dlsch_buffer + 1);   // RAR subPDU pointer
   uint8_t preamble_index = ra->ra_PreambleIndex;
@@ -3907,7 +4027,8 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
   T(T_NRUE_MAC_DL_RAR_PDU_WITH_DATA, T_INT(rnti), T_INT(frame), T_INT(slot),
     T_BUFFER(dlsch_buffer, dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.pdu_length));
 
-  LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] invoking MAC for received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index);
+  ra->RA_backoff_limit = 0;
+  LOG_D(NR_MAC, "[%d.%d]: [UE %d][RAPROC] MAC received RAR (current preamble %d)\n", frame, slot, mac->ue_id, preamble_index);
 
   while (1) {
     n_subheaders++;
@@ -3915,10 +4036,11 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
       n_subPDUs++;
       LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got RAPID RAR subPDU\n", mac->ue_id, rnti);
     } else {
-      ra->RA_backoff_indicator = get_backoff_indicator(((NR_RA_HEADER_BI *)rarh)->BI);
-      ra->RA_BI_found = 1;
-      LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, ra->RA_backoff_indicator, rnti);
-      if ( ((NR_RA_HEADER_BI *)rarh)->E == 1) {
+      int bi_ms = table_7_2_1[((NR_RA_HEADER_BI *)rarh)->BI] * ra->scaling_factor_bi;
+      int slots_per_ms = mac->frame_structure.numb_slots_frame / 10;
+      ra->RA_backoff_limit = bi_ms * slots_per_ms;
+      LOG_I(NR_MAC, "[UE %d][RAPROC][RA-RNTI %04x] Got BI RAR subPDU %d ms\n", mac->ue_id, rnti, bi_ms);
+      if (((NR_RA_HEADER_BI *)rarh)->E == 1) {
         rarh += sizeof(NR_RA_HEADER_BI);
         continue;
       } else {
@@ -3926,9 +4048,15 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
       }
     }
     if (rarh->RAPID == preamble_index) {
+      // The MAC entity may stop ra-ResponseWindow (and hence monitoring for Random Access Response(s)) after
+      // successful reception of a Random Access Response containing Random Access Preamble identifiers
+      // that matches the transmitted PREAMBLE_INDEX.
+      nr_timer_stop(&ra->response_window_timer);
       LOG_A(NR_MAC, "[UE %d][RAPROC][%d.%d] Found RAR with the intended RAPID %d\n", mac->ue_id, frame, slot, rarh->RAPID);
       rar = (NR_MAC_RAR *) (dlsch_buffer + n_subheaders + (n_subPDUs - 1) * sizeof(NR_MAC_RAR));
-      ra->RA_RAPID_found = 1;
+      handle_rar_reception(mac, rar, frame, slot);
+      if (ra->cfra)
+        nr_ra_succeeded(mac, dl_info->gNB_index, frame, slot);
       if (get_softmodem_params()->emulate_l1) {
         /* When we are emulating L1 with multiple UEs, the rx_indication will have
            multiple RAR PDUs. The code would previously handle each of these PDUs,
@@ -3953,6 +4081,8 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
             slot,
             rarh->RAPID,
             preamble_index);
+      // resume RAR response window timer if MSG2 decoding failed
+      nr_timer_suspension(&mac->ra.response_window_timer);
       break;
     } else {
       rarh += sizeof(NR_MAC_RAR) + 1;
@@ -3978,142 +4108,6 @@ static void nr_ue_process_rar(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *d
         rarh->RAPID,
         preamble_index);
 #endif
-
-  if (ra->RA_RAPID_found) {
-    RAR_grant_t rar_grant;
-
-#ifdef DEBUG_RAR
-    // CSI
-    unsigned char csi_req = (unsigned char) (rar->UL_GRANT_4 & 0x01);
-#endif
-
-    // TPC
-    unsigned char tpc_command = (unsigned char) ((rar->UL_GRANT_4 >> 1) & 0x07);
-    switch (tpc_command){
-      case 0:
-        ra->Msg3_TPC = -6;
-        break;
-      case 1:
-        ra->Msg3_TPC = -4;
-        break;
-      case 2:
-        ra->Msg3_TPC = -2;
-        break;
-      case 3:
-        ra->Msg3_TPC = 0;
-        break;
-      case 4:
-        ra->Msg3_TPC = 2;
-        break;
-      case 5:
-        ra->Msg3_TPC = 4;
-        break;
-      case 6:
-        ra->Msg3_TPC = 6;
-        break;
-      case 7:
-        ra->Msg3_TPC = 8;
-        break;
-      default:
-        LOG_E(NR_PHY, "RAR impossible msg3 TPC\n");
-    }
-    // MCS
-    rar_grant.mcs = (unsigned char) (rar->UL_GRANT_4 >> 4);
-    // time alloc
-    rar_grant.Msg3_t_alloc = (unsigned char) (rar->UL_GRANT_3 & 0x0f);
-    // frequency alloc
-    rar_grant.Msg3_f_alloc = (uint16_t) ((rar->UL_GRANT_3 >> 4) | (rar->UL_GRANT_2 << 4) | ((rar->UL_GRANT_1 & 0x03) << 12));
-    // frequency hopping
-    rar_grant.freq_hopping = (unsigned char) (rar->UL_GRANT_1 >> 2);
-
-    // Schedule Msg3
-    const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
-    const NR_UE_DL_BWP_t *current_DL_BWP = mac->current_DL_BWP;
-    const NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[current_DL_BWP->bwp_id];
-    NR_tda_info_t tda_info = get_ul_tda_info(current_UL_BWP,
-                                             *pdcch_config->ra_SS->controlResourceSetId,
-                                             pdcch_config->ra_SS->searchSpaceType->present,
-                                             TYPE_RA_RNTI_,
-                                             rar_grant.Msg3_t_alloc);
-    if (!tda_info.valid_tda || tda_info.nrOfSymbols == 0) {
-      LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n");
-      return;
-    }
-    const int ntn_ue_koffset = GET_NTN_UE_K_OFFSET(&mac->ntn_ta, mac->current_UL_BWP->scs);
-    ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2 + ntn_ue_koffset);
-
-    // TA command
-    // if the timeAlignmentTimer associated with this TAG is not running
-    if (!nr_timer_is_active(&mac->time_alignment_timer)) {
-      const int ta = rar->TA2 + (rar->TA1 << 5);
-      set_time_alignment(mac, ta, rar_ta, frame_tx, slot_tx);
-      LOG_W(MAC, "received TA command %d\n", 31 + ta);
-    }
-    // else ignore the received Timing Advance Command
-
-#ifdef DEBUG_RAR
-    LOG_I(NR_MAC, "rarh->E = 0x%x\n", rarh->E);
-    LOG_I(NR_MAC, "rarh->T = 0x%x\n", rarh->T);
-    LOG_I(NR_MAC, "rarh->RAPID = 0x%x (%i)\n", rarh->RAPID, rarh->RAPID);
-
-    LOG_I(NR_MAC, "rar->R = 0x%x\n", rar->R);
-    LOG_I(NR_MAC, "rar->TA1 = 0x%x\n", rar->TA1);
-
-    LOG_I(NR_MAC, "rar->TA2 = 0x%x\n", rar->TA2);
-    LOG_I(NR_MAC, "rar->UL_GRANT_1 = 0x%x\n", rar->UL_GRANT_1);
-
-    LOG_I(NR_MAC, "rar->UL_GRANT_2 = 0x%x\n", rar->UL_GRANT_2);
-    LOG_I(NR_MAC, "rar->UL_GRANT_3 = 0x%x\n", rar->UL_GRANT_3);
-    LOG_I(NR_MAC, "rar->UL_GRANT_4 = 0x%x\n", rar->UL_GRANT_4);
-
-    LOG_I(NR_MAC, "rar->TCRNTI_1 = 0x%x\n", rar->TCRNTI_1);
-    LOG_I(NR_MAC, "rar->TCRNTI_2 = 0x%x\n", rar->TCRNTI_2);
-
-    LOG_I(NR_MAC, "[%d.%d]: [UE %d] Received RAR with t_alloc %d f_alloc %d ta_command %d mcs %d freq_hopping %d tpc_command %d\n",
-          frame,
-          slot,
-          mac->ue_id,
-          rar_grant.Msg3_t_alloc,
-          rar_grant.Msg3_f_alloc,
-          ta_command,
-          rar_grant.mcs,
-          rar_grant.freq_hopping,
-          tpc_command);
-#endif
-
-    if (ret != -1) {
-      uint16_t rnti = mac->crnti;
-      // Upon successful reception, set the T-CRNTI to the RAR value if the RA preamble is selected among the contention-based RA Preambles
-      if (!ra->cfra) {
-        ra->t_crnti = rar->TCRNTI_2 + (rar->TCRNTI_1 << 8);
-        rnti = ra->t_crnti;
-        if (!ra->msg3_C_RNTI)
-          nr_mac_rrc_msg3_ind(mac->ue_id, rnti, dl_info->gNB_index);
-      }
-      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
-      if (!pdu)
-        return;
-      // Config Msg3 PDU
-      int ret = nr_config_pusch_pdu(mac,
-                                    &tda_info,
-                                    &pdu->pusch_config_pdu,
-                                    NULL,
-                                    NULL,
-                                    &rar_grant,
-                                    rnti,
-                                    NR_SearchSpace__searchSpaceType_PR_common,
-                                    NR_DCI_NONE);
-      if (ret != 0)
-        remove_ul_config_last_item(pdu);
-      release_ul_config(pdu, false);
-    }
-
-  } else {
-    ra->t_crnti = 0;
-    // TODO if the Random Access Preamble was not selected by the MAC entity
-    //      among the contention-based Random Access Preamble
-    //      apply the Timing Advance Command and start or restart the timeAlignmentTimer
-  }
   return;
 }
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
index 5300c9ed1f2d15c456aeb81f64107c1ca3a7623b..edd3bc1db72a56418fe9d3057ac3c86ab48997e4 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
@@ -182,17 +182,26 @@ void handle_time_alignment_timer_expired(NR_UE_MAC_INST_t *mac)
   // TODO not sure what to do here
 }
 
-void update_mac_timers(NR_UE_MAC_INST_t *mac)
+void update_mac_dl_timers(NR_UE_MAC_INST_t *mac)
+{
+  bool ra_window_expired = nr_timer_tick(&mac->ra.response_window_timer);
+  if (ra_window_expired) // consider the Random Access Response reception not successful
+    nr_rar_not_successful(mac);
+  bool alignment_timer_expired = nr_timer_tick(&mac->time_alignment_timer);
+  if (alignment_timer_expired)
+    handle_time_alignment_timer_expired(mac);
+}
+
+void update_mac_ul_timers(NR_UE_MAC_INST_t *mac)
 {
   if (mac->data_inactivity_timer) {
     bool inactivity_timer_expired = nr_timer_tick(mac->data_inactivity_timer);
     if (inactivity_timer_expired)
       nr_mac_rrc_inactivity_timer_ind(mac->ue_id);
   }
-  bool alignment_timer_expired = nr_timer_tick(&mac->time_alignment_timer);
-  if (alignment_timer_expired)
-    handle_time_alignment_timer_expired(mac);
-  nr_timer_tick(&mac->ra.contention_resolution_timer);
+  bool contention_resolution_expired = nr_timer_tick(&mac->ra.contention_resolution_timer);
+  if (contention_resolution_expired)
+    nr_ra_contention_resolution_failed(mac);
   for (int j = 0; j < NR_MAX_SR_ID; j++)
     nr_timer_tick(&mac->scheduling_info.sr_info[j].prohibitTimer);
   nr_timer_tick(&mac->scheduling_info.sr_DelayTimer);
@@ -236,6 +245,24 @@ void update_mac_timers(NR_UE_MAC_INST_t *mac)
       phr_info->phr_reporting |= (1 << phr_cause_periodic_timer);
     }
   }
+  bool ra_backoff_expired = nr_timer_tick(&mac->ra.RA_backoff_timer);
+  if (ra_backoff_expired) {
+    // perform the Random Access Resource selection procedure after the backoff time
+    mac->ra.ra_state = nrRA_GENERATE_PREAMBLE;
+    ra_resource_selection(mac);
+  } else {
+    if (nr_timer_is_active(&mac->ra.RA_backoff_timer)) {
+      // if the criteria (as defined in clause 5.1.2) to select contention-free Random Access Resources
+      // is met during the backoff time
+      // TODO verify what does this mean
+      if (mac->ra.cfra) {
+        // perform the Random Access Resource selection procedure
+        nr_timer_stop(&mac->ra.RA_backoff_timer);
+        mac->ra.ra_state = nrRA_GENERATE_PREAMBLE;
+        ra_resource_selection(mac);
+      }
+    }
+  }
 }
 
 void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu)
@@ -1144,7 +1171,7 @@ void schedule_RA_after_SR_failure(NR_UE_MAC_INST_t *mac)
 {
   if (get_softmodem_params()->phy_test)
     return; // cannot trigger RA in phytest mode
-  trigger_MAC_UE_RA(mac);
+  trigger_MAC_UE_RA(mac, NULL);
   // release PUCCH for all Serving Cells;
   // release SRS for all Serving Cells;
   release_PUCCH_SRS(mac);
@@ -1206,7 +1233,9 @@ static void nr_update_sr(NR_UE_MAC_INST_t *mac, bool BSRsent)
 
   NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
   NR_PUCCH_Config_t *pucch_Config = current_UL_BWP ? current_UL_BWP->pucch_Config : NULL;
-  if (!pucch_Config || !pucch_Config->schedulingRequestResourceToAddModList)
+  if (!pucch_Config
+      || !pucch_Config->schedulingRequestResourceToAddModList
+      || pucch_Config->schedulingRequestResourceToAddModList->list.count == 0)
     return; // cannot schedule SR if there is no schedulingRequestResource configured
 
   if (lc_info->sr_id < 0 || lc_info->sr_id >= NR_MAX_SR_ID)
@@ -1304,11 +1333,16 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
   uint32_t gNB_index = ul_info->gNB_index;
 
   RA_config_t *ra = &mac->ra;
-  if (mac->state == UE_PERFORMING_RA) {
-    nr_ue_get_rach(mac, cc_id, frame_tx, gNB_index, slot_tx);
-    nr_ue_prach_scheduler(mac, frame_tx, slot_tx);
+
+  if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_UE_IDLE) {
+    init_RA(mac, frame_tx);
+    // perform the Random Access Resource selection procedure (see clause 5.1.2 and .2a)
+    ra_resource_selection(mac);
   }
 
+  if (mac->state == UE_PERFORMING_RA && ra->ra_state == nrRA_GENERATE_PREAMBLE)
+    nr_ue_prach_scheduler(mac, frame_tx, slot_tx);
+
   bool BSRsent = false;
   if (mac->state == UE_CONNECTED) {
     nr_ue_periodic_srs_scheduling(mac, frame_tx, slot_tx);
@@ -1352,7 +1386,7 @@ void nr_ue_ul_scheduler(NR_UE_MAC_INST_t *mac, nr_uplink_indication_t *ul_info)
             && (mac->state == UE_CONNECTED || (ra->ra_state == nrRA_WAIT_RAR && ra->cfra))) {
           if (!nr_timer_is_active(&mac->time_alignment_timer) && mac->state == UE_CONNECTED && !get_softmodem_params()->phy_test) {
             // UL data arrival during RRC_CONNECTED when UL synchronisation status is "non-synchronised"
-            trigger_MAC_UE_RA(mac);
+            trigger_MAC_UE_RA(mac, NULL);
             return;
           }
           // Getting IP traffic to be transmitted
@@ -1561,547 +1595,6 @@ int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
   return 0;
 }
 
-// Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
-static void build_ro_list(NR_UE_MAC_INST_t *mac)
-{
-  int x,y; // PRACH Configuration Index table variables used to compute the valid frame numbers
-  int y2;  // PRACH Configuration Index table additional variable used to compute the valid frame numbers
-  uint8_t slot_shift_for_map;
-  uint8_t map_shift;
-  bool even_slot_invalid;
-  int64_t s_map;
-  uint8_t prach_conf_start_symbol; // Starting symbol of the PRACH occasions in the PRACH slot
-  uint8_t N_t_slot; // Number of PRACH occasions in a 14-symbols PRACH slot
-  uint8_t N_dur; // Duration of a PRACH occasion (nb of symbols)
-  uint16_t format = 0xffff;
-  uint8_t format2 = 0xff;
-  int nb_fdm;
-
-  uint8_t config_index;
-  int msg1_FDM;
-
-  uint8_t nb_of_frames_per_prach_conf_period;
-
-  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
-
-  config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
-  msg1_FDM = rach_ConfigGeneric->msg1_FDM;
-
-  switch (msg1_FDM){
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-      nb_fdm = 1 << msg1_FDM;
-      break;
-    default:
-      AssertFatal(1 == 0, "Unknown msg1_FDM from rach_ConfigGeneric %d\n", msg1_FDM);
-  }
-
-  // Create the PRACH occasions map
-  // WIP: For now assume no rejected PRACH occasions because of conflict with SSB or TDD_UL_DL_ConfigurationCommon schedule
-
-  int unpaired = mac->phy_config.config_req.cell_config.frame_duplex_type;
-
-  const int64_t *prach_config_info_p = get_prach_config_info(mac->frequency_range, config_index, unpaired);
-  const int ul_mu = mac->current_UL_BWP->scs;
-  const int mu = nr_get_prach_or_ul_mu(mac->current_UL_BWP->msgA_ConfigCommon_r16, setup, ul_mu);
-
-  // Identify the proper PRACH Configuration Index table according to the operating frequency
-  LOG_D(NR_MAC,"mu = %u, PRACH config index  = %u, unpaired = %u\n", mu, config_index, unpaired);
-
-  if (mac->frequency_range == FR2) { //FR2
-
-    x = prach_config_info_p[2];
-    y = prach_config_info_p[3];
-    y2 = prach_config_info_p[4];
-
-    s_map = prach_config_info_p[5];
-
-    prach_conf_start_symbol = prach_config_info_p[6];
-    N_t_slot = prach_config_info_p[8];
-    N_dur = prach_config_info_p[9];
-    if (prach_config_info_p[1] != -1)
-      format2 = (uint8_t) prach_config_info_p[1];
-    format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);
-
-    slot_shift_for_map = mu-2;
-    if ( (mu == 3) && (prach_config_info_p[7] == 1) )
-      even_slot_invalid = true;
-    else
-      even_slot_invalid = false;
-  }
-  else { // FR1
-    x = prach_config_info_p[2];
-    y = prach_config_info_p[3];
-    y2 = y;
-
-    s_map = prach_config_info_p[4];
-
-    prach_conf_start_symbol = prach_config_info_p[5];
-    N_t_slot = prach_config_info_p[7];
-    N_dur = prach_config_info_p[8];
-    LOG_D(NR_MAC,"N_t_slot %d, N_dur %d\n",N_t_slot,N_dur);
-    if (prach_config_info_p[1] != -1)
-      format2 = (uint8_t) prach_config_info_p[1];
-    format = ((uint8_t) prach_config_info_p[0]) | (format2<<8);
-
-    slot_shift_for_map = mu;
-    if ( (mu == 1) && (prach_config_info_p[6] == 1) && ((format & 0xff) > 3) )
-      // no prach in even slots @ 30kHz for 1 prach per subframe
-      even_slot_invalid = true;
-    else
-      even_slot_invalid = false;
-  } // FR2 / FR1
-
-  const int bwp_id = mac->current_UL_BWP->bwp_id;
-  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
-  prach_assoc_pattern->nb_of_prach_conf_period_in_max_period = MAX_NB_PRACH_CONF_PERIOD_IN_ASSOCIATION_PATTERN_PERIOD / x;
-  nb_of_frames_per_prach_conf_period = x;
-  int slots_per_frame = mac->frame_structure.numb_slots_frame;
-  LOG_D(NR_MAC,"nb_of_prach_conf_period_in_max_period %d\n", prach_assoc_pattern->nb_of_prach_conf_period_in_max_period);
-
-  // Fill in the PRACH occasions table for every slot in every frame in every PRACH configuration periods in the maximum association pattern period
-  // ----------------------------------------------------------------------------------------------------------------------------------------------
-  // ----------------------------------------------------------------------------------------------------------------------------------------------
-  // For every PRACH configuration periods
-  // -------------------------------------
-  for (int period_idx = 0; period_idx < prach_assoc_pattern->nb_of_prach_conf_period_in_max_period; period_idx++) {
-    prach_conf_period_t *prach_conf_period_list = &prach_assoc_pattern->prach_conf_period_list[period_idx];
-    prach_conf_period_list->nb_of_prach_occasion = 0;
-    prach_conf_period_list->nb_of_frame = nb_of_frames_per_prach_conf_period;
-    prach_conf_period_list->nb_of_slot = slots_per_frame;
-
-    LOG_D(NR_MAC,"PRACH Conf Period Idx %d\n", period_idx);
-
-    // For every frames in a PRACH configuration period
-    // ------------------------------------------------
-    for (int frame_idx = 0; frame_idx < nb_of_frames_per_prach_conf_period; frame_idx++) {
-      int frame_rach = (period_idx * nb_of_frames_per_prach_conf_period) + frame_idx;
-
-      LOG_D(NR_MAC,"PRACH Conf Period Frame Idx %d - Frame %d\n", frame_idx, frame_rach);
-      // Is it a valid frame for this PRACH configuration index? (n_sfn mod x = y)
-      if ((frame_rach % x) == y || (frame_rach % x) == y2) {
-
-        // For every slot in a frame
-        // -------------------------
-        for (int slot = 0; slot < slots_per_frame; slot++) {
-          // Is it a valid slot?
-          map_shift = slot >> slot_shift_for_map; // in PRACH configuration index table slots are numbered wrt 60kHz
-          if ((s_map>>map_shift) & 0x01) {
-            // Valid slot
-
-            // Additionally, for 30kHz/120kHz, we must check for the n_RA_Slot param also
-            if (even_slot_invalid && (slot%2 == 0))
-              continue; // no prach in even slots @ 30kHz/120kHz for 1 prach per 60khz slot/subframe
-
-            // We're good: valid frame and valid slot
-            // Compute all the PRACH occasions in the slot
-
-            prach_occasion_slot_t *slot_map = &prach_conf_period_list->prach_occasion_slot_map[frame_idx][slot];
-            slot_map->nb_of_prach_occasion_in_time = N_t_slot;
-            slot_map->nb_of_prach_occasion_in_freq = nb_fdm;
-            slot_map->prach_occasion = malloc(N_t_slot * nb_fdm * sizeof(*slot_map->prach_occasion));
-            AssertFatal(slot_map->prach_occasion, "no memory available\n");
-            for (int n_prach_occ_in_time = 0; n_prach_occ_in_time < N_t_slot; n_prach_occ_in_time++) {
-              uint8_t start_symbol = prach_conf_start_symbol + n_prach_occ_in_time * N_dur;
-              LOG_D(NR_MAC,"PRACH Occ in time %d\n", n_prach_occ_in_time);
-
-              for (int n_prach_occ_in_freq = 0; n_prach_occ_in_freq < nb_fdm; n_prach_occ_in_freq++) {
-                slot_map->prach_occasion[n_prach_occ_in_time * nb_fdm + n_prach_occ_in_freq] =
-                    (prach_occasion_info_t){.start_symbol = start_symbol,
-                                            .fdm = n_prach_occ_in_freq,
-                                            .frame = frame_idx,
-                                            .slot = slot,
-                                            .format = format};
-                prach_assoc_pattern->prach_conf_period_list[period_idx].nb_of_prach_occasion++;
-
-                LOG_D(NR_MAC,
-                      "Adding a PRACH occasion: frame %u, slot-symbol %d-%d, occ_in_time-occ_in-freq %d-%d, nb ROs in conf period %d, for this slot: RO# in time %d, RO# in freq %d\n",
-                      frame_rach,
-                      slot,
-                      start_symbol,
-                      n_prach_occ_in_time,
-                      n_prach_occ_in_freq,
-                      prach_conf_period_list->nb_of_prach_occasion,
-                      slot_map->nb_of_prach_occasion_in_time,
-                      slot_map->nb_of_prach_occasion_in_freq);
-              } // For every freq in the slot
-            } // For every time occasions in the slot
-          } // Valid slot?
-        } // For every slots in a frame
-      } // Valid frame?
-    } // For every frames in a prach configuration period
-  } // For every prach configuration periods in the maximum association pattern period (160ms)
-}
-
-// Build the list of all the valid/transmitted SSBs according to the config
-static void build_ssb_list(NR_UE_MAC_INST_t *mac)
-{
-  // Create the list of transmitted SSBs
-  const int bwp_id = mac->current_UL_BWP->bwp_id;
-  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
-  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
-  ssb_list->nb_tx_ssb = 0;
-
-  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
-    uint32_t curr_mask = cfg->ssb_table.ssb_mask_list[ssb_index / 32].ssb_mask;
-    // check if if current SSB is transmitted
-    if ((curr_mask >> (31 - (ssb_index % 32))) & 0x01) {
-      ssb_list->nb_ssb_per_index[ssb_index] = ssb_list->nb_tx_ssb;
-      ssb_list->nb_tx_ssb++;
-    }
-    else
-      ssb_list->nb_ssb_per_index[ssb_index] = -1;
-  }
-  ssb_list->tx_ssb = calloc(ssb_list->nb_tx_ssb, sizeof(*ssb_list->tx_ssb));
-}
-
-static int get_ssb_idx_from_list(ssb_list_info_t *ssb_list, int idx)
-{
-  for (int ssb_index = 0; ssb_index < MAX_NB_SSB; ssb_index++) {
-    if (ssb_list->nb_ssb_per_index[ssb_index] == idx)
-      return ssb_index;
-  }
-  AssertFatal(false, "Couldn't find SSB index in SSB list\n");
-  return 0;
-}
-
-// Map the transmitted SSBs to the ROs and create the association pattern according to the config
-static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
-{
-  // Map SSBs to PRACH occasions
-  // WIP: Assumption: No PRACH occasion is rejected because of a conflict with SSBs or TDD_UL_DL_ConfigurationCommon schedule
-  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-  NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR ssb_perRACH_config = setup->ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present;
-
-  const struct {
-    // true if more than one or exactly one SSB per RACH occasion, false if more than one RO per SSB
-    bool multiple_ssb_per_ro;
-    // Nb of SSBs per RACH or RACHs per SSB
-    int ssb_rach_ratio;
-  } config[] = {{false, 0}, {false, 8}, {false, 4}, {false, 2}, {true, 1}, {true, 2}, {true, 4}, {true, 8}, {true, 16}};
-  AssertFatal(ssb_perRACH_config <= NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_sixteen,
-              "Unsupported ssb_perRACH_config %d\n",
-              ssb_perRACH_config);
-  const bool multiple_ssb_per_ro = config[ssb_perRACH_config].multiple_ssb_per_ro;
-  const int ssb_rach_ratio = config[ssb_perRACH_config].ssb_rach_ratio;
-
-  LOG_D(NR_MAC,"SSB rach ratio %d, Multiple SSB per RO %d\n", ssb_rach_ratio, multiple_ssb_per_ro);
-
-  const int bwp_id = mac->current_UL_BWP->bwp_id;
-  ssb_list_info_t *ssb_list = &mac->ssb_list[bwp_id];
-
-  // Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period
-  // WIP: Assumption for now is that all the PRACH configuration periods within a maximum association pattern period have the same
-  // number of PRACH occasions
-  //      (No PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule)
-  //      There is only one possible association period which can contain up to 16 PRACH configuration periods
-  LOG_D(NR_MAC,"Evaluate the number of PRACH configuration periods required to map all the SSBs and set the association period\n");
-  const int required_nb_of_prach_occasion =
-      multiple_ssb_per_ro ? ((ssb_list->nb_tx_ssb - 1) + ssb_rach_ratio) / ssb_rach_ratio : ssb_list->nb_tx_ssb * ssb_rach_ratio;
-
-  prach_association_pattern_t *prach_assoc_pattern = &mac->prach_assoc_pattern[bwp_id];
-  const prach_conf_period_t *prach_conf_period = &prach_assoc_pattern->prach_conf_period_list[0];
-  AssertFatal(prach_conf_period->nb_of_prach_occasion > 0,
-              "prach_conf_period->nb_of_prach_occasion shouldn't be 0 (nb_tx_ssb %d, ssb_rach_ratio %d)\n",
-              ssb_list->nb_tx_ssb,
-              ssb_rach_ratio);
-  prach_association_period_t *prach_association_period = &prach_assoc_pattern->prach_association_period_list[0];
-  const int required_nb_of_prach_conf_period =
-      ((required_nb_of_prach_occasion - 1) + prach_conf_period->nb_of_prach_occasion) / prach_conf_period->nb_of_prach_occasion;
-
-  if (required_nb_of_prach_conf_period == 1) {
-    prach_association_period->nb_of_prach_conf_period = 1;
-  }
-  else if (required_nb_of_prach_conf_period == 2) {
-    prach_association_period->nb_of_prach_conf_period = 2;
-  }
-  else if (required_nb_of_prach_conf_period <= 4) {
-    prach_association_period->nb_of_prach_conf_period = 4;
-  }
-  else if (required_nb_of_prach_conf_period <= 8) {
-    prach_association_period->nb_of_prach_conf_period = 8;
-  }
-  else if (required_nb_of_prach_conf_period <= 16) {
-    prach_association_period->nb_of_prach_conf_period = 16;
-  }
-  else {
-    AssertFatal(1 == 0, "Invalid number of PRACH config periods within an association period %d\n", required_nb_of_prach_conf_period);
-  }
-
-  prach_assoc_pattern->nb_of_assoc_period = 1; // WIP: only one possible association period
-  prach_association_period->nb_of_frame = prach_association_period->nb_of_prach_conf_period * prach_conf_period->nb_of_frame;
-  prach_assoc_pattern->nb_of_frame = prach_association_period->nb_of_frame;
-
-  LOG_D(NR_MAC,
-        "Assoc period %d, Nb of frames in assoc period %d\n",
-        prach_association_period->nb_of_prach_conf_period,
-        prach_association_period->nb_of_frame);
-
-  // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
-  int prach_configuration_period_idx =
-      0; // WIP: only one possible association period so the starting PRACH configuration period is automatically 0
-
-  // Map all the association periods within the association pattern period
-  LOG_D(NR_MAC,"Proceed to the SSB to RO mapping\n");
-  // Check if we need to map multiple SSBs per RO or multiple ROs per SSB
-
-  if (multiple_ssb_per_ro) {
-    const prach_association_period_t *end =
-        prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period;
-    for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end;
-         prach_period++) {
-      // Set the starting PRACH Configuration period index in the association_pattern map for this particular association period
-      // WIP: only one possible association period so the starting PRACH configuration period is automatically 0
-      // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
-      //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
-      int idx = 0;
-      bool done = false;
-      for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) {
-        prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx];
-        prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i];
-        // Build the association period with its association PRACH Configuration indexes
-        // Go through all the ROs within the PRACH config period
-        for (int frame = 0; frame < prach_conf->nb_of_frame && !done; frame++) {
-          for (int slot = 0; slot < prach_conf->nb_of_slot && !done; slot++) {
-            prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot];
-            for (int ro_in_time = 0; ro_in_time < slot_map->nb_of_prach_occasion_in_time && !done; ro_in_time++) {
-              for (int ro_in_freq = 0; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq && !done; ro_in_freq++) {
-                prach_occasion_info_t *ro_p =
-                    slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
-                // Go through the list of transmitted SSBs and map the required amount of SSBs to this RO
-                // WIP: For the moment, only map each SSB idx once per association period if configuration is multiple SSBs per RO
-                //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
-                for (; idx < ssb_list->nb_tx_ssb; idx++) {
-                  ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
-                  // Map only the transmitted ssb_idx
-                  int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
-                  ro_p->mapped_ssb_idx[ro_p->nb_mapped_ssb] = ssb_idx;
-                  ro_p->nb_mapped_ssb++;
-                  AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
-                              "Too many mapped ROs (%d) to a single SSB\n",
-                              tx_ssb->nb_mapped_ro);
-                  tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p;
-                  tx_ssb->nb_mapped_ro++;
-                  LOG_D(NR_MAC,
-                        "Mapped ssb_idx %u to RO slot-symbol %u-%u, %u-%u-%u/%u\n"
-                        "Nb mapped ROs for this ssb idx: in the association period only %u\n",
-                        ssb_idx,
-                        ro_p->slot,
-                        ro_p->start_symbol,
-                        slot,
-                        ro_in_time,
-                        ro_in_freq,
-                        slot_map->nb_of_prach_occasion_in_freq,
-                        tx_ssb->nb_mapped_ro);
-                  // If all the required SSBs are mapped to this RO, exit the loop of SSBs
-                  if (ro_p->nb_mapped_ssb == ssb_rach_ratio) {
-                    idx++;
-                    break;
-                  }
-                }
-                done = MAX_NB_SSB == idx;
-              }
-            }
-          }
-        }
-      }
-    }
-  } else {
-    int frame = 0;
-    int slot = 0;
-    int ro_in_time = 0;
-    int ro_in_freq = 0;
-    prach_association_period_t *end = prach_assoc_pattern->prach_association_period_list + prach_assoc_pattern->nb_of_assoc_period;
-    for (prach_association_period_t *prach_period = prach_assoc_pattern->prach_association_period_list; prach_period < end;
-         prach_period++) {
-      // Go through the list of transmitted SSBs
-      for (int idx = 0; idx < ssb_list->nb_tx_ssb; idx++) {
-        ssb_info_t *tx_ssb = ssb_list->tx_ssb + idx;
-        uint8_t nb_mapped_ro_in_association_period = 0; // Reset the nb of mapped ROs for the new SSB index
-        bool done = false;
-        // Map all the required ROs to this SSB
-        // Go through the list of PRACH config periods within this association period
-        for (int i = 0; i < prach_period->nb_of_prach_conf_period && !done; i++, prach_configuration_period_idx++) {
-          // Build the association period with its association PRACH Configuration indexes
-          prach_period->prach_conf_period_list[i] = &prach_assoc_pattern->prach_conf_period_list[prach_configuration_period_idx];
-	  prach_conf_period_t *prach_conf = prach_period->prach_conf_period_list[i];
-          for (; frame < prach_conf->nb_of_frame; frame++) {
-            for (; slot < prach_conf->nb_of_slot; slot++) {
-              prach_occasion_slot_t *slot_map = &prach_conf->prach_occasion_slot_map[frame][slot];
-              for (; ro_in_time < slot_map->nb_of_prach_occasion_in_time; ro_in_time++) {
-                for (; ro_in_freq < slot_map->nb_of_prach_occasion_in_freq; ro_in_freq++) {
-                  prach_occasion_info_t *ro_p =
-                      slot_map->prach_occasion + ro_in_time * slot_map->nb_of_prach_occasion_in_freq + ro_in_freq;
-                  int ssb_idx = get_ssb_idx_from_list(ssb_list, idx);
-                  ro_p->mapped_ssb_idx[0] = ssb_idx;
-                  ro_p->nb_mapped_ssb = 1;
-                  AssertFatal(MAX_NB_RO_PER_SSB_IN_ASSOCIATION_PATTERN > tx_ssb->nb_mapped_ro + 1,
-                              "Too many mapped ROs (%d) to a single SSB\n",
-                              tx_ssb->nb_mapped_ro);
-                  tx_ssb->mapped_ro[tx_ssb->nb_mapped_ro] = ro_p;
-                  tx_ssb->nb_mapped_ro++;
-                  nb_mapped_ro_in_association_period++;
-
-                  LOG_D(NR_MAC,
-                        "Mapped ssb_idx %u to RO slot-symbol %u-%u-%u, %u-%u-%u-%u/%u\n"
-                        "Nb mapped ROs for this ssb idx: in the association period only %u / total %u\n",
-                        ssb_idx,
-                        ro_p->frame,
-                        ro_p->slot,
-                        ro_p->start_symbol,
-                        frame,
-                        slot,
-                        ro_in_time,
-                        ro_in_freq,
-                        slot_map->nb_of_prach_occasion_in_freq,
-                        tx_ssb->nb_mapped_ro,
-                        nb_mapped_ro_in_association_period);
-
-                  // Exit the loop if this SSB has been mapped to all the required ROs
-                  // WIP: Assuming that ssb_rach_ratio equals the maximum nb of times a given ssb_idx is mapped within an
-                  // association period:
-                  //      this is true if no PRACH occasions are conflicting with SSBs nor TDD_UL_DL_ConfigurationCommon schedule
-                  if (nb_mapped_ro_in_association_period == ssb_rach_ratio) {
-                    ro_in_freq++;
-                    break;
-                  }
-                }
-                if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
-                  break;
-                else
-                  ro_in_freq = 0;
-              }
-              if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
-                break;
-              else
-                ro_in_time = 0;
-            }
-            if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
-              break;
-            else
-              slot = 0;
-          }
-          if (nb_mapped_ro_in_association_period == ssb_rach_ratio)
-            break;
-          else
-            frame = 0;
-        }
-      }
-    }
-  }
-}
-
-// Returns a RACH occasion if any matches the SSB idx, the frame and the slot
-static int get_nr_prach_info_from_ssb_index(prach_association_pattern_t *prach_assoc_pattern,
-                                            int ssb_idx,
-                                            int frame,
-                                            int slot,
-                                            ssb_list_info_t *ssb_list,
-                                            prach_occasion_info_t **prach_occasion_info_pp)
-{
-  prach_occasion_slot_t *prach_occasion_slot_p = NULL;
-
-  *prach_occasion_info_pp = NULL;
-
-  // Search for a matching RO slot in the SSB_to_RO map
-  // A valid RO slot will match:
-  //      - ssb_idx mapped to one of the ROs in that RO slot
-  //      - exact slot number
-  //      - frame offset
-  int idx_list = ssb_list->nb_ssb_per_index[ssb_idx];
-  ssb_info_t *ssb_info_p = &ssb_list->tx_ssb[idx_list];
-  LOG_D(NR_MAC, "checking for prach : ssb_info_p->nb_mapped_ro %d\n", ssb_info_p->nb_mapped_ro);
-  for (int n_mapped_ro = 0; n_mapped_ro < ssb_info_p->nb_mapped_ro; n_mapped_ro++) {
-    LOG_D(NR_MAC,
-          "%d.%d: mapped_ro[%d]->frame.slot %d.%d, prach_assoc_pattern->nb_of_frame %d\n",
-          frame,
-          slot,
-          n_mapped_ro,
-          ssb_info_p->mapped_ro[n_mapped_ro]->frame,
-          ssb_info_p->mapped_ro[n_mapped_ro]->slot,
-          prach_assoc_pattern->nb_of_frame);
-    if ((slot == ssb_info_p->mapped_ro[n_mapped_ro]->slot) && prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame != 0 &&
-        (ssb_info_p->mapped_ro[n_mapped_ro]->frame == (frame % prach_assoc_pattern->nb_of_frame))) {
-      uint8_t prach_config_period_nb = ssb_info_p->mapped_ro[n_mapped_ro]->frame / prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
-      uint8_t frame_nb_in_prach_config_period = ssb_info_p->mapped_ro[n_mapped_ro]->frame % prach_assoc_pattern->prach_conf_period_list[0].nb_of_frame;
-      prach_occasion_slot_p = &prach_assoc_pattern->prach_conf_period_list[prach_config_period_nb].prach_occasion_slot_map[frame_nb_in_prach_config_period][slot];
-    }
-  }
-
-  // If there is a matching RO slot in the SSB_to_RO map
-  if (NULL != prach_occasion_slot_p) {
-    // A random RO mapped to the SSB index should be selected in the slot
-
-    // First count the number of times the SSB index is found in that RO
-    uint8_t nb_mapped_ssb = 0;
-
-    for (int ro_in_time = 0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
-      for (int ro_in_freq = 0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
-        prach_occasion_info_t *ro_p =
-            prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq;
-        for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) {
-          if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
-            nb_mapped_ssb++;
-          }
-        }
-      }
-    }
-
-    // Choose a random SSB nb
-    uint8_t random_ssb_nb = 0;
-
-    random_ssb_nb = ((taus()) % nb_mapped_ssb);
-
-    // Select the RO according to the chosen random SSB nb
-    nb_mapped_ssb=0;
-    for (int ro_in_time=0; ro_in_time < prach_occasion_slot_p->nb_of_prach_occasion_in_time; ro_in_time++) {
-      for (int ro_in_freq=0; ro_in_freq < prach_occasion_slot_p->nb_of_prach_occasion_in_freq; ro_in_freq++) {
-        prach_occasion_info_t *ro_p =
-            prach_occasion_slot_p->prach_occasion + ro_in_time * prach_occasion_slot_p->nb_of_prach_occasion_in_freq + ro_in_freq;
-        for (uint8_t ssb_nb = 0; ssb_nb < ro_p->nb_mapped_ssb; ssb_nb++) {
-          if (ro_p->mapped_ssb_idx[ssb_nb] == ssb_idx) {
-            if (nb_mapped_ssb == random_ssb_nb) {
-              *prach_occasion_info_pp = ro_p;
-              return 1;
-            }
-            else {
-              nb_mapped_ssb++;
-            }
-          }
-        }
-      }
-    }
-  }
-
-  return 0;
-}
-
-// Build the SSB to RO mapping upon RRC configuration update
-void build_ssb_to_ro_map(NR_UE_MAC_INST_t *mac)
-{
-  // Clear all the lists and maps
-  const int bwp_id = mac->current_UL_BWP->bwp_id;
-  free_rach_structures(mac, bwp_id);
-  memset(&mac->ssb_list[bwp_id], 0, sizeof(ssb_list_info_t));
-  memset(&mac->prach_assoc_pattern[bwp_id], 0, sizeof(prach_association_pattern_t));
-
-  // Build the list of all the valid RACH occasions in the maximum association pattern period according to the PRACH config
-  LOG_D(NR_MAC,"Build RO list\n");
-  build_ro_list(mac);
-
-  // Build the list of all the valid/transmitted SSBs according to the config
-  LOG_D(NR_MAC,"Build SSB list\n");
-  build_ssb_list(mac);
-
-  // Map the transmitted SSBs to the ROs and create the association pattern according to the config
-  LOG_D(NR_MAC,"Map SSB to RO\n");
-  map_ssb_to_ro(mac);
-  LOG_D(NR_MAC,"Map SSB to RO done\n");
-}
-
 static bool schedule_uci_on_pusch(NR_UE_MAC_INST_t *mac,
                                   frame_t frame_tx,
                                   int slot_tx,
@@ -2581,6 +2074,23 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
   }
 }
 
+static bool is_prach_frame(frame_t frame, prach_occasion_info_t *prach_occasion_info, int association_periods)
+{
+  int config_period = prach_occasion_info->frame_info[0];
+  int frame_period = config_period * association_periods;
+  int frame_in_period = frame % frame_period;
+  if (association_periods > 1) {
+    int current_assoc_period = frame_in_period / config_period;
+    if (current_assoc_period != prach_occasion_info->association_period_idx)
+      return false;
+    frame_in_period %= config_period;
+  }
+  if (frame_in_period == prach_occasion_info->frame_info[1]) // SFN % x == y (see Tables in Table 6.3.3.2 of 38.211)
+    return true;
+  else
+    return false;
+}
+
 // This function schedules the PRACH according to prach_ConfigurationIndex and TS 38.211, tables 6.3.3.2.x
 // PRACH formats 9, 10, 11 are corresponding to dual PRACH format configurations A1/B1, A2/B2, A3/B3.
 // - todo:
@@ -2588,56 +2098,33 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
 static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t slotP)
 {
   RA_config_t *ra = &mac->ra;
-  ra->RA_offset = 2; // to compensate the rx frame offset at the gNB
-  if (ra->ra_state != nrRA_GENERATE_PREAMBLE)
-    return;
 
-  fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
-  fapi_nr_prach_config_t *prach_config = &cfg->prach_config;
+  // Get any valid PRACH occasion in the current slot for the selected SSB index
+  prach_occasion_info_t *prach_occasion_info = &ra->sched_ro_info;
 
-  NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
-  NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
-  const int bwp_id = mac->current_UL_BWP->bwp_id;
+  if (!is_prach_frame(frameP, prach_occasion_info, ra->association_periods))
+    return;
 
   if (is_ul_slot(slotP, &mac->frame_structure)) {
-    // WIP Need to get the proper selected ssb_idx
-    //     Initial beam selection functionality is not available yet
-    uint8_t selected_gnb_ssb_idx = mac->mib_ssb;
-
-    // Get any valid PRACH occasion in the current slot for the selected SSB index
-    prach_occasion_info_t *prach_occasion_info_p;
-    int is_nr_prach_slot = get_nr_prach_info_from_ssb_index(&mac->prach_assoc_pattern[bwp_id],
-                                                            selected_gnb_ssb_idx,
-                                                            (int)frameP,
-                                                            (int)slotP,
-                                                            &mac->ssb_list[bwp_id],
-                                                            &prach_occasion_info_p);
-
-    if (is_nr_prach_slot) {
-      AssertFatal(NULL != prach_occasion_info_p,"PRACH Occasion Info not returned in a valid NR Prach Slot\n");
-
-      nr_get_RA_window(mac);
-
-      uint16_t format = prach_occasion_info_p->format;
-      uint16_t format0 = format & 0xff;        // single PRACH format
-      uint16_t format1 = (format >> 8) & 0xff; // dual PRACH format
-
+    if (slotP == prach_occasion_info->slot) {
       fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH);
       if (!pdu) {
         LOG_E(NR_MAC, "Error in PRACH allocation\n");
         return;
       }
-      uint16_t ncs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig, format0, setup->restrictedSetConfig);
+
+      int format = prach_occasion_info->format;
+      fapi_nr_prach_config_t *prach_config = &mac->phy_config.config_req.prach_config;
       pdu->prach_config_pdu = (fapi_nr_ul_config_prach_pdu){
           .phys_cell_id = mac->physCellId,
           .num_prach_ocas = 1,
-          .prach_slot = prach_occasion_info_p->slot,
-          .prach_start_symbol = prach_occasion_info_p->start_symbol,
-          .num_ra = prach_occasion_info_p->fdm,
-          .num_cs = ncs,
-          .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index,
+          .prach_slot = prach_occasion_info->slot,
+          .prach_start_symbol = prach_occasion_info->start_symbol,
+          .num_ra = prach_occasion_info->fdm,
+          .num_cs = get_NCS(ra->zeroCorrelationZoneConfig, format, ra->restricted_set_config),
+          .root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].prach_root_sequence_index,
           .restricted_set = prach_config->restricted_set_config,
-          .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1};
+          .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info->fdm].k1};
 
       LOG_I(NR_MAC,
             "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n",
@@ -2646,82 +2133,46 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
             pdu->prach_config_pdu.prach_start_symbol,
             pdu->prach_config_pdu.num_ra);
 
-      // Search which SSB is mapped in the RO (among all the SSBs mapped to this RO)
-      for (int ssb_nb_in_ro=0; ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb; ssb_nb_in_ro++) {
-        if (prach_occasion_info_p->mapped_ssb_idx[ssb_nb_in_ro] == selected_gnb_ssb_idx) {
-          ra->ssb_nb_in_ro = ssb_nb_in_ro;
+      switch (format) { // single PRACH format
+        case 0:
+          pdu->prach_config_pdu.prach_format = 0;
           break;
-        }
+        case 1:
+          pdu->prach_config_pdu.prach_format = 1;
+          break;
+        case 2:
+          pdu->prach_config_pdu.prach_format = 2;
+          break;
+        case 3:
+          pdu->prach_config_pdu.prach_format = 3;
+          break;
+        case 0xa1:
+          pdu->prach_config_pdu.prach_format = 4;
+          break;
+        case 0xa2:
+          pdu->prach_config_pdu.prach_format = 5;
+          break;
+        case 0xa3:
+          pdu->prach_config_pdu.prach_format = 6;
+          break;
+        case 0xb1:
+          pdu->prach_config_pdu.prach_format = 7;
+          break;
+        case 0xb4:
+          pdu->prach_config_pdu.prach_format = 8;
+          break;
+        case 0xc0:
+          pdu->prach_config_pdu.prach_format = 9;
+          break;
+        case 0xc2:
+          pdu->prach_config_pdu.prach_format = 10;
+          break;
+        default:
+          AssertFatal(false, "Invalid PRACH format");
       }
-      AssertFatal(ra->ssb_nb_in_ro<prach_occasion_info_p->nb_mapped_ssb, "%u not found in the mapped SSBs to the PRACH occasion", selected_gnb_ssb_idx);
 
-      if (format1 != 0xff) {
-        switch (format0) { // dual PRACH format
-          case 0xa1:
-            pdu->prach_config_pdu.prach_format = 11;
-            break;
-          case 0xa2:
-            pdu->prach_config_pdu.prach_format = 12;
-            break;
-          case 0xa3:
-            pdu->prach_config_pdu.prach_format = 13;
-            break;
-          default:
-            AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
-        }
-      } else {
-        switch (format0) { // single PRACH format
-          case 0:
-            pdu->prach_config_pdu.prach_format = 0;
-            break;
-          case 1:
-            pdu->prach_config_pdu.prach_format = 1;
-            break;
-          case 2:
-            pdu->prach_config_pdu.prach_format = 2;
-            break;
-          case 3:
-            pdu->prach_config_pdu.prach_format = 3;
-            break;
-          case 0xa1:
-            pdu->prach_config_pdu.prach_format = 4;
-            break;
-          case 0xa2:
-            pdu->prach_config_pdu.prach_format = 5;
-            break;
-          case 0xa3:
-            pdu->prach_config_pdu.prach_format = 6;
-            break;
-          case 0xb1:
-            pdu->prach_config_pdu.prach_format = 7;
-            break;
-          case 0xb4:
-            pdu->prach_config_pdu.prach_format = 8;
-            break;
-          case 0xc0:
-            pdu->prach_config_pdu.prach_format = 9;
-            break;
-          case 0xc2:
-            pdu->prach_config_pdu.prach_format = 10;
-            break;
-          default:
-            AssertFatal(1 == 0, "Invalid PRACH format");
-        }
-      } // if format1
-
-      nr_get_prach_resources(mac, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated);
       pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex;
       pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(mac);
-      unsigned int slot_RA;
-      // 3GPP TS 38.321 Section 5.1.3 says t_id for RA-RNTI depends on mu as specified in clause 5.3.2 in TS 38.211
-      // so mu = 0 for prach format < 4.
-      if (pdu->prach_config_pdu.prach_format < 4) {
-        unsigned int slots_per_sf = (1 << mac->current_UL_BWP->scs);
-        slot_RA = pdu->prach_config_pdu.prach_slot / slots_per_sf;
-      } else {
-        slot_RA = pdu->prach_config_pdu.prach_slot;
-      }
-      mac->ra.ra_rnti = nr_get_ra_rnti(pdu->prach_config_pdu.prach_start_symbol, slot_RA, pdu->prach_config_pdu.num_ra, 0);
       release_ul_config(pdu, false);
       nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
                                                     .mac = mac,
@@ -2733,12 +2184,31 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
       T(T_UE_PHY_INITIATE_RA_PROCEDURE, T_INT(frameP), T_INT(pdu->prach_config_pdu.prach_slot),
         T_INT(pdu->prach_config_pdu.ra_PreambleIndex), T_INT(pdu->prach_config_pdu.prach_tx_power));
 
+      const int n_slots_frame = mac->frame_structure.numb_slots_frame;
       if (ra->ra_type == RA_4_STEP) {
-        nr_Msg1_transmitted(mac);
+        ra->ra_state = nrRA_WAIT_RAR;
+        // we start to monitor DCI for RAR in the first valid occasion after transmitting RACH
+        // the response window timer should be started at that time
+        // but for processing reasons it is better to start it here and to add the slot difference
+        // that also takes into account the rx to tx slot offset
+        int next_slot = (slotP + 1) % n_slots_frame;
+        int next_frame = (frameP + (next_slot < slotP)) % MAX_FRAME_NUMBER;
+        int add_slots = 1;
+        NR_BWP_PDCCH_t *pdcch_config = &mac->config_BWP_PDCCH[mac->current_DL_BWP->bwp_id];
+        while (!is_dl_slot(next_slot, &mac->frame_structure)
+               || !is_ss_monitor_occasion(next_frame, next_slot, n_slots_frame, pdcch_config->ra_SS)) {
+          int temp_slot = (next_slot + 1) % n_slots_frame;
+          next_frame = (next_frame + (temp_slot < next_slot)) % MAX_FRAME_NUMBER;
+          next_slot = temp_slot;
+          add_slots++;
+        }
+        nr_timer_setup(&ra->response_window_timer,
+                       ra->response_window_setup_time + add_slots + GET_DURATION_RX_TO_TX(&mac->ntn_ta),
+                       1);
+        nr_timer_start(&ra->response_window_timer);
       } else if (ra->ra_type == RA_2_STEP) {
         NR_MsgA_PUSCH_Resource_r16_t *msgA_PUSCH_Resource =
             mac->current_UL_BWP->msgA_ConfigCommon_r16->msgA_PUSCH_Config_r16->msgA_PUSCH_ResourceGroupA_r16;
-        const int n_slots_frame = mac->frame_structure.numb_slots_frame;
         slot_t msgA_pusch_slot = (slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) % n_slots_frame;
         frame_t msgA_pusch_frame =
             (frameP + ((slotP + msgA_PUSCH_Resource->msgA_PUSCH_TimeDomainOffset_r16) / n_slots_frame)) % 1024;
@@ -2767,9 +2237,6 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
           remove_ul_config_last_item(pdu);
         release_ul_config(pdu, false);
 
-        // Compute MsgB RNTI
-        ra->MsgB_rnti =
-            nr_get_MsgB_rnti(prach_occasion_info_p->start_symbol, slot_RA, prach_occasion_info_p->fdm, 0);
         LOG_D(NR_MAC, "ra->ra_state %s\n", nrra_ue_text[ra->ra_state]);
         ra->ra_state = nrRA_WAIT_MSGB;
         ra->t_crnti = 0;
@@ -2778,8 +2245,6 @@ static void nr_ue_prach_scheduler(NR_UE_MAC_INST_t *mac, frame_t frameP, slot_t
       } else {
         AssertFatal(false, "RA type %d not implemented!\n", ra->ra_type);
       }
-
-      // rnti = ra->t_crnti;
     } // is_nr_prach_slot
   } // if is_nr_UL_slot
 }
@@ -3382,7 +2847,6 @@ static void schedule_ta_command(fapi_nr_dl_config_request_t *dl_config, NR_UE_MA
   fapi_nr_ta_command_pdu *ta = &dl_config->dl_config_list[dl_config->number_pdus].ta_command_pdu;
   ta->ta_frame = ul_time_alignment->frame;
   ta->ta_slot = ul_time_alignment->slot;
-  ta->ta_offset = mac->n_ta_offset;
   ta->is_rar = ul_time_alignment->ta_apply == rar_ta;
   ta->ta_command = ul_time_alignment->ta_command;
   dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_CONFIG_TA_COMMAND;
diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp
index bcbec989c2240438583d4a1735fc891992c9bcda..7dc0b43ec3abea48e4141717d16fe4e5007f2846 100644
--- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp
+++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_power_procedures.cpp
@@ -192,8 +192,6 @@ TEST(pusch_power_control, pusch_power_control_msg3)
   current_UL_BWP.BWPSize = 106;
   current_UL_BWP.channel_bandwidth = 40;
   mac.current_UL_BWP = &current_UL_BWP;
-  NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0};
-  current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon;
   mac.nr_band = 78;
   NR_PUSCH_Config_t pusch_Config = {0};
   current_UL_BWP.pusch_Config = &pusch_Config;
@@ -229,8 +227,8 @@ TEST(pusch_power_control, pusch_power_control_msg3)
                             num_rb,
                             start_prb);
 
-  long preambleReceivedTargetPower = -96;
-  nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower = preambleReceivedTargetPower;
+  int preambleReceivedTargetPower = -96;
+  mac.ra.prach_resources.ra_preamble_rx_target_power = preambleReceivedTargetPower;
 
   int power = get_pusch_tx_power_ue(&mac,
                                     num_rb,
@@ -247,7 +245,7 @@ TEST(pusch_power_control, pusch_power_control_msg3)
                                     false);
   EXPECT_EQ(power, -84);
   EXPECT_LT(power, P_CMAX);
-  nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower -= 2;
+  mac.ra.prach_resources.ra_preamble_rx_target_power -= 2;
 
   int reduced_power = get_pusch_tx_power_ue(&mac,
                                             num_rb,
@@ -372,8 +370,6 @@ TEST(pusch_power_control, pusch_power_control_state_initialization)
   current_UL_BWP.BWPSize = 106;
   current_UL_BWP.channel_bandwidth = 40;
   mac.current_UL_BWP = &current_UL_BWP;
-  NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0};
-  current_UL_BWP.rach_ConfigCommon = &nr_rach_ConfigCommon;
   mac.nr_band = 78;
   NR_PUSCH_Config_t pusch_Config = {0};
   current_UL_BWP.pusch_Config = &pusch_Config;
@@ -393,8 +389,8 @@ TEST(pusch_power_control, pusch_power_control_state_initialization)
   uint32_t sum_bits_in_codeblocks = 56;
   int delta_pusch = 0;
   bool is_rar_tx_retx = true;
-  long preambleReceivedTargetPower = -96;
-  nr_rach_ConfigCommon.rach_ConfigGeneric.preambleReceivedTargetPower = preambleReceivedTargetPower;
+  int preambleReceivedTargetPower = -96;
+  mac.ra.prach_resources.ra_preamble_rx_target_power = preambleReceivedTargetPower;
 
   get_pusch_tx_power_ue(&mac,
                         num_rb,
diff --git a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp
index f5a402c467032e037f29fc4f4d0f99a7a8937105..25ea5edcd0c0f318b3e61203fcb2022c484ebcf7 100644
--- a/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp
+++ b/openair2/LAYER2/NR_MAC_UE/tests/test_nr_ue_ra_procedures.cpp
@@ -29,20 +29,11 @@ softmodem_params_t *get_softmodem_params(void)
 {
   return &softmodem_params;
 }
-void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success)
+void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success)
 {
 }
-int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
-                          NR_UE_MAC_INST_t *mac,
-                          NR_SINGLE_ENTRY_PHR_MAC_CE *power_headroom,
-                          const type_bsr_t *bsr,
-                          uint8_t *mac_ce_end)
+void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload)
 {
-  return 0;
-}
-int nr_write_ce_msg3_pdu(uint8_t *mac_ce, NR_UE_MAC_INST_t *mac, rnti_t crnti, uint8_t *mac_ce_end)
-{
-  return 0;
 }
 tbs_size_t mac_rlc_data_req(const module_id_t module_idP,
                             const rnti_t rntiP,
@@ -77,6 +68,14 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
 {
   return 0;
 }
+NR_UE_DL_BWP_t *get_dl_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
+{
+  return NULL;
+}
+NR_UE_UL_BWP_t *get_ul_bwp_structure(NR_UE_MAC_INST_t *mac, int bwp_id, bool setup)
+{
+  return NULL;
+}
 }
 #include <cstdio>
 #include "common/utils/LOG/log.h"
@@ -84,22 +83,32 @@ int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
 TEST(test_init_ra, four_step_cbra)
 {
   NR_UE_MAC_INST_t mac = {0};
-  NR_PRACH_RESOURCES_t prach_resources = {0};
+  RA_config_t *ra = &mac.ra;
   NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0};
   NR_RACH_ConfigGeneric_t rach_ConfigGeneric = {0};
-  NR_RACH_ConfigDedicated_t *rach_ConfigDedicated = nullptr;
+  NR_RACH_ConfigDedicated_t rach_ConfigDedicated = {0};
   NR_UE_UL_BWP_t current_bwp;
+  NR_UE_DL_BWP_t dl_bwp;
   mac.current_UL_BWP = &current_bwp;
+  mac.current_DL_BWP = &dl_bwp;
+  mac.mib_ssb = 0;
   long scs = 1;
   current_bwp.scs = scs;
+  current_bwp.bwp_id = 0;
+  dl_bwp.bwp_id = 0;
   current_bwp.channel_bandwidth = 40;
   nr_rach_ConfigCommon.msg1_SubcarrierSpacing = &scs;
+  nr_rach_ConfigCommon.rach_ConfigGeneric = rach_ConfigGeneric;
+  current_bwp.rach_ConfigCommon = &nr_rach_ConfigCommon;
+  ra->rach_ConfigDedicated = &rach_ConfigDedicated;
   mac.p_Max = 23;
   mac.nr_band = 78;
   mac.frame_structure.frame_type = TDD;
+  mac.frame_structure.numb_slots_frame = 20;
   mac.frequency_range = FR1;
+  int frame = 151;
 
-  init_RA(&mac, &prach_resources, &nr_rach_ConfigCommon, &rach_ConfigGeneric, rach_ConfigDedicated);
+  init_RA(&mac, frame);
 
   EXPECT_EQ(mac.ra.ra_type, RA_4_STEP);
   EXPECT_EQ(mac.state, UE_PERFORMING_RA);
@@ -110,25 +119,35 @@ TEST(test_init_ra, four_step_cbra)
 TEST(test_init_ra, four_step_cfra)
 {
   NR_UE_MAC_INST_t mac = {0};
-  NR_PRACH_RESOURCES_t prach_resources = {0};
+  RA_config_t *ra = &mac.ra;
   NR_RACH_ConfigCommon_t nr_rach_ConfigCommon = {0};
   NR_RACH_ConfigGeneric_t rach_ConfigGeneric = {0};
   NR_UE_UL_BWP_t current_bwp;
+  NR_UE_DL_BWP_t dl_bwp;
   mac.current_UL_BWP = &current_bwp;
+  mac.current_DL_BWP = &dl_bwp;
+  mac.mib_ssb = 0;
   long scs = 1;
   current_bwp.scs = scs;
+  current_bwp.bwp_id = 0;
+  dl_bwp.bwp_id = 0;
   current_bwp.channel_bandwidth = 40;
   nr_rach_ConfigCommon.msg1_SubcarrierSpacing = &scs;
+  nr_rach_ConfigCommon.rach_ConfigGeneric = rach_ConfigGeneric;
+  current_bwp.rach_ConfigCommon = &nr_rach_ConfigCommon;
   mac.p_Max = 23;
   mac.nr_band = 78;
   mac.frame_structure.frame_type = TDD;
+  mac.frame_structure.numb_slots_frame = 20;
   mac.frequency_range = FR1;
+  int frame = 151;
 
   NR_RACH_ConfigDedicated_t rach_ConfigDedicated = {0};
-  struct NR_CFRA cfra;
+  NR_CFRA_t cfra;
   rach_ConfigDedicated.cfra = &cfra;
+  ra->rach_ConfigDedicated = &rach_ConfigDedicated;
 
-  init_RA(&mac, &prach_resources, &nr_rach_ConfigCommon, &rach_ConfigGeneric, &rach_ConfigDedicated);
+  init_RA(&mac, frame);
 
   EXPECT_EQ(mac.ra.ra_type, RA_4_STEP);
   EXPECT_EQ(mac.state, UE_PERFORMING_RA);
diff --git a/openair2/LAYER2/NR_MAC_gNB/config.c b/openair2/LAYER2/NR_MAC_gNB/config.c
index d7b9b5e12912748c72a589b44ab89312da5f809f..0abe35b80db0f62afa6459cd980c4869e2911af0 100644
--- a/openair2/LAYER2/NR_MAC_gNB/config.c
+++ b/openair2/LAYER2/NR_MAC_gNB/config.c
@@ -521,8 +521,7 @@ static void config_common(gNB_MAC_INST *nrmac,
     // If absent, use SCS as derived from the prach-ConfigurationIndex (for 839)
     int config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
     int frame_type = get_frame_type(band, frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing);
-    const int64_t *prach_config_info_p = get_prach_config_info(frequency_range, config_index, frame_type);
-    int format = prach_config_info_p[0];
+    int format = get_nr_prach_format_from_index(config_index, UL_pointA, frame_type) & 0xff;
     cfg->prach_config.prach_sub_c_spacing.value = get_delta_f_RA_long(format);
   }
 
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
index cc0317cf5133cb36d9e0d8c24f3e9355387d6757..9bf8b739bfa4cce889eccb2183cf3c0555dcb8ec 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_RA.c
@@ -83,9 +83,8 @@ static int16_t ssb_index_from_prach(module_id_t module_idP,
   
   float  num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
   uint16_t start_symbol_index = 0;
-  uint8_t N_dur=0,N_t_slot=0,start_symbol = 0, temp_start_symbol = 0, N_RA_slot=0;
-  uint16_t format,RA_sfn_index = -1;
-  uint8_t config_period = 1;
+  uint8_t temp_start_symbol = 0;
+  uint16_t RA_sfn_index = -1;
   uint16_t prach_occasion_id = -1;
   uint8_t num_active_ssb = cc->num_active_ssb;
   NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
@@ -93,42 +92,32 @@ static int16_t ssb_index_from_prach(module_id_t module_idP,
     msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
   const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
   const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu);
+  frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1;
+  get_nr_prach_sched_from_info(cc->prach_info, config_index, frameP, slotP, mu, freq_range, &RA_sfn_index, cc->frame_type);
 
-  get_nr_prach_info_from_index(config_index,
-			       (int)frameP,
-			       (int)slotP,
-			       scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-			       mu,
-			       cc->frame_type,
-			       &format,
-			       &start_symbol,
-			       &N_t_slot,
-			       &N_dur,
-			       &RA_sfn_index,
-			       &N_RA_slot,
-			       &config_period);
   uint8_t index = 0, slot_index = 0;
-  for (slot_index = 0; slot_index < N_RA_slot; slot_index++) {
-    if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
+  for (slot_index = 0; slot_index < cc->prach_info.N_RA_slot; slot_index++) {
+    if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe
        if((mu == 1) || (mu == 3))
-         slot_index = 1;  //For scs = 30khz and 120khz
+         slot_index = 1; // For scs = 30khz and 120khz
     }
-    for (int i = 0; i < N_t_slot; i++) {
-      temp_start_symbol = (start_symbol + i * N_dur + 14 * slot_index) % 14;
+    for (int i = 0; i < cc->prach_info.N_t_slot; i++) {
+      temp_start_symbol = (cc->prach_info.start_symbol + i * cc->prach_info.N_dur + 14 * slot_index) % 14;
       if(symbol == temp_start_symbol) {
         start_symbol_index = i;
         break;
       }
     }
   }
-  if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
+  if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe
     if((mu == 1) || (mu == 3))
-      slot_index = 0;  //For scs = 30khz and 120khz
+      slot_index = 0; // For scs = 30khz and 120khz
   }
-
+  int config_period = cc->prach_info.x;
   //  prach_occasion_id = subframe_index * N_t_slot * N_RA_slot * fdm + N_RA_slot_index * N_t_slot * fdm + freq_index + fdm * start_symbol_index;
-  prach_occasion_id = (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period) +
-                      (RA_sfn_index + slot_index) * N_t_slot * fdm + start_symbol_index * fdm + freq_index;
+  prach_occasion_id =
+      (((frameP % (cc->max_association_period * config_period)) / config_period) * cc->total_prach_occasions_per_config_period)
+      + (RA_sfn_index + slot_index) * cc->prach_info.N_t_slot * fdm + start_symbol_index * fdm + freq_index;
 
   //one SSB have more than one continuous RO
   if(num_ssb_per_RO <= 1)
@@ -159,14 +148,12 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
   nfapi_nr_config_request_scf_t *cfg = &nrmac->config[0];
   NR_RACH_ConfigCommon_t *rach_ConfigCommon = scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup;
   uint8_t config_index = rach_ConfigCommon->rach_ConfigGeneric.prach_ConfigurationIndex;
-  uint8_t N_dur=0,N_t_slot=0,start_symbol=0,N_RA_slot = 0;
-  uint16_t format,N_RA_sfn = 0,unused_RA_occasion,repetition = 0;
+  uint16_t unused_RA_occasion, repetition = 0;
   uint8_t num_active_ssb = 0;
-  uint8_t max_association_period = 1;
 
   struct NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB *ssb_perRACH_OccasionAndCB_PreamblesPerSSB = rach_ConfigCommon->ssb_perRACH_OccasionAndCB_PreamblesPerSSB;
 
-  switch (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present){
+  switch (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present) {
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
       cc->cb_preambles_per_ssb = 4 * (ssb_perRACH_OccasionAndCB_PreamblesPerSSB->choice.oneEighth + 1);
       break;
@@ -194,31 +181,16 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
     default:
       AssertFatal(1 == 0, "Unsupported ssb_perRACH_config %d\n", ssb_perRACH_OccasionAndCB_PreamblesPerSSB->present);
       break;
-    }
-
-  NR_MsgA_ConfigCommon_r16_t *msgacc = NULL;
-  if (scc->uplinkConfigCommon->initialUplinkBWP->ext1 && scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16)
-    msgacc = scc->uplinkConfigCommon->initialUplinkBWP->ext1->msgA_ConfigCommon_r16->choice.setup;
-  const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
-  const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu);
+  }
 
   // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
-  get_nr_prach_occasion_info_from_index(config_index,
-                                        scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                        mu,
-                                        cc->frame_type,
-                                        &format,
-                                        &start_symbol,
-                                        &N_t_slot,
-                                        &N_dur,
-                                        &N_RA_slot,
-                                        &N_RA_sfn,
-                                        &max_association_period);
+  frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1;
+  nr_prach_info_t prach_info =  get_nr_prach_occasion_info_from_index(config_index, freq_range, cc->frame_type);
 
   float num_ssb_per_RO = ssb_per_rach_occasion[cfg->prach_config.ssb_per_rach.value];	
   uint8_t fdm = cfg->prach_config.num_prach_fd_occasions.value;
   uint64_t L_ssb = (((uint64_t) cfg->ssb_table.ssb_mask_list[0].ssb_mask.value) << 32) | cfg->ssb_table.ssb_mask_list[1].ssb_mask.value;
-  uint32_t total_RA_occasions = N_RA_sfn * N_t_slot * N_RA_slot * fdm;
+  uint32_t total_RA_occasions = prach_info.N_RA_sfn * prach_info.N_t_slot * prach_info.N_RA_slot * fdm;
 
   for(int i = 0; i < 64; i++) {
     if ((L_ssb >> (63 - i)) & 0x01) { // only if the bit of L_ssb at current ssb index is 1
@@ -228,7 +200,7 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
   }
 
   cc->total_prach_occasions_per_config_period = total_RA_occasions;
-  for(int i = 1; (1 << (i-1)) <= max_association_period; i++) {
+  for (int i = 1; (1 << (i - 1)) <= prach_info.max_association_period; i++) {
     cc->max_association_period = (1 << (i - 1));
     total_RA_occasions = total_RA_occasions * cc->max_association_period;
     if(total_RA_occasions >= (int) (num_active_ssb / num_ssb_per_RO)) {
@@ -240,14 +212,16 @@ void find_SSB_and_RO_available(gNB_MAC_INST *nrmac)
   unused_RA_occasion = total_RA_occasions - (int)((num_active_ssb * repetition) / num_ssb_per_RO);
   cc->total_prach_occasions = total_RA_occasions - unused_RA_occasion;
   cc->num_active_ssb = num_active_ssb;
+  cc->prach_info = prach_info;
 
   LOG_D(NR_MAC,
-        "Total available RO %d, num of active SSB %d: unused RO = %d association_period %u N_RA_sfn %u total_prach_occasions_per_config_period %u\n",
+        "Total available RO %d, num of active SSB %d: unused RO = %d association_period %u N_RA_sfn %u "
+        "total_prach_occasions_per_config_period %u\n",
         cc->total_prach_occasions,
         cc->num_active_ssb,
         unused_RA_occasion,
         cc->max_association_period,
-        N_RA_sfn,
+        prach_info.N_RA_sfn,
         cc->total_prach_occasions_per_config_period);
 }
 
@@ -396,10 +370,6 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
   if (is_ul_slot(slotP, &RC.nrmac[module_idP]->frame_structure)) {
     const NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &rach_ConfigCommon->rach_ConfigGeneric;
     uint8_t config_index = rach_ConfigGeneric->prach_ConfigurationIndex;
-    uint8_t N_dur, N_t_slot, start_symbol = 0, N_RA_slot;
-    uint16_t RA_sfn_index = -1;
-    uint8_t config_period = 1;
-    uint16_t format;
     int slot_index = 0;
     uint16_t prach_occasion_id = -1;
 
@@ -409,29 +379,18 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
     const int ul_mu = scc->uplinkConfigCommon->frequencyInfoUL->scs_SpecificCarrierList.list.array[0]->subcarrierSpacing;
     const int mu = nr_get_prach_or_ul_mu(msgacc, rach_ConfigCommon, ul_mu);
     // prach is scheduled according to configuration index and tables 6.3.3.2.2 to 6.3.3.2.4
-    if (get_nr_prach_info_from_index(config_index,
-                                     (int)frameP,
-                                     (int)slotP,
-                                     scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA,
-                                     mu,
-                                     cc->frame_type,
-                                     &format,
-                                     &start_symbol,
-                                     &N_t_slot,
-                                     &N_dur,
-                                     &RA_sfn_index,
-                                     &N_RA_slot,
-                                     &config_period)) {
-
-      uint16_t format0 = format & 0xff;      // first column of format from table
-      uint16_t format1 = (format >> 8) & 0xff; // second column of format from table
-
-      if (N_RA_slot > 1) { //more than 1 PRACH slot in a subframe
+    uint16_t RA_sfn_index = -1;
+    frequency_range_t freq_range = scc->downlinkConfigCommon->frequencyInfoDL->absoluteFrequencyPointA > 2016666 ? FR2 : FR1;
+    if (get_nr_prach_sched_from_info(cc->prach_info, config_index, frameP, slotP, mu, freq_range, &RA_sfn_index, cc->frame_type)) {
+      uint16_t format0 = cc->prach_info.format & 0xff; // first column of format from table
+      uint16_t format1 = (cc->prach_info.format >> 8) & 0xff; // second column of format from table
+
+      if (cc->prach_info.N_RA_slot > 1) { // more than 1 PRACH slot in a subframe
         if (slotP % 2 == 1)
           slot_index = 1;
         else
           slot_index = 0;
-      } else if (N_RA_slot <= 1) { //1 PRACH slot in a subframe
+      } else if (cc->prach_info.N_RA_slot <= 1) { // 1 PRACH slot in a subframe
         slot_index = 0;
       }
 
@@ -439,9 +398,11 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
       UL_tti_req->Slot = slotP;
       UL_tti_req->rach_present = 1;
       NR_beam_alloc_t beam = {0};
+      uint32_t N_t_slot = cc->prach_info.N_t_slot;
+      uint32_t start_symb = cc->prach_info.start_symbol;
       for (int fdm_index = 0; fdm_index < fdm; fdm_index++) { // one structure per frequency domain occasion
         for (int td_index = 0; td_index < N_t_slot; td_index++) {
-
+          uint32_t config_period = cc->prach_info.x;
           prach_occasion_id = (((frameP % (cc->max_association_period * config_period))/config_period) * cc->total_prach_occasions_per_config_period) +
                               (RA_sfn_index + slot_index) * N_t_slot * fdm + td_index * fdm + fdm_index;
 
@@ -482,7 +443,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
             // filling the prach fapi structure
             prach_pdu->phys_cell_id = *scc->physCellId;
             prach_pdu->num_prach_ocas = N_t_slot;
-            prach_pdu->prach_start_symbol = start_symbol;
+            prach_pdu->prach_start_symbol = start_symb;
             prach_pdu->num_ra = fdm_index;
             prach_pdu->num_cs = get_NCS(rach_ConfigGeneric->zeroCorrelationZoneConfig,
                                         format0,
@@ -499,7 +460,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
                   slotP,
                   prach_occasion_id,
                   prach_pdu->num_ra,
-                  prach_pdu->prach_start_symbol,
+                  start_symb,
                   slot_index,
                   RA_sfn_index);
             // SCF PRACH PDU format field does not consider A1/B1 etc. possibilities
@@ -579,13 +540,12 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
       const int16_t n_ra_rb = get_N_RA_RB(cfg->prach_config.prach_sub_c_spacing.value, mu_pusch);
       // mark PRBs as occupied for current and future slots if prach extends beyond current slot
       int total_prach_slots;
+      uint32_t N_dur = cc->prach_info.N_dur;
       if (format0 < 4) {
         N_dur = 14; // number of PRACH symbols in PRACH slot
         total_prach_slots = get_long_prach_dur(format0, mu_pusch);
         AssertFatal(slotP + total_prach_slots - 1 < slots_frame, "PRACH cannot extend across frames\n");
       } else {
-        // TODO: to be revisited for format B4 (also extends beyond current slot for FR1 30kHz SCS and FR2)
-        AssertFatal((format != 0xb4) || (mu_pusch < 1), "Format B4 not supported for this PUSCH SCS\n");
         total_prach_slots = 1;
       }
       // reserve PRBs occupied by PRACH in all PRACH slot.
@@ -597,7 +557,7 @@ void schedule_nr_prach(module_id_t module_idP, frame_t frameP, slot_t slotP)
                  gNB->vrb_map_UL_size,
                  slots_frame,
                  bwp_start + rach_ConfigGeneric->msg1_FrequencyStart,
-                 start_symbol,
+                 start_symb,
                  N_t_slot * N_dur,
                  cc);
       }
@@ -1413,6 +1373,8 @@ static bool msg2_in_response_window(int rach_frame,
                                     int current_slot)
 {
   int window_slots = get_response_window(rrc_ra_ResponseWindow);
+  if (window_slots > n_slots_frame)
+    LOG_E(NR_MAC, "RA-ResponseWindow need to be configured to a value lower than or equal to 10 ms\n");
   int abs_rach = n_slots_frame * rach_frame + rach_slot;
   int abs_now = n_slots_frame * current_frame + current_slot;
   int diff = (n_slots_frame * 1024 + abs_now - abs_rach) % (n_slots_frame * 1024);
diff --git a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
index 3f992f04095a8abdb10fb79fcfd466c1b5054c86..8b1bb3ec5c547faa4edd322f40c34142a4aa8a22 100644
--- a/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
+++ b/openair2/LAYER2/NR_MAC_gNB/nr_mac_gNB.h
@@ -302,6 +302,7 @@ typedef struct {
   int cb_preambles_per_ssb;
   /// Max prach length in slots
   int prach_len;
+  nr_prach_info_t prach_info;
 } NR_COMMON_channels_t;
 
 // SP ZP CSI-RS Resource Set Activation/Deactivation MAC CE
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
index 9e7310cf40818b29a70fa0c0fd43024abab7f816..64de7b4560de477f7d39db09930cdb3f038c0443 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
@@ -390,8 +390,7 @@ static bool is_my_dci(NR_UE_MAC_INST_t *mac, nfapi_nr_dl_dci_pdu_t *received_pdu
      already. Only once the RA procedure succeeds is the CRNTI value updated
      to the TC_RNTI. */
   if (get_softmodem_params()->nsa) {
-    if (received_pdu->RNTI != mac->crnti &&
-        (received_pdu->RNTI != mac->ra.ra_rnti || mac->ra.RA_RAPID_found))
+    if (received_pdu->RNTI != mac->crnti && (received_pdu->RNTI != mac->ra.ra_rnti))
       return false;
   }
   if (IS_SA_MODE(get_softmodem_params())) {
@@ -1122,9 +1121,14 @@ static nr_dci_format_t handle_dci(NR_UE_MAC_INST_t *mac,
   // if notification of a reception of a PDCCH transmission of the SpCell is received from lower layers
   // if the C-RNTI MAC CE was included in Msg3
   // consider this Contention Resolution successful
-  if (mac->ra.msg3_C_RNTI && mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION)
+  if (mac->msg3_C_RNTI && mac->ra.ra_state == nrRA_WAIT_CONTENTION_RESOLUTION)
     nr_ra_succeeded(mac, gNB_index, frame, slot);
 
+  // suspend RAR response window timer
+  // (in RFsim running multiple slot in parallel it might expire while decoding MSG2)
+  if (mac->ra.ra_state == nrRA_WAIT_RAR)
+    nr_timer_suspension(&mac->ra.response_window_timer);
+
   return nr_ue_process_dci_indication_pdu(mac, frame, slot, dci);
 }
 
@@ -1292,11 +1296,14 @@ static uint32_t nr_ue_dl_processing(NR_UE_MAC_INST_t *mac, nr_downlink_indicatio
           ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH;
           break;
         case FAPI_NR_RX_PDU_TYPE_RAR:
-          ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR;
-          if (!dl_info->rx_ind->rx_indication_body[i].pdsch_pdu.ack_nack)
+          if (!dl_info->rx_ind->rx_indication_body[i].pdsch_pdu.ack_nack) {
             LOG_W(PHY, "Received a RAR-Msg2 but LDPC decode failed\n");
-          else
+            // resume RAR response window timer if MSG2 decoding failed
+            nr_timer_suspension(&mac->ra.response_window_timer);
+          } else {
             LOG_I(PHY, "RAR-Msg2 decoded\n");
+          }
+          ret_mask |= (handle_dlsch(mac, dl_info, i)) << FAPI_NR_RX_PDU_TYPE_RAR;
           break;
         case FAPI_NR_CSIRS_IND:
           ret_mask |= (handle_csirs_measurements(mac,
@@ -1330,12 +1337,15 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
   return ret2;
 }
 
-void nr_ue_slot_indication(uint8_t mod_id)
+void nr_ue_slot_indication(uint8_t mod_id, bool is_tx)
 {
   NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
   int ret = pthread_mutex_lock(&mac->if_mutex);
   AssertFatal(!ret, "mutex failed %d\n", ret);
-  update_mac_timers(mac);
+  if (is_tx)
+    update_mac_ul_timers(mac);
+  else
+    update_mac_dl_timers(mac);
   ret = pthread_mutex_unlock(&mac->if_mutex);
   AssertFatal(!ret, "mutex failed %d\n", ret);
 }
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
index e6a4bfa80b136bfb03e0ac7ad9b14f4b519b71ff..2bbd97db843d2c9cb40824a6ebdd96b5cc008ac2 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
@@ -260,7 +260,7 @@ typedef int (nr_ue_dl_indication_f)(nr_downlink_indication_t *dl_info);
  */
 typedef int (nr_ue_ul_indication_f)(nr_uplink_indication_t *ul_info);
 
-typedef void (nr_ue_slot_indication_f)(uint8_t mod_id);
+typedef void (nr_ue_slot_indication_f)(uint8_t mod_id, bool is_tx);
 
 /*
  * Generic type of an application-defined callback to return various
diff --git a/openair2/RRC/NR/nr_rrc_config.c b/openair2/RRC/NR/nr_rrc_config.c
index f6dead1213369ef0ca5f4cd7298d65a827501799..a6c2ae1c9cac47ed4e32350c399133aea7d97501 100644
--- a/openair2/RRC/NR/nr_rrc_config.c
+++ b/openair2/RRC/NR/nr_rrc_config.c
@@ -3819,11 +3819,7 @@ NR_ReconfigurationWithSync_t *get_reconfiguration_with_sync(rnti_t rnti, uid_t u
   uplink->ra_Prioritization = NULL;
   uplink->cfra = calloc(1, sizeof(struct NR_CFRA));
   uplink->cfra->ext1 = NULL;
-  uplink->cfra->occasions = calloc(1, sizeof(struct NR_CFRA__occasions));
-  memcpy(&uplink->cfra->occasions->rach_ConfigGeneric,
-         &scc->uplinkConfigCommon->initialUplinkBWP->rach_ConfigCommon->choice.setup->rach_ConfigGeneric,
-         sizeof(NR_RACH_ConfigGeneric_t));
-  asn1cCallocOne(uplink->cfra->occasions->ssb_perRACH_Occasion, NR_CFRA__occasions__ssb_perRACH_Occasion_one);
+  uplink->cfra->occasions = NULL;
   uplink->cfra->resources.present = NR_CFRA__resources_PR_ssb;
   uplink->cfra->resources.choice.ssb = calloc(1, sizeof(struct NR_CFRA__resources__ssb));
   uplink->cfra->resources.choice.ssb->ra_ssb_OccasionMaskIndex = 0;
diff --git a/openair2/RRC/NR_UE/L2_interface_ue.c b/openair2/RRC/NR_UE/L2_interface_ue.c
index 7fd34ff91c5d3b72b086b75f95e3cd8ff8ae6c0e..3bfe1d34e02b0bd2efcc5dae5688bd443aabfb4b 100644
--- a/openair2/RRC/NR_UE/L2_interface_ue.c
+++ b/openair2/RRC/NR_UE/L2_interface_ue.c
@@ -159,11 +159,11 @@ void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id)
   itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p);
 }
 
-void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, int gnb_id)
+void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload)
 {
   MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_MSG3_IND);
   NR_RRC_MAC_MSG3_IND (message_p).rnti = rnti;
-  NR_RRC_MAC_MSG3_IND (message_p).gnb_id = gnb_id;
+  NR_RRC_MAC_MSG3_IND (message_p).prepare_payload = prepare_payload;
   itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p);
 }
 
@@ -177,10 +177,9 @@ void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id)
   itti_send_msg_to_task(TASK_RRC_NRUE, instance, message_p);
 }
 
-void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success)
+void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success)
 {
   MessageDef *message_p = itti_alloc_new_message(TASK_MAC_UE, 0, NR_RRC_MAC_RA_IND);
-  NR_RRC_MAC_RA_IND (message_p).frame = frame;
   NR_RRC_MAC_RA_IND (message_p).RA_succeeded = success;
   itti_send_msg_to_task(TASK_RRC_NRUE, GNB_MODULE_ID_TO_INSTANCE(mod_id), message_p);
 }
diff --git a/openair2/RRC/NR_UE/L2_interface_ue.h b/openair2/RRC/NR_UE/L2_interface_ue.h
index 05888cbc0e8f0ab360426dc4278e52711ad0e8e4..f394e5e33372da54d0972c5a8458432df9f00d44 100644
--- a/openair2/RRC/NR_UE/L2_interface_ue.h
+++ b/openair2/RRC/NR_UE/L2_interface_ue.h
@@ -37,9 +37,9 @@ void nr_mac_rrc_data_ind_ue(const module_id_t module_id,
                             const uint8_t* pduP,
                             const sdu_size_t pdu_len);
 void nr_mac_rrc_inactivity_timer_ind(const module_id_t mod_id);
-void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, int gnb_id);
+void nr_mac_rrc_msg3_ind(const module_id_t mod_id, const int rnti, bool prepare_payload);
 void nr_ue_rrc_timer_trigger(int instance, int frame, int gnb_id);
-void nr_mac_rrc_ra_ind(const module_id_t mod_id, int frame, bool success);
+void nr_mac_rrc_ra_ind(const module_id_t mod_id, bool success);
 void nsa_sendmsg_to_lte_ue(const void *message, size_t msg_len, Rrc_Msg_Type_t msg_type);
 void process_msg_rcc_to_mac(MessageDef *msg);
 #endif
diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c
index f61ce49494fadfff7e0053e9cc34fa8f5b399636..d0d127377634516a81c2156568d5e5de65197a98 100644
--- a/openair2/RRC/NR_UE/rrc_UE.c
+++ b/openair2/RRC/NR_UE/rrc_UE.c
@@ -335,8 +335,6 @@ static void nr_rrc_process_sib1(NR_UE_RRC_INST_t *rrc, NR_UE_RRC_SI_INFO *SI_inf
   SI_info->sib1_validity = SIB_VALID;
   if (rrc->nrRrcState == RRC_STATE_IDLE_NR) {
     rrc->ra_trigger = RRC_CONNECTION_SETUP;
-    // preparing RRC setup request payload in advance
-    nr_rrc_ue_prepare_RRCSetupRequest(rrc);
   }
 
   NR_SIB1_v1700_IEs_t *sib1_v1700 = NULL;
@@ -856,15 +854,6 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
     nr_timer_stop(&timers->T311);
     rrc->ra_trigger = RRC_CONNECTION_REESTABLISHMENT;
 
-    // preparing MSG3 for re-establishment in advance
-    uint8_t buffer[1024];
-    int buf_size = do_RRCReestablishmentRequest(buffer,
-                                                rrc->reestablishment_cause,
-                                                rrc->phyCellID,
-                                                rrc->rnti); // old rnti
-
-    nr_rlc_srb_recv_sdu(rrc->ue_id, 0, buffer, buf_size);
-
     // apply the default MAC Cell Group configuration
     // (done at MAC by calling nr_ue_mac_default_configs)
 
@@ -892,6 +881,31 @@ static void nr_rrc_ue_decode_NR_BCCH_BCH_Message(NR_UE_RRC_INST_t *rrc,
   return;
 }
 
+static void nr_rrc_ue_prepare_RRCReestablishmentRequest(NR_UE_RRC_INST_t *rrc)
+{
+  uint8_t buffer[1024];
+  int buf_size = do_RRCReestablishmentRequest(buffer, rrc->reestablishment_cause, rrc->phyCellID, rrc->rnti); // old rnti
+  nr_rlc_srb_recv_sdu(rrc->ue_id, 0, buffer, buf_size);
+}
+
+static void nr_rrc_prepare_msg3_payload(NR_UE_RRC_INST_t *rrc)
+{
+  if (!IS_SA_MODE(get_softmodem_params()))
+    return;
+  switch (rrc->ra_trigger) {
+    case RRC_CONNECTION_SETUP:
+      // preparing RRC setup request payload in advance
+      nr_rrc_ue_prepare_RRCSetupRequest(rrc);
+      break;
+    case RRC_CONNECTION_REESTABLISHMENT:
+      // preparing MSG3 for re-establishment in advance
+      nr_rrc_ue_prepare_RRCReestablishmentRequest(rrc);
+      break;
+    default:
+      AssertFatal(false, "RA trigger not implemented\n");
+  }
+}
+
 static void nr_rrc_handle_msg3_indication(NR_UE_RRC_INST_t *rrc, rnti_t rnti)
 {
   NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
@@ -1975,6 +1989,16 @@ void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
     nr_timer_stop(&timers->T304);
     // TODO handle the rest of procedures as described in 5.3.5.3 for when
     // reconfigurationWithSync is included in spCellConfig
+  } else if (!ra_succeeded) {
+    // upon random access problem indication from MCG MAC
+    // while neither T300, T301, T304, T311 nor T319 are running
+    // consider radio link failure to be detected
+    if (!nr_timer_is_active(&timers->T300)
+        && !nr_timer_is_active(&timers->T301)
+        && !nr_timer_is_active(&timers->T304)
+        && !nr_timer_is_active(&timers->T311)
+        && !nr_timer_is_active(&timers->T319))
+      handle_rlf_detection(rrc);
   }
 }
 
@@ -2035,16 +2059,18 @@ void *rrc_nrue(void *notUsed)
     break;
 
   case NR_RRC_MAC_MSG3_IND:
-    nr_rrc_handle_msg3_indication(rrc, NR_RRC_MAC_MSG3_IND(msg_p).rnti);
+    if (NR_RRC_MAC_MSG3_IND(msg_p).prepare_payload)
+      nr_rrc_prepare_msg3_payload(rrc);
+    else
+      nr_rrc_handle_msg3_indication(rrc, NR_RRC_MAC_MSG3_IND(msg_p).rnti);
     break;
 
   case NR_RRC_MAC_RA_IND:
     LOG_D(NR_RRC,
-	  "[UE %ld] Received %s: frame %d RA %s\n",
-	  rrc->ue_id,
-	  ITTI_MSG_NAME(msg_p),
-	  NR_RRC_MAC_RA_IND(msg_p).frame,
-	  NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed");
+          "[UE %ld] Received %s: RA %s\n",
+          rrc->ue_id,
+          ITTI_MSG_NAME(msg_p),
+          NR_RRC_MAC_RA_IND(msg_p).RA_succeeded ? "successful" : "failed");
     nr_rrc_handle_ra_indication(rrc, NR_RRC_MAC_RA_IND(msg_p).RA_succeeded);
     break;