diff --git a/ci-scripts/cls_containerize.py b/ci-scripts/cls_containerize.py
index 79bc4fa46ec490f843c044395f3d558ad4aeadac..6c47787250f31c1facea28349a117f254e967d76 100644
--- a/ci-scripts/cls_containerize.py
+++ b/ci-scripts/cls_containerize.py
@@ -424,14 +424,13 @@ class Containerize():
 
 		# Let's remove any previous run artifacts if still there
 		cmd.run(f"{self.cli} image prune --force")
-		if forceBaseImageBuild:
-			cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
 		for image,pattern,name,option in imageNames:
 			cmd.run(f"{self.cli} image rm {name}:{imageTag}")
 
 		# Build the base image only on Push Events (not on Merge Requests)
 		# On when the base image docker file is being modified.
 		if forceBaseImageBuild:
+			cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
 			cmd.run(f"{self.cli} build {self.cliBuildOptions} --target {baseImage} --tag {baseImage}:{baseTag} --file docker/Dockerfile.base{self.dockerfileprefix} . &> cmake_targets/log/ran-base.log", timeout=1600)
 		# First verify if the base image was properly created.
 		ret = cmd.run(f"{self.cli} image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
@@ -445,7 +444,7 @@ class Containerize():
 			logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
 			HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
 			HTML.CreateHtmlTabFooter(False)
-			sys.exit(1)
+			return False
 		else:
 			result = re.search('Size *= *(?P<size>[0-9\-]+) *bytes', cmd.getBefore())
 			if result is not None:
@@ -506,10 +505,11 @@ class Containerize():
 			cmd.run(f"{self.cli} image prune --force")
 
 		# Remove all intermediate build images and clean up
-		if self.ranAllowMerge and forceBaseImageBuild:
-			cmd.run(f"{self.cli} image rm {baseImage}:{baseTag}")
 		cmd.run(f"{self.cli} image rm ran-build:{imageTag} ran-build-asan:{imageTag}")
 		cmd.run(f"{self.cli} volume prune --force")
+		# Remove any cached artifacts: we don't use the cache for now, prevent
+		# out of diskspace problem
+		cmd.run(f"{self.cli} buildx prune --force")
 
 		# create a zip with all logs
 		build_log_name = f'build_log_{self.testCase_id}'
@@ -523,12 +523,13 @@ class Containerize():
 			logging.info('\u001B[1m Building OAI Image(s) Pass\u001B[0m')
 			HTML.CreateHtmlTestRow(self.imageKind, 'OK', CONST.ALL_PROCESSES_OK)
 			HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
+			return True
 		else:
 			logging.error('\u001B[1m Building OAI Images Failed\u001B[0m')
 			HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
 			HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
 			HTML.CreateHtmlTabFooter(False)
-			sys.exit(1)
+			return False
 
 	def BuildProxy(self, HTML):
 		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
@@ -611,7 +612,7 @@ class Containerize():
 				mySSH.close()
 				HTML.CreateHtmlTestRow('commit ' + tag, 'KO', CONST.ALL_PROCESSES_OK)
 				HTML.CreateHtmlTabFooter(False)
-				sys.exit(1)
+				return False
 		else:
 			logging.debug('L2sim proxy image for tag ' + tag + ' already exists, skipping build')
 
@@ -673,6 +674,87 @@ class Containerize():
 		HTML.CreateHtmlTestRow('commit ' + tag, 'OK', CONST.ALL_PROCESSES_OK)
 		HTML.CreateHtmlNextTabHeaderTestRow(collectInfo, allImagesSize)
 
+	def BuildRunTests(self, HTML):
+		if self.ranRepository == '' or self.ranBranch == '' or self.ranCommitID == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		if self.eNB_serverId[self.eNB_instance] == '0':
+			lIpAddr = self.eNBIPAddress
+			lUserName = self.eNBUserName
+			lPassWord = self.eNBPassword
+			lSourcePath = self.eNBSourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '1':
+			lIpAddr = self.eNB1IPAddress
+			lUserName = self.eNB1UserName
+			lPassWord = self.eNB1Password
+			lSourcePath = self.eNB1SourceCodePath
+		elif self.eNB_serverId[self.eNB_instance] == '2':
+			lIpAddr = self.eNB2IPAddress
+			lUserName = self.eNB2UserName
+			lPassWord = self.eNB2Password
+			lSourcePath = self.eNB2SourceCodePath
+		if lIpAddr == '' or lUserName == '' or lPassWord == '' or lSourcePath == '':
+			HELP.GenericHelp(CONST.Version)
+			sys.exit('Insufficient Parameter')
+		logging.debug('Building on server: ' + lIpAddr)
+		cmd = cls_cmd.RemoteCmd(lIpAddr)
+		cmd.cd(lSourcePath)
+
+		ret = cmd.run('hostnamectl')
+		result = re.search('Ubuntu', ret.stdout)
+		host = result.group(0)
+		if host != 'Ubuntu':
+			cmd.close()
+			raise Exception("Can build unit tests only on Ubuntu server")
+		logging.debug('running on Ubuntu as expected')
+
+		if self.forcedWorkspaceCleanup:
+			cmd.run(f'sudo -S rm -Rf {lSourcePath}')
+		self.testCase_id = HTML.testCase_id
+	
+		# check that ran-base image exists as we expect it
+		baseImage = 'ran-base'
+		baseTag = 'develop'
+		if self.ranAllowMerge:
+			if self.ranTargetBranch == 'develop':
+				cmd.run(f'git diff HEAD..origin/develop -- cmake_targets/build_oai cmake_targets/tools/build_helper docker/Dockerfile.base{self.dockerfileprefix} | grep --colour=never -i INDEX')
+				result = re.search('index', cmd.getBefore())
+				if result is not None:
+					baseTag = 'develop'
+		ret = cmd.run(f"docker image inspect --format=\'Size = {{{{.Size}}}} bytes\' {baseImage}:{baseTag}")
+		if ret.returncode != 0:
+			logging.error(f'No {baseImage} image present, cannot build tests')
+			HTML.CreateHtmlTestRow(self.imageKind, 'KO', CONST.ALL_PROCESSES_OK)
+			HTML.CreateHtmlTabFooter(False)
+			return False
+
+		# build ran-unittests image
+		dockerfile = "ci-scripts/docker/Dockerfile.unittest.ubuntu20"
+		ret = cmd.run(f'docker build --progress=plain --tag ran-unittests:{baseTag} --file {dockerfile} . &> {lSourcePath}/cmake_targets/log/unittest-build.log')
+		if ret.returncode != 0:
+			logging.error(f'Cannot build unit tests')
+			HTML.CreateHtmlTestRow("Unit test build failed", 'KO', [dockerfile])
+			HTML.CreateHtmlTabFooter(False)
+			return False
+
+		HTML.CreateHtmlTestRowQueue("Build unit tests", 'OK', [dockerfile])
+
+		# it worked, build and execute tests, and close connection
+		ret = cmd.run(f'docker run -a STDOUT --rm ran-unittests:develop ctest --output-on-failure --no-label-summary -j$(nproc)')
+		cmd.run(f'docker rmi ran-unittests:develop')
+		build_log_name = f'build_log_{self.testCase_id}'
+		CopyLogsToExecutor(cmd, lSourcePath, build_log_name)
+		cmd.close()
+
+		if ret.returncode == 0:
+			HTML.CreateHtmlTestRowQueue('Unit tests succeeded', 'OK', [ret.stdout])
+			HTML.CreateHtmlTabFooter(True)
+			return True
+		else:
+			HTML.CreateHtmlTestRowQueue('Unit tests failed (see also doc/UnitTests.md)', 'KO', [ret.stdout])
+			HTML.CreateHtmlTabFooter(False)
+			return False
+
 	def Push_Image_to_Local_Registry(self, HTML):
 		if self.registrySvrId == '0':
 			lIpAddr = self.eNBIPAddress
diff --git a/ci-scripts/docker/Dockerfile.unittest.ubuntu20 b/ci-scripts/docker/Dockerfile.unittest.ubuntu20
new file mode 100644
index 0000000000000000000000000000000000000000..7e4798871902cd9b5f0f8305e14f9c652f842844
--- /dev/null
+++ b/ci-scripts/docker/Dockerfile.unittest.ubuntu20
@@ -0,0 +1,35 @@
+#/*
+# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+# * contributor license agreements.  See the NOTICE file distributed with
+# * this work for additional information regarding copyright ownership.
+# * The OpenAirInterface Software Alliance licenses this file to You under
+# * the OAI Public License, Version 1.1  (the "License"); you may not use this file
+# * except in compliance with the License.
+# * You may obtain a copy of the License at
+# *
+# *      http://www.openairinterface.org/?page_id=698
+# *
+# * Unless required by applicable law or agreed to in writing, software
+# * distributed under the License is distributed on an "AS IS" BASIS,
+# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# * See the License for the specific language governing permissions and
+# * limitations under the License.
+# *-------------------------------------------------------------------------------
+# * For more information about the OpenAirInterface (OAI) Software Alliance:
+# *      contact@openairinterface.org
+# */
+#---------------------------------------------------------------------
+#
+# Dockerfile for the Open-Air-Interface BUILD service
+#   Valid for Ubuntu 20.04
+#
+#---------------------------------------------------------------------
+
+FROM ran-base:develop as ran-tests
+
+RUN rm -Rf /oai-ran
+WORKDIR /oai-ran
+COPY . .
+
+WORKDIR /oai-ran/build
+RUN cmake -GNinja -DENABLE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug .. && ninja tests
diff --git a/ci-scripts/main.py b/ci-scripts/main.py
index 87702243937cbaeef5ebd40e52860e23be54252c..db6fedde1a34309bbb2a7fcea43d782efb7b2645 100644
--- a/ci-scripts/main.py
+++ b/ci-scripts/main.py
@@ -65,6 +65,7 @@ import logging
 import datetime
 import signal
 import subprocess
+import traceback
 from multiprocessing import Process, Lock, SimpleQueue
 logging.basicConfig(
 	level=logging.DEBUG,
@@ -102,7 +103,7 @@ def AssignParams(params_dict):
 
 
 def GetParametersFromXML(action):
-	if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy' or action == "Build_Cluster_Image":
+	if action == 'Build_eNB' or action == 'Build_Image' or action == 'Build_Proxy' or action == "Build_Cluster_Image" or action == "Build_Run_Tests":
 		RAN.Build_eNB_args=test.findtext('Build_eNB_args')
 		CONTAINERS.imageKind=test.findtext('kind')
 		forced_workspace_cleanup = test.findtext('forced_workspace_cleanup')
@@ -745,142 +746,157 @@ elif re.match('^TesteNB$', mode, re.IGNORECASE) or re.match('^TestUE$', mode, re
 					continue
 				CiTestObj.ShowTestID()
 				GetParametersFromXML(action)
-				if action == 'Build_eNB':
-					RAN.BuildeNB(HTML)
-				elif action == 'WaitEndBuild_eNB':
-					RAN.WaitBuildeNBisFinished(HTML)
-				elif action == 'Custom_Command':
-					RAN.CustomCommand(HTML)
-					if RAN.prematureExit:
-						CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Initialize_eNB':
-					RAN.InitializeeNB(HTML, EPC)
-					if RAN.prematureExit:
-						CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Terminate_eNB':
-					RAN.TerminateeNB(HTML, EPC)
-				elif action == 'Initialize_UE':
-					CiTestObj.InitializeUE(HTML)
-				elif action == 'Terminate_UE':
-					CiTestObj.TerminateUE(HTML)
-				elif action == 'Attach_UE':
-					CiTestObj.AttachUE(HTML, RAN, EPC, CONTAINERS)
-				elif action == 'Detach_UE':
-					CiTestObj.DetachUE(HTML)
-				elif action == 'DataDisable_UE':
-					CiTestObj.DataDisableUE(HTML)
-				elif action == 'DataEnable_UE':
-					CiTestObj.DataEnableUE(HTML)
-				elif action == 'CheckStatusUE':
-					CiTestObj.CheckStatusUE(HTML)
-				elif action == 'Build_OAI_UE':
-					CiTestObj.BuildOAIUE(HTML)
-				elif action == 'Initialize_OAI_UE':
-					CiTestObj.InitializeOAIUE(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Terminate_OAI_UE':
-					CiTestObj.TerminateOAIUE(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Ping':
-					CiTestObj.Ping(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Iperf':
-					CiTestObj.Iperf(HTML,RAN,EPC,CONTAINERS)
-				elif action == 'Initialize_HSS':
-					EPC.InitializeHSS(HTML)
-				elif action == 'Terminate_HSS':
-					EPC.TerminateHSS(HTML)
-				elif action == 'Initialize_MME':
-					EPC.InitializeMME(HTML)
-				elif action == 'Terminate_MME':
-					EPC.TerminateMME(HTML)
-				elif action == 'Initialize_SPGW':
-					EPC.InitializeSPGW(HTML)
-				elif action == 'Terminate_SPGW':
-					EPC.TerminateSPGW(HTML)
-				elif action == 'Initialize_5GCN':
-					EPC.Initialize5GCN(HTML)
-				elif action == 'Terminate_5GCN':
-					EPC.Terminate5GCN(HTML)
-				elif action == 'Deploy_EPC':
-					EPC.DeployEpc(HTML)
-				elif action == 'Undeploy_EPC':
-					EPC.UndeployEpc(HTML)
-				elif action == 'IdleSleep':
-					CiTestObj.IdleSleep(HTML)
-				elif action == 'Perform_X2_Handover':
-					CiTestObj.Perform_X2_Handover(HTML,RAN,EPC)
-				elif action == 'Build_PhySim':
-					HTML=ldpc.Build_PhySim(HTML,CONST)
-					if ldpc.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'Run_LDPCTest':
-					HTML=ldpc.Run_LDPCTest(HTML,CONST,id)
-					if ldpc.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'Run_LDPCt1Test':
-					HTML=ldpc.Run_LDPCt1Test(HTML,CONST,id)
-					if ldpc.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'Run_NRulsimTest':
-					HTML=ldpc.Run_NRulsimTest(HTML,CONST,id)
-					if ldpc.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'Pull_Cluster_Image':
-					if not CLUSTER.PullClusterImage(HTML,RAN):
-						RAN.prematureExit = True
-				elif action == 'Build_Cluster_Image':
-					if not CLUSTER.BuildClusterImage(HTML):
-						RAN.prematureExit = True
-				elif action == 'Build_Image':
-					CONTAINERS.BuildImage(HTML)
-				elif action == 'Build_Proxy':
-					CONTAINERS.BuildProxy(HTML)
-				elif action == 'Push_Local_Registry':
-					success = CONTAINERS.Push_Image_to_Local_Registry(HTML)
-					if not success:
-						RAN.prematureExit = True
-				elif action == 'Pull_Local_Registry':
-					success = CONTAINERS.Pull_Image_from_Local_Registry(HTML)
-					if not success:
-						RAN.prematureExit = True
-				elif action == 'Clean_Test_Server_Images':
-					success = CONTAINERS.Clean_Test_Server_Images(HTML)
-					if not success:
-						RAN.prematureExit = True
-				elif action == 'Deploy_Object':
-					CONTAINERS.DeployObject(HTML, EPC)
-					if CONTAINERS.exitStatus==1:
-						CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
-						RAN.prematureExit = True
-				elif action == 'Undeploy_Object':
-					CONTAINERS.UndeployObject(HTML, RAN)
-					if CONTAINERS.exitStatus == 1:
-						CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
-						RAN.prematureExit = True
-				elif action == 'Cppcheck_Analysis':
-					SCA.CppCheckAnalysis(HTML)
-				elif action == 'LicenceAndFormattingCheck':
-					ret = SCA.LicenceAndFormattingCheck(HTML)
-					if ret != 0:
-						RAN.prematureExit = True
-				elif action == 'Deploy_Run_PhySim':
-					PHYSIM.Deploy_PhySim(HTML, RAN)
-				elif action == 'DeployGenObject':
-					CONTAINERS.DeployGenObject(HTML, RAN, CiTestObj)
-					if CONTAINERS.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'UndeployGenObject':
-					CONTAINERS.UndeployGenObject(HTML, RAN, CiTestObj)
-					if CONTAINERS.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'IperfFromContainer':
-					CONTAINERS.IperfFromContainer(HTML, RAN, CiTestObj)
-					if CONTAINERS.exitStatus==1:
-						RAN.prematureExit = True
-				elif action == 'StatsFromGenObject':
-					CONTAINERS.StatsFromGenObject(HTML)
-				elif action == 'Push_Images_To_Test_Servers':
-					logging.debug('To be implemented')
-				else:
-					sys.exit('Invalid class (action) from xml')
+				try:
+					if action == 'Build_eNB':
+						RAN.BuildeNB(HTML)
+					elif action == 'WaitEndBuild_eNB':
+						RAN.WaitBuildeNBisFinished(HTML)
+					elif action == 'Custom_Command':
+						RAN.CustomCommand(HTML)
+						if RAN.prematureExit:
+							CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Initialize_eNB':
+						RAN.InitializeeNB(HTML, EPC)
+						if RAN.prematureExit:
+							CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Terminate_eNB':
+						RAN.TerminateeNB(HTML, EPC)
+					elif action == 'Initialize_UE':
+						CiTestObj.InitializeUE(HTML)
+					elif action == 'Terminate_UE':
+						CiTestObj.TerminateUE(HTML)
+					elif action == 'Attach_UE':
+						CiTestObj.AttachUE(HTML, RAN, EPC, CONTAINERS)
+					elif action == 'Detach_UE':
+						CiTestObj.DetachUE(HTML)
+					elif action == 'DataDisable_UE':
+						CiTestObj.DataDisableUE(HTML)
+					elif action == 'DataEnable_UE':
+						CiTestObj.DataEnableUE(HTML)
+					elif action == 'CheckStatusUE':
+						CiTestObj.CheckStatusUE(HTML)
+					elif action == 'Build_OAI_UE':
+						CiTestObj.BuildOAIUE(HTML)
+					elif action == 'Initialize_OAI_UE':
+						CiTestObj.InitializeOAIUE(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Terminate_OAI_UE':
+						CiTestObj.TerminateOAIUE(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Ping':
+						CiTestObj.Ping(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Iperf':
+						CiTestObj.Iperf(HTML,RAN,EPC,CONTAINERS)
+					elif action == 'Initialize_HSS':
+						EPC.InitializeHSS(HTML)
+					elif action == 'Terminate_HSS':
+						EPC.TerminateHSS(HTML)
+					elif action == 'Initialize_MME':
+						EPC.InitializeMME(HTML)
+					elif action == 'Terminate_MME':
+						EPC.TerminateMME(HTML)
+					elif action == 'Initialize_SPGW':
+						EPC.InitializeSPGW(HTML)
+					elif action == 'Terminate_SPGW':
+						EPC.TerminateSPGW(HTML)
+					elif action == 'Initialize_5GCN':
+						EPC.Initialize5GCN(HTML)
+					elif action == 'Terminate_5GCN':
+						EPC.Terminate5GCN(HTML)
+					elif action == 'Deploy_EPC':
+						EPC.DeployEpc(HTML)
+					elif action == 'Undeploy_EPC':
+						EPC.UndeployEpc(HTML)
+					elif action == 'IdleSleep':
+						CiTestObj.IdleSleep(HTML)
+					elif action == 'Perform_X2_Handover':
+						CiTestObj.Perform_X2_Handover(HTML,RAN,EPC)
+					elif action == 'Build_PhySim':
+						HTML=ldpc.Build_PhySim(HTML,CONST)
+						if ldpc.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'Run_LDPCTest':
+						HTML=ldpc.Run_LDPCTest(HTML,CONST,id)
+						if ldpc.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'Run_LDPCt1Test':
+						HTML=ldpc.Run_LDPCt1Test(HTML,CONST,id)
+						if ldpc.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'Run_NRulsimTest':
+						HTML=ldpc.Run_NRulsimTest(HTML,CONST,id)
+						if ldpc.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'Pull_Cluster_Image':
+						if not CLUSTER.PullClusterImage(HTML,RAN):
+							RAN.prematureExit = True
+					elif action == 'Build_Cluster_Image':
+						if not CLUSTER.BuildClusterImage(HTML):
+							RAN.prematureExit = True
+					elif action == 'Build_Image':
+						success = CONTAINERS.BuildImage(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Build_Run_Tests':
+						success = CONTAINERS.BuildRunTests(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Build_Proxy':
+						success = CONTAINERS.BuildProxy(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Push_Local_Registry':
+						success = CONTAINERS.Push_Image_to_Local_Registry(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Pull_Local_Registry':
+						success = CONTAINERS.Pull_Image_from_Local_Registry(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Clean_Test_Server_Images':
+						success = CONTAINERS.Clean_Test_Server_Images(HTML)
+						if not success:
+							RAN.prematureExit = True
+					elif action == 'Deploy_Object':
+						CONTAINERS.DeployObject(HTML, EPC)
+						if CONTAINERS.exitStatus==1:
+							CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
+							RAN.prematureExit = True
+					elif action == 'Undeploy_Object':
+						CONTAINERS.UndeployObject(HTML, RAN)
+						if CONTAINERS.exitStatus == 1:
+							CiTestObj.AutoTerminateeNB(HTML,RAN,EPC,CONTAINERS)
+							RAN.prematureExit = True
+					elif action == 'Cppcheck_Analysis':
+						SCA.CppCheckAnalysis(HTML)
+					elif action == 'LicenceAndFormattingCheck':
+						ret = SCA.LicenceAndFormattingCheck(HTML)
+						if ret != 0:
+							RAN.prematureExit = True
+					elif action == 'Deploy_Run_PhySim':
+						PHYSIM.Deploy_PhySim(HTML, RAN)
+					elif action == 'DeployGenObject':
+						CONTAINERS.DeployGenObject(HTML, RAN, CiTestObj)
+						if CONTAINERS.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'UndeployGenObject':
+						CONTAINERS.UndeployGenObject(HTML, RAN, CiTestObj)
+						if CONTAINERS.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'IperfFromContainer':
+						CONTAINERS.IperfFromContainer(HTML, RAN, CiTestObj)
+						if CONTAINERS.exitStatus==1:
+							RAN.prematureExit = True
+					elif action == 'StatsFromGenObject':
+						CONTAINERS.StatsFromGenObject(HTML)
+					elif action == 'Push_Images_To_Test_Servers':
+						logging.debug('To be implemented')
+					else:
+						sys.exit('Invalid class (action) from xml')
+				except Exception as e:
+					s = traceback.format_exc()
+					logging.error(f'while running CI, an exception occurred:\n{s}')
+					HTML.CreateHtmlTestRowQueue("N/A", 'KO', [f"CI test code encountered an exception:\n{s}"])
+					RAN.prematureExit = True
+
 				if RAN.prematureExit:
 					if CiTestObj.testCase_id == CiTestObj.testMinStableId:
 						logging.warning('Scenario has reached minimal stability point')
diff --git a/ci-scripts/xml_class_list.yml b/ci-scripts/xml_class_list.yml
index 116ad769c1969fe56909f9baf91cfefaa0baedf1..645e5480bebaa6fa94bc04766f28bb01a0add8b9 100755
--- a/ci-scripts/xml_class_list.yml
+++ b/ci-scripts/xml_class_list.yml
@@ -34,6 +34,7 @@
   - IdleSleep
   - Perform_X2_Handover
   - Build_Image
+  - Build_Run_Tests
   - Deploy_Object
   - Undeploy_Object
   - Cppcheck_Analysis
diff --git a/ci-scripts/xml_files/container_build_run_tests.xml b/ci-scripts/xml_files/container_build_run_tests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..479bb20a5d70c5b6e43c86c740f93bdc94425fde
--- /dev/null
+++ b/ci-scripts/xml_files/container_build_run_tests.xml
@@ -0,0 +1,40 @@
+<!--
+
+ Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The OpenAirInterface Software Alliance licenses this file to You under
+ the OAI Public License, Version 1.1  (the "License"); you may not use this file
+ except in compliance with the License.
+ You may obtain a copy of the License at
+
+      http://www.openairinterface.org/?page_id=698
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ For more information about the OpenAirInterface (OAI) Software Alliance:
+      contact@openairinterface.org
+
+-->
+<testCaseList>
+	<htmlTabRef>build-run-test-tab</htmlTabRef>
+	<htmlTabName>Build and Run Unit Tests</htmlTabName>
+	<htmlTabIcon>wrench</htmlTabIcon>
+	<TestCaseRequestedList>
+ 030201
+	</TestCaseRequestedList>
+	<TestCaseExclusionList></TestCaseExclusionList>
+
+	<testCase id="030201">
+		<class>Build_Run_Tests</class>
+		<desc>Build and Run UnitTests</desc>
+		<kind>all</kind>
+		<eNB_instance>0</eNB_instance>
+		<eNB_serverId>0</eNB_serverId>
+	</testCase>
+
+</testCaseList>
diff --git a/common/utils/ds/byte_array.c b/common/utils/ds/byte_array.c
index c3281ffa275d9a3845a9ac318ab3ea602e46ddc3..78e1ef4e31d6310c07496aed70bddd1866524a2d 100644
--- a/common/utils/ds/byte_array.c
+++ b/common/utils/ds/byte_array.c
@@ -21,7 +21,6 @@
 
 #include "byte_array.h"
 
-#include "common/utils/assertions.h"
 #include <assert.h>
 #include <string.h>
 
@@ -29,7 +28,7 @@ byte_array_t copy_byte_array(byte_array_t src)
 {
   byte_array_t dst = {0};
   dst.buf = malloc(src.len);
-  AssertFatal(dst.buf != NULL, "Memory exhausted");
+  assert(dst.buf != NULL && "Memory exhausted");
   memcpy(dst.buf, src.buf, src.len);
   dst.len = src.len;
   return dst;
diff --git a/common/utils/minimal_stub.c b/common/utils/minimal_stub.c
index 64f2e3faa91d885d9175a919fd30d80b08b3bfc7..5660ed92f12554c3853d9ae5328a45f5d13106f5 100644
--- a/common/utils/minimal_stub.c
+++ b/common/utils/minimal_stub.c
@@ -4,6 +4,9 @@
 int T_stdout;
 #endif
 
+struct configmodule_interface_s;
+struct configmodule_interface_s *uniqCfg = NULL;
+
 void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
 {
   if (assert) {
diff --git a/common/utils/nr/nr_common.c b/common/utils/nr/nr_common.c
index 24e04f833aed40070d7887f045fe8bf4cb2cf902..73f4f8924115352a733f17b1377f6e43775c346c 100644
--- a/common/utils/nr/nr_common.c
+++ b/common/utils/nr/nr_common.c
@@ -865,3 +865,44 @@ void nr_est_delay(int ofdm_symbol_size, const c16_t *ls_est, c16_t *ch_estimates
   delay->delay_max_val = max_val;
   delay->est_delay = max_pos - sync_pos;
 }
+
+void nr_timer_start(NR_timer_t *timer)
+{
+  timer->active = true;
+  timer->counter = 0;
+}
+
+void nr_timer_stop(NR_timer_t *timer)
+{
+  timer->active = false;
+  timer->counter = 0;
+}
+
+bool is_nr_timer_active(NR_timer_t timer)
+{
+  return timer.active;
+}
+
+bool nr_timer_tick(NR_timer_t *timer)
+{
+  bool expired = false;
+  if (timer->active) {
+    timer->counter += timer->step;
+    expired = nr_timer_expired(*timer);
+    if (expired)
+      timer->active = false;
+  }
+  return expired;
+}
+
+bool nr_timer_expired(NR_timer_t timer)
+{
+  return (timer.counter >= timer.target);
+}
+
+void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step)
+{
+  timer->target = target;
+  timer->step = step;
+  nr_timer_stop(timer);
+}
diff --git a/common/utils/nr/nr_common.h b/common/utils/nr/nr_common.h
index 3cc3844cc4cbd7c1b67125a36a4be7488c8a912a..671f232928f56e120d7b1277ba0c68535889dd76 100644
--- a/common/utils/nr/nr_common.h
+++ b/common/utils/nr/nr_common.h
@@ -116,6 +116,49 @@ typedef struct {
   int delay_max_val;
 } delay_t;
 
+typedef struct {
+  bool active;
+  uint32_t counter;
+  uint32_t target;
+  uint32_t step;
+} NR_timer_t;
+
+/**
+ * @brief To start a timer
+ * @param timer Timer to be started
+ */
+void nr_timer_start(NR_timer_t *timer);
+/**
+ * @brief To stop a timer
+ * @param timer Timer to stopped
+ */
+void nr_timer_stop(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
+ * @return Indication if the timer is expired or not
+ */
+bool nr_timer_tick(NR_timer_t *timer);
+/**
+ * @brief To setup a timer
+ * @param timer Timer to setup
+ * @param target Target value for timer (when reached, timer is considered expired)
+ * @param step Amount of units to add to timer counter every tick
+ */
+void nr_timer_setup(NR_timer_t *timer, const uint32_t target, const uint32_t step);
+/**
+ * @brief To check if a timer is expired
+ * @param timer Timer to be checked
+ * @return Indication if the timer is expired or not
+ */
+bool nr_timer_expired(NR_timer_t timer);
+/**
+ * @brief To check if a timer is active
+ * @param timer Timer to be checked
+ * @return Indication if the timer is active or not
+ */
+bool is_nr_timer_active(NR_timer_t timer);
+
 extern const nr_bandentry_t nr_bandtable[];
 
 static inline int get_num_dmrs(uint16_t dmrs_mask ) {
diff --git a/common/utils/time_meas.h b/common/utils/time_meas.h
index 0735597633c82420539cc58180d29cd4ef5c4cbc..f791b485d1aabe2b2d4410ec0f98f4d5185a3a60 100644
--- a/common/utils/time_meas.h
+++ b/common/utils/time_meas.h
@@ -218,4 +218,10 @@ time_stats_t *register_meas(char *name);
 void send_meas(time_stats_t *ts, int msgid);
 void end_meas(void);
 
+#define timeIt(a)                                           \
+  {                                                         \
+    uint64_t deb = rdtsc_oai();                             \
+    a;                                                      \
+    LOG_W(UTIL, #a ": %llu\n", (rdtsc_oai() - deb) / 3000); \
+  }
 #endif
diff --git a/doc/BUILD.md b/doc/BUILD.md
index 87b6dcca8900221cf0d14ac5e3ff1bc9af1d9b8e..1cc9a688c5d8daa978bed8037e92fa951f461447 100644
--- a/doc/BUILD.md
+++ b/doc/BUILD.md
@@ -63,6 +63,8 @@ Calling the `build_oai` script with the `-h` option gives the list of all availa
 - `--ninja` is to use the `ninja` build tool, which speeds up compilation.
 - `-c` is to clean the workspace and force a complete rebuild.
 
+`build_oai` also provides various options to enable runtime error checkers, i.e. sanitizers in order to find various types of bugs in the codebase and eventually enhance the stability of the OAI softmodems. Refer to [sanitizers.md](./dev_tools/sanitizers.md) for more details.
+
 ## Installing dependencies
 
 Install all dependencies by issuing the `-I` option. To install furthermore libraries for optional libraries, use the `--install-optional-packages` option. The `-I` option will also install dependencies for an SDR when paired with `-w`. For instance, in order to install all dependencies and the ones for USRP, run:
diff --git a/doc/E1-design.md b/doc/E1-design.md
index 983013dce740346bc9bab9e0d5751297b472e85a..6939e3867e3d0d722b712ace237f51f24152d530 100644
--- a/doc/E1-design.md
+++ b/doc/E1-design.md
@@ -17,17 +17,22 @@ connection setup only in split-mode, the rest is the same for CU):
 sequenceDiagram
   participant c as CUCP
   participant u as CUUP
+
+  Note over c,u: E1 Setup Procedure
   u->c: SCTP connection setup (in split mode)
-  u->>c: E1AP Setup Request
+  u->>c: E1 Setup Request
   Note over c: Execute rrc_gNB_process_e1_setup_req()
-  c->>u: E1AP Setup Response
+  c->>u: E1 Setup Response
+  c-->>u: E1 Setup Failure
 
+  Note over c,u: E1 Bearer Context Setup Procedure
   Note over c: Receives PDU session setup request from AMF
   c->>u: Bearer Context Setup Request
   Note over u: Execute e1_bearer_context_setup()<br/>Configure DRBs and create GTP Tunnels for F1-U and N3
   u->>c: Bearer Context Setup Response
   Note over c: Execute rrc_gNB_process_e1_setup_req()<br/>Sends F1-U UL TNL info to DU and receives DL TNL info
 
+  Note over c,u: E1 Bearer Context Modification (CU-CP Initiated) Procedure
   c->>u: Bearer Context Modification Request
   Note over u: Execute e1_bearer_context_modif()<br/>Updates GTP Tunnels with received info
   u->>c: Bearer Context Modification Response
@@ -40,19 +45,63 @@ sequenceDiagram
   Note over c: Execute rrc_gNB_process_e1_bearer_context_release_cplt()
 ```
 
-The files that implement the callback towards these handlers are in
-- `cucp_cuup_direct.c`: integrated CU (for CP=>UP messages)
-- `cucp_cuup_e1ap.c`: E1 split mode (for CP=>UP messages)
-- `cuup_cucp_direct.c`: integrated CU (for UP=>CP messages)
-- `cuup_cucp_e1ap.c`: E1 split mode (for UP=>CP messages)
+The implementation of callbacks towards these handlers is distributed across the following file, depending on the operating mode:
+
+| Mode          | CP=>UP messages     |UP=>CP messages     |
+| --------------| --------------------|--------------------|
+| Integrated CU | `cucp_cuup_direct.c`|`cuup_cucp_direct.c`|
+| E1 Split      | `cucp_cuup_e1ap.c`  |`cuup_cucp_e1ap.c`  |
+
+As long as concerns E1 Interface Management Procedures, the code flow of request messages towards northbound looks like this:
+
+```mermaid
+sequenceDiagram
+  participant r as RRC
+  participant c as CUCP
+  participant u as CUUP
+
+  Note over u: E1AP_CUUP_task (SCTP Handler)
+  Note over u: ASN1 encoder
+  u->>c: e.g. E1 Setup Request (SCTP)
+  Note over c: E1AP_CUCP_task (SCTP Handler)
+  Note over c: ASN1 decoder
+  c->>r: E1AP_SETUP_REQ (ITTI)
+  Note over r: TASK_RRC_GNB (RRC Handler)
+  r->>c: E1AP_SETUP_RESP (ITTI)
+  Note over c: E1AP_CUCP_task (E1AP Callback)
+  Note over c: ASN1 encoder
+
+  c->>u: e.g. E1 Setup Response/Failure
+  Note over u: E1AP_CUUP_task (SCTP Handler)
+  Note over u: ASN1 decoder
+```
+
 
 # 2. Running the E1 Split
 
+The setup is assuming that all modules are running on the same machine. The user can refer to the [F1 design document](./F1-design.md) for local deployment of the DU.
+
 ## 2.1 Configuration File
 
-The gNB is started based on the node type that is specified in the configuration file. To start a gNB instance in CUCP or CUUP, the `tr_s_preference` should be set to "f1" and the config member `E1_INTERFACE` should be present in the config file. The `type` parameter within the `E1_INTERFACE` should be set to `cp`, and executable `nr-softmodem` should be used to run a CU-CP. The type should be `up` and executable `nr-cuup` should be used to run the CU-UP. Further, there are the parameters `ipv4_cucp` and `ipv4_cuup` to specify the IP addresses of the respective network functions.
+The gNB is started based on the node type that is specified in the configuration file. The following parameters must be configured accordingly.
+
+On either CUCP and CUUP:
+* The southbound transport preference `gNBs.[0].tr_s_preference` set to `f1`
+* config section `E1_INTERFACE` should be present
+
+On the CU-CP:
+* `type` parameter within the `E1_INTERFACE` should be set to `cp`
+
+On the CU-UP:
+* `type` parameter within the `E1_INTERFACE` should be set to `up`
+
+Executables:
+* executable `nr-softmodem` to run a CU-CP
+* executable `nr-cuup` to run the CU-UP
+
+In the `E1_INTERFACE` configuration section, the parameters `ipv4_cucp` and `ipv4_cuup` must be configured to specify the IP addresses of the respective network functions.
 
-For CUCP, a typical `E1_INTERFACE` config looks like
+For CUCP, a typical `E1_INTERFACE` config looks like:
 ```
 E1_INTERFACE =
 (
@@ -64,7 +113,7 @@ E1_INTERFACE =
 )
 ```
 
-For CUUP, it is
+For CUUP, it is:
 ```
 E1_INTERFACE =
 (
@@ -77,7 +126,7 @@ E1_INTERFACE =
 ```
 One could take an existing CU configuration file and add the above parameters to run the gNB as CUCP or CUUP.
 
-The CUUP uses the IP address specified in `local_s_address` for F1-U and `GNB_IPV4_ADDRESS_FOR_NGU` for N3 links. Note that `local_s_address` is under `gNBs` and `GNB_IPV4_ADDRESS_FOR_NGU` is part of the `NETWORK_INTERFACES` config member.  
+The CUUP uses the IP address specified in `gNBs.[0].local_s_address` for F1-U and `GNB_IPV4_ADDRESS_FOR_NGU` for N3 links. Note that `local_s_address` is under `gNBs` and `GNB_IPV4_ADDRESS_FOR_NGU` is part of the `NETWORK_INTERFACES` config member.
 
 Alternatively, you can use the config files `ci-scripts/conf_files/gnb-cucp.sa.f1.conf` and `ci-scripts/conf_files/gnb-cuup.sa.f1.conf`.
 
diff --git a/doc/F1-design.md b/doc/F1-design.md
index ee45128ebb37759c6fc0d2a6b314132f42a2587f..115ad916d26b8c54e428072b470c4c12a3eeea8a 100644
--- a/doc/F1-design.md
+++ b/doc/F1-design.md
@@ -20,15 +20,15 @@ The F1 interface is the functional split of 3GPP between the CU (centralized
 unit: PDCP, RRC, SDAP) and the DU (distributed unit: RLC, MAC, PHY). It is
 standardized in TS 38.470 - 38.473 for 5G NR. No equivalent for 4G exists.
 
-We assume that each DU handles only one cell.  Multiple DUs connected to one CU
+We assume that each DU handles only one cell. Multiple DUs connected to one CU
 are supported. Mobility over F1 is not yet supported.
 
 # Control plane status (F1-C)
 
 ## Implementation Status
 
-Note that OAI uses F1 "internally". That means, that even if you run a
-monolithic gNB, the internal information exchange uses F1. You can therefore
+Note that OAI uses F1 "internally". That means, that even **if you run a
+monolithic gNB, the internal information exchange uses F1**. You can therefore
 expect that everything working in a monolithic deployment should also work in
 F1.  The current implementation is based on R16.3.
 
@@ -118,13 +118,13 @@ see [this `docker-compose` file](../ci-scripts/yaml_files/5g_f1_rfsimulator/dock
 
 The rules to decide if a config triggers a start of a DU, CU, or monolithic
 gNB, are, in order:
-1. If the `MACRLCs` section lists `f1` as northbound transport preference
+1. If the `MACRLCs` section lists `f1` as **northbound transport preference**
    (`tr_n_preference`), it is a DU.
-2. If the `gNBs` section lists `f1` as a southound transport preference
+2. If the `gNBs` section lists `f1` as a **southound transport preference**
    (`tr_s_preference`), it is a CU.
 3. It is a (monolithic) gNB.
 
-## Configuration of F1 IP/port information
+## Local network deployment of F1
 
 For a local deployment, you should update the following fields.
 We assume that the CU will bind on `192.168.70.129` towards the core,
diff --git a/doc/FEATURE_SET.md b/doc/FEATURE_SET.md
index 831561e025e12b6c5ccf5c8f5dd2ee0d5dca340f..9933ba3107934f776b35c3732c9066bf7f970552 100644
--- a/doc/FEATURE_SET.md
+++ b/doc/FEATURE_SET.md
@@ -191,22 +191,30 @@ Furthermore, the gNB and UE support
 ## gNB F1AP
 
 - Integration of F1AP messages and procedures for the control plane exchanges between the CU and DU entities according to 38.473 Rel. 16
-  - F1 Setup request/response
+  - F1 Setup request/response/failure
   - F1 DL/UL RRC message transfer
   - F1 Initial UL RRC message transfer
   - F1 UE Context setup request/response
   - F1 UE Context modification request/response
-  - F1 UE Context release
+  - F1 UE Context modification required
+  - F1 UE Context release req/cmd/complete
   - F1 gNB CU configuration update
 - Interface with RRC
 - Interface with gtp-u (tunnel creation/handling for F1-U interface)
 
 ## gNB E1AP
 
-- Integration of E1AP messages and procedures for exchange between CU-CP and CU-UP according to 38.463 Rel. 16
-  - gNB-CU-UP E1 Setup Setup request/response
-  - E1 Bearer Context Setup
+- Integration of E1AP messages and procedures for exchange between CU-CP and CU-UP according to TS 38.463 Rel. 16
+  - E1 Setup (gNB-CU-UP initiated)
+      - E1 Setup Request
+      - E1 Setup Response
+      - E1 Setup Failure
+  - E1 Bearer Context Setup (gNB-CU-CP initiated)
+      - E1 Bearer Context Setup Request
+      - E1 Bearer Context Setup Response
   - Bearer Context Modification (gNB-CU-CP initiated)
+      - E1 Bearer Context Modification Request
+      - E1 Bearer Context Modification Response
 - Interface with RRC and PDCP
 
 ## gNB GTP-U
diff --git a/doc/LDPC_T2_OFFLOAD_SETUP.md b/doc/LDPC_T2_OFFLOAD_SETUP.md
index 485ad4c4a4cd9507e6c70aa05065d7939fd24c41..d6335ecbaf39af7a4d041a93cd6189377c7c833c 100644
--- a/doc/LDPC_T2_OFFLOAD_SETUP.md
+++ b/doc/LDPC_T2_OFFLOAD_SETUP.md
@@ -62,7 +62,7 @@ sudo python3 ~/dpdk-stable/usertools/dpdk-devbind.py --bind=vfio-pci 41:00.0
 Replace PCI address of the card *41:00.0* by address detected by *lspci | grep "Xilinx"* command
  - hugepages setup (10 x 1GB hugepages)
 ```
-sudo python3 ~/dpdk-stable/usertools/dpdk-hugepages.py -p 1G --setup 10G`
+sudo python3 ~/dpdk-stable/usertools/dpdk-hugepages.py -p 1G --setup 10G
 ```
 
 *Note: device binding and hugepages setup has to be done after every reboot of
@@ -144,7 +144,6 @@ sudo ./nr-softmodem --sa -O ../../../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa
 
 # Limitations
 ## AMD Xilinx T2 card
- - offload of the LDPC encoding implemented for MCS > 2, OAI CPU encoder is used for MCS =< 2
  - functionality of the LDPC encoding and decoding offload verified in OTA SISO setup with USRP N310 and Quectel RM500Q, blocking of the card reported for MIMO setup (2 layers)
 
 *Note: AMD Xilinx T1 Telco card is not supported anymore.*
diff --git a/doc/ORAN_FHI7.2_Tutorial.md b/doc/ORAN_FHI7.2_Tutorial.md
index a6d0ee6f6d1973ae11cdd030cd215d4ccd31ade8..ccd0c868a20e0f33e3fdfe49a936c1930c185e99 100644
--- a/doc/ORAN_FHI7.2_Tutorial.md
+++ b/doc/ORAN_FHI7.2_Tutorial.md
@@ -442,9 +442,9 @@ We are evaluating if we can share RU configuration steps.
 # Configure OAI gNB
 
 Sample configuration files for OAI gNB, specific to the manufacturer of the radio unit, are available at:
-1. LITE-ON RU: [`gnb.sa.band78.273prb.fhi72.4x4-liteon.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf) (band n78, 273 PRBs, 3.5GHz center freq, 4x4 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2x2 DL MIMO, UL SISO)
-2. Benetel 650 RU: [`gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf) (band n78, 273 PRBs, 3.5GHz center freq, 4x2 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2x2 DL MIMO, UL SISO)
-3. VVDN RU: [`gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf) (band n77, 273 PRBs, 4.0GHz center freq, 4x4 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2x2 DL MIMO, UL SISO)
+1. LITE-ON RU: [`gnb.sa.band78.273prb.fhi72.4x4-liteon.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf) (band n78, 273 PRBs, 3.5GHz center freq, 4x4 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2-layer DL MIMO, UL SISO)
+2. Benetel 650 RU: [`gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf) (band n78, 273 PRBs, 3.5GHz center freq, 4x2 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2-layer DL MIMO, UL SISO)
+3. VVDN RU: [`gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf`](../targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf) (band n77, 273 PRBs, 4.0GHz center freq, 4x4 antenna configuration with 9 bit I/Q samples (compressed) for PUSCH/PDSCH/PRACH, 2-layer DL MIMO, UL SISO)
 
 ## Adapt the OAI-gNB configuration file to your system/workspace
 
diff --git a/doc/README.md b/doc/README.md
index 0e6c78fd63bd7bce66be079eecf89db1ca812f96..9ff7079f8bc0f444656ed760b7e97ef3456e36ba 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -21,6 +21,7 @@
 - [BUILD.md](./BUILD.md): how to build the sources
 - [cross-compile.md](./cross-compile.md): how to cross-compile OAI for ARM
 - [clang-format.md](./clang-format.md): how to format the code
+- [sanitizers.md](./dev_tools/sanitizers.md): how to run with ASan/UBSan/MemSAN/TSan
 - [environment-variables.md](./environment-variables.md): the environment variables used by OAI
 
 There is some general information in the [OpenAirInterface Gitlab Wiki](https://gitlab.eurecom.fr/oai/openairinterface5g/-/wikis/home)
diff --git a/doc/TESTBenches.md b/doc/TESTBenches.md
index 45f1353dfe3c725b4f970e9568d862e775db767c..40f410e9c575a05072a2115c2c2f676b1259f1a4 100644
--- a/doc/TESTBenches.md
+++ b/doc/TESTBenches.md
@@ -109,6 +109,7 @@ information on how the images are built.
   - build image from `Dockerfile.clang.rhel9` (compilation only, artifacts not used currently)
 - [RAN-Ubuntu18-Image-Builder](https://jenkins-oai.eurecom.fr/job/RAN-Ubuntu18-Image-Builder/)
   ~BUILD-ONLY ~4G-LTE ~5G-NR
+  - run formatting check from `ci-scripts/docker/Dockerfile.formatting.bionic`
   - obelix: Ubuntu 20 image build using docker (Note: builds U20 images while pipeline is named U18!)
   - base image from `Dockerfile.base.ubuntu20`
   - build image from `Dockerfile.build.ubuntu20`, followed by
@@ -118,6 +119,7 @@ information on how the images are built.
     - target image from `Dockerfile.nrUE.ubuntu20`
     - target image from `Dockerfile.lteUE.ubuntu20`
     - target image from `Dockerfile.lteRU.ubuntu20`
+  - build unit tests from `ci-scripts/docker/Dockerfile.unittest.ubuntu20`, and run them
 
 #### Image Test pipelines
 
diff --git a/doc/dev_tools/sanitizers.md b/doc/dev_tools/sanitizers.md
new file mode 100644
index 0000000000000000000000000000000000000000..6e6376ee08fd2d252ef2d71d71dd186d03877e1d
--- /dev/null
+++ b/doc/dev_tools/sanitizers.md
@@ -0,0 +1,63 @@
+<table style="border-collapse: collapse; border: none;">
+  <tr style="border-collapse: collapse; border: none;">
+    <td style="border-collapse: collapse; border: none;">
+      <a href="http://www.openairinterface.org/">
+         <img src="./../images/oai_final_logo.png" alt="" border=3 height=50 width=150>
+         </img>
+      </a>
+    </td>
+    <td style="border-collapse: collapse; border: none; vertical-align: center;">
+      <b><font size = "5">OAI Build Procedures</font></b>
+    </td>
+  </tr>
+</table>
+
+[[_TOC_]]
+
+# Sanitize options in `build_oai`
+
+The `build_oai` script provides various [Instrumentation Options](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html) to add run-time instrumentation to the code and enable runtime error checkers, i.e. sanitizers, in order to help find various types of bugs in the codebase and eventually enhance the stability of the OAI softmodems.  The following sanitizers can be enabled using different build options:
+
+## Address Sanitizer (ASAN)
+[Address Sanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) is enabled using the `--sanitize-address` option or its shorthand `-fsanitize=address`. It serves as a fast memory error detector and helps detect issues like out-of-bounds accesses, use-after-free bugs, and memory leaks.
+
+### Run OAI Softmodem with ASAN on
+
+It is necessary to add the envinronment variable `LD_LIBRARY_PATH` to the run command, e.g.:
+```
+cd cmake_targets/ran_build/build
+sudo LD_LIBRARY_PATH=. ./nr-softmodem ...
+```
+
+## Undefined Behavior Sanitizer (UBSAN)
+[Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html) (UBSAN) is a runtime undefined behavior checker. It uses compile-time instrumentation to catch undefined behavior by inserting code that performs specific checks before operations that may cause it. UBSAN can be activated with the `--sanitize-undefined` option or `-fsanitize=undefined`.
+
+UBSAN offers a range of suboptions that enable precise checks for various types of undefined behavior at runtime. These suboptions can be set by tweaking the [CMakeLists.txt](../../CMakeLists.txt) file. Here is an overview of some key suboptions:
+
+* `-fsanitize=shift`: Enables checks for the result of shift operations, with suboptions for base and exponent.
+* `-fsanitize=integer-divide-by-zero`: Detects integer division by zero.
+* `-fsanitize=null`: Enables pointer checking, issuing an error message when dereferencing a NULL pointer or binding a reference to a NULL pointer.
+* `-fsanitize=signed-integer-overflow`: Detects signed integer overflow.
+* `-fsanitize=bounds`: Instruments array bounds, detecting various out-of-bounds accesses.
+* `-fsanitize=alignment`: Checks the alignment of pointers when dereferenced or when a reference is bound to an insufficiently aligned target.
+* `-fsanitize=object-size`: Checks out-of-bounds pointer accesses.
+* `-fsanitize=float-divide-by-zero`: Detects floating-point division by zero.
+
+## Memory Sanitizer
+To enable [Memory Sanitizer](https://clang.llvm.org/docs/MemorySanitizer.html), use the `--sanitize-memory` option or `-fsanitize=memory`. It requires clang and is incompatible with ASAN and UBSAN. Building with this option helps catch issues related to uninitialized memory reads.
+
+To build with Memory Sanitizer, use the following command:
+```
+CC=/usr/bin/clang CXX=/usr/bin/clang++ ./build_oai ... --sanitize-memory
+```
+
+## Thread Sanitizer
+[Thread Sanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) can be activated using the `--sanitize-thread` option or `-fsanitize=thread`. This sanitizer helps identify data races and other threading-related issues in the code.
+
+# Summary of Sanitizer Options
+
+- `--sanitize`: Shortcut for using both ASAN and UBSAN.
+- `--sanitize-address` or `-fsanitize=address`: Enable ASAN on all targets.
+- `--sanitize-undefined` or `-fsanitize=undefined`: Enable UBSAN on all targets.
+- `--sanitize-memory` or `-fsanitize=memory`: Enable Memory Sanitizer on all targets (requires clang).
+- `--sanitize-thread` or `-fsanitize=thread`: Enable Thread Sanitizer on all targets.
diff --git a/executables/nr-softmodem.c b/executables/nr-softmodem.c
index ad24e557557e35649c7c97f0e3d58950c75bef01..2a8ebabef2d7a073ee721482e8bcb195a8deab87 100644
--- a/executables/nr-softmodem.c
+++ b/executables/nr-softmodem.c
@@ -400,7 +400,7 @@ static int create_gNB_tasks(ngran_node_t node_type, configmodule_interface_t *cf
       }
     }
 
-    // If CU
+    // E1AP initialisation, whether the node is a CU or has integrated CU
     if (node_type == ngran_gNB_CU || node_type == ngran_gNB) {
       MessageDef *msg = RCconfig_NR_CU_E1(NULL);
       instance_t inst = 0;
diff --git a/executables/nr-ue.c b/executables/nr-ue.c
index 6e668c8901884093a2040c9c2e339ddde156396d..f30bebbbfbf698e82aad7f7c9ed9f50df814b6a0 100644
--- a/executables/nr-ue.c
+++ b/executables/nr-ue.c
@@ -310,16 +310,13 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
 
     int CC_id = 0;
     uint8_t gNB_id = 0;
-    nr_uplink_indication_t ul_info;
     int slots_per_frame = 20; //30 kHZ subcarrier spacing
     int slot_ahead = 2; // TODO: Make this dynamic
-    ul_info.cc_id = CC_id;
-    ul_info.gNB_index = gNB_id;
-    ul_info.module_id = mod_id;
-    ul_info.frame_rx = frame;
-    ul_info.slot_rx = slot;
-    ul_info.slot_tx = (slot + slot_ahead) % slots_per_frame;
-    ul_info.frame_tx = (ul_info.slot_rx + slot_ahead >= slots_per_frame) ? ul_info.frame_rx + 1 : ul_info.frame_rx;
+    nr_uplink_indication_t ul_info = {.cc_id = CC_id,
+                                      .gNB_index = gNB_id,
+                                      .module_id = mod_id,
+                                      .slot = (slot + slot_ahead) % slots_per_frame,
+                                      .frame = (slot + slot_ahead >= slots_per_frame) ? (frame + 1) % 1024 : frame};
 
     if (pthread_mutex_lock(&mac->mutex_dl_info)) abort();
 
@@ -330,8 +327,7 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
       free_and_zero(ch_info);
     }
 
-    if (is_nr_DL_slot(mac->tdd_UL_DL_ConfigurationCommon,
-                      ul_info.slot_rx)) {
+    if (is_nr_DL_slot(mac->tdd_UL_DL_ConfigurationCommon, slot)) {
       memset(&mac->dl_info, 0, sizeof(mac->dl_info));
       mac->dl_info.cc_id = CC_id;
       mac->dl_info.gNB_index = gNB_id;
@@ -345,9 +341,8 @@ static void *NRUE_phy_stub_standalone_pnf_task(void *arg)
 
     if (pthread_mutex_unlock(&mac->mutex_dl_info)) abort();
 
-    if (is_nr_UL_slot(mac->tdd_UL_DL_ConfigurationCommon,
-                      ul_info.slot_tx, mac->frame_type)) {
-      LOG_D(NR_MAC, "Slot %d. calling nr_ue_ul_ind()\n", ul_info.slot_tx);
+    if (is_nr_UL_slot(mac->tdd_UL_DL_ConfigurationCommon, ul_info.slot, mac->frame_type)) {
+      LOG_D(NR_MAC, "Slot %d. calling nr_ue_ul_ind()\n", ul_info.slot);
       nr_ue_ul_scheduler(&ul_info);
     }
     process_queued_nr_nfapi_msgs(mac, sfn_slot);
@@ -545,7 +540,12 @@ void processSlotTX(void *arg) {
   PHY_VARS_NR_UE    *UE   = rxtxD->UE;
   nr_phy_data_tx_t phy_data = {0};
 
-  LOG_D(PHY,"%d.%d => slot type %d\n", proc->frame_tx, proc->nr_slot_tx, proc->tx_slot_type);
+  LOG_D(PHY,
+        "SlotTx %d.%d => slot type %d, wait: %d \n",
+        proc->frame_tx,
+        proc->nr_slot_tx,
+        proc->tx_slot_type,
+        rxtxD->tx_wait_for_dlsch);
   if (proc->tx_slot_type == NR_UPLINK_SLOT || proc->tx_slot_type == NR_MIXED_SLOT){
     if (rxtxD->tx_wait_for_dlsch)
       LOG_D(PHY, "enter wait for tx, slot %d, nb events to wait %d; ", proc->nr_slot_tx, rxtxD->tx_wait_for_dlsch);
@@ -587,17 +587,12 @@ void processSlotTX(void *arg) {
     // [TODO] mapping right after NR initial sync
     if(UE->if_inst != NULL && UE->if_inst->ul_indication != NULL) {
       start_meas(&UE->ue_ul_indication_stats);
-      nr_uplink_indication_t ul_indication;
-      memset((void*)&ul_indication, 0, sizeof(ul_indication));
-
-      ul_indication.module_id = UE->Mod_id;
-      ul_indication.gNB_index = proc->gNB_id;
-      ul_indication.cc_id     = UE->CC_id;
-      ul_indication.frame_rx  = proc->frame_rx;
-      ul_indication.slot_rx   = proc->nr_slot_rx;
-      ul_indication.frame_tx  = proc->frame_tx;
-      ul_indication.slot_tx   = proc->nr_slot_tx;
-      ul_indication.phy_data      = &phy_data;
+      nr_uplink_indication_t ul_indication = {.module_id = UE->Mod_id,
+                                              .gNB_index = proc->gNB_id,
+                                              .cc_id = UE->CC_id,
+                                              .frame = proc->frame_tx,
+                                              .slot = proc->nr_slot_tx,
+                                              .phy_data = &phy_data};
 
       UE->if_inst->ul_indication(&ul_indication);
       stop_meas(&UE->ue_ul_indication_stats);
@@ -989,29 +984,8 @@ void init_NR_UE(int nb_inst, char *uecap_file, char *reconfig_file, char *rbconf
     NR_UE_MAC_INST_t *mac = get_mac_inst(i);
     AssertFatal((mac->if_module = nr_ue_if_module_init(i)) != NULL, "can not initialize IF module\n");
     if (!get_softmodem_params()->sa) {
-      init_nsa_message(&rrc_inst[i], reconfig_file, rbconfig_file);
-      // TODO why do we need noS1 configuration?
-      // temporarily moved here to understand why not using the one provided by gNB
-      nr_rlc_activate_srb0(i, NULL, send_srb0_rrc);
-      if (IS_SOFTMODEM_NOS1) {
-        // get default noS1 configuration
-        NR_RadioBearerConfig_t *rbconfig = NULL;
-        NR_RLC_BearerConfig_t *rlc_rbconfig = NULL;
-        fill_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig);
-
-        // set up PDCP, RLC, MAC
-        nr_pdcp_layer_init(false);
-        nr_pdcp_add_drbs(ENB_FLAG_NO, i, rbconfig->drb_ToAddModList, 0, NULL, NULL);
-        nr_rlc_add_drb(i, rbconfig->drb_ToAddModList->list.array[0]->drb_Identity, rlc_rbconfig);
-        struct NR_CellGroupConfig__rlc_BearerToAddModList rlc_toadd_list;
-        rlc_toadd_list.list.count = 1;
-        rlc_toadd_list.list.array = calloc(1, sizeof(NR_RLC_BearerConfig_t));
-        rlc_toadd_list.list.array[0] = rlc_rbconfig;
-        nr_rrc_mac_config_req_ue_logicalChannelBearer(0, &rlc_toadd_list, NULL);
-
-        // free memory
-        free_nr_noS1_bearer_config(&rbconfig, NULL);
-      }
+      init_nsa_message(rrc_inst, reconfig_file, rbconfig_file);
+      nr_rlc_activate_srb0(mac_inst->crnti, NULL, send_srb0_rrc);
     }
   }
 }
diff --git a/executables/nr-uesoftmodem.c b/executables/nr-uesoftmodem.c
index 6fe411c2531cee5d97c46638f4dece5330546d83..4e5e14089c2e03eb268e0a2f11b172393335481a 100644
--- a/executables/nr-uesoftmodem.c
+++ b/executables/nr-uesoftmodem.c
@@ -368,7 +368,8 @@ void init_openair0(void) {
   }
 }
 
-static void init_pdcp(int ue_id) {
+static void init_pdcp(int ue_id)
+{
   uint32_t pdcp_initmask = (!IS_SOFTMODEM_NOS1) ? LINK_ENB_PDCP_TO_GTPV1U_BIT : (LINK_ENB_PDCP_TO_GTPV1U_BIT | PDCP_USE_NETLINK_BIT | LINK_ENB_PDCP_TO_IP_DRIVER_BIT);
 
   /*if (IS_SOFTMODEM_RFSIM || (nfapi_getmode()==NFAPI_UE_STUB_PNF)) {
@@ -510,8 +511,6 @@ int main(int argc, char **argv)
     memset(PHY_vars_UE_g[0][CC_id], 0, sizeof(*PHY_vars_UE_g[0][CC_id]));
   }
 
-  init_NR_UE(NB_UE_INST, uecap_file, reconfig_file, rbconfig_file);
-
   int mode_offset = get_softmodem_params()->nsa ? NUMBER_OF_UE_MAX : 1;
   uint16_t node_number = get_softmodem_params()->node_number;
   ue_id_g = (node_number == 0) ? 0 : node_number - 2;
@@ -525,6 +524,8 @@ int main(int argc, char **argv)
     }
   }
 
+  init_NR_UE(NB_UE_INST, uecap_file, reconfig_file, rbconfig_file);
+
   if (get_softmodem_params()->emulate_l1) {
     RCconfig_nr_ue_macrlc();
     get_channel_model_mode(uniqCfg);
diff --git a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h
index 276f417fbb71533346ce9c2d1ca71aee60e35972..1094e82fa71ec377255e61ed0acf9b394672d08c 100644
--- a/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h
+++ b/nfapi/open-nFAPI/nfapi/public_inc/fapi_nr_ue_constants.h
@@ -69,4 +69,5 @@
 #define FAPI_NR_UL_CONFIG_TYPE_SRS   0x04
 #define FAPI_NR_UL_CONFIG_TYPES      0x04
 
+#define FAPI_NR_END 0xff
 #endif
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 70ef3d978faa2a4244f15a89ae202e9e60cf5924..dd8f3098baf644fabb00a7afe9032a47f9090b4d 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
@@ -168,7 +168,6 @@ typedef struct {
 
 typedef struct {
   uint16_t pdu_length;
-  uint16_t pdu_index;
   uint8_t* pdu;
 } fapi_nr_tx_request_body_t;
 
@@ -337,7 +336,7 @@ typedef struct
   uint16_t dmrs_ports;//DMRS ports. [TS38.212 7.3.1.1.2] provides description between DCI 0-1 content and DMRS ports. Bitmap occupying the 11 LSBs with: bit 0: antenna port 1000 bit 11: antenna port 1011 and for each bit 0: DMRS port not used 1: DMRS port used
   //Pusch Allocation in frequency domain [TS38.214, sec 6.1.2.2]
   uint8_t  resource_alloc;
-  uint8_t  rb_bitmap[36];//
+  uint8_t  rb_bitmap[36];
   uint16_t rb_start;
   uint16_t rb_size;
   uint8_t  vrb_to_prb_mapping;
@@ -358,6 +357,7 @@ typedef struct
   nfapi_nr_ue_ul_beamforming_t beamforming;
   //OAI specific
   int8_t absolute_delta_PUSCH;
+  fapi_nr_tx_request_body_t tx_request_body;
 } nfapi_nr_ue_pusch_pdu_t;
 
 typedef struct {
@@ -391,24 +391,25 @@ typedef struct {
 } fapi_nr_ul_config_srs_pdu;
 
 typedef struct {
-  uint8_t pdu_type;
+  int pdu_type;
   union {
     fapi_nr_ul_config_prach_pdu prach_config_pdu;
     fapi_nr_ul_config_pucch_pdu pucch_config_pdu;
     nfapi_nr_ue_pusch_pdu_t     pusch_config_pdu;
     fapi_nr_ul_config_srs_pdu   srs_config_pdu;
   };
+  pthread_mutex_t* lock;
+  int* privateNBpdus;
 } fapi_nr_ul_config_request_pdu_t;
 
 typedef struct {
-  uint16_t sfn;
-  uint16_t slot;
-  uint8_t number_pdus;
-  fapi_nr_ul_config_request_pdu_t ul_config_list[FAPI_NR_UL_CONFIG_LIST_NUM];
+  int frame;
+  int slot;
+  int number_pdus;
+  fapi_nr_ul_config_request_pdu_t ul_config_list[FAPI_NR_UL_CONFIG_LIST_NUM + 1]; // +1 to have space for iterator ending
   pthread_mutex_t mutex_ul_config;
 } fapi_nr_ul_config_request_t;
 
-
 typedef struct {
   uint16_t rnti;
   uint16_t BWPSize;
@@ -438,7 +439,9 @@ typedef enum{vrb_to_prb_mapping_non_interleaved = 0, vrb_to_prb_mapping_interlea
 typedef struct {
   uint16_t BWPSize;
   uint16_t BWPStart;
-  uint8_t SubcarrierSpacing;  
+  uint8_t SubcarrierSpacing;
+  uint8_t resource_alloc;
+  uint8_t rb_bitmap[36];
   uint16_t number_rbs;
   uint16_t start_rb;
   uint16_t number_symbols;
diff --git a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c
index 1f2163ca5e6bd1b8bdfdbe3685be040e0c917e81..dafdf286442877441a79398ae9b7e09c7d471cca 100644
--- a/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c
+++ b/openair1/PHY/CODING/nrLDPC_decoder/nrLDPC_decoder_offload.c
@@ -568,14 +568,14 @@ static void set_ldpc_enc_op(struct rte_bbdev_enc_op **ops,
 {
   // struct rte_bbdev_op_ldpc_enc *ldpc_enc = &ref_op->ldpc_enc;
   for (int i = 0; i < n; ++i) {
-    ops[i]->ldpc_enc.cb_params.e = 3 * p_offloadParams->E; // Fix mee: what is the correct size for "e" ???
+    ops[i]->ldpc_enc.cb_params.e = p_offloadParams->E;
     ops[i]->ldpc_enc.basegraph = p_offloadParams->BG;
     ops[i]->ldpc_enc.z_c = p_offloadParams->Z;
     ops[i]->ldpc_enc.q_m = p_offloadParams->Qm;
     ops[i]->ldpc_enc.n_filler = p_offloadParams->F;
     ops[i]->ldpc_enc.n_cb = p_offloadParams->n_cb;
     ops[i]->ldpc_enc.rv_index = p_offloadParams->rv;
-    ops[i]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_INTERLEAVER_BYPASS; // RTE_BBDEV_LDPC_RATE_MATCH;
+    ops[i]->ldpc_enc.op_flags = RTE_BBDEV_LDPC_RATE_MATCH;
     ops[i]->ldpc_enc.code_block_mode = 1;
     ops[i]->ldpc_enc.output = outputs[start_idx + i];
     ops[i]->ldpc_enc.input = inputs[start_idx + i];
@@ -613,7 +613,7 @@ static int retrieve_ldpc_enc_op(struct rte_bbdev_enc_op **ops, const uint16_t n,
   for (i = 0; i < n; ++i) {
     output = &ops[i]->ldpc_enc.output;
     m = output->data;
-    uint16_t data_len = min((384 * 68) / 8, rte_pktmbuf_data_len(m)); // fix me
+    uint16_t data_len = min((LDPC_MAX_CB_SIZE) / 8, rte_pktmbuf_data_len(m)); // fix me
     data = m->buf_addr;
     for (int byte = 0; byte < data_len; byte++)
       for (int bit = 0; bit < 8; bit++)
@@ -1103,10 +1103,10 @@ int32_t LDPCencoder(unsigned char **input, unsigned char **output, encoder_imple
                                           .n_cb = (BG == 1) ? (66 * Zc) : (50 * Zc),
                                           .BG = BG,
                                           .Z = Zc,
-                                          .rv = 0, //impp->rv,
-                                          .F = 0, //impp->F,
+                                          .rv = impp->rv,
+                                          .F = impp->F,
                                           .Qm = impp->Qm,
-                                          .Kr = impp->Kr};
+                                          .Kr = (impp->K - impp->F + 7) / 8};
   struct rte_bbdev_info info;
   rte_bbdev_info_get(ad->dev_id, &info);
   int socket_id = GET_SOCKET(info.socket_id);
@@ -1126,7 +1126,7 @@ int32_t LDPCencoder(unsigned char **input, unsigned char **output, encoder_imple
   for (enum op_data_type type = DATA_INPUT; type < 3; type += 2) {
     int ret = init_op_data_objs(*queue_ops[type],
                                 *input,
-                                (offloadParams.Kr + 7) / 8,
+                                offloadParams.Kr,
                                 m_head[type],
                                 mbuf_pools[type],
                                 1,
diff --git a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
index 04a320be248a42fbd4258d042729188708a75e0c..07dabe07e1337e4ecffb12cc853b097452102043 100644
--- a/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
+++ b/openair1/PHY/NR_TRANSPORT/nr_dlsch_coding.c
@@ -363,7 +363,7 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
   impp.tparity = tparity;
   impp.toutput = toutput;
   impp.harq = harq;
-  if (gNB->ldpc_offload_flag && *rel15->mcsIndex > 2) {
+  if (gNB->ldpc_offload_flag) {
     impp.Qm = rel15->qamModOrder[0];
     impp.rv = rel15->rvIndex[0];
     int nb_re_dmrs =
@@ -375,26 +375,11 @@ int nr_dlsch_encoding(PHY_VARS_gNB *gNB,
                       harq->unav_res,
                       rel15->qamModOrder[0],
                       rel15->nrOfLayers);
-    uint8_t tmp[68 * 384] __attribute__((aligned(32)));
-    uint8_t *d = tmp;
     int r_offset = 0;
     for (int r = 0; r < impp.n_segments; r++) {
       impp.E = nr_get_E(impp.G, impp.n_segments, impp.Qm, rel15->nrOfLayers, r);
-      impp.Kr = impp.K;
-      ldpc_interface_offload.LDPCencoder(&harq->c[r], &d, &impp);
-      uint8_t e[impp.E];
-      bzero(e, impp.E);
-      nr_rate_matching_ldpc(rel15->maintenance_parms_v3.tbSizeLbrmBytes,
-                            impp.BG,
-                            impp.Zc,
-                            tmp,
-                            e,
-                            impp.n_segments,
-                            impp.F,
-                            impp.K - impp.F - 2 * impp.Zc,
-                            impp.rv,
-                            impp.E);
-      nr_interleaving_ldpc(impp.E, impp.Qm, e, impp.output + r_offset);
+      uint8_t *f = impp.output + r_offset;
+      ldpc_interface_offload.LDPCencoder(&harq->c[r], &f, &impp);
       r_offset += impp.E;
     }
   } else {
diff --git a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
index fadd7d6ac61616c1928e86eff5832344d870b567..fa9d69275166a0d973eafbffa7a2e357610341b3 100644
--- a/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
+++ b/openair1/PHY/NR_UE_TRANSPORT/nr_ulsch_coding.c
@@ -50,42 +50,39 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
 {
   start_meas(&ue->ulsch_encoding_stats);
 
-/////////////////////////parameters and variables initialization/////////////////////////
-///////////
+  /////////////////////////parameters and variables initialization/////////////////////////
 
   unsigned int crc = 1;
   NR_UL_UE_HARQ_t *harq_process = &ue->ul_harq_processes[harq_pid];
   uint16_t nb_rb = ulsch->pusch_pdu.rb_size;
   uint32_t A = tb_size << 3;
-  uint8_t mod_order = ulsch->pusch_pdu.qam_mod_order;
-  uint16_t Kr = 0;
   uint32_t r_offset = 0;
-  uint32_t F = 0;
   // target_code_rate is in 0.1 units
   float Coderate = (float) ulsch->pusch_pdu.target_code_rate / 10240.0f;
-
-///////////
-/////////////////////////////////////////////////////////////////////////////////////////  
+  encoder_implemparams_t impp = {.n_segments = harq_process->C,
+                                 .macro_num = 0,
+                                 .K = harq_process->K,
+                                 .Kr = harq_process->K,
+                                 .Zc = harq_process->Z,
+                                 .BG = harq_process->BG,
+                                 .F = harq_process->F,
+                                 .rv = ulsch->pusch_pdu.pusch_data.rv_index,
+                                 .Qm = ulsch->pusch_pdu.qam_mod_order,
+                                 .tinput = NULL,
+                                 .tprep = NULL,
+                                 .tparity = NULL,
+                                 .toutput = NULL};
+  /////////////////////////////////////////////////////////////////////////////////////////
 
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_IN);
-
   LOG_D(NR_PHY, "ulsch coding nb_rb %d, Nl = %d\n", nb_rb, ulsch->pusch_pdu.nrOfLayers);
-  LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G, mod_order, Coderate);
+  LOG_D(NR_PHY, "ulsch coding A %d G %d mod_order %d Coderate %f\n", A, G, impp.Qm, Coderate);
   LOG_D(NR_PHY, "harq_pid %d, pusch_data.new_data_indicator %d\n", harq_pid, ulsch->pusch_pdu.pusch_data.new_data_indicator);
   if (ulsch->pusch_pdu.pusch_data.new_data_indicator) {  // this is a new packet
 #ifdef DEBUG_ULSCH_CODING
-  printf("encoding thinks this is a new packet \n");
+    printf("encoding thinks this is a new packet \n");
 #endif
-///////////////////////// a---->| add CRC |---->b /////////////////////////
-///////////
-   /* 
-    int i;
-    printf("ulsch (tx): \n");
-    for (i=0;i<(A>>3);i++)
-      printf("%02x.",harq_process->a[i]);
-    printf("\n");
-   */ 
-
+    ///////////////////////// a---->| add CRC |---->b /////////////////////////
     int max_payload_bytes = MAX_NUM_NR_ULSCH_SEGMENTS_PER_LAYER*ulsch->pusch_pdu.nrOfLayers*1056;
     int B;
     if (A > NR_MAX_PDSCH_TBS) {
@@ -93,222 +90,154 @@ int nr_ulsch_encoding(PHY_VARS_NR_UE *ue,
       crc = crc24a(harq_process->a,A)>>8;
       harq_process->a[A>>3] = ((uint8_t*)&crc)[2];
       harq_process->a[1+(A>>3)] = ((uint8_t*)&crc)[1];
-      harq_process->a[2+(A>>3)] = ((uint8_t*)&crc)[0];
-      //printf("CRC %x (A %d)\n",crc,A);
-      //printf("a0 %d a1 %d a2 %d\n", a[A>>3], a[1+(A>>3)], a[2+(A>>3)]);
-
+      harq_process->a[2 + (A >> 3)] = ((uint8_t *)&crc)[0];
       B = A + 24;
-
-      AssertFatal((A/8)+4 <= max_payload_bytes,"A %d is too big (A/8+4 = %d > %d)\n",A,(A/8)+4,max_payload_bytes);
-
+      AssertFatal((A / 8) + 4 <= max_payload_bytes, "A %d is too big (A/8+4 = %d > %d)\n", A, (A / 8) + 4, max_payload_bytes);
       memcpy(harq_process->b,harq_process->a,(A/8)+4);
     } else {
       // Add 16-bit crc (polynomial A) to payload
       crc = crc16(harq_process->a,A)>>16;
       harq_process->a[A>>3] = ((uint8_t*)&crc)[1];
-      harq_process->a[1+(A>>3)] = ((uint8_t*)&crc)[0];
-      //printf("CRC %x (A %d)\n",crc,A);
-      //printf("a0 %d a1 %d \n", a[A>>3], a[1+(A>>3)]);
-
+      harq_process->a[1 + (A >> 3)] = ((uint8_t *)&crc)[0];
       B = A + 16;
-
-      AssertFatal((A/8)+3 <= max_payload_bytes,"A %d is too big (A/8+3 = %d > %d)\n",A,(A/8)+3,max_payload_bytes);
-
+      AssertFatal((A / 8) + 3 <= max_payload_bytes, "A %d is too big (A/8+3 = %d > %d)\n", A, (A / 8) + 3, max_payload_bytes);
       memcpy(harq_process->b,harq_process->a,(A/8)+3);  // using 3 bytes to mimic the case of 24 bit crc
     }
-///////////
-///////////////////////////////////////////////////////////////////////////
 
-///////////////////////// b---->| block segmentation |---->c /////////////////////////
-///////////
+    ///////////////////////// b---->| block segmentation |---->c /////////////////////////
 
     harq_process->BG = ulsch->pusch_pdu.ldpcBaseGraph;
 
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_IN);
     start_meas(&ue->ulsch_segmentation_stats);
-    uint32_t Kb = nr_segmentation(harq_process->b,
-                                  harq_process->c,
-                                  B,
-                                  &harq_process->C,
-                                  &harq_process->K,
-                                  &harq_process->Z,
-                                  &harq_process->F,
-                                  harq_process->BG);
-
-    if (harq_process->C>MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER*ulsch->pusch_pdu.nrOfLayers) {
-      LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", harq_process->C, B);
+    impp.Kb = nr_segmentation(harq_process->b,
+                              harq_process->c,
+                              B,
+                              &harq_process->C,
+                              &harq_process->K,
+                              &harq_process->Z,
+                              &harq_process->F,
+                              harq_process->BG);
+    impp.n_segments = harq_process->C;
+    impp.K = harq_process->K;
+    impp.Kr = impp.K;
+    impp.Zc = harq_process->Z;
+    impp.F = harq_process->F;
+    impp.BG = harq_process->BG;
+    if (impp.n_segments > MAX_NUM_NR_DLSCH_SEGMENTS_PER_LAYER * ulsch->pusch_pdu.nrOfLayers) {
+      LOG_E(PHY, "nr_segmentation.c: too many segments %d, B %d\n", impp.n_segments, B);
       return(-1);
     }
     stop_meas(&ue->ulsch_segmentation_stats);
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_SEGMENTATION, VCD_FUNCTION_OUT);
 
-    F = harq_process->F;
-    Kr = harq_process->K;
 #ifdef DEBUG_ULSCH_CODING
     uint16_t Kr_bytes;
-    Kr_bytes = Kr>>3;
+    Kr_bytes = impp.Kr >> 3;
 #endif
 
-///////////////////////// c---->| LDCP coding |---->d /////////////////////////
-///////////
-
-    // printf("segment Z %d k %d Kr %d BG %d\n", harq_process->Z,harq_process->K,Kr,BG);
-
-    //start_meas(te_stats);
-    for (int r=0; r<harq_process->C; r++) {
-      //channel_input[r] = &harq_process->d[r][0];
+    ///////////////////////// c---->| LDCP coding |---->d ////////////////////////////////////
+    for (int r = 0; r < impp.n_segments; r++) {
 #ifdef DEBUG_ULSCH_CODING
-      printf("Encoder: B %d F %d \n", B, harq_process->F);
-      printf("start ldpc encoder segment %d/%d\n",r,harq_process->C);
+      printf("Encoder: B %d F %d \n", B, impp.F);
+      printf("start ldpc encoder segment %d/%d\n", r, impp.n_segments);
       printf("input %d %d %d %d %d \n", harq_process->c[r][0], harq_process->c[r][1], harq_process->c[r][2],harq_process->c[r][3], harq_process->c[r][4]);
-      for (int cnt = 0; cnt < 22 * harq_process->Z / 8; cnt++) {
+      for (int cnt = 0; cnt < 22 * impp.Zc / 8; cnt++) {
         printf("%d ", harq_process->c[r][cnt]);
       }
       printf("\n");
-
 #endif
-      //ldpc_encoder_orig((unsigned char*)harq_process->c[r],harq_process->d[r],Kr,BG,0);
-      //ldpc_encoder_optim((unsigned char*)harq_process->c[r],(unsigned char*)&harq_process->d[r][0],Kr,BG,NULL,NULL,NULL,NULL);
     }
-
-    //for (int i=0;i<68*384;i++)
-      //        printf("channel_input[%d]=%d\n",i,channel_input[i]);
-
-    /*printf("output %d %d %d %d %d \n", harq_process->d[0][0], harq_process->d[0][1], harq_process->d[r][2],harq_process->d[0][3],
-      harq_process->d[0][4]); for (int cnt =0 ; cnt < 66*harq_process->Z; cnt ++){ printf("%d \n",  harq_process->d[0][cnt]);
-      }
-      printf("\n");*/
-    encoder_implemparams_t impp = {.n_segments = harq_process->C,
-                                   .macro_num = 0,
-                                   .K = harq_process->K,
-                                   .Kb = Kb,
-                                   .Zc = harq_process->Z,
-                                   .BG = harq_process->BG,
-                                   .tinput = NULL,
-                                   .tprep = NULL,
-                                   .tparity = NULL,
-                                   .toutput = NULL};
-
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_IN);
-
-    start_meas(&ue->ulsch_ldpc_encoding_stats);
-    if (ldpc_interface_offload.LDPCencoder)
-      for (int j = 0; j < harq_process->C; j++) {
-        impp.macro_num = j;
-        impp.E = nr_get_E(G, harq_process->C, mod_order, ulsch->pusch_pdu.nrOfLayers, j);
-        impp.Kr = Kr;
-        ldpc_interface_offload.LDPCencoder(&harq_process->c[j], &harq_process->d[j], &impp);
-      }
-    else
-      for (int j = 0; j < (harq_process->C / 8 + 1); j++) {
+  }
+  start_meas(&ue->ulsch_ldpc_encoding_stats);
+  if (ldpc_interface_offload.LDPCencoder) {
+    for (int j = 0; j < impp.n_segments; j++) {
+      impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
+      uint8_t *f = harq_process->f + r_offset;
+      ldpc_interface_offload.LDPCencoder(&harq_process->c[j], &f, &impp);
+      r_offset += impp.E;
+    }
+  } else {
+    if (ulsch->pusch_pdu.pusch_data.new_data_indicator) {
+      for (int j = 0; j < (impp.n_segments / 8 + 1); j++) {
         impp.macro_num = j;
-        impp.E = nr_get_E(G, harq_process->C, mod_order, ulsch->pusch_pdu.nrOfLayers, j);
-        impp.Kr = Kr;
+        impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, j);
+        impp.Kr = impp.K;
         ldpc_interface.LDPCencoder(harq_process->c, harq_process->d, &impp);
       }
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT);
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_LDPC_ENCODER_OPTIM, VCD_FUNCTION_OUT);
 
-    //stop_meas(te_stats);
-    //printf("end ldpc encoder -- output\n");
 #ifdef DEBUG_ULSCH_CODING
-    write_output("ulsch_enc_input0.m","enc_in0",&harq_process->c[0][0],Kr_bytes,1,4);
-    write_output("ulsch_enc_output0.m","enc0",&harq_process->d[0][0],(3*8*Kr_bytes)+12,1,4);
+      write_output("ulsch_enc_input0.m", "enc_in0", &harq_process->c[0][0], Kr_bytes, 1, 4);
+      write_output("ulsch_enc_output0.m", "enc0", &harq_process->d[0][0], (3 * 8 * Kr_bytes) + 12, 1, 4);
 #endif
-
-///////////
+    }
 ///////////////////////////////////////////////////////////////////////////////
-  }
-  F = harq_process->F;
-  Kr = harq_process->K;
-
-  for (int r=0; r<harq_process->C; r++) { // looping over C segments
-    if (harq_process->F>0) {
-      for (int k = Kr - F - 2 * harq_process->Z; k < Kr - 2 * harq_process->Z; k++) {
-        harq_process->d[r][k] = NR_NULL;
-        //if (k<(Kr-F+8))
-        //printf("r %d filler bits [%d] = %d \n", r,k, harq_process->d[r][k]);
+    for (int r = 0; r < impp.n_segments; r++) { // looping over C segments
+      if (impp.F > 0) {
+        for (int k = impp.Kr - impp.F - 2 * impp.Zc; k < impp.Kr - 2 * impp.Zc; k++) {
+          harq_process->d[r][k] = NR_NULL;
+        }
       }
-    }
-
-
-    LOG_D(PHY,"Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb %d, rvidx %d)...\n",
-	  r,
-	  G,
-	  Kr*3,
-	  mod_order,nb_rb,
-	  ulsch->pusch_pdu.pusch_data.rv_index);
-
-    //start_meas(rm_stats);
-///////////////////////// d---->| Rate matching bit selection |---->e /////////////////////////
-///////////
-
-    uint32_t E = nr_get_E(G, harq_process->C, mod_order, ulsch->pusch_pdu.nrOfLayers, r);
-
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN);
-    start_meas(&ue->ulsch_rate_matching_stats);
-    if (nr_rate_matching_ldpc(ulsch->pusch_pdu.tbslbrm,
-                              harq_process->BG,
-                              harq_process->Z,
-                              harq_process->d[r],
-                              harq_process->e + r_offset,
-                              harq_process->C,
-                              F,
-                              Kr - F - 2 * harq_process->Z,
-                              ulsch->pusch_pdu.pusch_data.rv_index,
-                              E)
-        == -1)
-      return -1;
-
-    stop_meas(&ue->ulsch_rate_matching_stats);
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_OUT);
-
 
+      LOG_D(PHY,
+            "Rate Matching, Code segment %d (coded bits (G) %u, unpunctured/repeated bits per code segment %d, mod_order %d, nb_rb "
+            "%d, "
+            "rvidx %d)...\n",
+            r,
+            G,
+            impp.Kr * 3,
+            impp.Qm,
+            nb_rb,
+            ulsch->pusch_pdu.pusch_data.rv_index);
+
+      ///////////////////////// d---->| Rate matching bit selection |---->e /////////////////////////
+      impp.E = nr_get_E(G, impp.n_segments, impp.Qm, ulsch->pusch_pdu.nrOfLayers, r);
+
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_IN);
+      start_meas(&ue->ulsch_rate_matching_stats);
+      if (nr_rate_matching_ldpc(ulsch->pusch_pdu.tbslbrm,
+                                impp.BG,
+                                impp.Zc,
+                                harq_process->d[r],
+                                harq_process->e + r_offset,
+                                impp.n_segments,
+                                impp.F,
+                                impp.Kr - impp.F - 2 * impp.Zc,
+                                impp.rv,
+                                impp.E) == -1)
+        return -1;
+
+      stop_meas(&ue->ulsch_rate_matching_stats);
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_RATE_MATCHING_LDPC, VCD_FUNCTION_OUT);
 
 #ifdef DEBUG_ULSCH_CODING
-    for (int i =0; i<16; i++)
-      printf("output ratematching e[%d]= %d r_offset %u\n", i,harq_process->e[i+r_offset], r_offset);
+      for (int i = 0; i < 16; i++)
+        printf("output ratematching e[%d]= %d r_offset %u\n", i, harq_process->e[i + r_offset], r_offset);
 #endif
 
-///////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-    
 ///////////////////////// e---->| Rate matching bit interleaving |---->f /////////////////////////
-///////////
-
-    //stop_meas(rm_stats);
-
-    //start_meas(i_stats);
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN);
-    
-    start_meas(&ue->ulsch_interleaving_stats);
-    nr_interleaving_ldpc(E,
-                         mod_order,
-                         harq_process->e+r_offset,
-                         harq_process->f+r_offset);
-    stop_meas(&ue->ulsch_interleaving_stats);
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_IN);
+      start_meas(&ue->ulsch_interleaving_stats);
+      nr_interleaving_ldpc(impp.E,
+                           impp.Qm,
+                           harq_process->e + r_offset,
+                           harq_process->f + r_offset);
+      stop_meas(&ue->ulsch_interleaving_stats);
     
-    VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT);
-    //stop_meas(i_stats);
-
-
+      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_INTERLEAVING_LDPC, VCD_FUNCTION_OUT);
 #ifdef DEBUG_ULSCH_CODING
-    for (int i =0; i<16; i++)
-      printf("output interleaving f[%d]= %d r_offset %u\n", i,harq_process->f[i+r_offset], r_offset);
-
-    if (r==harq_process->C-1)
-      write_output("enc_output.m","enc",harq_process->f,G,1,4);
+      for (int i = 0; i < 16; i++)
+        printf("output interleaving f[%d]= %d r_offset %u\n", i, harq_process->f[i+r_offset], r_offset);
+      if (r == impp.n_segments - 1)
+        write_output("enc_output.m","enc", harq_process->f, G, 1, 4);
 #endif
-
-    r_offset += E;
-
-///////////
-///////////////////////////////////////////////////////////////////////////////////////////////
-
+      r_offset += impp.E;
+    }
   }
-
+  ///////////////////////////////////////////////////////////////////////////////////////////////
   VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_NR_UE_ULSCH_ENCODING, VCD_FUNCTION_OUT);
-
   stop_meas(&ue->ulsch_encoding_stats);
   return(0);
 }
diff --git a/openair1/PHY/defs_nr_UE.h b/openair1/PHY/defs_nr_UE.h
index f57d3f84798b8605f7f7873832be6de76b2eeede..834163d8ed0132862e2c5981517a8ee575ba58bd 100644
--- a/openair1/PHY/defs_nr_UE.h
+++ b/openair1/PHY/defs_nr_UE.h
@@ -268,8 +268,6 @@ typedef enum {
 #endif
 typedef struct {
   int nb_search_space;
-  uint16_t sfn;
-  uint16_t slot;
   fapi_nr_dl_config_dci_dl_pdu_rel15_t pdcch_config[FAPI_NR_MAX_SS];
 } NR_UE_PDCCH_CONFIG;
 
@@ -330,7 +328,7 @@ typedef struct UE_NR_SCAN_INFO_s {
 } UE_NR_SCAN_INFO_t;
 
 /// Top-level PHY Data Structure for UE
-typedef struct {
+typedef struct PHY_VARS_NR_UE_s {
   /// \brief Module ID indicator for this instance
   uint8_t Mod_id;
   /// \brief Component carrier ID for this PHY instance
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
index 4272485c4b96ee6fd456c75b079c7ad098cac4d4..476ec8db672229bb1d1c868eee7ae4aab0461ad0 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.c
@@ -104,189 +104,182 @@ int8_t nr_ue_scheduled_response_stub(nr_scheduled_response_t *scheduled_response
 
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
 
-  if(scheduled_response != NULL) {
-    if (scheduled_response->ul_config != NULL) {
-      fapi_nr_ul_config_request_t *ul_config = scheduled_response->ul_config;
-      AssertFatal(ul_config->number_pdus < sizeof(ul_config->ul_config_list) / sizeof(ul_config->ul_config_list[0]),
-                  "Too many ul_config pdus %d", ul_config->number_pdus);
-      for (int i = 0; i < ul_config->number_pdus; ++i) {
-        LOG_D(NR_PHY, "In %s: processing type %d PDU of %d total UL PDUs (ul_config %p) \n",
-              __FUNCTION__, ul_config->ul_config_list[i].pdu_type, ul_config->number_pdus, ul_config);
-
-        uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type;
-        switch (pdu_type) {
-          case FAPI_NR_UL_CONFIG_TYPE_PRACH: {
-            fapi_nr_ul_config_prach_pdu *prach_pdu = &ul_config->ul_config_list[i].prach_config_pdu;
-            nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind));
-            rach_ind->sfn = scheduled_response->frame;
-            rach_ind->slot = scheduled_response->slot;
-            rach_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION;
-            uint8_t pdu_index = 0;
-            rach_ind->pdu_list = CALLOC(1, sizeof(*rach_ind->pdu_list));
-            rach_ind->number_of_pdus  = 1;
-            rach_ind->pdu_list[pdu_index].phy_cell_id = prach_pdu->phys_cell_id;
-            rach_ind->pdu_list[pdu_index].symbol_index = prach_pdu->prach_start_symbol;
-            rach_ind->pdu_list[pdu_index].slot_index = prach_pdu->prach_slot;
-            rach_ind->pdu_list[pdu_index].freq_index = prach_pdu->num_ra;
-            rach_ind->pdu_list[pdu_index].avg_rssi = 128;
-            rach_ind->pdu_list[pdu_index].avg_snr = 0xff; // invalid for now
-            rach_ind->pdu_list[pdu_index].num_preamble  = 1;
-            const int num_p = rach_ind->pdu_list[pdu_index].num_preamble;
-            rach_ind->pdu_list[pdu_index].preamble_list = calloc(num_p, sizeof(nfapi_nr_prach_indication_preamble_t));
-            rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_index = prach_pdu->ra_PreambleIndex;
-            rach_ind->pdu_list[pdu_index].preamble_list[0].timing_advance = 0;
-            rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_pwr = 0xffffffff;
-
-            if (!put_queue(&nr_rach_ind_queue, rach_ind)) {
-              for (int pdu_index = 0; pdu_index < rach_ind->number_of_pdus; pdu_index++)
-                free(rach_ind->pdu_list[pdu_index].preamble_list);
-              free(rach_ind->pdu_list);
-              free(rach_ind);
-            }
-            LOG_D(NR_MAC, "We have successfully filled the rach_ind queue with the recently filled rach ind\n");
-            break;
+  if (scheduled_response && scheduled_response->ul_config) {
+    int frame = scheduled_response->ul_config->frame;
+    int slot = scheduled_response->ul_config->slot;
+    fapi_nr_ul_config_request_pdu_t *it = fapiLockIterator(scheduled_response->ul_config, frame, slot);
+    while (it->pdu_type != FAPI_NR_END) {
+      switch (it->pdu_type) {
+        case FAPI_NR_UL_CONFIG_TYPE_PRACH: {
+          fapi_nr_ul_config_prach_pdu *prach_pdu = &it->prach_config_pdu;
+          nfapi_nr_rach_indication_t *rach_ind = CALLOC(1, sizeof(*rach_ind));
+          rach_ind->sfn = frame;
+          rach_ind->slot = slot;
+          rach_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RACH_INDICATION;
+          uint8_t pdu_index = 0;
+          rach_ind->pdu_list = CALLOC(1, sizeof(*rach_ind->pdu_list));
+          rach_ind->number_of_pdus = 1;
+          rach_ind->pdu_list[pdu_index].phy_cell_id = prach_pdu->phys_cell_id;
+          rach_ind->pdu_list[pdu_index].symbol_index = prach_pdu->prach_start_symbol;
+          rach_ind->pdu_list[pdu_index].slot_index = prach_pdu->prach_slot;
+          rach_ind->pdu_list[pdu_index].freq_index = prach_pdu->num_ra;
+          rach_ind->pdu_list[pdu_index].avg_rssi = 128;
+          rach_ind->pdu_list[pdu_index].avg_snr = 0xff; // invalid for now
+          rach_ind->pdu_list[pdu_index].num_preamble = 1;
+          const int num_p = rach_ind->pdu_list[pdu_index].num_preamble;
+          rach_ind->pdu_list[pdu_index].preamble_list = calloc(num_p, sizeof(nfapi_nr_prach_indication_preamble_t));
+          rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_index = prach_pdu->ra_PreambleIndex;
+          rach_ind->pdu_list[pdu_index].preamble_list[0].timing_advance = 0;
+          rach_ind->pdu_list[pdu_index].preamble_list[0].preamble_pwr = 0xffffffff;
+
+          if (!put_queue(&nr_rach_ind_queue, rach_ind)) {
+            for (int pdu_index = 0; pdu_index < rach_ind->number_of_pdus; pdu_index++)
+              free(rach_ind->pdu_list[pdu_index].preamble_list);
+            free(rach_ind->pdu_list);
+            free(rach_ind);
           }
-          case (FAPI_NR_UL_CONFIG_TYPE_PUSCH): {
-            nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind));
-            nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind));
-            nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &ul_config->ul_config_list[i].pusch_config_pdu;
-            if (scheduled_response->tx_request) {
-              AssertFatal(scheduled_response->tx_request->number_of_pdus <
-                          sizeof(scheduled_response->tx_request->tx_request_body) / sizeof(scheduled_response->tx_request->tx_request_body[0]),
-                          "Too many tx_req pdus %d", scheduled_response->tx_request->number_of_pdus);
-              rx_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION;
-              rx_ind->sfn = scheduled_response->ul_config->sfn;
-              rx_ind->slot = scheduled_response->ul_config->slot;
-              rx_ind->number_of_pdus = scheduled_response->tx_request->number_of_pdus;
-              rx_ind->pdu_list = CALLOC(rx_ind->number_of_pdus, sizeof(*rx_ind->pdu_list));
-              for (int j = 0; j < rx_ind->number_of_pdus; j++) {
-                fapi_nr_tx_request_body_t *tx_req_body = &scheduled_response->tx_request->tx_request_body[j];
-                rx_ind->pdu_list[j].handle = pusch_config_pdu->handle;
-                rx_ind->pdu_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id;
-                rx_ind->pdu_list[j].pdu_length = tx_req_body->pdu_length;
-                rx_ind->pdu_list[j].pdu = CALLOC(tx_req_body->pdu_length, sizeof(*rx_ind->pdu_list[j].pdu));
-                memcpy(rx_ind->pdu_list[j].pdu, tx_req_body->pdu, tx_req_body->pdu_length * sizeof(*rx_ind->pdu_list[j].pdu));
-                rx_ind->pdu_list[j].rnti = pusch_config_pdu->rnti;
-                /* TODO: Implement channel modeling to abstract TA and CQI. For now,
-                   we hard code the values below since they are set in L1 and we are
-                   abstracting L1. */
-                rx_ind->pdu_list[j].timing_advance = 31;
-                rx_ind->pdu_list[j].ul_cqi = 255;
-              }
-
-              crc_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION;
-              crc_ind->number_crcs = scheduled_response->ul_config->number_pdus;
-              crc_ind->sfn = scheduled_response->ul_config->sfn;
-              crc_ind->slot = scheduled_response->ul_config->slot;
-              crc_ind->crc_list = CALLOC(crc_ind->number_crcs, sizeof(*crc_ind->crc_list));
-              for (int j = 0; j < crc_ind->number_crcs; j++) {
-                crc_ind->crc_list[j].handle = pusch_config_pdu->handle;
-                crc_ind->crc_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id;
-                LOG_D(NR_MAC, "This is the harq pid %d for crc_list[%d]\n", crc_ind->crc_list[j].harq_id, j);
-                LOG_D(NR_MAC, "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d]\n",
-                      scheduled_response->frame, scheduled_response->slot, crc_ind->sfn, crc_ind->slot);
-                crc_ind->crc_list[j].num_cb = pusch_config_pdu->pusch_data.num_cb;
-                crc_ind->crc_list[j].rnti = pusch_config_pdu->rnti;
-                crc_ind->crc_list[j].tb_crc_status = 0;
-                crc_ind->crc_list[j].timing_advance = 31;
-                crc_ind->crc_list[j].ul_cqi = 255;
-                AssertFatal(mac->nr_ue_emul_l1.harq[crc_ind->crc_list[j].harq_id].active_ul_harq_sfn_slot == -1,
-                            "We did not send an active CRC when we should have!\n");
-                mac->nr_ue_emul_l1.harq[crc_ind->crc_list[j].harq_id].active_ul_harq_sfn_slot = NFAPI_SFNSLOT2HEX(crc_ind->sfn, crc_ind->slot);
-                LOG_D(NR_MAC, "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d] with mcs_index in ul_cqi -> %d\n",
-                      scheduled_response->frame, scheduled_response->slot, crc_ind->sfn, crc_ind->slot,pusch_config_pdu->mcs_index);
-              }
+          LOG_D(NR_MAC, "We have successfully filled the rach_ind queue with the recently filled rach ind\n");
+          break;
+        }
+        case (FAPI_NR_UL_CONFIG_TYPE_PUSCH): {
+          nfapi_nr_rx_data_indication_t *rx_ind = CALLOC(1, sizeof(*rx_ind));
+          nfapi_nr_crc_indication_t *crc_ind = CALLOC(1, sizeof(*crc_ind));
+          nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &it->pusch_config_pdu;
+          if (pusch_config_pdu->tx_request_body.pdu) {
+            rx_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_RX_DATA_INDICATION;
+            rx_ind->sfn = frame;
+            rx_ind->slot = slot;
+            rx_ind->number_of_pdus = 1;
+            rx_ind->pdu_list = CALLOC(rx_ind->number_of_pdus, sizeof(*rx_ind->pdu_list));
+            for (int j = 0; j < rx_ind->number_of_pdus; j++) {
+              fapi_nr_tx_request_body_t *tx_req_body = &pusch_config_pdu->tx_request_body;
+              rx_ind->pdu_list[j].handle = pusch_config_pdu->handle;
+              rx_ind->pdu_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id;
+              rx_ind->pdu_list[j].pdu_length = tx_req_body->pdu_length;
+              rx_ind->pdu_list[j].pdu = CALLOC(tx_req_body->pdu_length, sizeof(*rx_ind->pdu_list[j].pdu));
+              memcpy(rx_ind->pdu_list[j].pdu, tx_req_body->pdu, tx_req_body->pdu_length * sizeof(*rx_ind->pdu_list[j].pdu));
+              rx_ind->pdu_list[j].rnti = pusch_config_pdu->rnti;
+              /* TODO: Implement channel modeling to abstract TA and CQI. For now,
+                 we hard code the values below since they are set in L1 and we are
+                 abstracting L1. */
+              rx_ind->pdu_list[j].timing_advance = 31;
+              rx_ind->pdu_list[j].ul_cqi = 255;
+            }
 
-              if (!put_queue(&nr_rx_ind_queue, rx_ind)) {
-                LOG_E(NR_MAC, "Put_queue failed for rx_ind\n");
-                for (int i = 0; i < rx_ind->number_of_pdus; i++) {
-                  free(rx_ind->pdu_list[i].pdu);
-                  rx_ind->pdu_list[i].pdu = NULL;
-                }
+            crc_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_CRC_INDICATION;
+            crc_ind->number_crcs = rx_ind->number_of_pdus;
+            crc_ind->sfn = frame;
+            crc_ind->slot = slot;
+            crc_ind->crc_list = CALLOC(crc_ind->number_crcs, sizeof(*crc_ind->crc_list));
+            for (int j = 0; j < crc_ind->number_crcs; j++) {
+              crc_ind->crc_list[j].handle = pusch_config_pdu->handle;
+              crc_ind->crc_list[j].harq_id = pusch_config_pdu->pusch_data.harq_process_id;
+              LOG_D(NR_MAC, "This is the harq pid %d for crc_list[%d]\n", crc_ind->crc_list[j].harq_id, j);
+              LOG_D(NR_MAC, "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d]\n", frame, slot, crc_ind->sfn, crc_ind->slot);
+              crc_ind->crc_list[j].num_cb = pusch_config_pdu->pusch_data.num_cb;
+              crc_ind->crc_list[j].rnti = pusch_config_pdu->rnti;
+              crc_ind->crc_list[j].tb_crc_status = 0;
+              crc_ind->crc_list[j].timing_advance = 31;
+              crc_ind->crc_list[j].ul_cqi = 255;
+              AssertFatal(mac->nr_ue_emul_l1.harq[crc_ind->crc_list[j].harq_id].active_ul_harq_sfn_slot == -1,
+                          "We did not send an active CRC when we should have!\n");
+              mac->nr_ue_emul_l1.harq[crc_ind->crc_list[j].harq_id].active_ul_harq_sfn_slot =
+                  NFAPI_SFNSLOT2HEX(crc_ind->sfn, crc_ind->slot);
+              LOG_D(NR_MAC,
+                    "This is sched sfn/sl [%d %d] and crc sfn/sl [%d %d] with mcs_index in ul_cqi -> %d\n",
+                    frame,
+                    slot,
+                    crc_ind->sfn,
+                    crc_ind->slot,
+                    pusch_config_pdu->mcs_index);
+            }
 
-                free(rx_ind->pdu_list);
-                rx_ind->pdu_list = NULL;
-                free(rx_ind);
-                rx_ind = NULL;
-              }
-              if (!put_queue(&nr_crc_ind_queue, crc_ind)) {
-                LOG_E(NR_MAC, "Put_queue failed for crc_ind\n");
-                free(crc_ind->crc_list);
-                crc_ind->crc_list = NULL;
-                free(crc_ind);
-                crc_ind = NULL;
+            if (!put_queue(&nr_rx_ind_queue, rx_ind)) {
+              LOG_E(NR_MAC, "Put_queue failed for rx_ind\n");
+              for (int i = 0; i < rx_ind->number_of_pdus; i++) {
+                free(rx_ind->pdu_list[i].pdu);
+                rx_ind->pdu_list[i].pdu = NULL;
               }
 
-              LOG_D(PHY, "In %s: Filled queue rx/crc_ind which was filled by ulconfig. \n", __FUNCTION__);
-              scheduled_response->tx_request->number_of_pdus = 0;
+              free(rx_ind->pdu_list);
+              rx_ind->pdu_list = NULL;
+              free(rx_ind);
+              rx_ind = NULL;
             }
-            break;
+            if (!put_queue(&nr_crc_ind_queue, crc_ind)) {
+              LOG_E(NR_MAC, "Put_queue failed for crc_ind\n");
+              free(crc_ind->crc_list);
+              crc_ind->crc_list = NULL;
+              free(crc_ind);
+              crc_ind = NULL;
+            }
+
+            LOG_D(PHY, "In %s: Filled queue rx/crc_ind which was filled by ulconfig. \n", __FUNCTION__);
           }
-          case FAPI_NR_UL_CONFIG_TYPE_PUCCH: {
-            nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind));
-            uci_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION;
-            uci_ind->sfn = scheduled_response->frame;
-            uci_ind->slot = scheduled_response->slot;
-            uci_ind->num_ucis = 1;
-            uci_ind->uci_list = CALLOC(uci_ind->num_ucis, sizeof(*uci_ind->uci_list));
-            for (int j = 0; j < uci_ind->num_ucis; j++) {
-              LOG_D(NR_MAC, "ul_config->ul_config_list[%d].pucch_config_pdu.n_bit = %d\n", i, ul_config->ul_config_list[i].pucch_config_pdu.n_bit);
-              if (ul_config->ul_config_list[i].pucch_config_pdu.n_bit > 3 && mac->nr_ue_emul_l1.num_csi_reports > 0) {
-                uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE;
-                uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t);
-                nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4 = &uci_ind->uci_list[j].pucch_pdu_format_2_3_4;
-                fill_uci_2_3_4(pdu_2_3_4, &ul_config->ul_config_list[i].pucch_config_pdu);
-              }
-              else {
-                nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu_0_1 = &uci_ind->uci_list[j].pucch_pdu_format_0_1;
-                uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE;
-                uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t);
-                memset(pdu_0_1, 0, sizeof(*pdu_0_1));
-                pdu_0_1->handle = 0;
-                pdu_0_1->rnti = ul_config->ul_config_list[i].pucch_config_pdu.rnti;
-                pdu_0_1->pucch_format = 1;
-                pdu_0_1->ul_cqi = 255;
-                pdu_0_1->timing_advance = 0;
-                pdu_0_1->rssi = 0;
-                if (mac->nr_ue_emul_l1.num_harqs > 0) {
-                  int harq_index = 0;
-                  pdu_0_1->pduBitmap = 2; // (value->pduBitmap >> 1) & 0x01) == HARQ and (value->pduBitmap) & 0x01) == SR
-                  pdu_0_1->harq.num_harq = mac->nr_ue_emul_l1.num_harqs;
-                  pdu_0_1->harq.harq_confidence_level = 0;
-                  int harq_pid = -1;
-                  for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) {
-                    if (mac->nr_ue_emul_l1.harq[k].active &&
-                        mac->nr_ue_emul_l1.harq[k].active_dl_harq_sfn == uci_ind->sfn &&
-                        mac->nr_ue_emul_l1.harq[k].active_dl_harq_slot == uci_ind->slot) {
-                      mac->nr_ue_emul_l1.harq[k].active = false;
-                      harq_pid = k;
-                      AssertFatal(harq_index < pdu_0_1->harq.num_harq, "Invalid harq_index %d\n", harq_index);
-                      pdu_0_1->harq.harq_list[harq_index].harq_value = !mac->dl_harq_info[k].ack;
-                      harq_index++;
-                    }
+          break;
+        }
+        case FAPI_NR_UL_CONFIG_TYPE_PUCCH: {
+          nfapi_nr_uci_indication_t *uci_ind = CALLOC(1, sizeof(*uci_ind));
+          uci_ind->header.message_id = NFAPI_NR_PHY_MSG_TYPE_UCI_INDICATION;
+          uci_ind->sfn = frame;
+          uci_ind->slot = slot;
+          uci_ind->num_ucis = 1;
+          uci_ind->uci_list = CALLOC(uci_ind->num_ucis, sizeof(*uci_ind->uci_list));
+          for (int j = 0; j < uci_ind->num_ucis; j++) {
+            LOG_D(NR_MAC, "pucch_config_pdu.n_bit = %d\n", it->pucch_config_pdu.n_bit);
+            if (it->pucch_config_pdu.n_bit > 3 && mac->nr_ue_emul_l1.num_csi_reports > 0) {
+              uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_2_3_4_PDU_TYPE;
+              uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_2_3_4_t);
+              nfapi_nr_uci_pucch_pdu_format_2_3_4_t *pdu_2_3_4 = &uci_ind->uci_list[j].pucch_pdu_format_2_3_4;
+              fill_uci_2_3_4(pdu_2_3_4, &it->pucch_config_pdu);
+            } else {
+              nfapi_nr_uci_pucch_pdu_format_0_1_t *pdu_0_1 = &uci_ind->uci_list[j].pucch_pdu_format_0_1;
+              uci_ind->uci_list[j].pdu_type = NFAPI_NR_UCI_FORMAT_0_1_PDU_TYPE;
+              uci_ind->uci_list[j].pdu_size = sizeof(nfapi_nr_uci_pucch_pdu_format_0_1_t);
+              memset(pdu_0_1, 0, sizeof(*pdu_0_1));
+              pdu_0_1->handle = 0;
+              pdu_0_1->rnti = it->pucch_config_pdu.rnti;
+              pdu_0_1->pucch_format = 1;
+              pdu_0_1->ul_cqi = 255;
+              pdu_0_1->timing_advance = 0;
+              pdu_0_1->rssi = 0;
+              if (mac->nr_ue_emul_l1.num_harqs > 0) {
+                int harq_index = 0;
+                pdu_0_1->pduBitmap = 2; // (value->pduBitmap >> 1) & 0x01) == HARQ and (value->pduBitmap) & 0x01) == SR
+                pdu_0_1->harq.num_harq = mac->nr_ue_emul_l1.num_harqs;
+                pdu_0_1->harq.harq_confidence_level = 0;
+                int harq_pid = -1;
+                for (int k = 0; k < NR_MAX_HARQ_PROCESSES; k++) {
+                  if (mac->nr_ue_emul_l1.harq[k].active && mac->nr_ue_emul_l1.harq[k].active_dl_harq_sfn == uci_ind->sfn
+                      && mac->nr_ue_emul_l1.harq[k].active_dl_harq_slot == uci_ind->slot) {
+                    mac->nr_ue_emul_l1.harq[k].active = false;
+                    harq_pid = k;
+                    AssertFatal(harq_index < pdu_0_1->harq.num_harq, "Invalid harq_index %d\n", harq_index);
+                    pdu_0_1->harq.harq_list[harq_index].harq_value = !mac->dl_harq_info[k].ack;
+                    harq_index++;
                   }
-                  AssertFatal(harq_pid != -1, "No active harq_pid, sfn_slot = %u.%u", uci_ind->sfn, uci_ind->slot);
                 }
+                AssertFatal(harq_pid != -1, "No active harq_pid, sfn_slot = %u.%u", uci_ind->sfn, uci_ind->slot);
               }
             }
-
-            LOG_D(NR_PHY, "Sending UCI with %d PDUs in sfn.slot %d/%d\n",
-                  uci_ind->num_ucis, uci_ind->sfn, uci_ind->slot);
-            NR_UL_IND_t ul_info = {
-                .uci_ind = *uci_ind,
-            };
-            send_nsa_standalone_msg(&ul_info, uci_ind->header.message_id);
-            free_uci_inds(uci_ind);
-            break;
           }
 
-          default:
-            LOG_W(NR_MAC, "Unknown ul_config->pdu_type %d\n", pdu_type);
+          LOG_D(NR_PHY, "Sending UCI with %d PDUs in sfn.slot %d/%d\n", uci_ind->num_ucis, uci_ind->sfn, uci_ind->slot);
+          NR_UL_IND_t ul_info = {
+              .uci_ind = *uci_ind,
+          };
+          send_nsa_standalone_msg(&ul_info, uci_ind->header.message_id);
+          free_uci_inds(uci_ind);
           break;
         }
+
+        default:
+          LOG_W(NR_MAC, "Unknown ul_config->pdu_type %d\n", it->pdu_type);
+          break;
       }
-      scheduled_response->ul_config->number_pdus = 0;
+      it++;
     }
+    release_ul_config(it, true);
   }
   return 0;
 }
@@ -294,7 +287,7 @@ int8_t nr_ue_scheduled_response_stub(nr_scheduled_response_t *scheduled_response
 static void configure_dlsch(NR_UE_DLSCH_t *dlsch0,
                             NR_DL_UE_HARQ_t *harq_list,
                             fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
-                            module_id_t module_id,
+                            NR_UE_MAC_INST_t *mac,
                             int rnti)
 {
   const uint8_t current_harq_pid = dlsch_config_pdu->harq_process_nbr;
@@ -316,7 +309,7 @@ static void configure_dlsch(NR_UE_DLSCH_t *dlsch0,
     // dlsch0_harq->status not ACTIVE due to false retransmission
     // Reset the following flag to skip PDSCH procedures in that case and retrasmit harq status
     dlsch0->active = false;
-    update_harq_status(module_id, current_harq_pid, dlsch0_harq->ack);
+    update_harq_status(mac, current_harq_pid, dlsch0_harq->ack);
   }
 }
 
@@ -376,261 +369,160 @@ void configure_ta_command(PHY_VARS_NR_UE *ue, fapi_nr_ta_command_pdu *ta_command
         ta_command_pdu->ta_frame, ta_command_pdu->ta_slot, ue->ta_frame, ue->ta_slot);
 }
 
-int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response){
-
-  bool found = false;
-  if(scheduled_response != NULL){
-
-    module_id_t module_id = scheduled_response->module_id;
-    uint8_t cc_id = scheduled_response->CC_id;
-    int slot = scheduled_response->slot;
-
-    // Note: we have to handle the thread IDs for this. To be revisited completely.
-    NR_UE_CSI_IM *csiim_vars = PHY_vars_UE_g[module_id][cc_id]->csiim_vars[0];
-    NR_UE_CSI_RS *csirs_vars = PHY_vars_UE_g[module_id][cc_id]->csirs_vars[0];
-    NR_UE_PDCCH_CONFIG *phy_pdcch_config = NULL;
-
-    if(scheduled_response->dl_config != NULL){
-      fapi_nr_dl_config_request_t *dl_config = scheduled_response->dl_config;
-      fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu;
-      fapi_nr_dl_config_dci_dl_pdu_rel15_t *pdcch_config;
-      fapi_nr_dl_config_csiim_pdu_rel15_t *csiim_config_pdu;
-      fapi_nr_dl_config_csirs_pdu_rel15_t *csirs_config_pdu;
-
-      for (int i = 0; i < dl_config->number_pdus; ++i){
-        AssertFatal(dl_config->number_pdus < FAPI_NR_DL_CONFIG_LIST_NUM,"dl_config->number_pdus %d out of bounds\n",dl_config->number_pdus);
-        AssertFatal(dl_config->dl_config_list[i].pdu_type<=FAPI_NR_DL_CONFIG_TYPES,"pdu_type %d > 2\n",dl_config->dl_config_list[i].pdu_type);
-        LOG_D(PHY, "In %s: frame %d slot %d received 1 DL %s PDU of %d total DL PDUs:\n",
-              __FUNCTION__, scheduled_response->frame, slot, dl_pdu_type[dl_config->dl_config_list[i].pdu_type - 1], dl_config->number_pdus);
-
-        switch(dl_config->dl_config_list[i].pdu_type) {
-          case FAPI_NR_DL_CONFIG_TYPE_DCI:
-            if (NULL == phy_pdcch_config) {
-              phy_pdcch_config = &((nr_phy_data_t *)scheduled_response->phy_data)->phy_pdcch_config;
-              phy_pdcch_config->nb_search_space = 0;
-            }
-            pdcch_config = &dl_config->dl_config_list[i].dci_config_pdu.dci_config_rel15;
-            memcpy((void*)&phy_pdcch_config->pdcch_config[phy_pdcch_config->nb_search_space],(void*)pdcch_config,sizeof(*pdcch_config));
-            phy_pdcch_config->nb_search_space = phy_pdcch_config->nb_search_space + 1;
-            phy_pdcch_config->sfn = scheduled_response->frame;
-            phy_pdcch_config->slot = slot;
-            LOG_D(PHY,"Number of DCI SearchSpaces %d\n",phy_pdcch_config->nb_search_space);
-            break;
-          case FAPI_NR_DL_CONFIG_TYPE_CSI_IM:
-            csiim_config_pdu = &dl_config->dl_config_list[i].csiim_config_pdu.csiim_config_rel15;
-            memcpy((void*)&(csiim_vars->csiim_config_pdu), (void*)csiim_config_pdu, sizeof(fapi_nr_dl_config_csiim_pdu_rel15_t));
-            csiim_vars->active = true;
-            break;
-          case FAPI_NR_DL_CONFIG_TYPE_CSI_RS:
-            csirs_config_pdu = &dl_config->dl_config_list[i].csirs_config_pdu.csirs_config_rel15;
-            memcpy((void*)&(csirs_vars->csirs_config_pdu), (void*)csirs_config_pdu, sizeof(fapi_nr_dl_config_csirs_pdu_rel15_t));
-            csirs_vars->active = true;
-            break;
-          case FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH: {
-            dlsch_config_pdu = &dl_config->dl_config_list[i].dlsch_config_pdu.dlsch_config_rel15;
-            NR_UE_DLSCH_t *dlsch0 = &((nr_phy_data_t *)scheduled_response->phy_data)->dlsch[0];
-            dlsch0->rnti_type = TYPE_RA_RNTI_;
-            dlsch0->dlsch_config = *dlsch_config_pdu;
-            configure_dlsch(dlsch0, PHY_vars_UE_g[module_id][cc_id]->dl_harq_processes[0], dlsch_config_pdu, module_id,
-                            dl_config->dl_config_list[i].dlsch_config_pdu.rnti);
-          } break;
-          case FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH: {
-            dlsch_config_pdu = &dl_config->dl_config_list[i].dlsch_config_pdu.dlsch_config_rel15;
-            NR_UE_DLSCH_t *dlsch0 = &((nr_phy_data_t *)scheduled_response->phy_data)->dlsch[0];
-            dlsch0->rnti_type = TYPE_SI_RNTI_;
-            dlsch0->dlsch_config = *dlsch_config_pdu;
-            configure_dlsch(dlsch0, PHY_vars_UE_g[module_id][cc_id]->dl_harq_processes[0], dlsch_config_pdu, module_id,
-                            dl_config->dl_config_list[i].dlsch_config_pdu.rnti);
-          } break;
-          case FAPI_NR_DL_CONFIG_TYPE_DLSCH: {
-            dlsch_config_pdu = &dl_config->dl_config_list[i].dlsch_config_pdu.dlsch_config_rel15;
-            NR_UE_DLSCH_t *dlsch0 = &((nr_phy_data_t *)scheduled_response->phy_data)->dlsch[0];
-            dlsch0->rnti_type = TYPE_C_RNTI_;
-            dlsch0->dlsch_config = *dlsch_config_pdu;
-            configure_dlsch(dlsch0, PHY_vars_UE_g[module_id][cc_id]->dl_harq_processes[0], dlsch_config_pdu, module_id,
-                            dl_config->dl_config_list[i].dlsch_config_pdu.rnti);
-          } break;
-          case FAPI_NR_CONFIG_TA_COMMAND:
-            configure_ta_command(PHY_vars_UE_g[module_id][cc_id], &dl_config->dl_config_list[i].ta_command_pdu);
-            break;
-        }
-      }
-      dl_config->number_pdus = 0;
+static void nr_ue_scheduled_response_dl(NR_UE_MAC_INST_t *mac,
+                                        PHY_VARS_NR_UE *phy,
+                                        fapi_nr_dl_config_request_t *dl_config,
+                                        nr_phy_data_t *phy_data)
+{
+  AssertFatal(dl_config->number_pdus < FAPI_NR_DL_CONFIG_LIST_NUM,
+              "dl_config->number_pdus %d out of bounds\n",
+              dl_config->number_pdus);
+
+  for (int i = 0; i < dl_config->number_pdus; ++i) {
+    fapi_nr_dl_config_request_pdu_t *pdu = dl_config->dl_config_list + i;
+    AssertFatal(pdu->pdu_type <= FAPI_NR_DL_CONFIG_TYPES, "pdu_type %d\n", pdu->pdu_type);
+    LOG_D(PHY, "Copying DL %s PDU of %d total DL PDUs:\n", dl_pdu_type[pdu->pdu_type - 1], dl_config->number_pdus);
+
+    switch (pdu->pdu_type) {
+      case FAPI_NR_DL_CONFIG_TYPE_DCI:
+        AssertFatal(phy_data->phy_pdcch_config.nb_search_space < FAPI_NR_MAX_SS, "Fix array size not large enough\n");
+        const int nextFree = phy_data->phy_pdcch_config.nb_search_space;
+        phy_data->phy_pdcch_config.pdcch_config[nextFree] = pdu->dci_config_pdu.dci_config_rel15;
+        phy_data->phy_pdcch_config.nb_search_space++;
+        LOG_D(PHY, "Number of DCI SearchSpaces %d\n", phy_data->phy_pdcch_config.nb_search_space);
+        break;
+      case FAPI_NR_DL_CONFIG_TYPE_CSI_IM:
+        phy->csiim_vars[0]->csiim_config_pdu = pdu->csiim_config_pdu.csiim_config_rel15;
+        phy->csiim_vars[0]->active = true;
+        break;
+      case FAPI_NR_DL_CONFIG_TYPE_CSI_RS:
+        phy->csirs_vars[0]->csirs_config_pdu = pdu->csirs_config_pdu.csirs_config_rel15;
+        phy->csirs_vars[0]->active = true;
+        break;
+      case FAPI_NR_DL_CONFIG_TYPE_RA_DLSCH: {
+        fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu = &pdu->dlsch_config_pdu.dlsch_config_rel15;
+        NR_UE_DLSCH_t *dlsch0 = phy_data->dlsch + 0;
+        dlsch0->rnti_type = TYPE_RA_RNTI_;
+        dlsch0->dlsch_config = *dlsch_config_pdu;
+        configure_dlsch(dlsch0, phy->dl_harq_processes[0], dlsch_config_pdu, mac, pdu->dlsch_config_pdu.rnti);
+      } break;
+      case FAPI_NR_DL_CONFIG_TYPE_SI_DLSCH: {
+        fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu = &pdu->dlsch_config_pdu.dlsch_config_rel15;
+        NR_UE_DLSCH_t *dlsch0 = phy_data->dlsch + 0;
+        dlsch0->rnti_type = TYPE_SI_RNTI_;
+        dlsch0->dlsch_config = *dlsch_config_pdu;
+        configure_dlsch(dlsch0, phy->dl_harq_processes[0], dlsch_config_pdu, mac, pdu->dlsch_config_pdu.rnti);
+      } break;
+      case FAPI_NR_DL_CONFIG_TYPE_DLSCH: {
+        fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu = &pdu->dlsch_config_pdu.dlsch_config_rel15;
+        NR_UE_DLSCH_t *dlsch0 = &phy_data->dlsch[0];
+        dlsch0->rnti_type = TYPE_C_RNTI_;
+        dlsch0->dlsch_config = *dlsch_config_pdu;
+        configure_dlsch(dlsch0, phy->dl_harq_processes[0], dlsch_config_pdu, mac, pdu->dlsch_config_pdu.rnti);
+      } break;
+      case FAPI_NR_CONFIG_TA_COMMAND:
+        configure_ta_command(phy, &pdu->ta_command_pdu);
+        break;
+      default:
+        LOG_W(PHY, "unhandled dl pdu type %d \n", pdu->pdu_type);
     }
+  }
+  dl_config->number_pdus = 0;
+}
 
-    if (scheduled_response->ul_config != NULL){
-
-      fapi_nr_ul_config_request_t *ul_config = scheduled_response->ul_config;
-      int pdu_done = 0;
-      pthread_mutex_lock(&ul_config->mutex_ul_config);
-
-      LOG_D(PHY, "%d.%d ul S ul_config %p pdu_done %d number_pdus %d\n", scheduled_response->frame, slot, ul_config, pdu_done, ul_config->number_pdus);
-      for (int i = 0; i < ul_config->number_pdus; ++i){
-
-        AssertFatal(ul_config->ul_config_list[i].pdu_type <= FAPI_NR_UL_CONFIG_TYPES,"pdu_type %d out of bounds\n",ul_config->ul_config_list[i].pdu_type);
-        LOG_D(PHY, "[%d.%d] i %d: processing %s PDU of %d total UL PDUs (ul_config %p) \n",
-              scheduled_response->frame, slot, i, ul_pdu_type[ul_config->ul_config_list[i].pdu_type - 1], ul_config->number_pdus, ul_config);
-
-        uint8_t pdu_type = ul_config->ul_config_list[i].pdu_type, current_harq_pid, gNB_id = 0;
-        /* PRACH */
-        fapi_nr_ul_config_prach_pdu *prach_config_pdu;
-        /* PUSCH */
-        nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu;
-        /* PUCCH */
-        fapi_nr_ul_config_pucch_pdu *pucch_config_pdu;
-        LOG_D(PHY, "%d.%d ul B ul_config %p t %d pdu_done %d number_pdus %d\n", scheduled_response->frame, slot, ul_config, pdu_type, pdu_done, ul_config->number_pdus);
-        /* SRS */
-        fapi_nr_ul_config_srs_pdu *srs_config_pdu;
-
-        switch (pdu_type){
-          case FAPI_NR_UL_CONFIG_TYPE_PUSCH: {
-            // pusch config pdu
-            pusch_config_pdu = &ul_config->ul_config_list[i].pusch_config_pdu;
-            current_harq_pid = pusch_config_pdu->pusch_data.harq_process_id;
-            NR_UL_UE_HARQ_t *harq_process_ul_ue = &PHY_vars_UE_g[module_id][cc_id]->ul_harq_processes[current_harq_pid];
-            NR_UE_ULSCH_t *ulsch = &((nr_phy_data_tx_t *)scheduled_response->phy_data)->ulsch;
-            nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &ulsch->pusch_pdu;
-
-            LOG_D(PHY,
-                  "In %s i %d: copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n",
-                  __FUNCTION__,
-                  i,
-                  pusch_config_pdu->nrOfLayers,
-                  pusch_config_pdu->num_dmrs_cdm_grps_no_data);
-
-            memcpy(pusch_pdu, pusch_config_pdu, sizeof(nfapi_nr_ue_pusch_pdu_t));
-            if (scheduled_response->tx_request) {
-              for (int j = 0; j < scheduled_response->tx_request->number_of_pdus; j++) {
-                fapi_nr_tx_request_body_t *tx_req_body = &scheduled_response->tx_request->tx_request_body[j];
-                if ((tx_req_body->pdu_index == i) && (tx_req_body->pdu_length > 0)) {
-                  LOG_D(PHY,
-                        "%d.%d Copying %d bytes to harq_process_ul_ue->a (harq_pid %d)\n",
-                        scheduled_response->frame,
-                        slot,
-                        tx_req_body->pdu_length,
-                        current_harq_pid);
-                  memcpy(harq_process_ul_ue->a, tx_req_body->pdu, tx_req_body->pdu_length);
-                  break;
-                }
-              }
-
-              harq_process_ul_ue->status = ACTIVE;
-              ul_config->ul_config_list[i].pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
-              pdu_done++;
-              LOG_D(PHY,
-                    "%d.%d ul A ul_config %p t %d pdu_done %d number_pdus %d\n",
-                    scheduled_response->frame,
-                    slot,
-                    ul_config,
-                    pdu_type,
-                    pdu_done,
-                    ul_config->number_pdus);
-
-            } else {
-              LOG_E(PHY, "[phy_procedures_nrUE_TX] harq_process_ul_ue is NULL !!\n");
-              return -1;
-            }
-          } break;
-
-          case FAPI_NR_UL_CONFIG_TYPE_PUCCH: {
-            NR_UE_PUCCH *pucch_vars = &((nr_phy_data_tx_t *)scheduled_response->phy_data)->pucch_vars;
-            found = false;
-            pucch_config_pdu = &ul_config->ul_config_list[i].pucch_config_pdu;
-            for (int j = 0; j < 2; j++) {
-              if (pucch_vars->active[j] == false) {
-                LOG_D(PHY, "%d.%d Copying pucch pdu to UE PHY\n", scheduled_response->frame, slot);
-                memcpy((void *)&(pucch_vars->pucch_pdu[j]), (void *)pucch_config_pdu, sizeof(fapi_nr_ul_config_pucch_pdu));
-                pucch_vars->active[j] = true;
-                found = true;
-                ul_config->ul_config_list[i].pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
-                pdu_done++;
-                LOG_D(PHY,
-                      "%d.%d ul A ul_config %p t %d pdu_done %d number_pdus %d\n",
-                      scheduled_response->frame,
-                      slot,
-                      ul_config,
-                      pdu_type,
-                      pdu_done,
-                      ul_config->number_pdus);
-                break;
-              }
-            }
-            if (!found)
-              LOG_E(PHY, "Couldn't find allocation for PUCCH PDU in PUCCH VARS\n");
-          } break;
-
-          case FAPI_NR_UL_CONFIG_TYPE_PRACH:
-            // prach config pdu
-            prach_config_pdu = &ul_config->ul_config_list[i].prach_config_pdu;
-            memcpy((void *)&(PHY_vars_UE_g[module_id][cc_id]->prach_vars[gNB_id]->prach_pdu),
-                   (void *)prach_config_pdu,
-                   sizeof(fapi_nr_ul_config_prach_pdu));
-            PHY_vars_UE_g[module_id][cc_id]->prach_vars[gNB_id]->active = true;
-            ul_config->ul_config_list[i].pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
-            pdu_done++;
-            LOG_D(PHY,
-                  "%d.%d ul A ul_config %p t %d pdu_done %d number_pdus %d\n",
-                  scheduled_response->frame,
-                  slot,
-                  ul_config,
-                  pdu_type,
-                  pdu_done,
-                  ul_config->number_pdus);
-            break;
-
-          case FAPI_NR_UL_CONFIG_TYPE_DONE:
-            pdu_done++; // count the no of pdu processed
-            LOG_D(PHY,
-                  "%d.%d ul A ul_config %p t %d pdu_done %d number_pdus %d\n",
-                  scheduled_response->frame,
-                  slot,
-                  ul_config,
-                  pdu_type,
-                  pdu_done,
-                  ul_config->number_pdus);
-            break;
+static void nr_ue_scheduled_response_ul(PHY_VARS_NR_UE *phy, fapi_nr_ul_config_request_t *ul_config, nr_phy_data_tx_t *phy_data)
+{
+  fapi_nr_ul_config_request_pdu_t *pdu = fapiLockIterator(ul_config, ul_config->frame, ul_config->slot);
+  if (!pdu) {
+    LOG_E(NR_MAC, "Error in locking ul scheduler dtata\n");
+    return;
+  }
 
-          case FAPI_NR_UL_CONFIG_TYPE_SRS:
-            // srs config pdu
-            srs_config_pdu = &ul_config->ul_config_list[i].srs_config_pdu;
-            memcpy((void *)&(PHY_vars_UE_g[module_id][cc_id]->srs_vars[gNB_id]->srs_config_pdu),
-                   (void *)srs_config_pdu,
-                   sizeof(fapi_nr_ul_config_srs_pdu));
-            PHY_vars_UE_g[module_id][cc_id]->srs_vars[gNB_id]->active = true;
-            ul_config->ul_config_list[i].pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
-            pdu_done++;
-            break;
+  while (pdu->pdu_type != FAPI_NR_END) {
+    switch (pdu->pdu_type) {
+      case FAPI_NR_UL_CONFIG_TYPE_PUSCH: {
+        // pusch config pdu
+        int current_harq_pid = pdu->pusch_config_pdu.pusch_data.harq_process_id;
+        NR_UL_UE_HARQ_t *harq_process_ul_ue = &phy->ul_harq_processes[current_harq_pid];
+        nfapi_nr_ue_pusch_pdu_t *pusch_pdu = &phy_data->ulsch.pusch_pdu;
+        LOG_D(PHY,
+              "copy pusch_config_pdu nrOfLayers:%d, num_dmrs_cdm_grps_no_data:%d \n",
+              pdu->pusch_config_pdu.nrOfLayers,
+              pdu->pusch_config_pdu.num_dmrs_cdm_grps_no_data);
+
+        memcpy(pusch_pdu, &pdu->pusch_config_pdu, sizeof(*pusch_pdu));
+        if (pdu->pusch_config_pdu.tx_request_body.pdu) {
+          LOG_D(PHY,
+                "%d.%d Copying %d bytes to harq_process_ul_ue->a (harq_pid %d)\n",
+                ul_config->frame,
+                ul_config->slot,
+                pdu->pusch_config_pdu.tx_request_body.pdu_length,
+                current_harq_pid);
+          memcpy(harq_process_ul_ue->a,
+                 pdu->pusch_config_pdu.tx_request_body.pdu,
+                 pdu->pusch_config_pdu.tx_request_body.pdu_length);
+        }
 
-          default:
-            ul_config->ul_config_list[i].pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
-            pdu_done++; // count the no of pdu processed
-            LOG_D(PHY,
-                  "%d.%d ul A ul_config %p t %d pdu_done %d number_pdus %d\n",
-                  scheduled_response->frame,
-                  slot,
-                  ul_config,
-                  pdu_type,
-                  pdu_done,
-                  ul_config->number_pdus);
+        harq_process_ul_ue->status = ACTIVE;
+        pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
+      } break;
+
+      case FAPI_NR_UL_CONFIG_TYPE_PUCCH: {
+        bool found = false;
+        for (int j = 0; j < 2; j++) {
+          if (phy_data->pucch_vars.active[j] == false) {
+            LOG_D(PHY, "Copying pucch pdu to UE PHY\n");
+            phy_data->pucch_vars.pucch_pdu[j] = pdu->pucch_config_pdu;
+            phy_data->pucch_vars.active[j] = true;
+            found = true;
+            pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
             break;
+          }
         }
-      }
-
-
-      //Clear the fields when all the config pdu are done
-      if (pdu_done == ul_config->number_pdus) {
-        if (scheduled_response->tx_request)
-          scheduled_response->tx_request->number_of_pdus = 0;
-        ul_config->sfn = 0;
-        ul_config->slot = 0;
-        ul_config->number_pdus = 0;
-        LOG_D(PHY, "%d.%d clear ul_config %p\n", scheduled_response->frame, slot, ul_config);
-        memset(ul_config->ul_config_list, 0, sizeof(ul_config->ul_config_list));
-      }
-
-      pthread_mutex_unlock(&ul_config->mutex_ul_config);
+        if (!found)
+          LOG_E(PHY, "Couldn't find allocation for PUCCH PDU in PUCCH VARS\n");
+      } break;
+
+      case FAPI_NR_UL_CONFIG_TYPE_PRACH: {
+        phy->prach_vars[0]->prach_pdu = pdu->prach_config_pdu;
+        phy->prach_vars[0]->active = true;
+        pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
+      } break;
+
+      case FAPI_NR_UL_CONFIG_TYPE_DONE:
+        break;
+
+      case FAPI_NR_UL_CONFIG_TYPE_SRS:
+        // srs config pdu
+        phy->srs_vars[0]->srs_config_pdu = pdu->srs_config_pdu;
+        phy->srs_vars[0]->active = true;
+        pdu->pdu_type = FAPI_NR_UL_CONFIG_TYPE_DONE; // not handle it any more
+        break;
+
+      default:
+        LOG_W(PHY, "unhandled ul pdu type %d \n", pdu->pdu_type);
+        break;
     }
+    pdu++;
   }
+
+  LOG_D(PHY, "clear ul_config\n");
+  release_ul_config(pdu, true);
+}
+
+int8_t nr_ue_scheduled_response(nr_scheduled_response_t *scheduled_response)
+{
+  PHY_VARS_NR_UE *phy = PHY_vars_UE_g[scheduled_response->module_id][scheduled_response->CC_id];
+  AssertFatal(!scheduled_response->dl_config || !scheduled_response->ul_config,
+              "phy_data parameter will be cast to two different types!\n");
+
+  if (scheduled_response->dl_config)
+    nr_ue_scheduled_response_dl(scheduled_response->mac,
+                                phy,
+                                scheduled_response->dl_config,
+                                (nr_phy_data_t *)scheduled_response->phy_data);
+  if (scheduled_response->ul_config)
+    nr_ue_scheduled_response_ul(phy, scheduled_response->ul_config, (nr_phy_data_tx_t *)scheduled_response->phy_data);
   return 0;
 }
 
diff --git a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h
index d83c014fa672fd0f107348a61f6459b5b0dc5645..65ca8455261143c2fe26b7ef25e3877036654360 100644
--- a/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h
+++ b/openair1/SCHED_NR_UE/fapi_nr_ue_l1.h
@@ -51,6 +51,6 @@ int8_t nr_ue_phy_config_request(nr_phy_config_t *phy_config);
    \param synch_request including target_Nid_cell*/
 void nr_ue_synch_request(nr_synch_request_t *synch_request);
 
-void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nack);
+void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nack);
 
 #endif
diff --git a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
index 14091975f38d7198b99c3eee854082ee75030855..1a2e41007192e2893f6819b5a67731f5a2c9638a 100644
--- a/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
+++ b/openair1/SCHED_NR_UE/phy_procedures_nr_ue.c
@@ -510,6 +510,9 @@ static int nr_ue_pdsch_procedures(PHY_VARS_NR_UE *ue,
     uint16_t s0             = dlsch0->dlsch_config.start_symbol;
     uint16_t s1             = dlsch0->dlsch_config.number_symbols;
 
+    AssertFatal(dlsch0->dlsch_config.resource_alloc == 1,
+                "DLSCH resource allocation type0 not supported at PHY\n");
+
     LOG_D(PHY,"[UE %d] nr_slot_rx %d, harq_pid %d (%d), BWP start %d, rb_start %d, nb_rb %d, symbol_start %d, nb_symbols %d, DMRS mask %x, Nl %d\n",
           ue->Mod_id,nr_slot_rx,harq_pid,dlsch0_harq->status,BWPStart,pdsch_start_rb,pdsch_nb_rb,s0,s1,dlsch0->dlsch_config.dlDmrsSymbPos, dlsch0->Nl);
 
@@ -1025,7 +1028,6 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
   time_stats_t meas = {0};
   start_meas(&meas);
   // do procedures for C-RNTI
-  int ret_pdsch = 0;
 
   const uint32_t rxdataF_sz = ue->frame_parms.samples_per_slot_wCP;
   __attribute__ ((aligned(32))) c16_t rxdataF[ue->frame_parms.nb_antennas_rx][rxdataF_sz];
@@ -1081,11 +1083,8 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
       llr[i] = (int16_t *)malloc16_clear(rx_llr_buf_sz * sizeof(int16_t));
 
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_C, VCD_FUNCTION_IN);
-    ret_pdsch = nr_ue_pdsch_procedures(ue,
-                                       proc,
-                                       dlsch,
-                                       llr,
-                                       rxdataF);
+    // it returns -1 in case of internal failure, or 0 in case of normal result
+    int ret_pdsch = nr_ue_pdsch_procedures(ue, proc, dlsch, llr, rxdataF);
 
     VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDSCH_PROC_C, VCD_FUNCTION_OUT);
 
@@ -1103,6 +1102,7 @@ void pdsch_processing(PHY_VARS_NR_UE *ue, const UE_nr_rxtx_proc_t *proc, nr_phy_
       send_dl_done_to_tx_thread(
           ue->tx_resume_ind_fifo + (proc->nr_slot_rx + dlsch_config->k1_feedback) % ue->frame_parms.slots_per_frame,
           proc->nr_slot_rx);
+      LOG_W(NR_PHY, "nr_ue_pdsch_procedures failed in slot %d\n", proc->nr_slot_rx);
     }
 
     stop_meas(&ue->dlsch_procedures_stat);
diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c
index 51da3088fa293c1db1278353e316f96c2912f052..5e6b8c5f454078f2f74b1259f87e47fe81780454 100644
--- a/openair1/SIMULATION/NR_PHY/dlsim.c
+++ b/openair1/SIMULATION/NR_PHY/dlsim.c
@@ -871,27 +871,14 @@ int main(int argc, char **argv)
   nr_rrc_mac_config_req_mib(0, 0, mib->message.choice.mib, false);
   nr_rrc_mac_config_req_cg(0, 0, UE_CellGroup);
 
+  asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, UE_CellGroup);
+
   UE_mac->state = UE_CONNECTED;
   UE_mac->ra.ra_state = RA_SUCCEEDED;
 
-  nr_dcireq_t dcireq;
-  nr_scheduled_response_t scheduled_response;
   nr_phy_data_t phy_data = {0};
-
-  memset((void*)&dcireq,0,sizeof(dcireq));
-  memset((void*)&scheduled_response,0,sizeof(scheduled_response));
-  dcireq.module_id = 0;
-  dcireq.gNB_index = 0;
-  dcireq.cc_id = 0;
-  
-  scheduled_response.dl_config = &dcireq.dl_config_req;
-  scheduled_response.ul_config = &dcireq.ul_config_req;
-  scheduled_response.tx_request = NULL;
-  scheduled_response.module_id = 0;
-  scheduled_response.CC_id = 0;
-  scheduled_response.frame = frame;
-  scheduled_response.slot  = slot;
-  scheduled_response.phy_data = &phy_data;
+  fapi_nr_dl_config_request_t dl_config = {.sfn = frame, .slot = slot};
+  nr_scheduled_response_t scheduled_response = {.dl_config = &dl_config, .phy_data = &phy_data, .mac = UE_mac};
 
   nr_ue_phy_config_request(&UE_mac->phy_config);
   //NR_COMMON_channels_t *cc = RC.nrmac[0]->common_channels;
@@ -976,9 +963,6 @@ int main(int argc, char **argv)
       UE_proc.frame_rx = frame;
       UE_proc.nr_slot_rx = slot;
       UE_proc.gNB_id = 0;
-      
-      dcireq.frame = frame;
-      dcireq.slot = slot;
 
       NR_UE_DLSCH_t *dlsch0 = &phy_data.dlsch[0];
 
@@ -1114,8 +1098,9 @@ int main(int argc, char **argv)
         // Apply MIMO Channel
         multipath_channel(gNB2UE, s_re, s_im, r_re, r_im, slot_length, 0, (n_trials == 1) ? 1 : 0);
         add_noise(UE->common_vars.rxdata, (const double **) r_re, (const double **) r_im, sigma2, slot_length, slot_offset, ts, delay, pdu_bit_map, 0x1, frame_parms->nb_antennas_rx);
-
-        nr_ue_dcireq(&dcireq); //to be replaced with function pointer later
+        dl_config.sfn = frame;
+        dl_config.slot = slot;
+        ue_dci_configuration(UE_mac, &dl_config, frame, slot);
         nr_ue_scheduled_response(&scheduled_response);
 
         pbch_pdcch_processing(UE,
diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c
index 9b227f3b7a2c7c9a070a4a0ced1a4590954b13d6..cc043c79748c68ab2fb571e9aa1481e709edc096 100644
--- a/openair1/SIMULATION/NR_PHY/ulsim.c
+++ b/openair1/SIMULATION/NR_PHY/ulsim.c
@@ -718,9 +718,7 @@ int main(int argc, char *argv[])
 
   uint32_t errors_decoding = 0;
 
-  nr_scheduled_response_t scheduled_response={0};
-  fapi_nr_ul_config_request_t ul_config={0};
-  fapi_nr_tx_request_t tx_req={0};
+  fapi_nr_ul_config_request_t ul_config = {0};
 
   uint8_t ptrs_mcs1 = 2;
   uint8_t ptrs_mcs2 = 4;
@@ -1073,24 +1071,7 @@ int main(int argc, char *argv[])
         nr_schedule_response(Sched_INFO);
 
         // --------- setting parameters for UE --------
-
-        scheduled_response.module_id = 0;
-        scheduled_response.CC_id = 0;
-        scheduled_response.frame = frame;
-        scheduled_response.slot = slot;
-        scheduled_response.dl_config = NULL;
-        scheduled_response.ul_config = &ul_config;
-        scheduled_response.tx_request = &tx_req;
-        scheduled_response.phy_data = (void *)&phy_data;
-
-        // Config UL TX PDU
-        tx_req.slot = slot;
-        tx_req.sfn = frame;
-        tx_req.number_of_pdus = 1; //do_SRS == 1 ? 2 : 1;
-
-        tx_req.tx_request_body[0].pdu_length = TBS / 8;
-        tx_req.tx_request_body[0].pdu_index = 0;
-        tx_req.tx_request_body[0].pdu = &ulsch_input_buffer[0];
+        nr_scheduled_response_t scheduled_response = {.ul_config = &ul_config, .phy_data = (void *)&phy_data};
 
         ul_config.slot = slot;
         ul_config.number_pdus = do_SRS == 1 ? 2 : 1;
@@ -1098,6 +1079,9 @@ int main(int argc, char *argv[])
         fapi_nr_ul_config_request_pdu_t *ul_config0 = &ul_config.ul_config_list[0];
         ul_config0->pdu_type = FAPI_NR_UL_CONFIG_TYPE_PUSCH;
         nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &ul_config0->pusch_config_pdu;
+        // Config UL TX PDU
+        pusch_config_pdu->tx_request_body.pdu = ulsch_input_buffer;
+        pusch_config_pdu->tx_request_body.pdu_length = TBS / 8;
         pusch_config_pdu->rnti = n_rnti;
         pusch_config_pdu->pdu_bit_map = pdu_bit_map;
         pusch_config_pdu->qam_mod_order = mod_order;
diff --git a/openair2/COMMON/e1ap_messages_def.h b/openair2/COMMON/e1ap_messages_def.h
index ea24ac9e18719cca0c4d641589a27a90ca60044a..df72a99f7f79e2037ebc6c9c3d184ec2bb6f99da 100644
--- a/openair2/COMMON/e1ap_messages_def.h
+++ b/openair2/COMMON/e1ap_messages_def.h
@@ -22,18 +22,27 @@
 /* gNB_CUUP application layer -> E1AP messages */
 MESSAGE_DEF(E1AP_REGISTER_REQ, MESSAGE_PRIORITY_MED, e1ap_register_req_t, e1ap_register_req)
 
-/* E1AP messages -> RRC (CU-CP) */
-MESSAGE_DEF(E1AP_SETUP_REQ  , MESSAGE_PRIORITY_MED , e1ap_setup_req_t , e1ap_setup_req)
+/* E1AP -> RRC to inform about lost connection */
+MESSAGE_DEF(E1AP_LOST_CONNECTION, MESSAGE_PRIORITY_MED, e1ap_lost_connection_t, e1ap_lost_connection)
 
-/* E1AP -> eNB_DU or eNB_CU_RRC -> E1AP application layer messages */
+/* E1AP Interface Management Messages */
+/* E1AP Setup Request: gNB-CU-UP -> gNB-CU-CP */
+MESSAGE_DEF(E1AP_SETUP_REQ  , MESSAGE_PRIORITY_MED , e1ap_setup_req_t , e1ap_setup_req)
+/* E1AP Setup Response: gNB-CU-CP -> gNB-CU-UP */
 MESSAGE_DEF(E1AP_SETUP_RESP , MESSAGE_PRIORITY_MED, e1ap_setup_resp_t , e1ap_setup_resp)
+/* E1AP Setup Failure: gNB-CU-CP -> gNB-CU-UP */
+MESSAGE_DEF(E1AP_SETUP_FAIL, MESSAGE_PRIORITY_MED, e1ap_setup_fail_t, e1ap_setup_fail)
 
+/* E1AP Bearer Context Management Procedures */
+/* E1AP Bearer Context Setup Request: gNB-CU-CP -> gNB-CU-UP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_req_t , e1ap_bearer_setup_req)
-
+/* E1AP Bearer Context Setup Response: gNB-CU-UP -> gNB-CU-CP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_RESP , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_resp_t , e1ap_bearer_setup_resp)
-
+/* E1AP Bearer Context Modification Request: gNB-CU-CP -> gNB-CU-UP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_req_t , e1ap_bearer_mod_req)
+/* E1AP Bearer Context Modification Response: gNB-CU-UP -> gNB-CU-CP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, e1ap_bearer_modif_resp_t, e1ap_bearer_modif_resp)
-
+/* E1AP Bearer Context Release Request: gNB-CU-CP -> gNB-CU-UP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cmd_t, e1ap_bearer_release_cmd)
+/* E1AP Bearer Context Release Response: gNB-CU-UP -> gNB-CU-CP */
 MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CPLT, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cplt_t, e1ap_bearer_release_cplt)
diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h
index b6400b53b55a0a04ccc0df9e704cb7a747b3288c..43d63924e0c1011fd240a28899a2625597352ac7 100644
--- a/openair2/COMMON/e1ap_messages_types.h
+++ b/openair2/COMMON/e1ap_messages_types.h
@@ -44,12 +44,14 @@
 #define E1AP_REGISTER_REQ(mSGpTR)                         (mSGpTR)->ittiMsg.e1ap_register_req
 #define E1AP_SETUP_REQ(mSGpTR)                            (mSGpTR)->ittiMsg.e1ap_setup_req
 #define E1AP_SETUP_RESP(mSGpTR)                           (mSGpTR)->ittiMsg.e1ap_setup_resp
+#define E1AP_SETUP_FAIL(mSGpTR)                           (mSGpTR)->ittiMsg.e1ap_setup_fail
 #define E1AP_BEARER_CONTEXT_SETUP_REQ(mSGpTR)             (mSGpTR)->ittiMsg.e1ap_bearer_setup_req
 #define E1AP_BEARER_CONTEXT_SETUP_RESP(mSGpTR)            (mSGpTR)->ittiMsg.e1ap_bearer_setup_resp
 #define E1AP_BEARER_CONTEXT_MODIFICATION_REQ(mSGpTR)      (mSGpTR)->ittiMsg.e1ap_bearer_setup_req
 #define E1AP_BEARER_CONTEXT_MODIFICATION_RESP(mSGpTR)     (mSGpTR)->ittiMsg.e1ap_bearer_modif_resp
 #define E1AP_BEARER_CONTEXT_RELEASE_CMD(mSGpTR)           (mSGpTR)->ittiMsg.e1ap_bearer_release_cmd
 #define E1AP_BEARER_CONTEXT_RELEASE_CPLT(mSGpTR)          (mSGpTR)->ittiMsg.e1ap_bearer_release_cplt
+#define E1AP_LOST_CONNECTION(mSGpTR)                      (mSGpTR)->ittiMsg.e1ap_lost_connection
 
 typedef net_ip_address_t e1ap_net_ip_address_t;
 
@@ -94,6 +96,11 @@ typedef struct e1ap_setup_resp_s {
   long transac_id;
 } e1ap_setup_resp_t;
 
+/* E1AP Setup Failure */
+typedef struct e1ap_setup_fail_s {
+  long transac_id;
+} e1ap_setup_fail_t;
+
 typedef struct cell_group_s {
   long id;
 } cell_group_t;
@@ -273,4 +280,10 @@ typedef struct e1ap_bearer_modif_resp_s {
   pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS];
 } e1ap_bearer_modif_resp_t;
 
+/* E1AP Connection Loss indication */
+typedef struct e1ap_lost_connection_t {
+  int dummy;
+} e1ap_lost_connection_t;
+
+
 #endif /* E1AP_MESSAGES_TYPES_H */
diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c
index 353b8931e19c4443bdb3c0b4c43f8ef3a7c07f5d..79581698d9c049dcbb7cfd5e4a0147eb1dde660b 100644
--- a/openair2/E1AP/e1ap.c
+++ b/openair2/E1AP/e1ap.c
@@ -36,6 +36,10 @@
 
 #define E1AP_NUM_MSG_HANDLERS 14
 typedef int (*e1ap_message_processing_t)(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p);
+
+/**
+ * @brief E1AP messages handlers
+ */
 const e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3] = {
 
     {0, 0, 0}, /* Reset */
@@ -61,17 +65,17 @@ const e1ap_message_processing_t e1ap_message_processing[E1AP_NUM_MSG_HANDLERS][3
 const char *const e1ap_direction2String(int e1ap_dir)
 {
   static const char *e1ap_direction_String[] = {
-    "", /* Nothing */
-    "Initiating message", /* initiating message */
-    "Successfull outcome", /* successfull outcome */
-    "UnSuccessfull outcome", /* successfull outcome */
+      "", /* Nothing */
+      "Initiating message", /* initiating message */
+      "Successfull outcome", /* successfull outcome */
+      "UnSuccessfull outcome", /* successfull outcome */
   };
-  return(e1ap_direction_String[e1ap_dir]);
+  return (e1ap_direction_String[e1ap_dir]);
 }
 
-int e1ap_handle_message(instance_t instance, sctp_assoc_t assoc_id, const uint8_t *const data, const uint32_t data_length)
+static int e1ap_handle_message(instance_t instance, sctp_assoc_t assoc_id, const uint8_t *const data, const uint32_t data_length)
 {
-  E1AP_E1AP_PDU_t pdu= {0};
+  E1AP_E1AP_PDU_t pdu = {0};
   int ret;
   DevAssert(data != NULL);
 
@@ -81,19 +85,25 @@ int e1ap_handle_message(instance_t instance, sctp_assoc_t assoc_id, const uint8_
   }
   const E1AP_ProcedureCode_t procedureCode = pdu.choice.initiatingMessage->procedureCode;
   /* Checking procedure Code and direction of message */
-  if ((procedureCode >= E1AP_NUM_MSG_HANDLERS) || (pdu.present > E1AP_E1AP_PDU_PR_unsuccessfulOutcome) || (pdu.present <= E1AP_E1AP_PDU_PR_NOTHING)) {
+  if ((procedureCode >= E1AP_NUM_MSG_HANDLERS) || (pdu.present > E1AP_E1AP_PDU_PR_unsuccessfulOutcome)
+      || (pdu.present <= E1AP_E1AP_PDU_PR_NOTHING)) {
     LOG_E(E1AP, "[SCTP %d] Either procedureCode %ld or direction %d exceed expected\n", assoc_id, procedureCode, pdu.present);
     ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_E1AP_E1AP_PDU, &pdu);
     return -1;
   }
 
   if (e1ap_message_processing[procedureCode][pdu.present - 1] == NULL) {
-    // No handler present. This can mean not implemented or no procedure for eNB (wrong direction).
-    LOG_E(E1AP, "[SCTP %d] No handler for procedureCode %ld in %s\n", assoc_id, procedureCode, e1ap_direction2String(pdu.present - 1));
-    ret=-1;
+    // No handler present. This can mean not implemented or no procedure for eNB
+    // (wrong direction).
+    LOG_E(E1AP,
+          "[SCTP %d] No handler for procedureCode %ld in %s\n",
+          assoc_id,
+          procedureCode,
+          e1ap_direction2String(pdu.present - 1));
+    ret = -1;
   } else {
     /* Calling the right handler */
-    LOG_D(E1AP, "Calling handler with instance %ld\n",instance);
+    LOG_D(E1AP, "Calling handler with instance %ld\n", instance);
     ret = (*e1ap_message_processing[procedureCode][pdu.present - 1])(assoc_id, getCxtE1(instance), &pdu);
   }
 
@@ -101,37 +111,37 @@ int e1ap_handle_message(instance_t instance, sctp_assoc_t assoc_id, const uint8_
   return ret;
 }
 
-void e1_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind)
+static void e1_task_handle_sctp_data_ind(instance_t instance, sctp_data_ind_t *sctp_data_ind)
 {
   int result;
   DevAssert(sctp_data_ind != NULL);
-  e1ap_handle_message(instance, sctp_data_ind->assoc_id,
-                      sctp_data_ind->buffer, sctp_data_ind->buffer_length);
+  e1ap_handle_message(instance, sctp_data_ind->assoc_id, sctp_data_ind->buffer, sctp_data_ind->buffer_length);
   result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
-  AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
+  AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
 }
 
 int e1ap_send_RESET(bool isCu, sctp_assoc_t assoc_id, E1AP_Reset_t *Reset)
 {
-  AssertFatal(false,"Not implemented yet\n");
-  E1AP_E1AP_PDU_t pdu= {0};
+  AssertFatal(false, "Not implemented yet\n");
+  E1AP_E1AP_PDU_t pdu = {0};
   return e1ap_encode_send(isCu, assoc_id, &pdu, 0, __func__);
 }
 
-int e1ap_send_RESET_ACKNOWLEDGE(instance_t instance, E1AP_Reset_t *Reset) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1ap_send_RESET_ACKNOWLEDGE(instance_t instance, E1AP_Reset_t *Reset)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1ap_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1ap_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -140,16 +150,16 @@ int e1ap_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, ui
 */
 int e1ap_handle_ERROR_INDICATION(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1ap_send_ERROR_INDICATION(instance_t instance, E1AP_ErrorIndication_t *ErrorIndication) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1ap_send_ERROR_INDICATION(instance_t instance, E1AP_ErrorIndication_t *ErrorIndication)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-
 /*
     E1 Setup: can be sent on both ways, to be refined
 */
@@ -207,7 +217,7 @@ static void fill_SETUP_REQUEST(e1ap_setup_req_t *setup, E1AP_E1AP_PDU_t *pdu)
 
   int numSupportedPLMNs = setup->supported_plmns;
 
-  for (int i=0; i < numSupportedPLMNs; i++) {
+  for (int i = 0; i < numSupportedPLMNs; i++) {
     asn1cSequenceAdd(ieC5->value.choice.SupportedPLMNs_List.list, E1AP_SupportedPLMNs_Item_t, supportedPLMN);
     /* 5.1 PLMN Identity */
     PLMN_ID_t *id = &setup->plmn[i].id;
@@ -257,25 +267,36 @@ void e1ap_send_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_setup_resp_t *e1
   e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__);
 }
 
+/**
+ * @brief E1 Setup Failure ASN1 messager builder
+ * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463
+ */
 static void fill_SETUP_FAILURE(long transac_id, E1AP_E1AP_PDU_t *pdu)
 {
   /* Create */
   /* 0. pdu Type */
   pdu->present = E1AP_E1AP_PDU_PR_unsuccessfulOutcome;
   asn1cCalloc(pdu->choice.unsuccessfulOutcome, initMsg);
+  /* mandatory */
+  /**
+   * Message Type IE
+   * -  procedureCode (integer)
+   * -  Type of Message (choice)
+   * @ref clause 9.3.1.1 of 3GPP TS 38.463
+   */
   initMsg->procedureCode = E1AP_ProcedureCode_id_gNB_CU_UP_E1Setup;
   initMsg->criticality = E1AP_Criticality_reject;
   initMsg->value.present = E1AP_UnsuccessfulOutcome__value_PR_GNB_CU_UP_E1SetupFailure;
   E1AP_GNB_CU_UP_E1SetupFailure_t *out = &pdu->choice.unsuccessfulOutcome->value.choice.GNB_CU_UP_E1SetupFailure;
   /* mandatory */
-  /* c1. Transaction ID (integer value) */
+  /* c1. Transaction ID (integer value), clause 9.3.1.53 of 3GPP TS 38.463 */
   asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ieC1);
   ieC1->id                         = E1AP_ProtocolIE_ID_id_TransactionID;
   ieC1->criticality                = E1AP_Criticality_reject;
   ieC1->value.present              = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_TransactionID;
   ieC1->value.choice.TransactionID = transac_id;
   /* mandatory */
-  /* c2. cause (integer value) */
+  /* c2. cause (integer value), clause 9.3.1.2 of 3GPP TS 38.463 */
   asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ieC2);
   ieC2->id                         = E1AP_ProtocolIE_ID_id_Cause;
   ieC2->criticality                = E1AP_Criticality_ignore;
@@ -284,33 +305,34 @@ static void fill_SETUP_FAILURE(long transac_id, E1AP_E1AP_PDU_t *pdu)
   ieC2->value.choice.Cause.choice.radioNetwork = E1AP_CauseRadioNetwork_unspecified;
 }
 
+/**
+ * @brief E1 Setup Failure ASN1 messager encoder
+ */
 void e1apCUCP_send_SETUP_FAILURE(sctp_assoc_t assoc_id, long transac_id)
 {
+  LOG_D(E1AP, "CU-CP: Encoding E1AP Setup Failure for transac_id %ld...\n", transac_id);
   E1AP_E1AP_PDU_t pdu = {0};
   fill_SETUP_FAILURE(transac_id, &pdu);
   e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__);
 }
 
-void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
-                           e1ap_setup_req_t *req) {
+static void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_req_t *req)
+{
   E1AP_GNB_CU_UP_E1SetupRequestIEs_t *ie;
   E1AP_GNB_CU_UP_E1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.GNB_CU_UP_E1SetupRequest;
 
   /* transac_id */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_TransactionID, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true);
   req->transac_id = ie->value.choice.TransactionID;
   LOG_D(E1AP, "gNB CU UP E1 setup request transaction ID: %ld\n", req->transac_id);
 
   /* gNB CU UP ID */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_ID, true);
   asn_INTEGER2ulong(&ie->value.choice.GNB_CU_UP_ID, &req->gNB_cu_up_id);
   LOG_D(E1AP, "gNB CU UP ID: %ld\n", req->gNB_cu_up_id);
 
   /* gNB CU UP name */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name, false);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_Name, false);
   req->gNB_cu_up_name = NULL;
   if (ie != NULL) {
     req->gNB_cu_up_name = calloc(ie->value.choice.GNB_CU_UP_Name.size + 1, sizeof(char));
@@ -320,18 +342,17 @@ void extract_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
   }
 
   /* CN Support */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_CNSupport, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_CNSupport, true);
   AssertFatal(ie->value.choice.CNSupport == E1AP_CNSupport_c_5gc, "only 5GC CN Support supported\n");
 
   /* Supported PLMNs */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_SupportedPLMNs, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_SupportedPLMNs, true);
   req->supported_plmns = ie->value.choice.SupportedPLMNs_List.list.count;
   LOG_D(E1AP, "Number of supported PLMNs: %d\n", req->supported_plmns);
 
-  for (int i=0; i < req->supported_plmns; i++) {
-    E1AP_SupportedPLMNs_Item_t *supported_plmn_item = (E1AP_SupportedPLMNs_Item_t *)(ie->value.choice.SupportedPLMNs_List.list.array[i]);
+  for (int i = 0; i < req->supported_plmns; i++) {
+    E1AP_SupportedPLMNs_Item_t *supported_plmn_item =
+        (E1AP_SupportedPLMNs_Item_t *)(ie->value.choice.SupportedPLMNs_List.list.array[i]);
 
     /* PLMN Identity */
     PLMN_ID_t *id = &req->plmn[i].id;
@@ -389,8 +410,7 @@ int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst
   /* transac_id */
   long transaction_id;
   long old_transaction_id = inst->cuup.setupReq.transac_id;
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_TransactionID, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true);
   transaction_id = ie->value.choice.TransactionID;
   LOG_D(E1AP, "gNB CU UP E1 setup response transaction ID: %ld\n", transaction_id);
 
@@ -404,18 +424,29 @@ int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst
   return 0;
 }
 
+/**
+ * @brief E1 Setup Failure ASN1 messager decoder on CU-UP
+ */
 int e1apCUUP_handle_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu)
 {
+  LOG_D(E1AP, "CU-UP: Decoding E1AP Setup Failure...\n");
   E1AP_GNB_CU_UP_E1SetupFailureIEs_t *ie;
   DevAssert(pdu != NULL);
   E1AP_GNB_CU_UP_E1SetupFailure_t *in = &pdu->choice.unsuccessfulOutcome->value.choice.GNB_CU_UP_E1SetupFailure;
   /* Transaction ID */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_TransactionID, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_TransactionID, true);
+  long transaction_id;
+  long old_transaction_id = inst->cuup.setupReq.transac_id;
+  transaction_id = ie->value.choice.TransactionID;
+  if (old_transaction_id != transaction_id)
+    LOG_E(E1AP, "Transaction IDs do not match %ld != %ld\n", old_transaction_id, transaction_id);
+  E1AP_free_transaction_identifier(transaction_id);
+
   /* Cause */
-  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in,
-                             E1AP_ProtocolIE_ID_id_Cause, true);
+  F1AP_FIND_PROTOCOLIE_BY_ID(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true);
 
+  LOG_E(E1AP, "received E1 Setup Failure, please check the CU-CP output and the CU-UP parameters\n");
+  exit(1);
   return 0;
 }
 
@@ -445,7 +476,7 @@ static void fill_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu)
 
   int numSupportedPLMNs = 1;
 
-  for (int i=0; i < numSupportedPLMNs; i++) {
+  for (int i = 0; i < numSupportedPLMNs; i++) {
     asn1cSequenceAdd(ieC2->value.choice.SupportedPLMNs_List.list, E1AP_SupportedPLMNs_Item_t, supportedPLMN);
     /* 5.1 PLMN Identity */
     OCTET_STRING_fromBuf(&supportedPLMN->pLMN_Identity, "OAI", strlen("OAI"));
@@ -460,7 +491,7 @@ static void fill_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu)
 
   int numTNLAtoRemoveList = 1;
 
-  for (int i=0; i < numTNLAtoRemoveList; i++) {
+  for (int i = 0; i < numTNLAtoRemoveList; i++) {
     asn1cSequenceAdd(ieC2->value.choice.GNB_CU_UP_TNLA_To_Remove_List.list, E1AP_GNB_CU_UP_TNLA_To_Remove_Item_t, TNLAtoRemove);
     TNLAtoRemove->tNLAssociationTransportLayerAddress.present = E1AP_CP_TNL_Information_PR_endpoint_IP_Address;
     TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(1234, &TNLAtoRemove->tNLAssociationTransportLayerAddress.choice.endpoint_IP_Address); // TODO: correct me
@@ -480,13 +511,13 @@ void e1apCUUP_send_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id)
 
 int e1apCUCP_send_gNB_DU_CONFIGURATION_FAILURE(void)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1apCUCP_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(void)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -498,23 +529,19 @@ int e1apCUCP_handle_CONFIGURATION_UPDATE(E1AP_E1AP_PDU_t *pdu)
   E1AP_GNB_CU_UP_E1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.GNB_CU_UP_E1SetupRequest;
   */
 
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1apCUUP_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id,
-                                                            uint32_t stream,
-                                                            E1AP_E1AP_PDU_t *pdu)
+int e1apCUUP_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1apCUUP_handle_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id,
-                                                 uint32_t stream,
-                                                 E1AP_E1AP_PDU_t *pdu)
+int e1apCUUP_handle_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -522,25 +549,27 @@ int e1apCUUP_handle_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id,
   E1 release
 */
 
-int e1ap_send_RELEASE_REQUEST(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1ap_send_RELEASE_REQUEST(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1ap_send_RELEASE_ACKNOWLEDGE(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1ap_send_RELEASE_ACKNOWLEDGE(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1ap_handle_RELEASE_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1ap_handle_RELEASE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -612,7 +641,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear
   msgNGRAN->criticality = E1AP_Criticality_reject;
   msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List;
   E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
-  for(pdu_session_to_setup_t *i=bearerCxt->pduSession; i < bearerCxt->pduSession+bearerCxt->numPDUSessions; i++) {
+  for (pdu_session_to_setup_t *i = bearerCxt->pduSession; i < bearerCxt->pduSession + bearerCxt->numPDUSessions; i++) {
     asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1);
     ieC6_1->pDU_Session_ID = i->sessionId;
     ieC6_1->pDU_Session_Type = i->sessionType;
@@ -632,7 +661,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear
     TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
     INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
 
-    for (DRB_nGRAN_to_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRB2Setup; j++) {
+    for (DRB_nGRAN_to_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRB2Setup; j++) {
       asn1cSequenceAdd(ieC6_1->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1);
       ieC6_1_1->dRB_ID = j->id;
 
@@ -648,12 +677,12 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear
       roTimer->t_Reordering = j->reorderingTimer;
       ieC6_1_1->pDCP_Configuration.rLC_Mode        = j->rLC_Mode;
 
-      for (cell_group_t *k=j->cellGroupList; k < j->cellGroupList+j->numCellGroups; k++) {
+      for (cell_group_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) {
         asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1);
         ieC6_1_1_1->cell_Group_ID = k->id;
       }
 
-      for (qos_flow_to_setup_t *k=j->qosFlows; k < j->qosFlows+j->numQosFlow2Setup; k++) {
+      for (qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
         asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1);
         ieC6_1_1_1->qoS_Flow_Identifier = k->qfi;
 
@@ -697,66 +726,78 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *r
   pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome;
   asn1cCalloc(pdu->choice.successfulOutcome, msg);
   msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup;
-  msg->criticality   = E1AP_Criticality_reject;
+  msg->criticality = E1AP_Criticality_reject;
   msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse;
   E1AP_BearerContextSetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
   /* mandatory */
   /* c1. gNB-CU-CP UE E1AP ID */
   asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC1);
-  ieC1->id                         = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
-  ieC1->criticality                = E1AP_Criticality_reject;
-  ieC1->value.present              = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
+  ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID;
+  ieC1->criticality = E1AP_Criticality_reject;
+  ieC1->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID;
   ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_cp_ue_id;
   /* mandatory */
   /* c2. gNB-CU-UP UE E1AP ID */
   asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC2);
-  ieC2->id                         = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
-  ieC2->criticality                = E1AP_Criticality_reject;
-  ieC2->value.present              = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
+  ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID;
+  ieC2->criticality = E1AP_Criticality_reject;
+  ieC2->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID;
   ieC2->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_up_ue_id;
 
   asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC3);
-  ieC3->id            = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse;
-  ieC3->criticality   = E1AP_Criticality_reject;
+  ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse;
+  ieC3->criticality = E1AP_Criticality_reject;
   ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse;
   /*if (0) { // EUTRAN
-    ieC3->value.choice.System_BearerContextSetupResponse.present = E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse;
-    E1AP_ProtocolIE_Container_4932P21_t *msgEUTRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P21_t));
-    ieC3->value.choice.System_BearerContextSetupResponse.choice.e_UTRAN_BearerContextSetupResponse = (struct E1AP_ProtocolIE_Container *) msgEUTRAN_list;
-    asn1cSequenceAdd(msgEUTRAN_list->list, E1AP_EUTRAN_BearerContextSetupResponse_t, msgEUTRAN);
-    msgEUTRAN->id = E1AP_ProtocolIE_ID_id_DRB_Setup_List_EUTRAN;
-    msgEUTRAN->criticality = E1AP_Criticality_reject;
-    msgEUTRAN->value.present = E1AP_EUTRAN_BearerContextSetupResponse__value_PR_DRB_Setup_List_EUTRAN;
-    E1AP_DRB_Setup_List_EUTRAN_t *drbSetup = &msgEUTRAN->value.choice.DRB_Setup_List_EUTRAN;
+    ieC3->value.choice.System_BearerContextSetupResponse.present =
+  E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse;
+  E1AP_ProtocolIE_Container_4932P21_t *msgEUTRAN_list = calloc(1,
+  sizeof(E1AP_ProtocolIE_Container_4932P21_t));
+    ieC3->value.choice.System_BearerContextSetupResponse.choice.e_UTRAN_BearerContextSetupResponse
+  = (struct E1AP_ProtocolIE_Container *) msgEUTRAN_list;
+  asn1cSequenceAdd(msgEUTRAN_list->list,
+  E1AP_EUTRAN_BearerContextSetupResponse_t, msgEUTRAN); msgEUTRAN->id =
+  E1AP_ProtocolIE_ID_id_DRB_Setup_List_EUTRAN; msgEUTRAN->criticality =
+  E1AP_Criticality_reject; msgEUTRAN->value.present =
+  E1AP_EUTRAN_BearerContextSetupResponse__value_PR_DRB_Setup_List_EUTRAN;
+    E1AP_DRB_Setup_List_EUTRAN_t *drbSetup =
+  &msgEUTRAN->value.choice.DRB_Setup_List_EUTRAN;
 
     for (drb_setup_t *i=resp->DRBList; i < resp->DRBList+resp->numDRBs; i++) {
       asn1cSequenceAdd(drbSetup->list, E1AP_DRB_Setup_Item_EUTRAN_t, ieC3_1);
       ieC3_1->dRB_ID = i->drbId;
 
-      ieC3_1->s1_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
+      ieC3_1->s1_DL_UP_TNL_Information.present =
+  E1AP_UP_TNL_Information_PR_gTPTunnel;
       asn1cCalloc(ieC3_1->s1_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel);
-      TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
-      INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
-
-      for (up_params_t *j=i->UpParamList; j < i->UpParamList+i->numUpParam; j++) {
-        asn1cSequenceAdd(ieC3_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1);
-        ieC3_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
+      TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress,
+  &gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(i->teId,
+  &gTPTunnel->gTP_TEID);
+
+      for (up_params_t *j=i->UpParamList; j < i->UpParamList+i->numUpParam; j++)
+  { asn1cSequenceAdd(ieC3_1->uL_UP_Transport_Parameters.list,
+  E1AP_UP_Parameters_Item_t, ieC3_1_1); ieC3_1_1->uP_TNL_Information.present =
+  E1AP_UP_TNL_Information_PR_gTPTunnel;
         asn1cCalloc(ieC3_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
-        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(j->tlAddress, &gTPTunnel->transportLayerAddress);
-        INT32_TO_OCTET_STRING(j->teId, &gTPTunnel->gTP_TEID);
+        TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(j->tlAddress,
+  &gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(j->teId,
+  &gTPTunnel->gTP_TEID);
       }
     }
-  } else */{
-    ieC3->value.choice.System_BearerContextSetupResponse.present = E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse;
+  } else */
+  {
+    ieC3->value.choice.System_BearerContextSetupResponse.present =
+        E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse;
     E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P22_t));
-    ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse = (struct E1AP_ProtocolIE_Container *) msgNGRAN_list;
+    ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse =
+        (struct E1AP_ProtocolIE_Container *)msgNGRAN_list;
     asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupResponse_t, msgNGRAN);
     msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List;
     msgNGRAN->criticality = E1AP_Criticality_reject;
     msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List;
     E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
 
-    for (const pdu_session_setup_t *i=resp->pduSession; i < resp->pduSession+resp->numPDUSessions; i++) {
+    for (const pdu_session_setup_t *i = resp->pduSession; i < resp->pduSession + resp->numPDUSessions; i++) {
       asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1);
       ieC3_1->pDU_Session_ID = i->id;
 
@@ -765,11 +806,11 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *r
       TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
       INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
 
-      for (const DRB_nGRAN_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRBSetup; j++) {
+      for (const DRB_nGRAN_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRBSetup; j++) {
         asn1cSequenceAdd(ieC3_1->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1);
         ieC3_1_1->dRB_ID = j->id;
 
-        for (const up_params_t *k=j->UpParamList; k < j->UpParamList+j->numUpParam; k++) {
+        for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) {
           asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
           ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
           asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
@@ -777,7 +818,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *r
           INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
         }
 
-        for (const qos_flow_setup_t *k=j->qosFlows; k < j->qosFlows+j->numQosFlowSetup; k++) {
+        for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) {
           asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1);
           ieC3_1_1_1->qoS_Flow_Identifier = k->qfi;
         }
@@ -786,7 +827,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *r
       if (i->numDRBFailed > 0)
         ieC3_1->dRB_Failed_List_NG_RAN = calloc(1, sizeof(E1AP_DRB_Failed_List_NG_RAN_t));
 
-      for (const DRB_nGRAN_failed_t *j=i->DRBnGRanFailedList; j < i->DRBnGRanFailedList+i->numDRBFailed; j++) {
+      for (const DRB_nGRAN_failed_t *j = i->DRBnGRanFailedList; j < i->DRBnGRanFailedList + i->numDRBFailed; j++) {
         asn1cSequenceAdd(ieC3_1->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1);
         ieC3_1_1->dRB_ID = j->id;
 
@@ -824,19 +865,20 @@ void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1
   e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
 }
 
-int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
-                                          e1ap_bearer_setup_req_t *bearerCxt) {
+void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *bearerCxt)
+{
   const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest;
   E1AP_BearerContextSetupRequestIEs_t *ie;
 
   LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count);
 
-  for (int i=0; i < in->protocolIEs.list.count; i++) {
+  for (int i = 0; i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
 
     switch(ie->id) {
@@ -898,7 +940,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
         E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2SetupList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List;
         bearerCxt->numPDUSessions = pdu2SetupList->list.count;
-        for (int i=0; i < pdu2SetupList->list.count; i++) {
+        for (int i = 0; i < pdu2SetupList->list.count; i++) {
           pdu_session_to_setup_t *pdu_session = bearerCxt->pduSession + i;
           E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i];
 
@@ -923,7 +965,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
           E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &pdu2Setup->dRB_To_Setup_List_NG_RAN;
           pdu_session->numDRB2Setup = drb2SetupList->list.count;
-          for (int j=0; j < drb2SetupList->list.count; j++) {
+          for (int j = 0; j < drb2SetupList->list.count; j++) {
             DRB_nGRAN_to_setup_t *drb = pdu_session->DRBnGRanList + j;
             E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j];
 
@@ -948,7 +990,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
             E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information;
             drb->numCellGroups = cellGroupList->list.count;
-            for (int k=0; k < cellGroupList->list.count; k++) {
+            for (int k = 0; k < cellGroupList->list.count; k++) {
               E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k];
 
               drb->cellGroupList[k].id = cg2Setup->cell_Group_ID;
@@ -956,7 +998,7 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
             E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup;
             drb->numQosFlow2Setup = qos2SetupList->list.count;
-            for (int k=0; k < qos2SetupList->list.count; k++) {
+            for (int k = 0; k < qos2SetupList->list.count; k++) {
               qos_flow_to_setup_t *qos_flow = drb->qosFlows + k;
               E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k];
 
@@ -993,8 +1035,6 @@ void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu,
         break;
     }
   }
-
-
 }
 
 int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu)
@@ -1012,14 +1052,14 @@ int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upc
   return 0;
 }
 
-void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu,
-                                           e1ap_bearer_setup_resp_t *bearerCxt) {
+void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_resp_t *bearerCxt)
+{
   const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse;
   E1AP_BearerContextSetupResponseIEs_t *ie;
 
   LOG_D(E1AP, "Bearer context setup response number of IEs %d\n", in->protocolIEs.list.count);
 
-  for (int i=0; i < in->protocolIEs.list.count; i++) {
+  for (int i = 0; i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
 
     switch(ie->id) {
@@ -1049,7 +1089,7 @@ void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu,
         E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
         bearerCxt->numPDUSessions = pduSetupList->list.count;
 
-        for (int i=0; i < pduSetupList->list.count; i++) {
+        for (int i = 0; i < pduSetupList->list.count; i++) {
           pdu_session_setup_t *pduSetup = bearerCxt->pduSession + i;
           E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i];
           pduSetup->id = pdu_session->pDU_Session_ID;
@@ -1063,14 +1103,14 @@ void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu,
           }
 
           pduSetup->numDRBSetup = pdu_session->dRB_Setup_List_NG_RAN.list.count;
-          for (int j=0; j < pdu_session->dRB_Setup_List_NG_RAN.list.count; j++) {
+          for (int j = 0; j < pdu_session->dRB_Setup_List_NG_RAN.list.count; j++) {
             DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j;
             E1AP_DRB_Setup_Item_NG_RAN_t *drb = pdu_session->dRB_Setup_List_NG_RAN.list.array[j];
 
             drbSetup->id = drb->dRB_ID;
 
             drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count;
-            for (int k=0; k < drb->uL_UP_Transport_Parameters.list.count; k++) {
+            for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) {
               up_params_t *UL_UP_param = drbSetup->UpParamList + k;
               E1AP_UP_Parameters_Item_t *in_UL_UP_param = drb->uL_UP_Transport_Parameters.list.array[k];
 
@@ -1126,7 +1166,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_up
 
 int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -1170,18 +1210,18 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con
   msgNGRAN->criticality = E1AP_Criticality_reject;
   msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List;
   E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List;
-  for(pdu_session_to_setup_t *i=bearerCxt->pduSessionMod; i < bearerCxt->pduSessionMod+bearerCxt->numPDUSessionsMod; i++) {
+  for (pdu_session_to_setup_t *i = bearerCxt->pduSessionMod; i < bearerCxt->pduSessionMod + bearerCxt->numPDUSessionsMod; i++) {
     asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Modify_Item_t, ieC3_1);
     ieC3_1->pDU_Session_ID = i->sessionId;
 
-    for (DRB_nGRAN_to_setup_t *j=i->DRBnGRanModList; j < i->DRBnGRanModList+i->numDRB2Modify; j++) {
+    for (DRB_nGRAN_to_setup_t *j = i->DRBnGRanModList; j < i->DRBnGRanModList + i->numDRB2Modify; j++) {
       asn1cCalloc(ieC3_1->dRB_To_Modify_List_NG_RAN, drb2Mod_List);
       asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod);
       drb2Mod->dRB_ID = j->id;
 
       if (j->numDlUpParam > 0) {
         asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List);
-        for (up_params_t *k=j->DlUpParamList; k < j->DlUpParamList+j->numDlUpParam; k++) {
+        for (up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) {
           asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param);
           DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
           asn1cCalloc(DL_UP_Param->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
@@ -1268,19 +1308,20 @@ static int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc
   return e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
 }
 
-int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu,
-                                                 e1ap_bearer_setup_req_t *bearerCxt) {
+void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *bearerCxt)
+{
   const E1AP_BearerContextModificationRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextModificationRequest;
   E1AP_BearerContextModificationRequestIEs_t *ie;
 
   LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count);
 
-  for (int i=0; i < in->protocolIEs.list.count; i++) {
+  for (int i = 0; i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
 
     switch(ie->id) {
@@ -1311,7 +1352,7 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
         E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2ModList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List;
         bearerCxt->numPDUSessionsMod = pdu2ModList->list.count;
-        for (int i=0; i < pdu2ModList->list.count; i++) {
+        for (int i = 0; i < pdu2ModList->list.count; i++) {
           pdu_session_to_setup_t *pdu_session = bearerCxt->pduSessionMod + i;
           E1AP_PDU_Session_Resource_To_Modify_Item_t *pdu2Mod = pdu2ModList->list.array[i];
 
@@ -1319,7 +1360,7 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
           E1AP_DRB_To_Modify_List_NG_RAN_t *drb2ModList = pdu2Mod->dRB_To_Modify_List_NG_RAN;
           pdu_session->numDRB2Modify = drb2ModList->list.count;
-          for (int j=0; j < drb2ModList->list.count; j++) {
+          for (int j = 0; j < drb2ModList->list.count; j++) {
             DRB_nGRAN_to_setup_t *drb = pdu_session->DRBnGRanModList + j;
             E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j];
 
@@ -1327,9 +1368,9 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu,
 
             E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters;
             drb->numDlUpParam = dl_up_paramList->list.count;
-            for (int k=0; k < dl_up_paramList->list.count; k++) {
+            for (int k = 0; k < dl_up_paramList->list.count; k++) {
               up_params_t *dl_up_param = drb->DlUpParamList + k;
-              E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; 
+              E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k];
               if (dl_up_param_in->uP_TNL_Information.choice.gTPTunnel) { // Optional IE
                 DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel);
                 BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress,
@@ -1351,7 +1392,9 @@ void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *pdu,
   }
 }
 
-int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu)
+int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id,
+                                                        e1ap_upcp_inst_t *e1_inst,
+                                                        const E1AP_E1AP_PDU_t *pdu)
 {
   DevAssert(pdu != NULL);
   DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage);
@@ -1403,7 +1446,7 @@ static void extract_BEARER_CONTEXT_MODIFICATION_RESPONSE(const E1AP_E1AP_PDU_t *
         E1AP_PDU_Session_Resource_Modified_List_t *pduModifiedList = &msgNGRAN->value.choice.PDU_Session_Resource_Modified_List;
         resp->numPDUSessionsMod = pduModifiedList->list.count;
 
-        for (int i=0; i < pduModifiedList->list.count; i++) {
+        for (int i = 0; i < pduModifiedList->list.count; i++) {
           pdu_session_modif_t *pduModified = &resp->pduSessionMod[i];
           E1AP_PDU_Session_Resource_Modified_Item_t *mod_it = pduModifiedList->list.array[i];
           pduModified->id = mod_it->pDU_Session_ID;
@@ -1416,7 +1459,7 @@ static void extract_BEARER_CONTEXT_MODIFICATION_RESPONSE(const E1AP_E1AP_PDU_t *
           AssertFatal(mod_it->dRB_Failed_To_Modify_List_NG_RAN == NULL, "not implemented\n");
 
           pduModified->numDRBModified = mod_it->dRB_Modified_List_NG_RAN->list.count;
-          for (int j=0; j < mod_it->dRB_Modified_List_NG_RAN->list.count; j++) {
+          for (int j = 0; j < mod_it->dRB_Modified_List_NG_RAN->list.count; j++) {
             DRB_nGRAN_modified_t *drbModified = &pduModified->DRBnGRanModList[j];
             E1AP_DRB_Modified_Item_NG_RAN_t *drb = mod_it->dRB_Modified_List_NG_RAN->list.array[j];
 
@@ -1433,7 +1476,9 @@ static void extract_BEARER_CONTEXT_MODIFICATION_RESPONSE(const E1AP_E1AP_PDU_t *
   }
 }
 
-int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu)
+int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id,
+                                                         e1ap_upcp_inst_t *e1_inst,
+                                                         const E1AP_E1AP_PDU_t *pdu)
 {
   DevAssert(pdu != NULL);
   DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome);
@@ -1453,17 +1498,19 @@ int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_FAILURE(instance_t instance,
                                                         uint32_t stream,
                                                         E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_REQUIRED(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_REQUIRED(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_CONFIRM(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUCP_send_BEARER_CONTEXT_MODIFICATION_CONFIRM(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -1472,7 +1519,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_REQUIRED(instance_t instance,
                                                          uint32_t stream,
                                                          E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -1481,7 +1528,7 @@ int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_CONFIRM(instance_t instance,
                                                         uint32_t stream,
                                                         E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 /*
@@ -1554,19 +1601,20 @@ int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, const e
   return e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__);
 }
 
-int e1apCUUP_send_BEARER_CONTEXT_RELEASE_REQUEST(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_BEARER_CONTEXT_RELEASE_REQUEST(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-void extract_BEARER_CONTEXT_RELEASE_COMMAND(const E1AP_E1AP_PDU_t *pdu,
-                                            e1ap_bearer_release_cmd_t *bearerCxt) {
+void extract_BEARER_CONTEXT_RELEASE_COMMAND(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_release_cmd_t *bearerCxt)
+{
   const E1AP_BearerContextReleaseCommand_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextReleaseCommand;
   E1AP_BearerContextReleaseCommandIEs_t *ie;
 
   LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count);
 
-  for (int i=0; i < in->protocolIEs.list.count; i++) {
+  for (int i = 0; i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
 
     switch(ie->id) {
@@ -1612,14 +1660,14 @@ int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_u
   return 0;
 }
 
-void extract_BEARER_CONTEXT_RELEASE_COMPLETE(const E1AP_E1AP_PDU_t *pdu,
-                                             e1ap_bearer_release_cplt_t *bearerCxt) {
+void extract_BEARER_CONTEXT_RELEASE_COMPLETE(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_release_cplt_t *bearerCxt)
+{
   const E1AP_BearerContextReleaseComplete_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextReleaseComplete;
   E1AP_BearerContextReleaseCompleteIEs_t *ie;
 
   LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count);
 
-  for (int i=0; i < in->protocolIEs.list.count; i++) {
+  for (int i = 0; i < in->protocolIEs.list.count; i++) {
     ie = in->protocolIEs.list.array[i];
 
     switch(ie->id) {
@@ -1664,7 +1712,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_REQUEST(instance_t instance,
                                                    uint32_t stream,
                                                    E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -1672,8 +1720,9 @@ int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_REQUEST(instance_t instance,
 BEARER CONTEXT INACTIVITY NOTIFICATION
  */
 
-int e1apCUUP_send_BEARER_CONTEXT_INACTIVITY_NOTIFICATION(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_BEARER_CONTEXT_INACTIVITY_NOTIFICATION(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
@@ -1682,39 +1731,42 @@ int e1apCUCP_handle_BEARER_CONTEXT_INACTIVITY_NOTIFICATION(instance_t instance,
                                                            uint32_t stream,
                                                            E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 /*
   DL DATA
 */
 
-int e1apCUUP_send_DL_DATA_NOTIFICATION(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_DL_DATA_NOTIFICATION(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-int e1apCUUP_send_DATA_USAGE_REPORT(instance_t instance) {
-  AssertFatal(false,"Not implemented yet\n");
+int e1apCUUP_send_DATA_USAGE_REPORT(instance_t instance)
+{
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1apCUCP_handle_DL_DATA_NOTIFICATION(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
 int e1apCUCP_handle_send_DATA_USAGE_REPORT(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, E1AP_E1AP_PDU_t *pdu)
 {
-  AssertFatal(false,"Not implemented yet\n");
+  AssertFatal(false, "Not implemented yet\n");
   return -1;
 }
 
-static instance_t cuup_task_create_gtpu_instance_to_du(eth_params_t *IPaddrs) {
-  openAddr_t tmp= {0};
-  strncpy(tmp.originHost, IPaddrs->my_addr, sizeof(tmp.originHost)-1);
-  sprintf(tmp.originService, "%d",  IPaddrs->my_portd);
+static instance_t cuup_task_create_gtpu_instance_to_du(eth_params_t *IPaddrs)
+{
+  openAddr_t tmp = {0};
+  strncpy(tmp.originHost, IPaddrs->my_addr, sizeof(tmp.originHost) - 1);
+  sprintf(tmp.originService, "%d", IPaddrs->my_portd);
   sprintf(tmp.destinationService, "%d", IPaddrs->remote_portd);
   return gtpv1Init(tmp);
 }
@@ -1742,12 +1794,26 @@ static void e1apCUUP_send_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_setup_req_t
   e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__);
 }
 
-static void e1_task_handle_sctp_association_resp(E1_t type, instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
+static void e1_task_handle_sctp_association_resp(E1_t type,
+                                                 instance_t instance,
+                                                 sctp_new_association_resp_t *sctp_new_association_resp)
 {
   DevAssert(sctp_new_association_resp != NULL);
   getCxtE1(instance)->sockState = sctp_new_association_resp->sctp_state;
+
+  if (sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN) {
+    LOG_I(E1AP, "Received SCTP shutdown for assoc_id %d, removing CUCP endpoint\n", sctp_new_association_resp->assoc_id);
+    /* inform RRC that the CU-UP is gone */
+    MessageDef *message_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_LOST_CONNECTION);
+    message_p->ittiMsgHeader.originInstance = sctp_new_association_resp->assoc_id;
+    itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p);
+    return;
+  }
+
   if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
-    LOG_W(E1AP, "Received unsuccessful result for SCTP association (%u), instance %ld, cnx_id %u\n",
+    LOG_W(E1AP,
+          "Received unsuccessful result for SCTP association (%u), instance "
+          "%ld, cnx_id %u\n",
           sctp_new_association_resp->sctp_state,
           instance,
           sctp_new_association_resp->ulp_cnx_id);
@@ -1796,7 +1862,8 @@ void cuup_init_n3(instance_t instance)
   N3GTPUInst = &getCxtE1(instance)->gtpInstN3;
 }
 
-void cucp_task_send_sctp_init_req(instance_t instance, char *my_addr) {
+void cucp_task_send_sctp_init_req(instance_t instance, char *my_addr)
+{
   LOG_I(E1AP, "E1AP_CUCP_SCTP_REQ(create socket)\n");
   MessageDef  *message_p = NULL;
   message_p = itti_alloc_new_message (TASK_CUCP_E1, 0, SCTP_INIT_MSG);
@@ -1832,7 +1899,16 @@ void e1apHandleTimer(instance_t myInstance)
     e1_task_send_sctp_association_req(TASK_CUUP_E1, myInstance, &getCxtE1(myInstance)->net_config);
 }
 
-void *E1AP_CUCP_task(void *arg) {
+/**
+ * @brief E1AP Centralized Unit Control Plane (CU-CP) task function.
+ *
+ * This is the main task loop for the E1AP CUCP module:
+ * it listens for incoming messages from the Inter-Task Interface (ITTI)
+ * and calls the relevant handlers for each message type.
+ *
+ */
+void *E1AP_CUCP_task(void *arg)
+{
   LOG_I(E1AP, "Starting E1AP at CU CP\n");
   MessageDef *msg = NULL;
   e1ap_common_init();
@@ -1840,7 +1916,7 @@ void *E1AP_CUCP_task(void *arg) {
 
   while (1) {
     itti_receive_msg(TASK_CUCP_E1, &msg);
-    instance_t myInstance=ITTI_MSG_DESTINATION_INSTANCE(msg);
+    instance_t myInstance = ITTI_MSG_DESTINATION_INSTANCE(msg);
     const int msgType = ITTI_MSG_ID(msg);
     LOG_D(E1AP, "CUCP received %s for instance %ld\n", messages_info[msgType].name, myInstance);
     sctp_assoc_t assoc_id = msg->ittiMsgHeader.originInstance;
@@ -1875,6 +1951,10 @@ void *E1AP_CUCP_task(void *arg) {
         e1ap_send_SETUP_RESPONSE(assoc_id, &E1AP_SETUP_RESP(msg));
         break;
 
+      case E1AP_SETUP_FAIL:
+        e1apCUCP_send_SETUP_FAILURE(assoc_id, E1AP_SETUP_FAIL(msg).transac_id);
+        break;
+
       case E1AP_BEARER_CONTEXT_SETUP_REQ:
         e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(assoc_id, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg));
         break;
@@ -1895,11 +1975,19 @@ void *E1AP_CUCP_task(void *arg) {
     result = itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
     AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d) in E1AP_CUCP_task!\n", result);
     msg = NULL;
-
   }
 }
 
-void *E1AP_CUUP_task(void *arg) {
+/**
+ * @brief E1AP Centralized Unit User Plane (CU-UP) task function.
+ *
+ * This is the main task loop for the E1AP CUUP module:
+ * it listens for incoming messages from the Inter-Task Interface (ITTI)
+ * and calls the relevant handlers for each message type.
+ *
+ */
+void *E1AP_CUUP_task(void *arg)
+{
   LOG_I(E1AP, "Starting E1AP at CU UP\n");
   e1ap_common_init();
   int result;
@@ -1935,21 +2023,21 @@ void *E1AP_CUUP_task(void *arg) {
         const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
         AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance);
         e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst->cuup.assoc_id, resp);
-        } break;
+      } break;
 
       case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: {
         const e1ap_bearer_modif_resp_t *resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg);
         const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
         AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance);
         e1apCUUP_send_BEARER_CONTEXT_MODIFICATION_RESPONSE(inst->cuup.assoc_id, resp);
-        } break;
+      } break;
 
       case E1AP_BEARER_CONTEXT_RELEASE_CPLT: {
         const e1ap_bearer_release_cplt_t *cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg);
         const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
         AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance);
         e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(inst->cuup.assoc_id, cplt);
-        } break;
+      } break;
 
       default:
         LOG_E(E1AP, "Unknown message received in TASK_CUUP_E1\n");
@@ -1959,7 +2047,5 @@ void *E1AP_CUUP_task(void *arg) {
     result = itti_free(ITTI_MSG_ORIGIN_ID(msg), msg);
     AssertFatal(result == EXIT_SUCCESS, "Failed to free memory (%d) in E1AP_CUUP_task!\n", result);
     msg = NULL;
-
   }
 }
-
diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c
index e2c0b48bd411898be4e81a15ffbb046c928eab91..39946c95f1cfed051f9fed38e8441144011da149 100644
--- a/openair2/GNB_APP/gnb_app.c
+++ b/openair2/GNB_APP/gnb_app.c
@@ -148,7 +148,7 @@ void *gNB_app_task(void *args_p)
         AssertFatal(false, "Create task for E1AP CP failed\n");
       E1_t e1type = CPtype;
       MessageDef *msg = RCconfig_NR_CU_E1(&e1type);
-      AssertFatal(msg != NULL, "Send inti to task for E1AP CP failed\n");
+      AssertFatal(msg != NULL, "Send ITTI to task for E1AP CP failed\n");
       // this sends the E1AP_REGISTER_REQ to CU-CP so it sets up the socket
       // it does NOT use the E1AP part
       itti_send_msg_to_task(TASK_CUCP_E1, 0, msg);
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
index 77369c19d520e593c98820fa60ce9f8a9f1a0f34..ceebf3900617e43651ccb74594d1676085ccbf34 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.c
@@ -2607,20 +2607,23 @@ uint32_t nr_get_code_rate_ul(uint8_t Imcs, uint8_t table_idx) {
 }
 
 // Table 5.1.2.2.1-1 38.214
-uint8_t getRBGSize(uint16_t bwp_size, long rbg_size_config) {
-  
-  AssertFatal(bwp_size < 276,"Invalid BWP Size > 275\n");
-  
-  if (bwp_size < 37)  return (rbg_size_config ? 4 : 2);
-  if (bwp_size < 73)  return (rbg_size_config ? 8 : 4);
-  if (bwp_size < 145) return (rbg_size_config ? 16 : 8);
-  else return 16;
+uint8_t getRBGSize(uint16_t bwp_size, long rbg_size_config)
+{
+  AssertFatal(bwp_size < 276, "Invalid BWP Size %d\n", bwp_size);
+  if (bwp_size < 37)
+    return (rbg_size_config ? 4 : 2);
+  if (bwp_size < 73)
+    return (rbg_size_config ? 8 : 4);
+  if (bwp_size < 145)
+    return (rbg_size_config ? 16 : 8);
+  else
+    return 16;
 }
 
-uint8_t getNRBG(uint16_t bwp_size, uint16_t bwp_start, long rbg_size_config) {
-
-  uint8_t rbg_size = getRBGSize(bwp_size,rbg_size_config);
-  return (uint8_t)ceil((float)(bwp_size+(bwp_start % rbg_size))/(float)rbg_size);
+uint8_t getNRBG(uint16_t bwp_size, uint16_t bwp_start, long rbg_size_config)
+{
+  uint8_t rbg_size = getRBGSize(bwp_size, rbg_size_config);
+  return (uint8_t)ceil((float)(bwp_size + (bwp_start % rbg_size)) / (float)rbg_size);
 }
 
 uint8_t getAntPortBitWidth(NR_SetupRelease_DMRS_DownlinkConfig_t *typeA, NR_SetupRelease_DMRS_DownlinkConfig_t *typeB) {
diff --git a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
index e84a3bb4680c0998c9c97b8d0272b971a5754850..27373c02d7d6f36e59443b6ece501a4494a2be66 100644
--- a/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
+++ b/openair2/LAYER2/NR_MAC_COMMON/nr_mac_common.h
@@ -109,6 +109,8 @@ NR_tda_info_t get_dl_tda_info(const NR_UE_DL_BWP_t *dl_BWP,
                               int coresetid,
                               bool sib1);
 
+uint8_t getRBGSize(uint16_t bwp_size, long rbg_size_config);
+
 uint16_t nr_dci_size(const NR_UE_DL_BWP_t *DL_BWP,
                      const NR_UE_UL_BWP_t *UL_BWP,
                      const NR_UE_ServingCell_Info_t *sc_info,
diff --git a/openair2/LAYER2/NR_MAC_UE/config_ue.c b/openair2/LAYER2/NR_MAC_UE/config_ue.c
index b2a45315d617cf78a3c2fcb777830767e06e2bd9..c8f01b3a6bbac497869894caa77ea73c054fb75b 100644
--- a/openair2/LAYER2/NR_MAC_UE/config_ue.c
+++ b/openair2/LAYER2/NR_MAC_UE/config_ue.c
@@ -669,29 +669,29 @@ void nr_release_mac_config_logicalChannelBearer(NR_UE_MAC_INST_t *mac, long chan
   }
 }
 
-static uint16_t nr_get_ms_bucketsizeduration(uint8_t bucketsizeduration)
+static int nr_get_ms_bucketsizeduration(long bucketsizeduration)
 {
   switch (bucketsizeduration) {
+    case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms5:
+      return 5;
+    case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms10:
+      return 10;
+    case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms20:
+      return 20;
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms50:
       return 50;
-
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms100:
       return 100;
-
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms150:
       return 150;
-
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms300:
       return 300;
-
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms500:
       return 500;
-
     case NR_LogicalChannelConfig__ul_SpecificParameters__bucketSizeDuration_ms1000:
       return 1000;
-
     default:
-      return 0;
+      AssertFatal(false, "Invalid bucketSizeDuration %ld\n", bucketsizeduration);
   }
 }
 
@@ -724,9 +724,9 @@ void nr_configure_mac_config_logicalChannelBearer(module_id_t module_id,
     mac->scheduling_info.lc_sched_info[channel_identity - 1].LCGID = 0;
 }
 
-void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id,
-                                                   struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list,
-                                                   struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list)
+static void configure_logicalChannelBearer(module_id_t module_id,
+                                           struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list,
+                                           struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list)
 {
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
   if (rlc_torelease_list) {
@@ -1956,6 +1956,10 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
     }
   }
 
+  configure_logicalChannelBearer(module_id,
+                                 cell_group_config->rlc_BearerToAddModList,
+                                 cell_group_config->rlc_BearerToReleaseList);
+
   // 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)
@@ -1963,6 +1967,4 @@ void nr_rrc_mac_config_req_cg(module_id_t module_id,
 
   if (!mac->dl_config_request || !mac->ul_config_request)
     ue_init_config_request(mac, mac->current_DL_BWP->scs);
-
-  asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, cell_group_config);
 }
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_defs.h b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
index 378411abcae8575162e09a26975f44aa6e050423..756273769c60380b6a35c1563be1e7002594fa7d 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_defs.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_defs.h
@@ -450,7 +450,7 @@ typedef struct {
 } NR_BWP_PDCCH_t;
 
 /*!\brief Top level UE MAC structure */
-typedef struct {
+typedef struct NR_UE_MAC_INST_s {
   module_id_t ue_id;
   NR_UE_L2_STATE_t state;
   int servCellIndex;
diff --git a/openair2/LAYER2/NR_MAC_UE/mac_proto.h b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
index ca0fac4908c160856a8ab04b321bb6037fb21202..05aba31afed6d6ffa5994f5128d19d3155122e39 100644
--- a/openair2/LAYER2/NR_MAC_UE/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_UE/mac_proto.h
@@ -177,10 +177,6 @@ void release_dl_BWP(NR_UE_MAC_INST_t *mac, int index);
 void release_ul_BWP(NR_UE_MAC_INST_t *mac, int index);
 void nr_release_mac_config_logicalChannelBearer(NR_UE_MAC_INST_t *mac, long channel_identity);
 
-void nr_rrc_mac_config_req_ue_logicalChannelBearer(module_id_t module_id,
-                                                   struct NR_CellGroupConfig__rlc_BearerToAddModList *rlc_toadd_list,
-                                                   struct NR_CellGroupConfig__rlc_BearerToReleaseList *rlc_torelease_list);
-
 void nr_rrc_mac_config_req_cg(module_id_t module_id,
                               int cc_idP,
                               NR_CellGroupConfig_t *cell_group_config);
@@ -215,26 +211,6 @@ void release_mac_configuration(NR_UE_MAC_INST_t *mac);
 void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info);
 void nr_ue_dl_scheduler(nr_downlink_indication_t *dl_info);
 
-/**\brief fill nr_scheduled_response struct instance
-   @param nr_scheduled_response_t *    pointer to scheduled_response instance to fill
-   @param fapi_nr_dl_config_request_t* pointer to dl_config,
-   @param fapi_nr_ul_config_request_t* pointer to ul_config,
-   @param fapi_nr_tx_request_t*        pointer to tx_request;
-   @param module_id_t mod_id           module ID
-   @param int cc_id                    CC ID
-   @param frame_t frame                frame number
-   @param int slot                     reference number
-   @param void *phy_pata               pointer to a PHY specific structure to be filled in the scheduler response (can be null) */
-void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
-                             fapi_nr_dl_config_request_t *dl_config,
-                             fapi_nr_ul_config_request_t *ul_config,
-                             fapi_nr_tx_request_t *tx_request,
-                             module_id_t mod_id,
-                             int cc_id,
-                             frame_t frame,
-                             int slot,
-                             void *phy_data);
-
 /*! \fn int8_t nr_ue_get_SR(module_id_t module_idP, frame_t frameP, slot_t slotP);
    \brief Called by PHY to get sdu for PUSCH transmission.  It performs the following operations: Checks BSR for DCCH, DCCH1 and
 DTCH corresponding to previous values computed either in SR or BSR procedures.  It gets rlc status indications on DCCH,DCCH1 and
@@ -379,8 +355,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);
 
-int find_pucch_resource_set(NR_UE_MAC_INST_t *mac, int uci_size);
-
 void multiplex_pucch_resource(NR_UE_MAC_INST_t *mac, PUCCH_sched_t *pucch, int num_res);
 
 int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
@@ -402,7 +376,7 @@ int get_deltatf(uint16_t nb_of_prbs,
                 int N_sc_ctrl_RB,
                 int O_UCI);
 
-void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
+int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
                            int slot,
                            uint16_t rnti,
                            PUCCH_sched_t *pucch,
@@ -489,24 +463,28 @@ void nr_Msg1_transmitted(module_id_t mod_id);
 
 void nr_Msg3_transmitted(module_id_t mod_id, uint8_t CC_id, frame_t frameP, slot_t slotP, uint8_t gNB_id);
 void nr_get_msg3_payload(module_id_t mod_id, uint8_t *buf, int TBS_max);
-void send_msg3_rrc_request(module_id_t mod_id, int rnti);
 
 void nr_ue_msg2_scheduler(module_id_t mod_id, uint16_t rach_frame, uint16_t rach_slot, uint16_t *msg2_frame, uint16_t *msg2_slot);
 
 int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
                                                       fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
+                                                      NR_PDSCH_Config_t *pdsch_Config,
                                                       uint16_t n_RB_ULBWP,
                                                       uint16_t n_RB_DLBWP,
-                                                      uint16_t riv);
+                                                      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 scs);
 
-fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int slot, int fb_time);
 fapi_nr_dl_config_request_t *get_dl_config_request(NR_UE_MAC_INST_t *mac, int slot);
 
-void fill_ul_config(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx, uint8_t pdu_type);
+fapi_nr_ul_config_request_pdu_t *lockGet_ul_config(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx, uint8_t pdu_type);
+void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu);
+fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx);
+
+void release_ul_config(fapi_nr_ul_config_request_pdu_t *pdu, bool clearIt);
 
 int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm);
 
@@ -516,7 +494,13 @@ int16_t compute_nr_SSB_PL(NR_UE_MAC_INST_t *mac, short ssb_rsrp_dBm);
 // - in which ULSCH should be scheduled. K2 is configured in RRC configuration.  
 // PUSCH Msg3 scheduler:
 // - scheduled by RAR UL grant according to 8.3 of TS 38.213
-int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t current_frame, int current_slot, frame_t *frame_tx, int *slot_tx, long k2);
+int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
+                          const uint8_t is_Msg3,
+                          const frame_t current_frame,
+                          const int current_slot,
+                          frame_t *frame_tx,
+                          int *slot_tx,
+                          const long k2);
 
 int get_rnti_type(NR_UE_MAC_INST_t *mac, uint16_t rnti);
 
diff --git a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
index 09b231205477e26858d894143e6fb5d5c91ded86..be013b6dffc7dd473857ecb43c9517e51d47a275 100644
--- a/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
+++ b/openair2/LAYER2/NR_MAC_UE/main_ue_nr.c
@@ -53,12 +53,6 @@ void send_srb0_rrc(int ue_id, const uint8_t *sdu, sdu_size_t sdu_len, void *data
   itti_send_msg_to_task(TASK_RRC_NRUE, ue_id, message_p);
 }
 
-void send_msg3_rrc_request(module_id_t mod_id, int rnti)
-{
-  nr_rlc_activate_srb0(mod_id, NULL, send_srb0_rrc);
-  nr_mac_rrc_msg3_ind(mod_id, rnti);
-}
-
 void nr_ue_init_mac(module_id_t module_idP)
 {
   LOG_I(NR_MAC, "[UE%d] Applying default macMainConfig\n", module_idP);
@@ -129,6 +123,10 @@ NR_UE_MAC_INST_t *nr_l2_init_ue(int nb_inst)
   int rc = rlc_module_init(0);
   AssertFatal(rc == 0, "Could not initialize RLC layer\n");
 
+  for (int j = 0; j < nb_inst; j++) {
+    nr_rlc_activate_srb0(j, NULL, send_srb0_rrc);
+  }
+
   return (nr_ue_mac_inst);
 }
 
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
index 7105d2f661d907f08e387b24f4b5863cd4205dbf..722530d696f88563a4ab2a611ab70009eb12b74c 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ra_procedures.c
@@ -949,19 +949,12 @@ void prepare_msg4_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack)
   NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[pid];
   int sched_slot = current_harq->ul_slot;
   int sched_frame = current_harq->ul_frame;
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, sched_slot, 0);
-  pthread_mutex_lock(&ul_config->mutex_ul_config);
   mac->nr_ue_emul_l1.num_harqs = 1;
-  AssertFatal(ul_config->number_pdus < FAPI_NR_UL_CONFIG_LIST_NUM,
-              "ul_config->number_pdus %d out of bounds\n",
-              ul_config->number_pdus);
-  fapi_nr_ul_config_pucch_pdu *pucch_pdu = &ul_config->ul_config_list[ul_config->number_pdus].pucch_config_pdu;
-  PUCCH_sched_t pucch = {0};
-  pucch.n_CCE = current_harq->n_CCE;
-  pucch.N_CCE = current_harq->N_CCE;
-  pucch.delta_pucch = current_harq->delta_pucch;
-  pucch.ack_payload = ack_nack;
-  pucch.n_harq = 1;
+  PUCCH_sched_t pucch = {.n_CCE = current_harq->n_CCE,
+                         .N_CCE = current_harq->N_CCE,
+                         .delta_pucch = current_harq->delta_pucch,
+                         .ack_payload = ack_nack,
+                         .n_harq = 1};
   current_harq->active = false;
   current_harq->ack_received = false;
   if (get_softmodem_params()->emulate_l1) {
@@ -969,11 +962,11 @@ void prepare_msg4_feedback(NR_UE_MAC_INST_t *mac, int pid, int ack_nack)
     mac->nr_ue_emul_l1.harq[pid].active_dl_harq_sfn = sched_frame;
     mac->nr_ue_emul_l1.harq[pid].active_dl_harq_slot = sched_slot;
   }
-  nr_ue_configure_pucch(mac,
-                        sched_slot,
-                        mac->ra.t_crnti,
-                        &pucch,
-                        pucch_pdu);
-  fill_ul_config(ul_config, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
-  pthread_mutex_unlock(&ul_config->mutex_ul_config);
+  fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
+  if (!pdu)
+    return;
+  int ret = nr_ue_configure_pucch(mac, sched_slot, mac->ra.t_crnti, &pucch, &pdu->pucch_config_pdu);
+  if (ret != 0)
+    remove_ul_config_last_item(pdu);
+  release_ul_config(pdu, false);
 }
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
index 1f76ef28257d849ac0ce60fe64ef2e7e4d158204..f83596f7dbae0e9e9f7d43b8aea059f1a7658a15 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_procedures.c
@@ -102,7 +102,7 @@ random-access procedure
 @param selected_rar_buffer the output buffer for storing the selected RAR header and RAR payload
 @returns timing advance or 0xffff if preamble doesn't match
 */
-static int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id);
+static void nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id);
 
 int get_pucch0_mcs(const int O_ACK, const int O_SR, const int ack_payload, const int sr_payload)
 {
@@ -190,7 +190,7 @@ int get_rnti_type(NR_UE_MAC_INST_t *mac, uint16_t rnti)
     } else if (rnti == 0xFFFF) {
       rnti_type = TYPE_SI_RNTI_;
     } else {
-      AssertFatal(1 == 0, "In %s: Not identified/handled rnti %d \n", __FUNCTION__, rnti);
+      AssertFatal(1 == 0, "Not identified/handled rnti %d \n", rnti);
     }
 
     LOG_D(MAC, "Returning rnti_type %s \n", rnti_types(rnti_type));
@@ -284,38 +284,63 @@ int8_t nr_ue_decode_BCCH_DL_SCH(module_id_t module_id,
  */
 int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu,
                                                       fapi_nr_dl_config_dlsch_pdu_rel15_t *dlsch_config_pdu,
+                                                      NR_PDSCH_Config_t *pdsch_Config,
                                                       uint16_t n_RB_ULBWP,
                                                       uint16_t n_RB_DLBWP,
-                                                      uint16_t riv)
+                                                      int start_DLBWP,
+                                                      dci_field_t frequency_domain_assignment)
 {
 
   /*
    * TS 38.214 subclause 5.1.2.2 Resource allocation in frequency domain (downlink)
    * when the scheduling grant is received with DCI format 1_0, then downlink resource allocation type 1 is used
    */
-  if(dlsch_config_pdu != NULL){
-
-    /*
-     * TS 38.214 subclause 5.1.2.2.1 Downlink resource allocation type 0
-     */
-    /*
-     * TS 38.214 subclause 5.1.2.2.2 Downlink resource allocation type 1
-     */
-    dlsch_config_pdu->number_rbs = NRRIV2BW(riv,n_RB_DLBWP);
-    dlsch_config_pdu->start_rb   = NRRIV2PRBOFFSET(riv,n_RB_DLBWP);
-
-    // Sanity check in case a false or erroneous DCI is received
-    if ((dlsch_config_pdu->number_rbs < 1 ) || (dlsch_config_pdu->number_rbs > n_RB_DLBWP - dlsch_config_pdu->start_rb)) {
-      // DCI is invalid!
-      LOG_W(MAC, "Frequency domain assignment values are invalid! #RBs: %d, Start RB: %d, n_RB_DLBWP: %d \n", dlsch_config_pdu->number_rbs, dlsch_config_pdu->start_rb, n_RB_DLBWP);
-      return -1;
+  if(dlsch_config_pdu != NULL) {
+    if (pdsch_Config &&
+        pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_resourceAllocationType0) {
+      // TS 38.214 subclause 5.1.2.2.1 Downlink resource allocation type 0
+      dlsch_config_pdu->resource_alloc = 0;
+      int P = getRBGSize(n_RB_DLBWP, pdsch_Config->rbg_Size);
+      int n_RBG = frequency_domain_assignment.nbits;
+      int index = 0;
+      for (int i = 0; i < n_RBG; i++) {
+        // The order of RBG bitmap is such that RBG 0 to RBG n_RBG − 1 are mapped from MSB to LSB
+        int bit_rbg = (frequency_domain_assignment.val >> (n_RBG - 1 - i)) & 0x01;
+        int size_RBG;
+        if (i == n_RBG - 1)
+          size_RBG = (start_DLBWP + n_RB_DLBWP) % P > 0 ?
+                     (start_DLBWP + n_RB_DLBWP) % P :
+                     P;
+        else if (i == 0)
+          size_RBG = P - (start_DLBWP % P);
+        else
+          size_RBG = P;
+        for (int j = index; j < size_RBG; j++)
+          dlsch_config_pdu->rb_bitmap[j / 8] |= bit_rbg << (j % 8);
+        index += size_RBG;
+      }
+    }
+    else if (pdsch_Config &&
+             pdsch_Config->resourceAllocation == NR_PDSCH_Config__resourceAllocation_dynamicSwitch)
+      AssertFatal(false, "DLSCH dynamic switch allocation not yet supported\n");
+    else {
+      // TS 38.214 subclause 5.1.2.2.2 Downlink resource allocation type 1
+      dlsch_config_pdu->resource_alloc = 1;
+      int riv = frequency_domain_assignment.val;
+      dlsch_config_pdu->number_rbs = NRRIV2BW(riv,n_RB_DLBWP);
+      dlsch_config_pdu->start_rb   = NRRIV2PRBOFFSET(riv,n_RB_DLBWP);
+
+      // Sanity check in case a false or erroneous DCI is received
+      if ((dlsch_config_pdu->number_rbs < 1) || (dlsch_config_pdu->number_rbs > n_RB_DLBWP - dlsch_config_pdu->start_rb)) {
+        // DCI is invalid!
+        LOG_W(MAC, "Frequency domain assignment values are invalid! #RBs: %d, Start RB: %d, n_RB_DLBWP: %d \n", dlsch_config_pdu->number_rbs, dlsch_config_pdu->start_rb, n_RB_DLBWP);
+        return -1;
+      }
+      LOG_D(MAC,"DLSCH riv = %i\n", riv);
+      LOG_D(MAC,"DLSCH n_RB_DLBWP = %i\n", n_RB_DLBWP);
+      LOG_D(MAC,"DLSCH number_rbs = %i\n", dlsch_config_pdu->number_rbs);
+      LOG_D(MAC,"DLSCH start_rb = %i\n", dlsch_config_pdu->start_rb);
     }
-
-    LOG_D(MAC,"DLSCH riv = %i\n", riv);
-    LOG_D(MAC,"DLSCH n_RB_DLBWP = %i\n", n_RB_DLBWP);
-    LOG_D(MAC,"DLSCH number_rbs = %i\n", dlsch_config_pdu->number_rbs);
-    LOG_D(MAC,"DLSCH start_rb = %i\n", dlsch_config_pdu->start_rb);
-
   }
   if(pusch_config_pdu != NULL){
     /*
@@ -327,7 +352,7 @@ int8_t nr_ue_process_dci_freq_dom_resource_assignment(nfapi_nr_ue_pusch_pdu_t *p
     /*
      * TS 38.214 subclause 6.1.2.2.2 Uplink resource allocation type 1
      */
-
+    int riv = frequency_domain_assignment.val;
     pusch_config_pdu->rb_size  = NRRIV2BW(riv,n_RB_ULBWP);
     pusch_config_pdu->rb_start = NRRIV2PRBOFFSET(riv,n_RB_ULBWP);
 
@@ -408,25 +433,15 @@ static int nr_ue_process_dci_ul_00(module_id_t module_id,
     return -1;
   }
 
-  // Get UL config request corresponding slot_tx
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slot_tx, tda_info.k2);
-
-  if (!ul_config) {
-    LOG_W(MAC, "ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!\n", frame, slot);
+  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 -1;
-  }
-
-  pthread_mutex_lock(&ul_config->mutex_ul_config);
-  AssertFatal(ul_config->number_pdus < FAPI_NR_UL_CONFIG_LIST_NUM,
-              "ul_config->number_pdus %d out of bounds\n",
-              ul_config->number_pdus);
-  nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu;
 
-  fill_ul_config(ul_config, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
-  pthread_mutex_unlock(&ul_config->mutex_ul_config);
-
-  // Config PUSCH PDU
-  return nr_config_pusch_pdu(mac, &tda_info, pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_0);
+  int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_0);
+  if (ret != 0)
+    remove_ul_config_last_item(pdu);
+  release_ul_config(pdu, false);
+  return ret;
 }
 
 static int nr_ue_process_dci_ul_01(module_id_t module_id,
@@ -493,26 +508,14 @@ static int nr_ue_process_dci_ul_01(module_id_t module_id,
     return -1;
   }
 
-  // Get UL config request corresponding slot_tx
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slot_tx, tda_info.k2);
-
-  if (!ul_config) {
-    LOG_W(MAC, "ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!\n", frame, slot);
+  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 -1;
-  }
-  ul_config->number_pdus = 0;
-
-  pthread_mutex_lock(&ul_config->mutex_ul_config);
-  AssertFatal(ul_config->number_pdus < FAPI_NR_UL_CONFIG_LIST_NUM,
-              "ul_config->number_pdus %d out of bounds\n",
-              ul_config->number_pdus);
-  nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu;
-
-  fill_ul_config(ul_config, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
-  pthread_mutex_unlock(&ul_config->mutex_ul_config);
-
-  // Config PUSCH PDU
-  return nr_config_pusch_pdu(mac, &tda_info, pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_1);
+  int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, dci, NULL, dci_ind->rnti, NR_UL_DCI_FORMAT_0_1);
+  if (ret != 0)
+    remove_ul_config_last_item(pdu);
+  release_ul_config(pdu, false);
+  return ret;
 }
 
 static int nr_ue_process_dci_dl_10(module_id_t module_id,
@@ -611,7 +614,13 @@ static int nr_ue_process_dci_dl_10(module_id_t module_id,
 
   /* IDENTIFIER_DCI_FORMATS */
   /* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
-  if (nr_ue_process_dci_freq_dom_resource_assignment(NULL, dlsch_pdu, 0, dlsch_pdu->BWPSize, dci->frequency_domain_assignment.val)
+  if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,
+                                                     dlsch_pdu,
+                                                     NULL,
+                                                     0,
+                                                     dlsch_pdu->BWPSize,
+                                                     0,
+                                                     dci->frequency_domain_assignment)
       < 0) {
     LOG_W(MAC, "[%d.%d] Invalid frequency_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot);
     return -1;
@@ -884,9 +893,11 @@ static int nr_ue_process_dci_dl_11(module_id_t module_id,
   /* FREQ_DOM_RESOURCE_ASSIGNMENT_DL */
   if (nr_ue_process_dci_freq_dom_resource_assignment(NULL,
                                                      dlsch_pdu,
+                                                     pdsch_Config,
                                                      0,
                                                      current_DL_BWP->BWPSize,
-                                                     dci->frequency_domain_assignment.val)
+                                                     current_DL_BWP->BWPStart,
+                                                     dci->frequency_domain_assignment)
       < 0) {
     LOG_W(MAC, "[%d.%d] Invalid frequency_domain_assignment. Possibly due to false DCI. Ignoring DCI!\n", frame, slot);
     return -1;
@@ -1279,7 +1290,7 @@ void set_harq_status(NR_UE_MAC_INST_t *mac,
         harq_id, frame, slot, current_harq->ul_frame, current_harq->ul_slot, data_toul_fb);
 }
 
-void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
+int nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
                            int slot,
                            uint16_t rnti,
                            PUCCH_sched_t *pucch,
@@ -1341,11 +1352,11 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
 
     if (mac->harq_ACK_SpatialBundlingPUCCH ||
         mac->pdsch_HARQ_ACK_Codebook != NR_PhysicalCellGroupConfig__pdsch_HARQ_ACK_Codebook_dynamic) {
-      LOG_E(MAC,"PUCCH Unsupported cell group configuration\n");
-      return;
+      LOG_E(NR_MAC, "PUCCH Unsupported cell group configuration\n");
+      return -1;
     } else if (sc_info->pdsch_CGB_Transmission) {
-      LOG_E(MAC,"PUCCH Unsupported code block group for serving cell config\n");
-      return;
+      LOG_E(NR_MAC, "PUCCH Unsupported code block group for serving cell config\n");
+      return -1;
     }
 
     NR_PUSCH_Config_t *pusch_Config = current_UL_BWP ? current_UL_BWP->pusch_Config : NULL;
@@ -1371,8 +1382,8 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
 
     int n_uci = pucch->n_sr + pucch->n_harq + pucch->n_csi;
     if (n_uci > (sizeof(uint64_t) * 8)) {
-      LOG_E(MAC,"PUCCH number of UCI bits exceeds payload size\n");
-      return;
+      LOG_E(NR_MAC, "PUCCH number of UCI bits exceeds payload size\n");
+      return -1;
     }
 
     switch(pucchres->format.present) {
@@ -1470,7 +1481,8 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
         pucch_pdu->payload = (pucch->csi_part1_payload << (pucch->n_harq + pucch->n_sr)) | (pucch->sr_payload << pucch->n_harq) | pucch->ack_payload;
         break;
       default :
-        AssertFatal(1==0,"Undefined PUCCH format \n");
+        LOG_E(NR_MAC, "Undefined PUCCH format \n");
+        return -1;
     }
 
     pucch_pdu->pucch_tx_power = get_pucch_tx_power_ue(mac,
@@ -1484,8 +1496,10 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
                                                       pucch_pdu->nr_of_symbols,
                                                       subframe_number,
                                                       n_uci);
-  } else
-    AssertFatal(1 == 0, "problem with pucch configuration\n");
+  } else {
+    LOG_E(NR_MAC, "problem with pucch configuration\n");
+    return -1;
+  }
 
   NR_PUCCH_ConfigCommon_t *pucch_ConfigCommon = current_UL_BWP->pucch_ConfigCommon;
 
@@ -1511,8 +1525,10 @@ void nr_ue_configure_pucch(NR_UE_MAC_INST_t *mac,
       pucch_pdu->sequence_hop_flag = 1;
       break;
     default:
-      AssertFatal(1==0,"Group hopping flag undefined (0,1,2) \n");
+      LOG_E(NR_MAC, "Group hopping flag undefined (0,1,2) \n");
+      return -1;
   }
+  return 0;
 }
 
 int16_t get_pucch_tx_power_ue(NR_UE_MAC_INST_t *mac,
@@ -1633,55 +1649,38 @@ int get_deltatf(uint16_t nb_of_prbs,
   return DELTA_TF;
 }
 
-/*******************************************************************
-*
-* NAME :         find_pucch_resource_set
-*
-* PARAMETERS :   ue context
-*                gNB_id identifier
-*
-*
-* RETURN :       harq process identifier
-*
-* DESCRIPTION :  return tx harq process identifier for given transmission slot
-*                YS 38.213 9.2.2  PUCCH Formats for UCI transmission
-*
-*********************************************************************/
-
-int find_pucch_resource_set(NR_UE_MAC_INST_t *mac, int size)
+static int find_pucch_resource_set(NR_PUCCH_Config_t *pucch_Config, int size)
 {
-  int pucch_resource_set_id = 0;
-  NR_PUCCH_Config_t *pucch_Config = mac->current_UL_BWP->pucch_Config;
+  // Procedure described in 38.213 Section 9.2.1
 
-  //long *pucch_max_pl_bits = NULL;
-
-  /* from TS 38.331 field maxPayloadMinus1
-    -- Maximum number of payload bits minus 1 that the UE may transmit using this PUCCH resource set. In a PUCCH occurrence, the UE
-    -- chooses the first of its PUCCH-ResourceSet which supports the number of bits that the UE wants to transmit.
-    -- The field is not present in the first set (Set0) since the maximum Size of Set0 is specified to be 3 bit.
-    -- The field is not present in the last configured set since the UE derives its maximum payload size as specified in 38.213.
-    -- This field can take integer values that are multiples of 4. Corresponds to L1 parameter 'N_2' or 'N_3' (see 38.213, section 9.2)
-  */
-  /* look for the first resource set which supports size number of bits for payload */
-  while (pucch_resource_set_id < MAX_NB_OF_PUCCH_RESOURCE_SETS) {
-    if (pucch_Config && pucch_Config->resourceSetToAddModList && pucch_Config->resourceSetToAddModList->list.array[pucch_resource_set_id] != NULL) {
-      // PUCCH with format0 can be up to 3 bits (2 ack/nacks + 1 sr is 3 max bits)
-      if (size <= 3) {
-        pucch_resource_set_id = 0;
-        return (pucch_resource_set_id);
-        break;
-      } else {
-        pucch_resource_set_id = 1;
-        return (pucch_resource_set_id);
-        break;
-      }
-    }
-    pucch_resource_set_id++;
-  }
+  AssertFatal(pucch_Config && pucch_Config->resourceSetToAddModList, "pucch-Config NULL, this function shouldn't have been called\n");
+  AssertFatal(size <= 1706, "O_UCI cannot be larger that 1706 bits\n");
 
-  pucch_resource_set_id = MAX_NB_OF_PUCCH_RESOURCE_SETS;
+  // a first set of PUCCH resources with pucch-ResourceSetId = 0 if O UCI ≤ 2 including 1 or 2 HARQ-ACK information bits
+  if (size <= 2)
+    return 0;
+
+  const int n_set = pucch_Config->resourceSetToAddModList->list.count;
+
+  int N2 = 1706;
+  int N3 = 1706;
+  for (int i = 0; i < n_set; i++) {
+    NR_PUCCH_ResourceSet_t *pucchresset = pucch_Config->resourceSetToAddModList->list.array[i];
+    NR_PUCCH_ResourceId_t id = pucchresset->pucch_ResourceSetId;
+    if (id == 1)
+      N2 = pucchresset->maxPayloadSize ? *pucchresset->maxPayloadSize : 1706;
+    if (id == 2)
+      N3 = pucchresset->maxPayloadSize ? *pucchresset->maxPayloadSize : 1706;
+  }
 
-  return (pucch_resource_set_id);
+  // a second set of PUCCH resources with pucch-ResourceSetId = 1, if provided by higher layers, if 2 < O UCI ≤ N 2
+  if (size <= N2)
+    return 1;
+  // a third set of PUCCH resources with pucch-ResourceSetId = 2, if provided by higher layers, if N 2 < O UCI ≤ N 3
+  if (size <= N3)
+    return 2;
+  // a fourth set of PUCCH resources with pucch-ResourceSetId = 3, if provided by higher layers, if N 3 < O UCI ≤ 1706
+  return 3;
 }
 
 NR_PUCCH_Resource_t *find_pucch_resource_from_list(struct NR_PUCCH_Config__resourceToAddModList *resourceToAddModList,
@@ -1696,7 +1695,7 @@ NR_PUCCH_Resource_t *find_pucch_resource_from_list(struct NR_PUCCH_Config__resou
   return pucch_resource;
 }
 
-bool check_mux_acknack_csi(NR_PUCCH_Resource_t *csi_res, NR_PUCCH_Config_t *pucch_Config)
+static bool check_mux_acknack_csi(NR_PUCCH_Resource_t *csi_res, NR_PUCCH_Config_t *pucch_Config)
 {
   bool ret;
   switch (csi_res->format.present) {
@@ -2349,7 +2348,7 @@ bool get_downlink_ack(NR_UE_MAC_INST_t *mac, frame_t frame, int slot, PUCCH_sche
       || pucch_Config->resourceSetToAddModList->list.array[0] == NULL)
     configure_initial_pucch(pucch, res_ind);
   else {
-    int resource_set_id = find_pucch_resource_set(mac, O_ACK);
+    int resource_set_id = find_pucch_resource_set(pucch_Config, O_ACK);
     int n_list = pucch_Config->resourceSetToAddModList->list.count;
     AssertFatal(resource_set_id < n_list, "Invalid PUCCH resource set id %d\n", resource_set_id);
     n_list = pucch_Config->resourceSetToAddModList->list.array[resource_set_id]->resourceList.list.count;
@@ -2823,7 +2822,7 @@ void nr_ue_send_sdu(nr_downlink_indication_t *dl_info, int pdu_id)
     nr_ue_process_mac_pdu(dl_info, pdu_id);
     break;
     case FAPI_NR_RX_PDU_TYPE_RAR:
-    nr_ue_process_rar(dl_info, pdu_id);
+      nr_ue_process_rar(dl_info, pdu_id);
     break;
     default:
     break;
@@ -3969,7 +3968,7 @@ int nr_write_ce_ulsch_pdu(uint8_t *mac_ce,
 // - b buffer
 // - ulsch power offset
 // - optimize: mu_pusch, j and table_6_1_2_1_1_2_time_dom_res_alloc_A are already defined in nr_ue_procedures
-static int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
+static void nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
 {
   module_id_t mod_id       = dl_info->module_id;
   frame_t frame            = dl_info->frame;
@@ -3977,7 +3976,7 @@ static int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
 
   if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack == 0) {
     LOG_W(NR_MAC,"[UE %d][RAPROC][%d.%d] CRC check failed on RAR (NAK)\n", mod_id, frame, slot);
-    return 0;
+    return;
   }
 
   NR_UE_MAC_INST_t *mac    = get_mac_inst(mod_id);
@@ -4046,7 +4045,6 @@ static int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
   #endif
 
   if (ra->RA_RAPID_found) {
-
     RAR_grant_t rar_grant;
 
     unsigned char tpc_command;
@@ -4147,45 +4145,33 @@ static int nr_ue_process_rar(nr_downlink_indication_t *dl_info, int pdu_id)
                                              rar_grant.Msg3_t_alloc);
     if (tda_info.nrOfSymbols == 0) {
       LOG_E(MAC, "Cannot schedule Msg3. Something wrong in TDA information\n");
-      return -1;
+      return;
     }
     ret = nr_ue_pusch_scheduler(mac, is_Msg3, frame, slot, &frame_tx, &slot_tx, tda_info.k2);
 
     if (ret != -1) {
-
-      fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slot_tx, tda_info.k2);
       uint16_t rnti = mac->crnti;
-
-      if (!ul_config) {
-        LOG_W(MAC, "In %s: ul_config request is NULL. Probably due to unexpected UL DCI in frame.slot %d.%d. Ignoring DCI!\n", __FUNCTION__, frame, slot);
-        return -1;
-      }
-      AssertFatal(ul_config->number_pdus < sizeof(ul_config->ul_config_list) / sizeof(ul_config->ul_config_list[0]),
-                  "Number of PDUS in ul_config = %d > ul_config_list num elements", ul_config->number_pdus);
-
       // 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;
-        send_msg3_rrc_request(mod_id, rnti);
+        nr_mac_rrc_msg3_ind(mod_id, rnti);
       }
-
-      pthread_mutex_lock(&ul_config->mutex_ul_config);
-      AssertFatal(ul_config->number_pdus<FAPI_NR_UL_CONFIG_LIST_NUM, "ul_config->number_pdus %d out of bounds\n",ul_config->number_pdus);
-      nfapi_nr_ue_pusch_pdu_t *pusch_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].pusch_config_pdu;
-
-      fill_ul_config(ul_config, frame_tx, slot_tx, FAPI_NR_UL_CONFIG_TYPE_PUSCH);
-      pthread_mutex_unlock(&ul_config->mutex_ul_config);
-
+      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
-      nr_config_pusch_pdu(mac, &tda_info, pusch_config_pdu, NULL, &rar_grant, rnti, NR_DCI_NONE);
+      int ret = nr_config_pusch_pdu(mac, &tda_info, &pdu->pusch_config_pdu, NULL, &rar_grant, rnti, NR_DCI_NONE);
+      if (ret != 0)
+        remove_ul_config_last_item(pdu);
+      release_ul_config(pdu, false);
     }
 
   } else {
     ra->t_crnti = 0;
   }
 
-  return ret;
+  return;
 }
 
 // Returns the pathloss in dB for the active UL BWP on the selected carrier based on the DL RS associated with the PRACH transmission
diff --git a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
index 354d6f0b88f48e692f421d128ac5309ce2caffbd..9a89ff647419baf7e75079e96c5d89d3819f7585 100644
--- a/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
+++ b/openair2/LAYER2/NR_MAC_UE/nr_ue_scheduler.c
@@ -59,67 +59,84 @@
 
 static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_frame_t slotP);
 
-void fill_ul_config(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx, uint8_t pdu_type)
+fapi_nr_ul_config_request_pdu_t *lockGet_ul_config(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx, uint8_t pdu_type)
 {
-  AssertFatal(ul_config->number_pdus < sizeof(ul_config->ul_config_list) / sizeof(ul_config->ul_config_list[0]),
-              "Number of PDUS in ul_config = %d > ul_config_list num elements", ul_config->number_pdus);
-  // clear ul_config for new frame/slot
-  if ((ul_config->slot != slot_tx || ul_config->sfn != frame_tx) &&
-      ul_config->number_pdus != 0 &&
-      !get_softmodem_params()->emulate_l1) {
-    LOG_D(MAC, "%d.%d %d.%d f clear ul_config %p t %d pdu %d\n", frame_tx, slot_tx, ul_config->sfn, ul_config->slot, ul_config, pdu_type, ul_config->number_pdus);
+  NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
+
+  // Check if requested on the right slot
+  AssertFatal(is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type) != 0, "UL config_request called at wrong slot %d\n", slot_tx);
+
+  AssertFatal(mac->ul_config_request != NULL, "mac->ul_config_request not initialized, logic bug\n");
+  fapi_nr_ul_config_request_t *ul_config = mac->ul_config_request + slot_tx;
+
+  pthread_mutex_lock(&ul_config->mutex_ul_config);
+  if (ul_config->number_pdus != 0 && (ul_config->frame != frame_tx || ul_config->slot != slot_tx)) {
+    LOG_E(NR_MAC, "Error in ul config consistency, clearing slot %d\n", slot_tx);
     ul_config->number_pdus = 0;
-    memset(ul_config->ul_config_list, 0, sizeof(ul_config->ul_config_list)); 
   }
-  ul_config->ul_config_list[ul_config->number_pdus].pdu_type = pdu_type;
-  //ul_config->slot = slot_tx;
-  //ul_config->sfn = frame_tx;
+  ul_config->frame = frame_tx;
   ul_config->slot = slot_tx;
-  ul_config->sfn = frame_tx;
-  ul_config->number_pdus++;
-
-  LOG_D(NR_MAC, "In %s: Set config request for UL transmission in [%d.%d], number of UL PDUs: %d\n", __FUNCTION__, ul_config->sfn, ul_config->slot, ul_config->number_pdus);
-
+  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
+    LOG_E(NR_MAC, "Error in ul config for slot %d, no memory\n", slot_tx);
+    pthread_mutex_unlock(&ul_config->mutex_ul_config);
+    return NULL;
+  }
+  fapi_nr_ul_config_request_pdu_t *pdu = ul_config->ul_config_list + ul_config->number_pdus++;
+  pdu->pdu_type = pdu_type;
+  AssertFatal(!pdu->lock, "no lock in fapi_nr_ul_config_request_pdu_t, aborting");
+  pdu->lock = &ul_config->mutex_ul_config;
+  pdu->privateNBpdus = &ul_config->number_pdus;
+  LOG_D(NR_MAC, "Added ul pdu for %d.%d, type %d\n", frame_tx, slot_tx, pdu_type);
+  return pdu;
 }
 
-void fill_scheduled_response(nr_scheduled_response_t *scheduled_response,
-                             fapi_nr_dl_config_request_t *dl_config,
-                             fapi_nr_ul_config_request_t *ul_config,
-                             fapi_nr_tx_request_t *tx_request,
-                             module_id_t mod_id,
-                             int cc_id,
-                             frame_t frame,
-                             int slot,
-                             void *phy_data)
+void remove_ul_config_last_item(fapi_nr_ul_config_request_pdu_t *pdu)
 {
-  scheduled_response->dl_config  = dl_config;
-  scheduled_response->ul_config  = ul_config;
-  scheduled_response->tx_request = tx_request;
-  scheduled_response->module_id  = mod_id;
-  scheduled_response->CC_id      = cc_id;
-  scheduled_response->frame      = frame;
-  scheduled_response->slot       = slot;
-  scheduled_response->phy_data   = phy_data;
+  pdu->privateNBpdus--;
+}
 
+void release_ul_config(fapi_nr_ul_config_request_pdu_t *configPerSlot, bool clearIt)
+{
+  pthread_mutex_t *lock = configPerSlot->lock;
+  configPerSlot->lock = NULL;
+  if (clearIt)
+    *configPerSlot->privateNBpdus = 0;
+  pthread_mutex_unlock(lock);
 }
 
-/*
- * This function returns the UL config corresponding to a given UL slot
- * from MAC instance .
- */
-fapi_nr_ul_config_request_t *get_ul_config_request(NR_UE_MAC_INST_t *mac, int slot, int fb_time)
+fapi_nr_ul_config_request_pdu_t *fapiLockIterator(fapi_nr_ul_config_request_t *ul_config, frame_t frame_tx, int slot_tx)
 {
+  pthread_mutex_lock(&ul_config->mutex_ul_config);
+  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
+    LOG_E(NR_MAC, "Error in ul config in slot %d no memory\n", ul_config->slot);
+    pthread_mutex_unlock(&ul_config->mutex_ul_config);
+    return NULL;
+  }
+  if (ul_config->number_pdus != 0 && (ul_config->frame != frame_tx || ul_config->slot != slot_tx)) {
+    LOG_E(NR_MAC, "Error in ul config consistency, clearing it slot %d\n", slot_tx);
+    ul_config->number_pdus = 0;
+    pthread_mutex_unlock(&ul_config->mutex_ul_config);
+    return NULL;
+  }
+  if (ul_config->number_pdus >= FAPI_NR_UL_CONFIG_LIST_NUM) {
+    LOG_E(NR_MAC, "Error in ul config for slot %d, no memory\n", slot_tx);
+    pthread_mutex_unlock(&ul_config->mutex_ul_config);
+    return NULL;
+  }
+  fapi_nr_ul_config_request_pdu_t *pdu = ul_config->ul_config_list + ul_config->number_pdus;
+  pdu->pdu_type = FAPI_NR_END;
+  pdu->lock = &ul_config->mutex_ul_config;
+  pdu->privateNBpdus = &ul_config->number_pdus;
+  return ul_config->ul_config_list;
+}
 
+fapi_nr_ul_config_request_pdu_t *lockGet_ul_iterator(NR_UE_MAC_INST_t *mac, frame_t frame_tx, int slot_tx)
+{
   NR_TDD_UL_DL_ConfigCommon_t *tdd_config = mac->tdd_UL_DL_ConfigurationCommon;
-
   //Check if requested on the right slot
-  AssertFatal(is_nr_UL_slot(tdd_config, slot, mac->frame_type) != 0, "UL config_request called at wrong slot %d\n", slot);
-
-  int mu = mac->current_UL_BWP ? mac->current_UL_BWP->scs : get_softmodem_params()->numerology;
-  const int n = nr_slots_per_frame[mu];
-  AssertFatal(fb_time < n, "Cannot schedule to a slot more than 1 frame away, ul_config_request is not big enough\n");
+  AssertFatal(is_nr_UL_slot(tdd_config, slot_tx, mac->frame_type) != 0, "UL config_request called at wrong slot %d\n", slot_tx);
   AssertFatal(mac->ul_config_request != NULL, "mac->ul_config_request not initialized, logic bug\n");
-  return &mac->ul_config_request[slot];
+  return fapiLockIterator(mac->ul_config_request + slot_tx, frame_tx, slot_tx);
 }
 
 /*
@@ -156,10 +173,7 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
 
       // Table 7.3.1.1.2-2: transformPrecoder=disabled and maxRank = 2 or 3 or 4
       if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled)
-        && ((*pusch_Config->maxRank == 2) ||
-        (*pusch_Config->maxRank == 3) ||
-        (*pusch_Config->maxRank == 4))){
-
+          && ((*pusch_Config->maxRank == 2) || (*pusch_Config->maxRank == 3) || (*pusch_Config->maxRank == 4))) {
         if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][0];
           pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][1];
@@ -178,9 +192,8 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
 
       // Table 7.3.1.1.2-3: transformPrecoder= enabled, or transformPrecoder=disabled and maxRank = 1
       if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
-        || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
-        && (*pusch_Config->maxRank == 1)) {
-
+           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
+          && (*pusch_Config->maxRank == 1)) {
         if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][6];
           pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][7];
@@ -216,9 +229,8 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
 
       // Table 7.3.1.1.2-5: transformPrecoder= enabled, or transformPrecoder= disabled and maxRank = 1
       if (((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled)
-        || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
-        && (*pusch_Config->maxRank == 1)) {
-
+           || (transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled))
+          && (*pusch_Config->maxRank == 1)) {
         if (*pusch_Config->codebookSubset == NR_PUSCH_Config__codebookSubset_fullyAndPartialAndNonCoherent) {
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][16];
           pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][17];
@@ -228,7 +240,6 @@ void ul_layers_config(NR_UE_MAC_INST_t *mac, nfapi_nr_ue_pusch_pdu_t *pusch_conf
           pusch_config_pdu->nrOfLayers = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][18];
           pusch_config_pdu->Tpmi = table_7_3_1_1_2_2_3_4_5[dci->precoding_information.val][19];
         }
-
       }
     }
   }
@@ -261,8 +272,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
 
   if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
       (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-6
-      pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
-      pusch_config_pdu->dmrs_ports = 1<<dci->antenna_ports.val;
+    pusch_config_pdu->num_dmrs_cdm_grps_no_data = 2;
+    pusch_config_pdu->dmrs_ports = 1 << dci->antenna_ports.val;
   }
 
   if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_enabled) &&
@@ -273,8 +284,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
     *n_front_load_symb = (dci->antenna_ports.val > 3)?2:1;
   }
 
-  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
-    (dmrs_type == NULL) && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
+      && (max_length == NULL)) { // tables 7.3.1.1.2-8/9/10/11
 
     if (rank == 1) {
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1;
@@ -297,8 +308,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
     }
   }
 
-  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
-    (dmrs_type == NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-12/13/14/15
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type == NULL)
+      && (max_length != NULL)) { // tables 7.3.1.1.2-12/13/14/15
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?2:1; //TBC
@@ -334,9 +345,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
     }
   }
 
-  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
-    (dmrs_type != NULL) &&
-    (max_length == NULL)) { // tables 7.3.1.1.2-16/17/18/19
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
+      && (max_length == NULL)) { // tables 7.3.1.1.2-16/17/18/19
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = (dci->antenna_ports.val > 1)?((dci->antenna_ports.val > 5)?3:2):1; //TBC
@@ -368,8 +378,8 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
     }
   }
 
-  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) &&
-    (dmrs_type != NULL) && (max_length != NULL)) { // tables 7.3.1.1.2-20/21/22/23
+  if ((transformPrecoder == NR_PUSCH_Config__transformPrecoder_disabled) && (dmrs_type != NULL)
+      && (max_length != NULL)) { // tables 7.3.1.1.2-20/21/22/23
 
     if (rank == 1){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_20[dci->antenna_ports.val][0]; //TBC
@@ -383,7 +393,7 @@ void ul_ports_config(NR_UE_MAC_INST_t *mac, int *n_front_load_symb, nfapi_nr_ue_
       //pusch_config_pdu->dmrs_ports[0] = table_7_3_1_1_2_21[dci->antenna_ports.val][1];
       //pusch_config_pdu->dmrs_ports[1] = table_7_3_1_1_2_21[dci->antenna_ports.val][2];
       //n_front_load_symb = table_7_3_1_1_2_21[dci->antenna_ports.val][3]; //FIXME
-      }
+    }
 
     if (rank == 3){
       pusch_config_pdu->num_dmrs_cdm_grps_no_data = table_7_3_1_1_2_22[dci->antenna_ports.val][0]; //TBC
@@ -450,7 +460,7 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     int abwp_size = current_UL_BWP->BWPSize;
     int scs = current_UL_BWP->scs;
 
-      // BWP start selection according to 8.3 of TS 38.213
+    // BWP start selection according to 8.3 of TS 38.213
     if ((ibwp_start < abwp_start) || (ibwp_size > abwp_size)) {
       pusch_config_pdu->bwp_start = abwp_start;
       pusch_config_pdu->bwp_size = abwp_size;
@@ -467,9 +477,18 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     else
       mask = (1 << (28 - (int)(ceil(log2((ibwp_size*(ibwp_size+1))>>1))))) - 1;
 
-    int f_alloc = rar_grant->Msg3_f_alloc & mask;
-    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu, NULL, ibwp_size, 0, f_alloc) < 0)
+    dci_field_t f_alloc;
+    f_alloc.val = rar_grant->Msg3_f_alloc & mask;
+    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu,
+                                                       NULL,
+                                                       NULL,
+                                                       ibwp_size,
+                                                       0,
+                                                       0,
+                                                       f_alloc) < 0) {
+      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
       return -1;
+    }
 
     // virtual resource block to physical resource mapping for Msg3 PUSCH (6.3.1.7 in 38.211)
     //pusch_config_pdu->rb_start += ibwp_start - abwp_start;
@@ -554,7 +573,8 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
     NR_DMRS_UplinkConfig_t *NR_DMRS_ulconfig = NULL;
     if(pusch_Config) {
       NR_DMRS_ulconfig = (mappingtype == NR_PUSCH_TimeDomainResourceAllocation__mappingType_typeA)
-                         ? pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup : pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
+                             ? pusch_Config->dmrs_UplinkForPUSCH_MappingTypeA->choice.setup
+                             : pusch_Config->dmrs_UplinkForPUSCH_MappingTypeB->choice.setup;
     }
 
     pusch_config_pdu->scid = 0;
@@ -582,8 +602,10 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
       else
         AssertFatal(1==0,"SequenceGroupHopping or sequenceHopping are NOT Supported\n");
 
-      LOG_D(NR_MAC,"TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d \n", pusch_config_pdu->num_dmrs_cdm_grps_no_data,
-                pusch_config_pdu->dfts_ofdm.low_papr_group_number);
+      LOG_D(NR_MAC,
+            "TRANSFORM PRECODING IS ENABLED. CDM groups: %d, U: %d \n",
+            pusch_config_pdu->num_dmrs_cdm_grps_no_data,
+            pusch_config_pdu->dfts_ofdm.low_papr_group_number);
     }
     else {
       if (pusch_config_pdu->scid == 0 && NR_DMRS_ulconfig &&
@@ -598,7 +620,14 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
 
     /* IDENTIFIER_DCI_FORMATS */
     /* FREQ_DOM_RESOURCE_ASSIGNMENT_UL */
-    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu, NULL, current_UL_BWP->BWPSize, 0, dci->frequency_domain_assignment.val) < 0){
+    if (nr_ue_process_dci_freq_dom_resource_assignment(pusch_config_pdu,
+                                                       NULL,
+                                                       NULL,
+                                                       current_UL_BWP->BWPSize,
+                                                       0,
+                                                       0,
+                                                       dci->frequency_domain_assignment) < 0) {
+      LOG_E(NR_MAC, "can't nr_ue_process_dci_freq_dom_resource_assignment()\n");
       return -1;
     }
 
@@ -743,10 +772,11 @@ int nr_config_pusch_pdu(NR_UE_MAC_INST_t *mac,
   return 0;
 }
 
-void configure_srs_pdu(NR_UE_MAC_INST_t *mac,
-                       NR_SRS_Resource_t *srs_resource,
-                       fapi_nr_ul_config_srs_pdu *srs_config_pdu,
-                       int period, int offset)
+int configure_srs_pdu(NR_UE_MAC_INST_t *mac,
+                      NR_SRS_Resource_t *srs_resource,
+                      fapi_nr_ul_config_srs_pdu *srs_config_pdu,
+                      int period,
+                      int offset)
 {
   NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
 
@@ -814,6 +844,7 @@ void configure_srs_pdu(NR_UE_MAC_INST_t *mac,
   LOG_I(NR_MAC,"srs_config_pdu->t_srs = %u\n", srs_config_pdu->t_srs);
   LOG_I(NR_MAC,"srs_config_pdu->t_offset = %u\n", srs_config_pdu->t_offset);
 #endif
+  return 0;
 }
 
 // Aperiodic SRS scheduling
@@ -870,11 +901,13 @@ void nr_ue_aperiodic_srs_scheduling(NR_UE_MAC_INST_t *mac, long resource_trigger
     return;
   }
   int sched_frame = frame + (slot + slot_offset >= n_slots_frame) % 1024;
-
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, sched_slot, slot_offset);
-  fapi_nr_ul_config_srs_pdu *srs_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].srs_config_pdu;
-  configure_srs_pdu(mac, srs_resource, srs_config_pdu, 0, 0);
-  fill_ul_config(ul_config, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
+  fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, sched_frame, sched_slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
+  if (!pdu)
+    return;
+  int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, 0, 0);
+  if (ret != 0)
+    remove_ul_config_last_item(pdu);
+  release_ul_config(pdu, false);
 }
 
 
@@ -923,14 +956,15 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo
 
     // Check if UE should transmit the SRS
     if((frame*n_slots_frame+slot-offset)%period == 0) {
-
-      fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slot, 0);
-      fapi_nr_ul_config_srs_pdu *srs_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].srs_config_pdu;
-
-      configure_srs_pdu(mac, srs_resource, srs_config_pdu, period, offset);
-
-      fill_ul_config(ul_config, frame, slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
-      srs_scheduled = true;
+      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frame, slot, FAPI_NR_UL_CONFIG_TYPE_SRS);
+      if (!pdu)
+        return false;
+      int ret = configure_srs_pdu(mac, srs_resource, &pdu->srs_config_pdu, period, offset);
+      if (ret != 0)
+        remove_ul_config_last_item(pdu);
+      else
+        srs_scheduled = true;
+      release_ul_config(pdu, false);
     }
   }
   return srs_scheduled;
@@ -942,9 +976,7 @@ bool nr_ue_periodic_srs_scheduling(module_id_t mod_id, frame_t frame, slot_t slo
 // 3. TODO: Perform PHR procedures
 void nr_ue_dl_scheduler(nr_downlink_indication_t *dl_info)
 {
-  module_id_t mod_id    = dl_info->module_id;
-  uint32_t gNB_index    = dl_info->gNB_index;
-  int cc_id             = dl_info->cc_id;
+  module_id_t mod_id = dl_info->module_id;
   frame_t rx_frame      = dl_info->frame;
   slot_t rx_slot        = dl_info->slot;
   NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
@@ -952,54 +984,41 @@ void nr_ue_dl_scheduler(nr_downlink_indication_t *dl_info)
   fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, rx_slot);
   dl_config->sfn  = rx_frame;
   dl_config->slot = rx_slot;
+  dl_config->number_pdus = 0;
 
-  nr_scheduled_response_t scheduled_response;
-  nr_dcireq_t dcireq;
-
-  if(mac->state > UE_NOT_SYNC) {
-
-    dcireq.module_id = mod_id;
-    dcireq.gNB_index = gNB_index;
-    dcireq.cc_id     = cc_id;
-    dcireq.frame     = rx_frame;
-    dcireq.slot      = rx_slot;
-    dcireq.dl_config_req.number_pdus = 0;
-    nr_ue_dcireq(&dcireq); //to be replaced with function pointer later
-    *dl_config = dcireq.dl_config_req;
+  if (mac->state == UE_NOT_SYNC)
+    return;
 
-    if(mac->ul_time_alignment.ta_apply)
-      schedule_ta_command(dl_config, &mac->ul_time_alignment);
-    if(mac->state == UE_CONNECTED) {
-      nr_schedule_csirs_reception(mac, rx_frame, rx_slot);
-      nr_schedule_csi_for_im(mac, rx_frame, rx_slot);
-    }
-    dcireq.dl_config_req = *dl_config;
+  ue_dci_configuration(mac, dl_config, rx_frame, rx_slot);
 
-    fill_scheduled_response(&scheduled_response, &dcireq.dl_config_req, NULL, NULL, mod_id, cc_id, rx_frame, rx_slot, dl_info->phy_data);
-    if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
-      LOG_D(NR_MAC,"1# scheduled_response transmitted, %d, %d\n", rx_frame, rx_slot);
-      mac->if_module->scheduled_response(&scheduled_response);
-    }
+  if (mac->ul_time_alignment.ta_apply)
+    schedule_ta_command(dl_config, &mac->ul_time_alignment);
+  if (mac->state == UE_CONNECTED) {
+    nr_schedule_csirs_reception(mac, rx_frame, rx_slot);
+    nr_schedule_csi_for_im(mac, rx_frame, rx_slot);
   }
+
+  nr_scheduled_response_t scheduled_response = {.dl_config = dl_config,
+                                                .module_id = dl_info->module_id,
+                                                .CC_id = dl_info->cc_id,
+                                                .phy_data = dl_info->phy_data,
+                                                .mac = mac};
+  if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
+    mac->if_module->scheduled_response(&scheduled_response);
   else
-    dl_config->number_pdus = 0;
+    LOG_E(NR_MAC, "Internal error, no scheduled_response function\n");
 }
 
 void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info)
 {
   int cc_id             = ul_info->cc_id;
-  frame_t frame_tx      = ul_info->frame_tx;
-  slot_t slot_tx        = ul_info->slot_tx;
+  frame_t frame_tx = ul_info->frame;
+  slot_t slot_tx = ul_info->slot;
   module_id_t mod_id    = ul_info->module_id;
   uint32_t gNB_index    = ul_info->gNB_index;
 
   NR_UE_MAC_INST_t *mac = get_mac_inst(mod_id);
-  RA_config_t *ra       = &mac->ra;
-
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slot_tx, 0);
-  if (!ul_config)
-    LOG_E(NR_MAC, "mac->ul_config is null!\n");
-
+  RA_config_t *ra = &mac->ra;
   if(mac->state < UE_CONNECTED) {
     nr_ue_get_rach(mod_id, cc_id, frame_tx, gNB_index, slot_tx);
     nr_ue_prach_scheduler(mod_id, frame_tx, slot_tx);
@@ -1011,74 +1030,68 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info)
 
   // Schedule ULSCH only if the current frame and slot match those in ul_config_req
   // AND if a UL grant (UL DCI or Msg3) has been received (as indicated by num_pdus)
-  if (ul_config) {
-    pthread_mutex_lock(&ul_config->mutex_ul_config);
-    if ((ul_info->slot_tx == ul_config->slot && ul_info->frame_tx == ul_config->sfn) && ul_config->number_pdus > 0){
-
-      LOG_D(NR_MAC, "[%d.%d]: number of UL PDUs: %d with UL transmission in [%d.%d]\n", frame_tx, slot_tx, ul_config->number_pdus, ul_config->sfn, ul_config->slot);
-
-      uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
-      nr_scheduled_response_t scheduled_response;
-      fapi_nr_tx_request_t tx_req;
-      tx_req.slot = slot_tx;
-      tx_req.sfn = frame_tx;
-      tx_req.number_of_pdus = 0;
-
-      for (int j = 0; j < ul_config->number_pdus; j++) {
-        uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[tx_req.number_of_pdus];
-
-        fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = &ul_config->ul_config_list[j];
-
-        if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
-          int mac_pdu_exist = 0;
-          uint16_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size;
-          LOG_D(NR_MAC,"harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n",
-                ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id,
-                ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator,
-                TBS_bytes,ra->ra_state);
-          if (ra->ra_state == WAIT_RAR && !ra->cfra) {
-            nr_get_msg3_payload(mod_id, ulsch_input_buffer, TBS_bytes);
-            for (int k = 0; k < TBS_bytes; k++) {
-              LOG_D(NR_MAC,"(%i): 0x%x\n", k, ulsch_input_buffer[k]);
-            }
-            mac_pdu_exist = 1;
-          } else {
-            if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator &&
-                (mac->state == UE_CONNECTED ||
-                (ra->ra_state == WAIT_RAR && ra->cfra))){
-              // Getting IP traffic to be transmitted
-              nr_ue_get_sdu(mod_id, cc_id,frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes);
-              mac_pdu_exist = 1;
-            }
-          }
+  uint8_t ulsch_input_buffer_array[NFAPI_MAX_NUM_UL_PDU][MAX_ULSCH_PAYLOAD_BYTES];
+  int number_of_pdus = 0;
 
-          // Config UL TX PDU
-          if (mac_pdu_exist) {
-            tx_req.tx_request_body[tx_req.number_of_pdus].pdu_length = TBS_bytes;
-            tx_req.tx_request_body[tx_req.number_of_pdus].pdu_index = j;
-            tx_req.tx_request_body[tx_req.number_of_pdus].pdu = ulsch_input_buffer;
-            tx_req.number_of_pdus++;
-          }
-          if (ra->ra_state == WAIT_CONTENTION_RESOLUTION && !ra->cfra){
-            LOG_I(NR_MAC,"[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx);
-            // 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3 transmission
-            nr_Msg3_transmitted(ul_info->module_id, ul_info->cc_id, ul_info->frame_tx, ul_info->slot_tx, ul_info->gNB_index);
-          }
-          if (ra->ra_state == WAIT_RAR && !ra->cfra){
-            LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
-            nr_Msg3_transmitted(ul_info->module_id, ul_info->cc_id, ul_info->frame_tx, ul_info->slot_tx, ul_info->gNB_index);
-          }
+  fapi_nr_ul_config_request_pdu_t *ulcfg_pdu = lockGet_ul_iterator(mac, frame_tx, slot_tx);
+  if (!ulcfg_pdu)
+    return;
+  LOG_D(NR_MAC, "number of UL PDUs: %d with UL transmission in sfn [%d.%d]\n", *ulcfg_pdu->privateNBpdus, frame_tx, slot_tx);
+
+  while (ulcfg_pdu->pdu_type != FAPI_NR_END) {
+    uint8_t *ulsch_input_buffer = ulsch_input_buffer_array[number_of_pdus];
+    if (ulcfg_pdu->pdu_type == FAPI_NR_UL_CONFIG_TYPE_PUSCH) {
+      int mac_pdu_exist = 0;
+      uint16_t TBS_bytes = ulcfg_pdu->pusch_config_pdu.pusch_data.tb_size;
+      LOG_D(NR_MAC,
+            "harq_id %d, new_data_indicator %d, TBS_bytes %d (ra_state %d)\n",
+            ulcfg_pdu->pusch_config_pdu.pusch_data.harq_process_id,
+            ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator,
+            TBS_bytes,
+            ra->ra_state);
+      if (ra->ra_state == WAIT_RAR && !ra->cfra) {
+        nr_get_msg3_payload(mod_id, ulsch_input_buffer, TBS_bytes);
+        for (int k = 0; k < TBS_bytes; k++) {
+          LOG_D(NR_MAC, "(%i): 0x%x\n", k, ulsch_input_buffer[k]);
+        }
+        mac_pdu_exist = 1;
+      } else {
+        if (ulcfg_pdu->pusch_config_pdu.pusch_data.new_data_indicator
+            && (mac->state == UE_CONNECTED || (ra->ra_state == WAIT_RAR && ra->cfra))) {
+          // Getting IP traffic to be transmitted
+          nr_ue_get_sdu(mod_id, cc_id, frame_tx, slot_tx, gNB_index, ulsch_input_buffer, TBS_bytes);
+          mac_pdu_exist = 1;
         }
       }
-      pthread_mutex_unlock(&ul_config->mutex_ul_config); // avoid double lock
-      fill_scheduled_response(&scheduled_response, NULL, ul_config, &tx_req, mod_id, cc_id, frame_tx, slot_tx, ul_info->phy_data);
-      if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL){
-        LOG_D(NR_MAC,"3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
-        mac->if_module->scheduled_response(&scheduled_response);
+
+      // Config UL TX PDU
+      if (mac_pdu_exist) {
+        ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu = ulsch_input_buffer;
+        ulcfg_pdu->pusch_config_pdu.tx_request_body.pdu_length = TBS_bytes;
+        number_of_pdus++;
+      }
+      if (ra->ra_state == WAIT_CONTENTION_RESOLUTION && !ra->cfra) {
+        LOG_I(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 retransmitted\n", frame_tx, slot_tx);
+        // 38.321 restart the ra-ContentionResolutionTimer at each HARQ retransmission in the first symbol after the end of the Msg3
+        // transmission
+        nr_Msg3_transmitted(ul_info->module_id, ul_info->cc_id, ul_info->frame, ul_info->slot, ul_info->gNB_index);
+      }
+      if (ra->ra_state == WAIT_RAR && !ra->cfra) {
+        LOG_A(NR_MAC, "[RAPROC][%d.%d] RA-Msg3 transmitted\n", frame_tx, slot_tx);
+        nr_Msg3_transmitted(ul_info->module_id, ul_info->cc_id, frame_tx, slot_tx, ul_info->gNB_index);
       }
-      pthread_mutex_lock(&ul_config->mutex_ul_config);
     }
-    pthread_mutex_unlock(&ul_config->mutex_ul_config);
+    ulcfg_pdu++;
+  }
+  release_ul_config(ulcfg_pdu, false);
+  if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
+    LOG_D(NR_MAC, "3# scheduled_response transmitted,%d, %d\n", frame_tx, slot_tx);
+    nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slot_tx,
+                                                  .mac = mac,
+                                                  .module_id = ul_info->module_id,
+                                                  .CC_id = ul_info->cc_id,
+                                                  .phy_data = ul_info->phy_data};
+    mac->if_module->scheduled_response(&scheduled_response);
   }
 
   // update Bj for all active lcids before LCP procedure
@@ -1087,8 +1100,9 @@ void nr_ue_ul_scheduler(nr_uplink_indication_t *ul_info)
     int lcid = lc_bearer->lcids_ordered;
     NR_LogicalChannelConfig_t *lcconfig = mac->logicalChannelConfig[lcid - 1];
     NR_LC_SCHEDULING_INFO *sched_lc = &mac->scheduling_info.lc_sched_info[lcid - 1];
-    int32_t bucketSize_max =
-        sched_lc->bucket_size; // max amount of data that can be buffered/accumulated in a logical channel buffer
+    // max amount of data that can be buffered/accumulated in a logical channel buffer
+    int32_t bucketSize_max = sched_lc->bucket_size;
+    AssertFatal(bucketSize_max >= 0, "negative bucketSize_max %d, will never schedule UE: lcid %d\n",bucketSize_max, lcid);
 
     /*
       measure Bj
@@ -1141,11 +1155,12 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t
   uint32_t lcgid_buffer_remain[NR_MAX_NUM_LCGID] = {0,0,0,0,0,0,0,0};
   int32_t lcid_bytes_in_buffer[NR_MAX_NUM_LCID];
   /* Array for ordering LCID with data per decreasing priority order */
-  uint8_t lcid_reordered_array[NR_MAX_NUM_LCID]=
-  {NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,
-   NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,
-   NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,
-   NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,NR_MAX_NUM_LCID,
+  uint8_t lcid_reordered_array[NR_MAX_NUM_LCID] = {
+      NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID,
+      NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID,
+      NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID,
+      NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID,
+      NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID, NR_MAX_NUM_LCID,
   };
   uint8_t pos_next = 0;
   //uint8_t highest_priority = 16;
@@ -1235,7 +1250,7 @@ bool nr_update_bsr(module_id_t module_idP, frame_t frameP, slot_t slotP, uint8_t
       /* UL data, for a logical channel which belongs to a LCG, becomes available for transmission in the RLC entity
          either the data belongs to a logical channel with higher priority than the priorities of the logical channels
          which belong to any LCG and for which data is already available for transmission
-       */
+      */
       {
         bsr_regular_triggered = true;
         LOG_D(NR_MAC,
@@ -1431,7 +1446,13 @@ int nr_get_sf_retxBSRTimer(uint8_t sf_offset) {
 // PUSCH Msg3 scheduler:
 // - scheduled by RAR UL grant according to 8.3 of TS 38.213
 // Note: Msg3 tx in the uplink symbols of mixed slot
-int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t current_frame, int current_slot, frame_t *frame_tx, int *slot_tx, long k2)
+int nr_ue_pusch_scheduler(const NR_UE_MAC_INST_t *mac,
+                          const uint8_t is_Msg3,
+                          const frame_t current_frame,
+                          const int current_slot,
+                          frame_t *frame_tx,
+                          int *slot_tx,
+                          const long k2)
 {
   AssertFatal(k2 > DURATION_RX_TO_TX,
               "Slot offset K2 (%ld) needs to be higher than DURATION_RX_TO_TX (%d). Please set min_rxtxtime at least to %d in gNB config file or gNBs.[0].min_rxtxtime=%d via command line.\n",
@@ -1441,7 +1462,7 @@ int nr_ue_pusch_scheduler(NR_UE_MAC_INST_t *mac, uint8_t is_Msg3, frame_t curren
               DURATION_RX_TO_TX);
 
   int delta = 0;
-  NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
+  const NR_UE_UL_BWP_t *current_UL_BWP = mac->current_UL_BWP;
 
   // Get the numerology to calculate the Tx frame and slot
   int mu = current_UL_BWP->scs;
@@ -1547,7 +1568,6 @@ static void build_ro_list(NR_UE_MAC_INST_t *mac)
   }
 
   // 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;
@@ -1702,7 +1722,6 @@ static void build_ssb_list(NR_UE_MAC_INST_t *mac)
 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;
@@ -1713,7 +1732,6 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
   uint8_t required_nb_of_prach_conf_period; // Nb of PRACH configuration periods required to map all the SSBs
 
   // Determine the SSB to RACH mapping ratio
-  // =======================================
   switch (ssb_perRACH_config){
     case NR_RACH_ConfigCommon__ssb_perRACH_OccasionAndCB_PreamblesPerSSB_PR_oneEighth:
       multiple_ssb_per_ro = false;
@@ -1757,8 +1775,8 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
   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
+  // 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");
@@ -1774,8 +1792,9 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
   AssertFatal(prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion > 0,
               "prach_assoc_pattern.prach_conf_period_list[0].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);
-  required_nb_of_prach_conf_period = ((required_nb_of_prach_occasion-1) + prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion) /
-                                     prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion;
+  required_nb_of_prach_conf_period =
+      ((required_nb_of_prach_occasion - 1) + prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion)
+      / prach_assoc_pattern->prach_conf_period_list[0].nb_of_prach_occasion;
 
   if (required_nb_of_prach_conf_period == 1) {
     prach_association_period_list->nb_of_prach_conf_period = 1;
@@ -1805,7 +1824,6 @@ static void map_ssb_to_ro(NR_UE_MAC_INST_t *mac)
         prach_association_period_list->nb_of_frame);
 
   // Proceed to the SSB to RO mapping
-  // ================================
   uint8_t ssb_idx = 0;
   uint8_t prach_configuration_period_idx; // PRACH Configuration period index within the association pattern
   prach_conf_period_t *prach_conf_period_p;
@@ -2128,8 +2146,6 @@ void nr_ue_pucch_scheduler(module_id_t module_idP, frame_t frameP, int slotP, vo
 
   if (num_res > 1)
     multiplex_pucch_resource(mac, pucch, num_res);
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slotP, 0);
-  pthread_mutex_lock(&ul_config->mutex_ul_config);
   for (int j = 0; j < num_res; j++) {
     if (pucch[j].n_harq + pucch[j].n_sr + pucch[j].n_csi != 0) {
       LOG_D(NR_MAC,
@@ -2142,22 +2158,28 @@ void nr_ue_pucch_scheduler(module_id_t module_idP, frame_t frameP, int slotP, vo
       mac->nr_ue_emul_l1.num_srs = pucch[j].n_sr;
       mac->nr_ue_emul_l1.num_harqs = pucch[j].n_harq;
       mac->nr_ue_emul_l1.num_csi_reports = pucch[j].n_csi;
-      AssertFatal(ul_config->number_pdus < FAPI_NR_UL_CONFIG_LIST_NUM,
-                  "ul_config->number_pdus %d out of bounds\n",
-                  ul_config->number_pdus);
-      fapi_nr_ul_config_pucch_pdu *pucch_pdu = &ul_config->ul_config_list[ul_config->number_pdus].pucch_config_pdu;
-      fill_ul_config(ul_config, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
+      fapi_nr_ul_config_request_pdu_t *pdu = lockGet_ul_config(mac, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PUCCH);
+      if (!pdu) {
+        LOG_E(NR_MAC, "Error in pucch allocation\n");
+        return;
+      }
       mac->nr_ue_emul_l1.active_uci_sfn_slot = NFAPI_SFNSLOT2HEX(frameP, slotP);
-      pthread_mutex_unlock(&ul_config->mutex_ul_config);
-      nr_ue_configure_pucch(mac,
-                            slotP,
-                            mac->crnti, // FIXME not sure this is valid for all pucch instances
-                            &pucch[j],
-                            pucch_pdu);
-      nr_scheduled_response_t scheduled_response;
-      fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, phy_data);
-      if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
-        mac->if_module->scheduled_response(&scheduled_response);
+      int ret = nr_ue_configure_pucch(mac,
+                                      slotP,
+                                      mac->crnti, // FIXME not sure this is valid for all pucch instances
+                                      &pucch[j],
+                                      &pdu->pucch_config_pdu);
+      if (ret != 0)
+        remove_ul_config_last_item(pdu);
+      release_ul_config(pdu, false);
+    }
+    if (mac->if_module != NULL && mac->if_module->scheduled_response != NULL) {
+      nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
+                                                    .mac = mac,
+                                                    .module_id = module_idP,
+                                                    .CC_id = 0 /*TBR fix*/,
+                                                    .phy_data = phy_data};
+      mac->if_module->scheduled_response(&scheduled_response);
     }
   }
 }
@@ -2195,19 +2217,20 @@ void nr_schedule_csi_for_im(NR_UE_MAC_INST_t *mac, int frame, int slot)
     // As specified in 5.2.2.4 of 38.214
     switch (imcsi->csi_IM_ResourceElementPattern->present) {
       case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern0:
-        for (int i = 0; i<4; i++) {
-          csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0<<1) + (i>>1);
-          csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i%2);
+        for (int i = 0; i < 4; i++) {
+          csiim_config_pdu->k_csiim[i] =
+              (imcsi->csi_IM_ResourceElementPattern->choice.pattern0->subcarrierLocation_p0 << 1) + (i >> 1);
+          csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern0->symbolLocation_p0 + (i % 2);
         }
         break;
       case NR_CSI_IM_Resource__csi_IM_ResourceElementPattern_PR_pattern1:
-        for (int i = 0; i<4; i++) {
-          csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1<<2) + i;
+        for (int i = 0; i < 4; i++) {
+          csiim_config_pdu->k_csiim[i] = (imcsi->csi_IM_ResourceElementPattern->choice.pattern1->subcarrierLocation_p1 << 2) + i;
           csiim_config_pdu->l_csiim[i] = imcsi->csi_IM_ResourceElementPattern->choice.pattern1->symbolLocation_p1;
         }
         break;
       default:
-        AssertFatal(1==0, "Invalid CSI-IM pattern\n");
+        AssertFatal(1 == 0, "Invalid CSI-IM pattern\n");
     }
     dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_IM;
     dl_config->number_pdus += 1;
@@ -2235,11 +2258,10 @@ NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measc
       AssertFatal(res_list, "nzp_CSI_RS_ResourceSetToAddModList shouldn't be NULL\n");
       for (int j = 0; j < res_list->list.count; j++) {
         NR_NZP_CSI_RS_ResourceSet_t *csi_res = res_list->list.array[j];
-        if(*res_id != csi_res->nzp_CSI_ResourceSetId)
+        if (*res_id != csi_res->nzp_CSI_ResourceSetId)
           continue;
         for (int k = 0; k < csi_res->nzp_CSI_RS_Resources.list.count; k++) {
-          AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k],
-                      "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
+          AssertFatal(csi_res->nzp_CSI_RS_Resources.list.array[k], "NZP_CSI_RS_ResourceId shoulan't be NULL\n");
           if (csi_id == *csi_res->nzp_CSI_RS_Resources.list.array[k]) {
             found = true;
             break;
@@ -2259,8 +2281,7 @@ NR_CSI_ResourceConfigId_t find_CSI_resourceconfig(NR_CSI_MeasConfig_t *csi_measc
   return -1; // not found any CSI-resource in current DL BWP associated with this CSI-RS ID
 }
 
-uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig,
-                                     NR_CSI_ResourceConfigId_t csi_res_id)
+uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig, NR_CSI_ResourceConfigId_t csi_res_id)
 {
   uint8_t meas_bitmap = 0;
   if (csi_res_id > NR_maxNrofCSI_ResourceConfigurations)
@@ -2271,27 +2292,26 @@ uint8_t set_csirs_measurement_bitmap(NR_CSI_MeasConfig_t *csi_measconfig,
       continue;
     // bit 0 RSRP bit 1 RI bit 2 LI bit 3 PMI bit 4 CQI bit 5 i1
     switch (report_config->reportQuantity.present) {
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_PMI_CQI:
         meas_bitmap += (1 << 1) + (1 << 3) + (1 << 4);
         break;
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1 :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1:
         meas_bitmap += (1 << 1) + (1 << 5);
         break;
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_i1_CQI:
         meas_bitmap += (1 << 1) + (1 << 4) + (1 << 5);
         break;
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_CQI:
         meas_bitmap += (1 << 1) + (1 << 4);
         break;
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RSRP:
         meas_bitmap += 1;
         break;
-      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI :
+      case NR_CSI_ReportConfig__reportQuantity_PR_cri_RI_LI_PMI_CQI:
         meas_bitmap += (1 << 1) + (1 << 2) + (1 << 3) + (1 << 4);
         break;
-      default :
-        AssertFatal(false, "Unexpected measurement report type %d\n",
-                    report_config->reportQuantity.present);
+      default:
+        AssertFatal(false, "Unexpected measurement report type %d\n", report_config->reportQuantity.present);
     }
   }
   AssertFatal(meas_bitmap > 0, "Expected to have at least 1 measurement configured for CSI-RS\n");
@@ -2322,9 +2342,7 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
     csi_period_offset(NULL, nzpcsi->periodicityAndOffset, &period, &offset);
     if((frame * nr_slots_per_frame[mu] + slot-offset) % period != 0)
       continue;
-    NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig,
-                                                                   dl_bwp_id,
-                                                                   nzpcsi->nzp_CSI_RS_ResourceId);
+    NR_CSI_ResourceConfigId_t csi_res_id = find_CSI_resourceconfig(csi_measconfig, dl_bwp_id, nzpcsi->nzp_CSI_RS_ResourceId);
     // do not schedule reseption of this CSI-RS if not associated with current BWP
     if(csi_res_id < 0)
       continue;
@@ -2366,23 +2384,23 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
     switch(resourceMapping.frequencyDomainAllocation.present){
       case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row1:
         csirs_config_pdu->row = 1;
-        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row1.buf[0])>>4)&0x0f;
+        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row1.buf[0]) >> 4) & 0x0f;
         break;
       case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row2:
         csirs_config_pdu->row = 2;
-        csirs_config_pdu->freq_domain = (((resourceMapping.frequencyDomainAllocation.choice.row2.buf[1]>>4)&0x0f) |
-                                        ((resourceMapping.frequencyDomainAllocation.choice.row2.buf[0]<<4)&0xff0));
+        csirs_config_pdu->freq_domain = (((resourceMapping.frequencyDomainAllocation.choice.row2.buf[1] >> 4) & 0x0f)
+                                         | ((resourceMapping.frequencyDomainAllocation.choice.row2.buf[0] << 4) & 0xff0));
         break;
       case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_row4:
         csirs_config_pdu->row = 4;
-        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row4.buf[0])>>5)&0x07;
+        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.row4.buf[0]) >> 5) & 0x07;
         break;
       case NR_CSI_RS_ResourceMapping__frequencyDomainAllocation_PR_other:
-        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.other.buf[0])>>2)&0x3f;
+        csirs_config_pdu->freq_domain = ((resourceMapping.frequencyDomainAllocation.choice.other.buf[0]) >> 2) & 0x3f;
         // determining the row of table 7.4.1.5.3-1 in 38.211
-        switch(resourceMapping.nrofPorts){
+        switch (resourceMapping.nrofPorts) {
           case NR_CSI_RS_ResourceMapping__nrofPorts_p1:
-            AssertFatal(1==0,"Resource with 1 CSI port shouldn't be within other rows\n");
+            AssertFatal(1 == 0, "Resource with 1 CSI port shouldn't be within other rows\n");
             break;
           case NR_CSI_RS_ResourceMapping__nrofPorts_p2:
             csirs_config_pdu->row = 3;
@@ -2393,11 +2411,11 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
           case NR_CSI_RS_ResourceMapping__nrofPorts_p8:
             if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
               csirs_config_pdu->row = 8;
-            else{
+            else {
               int num_k = 0;
-              for (int k=0; k<6; k++)
-                num_k+=(((csirs_config_pdu->freq_domain)>>k)&0x01);
-              if(num_k==4)
+              for (int k = 0; k < 6; k++)
+                num_k += (((csirs_config_pdu->freq_domain) >> k) & 0x01);
+              if (num_k == 4)
                 csirs_config_pdu->row = 6;
               else
                 csirs_config_pdu->row = 7;
@@ -2418,7 +2436,7 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
           case NR_CSI_RS_ResourceMapping__nrofPorts_p24:
             if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
               csirs_config_pdu->row = 14;
-            else{
+            else {
               if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
                 csirs_config_pdu->row = 15;
               else
@@ -2428,19 +2446,19 @@ void nr_schedule_csirs_reception(NR_UE_MAC_INST_t *mac, int frame, int slot)
           case NR_CSI_RS_ResourceMapping__nrofPorts_p32:
             if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm4_FD2_TD2)
               csirs_config_pdu->row = 17;
-            else{
+            else {
               if (resourceMapping.cdm_Type == NR_CSI_RS_ResourceMapping__cdm_Type_cdm8_FD2_TD4)
                 csirs_config_pdu->row = 18;
               else
                 csirs_config_pdu->row = 16;
             }
             break;
-        default:
-          AssertFatal(1==0,"Invalid number of ports in CSI-RS resource\n");
+          default:
+            AssertFatal(1 == 0, "Invalid number of ports in CSI-RS resource\n");
         }
         break;
       default:
-        AssertFatal(1==0,"Invalid freqency domain allocation in CSI-RS resource\n");
+        AssertFatal(1 == 0, "Invalid freqency domain allocation in CSI-RS resource\n");
     }
     dl_config->dl_config_list[dl_config->number_pdus].pdu_type = FAPI_NR_DL_CONFIG_TYPE_CSI_RS;
     dl_config->number_pdus += 1;
@@ -2459,16 +2477,8 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
   if(ra->ra_state != GENERATE_PREAMBLE)
     return;
 
-  fapi_nr_ul_config_request_t *ul_config = get_ul_config_request(mac, slotP, 0);
-  if (!ul_config) {
-    LOG_E(NR_MAC, "mac->ul_config is null! \n");
-    return;
-  }
-
-  fapi_nr_ul_config_prach_pdu *prach_config_pdu;
   fapi_nr_config_request_t *cfg = &mac->phy_config.config_req;
   fapi_nr_prach_config_t *prach_config = &cfg->prach_config;
-  nr_scheduled_response_t scheduled_response;
 
   NR_RACH_ConfigCommon_t *setup = mac->current_UL_BWP->rach_ConfigCommon;
   NR_RACH_ConfigGeneric_t *rach_ConfigGeneric = &setup->rach_ConfigGeneric;
@@ -2498,34 +2508,30 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
       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
-      AssertFatal(ul_config->number_pdus < sizeof(ul_config->ul_config_list) / sizeof(ul_config->ul_config_list[0]),
-                  "Number of PDUS in ul_config = %d > ul_config_list num elements", ul_config->number_pdus);
-
-      pthread_mutex_lock(&ul_config->mutex_ul_config);
-      AssertFatal(ul_config->number_pdus<FAPI_NR_UL_CONFIG_LIST_NUM, "ul_config->number_pdus %d out of bounds\n",ul_config->number_pdus);
-      prach_config_pdu = &ul_config->ul_config_list[ul_config->number_pdus].prach_config_pdu;
-      memset(prach_config_pdu, 0, sizeof(fapi_nr_ul_config_prach_pdu));
-      fill_ul_config(ul_config, frameP, slotP, FAPI_NR_UL_CONFIG_TYPE_PRACH);
-      pthread_mutex_unlock(&ul_config->mutex_ul_config);
-      LOG_D(PHY, "In %s: (%p) %d UL PDUs:\n", __FUNCTION__, ul_config, ul_config->number_pdus);
-
-      memset(prach_config_pdu, 0, sizeof(fapi_nr_ul_config_prach_pdu));
 
+      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);
-
-      prach_config_pdu->phys_cell_id = mac->physCellId;
-      prach_config_pdu->num_prach_ocas = 1;
-      prach_config_pdu->prach_slot = prach_occasion_info_p->slot;
-      prach_config_pdu->prach_start_symbol = prach_occasion_info_p->start_symbol;
-      prach_config_pdu->num_ra = prach_occasion_info_p->fdm;
-
-      prach_config_pdu->num_cs = ncs;
-      prach_config_pdu->root_seq_id = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].prach_root_sequence_index;
-      prach_config_pdu->restricted_set = prach_config->restricted_set_config;
-      prach_config_pdu->freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1;
-
-      LOG_I(NR_MAC,"PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n",
-            frameP, prach_config_pdu->prach_slot, prach_config_pdu->prach_start_symbol, prach_config_pdu->num_ra);
+      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,
+          .restricted_set = prach_config->restricted_set_config,
+          .freq_msg1 = prach_config->num_prach_fd_occasions_list[prach_occasion_info_p->fdm].k1};
+
+      LOG_I(NR_MAC,
+            "PRACH scheduler: Selected RO Frame %u, Slot %u, Symbol %u, Fdm %u\n",
+            frameP,
+            pdu->prach_config_pdu.prach_slot,
+            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++) {
@@ -2537,53 +2543,53 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
       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
+        switch (format0) { // dual PRACH format
           case 0xa1:
-            prach_config_pdu->prach_format = 11;
+            pdu->prach_config_pdu.prach_format = 11;
             break;
           case 0xa2:
-            prach_config_pdu->prach_format = 12;
+            pdu->prach_config_pdu.prach_format = 12;
             break;
           case 0xa3:
-            prach_config_pdu->prach_format = 13;
+            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");
+          default:
+            AssertFatal(1 == 0, "Only formats A1/B1 A2/B2 A3/B3 are valid for dual format");
         }
       } else {
-        switch(format0) { // single PRACH format
+        switch (format0) { // single PRACH format
           case 0:
-            prach_config_pdu->prach_format = 0;
+            pdu->prach_config_pdu.prach_format = 0;
             break;
           case 1:
-            prach_config_pdu->prach_format = 1;
+            pdu->prach_config_pdu.prach_format = 1;
             break;
           case 2:
-            prach_config_pdu->prach_format = 2;
+            pdu->prach_config_pdu.prach_format = 2;
             break;
           case 3:
-            prach_config_pdu->prach_format = 3;
+            pdu->prach_config_pdu.prach_format = 3;
             break;
           case 0xa1:
-            prach_config_pdu->prach_format = 4;
+            pdu->prach_config_pdu.prach_format = 4;
             break;
           case 0xa2:
-            prach_config_pdu->prach_format = 5;
+            pdu->prach_config_pdu.prach_format = 5;
             break;
           case 0xa3:
-            prach_config_pdu->prach_format = 6;
+            pdu->prach_config_pdu.prach_format = 6;
             break;
           case 0xb1:
-            prach_config_pdu->prach_format = 7;
+            pdu->prach_config_pdu.prach_format = 7;
             break;
           case 0xb4:
-            prach_config_pdu->prach_format = 8;
+            pdu->prach_config_pdu.prach_format = 8;
             break;
           case 0xc0:
-            prach_config_pdu->prach_format = 9;
+            pdu->prach_config_pdu.prach_format = 9;
             break;
           case 0xc2:
-            prach_config_pdu->prach_format = 10;
+            pdu->prach_config_pdu.prach_format = 10;
             break;
           default:
             AssertFatal(1 == 0, "Invalid PRACH format");
@@ -2591,11 +2597,14 @@ static void nr_ue_prach_scheduler(module_id_t module_idP, frame_t frameP, sub_fr
       } // if format1
 
       nr_get_prach_resources(module_idP, 0, 0, &ra->prach_resources, ra->rach_ConfigDedicated);
-      prach_config_pdu->ra_PreambleIndex = ra->ra_PreambleIndex;
-      prach_config_pdu->prach_tx_power = get_prach_tx_power(module_idP);
-      set_ra_rnti(mac, prach_config_pdu);
-
-      fill_scheduled_response(&scheduled_response, NULL, ul_config, NULL, module_idP, 0 /*TBR fix*/, frameP, slotP, NULL);
+      pdu->prach_config_pdu.ra_PreambleIndex = ra->ra_PreambleIndex;
+      pdu->prach_config_pdu.prach_tx_power = get_prach_tx_power(module_idP);
+      set_ra_rnti(mac, &pdu->prach_config_pdu);
+      release_ul_config(pdu, false);
+      nr_scheduled_response_t scheduled_response = {.ul_config = mac->ul_config_request + slotP,
+                                                    .mac = mac,
+                                                    .module_id = module_idP,
+                                                    .CC_id = 0 /*TBR fix*/};
       if(mac->if_module != NULL && mac->if_module->scheduled_response != NULL)
         mac->if_module->scheduled_response(&scheduled_response);
 
@@ -2621,24 +2630,25 @@ typedef struct {
 } NR_UE_MAC_CE_INFO;
 
 /*
-nr_ue_get_sdu_mac_ce_pre finds length in various mac_ce field
-Need nothing from mac_ce_p:
-Update the following in mac_ce_p:
-	bsr_len;
-	bsr_ce_len;
-	bsr_header_len;
-	phr_len; TBD
-	phr_ce_len; TBD
-	phr_header_len; TBD
+  nr_ue_get_sdu_mac_ce_pre finds length in various mac_ce field
+  Need nothing from mac_ce_p:
+  Update the following in mac_ce_p:
+  bsr_len;
+  bsr_ce_len;
+  bsr_header_len;
+  phr_len; TBD
+  phr_ce_len; TBD
+  phr_header_len; TBD
 */
 int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP,
-                      int CC_id,
-                      frame_t frameP,
-                      sub_frame_t subframe,
-                      uint8_t gNB_index,
-                      uint8_t *ulsch_buffer,
-                      uint16_t buflen,
-                      NR_UE_MAC_CE_INFO *mac_ce_p) {
+                             int CC_id,
+                             frame_t frameP,
+                             sub_frame_t subframe,
+                             uint8_t gNB_index,
+                             uint8_t *ulsch_buffer,
+                             uint16_t buflen,
+                             NR_UE_MAC_CE_INFO *mac_ce_p)
+{
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_idP);
 
   int num_lcg_id_with_data = 0;
@@ -2664,8 +2674,12 @@ int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP,
       && (mac->scheduling_info.periodicBSR_SF == 0)) {
     // Trigger BSR Periodic
     mac->BSR_reporting_active |= NR_BSR_TRIGGER_PERIODIC;
-    LOG_D(NR_MAC, "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n",
-          module_idP, frameP, subframe, buflen);
+    LOG_D(NR_MAC,
+          "[UE %d] MAC BSR Triggered PeriodicBSR Timer expiry at frame%d subframe %d TBS=%d\n",
+          module_idP,
+          frameP,
+          subframe,
+          buflen);
   }
 
   //Compute BSR Length if Regular or Periodic BSR is triggered
@@ -2678,13 +2692,13 @@ int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP,
     //A Regular or Periodic BSR can only be sent if TBS is sufficient as transmitting only a BSR is not allowed if UE has data to transmit
     if (num_lcg_id_with_data <= 1) {
       if (buflen >= (sizeof(NR_BSR_SHORT)+sizeof(NR_MAC_SUBHEADER_FIXED)+1)) {
-        mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); //1 byte
-        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); //1 byte
+        mac_ce_p->bsr_ce_len = sizeof(NR_BSR_SHORT); // 1 byte
+        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_FIXED); // 1 byte
       }
     } else {
       if (buflen >= (num_lcg_id_with_data+1+sizeof(NR_MAC_SUBHEADER_SHORT)+1)) {
-        mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; //variable size
-        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); //2 bytes
+        mac_ce_p->bsr_ce_len = num_lcg_id_with_data + 1; // variable size
+        mac_ce_p->bsr_header_len = sizeof(NR_MAC_SUBHEADER_SHORT); // 2 bytes
       }
     }
   }
@@ -2694,21 +2708,21 @@ int nr_ue_get_sdu_mac_ce_pre(module_id_t module_idP,
 }
 
 /*
-nr_ue_get_sdu_mac_ce_post recalculates length and prepares the mac_ce field
-Need the following from mac_ce_p:
-	bsr_ce_len
-	bsr_len
-	sdu_length_total
-	total_mac_pdu_header_len
-Update the following in mac_ce_p:
-	bsr_ce_len
-	bsr_header_len
-	bsr_len
-	tot_mac_ce_len
-	total_mac_pdu_header_len
-	bsr_s
-	bsr_l
-	bsr_t
+  nr_ue_get_sdu_mac_ce_post recalculates length and prepares the mac_ce field
+  Need the following from mac_ce_p:
+  bsr_ce_len
+  bsr_len
+  sdu_length_total
+  total_mac_pdu_header_len
+  Update the following in mac_ce_p:
+  bsr_ce_len
+  bsr_header_len
+  bsr_len
+  tot_mac_ce_len
+  total_mac_pdu_header_len
+  bsr_s
+  bsr_l
+  bsr_t
 */
 void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
                                int CC_id,
@@ -2748,11 +2762,13 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
   // Check BSR padding: it is done after PHR according to Logical Channel Prioritization order
   // Check for max padding size, ie MAC Hdr for last RLC PDU = 1
   /* For Padding BSR:
-     -  if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the size of the Long BSR plus its subheader:
-     -  if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of the LCG with the highest priority logical channel with data available for transmission;
+     -  if the number of padding bits is equal to or larger than the size of the Short BSR plus its subheader but smaller than the
+     size of the Long BSR plus its subheader:
+     -  if more than one LCG has data available for transmission in the TTI where the BSR is transmitted: report Truncated BSR of
+     the LCG with the highest priority logical channel with data available for transmission;
      -  else report Short BSR.
      -  else if the number of padding bits is equal to or larger than the size of the Long BSR plus its subheader, report Long BSR.
-   */
+  */
   if (mac_ce_p->sdu_length_total) {
     padding_len = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total);
   }
@@ -2770,7 +2786,7 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
 
       if (num_lcg_id_with_data > 1) {
         // REPORT SHORT TRUNCATED BSR
-        //Get LCGID of highest priority LCID with data (todo)
+        // Get LCGID of highest priority LCID with data (todo)
         for (int lcid = 1; lcid <= NR_MAX_NUM_LCID; lcid++) {
           lcg_id = mac->scheduling_info.lc_sched_info[lcid - 1].LCGID;
           if ((lcg_id < NR_MAX_NUM_LCGID) && (mac->scheduling_info.lcg_sched_info[lcg_id].BSR_bytes)) {
@@ -2778,7 +2794,7 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
           }
         }
       } else {
-        //Report SHORT BSR, clear bsr_t
+        // Report SHORT BSR, clear bsr_t
         mac_ce_p->bsr_t = NULL;
       }
 
@@ -2859,8 +2875,12 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
 
   /* Actions when a BSR is sent */
   if (mac_ce_p->bsr_ce_len) {
-    LOG_D(NR_MAC, "[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n",
-          module_idP, mac_ce_p->bsr_ce_len, mac_ce_p->bsr_header_len, buflen);
+    LOG_D(NR_MAC,
+          "[UE %d] MAC BSR Sent !! bsr (ce%d,hdr%d) buff_len %d\n",
+          module_idP,
+          mac_ce_p->bsr_ce_len,
+          mac_ce_p->bsr_header_len,
+          buflen);
     // Reset ReTx BSR Timer
     mac->scheduling_info.retxBSR_SF = nr_get_sf_retxBSRTimer(mac->scheduling_info.retxBSR_Timer);
     LOG_D(NR_MAC, "[UE %d] MAC ReTx BSR Timer Reset =%d\n", module_idP, mac->scheduling_info.retxBSR_SF);
@@ -2868,9 +2888,7 @@ void nr_ue_get_sdu_mac_ce_post(module_id_t module_idP,
     // Reset Periodic Timer except when BSR is truncated
     if ((mac_ce_p->bsr_t == NULL) && (mac->scheduling_info.periodicBSR_Timer != NR_BSR_Config__periodicBSR_Timer_infinity)) {
       mac->scheduling_info.periodicBSR_SF = nr_get_sf_periodicBSRTimer(mac->scheduling_info.periodicBSR_Timer);
-      LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset =%d\n",
-            module_idP,
-            mac->scheduling_info.periodicBSR_SF);
+      LOG_D(NR_MAC, "[UE %d] MAC Periodic BSR Timer Reset =%d\n", module_idP, mac->scheduling_info.periodicBSR_SF);
     }
 
     // Reset BSR Trigger flags
@@ -3097,7 +3115,7 @@ static bool fill_mac_sdu(module_id_t module_idP,
   if ((*counter == 0 && lcids_bytes_tot[lcid - 1] >= target)
       || (count_same_priority_lcids > 1
           && lcids_bytes_tot[lcid - 1] >= buflen_ep)) { // only prioritized bit rate should be taken from logical channel in
-                                                        // the first lcp run except when infinity
+    // the first lcp run except when infinity
     LOG_D(NR_MAC,
           "In %s: total number bytes read from rlc buffer for lcid %d are %d\n",
           __FUNCTION__,
@@ -3111,8 +3129,8 @@ static bool fill_mac_sdu(module_id_t module_idP,
 
 /**
  * Function:      to fetch data to be transmitted from RLC, place it in the ULSCH PDU buffer
-                  to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321)
-                  the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG
+ to generate the complete MAC PDU with sub-headers and MAC CEs according to ULSCH MAC PDU generation (6.1.2 TS 38.321)
+ the selected sub-header for the payload sub-PDUs is NR_MAC_SUBHEADER_LONG
  * @module_idP    Module ID
  * @CC_id         Component Carrier index
  * @frameP        current UL frame
@@ -3167,9 +3185,9 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
 
   uint32_t lcp_allocation_counter =
       0; // in the first run all the lc are allocated as per bj and prioritized bit rate but in subsequent runs, no need to consider
-         // bj and prioritized bit rate but just consider priority
+  // bj and prioritized bit rate but just consider priority
   uint16_t buflen_ep = 0; // this variable holds the length in bytes in mac pdu when multiple equal priority channels are present
-                          // because as per standard(TS38.321), all equal priority channels should be served equally
+  // because as per standard(TS38.321), all equal priority channels should be served equally
 
   // nr_ue_get_sdu_mac_ce_pre updates all mac_ce related header field related to length
   mac_ce_p->tot_mac_ce_len = nr_ue_get_sdu_mac_ce_pre(module_idP, CC_id, frameP, subframe, gNB_index, ulsch_buffer, buflen, mac_ce_p);
@@ -3183,7 +3201,7 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
   // multiplex in the order of highest priority
   do {
     /*
-     go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels
+      go until there is space availabile in the MAC PDU and there is data available in RLC buffers of active logical channels
     */
     uint8_t num_lcids_same_priority = 0;
     uint8_t count_same_priority_lcids = 0;
@@ -3193,10 +3211,10 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
 
     for (uint8_t id = 0; id < avail_lcids_count; id++) {
       /*
-       loop over all logical channels in the order of priority. As stated in TS138.321 Section 5.4.3.1, in the first run, only
-       prioritized number of bytes are taken out from the corresponding RLC buffers of all active logical channels and if there is
-       still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel
-       is placed in the MAC PDU before going on to next high priority logical channel
+  loop over all logical channels in the order of priority. As stated in TS138.321 Section 5.4.3.1, in the first run, only
+  prioritized number of bytes are taken out from the corresponding RLC buffers of all active logical channels and if there is
+  still space availble in the MAC PDU, then from the next run all the remaining data from the higher priority logical channel
+  is placed in the MAC PDU before going on to next high priority logical channel
       */
       int lcid = lcids_bj_pos[id];
 
@@ -3235,11 +3253,11 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
 
       while (buflen_remain > 0) {
         /*
-         loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes
-         depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all
-         active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates
-         the target number of bytes to request from RLC via 'mac_rlc_data_req'
-       */
+          loops until the requested number of bytes from MAC to RLC are placed in the MAC PDU. The number of requested bytes
+          depends on whether it is the first run or otherwise because in the first run only prioritited number of bytes of all
+          active logical channels in the order of priority are placed in the MAC PDU. The 'get_num_bytes_to_reqlc' calculates
+          the target number of bytes to request from RLC via 'mac_rlc_data_req'
+        */
         if (!fill_mac_sdu(module_idP,
                           frameP,
                           subframe,
@@ -3274,11 +3292,10 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
     nr_write_ce_ulsch_pdu(pdu, mac, 0, NULL, mac_ce_p->bsr_t, mac_ce_p->bsr_s, mac_ce_p->bsr_l);
     pdu += (unsigned char) mac_ce_p->tot_mac_ce_len;
 
-    #ifdef ENABLE_MAC_PAYLOAD_DEBUG
+#ifdef ENABLE_MAC_PAYLOAD_DEBUG
     LOG_I(NR_MAC, "In %s: dumping MAC CE with length tot_mac_ce_len %d: \n", __FUNCTION__, mac_ce_p->tot_mac_ce_len);
     log_dump(NR_MAC, mac_header_control_elements, mac_ce_p->tot_mac_ce_len, LOG_DUMP_CHAR, "\n");
-    #endif
-
+#endif
   }
 
   buflen_remain = buflen - (mac_ce_p->total_mac_pdu_header_len + mac_ce_p->sdu_length_total);
@@ -3290,33 +3307,32 @@ uint8_t nr_ue_get_sdu(module_id_t module_idP,
     ((NR_MAC_SUBHEADER_FIXED *) pdu)->R = 0;
     ((NR_MAC_SUBHEADER_FIXED *) pdu)->LCID = UL_SCH_LCID_PADDING;
 
-    #ifdef ENABLE_MAC_PAYLOAD_DEBUG
+#ifdef ENABLE_MAC_PAYLOAD_DEBUG
     LOG_I(NR_MAC, "In %s: padding MAC sub-header with length %ld bytes \n", __FUNCTION__, sizeof(NR_MAC_SUBHEADER_FIXED));
     log_dump(NR_MAC, pdu, sizeof(NR_MAC_SUBHEADER_FIXED), LOG_DUMP_CHAR, "\n");
-    #endif
+#endif
 
     pdu++;
     buflen_remain--;
 
     if (IS_SOFTMODEM_RFSIM) {
       for (int j = 0; j < buflen_remain; j++) {
-        pdu[j] = (unsigned char) rand();
+        pdu[j] = (unsigned char)rand();
       }
     } else {
       memset(pdu, 0, buflen_remain);
     }
 
-    #ifdef ENABLE_MAC_PAYLOAD_DEBUG
+#ifdef ENABLE_MAC_PAYLOAD_DEBUG
     LOG_I(NR_MAC, "In %s: MAC padding sub-PDU with length %d bytes \n", __FUNCTION__, buflen_remain);
     log_dump(NR_MAC, pdu, buflen_remain, LOG_DUMP_CHAR, "\n");
-    #endif
-
+#endif
   }
 
-  #ifdef ENABLE_MAC_PAYLOAD_DEBUG
+#ifdef ENABLE_MAC_PAYLOAD_DEBUG
   LOG_I(NR_MAC, "In %s: dumping MAC PDU with length %d: \n", __FUNCTION__, buflen);
   log_dump(NR_MAC, ulsch_buffer, buflen, LOG_DUMP_CHAR, "\n");
-  #endif
+#endif
 
   return num_sdus > 0 ? 1 : 0;
 }
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
index 66fda58122e2b8d9bc00110ded1c8770ec950b93..54a5bd4b6a50f7751656f2e82e9c468040f21481 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_dlsch.c
@@ -668,7 +668,8 @@ static void pf_dl(module_id_t module_id,
       else
         sched_pdsch->mcs = get_mcs_from_bler(bo, stats, &sched_ctrl->dl_bler_stats, max_mcs, frame);
       sched_pdsch->nrOfLayers = get_dl_nrOfLayers(sched_ctrl, current_BWP->dci_format);
-      sched_pdsch->pm_index = mac->identity_pm ? 0 : get_pm_index(mac, UE, sched_pdsch->nrOfLayers, mac->radio_config.pdsch_AntennaPorts.XP);
+      sched_pdsch->pm_index =
+          get_pm_index(mac, UE, current_BWP->dci_format, sched_pdsch->nrOfLayers, mac->radio_config.pdsch_AntennaPorts.XP);
       const uint8_t Qm = nr_get_Qm_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
       const uint16_t R = nr_get_code_rate_dl(sched_pdsch->mcs, current_BWP->mcsTableIdx);
       uint32_t tbs = nr_compute_tbs(Qm,
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
index 73cd0de6d25487152af5d3b473f6484faba384fa..04162b8f37810c917d6799dab3f9384de1f85bad 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_primitives.c
@@ -131,19 +131,19 @@ uint8_t get_dl_nrOfLayers(const NR_UE_sched_ctrl_t *sched_ctrl,
 
 uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
                       const NR_UE_info_t *UE,
+                      nr_dci_format_t dci_format,
                       int layers,
                       int xp_pdsch_antenna_ports)
 {
+  if (dci_format == NR_DL_DCI_FORMAT_1_0 || nrmac->identity_pm || xp_pdsch_antenna_ports == 1)
+    return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
+
   const NR_UE_sched_ctrl_t *sched_ctrl = &UE->UE_sched_ctrl;
   const int report_id = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.csi_report_id;
   const nr_csi_report_t *csi_report = &UE->csi_report_template[report_id];
   const int N1 = csi_report->N1;
   const int N2 = csi_report->N2;
   const int antenna_ports = (N1 * N2) << 1;
-
-  if (xp_pdsch_antenna_ports == 1)
-    return 0; //identity matrix (basic 5G configuration handled by PMI report is with XP antennas)
-
   const int x1 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x1;
   const int x2 = sched_ctrl->CSI_report.cri_ri_li_pmi_cqi_report.pmi_x2;
   LOG_D(NR_MAC,"PMI report: x1 %d x2 %d layers: %d\n", x1, x2, layers);
diff --git a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
index 220ce9aef2de84129594660e409ddabf828fbaa2..829dc2835f3bf07ea7a4640aedeacad41da98138 100644
--- a/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
+++ b/openair2/LAYER2/NR_MAC_gNB/gNB_scheduler_uci.c
@@ -1268,6 +1268,9 @@ int nr_acknack_scheduling(gNB_MAC_INST *mac,
                                            curr_pucch->csi_bits + curr_pucch->dai_c + 2,
                                            curr_pucch->resource_indicator))
         continue;
+      // TODO temporarily limit ack/nak to 3 bits because of performances of polar for PUCCH (required for > 11 bits)
+      if (curr_pucch->csi_bits > 0 && curr_pucch->dai_c >= 3)
+        continue;
 
       // otherwise we can schedule in this active PUCCH
       // no need to check VRB occupation because already done when PUCCH has been activated
diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
index 1bdb08bb60ba1c07e112f59b521049b0759da73f..61ce2c49f91439b0391de5bced37f7eaceec18ef 100644
--- a/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
+++ b/openair2/LAYER2/NR_MAC_gNB/mac_proto.h
@@ -379,6 +379,7 @@ NR_pdsch_dmrs_t get_dl_dmrs_params(const NR_ServingCellConfigCommon_t *scc,
 
 uint16_t get_pm_index(const gNB_MAC_INST *nrmac,
                       const NR_UE_info_t *UE,
+                      nr_dci_format_t dci_format,
                       int layers,
                       int xp_pdsch_antenna_ports);
 
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
index 036ca5428558821f628b4339f6b74ba19ded8694..a6ff4bb993d35171c0907e595504359dcae6d8dc 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.c
@@ -66,6 +66,7 @@ queue_t nr_tx_req_queue;
 queue_t nr_ul_dci_req_queue;
 queue_t nr_ul_tti_req_queue;
 pthread_mutex_t mac_IF_mutex;
+static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request);
 
 void nrue_init_standalone_socket(int tx_port, int rx_port)
 {
@@ -746,11 +747,8 @@ void check_and_process_dci(nfapi_nr_dl_tti_request_t *dl_tti_request,
                       mac->frame_type)
         && mac->ra.ra_state != RA_SUCCEEDED) {
       // If we filled dl_info AFTER we got the slot indication, we want to check if we should fill tx_req:
-      nr_uplink_indication_t ul_info = {
-            .frame_rx = frame,
-            .slot_rx = slot,
-            .slot_tx = (slot + slot_ahead) % slots_per_frame,
-            .frame_tx = (ul_info.slot_rx + slot_ahead >= slots_per_frame) ? ul_info.frame_rx + 1 : ul_info.frame_rx};
+      nr_uplink_indication_t ul_info = {.slot = (slot + slot_ahead) % slots_per_frame,
+                                        .frame = slot + slot_ahead >= slots_per_frame ? (frame + 1) % 1024 : frame};
       nr_ue_ul_scheduler(&ul_info);
     }
 }
@@ -906,7 +904,7 @@ static void enqueue_nr_nfapi_msg(void *buffer, ssize_t len, nfapi_p7_message_hea
     return;
 }
 
-void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request)
+static void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request)
 {
   int count_sent = 0;
   NR_UE_MAC_INST_t *mac = get_mac_inst(0);
@@ -1032,11 +1030,16 @@ void *nrue_standalone_pnf_task(void *context)
 }
 
 //  L2 Abstraction Layer
-int handle_bcch_bch(module_id_t module_id, int cc_id,
-                    unsigned int gNB_index, void *phy_data, uint8_t *pduP,
-                    unsigned int additional_bits,
-                    uint32_t ssb_index, uint32_t ssb_length,
-                    uint16_t ssb_start_subcarrier, uint16_t cell_id)
+static int handle_bcch_bch(module_id_t module_id,
+                           int cc_id,
+                           unsigned int gNB_index,
+                           void *phy_data,
+                           uint8_t *pduP,
+                           unsigned int additional_bits,
+                           uint32_t ssb_index,
+                           uint32_t ssb_length,
+                           uint16_t ssb_start_subcarrier,
+                           uint16_t cell_id)
 {
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
   mac->mib_ssb = ssb_index;
@@ -1051,19 +1054,28 @@ int handle_bcch_bch(module_id_t module_id, int cc_id,
 }
 
 //  L2 Abstraction Layer
-int handle_bcch_dlsch(module_id_t module_id, int cc_id, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, uint32_t pdu_len)
+static int handle_bcch_dlsch(module_id_t module_id,
+                             int cc_id,
+                             unsigned int gNB_index,
+                             uint8_t ack_nack,
+                             uint8_t *pduP,
+                             uint32_t pdu_len)
 {
   return nr_ue_decode_BCCH_DL_SCH(module_id, cc_id, gNB_index, ack_nack, pduP, pdu_len);
 }
 
 //  L2 Abstraction Layer
-int handle_dci(module_id_t module_id, int cc_id, unsigned int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci){
-
+static int handle_dci(module_id_t module_id,
+                      int cc_id,
+                      unsigned int gNB_index,
+                      frame_t frame,
+                      int slot,
+                      fapi_nr_dci_indication_pdu_t *dci)
+{
   return nr_ue_process_dci_indication_pdu(module_id, cc_id, gNB_index, frame, slot, dci);
-
 }
 
-void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm)
+static void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm)
 {
   mac->ssb_measurements.ssb_index = ssb_index;
   mac->ssb_measurements.ssb_rsrp_dBm = rsrp_dbm;
@@ -1071,7 +1083,7 @@ void handle_ssb_meas(NR_UE_MAC_INST_t *mac, uint8_t ssb_index, int16_t rsrp_dbm)
 
 // L2 Abstraction Layer
 // Note: sdu should always be processed because data and timing advance updates are transmitted by the UE
-static int8_t handle_dlsch(nr_downlink_indication_t *dl_info, int pdu_id)
+static int8_t handle_dlsch(NR_UE_MAC_INST_t *mac, nr_downlink_indication_t *dl_info, int pdu_id)
 {
   /* L1 assigns harq_pid, but in emulated L1 mode we need to assign
      the harq_pid based on the saved global g_harq_pid. Because we are
@@ -1080,7 +1092,7 @@ static int8_t handle_dlsch(nr_downlink_indication_t *dl_info, int pdu_id)
   if (get_softmodem_params()->emulate_l1)
     dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid = g_harq_pid;
 
-  update_harq_status(dl_info->module_id,
+  update_harq_status(mac,
                      dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.harq_pid,
                      dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack);
   if(dl_info->rx_ind->rx_indication_body[pdu_id].pdsch_pdu.ack_nack)
@@ -1089,7 +1101,7 @@ static int8_t handle_dlsch(nr_downlink_indication_t *dl_info, int pdu_id)
   return 0;
 }
 
-void handle_rlm(rlm_t rlm_result, int frame, module_id_t module_id)
+static void handle_rlm(rlm_t rlm_result, int frame, module_id_t module_id)
 {
   if (rlm_result == RLM_no_monitoring)
     return;
@@ -1097,15 +1109,17 @@ void handle_rlm(rlm_t rlm_result, int frame, module_id_t module_id)
   nr_mac_rrc_sync_ind(module_id, frame, is_sync);
 }
 
-int8_t handle_csirs_measurements(module_id_t module_id, frame_t frame, int slot, fapi_nr_csirs_measurements_t *csirs_measurements)
+static int8_t handle_csirs_measurements(module_id_t module_id,
+                                        frame_t frame,
+                                        int slot,
+                                        fapi_nr_csirs_measurements_t *csirs_measurements)
 {
   handle_rlm(csirs_measurements->radiolink_monitoring, frame, module_id);
   return nr_ue_process_csirs_measurements(module_id, frame, slot, csirs_measurements);
 }
 
-void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nack)
+void update_harq_status(NR_UE_MAC_INST_t *mac, uint8_t harq_pid, uint8_t ack_nack)
 {
-  NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
   NR_UE_HARQ_STATUS_t *current_harq = &mac->dl_harq_info[harq_pid];
 
   if (current_harq->active) {
@@ -1126,8 +1140,9 @@ void update_harq_status(module_id_t module_id, uint8_t harq_pid, uint8_t ack_nac
 
 int nr_ue_ul_indication(nr_uplink_indication_t *ul_info)
 {
-
-  pthread_mutex_lock(&mac_IF_mutex);
+  int ret = pthread_mutex_lock(&mac_IF_mutex);
+  AssertFatal(!ret, "mutex failed %d\n", ret);
+  LOG_D(PHY, "Locked in ul, slot %d\n", ul_info->slot);
 
   module_id_t module_id = ul_info->module_id;
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
@@ -1135,58 +1150,55 @@ int nr_ue_ul_indication(nr_uplink_indication_t *ul_info)
   LOG_T(NR_MAC, "In %s():%d not calling scheduler mac->ra.ra_state = %d\n",
         __FUNCTION__, __LINE__, mac->ra.ra_state);
 
-  if (mac->phy_config_request_sent && is_nr_UL_slot(mac->tdd_UL_DL_ConfigurationCommon, ul_info->slot_tx, mac->frame_type))
+  if (mac->phy_config_request_sent && is_nr_UL_slot(mac->tdd_UL_DL_ConfigurationCommon, ul_info->slot, mac->frame_type))
     nr_ue_ul_scheduler(ul_info);
-
   pthread_mutex_unlock(&mac_IF_mutex);
 
   return 0;
 }
 
-int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
+static uint32_t nr_ue_dl_processing(nr_downlink_indication_t *dl_info)
 {
-  pthread_mutex_lock(&mac_IF_mutex);
   uint32_t ret_mask = 0x0;
   module_id_t module_id = dl_info->module_id;
   NR_UE_MAC_INST_t *mac = get_mac_inst(module_id);
-  if ((!dl_info->dci_ind && !dl_info->rx_ind)) {
-    // UL indication to schedule DCI reception
-    nr_ue_dl_scheduler(dl_info);
-  } else {
-    // UL indication after reception of DCI or DL PDU
-    if (dl_info && dl_info->dci_ind && dl_info->dci_ind->number_of_dcis) {
-      LOG_T(MAC,"[L2][IF MODULE][DL INDICATION][DCI_IND]\n");
-      for (int i = 0; i < dl_info->dci_ind->number_of_dcis; i++) {
-        LOG_T(MAC,">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d\n",i,dl_info->dci_ind->number_of_dcis);
-        nr_scheduled_response_t scheduled_response;
-        int8_t ret = handle_dci(dl_info->module_id,
-                                dl_info->cc_id,
-                                dl_info->gNB_index,
-                                dl_info->frame,
-                                dl_info->slot,
-                                dl_info->dci_ind->dci_list+i);
-        if (ret < 0)
-          continue;
-        fapi_nr_dci_indication_pdu_t *dci_index = dl_info->dci_ind->dci_list+i;
-
-        /* The check below filters out UL_DCIs which are being processed as DL_DCIs. */
-        if (dci_index->dci_format != NR_DL_DCI_FORMAT_1_0 && dci_index->dci_format != NR_DL_DCI_FORMAT_1_1) {
-          LOG_D(NR_MAC, "We are filtering a UL_DCI to prevent it from being treated like a DL_DCI\n");
-          continue;
-        }
-        dci_pdu_rel15_t *def_dci_pdu_rel15 = &mac->def_dci_pdu_rel15[dl_info->slot][dci_index->dci_format];
-        g_harq_pid = def_dci_pdu_rel15->harq_pid;
-        LOG_T(NR_MAC, "Setting harq_pid = %d and dci_index = %d (based on format)\n", g_harq_pid, dci_index->dci_format);
-
-        ret_mask |= (ret << FAPI_NR_DCI_IND);
-        AssertFatal( nr_ue_if_module_inst[module_id] != NULL, "IF module is NULL!\n" );
-        AssertFatal( nr_ue_if_module_inst[module_id]->scheduled_response != NULL, "scheduled_response is NULL!\n" );
-        fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, dl_info->slot);
-        fill_scheduled_response(&scheduled_response, dl_config, NULL, NULL, dl_info->module_id, dl_info->cc_id, dl_info->frame, dl_info->slot, dl_info->phy_data);
-        nr_ue_if_module_inst[module_id]->scheduled_response(&scheduled_response);
-        memset(def_dci_pdu_rel15, 0, sizeof(*def_dci_pdu_rel15));
+
+  // DL indication after reception of DCI or DL PDU
+  if (dl_info && dl_info->dci_ind && dl_info->dci_ind->number_of_dcis) {
+    LOG_T(MAC, "[L2][IF MODULE][DL INDICATION][DCI_IND]\n");
+    for (int i = 0; i < dl_info->dci_ind->number_of_dcis; i++) {
+      LOG_T(MAC, ">>>NR_IF_Module i=%d, dl_info->dci_ind->number_of_dcis=%d\n", i, dl_info->dci_ind->number_of_dcis);
+      int8_t ret = handle_dci(dl_info->module_id,
+                              dl_info->cc_id,
+                              dl_info->gNB_index,
+                              dl_info->frame,
+                              dl_info->slot,
+                              dl_info->dci_ind->dci_list + i);
+      if (ret < 0)
+        continue;
+      fapi_nr_dci_indication_pdu_t *dci_index = dl_info->dci_ind->dci_list + i;
+
+      /* The check below filters out UL_DCIs which are being processed as DL_DCIs. */
+      if (dci_index->dci_format != NR_DL_DCI_FORMAT_1_0 && dci_index->dci_format != NR_DL_DCI_FORMAT_1_1) {
+        LOG_D(NR_MAC, "We are filtering a UL_DCI to prevent it from being treated like a DL_DCI\n");
+        continue;
       }
-      dl_info->dci_ind = NULL;
+      dci_pdu_rel15_t *def_dci_pdu_rel15 = &mac->def_dci_pdu_rel15[dl_info->slot][dci_index->dci_format];
+      g_harq_pid = def_dci_pdu_rel15->harq_pid;
+      LOG_T(NR_MAC, "Setting harq_pid = %d and dci_index = %d (based on format)\n", g_harq_pid, dci_index->dci_format);
+
+      ret_mask |= (ret << FAPI_NR_DCI_IND);
+      AssertFatal(nr_ue_if_module_inst[module_id] != NULL, "IF module is NULL!\n");
+      fapi_nr_dl_config_request_t *dl_config = get_dl_config_request(mac, dl_info->slot);
+      nr_scheduled_response_t scheduled_response = {.dl_config = dl_config,
+                                                    .mac = mac,
+                                                    .module_id = dl_info->module_id,
+                                                    .CC_id = dl_info->cc_id,
+                                                    .phy_data = dl_info->phy_data};
+      nr_ue_if_module_inst[module_id]->scheduled_response(&scheduled_response);
+      memset(def_dci_pdu_rel15, 0, sizeof(*def_dci_pdu_rel15));
+    }
+    dl_info->dci_ind = NULL;
     }
 
     if (dl_info->rx_ind != NULL) {
@@ -1194,7 +1206,9 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
       for (int i = 0; i < dl_info->rx_ind->number_pdus; ++i) {
 
         fapi_nr_rx_indication_body_t rx_indication_body = dl_info->rx_ind->rx_indication_body[i];
-        LOG_D(NR_MAC, "Sending DL indication to MAC. 1 PDU type %d of %d total number of PDUs \n",
+        LOG_D(NR_MAC,
+              "slot %d Sending DL indication to MAC. 1 PDU type %d of %d total number of PDUs \n",
+              dl_info->slot,
               rx_indication_body.pdu_type,
               dl_info->rx_ind->number_pdus);
 
@@ -1224,10 +1238,10 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
                                            rx_indication_body.pdsch_pdu.pdu_length)) << FAPI_NR_RX_PDU_TYPE_SIB;
             break;
           case FAPI_NR_RX_PDU_TYPE_DLSCH:
-            ret_mask |= (handle_dlsch(dl_info, i)) << FAPI_NR_RX_PDU_TYPE_DLSCH;
+            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(dl_info, i)) << 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)
               LOG_W(PHY, "Received a RAR-Msg2 but LDPC decode failed\n");
             else
@@ -1245,9 +1259,22 @@ int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
       }
       dl_info->rx_ind = NULL;
     }
-  }
+    return ret_mask;
+}
+
+int nr_ue_dl_indication(nr_downlink_indication_t *dl_info)
+{
+  int ret = pthread_mutex_lock(&mac_IF_mutex);
+  AssertFatal(!ret, "mutex failed %d\n", ret);
+  uint32_t ret2 = 0;
+  if (!dl_info->dci_ind && !dl_info->rx_ind)
+    // DL indication to process DCI reception
+    nr_ue_dl_scheduler(dl_info);
+  else
+    // DL indication to process data channels
+    ret2 = nr_ue_dl_processing(dl_info);
   pthread_mutex_unlock(&mac_IF_mutex);
-  return ret_mask;
+  return ret2;
 }
 
 nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id)
@@ -1273,28 +1300,6 @@ nr_ue_if_module_t *nr_ue_if_module_init(uint32_t module_id)
   return nr_ue_if_module_inst[module_id];
 }
 
-int nr_ue_if_module_kill(uint32_t module_id) {
-
-  if (nr_ue_if_module_inst[module_id] != NULL){
-    free(nr_ue_if_module_inst[module_id]);
-  }
-  return 0;
-}
-
-int nr_ue_dcireq(nr_dcireq_t *dcireq) {
-
-  fapi_nr_dl_config_request_t *dl_config = &dcireq->dl_config_req;
-  NR_UE_MAC_INST_t *UE_mac = get_mac_inst(0);
-  dl_config->sfn = dcireq->frame;
-  dl_config->slot = dcireq->slot;
-
-  LOG_T(PHY, "Entering UE DCI configuration frame %d slot %d \n", dcireq->frame, dcireq->slot);
-
-  ue_dci_configuration(UE_mac, dl_config, dcireq->frame, dcireq->slot);
-
-  return 0;
-}
-
 void RCconfig_nr_ue_macrlc(void) {
   int j;
   paramdef_t MACRLC_Params[] = MACRLCPARAMS_DESC;
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
index 5be2d3c03cdb585cb1ec6c6bf9337425be311975..c8648d4855d90c82e6276f7e87c6252b796f88ff 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_IF_Module.h
@@ -58,22 +58,6 @@ typedef struct {
   /// slot
   int slot;
 
-  fapi_nr_dl_config_request_t dl_config_req;
-  fapi_nr_ul_config_request_t ul_config_req;
-} nr_dcireq_t;
-
-typedef struct {
-    /// module id
-    module_id_t module_id;
-    /// gNB index
-    uint32_t gNB_index;
-    /// component carrier id
-    int cc_id;
-    /// frame 
-    frame_t frame;
-    /// slot
-    int slot;
-
     /// NR UE FAPI-like P7 message, direction: L1 to L2
     /// data reception indication structure
     fapi_nr_rx_indication_t *rx_ind;
@@ -95,14 +79,10 @@ typedef struct {
     uint32_t gNB_index;
     /// component carrier id
     int cc_id;
-    /// frame 
-    frame_t frame_rx;
-    /// slot rx
-    uint32_t slot_rx;
     /// frame tx
-    frame_t frame_tx;
+    frame_t frame;
     /// slot tx
-    uint32_t slot_tx;
+    uint32_t slot;
 
     /// dci reception indication structure
     fapi_nr_dci_indication_t *dci_ind;
@@ -142,17 +122,13 @@ typedef struct {
 
 // Downlink subframe P7
 
-
+struct PHY_VARS_NR_UE_s;
+struct NR_UE_MAC_INST_s;
 typedef struct {
     /// module id
     module_id_t module_id; 
     /// component carrier id
     int CC_id;
-    /// frame
-    frame_t frame;
-    /// slot
-    int slot;
-
     /// NR UE FAPI-like P7 message, direction: L2 to L1
     /// downlink transmission configuration request structure
     fapi_nr_dl_config_request_t *dl_config;
@@ -166,12 +142,10 @@ typedef struct {
     // Sidelink TX configuration request
     sl_nr_tx_config_request_t *sl_tx_config;
 
-    /// data transmission request structure
-    fapi_nr_tx_request_t *tx_request;
-
     /// PHY data structure initially passed on to L2 via the nr_downlink_indication_t and
     /// returned to L1 via nr_scheduled_response_t
     void *phy_data;
+    struct NR_UE_MAC_INST_s *mac;
 } nr_scheduled_response_t;
 
 typedef struct {
@@ -322,46 +296,11 @@ void check_and_process_dci(nfapi_nr_dl_tti_request_t *dl_tti_request,
 
 bool sfn_slot_matcher(void *wanted, void *candidate);
 
-/**\brief done free of memory allocation by module_id and release to pointer pool.
-   \param module_id module id*/
-int nr_ue_if_module_kill(uint32_t module_id);
-
-
 /**\brief interface between L1/L2, indicating the downlink related information, like dci_ind and rx_req
    \param dl_info including dci_ind and rx_request messages*/
 int nr_ue_dl_indication(nr_downlink_indication_t *dl_info);
 
 int nr_ue_ul_indication(nr_uplink_indication_t *ul_info);
 
-int nr_ue_dcireq(nr_dcireq_t *dcireq);
-
-//  TODO check
-/**\brief handle BCCH-BCH message from dl_indication
-   \param phy_data        PHY structure to be filled in by the callee in the FAPI call (L1 caller -> indication to L2 -> FAPI call to L1 callee)
-   \param pduP            pointer to bch pdu
-   \param additional_bits corresponding to 38.212 ch.7
-   \param ssb_index       SSB index within 0 - (L_ssb-1) corresponding to 38.331 ch.13 parameter i
-   \param ssb_length      corresponding to L1 parameter L_ssb 
-   \param cell_id         cell id */
-int handle_bcch_bch(module_id_t module_id,
-                    int cc_id,
-                    unsigned int gNB_index,
-                    void *phy_data,
-                    uint8_t *pduP,
-                    unsigned int additional_bits,
-                    uint32_t ssb_index,
-                    uint32_t ssb_length,
-                    uint16_t ssb_start_subcarrier,
-                    uint16_t cell_id);
-
-//  TODO check
-/**\brief handle BCCH-DL-SCH message from dl_indication
-   \param pdu_len   length(bytes) of pdu
-   \param pduP      pointer to pdu*/
-int handle_bcch_dlsch(module_id_t module_id, int cc_id, unsigned int gNB_index, uint8_t ack_nack, uint8_t *pduP, uint32_t pdu_len);
-
-int handle_dci(module_id_t module_id, int cc_id, unsigned int gNB_index, frame_t frame, int slot, fapi_nr_dci_indication_pdu_t *dci);
-
-
 #endif
 
diff --git a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h
index c395ff95e78e966953877fca0fe80a0dafdf71cd..6658eec5950929e07a3b4c69ef571ab4164a844b 100644
--- a/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h
+++ b/openair2/NR_UE_PHY_INTERFACE/NR_Packet_Drop.h
@@ -72,8 +72,7 @@ typedef struct {
 extern nr_bler_struct nr_bler_data[NR_NUM_MCS];
 extern nr_bler_struct nr_mimo_bler_data[NR_NUM_MCS];
 
-void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t * pdu, int sf, int index);
-void save_pdsch_pdu_for_crnti(nfapi_nr_dl_tti_request_t *dl_tti_request);
+void read_channel_param(const nfapi_nr_dl_tti_pdsch_pdu_rel15_t *pdu, int sf, int index);
 float get_bler_val(uint8_t mcs, int sinr);
 bool should_drop_transport_block(int slot, uint16_t rnti);
 bool is_channel_modeling(void);
diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h
index a1342a33f9df682e54201de82241d8087a063a41..45cb2d34394439b4c17000ca75af5144617b2302 100644
--- a/openair2/RRC/NR/nr_rrc_proto.h
+++ b/openair2/RRC/NR/nr_rrc_proto.h
@@ -129,6 +129,9 @@ sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_
 sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd);
 int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req);
 
+/* Process indication of E1 connection loss on CU-CP */
+void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_t *lc, sctp_assoc_t assoc_id);
+
 void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req,
                                  instance_t instance);
 
diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c
index 48f59fcb5151a19ab56ff764636a3c5dc76f0b21..7c3c200f151500a6020bb7c01c066f4a7c718d53 100644
--- a/openair2/RRC/NR/rrc_gNB.c
+++ b/openair2/RRC/NR/rrc_gNB.c
@@ -2065,6 +2065,9 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi,
   return NULL;
 }
 
+/**
+ * @brief E1AP Bearer Context Setup Response processing on CU-CP
+*/
 void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp, instance_t instance)
 {
   gNB_RRC_INST *rrc = RC.nrrrc[0];
@@ -2172,6 +2175,9 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
   rrc->mac_rrc.ue_context_modification_request(ue_data.du_assoc_id, &ue_context_modif_req);
 }
 
+/**
+ * @brief E1AP Bearer Context Modification Response processing on CU-CP
+*/
 void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t *resp)
 {
   gNB_RRC_INST *rrc = RC.nrrrc[0];
@@ -2188,6 +2194,9 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t
   }
 }
 
+/**
+ * @brief E1AP Bearer Context Release processing
+*/
 void rrc_gNB_process_e1_bearer_context_release_cplt(const e1ap_bearer_release_cplt_t *cplt)
 {
   // there is not really anything to do here as of now
@@ -2467,6 +2476,10 @@ void *rrc_gnb_task(void *args_p) {
         rrc_gNB_process_e1_bearer_context_release_cplt(&E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg_p));
         break;
 
+      case E1AP_LOST_CONNECTION: /* CUCP */
+        rrc_gNB_process_e1_lost_connection(RC.nrrrc[0], &E1AP_LOST_CONNECTION(msg_p), msg_p->ittiMsgHeader.originInstance);
+        break;
+
       case NGAP_PAGING_IND:
         rrc_gNB_process_PAGING_IND(msg_p, instance);
         break;
diff --git a/openair2/RRC/NR/rrc_gNB_cuup.c b/openair2/RRC/NR/rrc_gNB_cuup.c
index 6c5ea8aef52de0ce4dafcc38de42d7245c7ff15d..6751739cacc79e828172c1379f2be824a718c488 100644
--- a/openair2/RRC/NR/rrc_gNB_cuup.c
+++ b/openair2/RRC/NR/rrc_gNB_cuup.c
@@ -122,6 +122,26 @@ sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue
   return ue_data.e1_assoc_id;
 }
 
+/* CU-CP Functions */
+
+/**
+ * @brief Trigger E1AP Setup Failure on CU-CP
+*/
+static void e1ap_setup_failure(sctp_assoc_t assoc_id, uint64_t transac_id)
+{
+  MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_FAIL);
+  msg_p->ittiMsgHeader.originInstance = assoc_id;
+  e1ap_setup_fail_t *setup_fail = &E1AP_SETUP_FAIL(msg_p);
+  setup_fail->transac_id = transac_id;
+  LOG_I(NR_RRC, "Triggering E1AP Setup Failure for transac_id %ld, assoc_id %ld\n",
+        transac_id,
+        msg_p->ittiMsgHeader.originInstance);
+  itti_send_msg_to_task(TASK_CUCP_E1, 0 /*unused by callee*/, msg_p);
+}
+
+/**
+ * @brief E1AP Setup Request processing on CU-CP
+*/
 int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req)
 {
   AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n");
@@ -138,6 +158,7 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req)
             c->setup_req->gNB_cu_up_id,
             c->setup_req->gNB_cu_up_name,
             c->assoc_id);
+      e1ap_setup_failure(assoc_id, req->transac_id);
       return -1;
     }
   }
@@ -151,11 +172,12 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req)
             id->mnc,
             rrc->configuration.mcc[i],
             rrc->configuration.mnc[i]);
+      e1ap_setup_failure(assoc_id, req->transac_id);
       return -1;
     }
   }
 
-  LOG_I(RRC, "Accepting new CU-UP ID %ld name %s (assoc_id %d)\n", req->gNB_cu_up_id, req->gNB_cu_up_name, assoc_id);
+  LOG_I(NR_RRC, "Accepting new CU-UP ID %ld name %s (assoc_id %d)\n", req->gNB_cu_up_id, req->gNB_cu_up_name, assoc_id);
   nr_rrc_cuup_container_t *cuup = malloc(sizeof(*cuup));
   AssertFatal(cuup, "out of memory\n");
   cuup->setup_req = malloc(sizeof(*cuup->setup_req));
@@ -172,3 +194,28 @@ int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req)
 
   return 0;
 }
+
+/**
+ * @brief RRC Processing of the indication of E1 connection loss on CU-CP
+*/
+void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
+{
+  LOG_I(NR_RRC, "Received E1 connection loss indication on RRC\n");
+  AssertFatal(assoc_id != 0, "illegal assoc_id == 0: should be -1 (monolithic) or >0 (split)\n");
+  nr_rrc_cuup_container_t e = {.assoc_id = assoc_id};
+  nr_rrc_cuup_container_t *cuup = RB_FIND(rrc_cuup_tree, &rrc->cuups, &e);
+  if (cuup == NULL) {
+    LOG_W(NR_RRC, "CU-UP for assoc_id %d not found!\n", assoc_id);
+    return;
+  }
+  if (cuup->setup_req != NULL) {
+    e1ap_setup_req_t *req = cuup->setup_req;
+    LOG_I(NR_RRC, "releasing CU-UP %s on assoc_id %d\n", req->gNB_cu_up_name, assoc_id);
+    free(cuup->setup_req);
+  }
+  nr_rrc_cuup_container_t *removed = RB_REMOVE(rrc_cuup_tree, &rrc->cuups, cuup);
+  // Free relevant CU-UP structures
+  free(cuup);
+  DevAssert(removed != NULL);
+  rrc->num_cuups--;
+}
diff --git a/openair2/RRC/NR_UE/rrc_UE.c b/openair2/RRC/NR_UE/rrc_UE.c
index badf181f39f8c316004b8b374ffbe472f74d42e8..a38c0fded07ccaa7fb8074b1a01d4765a4ea0169 100644
--- a/openair2/RRC/NR_UE/rrc_UE.c
+++ b/openair2/RRC/NR_UE/rrc_UE.c
@@ -33,7 +33,6 @@
 #define RRC_UE
 #define RRC_UE_C
 
-#include "oai_asn1.h"
 #include "NR_DL-DCCH-Message.h"        //asn_DEF_NR_DL_DCCH_Message
 #include "NR_DL-CCCH-Message.h"        //asn_DEF_NR_DL_CCCH_Message
 #include "NR_BCCH-BCH-Message.h"       //asn_DEF_NR_BCCH_BCH_Message
@@ -141,7 +140,6 @@ static void nr_rrc_manage_rlc_bearers(const NR_UE_RRC_INST_t *rrc,
 static void nr_rrc_ue_process_RadioBearerConfig(NR_UE_RRC_INST_t *ue_rrc,
                                                 rrcPerNB_t *rrcNB,
                                                 NR_RadioBearerConfig_t *const radioBearerConfig);
-static void nr_rrc_ue_generate_RRCSetupRequest(NR_UE_RRC_INST_t *rrc);
 static void nr_rrc_ue_generate_rrcReestablishmentComplete(NR_RRCReestablishment_t *rrcReestablishment);
 static void process_lte_nsa_msg(NR_UE_RRC_INST_t *rrc, nsa_msg_t *msg, int msg_len);
 static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc,
@@ -216,8 +214,10 @@ static void nr_rrc_ue_process_rrcReconfiguration(NR_UE_RRC_INST_t *rrc,
 
         nr_rrc_cellgroup_configuration(rrcNB, rrc, cellGroupConfig);
 
-        if (!get_softmodem_params()->sa)
-          nr_rrc_mac_config_req_cg(0, 0, cellGroupConfig);
+        AssertFatal(!get_softmodem_params()->sa, "secondaryCellGroup only used in NSA for now\n");
+        nr_rrc_mac_config_req_cg(rrc->ue_id, 0, cellGroupConfig);
+
+        asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, cellGroupConfig);
       }
       if (ie->measConfig != NULL) {
         LOG_I(NR_RRC, "Measurement Configuration is present\n");
@@ -275,14 +275,12 @@ void process_nsa_message(NR_UE_RRC_INST_t *rrc, nsa_message_t nsa_message_type,
           SEQUENCE_free( &asn_DEF_NR_RadioBearerConfig, RadioBearerConfig, 1 );
           return;
         }
-        if (get_softmodem_params()->nsa) {
-          LOG_D(NR_RRC, "Calling nr_rrc_ue_process_RadioBearerConfig() at %d with: e_rab_id = %ld, drbID = %ld, cipher_algo = %ld, key = %ld \n",
-                          __LINE__, RadioBearerConfig->drb_ToAddModList->list.array[0]->cnAssociation->choice.eps_BearerIdentity,
-                          RadioBearerConfig->drb_ToAddModList->list.array[0]->drb_Identity,
-                          RadioBearerConfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm,
-                          *RadioBearerConfig->securityConfig->keyToUse);
-          nr_rrc_ue_process_RadioBearerConfig(rrc, rrc->perNB + 0, RadioBearerConfig);
-        }
+        LOG_D(NR_RRC, "Calling nr_rrc_ue_process_RadioBearerConfig()with: e_rab_id = %ld, drbID = %ld, cipher_algo = %ld, key = %ld \n",
+                     RadioBearerConfig->drb_ToAddModList->list.array[0]->cnAssociation->choice.eps_BearerIdentity,
+                     RadioBearerConfig->drb_ToAddModList->list.array[0]->drb_Identity,
+                     RadioBearerConfig->securityConfig->securityAlgorithmConfig->cipheringAlgorithm,
+                     *RadioBearerConfig->securityConfig->keyToUse);
+        nr_rrc_ue_process_RadioBearerConfig(rrc, rrc->perNB + 0, RadioBearerConfig);
         if (LOG_DEBUGFLAG(DEBUG_ASN1))
           xer_fprint(stdout, &asn_DEF_NR_RadioBearerConfig, (const void *)RadioBearerConfig);
         ASN_STRUCT_FREE(asn_DEF_NR_RadioBearerConfig, RadioBearerConfig);
@@ -309,12 +307,15 @@ NR_UE_RRC_INST_t* nr_rrc_init_ue(char* uecap_file, int nb_inst)
     rrc->dl_bwp_id = 0;
     rrc->ul_bwp_id = 0;
     rrc->as_security_activated = false;
-
+    rrc->ra_trigger = RA_NOT_RUNNING;
     rrc->uecap_file = uecap_file;
 
+    memset(&rrc->timers_and_constants, 0, sizeof(rrc->timers_and_constants));
+
     for (int i = 0; i < NB_CNX_UE; i++) {
       rrcPerNB_t *ptr = &rrc->perNB[i];
       ptr->SInfo = (NR_UE_RRC_SI_INFO){0};
+      init_SI_timers(&ptr->SInfo);
       for (int j = 0; j < NR_NUM_SRB; j++)
         ptr->Srb[j] = RB_NOT_PRESENT;
       for (int j = 0; j < MAX_DRBS_PER_UE; j++)
@@ -335,57 +336,44 @@ bool check_si_validity(NR_UE_RRC_SI_INFO *SI_info, int si_type)
 {
   switch (si_type) {
     case NR_SIB_TypeInfo__type_sibType2:
-      if (!SI_info->sib2 || SI_info->sib2_timer == -1)
+      if (!SI_info->sib2)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType3:
-      if (!SI_info->sib3 || SI_info->sib3_timer == -1)
+      if (!SI_info->sib3)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType4:
-      if (!SI_info->sib4 || SI_info->sib4_timer == -1)
+      if (!SI_info->sib4)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType5:
-      if (!SI_info->sib5 || SI_info->sib5_timer == -1)
+      if (!SI_info->sib5)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType6:
-      if (!SI_info->sib6 || SI_info->sib6_timer == -1)
+      if (!SI_info->sib6)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType7:
-      if (!SI_info->sib7 || SI_info->sib7_timer == -1)
+      if (!SI_info->sib7)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType8:
-      if (!SI_info->sib8 || SI_info->sib8_timer == -1)
+      if (!SI_info->sib8)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType9:
-      if (!SI_info->sib9 || SI_info->sib9_timer == -1)
+      if (!SI_info->sib9)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType10_v1610:
-      if (!SI_info->sib10 || SI_info->sib10_timer == -1)
+      if (!SI_info->sib10)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType11_v1610:
-      if (!SI_info->sib11 || SI_info->sib11_timer == -1)
+      if (!SI_info->sib11)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType12_v1610:
-      if (!SI_info->sib12 || SI_info->sib12_timer == -1)
+      if (!SI_info->sib12)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType13_v1610:
-      if (!SI_info->sib13 || SI_info->sib13_timer == -1)
+      if (!SI_info->sib13)
         return false;
-      break;
     case NR_SIB_TypeInfo__type_sibType14_v1610:
-      if (!SI_info->sib14 || SI_info->sib14_timer == -1)
+      if (!SI_info->sib14)
         return false;
-      break;
     default :
       AssertFatal(false, "Invalid SIB type %d\n", si_type);
   }
@@ -395,8 +383,7 @@ bool check_si_validity(NR_UE_RRC_SI_INFO *SI_info, int si_type)
 int check_si_status(NR_UE_RRC_SI_INFO *SI_info)
 {
   // schedule reception of SIB1 if RRC doesn't have it
-  // or if the timer expired
-  if (!SI_info->sib1 || SI_info->sib1_timer == -1)
+  if (!SI_info->sib1)
     return 1;
   else {
     if (SI_info->sib1->si_SchedulingInfo) {
@@ -472,91 +459,91 @@ static int nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si)
         if(!SI_info->sib2)
           SI_info->sib2 = calloc(1, sizeof(*SI_info->sib2));
         memcpy(SI_info->sib2, typeandinfo->choice.sib2, sizeof(NR_SIB2_t));
-        SI_info->sib2_timer = 0;
+        nr_timer_start(&SI_info->sib2_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib3:
         if(!SI_info->sib3)
           SI_info->sib3 = calloc(1, sizeof(*SI_info->sib3));
         memcpy(SI_info->sib3, typeandinfo->choice.sib3, sizeof(NR_SIB3_t));
-        SI_info->sib3_timer = 0;
+        nr_timer_start(&SI_info->sib3_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib4:
         if(!SI_info->sib4)
           SI_info->sib4 = calloc(1, sizeof(*SI_info->sib4));
         memcpy(SI_info->sib4, typeandinfo->choice.sib4, sizeof(NR_SIB4_t));
-        SI_info->sib4_timer = 0;
+        nr_timer_start(&SI_info->sib4_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib5:
         if(!SI_info->sib5)
           SI_info->sib5 = calloc(1, sizeof(*SI_info->sib5));
         memcpy(SI_info->sib5, typeandinfo->choice.sib5, sizeof(NR_SIB5_t));
-        SI_info->sib5_timer = 0;
+        nr_timer_start(&SI_info->sib5_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib6:
         if(!SI_info->sib6)
           SI_info->sib6 = calloc(1, sizeof(*SI_info->sib6));
         memcpy(SI_info->sib6, typeandinfo->choice.sib6, sizeof(NR_SIB6_t));
-        SI_info->sib6_timer = 0;
+        nr_timer_start(&SI_info->sib6_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib7:
         if(!SI_info->sib7)
           SI_info->sib7 = calloc(1, sizeof(*SI_info->sib7));
         memcpy(SI_info->sib7, typeandinfo->choice.sib7, sizeof(NR_SIB7_t));
-        SI_info->sib7_timer = 0;
+        nr_timer_start(&SI_info->sib7_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib8:
         if(!SI_info->sib8)
           SI_info->sib8 = calloc(1, sizeof(*SI_info->sib8));
         memcpy(SI_info->sib8, typeandinfo->choice.sib8, sizeof(NR_SIB8_t));
-        SI_info->sib8_timer = 0;
+        nr_timer_start(&SI_info->sib8_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib9:
         if(!SI_info->sib9)
           SI_info->sib9 = calloc(1, sizeof(*SI_info->sib9));
         memcpy(SI_info->sib9, typeandinfo->choice.sib9, sizeof(NR_SIB9_t));
-        SI_info->sib9_timer = 0;
+        nr_timer_start(&SI_info->sib9_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib10_v1610:
         if(!SI_info->sib10)
           SI_info->sib10 = calloc(1, sizeof(*SI_info->sib10));
         memcpy(SI_info->sib10, typeandinfo->choice.sib10_v1610, sizeof(NR_SIB10_r16_t));
-        SI_info->sib10_timer = 0;
+        nr_timer_start(&SI_info->sib10_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib11_v1610:
         if(!SI_info->sib11)
           SI_info->sib11 = calloc(1, sizeof(*SI_info->sib11));
         memcpy(SI_info->sib11, typeandinfo->choice.sib11_v1610, sizeof(NR_SIB11_r16_t));
-        SI_info->sib11_timer = 0;
+        nr_timer_start(&SI_info->sib11_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib12_v1610:
         if(!SI_info->sib12)
           SI_info->sib12 = calloc(1, sizeof(*SI_info->sib12));
         memcpy(SI_info->sib12, typeandinfo->choice.sib12_v1610, sizeof(NR_SIB12_r16_t));
-        SI_info->sib12_timer = 0;
+        nr_timer_start(&SI_info->sib12_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib13_v1610:
         if(!SI_info->sib13)
           SI_info->sib13 = calloc(1, sizeof(*SI_info->sib13));
         memcpy(SI_info->sib13, typeandinfo->choice.sib13_v1610, sizeof(NR_SIB13_r16_t));
-        SI_info->sib13_timer = 0;
+        nr_timer_start(&SI_info->sib13_timer);
         break;
 
       case NR_SystemInformation_IEs__sib_TypeAndInfo__Member_PR_sib14_v1610:
         if(!SI_info->sib14)
           SI_info->sib14 = calloc(1, sizeof(*SI_info->sib14));
         memcpy(SI_info->sib12, typeandinfo->choice.sib14_v1610, sizeof(NR_SIB14_r16_t));
-        SI_info->sib14_timer = 0;
+        nr_timer_start(&SI_info->sib14_timer);
         break;
       default:
         break;
@@ -566,13 +553,15 @@ static int nr_decode_SI(NR_UE_RRC_SI_INFO *SI_info, NR_SystemInformation_t *si)
   return 0;
 }
 
-void nr_rrc_ue_generate_ra_msg(NR_UE_RRC_INST_t *rrc, RA_trigger_t trigger, int rnti)
+static void nr_rrc_handle_msg3_indication(NR_UE_RRC_INST_t *rrc, rnti_t rnti)
 {
-  switch (trigger) {
+  switch (rrc->ra_trigger) {
     case INITIAL_ACCESS_FROM_RRC_IDLE:
       // After SIB1 is received, prepare RRCConnectionRequest
       rrc->rnti = rnti;
-      nr_rrc_ue_generate_RRCSetupRequest(rrc);
+      // start timer T300
+      NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
+      nr_timer_start(&tac->T300);
       break;
     case RRC_CONNECTION_REESTABLISHMENT:
       AssertFatal(1==0, "ra_trigger not implemented yet!\n");
@@ -601,7 +590,7 @@ void nr_rrc_ue_generate_ra_msg(NR_UE_RRC_INST_t *rrc, RA_trigger_t trigger, int
   }
 }
 
-static void nr_rrc_ue_generate_RRCSetupRequest(NR_UE_RRC_INST_t *rrc)
+static void nr_rrc_ue_prepare_RRCSetupRequest(NR_UE_RRC_INST_t *rrc)
 {
   LOG_D(NR_RRC, "Generation of RRCSetupRequest\n");
   uint8_t rv[6];
@@ -619,11 +608,6 @@ static void nr_rrc_ue_generate_RRCSetupRequest(NR_UE_RRC_INST_t *rrc)
   uint8_t buf[1024];
   int len = do_RRCSetupRequest(buf, sizeof(buf), rv);
 
-  // start timer T300
-  NR_UE_Timers_Constants_t *tac = &rrc->timers_and_constants;
-  tac->T300_active = true;
-
-  /* convention: RNTI for SRB0 is zero, as it changes all the time */
   nr_rlc_srb_recv_sdu(rrc->ue_id, 0, buf, len);
 }
 
@@ -686,10 +670,11 @@ static int8_t nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
         if(g_log->log_component[NR_RRC].level >= OAILOG_DEBUG)
           xer_fprint(stdout, &asn_DEF_NR_SIB1, (const void *) SI_info->sib1);
         LOG_A(NR_RRC, "SIB1 decoded\n");
-        SI_info->sib1_timer = 0;
-        // FIXME: improve condition for the RA trigger
+        nr_timer_start(&SI_info->sib1_timer);
         if (rrc->nrRrcState == RRC_STATE_IDLE_NR) {
-          LOG_D(PHY,"Setting state to RRC_STATE_IDLE_NR\n");
+          rrc->ra_trigger = INITIAL_ACCESS_FROM_RRC_IDLE;
+          // preparing RRC setup request payload in advance
+          nr_rrc_ue_prepare_RRCSetupRequest(rrc);
         }
         // configure default SI
         nr_rrc_configure_default_SI(SI_info, sib1);
@@ -747,9 +732,6 @@ static void nr_rrc_manage_rlc_bearers(const NR_UE_RRC_INST_t *rrc,
       }
     }
   }
-  nr_rrc_mac_config_req_ue_logicalChannelBearer(rrc->ue_id,
-                                                cellGroupConfig->rlc_BearerToAddModList,
-                                                cellGroupConfig->rlc_BearerToReleaseList);
 }
 
 void nr_rrc_cellgroup_configuration(rrcPerNB_t *rrcNB, NR_UE_RRC_INST_t *rrc, NR_CellGroupConfig_t *cellGroupConfig)
@@ -766,13 +748,10 @@ void nr_rrc_cellgroup_configuration(rrcPerNB_t *rrcNB, NR_UE_RRC_INST_t *rrc, NR
         // with the release cause 'other' upon which the procedure ends
         // TODO
       }
-      if (tac->T310_active) {
-        tac->T310_active = false;
-        tac->T310_cnt = 0;
-      }
-      nr_rrc_set_T304(&rrc->timers_and_constants, reconfigurationWithSync);
-      tac->T304_active = true;
-      tac->T304_cnt = 0;
+      nr_timer_stop(&tac->T310);
+      int t304_value = nr_rrc_get_T304(reconfigurationWithSync->t304);
+      nr_timer_setup(&tac->T304, t304_value, 10); // 10ms step
+      nr_timer_start(&tac->T304);
       rrc->rnti = reconfigurationWithSync->newUE_Identity;
       // resume suspended radio bearers
       for (int i = 0; i < NR_NUM_SRB; i++) {
@@ -795,9 +774,7 @@ void nr_rrc_cellgroup_configuration(rrcPerNB_t *rrcNB, NR_UE_RRC_INST_t *rrc, NR
     }
   }
 
-  // TODO verify why we need this limitation
-  if (get_softmodem_params()->sa || get_softmodem_params()->nsa)
-    nr_rrc_manage_rlc_bearers(rrc, cellGroupConfig, rrcNB);
+  nr_rrc_manage_rlc_bearers(rrc, cellGroupConfig, rrcNB);
 
   AssertFatal(cellGroupConfig->sCellToReleaseList == NULL,
               "Secondary serving cell release not implemented\n");
@@ -828,6 +805,8 @@ static void nr_rrc_ue_process_masterCellGroup(NR_UE_RRC_INST_t *rrc,
 
   LOG_D(RRC,"Sending CellGroupConfig to MAC\n");
   nr_rrc_mac_config_req_cg(rrc->ue_id, 0, cellGroupConfig);
+
+  asn1cFreeStruc(asn_DEF_NR_CellGroupConfig, cellGroupConfig);
 }
 
 static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const uint8_t Transaction_id)
@@ -877,16 +856,12 @@ static void nr_rrc_process_rrcsetup(NR_UE_RRC_INST_t *rrc,
   // TODO (not handled) if stored, discard the cell reselection priority information provided by
   // the cellReselectionPriorities or inherited from another RAT
 
-  // stop timer T300, T301 or T319 if running;
+  // stop timer T300, T301, T319, T320 if running;
   NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
-  timers->T300_active = false;
-  timers->T300_cnt = 0;
-  timers->T301_active = false;
-  timers->T301_cnt = 0;
-  timers->T319_active = false;
-  timers->T319_cnt = 0;
-  timers->T320_active = false;
-  timers->T320_cnt = 0;
+  nr_timer_stop(&timers->T300);
+  nr_timer_stop(&timers->T301);
+  nr_timer_stop(&timers->T319);
+  nr_timer_stop(&timers->T320);
 
   // TODO if T390 and T302 are running (not implemented)
 
@@ -1389,10 +1364,9 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
 void nr_rrc_handle_ra_indication(NR_UE_RRC_INST_t *rrc, bool ra_succeeded)
 {
   NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
-  if (ra_succeeded && timers->T304_active == true) {
+  if (ra_succeeded && is_nr_timer_active(timers->T304)) {
     // successful Random Access procedure triggered by reconfigurationWithSync
-    timers->T304_active = false;
-    timers->T304_cnt = 0;
+    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
   }
@@ -1440,7 +1414,7 @@ void *rrc_nrue(void *notUsed)
     break;
 
   case NR_RRC_MAC_MSG3_IND:
-    nr_rrc_ue_generate_ra_msg(rrc, INITIAL_ACCESS_FROM_RRC_IDLE, NR_RRC_MAC_MSG3_IND(msg_p).rnti);
+    nr_rrc_handle_msg3_indication(rrc, NR_RRC_MAC_MSG3_IND(msg_p).rnti);
     break;
 
   case NR_RRC_MAC_RA_IND:
@@ -1829,11 +1803,11 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
       waitTime = rrcReleaseIEs->nonCriticalExtension ?
                  rrcReleaseIEs->nonCriticalExtension->waitTime : NULL;
       if (waitTime) {
-        if (tac->T302_active)
-          tac->T302_cnt = 0; // stop 302
+        nr_timer_stop(&tac->T302); // stop 302
         // start timer T302 with the value set to the waitTime
-        tac->T302_active = true;
-        tac->T302_k = *waitTime * 1000; // waitTime is in seconds
+        int target = *waitTime * 1000; // waitTime is in seconds
+        nr_timer_setup(&tac->T302, target, 10);
+        nr_timer_start(&tac->T302);
         // TODO inform upper layers that access barring is applicable
         // for all access categories except categories '0' and '2'.
         LOG_E(NR_RRC,"Go to IDLE. Handling RRCRelease message including a waitTime not implemented\n");
@@ -1841,17 +1815,15 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
     }
   }
   if (!waitTime) {
-    if (tac->T302_active) {
-      tac->T302_cnt = 0;
-      tac->T302_active = false;
+    if (is_nr_timer_active(tac->T302)) {
+      nr_timer_stop(&tac->T302);
       // TODO barring alleviation as in 5.3.14.4
       // not implemented
       LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n");
     }
   }
-  if (tac->T390_active) {
-    tac->T390_cnt = 0;
-    tac->T390_active = false;
+  if (is_nr_timer_active(tac->T390)) {
+    nr_timer_stop(&tac->T390);
     // TODO barring alleviation as in 5.3.14.4
     // not implemented
     LOG_E(NR_RRC,"Go to IDLE. Barring alleviation not implemented\n");
@@ -1859,24 +1831,15 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
   if (!RRCRelease && rrc->nrRrcState == RRC_STATE_INACTIVE_NR) {
     // TODO discard the cell reselection priority information provided by the cellReselectionPriorities
     // cell reselection priorities not implemented yet
-    if (tac->T320_active) {
-      tac->T320_cnt = 0;
-      tac->T320_active = false;
-    }
+    nr_timer_stop(&tac->T320);
   }
   // Stop all the timers except T302, T320 and T325
-  tac->T300_active = false;
-  tac->T300_cnt = 0;
-  tac->T301_active = false;
-  tac->T301_cnt = 0;
-  tac->T304_active = false;
-  tac->T304_cnt = 0;
-  tac->T310_active = false;
-  tac->T310_cnt = 0;
-  tac->T311_active = false;
-  tac->T311_cnt = 0;
-  tac->T319_active = false;
-  tac->T319_cnt = 0;
+  nr_timer_stop(&tac->T300);
+  nr_timer_stop(&tac->T301);
+  nr_timer_stop(&tac->T304);
+  nr_timer_stop(&tac->T310);
+  nr_timer_stop(&tac->T311);
+  nr_timer_stop(&tac->T319);
 
   // discard the UE Inactive AS context
   // TODO there is no inactive AS context
@@ -1915,6 +1878,7 @@ void nr_rrc_going_to_IDLE(NR_UE_RRC_INST_t *rrc,
   for (int i = 0; i < NB_CNX_UE; i++) {
     rrcPerNB_t *nb = &rrc->perNB[i];
     NR_UE_RRC_SI_INFO *SI_info = &nb->SInfo;
+    init_SI_timers(SI_info);
     asn1cFreeStruc(asn_DEF_NR_SIB1, SI_info->sib1);
     asn1cFreeStruc(asn_DEF_NR_SIB2, SI_info->sib2);
     asn1cFreeStruc(asn_DEF_NR_SIB3, SI_info->sib3);
diff --git a/openair2/RRC/NR_UE/rrc_defs.h b/openair2/RRC/NR_UE/rrc_defs.h
index efcb9acfe5fd3dafbfc8214d8aea3565617c74cd..9c2ef2a00a75630282b365eec99317c657822fe3 100644
--- a/openair2/RRC/NR_UE/rrc_defs.h
+++ b/openair2/RRC/NR_UE/rrc_defs.h
@@ -114,74 +114,53 @@ typedef enum RA_trigger_e {
 typedef struct UE_RRC_SI_INFO_NR_s {
   uint32_t default_otherSI_map;
   NR_SIB1_t *sib1;
-  int sib1_timer;
+  NR_timer_t sib1_timer;
   NR_SIB2_t *sib2;
-  int sib2_timer;
+  NR_timer_t sib2_timer;
   NR_SIB3_t *sib3;
-  int sib3_timer;
+  NR_timer_t sib3_timer;
   NR_SIB4_t *sib4;
-  int sib4_timer;
+  NR_timer_t sib4_timer;
   NR_SIB5_t *sib5;
-  int sib5_timer;
+  NR_timer_t sib5_timer;
   NR_SIB6_t *sib6;
-  int sib6_timer;
+  NR_timer_t sib6_timer;
   NR_SIB7_t *sib7;
-  int sib7_timer;
+  NR_timer_t sib7_timer;
   NR_SIB8_t *sib8;
-  int sib8_timer;
+  NR_timer_t sib8_timer;
   NR_SIB9_t *sib9;
-  int sib9_timer;
+  NR_timer_t sib9_timer;
   NR_SIB10_r16_t *sib10;
-  int sib10_timer;
+  NR_timer_t sib10_timer;
   NR_SIB11_r16_t *sib11;
-  int sib11_timer;
+  NR_timer_t sib11_timer;
   NR_SIB12_r16_t *sib12;
-  int sib12_timer;
+  NR_timer_t sib12_timer;
   NR_SIB13_r16_t *sib13;
-  int sib13_timer;
+  NR_timer_t sib13_timer;
   NR_SIB14_r16_t *sib14;
-  int sib14_timer;
-} __attribute__ ((__packed__)) NR_UE_RRC_SI_INFO;
+  NR_timer_t sib14_timer;
+} NR_UE_RRC_SI_INFO;
 
 typedef struct NR_UE_Timers_Constants_s {
-  // timers status
-  bool T300_active;
-  bool T301_active;
-  bool T302_active;
-  bool T304_active;
-  bool T310_active;
-  bool T311_active;
-  bool T319_active;
-  bool T320_active;
-  bool T325_active;
-  bool T390_active;
   // timers
-  uint32_t T300_cnt;
-  uint32_t T301_cnt;
-  uint32_t T302_cnt;
-  uint32_t T304_cnt;
-  uint32_t T310_cnt;
-  uint32_t T311_cnt;
-  uint32_t T319_cnt;
-  uint32_t T320_cnt;
-  uint32_t T325_cnt;
-  uint32_t T390_cnt;
+  NR_timer_t T300;
+  NR_timer_t T301;
+  NR_timer_t T302;
+  NR_timer_t T304;
+  NR_timer_t T310;
+  NR_timer_t T311;
+  NR_timer_t T319;
+  NR_timer_t T320;
+  NR_timer_t T325;
+  NR_timer_t T390;
   // counters
   uint32_t N310_cnt;
   uint32_t N311_cnt;
   // constants (limits configured by the network)
   uint32_t N310_k;
   uint32_t N311_k;
-  uint32_t T300_k;
-  uint32_t T301_k;
-  uint32_t T302_k;
-  uint32_t T304_k;
-  uint32_t T310_k;
-  uint32_t T311_k;
-  uint32_t T319_k;
-  uint32_t T320_k;
-  uint32_t T325_k;
-  uint32_t T390_k;
 } NR_UE_Timers_Constants_t;
 
 typedef enum {
@@ -213,9 +192,8 @@ typedef struct NR_UE_RRC_INST_s {
 
   OAI_NR_UECapability_t UECap;
   NR_UE_Timers_Constants_t timers_and_constants;
-  plmn_t                         plmnID;
-
-  // NR_MIB_t *mib;
+  RA_trigger_t ra_trigger;
+  plmn_t plmnID;
 
   NR_BWP_Id_t dl_bwp_id;
   NR_BWP_Id_t ul_bwp_id;
diff --git a/openair2/RRC/NR_UE/rrc_proto.h b/openair2/RRC/NR_UE/rrc_proto.h
index 1001652037b1de33262041c8f1586675a5d1eb9b..45fb1a1c0feffd0a2bcde66f292b76f24dd98acc 100644
--- a/openair2/RRC/NR_UE/rrc_proto.h
+++ b/openair2/RRC/NR_UE/rrc_proto.h
@@ -33,7 +33,7 @@
 #ifndef _RRC_PROTO_H_
 #define _RRC_PROTO_H_
 
-
+#include "oai_asn1.h"
 #include "rrc_defs.h"
 #include "NR_RRCReconfiguration.h"
 #include "NR_MeasConfig.h"
@@ -108,6 +108,7 @@ extern void start_oai_nrue_threads(void);
 int get_from_lte_ue_fd();
 
 void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo);
+void init_SI_timers(NR_UE_RRC_SI_INFO *SInfo);
 
 void nr_ue_rrc_timer_trigger(int module_id, int frame, int gnb_id);
 void handle_t300_expiry(NR_UE_RRC_INST_t *rrc);
@@ -115,9 +116,8 @@ void handle_t300_expiry(NR_UE_RRC_INST_t *rrc);
 void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac);
 void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac);
 void nr_rrc_set_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1_t *sib1);
-void nr_rrc_set_T304(NR_UE_Timers_Constants_t *tac, NR_ReconfigurationWithSync_t *reconfigurationWithSync);
-void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
-                     nr_sync_msg_t sync_msg);
+int nr_rrc_get_T304(long t304);
+void handle_rlf_sync(NR_UE_Timers_Constants_t *tac, nr_sync_msg_t sync_msg);
 void nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(NR_UE_RRC_INST_t *rrc,
                                                        struct NR_SetupRelease_RLF_TimersAndConstants *rlf_TimersAndConstants);
 
diff --git a/openair2/RRC/NR_UE/rrc_timers_and_constants.c b/openair2/RRC/NR_UE/rrc_timers_and_constants.c
index c01755e4de4a28a30398b8c9b4a530354503f0e6..cd5b79640c45c27d34b9c28e928a366faa2584b4 100644
--- a/openair2/RRC/NR_UE/rrc_timers_and_constants.c
+++ b/openair2/RRC/NR_UE/rrc_timers_and_constants.c
@@ -21,80 +21,97 @@
 
 #include "openair2/RRC/NR_UE/rrc_proto.h"
 
-void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo)
+void init_SI_timers(NR_UE_RRC_SI_INFO *SInfo)
 {
   // delete any stored version of a SIB after 3 hours
   // from the moment it was successfully confirmed as valid
-  if (SInfo->sib1 && SInfo->sib1_timer >= 0) {
-    SInfo->sib1_timer += 10;
-    if (SInfo->sib1_timer > 10800000)
-      SInfo->sib1_timer = -1;
+  nr_timer_setup(&SInfo->sib1_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib2_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib3_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib4_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib5_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib6_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib7_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib8_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib9_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib10_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib11_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib12_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib13_timer, 10800000, 10);
+  nr_timer_setup(&SInfo->sib14_timer, 10800000, 10);
+}
+
+void nr_rrc_SI_timers(NR_UE_RRC_SI_INFO *SInfo)
+{
+  if (SInfo->sib1) {
+   bool sib1_expired = nr_timer_tick(&SInfo->sib1_timer);
+   if (sib1_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB1, SInfo->sib1);
   }
-  if (SInfo->sib2 && SInfo->sib2_timer >= 0) {
-    SInfo->sib2_timer += 10;
-    if (SInfo->sib2_timer > 10800000)
-      SInfo->sib2_timer = -1;
+  if (SInfo->sib2) {
+   bool sib2_expired = nr_timer_tick(&SInfo->sib2_timer);
+   if (sib2_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB2, SInfo->sib2);
   }
-  if (SInfo->sib3 && SInfo->sib3_timer >= 0) {
-    SInfo->sib3_timer += 10;
-    if (SInfo->sib3_timer > 10800000)
-      SInfo->sib3_timer = -1;
+  if (SInfo->sib3) {
+   bool sib3_expired = nr_timer_tick(&SInfo->sib3_timer);
+   if (sib3_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB3, SInfo->sib3);
   }
-  if (SInfo->sib4 && SInfo->sib4_timer >= 0) {
-    SInfo->sib4_timer += 10;
-    if (SInfo->sib4_timer > 10800000)
-      SInfo->sib4_timer = -1;
+  if (SInfo->sib4) {
+   bool sib4_expired = nr_timer_tick(&SInfo->sib4_timer);
+   if (sib4_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB4, SInfo->sib4);
   }
-  if (SInfo->sib5 && SInfo->sib5_timer >= 0) {
-    SInfo->sib5_timer += 10;
-    if (SInfo->sib5_timer > 10800000)
-      SInfo->sib5_timer = -1;
+  if (SInfo->sib5) {
+   bool sib5_expired = nr_timer_tick(&SInfo->sib5_timer);
+   if (sib5_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB5, SInfo->sib5);
   }
-  if (SInfo->sib6 && SInfo->sib6_timer >= 0) {
-    SInfo->sib6_timer += 10;
-    if (SInfo->sib6_timer > 10800000)
-      SInfo->sib6_timer = -1;
+  if (SInfo->sib6) {
+   bool sib6_expired = nr_timer_tick(&SInfo->sib6_timer);
+   if (sib6_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB6, SInfo->sib6);
   }
-  if (SInfo->sib7 && SInfo->sib7_timer >= 0) {
-    SInfo->sib7_timer += 10;
-    if (SInfo->sib7_timer > 10800000)
-      SInfo->sib7_timer = -1;
+  if (SInfo->sib7) {
+   bool sib7_expired = nr_timer_tick(&SInfo->sib7_timer);
+   if (sib7_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB7, SInfo->sib7);
   }
-  if (SInfo->sib8 && SInfo->sib8_timer >= 0) {
-    SInfo->sib8_timer += 10;
-    if (SInfo->sib8_timer > 10800000)
-      SInfo->sib8_timer = -1;
+  if (SInfo->sib8) {
+   bool sib8_expired = nr_timer_tick(&SInfo->sib8_timer);
+   if (sib8_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB8, SInfo->sib8);
   }
-  if (SInfo->sib9 && SInfo->sib9_timer >= 0) {
-    SInfo->sib9_timer += 10;
-    if (SInfo->sib9_timer > 10800000)
-      SInfo->sib9_timer = -1;
-
+  if (SInfo->sib9) {
+   bool sib9_expired = nr_timer_tick(&SInfo->sib9_timer);
+   if (sib9_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB9, SInfo->sib9);
   }
-  if (SInfo->sib10 && SInfo->sib10_timer >= 0) {
-    SInfo->sib10_timer += 10;
-    if (SInfo->sib10_timer > 10800000)
-      SInfo->sib10_timer = -1;
+  if (SInfo->sib10) {
+   bool sib10_expired = nr_timer_tick(&SInfo->sib10_timer);
+   if (sib10_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB10_r16, SInfo->sib10);
   }
-  if (SInfo->sib11 && SInfo->sib11_timer >= 0) {
-    SInfo->sib11_timer += 10;
-    if (SInfo->sib11_timer > 10800000)
-      SInfo->sib11_timer = -1;
+  if (SInfo->sib11) {
+   bool sib11_expired = nr_timer_tick(&SInfo->sib11_timer);
+   if (sib11_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB11_r16, SInfo->sib11);
   }
-  if (SInfo->sib12 && SInfo->sib12_timer >= 0) {
-    SInfo->sib12_timer += 10;
-    if (SInfo->sib12_timer > 10800000)
-      SInfo->sib12_timer = -1;
+  if (SInfo->sib12) {
+   bool sib12_expired = nr_timer_tick(&SInfo->sib12_timer);
+   if (sib12_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB12_r16, SInfo->sib12);
   }
-  if (SInfo->sib13 && SInfo->sib13_timer >= 0) {
-    SInfo->sib13_timer += 10;
-    if (SInfo->sib13_timer > 10800000)
-      SInfo->sib13_timer = -1;
+  if (SInfo->sib13) {
+   bool sib13_expired = nr_timer_tick(&SInfo->sib13_timer);
+   if (sib13_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB13_r16, SInfo->sib13);
   }
-  if (SInfo->sib14 && SInfo->sib14_timer >= 0) {
-    SInfo->sib14_timer += 10;
-    if (SInfo->sib14_timer > 10800000)
-      SInfo->sib14_timer = -1;
+  if (SInfo->sib14) {
+   bool sib14_expired = nr_timer_tick(&SInfo->sib14_timer);
+   if (sib14_expired)
+     asn1cFreeStruc(asn_DEF_NR_SIB14_r16, SInfo->sib14);
   }
 }
 
@@ -102,158 +119,154 @@ void nr_rrc_handle_timers(NR_UE_RRC_INST_t *rrc)
 {
   NR_UE_Timers_Constants_t *timers = &rrc->timers_and_constants;
 
-  if (timers->T300_active == true) {
-    timers->T300_cnt += 10;
-    if(timers->T300_cnt >= timers->T300_k) {
-      timers->T300_active = false;
-      timers->T300_cnt = 0;
-      handle_t300_expiry(rrc);
-    }
-  }
-  if (timers->T304_active == true) {
-    timers->T304_cnt += 10;
-    if(timers->T304_cnt >= timers->T304_k) {
-      // TODO
-      // For T304 of MCG, in case of the handover from NR or intra-NR
-      // handover, initiate the RRC re-establishment procedure;
-      // In case of handover to NR, perform the actions defined in the
-      // specifications applicable for the source RAT.
-    }
+  bool t300_expired = nr_timer_tick(&timers->T300);
+  if(t300_expired)
+    handle_t300_expiry(rrc);
+
+  bool t304_expired = nr_timer_tick(&timers->T304);
+  if(t304_expired) {
+    // TODO
+    // For T304 of MCG, in case of the handover from NR or intra-NR
+    // handover, initiate the RRC re-establishment procedure;
+    // In case of handover to NR, perform the actions defined in the
+    // specifications applicable for the source RAT.
   }
-  if (timers->T310_active == true) {
-    timers->T310_cnt += 10;
-    if(timers->T310_cnt >= timers->T310_k) {
-      // TODO
-      // handle detection of radio link failure
-      // as described in 5.3.10.3 of 38.331
-      AssertFatal(false, "Radio link failure! Not handled yet!\n");
-    }
+
+  bool t310_expired = nr_timer_tick(&timers->T310);
+  if(t310_expired) {
+    // TODO
+    // handle detection of radio link failure
+    // as described in 5.3.10.3 of 38.331
+    AssertFatal(false, "Radio link failure! Not handled yet!\n");
   }
-  if (timers->T311_active == true) {
-    timers->T311_cnt += 10;
-    if(timers->T311_cnt >= timers->T311_k) {
-      // Upon T311 expiry, the UE shall perform the actions upon going to RRC_IDLE
-      // with release cause 'RRC connection failure'
-      nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL);
-    }
+
+  bool t311_expired = nr_timer_tick(&timers->T311);
+  if(t311_expired) {
+    // Upon T311 expiry, the UE shall perform the actions upon going to RRC_IDLE
+    // with release cause 'RRC connection failure'
+    nr_rrc_going_to_IDLE(rrc, RRC_CONNECTION_FAILURE, NULL);
   }
 }
 
-void nr_rrc_set_T304(NR_UE_Timers_Constants_t *tac, NR_ReconfigurationWithSync_t *reconfigurationWithSync)
+int nr_rrc_get_T304(long t304)
 {
-  if(reconfigurationWithSync) {
-    switch (reconfigurationWithSync->t304) {
-      case NR_ReconfigurationWithSync__t304_ms50 :
-        tac->T304_k = 50;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms100 :
-        tac->T304_k = 100;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms150 :
-        tac->T304_k = 150;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms200 :
-        tac->T304_k = 200;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms500 :
-        tac->T304_k = 500;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms1000 :
-        tac->T304_k = 1000;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms2000 :
-        tac->T304_k = 2000;
-        break;
-      case NR_ReconfigurationWithSync__t304_ms10000 :
-        tac->T304_k = 10000;
-        break;
-      default :
-        AssertFatal(false, "Invalid T304 %ld\n", reconfigurationWithSync->t304);
-    }
+  int target = 0;
+  switch (t304) {
+    case NR_ReconfigurationWithSync__t304_ms50 :
+      target = 50;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms100 :
+      target = 100;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms150 :
+      target = 150;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms200 :
+      target = 200;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms500 :
+      target = 500;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms1000 :
+      target = 1000;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms2000 :
+      target = 2000;
+      break;
+    case NR_ReconfigurationWithSync__t304_ms10000 :
+      target = 10000;
+      break;
+    default :
+      AssertFatal(false, "Invalid T304 %ld\n", t304);
   }
+  return target;
 }
 
 void set_rlf_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1_t *sib1)
 {
   if(sib1 && sib1->ue_TimersAndConstants) {
+    int k = 0;
     switch (sib1->ue_TimersAndConstants->t301) {
       case NR_UE_TimersAndConstants__t301_ms100 :
-        tac->T301_k = 100;
+        k = 100;
         break;
       case NR_UE_TimersAndConstants__t301_ms200 :
-        tac->T301_k = 200;
+        k = 200;
         break;
       case NR_UE_TimersAndConstants__t301_ms300 :
-        tac->T301_k = 300;
+        k = 300;
         break;
       case NR_UE_TimersAndConstants__t301_ms400 :
-        tac->T301_k = 400;
+        k = 400;
         break;
       case NR_UE_TimersAndConstants__t301_ms600 :
-        tac->T301_k = 600;
+        k = 600;
         break;
       case NR_UE_TimersAndConstants__t301_ms1000 :
-        tac->T301_k = 1000;
+        k = 1000;
         break;
       case NR_UE_TimersAndConstants__t301_ms1500 :
-        tac->T301_k = 1500;
+        k = 1500;
         break;
       case NR_UE_TimersAndConstants__t301_ms2000 :
-        tac->T301_k = 2000;
+        k = 2000;
         break;
       default :
         AssertFatal(false, "Invalid T301 %ld\n", sib1->ue_TimersAndConstants->t301);
     }
+    nr_timer_setup(&tac->T301, k, 10); // 10ms step
     switch (sib1->ue_TimersAndConstants->t310) {
       case NR_UE_TimersAndConstants__t310_ms0 :
-        tac->T310_k = 0;
+        k = 0;
         break;
       case NR_UE_TimersAndConstants__t310_ms50 :
-        tac->T310_k = 50;
+        k = 50;
         break;
       case NR_UE_TimersAndConstants__t310_ms100 :
-        tac->T310_k = 100;
+        k = 100;
         break;
       case NR_UE_TimersAndConstants__t310_ms200 :
-        tac->T310_k = 200;
+        k = 200;
         break;
       case NR_UE_TimersAndConstants__t310_ms500 :
-        tac->T310_k = 500;
+        k = 500;
         break;
       case NR_UE_TimersAndConstants__t310_ms1000 :
-        tac->T310_k = 1000;
+        k = 1000;
         break;
       case NR_UE_TimersAndConstants__t310_ms2000 :
-        tac->T310_k = 2000;
+        k = 2000;
         break;
       default :
         AssertFatal(false, "Invalid T310 %ld\n", sib1->ue_TimersAndConstants->t310);
     }
+    nr_timer_setup(&tac->T310, k, 10); // 10ms step
     switch (sib1->ue_TimersAndConstants->t311) {
       case NR_UE_TimersAndConstants__t311_ms1000 :
-        tac->T311_k = 1000;
+        k = 1000;
         break;
       case NR_UE_TimersAndConstants__t311_ms3000 :
-        tac->T311_k = 3000;
+        k = 3000;
         break;
       case NR_UE_TimersAndConstants__t311_ms5000 :
-        tac->T311_k = 5000;
+        k = 5000;
         break;
       case NR_UE_TimersAndConstants__t311_ms10000 :
-        tac->T311_k = 10000;
+        k = 10000;
         break;
       case NR_UE_TimersAndConstants__t311_ms15000 :
-        tac->T311_k = 15000;
+        k = 15000;
         break;
       case NR_UE_TimersAndConstants__t311_ms20000 :
-        tac->T311_k = 20000;
+        k = 20000;
         break;
       case NR_UE_TimersAndConstants__t311_ms30000 :
-        tac->T311_k = 30000;
+        k = 30000;
         break;
       default :
         AssertFatal(false, "Invalid T311 %ld\n", sib1->ue_TimersAndConstants->t311);
     }
+    nr_timer_setup(&tac->T311, k, 10); // 10ms step
     switch (sib1->ue_TimersAndConstants->n310) {
       case NR_UE_TimersAndConstants__n310_n1 :
         tac->N310_k = 1;
@@ -319,62 +332,65 @@ void nr_rrc_set_sib1_timers_and_constants(NR_UE_Timers_Constants_t *tac, NR_SIB1
 {
   set_rlf_sib1_timers_and_constants(tac, sib1);
   if(sib1 && sib1->ue_TimersAndConstants) {
+    int k = 0;
     switch (sib1->ue_TimersAndConstants->t300) {
       case NR_UE_TimersAndConstants__t300_ms100 :
-        tac->T300_k = 100;
+        k = 100;
         break;
       case NR_UE_TimersAndConstants__t300_ms200 :
-        tac->T300_k = 200;
+        k = 200;
         break;
       case NR_UE_TimersAndConstants__t300_ms300 :
-        tac->T300_k = 300;
+        k = 300;
         break;
       case NR_UE_TimersAndConstants__t300_ms400 :
-        tac->T300_k = 400;
+        k = 400;
         break;
       case NR_UE_TimersAndConstants__t300_ms600 :
-        tac->T300_k = 600;
+        k = 600;
         break;
       case NR_UE_TimersAndConstants__t300_ms1000 :
-        tac->T300_k = 1000;
+        k = 1000;
         break;
       case NR_UE_TimersAndConstants__t300_ms1500 :
-        tac->T300_k = 1500;
+        k = 1500;
         break;
       case NR_UE_TimersAndConstants__t300_ms2000 :
-        tac->T300_k = 2000;
+        k = 2000;
         break;
       default :
         AssertFatal(false, "Invalid T300 %ld\n", sib1->ue_TimersAndConstants->t300);
     }
+    nr_timer_setup(&tac->T300, k, 10); // 10ms step
     switch (sib1->ue_TimersAndConstants->t319) {
       case NR_UE_TimersAndConstants__t319_ms100 :
-        tac->T319_k = 100;
+        k = 100;
         break;
       case NR_UE_TimersAndConstants__t319_ms200 :
-        tac->T319_k = 200;
+        k = 200;
         break;
       case NR_UE_TimersAndConstants__t319_ms300 :
-        tac->T319_k = 300;
+        k = 300;
         break;
       case NR_UE_TimersAndConstants__t319_ms400 :
-        tac->T319_k = 400;
+        k = 400;
         break;
       case NR_UE_TimersAndConstants__t319_ms600 :
-        tac->T319_k = 600;
+        k = 600;
         break;
       case NR_UE_TimersAndConstants__t319_ms1000 :
-        tac->T319_k = 1000;
+        k = 1000;
         break;
       case NR_UE_TimersAndConstants__t319_ms1500 :
-        tac->T319_k = 1500;
+        k = 1500;
         break;
       case NR_UE_TimersAndConstants__t319_ms2000 :
-        tac->T319_k = 2000;
+        k = 2000;
         break;
       default :
         AssertFatal(false, "Invalid T319 %ld\n", sib1->ue_TimersAndConstants->t319);
     }
+    nr_timer_setup(&tac->T319, k, 10); // 10ms step
   }
   else
     LOG_E(NR_RRC,"SIB1 should not be NULL and neither UE_Timers_Constants\n");
@@ -398,37 +414,39 @@ void nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(NR_UE_RRC_INST_t *rrc,
       if (rlf_tac == NULL)
         return;
       // (re-)configure the value of timers and constants in accordance with received rlf-TimersAndConstants
+      int k = 0;
       switch (rlf_tac->t310) {
         case NR_RLF_TimersAndConstants__t310_ms0 :
-          tac->T310_k = 0;
+          k = 0;
           break;
         case NR_RLF_TimersAndConstants__t310_ms50 :
-          tac->T310_k = 50;
+          k = 50;
           break;
         case NR_RLF_TimersAndConstants__t310_ms100 :
-          tac->T310_k = 100;
+          k = 100;
           break;
         case NR_RLF_TimersAndConstants__t310_ms200 :
-          tac->T310_k = 200;
+          k = 200;
           break;
         case NR_RLF_TimersAndConstants__t310_ms500 :
-          tac->T310_k = 500;
+          k = 500;
           break;
         case NR_RLF_TimersAndConstants__t310_ms1000 :
-          tac->T310_k = 1000;
+          k = 1000;
           break;
         case NR_RLF_TimersAndConstants__t310_ms2000 :
-          tac->T310_k = 2000;
+          k = 2000;
           break;
         case NR_RLF_TimersAndConstants__t310_ms4000 :
-          tac->T310_k = 4000;
+          k = 4000;
           break;
         case NR_RLF_TimersAndConstants__t310_ms6000 :
-          tac->T310_k = 6000;
+          k = 6000;
           break;
         default :
           AssertFatal(false, "Invalid T310 %ld\n", rlf_tac->t310);
       }
+      nr_timer_setup(&tac->T310, k, 10); // 10ms step
       switch (rlf_tac->n310) {
         case NR_RLF_TimersAndConstants__n310_n1 :
           tac->N310_k = 1;
@@ -488,29 +506,30 @@ void nr_rrc_handle_SetupRelease_RLF_TimersAndConstants(NR_UE_RRC_INST_t *rrc,
       if (rlf_tac->ext1) {
         switch (rlf_tac->ext1->t311) {
           case NR_RLF_TimersAndConstants__ext1__t311_ms1000 :
-            tac->T311_k = 1000;
+            k = 1000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms3000 :
-            tac->T311_k = 3000;
+            k = 3000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms5000 :
-            tac->T311_k = 5000;
+            k = 5000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms10000 :
-            tac->T311_k = 10000;
+            k = 10000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms15000 :
-            tac->T311_k = 15000;
+            k = 15000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms20000 :
-            tac->T311_k = 20000;
+            k = 20000;
             break;
           case NR_RLF_TimersAndConstants__ext1__t311_ms30000 :
-            tac->T311_k = 30000;
+            k = 30000;
             break;
           default :
             AssertFatal(false, "Invalid T311 %ld\n", rlf_tac->ext1->t311);
         }
+        nr_timer_setup(&tac->T311, k, 10); // 10ms step
       }
       reset_rlf_timers_and_constants(tac);
       break;
@@ -524,13 +543,12 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
 {
   if (sync_msg == IN_SYNC) {
     tac->N310_cnt = 0;
-    if (tac->T310_active) {
+    if (is_nr_timer_active(tac->T310)) {
       tac->N311_cnt++;
       // Upon receiving N311 consecutive "in-sync" indications
       if (tac->N311_cnt >= tac->N311_k) {
         // stop timer T310
-        tac->T310_active = false;
-        tac->T310_cnt = 0;
+        nr_timer_stop(&tac->T310);
         tac->N311_cnt = 0;
       }
     }
@@ -538,20 +556,19 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
   else {
     // OUT_OF_SYNC
     tac->N311_cnt = 0;
-    if(tac->T300_active ||
-       tac->T301_active ||
-       tac->T304_active ||
-       tac->T310_active ||
-       tac->T311_active ||
-       tac->T319_active)
+    if(is_nr_timer_active(tac->T300) ||
+       is_nr_timer_active(tac->T301) ||
+       is_nr_timer_active(tac->T304) ||
+       is_nr_timer_active(tac->T310) ||
+       is_nr_timer_active(tac->T311) ||
+       is_nr_timer_active(tac->T319))
       return;
     tac->N310_cnt++;
     // upon receiving N310 consecutive "out-of-sync" indications
     if (tac->N310_cnt >= tac->N310_k) {
       // start timer T310
-        tac->T310_active = true;
-        tac->T310_cnt = 0;
-        tac->N310_cnt = 0;
+      nr_timer_start(&tac->T310);
+      tac->N310_cnt = 0;
     }
   }
 }
@@ -559,17 +576,16 @@ void handle_rlf_sync(NR_UE_Timers_Constants_t *tac,
 void set_default_timers_and_constants(NR_UE_Timers_Constants_t *tac)
 {
   // 38.331 9.2.3 Default values timers and constants
-  tac->T310_k = 1000;
+  nr_timer_setup(&tac->T310, 1000, 10); // 10ms step
+  nr_timer_setup(&tac->T310, 30000, 10); // 10ms step
   tac->N310_k = 1;
-  tac->T311_k = 30000;
   tac->N311_k = 1;
 }
 
 void reset_rlf_timers_and_constants(NR_UE_Timers_Constants_t *tac)
 {
   // stop timer T310 for this cell group, if running
-  tac->T310_active = false;
-  tac->T310_cnt = 0;
+  nr_timer_stop(&tac->T310);
   // reset the counters N310 and N311
   tac->N310_cnt = 0;
   tac->N311_cnt = 0;
diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c
index 3ed50b49ccead57c0b602fe98d48ea2aab2bfcec..dfc0f64aa9cefd84962eab28adabb9f0b0533a67 100644
--- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c
+++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c
@@ -48,7 +48,6 @@
 #include "intertask_interface.h"
 #include "openair2/RRC/NAS/nas_config.h"
 #include <openair3/NAS/COMMON/NR_NAS_defs.h>
-#include <openair1/PHY/phy_extern_nr_ue.h>
 #include <openair1/SIMULATION/ETH_TRANSPORT/proto.h>
 #include "openair2/SDAP/nr_sdap/nr_sdap.h"
 #include "openair3/SECU/nas_stream_eia2.h"
diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf
index 3dfe31144812ebd21efb14b2203af800fde80101..1e377e5664b7ff9c063446de8e97e490b8992402 100644
--- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf
+++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band77.273prb.fhi72.4x4-vvdn.conf
@@ -194,7 +194,7 @@ MACRLCs = (
   num_cc                      = 1;
   tr_s_preference             = "local_L1";
   tr_n_preference             = "local_RRC";
-  pusch_TargetSNRx10          = 80;
+  pusch_TargetSNRx10          = 300;
   pucch_TargetSNRx10          = 200;
  # dl_bler_target_upper=.35;
  # dl_bler_target_lower=.15; 
diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf
index bc532c6a23f6f5772b4508598ebfe5992651d086..c362f05ac15e2ad0153a8cbcbeeb3b01bceadff3 100644
--- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf
+++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x2-benetel650.conf
@@ -193,7 +193,7 @@ MACRLCs = (
   num_cc                      = 1;
   tr_s_preference             = "local_L1";
   tr_n_preference             = "local_RRC";
-  pusch_TargetSNRx10          = 100;
+  pusch_TargetSNRx10          = 300;
   pucch_TargetSNRx10          = 230;
   dl_bler_target_upper=.35;
   dl_bler_target_lower=.15; 
@@ -235,12 +235,8 @@ RUs = (
   sl_ahead       = 10;
   ##beamforming 1x2 matrix: 1 layer x 2 antennas
   bf_weights = [0x00007fff, 0x0000,0x00007fff, 0x0000];
-  #clock_src = "internal";
-  sdr_addrs = "dummy --usecasefile /home/eurecom/raymond/usecase_du_3450_4ant.cfg --num_eth_vfs 2 --vf_addr_o_xu_a \"0000:31:06.0,0000:31:06.1\""
-  clock_src = "internal";
   tr_preference  = "raw_if4p5"; # important: activate FHI7.2
   do_precoding = 0; # needs to match O-RU configuration
-  
 }
 );
 
diff --git a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf
index b8dbd61cbc834cdc4740324acb32400574ca06ca..5de3d3a4b525003f4eca9271d7da633b3d38d38d 100644
--- a/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf
+++ b/targets/PROJECTS/GENERIC-NR-5GC/CONF/gnb.sa.band78.273prb.fhi72.4x4-liteon.conf
@@ -193,7 +193,7 @@ MACRLCs = (
   num_cc                      = 1;
   tr_s_preference             = "local_L1";
   tr_n_preference             = "local_RRC";
-  pusch_TargetSNRx10          = 200;
+  pusch_TargetSNRx10          = 300;
   pucch_TargetSNRx10          = 200;
  # dl_bler_target_upper=.35;
  # dl_bler_target_lower=.15;